@@ -2534,128 +2534,200 @@ SwiftDeclSynthesizer::makeDefaultArgument(const clang::ParmVarDecl *param,
25342534
25352535// MARK: C++ foreign reference type constructors
25362536
2537- clang::CXXMethodDecl *
2537+ llvm::SmallVector< clang::CXXMethodDecl *, 4 >
25382538SwiftDeclSynthesizer::synthesizeStaticFactoryForCXXForeignRef (
25392539 const clang::CXXRecordDecl *cxxRecordDecl) {
25402540
2541+ if (cxxRecordDecl->isAbstract ())
2542+ return {};
2543+
25412544 clang::ASTContext &clangCtx = cxxRecordDecl->getASTContext ();
25422545 clang::Sema &clangSema = ImporterImpl.getClangSema ();
25432546
25442547 clang::QualType cxxRecordTy = clangCtx.getRecordType (cxxRecordDecl);
2548+ clang::SourceLocation cxxRecordDeclLoc = cxxRecordDecl->getLocation ();
25452549
2546- clang::CXXConstructorDecl *defaultCtorDecl = nullptr ;
2547- for (clang::CXXConstructorDecl *ctor : cxxRecordDecl->ctors ()) {
2548- if (ctor->parameters ().empty () && !ctor->isDeleted () &&
2549- ctor->getAccess () != clang::AS_private &&
2550- ctor->getAccess () != clang::AS_protected) {
2551- defaultCtorDecl = ctor;
2552- break ;
2553- }
2550+ llvm::SmallVector<clang::CXXConstructorDecl *, 4 > ctorDeclsForSynth;
2551+ for (clang::CXXConstructorDecl *ctorDecl : cxxRecordDecl->ctors ()) {
2552+ if (ctorDecl->isDeleted () || ctorDecl->getAccess () == clang::AS_private ||
2553+ ctorDecl->getAccess () == clang::AS_protected ||
2554+ ctorDecl->isCopyOrMoveConstructor () || ctorDecl->isVariadic ())
2555+ continue ;
2556+
2557+ bool hasDefaultArg = !ctorDecl->parameters ().empty () &&
2558+ ctorDecl->parameters ().back ()->hasDefaultArg ();
2559+ // TODO: Add support for default args in ctors for C++ foreign reference
2560+ // types.
2561+ if (hasDefaultArg)
2562+ continue ;
2563+ ctorDeclsForSynth.push_back (ctorDecl);
25542564 }
2555- if (!defaultCtorDecl)
2556- return nullptr ;
2565+
2566+ if (ctorDeclsForSynth.empty ())
2567+ return {};
25572568
25582569 clang::FunctionDecl *operatorNew = nullptr ;
25592570 clang::FunctionDecl *operatorDelete = nullptr ;
25602571 bool passAlignment = false ;
2572+ clang::Sema::SFINAETrap trap (clangSema);
25612573 bool findingAllocFuncFailed = clangSema.FindAllocationFunctions (
2562- cxxRecordDecl->getLocation (), clang::SourceRange (), clang::Sema::AFS_Both,
2563- clang::Sema::AFS_Both, cxxRecordTy,
2564- /* IsArray*/ false , passAlignment, clang::MultiExprArg (), operatorNew,
2565- operatorDelete, /* Diagnose*/ false );
2566- if (findingAllocFuncFailed || !operatorNew || operatorNew->isDeleted () ||
2574+ cxxRecordDeclLoc, clang::SourceRange (), clang::Sema::AFS_Both,
2575+ clang::Sema::AFS_Both, cxxRecordTy, /* IsArray=*/ false , passAlignment,
2576+ clang::MultiExprArg (), operatorNew, operatorDelete,
2577+ /* Diagnose=*/ false );
2578+ if (trap.hasErrorOccurred () || findingAllocFuncFailed || !operatorNew ||
2579+ operatorNew->isDeleted () ||
25672580 operatorNew->getAccess () == clang::AS_private ||
25682581 operatorNew->getAccess () == clang::AS_protected)
2569- return nullptr ;
2582+ return {} ;
25702583
25712584 clang::QualType cxxRecordPtrTy = clangCtx.getPointerType (cxxRecordTy);
25722585 // Adding `_Nonnull` to the return type of synthesized static factory
25732586 bool nullabilityCannotBeAdded =
25742587 clangSema.CheckImplicitNullabilityTypeSpecifier (
2575- cxxRecordPtrTy, clang::NullabilityKind::NonNull,
2576- cxxRecordDecl->getLocation (),
2577- /* isParam=*/ false ,
2578- /* OverrideExisting=*/ true );
2588+ cxxRecordPtrTy, clang::NullabilityKind::NonNull, cxxRecordDeclLoc,
2589+ /* isParam=*/ false , /* OverrideExisting=*/ true );
25792590 assert (!nullabilityCannotBeAdded &&
25802591 " Failed to add _Nonnull specifier to synthesized "
25812592 " static factory's return type" );
25822593
25832594 clang::IdentifierTable &clangIdents = clangCtx.Idents ;
2584- clang::IdentifierInfo *funcNameToSynthesize = &clangIdents.get (
2585- (" __returns_" + cxxRecordDecl->getNameAsString ()).c_str ());
2586- clang::FunctionProtoType::ExtProtoInfo EPI;
2587- clang::QualType funcTypeToSynthesize =
2588- clangCtx.getFunctionType (cxxRecordPtrTy, {}, EPI);
2589-
2590- clang::CXXMethodDecl *synthesizedCxxMethodDecl = clang::CXXMethodDecl::Create (
2591- clangCtx, const_cast <clang::CXXRecordDecl *>(cxxRecordDecl),
2592- cxxRecordDecl->getLocation (),
2593- clang::DeclarationNameInfo (funcNameToSynthesize,
2594- cxxRecordDecl->getLocation ()),
2595- funcTypeToSynthesize,
2596- clangCtx.getTrivialTypeSourceInfo (funcTypeToSynthesize), clang::SC_Static,
2597- /* UsesFPIntrin=*/ false , /* isInline=*/ true ,
2598- clang::ConstexprSpecKind::Unspecified, cxxRecordDecl->getLocation ());
2599- assert (synthesizedCxxMethodDecl &&
2600- " Unable to synthesize static factory for c++ foreign reference type" );
2601- synthesizedCxxMethodDecl->setAccess (clang::AccessSpecifier::AS_public);
2602-
2603- if (!hasImmortalAttrs (cxxRecordDecl)) {
2604- clang::SwiftAttrAttr *returnsRetainedAttrForSynthesizedCxxMethodDecl =
2605- clang::SwiftAttrAttr::Create (clangCtx, " returns_retained" );
2606- synthesizedCxxMethodDecl->addAttr (
2607- returnsRetainedAttrForSynthesizedCxxMethodDecl);
2595+
2596+ llvm::SmallVector<clang::CXXMethodDecl *, 4 > synthesizedFactories;
2597+ unsigned int selectedCtorDeclCounter = 0 ;
2598+ for (clang::CXXConstructorDecl *selectedCtorDecl : ctorDeclsForSynth) {
2599+ unsigned int ctorParamCount = selectedCtorDecl->getNumParams ();
2600+ selectedCtorDeclCounter++;
2601+
2602+ std::string funcName = " __returns_" + cxxRecordDecl->getNameAsString ();
2603+ if (ctorParamCount > 0 )
2604+ funcName += " _" + std::to_string (ctorParamCount) + " _params" ;
2605+ funcName += " _" + std::to_string (selectedCtorDeclCounter);
2606+ clang::IdentifierInfo *funcNameToSynth = &clangIdents.get (funcName);
2607+
2608+ auto ctorFunctionProtoTy =
2609+ selectedCtorDecl->getType ()->getAs <clang::FunctionProtoType>();
2610+ clang::ArrayRef<clang::QualType> paramTypes =
2611+ ctorFunctionProtoTy->getParamTypes ();
2612+ clang::FunctionProtoType::ExtProtoInfo EPI;
2613+ clang::QualType funcTypeToSynth =
2614+ clangCtx.getFunctionType (cxxRecordPtrTy, paramTypes, EPI);
2615+
2616+ clang::CXXMethodDecl *synthCxxMethodDecl = clang::CXXMethodDecl::Create (
2617+ clangCtx, const_cast <clang::CXXRecordDecl *>(cxxRecordDecl),
2618+ cxxRecordDeclLoc,
2619+ clang::DeclarationNameInfo (funcNameToSynth, cxxRecordDeclLoc),
2620+ funcTypeToSynth, clangCtx.getTrivialTypeSourceInfo (funcTypeToSynth),
2621+ clang::SC_Static, /* UsesFPIntrin=*/ false , /* isInline=*/ true ,
2622+ clang::ConstexprSpecKind::Unspecified, cxxRecordDeclLoc);
2623+ assert (
2624+ synthCxxMethodDecl &&
2625+ " Unable to synthesize static factory for c++ foreign reference type" );
2626+ synthCxxMethodDecl->setAccess (clang::AccessSpecifier::AS_public);
2627+
2628+ llvm::SmallVector<clang::ParmVarDecl *, 4 > synthParams;
2629+ for (unsigned int i = 0 ; i < ctorParamCount; ++i) {
2630+ auto *origParam = selectedCtorDecl->getParamDecl (i);
2631+ clang::IdentifierInfo *paramIdent = origParam->getIdentifier ();
2632+ if (!paramIdent) {
2633+ std::string dummyName = " __unnamed_param_" + std::to_string (i);
2634+ paramIdent = &clangIdents.get (dummyName);
2635+ }
2636+ auto *param = clang::ParmVarDecl::Create (
2637+ clangCtx, synthCxxMethodDecl, cxxRecordDeclLoc, cxxRecordDeclLoc,
2638+ paramIdent, origParam->getType (),
2639+ clangCtx.getTrivialTypeSourceInfo (origParam->getType ()),
2640+ clang::SC_None, /* DefArg=*/ nullptr );
2641+ param->setIsUsed ();
2642+ synthParams.push_back (param);
2643+ }
2644+ synthCxxMethodDecl->setParams (synthParams);
2645+
2646+ if (!hasImmortalAttrs (cxxRecordDecl)) {
2647+ synthCxxMethodDecl->addAttr (
2648+ clang::SwiftAttrAttr::Create (clangCtx, " returns_retained" ));
2649+ }
2650+
2651+ std::string swiftInitStr = " init(" ;
2652+ for (unsigned i = 0 ; i < ctorParamCount; ++i) {
2653+ auto paramType = selectedCtorDecl->getParamDecl (i)->getType ();
2654+ if (paramType->isRValueReferenceType ()) {
2655+ swiftInitStr += " consuming:" ;
2656+ } else {
2657+ swiftInitStr += " _:" ;
2658+ }
2659+ }
2660+ swiftInitStr += " )" ;
2661+ synthCxxMethodDecl->addAttr (
2662+ clang::SwiftNameAttr::Create (clangCtx, swiftInitStr));
2663+
2664+ llvm::SmallVector<clang::Expr *, 4 > ctorArgs;
2665+ for (auto *param : synthParams) {
2666+ clang::QualType paramTy = param->getType ();
2667+ clang::QualType exprTy = paramTy.getNonReferenceType ();
2668+ clang::Expr *argExpr = clang::DeclRefExpr::Create (
2669+ clangCtx, clang::NestedNameSpecifierLoc (), cxxRecordDeclLoc, param,
2670+ /* RefersToEnclosingVariableOrCapture=*/ false , cxxRecordDeclLoc,
2671+ exprTy, clang::VK_LValue);
2672+ if (paramTy->isRValueReferenceType ()) {
2673+ argExpr = clangSema
2674+ .BuildCXXNamedCast (
2675+ cxxRecordDeclLoc, clang::tok::kw_static_cast,
2676+ clangCtx.getTrivialTypeSourceInfo (paramTy), argExpr,
2677+ clang::SourceRange (), clang::SourceRange ())
2678+ .get ();
2679+ }
2680+ ctorArgs.push_back (argExpr);
2681+ }
2682+ llvm::SmallVector<clang::Expr *, 4 > ctorArgsToAdd;
2683+
2684+ if (clangSema.CompleteConstructorCall (selectedCtorDecl, cxxRecordTy,
2685+ ctorArgs, cxxRecordDeclLoc,
2686+ ctorArgsToAdd))
2687+ continue ;
2688+
2689+ clang::ExprResult synthCtorExprResult = clangSema.BuildCXXConstructExpr (
2690+ cxxRecordDeclLoc, cxxRecordTy, selectedCtorDecl,
2691+ /* Elidable=*/ false , ctorArgsToAdd,
2692+ /* HadMultipleCandidates=*/ false ,
2693+ /* IsListInitialization=*/ false ,
2694+ /* IsStdInitListInitialization=*/ false ,
2695+ /* RequiresZeroInit=*/ false , clang::CXXConstructionKind::Complete,
2696+ clang::SourceRange (cxxRecordDeclLoc, cxxRecordDeclLoc));
2697+ assert (!synthCtorExprResult.isInvalid () &&
2698+ " Unable to synthesize constructor expression for c++ foreign "
2699+ " reference type" );
2700+ clang::Expr *synthCtorExpr = synthCtorExprResult.get ();
2701+
2702+ clang::ExprResult synthNewExprResult = clangSema.BuildCXXNew (
2703+ clang::SourceRange (), /* UseGlobal=*/ false , clang::SourceLocation (), {},
2704+ clang::SourceLocation (), clang::SourceRange (), cxxRecordTy,
2705+ clangCtx.getTrivialTypeSourceInfo (cxxRecordTy), std::nullopt ,
2706+ clang::SourceRange (cxxRecordDeclLoc, cxxRecordDeclLoc), synthCtorExpr);
2707+ assert (
2708+ !synthNewExprResult.isInvalid () &&
2709+ " Unable to synthesize `new` expression for c++ foreign reference type" );
2710+ auto *synthNewExpr = cast<clang::CXXNewExpr>(synthNewExprResult.get ());
2711+
2712+ clang::ReturnStmt *synthRetStmt = clang::ReturnStmt::Create (
2713+ clangCtx, cxxRecordDeclLoc, synthNewExpr, /* NRVOCandidate=*/ nullptr );
2714+ assert (synthRetStmt && " Unable to synthesize return statement for "
2715+ " static factory of c++ foreign reference type" );
2716+
2717+ clang::CompoundStmt *synthFuncBody = clang::CompoundStmt::Create (
2718+ clangCtx, {synthRetStmt}, clang::FPOptionsOverride (), cxxRecordDeclLoc,
2719+ cxxRecordDeclLoc);
2720+ assert (synthRetStmt && " Unable to synthesize function body for static "
2721+ " factory of c++ foreign reference type" );
2722+
2723+ synthCxxMethodDecl->setBody (synthFuncBody);
2724+ synthCxxMethodDecl->addAttr (clang::NoDebugAttr::CreateImplicit (clangCtx));
2725+
2726+ synthCxxMethodDecl->setImplicit ();
2727+ synthCxxMethodDecl->setImplicitlyInline ();
2728+
2729+ synthesizedFactories.push_back (synthCxxMethodDecl);
26082730 }
26092731
2610- clang::SwiftNameAttr *swiftNameInitAttrForSynthesizedCxxMethodDecl =
2611- clang::SwiftNameAttr::Create (clangCtx, " init()" );
2612- synthesizedCxxMethodDecl->addAttr (
2613- swiftNameInitAttrForSynthesizedCxxMethodDecl);
2614-
2615- clang::ExprResult synthesizedConstructExprResult =
2616- clangSema.BuildCXXConstructExpr (
2617- clang::SourceLocation (), cxxRecordTy, defaultCtorDecl,
2618- /* Elidable=*/ false , clang::MultiExprArg (),
2619- /* HadMultipleCandidates=*/ false ,
2620- /* IsListInitialization=*/ false ,
2621- /* IsStdInitListInitialization=*/ false ,
2622- /* RequiresZeroInit=*/ false , clang::CXXConstructionKind::Complete,
2623- clang::SourceRange ());
2624- assert (!synthesizedConstructExprResult.isInvalid () &&
2625- " Unable to synthesize constructor expression for c++ foreign "
2626- " reference type" );
2627- clang::CXXConstructExpr *synthesizedConstructExpr =
2628- cast<clang::CXXConstructExpr>(synthesizedConstructExprResult.get ());
2629-
2630- clang::ExprResult synthesizedNewExprResult = clangSema.BuildCXXNew (
2631- clang::SourceRange (), /* UseGlobal=*/ false , clang::SourceLocation (), {},
2632- clang::SourceLocation (), clang::SourceRange (), cxxRecordTy,
2633- clangCtx.getTrivialTypeSourceInfo (cxxRecordTy), std::nullopt ,
2634- clang::SourceRange (), synthesizedConstructExpr);
2635- assert (
2636- !synthesizedNewExprResult.isInvalid () &&
2637- " Unable to synthesize `new` expression for c++ foreign reference type" );
2638- clang::CXXNewExpr *synthesizedNewExpr =
2639- cast<clang::CXXNewExpr>(synthesizedNewExprResult.get ());
2640-
2641- clang::ReturnStmt *synthesizedRetStmt =
2642- clang::ReturnStmt::Create (clangCtx, clang::SourceLocation (),
2643- synthesizedNewExpr, /* VarDecl=*/ nullptr );
2644- assert (synthesizedRetStmt && " Unable to synthesize return statement for "
2645- " static factory of c++ foreign reference type" );
2646-
2647- clang::CompoundStmt *synthesizedFuncBody = clang::CompoundStmt::Create (
2648- clangCtx, {synthesizedRetStmt}, clang::FPOptionsOverride (),
2649- clang::SourceLocation (), clang::SourceLocation ());
2650- assert (synthesizedRetStmt && " Unable to synthesize function body for static "
2651- " factory of c++ foreign reference type" );
2652-
2653- synthesizedCxxMethodDecl->setBody (synthesizedFuncBody);
2654- synthesizedCxxMethodDecl->addAttr (
2655- clang::NoDebugAttr::CreateImplicit (clangCtx));
2656-
2657- synthesizedCxxMethodDecl->setImplicit ();
2658- synthesizedCxxMethodDecl->setImplicitlyInline ();
2659-
2660- return synthesizedCxxMethodDecl;
2732+ return synthesizedFactories;
26612733}
0 commit comments