Skip to content

Commit cef3770

Browse files
committed
[cxx-interop] Support first non default ctor of c++ foreign reference types
1 parent 7191d19 commit cef3770

File tree

3 files changed

+72
-37
lines changed

3 files changed

+72
-37
lines changed

lib/ClangImporter/SwiftDeclSynthesizer.cpp

Lines changed: 65 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2538,29 +2538,29 @@ SwiftDeclSynthesizer::synthesizeStaticFactoryForCXXForeignRef(
25382538

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

25422543
clang::QualType cxxRecordTy = clangCtx.getRecordType(cxxRecordDecl);
25432544

2544-
clang::CXXConstructorDecl *defaultCtorDecl = nullptr;
2545+
// Todo: synthesize static factories for all available ctors
2546+
clang::CXXConstructorDecl *selectedCtorDecl = nullptr;
25452547
for (clang::CXXConstructorDecl *ctor : cxxRecordDecl->ctors()) {
2546-
if (ctor->parameters().empty() && !ctor->isDeleted() &&
2547-
ctor->getAccess() != clang::AS_private &&
2548+
if (!ctor->isDeleted() && ctor->getAccess() != clang::AS_private &&
25482549
ctor->getAccess() != clang::AS_protected) {
2549-
defaultCtorDecl = ctor;
2550+
selectedCtorDecl = ctor;
25502551
break;
25512552
}
25522553
}
2553-
if (!defaultCtorDecl)
2554+
if (!selectedCtorDecl)
25542555
return nullptr;
25552556

25562557
clang::FunctionDecl *operatorNew = nullptr;
25572558
clang::FunctionDecl *operatorDelete = nullptr;
25582559
bool passAlignment = false;
25592560
bool findingAllocFuncFailed = clangSema.FindAllocationFunctions(
2560-
cxxRecordDecl->getLocation(), clang::SourceRange(), clang::Sema::AFS_Both,
2561-
clang::Sema::AFS_Both, cxxRecordTy,
2562-
/*IsArray*/ false, passAlignment, clang::MultiExprArg(), operatorNew,
2563-
operatorDelete, /*Diagnose*/ false);
2561+
cxxRecordDeclLoc, clang::SourceRange(), clang::Sema::AFS_Both,
2562+
clang::Sema::AFS_Both, cxxRecordTy, /*IsArray=*/false, passAlignment,
2563+
clang::MultiExprArg(), operatorNew, operatorDelete, /*Diagnose=*/false);
25642564
if (findingAllocFuncFailed || !operatorNew || operatorNew->isDeleted() ||
25652565
operatorNew->getAccess() == clang::AS_private ||
25662566
operatorNew->getAccess() == clang::AS_protected)
@@ -2570,81 +2570,111 @@ SwiftDeclSynthesizer::synthesizeStaticFactoryForCXXForeignRef(
25702570
// Adding `_Nonnull` to the return type of synthesized static factory
25712571
bool nullabilityCannotBeAdded =
25722572
clangSema.CheckImplicitNullabilityTypeSpecifier(
2573-
cxxRecordPtrTy, clang::NullabilityKind::NonNull,
2574-
cxxRecordDecl->getLocation(),
2575-
/*isParam=*/false,
2576-
/*OverrideExisting=*/true);
2573+
cxxRecordPtrTy, clang::NullabilityKind::NonNull, cxxRecordDeclLoc,
2574+
/*isParam=*/false, /*OverrideExisting=*/true);
25772575
assert(!nullabilityCannotBeAdded &&
25782576
"Failed to add _Nonnull specifier to synthesized "
25792577
"static factory's return type");
25802578

25812579
clang::IdentifierTable &clangIdents = clangCtx.Idents;
25822580
clang::IdentifierInfo *funcNameToSynthesize = &clangIdents.get(
25832581
("__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());
25842586
clang::FunctionProtoType::ExtProtoInfo EPI;
25852587
clang::QualType funcTypeToSynthesize =
2586-
clangCtx.getFunctionType(cxxRecordPtrTy, {}, EPI);
2588+
clangCtx.getFunctionType(cxxRecordPtrTy, paramTypes, EPI);
25872589

25882590
clang::CXXMethodDecl *synthesizedCxxMethodDecl = clang::CXXMethodDecl::Create(
25892591
clangCtx, const_cast<clang::CXXRecordDecl *>(cxxRecordDecl),
2590-
cxxRecordDecl->getLocation(),
2591-
clang::DeclarationNameInfo(funcNameToSynthesize,
2592-
cxxRecordDecl->getLocation()),
2592+
cxxRecordDeclLoc,
2593+
clang::DeclarationNameInfo(funcNameToSynthesize, cxxRecordDeclLoc),
25932594
funcTypeToSynthesize,
25942595
clangCtx.getTrivialTypeSourceInfo(funcTypeToSynthesize), clang::SC_Static,
25952596
/*UsesFPIntrin=*/false, /*isInline=*/true,
2596-
clang::ConstexprSpecKind::Unspecified, cxxRecordDecl->getLocation());
2597-
assert(synthesizedCxxMethodDecl &&
2598-
"Unable to synthesize static factory for c++ foreign reference type");
2597+
clang::ConstexprSpecKind::Unspecified, cxxRecordDeclLoc);
25992598
synthesizedCxxMethodDecl->setAccess(clang::AccessSpecifier::AS_public);
26002599

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);
2611+
26012612
if (!hasImmortalAttrs(cxxRecordDecl)) {
26022613
clang::SwiftAttrAttr *returnsRetainedAttrForSynthesizedCxxMethodDecl =
26032614
clang::SwiftAttrAttr::Create(clangCtx, "returns_retained");
26042615
synthesizedCxxMethodDecl->addAttr(
26052616
returnsRetainedAttrForSynthesizedCxxMethodDecl);
26062617
}
26072618

2608-
clang::SwiftNameAttr *swiftNameInitAttrForSynthesizedCxxMethodDecl =
2609-
clang::SwiftNameAttr::Create(clangCtx, "init()");
2610-
synthesizedCxxMethodDecl->addAttr(
2611-
swiftNameInitAttrForSynthesizedCxxMethodDecl);
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+
}
2639+
2640+
llvm::SmallVector<clang::Expr *, 8> convertedCtorArgs;
2641+
if (clangSema.CompleteConstructorCall(selectedCtorDecl, cxxRecordTy, ctorArgs,
2642+
cxxRecordDeclLoc, convertedCtorArgs))
2643+
return nullptr;
26122644

26132645
clang::ExprResult synthesizedConstructExprResult =
26142646
clangSema.BuildCXXConstructExpr(
2615-
clang::SourceLocation(), cxxRecordTy, defaultCtorDecl,
2616-
/*Elidable=*/false, clang::MultiExprArg(),
2647+
cxxRecordDeclLoc, cxxRecordTy, selectedCtorDecl,
2648+
/*Elidable=*/false, convertedCtorArgs,
26172649
/*HadMultipleCandidates=*/false,
26182650
/*IsListInitialization=*/false,
26192651
/*IsStdInitListInitialization=*/false,
26202652
/*RequiresZeroInit=*/false, clang::CXXConstructionKind::Complete,
2621-
clang::SourceRange());
2653+
clang::SourceRange(cxxRecordDeclLoc, cxxRecordDeclLoc));
26222654
assert(!synthesizedConstructExprResult.isInvalid() &&
26232655
"Unable to synthesize constructor expression for c++ foreign "
26242656
"reference type");
2625-
clang::CXXConstructExpr *synthesizedConstructExpr =
2626-
cast<clang::CXXConstructExpr>(synthesizedConstructExprResult.get());
2657+
clang::Expr *synthesizedConstructExpr = synthesizedConstructExprResult.get();
26272658

26282659
clang::ExprResult synthesizedNewExprResult = clangSema.BuildCXXNew(
26292660
clang::SourceRange(), /*UseGlobal=*/false, clang::SourceLocation(), {},
26302661
clang::SourceLocation(), clang::SourceRange(), cxxRecordTy,
26312662
clangCtx.getTrivialTypeSourceInfo(cxxRecordTy), std::nullopt,
2632-
clang::SourceRange(), synthesizedConstructExpr);
2663+
clang::SourceRange(cxxRecordDeclLoc, cxxRecordDeclLoc),
2664+
synthesizedConstructExpr);
26332665
assert(
26342666
!synthesizedNewExprResult.isInvalid() &&
26352667
"Unable to synthesize `new` expression for c++ foreign reference type");
26362668
clang::CXXNewExpr *synthesizedNewExpr =
26372669
cast<clang::CXXNewExpr>(synthesizedNewExprResult.get());
26382670

2639-
clang::ReturnStmt *synthesizedRetStmt =
2640-
clang::ReturnStmt::Create(clangCtx, clang::SourceLocation(),
2641-
synthesizedNewExpr, /*VarDecl=*/nullptr);
2671+
clang::ReturnStmt *synthesizedRetStmt = clang::ReturnStmt::Create(
2672+
clangCtx, cxxRecordDeclLoc, synthesizedNewExpr, nullptr);
26422673
assert(synthesizedRetStmt && "Unable to synthesize return statement for "
26432674
"static factory of c++ foreign reference type");
2644-
26452675
clang::CompoundStmt *synthesizedFuncBody = clang::CompoundStmt::Create(
26462676
clangCtx, {synthesizedRetStmt}, clang::FPOptionsOverride(),
2647-
clang::SourceLocation(), clang::SourceLocation());
2677+
cxxRecordDeclLoc, cxxRecordDeclLoc);
26482678
assert(synthesizedRetStmt && "Unable to synthesize function body for static "
26492679
"factory of c++ foreign reference type");
26502680

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,5 @@ let _ = SwiftInitSynthesisForCXXRefTypes.DefaulltAndNonDefaultCtors()
2323
// TODO: change the error message when we start supporting parameterised ctors
2424
let _ = SwiftInitSynthesisForCXXRefTypes.DefaulltAndNonDefaultCtors(2) // expected-error {{argument passed to call that takes no arguments}}
2525

26-
let _ = SwiftInitSynthesisForCXXRefTypes.ParameterizedCtor() // expected-error {{'SwiftInitSynthesisForCXXRefTypes.ParameterizedCtor' cannot be constructed because it has no accessible initializers}}
27-
let _ = SwiftInitSynthesisForCXXRefTypes.ParameterizedCtor(3) // expected-error {{'SwiftInitSynthesisForCXXRefTypes.ParameterizedCtor' cannot be constructed because it has no accessible initializers}}
26+
// TODO: fix the error message in this case
27+
let _ = SwiftInitSynthesisForCXXRefTypes.ParameterizedCtor() // expected-error {{missing argument for parameter #1 in call}}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,11 @@ CxxConstructorTestSuite.test("SynthesizeAndImportStaticFactoryAsInitializer") {
113113

114114
let x6 = SwiftInitSynthesisForCXXRefTypes.UserProvidedStaticFactory(3)
115115
expectEqual(x6.val, 3)
116+
117+
let x7 = SwiftInitSynthesisForCXXRefTypes.ParameterizedCtor(2)
118+
expectEqual(x7.val, 2)
119+
x7.val = 3
120+
expectEqual(x7.val, 3)
116121
}
117122

118123
runAllTests()

0 commit comments

Comments
 (0)