Skip to content

Commit f36e5cf

Browse files
committed
[interop] add 'ImportSymbolicCXXDecls' experimental import mode for importing class templates syntactically but not semantically
1 parent e6e7bd0 commit f36e5cf

File tree

10 files changed

+140
-13
lines changed

10 files changed

+140
-13
lines changed

include/swift/Basic/Features.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,11 @@ EXPERIMENTAL_FEATURE(BuiltinMacros, false)
167167
/// declare an attribute which is discoverable and constructable at runtime.
168168
EXPERIMENTAL_FEATURE(RuntimeDiscoverableAttrs, false)
169169

170+
/// Import C++ class templates as semantically-meaningless symbolic
171+
/// Swift types and C++ methods as symbolic functions with blank
172+
/// signatures.
173+
EXPERIMENTAL_FEATURE(ImportSymbolicCXXDecls, false)
174+
170175
#undef EXPERIMENTAL_FEATURE
171176
#undef UPCOMING_FEATURE
172177
#undef SUPPRESSIBLE_LANGUAGE_FEATURE

lib/AST/ASTPrinter.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3170,6 +3170,8 @@ static bool usesFeatureBuiltinMacros(Decl *decl) {
31703170
return false;
31713171
}
31723172

3173+
static bool usesFeatureImportSymbolicCXXDecls(Decl *decl) { return false; }
3174+
31733175
static void
31743176
suppressingFeatureNoAsyncAvailability(PrintOptions &options,
31753177
llvm::function_ref<void()> action) {

lib/ClangImporter/ClangImporter.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2269,13 +2269,13 @@ ClangImporter::Implementation::Implementation(
22692269
!ctx.ClangImporterOpts.BridgingHeader.empty()),
22702270
DisableOverlayModules(ctx.ClangImporterOpts.DisableOverlayModules),
22712271
EnableClangSPI(ctx.ClangImporterOpts.EnableClangSPI),
2272+
importSymbolicCXXDecls(
2273+
ctx.LangOpts.hasFeature(Feature::ImportSymbolicCXXDecls)),
22722274
IsReadingBridgingPCH(false),
22732275
CurrentVersion(ImportNameVersion::fromOptions(ctx.LangOpts)),
2274-
Walker(DiagnosticWalker(*this)),
2275-
BuffersForDiagnostics(ctx.SourceMgr),
2276+
Walker(DiagnosticWalker(*this)), BuffersForDiagnostics(ctx.SourceMgr),
22762277
BridgingHeaderLookupTable(new SwiftLookupTable(nullptr)),
2277-
platformAvailability(ctx.LangOpts),
2278-
nameImporter(),
2278+
platformAvailability(ctx.LangOpts), nameImporter(),
22792279
DisableSourceImport(ctx.ClangImporterOpts.DisableSourceImport),
22802280
DWARFImporter(dwarfImporterDelegate) {}
22812281

lib/ClangImporter/ImportDecl.cpp

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2005,7 +2005,8 @@ namespace {
20052005
}
20062006

20072007
// TODO(https://github.com/apple/swift/issues/56206): Fix this once we support dependent types.
2008-
if (decl->getTypeForDecl()->isDependentType()) {
2008+
if (decl->getTypeForDecl()->isDependentType() &&
2009+
!Impl.importSymbolicCXXDecls) {
20092010
Impl.addImportDiagnostic(
20102011
decl, Diagnostic(
20112012
diag::record_is_dependent,
@@ -2681,6 +2682,12 @@ namespace {
26812682

26822683
Decl *VisitClassTemplateSpecializationDecl(
26832684
const clang::ClassTemplateSpecializationDecl *decl) {
2685+
// Treat a specific specialization like the unspecialized class template
2686+
// when importing it in symbolic mode.
2687+
if (Impl.importSymbolicCXXDecls)
2688+
return Impl.importDecl(decl->getSpecializedTemplate(),
2689+
Impl.CurrentVersion);
2690+
26842691
// Before we go any further, check if we've already got tens of thousands
26852692
// of specializations. If so, it means we're likely instantiating a very
26862693
// deep/complex template, or we've run into an infinite loop. In either
@@ -3067,6 +3074,8 @@ namespace {
30673074
Impl.SwiftContext, SourceLoc(), templateParams, SourceLoc());
30683075
}
30693076

3077+
bool importFuncWithoutSignature =
3078+
isa<clang::CXXMethodDecl>(decl) && Impl.importSymbolicCXXDecls;
30703079
if (!dc->isModuleScopeContext() && !isa<clang::CXXMethodDecl>(decl)) {
30713080
// Handle initializers.
30723081
if (name.getBaseName() == DeclBaseName::createConstructor()) {
@@ -3132,12 +3141,17 @@ namespace {
31323141
importedType =
31333142
Impl.importFunctionReturnType(dc, decl, allowNSUIntegerAsInt);
31343143
} else {
3135-
// Import the function type. If we have parameters, make sure their
3136-
// names get into the resulting function type.
3137-
importedType = Impl.importFunctionParamsAndReturnType(
3138-
dc, decl, {decl->param_begin(), decl->param_size()},
3139-
decl->isVariadic(), isInSystemModule(dc), name, bodyParams,
3140-
templateParams);
3144+
if (importFuncWithoutSignature) {
3145+
importedType = ImportedType{Impl.SwiftContext.getVoidType(), false};
3146+
bodyParams = ParameterList::createEmpty(Impl.SwiftContext);
3147+
} else {
3148+
// Import the function type. If we have parameters, make sure their
3149+
// names get into the resulting function type.
3150+
importedType = Impl.importFunctionParamsAndReturnType(
3151+
dc, decl, {decl->param_begin(), decl->param_size()},
3152+
decl->isVariadic(), isInSystemModule(dc), name, bodyParams,
3153+
templateParams);
3154+
}
31413155

31423156
if (auto *mdecl = dyn_cast<clang::CXXMethodDecl>(decl)) {
31433157
if (mdecl->isStatic()) {
@@ -3221,7 +3235,7 @@ namespace {
32213235
}
32223236
}
32233237

3224-
if (importedName.isSubscriptAccessor()) {
3238+
if (importedName.isSubscriptAccessor() && !importFuncWithoutSignature) {
32253239
assert(func->getParameters()->size() == 1);
32263240
auto typeDecl = dc->getSelfNominalTypeDecl();
32273241
auto parameter = func->getParameters()->get(0);
@@ -3496,6 +3510,12 @@ namespace {
34963510
auto name = importedName.getDeclName().getBaseIdentifier();
34973511
if (name.empty())
34983512
return nullptr;
3513+
3514+
if (Impl.importSymbolicCXXDecls)
3515+
// Import an unspecialized C++ class template as a Swift value/class
3516+
// type in symbolic mode.
3517+
return Impl.importDecl(decl->getTemplatedDecl(), Impl.CurrentVersion);
3518+
34993519
auto loc = Impl.importSourceLoc(decl->getLocation());
35003520
auto dc = Impl.importDeclContextOf(
35013521
decl, importedName.getEffectiveContext());

lib/ClangImporter/ImportName.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2173,6 +2173,11 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
21732173

21742174
if (auto classTemplateSpecDecl =
21752175
dyn_cast<clang::ClassTemplateSpecializationDecl>(D)) {
2176+
/// Symbolic specializations get imported as the symbolic class template
2177+
/// type.
2178+
if (importSymbolicCXXDecls)
2179+
return importNameImpl(classTemplateSpecDecl->getSpecializedTemplate(),
2180+
version, givenName);
21762181
if (!isa<clang::ClassTemplatePartialSpecializationDecl>(D)) {
21772182

21782183
auto &astContext = classTemplateSpecDecl->getASTContext();

lib/ClangImporter/ImportName.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -387,11 +387,15 @@ class NameImporter {
387387
llvm::DenseMap<std::pair<const clang::ObjCInterfaceDecl *, char>,
388388
std::unique_ptr<InheritedNameSet>> allProperties;
389389

390+
bool importSymbolicCXXDecls;
391+
390392
public:
391393
NameImporter(ASTContext &ctx, const PlatformAvailability &avail,
392394
clang::Sema &cSema)
393395
: swiftCtx(ctx), availability(avail), clangSema(cSema),
394-
enumInfos(clangSema.getPreprocessor()) {}
396+
enumInfos(clangSema.getPreprocessor()),
397+
importSymbolicCXXDecls(
398+
ctx.LangOpts.hasFeature(Feature::ImportSymbolicCXXDecls)) {}
395399

396400
/// Determine the Swift name for a Clang decl
397401
ImportedName importName(const clang::NamedDecl *decl,

lib/ClangImporter/ImportType.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ bool ClangImporter::Implementation::isOverAligned(const clang::TypeDecl *decl) {
6666
}
6767

6868
bool ClangImporter::Implementation::isOverAligned(clang::QualType type) {
69+
// Do not check type layout for a clang type in symbolic mode as the
70+
// type could be a dependent type.
71+
if (importSymbolicCXXDecls)
72+
return false;
6973
auto align = getClangASTContext().getTypeAlignInChars(type);
7074
return align > clang::CharUnits::fromQuantity(MaximumAlignment);
7175
}

lib/ClangImporter/ImporterImpl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,7 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
452452
const bool BridgingHeaderExplicitlyRequested;
453453
const bool DisableOverlayModules;
454454
const bool EnableClangSPI;
455+
bool importSymbolicCXXDecls;
455456

456457
bool IsReadingBridgingPCH;
457458
llvm::SmallVector<clang::serialization::SubmoduleID, 2> PCHImportedSubmodules;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// RUN: %target-swift-ide-test -print-module -module-to-print=CxxStdlib -source-filename=x -enable-experimental-cxx-interop -enable-objc-interop -module-print-submodules -enable-experimental-feature ImportSymbolicCXXDecls | %FileCheck %s
2+
3+
// REQUIRES: asserts
4+
// REQUIRES: OS=macosx
5+
// REQUIRES: libcxx-in-sdk
6+
7+
// CHECK: enum std {
8+
// CHECK-NEXT: enum __1 {
9+
10+
// CHECK: struct basic_string {
11+
12+
// CHECK: typealias string = std.__1.basic_string
13+
14+
// CHECK: struct vector {
15+
// CHECK: mutating func push_back()
16+
// CHECK: }
17+
18+
// CHECK: struct map {
19+
20+
// CHECK-NOT: enum std
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// RUN: rm -rf %t
2+
// RUN: split-file %s %t
3+
// RUN: %target-swift-ide-test -print-module -module-to-print=CxxModule -I %t/Inputs -source-filename=x -enable-experimental-cxx-interop -enable-experimental-feature ImportSymbolicCXXDecls | %FileCheck %s
4+
5+
// REQUIRES: asserts
6+
7+
//--- Inputs/module.modulemap
8+
module CxxModule {
9+
header "headerA.h"
10+
header "headerB.h"
11+
requires cplusplus
12+
}
13+
14+
//--- Inputs/headerA.h
15+
16+
namespace ns {
17+
int freeFunction(int x, int y);
18+
}
19+
20+
//--- Inputs/headerB.h
21+
22+
#include "headerA.h"
23+
24+
namespace ns {
25+
struct B {
26+
int y;
27+
};
28+
29+
template<class T>
30+
struct TemplateRecord {
31+
void methodFunc(int x);
32+
33+
struct InnerRecord {
34+
int innerMethod(int y);
35+
};
36+
37+
template<class T2>
38+
struct InnerTemplate {
39+
void innerTemplateMethod();
40+
};
41+
42+
InnerTemplate<int> returnsTemplateMethod();
43+
};
44+
}
45+
46+
using MyType = ns::TemplateRecord<int>;
47+
48+
// CHECK: enum ns {
49+
// CHECK-NEXT: struct B {
50+
// CHECK-NEXT: init()
51+
// CHECK-NEXT: init(y: Int32)
52+
// CHECK-NEXT: var y: Int32
53+
// CHECK-NEXT: }
54+
// CHECK-NEXT: struct TemplateRecord {
55+
// CHECK-NEXT: mutating func methodFunc()
56+
// CHECK-NEXT: struct InnerRecord {
57+
// CHECK-NEXT: mutating func innerMethod()
58+
// CHECK-NEXT: }
59+
// CHECK-NEXT: struct InnerTemplate {
60+
// CHECK-NEXT: mutating func innerTemplateMethod()
61+
// CHECK-NEXT: }
62+
// CHECK-NEXT: mutating func returnsTemplateMethod()
63+
// CHECK-NEXT: }
64+
// CHECK-NEXT: static func freeFunction(_ x: Int32, _ y: Int32) -> Int32
65+
// CHECK-NEXT: }
66+
// CHECK-NEXT: typealias MyType = ns.TemplateRecord

0 commit comments

Comments
 (0)