Skip to content

Commit 8a7f740

Browse files
committed
Added support for multiple ctors
1 parent cef3770 commit 8a7f740

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
@@ -2507,12 +2507,13 @@ namespace {
25072507
});
25082508
});
25092509
if (!hasUserProvidedStaticFactory) {
2510-
if (auto generatedCxxMethodDecl =
2511-
synthesizer.synthesizeStaticFactoryForCXXForeignRef(
2512-
cxxRecordDecl)) {
2510+
auto generatedCxxMethodDecls =
2511+
synthesizer.synthesizeStaticFactoryForCXXForeignRef(
2512+
cxxRecordDecl);
2513+
for (auto *methodDecl : generatedCxxMethodDecls) {
25132514
if (Decl *importedInitDecl =
25142515
Impl.SwiftContext.getClangModuleLoader()
2515-
->importDeclDirectly(generatedCxxMethodDecl))
2516+
->importDeclDirectly(methodDecl))
25162517
result->addMember(importedInitDecl);
25172518
}
25182519
}

lib/ClangImporter/SwiftDeclSynthesizer.cpp

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

25332533
// MARK: C++ foreign reference type constructors
25342534

2535-
clang::CXXMethodDecl *
2535+
llvm::SmallVector<clang::CXXMethodDecl *, 4>
25362536
SwiftDeclSynthesizer::synthesizeStaticFactoryForCXXForeignRef(
25372537
const clang::CXXRecordDecl *cxxRecordDecl) {
25382538

25392539
clang::ASTContext &clangCtx = cxxRecordDecl->getASTContext();
25402540
clang::Sema &clangSema = ImporterImpl.getClangSema();
2541-
clang::SourceLocation cxxRecordDeclLoc = cxxRecordDecl->getLocation();
25422541

25432542
clang::QualType cxxRecordTy = clangCtx.getRecordType(cxxRecordDecl);
2543+
clang::SourceLocation cxxRecordDeclLoc = cxxRecordDecl->getLocation();
25442544

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

25572547
clang::FunctionDecl *operatorNew = nullptr;
25582548
clang::FunctionDecl *operatorDelete = nullptr;
@@ -2564,7 +2554,7 @@ SwiftDeclSynthesizer::synthesizeStaticFactoryForCXXForeignRef(
25642554
if (findingAllocFuncFailed || !operatorNew || operatorNew->isDeleted() ||
25652555
operatorNew->getAccess() == clang::AS_private ||
25662556
operatorNew->getAccess() == clang::AS_protected)
2567-
return nullptr;
2557+
return synthesizedFactories;
25682558

25692559
clang::QualType cxxRecordPtrTy = clangCtx.getPointerType(cxxRecordTy);
25702560
// Adding `_Nonnull` to the return type of synthesized static factory
@@ -2577,113 +2567,132 @@ SwiftDeclSynthesizer::synthesizeStaticFactoryForCXXForeignRef(
25772567
"static factory's return type");
25782568

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

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

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

2640-
llvm::SmallVector<clang::Expr *, 8> convertedCtorArgs;
2641-
if (clangSema.CompleteConstructorCall(selectedCtorDecl, cxxRecordTy, ctorArgs,
2642-
cxxRecordDeclLoc, convertedCtorArgs))
2643-
return nullptr;
2694+
synthesizedFactories.push_back(synthesizedCxxMethodDecl);
2695+
}
26442696

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

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)