@@ -2534,128 +2534,200 @@ SwiftDeclSynthesizer::makeDefaultArgument(const clang::ParmVarDecl *param,
2534
2534
2535
2535
// MARK: C++ foreign reference type constructors
2536
2536
2537
- clang::CXXMethodDecl *
2537
+ llvm::SmallVector< clang::CXXMethodDecl *, 4 >
2538
2538
SwiftDeclSynthesizer::synthesizeStaticFactoryForCXXForeignRef (
2539
2539
const clang::CXXRecordDecl *cxxRecordDecl) {
2540
2540
2541
+ if (cxxRecordDecl->isAbstract ())
2542
+ return {};
2543
+
2541
2544
clang::ASTContext &clangCtx = cxxRecordDecl->getASTContext ();
2542
2545
clang::Sema &clangSema = ImporterImpl.getClangSema ();
2543
2546
2544
2547
clang::QualType cxxRecordTy = clangCtx.getRecordType (cxxRecordDecl);
2548
+ clang::SourceLocation cxxRecordDeclLoc = cxxRecordDecl->getLocation ();
2545
2549
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);
2554
2564
}
2555
- if (!defaultCtorDecl)
2556
- return nullptr ;
2565
+
2566
+ if (ctorDeclsForSynth.empty ())
2567
+ return {};
2557
2568
2558
2569
clang::FunctionDecl *operatorNew = nullptr ;
2559
2570
clang::FunctionDecl *operatorDelete = nullptr ;
2560
2571
bool passAlignment = false ;
2572
+ clang::Sema::SFINAETrap trap (clangSema);
2561
2573
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 () ||
2567
2580
operatorNew->getAccess () == clang::AS_private ||
2568
2581
operatorNew->getAccess () == clang::AS_protected)
2569
- return nullptr ;
2582
+ return {} ;
2570
2583
2571
2584
clang::QualType cxxRecordPtrTy = clangCtx.getPointerType (cxxRecordTy);
2572
2585
// Adding `_Nonnull` to the return type of synthesized static factory
2573
2586
bool nullabilityCannotBeAdded =
2574
2587
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 );
2579
2590
assert (!nullabilityCannotBeAdded &&
2580
2591
" Failed to add _Nonnull specifier to synthesized "
2581
2592
" static factory's return type" );
2582
2593
2583
2594
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);
2608
2730
}
2609
2731
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;
2661
2733
}
0 commit comments