Skip to content

Commit 761c503

Browse files
authored
Merge pull request #83002 from Xazax-hun/guard-more-objc
[cxx-interop] Types exposed from ObjC modules should be behind a macro
2 parents 67506f5 + 9b1b9b7 commit 761c503

File tree

5 files changed

+63
-5
lines changed

5 files changed

+63
-5
lines changed

include/swift/AST/SwiftNameTranslation.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ inline bool isExposableToCxx(
112112
return !getDeclRepresentation(VD, isZeroSized).isUnsupported();
113113
}
114114

115+
bool isObjCxxOnly(const ValueDecl *VD);
116+
bool isObjCxxOnly(const clang::Decl *D);
117+
115118
/// Returns true if the given value decl D is visible to C++ of its
116119
/// own accord (i.e. without considering its context)
117120
bool isVisibleToCxx(const ValueDecl *VD, AccessLevel minRequiredAccess,

lib/AST/SwiftNameTranslation.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "swift/Basic/StringExtras.h"
3030

3131
#include "clang/AST/DeclObjC.h"
32+
#include "clang/Basic/Module.h"
3233
#include "llvm/ADT/SmallString.h"
3334
#include <optional>
3435

@@ -237,6 +238,39 @@ swift::cxx_translation::getNameForCxx(const ValueDecl *VD,
237238
return VD->getBaseIdentifier().str();
238239
}
239240

241+
namespace {
242+
struct ObjCTypeWalker : TypeWalker {
243+
bool hadObjCType = false;
244+
Action walkToTypePre(Type ty) override {
245+
if (auto *nominal = ty->getNominalOrBoundGenericNominal()) {
246+
if (auto clangDecl = nominal->getClangDecl()) {
247+
if (cxx_translation::isObjCxxOnly(clangDecl)) {
248+
hadObjCType = true;
249+
return Action::Stop;
250+
}
251+
}
252+
}
253+
return Action::Continue;
254+
}
255+
};
256+
} // namespace
257+
258+
bool swift::cxx_translation::isObjCxxOnly(const ValueDecl *VD) {
259+
ObjCTypeWalker walker;
260+
VD->getInterfaceType().walk(walker);
261+
return walker.hadObjCType;
262+
}
263+
264+
bool swift::cxx_translation::isObjCxxOnly(const clang::Decl *D) {
265+
// By default, we import all modules in Obj-C++ mode, so there is no robust
266+
// way to tell if something is coming from an Obj-C module. The best
267+
// approximation is to check if something is a framework module as most of
268+
// those are written in Obj-C. Ideally, we want to add `requires ObjC` to all
269+
// ObjC modules and respect that here to make this completely precise.
270+
return D->getASTContext().getLangOpts().ObjC &&
271+
D->getOwningModule()->isPartOfFramework();
272+
}
273+
240274
swift::cxx_translation::DeclRepresentation
241275
swift::cxx_translation::getDeclRepresentation(
242276
const ValueDecl *VD,
@@ -323,6 +357,9 @@ swift::cxx_translation::getDeclRepresentation(
323357
return {Unsupported, UnrepresentableGenericRequirements};
324358
}
325359

360+
if (isObjCxxOnly(VD))
361+
return {ObjCxxOnly, std::nullopt};
362+
326363
return {Representable, std::nullopt};
327364
}
328365

lib/PrintAsClang/PrintClangFunction.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -812,7 +812,8 @@ ClangRepresentation DeclAndTypeClangFunctionPrinter::printFunctionSignature(
812812
ClangSyntaxPrinter(FD->getASTContext(), functionSignatureOS).printInlineForThunk();
813813

814814
ClangRepresentation resultingRepresentation =
815-
ClangRepresentation::representable;
815+
cxx_translation::isObjCxxOnly(FD) ? ClangRepresentation::objcxxonly
816+
: ClangRepresentation::representable;
816817

817818
// Print out the return type.
818819
if (FD->hasThrows() && outputLang == OutputLanguageMode::Cxx)

lib/PrintAsClang/PrintClangValueType.cpp

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "swift/ClangImporter/ClangImporter.h"
2323
#include "swift/IRGen/IRABIDetailsProvider.h"
2424
#include "swift/IRGen/Linking.h"
25+
#include "clang/Basic/Module.h"
2526
#include "llvm/ADT/STLExtras.h"
2627
#include "llvm/Support/raw_ostream.h"
2728

@@ -616,20 +617,28 @@ void ClangValueTypePrinter::printTypeGenericTraits(
616617
});
617618
}
618619

620+
bool objCxxOnly = false;
621+
if (const auto *clangDecl = typeDecl->getClangDecl()) {
622+
if (cxx_translation::isObjCxxOnly(clangDecl))
623+
objCxxOnly = true;
624+
}
625+
619626
// FIXME: avoid popping out of the module's namespace here.
620627
os << "} // end namespace \n\n";
621628
os << "namespace swift SWIFT_PRIVATE_ATTR {\n";
622629
auto classDecl = dyn_cast<ClassDecl>(typeDecl);
623630
bool addPointer =
624631
typeDecl->isObjC() || (classDecl && classDecl->isForeignReferenceType());
625632

633+
if (objCxxOnly)
634+
os << "#if defined(__OBJC__)\n";
626635
os << "#pragma clang diagnostic push\n";
627636
os << "#pragma clang diagnostic ignored \"-Wc++17-extensions\"\n";
628-
if (typeDecl->hasClangNode()) {
637+
if (const auto *clangDecl = typeDecl->getClangDecl()) {
629638
// FIXME: share the code.
630639
os << "template<>\n";
631640
os << "inline const constexpr bool isUsableInGenericContext<";
632-
printer.printClangTypeReference(typeDecl->getClangDecl());
641+
printer.printClangTypeReference(clangDecl);
633642
if (addPointer)
634643
os << "*";
635644
os << "> = true;\n";
@@ -639,8 +648,8 @@ void ClangValueTypePrinter::printTypeGenericTraits(
639648
os << "struct";
640649
declAndTypePrinter.printAvailability(os, typeDecl);
641650
os << " TypeMetadataTrait<";
642-
if (typeDecl->hasClangNode()) {
643-
printer.printClangTypeReference(typeDecl->getClangDecl());
651+
if (const auto *clangDecl = typeDecl->getClangDecl()) {
652+
printer.printClangTypeReference(clangDecl);
644653
if (addPointer)
645654
os << "*";
646655
} else {
@@ -720,6 +729,8 @@ void ClangValueTypePrinter::printTypeGenericTraits(
720729
}
721730
os << "} // namespace\n";
722731
os << "#pragma clang diagnostic pop\n";
732+
if (objCxxOnly)
733+
os << "#endif // #if defined(__OBJC__)\n";
723734
os << "} // namespace swift\n";
724735
os << "\n";
725736
printer.printModuleNamespaceStart(*moduleContext);

test/Interop/SwiftToCxx/stdlib/foundation-type-not-exposed-by-default-to-cxx.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
// RUN: %target-swift-frontend %s -module-name UseFoundation -enable-experimental-cxx-interop -typecheck -verify -emit-clang-header-path %t/UseFoundation.h
44
// RUN: %FileCheck %s < %t/UseFoundation.h
55

6+
// RUN: %check-interop-cxx-header-in-clang(%t/UseFoundation.h -DSWIFT_CXX_INTEROP_HIDE_STL_OVERLAY)
7+
68
// REQUIRES: objc_interop
79

810
import Foundation
@@ -12,4 +14,8 @@ public enum UseFoundationEnum {
1214
case B
1315
}
1416

17+
public func f() -> NSEdgeInsets {
18+
NSEdgeInsets()
19+
}
20+
1521
// CHECK: class UseFoundationEnum { } SWIFT_UNAVAILABLE_MSG("Swift enum 'UseFoundationEnum' cannot be represented in C++");

0 commit comments

Comments
 (0)