@@ -2747,3 +2747,107 @@ SwiftDeclSynthesizer::synthesizeStaticFactoryForCXXForeignRef(
27472747
27482748 return synthesizedFactories;
27492749}
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