@@ -2747,3 +2747,107 @@ SwiftDeclSynthesizer::synthesizeStaticFactoryForCXXForeignRef(
2747
2747
2748
2748
return synthesizedFactories;
2749
2749
}
2750
+
2751
+ static std::pair<BraceStmt *, bool >
2752
+ synthesizeAvailabilityDomainPredicateBody (AbstractFunctionDecl *afd,
2753
+ void *context) {
2754
+ auto clangVarDecl = static_cast <const clang::VarDecl *>(context);
2755
+ clang::ASTContext &clangCtx = clangVarDecl->getASTContext ();
2756
+ auto domainInfo =
2757
+ clangCtx.getFeatureAvailInfo (const_cast <clang::VarDecl *>(clangVarDecl));
2758
+ ASSERT (domainInfo.second .Call );
2759
+
2760
+ auto funcDecl = cast<FuncDecl>(afd);
2761
+ ASTContext &ctx = funcDecl->getASTContext ();
2762
+
2763
+ // FIXME: The need for an intermediate function to call could be eliminated if
2764
+ // Clang provided the predicate function decl directly, rather than a call
2765
+ // expression that must be wrapped in a function.
2766
+ // Synthesize `return {domain predicate expression}`.
2767
+ auto clangHelperReturnStmt = clang::ReturnStmt::Create (
2768
+ clangCtx, clang::SourceLocation (), domainInfo.second .Call , nullptr );
2769
+
2770
+ // Synthesize `int __XYZ_isAvailable() { return {predicate expr}; }`.
2771
+ auto clangDeclName = clang::DeclarationName (
2772
+ &clangCtx.Idents .get (" __" + domainInfo.first .str () + " _isAvailable" ));
2773
+ auto clangDeclContext = clangCtx.getTranslationUnitDecl ();
2774
+ clang::QualType funcTy =
2775
+ clangCtx.getFunctionType (domainInfo.second .Call ->getType (), {},
2776
+ clang::FunctionProtoType::ExtProtoInfo ());
2777
+
2778
+ auto clangHelperFuncDecl = clang::FunctionDecl::Create (
2779
+ clangCtx, clangDeclContext, clang::SourceLocation (),
2780
+ clang::SourceLocation (), clangDeclName, funcTy,
2781
+ clangCtx.getTrivialTypeSourceInfo (funcTy),
2782
+ clang::StorageClass::SC_Static);
2783
+ clangHelperFuncDecl->setImplicit ();
2784
+ clangHelperFuncDecl->setImplicitlyInline ();
2785
+ clangHelperFuncDecl->setBody (clangHelperReturnStmt);
2786
+
2787
+ // Import `func __XYZ_isAvailable() -> Bool` into Swift.
2788
+ auto helperFuncDecl = dyn_cast_or_null<FuncDecl>(
2789
+ ctx.getClangModuleLoader ()->importDeclDirectly (clangHelperFuncDecl));
2790
+ if (!helperFuncDecl)
2791
+ return {nullptr , /* isTypeChecked=*/ true };
2792
+
2793
+ auto helperFuncRef = new (ctx) DeclRefExpr (ConcreteDeclRef (helperFuncDecl),
2794
+ DeclNameLoc (), /* Implicit=*/ true );
2795
+ helperFuncRef->setType (helperFuncDecl->getInterfaceType ());
2796
+
2797
+ // Synthesize `__XYZ_isAvailable()`.
2798
+ auto helperCall = CallExpr::createImplicit (
2799
+ ctx, helperFuncRef, ArgumentList::createImplicit (ctx, {}));
2800
+ helperCall->setType (helperFuncDecl->getResultInterfaceType ());
2801
+ helperCall->setThrows (nullptr );
2802
+
2803
+ // Synthesize `__XYZ_isAvailable()._value`.
2804
+ auto *memberRef =
2805
+ UnresolvedDotExpr::createImplicit (ctx, helperCall, ctx.Id_value_ );
2806
+
2807
+ // Synthesize `return __XYZ_isAvailable()._value`.
2808
+ auto *returnStmt = ReturnStmt::createImplicit (ctx, memberRef);
2809
+ auto body = BraceStmt::create (ctx, SourceLoc (), {returnStmt}, SourceLoc (),
2810
+ /* implicit=*/ true );
2811
+
2812
+ return {body, /* isTypeChecked=*/ false };
2813
+ }
2814
+
2815
+ FuncDecl *SwiftDeclSynthesizer::makeAvailabilityDomainPredicate (
2816
+ const clang::VarDecl *var) {
2817
+ ASTContext &ctx = ImporterImpl.SwiftContext ;
2818
+ clang::ASTContext &clangCtx = var->getASTContext ();
2819
+ auto featureInfo =
2820
+ clangCtx.getFeatureAvailInfo (const_cast <clang::VarDecl *>(var));
2821
+
2822
+ // If the decl doesn't represent and availability domain, skip it.
2823
+ if (featureInfo.first .empty ())
2824
+ return nullptr ;
2825
+
2826
+ // Only dynamic availability domains require a predicate function.
2827
+ if (featureInfo.second .Kind != clang::FeatureAvailKind::Dynamic)
2828
+ return nullptr ;
2829
+
2830
+ if (!featureInfo.second .Call )
2831
+ return nullptr ;
2832
+
2833
+ // Synthesize `func __swift_XYZ_isAvailable() -> Builtin.Int1 { ... }`.
2834
+ std::string s;
2835
+ llvm::raw_string_ostream os (s);
2836
+ os << " __swift_" << featureInfo.first << " _isAvailable" ;
2837
+ DeclName funcName (ctx, DeclBaseName (ctx.getIdentifier (s)),
2838
+ ParameterList::createEmpty (ctx));
2839
+
2840
+ auto funcDecl = FuncDecl::createImplicit (
2841
+ ctx, StaticSpellingKind::None, funcName, SourceLoc (), /* Async=*/ false ,
2842
+ /* Throws=*/ false , Type (), {}, ParameterList::createEmpty (ctx),
2843
+ BuiltinIntegerType::get (1 , ctx), ImporterImpl.ImportedHeaderUnit );
2844
+ funcDecl->setBodySynthesizer (synthesizeAvailabilityDomainPredicateBody,
2845
+ (void *)var);
2846
+ funcDecl->setAccess (AccessLevel::Public);
2847
+ funcDecl->getAttrs ().add (new (ctx)
2848
+ AlwaysEmitIntoClientAttr (/* IsImplicit=*/ true ));
2849
+
2850
+ ImporterImpl.availabilityDomainPredicates [var] = funcDecl;
2851
+
2852
+ return funcDecl;
2853
+ }
0 commit comments