//===--- DeclSynthesizer.cpp - Synthesize helper Swift decls --------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// #include "SwiftDeclSynthesizer.h" #include "CXXMethodBridging.h" #include "swift/AST/ASTMangler.h" #include "swift/AST/Attr.h" #include "swift/AST/AttrKind.h" #include "swift/AST/Builtins.h" #include "swift/AST/Decl.h" #include "swift/AST/DiagnosticsClangImporter.h" #include "swift/AST/Expr.h" #include "swift/AST/ParameterList.h" #include "swift/AST/Pattern.h" #include "swift/AST/Stmt.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/Basic/Assertions.h" #include "swift/ClangImporter/ClangImporterRequests.h" #include "clang/AST/Mangle.h" #include "clang/Sema/DelayedDiagnostic.h" using namespace swift; using namespace importer; static Argument createSelfArg(AccessorDecl *accessorDecl) { ASTContext &ctx = accessorDecl->getASTContext(); auto selfDecl = accessorDecl->getImplicitSelfDecl(); auto selfRefExpr = new (ctx) DeclRefExpr(selfDecl, DeclNameLoc(), /*implicit*/ true); if (!accessorDecl->isMutating()) { selfRefExpr->setType(selfDecl->getInterfaceType()); return Argument::unlabeled(selfRefExpr); } selfRefExpr->setType(LValueType::get(selfDecl->getInterfaceType())); return Argument::implicitInOut(ctx, selfRefExpr); } static CallExpr *createAccessorImplCallExpr(FuncDecl *accessorImpl, Argument selfArg, ArrayRef keyRefExprs) { ASTContext &ctx = accessorImpl->getASTContext(); auto accessorImplExpr = new (ctx) DeclRefExpr(ConcreteDeclRef(accessorImpl), DeclNameLoc(), /*Implicit*/ true); accessorImplExpr->setType(accessorImpl->getInterfaceType()); auto accessorImplDotCallExpr = DotSyntaxCallExpr::create(ctx, accessorImplExpr, SourceLoc(), selfArg); accessorImplDotCallExpr->setType(accessorImpl->getMethodInterfaceType()); accessorImplDotCallExpr->setThrows(nullptr); ArgumentList *argList = ArgumentList::forImplicitUnlabeled(ctx, keyRefExprs); auto *accessorImplCallExpr = CallExpr::createImplicit(ctx, accessorImplDotCallExpr, argList); accessorImplCallExpr->setType(accessorImpl->getResultInterfaceType()); accessorImplCallExpr->setThrows(nullptr); return accessorImplCallExpr; } static DeclRefExpr *createParamRefExpr(AccessorDecl *accessorDecl, unsigned index) { ASTContext &ctx = accessorDecl->getASTContext(); auto paramDecl = accessorDecl->getParameters()->get(index); auto paramRefExpr = new (ctx) DeclRefExpr(paramDecl, DeclNameLoc(), /*Implicit*/ true); paramRefExpr->setType(paramDecl->getTypeInContext()); return paramRefExpr; } static AccessorDecl *makeFieldGetterDecl(ClangImporter::Implementation &Impl, NominalTypeDecl *importedDecl, VarDecl *importedFieldDecl, ClangNode clangNode = ClangNode()) { auto &C = Impl.SwiftContext; auto *params = ParameterList::createEmpty(C); auto getterType = importedFieldDecl->getInterfaceType(); auto getterDecl = AccessorDecl::create( C, /*declLoc=*/importedFieldDecl->getLoc(), /*AccessorKeywordLoc=*/SourceLoc(), AccessorKind::Get, importedFieldDecl, /*Async=*/false, /*AsyncLoc=*/SourceLoc(), /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*ThrownType=*/TypeLoc(), params, getterType, importedDecl, clangNode); getterDecl->setAccess(importedFieldDecl->getFormalAccess()); getterDecl->setIsObjC(false); getterDecl->setIsDynamic(false); return getterDecl; } static AccessorDecl *makeFieldSetterDecl(ClangImporter::Implementation &Impl, NominalTypeDecl *importedDecl, VarDecl *importedFieldDecl, ClangNode clangNode = ClangNode()) { auto &C = Impl.SwiftContext; auto newValueDecl = new (C) ParamDecl(SourceLoc(), SourceLoc(), Identifier(), SourceLoc(), C.Id_value, importedDecl); newValueDecl->setSpecifier(ParamSpecifier::Default); newValueDecl->setInterfaceType(importedFieldDecl->getInterfaceType()); auto *params = ParameterList::createWithoutLoc(newValueDecl); auto voidTy = TupleType::getEmpty(C); auto setterDecl = AccessorDecl::create( C, /*declLoc=*/SourceLoc(), /*AccessorKeywordLoc=*/SourceLoc(), AccessorKind::Set, importedFieldDecl, /*Async=*/false, /*AsyncLoc=*/SourceLoc(), /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*ThrownType=*/TypeLoc(), params, voidTy, importedDecl, clangNode); setterDecl->setIsObjC(false); setterDecl->setIsDynamic(false); if (!isa(importedDecl)) setterDecl->setSelfAccessKind(SelfAccessKind::Mutating); setterDecl->setAccess(importedFieldDecl->getSetterFormalAccess()); return setterDecl; } std::pair SwiftDeclSynthesizer::createVarWithPattern(DeclContext *dc, Identifier name, Type ty, VarDecl::Introducer introducer, bool isImplicit, AccessLevel access, AccessLevel setterAccess) { ASTContext &ctx = dc->getASTContext(); // Create a variable to store the underlying value. auto var = new (ctx) VarDecl( /*IsStatic*/ false, introducer, SourceLoc(), name, dc); if (isImplicit) var->setImplicit(); var->setInterfaceType(ty); var->setAccess(access); var->setSetterAccess(setterAccess); // Create a pattern binding to describe the variable. Pattern *varPattern = createTypedNamedPattern(var); auto *patternBinding = PatternBindingDecl::create( ctx, /*StaticLoc*/ SourceLoc(), StaticSpellingKind::None, /*VarLoc*/ SourceLoc(), varPattern, /*EqualLoc*/ SourceLoc(), /*InitExpr*/ nullptr, dc); if (isImplicit) patternBinding->setImplicit(); return {var, patternBinding}; } Pattern *SwiftDeclSynthesizer::createTypedNamedPattern(VarDecl *decl) { ASTContext &Ctx = decl->getASTContext(); Type ty = decl->getTypeInContext(); Pattern *P = new (Ctx) NamedPattern(decl); P->setType(ty); P->setImplicit(); return TypedPattern::createImplicit(Ctx, P, ty); } namespace { using ConstantGetterBodyContextData = llvm::PointerIntPair; } Type SwiftDeclSynthesizer::getConstantLiteralType( Type type, ConstantConvertKind convertKind) { switch (convertKind) { case ConstantConvertKind::Construction: case ConstantConvertKind::ConstructionWithUnwrap: { auto found = ImporterImpl.RawTypes.find(type->getAnyNominal()); assert(found != ImporterImpl.RawTypes.end()); return found->second; } default: return type; } } // This method is exposed on SwiftDeclSynthesizer to keep code that accesses // RawTypes together. bool SwiftDeclSynthesizer::isCGFloat(Type type) { auto found = ImporterImpl.RawTypes.find(type->getAnyNominal()); if (found == ImporterImpl.RawTypes.end()) { return false; } Type importTy = found->second; return importTy->isCGFloat(); } // This method is exposed on SwiftDeclSynthesizer to keep code that accesses // RawTypes together. bool SwiftDeclSynthesizer::isObjCBool(Type type) { auto found = ImporterImpl.RawTypes.find(type->getAnyNominal()); if (found == ImporterImpl.RawTypes.end()) { return false; } Type importTy = found->second; return importTy->isObjCBool(); } bool SwiftDeclSynthesizer::isUnicodeScalar(Type type) { auto found = ImporterImpl.RawTypes.find(type->getAnyNominal()); if (found == ImporterImpl.RawTypes.end()) { return false; } Type importTy = found->second; return importTy->isUnicodeScalar(); } ValueDecl *SwiftDeclSynthesizer::createConstant(Identifier name, DeclContext *dc, Type type, const clang::APValue &value, ConstantConvertKind convertKind, bool isStatic, ClangNode ClangN, AccessLevel access) { auto &context = ImporterImpl.SwiftContext; // Create the integer literal value. Expr *expr = nullptr; switch (value.getKind()) { case clang::APValue::AddrLabelDiff: case clang::APValue::Array: case clang::APValue::ComplexFloat: case clang::APValue::ComplexInt: case clang::APValue::FixedPoint: case clang::APValue::Indeterminate: case clang::APValue::LValue: case clang::APValue::MemberPointer: case clang::APValue::None: case clang::APValue::Struct: case clang::APValue::Union: case clang::APValue::Vector: llvm_unreachable("Unhandled APValue kind"); case clang::APValue::Float: case clang::APValue::Int: { // Print the value. llvm::SmallString<16> printedValueBuf; if (value.getKind() == clang::APValue::Int) { value.getInt().toString(printedValueBuf); } else { assert(value.getFloat().isFinite() && "can't handle infinities or NaNs"); value.getFloat().toString(printedValueBuf); } StringRef printedValue = printedValueBuf.str(); // If this was a negative number, record that and strip off the '-'. bool isNegative = printedValue.front() == '-'; if (isNegative) printedValue = printedValue.drop_front(); auto literalType = getConstantLiteralType(type, convertKind); // Create the expression node. StringRef printedValueCopy(context.AllocateCopy(printedValue)); if (value.getKind() == clang::APValue::Int) { bool isBool = type->getCanonicalType()->isBool(); // Check if "type" is a C++ enum with an underlying type of "bool". if (!isBool && type->getStructOrBoundGenericStruct() && type->getStructOrBoundGenericStruct()->getClangDecl()) { if (auto enumDecl = dyn_cast( type->getStructOrBoundGenericStruct()->getClangDecl())) { isBool = enumDecl->getIntegerType()->isBooleanType(); } } if (isBool) { auto *boolExpr = new (context) BooleanLiteralExpr(value.getInt().getBoolValue(), SourceLoc(), /*Implicit=*/true); boolExpr->setBuiltinInitializer(context.getBoolBuiltinInitDecl()); boolExpr->setType(literalType); expr = boolExpr; } else { auto *intExpr = new (context) IntegerLiteralExpr(printedValueCopy, SourceLoc(), /*Implicit=*/true); auto *intDecl = literalType->getAnyNominal(); intExpr->setBuiltinInitializer(context.getIntBuiltinInitDecl(intDecl)); intExpr->setType(literalType); expr = intExpr; } } else { auto *floatExpr = new (context) FloatLiteralExpr(printedValueCopy, SourceLoc(), /*Implicit=*/true); auto maxFloatTypeDecl = context.get_MaxBuiltinFloatTypeDecl(); floatExpr->setBuiltinType(maxFloatTypeDecl->getUnderlyingType()); auto *floatDecl = literalType->getAnyNominal(); floatExpr->setBuiltinInitializer( context.getFloatBuiltinInitDecl(floatDecl)); floatExpr->setType(literalType); expr = floatExpr; } if (isNegative) cast(expr)->setNegative(SourceLoc()); break; } } assert(expr); return createConstant(name, dc, type, expr, convertKind, isStatic, ClangN, access); } ValueDecl *SwiftDeclSynthesizer::createConstant(Identifier name, DeclContext *dc, Type type, StringRef value, ConstantConvertKind convertKind, bool isStatic, ClangNode ClangN, AccessLevel access) { ASTContext &ctx = ImporterImpl.SwiftContext; auto expr = new (ctx) StringLiteralExpr(value, SourceRange()); auto literalType = getConstantLiteralType(type, convertKind); auto *stringDecl = literalType->getAnyNominal(); expr->setBuiltinInitializer(ctx.getStringBuiltinInitDecl(stringDecl)); expr->setType(literalType); return createConstant(name, dc, type, expr, convertKind, isStatic, ClangN, access); } /// Synthesizer callback to synthesize the getter for a constant value. static std::pair synthesizeConstantGetterBody(AbstractFunctionDecl *afd, void *voidContext) { ASTContext &ctx = afd->getASTContext(); auto func = cast(afd); VarDecl *constantVar = cast(func->getStorage()); Type type = func->mapTypeIntoEnvironment(constantVar->getValueInterfaceType()); auto contextData = ConstantGetterBodyContextData::getFromOpaqueValue(voidContext); Expr *expr = contextData.getPointer(); ConstantConvertKind convertKind = contextData.getInt(); // If we need a conversion, add one now. switch (convertKind) { case ConstantConvertKind::None: break; case ConstantConvertKind::Construction: case ConstantConvertKind::ConstructionWithUnwrap: { auto typeRef = TypeExpr::createImplicit(type, ctx); // Reference init(rawValue: T) ConstructorDecl *init = nullptr; DeclName initName = DeclName(ctx, DeclBaseName::createConstructor(), {ctx.Id_rawValue}); auto nominal = type->getAnyNominal(); for (auto found : nominal->lookupDirect(initName)) { init = dyn_cast(found); if (init && init->getDeclContext() == nominal) break; } assert(init && "did not find init(rawValue:)"); auto initTy = init->getInterfaceType()->removeArgumentLabels(1); auto declRef = new (ctx) DeclRefExpr(init, DeclNameLoc(), /*Implicit=*/true, AccessSemantics::Ordinary, initTy); // (Self) -> ... initTy = initTy->castTo()->getResult(); auto initRef = DotSyntaxCallExpr::create( ctx, declRef, SourceLoc(), Argument::unlabeled(typeRef), initTy); initRef->setThrows(nullptr); // (rawValue: T) -> ... initTy = initTy->castTo()->getResult(); auto *argList = ArgumentList::forImplicitSingle(ctx, ctx.Id_rawValue, expr); auto initCall = CallExpr::createImplicit(ctx, initRef, argList); initCall->setType(initTy); initCall->setThrows(nullptr); expr = initCall; // Force unwrap if our init(rawValue:) is failable, which is currently // the case with enums. if (convertKind == ConstantConvertKind::ConstructionWithUnwrap) { initTy = initTy->getOptionalObjectType(); expr = new (ctx) ForceValueExpr(expr, SourceLoc()); expr->setType(initTy); } assert(initTy->isEqual(type)); break; } } // Create the return statement. auto ret = ReturnStmt::createImplicit(ctx, expr); return {BraceStmt::create(ctx, SourceLoc(), ASTNode(ret), SourceLoc()), /*isTypeChecked=*/true}; } ValueDecl *SwiftDeclSynthesizer::createConstant(Identifier name, DeclContext *dc, Type type, Expr *valueExpr, ConstantConvertKind convertKind, bool isStatic, ClangNode ClangN, AccessLevel access) { auto &C = ImporterImpl.SwiftContext; VarDecl *var = nullptr; if (ClangN) { var = ImporterImpl.createDeclWithClangNode( ClangN, access, /*IsStatic*/ isStatic, VarDecl::Introducer::Var, SourceLoc(), name, dc); } else { var = new (C) VarDecl( /*IsStatic*/ isStatic, VarDecl::Introducer::Var, SourceLoc(), name, dc); } var->setInterfaceType(type); var->setIsObjC(false); var->setIsDynamic(false); auto *params = ParameterList::createEmpty(C); // Create the getter function declaration. auto func = AccessorDecl::create( C, /*declLoc=*/SourceLoc(), /*AccessorKeywordLoc=*/SourceLoc(), AccessorKind::Get, var, /*Async=*/false, /*AsyncLoc=*/SourceLoc(), /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*ThrownType=*/TypeLoc(), params, type, dc); func->setStatic(isStatic); func->setIsObjC(false); func->setIsDynamic(false); func->setBodySynthesizer( synthesizeConstantGetterBody, ConstantGetterBodyContextData(valueExpr, convertKind).getOpaqueValue()); // Mark the function transparent so that we inline it away completely. func->addAttribute(new (C) TransparentAttr(/*implicit*/ true)); var->addAttribute(NonisolatedAttr::createImplicit(C)); // Set the function up as the getter. ImporterImpl.makeComputed(var, func, nullptr); return var; } // MARK: Struct default initializers /// Synthesize the body for an struct default initializer. static std::pair synthesizeStructDefaultConstructorBody(AbstractFunctionDecl *afd, void *context) { auto constructor = cast(afd); ASTContext &ctx = constructor->getASTContext(); auto structDecl = static_cast(context); // Use a builtin to produce a zero initializer, and assign it to self. // Construct the left-hand reference to self. auto *selfDecl = constructor->getImplicitSelfDecl(); Expr *lhs = new (ctx) DeclRefExpr(selfDecl, DeclNameLoc(), /*Implicit=*/true); auto selfType = structDecl->getDeclaredInterfaceType(); lhs->setType(LValueType::get(selfType)); auto emptyTuple = TupleType::getEmpty(ctx); // Construct the right-hand call to Builtin.zeroInitializer. Identifier zeroInitID = ctx.getIdentifier("zeroInitializer"); auto zeroInitializerFunc = cast(getBuiltinValueDecl(ctx, zeroInitID)); SubstitutionMap subMap = SubstitutionMap::get( zeroInitializerFunc->getGenericSignature(), llvm::ArrayRef(selfType), LookUpConformanceInModule()); ConcreteDeclRef concreteDeclRef(zeroInitializerFunc, subMap); auto zeroInitializerRef = new (ctx) DeclRefExpr(concreteDeclRef, DeclNameLoc(), /*implicit*/ true); // FIXME: Verify ExtInfo state is correct, not working by accident. FunctionType::ExtInfo info; zeroInitializerRef->setType(FunctionType::get({}, selfType, info)); auto call = CallExpr::createImplicitEmpty(ctx, zeroInitializerRef); call->setType(selfType); call->setThrows(nullptr); auto assign = new (ctx) AssignExpr(lhs, SourceLoc(), call, /*implicit*/ true); assign->setType(emptyTuple); auto *ret = ReturnStmt::createImplicit(ctx, /*expr*/ nullptr); // Create the function body. auto body = BraceStmt::create(ctx, SourceLoc(), {assign, ret}, SourceLoc()); return {body, /*isTypeChecked*/ true}; } ConstructorDecl * SwiftDeclSynthesizer::createDefaultConstructor(NominalTypeDecl *structDecl) { auto &context = ImporterImpl.SwiftContext; auto emptyPL = ParameterList::createEmpty(context); // Create the constructor. DeclName name(context, DeclBaseName::createConstructor(), emptyPL); auto constructor = new (context) ConstructorDecl(name, structDecl->getLoc(), /*Failable=*/false, /*FailabilityLoc=*/SourceLoc(), /*Async=*/false, /*AsyncLoc=*/SourceLoc(), /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*ThrownType=*/TypeLoc(), emptyPL, /*GenericParams=*/nullptr, structDecl); constructor->copyFormalAccessFrom(structDecl); // Mark the constructor transparent so that we inline it away completely. constructor->addAttribute(new (context) TransparentAttr(/*implicit*/ true)); constructor->setBodySynthesizer(synthesizeStructDefaultConstructorBody, structDecl); // We're done. return constructor; } // MARK: Struct value initializers /// Synthesizer callback for the body of a struct value constructor. static std::pair synthesizeValueConstructorBody(AbstractFunctionDecl *afd, void *context) { auto constructor = cast(afd); ArrayRef members(static_cast(context) + 1, static_cast(context)[0]); ASTContext &ctx = constructor->getASTContext(); // Assign all of the member variables appropriately. SmallVector stmts; auto *selfDecl = constructor->getImplicitSelfDecl(); // To keep DI happy, initialize stored properties before computed. auto parameters = constructor->getParameters(); for (unsigned pass = 0; pass < 2; ++pass) { unsigned paramPos = 0; for (unsigned i = 0, e = members.size(); i < e; ++i) { auto var = members[i]; if (isa_and_nonnull(var->getClangDecl())) continue; if (var->hasStorage() == (pass != 0)) { ++paramPos; continue; } // Construct left-hand side. Expr *lhs = new (ctx) DeclRefExpr(selfDecl, DeclNameLoc(), /*Implicit=*/true); lhs->setType(LValueType::get(selfDecl->getTypeInContext())); auto semantics = (var->hasStorage() ? AccessSemantics::DirectToStorage : AccessSemantics::Ordinary); lhs = new (ctx) MemberRefExpr(lhs, SourceLoc(), var, DeclNameLoc(), /*Implicit=*/true, semantics); lhs->setType(LValueType::get(var->getTypeInContext())); // Construct right-hand side. auto rhs = new (ctx) DeclRefExpr(parameters->get(paramPos), DeclNameLoc(), /*Implicit=*/true); rhs->setType(parameters->get(paramPos)->getTypeInContext()); // Add assignment. auto assign = new (ctx) AssignExpr(lhs, SourceLoc(), rhs, /*Implicit=*/true); assign->setType(TupleType::getEmpty(ctx)); stmts.push_back(assign); ++paramPos; } } stmts.push_back(ReturnStmt::createImplicit(ctx, /*expr*/ nullptr)); // Create the function body. auto body = BraceStmt::create(ctx, SourceLoc(), stmts, SourceLoc()); return {body, /*isTypeChecked=*/true}; } ConstructorDecl *SwiftDeclSynthesizer::createValueConstructor( NominalTypeDecl *structDecl, ArrayRef members, bool wantCtorParamNames, bool wantBody) { auto &context = ImporterImpl.SwiftContext; // Construct the set of parameters from the list of members. SmallVector valueParameters; for (auto var : members) { if (var->isStatic()) continue; bool generateParamName = wantCtorParamNames; if (var->hasClangNode()) { // TODO create value constructor with indirect fields instead of the // generated __Anonymous_field. if (isa(var->getClangDecl())) continue; if (auto clangField = dyn_cast(var->getClangDecl())) if (clangField->isAnonymousStructOrUnion() || clangField->getDeclName().isEmpty()) generateParamName = false; } Identifier argName = generateParamName ? var->getName() : Identifier(); auto param = new (context) ParamDecl(SourceLoc(), SourceLoc(), argName, SourceLoc(), var->getName(), structDecl); param->setSpecifier(ParamSpecifier::Default); param->setInterfaceType(var->getInterfaceType()); ImporterImpl.recordImplicitUnwrapForDecl( param, var->isImplicitlyUnwrappedOptional()); // Don't allow the parameter to accept temporary pointer conversions. param->setNonEphemeralIfPossible(); valueParameters.push_back(param); } auto *paramList = ParameterList::create(context, valueParameters); // Create the constructor DeclName name(context, DeclBaseName::createConstructor(), paramList); auto constructor = new (context) ConstructorDecl(name, structDecl->getLoc(), /*Failable=*/false, /*FailabilityLoc=*/SourceLoc(), /*Async=*/false, /*AsyncLoc=*/SourceLoc(), /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*ThrownType=*/TypeLoc(), paramList, /*GenericParams=*/nullptr, structDecl); constructor->copyFormalAccessFrom(structDecl); // Make the constructor transparent so we inline it away completely. constructor->addAttribute(new (context) TransparentAttr(/*implicit*/ true)); if (wantBody) { auto memberMemory = context.AllocateUninitialized(members.size() + 1); memberMemory[0] = members.size(); for (unsigned i : indices(members)) { memberMemory[i + 1] = reinterpret_cast(members[i]); } constructor->setBodySynthesizer(synthesizeValueConstructorBody, memberMemory.data()); } // We're done. return constructor; } // MARK: Struct RawValue initializers /// Synthesizer callback for a raw value bridging constructor body. static std::pair synthesizeRawValueBridgingConstructorBody(AbstractFunctionDecl *afd, void *context) { auto init = cast(afd); VarDecl *storedRawValue = static_cast(context); ASTContext &ctx = init->getASTContext(); auto selfDecl = init->getImplicitSelfDecl(); auto storedType = storedRawValue->getInterfaceType(); // Construct left-hand side. Expr *lhs = new (ctx) DeclRefExpr(selfDecl, DeclNameLoc(), /*Implicit=*/true); lhs->setType(LValueType::get(selfDecl->getTypeInContext())); lhs = new (ctx) MemberRefExpr(lhs, SourceLoc(), storedRawValue, DeclNameLoc(), /*Implicit=*/true, AccessSemantics::DirectToStorage); lhs->setType(LValueType::get(storedType)); // Construct right-hand side. // FIXME: get the parameter from the init, and plug it in here. auto *paramDecl = init->getParameters()->get(0); auto *paramRef = new (ctx) DeclRefExpr(paramDecl, DeclNameLoc(), /*Implicit=*/true); paramRef->setType(paramDecl->getTypeInContext()); Expr *rhs = paramRef; if (!storedRawValue->getInterfaceType()->isEqual(paramDecl->getInterfaceType())) { auto bridge = new (ctx) BridgeToObjCExpr(paramRef, storedType); bridge->setType(storedType); rhs = CoerceExpr::createImplicit(ctx, bridge, storedType); } // Add assignment. auto assign = new (ctx) AssignExpr(lhs, SourceLoc(), rhs, /*Implicit=*/true); assign->setType(TupleType::getEmpty(ctx)); auto *ret = ReturnStmt::createImplicit(ctx, /*expr*/ nullptr); auto body = BraceStmt::create(ctx, SourceLoc(), {assign, ret}, SourceLoc()); return {body, /*isTypeChecked=*/true}; } ConstructorDecl *SwiftDeclSynthesizer::createRawValueBridgingConstructor( StructDecl *structDecl, VarDecl *computedRawValue, VarDecl *storedRawValue, bool wantLabel, bool wantBody) { auto init = createValueConstructor(structDecl, computedRawValue, /*wantCtorParamNames=*/wantLabel, /*wantBody=*/false); // Insert our custom init body if (wantBody) { init->setBodySynthesizer(synthesizeRawValueBridgingConstructorBody, storedRawValue); } return init; } void SwiftDeclSynthesizer::makeStructRawValuedWithBridge( StructDecl *structDecl, Type storedUnderlyingType, Type bridgedType, ArrayRef synthesizedProtocolAttrs, bool makeUnlabeledValueInit) { auto &ctx = ImporterImpl.SwiftContext; ImporterImpl.addSynthesizedProtocolAttrs(structDecl, synthesizedProtocolAttrs); auto storedVarName = ctx.getIdentifier("_rawValue"); auto computedVarName = ctx.Id_rawValue; // Create a variable to store the underlying value. VarDecl *storedVar; PatternBindingDecl *storedPatternBinding; std::tie(storedVar, storedPatternBinding) = createVarWithPattern( structDecl, storedVarName, storedUnderlyingType, VarDecl::Introducer::Var, /*isImplicit=*/true, AccessLevel::Private, AccessLevel::Private); // Create a computed value variable. auto computedVar = new (ctx) VarDecl( /*IsStatic*/ false, VarDecl::Introducer::Var, SourceLoc(), computedVarName, structDecl); computedVar->setInterfaceType(bridgedType); computedVar->setImplicit(); computedVar->copyFormalAccessFrom(structDecl); computedVar->setSetterAccess(AccessLevel::Private); // Create the getter for the computed value variable. auto computedVarGetter = makeStructRawValueGetter(structDecl, computedVar, storedVar); ImporterImpl.makeComputed(computedVar, computedVarGetter, nullptr); // Create a pattern binding to describe the variable. Pattern *computedBindingPattern = createTypedNamedPattern(computedVar); auto *computedPatternBinding = PatternBindingDecl::createImplicit( ctx, StaticSpellingKind::None, computedBindingPattern, /*InitExpr*/ nullptr, structDecl); auto init = createRawValueBridgingConstructor(structDecl, computedVar, storedVar, /*wantLabel*/ true, /*wantBody*/ true); ConstructorDecl *unlabeledCtor = nullptr; if (makeUnlabeledValueInit) unlabeledCtor = createRawValueBridgingConstructor( structDecl, computedVar, storedVar, /*wantLabel*/ false, /*wantBody*/ true); if (unlabeledCtor) structDecl->addMember(unlabeledCtor); structDecl->addMember(init); structDecl->addMember(storedPatternBinding); structDecl->addMember(storedVar); structDecl->addMember(computedPatternBinding); structDecl->addMember(computedVar); ImporterImpl.addSynthesizedTypealias(structDecl, ctx.Id_RawValue, bridgedType); ImporterImpl.RawTypes[structDecl] = bridgedType; } void SwiftDeclSynthesizer::makeStructRawValued( StructDecl *structDecl, Type underlyingType, ArrayRef synthesizedProtocolAttrs, MakeStructRawValuedOptions options, AccessLevel setterAccess) { auto &ctx = ImporterImpl.SwiftContext; ImporterImpl.addSynthesizedProtocolAttrs(structDecl, synthesizedProtocolAttrs); // Create a variable to store the underlying value. VarDecl *var; PatternBindingDecl *patternBinding; auto introducer = (options.contains(MakeStructRawValuedFlags::IsLet) ? VarDecl::Introducer::Let : VarDecl::Introducer::Var); std::tie(var, patternBinding) = createVarWithPattern( structDecl, ctx.Id_rawValue, underlyingType, introducer, options.contains(MakeStructRawValuedFlags::IsImplicit), structDecl->getFormalAccess(), setterAccess); assert(var->hasStorage()); // Create constructors to initialize that value from a value of the // underlying type. if (options.contains(MakeStructRawValuedFlags::MakeUnlabeledValueInit)) structDecl->addMember(createValueConstructor(structDecl, var, /*wantCtorParamNames=*/false, /*wantBody=*/true)); auto *initRawValue = createValueConstructor(structDecl, var, /*wantCtorParamNames=*/true, /*wantBody=*/true); structDecl->addMember(initRawValue); structDecl->addMember(patternBinding); structDecl->addMember(var); ImporterImpl.addSynthesizedTypealias(structDecl, ctx.Id_RawValue, underlyingType); ImporterImpl.RawTypes[structDecl] = underlyingType; } // MARK: Unions /// Synthesizer for the body of a union field getter. static std::pair synthesizeUnionFieldGetterBody(AbstractFunctionDecl *afd, void *context) { auto getterDecl = cast(afd); ASTContext &ctx = getterDecl->getASTContext(); auto importedFieldDecl = static_cast(context); auto selfDecl = getterDecl->getImplicitSelfDecl(); auto selfRef = new (ctx) DeclRefExpr(selfDecl, DeclNameLoc(), /*implicit*/ true); selfRef->setType(selfDecl->getInterfaceType()); auto reinterpretCast = cast( getBuiltinValueDecl(ctx, ctx.getIdentifier("reinterpretCast"))); ConcreteDeclRef reinterpretCastRef( reinterpretCast, SubstitutionMap::get( reinterpretCast->getGenericSignature(), {selfDecl->getInterfaceType(), importedFieldDecl->getInterfaceType()}, LookUpConformanceInModule())); auto reinterpretCastRefExpr = new (ctx) DeclRefExpr(reinterpretCastRef, DeclNameLoc(), /*implicit*/ true); // FIXME: Verify ExtInfo state is correct, not working by accident. FunctionType::ExtInfo info; reinterpretCastRefExpr->setType( FunctionType::get(AnyFunctionType::Param(selfDecl->getInterfaceType()), importedFieldDecl->getInterfaceType(), info)); auto *argList = ArgumentList::forImplicitUnlabeled(ctx, {selfRef}); auto reinterpreted = CallExpr::createImplicit(ctx, reinterpretCastRefExpr, argList); reinterpreted->setType(importedFieldDecl->getInterfaceType()); reinterpreted->setThrows(nullptr); auto *ret = ReturnStmt::createImplicit(ctx, reinterpreted); auto body = BraceStmt::create(ctx, SourceLoc(), ASTNode(ret), SourceLoc(), /*implicit*/ true); return {body, /*isTypeChecked*/ true}; } /// Synthesizer for the body of a union field setter. static std::pair synthesizeUnionFieldSetterBody(AbstractFunctionDecl *afd, void *context) { auto setterDecl = cast(afd); ASTContext &ctx = setterDecl->getASTContext(); auto inoutSelfDecl = setterDecl->getImplicitSelfDecl(); auto inoutSelfRef = new (ctx) DeclRefExpr(inoutSelfDecl, DeclNameLoc(), /*implicit*/ true); inoutSelfRef->setType(LValueType::get(inoutSelfDecl->getInterfaceType())); auto newValueDecl = setterDecl->getParameters()->get(0); auto newValueRef = new (ctx) DeclRefExpr(newValueDecl, DeclNameLoc(), /*implicit*/ true); newValueRef->setType(newValueDecl->getInterfaceType()); auto addressofFn = cast(getBuiltinValueDecl(ctx, ctx.getIdentifier("unprotectedAddressOf"))); ConcreteDeclRef addressofFnRef( addressofFn, SubstitutionMap::get(addressofFn->getGenericSignature(), {inoutSelfDecl->getInterfaceType()}, LookUpConformanceInModule())); auto addressofFnRefExpr = new (ctx) DeclRefExpr(addressofFnRef, DeclNameLoc(), /*implicit*/ true); // FIXME: Verify ExtInfo state is correct, not working by accident. FunctionType::ExtInfo addressOfInfo; addressofFnRefExpr->setType(FunctionType::get( AnyFunctionType::Param(inoutSelfDecl->getInterfaceType(), Identifier(), ParameterTypeFlags().withInOut(true)), ctx.TheRawPointerType, addressOfInfo)); auto *selfPtrArgs = ArgumentList::createImplicit( ctx, {Argument::implicitInOut(ctx, inoutSelfRef)}); auto selfPointer = CallExpr::createImplicit(ctx, addressofFnRefExpr, selfPtrArgs); selfPointer->setType(ctx.TheRawPointerType); selfPointer->setThrows(nullptr); auto initializeFn = cast(getBuiltinValueDecl(ctx, ctx.getIdentifier("initialize"))); ConcreteDeclRef initializeFnRef( initializeFn, SubstitutionMap::get(initializeFn->getGenericSignature(), {newValueDecl->getInterfaceType()}, LookUpConformanceInModule())); auto initializeFnRefExpr = new (ctx) DeclRefExpr(initializeFnRef, DeclNameLoc(), /*implicit*/ true); // FIXME: Verify ExtInfo state is correct, not working by accident. FunctionType::ExtInfo initializeInfo; initializeFnRefExpr->setType(FunctionType::get( {AnyFunctionType::Param(newValueDecl->getInterfaceType()), AnyFunctionType::Param(ctx.TheRawPointerType)}, TupleType::getEmpty(ctx), initializeInfo)); auto *initArgs = ArgumentList::forImplicitUnlabeled(ctx, {newValueRef, selfPointer}); auto initialize = CallExpr::createImplicit(ctx, initializeFnRefExpr, initArgs); initialize->setType(TupleType::getEmpty(ctx)); initialize->setThrows(nullptr); auto body = BraceStmt::create(ctx, SourceLoc(), {initialize}, SourceLoc(), /*implicit*/ true); return {body, /*isTypeChecked*/ true}; } std::pair SwiftDeclSynthesizer::makeUnionFieldAccessors( NominalTypeDecl *importedUnionDecl, VarDecl *importedFieldDecl) { auto &C = ImporterImpl.SwiftContext; auto getterDecl = makeFieldGetterDecl(ImporterImpl, importedUnionDecl, importedFieldDecl); getterDecl->setBodySynthesizer(synthesizeUnionFieldGetterBody, importedFieldDecl); getterDecl->addAttribute(new (C) TransparentAttr(/*implicit*/ true)); auto setterDecl = makeFieldSetterDecl(ImporterImpl, importedUnionDecl, importedFieldDecl); setterDecl->setBodySynthesizer(synthesizeUnionFieldSetterBody, importedFieldDecl); setterDecl->addAttribute(new (C) TransparentAttr(/*implicit*/ true)); ImporterImpl.makeComputed(importedFieldDecl, getterDecl, setterDecl); return {getterDecl, setterDecl}; } static clang::DeclarationName getAccessorDeclarationName(clang::ASTContext &Ctx, NominalTypeDecl *structDecl, VarDecl *fieldDecl, const char *suffix) { std::string id; llvm::raw_string_ostream IdStream(id); Mangle::ASTMangler mangler(structDecl->getASTContext()); IdStream << "$" << mangler.mangleDeclWithPrefix(structDecl, "") << "$" << fieldDecl->getName() << "$" << suffix; return clang::DeclarationName(&Ctx.Idents.get(IdStream.str())); } std::pair SwiftDeclSynthesizer::makeBitFieldAccessors( clang::RecordDecl *structDecl, NominalTypeDecl *importedStructDecl, clang::FieldDecl *fieldDecl, VarDecl *importedFieldDecl) { clang::ASTContext &Ctx = ImporterImpl.getClangASTContext(); // Getter: static inline FieldType get(RecordType self); auto recordType = Ctx.getRecordType(structDecl); auto recordPointerType = Ctx.getPointerType(recordType); auto fieldType = fieldDecl->getType(); auto cGetterName = getAccessorDeclarationName(Ctx, importedStructDecl, importedFieldDecl, "getter"); auto cGetterType = Ctx.getFunctionType(fieldDecl->getType(), recordType, clang::FunctionProtoType::ExtProtoInfo()); auto cGetterTypeInfo = Ctx.getTrivialTypeSourceInfo(cGetterType); auto cGetterDecl = clang::FunctionDecl::Create( Ctx, structDecl->getDeclContext(), clang::SourceLocation(), clang::SourceLocation(), cGetterName, cGetterType, cGetterTypeInfo, clang::SC_Static); cGetterDecl->setImplicit(); cGetterDecl->setImplicitlyInline(); assert(!cGetterDecl->isExternallyVisible()); auto getterDecl = makeFieldGetterDecl(ImporterImpl, importedStructDecl, importedFieldDecl, cGetterDecl); // Setter: static inline void set(FieldType newValue, RecordType *self); SmallVector cSetterParamTypes; cSetterParamTypes.push_back(fieldType); cSetterParamTypes.push_back(recordPointerType); auto cSetterName = getAccessorDeclarationName(Ctx, importedStructDecl, importedFieldDecl, "setter"); auto cSetterType = Ctx.getFunctionType( Ctx.VoidTy, cSetterParamTypes, clang::FunctionProtoType::ExtProtoInfo()); auto cSetterTypeInfo = Ctx.getTrivialTypeSourceInfo(cSetterType); auto cSetterDecl = clang::FunctionDecl::Create( Ctx, structDecl->getDeclContext(), clang::SourceLocation(), clang::SourceLocation(), cSetterName, cSetterType, cSetterTypeInfo, clang::SC_Static); cSetterDecl->setImplicit(); cSetterDecl->setImplicitlyInline(); assert(!cSetterDecl->isExternallyVisible()); auto setterDecl = makeFieldSetterDecl(ImporterImpl, importedStructDecl, importedFieldDecl, cSetterDecl); ImporterImpl.makeComputed(importedFieldDecl, getterDecl, setterDecl); // Synthesize the getter body { auto cGetterSelfId = nullptr; auto recordTypeInfo = Ctx.getTrivialTypeSourceInfo(recordType); auto cGetterSelf = clang::ParmVarDecl::Create( Ctx, cGetterDecl, clang::SourceLocation(), clang::SourceLocation(), cGetterSelfId, recordType, recordTypeInfo, clang::SC_None, nullptr); cGetterSelf->setImplicit(); cGetterDecl->setParams(cGetterSelf); auto cGetterSelfExpr = new (Ctx) clang::DeclRefExpr(Ctx, cGetterSelf, false, recordType, clang::VK_PRValue, clang::SourceLocation()); auto cGetterExpr = clang::MemberExpr::CreateImplicit( Ctx, cGetterSelfExpr, /*isarrow=*/false, fieldDecl, fieldType, clang::VK_PRValue, clang::OK_BitField); auto cGetterBody = clang::ReturnStmt::Create(Ctx, clang::SourceLocation(), cGetterExpr, nullptr); cGetterDecl->setBody(cGetterBody); } // Synthesize the setter body { SmallVector cSetterParams; auto fieldTypeInfo = Ctx.getTrivialTypeSourceInfo(fieldType); auto cSetterValue = clang::ParmVarDecl::Create( Ctx, cSetterDecl, clang::SourceLocation(), clang::SourceLocation(), /* nameID? */ nullptr, fieldType, fieldTypeInfo, clang::SC_None, nullptr); cSetterValue->setImplicit(); cSetterParams.push_back(cSetterValue); auto recordPointerTypeInfo = Ctx.getTrivialTypeSourceInfo(recordPointerType); auto cSetterSelf = clang::ParmVarDecl::Create( Ctx, cSetterDecl, clang::SourceLocation(), clang::SourceLocation(), /* nameID? */ nullptr, recordPointerType, recordPointerTypeInfo, clang::SC_None, nullptr); cSetterSelf->setImplicit(); cSetterParams.push_back(cSetterSelf); cSetterDecl->setParams(cSetterParams); auto cSetterSelfExpr = new (Ctx) clang::DeclRefExpr(Ctx, cSetterSelf, false, recordPointerType, clang::VK_PRValue, clang::SourceLocation()); auto cSetterMemberExpr = clang::MemberExpr::CreateImplicit( Ctx, cSetterSelfExpr, /*isarrow=*/true, fieldDecl, fieldType, clang::VK_LValue, clang::OK_BitField); auto cSetterValueExpr = new (Ctx) clang::DeclRefExpr(Ctx, cSetterValue, false, fieldType, clang::VK_PRValue, clang::SourceLocation()); auto cSetterExpr = clang::BinaryOperator::Create( Ctx, cSetterMemberExpr, cSetterValueExpr, clang::BO_Assign, fieldType, clang::VK_PRValue, clang::OK_Ordinary, clang::SourceLocation(), clang::FPOptionsOverride()); cSetterDecl->setBody(cSetterExpr); } return {getterDecl, setterDecl}; } /// Find the anonymous inner field declaration for the given anonymous field. static VarDecl *findAnonymousInnerFieldDecl(VarDecl *importedFieldDecl, VarDecl *anonymousFieldDecl) { auto anonymousFieldType = anonymousFieldDecl->getInterfaceType(); auto anonymousFieldTypeDecl = anonymousFieldType->getStructOrBoundGenericStruct(); for (auto decl : anonymousFieldTypeDecl->lookupDirect(importedFieldDecl->getName())) { if (isa(decl)) { return cast(decl); } } llvm_unreachable("couldn't find anonymous inner field decl"); } // MARK: Indirect fields /// Synthesize the getter body for an indirect field. static std::pair synthesizeIndirectFieldGetterBody(AbstractFunctionDecl *afd, void *context) { auto getterDecl = cast(afd); auto anonymousFieldDecl = static_cast(context); ASTContext &ctx = getterDecl->getASTContext(); auto selfDecl = getterDecl->getImplicitSelfDecl(); Expr *expr = new (ctx) DeclRefExpr(selfDecl, DeclNameLoc(), /*implicit*/ true); expr->setType(selfDecl->getInterfaceType()); expr = new (ctx) MemberRefExpr(expr, SourceLoc(), anonymousFieldDecl, DeclNameLoc(), /*implicit*/ true); expr->setType(anonymousFieldDecl->getInterfaceType()); auto importedFieldDecl = cast(getterDecl->getStorage()); auto anonymousInnerFieldDecl = findAnonymousInnerFieldDecl(importedFieldDecl, anonymousFieldDecl); expr = new (ctx) MemberRefExpr(expr, SourceLoc(), anonymousInnerFieldDecl, DeclNameLoc(), /*implicit*/ true); expr->setType(anonymousInnerFieldDecl->getInterfaceType()); auto *ret = ReturnStmt::createImplicit(ctx, expr); auto body = BraceStmt::create(ctx, SourceLoc(), ASTNode(ret), SourceLoc(), /*implicit*/ true); return {body, /*isTypeChecked=*/true}; } /// Synthesize the setter body for an indirect field. static std::pair synthesizeIndirectFieldSetterBody(AbstractFunctionDecl *afd, void *context) { auto setterDecl = cast(afd); auto anonymousFieldDecl = static_cast(context); ASTContext &ctx = setterDecl->getASTContext(); auto selfDecl = setterDecl->getImplicitSelfDecl(); Expr *lhs = new (ctx) DeclRefExpr(selfDecl, DeclNameLoc(), /*implicit*/ true); lhs->setType(LValueType::get(selfDecl->getInterfaceType())); lhs = new (ctx) MemberRefExpr(lhs, SourceLoc(), anonymousFieldDecl, DeclNameLoc(), /*implicit*/ true); lhs->setType(LValueType::get(anonymousFieldDecl->getInterfaceType())); auto importedFieldDecl = cast(setterDecl->getStorage()); auto anonymousInnerFieldDecl = findAnonymousInnerFieldDecl(importedFieldDecl, anonymousFieldDecl); lhs = new (ctx) MemberRefExpr(lhs, SourceLoc(), anonymousInnerFieldDecl, DeclNameLoc(), /*implicit*/ true); lhs->setType(LValueType::get(anonymousInnerFieldDecl->getInterfaceType())); auto newValueDecl = setterDecl->getParameters()->get(0); auto rhs = new (ctx) DeclRefExpr(newValueDecl, DeclNameLoc(), /*implicit*/ true); rhs->setType(newValueDecl->getInterfaceType()); auto assign = new (ctx) AssignExpr(lhs, SourceLoc(), rhs, /*implicit*/ true); assign->setType(TupleType::getEmpty(ctx)); auto body = BraceStmt::create(ctx, SourceLoc(), {assign}, SourceLoc(), /*implicit*/ true); return {body, /*isTypeChecked=*/true}; } std::pair SwiftDeclSynthesizer::makeIndirectFieldAccessors( const clang::IndirectFieldDecl *indirectField, ArrayRef members, NominalTypeDecl *importedStructDecl, VarDecl *importedFieldDecl) { auto &C = ImporterImpl.SwiftContext; auto getterDecl = makeFieldGetterDecl(ImporterImpl, importedStructDecl, importedFieldDecl); getterDecl->addAttribute(new (C) TransparentAttr(/*implicit*/ true)); auto setterDecl = makeFieldSetterDecl(ImporterImpl, importedStructDecl, importedFieldDecl); setterDecl->addAttribute(new (C) TransparentAttr(/*implicit*/ true)); ImporterImpl.makeComputed(importedFieldDecl, getterDecl, setterDecl); auto containingField = indirectField->chain().front(); VarDecl *anonymousFieldDecl = nullptr; // Reverse scan of the members because indirect field are generated just // after the corresponding anonymous type, so a reverse scan allows // switching from O(n) to O(1) here. for (auto decl : reverse(members)) { if (decl->getClangDecl() == containingField) { anonymousFieldDecl = cast(decl); break; } } assert(anonymousFieldDecl && "anonymous field not generated"); getterDecl->setBodySynthesizer(synthesizeIndirectFieldGetterBody, anonymousFieldDecl); setterDecl->setBodySynthesizer(synthesizeIndirectFieldSetterBody, anonymousFieldDecl); return {getterDecl, setterDecl}; } // MARK: Enum RawValue initializers /// Synthesize the body of \c init?(rawValue:RawType) for an imported enum. static std::pair synthesizeEnumRawValueConstructorBody(AbstractFunctionDecl *afd, void *context) { ASTContext &ctx = afd->getASTContext(); auto ctorDecl = cast(afd); auto enumDecl = static_cast(context); auto selfDecl = ctorDecl->getImplicitSelfDecl(); auto selfRef = new (ctx) DeclRefExpr(selfDecl, DeclNameLoc(), /*implicit*/ true); selfRef->setType(LValueType::get(selfDecl->getTypeInContext())); auto param = ctorDecl->getParameters()->get(0); auto paramRef = new (ctx) DeclRefExpr(param, DeclNameLoc(), /*implicit*/ true); paramRef->setType(param->getTypeInContext()); auto reinterpretCast = cast( getBuiltinValueDecl(ctx, ctx.getIdentifier("reinterpretCast"))); auto rawTy = enumDecl->getRawType(); auto enumTy = enumDecl->getDeclaredInterfaceType(); SubstitutionMap subMap = SubstitutionMap::get( reinterpretCast->getGenericSignature(), {rawTy, enumTy}, LookUpConformanceInModule()); ConcreteDeclRef concreteDeclRef(reinterpretCast, subMap); auto reinterpretCastRef = new (ctx) DeclRefExpr(concreteDeclRef, DeclNameLoc(), /*implicit*/ true); // FIXME: Verify ExtInfo state is correct, not working by accident. FunctionType::ExtInfo info; reinterpretCastRef->setType( FunctionType::get({FunctionType::Param(rawTy)}, enumTy, info)); auto *argList = ArgumentList::forImplicitUnlabeled(ctx, {paramRef}); auto reinterpreted = CallExpr::createImplicit(ctx, reinterpretCastRef, argList); reinterpreted->setType(enumTy); reinterpreted->setThrows(nullptr); auto assign = new (ctx) AssignExpr(selfRef, SourceLoc(), reinterpreted, /*implicit*/ true); assign->setType(TupleType::getEmpty(ctx)); auto *ret = ReturnStmt::createImplicit(ctx, /*expr*/ nullptr); auto body = BraceStmt::create(ctx, SourceLoc(), {assign, ret}, SourceLoc(), /*implicit*/ true); return {body, /*isTypeChecked=*/true}; } ConstructorDecl * SwiftDeclSynthesizer::makeEnumRawValueConstructor(EnumDecl *enumDecl) { ASTContext &C = ImporterImpl.SwiftContext; auto rawTy = enumDecl->getRawType(); auto param = new (C) ParamDecl(SourceLoc(), SourceLoc(), C.Id_rawValue, SourceLoc(), C.Id_rawValue, enumDecl); param->setSpecifier(ParamSpecifier::Default); param->setInterfaceType(rawTy); auto paramPL = ParameterList::createWithoutLoc(param); DeclName name(C, DeclBaseName::createConstructor(), paramPL); auto *ctorDecl = new (C) ConstructorDecl(name, enumDecl->getLoc(), /*Failable=*/true, /*FailabilityLoc=*/SourceLoc(), /*Async=*/false, /*AsyncLoc=*/SourceLoc(), /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*ThrownType=*/TypeLoc(), paramPL, /*GenericParams=*/nullptr, enumDecl); ctorDecl->setImplicit(); ctorDecl->copyFormalAccessFrom(enumDecl); ctorDecl->setBodySynthesizer(synthesizeEnumRawValueConstructorBody, enumDecl); return ctorDecl; } // MARK: Enum RawValue getters & setters /// Synthesizer callback for an enum's rawValue getter. static std::pair synthesizeEnumRawValueGetterBody(AbstractFunctionDecl *afd, void *context) { auto getterDecl = cast(afd); auto enumDecl = static_cast(context); auto rawTy = enumDecl->getRawType(); auto enumTy = enumDecl->getDeclaredInterfaceType(); ASTContext &ctx = getterDecl->getASTContext(); auto *selfDecl = getterDecl->getImplicitSelfDecl(); auto selfRef = new (ctx) DeclRefExpr(selfDecl, DeclNameLoc(), /*implicit*/ true); selfRef->setType(selfDecl->getTypeInContext()); auto reinterpretCast = cast( getBuiltinValueDecl(ctx, ctx.getIdentifier("reinterpretCast"))); SubstitutionMap subMap = SubstitutionMap::get( reinterpretCast->getGenericSignature(), {enumTy, rawTy}, LookUpConformanceInModule()); ConcreteDeclRef concreteDeclRef(reinterpretCast, subMap); auto reinterpretCastRef = new (ctx) DeclRefExpr(concreteDeclRef, DeclNameLoc(), /*implicit*/ true); // FIXME: Verify ExtInfo state is correct, not working by accident. FunctionType::ExtInfo info; reinterpretCastRef->setType( FunctionType::get({FunctionType::Param(enumTy)}, rawTy, info)); auto *argList = ArgumentList::forImplicitUnlabeled(ctx, {selfRef}); auto reinterpreted = CallExpr::createImplicit(ctx, reinterpretCastRef, argList); reinterpreted->setType(rawTy); reinterpreted->setThrows(nullptr); auto *ret = ReturnStmt::createImplicit(ctx, reinterpreted); auto body = BraceStmt::create(ctx, SourceLoc(), ASTNode(ret), SourceLoc(), /*implicit*/ true); return {body, /*isTypeChecked=*/true}; } // Build the rawValue getter for an imported NS_ENUM. // enum NSSomeEnum: RawType { // var rawValue: RawType { // return Builtin.reinterpretCast(self) // } // } // Unlike a standard init(rawValue:) enum initializer, this does a reinterpret // cast in order to preserve unknown or future cases from C. void SwiftDeclSynthesizer::makeEnumRawValueGetter(EnumDecl *enumDecl, VarDecl *rawValueDecl) { ASTContext &C = ImporterImpl.SwiftContext; auto rawTy = enumDecl->getRawType(); auto *params = ParameterList::createEmpty(C); auto getterDecl = AccessorDecl::create( C, /*declLoc=*/SourceLoc(), /*AccessorKeywordLoc=*/SourceLoc(), AccessorKind::Get, rawValueDecl, /*Async=*/false, /*AsyncLoc=*/SourceLoc(), /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*ThrownType=*/TypeLoc(), params, rawTy, enumDecl); getterDecl->setImplicit(); getterDecl->setIsObjC(false); getterDecl->setIsDynamic(false); getterDecl->setIsTransparent(false); getterDecl->copyFormalAccessFrom(enumDecl); getterDecl->setBodySynthesizer(synthesizeEnumRawValueGetterBody, enumDecl); ImporterImpl.makeComputed(rawValueDecl, getterDecl, nullptr); } // MARK: Struct RawValue getters /// Synthesizer for the rawValue getter for an imported struct. static std::pair synthesizeStructRawValueGetterBody(AbstractFunctionDecl *afd, void *context) { auto getterDecl = cast(afd); VarDecl *storedVar = static_cast(context); ASTContext &ctx = getterDecl->getASTContext(); auto *selfDecl = getterDecl->getImplicitSelfDecl(); auto selfRef = new (ctx) DeclRefExpr(selfDecl, DeclNameLoc(), /*implicit*/ true); selfRef->setType(selfDecl->getTypeInContext()); auto storedType = storedVar->getInterfaceType(); auto storedRef = new (ctx) MemberRefExpr(selfRef, SourceLoc(), storedVar, DeclNameLoc(), /*Implicit=*/true, AccessSemantics::DirectToStorage); storedRef->setType(storedType); Expr *result = storedRef; Type computedType = getterDecl->getResultInterfaceType(); if (!computedType->isEqual(storedType)) { auto bridge = new (ctx) BridgeFromObjCExpr(storedRef, computedType); bridge->setType(computedType); result = CoerceExpr::createImplicit(ctx, bridge, computedType); } auto ret = ReturnStmt::createImplicit(ctx, result); auto body = BraceStmt::create(ctx, SourceLoc(), ASTNode(ret), SourceLoc(), /*implicit*/ true); return {body, /*isTypeChecked=*/true}; } AccessorDecl *SwiftDeclSynthesizer::makeStructRawValueGetter( StructDecl *structDecl, VarDecl *computedVar, VarDecl *storedVar) { assert(storedVar->hasStorage()); ASTContext &C = ImporterImpl.SwiftContext; auto *params = ParameterList::createEmpty(C); auto computedType = computedVar->getInterfaceType(); auto getterDecl = AccessorDecl::create( C, /*declLoc=*/SourceLoc(), /*AccessorKeywordLoc=*/SourceLoc(), AccessorKind::Get, computedVar, /*Async=*/false, /*AsyncLoc=*/SourceLoc(), /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*ThrownType=*/TypeLoc(), params, computedType, structDecl); getterDecl->setImplicit(); getterDecl->setIsObjC(false); getterDecl->setIsDynamic(false); getterDecl->setIsTransparent(false); getterDecl->copyFormalAccessFrom(structDecl); getterDecl->setBodySynthesizer(synthesizeStructRawValueGetterBody, storedVar); return getterDecl; } // MARK: ObjC subscripts AccessorDecl *SwiftDeclSynthesizer::buildSubscriptGetterDecl( SubscriptDecl *subscript, const FuncDecl *getter, Type elementTy, DeclContext *dc, ParamDecl *index) { auto &C = ImporterImpl.SwiftContext; auto loc = getter->getLoc(); auto *params = ParameterList::create(C, index); // Create the getter thunk. auto thunk = AccessorDecl::create( C, /*declLoc=*/loc, /*AccessorKeywordLoc=*/SourceLoc(), AccessorKind::Get, subscript, /*Async=*/false, /*AsyncLoc=*/SourceLoc(), /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*ThrownType=*/TypeLoc(), params, elementTy, dc, getter->getClangNode()); thunk->setAccess(getOverridableAccessLevel(dc)); if (auto objcAttr = getter->getAttrs().getAttribute()) thunk->addAttribute(objcAttr->clone(C)); thunk->setIsObjC(getter->isObjC()); thunk->setIsDynamic(getter->isDynamic()); // FIXME: Should we record thunks? return thunk; } AccessorDecl *SwiftDeclSynthesizer::buildSubscriptSetterDecl( SubscriptDecl *subscript, const FuncDecl *setter, Type elementInterfaceTy, DeclContext *dc, ParamDecl *index) { auto &C = ImporterImpl.SwiftContext; auto loc = setter->getLoc(); // Objective-C subscript setters are imported with a function type // such as: // // (self) -> (value, index) -> () // // Build a setter thunk with the latter signature that maps to the // former. auto valueIndex = setter->getParameters(); auto paramVarDecl = new (C) ParamDecl(SourceLoc(), SourceLoc(), Identifier(), loc, valueIndex->get(0)->getName(), dc); paramVarDecl->setSpecifier(ParamSpecifier::Default); paramVarDecl->setInterfaceType(elementInterfaceTy); auto valueIndicesPL = ParameterList::create(C, {paramVarDecl, index}); // Create the setter thunk. auto thunk = AccessorDecl::create( C, /*declLoc=*/setter->getLoc(), /*AccessorKeywordLoc=*/SourceLoc(), AccessorKind::Set, subscript, /*Async=*/false, /*AsyncLoc=*/SourceLoc(), /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*ThrownType=*/TypeLoc(), valueIndicesPL, TupleType::getEmpty(C), dc, setter->getClangNode()); thunk->setAccess(getOverridableAccessLevel(dc)); if (auto objcAttr = setter->getAttrs().getAttribute()) thunk->addAttribute(objcAttr->clone(C)); thunk->setIsObjC(setter->isObjC()); thunk->setIsDynamic(setter->isDynamic()); return thunk; } // MARK: C++ subscripts Expr *SwiftDeclSynthesizer::synthesizeReturnReinterpretCast(ASTContext &ctx, Type givenType, Type exprType, Expr *baseExpr) { auto reinterpretCast = cast( getBuiltinValueDecl(ctx, ctx.getIdentifier("reinterpretCast"))); SubstitutionMap subMap = SubstitutionMap::get( reinterpretCast->getGenericSignature(), {givenType, exprType}, LookUpConformanceInModule()); ConcreteDeclRef concreteDeclRef(reinterpretCast, subMap); auto reinterpretCastRef = new (ctx) DeclRefExpr(concreteDeclRef, DeclNameLoc(), /*implicit*/ true); FunctionType::ExtInfo info; reinterpretCastRef->setType( FunctionType::get({FunctionType::Param(givenType)}, exprType, info)); auto *argList = ArgumentList::forImplicitUnlabeled(ctx, {baseExpr}); auto reinterpreted = CallExpr::createImplicit(ctx, reinterpretCastRef, argList); reinterpreted->setType(exprType); reinterpreted->setThrows(nullptr); return reinterpreted; } /// Synthesizer callback for a subscript getter or a getter for a /// dereference property (`var pointee`). If the getter's implementation returns /// an UnsafePointer or UnsafeMutablePointer, it unwraps the pointer and returns /// the underlying value. static std::pair synthesizeUnwrappingGetterOrAddressGetterBody(AbstractFunctionDecl *afd, void *context, bool isAddress) { auto getterDecl = cast(afd); auto getterImpl = static_cast(context); ASTContext &ctx = getterDecl->getASTContext(); auto selfArg = createSelfArg(getterDecl); SmallVector arguments; for (size_t idx = 0, end = getterDecl->getParameters()->size(); idx < end; ++idx) arguments.push_back(createParamRefExpr(getterDecl, idx)); Type elementTy = getterDecl->getResultInterfaceType(); auto *getterImplCallExpr = createAccessorImplCallExpr(getterImpl, selfArg, arguments); // This default handles C++'s operator[] that returns a value type. Expr *propertyExpr = getterImplCallExpr; PointerTypeKind ptrKind; // The following check returns true if the subscript operator returns a // C++ reference type. This check actually checks to see if the type is // a pointer type, but this does not apply to C pointers because they // are Optional types when imported. TODO: Use a more obvious check // here. if (!isAddress && getterImpl->getResultInterfaceType()->getAnyPointerElementType(ptrKind)) { // `getterImpl` can return either UnsafePointer or // UnsafeMutablePointer. Retrieve the corresponding `.pointee` // declaration. VarDecl *pointeePropertyDecl = ctx.getPointerPointeePropertyDecl(ptrKind); // Handle operator[] that returns a reference type. SubstitutionMap subMap = SubstitutionMap::get(ctx.getUnsafePointerDecl()->getGenericSignature(), {elementTy}, LookUpConformanceInModule()); auto pointeePropertyRefExpr = new (ctx) MemberRefExpr( getterImplCallExpr, SourceLoc(), ConcreteDeclRef(pointeePropertyDecl, subMap), DeclNameLoc(), /*implicit*/ true); pointeePropertyRefExpr->setType(elementTy); propertyExpr = pointeePropertyRefExpr; } // Cast an 'address' result from a mutable pointer if needed. if (isAddress && getterImpl->getResultInterfaceType()->isUnsafeMutablePointer()) propertyExpr = SwiftDeclSynthesizer::synthesizeReturnReinterpretCast( ctx, getterImpl->getResultInterfaceType(), elementTy, propertyExpr); auto *returnStmt = ReturnStmt::createImplicit(ctx, propertyExpr); auto body = BraceStmt::create(ctx, SourceLoc(), {returnStmt}, SourceLoc(), /*implicit*/ true); return {body, /*isTypeChecked*/ true}; } static std::pair synthesizeUnwrappingGetterBody(AbstractFunctionDecl *afd, void *context) { return synthesizeUnwrappingGetterOrAddressGetterBody(afd, context, /*isAddress=*/false); } static std::pair synthesizeUnwrappingAddressGetterBody(AbstractFunctionDecl *afd, void *context) { return synthesizeUnwrappingGetterOrAddressGetterBody(afd, context, /*isAddress=*/true); } /// Synthesizer callback for a subscript setter or a setter for a dereference /// property (`var pointee`). static std::pair synthesizeUnwrappingSetterBody(AbstractFunctionDecl *afd, void *context) { auto setterDecl = cast(afd); auto setterImpl = static_cast(context); ASTContext &ctx = setterDecl->getASTContext(); auto selfArg = createSelfArg(setterDecl); DeclRefExpr *valueParamRefExpr = createParamRefExpr(setterDecl, 0); SmallVector arguments; for (size_t idx = 1, end = setterDecl->getParameters()->size(); idx < end; ++idx) arguments.push_back(createParamRefExpr(setterDecl, idx)); Type elementTy = valueParamRefExpr->getDecl()->getInterfaceType(); auto *setterImplCallExpr = createAccessorImplCallExpr(setterImpl, selfArg, arguments); VarDecl *pointeePropertyDecl = ctx.getPointerPointeePropertyDecl(PTK_UnsafeMutablePointer); SubstitutionMap subMap = SubstitutionMap::get( ctx.getUnsafeMutablePointerDecl()->getGenericSignature(), {elementTy}, LookUpConformanceInModule()); auto pointeePropertyRefExpr = new (ctx) MemberRefExpr(setterImplCallExpr, SourceLoc(), ConcreteDeclRef(pointeePropertyDecl, subMap), DeclNameLoc(), /*implicit*/ true); pointeePropertyRefExpr->setType(LValueType::get(elementTy)); auto assignExpr = new (ctx) AssignExpr(pointeePropertyRefExpr, SourceLoc(), valueParamRefExpr, /*implicit*/ true); assignExpr->setType(TupleType::getEmpty(ctx)); auto body = BraceStmt::create(ctx, SourceLoc(), { assignExpr, }, SourceLoc()); return {body, /*isTypeChecked*/ true}; } static std::pair synthesizeUnwrappingAddressSetterBody(AbstractFunctionDecl *afd, void *context) { auto setterDecl = cast(afd); auto setterImpl = static_cast(context); ASTContext &ctx = setterDecl->getASTContext(); auto selfArg = createSelfArg(setterDecl); auto *setterImplCallExpr = createAccessorImplCallExpr(setterImpl, selfArg, {}); auto *returnStmt = ReturnStmt::createImplicit(ctx, setterImplCallExpr); auto body = BraceStmt::create(ctx, SourceLoc(), {returnStmt}, SourceLoc(), /*implicit*/ true); return {body, /*isTypeChecked*/ true}; } SubscriptDecl *SwiftDeclSynthesizer::makeSubscript(FuncDecl *getter, FuncDecl *setter) { assert((getter || setter) && "getter or setter required to generate subscript"); // If only a setter (imported from non-const `operator[]`) is defined, // generate both get & set accessors from it. FuncDecl *getterImpl = getter ? getter : setter; FuncDecl *setterImpl = setter; // FIXME: support unsafeAddress accessors. // Get the return type wrapped in `Unsafe(Mutable)Pointer`. const auto rawElementTy = getterImpl->getResultInterfaceType(); // Unwrap `T`. Use rawElementTy for return by value. const auto elementTy = rawElementTy->getAnyPointerElementType() ? rawElementTy->getAnyPointerElementType() : rawElementTy; auto &ctx = ImporterImpl.SwiftContext; SmallVector paramVec; for (auto [i, param] : llvm::enumerate(*getterImpl->getParameters())) { auto clonedParam = ParamDecl::clone(ctx, param); // If the subscript parameter is unnamed, give it a name to make sure SILGen // creates a variable for it. if (clonedParam->getName().empty()) clonedParam->setName(ctx.getIdentifier("__index" + std::to_string(i))); paramVec.push_back(clonedParam); } auto bodyParams = ParameterList::create(ctx, paramVec); DeclName name(ctx, DeclBaseName::createSubscript(), bodyParams); auto dc = getterImpl->getDeclContext(); SubscriptDecl *subscript = SubscriptDecl::createImported( ctx, name, getterImpl->getLoc(), bodyParams, getterImpl->getLoc(), elementTy, dc, getterImpl->getGenericParams(), getterImpl->getClangNode()); subscript->copyFormalAccessFrom(getterImpl); AccessorDecl *getterDecl = AccessorDecl::create(ctx, getterImpl->getLoc(), getterImpl->getLoc(), AccessorKind::Get, subscript, /*async*/ false, SourceLoc(), /*throws*/ false, SourceLoc(), /*ThrownType=*/TypeLoc(), bodyParams, elementTy, dc); getterDecl->copyFormalAccessFrom(subscript); getterDecl->setImplicit(); getterDecl->setIsDynamic(false); getterDecl->setIsTransparent(true); getterDecl->setBodySynthesizer(synthesizeUnwrappingGetterBody, getterImpl); if (getterImpl->isMutating()) { getterDecl->setSelfAccessKind(SelfAccessKind::Mutating); subscript->setIsGetterMutating(true); } AccessorDecl *setterDecl = nullptr; if (setterImpl) { auto paramVarDecl = new (ctx) ParamDecl(SourceLoc(), SourceLoc(), Identifier(), SourceLoc(), ctx.getIdentifier("newValue"), dc); paramVarDecl->setSpecifier(ParamSpecifier::Default); paramVarDecl->setInterfaceType(elementTy); SmallVector setterParams; setterParams.push_back(paramVarDecl); setterParams.append(bodyParams->begin(), bodyParams->end()); auto setterParamList = ParameterList::create(ctx, setterParams); setterDecl = AccessorDecl::create( ctx, setterImpl->getLoc(), setterImpl->getLoc(), AccessorKind::Set, subscript, /*async*/ false, SourceLoc(), /*throws*/ false, SourceLoc(), /*ThrownType=*/TypeLoc(), setterParamList, TupleType::getEmpty(ctx), dc); setterDecl->copyFormalAccessFrom(subscript); setterDecl->setImplicit(); setterDecl->setIsDynamic(false); setterDecl->setIsTransparent(true); setterDecl->setBodySynthesizer(synthesizeUnwrappingSetterBody, setterImpl); if (setterImpl->isMutating()) { setterDecl->setSelfAccessKind(SelfAccessKind::Mutating); subscript->setIsSetterMutating(true); } } ImporterImpl.makeComputed(subscript, getterDecl, setterDecl); // Implicitly unwrap Optional types for T *operator[]. ImporterImpl.recordImplicitUnwrapForDecl( subscript, getterImpl->isImplicitlyUnwrappedOptional()); return subscript; } // MARK: C++ dereference operator VarDecl * SwiftDeclSynthesizer::makeDereferencedPointeeProperty(FuncDecl *getter, FuncDecl *setter) { assert((getter || setter) && "getter or setter required to generate a pointee property"); auto &ctx = ImporterImpl.SwiftContext; FuncDecl *getterImpl = getter ? getter : setter; FuncDecl *setterImpl = setter; auto dc = getterImpl->getDeclContext(); bool resultDependsOnSelf = ImporterImpl.returnsSelfDependentValue.contains(getterImpl); // Get the return type wrapped in `Unsafe(Mutable)Pointer`. const auto rawElementTy = getterImpl->getResultInterfaceType(); // Unwrap `T`. Use rawElementTy for return by value. const auto elementTy = rawElementTy->getAnyPointerElementType() ? rawElementTy->getAnyPointerElementType() : rawElementTy; // Use 'address' or 'mutableAddress' accessors for non-copyable // types that are returned indirectly. bool isNoncopyable = dc->mapTypeIntoEnvironment(elementTy)->isNoncopyable(); bool isImplicit = !(isNoncopyable || resultDependsOnSelf); bool useAddress = rawElementTy->getAnyPointerElementType() && (isNoncopyable || resultDependsOnSelf); auto result = new (ctx) VarDecl(/*isStatic*/ false, VarDecl::Introducer::Var, getterImpl->getStartLoc(), ctx.getIdentifier("pointee"), dc); result->setInterfaceType(elementTy); result->copyFormalAccessFrom(getterImpl); AccessorDecl *getterDecl = AccessorDecl::create( ctx, getterImpl->getLoc(), getterImpl->getLoc(), useAddress ? AccessorKind::Address : AccessorKind::Get, result, /*async*/ false, SourceLoc(), /*throws*/ false, SourceLoc(), /*ThrownType=*/TypeLoc(), ParameterList::createEmpty(ctx), useAddress ? elementTy->wrapInPointer(PTK_UnsafePointer) : elementTy, dc); getterDecl->copyFormalAccessFrom(getterImpl); if (isImplicit) getterDecl->setImplicit(); getterDecl->setIsDynamic(false); getterDecl->setIsTransparent(true); getterDecl->setBodySynthesizer(useAddress ? synthesizeUnwrappingAddressGetterBody : synthesizeUnwrappingGetterBody, getterImpl); if (getterImpl->isMutating()) { getterDecl->setSelfAccessKind(SelfAccessKind::Mutating); result->setIsGetterMutating(true); } else { getterDecl->setSelfAccessKind(SelfAccessKind::NonMutating); result->setIsGetterMutating(false); } AccessorDecl *setterDecl = nullptr; if (setterImpl) { auto paramVarDecl = new (ctx) ParamDecl(SourceLoc(), SourceLoc(), Identifier(), SourceLoc(), ctx.getIdentifier("newValue"), dc); paramVarDecl->setSpecifier(ParamSpecifier::Default); paramVarDecl->setInterfaceType(elementTy); auto setterParamList = useAddress ? ParameterList::create(ctx, {}) : ParameterList::create(ctx, {paramVarDecl}); setterDecl = AccessorDecl::create( ctx, setterImpl->getLoc(), setterImpl->getLoc(), useAddress ? AccessorKind::MutableAddress : AccessorKind::Set, result, /*async*/ false, SourceLoc(), /*throws*/ false, SourceLoc(), /*ThrownType=*/TypeLoc(), setterParamList, useAddress ? elementTy->wrapInPointer(PTK_UnsafeMutablePointer) : TupleType::getEmpty(ctx), dc); setterDecl->copyFormalAccessFrom(setterImpl); if (isImplicit) setterDecl->setImplicit(); setterDecl->setIsDynamic(false); setterDecl->setIsTransparent(true); setterDecl->setBodySynthesizer(useAddress ? synthesizeUnwrappingAddressSetterBody : synthesizeUnwrappingSetterBody, setterImpl); if (setterImpl->isMutating()) { setterDecl->setSelfAccessKind(SelfAccessKind::Mutating); result->setIsSetterMutating(true); } else { setterDecl->setSelfAccessKind(SelfAccessKind::NonMutating); result->setIsSetterMutating(false); } } ImporterImpl.makeComputed(result, getterDecl, setterDecl); return result; } // MARK: C++ increment operator /// Synthesizer callback for a successor function. /// /// \code /// var __copy: Self /// __copy = self /// __copy.__operatorPlusPlus() /// return __copy /// \endcode static std::pair synthesizeSuccessorFuncBody(AbstractFunctionDecl *afd, void *context) { auto successorDecl = cast(afd); auto incrementImpl = static_cast(context); ASTContext &ctx = successorDecl->getASTContext(); auto emptyTupleTy = TupleType::getEmpty(ctx); auto returnTy = successorDecl->getResultInterfaceType(); auto selfDecl = successorDecl->getImplicitSelfDecl(); auto selfRefExpr = new (ctx) DeclRefExpr(selfDecl, DeclNameLoc(), /*implicit*/ true); selfRefExpr->setType(selfDecl->getInterfaceType()); // Create a `__copy` variable. VarDecl *copyDecl = nullptr; PatternBindingDecl *patternDecl = nullptr; std::tie(copyDecl, patternDecl) = SwiftDeclSynthesizer::createVarWithPattern( successorDecl, ctx.getIdentifier("__copy"), returnTy, VarDecl::Introducer::Var, /*isImplicit*/ true, successorDecl->getFormalAccess(), successorDecl->getFormalAccess()); auto copyRefLValueExpr = new (ctx) DeclRefExpr(copyDecl, DeclNameLoc(), /*implicit*/ true); copyRefLValueExpr->setType(LValueType::get(copyDecl->getInterfaceType())); // Copy `self` to `__copy`. auto copyAssignExpr = new (ctx) AssignExpr(copyRefLValueExpr, SourceLoc(), selfRefExpr, /*implicit*/ true); copyAssignExpr->setType(emptyTupleTy); // Call `operator++`. auto incrementExpr = createAccessorImplCallExpr( incrementImpl, Argument::implicitInOut(ctx, copyRefLValueExpr), {}); auto copyRefRValueExpr = new (ctx) DeclRefExpr(copyDecl, DeclNameLoc(), /*implicit*/ true); copyRefRValueExpr->setType(copyDecl->getInterfaceType()); auto *returnStmt = ReturnStmt::createImplicit(ctx, copyRefRValueExpr); auto body = BraceStmt::create(ctx, SourceLoc(), { copyDecl, patternDecl, copyAssignExpr, incrementExpr, returnStmt, }, SourceLoc()); return {body, /*isTypeChecked*/ true}; } FuncDecl *SwiftDeclSynthesizer::makeSuccessorFunc(FuncDecl *incrementFunc) { auto &ctx = ImporterImpl.SwiftContext; auto dc = incrementFunc->getDeclContext(); auto returnTy = incrementFunc->getImplicitSelfDecl()->getInterfaceType(); auto nameId = ctx.getIdentifier("successor"); auto *params = ParameterList::createEmpty(ctx); DeclName name(ctx, DeclBaseName(nameId), params); auto result = FuncDecl::createImplicit( ctx, StaticSpellingKind::None, name, SourceLoc(), /*Async*/ false, /*Throws*/ false, /*ThrownType=*/Type(), /*GenericParams*/ nullptr, params, returnTy, dc); result->copyFormalAccessFrom(incrementFunc); result->setIsDynamic(false); result->setBodySynthesizer(synthesizeSuccessorFuncBody, incrementFunc); return result; } // MARK: C++ arithmetic operators static std::pair synthesizeOperatorMethodBody(AbstractFunctionDecl *afd, void *context) { ASTContext &ctx = afd->getASTContext(); auto funcDecl = cast(afd); auto methodDecl = static_cast(context); /* Swift version of CXXMethod */ SmallVector forwardingArgs; // We start from +1 since the first param is our lhs. All other params are // forwarded for (auto itr = funcDecl->getParameters()->begin() + 1; itr != funcDecl->getParameters()->end(); itr++) { auto param = *itr; auto isInOut = param->isInOut(); auto paramTy = param->getTypeInContext(); Expr *paramRefExpr = new (ctx) DeclRefExpr(param, DeclNameLoc(), /*Implicit*/ true); paramRefExpr->setType(isInOut ? LValueType::get(paramTy) : paramTy); auto arg = isInOut ? Argument::implicitInOut(ctx, paramRefExpr) : Argument::unlabeled(paramRefExpr); forwardingArgs.push_back(arg); } auto methodExpr = new (ctx) DeclRefExpr(methodDecl, DeclNameLoc(), /*implicit*/ true); methodExpr->setType(methodDecl->getInterfaceType()); // Lhs parameter auto baseParam = funcDecl->getParameters()->front(); auto baseParamTy = baseParam->getTypeInContext(); auto baseIsInOut = baseParam->isInOut(); Expr *baseExpr = new (ctx) DeclRefExpr(baseParam, DeclNameLoc(), /*implicit*/ true); baseExpr->setType(baseIsInOut ? LValueType::get(baseParamTy) : baseParamTy); auto baseArg = baseIsInOut ? Argument::implicitInOut(ctx, baseExpr) : Argument::unlabeled(baseExpr); auto dotCallExpr = DotSyntaxCallExpr::create(ctx, methodExpr, SourceLoc(), baseArg); dotCallExpr->setType(methodDecl->getMethodInterfaceType()); dotCallExpr->setThrows(nullptr); auto *argList = ArgumentList::createImplicit(ctx, forwardingArgs); auto callExpr = CallExpr::createImplicit(ctx, dotCallExpr, argList); callExpr->setType(funcDecl->getResultInterfaceType()); callExpr->setThrows(nullptr); auto *returnStmt = ReturnStmt::createImplicit(ctx, callExpr); auto body = BraceStmt::create(ctx, SourceLoc(), {returnStmt}, SourceLoc(), /*implicit*/ true); return {body, /*isTypeChecked*/ true}; } clang::CXXMethodDecl *SwiftDeclSynthesizer::synthesizeCXXForwardingMethod( const clang::CXXRecordDecl *derivedClass, const clang::CXXRecordDecl *baseClass, const clang::CXXMethodDecl *method, ForwardingMethodKind forwardingMethodKind, ReferenceReturnTypeBehaviorForBaseMethodSynthesis referenceReturnTypeBehavior, bool forceConstQualifier) { auto &clangCtx = ImporterImpl.getClangASTContext(); auto &clangSema = ImporterImpl.getClangSema(); assert(!method->isStatic() || method->getNameInfo().getName().getCXXOverloadedOperator() == clang::OO_Call); // Create a new method in the derived class that calls the base method. clang::DeclarationName name = method->getNameInfo().getName(); std::string newName; llvm::raw_string_ostream os(newName); bool useExistingName = false; if (name.isIdentifier()) { os << (forwardingMethodKind == ForwardingMethodKind::Virtual ? "__synthesizedVirtualCall_" : "__synthesizedBaseCall_") << name.getAsIdentifierInfo()->getName(); } else { switch (auto op = name.getCXXOverloadedOperator()) { case clang::OO_Subscript: os << (forwardingMethodKind == ForwardingMethodKind::Virtual ? "__synthesizedVirtualCall_operatorSubscript" : "__synthesizedBaseCall_operatorSubscript"); if (forceConstQualifier) os << "C"; break; case clang::OO_Star: os << (forwardingMethodKind == ForwardingMethodKind::Virtual ? "__synthesizedVirtualCall_operatorStar" : "__synthesizedBaseCall_operatorStar"); if (forceConstQualifier) os << "C"; break; case clang::OO_Call: assert(forwardingMethodKind != ForwardingMethodKind::Virtual); os << "__synthesizedBaseCall_operatorCall"; if (forceConstQualifier) os << "C"; break; case clang::OO_Plus: case clang::OO_Minus: case clang::OO_Slash: case clang::OO_PlusEqual: case clang::OO_MinusEqual: case clang::OO_StarEqual: case clang::OO_SlashEqual: case clang::OO_Percent: case clang::OO_Caret: case clang::OO_Amp: case clang::OO_Pipe: case clang::OO_Tilde: case clang::OO_Exclaim: case clang::OO_Less: case clang::OO_Greater: case clang::OO_LessLess: case clang::OO_GreaterGreater: case clang::OO_EqualEqual: case clang::OO_PlusPlus: case clang::OO_ExclaimEqual: case clang::OO_LessEqual: case clang::OO_GreaterEqual: case clang::OO_AmpAmp: case clang::OO_PipePipe: os << importer::getOperatorName(ImporterImpl.SwiftContext, op).str(); break; default: useExistingName = true; break; } } if (!useExistingName) { // The created method is inside the derived class already. If that's // different from the base class, also include the base class in the // mangling to keep this separate from other similar functions cloned from // other base classes. if (derivedClass != baseClass) { os << "_"; std::unique_ptr mangler{ clang::ItaniumMangleContext::create(clangCtx, clangCtx.getDiagnostics())}; auto derivedType = clangCtx.getTypeDeclType(baseClass) .getCanonicalType(); mangler->mangleCanonicalTypeName(derivedType, os); } name = clang::DeclarationName( &ImporterImpl.getClangPreprocessor().getIdentifierTable().get( os.str())); } auto methodType = method->getType(); // Check if we need to drop the reference from the return type // of the new method. This is needed when a synthesized `operator []` // derived-to-base call is invoked from Swift's subscript getter. if (referenceReturnTypeBehavior != ReferenceReturnTypeBehaviorForBaseMethodSynthesis::KeepReference) { if (const auto *fpt = methodType->getAs()) { auto retType = fpt->getReturnType(); if (retType->isReferenceType() && (referenceReturnTypeBehavior == ReferenceReturnTypeBehaviorForBaseMethodSynthesis:: RemoveReference || (referenceReturnTypeBehavior == ReferenceReturnTypeBehaviorForBaseMethodSynthesis:: RemoveReferenceIfPointer && retType->getPointeeType()->isPointerType()))) { methodType = clangCtx.getFunctionType(retType->getPointeeType(), fpt->getParamTypes(), fpt->getExtProtoInfo()); } } } // Check if this method requires an additional `const` qualifier. // This might needed when a non-const synthesized `operator []` // derived-to-base call is invoked from Swift's subscript getter. bool castThisToNonConstThis = false; if (forceConstQualifier) { if (const auto *fpt = methodType->getAs()) { auto info = fpt->getExtProtoInfo(); if (!info.TypeQuals.hasConst()) { info.TypeQuals.addConst(); castThisToNonConstThis = true; methodType = clangCtx.getFunctionType(fpt->getReturnType(), fpt->getParamTypes(), info); } } } auto newMethod = clang::CXXMethodDecl::Create( clangCtx, const_cast(derivedClass), method->getSourceRange().getBegin(), clang::DeclarationNameInfo(name, clang::SourceLocation()), methodType, method->getTypeSourceInfo(), method->isStatic() ? clang::SC_None : method->getStorageClass(), method->UsesFPIntrin(), /*isInline=*/true, method->getConstexprKind(), method->getSourceRange().getEnd()); newMethod->setImplicit(); newMethod->setImplicitlyInline(); newMethod->setAccess(clang::AccessSpecifier::AS_public); newMethod->addAttr(clang::NoDebugAttr::CreateImplicit(clangCtx)); if (method->hasAttr()) { // Return an FRT field at +1 if the base method also follows this // convention. newMethod->addAttr(clang::CFReturnsRetainedAttr::CreateImplicit(clangCtx)); } if (auto swiftNameAttr = method->getAttr()) newMethod->addAttr(swiftNameAttr->clone(clangCtx)); llvm::SmallVector params; for (size_t i = 0; i < method->getNumParams(); ++i) { const auto ¶m = *method->getParamDecl(i); params.push_back(clang::ParmVarDecl::Create( clangCtx, newMethod, param.getSourceRange().getBegin(), param.getLocation(), param.getIdentifier(), param.getType(), param.getTypeSourceInfo(), param.getStorageClass(), /*DefExpr=*/nullptr)); } newMethod->setParams(params); clang::Sema::SynthesizedFunctionScope scope(clangSema, newMethod); // Create a new Clang diagnostic pool to capture any diagnostics // emitted during the construction of the method. clang::sema::DelayedDiagnosticPool diagPool{ clangSema.DelayedDiagnostics.getCurrentPool()}; auto diagState = clangSema.DelayedDiagnostics.push(diagPool); // Construct the method's body. clang::Expr *thisExpr = clang::CXXThisExpr::Create( clangCtx, clang::SourceLocation(), newMethod->getThisType(), /*IsImplicit=*/false); if (castThisToNonConstThis) { auto baseClassPtr = clangCtx.getPointerType(clangCtx.getRecordType(derivedClass)); clang::CastKind Kind; clang::CXXCastPath Path; clangSema.CheckPointerConversion(thisExpr, baseClassPtr, Kind, Path, /*IgnoreBaseAccess=*/false, /*Diagnose=*/true); auto conv = clangSema.ImpCastExprToType(thisExpr, baseClassPtr, Kind, clang::VK_PRValue, &Path); if (!conv.isUsable()) return nullptr; thisExpr = conv.get(); } auto memberExprTy = (method->isStatic() && method->getOverloadedOperator() == clang::OverloadedOperatorKind::OO_Call) ? method->getType() : clangCtx.BoundMemberTy; auto memberExpr = clangSema.BuildMemberExpr( thisExpr, /*isArrow=*/true, clang::SourceLocation(), clang::NestedNameSpecifierLoc(), clang::SourceLocation(), const_cast(method), clang::DeclAccessPair::make(const_cast(method), clang::AS_public), /*HadMultipleCandidates=*/false, method->getNameInfo(), memberExprTy, clang::VK_PRValue, clang::OK_Ordinary); llvm::SmallVector args; for (size_t i = 0; i < newMethod->getNumParams(); ++i) { auto *param = newMethod->getParamDecl(i); auto type = param->getType(); clang::Expr *argExpr = new (clangCtx) clang::DeclRefExpr( clangCtx, param, false, type.getNonReferenceType(), clang::ExprValueKind::VK_LValue, clang::SourceLocation()); if (type->isRValueReferenceType()) { argExpr = clangSema .BuildCXXNamedCast( clang::SourceLocation(), clang::tok::kw_static_cast, clangCtx.getTrivialTypeSourceInfo(type), argExpr, clang::SourceRange(), clang::SourceRange()) .get(); } args.push_back(argExpr); } auto memberCall = clangSema.BuildCallExpr( nullptr, memberExpr, clang::SourceLocation(), args, clang::SourceLocation()); if (!memberCall.isUsable()) return nullptr; auto returnStmt = clangSema.BuildReturnStmt(clang::SourceLocation(), memberCall.get()) .get(); // Check if there were any Clang errors during the construction // of the method body. clangSema.DelayedDiagnostics.popWithoutEmitting(diagState); if (!diagPool.empty()) return nullptr; newMethod->setBody(returnStmt); return newMethod; } FuncDecl * SwiftDeclSynthesizer::makeOperator(FuncDecl *operatorMethod, clang::OverloadedOperatorKind opKind) { assert(opKind != clang::OverloadedOperatorKind::OO_None && "expected a C++ operator"); auto &ctx = ImporterImpl.SwiftContext; auto opName = clang::getOperatorSpelling(opKind); auto paramList = operatorMethod->getParameters(); auto genericParamList = operatorMethod->getGenericParams(); auto opId = ctx.getIdentifier(opName); auto parentCtx = operatorMethod->getDeclContext(); auto lhsParam = new (ctx) ParamDecl(SourceLoc(), SourceLoc(), Identifier(), SourceLoc(), ctx.getIdentifier("lhs"), parentCtx); lhsParam->setInterfaceType( operatorMethod->getDeclContext()->getSelfInterfaceType()); if (operatorMethod->isMutating()) { // This implicitly makes the parameter indirect. lhsParam->setSpecifier(ParamSpecifier::InOut); } else { lhsParam->setSpecifier(ParamSpecifier::Default); } SmallVector newParams; newParams.push_back(lhsParam); for (auto param : *paramList) { auto clonedParam = ParamDecl::clone(ctx, param); if (clonedParam->getParameterName().empty()) { clonedParam->setName(ctx.getIdentifier("other")); } newParams.push_back(clonedParam); } auto oldArgNames = operatorMethod->getName().getArgumentNames(); SmallVector newArgNames; newArgNames.push_back(Identifier()); for (auto id : oldArgNames) { newArgNames.push_back(id); } auto opDeclName = DeclName(ctx, opId, {newArgNames.begin(), newArgNames.end()}); auto topLevelStaticFuncDecl = FuncDecl::createImplicit( ctx, StaticSpellingKind::None, opDeclName, SourceLoc(), /*Async*/ false, /*Throws*/ false, /*ThrownType=*/Type(), genericParamList, ParameterList::create(ctx, newParams), operatorMethod->getResultInterfaceType(), parentCtx); topLevelStaticFuncDecl->copyFormalAccessFrom(operatorMethod); topLevelStaticFuncDecl->setIsDynamic(false); topLevelStaticFuncDecl->setStatic(); topLevelStaticFuncDecl->setBodySynthesizer(synthesizeOperatorMethodBody, operatorMethod); // If this is a unary prefix operator (e.g. `!`), add a `prefix` attribute. size_t numParams = operatorMethod->getParameters()->size(); if (numParams == 0 || (operatorMethod->isStatic() && numParams == 1)) { topLevelStaticFuncDecl->addAttribute(new (ctx) PrefixAttr(SourceLoc())); } return topLevelStaticFuncDecl; } // MARK: C++ virtual methods FuncDecl *SwiftDeclSynthesizer::makeVirtualMethod( const clang::CXXMethodDecl *clangMethodDecl, StringRef swiftName) { auto clangDC = clangMethodDecl->getParent(); auto &ctx = ImporterImpl.SwiftContext; assert(!clangMethodDecl->isStatic() && "C++ virtual functions cannot be static"); auto newMethod = synthesizeCXXForwardingMethod( clangDC, clangDC, clangMethodDecl, ForwardingMethodKind::Virtual, ReferenceReturnTypeBehaviorForBaseMethodSynthesis::KeepReference, /*forceConstQualifier*/ false); // If the override has a swift_name different from the base // method, we ignore the swift_name attribute and instead use the base method's name. // In this case, swiftName holds the correct derived method name obtained through NameImporter if (clangMethodDecl->size_overridden_methods() > 0) { if (auto oldSwiftNameAttr = newMethod->getAttr()) { auto oldSwiftName = oldSwiftNameAttr->getName(); if (swiftName != oldSwiftName) { ImporterImpl.diagnose(HeaderLoc(oldSwiftNameAttr->getLoc()), diag::swift_name_attr_ignored, oldSwiftName); oldSwiftNameAttr->setName(newMethod->getASTContext(), swiftName); } } else { newMethod->addAttr(clang::SwiftNameAttr::CreateImplicit( newMethod->getASTContext(), swiftName)); } } auto result = dyn_cast_or_null( ctx.getClangModuleLoader()->importDeclDirectly(newMethod)); return result; } // MARK: C++ operators FuncDecl *SwiftDeclSynthesizer::makeInstanceToStaticOperatorCallMethod( const clang::CXXMethodDecl *clangMethodDecl) { auto clangDC = clangMethodDecl->getParent(); auto &ctx = ImporterImpl.SwiftContext; assert(clangMethodDecl->isStatic() && "Expected a static operator"); auto newMethod = synthesizeCXXForwardingMethod( clangDC, clangDC, clangMethodDecl, ForwardingMethodKind::Base, ReferenceReturnTypeBehaviorForBaseMethodSynthesis::KeepReference, /*forceConstQualifier*/ true); newMethod->addAttr(clang::SwiftNameAttr::CreateImplicit( clangMethodDecl->getASTContext(), "callAsFunction")); auto result = dyn_cast_or_null( ctx.getClangModuleLoader()->importDeclDirectly(newMethod)); return result; } // MARK: C++ properties static std::pair synthesizeComputedGetterFromCXXMethod(AbstractFunctionDecl *afd, void *context) { auto accessor = cast(afd); auto method = static_cast(context); auto selfArg = createSelfArg(accessor); auto *getterImplCallExpr = createAccessorImplCallExpr(method, selfArg, {}); auto &ctx = method->getASTContext(); auto *returnStmt = ReturnStmt::createImplicit(ctx, getterImplCallExpr); auto *body = BraceStmt::create(ctx, SourceLoc(), {returnStmt}, SourceLoc()); return {body, /*isTypeChecked*/ true}; } static std::pair synthesizeComputedSetterFromCXXMethod(AbstractFunctionDecl *afd, void *context) { auto setterDecl = cast(afd); auto setterImpl = static_cast(context); auto selfArg = createSelfArg(setterDecl); DeclRefExpr *valueParamRefExpr = createParamRefExpr(setterDecl, 0); auto *getterImplCallExpr = createAccessorImplCallExpr(setterImpl, selfArg, {valueParamRefExpr}); auto body = BraceStmt::create(setterImpl->getASTContext(), SourceLoc(), {getterImplCallExpr}, SourceLoc()); return {body, /*isTypeChecked*/ true}; } VarDecl * SwiftDeclSynthesizer::makeComputedPropertyFromCXXMethods(FuncDecl *getter, FuncDecl *setter) { auto &ctx = ImporterImpl.SwiftContext; auto dc = getter->getDeclContext(); assert(isa(getter->getClangDecl()) && (!setter || isa(setter->getClangDecl())) && "Functions passed to makeProperty must be imported C++ method decls."); CXXMethodBridging bridgingInfo( cast(getter->getClangDecl())); assert(bridgingInfo.classify() == CXXMethodBridging::Kind::getter); auto importedName = bridgingInfo.importNameAsCamelCaseName(); auto result = new (ctx) VarDecl(false, VarDecl::Introducer::Var, getter->getStartLoc(), ctx.getIdentifier(importedName), dc); result->setInterfaceType(getter->getResultInterfaceType()); result->copyFormalAccessFrom(getter); result->setImplInfo(StorageImplInfo::getMutableComputed()); AccessorDecl *getterDecl = AccessorDecl::create( ctx, getter->getLoc(), getter->getLoc(), AccessorKind::Get, result, /*async*/ false, SourceLoc(), /*throws*/ false, SourceLoc(), /*ThrownType=*/TypeLoc(), ParameterList::createEmpty(ctx), getter->getResultInterfaceType(), dc); getterDecl->copyFormalAccessFrom(getter); getterDecl->setImplicit(); getterDecl->setIsDynamic(false); getterDecl->setIsTransparent(true); getterDecl->setBodySynthesizer(synthesizeComputedGetterFromCXXMethod, getter); if (getter->isMutating()) { getterDecl->setSelfAccessKind(SelfAccessKind::Mutating); result->setIsGetterMutating(true); } AccessorDecl *setterDecl = nullptr; if (setter) { auto paramVarDecl = new (ctx) ParamDecl(SourceLoc(), SourceLoc(), Identifier(), SourceLoc(), ctx.getIdentifier("newValue"), dc); paramVarDecl->setSpecifier(ParamSpecifier::Default); paramVarDecl->setInterfaceType(getter->getResultInterfaceType()); auto setterParamList = ParameterList::create(ctx, {paramVarDecl}); setterDecl = AccessorDecl::create( ctx, setter->getLoc(), setter->getLoc(), AccessorKind::Set, result, /*async*/ false, SourceLoc(), /*throws*/ false, SourceLoc(), /*thrownType*/ TypeLoc(), setterParamList, setter->getResultInterfaceType(), dc); setterDecl->copyFormalAccessFrom(setter); setterDecl->setImplicit(); setterDecl->setIsDynamic(false); setterDecl->setIsTransparent(true); setterDecl->setBodySynthesizer(synthesizeComputedSetterFromCXXMethod, setter); if (setter->isMutating()) { setterDecl->setSelfAccessKind(SelfAccessKind::Mutating); result->setIsSetterMutating(true); } else { setterDecl->setSelfAccessKind(SelfAccessKind::NonMutating); result->setIsSetterMutating(false); } } ImporterImpl.makeComputed(result, getterDecl, setterDecl); return result; } static std::pair synthesizeDefaultArgumentBody(AbstractFunctionDecl *afd, void *context) { auto funcDecl = cast(afd); auto clangParam = static_cast(context); auto clangFuncDecl = cast(clangParam->getDeclContext()); ASTContext &ctx = funcDecl->getASTContext(); clang::ASTContext &clangCtx = clangParam->getASTContext(); clang::Sema &clangSema = ctx.getClangModuleLoader()->getClangSema(); auto clangDeclName = clang::DeclarationName( &clangCtx.Idents.get(("__cxx" + funcDecl->getNameStr()).str())); auto clangDeclContext = clangCtx.getTranslationUnitDecl(); // The following also instantiates the default argument if needed. auto defaultArgCallExpr = clangSema.BuildCXXDefaultArgExpr( clang::SourceLocation(), const_cast(clangFuncDecl), const_cast(clangParam)); if (!defaultArgCallExpr.isUsable()) return {nullptr, /*isTypeChecked=*/true}; // The following requires the default argument to be instantiated. clang::QualType clangParamTy = clangParam->getDefaultArg()->getType(); clang::QualType funcTy = clangCtx.getFunctionType( clangParamTy, {}, clang::FunctionProtoType::ExtProtoInfo()); // Synthesize `return {default expr};`. auto defaultArgReturnStmt = clang::ReturnStmt::Create( clangCtx, clang::SourceLocation(), defaultArgCallExpr.get(), nullptr); // Synthesize `ParamTy __cxx__defaultArg_XYZ() { return {default expr}; }`. auto defaultArgFuncDecl = clang::FunctionDecl::Create( clangCtx, clangDeclContext, clang::SourceLocation(), clang::SourceLocation(), clangDeclName, funcTy, clangCtx.getTrivialTypeSourceInfo(clangParamTy), clang::StorageClass::SC_Static); defaultArgFuncDecl->setImplicit(); defaultArgFuncDecl->setImplicitlyInline(); defaultArgFuncDecl->setAccess(clang::AccessSpecifier::AS_public); defaultArgFuncDecl->setBody(defaultArgReturnStmt); // Import `func __cxx__defaultArg_XYZ() -> ParamTY` into Swift. auto defaultArgGenerator = dyn_cast_or_null( ctx.getClangModuleLoader()->importDeclDirectly(defaultArgFuncDecl)); if (!defaultArgGenerator) return {nullptr, /*isTypeChecked=*/true}; auto defaultArgGeneratorRef = new (ctx) DeclRefExpr( ConcreteDeclRef(defaultArgGenerator), DeclNameLoc(), /*Implicit=*/true); defaultArgGeneratorRef->setType(defaultArgGenerator->getInterfaceType()); // Synthesize a call to `__cxx__defaultArg_XYZ()`. auto initCall = CallExpr::createImplicit( ctx, defaultArgGeneratorRef, ArgumentList::createImplicit(ctx, {})); initCall->setType(defaultArgGenerator->getResultInterfaceType()); initCall->setThrows(nullptr); // Synthesize `return __cxx__defaultArg_XYZ()`. auto *returnStmt = ReturnStmt::createImplicit(ctx, initCall); auto body = BraceStmt::create(ctx, SourceLoc(), {returnStmt}, SourceLoc(), /*implicit=*/true); return {body, /*isTypeChecked=*/true}; } CallExpr * SwiftDeclSynthesizer::makeDefaultArgument(const clang::ParmVarDecl *param, const swift::Type &swiftParamTy, SourceLoc paramLoc) { assert(param->hasDefaultArg() && "must have a C++ default argument"); ASTContext &ctx = ImporterImpl.SwiftContext; clang::ASTContext &clangCtx = param->getASTContext(); auto clangFunc = cast(param->getParentFunctionOrMethod()); if (isa(clangFunc)) // TODO: support default arguments of constructors // (https://github.com/apple/swift/issues/70124) return nullptr; std::string s; llvm::raw_string_ostream os(s); std::unique_ptr mangler{ clang::ItaniumMangleContext::create(clangCtx, clangCtx.getDiagnostics())}; os << "__defaultArg_" << param->getFunctionScopeIndex() << "_"; ImporterImpl.getMangledName(mangler.get(), clangFunc, os); // Synthesize `func __defaultArg_XYZ() -> ParamTy { ... }`. DeclName funcName(ctx, DeclBaseName(ctx.getIdentifier(s)), ParameterList::createEmpty(ctx)); auto funcDecl = FuncDecl::createImplicit( ctx, StaticSpellingKind::None, funcName, paramLoc, false, false, Type(), {}, ParameterList::createEmpty(ctx), swiftParamTy, ImporterImpl.ImportedHeaderUnit); funcDecl->setBodySynthesizer(synthesizeDefaultArgumentBody, (void *)param); funcDecl->setAccess(AccessLevel::Public); funcDecl->addAttribute( new (ctx) ExportAttr(ExportKind::Implementation, /*IsImplicit=*/true)); // At this point, the parameter/return types of funcDecl might not be imported // into Swift completely, meaning that their protocol conformances might not // be populated yet. Prevent LifetimeDependenceInfoRequest from prematurely // populating the conformance table for the types involved. ctx.evaluator.cacheOutput(LifetimeDependenceInfoRequest{funcDecl}, {}); ImporterImpl.defaultArgGenerators[param] = funcDecl; auto declRefExpr = new (ctx) DeclRefExpr(ConcreteDeclRef(funcDecl), DeclNameLoc(), /*Implicit*/ true); declRefExpr->setType(funcDecl->getInterfaceType()); declRefExpr->setFunctionRefInfo(FunctionRefInfo::singleBaseNameApply()); auto callExpr = CallExpr::createImplicit( ctx, declRefExpr, ArgumentList::forImplicitUnlabeled(ctx, {})); callExpr->setType(funcDecl->getResultInterfaceType()); callExpr->setThrows(nullptr); return callExpr; } // MARK: C++ foreign reference type constructors llvm::SmallVector SwiftDeclSynthesizer::synthesizeStaticFactoryForCXXForeignRef( const clang::CXXRecordDecl *cxxRecordDecl) { if (!cxxRecordDecl->isCompleteDefinition() || cxxRecordDecl->isAbstract()) return {}; clang::ASTContext &clangCtx = cxxRecordDecl->getASTContext(); clang::Sema &clangSema = ImporterImpl.getClangSema(); clang::QualType cxxRecordTy = clangCtx.getRecordType(cxxRecordDecl); clang::SourceLocation cxxRecordDeclLoc = cxxRecordDecl->getLocation(); llvm::SmallVector ctorDeclsForSynth; for (clang::CXXConstructorDecl *ctorDecl : cxxRecordDecl->ctors()) { if (ctorDecl->isDeleted() || ctorDecl->getAccess() == clang::AS_private || ctorDecl->getAccess() == clang::AS_protected || ctorDecl->isCopyOrMoveConstructor() || ctorDecl->isVariadic()) continue; bool hasDefaultArg = !ctorDecl->parameters().empty() && ctorDecl->parameters().back()->hasDefaultArg(); // TODO: Add support for default args in ctors for C++ foreign reference // types. if (hasDefaultArg) continue; ctorDeclsForSynth.push_back(ctorDecl); } if (ctorDeclsForSynth.empty()) return {}; clang::FunctionDecl *operatorNew = nullptr; clang::FunctionDecl *operatorDelete = nullptr; clang::ImplicitAllocationParameters IAP(clang::AlignedAllocationMode::No); clang::Sema::SFINAETrap trap(clangSema); bool findingAllocFuncFailed = clangSema.FindAllocationFunctions( cxxRecordDeclLoc, clang::SourceRange(), clang::AllocationFunctionScope::Both, clang::AllocationFunctionScope::Both, cxxRecordTy, /*IsArray=*/false, IAP, clang::MultiExprArg(), operatorNew, operatorDelete, /*Diagnose=*/false); if (trap.hasErrorOccurred() || findingAllocFuncFailed || !operatorNew || operatorNew->isDeleted() || operatorNew->getAccess() == clang::AS_private || operatorNew->getAccess() == clang::AS_protected) return {}; clang::QualType cxxRecordPtrTy = clangCtx.getPointerType(cxxRecordTy); // Adding `_Nonnull` to the return type of synthesized static factory bool nullabilityCannotBeAdded = clangSema.CheckImplicitNullabilityTypeSpecifier( cxxRecordPtrTy, clang::NullabilityKind::NonNull, cxxRecordDeclLoc, /*isParam=*/false, /*OverrideExisting=*/true); assert(!nullabilityCannotBeAdded && "Failed to add _Nonnull specifier to synthesized " "static factory's return type"); clang::IdentifierTable &clangIdents = clangCtx.Idents; llvm::SmallVector synthesizedFactories; unsigned int selectedCtorDeclCounter = 0; for (clang::CXXConstructorDecl *selectedCtorDecl : ctorDeclsForSynth) { unsigned int ctorParamCount = selectedCtorDecl->getNumParams(); selectedCtorDeclCounter++; std::string funcName = "__returns_" + cxxRecordDecl->getNameAsString(); if (ctorParamCount > 0) funcName += "_" + std::to_string(ctorParamCount) + "_params"; funcName += "_" + std::to_string(selectedCtorDeclCounter); clang::IdentifierInfo *funcNameToSynth = &clangIdents.get(funcName); auto ctorFunctionProtoTy = selectedCtorDecl->getType()->getAs(); clang::ArrayRef paramTypes = ctorFunctionProtoTy->getParamTypes(); clang::FunctionProtoType::ExtProtoInfo EPI; clang::QualType funcTypeToSynth = clangCtx.getFunctionType(cxxRecordPtrTy, paramTypes, EPI); clang::CXXMethodDecl *synthCxxMethodDecl = clang::CXXMethodDecl::Create( clangCtx, const_cast(cxxRecordDecl), cxxRecordDeclLoc, clang::DeclarationNameInfo(funcNameToSynth, cxxRecordDeclLoc), funcTypeToSynth, clangCtx.getTrivialTypeSourceInfo(funcTypeToSynth), clang::SC_Static, /*UsesFPIntrin=*/false, /*isInline=*/true, clang::ConstexprSpecKind::Unspecified, cxxRecordDeclLoc); assert( synthCxxMethodDecl && "Unable to synthesize static factory for c++ foreign reference type"); synthCxxMethodDecl->setAccess(clang::AccessSpecifier::AS_public); llvm::SmallVector synthParams; for (unsigned int i = 0; i < ctorParamCount; ++i) { auto *origParam = selectedCtorDecl->getParamDecl(i); clang::IdentifierInfo *paramIdent = origParam->getIdentifier(); if (!paramIdent) { std::string dummyName = "__unnamed_param_" + std::to_string(i); paramIdent = &clangIdents.get(dummyName); } auto *param = clang::ParmVarDecl::Create( clangCtx, synthCxxMethodDecl, cxxRecordDeclLoc, cxxRecordDeclLoc, paramIdent, origParam->getType(), clangCtx.getTrivialTypeSourceInfo(origParam->getType()), clang::SC_None, /*DefArg=*/nullptr); param->setIsUsed(); synthParams.push_back(param); } synthCxxMethodDecl->setParams(synthParams); if (!hasImmortalAttrs(cxxRecordDecl)) { synthCxxMethodDecl->addAttr( clang::SwiftAttrAttr::Create(clangCtx, "returns_retained")); } std::string swiftInitStr = "init("; for (unsigned i = 0; i < ctorParamCount; ++i) { auto paramType = selectedCtorDecl->getParamDecl(i)->getType(); if (paramType->isRValueReferenceType()) { swiftInitStr += "consuming:"; } else { swiftInitStr += "_:"; } } swiftInitStr += ")"; synthCxxMethodDecl->addAttr( clang::SwiftNameAttr::Create(clangCtx, swiftInitStr)); llvm::SmallVector ctorArgs; for (auto *param : synthParams) { clang::QualType paramTy = param->getType(); clang::QualType exprTy = paramTy.getNonReferenceType(); clang::Expr *argExpr = clang::DeclRefExpr::Create( clangCtx, clang::NestedNameSpecifierLoc(), cxxRecordDeclLoc, param, /*RefersToEnclosingVariableOrCapture=*/false, cxxRecordDeclLoc, exprTy, clang::VK_LValue); if (paramTy->isRValueReferenceType()) { argExpr = clangSema .BuildCXXNamedCast( cxxRecordDeclLoc, clang::tok::kw_static_cast, clangCtx.getTrivialTypeSourceInfo(paramTy), argExpr, clang::SourceRange(), clang::SourceRange()) .get(); } ctorArgs.push_back(argExpr); } llvm::SmallVector ctorArgsToAdd; if (clangSema.CompleteConstructorCall(selectedCtorDecl, cxxRecordTy, ctorArgs, cxxRecordDeclLoc, ctorArgsToAdd)) continue; clang::ExprResult synthCtorExprResult = clangSema.BuildCXXConstructExpr( cxxRecordDeclLoc, cxxRecordTy, selectedCtorDecl, /*Elidable=*/false, ctorArgsToAdd, /*HadMultipleCandidates=*/false, /*IsListInitialization=*/false, /*IsStdInitListInitialization=*/false, /*RequiresZeroInit=*/false, clang::CXXConstructionKind::Complete, clang::SourceRange(cxxRecordDeclLoc, cxxRecordDeclLoc)); assert(!synthCtorExprResult.isInvalid() && "Unable to synthesize constructor expression for c++ foreign " "reference type"); clang::Expr *synthCtorExpr = synthCtorExprResult.get(); clang::ExprResult synthNewExprResult = clangSema.BuildCXXNew( clang::SourceRange(), /*UseGlobal=*/false, clang::SourceLocation(), {}, clang::SourceLocation(), clang::SourceRange(), cxxRecordTy, clangCtx.getTrivialTypeSourceInfo(cxxRecordTy), std::nullopt, clang::SourceRange(cxxRecordDeclLoc, cxxRecordDeclLoc), synthCtorExpr); assert( !synthNewExprResult.isInvalid() && "Unable to synthesize `new` expression for c++ foreign reference type"); auto *synthNewExpr = cast(synthNewExprResult.get()); clang::ReturnStmt *synthRetStmt = clang::ReturnStmt::Create( clangCtx, cxxRecordDeclLoc, synthNewExpr, /*NRVOCandidate=*/nullptr); assert(synthRetStmt && "Unable to synthesize return statement for " "static factory of c++ foreign reference type"); clang::CompoundStmt *synthFuncBody = clang::CompoundStmt::Create( clangCtx, {synthRetStmt}, clang::FPOptionsOverride(), cxxRecordDeclLoc, cxxRecordDeclLoc); assert(synthRetStmt && "Unable to synthesize function body for static " "factory of c++ foreign reference type"); synthCxxMethodDecl->setBody(synthFuncBody); synthCxxMethodDecl->addAttr(clang::NoDebugAttr::CreateImplicit(clangCtx)); synthCxxMethodDecl->setImplicit(); synthCxxMethodDecl->setImplicitlyInline(); synthesizedFactories.push_back(synthCxxMethodDecl); } return synthesizedFactories; } static std::pair synthesizeAvailabilityDomainPredicateBody(AbstractFunctionDecl *afd, void *context) { auto clangVarDecl = static_cast(context); clang::ASTContext &clangCtx = clangVarDecl->getASTContext(); auto domainInfo = clangCtx.getFeatureAvailInfo(const_cast(clangVarDecl)); ASSERT(domainInfo.second.Call); auto funcDecl = cast(afd); ASTContext &ctx = funcDecl->getASTContext(); // FIXME: The need for an intermediate function to call could be eliminated if // Clang provided the predicate function decl directly, rather than a call // expression that must be wrapped in a function. // Synthesize `return {domain predicate expression}`. auto clangHelperReturnStmt = clang::ReturnStmt::Create( clangCtx, clang::SourceLocation(), domainInfo.second.Call, nullptr); // Synthesize `int __XYZ_isAvailable() { return {predicate expr}; }`. auto clangDeclName = clang::DeclarationName( &clangCtx.Idents.get("__" + domainInfo.first.str() + "_isAvailable")); auto clangDeclContext = clangCtx.getTranslationUnitDecl(); clang::QualType funcTy = clangCtx.getFunctionType(domainInfo.second.Call->getType(), {}, clang::FunctionProtoType::ExtProtoInfo()); auto clangHelperFuncDecl = clang::FunctionDecl::Create( clangCtx, clangDeclContext, clang::SourceLocation(), clang::SourceLocation(), clangDeclName, funcTy, clangCtx.getTrivialTypeSourceInfo(funcTy), clang::StorageClass::SC_Static); clangHelperFuncDecl->setImplicit(); clangHelperFuncDecl->setImplicitlyInline(); clangHelperFuncDecl->setBody(clangHelperReturnStmt); // Import `func __XYZ_isAvailable() -> Bool` into Swift. auto helperFuncDecl = dyn_cast_or_null( ctx.getClangModuleLoader()->importDeclDirectly(clangHelperFuncDecl)); if (!helperFuncDecl) return {nullptr, /*isTypeChecked=*/true}; auto helperFuncRef = new (ctx) DeclRefExpr(ConcreteDeclRef(helperFuncDecl), DeclNameLoc(), /*Implicit=*/true); helperFuncRef->setType(helperFuncDecl->getInterfaceType()); // Synthesize `__XYZ_isAvailable()`. auto helperCall = CallExpr::createImplicit( ctx, helperFuncRef, ArgumentList::createImplicit(ctx, {})); helperCall->setType(helperFuncDecl->getResultInterfaceType()); helperCall->setThrows(nullptr); // Synthesize `__XYZ_isAvailable()._value`. auto *memberRef = UnresolvedDotExpr::createImplicit(ctx, helperCall, ctx.Id_value_); // Synthesize `return __XYZ_isAvailable()._value`. auto *returnStmt = ReturnStmt::createImplicit(ctx, memberRef); auto body = BraceStmt::create(ctx, SourceLoc(), {returnStmt}, SourceLoc(), /*implicit=*/true); return {body, /*isTypeChecked=*/false}; } /// Mark the given declaration as always deprecated for the given reason. static void markDeprecated(Decl *decl, llvm::Twine message) { ASTContext &ctx = decl->getASTContext(); decl->addAttribute(AvailableAttr::createUniversallyDeprecated( ctx, ctx.AllocateCopy(message.str()))); } static bool copyConstructorIsDefaulted(const clang::CXXRecordDecl *decl) { auto ctor = llvm::find_if(decl->ctors(), [](clang::CXXConstructorDecl *ctor) { return ctor->isCopyConstructor(); }); assert(ctor != decl->ctor_end()); return ctor->isDefaulted(); } static bool copyAssignOperatorIsDefaulted(const clang::CXXRecordDecl *decl) { auto copyAssignOp = llvm::find_if(decl->decls(), [](clang::Decl *member) { if (auto method = dyn_cast(member)) return method->isCopyAssignmentOperator(); return false; }); assert(copyAssignOp != decl->decls_end()); return cast(*copyAssignOp)->isDefaulted(); } /// Recursively checks that there are no user-provided copy constructors or /// destructors in any fields or base classes. /// Does not check C++ records with specific API annotations. static bool isSufficientlyTrivial(const clang::CXXRecordDecl *decl) { // Probably a class template that has not yet been specialized: if (!decl->getDefinition()) return true; if ((decl->hasUserDeclaredCopyConstructor() && !copyConstructorIsDefaulted(decl)) || (decl->hasUserDeclaredCopyAssignment() && !copyAssignOperatorIsDefaulted(decl)) || (decl->hasUserDeclaredDestructor() && decl->getDestructor() && !decl->getDestructor()->isDefaulted())) return false; auto checkType = [](clang::QualType t) { if (auto recordType = dyn_cast(t.getCanonicalType())) { if (auto cxxRecord = dyn_cast(recordType->getDecl())) { if (hasImportAsRefAttr(cxxRecord) || hasOwnedValueAttr(cxxRecord) || hasUnsafeAPIAttr(cxxRecord)) return true; if (!isSufficientlyTrivial(cxxRecord)) return false; } } return true; }; for (auto field : decl->fields()) { if (!checkType(field->getType())) return false; } for (auto base : decl->bases()) { if (!checkType(base.getType())) return false; } return true; } /// Find an explicitly-provided "destroy" operation specified for the /// given Clang type and return it. FuncDecl *SwiftDeclSynthesizer::findExplicitDestroy( NominalTypeDecl *nominal, const clang::RecordDecl *clangType) { if (!clangType->hasAttrs()) return nullptr; llvm::SmallPtrSet matchingDestroyFuncs; llvm::TinyPtrVector nonMatchingDestroyFuncs; for (auto attr : clangType->getAttrs()) { auto swiftAttr = dyn_cast(attr); if (!swiftAttr) continue; auto destroyFuncName = swiftAttr->getAttribute(); if (!destroyFuncName.consume_front("destroy:")) continue; auto decls = getValueDeclsForName(nominal, destroyFuncName); for (auto decl : decls) { auto func = dyn_cast(decl); if (!func) continue; auto params = func->getParameters(); if (params->size() != 1) { nonMatchingDestroyFuncs.push_back(func); continue; } if (!params->get(0)->getInterfaceType()->isEqual( nominal->getDeclaredInterfaceType())) { nonMatchingDestroyFuncs.push_back(func); continue; } matchingDestroyFuncs.insert(func); } } switch (matchingDestroyFuncs.size()) { case 0: if (!nonMatchingDestroyFuncs.empty()) { markDeprecated( nominal, "destroy function '" + nonMatchingDestroyFuncs.front()->getName().getBaseName() .userFacingName() + "' must have a single parameter with type '" + nominal->getDeclaredInterfaceType().getString() + "'"); } return nullptr; case 1: // Handled below. break; default: { auto iter = matchingDestroyFuncs.begin(); auto first = *iter++; auto second = *iter; markDeprecated( nominal, "multiple destroy operations ('" + first->getName().getBaseName().userFacingName() + "' and '" + second->getName().getBaseName().userFacingName() + "') provided for type"); return nullptr; } } auto destroyFunc = *matchingDestroyFuncs.begin(); // If this type isn't imported as noncopyable, we can't respect the request // for a destroy operation. ASTContext &ctx = ImporterImpl.SwiftContext; auto valueSemanticsKind = evaluateOrDefault( ctx.evaluator, CxxValueSemantics({clangType->getTypeForDecl(), &ImporterImpl}), {}); if (valueSemanticsKind != CxxValueSemanticsKind::Copyable && valueSemanticsKind != CxxValueSemanticsKind::MoveOnly) return nullptr; auto cxxRecordSemanticsKind = evaluateOrDefault( ctx.evaluator, CxxRecordSemantics({clangType, ctx, &ImporterImpl}), {}); switch (cxxRecordSemanticsKind) { case CxxRecordSemanticsKind::Value: case CxxRecordSemanticsKind::Reference: if (auto cxxRecord = dyn_cast(clangType)) { if (!isSufficientlyTrivial(cxxRecord)) { markDeprecated( nominal, "destroy operation '" + destroyFunc->getName().getBaseName().userFacingName() + "' is not allowed on types with a non-trivial destructor"); return nullptr; } } if (valueSemanticsKind == CxxValueSemanticsKind::MoveOnly) return destroyFunc; markDeprecated( nominal, "destroy operation '" + destroyFunc->getName().getBaseName().userFacingName() + "' is only allowed on non-copyable types; " "did you mean to use SWIFT_NONCOPYABLE?"); return nullptr; case CxxRecordSemanticsKind::Iterator: case CxxRecordSemanticsKind::SwiftClassType: return nullptr; } } /// Function body synthesizer for a deinit of a noncopyable type, which /// passes "self" to the given "destroy" function. static std::pair synthesizeDeinitBodyForCustomDestroy( AbstractFunctionDecl *deinitFunc, void *opaqueDestroyFunc) { auto deinit = cast(deinitFunc); auto destroyFunc = static_cast(opaqueDestroyFunc); ASTContext &ctx = deinit->getASTContext(); auto funcRef = new (ctx) DeclRefExpr( destroyFunc, DeclNameLoc(), /*Implicit=*/true); auto selfRef = new (ctx) DeclRefExpr( deinit->getImplicitSelfDecl(), DeclNameLoc(), /*Implicit=*/true); auto callExpr = CallExpr::createImplicit( ctx, funcRef, ArgumentList::createImplicit( ctx, { Argument(SourceLoc(), Identifier(), selfRef)} ) ); auto braceStmt = BraceStmt::createImplicit(ctx, { ASTNode(callExpr) }); return std::make_pair(braceStmt, /*typechecked=*/false); } void SwiftDeclSynthesizer::addExplicitDeinitIfRequired( NominalTypeDecl *nominal, const clang::RecordDecl *clangType) { auto destroyFunc = findExplicitDestroy(nominal, clangType); if (!destroyFunc) return; ASTContext &ctx = nominal->getASTContext(); auto destructor = new (ctx) DestructorDecl(SourceLoc(), nominal); destructor->setSynthesized(true); destructor->copyFormalAccessFrom(nominal, /*sourceIsParentContext*/true); destructor->setBodySynthesizer( synthesizeDeinitBodyForCustomDestroy, destroyFunc); nominal->addMember(destructor); } FuncDecl *SwiftDeclSynthesizer::makeAvailabilityDomainPredicate( const clang::VarDecl *var) { ASTContext &ctx = ImporterImpl.SwiftContext; clang::ASTContext &clangCtx = var->getASTContext(); auto featureInfo = clangCtx.getFeatureAvailInfo(const_cast(var)); // If the decl doesn't represent and availability domain, skip it. if (featureInfo.first.empty()) return nullptr; // Only dynamic availability domains require a predicate function. if (featureInfo.second.Kind != clang::FeatureAvailKind::Dynamic) return nullptr; if (!featureInfo.second.Call) return nullptr; // Synthesize `func __swift_XYZ_isAvailable() -> Builtin.Int1 { ... }`. std::string s; llvm::raw_string_ostream os(s); os << "__swift_" << featureInfo.first << "_isAvailable"; DeclName funcName(ctx, DeclBaseName(ctx.getIdentifier(s)), ParameterList::createEmpty(ctx)); auto funcDecl = FuncDecl::createImplicit( ctx, StaticSpellingKind::None, funcName, SourceLoc(), /*Async=*/false, /*Throws=*/false, Type(), {}, ParameterList::createEmpty(ctx), BuiltinIntegerType::get(1, ctx), ImporterImpl.ImportedHeaderUnit); funcDecl->setBodySynthesizer(synthesizeAvailabilityDomainPredicateBody, (void *)var); funcDecl->setAccess(AccessLevel::Private); ImporterImpl.availabilityDomainPredicates[var] = funcDecl; return funcDecl; }