Skip to content

Commit 85b970a

Browse files
author
Gabor Horvath
committed
[cxx-interop] Configure requires ObjC from frontend option
We sometimes don't have the information in the modulemaps whether a module requires ObjC or not. This info is useful for reverse interop. This PR introduces a frontend flag to have a comma separated list of modules that we should import as if they had "requires ObjC" in their modulemaps.
1 parent 48fb7cd commit 85b970a

File tree

7 files changed

+41
-12
lines changed

7 files changed

+41
-12
lines changed

include/swift/AST/SwiftNameTranslation.h

Lines changed: 2 additions & 1 deletion
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"
@@ -113,7 +114,7 @@ inline bool isExposableToCxx(
113114
}
114115

115116
bool isObjCxxOnly(const ValueDecl *VD);
116-
bool isObjCxxOnly(const clang::Decl *D);
117+
bool isObjCxxOnly(const clang::Decl *D, const ASTContext &ctx);
117118

118119
/// Returns true if the given value decl D is visible to C++ of its
119120
/// own accord (i.e. without considering its context)

include/swift/Basic/LangOptions.h

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

643+
/// List of top level modules to be considered as if they had require ObjC
644+
/// in their module map.
645+
llvm::SmallVector<StringRef> ModulesRequiringObjC;
646+
643647
/// Whether to ignore checks that a module is resilient during
644648
/// type-checking, SIL verification, and IR emission,
645649
bool BypassResilienceChecks = false;

include/swift/Option/FrontendOptions.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,6 +1023,11 @@ def cxx_interop_use_opaque_pointer_for_moveonly :
10231023
HelpText<"Testing flag that will be eliminated soon. Do not use.">,
10241024
Flags<[FrontendOption, HelpHidden]>;
10251025

1026+
def cxx_modules_require_objc :
1027+
Separate<["-"], "cxx-modules-require-objc">, MetaVarName<"<name>">,
1028+
HelpText<"A comma separated list of top level module names to consider require ObjC.">,
1029+
Flags<[FrontendOption, NoDriverOption, HelpHidden]>;
1030+
10261031
def use_malloc : Flag<["-"], "use-malloc">,
10271032
HelpText<"Allocate internal data structures using malloc "
10281033
"(for memory debugging)">;

lib/AST/SwiftNameTranslation.cpp

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
#include "clang/AST/DeclObjC.h"
3232
#include "clang/Basic/Module.h"
33+
#include "llvm/ADT/STLExtras.h"
3334
#include "llvm/ADT/SmallString.h"
3435
#include <optional>
3536

@@ -241,10 +242,12 @@ swift::cxx_translation::getNameForCxx(const ValueDecl *VD,
241242
namespace {
242243
struct ObjCTypeWalker : TypeWalker {
243244
bool hadObjCType = false;
245+
const ASTContext &ctx;
246+
ObjCTypeWalker(const ASTContext &ctx) : ctx(ctx) {}
244247
Action walkToTypePre(Type ty) override {
245248
if (auto *nominal = ty->getNominalOrBoundGenericNominal()) {
246249
if (auto clangDecl = nominal->getClangDecl()) {
247-
if (cxx_translation::isObjCxxOnly(clangDecl)) {
250+
if (cxx_translation::isObjCxxOnly(clangDecl, ctx)) {
248251
hadObjCType = true;
249252
return Action::Stop;
250253
}
@@ -256,19 +259,29 @@ struct ObjCTypeWalker : TypeWalker {
256259
} // namespace
257260

258261
bool swift::cxx_translation::isObjCxxOnly(const ValueDecl *VD) {
259-
ObjCTypeWalker walker;
262+
ObjCTypeWalker walker{VD->getASTContext()};
260263
VD->getInterfaceType().walk(walker);
261264
return walker.hadObjCType;
262265
}
263266

264-
bool swift::cxx_translation::isObjCxxOnly(const clang::Decl *D) {
267+
bool swift::cxx_translation::isObjCxxOnly(const clang::Decl *D,
268+
const ASTContext &ctx) {
265269
// 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();
270+
// way to tell if something is coming from an Obj-C module. Use the
271+
// requirements and the language options to check if we should actually
272+
// consider the module to have ObjC constructs.
273+
const auto &langOpts = D->getASTContext().getLangOpts();
274+
auto clangModule = D->getOwningModule()->getTopLevelModule();
275+
bool requiresObjC = false;
276+
for (auto req : clangModule->Requirements)
277+
if (req.RequiredState && req.FeatureName == "ObjC")
278+
requiresObjC = true;
279+
return langOpts.ObjC &&
280+
(requiresObjC ||
281+
llvm::any_of(ctx.LangOpts.ModulesRequiringObjC,
282+
[clangModule](StringRef moduleName) {
283+
return clangModule->getFullModuleName() == moduleName;
284+
}));
272285
}
273286

274287
swift::cxx_translation::DeclRepresentation

lib/Frontend/CompilerInvocation.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,11 @@ void LangOptions::setCxxInteropFromArgs(ArgList &Args,
750750
else
751751
FormalCxxInteropMode = std::nullopt;
752752
}
753+
754+
if (Arg *A = Args.getLastArg(options::OPT_cxx_modules_require_objc)) {
755+
StringRef modules = A->getValue();
756+
modules.split(ModulesRequiringObjC, ",");
757+
}
753758
}
754759

755760
static std::string printFormalCxxInteropVersion(const LangOptions &Opts) {

lib/PrintAsClang/PrintClangValueType.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
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"
@@ -619,7 +620,7 @@ void ClangValueTypePrinter::printTypeGenericTraits(
619620

620621
bool objCxxOnly = false;
621622
if (const auto *clangDecl = typeDecl->getClangDecl()) {
622-
if (cxx_translation::isObjCxxOnly(clangDecl))
623+
if (cxx_translation::isObjCxxOnly(clangDecl, typeDecl->getASTContext()))
623624
objCxxOnly = true;
624625
}
625626

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
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 -cxx-modules-require-objc "CoreGraphics,Foundation"
44
// RUN: %FileCheck %s < %t/UseFoundation.h
55

66
// RUN: %check-interop-cxx-header-in-clang(%t/UseFoundation.h -DSWIFT_CXX_INTEROP_HIDE_STL_OVERLAY)

0 commit comments

Comments
 (0)