Skip to content

Commit 7e16e3b

Browse files
authored
Merge pull request #30630 from martinboehme/cxx-constructors
2 parents 8d2c85d + 545b44e commit 7e16e3b

27 files changed

+664
-205
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3590,7 +3590,13 @@ void ClangImporter::getMangledName(raw_ostream &os,
35903590
if (!Impl.Mangler)
35913591
Impl.Mangler.reset(Impl.getClangASTContext().createMangleContext());
35923592

3593-
Impl.Mangler->mangleName(clangDecl, os);
3593+
if (auto ctor = dyn_cast<clang::CXXConstructorDecl>(clangDecl)) {
3594+
auto ctorGlobalDecl =
3595+
clang::GlobalDecl(ctor, clang::CXXCtorType::Ctor_Complete);
3596+
Impl.Mangler->mangleCXXName(ctorGlobalDecl, os);
3597+
} else {
3598+
Impl.Mangler->mangleName(clangDecl, os);
3599+
}
35943600
}
35953601

35963602
// ---------------------------------------------------------------------------

lib/ClangImporter/ImportDecl.cpp

Lines changed: 87 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1241,6 +1241,10 @@ synthesizeStructDefaultConstructorBody(AbstractFunctionDecl *afd,
12411241
ASTContext &ctx = constructor->getASTContext();
12421242
auto structDecl = static_cast<StructDecl *>(context);
12431243

1244+
// We should call into C++ constructors directly.
1245+
assert(!isa<clang::CXXRecordDecl>(structDecl->getClangDecl()) &&
1246+
"Should not synthesize a C++ object constructor.");
1247+
12441248
// Use a builtin to produce a zero initializer, and assign it to self.
12451249

12461250
// Construct the left-hand reference to self.
@@ -3378,6 +3382,11 @@ namespace {
33783382
continue;
33793383
}
33803384

3385+
if (auto CD = dyn_cast<ConstructorDecl>(member)) {
3386+
ctors.push_back(CD);
3387+
continue;
3388+
}
3389+
33813390
if (auto MD = dyn_cast<FuncDecl>(member)) {
33823391
methods.push_back(MD);
33833392
continue;
@@ -3434,12 +3443,17 @@ namespace {
34343443

34353444
bool hasReferenceableFields = !members.empty();
34363445

3437-
if (hasZeroInitializableStorage) {
3438-
// Add constructors for the struct.
3446+
const clang::CXXRecordDecl *cxxRecordDecl =
3447+
dyn_cast<clang::CXXRecordDecl>(decl);
3448+
if (hasZeroInitializableStorage && !cxxRecordDecl) {
3449+
// Add default constructor for the struct if compiling in C mode.
3450+
// If we're compiling for C++, we'll import the C++ default constructor
3451+
// (if there is one), so we don't need to synthesize one here.
34393452
ctors.push_back(createDefaultConstructor(Impl, result));
34403453
}
34413454

3442-
if (hasReferenceableFields && hasMemberwiseInitializer) {
3455+
bool isAggregate = !cxxRecordDecl || cxxRecordDecl->isAggregate();
3456+
if (hasReferenceableFields && hasMemberwiseInitializer && isAggregate) {
34433457
// The default zero initializer suppresses the implicit value
34443458
// constructor that would normally be formed, so we have to add that
34453459
// explicitly as well.
@@ -3470,7 +3484,7 @@ namespace {
34703484

34713485
result->setHasUnreferenceableStorage(hasUnreferenceableStorage);
34723486

3473-
if (auto cxxRecordDecl = dyn_cast<clang::CXXRecordDecl>(decl)) {
3487+
if (cxxRecordDecl) {
34743488
result->setIsCxxNonTrivial(!cxxRecordDecl->isTriviallyCopyable());
34753489

34763490
for (auto ctor : cxxRecordDecl->ctors()) {
@@ -3491,6 +3505,34 @@ namespace {
34913505
return result;
34923506
}
34933507

3508+
Decl *VisitCXXRecordDecl(const clang::CXXRecordDecl *decl) {
3509+
// This can be called from lldb without C++ interop being enabled: There
3510+
// may be C++ declarations in imported modules, but the interface for
3511+
// those modules may be a pure C or Objective-C interface.
3512+
// To avoid crashing in Clang's Sema, fall back to importing this as a
3513+
// plain RecordDecl.
3514+
if (!Impl.SwiftContext.LangOpts.EnableCXXInterop)
3515+
return VisitRecordDecl(decl);
3516+
3517+
auto &clangSema = Impl.getClangSema();
3518+
// Make Clang define the implicit default constructor if the class needs
3519+
// it. Make sure we only do this if the class has been fully defined and
3520+
// we're not in a dependent context (this is equivalent to the logic in
3521+
// CanDeclareSpecialMemberFunction in Clang's SemaLookup.cpp).
3522+
if (decl->getDefinition() && !decl->isBeingDefined() &&
3523+
!decl->isDependentContext() &&
3524+
decl->needsImplicitDefaultConstructor()) {
3525+
clang::CXXConstructorDecl *ctor =
3526+
clangSema.DeclareImplicitDefaultConstructor(
3527+
const_cast<clang::CXXRecordDecl *>(decl));
3528+
if (!ctor->isDeleted())
3529+
clangSema.DefineImplicitDefaultConstructor(clang::SourceLocation(),
3530+
ctor);
3531+
}
3532+
3533+
return VisitRecordDecl(decl);
3534+
}
3535+
34943536
Decl *VisitClassTemplateSpecializationDecl(
34953537
const clang::ClassTemplateSpecializationDecl *decl) {
34963538
// `Sema::isCompleteType` will try to instantiate the class template as a
@@ -3514,7 +3556,7 @@ namespace {
35143556
Impl.getClangSema().InstantiateClassTemplateSpecializationMembers(
35153557
def->getLocation(), def, clang::TSK_ExplicitInstantiationDefinition);
35163558

3517-
return VisitRecordDecl(def);
3559+
return VisitCXXRecordDecl(def);
35183560
}
35193561

35203562
Decl *VisitClassTemplatePartialSpecializationDecl(
@@ -3745,6 +3787,9 @@ namespace {
37453787
ImportedName importedName,
37463788
Optional<ImportedName> correctSwiftName,
37473789
Optional<AccessorInfo> accessorInfo) {
3790+
if (decl->isDeleted())
3791+
return nullptr;
3792+
37483793
auto dc =
37493794
Impl.importDeclContextOf(decl, importedName.getEffectiveContext());
37503795
if (!dc)
@@ -3753,7 +3798,6 @@ namespace {
37533798
DeclName name = accessorInfo ? DeclName() : importedName.getDeclName();
37543799
auto selfIdx = importedName.getSelfIndex();
37553800

3756-
FuncDecl *result = nullptr;
37573801
ImportedType importedType;
37583802
bool selfIsInOut = false;
37593803
ParameterList *bodyParams = nullptr;
@@ -3855,27 +3899,48 @@ namespace {
38553899
if (!importedType)
38563900
return nullptr;
38573901

3858-
auto resultTy = importedType.getType();
38593902
auto loc = Impl.importSourceLoc(decl->getLocation());
38603903

38613904
// FIXME: Poor location info.
38623905
auto nameLoc = Impl.importSourceLoc(decl->getLocation());
3863-
result = createFuncOrAccessor(
3864-
Impl.SwiftContext, loc, accessorInfo, name,
3865-
nameLoc, bodyParams, resultTy,
3866-
/*async*/ false, /*throws*/ false, dc, decl);
3867-
3868-
if (!dc->isModuleScopeContext()) {
3869-
if (selfIsInOut)
3870-
result->setSelfAccessKind(SelfAccessKind::Mutating);
3871-
else
3872-
result->setSelfAccessKind(SelfAccessKind::NonMutating);
3873-
if (selfIdx) {
3874-
result->setSelfIndex(selfIdx.getValue());
3875-
} else {
3876-
result->setStatic();
3877-
result->setImportAsStaticMember();
3906+
3907+
AbstractFunctionDecl *result = nullptr;
3908+
if (auto *ctordecl = dyn_cast<clang::CXXConstructorDecl>(decl)) {
3909+
// Don't import copy constructor or move constructor -- these will be
3910+
// provided through the value witness table.
3911+
if (ctordecl->isCopyConstructor() || ctordecl->isMoveConstructor())
3912+
return nullptr;
3913+
3914+
DeclName ctorName(Impl.SwiftContext, DeclBaseName::createConstructor(),
3915+
bodyParams);
3916+
result = Impl.createDeclWithClangNode<ConstructorDecl>(
3917+
decl, AccessLevel::Public, ctorName, loc, /*failable=*/false,
3918+
/*FailabilityLoc=*/SourceLoc(), /*Throws=*/false,
3919+
/*ThrowsLoc=*/SourceLoc(), bodyParams, /*GenericParams=*/nullptr,
3920+
dc);
3921+
} else {
3922+
auto resultTy = importedType.getType();
3923+
3924+
FuncDecl *func =
3925+
createFuncOrAccessor(Impl.SwiftContext, loc, accessorInfo, name,
3926+
nameLoc, bodyParams, resultTy,
3927+
/*async=*/false, /*throws=*/false, dc, decl);
3928+
result = func;
3929+
3930+
if (!dc->isModuleScopeContext()) {
3931+
if (selfIsInOut)
3932+
func->setSelfAccessKind(SelfAccessKind::Mutating);
3933+
else
3934+
func->setSelfAccessKind(SelfAccessKind::NonMutating);
3935+
if (selfIdx) {
3936+
func->setSelfIndex(selfIdx.getValue());
3937+
} else {
3938+
func->setStatic();
3939+
func->setImportAsStaticMember();
3940+
}
38783941
}
3942+
// Someday, maybe this will need to be 'open' for C++ virtual methods.
3943+
func->setAccess(AccessLevel::Public);
38793944
}
38803945

38813946
result->setIsObjC(false);
@@ -3889,8 +3954,6 @@ namespace {
38893954
result->getAttrs().add(new (Impl.SwiftContext)
38903955
FinalAttr(/*IsImplicit=*/true));
38913956

3892-
// Someday, maybe this will need to be 'open' for C++ virtual methods.
3893-
result->setAccess(AccessLevel::Public);
38943957
finishFuncDecl(decl, result);
38953958

38963959
// If this is a compatibility stub, mark it as such.

lib/ClangImporter/ImportName.cpp

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1366,6 +1366,15 @@ static bool suppressFactoryMethodAsInit(const clang::ObjCMethodDecl *method,
13661366
initKind == CtorInitializerKind::ConvenienceFactory);
13671367
}
13681368

1369+
static void
1370+
addEmptyArgNamesForClangFunction(const clang::FunctionDecl *funcDecl,
1371+
SmallVectorImpl<StringRef> &argumentNames) {
1372+
for (size_t i = 0; i < funcDecl->param_size(); ++i)
1373+
argumentNames.push_back(StringRef());
1374+
if (funcDecl->isVariadic())
1375+
argumentNames.push_back(StringRef());
1376+
}
1377+
13691378
ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
13701379
ImportNameVersion version,
13711380
clang::DeclarationName givenName) {
@@ -1599,7 +1608,19 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
15991608
SmallString<16> selectorSplitScratch;
16001609
ArrayRef<const clang::ParmVarDecl *> params;
16011610
switch (D->getDeclName().getNameKind()) {
1602-
case clang::DeclarationName::CXXConstructorName:
1611+
case clang::DeclarationName::CXXConstructorName: {
1612+
isInitializer = true;
1613+
isFunction = true;
1614+
result.info.initKind = CtorInitializerKind::Designated;
1615+
baseName = "init";
1616+
auto ctor = dyn_cast<clang::CXXConstructorDecl>(D);
1617+
if (auto templateCtor = dyn_cast<clang::FunctionTemplateDecl>(D))
1618+
ctor = cast<clang::CXXConstructorDecl>(templateCtor->getAsFunction());
1619+
assert(ctor && "Unkown decl with CXXConstructorName.");
1620+
addEmptyArgNamesForClangFunction(ctor, argumentNames);
1621+
break;
1622+
}
1623+
16031624
case clang::DeclarationName::CXXConversionFunctionName:
16041625
case clang::DeclarationName::CXXDestructorName:
16051626
case clang::DeclarationName::CXXLiteralOperatorName:
@@ -1670,16 +1691,9 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
16701691
}
16711692
}
16721693

1673-
// For C functions, create empty argument names.
16741694
if (auto function = dyn_cast<clang::FunctionDecl>(D)) {
16751695
isFunction = true;
1676-
params = {function->param_begin(), function->param_end()};
1677-
for (auto param : params) {
1678-
(void)param;
1679-
argumentNames.push_back(StringRef());
1680-
}
1681-
if (function->isVariadic())
1682-
argumentNames.push_back(StringRef());
1696+
addEmptyArgNamesForClangFunction(function, argumentNames);
16831697
}
16841698
break;
16851699

lib/IRGen/GenCall.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1292,6 +1292,16 @@ void SignatureExpansion::expandExternalSignatureTypes() {
12921292
SmallVector<clang::CanQualType,4> paramTys;
12931293
auto const &clangCtx = IGM.getClangASTContext();
12941294

1295+
bool formalIndirectResult = FnType->getNumResults() > 0 &&
1296+
FnType->getSingleResult().isFormalIndirect();
1297+
if (formalIndirectResult) {
1298+
auto resultType = getSILFuncConventions().getSingleSILResultType(
1299+
IGM.getMaximalTypeExpansionContext());
1300+
auto clangTy =
1301+
IGM.getClangASTContext().getPointerType(IGM.getClangType(resultType));
1302+
paramTys.push_back(clangTy);
1303+
}
1304+
12951305
switch (FnType->getRepresentation()) {
12961306
case SILFunctionTypeRepresentation::ObjCMethod: {
12971307
// ObjC methods take their 'self' argument first, followed by an
@@ -1923,6 +1933,9 @@ class SyncCallEmission final : public CallEmission {
19231933
// This can happen when calling C functions, or class method dispatch thunks
19241934
// for methods that have covariant ABI-compatible overrides.
19251935
auto expectedNativeResultType = nativeSchema.getExpandedType(IGF.IGM);
1936+
// If the expected result type is void, bail.
1937+
if (expectedNativeResultType->isVoidTy())
1938+
return;
19261939
if (result->getType() != expectedNativeResultType) {
19271940
result =
19281941
IGF.coerceValue(result, expectedNativeResultType, IGF.IGM.DataLayout);
@@ -2815,6 +2828,11 @@ static void externalizeArguments(IRGenFunction &IGF, const Callee &callee,
28152828
== SILFunctionTypeRepresentation::Block) {
28162829
// Ignore the physical block-object parameter.
28172830
firstParam += 1;
2831+
// Or the indirect result parameter.
2832+
} else if (fnType->getNumResults() > 0 &&
2833+
fnType->getSingleResult().isFormalIndirect()) {
2834+
// Ignore the indirect result parameter.
2835+
firstParam += 1;
28182836
}
28192837

28202838
for (unsigned i = firstParam, e = FI.arg_size(); i != e; ++i) {

lib/IRGen/GenDecl.cpp

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
#include "clang/AST/ASTContext.h"
3939
#include "clang/AST/DeclCXX.h"
4040
#include "clang/AST/GlobalDecl.h"
41+
#include "clang/CodeGen/CodeGenABITypes.h"
42+
#include "clang/CodeGen/ModuleBuilder.h"
4143
#include "llvm/ADT/SmallString.h"
4244
#include "llvm/IR/DerivedTypes.h"
4345
#include "llvm/IR/GlobalAlias.h"
@@ -2761,6 +2763,77 @@ void IRGenModule::emitDynamicReplacementOriginalFunctionThunk(SILFunction *f) {
27612763
IGF.Builder.CreateRet(Res);
27622764
}
27632765

2766+
/// If the calling convention for `ctor` doesn't match the calling convention
2767+
/// that we assumed for it when we imported it as `initializer`, emit and
2768+
/// return a thunk that conforms to the assumed calling convention. The thunk
2769+
/// is marked `alwaysinline`, so it doesn't generate any runtime overhead.
2770+
/// If the assumed calling convention was correct, just return `ctor`.
2771+
///
2772+
/// See also comments in CXXMethodConventions in SIL/IR/SILFunctionType.cpp.
2773+
static llvm::Constant *
2774+
emitCXXConstructorThunkIfNeeded(IRGenModule &IGM, SILFunction *initializer,
2775+
const clang::CXXConstructorDecl *ctor,
2776+
const LinkEntity &entity,
2777+
llvm::Constant *ctorAddress) {
2778+
Signature signature = IGM.getSignature(initializer->getLoweredFunctionType());
2779+
2780+
llvm::FunctionType *assumedFnType = signature.getType();
2781+
llvm::FunctionType *ctorFnType =
2782+
cast<llvm::FunctionType>(ctorAddress->getType()->getPointerElementType());
2783+
2784+
if (assumedFnType == ctorFnType) {
2785+
return ctorAddress;
2786+
}
2787+
2788+
// The thunk has private linkage, so it doesn't need to have a predictable
2789+
// mangled name -- we just need to make sure the name is unique.
2790+
llvm::SmallString<32> name;
2791+
llvm::raw_svector_ostream stream(name);
2792+
stream << "__swift_cxx_ctor";
2793+
entity.mangle(stream);
2794+
2795+
llvm::Function *thunk = llvm::Function::Create(
2796+
assumedFnType, llvm::Function::PrivateLinkage, name, &IGM.Module);
2797+
2798+
thunk->setCallingConv(llvm::CallingConv::C);
2799+
2800+
llvm::AttrBuilder attrBuilder;
2801+
IGM.constructInitialFnAttributes(attrBuilder);
2802+
attrBuilder.addAttribute(llvm::Attribute::AlwaysInline);
2803+
llvm::AttributeList attr = signature.getAttributes().addAttributes(
2804+
IGM.getLLVMContext(), llvm::AttributeList::FunctionIndex, attrBuilder);
2805+
thunk->setAttributes(attr);
2806+
2807+
IRGenFunction subIGF(IGM, thunk);
2808+
if (IGM.DebugInfo)
2809+
IGM.DebugInfo->emitArtificialFunction(subIGF, thunk);
2810+
2811+
SmallVector<llvm::Value *, 8> Args;
2812+
for (auto i = thunk->arg_begin(), e = thunk->arg_end(); i != e; ++i) {
2813+
auto *argTy = i->getType();
2814+
auto *paramTy = ctorFnType->getParamType(i - thunk->arg_begin());
2815+
if (paramTy != argTy)
2816+
Args.push_back(subIGF.coerceValue(i, paramTy, IGM.DataLayout));
2817+
else
2818+
Args.push_back(i);
2819+
}
2820+
2821+
clang::CodeGen::ImplicitCXXConstructorArgs implicitArgs =
2822+
clang::CodeGen::getImplicitCXXConstructorArgs(IGM.ClangCodeGen->CGM(),
2823+
ctor);
2824+
for (size_t i = 0; i < implicitArgs.Prefix.size(); ++i) {
2825+
Args.insert(Args.begin() + 1 + i, implicitArgs.Prefix[i]);
2826+
}
2827+
for (const auto &arg : implicitArgs.Suffix) {
2828+
Args.push_back(arg);
2829+
}
2830+
2831+
subIGF.Builder.CreateCall(ctorFnType, ctorAddress, Args);
2832+
subIGF.Builder.CreateRetVoid();
2833+
2834+
return thunk;
2835+
}
2836+
27642837
/// Find the entry point for a SIL function.
27652838
llvm::Function *IRGenModule::getAddrOfSILFunction(
27662839
SILFunction *f, ForDefinition_t forDefinition,
@@ -2789,6 +2862,11 @@ llvm::Function *IRGenModule::getAddrOfSILFunction(
27892862
if (auto clangDecl = f->getClangDecl()) {
27902863
auto globalDecl = getClangGlobalDeclForFunction(clangDecl);
27912864
clangAddr = getAddrOfClangGlobalDecl(globalDecl, forDefinition);
2865+
2866+
if (auto ctor = dyn_cast<clang::CXXConstructorDecl>(clangDecl)) {
2867+
clangAddr =
2868+
emitCXXConstructorThunkIfNeeded(*this, f, ctor, entity, clangAddr);
2869+
}
27922870
}
27932871

27942872
bool isDefinition = f->isDefinition();

0 commit comments

Comments
 (0)