Skip to content

Commit 850ce16

Browse files
committed
Added support for multiple ctors
1 parent abd15ae commit 850ce16

File tree

4 files changed

+135
-124
lines changed

4 files changed

+135
-124
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2513,12 +2513,13 @@ namespace {
25132513
});
25142514
});
25152515
if (!hasUserProvidedStaticFactory) {
2516-
if (auto generatedCxxMethodDecl =
2517-
synthesizer.synthesizeStaticFactoryForCXXForeignRef(
2518-
cxxRecordDecl)) {
2516+
auto generatedCxxMethodDecls =
2517+
synthesizer.synthesizeStaticFactoryForCXXForeignRef(
2518+
cxxRecordDecl);
2519+
for (auto *methodDecl : generatedCxxMethodDecls) {
25192520
if (Decl *importedInitDecl =
25202521
Impl.SwiftContext.getClangModuleLoader()
2521-
->importDeclDirectly(generatedCxxMethodDecl))
2522+
->importDeclDirectly(methodDecl))
25222523
result->addMember(importedInitDecl);
25232524
}
25242525
}

lib/ClangImporter/SwiftDeclSynthesizer.cpp

Lines changed: 127 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -2534,27 +2534,17 @@ SwiftDeclSynthesizer::makeDefaultArgument(const clang::ParmVarDecl *param,
25342534

25352535
// MARK: C++ foreign reference type constructors
25362536

2537-
clang::CXXMethodDecl *
2537+
llvm::SmallVector<clang::CXXMethodDecl *, 4>
25382538
SwiftDeclSynthesizer::synthesizeStaticFactoryForCXXForeignRef(
25392539
const clang::CXXRecordDecl *cxxRecordDecl) {
25402540

25412541
clang::ASTContext &clangCtx = cxxRecordDecl->getASTContext();
25422542
clang::Sema &clangSema = ImporterImpl.getClangSema();
2543-
clang::SourceLocation cxxRecordDeclLoc = cxxRecordDecl->getLocation();
25442543

25452544
clang::QualType cxxRecordTy = clangCtx.getRecordType(cxxRecordDecl);
2545+
clang::SourceLocation cxxRecordDeclLoc = cxxRecordDecl->getLocation();
25462546

2547-
// Todo: synthesize static factories for all available ctors
2548-
clang::CXXConstructorDecl *selectedCtorDecl = nullptr;
2549-
for (clang::CXXConstructorDecl *ctor : cxxRecordDecl->ctors()) {
2550-
if (!ctor->isDeleted() && ctor->getAccess() != clang::AS_private &&
2551-
ctor->getAccess() != clang::AS_protected) {
2552-
selectedCtorDecl = ctor;
2553-
break;
2554-
}
2555-
}
2556-
if (!selectedCtorDecl)
2557-
return nullptr;
2547+
llvm::SmallVector<clang::CXXMethodDecl *, 4> synthesizedFactories;
25582548

25592549
clang::FunctionDecl *operatorNew = nullptr;
25602550
clang::FunctionDecl *operatorDelete = nullptr;
@@ -2566,7 +2556,7 @@ SwiftDeclSynthesizer::synthesizeStaticFactoryForCXXForeignRef(
25662556
if (findingAllocFuncFailed || !operatorNew || operatorNew->isDeleted() ||
25672557
operatorNew->getAccess() == clang::AS_private ||
25682558
operatorNew->getAccess() == clang::AS_protected)
2569-
return nullptr;
2559+
return synthesizedFactories;
25702560

25712561
clang::QualType cxxRecordPtrTy = clangCtx.getPointerType(cxxRecordTy);
25722562
// Adding `_Nonnull` to the return type of synthesized static factory
@@ -2579,113 +2569,132 @@ SwiftDeclSynthesizer::synthesizeStaticFactoryForCXXForeignRef(
25792569
"static factory's return type");
25802570

25812571
clang::IdentifierTable &clangIdents = clangCtx.Idents;
2582-
clang::IdentifierInfo *funcNameToSynthesize = &clangIdents.get(
2583-
("__returns_" + cxxRecordDecl->getNameAsString()).c_str());
2584-
2585-
llvm::SmallVector<clang::QualType, 4> paramTypes;
2586-
for (const auto *param : selectedCtorDecl->parameters())
2587-
paramTypes.push_back(param->getType());
2588-
clang::FunctionProtoType::ExtProtoInfo EPI;
2589-
clang::QualType funcTypeToSynthesize =
2590-
clangCtx.getFunctionType(cxxRecordPtrTy, paramTypes, EPI);
2591-
2592-
clang::CXXMethodDecl *synthesizedCxxMethodDecl = clang::CXXMethodDecl::Create(
2593-
clangCtx, const_cast<clang::CXXRecordDecl *>(cxxRecordDecl),
2594-
cxxRecordDeclLoc,
2595-
clang::DeclarationNameInfo(funcNameToSynthesize, cxxRecordDeclLoc),
2596-
funcTypeToSynthesize,
2597-
clangCtx.getTrivialTypeSourceInfo(funcTypeToSynthesize), clang::SC_Static,
2598-
/*UsesFPIntrin=*/false, /*isInline=*/true,
2599-
clang::ConstexprSpecKind::Unspecified, cxxRecordDeclLoc);
2600-
synthesizedCxxMethodDecl->setAccess(clang::AccessSpecifier::AS_public);
2601-
2602-
llvm::SmallVector<clang::ParmVarDecl *, 4> synthesizedParams;
2603-
for (unsigned int i = 0; i < selectedCtorDecl->getNumParams(); ++i) {
2604-
auto *origParam = selectedCtorDecl->getParamDecl(i);
2605-
auto *param = clang::ParmVarDecl::Create(
2606-
clangCtx, synthesizedCxxMethodDecl, cxxRecordDeclLoc, cxxRecordDeclLoc,
2607-
origParam->getIdentifier(), origParam->getType(),
2608-
clangCtx.getTrivialTypeSourceInfo(origParam->getType()), clang::SC_None,
2609-
nullptr);
2610-
synthesizedParams.push_back(param);
2611-
}
2612-
synthesizedCxxMethodDecl->setParams(synthesizedParams);
26132572

2614-
if (!hasImmortalAttrs(cxxRecordDecl)) {
2615-
clang::SwiftAttrAttr *returnsRetainedAttrForSynthesizedCxxMethodDecl =
2616-
clang::SwiftAttrAttr::Create(clangCtx, "returns_retained");
2573+
for (clang::CXXConstructorDecl *selectedCtorDecl : cxxRecordDecl->ctors()) {
2574+
if (selectedCtorDecl->isDeleted() ||
2575+
selectedCtorDecl->getAccess() == clang::AS_private ||
2576+
selectedCtorDecl->getAccess() == clang::AS_protected ||
2577+
selectedCtorDecl->isCopyOrMoveConstructor())
2578+
continue;
2579+
2580+
unsigned int ctorParamCount = selectedCtorDecl->getNumParams();
2581+
std::string funcName = "__returns_" + cxxRecordDecl->getNameAsString();
2582+
if (ctorParamCount > 0)
2583+
funcName += "_" + std::to_string(ctorParamCount) + "_params";
2584+
clang::IdentifierInfo *funcNameToSynthesize = &clangIdents.get(funcName);
2585+
2586+
llvm::SmallVector<clang::QualType, 4> paramTypes;
2587+
for (const auto *param : selectedCtorDecl->parameters())
2588+
paramTypes.push_back(param->getType());
2589+
clang::FunctionProtoType::ExtProtoInfo EPI;
2590+
clang::QualType funcTypeToSynthesize =
2591+
clangCtx.getFunctionType(cxxRecordPtrTy, paramTypes, EPI);
2592+
2593+
clang::CXXMethodDecl *synthesizedCxxMethodDecl =
2594+
clang::CXXMethodDecl::Create(
2595+
clangCtx, const_cast<clang::CXXRecordDecl *>(cxxRecordDecl),
2596+
cxxRecordDeclLoc,
2597+
clang::DeclarationNameInfo(funcNameToSynthesize, cxxRecordDeclLoc),
2598+
funcTypeToSynthesize,
2599+
clangCtx.getTrivialTypeSourceInfo(funcTypeToSynthesize),
2600+
clang::SC_Static, /*UsesFPIntrin=*/false, /*isInline=*/true,
2601+
clang::ConstexprSpecKind::Unspecified, cxxRecordDeclLoc);
2602+
assert(
2603+
synthesizedCxxMethodDecl &&
2604+
"Unable to synthesize static factory for c++ foreign reference type");
2605+
synthesizedCxxMethodDecl->setAccess(clang::AccessSpecifier::AS_public);
2606+
2607+
llvm::SmallVector<clang::ParmVarDecl *, 4> synthesizedParams;
2608+
for (unsigned int i = 0; i < ctorParamCount; ++i) {
2609+
auto *origParam = selectedCtorDecl->getParamDecl(i);
2610+
auto *param = clang::ParmVarDecl::Create(
2611+
clangCtx, synthesizedCxxMethodDecl, cxxRecordDeclLoc,
2612+
cxxRecordDeclLoc, origParam->getIdentifier(), origParam->getType(),
2613+
clangCtx.getTrivialTypeSourceInfo(origParam->getType()),
2614+
clang::SC_None, nullptr);
2615+
synthesizedParams.push_back(param);
2616+
}
2617+
synthesizedCxxMethodDecl->setParams(synthesizedParams);
2618+
2619+
if (!hasImmortalAttrs(cxxRecordDecl)) {
2620+
clang::SwiftAttrAttr *returnsRetainedAttrForSynthesizedCxxMethodDecl =
2621+
clang::SwiftAttrAttr::Create(clangCtx, "returns_retained");
2622+
synthesizedCxxMethodDecl->addAttr(
2623+
returnsRetainedAttrForSynthesizedCxxMethodDecl);
2624+
}
2625+
2626+
std::string swiftInitStr = "init(";
2627+
for (unsigned i = 0; i < ctorParamCount; ++i) {
2628+
swiftInitStr += "_:";
2629+
}
2630+
swiftInitStr += ")";
2631+
clang::SwiftNameAttr *swiftNameAttr =
2632+
clang::SwiftNameAttr::Create(clangCtx, swiftInitStr);
2633+
synthesizedCxxMethodDecl->addAttr(swiftNameAttr);
2634+
2635+
llvm::SmallVector<clang::Expr *, 8> ctorArgs;
2636+
for (auto *param : synthesizedParams) {
2637+
ctorArgs.push_back(clang::DeclRefExpr::Create(
2638+
clangCtx, clang::NestedNameSpecifierLoc(), clang::SourceLocation(),
2639+
param,
2640+
/*RefersToEnclosingVariableOrCapture=*/false, clang::SourceLocation(),
2641+
param->getType(), clang::VK_LValue));
2642+
}
2643+
llvm::SmallVector<clang::Expr *, 8> ctorArgsToAdd;
2644+
if (clangSema.CompleteConstructorCall(selectedCtorDecl, cxxRecordTy,
2645+
ctorArgs, cxxRecordDeclLoc,
2646+
ctorArgsToAdd))
2647+
continue;
2648+
2649+
clang::ExprResult synthesizedConstructExprResult =
2650+
clangSema.BuildCXXConstructExpr(
2651+
cxxRecordDeclLoc, cxxRecordTy, selectedCtorDecl,
2652+
/*Elidable=*/false, ctorArgsToAdd,
2653+
/*HadMultipleCandidates=*/false,
2654+
/*IsListInitialization=*/false,
2655+
/*IsStdInitListInitialization=*/false,
2656+
/*RequiresZeroInit=*/false, clang::CXXConstructionKind::Complete,
2657+
clang::SourceRange(cxxRecordDeclLoc, cxxRecordDeclLoc));
2658+
assert(!synthesizedConstructExprResult.isInvalid() &&
2659+
"Unable to synthesize constructor expression for c++ foreign "
2660+
"reference type");
2661+
clang::Expr *synthesizedConstructExpr =
2662+
synthesizedConstructExprResult.get();
2663+
2664+
clang::ExprResult synthesizedNewExprResult = clangSema.BuildCXXNew(
2665+
clang::SourceRange(), /*UseGlobal=*/false, clang::SourceLocation(), {},
2666+
clang::SourceLocation(), clang::SourceRange(), cxxRecordTy,
2667+
clangCtx.getTrivialTypeSourceInfo(cxxRecordTy), std::nullopt,
2668+
clang::SourceRange(cxxRecordDeclLoc, cxxRecordDeclLoc),
2669+
synthesizedConstructExpr);
2670+
assert(
2671+
!synthesizedNewExprResult.isInvalid() &&
2672+
"Unable to synthesize `new` expression for c++ foreign reference type");
2673+
clang::CXXNewExpr *synthesizedNewExpr =
2674+
cast<clang::CXXNewExpr>(synthesizedNewExprResult.get());
2675+
2676+
clang::ReturnStmt *synthesizedRetStmt = clang::ReturnStmt::Create(
2677+
clangCtx, cxxRecordDeclLoc, synthesizedNewExpr, nullptr);
2678+
assert(synthesizedRetStmt &&
2679+
"Unable to synthesize return statement for "
2680+
"static factory of c++ foreign reference type");
2681+
2682+
clang::CompoundStmt *synthesizedFuncBody = clang::CompoundStmt::Create(
2683+
clangCtx, {synthesizedRetStmt}, clang::FPOptionsOverride(),
2684+
cxxRecordDeclLoc, cxxRecordDeclLoc);
2685+
assert(synthesizedRetStmt &&
2686+
"Unable to synthesize function body for static "
2687+
"factory of c++ foreign reference type");
2688+
2689+
synthesizedCxxMethodDecl->setBody(synthesizedFuncBody);
26172690
synthesizedCxxMethodDecl->addAttr(
2618-
returnsRetainedAttrForSynthesizedCxxMethodDecl);
2619-
}
2691+
clang::NoDebugAttr::CreateImplicit(clangCtx));
26202692

2621-
std::string swiftInitSig = "init(";
2622-
bool first = true;
2623-
for (auto *param : selectedCtorDecl->parameters()) {
2624-
if (!first)
2625-
swiftInitSig += ":_";
2626-
swiftInitSig += ")";
2627-
first = false;
2628-
}
2629-
clang::SwiftNameAttr *swiftNameAttr =
2630-
clang::SwiftNameAttr::Create(clangCtx, swiftInitSig);
2631-
synthesizedCxxMethodDecl->addAttr(swiftNameAttr);
2632-
2633-
llvm::SmallVector<clang::Expr *, 8> ctorArgs;
2634-
for (auto *param : synthesizedParams) {
2635-
ctorArgs.push_back(clang::DeclRefExpr::Create(
2636-
clangCtx, clang::NestedNameSpecifierLoc(), clang::SourceLocation(),
2637-
param,
2638-
/*RefersToEnclosingVariableOrCapture=*/false, clang::SourceLocation(),
2639-
param->getType(), clang::VK_LValue));
2640-
}
2693+
synthesizedCxxMethodDecl->setImplicit();
2694+
synthesizedCxxMethodDecl->setImplicitlyInline();
26412695

2642-
llvm::SmallVector<clang::Expr *, 8> convertedCtorArgs;
2643-
if (clangSema.CompleteConstructorCall(selectedCtorDecl, cxxRecordTy, ctorArgs,
2644-
cxxRecordDeclLoc, convertedCtorArgs))
2645-
return nullptr;
2696+
synthesizedFactories.push_back(synthesizedCxxMethodDecl);
2697+
}
26462698

2647-
clang::ExprResult synthesizedConstructExprResult =
2648-
clangSema.BuildCXXConstructExpr(
2649-
cxxRecordDeclLoc, cxxRecordTy, selectedCtorDecl,
2650-
/*Elidable=*/false, convertedCtorArgs,
2651-
/*HadMultipleCandidates=*/false,
2652-
/*IsListInitialization=*/false,
2653-
/*IsStdInitListInitialization=*/false,
2654-
/*RequiresZeroInit=*/false, clang::CXXConstructionKind::Complete,
2655-
clang::SourceRange(cxxRecordDeclLoc, cxxRecordDeclLoc));
2656-
assert(!synthesizedConstructExprResult.isInvalid() &&
2657-
"Unable to synthesize constructor expression for c++ foreign "
2658-
"reference type");
2659-
clang::Expr *synthesizedConstructExpr = synthesizedConstructExprResult.get();
2660-
2661-
clang::ExprResult synthesizedNewExprResult = clangSema.BuildCXXNew(
2662-
clang::SourceRange(), /*UseGlobal=*/false, clang::SourceLocation(), {},
2663-
clang::SourceLocation(), clang::SourceRange(), cxxRecordTy,
2664-
clangCtx.getTrivialTypeSourceInfo(cxxRecordTy), std::nullopt,
2665-
clang::SourceRange(cxxRecordDeclLoc, cxxRecordDeclLoc),
2666-
synthesizedConstructExpr);
2667-
assert(
2668-
!synthesizedNewExprResult.isInvalid() &&
2669-
"Unable to synthesize `new` expression for c++ foreign reference type");
2670-
clang::CXXNewExpr *synthesizedNewExpr =
2671-
cast<clang::CXXNewExpr>(synthesizedNewExprResult.get());
2672-
2673-
clang::ReturnStmt *synthesizedRetStmt = clang::ReturnStmt::Create(
2674-
clangCtx, cxxRecordDeclLoc, synthesizedNewExpr, nullptr);
2675-
assert(synthesizedRetStmt && "Unable to synthesize return statement for "
2676-
"static factory of c++ foreign reference type");
2677-
clang::CompoundStmt *synthesizedFuncBody = clang::CompoundStmt::Create(
2678-
clangCtx, {synthesizedRetStmt}, clang::FPOptionsOverride(),
2679-
cxxRecordDeclLoc, cxxRecordDeclLoc);
2680-
assert(synthesizedRetStmt && "Unable to synthesize function body for static "
2681-
"factory of c++ foreign reference type");
2682-
2683-
synthesizedCxxMethodDecl->setBody(synthesizedFuncBody);
2684-
synthesizedCxxMethodDecl->addAttr(
2685-
clang::NoDebugAttr::CreateImplicit(clangCtx));
2686-
2687-
synthesizedCxxMethodDecl->setImplicit();
2688-
synthesizedCxxMethodDecl->setImplicitlyInline();
2689-
2690-
return synthesizedCxxMethodDecl;
2699+
return synthesizedFactories;
26912700
}

lib/ClangImporter/SwiftDeclSynthesizer.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,8 @@ class SwiftDeclSynthesizer {
337337
/// Synthesize a static factory method for a C++ foreign reference type,
338338
/// returning a `CXXMethodDecl*` or `nullptr` if the required constructor or
339339
/// allocation function is not found.
340-
clang::CXXMethodDecl *synthesizeStaticFactoryForCXXForeignRef(
340+
llvm::SmallVector<clang::CXXMethodDecl *, 4>
341+
synthesizeStaticFactoryForCXXForeignRef(
341342
const clang::CXXRecordDecl *cxxRecordDecl);
342343

343344
private:

test/Interop/Cxx/class/constructors-diagnostics.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,4 @@ let _ = SwiftInitSynthesisForCXXRefTypes.DefaulltAndNonDefaultCtors()
2424
let _ = SwiftInitSynthesisForCXXRefTypes.DefaulltAndNonDefaultCtors(2) // expected-error {{argument passed to call that takes no arguments}}
2525

2626
// TODO: fix the error message in this case
27-
let _ = SwiftInitSynthesisForCXXRefTypes.ParameterizedCtor() // expected-error {{missing argument for parameter #1 in call}}
27+
let _ = SwiftInitSynthesisForCXXRefTypes.ParameterizedCtor() // expected-error {{missing argument for parameter #1 in call}}

0 commit comments

Comments
 (0)