Skip to content

Commit 7429124

Browse files
authored
Merge pull request #83065 from Xazax-hun/guard-more-objc-on-6.2
[6.2][cxx-interop] Types exposed from ObjC modules should be behind a macro
2 parents b7acd12 + f48da45 commit 7429124

File tree

8 files changed

+92
-7
lines changed

8 files changed

+92
-7
lines changed

include/swift/AST/SwiftNameTranslation.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#ifndef SWIFT_NAME_TRANSLATION_H
1414
#define SWIFT_NAME_TRANSLATION_H
1515

16+
#include "swift/AST/ASTContext.h"
1617
#include "swift/AST/AttrKind.h"
1718
#include "swift/AST/Decl.h"
1819
#include "swift/AST/DiagnosticEngine.h"
@@ -112,6 +113,9 @@ inline bool isExposableToCxx(
112113
return !getDeclRepresentation(VD, isZeroSized).isUnsupported();
113114
}
114115

116+
bool isObjCxxOnly(const ValueDecl *VD);
117+
bool isObjCxxOnly(const clang::Decl *D, const ASTContext &ctx);
118+
115119
/// Returns true if the given value decl D is visible to C++ of its
116120
/// own accord (i.e. without considering its context)
117121
bool isVisibleToCxx(const ValueDecl *VD, AccessLevel minRequiredAccess,

include/swift/Basic/LangOptions.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,10 @@ namespace swift {
632632
/// All block list configuration files to be honored in this compilation.
633633
std::vector<std::string> BlocklistConfigFilePaths;
634634

635+
/// List of top level modules to be considered as if they had require ObjC
636+
/// in their module map.
637+
llvm::SmallVector<StringRef> ModulesRequiringObjC;
638+
635639
/// Whether to ignore checks that a module is resilient during
636640
/// type-checking, SIL verification, and IR emission,
637641
bool BypassResilienceChecks = false;

lib/AST/SwiftNameTranslation.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
#include "swift/Basic/StringExtras.h"
2929

3030
#include "clang/AST/DeclObjC.h"
31+
#include "clang/Basic/Module.h"
32+
#include "llvm/ADT/STLExtras.h"
3133
#include "llvm/ADT/SmallString.h"
3234
#include <optional>
3335

@@ -238,6 +240,51 @@ swift::cxx_translation::getNameForCxx(const ValueDecl *VD,
238240
return VD->getBaseIdentifier().str();
239241
}
240242

243+
namespace {
244+
struct ObjCTypeWalker : TypeWalker {
245+
bool hadObjCType = false;
246+
const ASTContext &ctx;
247+
ObjCTypeWalker(const ASTContext &ctx) : ctx(ctx) {}
248+
Action walkToTypePre(Type ty) override {
249+
if (auto *nominal = ty->getNominalOrBoundGenericNominal()) {
250+
if (auto clangDecl = nominal->getClangDecl()) {
251+
if (cxx_translation::isObjCxxOnly(clangDecl, ctx)) {
252+
hadObjCType = true;
253+
return Action::Stop;
254+
}
255+
}
256+
}
257+
return Action::Continue;
258+
}
259+
};
260+
} // namespace
261+
262+
bool swift::cxx_translation::isObjCxxOnly(const ValueDecl *VD) {
263+
ObjCTypeWalker walker{VD->getASTContext()};
264+
VD->getInterfaceType().walk(walker);
265+
return walker.hadObjCType;
266+
}
267+
268+
bool swift::cxx_translation::isObjCxxOnly(const clang::Decl *D,
269+
const ASTContext &ctx) {
270+
// By default, we import all modules in Obj-C++ mode, so there is no robust
271+
// way to tell if something is coming from an Obj-C module. Use the
272+
// requirements and the language options to check if we should actually
273+
// consider the module to have ObjC constructs.
274+
const auto &langOpts = D->getASTContext().getLangOpts();
275+
auto clangModule = D->getOwningModule()->getTopLevelModule();
276+
bool requiresObjC = false;
277+
for (auto req : clangModule->Requirements)
278+
if (req.RequiredState && req.FeatureName == "objc")
279+
requiresObjC = true;
280+
return langOpts.ObjC &&
281+
(requiresObjC ||
282+
llvm::any_of(ctx.LangOpts.ModulesRequiringObjC,
283+
[clangModule](StringRef moduleName) {
284+
return clangModule->getFullModuleName() == moduleName;
285+
}));
286+
}
287+
241288
swift::cxx_translation::DeclRepresentation
242289
swift::cxx_translation::getDeclRepresentation(
243290
const ValueDecl *VD,
@@ -324,6 +371,9 @@ swift::cxx_translation::getDeclRepresentation(
324371
return {Unsupported, UnrepresentableGenericRequirements};
325372
}
326373

374+
if (isObjCxxOnly(VD))
375+
return {ObjCxxOnly, std::nullopt};
376+
327377
return {Representable, std::nullopt};
328378
}
329379

lib/Frontend/CompilerInvocation.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -847,7 +847,8 @@ static bool ParseEnabledFeatureArgs(LangOptions &Opts, ArgList &Args,
847847
// Collect some special case pseudo-features which should be processed
848848
// separately.
849849
if (argValue.starts_with("StrictConcurrency") ||
850-
argValue.starts_with("AvailabilityMacro=")) {
850+
argValue.starts_with("AvailabilityMacro=") ||
851+
argValue.starts_with("RequiresObjC=")) {
851852
if (isEnableFeatureFlag)
852853
psuedoFeatures.push_back(argValue);
853854
continue;
@@ -974,6 +975,11 @@ static bool ParseEnabledFeatureArgs(LangOptions &Opts, ArgList &Args,
974975
Opts.AvailabilityMacros.push_back(availability.str());
975976
continue;
976977
}
978+
979+
if (featureName->starts_with("RequiresObjC")) {
980+
auto modules = featureName->split("=").second;
981+
modules.split(Opts.ModulesRequiringObjC, ",");
982+
}
977983
}
978984

979985
// Map historical flags over to experimental features. We do this for all

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: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@
1616
#include "OutputLanguageMode.h"
1717
#include "PrimitiveTypeMapping.h"
1818
#include "SwiftToClangInteropContext.h"
19+
#include "swift/AST/ASTContext.h"
1920
#include "swift/AST/Decl.h"
2021
#include "swift/AST/SwiftNameTranslation.h"
2122
#include "swift/AST/Type.h"
2223
#include "swift/ClangImporter/ClangImporter.h"
2324
#include "swift/IRGen/IRABIDetailsProvider.h"
2425
#include "swift/IRGen/Linking.h"
26+
#include "clang/Basic/Module.h"
2527
#include "llvm/ADT/STLExtras.h"
2628
#include "llvm/Support/raw_ostream.h"
2729

@@ -642,20 +644,28 @@ void ClangValueTypePrinter::printTypeGenericTraits(
642644
});
643645
}
644646

647+
bool objCxxOnly = false;
648+
if (const auto *clangDecl = typeDecl->getClangDecl()) {
649+
if (cxx_translation::isObjCxxOnly(clangDecl, typeDecl->getASTContext()))
650+
objCxxOnly = true;
651+
}
652+
645653
// FIXME: avoid popping out of the module's namespace here.
646654
os << "} // end namespace \n\n";
647655
os << "namespace swift SWIFT_PRIVATE_ATTR {\n";
648656
auto classDecl = dyn_cast<ClassDecl>(typeDecl);
649657
bool addPointer =
650658
typeDecl->isObjC() || (classDecl && classDecl->isForeignReferenceType());
651659

660+
if (objCxxOnly)
661+
os << "#if defined(__OBJC__)\n";
652662
os << "#pragma clang diagnostic push\n";
653663
os << "#pragma clang diagnostic ignored \"-Wc++17-extensions\"\n";
654-
if (typeDecl->hasClangNode()) {
664+
if (const auto *clangDecl = typeDecl->getClangDecl()) {
655665
// FIXME: share the code.
656666
os << "template<>\n";
657667
os << "inline const constexpr bool isUsableInGenericContext<";
658-
printer.printClangTypeReference(typeDecl->getClangDecl());
668+
printer.printClangTypeReference(clangDecl);
659669
if (addPointer)
660670
os << "*";
661671
os << "> = true;\n";
@@ -665,8 +675,8 @@ void ClangValueTypePrinter::printTypeGenericTraits(
665675
os << "struct";
666676
declAndTypePrinter.printAvailability(os, typeDecl);
667677
os << " TypeMetadataTrait<";
668-
if (typeDecl->hasClangNode()) {
669-
printer.printClangTypeReference(typeDecl->getClangDecl());
678+
if (const auto *clangDecl = typeDecl->getClangDecl()) {
679+
printer.printClangTypeReference(clangDecl);
670680
if (addPointer)
671681
os << "*";
672682
} else {
@@ -746,6 +756,8 @@ void ClangValueTypePrinter::printTypeGenericTraits(
746756
}
747757
os << "} // namespace\n";
748758
os << "#pragma clang diagnostic pop\n";
759+
if (objCxxOnly)
760+
os << "#endif // #if defined(__OBJC__)\n";
749761
os << "} // namespace swift\n";
750762
os << "\n";
751763
printer.printModuleNamespaceStart(*moduleContext);

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
// RUN: %empty-directory(%t)
22

3-
// RUN: %target-swift-frontend %s -module-name UseFoundation -enable-experimental-cxx-interop -typecheck -verify -emit-clang-header-path %t/UseFoundation.h
3+
// RUN: %target-swift-frontend %s -module-name UseFoundation -enable-experimental-cxx-interop -typecheck -verify -emit-clang-header-path %t/UseFoundation.h -enable-experimental-feature RequiresObjC=CoreGraphics,Foundation
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() -> Decimal {
18+
Decimal()
19+
}
20+
1521
// CHECK: class UseFoundationEnum { } SWIFT_UNAVAILABLE_MSG("Swift enum 'UseFoundationEnum' cannot be represented in C++");

test/Misc/verify-swift-feature-testing.test-sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ EXCEPTIONAL_FILES = [
2121
pathlib.Path("test/ModuleInterface/swift-export-as.swift"),
2222
# Uses the pseudo-feature AvailabilityMacro=
2323
pathlib.Path("test/Availability/availability_define.swift"),
24+
# Uses the pseudo-feature RequiresObjC=
25+
pathlib.Path("test/Interop/SwiftToCxx/stdlib/foundation-type-not-exposed-by-default-to-cxx.swift"),
2426
# Tests behavior when you try to use a feature without enabling it
2527
pathlib.Path("test/attr/feature_requirement.swift"),
2628
# Tests completion with features both enabled and disabled

0 commit comments

Comments
 (0)