Skip to content

Commit bb00e8d

Browse files
committed
[cxx-interop] Rudimentary support for importing base classes.
This commit adds very basic support for importing and calling base class methods, getting and setting base class fields, and using types inside of base classes.
1 parent 4b44ac5 commit bb00e8d

16 files changed

+1152
-71
lines changed

include/swift/AST/ClangModuleLoader.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ class ClangModuleLoader : public ModuleLoader {
268268
clang::DeclarationName givenName = clang::DeclarationName()) = 0;
269269

270270
/// Determine the effective Clang context for the given Swift nominal type.
271-
EffectiveClangContext virtual getEffectiveClangContext(
271+
virtual EffectiveClangContext getEffectiveClangContext(
272272
const NominalTypeDecl *nominal) = 0;
273273
};
274274

lib/ClangImporter/ClangImporter.cpp

Lines changed: 439 additions & 0 deletions
Large diffs are not rendered by default.

lib/ClangImporter/ImportDecl.cpp

Lines changed: 64 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -692,7 +692,7 @@ static AccessorDecl *makeStructRawValueGetter(
692692
assert(storedVar->hasStorage());
693693

694694
ASTContext &C = Impl.SwiftContext;
695-
695+
696696
auto *params = ParameterList::createEmpty(C);
697697

698698
auto computedType = computedVar->getInterfaceType();
@@ -726,7 +726,7 @@ static AccessorDecl *makeFieldGetterDecl(ClangImporter::Implementation &Impl,
726726
auto &C = Impl.SwiftContext;
727727

728728
auto *params = ParameterList::createEmpty(C);
729-
729+
730730
auto getterType = importedFieldDecl->getInterfaceType();
731731
auto getterDecl = AccessorDecl::create(C,
732732
/*FuncLoc=*/importedFieldDecl->getLoc(),
@@ -1152,7 +1152,7 @@ makeBitFieldAccessors(ClangImporter::Implementation &Impl,
11521152
cSetterParamTypes,
11531153
clang::FunctionProtoType::ExtProtoInfo());
11541154
auto cSetterTypeInfo = Ctx.getTrivialTypeSourceInfo(cSetterType);
1155-
1155+
11561156
auto cSetterDecl = clang::FunctionDecl::Create(Ctx,
11571157
structDecl->getDeclContext(),
11581158
clang::SourceLocation(),
@@ -1184,7 +1184,7 @@ makeBitFieldAccessors(ClangImporter::Implementation &Impl,
11841184
clang::SC_None,
11851185
nullptr);
11861186
cGetterDecl->setParams(cGetterSelf);
1187-
1187+
11881188
auto cGetterSelfExpr = new (Ctx) clang::DeclRefExpr(Ctx, cGetterSelf, false,
11891189
recordType,
11901190
clang::VK_PRValue,
@@ -1197,7 +1197,7 @@ makeBitFieldAccessors(ClangImporter::Implementation &Impl,
11971197
clang::VK_PRValue,
11981198
clang::OK_BitField);
11991199

1200-
1200+
12011201
auto cGetterBody = clang::ReturnStmt::Create(Ctx, clang::SourceLocation(),
12021202
cGetterExpr,
12031203
nullptr);
@@ -1228,20 +1228,20 @@ makeBitFieldAccessors(ClangImporter::Implementation &Impl,
12281228
nullptr);
12291229
cSetterParams.push_back(cSetterSelf);
12301230
cSetterDecl->setParams(cSetterParams);
1231-
1231+
12321232
auto cSetterSelfExpr = new (Ctx) clang::DeclRefExpr(Ctx, cSetterSelf, false,
12331233
recordPointerType,
12341234
clang::VK_PRValue,
12351235
clang::SourceLocation());
1236-
1236+
12371237
auto cSetterMemberExpr = clang::MemberExpr::CreateImplicit(Ctx,
12381238
cSetterSelfExpr,
12391239
/*isarrow=*/true,
12401240
fieldDecl,
12411241
fieldType,
12421242
clang::VK_LValue,
12431243
clang::OK_BitField);
1244-
1244+
12451245
auto cSetterValueExpr = new (Ctx) clang::DeclRefExpr(Ctx, cSetterValue, false,
12461246
fieldType,
12471247
clang::VK_PRValue,
@@ -1256,7 +1256,7 @@ makeBitFieldAccessors(ClangImporter::Implementation &Impl,
12561256
clang::OK_Ordinary,
12571257
clang::SourceLocation(),
12581258
clang::FPOptionsOverride());
1259-
1259+
12601260
cSetterDecl->setBody(cSetterExpr);
12611261
}
12621262

@@ -2419,7 +2419,7 @@ namespace {
24192419
if (auto *typedefForAnon = decl->getTypedefNameForAnonDecl())
24202420
return importFullName(typedefForAnon);
24212421
}
2422-
2422+
24232423
return {ImportedName(), None};
24242424
}
24252425

@@ -2806,7 +2806,7 @@ namespace {
28062806
});
28072807

28082808
Result->setUnderlyingType(SwiftType);
2809-
2809+
28102810
// Make Objective-C's 'id' unavailable.
28112811
if (Impl.SwiftContext.LangOpts.EnableObjCInterop && isObjCId(Decl)) {
28122812
auto attr = AvailableAttr::createPlatformAgnostic(
@@ -2882,7 +2882,7 @@ namespace {
28822882
Impl.importDeclContextOf(decl, importedName.getEffectiveContext());
28832883
if (!dc)
28842884
return nullptr;
2885-
2885+
28862886
auto name = importedName.getDeclName().getBaseIdentifier();
28872887

28882888
// Create the enum declaration and record it.
@@ -2948,7 +2948,7 @@ namespace {
29482948
ProtocolDecl *bridgedNSError = nullptr;
29492949
ClassDecl *nsErrorDecl = nullptr;
29502950
ProtocolDecl *errorCodeProto = nullptr;
2951-
if (enumInfo.isErrorEnum() &&
2951+
if (enumInfo.isErrorEnum() &&
29522952
(bridgedNSError =
29532953
C.getProtocol(KnownProtocolKind::BridgedStoredNSError)) &&
29542954
(nsErrorDecl = C.getNSErrorDecl()) &&
@@ -3124,7 +3124,7 @@ namespace {
31243124
Impl.ImportedDecls[{canonicalClangDecl, getVersion()}] = result;
31253125

31263126
// Import each of the enumerators.
3127-
3127+
31283128
bool addEnumeratorsAsMembers;
31293129
switch (enumKind) {
31303130
case EnumKind::Constants:
@@ -3282,7 +3282,7 @@ namespace {
32823282
addDecl(result, enumeratorDecl);
32833283
for (auto *variant : variantDecls)
32843284
addDecl(result, variant);
3285-
3285+
32863286
// If there is an error wrapper, add an alias within the
32873287
// wrapper to the corresponding value within the enumerator
32883288
// context.
@@ -3334,7 +3334,7 @@ namespace {
33343334
// Track whether this record contains fields we can't reference in Swift
33353335
// as stored properties.
33363336
bool hasUnreferenceableStorage = false;
3337-
3337+
33383338
// Track whether this record contains fields that can't be zero-
33393339
// initialized.
33403340
bool hasZeroInitializableStorage = true;
@@ -3576,6 +3576,12 @@ namespace {
35763576

35773577
const clang::CXXRecordDecl *cxxRecordDecl =
35783578
dyn_cast<clang::CXXRecordDecl>(decl);
3579+
bool hasBaseClasses = cxxRecordDecl && !cxxRecordDecl->bases().empty();
3580+
if (hasBaseClasses) {
3581+
hasUnreferenceableStorage = true;
3582+
hasMemberwiseInitializer = false;
3583+
}
3584+
35793585
if (hasZeroInitializableStorage && !cxxRecordDecl) {
35803586
// Add default constructor for the struct if compiling in C mode.
35813587
// If we're compiling for C++, we'll import the C++ default constructor
@@ -4212,10 +4218,10 @@ namespace {
42124218
DeclName ctorName(Impl.SwiftContext, DeclBaseName::createConstructor(),
42134219
bodyParams);
42144220
result = Impl.createDeclWithClangNode<ConstructorDecl>(
4215-
clangNode, AccessLevel::Public, ctorName, loc,
4221+
clangNode, AccessLevel::Public, ctorName, loc,
42164222
/*failable=*/false, /*FailabilityLoc=*/SourceLoc(),
42174223
/*Async=*/false, /*AsyncLoc=*/SourceLoc(),
4218-
/*Throws=*/false, /*ThrowsLoc=*/SourceLoc(),
4224+
/*Throws=*/false, /*ThrowsLoc=*/SourceLoc(),
42194225
bodyParams, genericParams, dc);
42204226
} else {
42214227
auto resultTy = importedType.getType();
@@ -4592,33 +4598,33 @@ namespace {
45924598
// Only import types for now.
45934599
if (!isa<clang::TypeDecl>(decl->getUnderlyingDecl()))
45944600
return nullptr;
4595-
4601+
45964602
ImportedName importedName;
45974603
Optional<ImportedName> correctSwiftName;
45984604
std::tie(importedName, correctSwiftName) = importFullName(decl);
45994605
auto Name = importedName.getDeclName().getBaseIdentifier();
46004606
if (Name.empty())
46014607
return nullptr;
4602-
4608+
46034609
// If we've been asked to produce a compatibility stub, handle it via a
46044610
// typealias.
46054611
if (correctSwiftName)
46064612
return importCompatibilityTypeAlias(decl, importedName,
46074613
*correctSwiftName);
4608-
4614+
46094615
auto DC =
46104616
Impl.importDeclContextOf(decl, importedName.getEffectiveContext());
46114617
if (!DC)
46124618
return nullptr;
4613-
4619+
46144620
Decl *SwiftDecl = Impl.importDecl(decl->getUnderlyingDecl(), getActiveSwiftVersion());
46154621
if (!SwiftDecl)
46164622
return nullptr;
46174623

46184624
const TypeDecl *SwiftTypeDecl = dyn_cast<TypeDecl>(SwiftDecl);
46194625
if (!SwiftTypeDecl)
46204626
return nullptr;
4621-
4627+
46224628
auto Loc = Impl.importSourceLoc(decl->getLocation());
46234629
auto Result = Impl.createDeclWithClangNode<TypeAliasDecl>(
46244630
decl,
@@ -5286,7 +5292,7 @@ namespace {
52865292
objcClass->getDeclaredType());
52875293
Impl.SwiftContext.evaluator.cacheOutput(ExtendedNominalRequest{result},
52885294
std::move(objcClass));
5289-
5295+
52905296
// Determine the type and generic args of the extension.
52915297
if (objcClass->getGenericParams()) {
52925298
result->setGenericSignature(objcClass->getGenericSignature());
@@ -5305,7 +5311,7 @@ namespace {
53055311
}
53065312

53075313
template <typename T, typename U>
5308-
T *resolveSwiftDeclImpl(const U *decl, Identifier name,
5314+
T *resolveSwiftDeclImpl(const U *decl, Identifier name,
53095315
bool hasKnownSwiftName, ModuleDecl *overlay) {
53105316
const auto &languageVersion =
53115317
Impl.SwiftContext.LangOpts.EffectiveLanguageVersion;
@@ -6178,7 +6184,7 @@ Decl *SwiftDeclConverter::importCompatibilityTypeAlias(
61786184
}
61796185

61806186
alias->setUnderlyingType(typeDecl->getDeclaredInterfaceType());
6181-
6187+
61826188
// Record that this is the official version of this declaration.
61836189
Impl.ImportedDecls[{decl->getCanonicalDecl(), getVersion()}] = alias;
61846190
markAsVariant(alias, correctSwiftName);
@@ -9335,7 +9341,7 @@ ClangImporter::Implementation::importMirroredDecl(const clang::NamedDecl *decl,
93359341

93369342
auto updateMirroredDecl = [&](Decl *result) {
93379343
result->setImplicit();
9338-
9344+
93399345
// Map the Clang attributes onto Swift attributes.
93409346
importAttributes(decl, result);
93419347

@@ -9926,10 +9932,10 @@ static void loadAllMembersOfSuperclassIfNeeded(ClassDecl *CD) {
99269932
E->loadAllMembers();
99279933
}
99289934

9929-
void ClangImporter::Implementation::loadAllMembersOfRecordDecl(
9930-
NominalTypeDecl *recordDecl) {
9931-
auto clangRecord = cast<clang::RecordDecl>(recordDecl->getClangDecl());
9935+
ValueDecl *cloneBaseMemberDecl(ValueDecl *decl, DeclContext *newContext);
99329936

9937+
void ClangImporter::Implementation::loadAllMembersOfRecordDecl(
9938+
NominalTypeDecl *swiftDecl, const clang::RecordDecl *clangRecord) {
99339939
// Import all of the members.
99349940
llvm::SmallVector<Decl *, 16> members;
99359941
for (const clang::Decl *m : clangRecord->decls()) {
@@ -9955,12 +9961,36 @@ void ClangImporter::Implementation::loadAllMembersOfRecordDecl(
99559961

99569962
// Add the members here.
99579963
for (auto member: members) {
9964+
// This means we found a member in a C++ record's base class.
9965+
if (swiftDecl->getClangDecl() != clangRecord) {
9966+
// So we need to clone the member into the derived class.
9967+
if (auto newDecl = cloneBaseMemberDecl(cast<ValueDecl>(member), swiftDecl)) {
9968+
swiftDecl->addMember(newDecl);
9969+
}
9970+
continue;
9971+
}
9972+
99589973
// FIXME: constructors are added eagerly, but shouldn't be
99599974
// FIXME: subscripts are added eagerly, but shouldn't be
99609975
if (!isa<AccessorDecl>(member) &&
99619976
!isa<SubscriptDecl>(member) &&
9962-
!isa<ConstructorDecl>(member))
9963-
recordDecl->addMember(member);
9977+
!isa<ConstructorDecl>(member)) {
9978+
swiftDecl->addMember(member);
9979+
}
9980+
}
9981+
9982+
// If this is a C++ record, look through the base classes too.
9983+
if (auto cxxRecord = dyn_cast<clang::CXXRecordDecl>(clangRecord)) {
9984+
for (auto base : cxxRecord->bases()) {
9985+
clang::QualType baseType = base.getType();
9986+
if (auto spectType = dyn_cast<clang::TemplateSpecializationType>(baseType))
9987+
baseType = spectType->desugar();
9988+
if (!isa<clang::RecordType>(baseType))
9989+
continue;
9990+
9991+
auto *baseRecord = cast<clang::RecordType>(baseType)->getDecl();
9992+
loadAllMembersOfRecordDecl(swiftDecl, baseRecord);
9993+
}
99649994
}
99659995
}
99669996

@@ -9996,7 +10026,8 @@ ClangImporter::Implementation::loadAllMembers(Decl *D, uint64_t extra) {
999610026
}
999710027

999810028
if (isa_and_nonnull<clang::RecordDecl>(D->getClangDecl())) {
9999-
loadAllMembersOfRecordDecl(cast<NominalTypeDecl>(D));
10029+
loadAllMembersOfRecordDecl(cast<NominalTypeDecl>(D),
10030+
cast<clang::RecordDecl>(D->getClangDecl()));
1000010031
return;
1000110032
}
1000210033

lib/ClangImporter/ImporterImpl.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1460,7 +1460,8 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
14601460
void
14611461
loadAllMembersOfObjcContainer(Decl *D,
14621462
const clang::ObjCContainerDecl *objcContainer);
1463-
void loadAllMembersOfRecordDecl(NominalTypeDecl *recordDecl);
1463+
void loadAllMembersOfRecordDecl(NominalTypeDecl *swiftDecl,
1464+
const clang::RecordDecl *clangRecord);
14641465

14651466
void collectMembersToAdd(const clang::ObjCContainerDecl *objcContainer,
14661467
Decl *D, DeclContext *DC,

0 commit comments

Comments
 (0)