From a5e953b69009b59541420d06496206a26961a976 Mon Sep 17 00:00:00 2001 From: Martin Boehme Date: Wed, 26 Feb 2020 15:49:33 +0100 Subject: [PATCH 01/33] Add support for calling C++ constructors. Because C++ constructors always take a `this` pointer to the object to be initialized, we mark the SIL function return type with the `@out` attribute. On the IRGen side, we retrofit support for formal indirect return values as well as thin metatypes. --- lib/ClangImporter/ClangImporter.cpp | 6 +- lib/ClangImporter/ImportDecl.cpp | 88 +- lib/ClangImporter/ImportName.cpp | 14 + lib/IRGen/GenCall.cpp | 27 +- lib/IRGen/GenClangType.cpp | 14 +- lib/SIL/IR/SILFunctionType.cpp | 21 + lib/SIL/SILFunctionType.cpp | 4284 +++++++++++++++++ test/CXXInterop/Inputs/cxx_constructors.h | 22 + test/CXXInterop/Inputs/module.modulemap | 3 + .../cxx-constructors-executable.swift | 37 + test/CXXInterop/cxx-constructors-ir.swift | 14 + .../cxx-constructors-module-interface.swift | 20 + test/CXXInterop/cxx-constructors-sil.swift | 13 + .../cxx-constructors-typecheck.swift | 13 + 14 files changed, 4547 insertions(+), 29 deletions(-) create mode 100644 lib/SIL/SILFunctionType.cpp create mode 100644 test/CXXInterop/Inputs/cxx_constructors.h create mode 100644 test/CXXInterop/Inputs/module.modulemap create mode 100644 test/CXXInterop/cxx-constructors-executable.swift create mode 100644 test/CXXInterop/cxx-constructors-ir.swift create mode 100644 test/CXXInterop/cxx-constructors-module-interface.swift create mode 100644 test/CXXInterop/cxx-constructors-sil.swift create mode 100644 test/CXXInterop/cxx-constructors-typecheck.swift diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 0720569da9558..2aad8328ac8cd 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -3589,7 +3589,11 @@ void ClangImporter::getMangledName(raw_ostream &os, if (!Impl.Mangler) Impl.Mangler.reset(Impl.getClangASTContext().createMangleContext()); - Impl.Mangler->mangleName(clangDecl, os); + if (auto ctor = dyn_cast(clangDecl)) { + Impl.Mangler->mangleCXXCtor(ctor, clang::Ctor_Complete, os); + } else { + Impl.Mangler->mangleName(clangDecl, os); + } } // --------------------------------------------------------------------------- diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 079ded2e02094..9bf0a0e91f309 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -3378,6 +3378,11 @@ namespace { continue; } + if (auto CD = dyn_cast(member)) { + ctors.push_back(CD); + continue; + } + if (auto MD = dyn_cast(member)) { methods.push_back(MD); continue; @@ -3434,12 +3439,14 @@ namespace { bool hasReferenceableFields = !members.empty(); - if (hasZeroInitializableStorage) { + if (hasZeroInitializableStorage && + !Impl.SwiftContext.LangOpts.EnableCXXInterop) { // Add constructors for the struct. ctors.push_back(createDefaultConstructor(Impl, result)); } - if (hasReferenceableFields && hasMemberwiseInitializer) { + if (hasReferenceableFields && hasMemberwiseInitializer && + !Impl.SwiftContext.LangOpts.EnableCXXInterop) { // The default zero initializer suppresses the implicit value // constructor that would normally be formed, so we have to add that // explicitly as well. @@ -3491,6 +3498,28 @@ namespace { return result; } + Decl *VisitCXXRecordDecl(const clang::CXXRecordDecl *decl) { + auto &clangSema = Impl.getClangSema(); + // Make Clang define the implicit default constructor if the class needs + // it. Make sure we only do this if the class has been fully defined and + // we're not in a dependent context (this is equivalent to the logic in + // CanDeclareSpecialMemberFunction in Clang's SemaLookup.cpp). + if (decl->getDefinition() && !decl->isBeingDefined() && + !decl->isDependentContext() && + decl->needsImplicitDefaultConstructor()) { + // Casting away const here should be OK because + // SwiftDeclConverter::Visit() is in practice called with a non-const + // argument. + clang::CXXConstructorDecl *ctor = + clangSema.DeclareImplicitDefaultConstructor( + const_cast(decl)); + clangSema.DefineImplicitDefaultConstructor(clang::SourceLocation(), + ctor); + } + + return VisitRecordDecl(decl); + } + Decl *VisitClassTemplateSpecializationDecl( const clang::ClassTemplateSpecializationDecl *decl) { // `Sema::isCompleteType` will try to instantiate the class template as a @@ -3745,6 +3774,9 @@ namespace { ImportedName importedName, Optional correctSwiftName, Optional accessorInfo) { + if (decl->isDeleted()) + return nullptr; + auto dc = Impl.importDeclContextOf(decl, importedName.getEffectiveContext()); if (!dc) @@ -3753,7 +3785,6 @@ namespace { DeclName name = accessorInfo ? DeclName() : importedName.getDeclName(); auto selfIdx = importedName.getSelfIndex(); - FuncDecl *result = nullptr; ImportedType importedType; bool selfIsInOut = false; ParameterList *bodyParams = nullptr; @@ -3855,27 +3886,44 @@ namespace { if (!importedType) return nullptr; - auto resultTy = importedType.getType(); auto loc = Impl.importSourceLoc(decl->getLocation()); // FIXME: Poor location info. auto nameLoc = Impl.importSourceLoc(decl->getLocation()); - result = createFuncOrAccessor( - Impl.SwiftContext, loc, accessorInfo, name, - nameLoc, bodyParams, resultTy, - /*async*/ false, /*throws*/ false, dc, decl); - - if (!dc->isModuleScopeContext()) { - if (selfIsInOut) - result->setSelfAccessKind(SelfAccessKind::Mutating); - else - result->setSelfAccessKind(SelfAccessKind::NonMutating); - if (selfIdx) { - result->setSelfIndex(selfIdx.getValue()); - } else { - result->setStatic(); - result->setImportAsStaticMember(); + + AbstractFunctionDecl *result = nullptr; + if (auto *ctordecl = dyn_cast(decl)) { + // TODO: Is failable, throws etc. correct? + DeclName ctorName(Impl.SwiftContext, DeclBaseName::createConstructor(), + bodyParams); + result = Impl.createDeclWithClangNode( + decl, AccessLevel::Public, ctorName, loc, /*failable=*/false, + /*FailabilityLoc=*/SourceLoc(), /*Throws=*/false, + /*ThrowsLoc=*/SourceLoc(), bodyParams, /*GenericParams=*/nullptr, + dc); + } else { + auto resultTy = importedType.getType(); + + FuncDecl *func = createFuncOrAccessor( + Impl.SwiftContext, loc, accessorInfo, name, + nameLoc, bodyParams, resultTy, + /*async*/ false, /*throws*/ false, dc, decl); + result = func; + + if (!dc->isModuleScopeContext()) { + if (selfIsInOut) + func->setSelfAccessKind(SelfAccessKind::Mutating); + else + func->setSelfAccessKind(SelfAccessKind::NonMutating); + if (selfIdx) { + func->setSelfIndex(selfIdx.getValue()); + } else { + func->setStatic(); + func->setImportAsStaticMember(); + } } + // Someday, maybe this will need to be 'open' for C++ virtual methods. + func->setAccess(AccessLevel::Public); } result->setIsObjC(false); @@ -3889,8 +3937,6 @@ namespace { result->getAttrs().add(new (Impl.SwiftContext) FinalAttr(/*IsImplicit=*/true)); - // Someday, maybe this will need to be 'open' for C++ virtual methods. - result->setAccess(AccessLevel::Public); finishFuncDecl(decl, result); // If this is a compatibility stub, mark it as such. diff --git a/lib/ClangImporter/ImportName.cpp b/lib/ClangImporter/ImportName.cpp index cae15627ba7ef..65df344f664a0 100644 --- a/lib/ClangImporter/ImportName.cpp +++ b/lib/ClangImporter/ImportName.cpp @@ -1600,6 +1600,20 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D, ArrayRef params; switch (D->getDeclName().getNameKind()) { case clang::DeclarationName::CXXConstructorName: + isInitializer = true; + isFunction = true; + result.info.initKind = CtorInitializerKind::Designated; + baseName = "init"; + // Add empty argument names. + if (auto ctor = dyn_cast(D)) { + for (size_t i = 0; i < ctor->param_size(); ++i) { + argumentNames.push_back(StringRef()); + } + if (ctor->isVariadic()) + argumentNames.push_back(StringRef()); + } + break; + case clang::DeclarationName::CXXConversionFunctionName: case clang::DeclarationName::CXXDestructorName: case clang::DeclarationName::CXXLiteralOperatorName: diff --git a/lib/IRGen/GenCall.cpp b/lib/IRGen/GenCall.cpp index a544328dc0193..3fa9365d3c04f 100644 --- a/lib/IRGen/GenCall.cpp +++ b/lib/IRGen/GenCall.cpp @@ -338,10 +338,12 @@ llvm::CallingConv::ID irgen::expandCallingConv(IRGenModule &IGM, static void addIndirectResultAttributes(IRGenModule &IGM, llvm::AttributeList &attrs, - unsigned paramIndex, bool allowSRet) { + unsigned paramIndex, bool allowSRet, + bool noCapture = true) { llvm::AttrBuilder b; b.addAttribute(llvm::Attribute::NoAlias); - b.addAttribute(llvm::Attribute::NoCapture); + if (noCapture) + b.addAttribute(llvm::Attribute::NoCapture); if (allowSRet) b.addAttribute(llvm::Attribute::StructRet); attrs = attrs.addAttributes(IGM.getLLVMContext(), @@ -428,7 +430,7 @@ namespace { private: void expand(SILParameterInfo param); - llvm::Type *addIndirectResult(); + llvm::Type *addIndirectResult(bool noCapture = true); SILFunctionConventions getSILFuncConventions() const { return SILFunctionConventions(FnType, IGM.getSILModule()); @@ -482,7 +484,8 @@ llvm::Type *SignatureExpansion::addIndirectResult() { auto resultType = getSILFuncConventions().getSILResultType( IGM.getMaximalTypeExpansionContext()); const TypeInfo &resultTI = IGM.getTypeInfo(resultType); - addIndirectResultAttributes(IGM, Attrs, ParamIRTypes.size(), claimSRet()); + addIndirectResultAttributes(IGM, Attrs, ParamIRTypes.size(), claimSRet(), + noCapture); addPointerParameter(resultTI.getStorageType()); return IGM.VoidTy; } @@ -1306,6 +1309,9 @@ void SignatureExpansion::expandExternalSignatureTypes() { // Convert each parameter to a Clang type. for (auto param : params) { auto clangTy = IGM.getClangType(param, FnType); + if (clangTy->isVoidType()) { + continue; + } paramTys.push_back(clangTy); } @@ -1330,8 +1336,17 @@ void SignatureExpansion::expandExternalSignatureTypes() { } // If we return indirectly, that is the first parameter type. - if (returnInfo.isIndirect()) { - addIndirectResult(); + bool formalIndirect = FnType->getNumResults() > 0 && + FnType->getSingleResult().isFormalIndirect(); + if (formalIndirect || returnInfo.isIndirect()) { + // Specify "nocapture" if we're returning the result indirectly for + // low-level ABI reasons, as the called function never sees the implicit + // output parameter. + // On the other hand, if the result is a formal indirect result in SIL, that + // means that the Clang function has an explicit output parameter (e.g. it's + // a C++ constructor), which it might capture -- so don't specify + // "nocapture" in that case. + addIndirectResult(/* noCapture = */ returnInfo.isIndirect()); } size_t firstParamToLowerNormally = 0; diff --git a/lib/IRGen/GenClangType.cpp b/lib/IRGen/GenClangType.cpp index 8bc35dd99c134..c8f38d6038a65 100644 --- a/lib/IRGen/GenClangType.cpp +++ b/lib/IRGen/GenClangType.cpp @@ -403,7 +403,19 @@ clang::CanQualType GenClangType::visitProtocolType(CanProtocolType type) { } clang::CanQualType GenClangType::visitMetatypeType(CanMetatypeType type) { - return getClangMetatypeType(getClangASTContext()); + assert(type->hasRepresentation() && + "metatype should have been assigned a representation by SIL"); + switch (type->getRepresentation()) { + case MetatypeRepresentation::Thin: + return getClangASTContext().VoidTy; + + case MetatypeRepresentation::Thick: + llvm_unreachable("thick metatypes don't have a corresponding Clang type"); + + case MetatypeRepresentation::ObjC: + return getClangMetatypeType(getClangASTContext()); + } + llvm_unreachable("bad representation"); } clang::CanQualType diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index fc175f4460017..ff07a080d7c4f 100644 --- a/lib/SIL/IR/SILFunctionType.cpp +++ b/lib/SIL/IR/SILFunctionType.cpp @@ -2788,6 +2788,27 @@ class CXXMethodConventions : public CFunctionTypeConventions { return ParameterConvention::Indirect_In_Guaranteed; return ParameterConvention::Indirect_Inout; } + ResultConvention getResult(const TypeLowering &resultTL) const override { + if (isa(TheDecl)) { + // Represent the `this` pointer as an indirectly returned result. + // This gets us most of the way towards representing the ABI of a + // constructor correctly, but it's not guaranteed to be entirely correct. + // C++ constructor ABIs are complicated and can require passing additional + // "implicit" arguments that depend not only on the signature of the + // constructor but on the class on which it's defined (e.g. whether that + // class has a virtual base class). + // Effectively, we're making an assumption here that there are no implicit + // arguments and that the return type of the constructor ABI is void (and + // indeed we have no way to represent anything else here). If this assumed + // ABI doesn't match the actual ABI, we insert a thunk in IRGen. On some + // ABIs (e.g. Itanium x64), we get lucky and the ABI for a complete + // constructor call always matches the ABI we assume here. Even if the + // actual ABI doesn't match the assumed ABI, we try to get as close as + // possible to make it easy for LLVM to optimize away the thunk. + return ResultConvention::Indirect; + } + return CFunctionTypeConventions::getResult(resultTL); + } static bool classof(const Conventions *C) { return C->getKind() == ConventionsKind::CXXMethod; } diff --git a/lib/SIL/SILFunctionType.cpp b/lib/SIL/SILFunctionType.cpp new file mode 100644 index 0000000000000..e50568874f4e0 --- /dev/null +++ b/lib/SIL/SILFunctionType.cpp @@ -0,0 +1,4284 @@ +//===--- SILFunctionType.cpp - Giving SIL types to AST functions ----------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2017 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 +// +//===----------------------------------------------------------------------===// +// +// This file defines the native Swift ownership transfer conventions +// and works in concert with the importer to give the correct +// conventions to imported functions and types. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "libsil" +#include "swift/AST/AnyFunctionRef.h" +#include "swift/AST/Decl.h" +#include "swift/AST/DiagnosticsSIL.h" +#include "swift/AST/ForeignInfo.h" +#include "swift/AST/GenericEnvironment.h" +#include "swift/AST/GenericSignatureBuilder.h" +#include "swift/AST/Module.h" +#include "swift/AST/ModuleLoader.h" +#include "swift/AST/ProtocolConformance.h" +#include "swift/SIL/SILModule.h" +#include "swift/SIL/SILType.h" +#include "clang/AST/Attr.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Analysis/DomainSpecific/CocoaConventions.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/SaveAndRestore.h" + +using namespace swift; +using namespace swift::Lowering; + +SILType SILFunctionType::substInterfaceType(SILModule &M, + SILType interfaceType) const { + // Apply pattern substitutions first, then invocation substitutions. + if (auto subs = getPatternSubstitutions()) + interfaceType = interfaceType.subst(M, subs); + if (auto subs = getInvocationSubstitutions()) + interfaceType = interfaceType.subst(M, subs); + return interfaceType; +} + +CanSILFunctionType SILFunctionType::getUnsubstitutedType(SILModule &M) const { + auto mutableThis = const_cast(this); + + // If we have no substitutions, there's nothing to do. + if (!hasPatternSubstitutions() && !hasInvocationSubstitutions()) + return CanSILFunctionType(mutableThis); + + // Otherwise, substitute the component types. + + SmallVector params; + SmallVector yields; + SmallVector results; + Optional errorResult; + + auto subs = getCombinedSubstitutions(); + auto substComponentType = [&](CanType type) { + if (!type->hasTypeParameter()) return type; + return SILType::getPrimitiveObjectType(type) + .subst(M, subs).getASTType(); + }; + + for (auto param : getParameters()) { + params.push_back(param.map(substComponentType)); + } + + for (auto yield : getYields()) { + yields.push_back(yield.map(substComponentType)); + } + + for (auto result : getResults()) { + results.push_back(result.map(substComponentType)); + } + + if (auto error = getOptionalErrorResult()) { + errorResult = error->map(substComponentType); + } + + auto signature = isPolymorphic() ? getInvocationGenericSignature() + : CanGenericSignature(); + return SILFunctionType::get(signature, + getExtInfo(), + getCoroutineKind(), + getCalleeConvention(), + params, yields, results, errorResult, + SubstitutionMap(), + SubstitutionMap(), + mutableThis->getASTContext(), + getWitnessMethodConformanceOrInvalid()); +} + +CanType SILParameterInfo::getArgumentType(SILModule &M, + const SILFunctionType *t) const { + // TODO: We should always require a function type. + if (t) + return t->substInterfaceType(M, + SILType::getPrimitiveAddressType(getInterfaceType())) + .getASTType(); + + return getInterfaceType(); +} + +CanType SILResultInfo::getReturnValueType(SILModule &M, + const SILFunctionType *t) const { + // TODO: We should always require a function type. + if (t) + return t->substInterfaceType(M, + SILType::getPrimitiveAddressType(getInterfaceType())) + .getASTType(); + + return getInterfaceType(); +} + +SILType SILFunctionType::getDirectFormalResultsType(SILModule &M) { + CanType type; + if (getNumDirectFormalResults() == 0) { + type = getASTContext().TheEmptyTupleType; + } else if (getNumDirectFormalResults() == 1) { + type = getSingleDirectFormalResult().getReturnValueType(M, this); + } else { + auto &cache = getMutableFormalResultsCache(); + if (cache) { + type = cache; + } else { + SmallVector elts; + for (auto result : getResults()) + if (!result.isFormalIndirect()) + elts.push_back(result.getReturnValueType(M, this)); + type = CanType(TupleType::get(elts, getASTContext())); + cache = type; + } + } + return SILType::getPrimitiveObjectType(type); +} + +SILType SILFunctionType::getAllResultsInterfaceType() { + CanType type; + if (getNumResults() == 0) { + type = getASTContext().TheEmptyTupleType; + } else if (getNumResults() == 1) { + type = getResults()[0].getInterfaceType(); + } else { + auto &cache = getMutableAllResultsCache(); + if (cache) { + type = cache; + } else { + SmallVector elts; + for (auto result : getResults()) + elts.push_back(result.getInterfaceType()); + type = CanType(TupleType::get(elts, getASTContext())); + cache = type; + } + } + return SILType::getPrimitiveObjectType(type); +} + +SILType SILFunctionType::getAllResultsSubstType(SILModule &M) { + return substInterfaceType(M, getAllResultsInterfaceType()); +} + +SILType SILFunctionType::getFormalCSemanticResult(SILModule &M) { + assert(getLanguage() == SILFunctionLanguage::C); + assert(getNumResults() <= 1); + return getDirectFormalResultsType(M); +} + +CanType SILFunctionType::getSelfInstanceType(SILModule &M) const { + auto selfTy = getSelfParameter().getArgumentType(M, this); + + // If this is a static method, get the instance type. + if (auto metaTy = dyn_cast(selfTy)) + return metaTy.getInstanceType(); + + return selfTy; +} + +ClassDecl * +SILFunctionType::getWitnessMethodClass(SILModule &M) const { + // TODO: When witnesses use substituted types, we'd get this from the + // substitution map. + auto selfTy = getSelfInstanceType(M); + auto genericSig = getSubstGenericSignature(); + if (auto paramTy = dyn_cast(selfTy)) { + assert(paramTy->getDepth() == 0 && paramTy->getIndex() == 0); + auto superclass = genericSig->getSuperclassBound(paramTy); + if (superclass) + return superclass->getClassOrBoundGenericClass(); + } + + return nullptr; +} + +IndexSubset * +SILFunctionType::getDifferentiabilityParameterIndices() { + assert(isDifferentiable() && "Must be a differentiable function"); + SmallVector result; + for (auto valueAndIndex : enumerate(getParameters())) + if (valueAndIndex.value().getDifferentiability() != + SILParameterDifferentiability::NotDifferentiable) + result.push_back(valueAndIndex.index()); + return IndexSubset::get(getASTContext(), getNumParameters(), result); +} + +CanSILFunctionType +SILFunctionType::getWithDifferentiability(DifferentiabilityKind kind, + IndexSubset *parameterIndices) { + assert(kind != DifferentiabilityKind::NonDifferentiable && + "Differentiability kind must be normal or linear"); + SmallVector newParameters; + for (auto paramAndIndex : enumerate(getParameters())) { + auto ¶m = paramAndIndex.value(); + unsigned index = paramAndIndex.index(); + newParameters.push_back(param.getWithDifferentiability( + index < parameterIndices->getCapacity() && + parameterIndices->contains(index) + ? SILParameterDifferentiability::DifferentiableOrNotApplicable + : SILParameterDifferentiability::NotDifferentiable)); + } + auto newExtInfo = getExtInfo().withDifferentiabilityKind(kind); + return get(getInvocationGenericSignature(), newExtInfo, getCoroutineKind(), + getCalleeConvention(), newParameters, getYields(), getResults(), + getOptionalErrorResult(), getPatternSubstitutions(), + getInvocationSubstitutions(), getASTContext(), + getWitnessMethodConformanceOrInvalid()); +} + +CanSILFunctionType SILFunctionType::getWithoutDifferentiability() { + if (!isDifferentiable()) + return CanSILFunctionType(this); + auto nondiffExtInfo = getExtInfo().withDifferentiabilityKind( + DifferentiabilityKind::NonDifferentiable); + SmallVector newParams; + for (auto ¶m : getParameters()) + newParams.push_back(param.getWithDifferentiability( + SILParameterDifferentiability::DifferentiableOrNotApplicable)); + return SILFunctionType::get(getInvocationGenericSignature(), nondiffExtInfo, + getCoroutineKind(), getCalleeConvention(), + newParams, getYields(), getResults(), + getOptionalErrorResult(), + getPatternSubstitutions(), + getInvocationSubstitutions(), + getASTContext()); +} + +/// Collects the differentiability parameters of the given original function +/// type in `diffParams`. +static void +getDifferentiabilityParameters(SILFunctionType *originalFnTy, + IndexSubset *parameterIndices, + SmallVectorImpl &diffParams) { + // Returns true if `index` is a differentiability parameter index. + auto isDiffParamIndex = [&](unsigned index) -> bool { + return index < parameterIndices->getCapacity() && + parameterIndices->contains(index); + }; + // Calculate differentiability parameter infos. + for (auto valueAndIndex : enumerate(originalFnTy->getParameters())) + if (isDiffParamIndex(valueAndIndex.index())) + diffParams.push_back(valueAndIndex.value()); +} + +/// Collects the semantic results of the given function type in +/// `originalResults`. The semantic results are formal results followed by +/// `inout` parameters, in type order. +// TODO(TF-983): Generalize to support multiple `inout` parameters. The current +// singular `inoutParam` and `isWrtInoutParameter` are hacky. +static void +getSemanticResults(SILFunctionType *functionType, IndexSubset *parameterIndices, + Optional &inoutParam, + bool &isWrtInoutParameter, + SmallVectorImpl &originalResults) { + inoutParam = None; + isWrtInoutParameter = false; + // Collect original formal results. + originalResults.append(functionType->getResults().begin(), + functionType->getResults().end()); + // Collect original `inout` parameters. + for (auto i : range(functionType->getNumParameters())) { + auto param = functionType->getParameters()[i]; + if (!param.isIndirectInOut()) + continue; + inoutParam = param; + isWrtInoutParameter = parameterIndices->contains(i); + originalResults.push_back( + SILResultInfo(param.getInterfaceType(), ResultConvention::Indirect)); + } +} + +/// Returns the differential type for the given original function type, +/// parameter indices, and result index. +static CanSILFunctionType +getAutoDiffDifferentialType(SILFunctionType *originalFnTy, + IndexSubset *parameterIndices, unsigned resultIndex, + LookupConformanceFn lookupConformance) { + auto &ctx = originalFnTy->getASTContext(); + SmallVector substGenericParams; + SmallVector substRequirements; + SmallVector substReplacements; + SmallVector substConformances; + + Optional inoutParam = None; + bool isWrtInoutParameter = false; + SmallVector originalResults; + getSemanticResults(originalFnTy, parameterIndices, inoutParam, + isWrtInoutParameter, originalResults); + + SmallVector diffParams; + getDifferentiabilityParameters(originalFnTy, parameterIndices, diffParams); + SmallVector differentialParams; + for (auto ¶m : diffParams) { + auto paramTan = + param.getInterfaceType()->getAutoDiffTangentSpace(lookupConformance); + assert(paramTan && "Parameter type does not have a tangent space?"); + auto paramTanType = paramTan->getCanonicalType(); + if (!paramTanType->hasArchetype() && !paramTanType->hasTypeParameter()) { + differentialParams.push_back( + {paramTan->getCanonicalType(), param.getConvention()}); + } else { + auto gpIndex = substGenericParams.size(); + auto gpType = CanGenericTypeParamType::get(0, gpIndex, ctx); + substGenericParams.push_back(gpType); + substReplacements.push_back(paramTanType); + differentialParams.push_back({gpType, param.getConvention()}); + } + } + SmallVector differentialResults; + if (!inoutParam || !isWrtInoutParameter) { + auto &result = originalResults[resultIndex]; + auto resultTan = + result.getInterfaceType()->getAutoDiffTangentSpace(lookupConformance); + assert(resultTan && "Result type does not have a tangent space?"); + auto resultTanType = resultTan->getCanonicalType(); + if (!resultTanType->hasArchetype() && !resultTanType->hasTypeParameter()) { + differentialResults.push_back( + {resultTan->getCanonicalType(), result.getConvention()}); + } else { + auto gpIndex = substGenericParams.size(); + auto gpType = CanGenericTypeParamType::get(0, gpIndex, ctx); + substGenericParams.push_back(gpType); + substReplacements.push_back(resultTanType); + differentialResults.push_back({gpType, result.getConvention()}); + } + } + SubstitutionMap substitutions; + if (!substGenericParams.empty()) { + auto genericSig = + GenericSignature::get(substGenericParams, substRequirements) + .getCanonicalSignature(); + substitutions = + SubstitutionMap::get(genericSig, llvm::makeArrayRef(substReplacements), + llvm::makeArrayRef(substConformances)); + } + return SILFunctionType::get( + GenericSignature(), SILFunctionType::ExtInfo(), SILCoroutineKind::None, + ParameterConvention::Direct_Guaranteed, differentialParams, {}, + differentialResults, None, substitutions, + /*invocationSubstitutions*/ SubstitutionMap(), ctx); +} + +/// Returns the pullback type for the given original function type, parameter +/// indices, and result index. +static CanSILFunctionType +getAutoDiffPullbackType(SILFunctionType *originalFnTy, + IndexSubset *parameterIndices, unsigned resultIndex, + LookupConformanceFn lookupConformance, + TypeConverter &TC) { + auto &ctx = originalFnTy->getASTContext(); + SmallVector substGenericParams; + SmallVector substRequirements; + SmallVector substReplacements; + SmallVector substConformances; + + Optional inoutParam = None; + bool isWrtInoutParameter = false; + SmallVector originalResults; + getSemanticResults(originalFnTy, parameterIndices, inoutParam, + isWrtInoutParameter, originalResults); + + // Given a type, returns its formal SIL parameter info. + auto getTangentParameterConventionForOriginalResult = + [&](CanType tanType, + ResultConvention origResConv) -> ParameterConvention { + tanType = + tanType->getCanonicalType(originalFnTy->getSubstGenericSignature()); + AbstractionPattern pattern(originalFnTy->getSubstGenericSignature(), + tanType); + auto &tl = + TC.getTypeLowering(pattern, tanType, TypeExpansionContext::minimal()); + ParameterConvention conv; + switch (origResConv) { + case ResultConvention::Owned: + case ResultConvention::Autoreleased: + if (tl.isAddressOnly()) { + conv = ParameterConvention::Indirect_In_Guaranteed; + } else { + conv = tl.isTrivial() ? ParameterConvention::Direct_Unowned + : ParameterConvention::Direct_Guaranteed; + } + break; + case ResultConvention::Unowned: + case ResultConvention::UnownedInnerPointer: + conv = ParameterConvention::Direct_Unowned; + break; + case ResultConvention::Indirect: + conv = ParameterConvention::Indirect_In_Guaranteed; + break; + } + return conv; + }; + + // Given a type, returns its formal SIL result info. + auto getTangentResultConventionForOriginalParameter = + [&](CanType tanType, + ParameterConvention origParamConv) -> ResultConvention { + tanType = + tanType->getCanonicalType(originalFnTy->getSubstGenericSignature()); + AbstractionPattern pattern(originalFnTy->getSubstGenericSignature(), + tanType); + auto &tl = + TC.getTypeLowering(pattern, tanType, TypeExpansionContext::minimal()); + ResultConvention conv; + switch (origParamConv) { + case ParameterConvention::Direct_Owned: + case ParameterConvention::Direct_Guaranteed: + case ParameterConvention::Direct_Unowned: + if (tl.isAddressOnly()) { + conv = ResultConvention::Indirect; + } else { + conv = tl.isTrivial() ? ResultConvention::Unowned + : ResultConvention::Owned; + } + break; + case ParameterConvention::Indirect_In: + case ParameterConvention::Indirect_Inout: + case ParameterConvention::Indirect_In_Constant: + case ParameterConvention::Indirect_In_Guaranteed: + case ParameterConvention::Indirect_InoutAliasable: + conv = ResultConvention::Indirect; + break; + } + return conv; + }; + + SmallVector pullbackParams; + if (inoutParam) { + auto paramTan = inoutParam->getInterfaceType()->getAutoDiffTangentSpace( + lookupConformance); + assert(paramTan && "Parameter type does not have a tangent space?"); + auto paramTanConvention = isWrtInoutParameter + ? inoutParam->getConvention() + : ParameterConvention::Indirect_In_Guaranteed; + auto paramTanType = paramTan->getCanonicalType(); + if (!paramTanType->hasArchetype() && !paramTanType->hasTypeParameter()) { + pullbackParams.push_back( + SILParameterInfo(paramTanType, paramTanConvention)); + } else { + auto gpIndex = substGenericParams.size(); + auto gpType = CanGenericTypeParamType::get(0, gpIndex, ctx); + substGenericParams.push_back(gpType); + substReplacements.push_back(paramTanType); + pullbackParams.push_back({gpType, paramTanConvention}); + } + } else { + auto &origRes = originalResults[resultIndex]; + auto resultTan = + origRes.getInterfaceType()->getAutoDiffTangentSpace(lookupConformance); + assert(resultTan && "Result type does not have a tangent space?"); + auto resultTanType = resultTan->getCanonicalType(); + auto paramTanConvention = getTangentParameterConventionForOriginalResult( + resultTanType, origRes.getConvention()); + if (!resultTanType->hasArchetype() && !resultTanType->hasTypeParameter()) { + auto resultTanType = resultTan->getCanonicalType(); + pullbackParams.push_back({resultTanType, paramTanConvention}); + } else { + auto gpIndex = substGenericParams.size(); + auto gpType = CanGenericTypeParamType::get(0, gpIndex, ctx); + substGenericParams.push_back(gpType); + substReplacements.push_back(resultTanType); + pullbackParams.push_back({gpType, paramTanConvention}); + } + } + SmallVector diffParams; + getDifferentiabilityParameters(originalFnTy, parameterIndices, diffParams); + SmallVector pullbackResults; + for (auto ¶m : diffParams) { + if (param.isIndirectInOut()) + continue; + auto paramTan = + param.getInterfaceType()->getAutoDiffTangentSpace(lookupConformance); + assert(paramTan && "Parameter type does not have a tangent space?"); + auto paramTanType = paramTan->getCanonicalType(); + auto resultTanConvention = getTangentResultConventionForOriginalParameter( + paramTanType, param.getConvention()); + if (!paramTanType->hasArchetype() && !paramTanType->hasTypeParameter()) { + pullbackResults.push_back({paramTanType, resultTanConvention}); + } else { + auto gpIndex = substGenericParams.size(); + auto gpType = CanGenericTypeParamType::get(0, gpIndex, ctx); + substGenericParams.push_back(gpType); + substReplacements.push_back(paramTanType); + pullbackResults.push_back({gpType, resultTanConvention}); + } + } + SubstitutionMap substitutions; + if (!substGenericParams.empty()) { + auto genericSig = + GenericSignature::get(substGenericParams, substRequirements) + .getCanonicalSignature(); + substitutions = + SubstitutionMap::get(genericSig, llvm::makeArrayRef(substReplacements), + llvm::makeArrayRef(substConformances)); + } + return SILFunctionType::get( + GenericSignature(), SILFunctionType::ExtInfo(), SILCoroutineKind::None, + ParameterConvention::Direct_Guaranteed, pullbackParams, {}, + pullbackResults, None, substitutions, + /*invocationSubstitutions*/ SubstitutionMap(), ctx); +} + +/// Constrains the `original` function type according to differentiability +/// requirements: +/// - All differentiability parameters are constrained to conform to +/// `Differentiable`. +/// - The invocation generic signature is replaced by the +/// `constrainedInvocationGenSig` argument. +static SILFunctionType *getConstrainedAutoDiffOriginalFunctionType( + SILFunctionType *original, IndexSubset *parameterIndices, + LookupConformanceFn lookupConformance, + CanGenericSignature constrainedInvocationGenSig) { + auto originalInvocationGenSig = original->getInvocationGenericSignature(); + if (!originalInvocationGenSig) { + assert(!constrainedInvocationGenSig || + constrainedInvocationGenSig->areAllParamsConcrete() && + "derivative function cannot have invocation generic signature " + "when original function doesn't"); + return original; + } + + assert(!original->getPatternSubstitutions() && + "cannot constrain substituted function type"); + if (!constrainedInvocationGenSig) + constrainedInvocationGenSig = originalInvocationGenSig; + if (!constrainedInvocationGenSig) + return original; + constrainedInvocationGenSig = + autodiff::getConstrainedDerivativeGenericSignature( + original, parameterIndices, constrainedInvocationGenSig, + lookupConformance) + .getCanonicalSignature(); + + SmallVector newParameters; + newParameters.reserve(original->getNumParameters()); + for (auto ¶m : original->getParameters()) { + newParameters.push_back( + param.getWithInterfaceType(param.getInterfaceType()->getCanonicalType( + constrainedInvocationGenSig))); + } + + SmallVector newResults; + newResults.reserve(original->getNumResults()); + for (auto &result : original->getResults()) { + newResults.push_back( + result.getWithInterfaceType(result.getInterfaceType()->getCanonicalType( + constrainedInvocationGenSig))); + } + return SILFunctionType::get( + constrainedInvocationGenSig->areAllParamsConcrete() + ? GenericSignature() + : constrainedInvocationGenSig, + original->getExtInfo(), original->getCoroutineKind(), + original->getCalleeConvention(), newParameters, original->getYields(), + newResults, original->getOptionalErrorResult(), + /*patternSubstitutions*/ SubstitutionMap(), + /*invocationSubstitutions*/ SubstitutionMap(), original->getASTContext(), + original->getWitnessMethodConformanceOrInvalid()); +} + +CanSILFunctionType SILFunctionType::getAutoDiffDerivativeFunctionType( + IndexSubset *parameterIndices, unsigned resultIndex, + AutoDiffDerivativeFunctionKind kind, TypeConverter &TC, + LookupConformanceFn lookupConformance, + CanGenericSignature derivativeFnInvocationGenSig, + bool isReabstractionThunk) { + auto &ctx = getASTContext(); + + // Look up result in cache. + auto *resultIndices = IndexSubset::get( + ctx, getNumResults() + getNumIndirectMutatingParameters(), {resultIndex}); + SILAutoDiffDerivativeFunctionKey key{this, + parameterIndices, + resultIndices, + kind, + derivativeFnInvocationGenSig, + isReabstractionThunk}; + auto insertion = + ctx.SILAutoDiffDerivativeFunctions.try_emplace(key, CanSILFunctionType()); + auto &cachedResult = insertion.first->getSecond(); + if (!insertion.second) + return cachedResult; + + SILFunctionType *constrainedOriginalFnTy = + getConstrainedAutoDiffOriginalFunctionType(this, parameterIndices, + lookupConformance, + derivativeFnInvocationGenSig); + // Compute closure type. + CanSILFunctionType closureType; + switch (kind) { + case AutoDiffDerivativeFunctionKind::JVP: + closureType = + getAutoDiffDifferentialType(constrainedOriginalFnTy, parameterIndices, + resultIndex, lookupConformance); + break; + case AutoDiffDerivativeFunctionKind::VJP: + closureType = + getAutoDiffPullbackType(constrainedOriginalFnTy, parameterIndices, + resultIndex, lookupConformance, TC); + break; + } + // Compute the derivative function parameters. + SmallVector newParameters; + newParameters.reserve(constrainedOriginalFnTy->getNumParameters()); + for (auto ¶m : constrainedOriginalFnTy->getParameters()) { + newParameters.push_back(param); + } + // Reabstraction thunks have a function-typed parameter (the function to + // reabstract) as their last parameter. Reabstraction thunk JVPs/VJPs have a + // `@differentiable` function-typed last parameter instead. + if (isReabstractionThunk) { + assert(!parameterIndices->contains(getNumParameters() - 1) && + "Function-typed parameter should not be wrt"); + auto fnParam = newParameters.back(); + auto fnParamType = dyn_cast(fnParam.getInterfaceType()); + assert(fnParamType); + auto diffFnType = fnParamType->getWithDifferentiability( + DifferentiabilityKind::Normal, parameterIndices); + newParameters.back() = fnParam.getWithInterfaceType(diffFnType); + } + + // Compute the derivative function results. + SmallVector newResults; + newResults.reserve(getNumResults() + 1); + for (auto &result : constrainedOriginalFnTy->getResults()) { + newResults.push_back(result); + } + newResults.push_back({closureType, ResultConvention::Owned}); + + // Compute the derivative function ExtInfo. + // If original function is `@convention(c)`, the derivative function should + // have `@convention(thin)`. IRGen does not support `@convention(c)` functions + // with multiple results. + auto extInfo = constrainedOriginalFnTy->getExtInfo(); + if (getRepresentation() == SILFunctionTypeRepresentation::CFunctionPointer) + extInfo = extInfo.withRepresentation(SILFunctionTypeRepresentation::Thin); + + // Put everything together to get the derivative function type. Then, store in + // cache and return. + cachedResult = SILFunctionType::get( + constrainedOriginalFnTy->getSubstGenericSignature(), extInfo, + constrainedOriginalFnTy->getCoroutineKind(), + constrainedOriginalFnTy->getCalleeConvention(), newParameters, + constrainedOriginalFnTy->getYields(), newResults, + constrainedOriginalFnTy->getOptionalErrorResult(), + /*patternSubstitutions*/ SubstitutionMap(), + /*invocationSubstitutions*/ SubstitutionMap(), + constrainedOriginalFnTy->getASTContext(), + constrainedOriginalFnTy->getWitnessMethodConformanceOrInvalid()); + return cachedResult; +} + +CanSILFunctionType SILFunctionType::getAutoDiffTransposeFunctionType( + IndexSubset *parameterIndices, Lowering::TypeConverter &TC, + LookupConformanceFn lookupConformance, + CanGenericSignature transposeFnGenSig) { + // Get the "constrained" transpose function generic signature. + if (!transposeFnGenSig) + transposeFnGenSig = getSubstGenericSignature(); + transposeFnGenSig = autodiff::getConstrainedDerivativeGenericSignature( + this, parameterIndices, transposeFnGenSig, + lookupConformance, /*isLinear*/ true) + .getCanonicalSignature(); + + // Given a type, returns its formal SIL parameter info. + auto getParameterInfoForOriginalResult = + [&](const SILResultInfo &result) -> SILParameterInfo { + AbstractionPattern pattern(transposeFnGenSig, result.getInterfaceType()); + auto &tl = TC.getTypeLowering(pattern, result.getInterfaceType(), + TypeExpansionContext::minimal()); + ParameterConvention newConv; + switch (result.getConvention()) { + case ResultConvention::Owned: + case ResultConvention::Autoreleased: + newConv = tl.isTrivial() ? ParameterConvention::Direct_Unowned + : ParameterConvention::Direct_Guaranteed; + break; + case ResultConvention::Unowned: + case ResultConvention::UnownedInnerPointer: + newConv = ParameterConvention::Direct_Unowned; + break; + case ResultConvention::Indirect: + newConv = ParameterConvention::Indirect_In_Guaranteed; + break; + } + return {result.getInterfaceType(), newConv}; + }; + + // Given a type, returns its formal SIL result info. + auto getResultInfoForOriginalParameter = + [&](const SILParameterInfo ¶m) -> SILResultInfo { + AbstractionPattern pattern(transposeFnGenSig, param.getInterfaceType()); + auto &tl = TC.getTypeLowering(pattern, param.getInterfaceType(), + TypeExpansionContext::minimal()); + ResultConvention newConv; + switch (param.getConvention()) { + case ParameterConvention::Direct_Owned: + case ParameterConvention::Direct_Guaranteed: + case ParameterConvention::Direct_Unowned: + newConv = + tl.isTrivial() ? ResultConvention::Unowned : ResultConvention::Owned; + break; + case ParameterConvention::Indirect_In: + case ParameterConvention::Indirect_Inout: + case ParameterConvention::Indirect_In_Constant: + case ParameterConvention::Indirect_In_Guaranteed: + case ParameterConvention::Indirect_InoutAliasable: + newConv = ResultConvention::Indirect; + break; + } + return {param.getInterfaceType(), newConv}; + }; + + SmallVector newParameters; + SmallVector newResults; + for (auto pair : llvm::enumerate(getParameters())) { + auto index = pair.index(); + auto param = pair.value(); + if (parameterIndices->contains(index)) + newResults.push_back(getResultInfoForOriginalParameter(param)); + else + newParameters.push_back(param); + } + for (auto &res : getResults()) + newParameters.push_back(getParameterInfoForOriginalResult(res)); + return SILFunctionType::get( + getInvocationGenericSignature(), getExtInfo(), getCoroutineKind(), + getCalleeConvention(), newParameters, getYields(), newResults, + getOptionalErrorResult(), getPatternSubstitutions(), + /*invocationSubstitutions*/ {}, getASTContext()); +} + +static CanType getKnownType(Optional &cacheSlot, ASTContext &C, + StringRef moduleName, StringRef typeName) { + if (!cacheSlot) { + cacheSlot = ([&] { + ModuleDecl *mod = C.getLoadedModule(C.getIdentifier(moduleName)); + if (!mod) + return CanType(); + + // Do a general qualified lookup instead of a direct lookupValue because + // some of the types we want are reexported through overlays and + // lookupValue would only give us types actually declared in the overlays + // themselves. + SmallVector decls; + mod->lookupQualified(mod, DeclNameRef(C.getIdentifier(typeName)), + NL_QualifiedDefault | NL_KnownNonCascadingDependency, + decls); + if (decls.size() != 1) + return CanType(); + + const auto *typeDecl = dyn_cast(decls.front()); + if (!typeDecl) + return CanType(); + + return typeDecl->getDeclaredInterfaceType()->getCanonicalType(); + })(); + } + CanType t = *cacheSlot; + + // It is possible that we won't find a bridging type (e.g. String) when we're + // parsing the stdlib itself. + if (t) { + LLVM_DEBUG(llvm::dbgs() << "Bridging type " << moduleName << '.' << typeName + << " mapped to "; + if (t) + t->print(llvm::dbgs()); + else + llvm::dbgs() << ""; + llvm::dbgs() << '\n'); + } + return t; +} + +#define BRIDGING_KNOWN_TYPE(BridgedModule,BridgedType) \ + CanType TypeConverter::get##BridgedType##Type() { \ + return getKnownType(BridgedType##Ty, Context, \ + #BridgedModule, #BridgedType); \ + } +#include "swift/SIL/BridgedTypes.def" + +/// Adjust a function type to have a slightly different type. +CanAnyFunctionType +Lowering::adjustFunctionType(CanAnyFunctionType t, + AnyFunctionType::ExtInfo extInfo) { + if (t->getExtInfo() == extInfo) + return t; + return CanAnyFunctionType(t->withExtInfo(extInfo)); +} + +/// Adjust a function type to have a slightly different type. +CanSILFunctionType +Lowering::adjustFunctionType(CanSILFunctionType type, + SILFunctionType::ExtInfo extInfo, + ParameterConvention callee, + ProtocolConformanceRef witnessMethodConformance) { + if (type->getExtInfo() == extInfo && type->getCalleeConvention() == callee && + type->getWitnessMethodConformanceOrInvalid() == witnessMethodConformance) + return type; + + return SILFunctionType::get(type->getInvocationGenericSignature(), + extInfo, type->getCoroutineKind(), callee, + type->getParameters(), type->getYields(), + type->getResults(), + type->getOptionalErrorResult(), + type->getPatternSubstitutions(), + type->getInvocationSubstitutions(), + type->getASTContext(), + witnessMethodConformance); +} + +CanSILFunctionType +SILFunctionType::getWithRepresentation(Representation repr) { + return getWithExtInfo(getExtInfo().withRepresentation(repr)); +} + +CanSILFunctionType SILFunctionType::getWithExtInfo(ExtInfo newExt) { + auto oldExt = getExtInfo(); + if (newExt == oldExt) + return CanSILFunctionType(this); + + auto calleeConvention = + (newExt.hasContext() + ? (oldExt.hasContext() + ? getCalleeConvention() + : Lowering::DefaultThickCalleeConvention) + : ParameterConvention::Direct_Unowned); + + return get(getInvocationGenericSignature(), newExt, getCoroutineKind(), + calleeConvention, getParameters(), getYields(), getResults(), + getOptionalErrorResult(), getPatternSubstitutions(), + getInvocationSubstitutions(), getASTContext(), + getWitnessMethodConformanceOrInvalid()); +} + +namespace { + +enum class ConventionsKind : uint8_t { + Default = 0, + DefaultBlock = 1, + ObjCMethod = 2, + CFunctionType = 3, + CFunction = 4, + ObjCSelectorFamily = 5, + Deallocator = 6, + Capture = 7, + CXXMethod = 8, +}; + +class Conventions { + ConventionsKind kind; + +protected: + virtual ~Conventions() = default; + +public: + Conventions(ConventionsKind k) : kind(k) {} + + ConventionsKind getKind() const { return kind; } + + virtual ParameterConvention + getIndirectParameter(unsigned index, + const AbstractionPattern &type, + const TypeLowering &substTL) const = 0; + virtual ParameterConvention + getDirectParameter(unsigned index, + const AbstractionPattern &type, + const TypeLowering &substTL) const = 0; + virtual ParameterConvention getCallee() const = 0; + virtual ResultConvention getResult(const TypeLowering &resultTL) const = 0; + virtual ParameterConvention + getIndirectSelfParameter(const AbstractionPattern &type) const = 0; + virtual ParameterConvention + getDirectSelfParameter(const AbstractionPattern &type) const = 0; + + // Helpers that branch based on a value ownership. + ParameterConvention getIndirect(ValueOwnership ownership, bool forSelf, + unsigned index, + const AbstractionPattern &type, + const TypeLowering &substTL) const { + switch (ownership) { + case ValueOwnership::Default: + if (forSelf) + return getIndirectSelfParameter(type); + return getIndirectParameter(index, type, substTL); + case ValueOwnership::InOut: + return ParameterConvention::Indirect_Inout; + case ValueOwnership::Shared: + return ParameterConvention::Indirect_In_Guaranteed; + case ValueOwnership::Owned: + return ParameterConvention::Indirect_In; + } + llvm_unreachable("unhandled ownership"); + } + + ParameterConvention getDirect(ValueOwnership ownership, bool forSelf, + unsigned index, const AbstractionPattern &type, + const TypeLowering &substTL) const { + switch (ownership) { + case ValueOwnership::Default: + if (forSelf) + return getDirectSelfParameter(type); + return getDirectParameter(index, type, substTL); + case ValueOwnership::InOut: + return ParameterConvention::Indirect_Inout; + case ValueOwnership::Shared: + return ParameterConvention::Direct_Guaranteed; + case ValueOwnership::Owned: + return ParameterConvention::Direct_Owned; + } + llvm_unreachable("unhandled ownership"); + } +}; + +/// A structure for building the substituted generic signature of a lowered type. +/// +/// Where the abstraction pattern for a lowered type involves substitutable types, we extract those positions +/// out into generic arguments. This signature only needs to consider the general calling convention, +/// so it can reduce away protocol and base class constraints aside from +/// `AnyObject`. We want similar-shaped generic function types to remain +/// canonically equivalent, like `(T, U) -> ()`, `(T, T) -> ()`, +/// `(U, T) -> ()` or `(T, T.A) -> ()` when given substitutions that produce +/// the same function types, so we also introduce a new generic argument for +/// each position where we see a dependent type, and canonicalize the order in +/// which we see independent generic arguments. +class SubstFunctionTypeCollector { +public: + TypeConverter &TC; + TypeExpansionContext Expansion; + CanGenericSignature GenericSig; + bool Enabled; + + SmallVector substGenericParams; + SmallVector substRequirements; + SmallVector substReplacements; + SmallVector substConformances; + + SubstFunctionTypeCollector(TypeConverter &TC, TypeExpansionContext context, + CanGenericSignature genericSig, bool enabled) + : TC(TC), Expansion(context), GenericSig(genericSig), Enabled(enabled) { + } + SubstFunctionTypeCollector(const SubstFunctionTypeCollector &) = delete; + + // Add a substitution for a fresh type variable, with the given replacement + // type and layout constraint. + CanType addSubstitution(LayoutConstraint layout, + CanType substType, + ArchetypeType *upperBound, + ArrayRef substTypeConformances) { + auto paramIndex = substGenericParams.size(); + auto param = CanGenericTypeParamType::get(0, paramIndex, TC.Context); + + // Expand the bound type according to the expansion context. + if (Expansion.shouldLookThroughOpaqueTypeArchetypes() + && substType->hasOpaqueArchetype()) { + substType = substOpaqueTypesWithUnderlyingTypes(substType, Expansion); + } + + substGenericParams.push_back(param); + substReplacements.push_back(substType); + + LayoutConstraint upperBoundLayout; + Type upperBoundSuperclass; + ArrayRef upperBoundConformances; + + // If the parameter is in a position with upper bound constraints, such + // as a generic nominal type with type constraints on its arguments, then + // preserve the constraints from that upper bound. + if (upperBound) { + upperBoundSuperclass = upperBound->getSuperclass(); + upperBoundConformances = upperBound->getConformsTo(); + upperBoundLayout = upperBound->getLayoutConstraint(); + } + + if (upperBoundSuperclass) { + upperBoundSuperclass = upperBoundSuperclass->mapTypeOutOfContext(); + substRequirements.push_back( + Requirement(RequirementKind::Superclass, param, upperBoundSuperclass)); + } + + // Preserve the layout constraint, if any, on the archetype in the + // generic signature, generalizing away some constraints that + // shouldn't affect ABI substitutability. + if (layout) { + switch (layout->getKind()) { + // Keep these layout constraints as is. + case LayoutConstraintKind::RefCountedObject: + case LayoutConstraintKind::TrivialOfAtMostSize: + break; + + case LayoutConstraintKind::UnknownLayout: + case LayoutConstraintKind::Trivial: + // These constraints don't really constrain the ABI, so we can + // eliminate them. + layout = LayoutConstraint(); + break; + + // Replace these specific constraints with one of the more general + // constraints above. + case LayoutConstraintKind::NativeClass: + case LayoutConstraintKind::Class: + case LayoutConstraintKind::NativeRefCountedObject: + // These can all be generalized to RefCountedObject. + layout = LayoutConstraint::getLayoutConstraint( + LayoutConstraintKind::RefCountedObject); + break; + + case LayoutConstraintKind::TrivialOfExactSize: + // Generalize to TrivialOfAtMostSize. + layout = LayoutConstraint::getLayoutConstraint( + LayoutConstraintKind::TrivialOfAtMostSize, + layout->getTrivialSizeInBits(), + layout->getAlignmentInBits(), + TC.Context); + break; + } + + if (layout) { + // Pick the more specific of the upper bound layout and the layout + // we chose above. + if (upperBoundLayout) { + layout = layout.merge(upperBoundLayout); + } + + substRequirements.push_back( + Requirement(RequirementKind::Layout, param, layout)); + } + } else { + (void)0; + } + + for (unsigned i : indices(upperBoundConformances)) { + auto proto = upperBoundConformances[i]; + auto conformance = substTypeConformances[i]; + substRequirements.push_back(Requirement(RequirementKind::Conformance, + param, proto->getDeclaredType())); + substConformances.push_back(conformance); + } + + return param; + } + + /// Given the destructured original abstraction pattern and substituted type for a destructured + /// parameter or result, introduce substituted generic parameters and requirements as needed for + /// the lowered type, and return the substituted type in terms of the substituted generic signature. + CanType getSubstitutedInterfaceType(AbstractionPattern origType, + CanType substType) { + if (!Enabled) + return substType; + + // Replace every dependent type we see with a fresh type variable in + // the substituted signature, substituted by the corresponding concrete + // type. + + // The entire original context could be a generic parameter. + if (origType.isTypeParameter()) { + return addSubstitution(origType.getLayoutConstraint(), substType, + nullptr, {}); + } + + auto origContextType = origType.getType(); + + // If the substituted type is a subclass of the abstraction pattern + // type, build substitutions for any type parameters in it. This only + // comes up when lowering override types for vtable entries. + auto areDifferentClasses = [](Type a, Type b) -> bool { + if (auto dynA = a->getAs()) { + a = dynA->getSelfType(); + } + if (auto dynB = b->getAs()) { + b = dynB->getSelfType(); + } + if (auto aClass = a->getClassOrBoundGenericClass()) { + if (auto bClass = b->getClassOrBoundGenericClass()) { + return aClass != bClass; + } + } + + return false; + }; + + bool substituteBindingsInSubstType = false; + if (areDifferentClasses(substType, origContextType)) { + substituteBindingsInSubstType = true; + } + if (auto substMeta = dyn_cast(substType)) { + if (auto origMeta = dyn_cast(origContextType)) { + if (areDifferentClasses(substMeta->getInstanceType(), + origMeta->getInstanceType())) { + substituteBindingsInSubstType = true; + } + } + } + + CanGenericSignature origSig = origType.getGenericSignature(); + if (substituteBindingsInSubstType) { + origContextType = substType; + origSig = TC.getCurGenericSignature(); + assert((!substType->hasTypeParameter() || origSig) && + "lowering mismatched interface types in a context without " + "a generic signature"); + } + + if (!origContextType->hasTypeParameter() + && !origContextType->hasArchetype()) { + // If the abstraction pattern doesn't have substitutable positions, nor + // should the concrete type. + assert(!substType->hasTypeParameter() + && !substType->hasArchetype()); + return substType; + } + + // Extract structural substitutions. + if (origContextType->hasTypeParameter()) { + origContextType = origSig->getGenericEnvironment() + ->mapTypeIntoContext(origContextType) + ->getCanonicalType(origSig); + } + + auto result = origContextType + ->substituteBindingsTo(substType, + [&](ArchetypeType *archetype, + CanType binding, + ArchetypeType *upperBound, + ArrayRef bindingConformances) -> CanType { + // TODO: ArchetypeType::getLayoutConstraint sometimes misses out on + // implied layout constraints. For now AnyObject is the only one we + // care about. + return addSubstitution(archetype->requiresClass() + ? LayoutConstraint::getLayoutConstraint(LayoutConstraintKind::Class) + : LayoutConstraint(), + binding, + upperBound, + bindingConformances); + }); + + assert(result && "substType was not bindable to abstraction pattern type?"); + return result; + } +}; + +/// A visitor for breaking down formal result types into a SILResultInfo +/// and possibly some number of indirect-out SILParameterInfos, +/// matching the abstraction patterns of the original type. +class DestructureResults { + TypeConverter &TC; + const Conventions &Convs; + SmallVectorImpl &Results; + TypeExpansionContext context; + SubstFunctionTypeCollector &Subst; + +public: + DestructureResults(TypeExpansionContext context, TypeConverter &TC, + const Conventions &conventions, + SmallVectorImpl &results, + SubstFunctionTypeCollector &subst) + : TC(TC), Convs(conventions), Results(results), context(context), + Subst(subst) {} + + void destructure(AbstractionPattern origType, CanType substType) { + // Recur into tuples. + if (origType.isTuple()) { + auto substTupleType = cast(substType); + for (auto eltIndex : indices(substTupleType.getElementTypes())) { + AbstractionPattern origEltType = + origType.getTupleElementType(eltIndex); + CanType substEltType = substTupleType.getElementType(eltIndex); + destructure(origEltType, substEltType); + } + return; + } + + auto substInterfaceType = Subst.getSubstitutedInterfaceType(origType, + substType); + + auto &substResultTLForConvention = TC.getTypeLowering( + origType, substInterfaceType, TypeExpansionContext::minimal()); + auto &substResultTL = TC.getTypeLowering(origType, substInterfaceType, + context); + + + // Determine the result convention. + ResultConvention convention; + if (isFormallyReturnedIndirectly(origType, substType, + substResultTLForConvention)) { + convention = ResultConvention::Indirect; + } else { + convention = Convs.getResult(substResultTLForConvention); + + // Reduce conventions for trivial types to an unowned convention. + if (substResultTL.isTrivial()) { + switch (convention) { + case ResultConvention::Indirect: + case ResultConvention::Unowned: + case ResultConvention::UnownedInnerPointer: + // Leave these as-is. + break; + + case ResultConvention::Autoreleased: + case ResultConvention::Owned: + // These aren't distinguishable from unowned for trivial types. + convention = ResultConvention::Unowned; + break; + } + } + } + + SILResultInfo result(substResultTL.getLoweredType().getASTType(), + convention); + Results.push_back(result); + } + + /// Query whether the original type is returned indirectly for the purpose + /// of reabstraction given complete lowering information about its + /// substitution. + bool isFormallyReturnedIndirectly(AbstractionPattern origType, + CanType substType, + const TypeLowering &substTL) { + // If the substituted type is returned indirectly, so must the + // unsubstituted type. + if ((origType.isTypeParameter() + && !origType.isConcreteType() + && !origType.requiresClass()) + || substTL.isAddressOnly()) { + return true; + + // If the substitution didn't change the type, then a negative + // response to the above is determinative as well. + } else if (origType.getType() == substType && + !origType.getType()->hasTypeParameter()) { + return false; + + // Otherwise, query specifically for the original type. + } else { + return SILType::isFormallyReturnedIndirectly( + origType.getType(), TC, origType.getGenericSignature()); + } + } +}; + +static bool isClangTypeMoreIndirectThanSubstType(TypeConverter &TC, + const clang::Type *clangTy, + CanType substTy) { + // A const pointer argument might have been imported as + // UnsafePointer, COpaquePointer, or a CF foreign class. + // (An ObjC class type wouldn't be const-qualified.) + if (clangTy->isPointerType() + && clangTy->getPointeeType().isConstQualified()) { + // Peek through optionals. + if (auto substObjTy = substTy.getOptionalObjectType()) + substTy = substObjTy; + + // Void pointers aren't usefully indirectable. + if (clangTy->isVoidPointerType()) + return false; + + if (auto eltTy = substTy->getAnyPointerElementType()) + return isClangTypeMoreIndirectThanSubstType(TC, + clangTy->getPointeeType().getTypePtr(), CanType(eltTy)); + + if (substTy->getAnyNominal() == + TC.Context.getOpaquePointerDecl()) + // TODO: We could conceivably have an indirect opaque ** imported + // as COpaquePointer. That shouldn't ever happen today, though, + // since we only ever indirect the 'self' parameter of functions + // imported as methods. + return false; + + if (clangTy->getPointeeType()->getAs()) { + // CF type as foreign class + if (substTy->getClassOrBoundGenericClass() && + substTy->getClassOrBoundGenericClass()->getForeignClassKind() == + ClassDecl::ForeignKind::CFType) { + return false; + } + } + + // swift_newtypes are always passed directly + if (auto typedefTy = clangTy->getAs()) { + if (typedefTy->getDecl()->getAttr()) + return false; + } + + return true; + } + return false; +} + +static bool isFormallyPassedIndirectly(TypeConverter &TC, + AbstractionPattern origType, + CanType substType, + const TypeLowering &substTL) { + // If the C type of the argument is a const pointer, but the Swift type + // isn't, treat it as indirect. + if (origType.isClangType() + && isClangTypeMoreIndirectThanSubstType(TC, origType.getClangType(), + substType)) { + return true; + } + + // If the substituted type is passed indirectly, so must the + // unsubstituted type. + if ((origType.isTypeParameter() && !origType.isConcreteType() + && !origType.requiresClass()) + || substTL.isAddressOnly()) { + return true; + + // If the substitution didn't change the type, then a negative + // response to the above is determinative as well. + } else if (origType.getType() == substType && + !origType.getType()->hasTypeParameter()) { + return false; + + // Otherwise, query specifically for the original type. + } else { + return SILType::isFormallyPassedIndirectly( + origType.getType(), TC, origType.getGenericSignature()); + } +} + +/// A visitor for turning formal input types into SILParameterInfos, matching +/// the abstraction patterns of the original type. +/// +/// If the original abstraction pattern is fully opaque, we must pass the +/// function's parameters and results indirectly, as if the original type were +/// the most general function signature (expressed entirely in generic +/// parameters) which can be substituted to equal the given signature. +/// +/// See the comment in AbstractionPattern.h for details. +class DestructureInputs { + TypeExpansionContext expansion; + TypeConverter &TC; + const Conventions &Convs; + const ForeignInfo &Foreign; + Optional> HandleForeignSelf; + SmallVectorImpl &Inputs; + SubstFunctionTypeCollector &Subst; + unsigned NextOrigParamIndex = 0; +public: + DestructureInputs(TypeExpansionContext expansion, TypeConverter &TC, + const Conventions &conventions, const ForeignInfo &foreign, + SmallVectorImpl &inputs, + SubstFunctionTypeCollector &subst) + : expansion(expansion), TC(TC), Convs(conventions), Foreign(foreign), + Inputs(inputs), Subst(subst) {} + + void destructure(AbstractionPattern origType, + CanAnyFunctionType::CanParamArrayRef params, + AnyFunctionType::ExtInfo extInfo) { + visitTopLevelParams(origType, params, extInfo); + } + +private: + /// Query whether the original type is address-only given complete + /// lowering information about its substitution. + bool isFormallyPassedIndirectly(AbstractionPattern origType, + CanType substType, + const TypeLowering &substTL) { + return ::isFormallyPassedIndirectly(TC, origType, substType, substTL); + } + + /// This is a special entry point that allows destructure inputs to handle + /// self correctly. + void visitTopLevelParams(AbstractionPattern origType, + CanAnyFunctionType::CanParamArrayRef params, + AnyFunctionType::ExtInfo extInfo) { + unsigned numEltTypes = params.size(); + + bool hasSelf = (extInfo.hasSelfParam() || Foreign.Self.isImportAsMember()); + unsigned numNonSelfParams = (hasSelf ? numEltTypes - 1 : numEltTypes); + + auto silRepresentation = extInfo.getSILRepresentation(); + + // We have to declare this out here so that the lambda scope lasts for + // the duration of the loop below. + auto handleForeignSelf = [&] { + // This is a "self", but it's not a Swift self, we handle it differently. + auto selfParam = params[numNonSelfParams]; + visit(selfParam.getValueOwnership(), + /*forSelf=*/false, + origType.getFunctionParamType(numNonSelfParams), + selfParam.getParameterType(), silRepresentation); + }; + + // If we have a foreign-self, install handleSelf as the handler. + if (Foreign.Self.isInstance()) { + assert(hasSelf && numEltTypes > 0); + // This is safe because function_ref just stores a pointer to the + // existing lambda object. + HandleForeignSelf = handleForeignSelf; + } + + // Add any leading foreign parameters. + maybeAddForeignParameters(); + + // Process all the non-self parameters. + for (unsigned i = 0; i != numNonSelfParams; ++i) { + auto ty = params[i].getParameterType(); + auto eltPattern = origType.getFunctionParamType(i); + auto flags = params[i].getParameterFlags(); + + visit(flags.getValueOwnership(), /*forSelf=*/false, eltPattern, ty, + silRepresentation, flags.isNoDerivative()); + } + + // Process the self parameter. Note that we implicitly drop self + // if this is a static foreign-self import. + if (hasSelf && !Foreign.Self.isImportAsMember()) { + auto selfParam = params[numNonSelfParams]; + auto ty = selfParam.getParameterType(); + auto eltPattern = origType.getFunctionParamType(numNonSelfParams); + auto flags = selfParam.getParameterFlags(); + + visit(flags.getValueOwnership(), /*forSelf=*/true, + eltPattern, ty, silRepresentation); + } + + // Clear the foreign-self handler for safety. + HandleForeignSelf.reset(); + } + + void visit(ValueOwnership ownership, bool forSelf, + AbstractionPattern origType, CanType substType, + SILFunctionTypeRepresentation rep, + bool isNonDifferentiable = false) { + assert(!isa(substType)); + + // Tuples get handled specially, in some cases: + CanTupleType substTupleTy = dyn_cast(substType); + if (substTupleTy && !origType.isTypeParameter()) { + assert(origType.getNumTupleElements() == substTupleTy->getNumElements()); + switch (ownership) { + case ValueOwnership::Default: + case ValueOwnership::Owned: + case ValueOwnership::Shared: + // Expand the tuple. + for (auto i : indices(substTupleTy.getElementTypes())) { + auto &elt = substTupleTy->getElement(i); + auto ownership = elt.getParameterFlags().getValueOwnership(); + assert(ownership == ValueOwnership::Default); + assert(!elt.isVararg()); + visit(ownership, forSelf, + origType.getTupleElementType(i), + CanType(elt.getRawType()), rep); + } + return; + case ValueOwnership::InOut: + // handled below + break; + } + } + + unsigned origParamIndex = NextOrigParamIndex++; + + auto substInterfaceType = + Subst.getSubstitutedInterfaceType(origType, substType); + + auto &substTLConv = TC.getTypeLowering(origType, substInterfaceType, + TypeExpansionContext::minimal()); + auto &substTL = TC.getTypeLowering(origType, substInterfaceType, expansion); + + ParameterConvention convention; + if (ownership == ValueOwnership::InOut) { + convention = ParameterConvention::Indirect_Inout; + } else if (isFormallyPassedIndirectly(origType, substType, substTLConv)) { + convention = Convs.getIndirect(ownership, forSelf, origParamIndex, + origType, substTLConv); + assert(isIndirectFormalParameter(convention)); + } else if (substTL.isTrivial()) { + convention = ParameterConvention::Direct_Unowned; + } else { + convention = Convs.getDirect(ownership, forSelf, origParamIndex, origType, + substTLConv); + assert(!isIndirectFormalParameter(convention)); + } + + SILParameterInfo param(substTL.getLoweredType().getASTType(), convention); + if (isNonDifferentiable) + param = param.getWithDifferentiability( + SILParameterDifferentiability::NotDifferentiable); + Inputs.push_back(param); + + maybeAddForeignParameters(); + } + + /// Given that we've just reached an argument index for the + /// first time, add any foreign parameters. + void maybeAddForeignParameters() { + while (maybeAddForeignErrorParameter() || + maybeAddForeignSelfParameter()) { + // Continue to see, just in case there are more parameters to add. + } + } + + bool maybeAddForeignErrorParameter() { + if (!Foreign.Error || + NextOrigParamIndex != Foreign.Error->getErrorParameterIndex()) + return false; + + auto foreignErrorTy = TC.getLoweredRValueType( + expansion, Foreign.Error->getErrorParameterType()); + + // Assume the error parameter doesn't have interesting lowering. + Inputs.push_back(SILParameterInfo(foreignErrorTy, + ParameterConvention::Direct_Unowned)); + NextOrigParamIndex++; + return true; + } + + bool maybeAddForeignSelfParameter() { + if (!Foreign.Self.isInstance() || + NextOrigParamIndex != Foreign.Self.getSelfIndex()) + return false; + + (*HandleForeignSelf)(); + return true; + } +}; + +} // end anonymous namespace + +static bool isPseudogeneric(SILDeclRef c) { + // FIXME: should this be integrated in with the Sema check that prevents + // illegal use of type arguments in pseudo-generic method bodies? + + // The implicitly-generated native initializer thunks for imported + // initializers are never pseudo-generic, because they may need + // to use their type arguments to bridge their value arguments. + if (!c.isForeign && + (c.kind == SILDeclRef::Kind::Allocator || + c.kind == SILDeclRef::Kind::Initializer) && + c.getDecl()->hasClangNode()) + return false; + + // Otherwise, we have to look at the entity's context. + DeclContext *dc; + if (c.hasDecl()) { + dc = c.getDecl()->getDeclContext(); + } else if (auto closure = c.getAbstractClosureExpr()) { + dc = closure->getParent(); + } else { + return false; + } + dc = dc->getInnermostTypeContext(); + if (!dc) return false; + + auto classDecl = dc->getSelfClassDecl(); + return (classDecl && classDecl->usesObjCGenericsModel()); +} + +/// Update the result type given the foreign error convention that we will be +/// using. +static std::pair updateResultTypeForForeignError( + ForeignErrorConvention convention, CanGenericSignature genericSig, + AbstractionPattern origResultType, CanType substFormalResultType) { + switch (convention.getKind()) { + // These conventions replace the result type. + case ForeignErrorConvention::ZeroResult: + case ForeignErrorConvention::NonZeroResult: + assert(substFormalResultType->isVoid()); + substFormalResultType = convention.getResultType(); + origResultType = AbstractionPattern(genericSig, substFormalResultType); + return {origResultType, substFormalResultType}; + + // These conventions wrap the result type in a level of optionality. + case ForeignErrorConvention::NilResult: + assert(!substFormalResultType->getOptionalObjectType()); + substFormalResultType = + OptionalType::get(substFormalResultType)->getCanonicalType(); + origResultType = + AbstractionPattern::getOptional(origResultType); + return {origResultType, substFormalResultType}; + + // These conventions don't require changes to the formal error type. + case ForeignErrorConvention::ZeroPreservedResult: + case ForeignErrorConvention::NonNilError: + return {origResultType, substFormalResultType}; + } + llvm_unreachable("unhandled kind"); +} + +/// Lower any/all capture context parameters. +/// +/// *NOTE* Currently default arg generators can not capture anything. +/// If we ever add that ability, it will be a different capture list +/// from the function to which the argument is attached. +static void +lowerCaptureContextParameters(TypeConverter &TC, SILDeclRef function, + CanGenericSignature genericSig, + TypeExpansionContext expansion, + SmallVectorImpl &inputs) { + + // NB: The generic signature may be elided from the lowered function type + // if the function is in a fully-specialized context, but we still need to + // canonicalize references to the generic parameters that may appear in + // non-canonical types in that context. We need the original generic + // signature from the AST for that. + auto origGenericSig = function.getAnyFunctionRef()->getGenericSignature(); + auto loweredCaptures = TC.getLoweredLocalCaptures(function); + + for (auto capture : loweredCaptures.getCaptures()) { + if (capture.isDynamicSelfMetadata()) { + ParameterConvention convention = ParameterConvention::Direct_Unowned; + auto dynamicSelfInterfaceType = + loweredCaptures.getDynamicSelfType()->mapTypeOutOfContext(); + + auto selfMetatype = MetatypeType::get(dynamicSelfInterfaceType, + MetatypeRepresentation::Thick); + + auto canSelfMetatype = selfMetatype->getCanonicalType(origGenericSig); + SILParameterInfo param(canSelfMetatype, convention); + inputs.push_back(param); + + continue; + } + + if (capture.isOpaqueValue()) { + OpaqueValueExpr *opaqueValue = capture.getOpaqueValue(); + auto canType = opaqueValue->getType()->mapTypeOutOfContext() + ->getCanonicalType(origGenericSig); + auto &loweredTL = + TC.getTypeLowering(AbstractionPattern(genericSig, canType), + canType, expansion); + auto loweredTy = loweredTL.getLoweredType(); + + ParameterConvention convention; + if (loweredTL.isAddressOnly()) { + convention = ParameterConvention::Indirect_In; + } else { + convention = ParameterConvention::Direct_Owned; + } + SILParameterInfo param(loweredTy.getASTType(), convention); + inputs.push_back(param); + + continue; + } + + auto *VD = capture.getDecl(); + auto type = VD->getInterfaceType(); + auto canType = type->getCanonicalType(origGenericSig); + + auto &loweredTL = + TC.getTypeLowering(AbstractionPattern(genericSig, canType), canType, + expansion); + auto loweredTy = loweredTL.getLoweredType(); + switch (TC.getDeclCaptureKind(capture, expansion)) { + case CaptureKind::Constant: { + // Constants are captured by value. + ParameterConvention convention; + assert (!loweredTL.isAddressOnly()); + if (loweredTL.isTrivial()) { + convention = ParameterConvention::Direct_Unowned; + } else { + convention = ParameterConvention::Direct_Guaranteed; + } + SILParameterInfo param(loweredTy.getASTType(), convention); + inputs.push_back(param); + break; + } + case CaptureKind::Box: { + // The type in the box is lowered in the minimal context. + auto minimalLoweredTy = + TC.getTypeLowering(AbstractionPattern(genericSig, canType), canType, + TypeExpansionContext::minimal()) + .getLoweredType(); + // Lvalues are captured as a box that owns the captured value. + auto boxTy = TC.getInterfaceBoxTypeForCapture( + VD, minimalLoweredTy.getASTType(), + /*mutable*/ true); + auto convention = ParameterConvention::Direct_Guaranteed; + auto param = SILParameterInfo(boxTy, convention); + inputs.push_back(param); + break; + } + case CaptureKind::StorageAddress: { + // Non-escaping lvalues are captured as the address of the value. + SILType ty = loweredTy.getAddressType(); + auto param = + SILParameterInfo(ty.getASTType(), + ParameterConvention::Indirect_InoutAliasable); + inputs.push_back(param); + break; + } + case CaptureKind::Immutable: { + // 'let' constants that are address-only are captured as the address of + // the value and will be consumed by the closure. + SILType ty = loweredTy.getAddressType(); + auto param = + SILParameterInfo(ty.getASTType(), + ParameterConvention::Indirect_In_Guaranteed); + inputs.push_back(param); + break; + } + } + } +} + +static AccessorDecl *getAsCoroutineAccessor(Optional constant) { + if (!constant || !constant->hasDecl()) + return nullptr;; + + auto accessor = dyn_cast(constant->getDecl()); + if (!accessor || !accessor->isCoroutine()) + return nullptr; + + return accessor; +} + +static void destructureYieldsForReadAccessor(TypeConverter &TC, + TypeExpansionContext expansion, + AbstractionPattern origType, + CanType valueType, + SmallVectorImpl &yields, + SubstFunctionTypeCollector &subst) { + // Recursively destructure tuples. + if (origType.isTuple()) { + auto valueTupleType = cast(valueType); + for (auto i : indices(valueTupleType.getElementTypes())) { + auto origEltType = origType.getTupleElementType(i); + auto valueEltType = valueTupleType.getElementType(i); + destructureYieldsForReadAccessor(TC, expansion, origEltType, valueEltType, + yields, subst); + } + return; + } + + auto valueInterfaceType = + subst.getSubstitutedInterfaceType(origType, valueType); + + auto &tlConv = + TC.getTypeLowering(origType, valueInterfaceType, + TypeExpansionContext::minimal()); + auto &tl = + TC.getTypeLowering(origType, valueInterfaceType, expansion); + auto convention = [&] { + if (isFormallyPassedIndirectly(TC, origType, valueInterfaceType, tlConv)) + return ParameterConvention::Indirect_In_Guaranteed; + if (tlConv.isTrivial()) + return ParameterConvention::Direct_Unowned; + return ParameterConvention::Direct_Guaranteed; + }(); + + yields.push_back(SILYieldInfo(tl.getLoweredType().getASTType(), + convention)); +} + +static void destructureYieldsForCoroutine(TypeConverter &TC, + TypeExpansionContext expansion, + Optional origConstant, + Optional constant, + Optional reqtSubs, + SmallVectorImpl &yields, + SILCoroutineKind &coroutineKind, + SubstFunctionTypeCollector &subst) { + assert(coroutineKind == SILCoroutineKind::None); + assert(yields.empty()); + + auto accessor = getAsCoroutineAccessor(constant); + if (!accessor) + return; + + auto origAccessor = cast(origConstant->getDecl()); + + // Coroutine accessors are implicitly yield-once coroutines, despite + // their function type. + coroutineKind = SILCoroutineKind::YieldOnce; + + // Coroutine accessors are always native, so fetch the native + // abstraction pattern. + auto origStorage = origAccessor->getStorage(); + auto origType = TC.getAbstractionPattern(origStorage, /*nonobjc*/ true) + .getReferenceStorageReferentType(); + + auto storage = accessor->getStorage(); + auto valueType = storage->getValueInterfaceType(); + if (reqtSubs) { + valueType = valueType.subst(*reqtSubs); + } + + auto canValueType = valueType->getCanonicalType( + accessor->getGenericSignature()); + + // 'modify' yields an inout of the target type. + if (accessor->getAccessorKind() == AccessorKind::Modify) { + auto valueInterfaceType = subst.getSubstitutedInterfaceType(origType, + canValueType); + auto loweredValueTy = + TC.getLoweredType(origType, valueInterfaceType, expansion); + yields.push_back(SILYieldInfo(loweredValueTy.getASTType(), + ParameterConvention::Indirect_Inout)); + return; + } + + // 'read' yields a borrowed value of the target type, destructuring + // tuples as necessary. + assert(accessor->getAccessorKind() == AccessorKind::Read); + destructureYieldsForReadAccessor(TC, expansion, origType, canValueType, + yields, subst); +} + +/// Create the appropriate SIL function type for the given formal type +/// and conventions. +/// +/// The lowering of function types is generally sensitive to the +/// declared abstraction pattern. We want to be able to take +/// advantage of declared type information in order to, say, pass +/// arguments separately and directly; but we also want to be able to +/// call functions from generic code without completely embarrassing +/// performance. Therefore, different abstraction patterns induce +/// different argument-passing conventions, and we must introduce +/// implicit reabstracting conversions where necessary to map one +/// convention to another. +/// +/// However, we actually can't reabstract arbitrary thin function +/// values while still leaving them thin, at least without costly +/// page-mapping tricks. Therefore, the representation must remain +/// consistent across all abstraction patterns. +/// +/// We could reabstract block functions in theory, but (1) we don't +/// really need to and (2) doing so would be problematic because +/// stuffing something in an Optional currently forces it to be +/// reabstracted to the most general type, which means that we'd +/// expect the wrong abstraction conventions on bridged block function +/// types. +/// +/// Therefore, we only honor abstraction patterns on thick or +/// polymorphic functions. +/// +/// FIXME: we shouldn't just drop the original abstraction pattern +/// when we can't reabstract. Instead, we should introduce +/// dynamic-indirect argument-passing conventions and map opaque +/// archetypes to that, then respect those conventions in IRGen by +/// using runtime call construction. +/// +/// \param conventions - conventions as expressed for the original type +static CanSILFunctionType getSILFunctionType( + TypeConverter &TC, TypeExpansionContext expansionContext, AbstractionPattern origType, + CanAnyFunctionType substFnInterfaceType, AnyFunctionType::ExtInfo extInfo, + const Conventions &conventions, const ForeignInfo &foreignInfo, + Optional origConstant, Optional constant, + Optional reqtSubs, + ProtocolConformanceRef witnessMethodConformance) { + // Find the generic parameters. + CanGenericSignature genericSig = + substFnInterfaceType.getOptGenericSignature(); + + Optional contextRAII; + if (genericSig) contextRAII.emplace(TC, genericSig); + + // Per above, only fully honor opaqueness in the abstraction pattern + // for thick or polymorphic functions. We don't need to worry about + // non-opaque patterns because the type-checker forbids non-thick + // function types from having generic parameters or results. + if (origType.isTypeParameter() && + substFnInterfaceType->getExtInfo().getSILRepresentation() + != SILFunctionType::Representation::Thick && + isa(substFnInterfaceType)) { + origType = AbstractionPattern(genericSig, + substFnInterfaceType); + } + + // Map 'throws' to the appropriate error convention. + Optional errorResult; + assert((!foreignInfo.Error || substFnInterfaceType->getExtInfo().throws()) && + "foreignError was set but function type does not throw?"); + if (substFnInterfaceType->getExtInfo().throws() && !foreignInfo.Error) { + assert(!origType.isForeign() && + "using native Swift error convention for foreign type!"); + SILType exnType = SILType::getExceptionType(TC.Context); + assert(exnType.isObject()); + errorResult = SILResultInfo(exnType.getASTType(), + ResultConvention::Owned); + } + + // Lower the result type. + AbstractionPattern origResultType = origType.getFunctionResultType(); + CanType substFormalResultType = substFnInterfaceType.getResult(); + + // If we have a foreign error convention, restore the original result type. + if (auto convention = foreignInfo.Error) { + std::tie(origResultType, substFormalResultType) = + updateResultTypeForForeignError(*convention, genericSig, origResultType, + substFormalResultType); + } + + bool shouldBuildSubstFunctionType = [&]{ + if (!TC.Context.LangOpts.EnableSubstSILFunctionTypesForFunctionValues) + return false; + + // We always use substituted function types for coroutines that are + // being lowered in the context of another coroutine, which is to say, + // for class override thunks. This is required to make the yields + // match in abstraction to the base method's yields, which is necessary + // to make the extracted continuation-function signatures match. + if (constant != origConstant && getAsCoroutineAccessor(constant)) + return true; + + // We don't currently use substituted function types for generic function + // type lowering, though we should for generic methods on classes and + // protocols. + if (genericSig) + return false; + + // We only currently use substituted function types for function values, + // which will have standard thin or thick representation. (Per the previous + // comment, it would be useful to do so for generic methods on classes and + // protocols too.) + auto rep = extInfo.getSILRepresentation(); + return (rep == SILFunctionTypeRepresentation::Thick || + rep == SILFunctionTypeRepresentation::Thin); + }(); + + SubstFunctionTypeCollector subst(TC, expansionContext, genericSig, + shouldBuildSubstFunctionType); + + // Destructure the input tuple type. + SmallVector inputs; + { + DestructureInputs destructurer(expansionContext, TC, conventions, + foreignInfo, inputs, subst); + destructurer.destructure(origType, + substFnInterfaceType.getParams(), + extInfo); + } + + // Destructure the coroutine yields. + SILCoroutineKind coroutineKind = SILCoroutineKind::None; + SmallVector yields; + destructureYieldsForCoroutine(TC, expansionContext, origConstant, constant, + reqtSubs, yields, coroutineKind, subst); + + // Destructure the result tuple type. + SmallVector results; + { + DestructureResults destructurer(expansionContext, TC, conventions, + results, subst); + destructurer.destructure(origResultType, substFormalResultType); + } + + // Lower the capture context parameters, if any. + if (constant && constant->getAnyFunctionRef()) { + auto expansion = TypeExpansionContext::maximal( + expansionContext.getContext(), expansionContext.isWholeModuleContext()); + if (constant->isSerialized()) + expansion = TypeExpansionContext::minimal(); + lowerCaptureContextParameters(TC, *constant, genericSig, expansion, inputs); + } + + auto calleeConvention = ParameterConvention::Direct_Unowned; + if (extInfo.hasContext()) + calleeConvention = conventions.getCallee(); + + bool pseudogeneric = genericSig && constant + ? isPseudogeneric(*constant) + : false; + + // NOTE: SILFunctionType::ExtInfo doesn't track everything that + // AnyFunctionType::ExtInfo tracks. For example: 'throws' or 'auto-closure' + auto silExtInfo = SILFunctionType::ExtInfo() + .withRepresentation(extInfo.getSILRepresentation()) + .withIsPseudogeneric(pseudogeneric) + .withNoEscape(extInfo.isNoEscape()) + .withDifferentiabilityKind(extInfo.getDifferentiabilityKind()); + + // Build the substituted generic signature we extracted. + SubstitutionMap substitutions; + if (subst.Enabled) { + if (!subst.substGenericParams.empty()) { + auto subSig = GenericSignature::get(subst.substGenericParams, + subst.substRequirements) + .getCanonicalSignature(); + substitutions = SubstitutionMap::get(subSig, + llvm::makeArrayRef(subst.substReplacements), + llvm::makeArrayRef(subst.substConformances)); + } + } + + return SILFunctionType::get(genericSig, silExtInfo, coroutineKind, + calleeConvention, inputs, yields, + results, errorResult, + substitutions, SubstitutionMap(), + TC.Context, witnessMethodConformance); +} + +//===----------------------------------------------------------------------===// +// Deallocator SILFunctionTypes +//===----------------------------------------------------------------------===// + +namespace { + +// The convention for general deallocators. +struct DeallocatorConventions : Conventions { + DeallocatorConventions() : Conventions(ConventionsKind::Deallocator) {} + + ParameterConvention getIndirectParameter(unsigned index, + const AbstractionPattern &type, + const TypeLowering &substTL) const override { + llvm_unreachable("Deallocators do not have indirect parameters"); + } + + ParameterConvention getDirectParameter(unsigned index, + const AbstractionPattern &type, + const TypeLowering &substTL) const override { + llvm_unreachable("Deallocators do not have non-self direct parameters"); + } + + ParameterConvention getCallee() const override { + llvm_unreachable("Deallocators do not have callees"); + } + + ResultConvention getResult(const TypeLowering &tl) const override { + // TODO: Put an unreachable here? + return ResultConvention::Owned; + } + + ParameterConvention + getDirectSelfParameter(const AbstractionPattern &type) const override { + // TODO: Investigate whether or not it is + return ParameterConvention::Direct_Owned; + } + + ParameterConvention + getIndirectSelfParameter(const AbstractionPattern &type) const override { + llvm_unreachable("Deallocators do not have indirect self parameters"); + } + + static bool classof(const Conventions *C) { + return C->getKind() == ConventionsKind::Deallocator; + } +}; + +} // end anonymous namespace + +//===----------------------------------------------------------------------===// +// Default Convention FunctionTypes +//===----------------------------------------------------------------------===// + +namespace { + +enum class NormalParameterConvention { Owned, Guaranteed }; + +/// The default Swift conventions. +class DefaultConventions : public Conventions { + NormalParameterConvention normalParameterConvention; + +public: + DefaultConventions(NormalParameterConvention normalParameterConvention) + : Conventions(ConventionsKind::Default), + normalParameterConvention(normalParameterConvention) {} + + bool isNormalParameterConventionGuaranteed() const { + return normalParameterConvention == NormalParameterConvention::Guaranteed; + } + + ParameterConvention getIndirectParameter(unsigned index, + const AbstractionPattern &type, + const TypeLowering &substTL) const override { + if (isNormalParameterConventionGuaranteed()) { + return ParameterConvention::Indirect_In_Guaranteed; + } + return ParameterConvention::Indirect_In; + } + + ParameterConvention getDirectParameter(unsigned index, + const AbstractionPattern &type, + const TypeLowering &substTL) const override { + if (isNormalParameterConventionGuaranteed()) + return ParameterConvention::Direct_Guaranteed; + return ParameterConvention::Direct_Owned; + } + + ParameterConvention getCallee() const override { + return DefaultThickCalleeConvention; + } + + ResultConvention getResult(const TypeLowering &tl) const override { + return ResultConvention::Owned; + } + + ParameterConvention + getDirectSelfParameter(const AbstractionPattern &type) const override { + return ParameterConvention::Direct_Guaranteed; + } + + ParameterConvention + getIndirectSelfParameter(const AbstractionPattern &type) const override { + return ParameterConvention::Indirect_In_Guaranteed; + } + + static bool classof(const Conventions *C) { + return C->getKind() == ConventionsKind::Default; + } +}; + +/// The default conventions for Swift initializing constructors. +/// +/// Initializing constructors take all parameters (including) self at +1. This +/// is because: +/// +/// 1. We are likely to be initializing fields of self implying that the +/// parameters are likely to be forwarded into memory without further +/// copies. +/// 2. Initializers must take 'self' at +1, since they will return it back +/// at +1, and may chain onto Objective-C initializers that replace the +/// instance. +struct DefaultInitializerConventions : DefaultConventions { + DefaultInitializerConventions() + : DefaultConventions(NormalParameterConvention::Owned) {} + + /// Initializers must take 'self' at +1, since they will return it back at +1, + /// and may chain onto Objective-C initializers that replace the instance. + ParameterConvention + getDirectSelfParameter(const AbstractionPattern &type) const override { + return ParameterConvention::Direct_Owned; + } + + ParameterConvention + getIndirectSelfParameter(const AbstractionPattern &type) const override { + return ParameterConvention::Indirect_In; + } +}; + +/// The convention used for allocating inits. Allocating inits take their normal +/// parameters at +1 and do not have a self parameter. +struct DefaultAllocatorConventions : DefaultConventions { + DefaultAllocatorConventions() + : DefaultConventions(NormalParameterConvention::Owned) {} + + ParameterConvention + getDirectSelfParameter(const AbstractionPattern &type) const override { + llvm_unreachable("Allocating inits do not have self parameters"); + } + + ParameterConvention + getIndirectSelfParameter(const AbstractionPattern &type) const override { + llvm_unreachable("Allocating inits do not have self parameters"); + } +}; + +/// The default conventions for Swift setter acccessors. +/// +/// These take self at +0, but all other parameters at +1. This is because we +/// assume that setter parameters are likely to be values to be forwarded into +/// memory. Thus by passing in the +1 value, we avoid a potential copy in that +/// case. +struct DefaultSetterConventions : DefaultConventions { + DefaultSetterConventions() + : DefaultConventions(NormalParameterConvention::Owned) {} +}; + +/// The default conventions for ObjC blocks. +struct DefaultBlockConventions : Conventions { + DefaultBlockConventions() : Conventions(ConventionsKind::DefaultBlock) {} + + ParameterConvention getIndirectParameter(unsigned index, + const AbstractionPattern &type, + const TypeLowering &substTL) const override { + llvm_unreachable("indirect block parameters unsupported"); + } + + ParameterConvention getDirectParameter(unsigned index, + const AbstractionPattern &type, + const TypeLowering &substTL) const override { + return ParameterConvention::Direct_Unowned; + } + + ParameterConvention getCallee() const override { + return ParameterConvention::Direct_Unowned; + } + + ResultConvention getResult(const TypeLowering &substTL) const override { + return ResultConvention::Autoreleased; + } + + ParameterConvention + getDirectSelfParameter(const AbstractionPattern &type) const override { + llvm_unreachable("objc blocks do not have a self parameter"); + } + + ParameterConvention + getIndirectSelfParameter(const AbstractionPattern &type) const override { + llvm_unreachable("objc blocks do not have a self parameter"); + } + + static bool classof(const Conventions *C) { + return C->getKind() == ConventionsKind::DefaultBlock; + } +}; + +} // end anonymous namespace + +static CanSILFunctionType +getSILFunctionTypeForAbstractCFunction(TypeConverter &TC, + AbstractionPattern origType, + CanAnyFunctionType substType, + AnyFunctionType::ExtInfo extInfo, + Optional constant); + +static CanSILFunctionType getNativeSILFunctionType( + TypeConverter &TC, TypeExpansionContext context, AbstractionPattern origType, + CanAnyFunctionType substInterfaceType, AnyFunctionType::ExtInfo extInfo, + Optional origConstant, Optional constant, + Optional reqtSubs, + ProtocolConformanceRef witnessMethodConformance) { + assert(bool(origConstant) == bool(constant)); + switch (extInfo.getSILRepresentation()) { + case SILFunctionType::Representation::Block: + case SILFunctionType::Representation::CFunctionPointer: + return getSILFunctionTypeForAbstractCFunction(TC, origType, + substInterfaceType, + extInfo, constant); + + case SILFunctionType::Representation::Thin: + case SILFunctionType::Representation::ObjCMethod: + case SILFunctionType::Representation::Thick: + case SILFunctionType::Representation::Method: + case SILFunctionType::Representation::Closure: + case SILFunctionType::Representation::WitnessMethod: { + switch (constant ? constant->kind : SILDeclRef::Kind::Func) { + case SILDeclRef::Kind::Initializer: + case SILDeclRef::Kind::EnumElement: + return getSILFunctionType(TC, context, origType, substInterfaceType, + extInfo, DefaultInitializerConventions(), + ForeignInfo(), origConstant, constant, reqtSubs, + witnessMethodConformance); + case SILDeclRef::Kind::Allocator: + return getSILFunctionType(TC, context, origType, substInterfaceType, + extInfo, DefaultAllocatorConventions(), + ForeignInfo(), origConstant, constant, reqtSubs, + witnessMethodConformance); + case SILDeclRef::Kind::Func: + // If we have a setter, use the special setter convention. This ensures + // that we take normal parameters at +1. + if (constant && constant->isSetter()) { + return getSILFunctionType(TC, context, origType, substInterfaceType, + extInfo, DefaultSetterConventions(), + ForeignInfo(), origConstant, constant, + reqtSubs, witnessMethodConformance); + } + LLVM_FALLTHROUGH; + case SILDeclRef::Kind::Destroyer: + case SILDeclRef::Kind::GlobalAccessor: + case SILDeclRef::Kind::DefaultArgGenerator: + case SILDeclRef::Kind::StoredPropertyInitializer: + case SILDeclRef::Kind::PropertyWrapperBackingInitializer: + case SILDeclRef::Kind::IVarInitializer: + case SILDeclRef::Kind::IVarDestroyer: { + auto conv = DefaultConventions(NormalParameterConvention::Guaranteed); + return getSILFunctionType(TC, context, origType, substInterfaceType, + extInfo, conv, ForeignInfo(), origConstant, + constant, reqtSubs, witnessMethodConformance); + } + case SILDeclRef::Kind::Deallocator: + return getSILFunctionType(TC, context, origType, substInterfaceType, + extInfo, DeallocatorConventions(), + ForeignInfo(), origConstant, constant, reqtSubs, + witnessMethodConformance); + } + } + } + + llvm_unreachable("Unhandled SILDeclRefKind in switch."); +} + +CanSILFunctionType swift::getNativeSILFunctionType( + TypeConverter &TC, TypeExpansionContext context, + AbstractionPattern origType, CanAnyFunctionType substType, + Optional origConstant, Optional substConstant, + Optional reqtSubs, + ProtocolConformanceRef witnessMethodConformance) { + AnyFunctionType::ExtInfo extInfo; + + // Preserve type information from the original type if possible. + if (auto origFnType = origType.getAs()) { + extInfo = origFnType->getExtInfo(); + + // Otherwise, preserve function type attributes from the substituted type. + } else { + extInfo = substType->getExtInfo(); + } + + return ::getNativeSILFunctionType(TC, context, origType, substType, extInfo, + origConstant, substConstant, reqtSubs, + witnessMethodConformance); +} + +//===----------------------------------------------------------------------===// +// Foreign SILFunctionTypes +//===----------------------------------------------------------------------===// + +static bool isCFTypedef(const TypeLowering &tl, clang::QualType type) { + // If we imported a C pointer type as a non-trivial type, it was + // a foreign class type. + return !tl.isTrivial() && type->isPointerType(); +} + +/// Given nothing but a formal C parameter type that's passed +/// indirectly, deduce the convention for it. +/// +/// Generally, whether the parameter is +1 is handled before this. +static ParameterConvention getIndirectCParameterConvention(clang::QualType type) { + // Non-trivial C++ types would be Indirect_Inout (at least in Itanium). + // A trivial const * parameter in C should be considered @in. + return ParameterConvention::Indirect_In; +} + +/// Given a C parameter declaration whose type is passed indirectly, +/// deduce the convention for it. +/// +/// Generally, whether the parameter is +1 is handled before this. +static ParameterConvention +getIndirectCParameterConvention(const clang::ParmVarDecl *param) { + return getIndirectCParameterConvention(param->getType()); +} + +/// Given nothing but a formal C parameter type that's passed +/// directly, deduce the convention for it. +/// +/// Generally, whether the parameter is +1 is handled before this. +static ParameterConvention getDirectCParameterConvention(clang::QualType type) { + return ParameterConvention::Direct_Unowned; +} + +/// Given a C parameter declaration whose type is passed directly, +/// deduce the convention for it. +static ParameterConvention +getDirectCParameterConvention(const clang::ParmVarDecl *param) { + if (param->hasAttr() || + param->hasAttr()) + return ParameterConvention::Direct_Owned; + return getDirectCParameterConvention(param->getType()); +} + +// FIXME: that should be Direct_Guaranteed +const auto ObjCSelfConvention = ParameterConvention::Direct_Unowned; + +namespace { + +class ObjCMethodConventions : public Conventions { + const clang::ObjCMethodDecl *Method; + +public: + const clang::ObjCMethodDecl *getMethod() const { return Method; } + + ObjCMethodConventions(const clang::ObjCMethodDecl *method) + : Conventions(ConventionsKind::ObjCMethod), Method(method) {} + + ParameterConvention getIndirectParameter(unsigned index, + const AbstractionPattern &type, + const TypeLowering &substTL) const override { + return getIndirectCParameterConvention(Method->param_begin()[index]); + } + + ParameterConvention getDirectParameter(unsigned index, + const AbstractionPattern &type, + const TypeLowering &substTL) const override { + return getDirectCParameterConvention(Method->param_begin()[index]); + } + + ParameterConvention getCallee() const override { + // Always thin. + return ParameterConvention::Direct_Unowned; + } + + /// Given that a method returns a CF type, infer its method + /// family. Unfortunately, Clang's getMethodFamily() never + /// considers a method to be in a special family if its result + /// doesn't satisfy isObjCRetainable(). + clang::ObjCMethodFamily getMethodFamilyForCFResult() const { + // Trust an explicit attribute. + if (auto attr = Method->getAttr()) { + switch (attr->getFamily()) { + case clang::ObjCMethodFamilyAttr::OMF_None: + return clang::OMF_None; + case clang::ObjCMethodFamilyAttr::OMF_alloc: + return clang::OMF_alloc; + case clang::ObjCMethodFamilyAttr::OMF_copy: + return clang::OMF_copy; + case clang::ObjCMethodFamilyAttr::OMF_init: + return clang::OMF_init; + case clang::ObjCMethodFamilyAttr::OMF_mutableCopy: + return clang::OMF_mutableCopy; + case clang::ObjCMethodFamilyAttr::OMF_new: + return clang::OMF_new; + } + llvm_unreachable("bad attribute value"); + } + + return Method->getSelector().getMethodFamily(); + } + + bool isImplicitPlusOneCFResult() const { + switch (getMethodFamilyForCFResult()) { + case clang::OMF_None: + case clang::OMF_dealloc: + case clang::OMF_finalize: + case clang::OMF_retain: + case clang::OMF_release: + case clang::OMF_autorelease: + case clang::OMF_retainCount: + case clang::OMF_self: + case clang::OMF_initialize: + case clang::OMF_performSelector: + return false; + + case clang::OMF_alloc: + case clang::OMF_new: + case clang::OMF_mutableCopy: + case clang::OMF_copy: + return true; + + case clang::OMF_init: + return Method->isInstanceMethod(); + } + llvm_unreachable("bad method family"); + } + + ResultConvention getResult(const TypeLowering &tl) const override { + // If we imported the result as something trivial, we need to + // use one of the unowned conventions. + if (tl.isTrivial()) { + if (Method->hasAttr()) + return ResultConvention::UnownedInnerPointer; + + auto type = tl.getLoweredType(); + if (type.unwrapOptionalType().getStructOrBoundGenericStruct() + == type.getASTContext().getUnmanagedDecl()) + return ResultConvention::UnownedInnerPointer; + return ResultConvention::Unowned; + } + + // Otherwise, the return type had better be a retainable object pointer. + auto resultType = Method->getReturnType(); + assert(resultType->isObjCRetainableType() || isCFTypedef(tl, resultType)); + + // If it's retainable for the purposes of ObjC ARC, we can trust + // the presence of ns_returns_retained, because Clang will add + // that implicitly based on the method family. + if (resultType->isObjCRetainableType()) { + if (Method->hasAttr()) + return ResultConvention::Owned; + return ResultConvention::Autoreleased; + } + + // Otherwise, it's a CF return type, which unfortunately means + // we can't just trust getMethodFamily(). We should really just + // change that, but that's an annoying change to make to Clang + // right now. + assert(isCFTypedef(tl, resultType)); + + // Trust the explicit attributes. + if (Method->hasAttr()) + return ResultConvention::Owned; + if (Method->hasAttr()) + return ResultConvention::Autoreleased; + + // Otherwise, infer based on the method family. + if (isImplicitPlusOneCFResult()) + return ResultConvention::Owned; + return ResultConvention::Autoreleased; + } + + ParameterConvention + getDirectSelfParameter(const AbstractionPattern &type) const override { + if (Method->hasAttr()) + return ParameterConvention::Direct_Owned; + + // The caller is supposed to take responsibility for ensuring + // that 'self' survives a method call. + return ObjCSelfConvention; + } + + ParameterConvention + getIndirectSelfParameter(const AbstractionPattern &type) const override { + llvm_unreachable("objc methods do not support indirect self parameters"); + } + + static bool classof(const Conventions *C) { + return C->getKind() == ConventionsKind::ObjCMethod; + } +}; + +/// Conventions based on a C function type. +class CFunctionTypeConventions : public Conventions { + const clang::FunctionType *FnType; + + clang::QualType getParamType(unsigned i) const { + return FnType->castAs()->getParamType(i); + } + +protected: + /// Protected constructor for subclasses to override the kind passed to the + /// super class. + CFunctionTypeConventions(ConventionsKind kind, + const clang::FunctionType *type) + : Conventions(kind), FnType(type) {} + +public: + CFunctionTypeConventions(const clang::FunctionType *type) + : Conventions(ConventionsKind::CFunctionType), FnType(type) {} + + ParameterConvention getIndirectParameter(unsigned index, + const AbstractionPattern &type, + const TypeLowering &substTL) const override { + return getIndirectCParameterConvention(getParamType(index)); + } + + ParameterConvention getDirectParameter(unsigned index, + const AbstractionPattern &type, + const TypeLowering &substTL) const override { + if (cast(FnType)->isParamConsumed(index)) + return ParameterConvention::Direct_Owned; + return getDirectCParameterConvention(getParamType(index)); + } + + ParameterConvention getCallee() const override { + // FIXME: blocks should be Direct_Guaranteed. + return ParameterConvention::Direct_Unowned; + } + + ResultConvention getResult(const TypeLowering &tl) const override { + if (tl.isTrivial()) + return ResultConvention::Unowned; + if (FnType->getExtInfo().getProducesResult()) + return ResultConvention::Owned; + return ResultConvention::Autoreleased; + } + + ParameterConvention + getDirectSelfParameter(const AbstractionPattern &type) const override { + llvm_unreachable("c function types do not have a self parameter"); + } + + ParameterConvention + getIndirectSelfParameter(const AbstractionPattern &type) const override { + llvm_unreachable("c function types do not have a self parameter"); + } + + static bool classof(const Conventions *C) { + return C->getKind() == ConventionsKind::CFunctionType; + } +}; + +/// Conventions based on C function declarations. +class CFunctionConventions : public CFunctionTypeConventions { + using super = CFunctionTypeConventions; + const clang::FunctionDecl *TheDecl; +public: + CFunctionConventions(const clang::FunctionDecl *decl) + : CFunctionTypeConventions(ConventionsKind::CFunction, + decl->getType()->castAs()), + TheDecl(decl) {} + + ParameterConvention getDirectParameter(unsigned index, + const AbstractionPattern &type, + const TypeLowering &substTL) const override { + if (auto param = TheDecl->getParamDecl(index)) + if (param->hasAttr()) + return ParameterConvention::Direct_Owned; + return super::getDirectParameter(index, type, substTL); + } + + ResultConvention getResult(const TypeLowering &tl) const override { + if (isCFTypedef(tl, TheDecl->getReturnType())) { + // The CF attributes aren't represented in the type, so we need + // to check them here. + if (TheDecl->hasAttr()) { + return ResultConvention::Owned; + } else if (TheDecl->hasAttr()) { + // Probably not actually autoreleased. + return ResultConvention::Autoreleased; + + // The CF Create/Copy rule only applies to functions that return + // a CF-runtime type; it does not apply to methods, and it does + // not apply to functions returning ObjC types. + } else if (clang::ento::coreFoundation::followsCreateRule(TheDecl)) { + return ResultConvention::Owned; + } else { + return ResultConvention::Autoreleased; + } + } + + // Otherwise, fall back on the ARC annotations, which are part + // of the type. + return super::getResult(tl); + } + + static bool classof(const Conventions *C) { + return C->getKind() == ConventionsKind::CFunction; + } +}; + +/// Conventions based on C++ method declarations. +class CXXMethodConventions : public CFunctionTypeConventions { + using super = CFunctionTypeConventions; + const clang::CXXMethodDecl *TheDecl; + +public: + CXXMethodConventions(const clang::CXXMethodDecl *decl) + : CFunctionTypeConventions( + ConventionsKind::CXXMethod, + decl->getType()->castAs()), + TheDecl(decl) {} + ParameterConvention + getIndirectSelfParameter(const AbstractionPattern &type) const override { + if (TheDecl->isConst()) + return ParameterConvention::Indirect_In_Guaranteed; + return ParameterConvention::Indirect_Inout; + } + ResultConvention getResult(const TypeLowering &resultTL) const override { + if (dyn_cast(TheDecl)) { + return ResultConvention::Indirect; + } + return CFunctionTypeConventions::getResult(resultTL); + } + static bool classof(const Conventions *C) { + return C->getKind() == ConventionsKind::CXXMethod; + } +}; + +} // end anonymous namespace + +/// Given that we have an imported Clang declaration, deduce the +/// ownership conventions for calling it and build the SILFunctionType. +static CanSILFunctionType +getSILFunctionTypeForClangDecl(TypeConverter &TC, const clang::Decl *clangDecl, + CanAnyFunctionType origType, + CanAnyFunctionType substInterfaceType, + AnyFunctionType::ExtInfo extInfo, + const ForeignInfo &foreignInfo, + Optional constant) { + if (auto method = dyn_cast(clangDecl)) { + auto origPattern = + AbstractionPattern::getObjCMethod(origType, method, foreignInfo.Error); + return getSILFunctionType(TC, TypeExpansionContext::minimal(), origPattern, + substInterfaceType, extInfo, + ObjCMethodConventions(method), foreignInfo, + constant, constant, None, + ProtocolConformanceRef()); + } + + if (auto method = dyn_cast(clangDecl)) { + AbstractionPattern origPattern = + AbstractionPattern::getCXXMethod(origType, method); + auto conventions = CXXMethodConventions(method); + return getSILFunctionType(TC, TypeExpansionContext::minimal(), origPattern, + substInterfaceType, extInfo, conventions, + foreignInfo, constant, constant, None, + ProtocolConformanceRef()); + } + + if (auto func = dyn_cast(clangDecl)) { + auto clangType = func->getType().getTypePtr(); + AbstractionPattern origPattern = + foreignInfo.Self.isImportAsMember() + ? AbstractionPattern::getCFunctionAsMethod(origType, clangType, + foreignInfo.Self) + : AbstractionPattern(origType, clangType); + return getSILFunctionType(TC, TypeExpansionContext::minimal(), origPattern, + substInterfaceType, extInfo, + CFunctionConventions(func), foreignInfo, constant, + constant, None, ProtocolConformanceRef()); + } + + llvm_unreachable("call to unknown kind of C function"); +} + +static CanSILFunctionType +getSILFunctionTypeForAbstractCFunction(TypeConverter &TC, + AbstractionPattern origType, + CanAnyFunctionType substType, + AnyFunctionType::ExtInfo extInfo, + Optional constant) { + if (origType.isClangType()) { + auto clangType = origType.getClangType(); + const clang::FunctionType *fnType; + if (auto blockPtr = clangType->getAs()) { + fnType = blockPtr->getPointeeType()->castAs(); + } else if (auto ptr = clangType->getAs()) { + fnType = ptr->getPointeeType()->getAs(); + } else if (auto ref = clangType->getAs()) { + fnType = ref->getPointeeType()->getAs(); + } else if (auto fn = clangType->getAs()) { + fnType = fn; + } else { + llvm_unreachable("unexpected type imported as a function type"); + } + if (fnType) { + return getSILFunctionType( + TC, TypeExpansionContext::minimal(), origType, substType, extInfo, + CFunctionTypeConventions(fnType), ForeignInfo(), constant, constant, + None, ProtocolConformanceRef()); + } + } + + // TODO: Ought to support captures in block funcs. + return getSILFunctionType(TC, TypeExpansionContext::minimal(), origType, + substType, extInfo, DefaultBlockConventions(), + ForeignInfo(), constant, constant, None, + ProtocolConformanceRef()); +} + +/// Try to find a clang method declaration for the given function. +static const clang::Decl *findClangMethod(ValueDecl *method) { + if (auto *methodFn = dyn_cast(method)) { + if (auto *decl = methodFn->getClangDecl()) + return decl; + + if (auto overridden = methodFn->getOverriddenDecl()) + return findClangMethod(overridden); + } + + if (auto *constructor = dyn_cast(method)) { + if (auto *decl = constructor->getClangDecl()) + return decl; + } + + return nullptr; +} + +//===----------------------------------------------------------------------===// +// Selector Family SILFunctionTypes +//===----------------------------------------------------------------------===// + +/// Derive the ObjC selector family from an identifier. +/// +/// Note that this will never derive the Init family, which is too dangerous +/// to leave to chance. Swift functions starting with "init" are always +/// emitted as if they are part of the "none" family. +static ObjCSelectorFamily getObjCSelectorFamily(ObjCSelector name) { + auto result = name.getSelectorFamily(); + + if (result == ObjCSelectorFamily::Init) + return ObjCSelectorFamily::None; + + return result; +} + +/// Get the ObjC selector family a foreign SILDeclRef belongs to. +static ObjCSelectorFamily getObjCSelectorFamily(SILDeclRef c) { + assert(c.isForeign); + switch (c.kind) { + case SILDeclRef::Kind::Func: { + if (!c.hasDecl()) + return ObjCSelectorFamily::None; + + auto *FD = cast(c.getDecl()); + if (auto accessor = dyn_cast(FD)) { + switch (accessor->getAccessorKind()) { + case AccessorKind::Get: + case AccessorKind::Set: + break; +#define OBJC_ACCESSOR(ID, KEYWORD) +#define ACCESSOR(ID) \ + case AccessorKind::ID: +#include "swift/AST/AccessorKinds.def" + llvm_unreachable("Unexpected AccessorKind of foreign FuncDecl"); + } + } + + return getObjCSelectorFamily(FD->getObjCSelector()); + } + case SILDeclRef::Kind::Initializer: + case SILDeclRef::Kind::IVarInitializer: + return ObjCSelectorFamily::Init; + + /// Currently IRGen wraps alloc/init methods into Swift constructors + /// with Swift conventions. + case SILDeclRef::Kind::Allocator: + /// These constants don't correspond to method families we care about yet. + case SILDeclRef::Kind::Destroyer: + case SILDeclRef::Kind::Deallocator: + case SILDeclRef::Kind::IVarDestroyer: + return ObjCSelectorFamily::None; + + case SILDeclRef::Kind::EnumElement: + case SILDeclRef::Kind::GlobalAccessor: + case SILDeclRef::Kind::DefaultArgGenerator: + case SILDeclRef::Kind::StoredPropertyInitializer: + case SILDeclRef::Kind::PropertyWrapperBackingInitializer: + llvm_unreachable("Unexpected Kind of foreign SILDeclRef"); + } + + llvm_unreachable("Unhandled SILDeclRefKind in switch."); +} + +namespace { + +class ObjCSelectorFamilyConventions : public Conventions { + ObjCSelectorFamily Family; + +public: + ObjCSelectorFamilyConventions(ObjCSelectorFamily family) + : Conventions(ConventionsKind::ObjCSelectorFamily), Family(family) {} + + ParameterConvention getIndirectParameter(unsigned index, + const AbstractionPattern &type, + const TypeLowering &substTL) const override { + return ParameterConvention::Indirect_In; + } + + ParameterConvention getDirectParameter(unsigned index, + const AbstractionPattern &type, + const TypeLowering &substTL) const override { + return ParameterConvention::Direct_Unowned; + } + + ParameterConvention getCallee() const override { + // Always thin. + return ParameterConvention::Direct_Unowned; + } + + ResultConvention getResult(const TypeLowering &tl) const override { + switch (Family) { + case ObjCSelectorFamily::Alloc: + case ObjCSelectorFamily::Copy: + case ObjCSelectorFamily::Init: + case ObjCSelectorFamily::MutableCopy: + case ObjCSelectorFamily::New: + return ResultConvention::Owned; + + case ObjCSelectorFamily::None: + // Defaults below. + break; + } + + // Get the underlying AST type, potentially stripping off one level of + // optionality while we do it. + CanType type = tl.getLoweredType().unwrapOptionalType().getASTType(); + if (type->hasRetainablePointerRepresentation() + || (type->getSwiftNewtypeUnderlyingType() && !tl.isTrivial())) + return ResultConvention::Autoreleased; + + return ResultConvention::Unowned; + } + + ParameterConvention + getDirectSelfParameter(const AbstractionPattern &type) const override { + if (Family == ObjCSelectorFamily::Init) + return ParameterConvention::Direct_Owned; + return ObjCSelfConvention; + } + + ParameterConvention + getIndirectSelfParameter(const AbstractionPattern &type) const override { + llvm_unreachable("selector family objc function types do not support " + "indirect self parameters"); + } + + static bool classof(const Conventions *C) { + return C->getKind() == ConventionsKind::ObjCSelectorFamily; + } +}; + +} // end anonymous namespace + +static CanSILFunctionType +getSILFunctionTypeForObjCSelectorFamily(TypeConverter &TC, ObjCSelectorFamily family, + CanAnyFunctionType origType, + CanAnyFunctionType substInterfaceType, + AnyFunctionType::ExtInfo extInfo, + const ForeignInfo &foreignInfo, + Optional constant) { + return getSILFunctionType( + TC, TypeExpansionContext::minimal(), AbstractionPattern(origType), + substInterfaceType, extInfo, ObjCSelectorFamilyConventions(family), + foreignInfo, constant, constant, + /*requirement subs*/ None, ProtocolConformanceRef()); +} + +static bool isImporterGeneratedAccessor(const clang::Decl *clangDecl, + SILDeclRef constant) { + // Must be an accessor. + auto accessor = dyn_cast(constant.getDecl()); + if (!accessor) + return false; + + // Must be a type member. + if (constant.getParameterListCount() != 2) + return false; + + // Must be imported from a function. + if (!isa(clangDecl)) + return false; + + return true; +} + +static CanSILFunctionType getUncachedSILFunctionTypeForConstant( + TypeConverter &TC, TypeExpansionContext context, SILDeclRef constant, + CanAnyFunctionType origLoweredInterfaceType) { + assert(origLoweredInterfaceType->getExtInfo().getSILRepresentation() + != SILFunctionTypeRepresentation::Thick + && origLoweredInterfaceType->getExtInfo().getSILRepresentation() + != SILFunctionTypeRepresentation::Block); + + auto extInfo = origLoweredInterfaceType->getExtInfo(); + + if (!constant.isForeign) { + ProtocolConformanceRef witnessMethodConformance; + + if (extInfo.getSILRepresentation() == + SILFunctionTypeRepresentation::WitnessMethod) { + auto proto = constant.getDecl()->getDeclContext()->getSelfProtocolDecl(); + witnessMethodConformance = ProtocolConformanceRef(proto); + } + + return ::getNativeSILFunctionType( + TC, context, AbstractionPattern(origLoweredInterfaceType), + origLoweredInterfaceType, extInfo, constant, constant, None, + witnessMethodConformance); + } + + ForeignInfo foreignInfo; + + // If we have a clang decl associated with the Swift decl, derive its + // ownership conventions. + if (constant.hasDecl()) { + auto decl = constant.getDecl(); + if (auto funcDecl = dyn_cast(decl)) { + foreignInfo.Error = funcDecl->getForeignErrorConvention(); + foreignInfo.Self = funcDecl->getImportAsMemberStatus(); + } + + if (auto clangDecl = findClangMethod(decl)) { + // The importer generates accessors that are not actually + // import-as-member but do involve the same gymnastics with the + // formal type. That's all that SILFunctionType cares about, so + // pretend that it's import-as-member. + if (!foreignInfo.Self.isImportAsMember() && + isImporterGeneratedAccessor(clangDecl, constant)) { + unsigned selfIndex = cast(decl)->isSetter() ? 1 : 0; + foreignInfo.Self.setSelfIndex(selfIndex); + } + + return getSILFunctionTypeForClangDecl(TC, clangDecl, + origLoweredInterfaceType, + origLoweredInterfaceType, + extInfo, foreignInfo, constant); + } + } + + // If the decl belongs to an ObjC method family, use that family's + // ownership conventions. + return getSILFunctionTypeForObjCSelectorFamily( + TC, getObjCSelectorFamily(constant), + origLoweredInterfaceType, origLoweredInterfaceType, + extInfo, foreignInfo, constant); +} + +CanSILFunctionType TypeConverter::getUncachedSILFunctionTypeForConstant( + TypeExpansionContext context, SILDeclRef constant, + CanAnyFunctionType origInterfaceType) { + auto origLoweredInterfaceType = + getLoweredFormalTypes(constant, origInterfaceType).Uncurried; + return ::getUncachedSILFunctionTypeForConstant(*this, context, constant, + origLoweredInterfaceType); +} + +static bool isClassOrProtocolMethod(ValueDecl *vd) { + if (!vd->getDeclContext()) + return false; + Type contextType = vd->getDeclContext()->getDeclaredInterfaceType(); + if (!contextType) + return false; + return contextType->getClassOrBoundGenericClass() + || contextType->isClassExistentialType(); +} + +SILFunctionTypeRepresentation +TypeConverter::getDeclRefRepresentation(SILDeclRef c) { + // If this is a foreign thunk, it always has the foreign calling convention. + if (c.isForeign) { + if (!c.hasDecl() || + c.getDecl()->isImportAsMember()) + return SILFunctionTypeRepresentation::CFunctionPointer; + + if (isClassOrProtocolMethod(c.getDecl()) || + c.kind == SILDeclRef::Kind::IVarInitializer || + c.kind == SILDeclRef::Kind::IVarDestroyer) + return SILFunctionTypeRepresentation::ObjCMethod; + + return SILFunctionTypeRepresentation::CFunctionPointer; + } + + // Anonymous functions currently always have Freestanding CC. + if (!c.hasDecl()) + return SILFunctionTypeRepresentation::Thin; + + // FIXME: Assert that there is a native entry point + // available. There's no great way to do this. + + // Protocol witnesses are called using the witness calling convention. + if (auto proto = dyn_cast(c.getDecl()->getDeclContext())) { + // Use the regular method convention for foreign-to-native thunks. + if (c.isForeignToNativeThunk()) + return SILFunctionTypeRepresentation::Method; + assert(!c.isNativeToForeignThunk() && "shouldn't be possible"); + return getProtocolWitnessRepresentation(proto); + } + + switch (c.kind) { + case SILDeclRef::Kind::GlobalAccessor: + case SILDeclRef::Kind::DefaultArgGenerator: + case SILDeclRef::Kind::StoredPropertyInitializer: + case SILDeclRef::Kind::PropertyWrapperBackingInitializer: + return SILFunctionTypeRepresentation::Thin; + + case SILDeclRef::Kind::Func: + if (c.getDecl()->getDeclContext()->isTypeContext()) + return SILFunctionTypeRepresentation::Method; + return SILFunctionTypeRepresentation::Thin; + + case SILDeclRef::Kind::Destroyer: + case SILDeclRef::Kind::Deallocator: + case SILDeclRef::Kind::Allocator: + case SILDeclRef::Kind::Initializer: + case SILDeclRef::Kind::EnumElement: + case SILDeclRef::Kind::IVarInitializer: + case SILDeclRef::Kind::IVarDestroyer: + return SILFunctionTypeRepresentation::Method; + } + + llvm_unreachable("Unhandled SILDeclRefKind in switch."); +} + +// Provide the ability to turn off the type converter cache to ease debugging. +static llvm::cl::opt + DisableConstantInfoCache("sil-disable-typelowering-constantinfo-cache", + llvm::cl::init(false)); + +const SILConstantInfo & +TypeConverter::getConstantInfo(TypeExpansionContext expansion, + SILDeclRef constant) { + if (!DisableConstantInfoCache) { + auto found = ConstantTypes.find(std::make_pair(expansion, constant)); + if (found != ConstantTypes.end()) + return *found->second; + } + + // First, get a function type for the constant. This creates the + // right type for a getter or setter. + auto formalInterfaceType = makeConstantInterfaceType(constant); + + // The formal type is just that with the right representation. + auto rep = getDeclRefRepresentation(constant); + formalInterfaceType = adjustFunctionType(formalInterfaceType, rep); + + // The lowered type is the formal type, but uncurried and with + // parameters automatically turned into their bridged equivalents. + auto bridgedTypes = getLoweredFormalTypes(constant, formalInterfaceType); + + CanAnyFunctionType loweredInterfaceType = bridgedTypes.Uncurried; + + // The SIL type encodes conventions according to the original type. + CanSILFunctionType silFnType = + ::getUncachedSILFunctionTypeForConstant(*this, expansion, constant, + loweredInterfaceType); + + // If the constant refers to a derivative function, get the SIL type of the + // original function and use it to compute the derivative SIL type. + // + // This is necessary because the "lowered AST derivative function type" (BC) + // may differ from the "derivative type of the lowered original function type" + // (AD): + // + // +--------------------+ lowering +--------------------+ + // | AST orig. fn type | -------(A)------> | SIL orig. fn type | + // +--------------------+ +--------------------+ + // | | + // (B, Sema) getAutoDiffDerivativeFunctionType (D, here) + // V V + // +--------------------+ lowering +--------------------+ + // | AST deriv. fn type | -------(C)------> | SIL deriv. fn type | + // +--------------------+ +--------------------+ + // + // (AD) does not always commute with (BC): + // - (BC) is the result of computing the AST derivative type (Sema), then + // lowering it via SILGen. This is the default lowering behavior, but may + // break SIL typing invariants because expected lowered derivative types are + // computed from lowered original function types. + // - (AD) is the result of lowering the original function type, then computing + // its derivative type. This is the expected lowered derivative type, + // preserving SIL typing invariants. + // + // Always use (AD) to compute lowered derivative function types. + if (auto *derivativeId = constant.derivativeFunctionIdentifier) { + // Get lowered original function type. + auto origFnConstantInfo = getConstantInfo( + TypeExpansionContext::minimal(), constant.asAutoDiffOriginalFunction()); + // Use it to compute lowered derivative function type. + auto *loweredIndices = autodiff::getLoweredParameterIndices( + derivativeId->getParameterIndices(), formalInterfaceType); + silFnType = origFnConstantInfo.SILFnType->getAutoDiffDerivativeFunctionType( + loweredIndices, /*resultIndex*/ 0, derivativeId->getKind(), *this, + LookUpConformanceInModule(&M)); + } + + LLVM_DEBUG(llvm::dbgs() << "lowering type for constant "; + constant.print(llvm::dbgs()); + llvm::dbgs() << "\n formal type: "; + formalInterfaceType.print(llvm::dbgs()); + llvm::dbgs() << "\n lowered AST type: "; + loweredInterfaceType.print(llvm::dbgs()); + llvm::dbgs() << "\n SIL type: "; + silFnType.print(llvm::dbgs()); + llvm::dbgs() << "\n Expansion context: " + << expansion.shouldLookThroughOpaqueTypeArchetypes(); + llvm::dbgs() << "\n"); + + auto resultBuf = Context.Allocate(sizeof(SILConstantInfo), + alignof(SILConstantInfo)); + + auto result = ::new (resultBuf) SILConstantInfo{formalInterfaceType, + bridgedTypes.Pattern, + loweredInterfaceType, + silFnType}; + if (DisableConstantInfoCache) + return *result; + + auto inserted = + ConstantTypes.insert({std::make_pair(expansion, constant), result}); + assert(inserted.second); + (void)inserted; + return *result; +} + +/// Returns the SILParameterInfo for the given declaration's `self` parameter. +/// `constant` must refer to a method. +SILParameterInfo +TypeConverter::getConstantSelfParameter(TypeExpansionContext context, + SILDeclRef constant) { + auto ty = getConstantFunctionType(context, constant); + + // In most cases the "self" parameter is lowered as the back parameter. + // The exception is C functions imported as methods. + if (!constant.isForeign) + return ty->getParameters().back(); + if (!constant.hasDecl()) + return ty->getParameters().back(); + auto fn = dyn_cast(constant.getDecl()); + if (!fn) + return ty->getParameters().back(); + if (fn->isImportAsStaticMember()) + return SILParameterInfo(); + if (fn->isImportAsInstanceMember()) + return ty->getParameters()[fn->getSelfIndex()]; + return ty->getParameters().back(); +} + +// This check duplicates TypeConverter::checkForABIDifferences(), +// but on AST types. The issue is we only want to introduce a new +// vtable thunk if the AST type changes, but an abstraction change +// is OK; we don't want a new entry if an @in parameter became +// @guaranteed or whatever. +static bool checkASTTypeForABIDifferences(CanType type1, + CanType type2) { + return !type1->matches(type2, TypeMatchFlags::AllowABICompatible); +} + +// FIXME: This makes me very upset. Can we do without this? +static CanType copyOptionalityFromDerivedToBase(TypeConverter &tc, + CanType derived, + CanType base) { + // Unwrap optionals, but remember that we did. + bool derivedWasOptional = false; + if (auto object = derived.getOptionalObjectType()) { + derivedWasOptional = true; + derived = object; + } + if (auto object = base.getOptionalObjectType()) { + base = object; + } + + // T? +> S = (T +> S)? + // T? +> S? = (T +> S)? + if (derivedWasOptional) { + base = copyOptionalityFromDerivedToBase(tc, derived, base); + + auto optDecl = tc.Context.getOptionalDecl(); + return CanType(BoundGenericEnumType::get(optDecl, Type(), base)); + } + + // (T1, T2, ...) +> (S1, S2, ...) = (T1 +> S1, T2 +> S2, ...) + if (auto derivedTuple = dyn_cast(derived)) { + if (auto baseTuple = dyn_cast(base)) { + assert(derivedTuple->getNumElements() == baseTuple->getNumElements()); + SmallVector elements; + for (unsigned i = 0, e = derivedTuple->getNumElements(); i < e; i++) { + elements.push_back( + baseTuple->getElement(i).getWithType( + copyOptionalityFromDerivedToBase( + tc, + derivedTuple.getElementType(i), + baseTuple.getElementType(i)))); + } + return CanType(TupleType::get(elements, tc.Context)); + } + } + + // (T1 -> T2) +> (S1 -> S2) = (T1 +> S1) -> (T2 +> S2) + if (auto derivedFunc = dyn_cast(derived)) { + if (auto baseFunc = dyn_cast(base)) { + SmallVector params; + + auto derivedParams = derivedFunc.getParams(); + auto baseParams = baseFunc.getParams(); + assert(derivedParams.size() == baseParams.size()); + for (unsigned i = 0, e = derivedParams.size(); i < e; i++) { + assert(derivedParams[i].getParameterFlags() == + baseParams[i].getParameterFlags()); + + params.emplace_back( + copyOptionalityFromDerivedToBase( + tc, + derivedParams[i].getPlainType(), + baseParams[i].getPlainType()), + Identifier(), + baseParams[i].getParameterFlags()); + } + + auto result = copyOptionalityFromDerivedToBase(tc, + derivedFunc.getResult(), + baseFunc.getResult()); + return CanAnyFunctionType::get(baseFunc.getOptGenericSignature(), + llvm::makeArrayRef(params), result, + baseFunc->getExtInfo()); + } + } + + return base; +} + +/// Returns the ConstantInfo corresponding to the VTable thunk for overriding. +/// Will be the same as getConstantInfo if the declaration does not override. +const SILConstantInfo & +TypeConverter::getConstantOverrideInfo(TypeExpansionContext context, + SILDeclRef derived, SILDeclRef base) { + // Foreign overrides currently don't need reabstraction. + if (derived.isForeign) + return getConstantInfo(context, derived); + + auto found = ConstantOverrideTypes.find({derived, base}); + if (found != ConstantOverrideTypes.end()) + return *found->second; + + assert(base.requiresNewVTableEntry() && "base must not be an override"); + + // Figure out the generic signature for the class method call. This is the + // signature of the derived class, with requirements transplanted from + // the base method. The derived method is allowed to have fewer + // requirements, in which case the thunk will translate the calling + // convention appropriately before calling the derived method. + bool hasGenericRequirementDifference = false; + + auto derivedSig = derived.getDecl()->getAsGenericContext() + ->getGenericSignature(); + auto genericSig = Context.getOverrideGenericSignature(base.getDecl(), + derived.getDecl()); + if (genericSig) { + hasGenericRequirementDifference = + !genericSig->requirementsNotSatisfiedBy(derivedSig).empty(); + } + + auto baseInfo = getConstantInfo(context, base); + auto derivedInfo = getConstantInfo(context, derived); + + auto params = derivedInfo.FormalType.getParams(); + assert(params.size() == 1); + auto selfInterfaceTy = params[0].getPlainType()->getMetatypeInstanceType(); + + auto overrideInterfaceTy = + cast( + selfInterfaceTy->adjustSuperclassMemberDeclType( + base.getDecl(), derived.getDecl(), baseInfo.FormalType) + ->getCanonicalType()); + + // Build the formal AST function type for the class method call. + auto basePattern = AbstractionPattern(baseInfo.LoweredType); + + if (!hasGenericRequirementDifference && + !checkASTTypeForABIDifferences(derivedInfo.FormalType, + overrideInterfaceTy)) { + + // The derived method is ABI-compatible with the base method. Let's + // just use the derived method's formal type. + basePattern = AbstractionPattern( + copyOptionalityFromDerivedToBase( + *this, + derivedInfo.LoweredType, + baseInfo.LoweredType)); + overrideInterfaceTy = derivedInfo.FormalType; + } + + if (genericSig && !genericSig->areAllParamsConcrete()) { + overrideInterfaceTy = + cast( + GenericFunctionType::get(genericSig, + overrideInterfaceTy->getParams(), + overrideInterfaceTy->getResult(), + overrideInterfaceTy->getExtInfo()) + ->getCanonicalType()); + } + + // Build the lowered AST function type for the class method call. + auto bridgedTypes = getLoweredFormalTypes(derived, overrideInterfaceTy); + + // Build the SILFunctionType for the class method call. + CanSILFunctionType fnTy = getNativeSILFunctionType( + *this, context, basePattern, bridgedTypes.Uncurried, base, derived, + /*reqt subs*/ None, ProtocolConformanceRef()); + + // Build the SILConstantInfo and cache it. + auto resultBuf = Context.Allocate(sizeof(SILConstantInfo), + alignof(SILConstantInfo)); + auto result = ::new (resultBuf) SILConstantInfo{ + overrideInterfaceTy, + basePattern, + bridgedTypes.Uncurried, + fnTy}; + + auto inserted = ConstantOverrideTypes.insert({{derived, base}, result}); + assert(inserted.second); + (void)inserted; + return *result; +} + +namespace { + +/// Given a lowered SIL type, apply a substitution to it to produce another +/// lowered SIL type which uses the same abstraction conventions. +class SILTypeSubstituter : + public CanTypeVisitor { + TypeConverter &TC; + TypeSubstitutionFn Subst; + LookupConformanceFn Conformances; + // The signature for the original type. + // + // Replacement types are lowered with respect to the current + // context signature. + CanGenericSignature Sig; + + TypeExpansionContext typeExpansionContext; + + bool shouldSubstituteOpaqueArchetypes; + +public: + SILTypeSubstituter(TypeConverter &TC, + TypeExpansionContext context, + TypeSubstitutionFn Subst, + LookupConformanceFn Conformances, + CanGenericSignature Sig, + bool shouldSubstituteOpaqueArchetypes) + : TC(TC), + Subst(Subst), + Conformances(Conformances), + Sig(Sig), + typeExpansionContext(context), + shouldSubstituteOpaqueArchetypes(shouldSubstituteOpaqueArchetypes) + {} + + // SIL type lowering only does special things to tuples and functions. + + // When a function appears inside of another type, we only perform + // substitutions if it is not polymorphic. + CanSILFunctionType visitSILFunctionType(CanSILFunctionType origType) { + return substSILFunctionType(origType, false); + } + + SubstitutionMap substSubstitutions(SubstitutionMap subs) { + // Substitute the substitutions. + SubstOptions options = None; + if (shouldSubstituteOpaqueArchetypes) + options |= SubstFlags::SubstituteOpaqueArchetypes; + + // Expand substituted type according to the expansion context. + auto newSubs = subs.subst(Subst, Conformances, options); + + // If we need to look through opaque types in this context, re-substitute + // according to the expansion context. + newSubs = substOpaqueTypes(newSubs); + + return newSubs; + } + + SubstitutionMap substOpaqueTypes(SubstitutionMap subs) { + if (!typeExpansionContext.shouldLookThroughOpaqueTypeArchetypes()) + return subs; + + return subs.subst([&](SubstitutableType *s) -> Type { + return substOpaqueTypesWithUnderlyingTypes(s->getCanonicalType(), + typeExpansionContext); + }, [&](CanType dependentType, + Type conformingReplacementType, + ProtocolDecl *conformedProtocol) -> ProtocolConformanceRef { + return substOpaqueTypesWithUnderlyingTypes( + ProtocolConformanceRef(conformedProtocol), + conformingReplacementType->getCanonicalType(), + typeExpansionContext); + }, SubstFlags::SubstituteOpaqueArchetypes); + } + + // Substitute a function type. + CanSILFunctionType substSILFunctionType(CanSILFunctionType origType, + bool isGenericApplication) { + assert((!isGenericApplication || origType->isPolymorphic()) && + "generic application without invocation signature or with " + "existing arguments"); + assert((!isGenericApplication || !shouldSubstituteOpaqueArchetypes) && + "generic application while substituting opaque archetypes"); + + // The general substitution rule is that we should only substitute + // into the free components of the type, i.e. the components that + // aren't inside a generic signature. That rule would say: + // + // - If there are invocation substitutions, just substitute those; + // the other components are necessarily inside the invocation + // generic signature. + // + // - Otherwise, if there's an invocation generic signature, + // substitute nothing. If we are applying generic arguments, + // add the appropriate invocation substitutions. + // + // - Otherwise, if there are pattern substitutions, just substitute + // those; the other components are inside the patttern generic + // signature. + // + // - Otherwise, substitute the basic components. + // + // There are two caveats here. The first is that we haven't yet + // written all the code that would be necessary in order to handle + // invocation substitutions everywhere, and so we never build those. + // Instead, we substitute into the pattern substitutions if present, + // or the components if not, and build a type with no invocation + // signature. As a special case, when substituting a coroutine type, + // we build pattern substitutions instead of substituting the + // component types in order to preserve the original yield structure, + // which factors into the continuation function ABI. + // + // The second is that this function is also used when substituting + // opaque archetypes. In this case, we may need to substitute + // into component types even within generic signatures. This is + // safe because the substitutions used in this case don't change + // generics, they just narrowly look through certain opaque archetypes. + // If substitutions are present, we still don't substitute into + // the basic components, in order to maintain the information about + // what was abstracted there. + + auto patternSubs = origType->getPatternSubstitutions(); + + // If we have an invocation signatture, we generally shouldn't + // substitute into the pattern substitutions and component types. + if (auto sig = origType->getInvocationGenericSignature()) { + // Substitute the invocation substitutions if present. + if (auto invocationSubs = origType->getInvocationSubstitutions()) { + assert(!isGenericApplication); + invocationSubs = substSubstitutions(invocationSubs); + auto substType = + origType->withInvocationSubstitutions(invocationSubs); + + // Also do opaque-type substitutions on the pattern substitutions + // if requested and applicable. + if (patternSubs) { + patternSubs = substOpaqueTypes(patternSubs); + substType = substType->withPatternSubstitutions(patternSubs); + } + + return substType; + } + + // Otherwise, we shouldn't substitute any components except + // when substituting opaque archetypes. + + // If we're doing a generic application, and there are pattern + // substitutions, substitute into the pattern substitutions; or if + // it's a coroutine, build pattern substitutions; or else, fall + // through to substitute the component types as discussed above. + if (isGenericApplication) { + if (patternSubs || origType->isCoroutine()) { + CanSILFunctionType substType = origType; + if (typeExpansionContext.shouldLookThroughOpaqueTypeArchetypes()) { + substType = + origType->substituteOpaqueArchetypes(TC, typeExpansionContext); + } + + SubstitutionMap subs; + if (patternSubs) { + subs = substSubstitutions(patternSubs); + } else { + subs = SubstitutionMap::get(sig, Subst, Conformances); + } + auto witnessConformance = substWitnessConformance(origType); + substType = substType->withPatternSpecialization(nullptr, subs, + witnessConformance); + + return substType; + } + // else fall down to component substitution + + // If we're substituting opaque archetypes, and there are pattern + // substitutions present, just substitute those and preserve the + // basic structure in the component types. Otherwise, fall through + // to substitute the component types. + } else if (shouldSubstituteOpaqueArchetypes) { + if (patternSubs) { + patternSubs = substOpaqueTypes(patternSubs); + auto witnessConformance = substWitnessConformance(origType); + return origType->withPatternSpecialization(sig, patternSubs, + witnessConformance); + } + // else fall down to component substitution + + // Otherwise, don't try to substitute bound components. + } else { + auto substType = origType; + if (patternSubs) { + patternSubs = substOpaqueTypes(patternSubs); + auto witnessConformance = substWitnessConformance(origType); + substType = substType->withPatternSpecialization(sig, patternSubs, + witnessConformance); + } + return substType; + } + + // Otherwise, if there are pattern substitutions, just substitute + // into those and don't touch the component types. + } else if (patternSubs) { + patternSubs = substSubstitutions(patternSubs); + auto witnessConformance = substWitnessConformance(origType); + return origType->withPatternSpecialization(nullptr, patternSubs, + witnessConformance); + } + + // Otherwise, we need to substitute component types. + + SmallVector substResults; + substResults.reserve(origType->getNumResults()); + for (auto origResult : origType->getResults()) { + substResults.push_back(substInterface(origResult)); + } + + auto substErrorResult = origType->getOptionalErrorResult(); + assert(!substErrorResult || + (!substErrorResult->getInterfaceType()->hasTypeParameter() && + !substErrorResult->getInterfaceType()->hasArchetype())); + + SmallVector substParams; + substParams.reserve(origType->getParameters().size()); + for (auto &origParam : origType->getParameters()) { + substParams.push_back(substInterface(origParam)); + } + + SmallVector substYields; + substYields.reserve(origType->getYields().size()); + for (auto &origYield : origType->getYields()) { + substYields.push_back(substInterface(origYield)); + } + + auto witnessMethodConformance = substWitnessConformance(origType); + + // The substituted type is no longer generic, so it'd never be + // pseudogeneric. + auto extInfo = origType->getExtInfo(); + if (!shouldSubstituteOpaqueArchetypes) + extInfo = extInfo.withIsPseudogeneric(false); + + auto genericSig = shouldSubstituteOpaqueArchetypes + ? origType->getInvocationGenericSignature() + : nullptr; + + return SILFunctionType::get(genericSig, extInfo, + origType->getCoroutineKind(), + origType->getCalleeConvention(), substParams, + substYields, substResults, substErrorResult, + SubstitutionMap(), SubstitutionMap(), + TC.Context, witnessMethodConformance); + } + + ProtocolConformanceRef substWitnessConformance(CanSILFunctionType origType) { + auto conformance = origType->getWitnessMethodConformanceOrInvalid(); + if (!conformance) return conformance; + + assert(origType->getExtInfo().hasSelfParam()); + auto selfType = origType->getSelfParameter().getInterfaceType(); + + // The Self type can be nested in a few layers of metatypes (etc.). + while (auto metatypeType = dyn_cast(selfType)) { + auto next = metatypeType.getInstanceType(); + if (next == selfType) + break; + selfType = next; + } + + auto substConformance = + conformance.subst(selfType, Subst, Conformances); + + // Substitute the underlying conformance of opaque type archetypes if we + // should look through opaque archetypes. + if (typeExpansionContext.shouldLookThroughOpaqueTypeArchetypes()) { + SubstOptions substOptions(None); + auto substType = selfType.subst(Subst, Conformances, substOptions) + ->getCanonicalType(); + if (substType->hasOpaqueArchetype()) { + substConformance = substOpaqueTypesWithUnderlyingTypes( + substConformance, substType, typeExpansionContext); + } + } + + return substConformance; + } + + SILType subst(SILType type) { + return SILType::getPrimitiveType(visit(type.getASTType()), + type.getCategory()); + } + + SILResultInfo substInterface(SILResultInfo orig) { + return SILResultInfo(visit(orig.getInterfaceType()), orig.getConvention()); + } + + SILYieldInfo substInterface(SILYieldInfo orig) { + return SILYieldInfo(visit(orig.getInterfaceType()), orig.getConvention()); + } + + SILParameterInfo substInterface(SILParameterInfo orig) { + return SILParameterInfo(visit(orig.getInterfaceType()), + orig.getConvention(), orig.getDifferentiability()); + } + + /// Tuples need to have their component types substituted by these + /// same rules. + CanType visitTupleType(CanTupleType origType) { + // Fast-path the empty tuple. + if (origType->getNumElements() == 0) return origType; + + SmallVector substElts; + substElts.reserve(origType->getNumElements()); + for (auto &origElt : origType->getElements()) { + auto substEltType = visit(CanType(origElt.getType())); + substElts.push_back(origElt.getWithType(substEltType)); + } + return CanType(TupleType::get(substElts, TC.Context)); + } + // Block storage types need to substitute their capture type by these same + // rules. + CanType visitSILBlockStorageType(CanSILBlockStorageType origType) { + auto substCaptureType = visit(origType->getCaptureType()); + return SILBlockStorageType::get(substCaptureType); + } + + /// Optionals need to have their object types substituted by these rules. + CanType visitBoundGenericEnumType(CanBoundGenericEnumType origType) { + // Only use a special rule if it's Optional. + if (!origType->getDecl()->isOptionalDecl()) { + return visitType(origType); + } + + CanType origObjectType = origType.getGenericArgs()[0]; + CanType substObjectType = visit(origObjectType); + return CanType(BoundGenericType::get(origType->getDecl(), Type(), + substObjectType)); + } + + /// Any other type would be a valid type in the AST. Just apply the + /// substitution on the AST level and then lower that. + CanType visitType(CanType origType) { + assert(!isa(origType)); + assert(!isa(origType) && !isa(origType)); + + SubstOptions substOptions(None); + if (shouldSubstituteOpaqueArchetypes) + substOptions = SubstFlags::SubstituteOpaqueArchetypes | + SubstFlags::AllowLoweredTypes; + auto substType = + origType.subst(Subst, Conformances, substOptions)->getCanonicalType(); + + // If the substitution didn't change anything, we know that the + // original type was a lowered type, so we're good. + if (origType == substType) { + return origType; + } + + AbstractionPattern abstraction(Sig, origType); + return TC.getLoweredRValueType(typeExpansionContext, abstraction, + substType); + } +}; + +} // end anonymous namespace + +SILType SILType::subst(TypeConverter &tc, TypeSubstitutionFn subs, + LookupConformanceFn conformances, + CanGenericSignature genericSig, + bool shouldSubstituteOpaqueArchetypes) const { + if (!hasArchetype() && !hasTypeParameter() && + (!shouldSubstituteOpaqueArchetypes || + !getASTType()->hasOpaqueArchetype())) + return *this; + + SILTypeSubstituter STST(tc, TypeExpansionContext::minimal(), subs, + conformances, genericSig, + shouldSubstituteOpaqueArchetypes); + return STST.subst(*this); +} + +SILType SILType::subst(SILModule &M, TypeSubstitutionFn subs, + LookupConformanceFn conformances, + CanGenericSignature genericSig, + bool shouldSubstituteOpaqueArchetypes) const { + return subst(M.Types, subs, conformances, genericSig, + shouldSubstituteOpaqueArchetypes); +} + +SILType SILType::subst(TypeConverter &tc, SubstitutionMap subs) const { + auto sig = subs.getGenericSignature(); + return subst(tc, QuerySubstitutionMap{subs}, + LookUpConformanceInSubstitutionMap(subs), + sig.getCanonicalSignature()); +} +SILType SILType::subst(SILModule &M, SubstitutionMap subs) const{ + return subst(M.Types, subs); +} + +/// Apply a substitution to this polymorphic SILFunctionType so that +/// it has the form of the normal SILFunctionType for the substituted +/// type, except using the original conventions. +CanSILFunctionType +SILFunctionType::substGenericArgs(SILModule &silModule, SubstitutionMap subs, + TypeExpansionContext context) { + if (!isPolymorphic()) { + return CanSILFunctionType(this); + } + + if (subs.empty()) { + return CanSILFunctionType(this); + } + + return substGenericArgs(silModule, + QuerySubstitutionMap{subs}, + LookUpConformanceInSubstitutionMap(subs), + context); +} + +CanSILFunctionType +SILFunctionType::substGenericArgs(SILModule &silModule, + TypeSubstitutionFn subs, + LookupConformanceFn conformances, + TypeExpansionContext context) { + if (!isPolymorphic()) return CanSILFunctionType(this); + SILTypeSubstituter substituter(silModule.Types, context, subs, conformances, + getSubstGenericSignature(), + /*shouldSubstituteOpaqueTypes*/ false); + return substituter.substSILFunctionType(CanSILFunctionType(this), true); +} + +CanSILFunctionType +SILFunctionType::substituteOpaqueArchetypes(TypeConverter &TC, + TypeExpansionContext context) { + if (!hasOpaqueArchetype() || + !context.shouldLookThroughOpaqueTypeArchetypes()) + return CanSILFunctionType(this); + + ReplaceOpaqueTypesWithUnderlyingTypes replacer( + context.getContext(), context.getResilienceExpansion(), + context.isWholeModuleContext()); + + SILTypeSubstituter substituter(TC, context, replacer, replacer, + getSubstGenericSignature(), + /*shouldSubstituteOpaqueTypes*/ true); + auto resTy = + substituter.substSILFunctionType(CanSILFunctionType(this), false); + + return resTy; +} + +/// Fast path for bridging types in a function type without uncurrying. +CanAnyFunctionType +TypeConverter::getBridgedFunctionType(AbstractionPattern pattern, + CanAnyFunctionType t, + AnyFunctionType::ExtInfo extInfo, + Bridgeability bridging) { + // Pull out the generic signature. + CanGenericSignature genericSig = t.getOptGenericSignature(); + + switch (auto rep = t->getExtInfo().getSILRepresentation()) { + case SILFunctionTypeRepresentation::Thick: + case SILFunctionTypeRepresentation::Thin: + case SILFunctionTypeRepresentation::Method: + case SILFunctionTypeRepresentation::Closure: + case SILFunctionTypeRepresentation::WitnessMethod: { + // No bridging needed for native functions. + if (t->getExtInfo() == extInfo) + return t; + return CanAnyFunctionType::get(genericSig, t.getParams(), t.getResult(), + extInfo); + } + + case SILFunctionTypeRepresentation::CFunctionPointer: + case SILFunctionTypeRepresentation::Block: + case SILFunctionTypeRepresentation::ObjCMethod: { + SmallVector params; + getBridgedParams(rep, pattern, t->getParams(), params, bridging); + + bool suppressOptional = pattern.hasForeignErrorStrippingResultOptionality(); + auto result = getBridgedResultType(rep, + pattern.getFunctionResultType(), + t.getResult(), + bridging, + suppressOptional); + + return CanAnyFunctionType::get(genericSig, llvm::makeArrayRef(params), + result, extInfo); + } + } + llvm_unreachable("bad calling convention"); +} + +static AbstractFunctionDecl *getBridgedFunction(SILDeclRef declRef) { + switch (declRef.kind) { + case SILDeclRef::Kind::Func: + case SILDeclRef::Kind::Allocator: + case SILDeclRef::Kind::Initializer: + return (declRef.hasDecl() + ? cast(declRef.getDecl()) + : nullptr); + + case SILDeclRef::Kind::EnumElement: + case SILDeclRef::Kind::Destroyer: + case SILDeclRef::Kind::Deallocator: + case SILDeclRef::Kind::GlobalAccessor: + case SILDeclRef::Kind::DefaultArgGenerator: + case SILDeclRef::Kind::StoredPropertyInitializer: + case SILDeclRef::Kind::PropertyWrapperBackingInitializer: + case SILDeclRef::Kind::IVarInitializer: + case SILDeclRef::Kind::IVarDestroyer: + return nullptr; + } + llvm_unreachable("bad SILDeclRef kind"); +} + +static AbstractionPattern +getAbstractionPatternForConstant(ASTContext &ctx, SILDeclRef constant, + CanAnyFunctionType fnType, + unsigned numParameterLists) { + if (!constant.isForeign) + return AbstractionPattern(fnType); + + auto bridgedFn = getBridgedFunction(constant); + if (!bridgedFn) + return AbstractionPattern(fnType); + const clang::Decl *clangDecl = bridgedFn->getClangDecl(); + if (!clangDecl) + return AbstractionPattern(fnType); + + // Don't implicitly turn non-optional results to optional if + // we're going to apply a foreign error convention that checks + // for nil results. + if (auto method = dyn_cast(clangDecl)) { + assert(numParameterLists == 2 && "getting curried ObjC method type?"); + auto foreignError = bridgedFn->getForeignErrorConvention(); + return AbstractionPattern::getCurriedObjCMethod(fnType, method, + foreignError); + } else if (auto value = dyn_cast(clangDecl)) { + if (numParameterLists == 1) { + // C function imported as a function. + return AbstractionPattern(fnType, value->getType().getTypePtr()); + } else { + assert(numParameterLists == 2); + if (auto method = dyn_cast(clangDecl)) { + // C++ method. + return AbstractionPattern::getCurriedCXXMethod(fnType, bridgedFn); + } else { + // C function imported as a method. + return AbstractionPattern::getCurriedCFunctionAsMethod(fnType, + bridgedFn); + } + } + } + + return AbstractionPattern(fnType); +} + +TypeConverter::LoweredFormalTypes +TypeConverter::getLoweredFormalTypes(SILDeclRef constant, + CanAnyFunctionType fnType) { + // We always use full bridging when importing a constant because we can + // directly bridge its arguments and results when calling it. + auto bridging = Bridgeability::Full; + + unsigned numParameterLists = constant.getParameterListCount(); + auto extInfo = fnType->getExtInfo(); + + // Form an abstraction pattern for bridging purposes. + AbstractionPattern bridgingFnPattern = + getAbstractionPatternForConstant(Context, constant, fnType, + numParameterLists); + + // Fast path: no uncurrying required. + if (numParameterLists == 1) { + auto bridgedFnType = + getBridgedFunctionType(bridgingFnPattern, fnType, extInfo, bridging); + bridgingFnPattern.rewriteType(bridgingFnPattern.getGenericSignature(), + bridgedFnType); + return { bridgingFnPattern, bridgedFnType }; + } + + SILFunctionTypeRepresentation rep = extInfo.getSILRepresentation(); + assert(rep != SILFunctionType::Representation::Block + && "objc blocks cannot be curried"); + + // The dependent generic signature. + CanGenericSignature genericSig = fnType.getOptGenericSignature(); + + // The 'self' parameter. + assert(fnType.getParams().size() == 1); + AnyFunctionType::Param selfParam = fnType.getParams()[0]; + + // The formal method parameters. + // If we actually partially-apply this, assume we'll need a thick function. + fnType = cast(fnType.getResult()); + auto innerExtInfo = + fnType->getExtInfo().withRepresentation(FunctionTypeRepresentation::Swift); + auto methodParams = fnType->getParams(); + + auto resultType = fnType.getResult(); + bool suppressOptionalResult = + bridgingFnPattern.hasForeignErrorStrippingResultOptionality(); + + // Bridge input and result types. + SmallVector bridgedParams; + CanType bridgedResultType; + + switch (rep) { + case SILFunctionTypeRepresentation::Thin: + case SILFunctionTypeRepresentation::Thick: + case SILFunctionTypeRepresentation::Method: + case SILFunctionTypeRepresentation::Closure: + case SILFunctionTypeRepresentation::WitnessMethod: + // Native functions don't need bridging. + bridgedParams.append(methodParams.begin(), methodParams.end()); + bridgedResultType = resultType; + break; + + case SILFunctionTypeRepresentation::ObjCMethod: + case SILFunctionTypeRepresentation::CFunctionPointer: { + if (rep == SILFunctionTypeRepresentation::ObjCMethod) { + // The "self" parameter should not get bridged unless it's a metatype. + if (selfParam.getPlainType()->is()) { + auto selfPattern = bridgingFnPattern.getFunctionParamType(0); + selfParam = getBridgedParam(rep, selfPattern, selfParam, bridging); + } + } + + auto partialFnPattern = bridgingFnPattern.getFunctionResultType(); + getBridgedParams(rep, partialFnPattern, methodParams, bridgedParams, + bridging); + + bridgedResultType = + getBridgedResultType(rep, + partialFnPattern.getFunctionResultType(), + resultType, bridging, suppressOptionalResult); + break; + } + + case SILFunctionTypeRepresentation::Block: + llvm_unreachable("Cannot uncurry native representation"); + } + + // Build the curried function type. + auto inner = + CanFunctionType::get(llvm::makeArrayRef(bridgedParams), + bridgedResultType, innerExtInfo); + + auto curried = + CanAnyFunctionType::get(genericSig, {selfParam}, inner, extInfo); + + // Replace the type in the abstraction pattern with the curried type. + bridgingFnPattern.rewriteType(genericSig, curried); + + // Build the uncurried function type. + if (innerExtInfo.throws()) + extInfo = extInfo.withThrows(true); + + bridgedParams.push_back(selfParam); + + auto uncurried = + CanAnyFunctionType::get(genericSig, + llvm::makeArrayRef(bridgedParams), + bridgedResultType, + extInfo); + + return { bridgingFnPattern, uncurried }; +} + +// TODO: We should compare generic signatures. Class and witness methods +// allow variance in "self"-fulfilled parameters; other functions must +// match exactly. +// TODO: More sophisticated param and return ABI compatibility rules could +// diverge. +static bool areABICompatibleParamsOrReturns(SILType a, SILType b, + SILFunction *inFunction) { + // Address parameters are all ABI-compatible, though the referenced + // values may not be. Assume whoever's doing this knows what they're + // doing. + if (a.isAddress() && b.isAddress()) + return true; + + // Addresses aren't compatible with values. + // TODO: An exception for pointerish types? + if (a.isAddress() || b.isAddress()) + return false; + + // Tuples are ABI compatible if their elements are. + // TODO: Should destructure recursively. + SmallVector aElements, bElements; + if (auto tup = a.getAs()) { + auto types = tup.getElementTypes(); + aElements.append(types.begin(), types.end()); + } else { + aElements.push_back(a.getASTType()); + } + if (auto tup = b.getAs()) { + auto types = tup.getElementTypes(); + bElements.append(types.begin(), types.end()); + } else { + bElements.push_back(b.getASTType()); + } + + if (aElements.size() != bElements.size()) + return false; + + for (unsigned i : indices(aElements)) { + auto aa = SILType::getPrimitiveObjectType(aElements[i]); + auto bb = SILType::getPrimitiveObjectType(bElements[i]); + // Equivalent types are always ABI-compatible. + if (aa == bb) + continue; + + // Opaque types are compatible with their substitution. + if (inFunction) { + auto opaqueTypesSubsituted = aa; + auto *dc = inFunction->getDeclContext(); + auto *currentModule = inFunction->getModule().getSwiftModule(); + if (!dc || !dc->isChildContextOf(currentModule)) + dc = currentModule; + ReplaceOpaqueTypesWithUnderlyingTypes replacer( + dc, inFunction->getResilienceExpansion(), + inFunction->getModule().isWholeModule()); + if (aa.getASTType()->hasOpaqueArchetype()) + opaqueTypesSubsituted = aa.subst(inFunction->getModule(), replacer, + replacer, CanGenericSignature(), true); + + auto opaqueTypesSubsituted2 = bb; + if (bb.getASTType()->hasOpaqueArchetype()) + opaqueTypesSubsituted2 = + bb.subst(inFunction->getModule(), replacer, replacer, + CanGenericSignature(), true); + if (opaqueTypesSubsituted == opaqueTypesSubsituted2) + continue; + } + + // FIXME: If one or both types are dependent, we can't accurately assess + // whether they're ABI-compatible without a generic context. We can + // do a better job here when dependent types are related to their + // generic signatures. + if (aa.hasTypeParameter() || bb.hasTypeParameter()) + continue; + + // Bridgeable object types are interchangeable. + if (aa.isBridgeableObjectType() && bb.isBridgeableObjectType()) + continue; + + // Optional and IUO are interchangeable if their elements are. + auto aObject = aa.getOptionalObjectType(); + auto bObject = bb.getOptionalObjectType(); + if (aObject && bObject && + areABICompatibleParamsOrReturns(aObject, bObject, inFunction)) + continue; + // Optional objects are ABI-interchangeable with non-optionals; + // None is represented by a null pointer. + if (aObject && aObject.isBridgeableObjectType() && + bb.isBridgeableObjectType()) + continue; + if (bObject && bObject.isBridgeableObjectType() && + aa.isBridgeableObjectType()) + continue; + + // Optional thick metatypes are ABI-interchangeable with non-optionals + // too. + if (aObject) + if (auto aObjMeta = aObject.getAs()) + if (auto bMeta = bb.getAs()) + if (aObjMeta->getRepresentation() == bMeta->getRepresentation() && + bMeta->getRepresentation() != MetatypeRepresentation::Thin) + continue; + if (bObject) + if (auto aMeta = aa.getAs()) + if (auto bObjMeta = bObject.getAs()) + if (aMeta->getRepresentation() == bObjMeta->getRepresentation() && + aMeta->getRepresentation() != MetatypeRepresentation::Thin) + continue; + + // Function types are interchangeable if they're also ABI-compatible. + if (auto aFunc = aa.getAs()) { + if (auto bFunc = bb.getAs()) { + // *NOTE* We swallow the specific error here for now. We will still get + // that the function types are incompatible though, just not more + // specific information. + return aFunc->isABICompatibleWith(bFunc, *inFunction).isCompatible(); + } + } + + // Metatypes are interchangeable with metatypes with the same + // representation. + if (auto aMeta = aa.getAs()) { + if (auto bMeta = bb.getAs()) { + if (aMeta->getRepresentation() == bMeta->getRepresentation()) + continue; + } + } + // Other types must match exactly. + return false; + } + + return true; +} + +namespace { +using ABICompatibilityCheckResult = + SILFunctionType::ABICompatibilityCheckResult; +} // end anonymous namespace + +ABICompatibilityCheckResult +SILFunctionType::isABICompatibleWith(CanSILFunctionType other, + SILFunction &context) const { + // The calling convention and function representation can't be changed. + if (getRepresentation() != other->getRepresentation()) + return ABICompatibilityCheckResult::DifferentFunctionRepresentations; + + // Check the results. + if (getNumResults() != other->getNumResults()) + return ABICompatibilityCheckResult::DifferentNumberOfResults; + + for (unsigned i : indices(getResults())) { + auto result1 = getResults()[i]; + auto result2 = other->getResults()[i]; + + if (result1.getConvention() != result2.getConvention()) + return ABICompatibilityCheckResult::DifferentReturnValueConventions; + + if (!areABICompatibleParamsOrReturns( + result1.getSILStorageType(context.getModule(), this), + result2.getSILStorageType(context.getModule(), other), + &context)) { + return ABICompatibilityCheckResult::ABIIncompatibleReturnValues; + } + } + + // Our error result conventions are designed to be ABI compatible + // with functions lacking error results. Just make sure that the + // actual conventions match up. + if (hasErrorResult() && other->hasErrorResult()) { + auto error1 = getErrorResult(); + auto error2 = other->getErrorResult(); + if (error1.getConvention() != error2.getConvention()) + return ABICompatibilityCheckResult::DifferentErrorResultConventions; + + if (!areABICompatibleParamsOrReturns( + error1.getSILStorageType(context.getModule(), this), + error2.getSILStorageType(context.getModule(), other), + &context)) + return ABICompatibilityCheckResult::ABIIncompatibleErrorResults; + } + + // Check the parameters. + // TODO: Could allow known-empty types to be inserted or removed, but SIL + // doesn't know what empty types are yet. + if (getParameters().size() != other->getParameters().size()) + return ABICompatibilityCheckResult::DifferentNumberOfParameters; + + for (unsigned i : indices(getParameters())) { + auto param1 = getParameters()[i]; + auto param2 = other->getParameters()[i]; + + if (param1.getConvention() != param2.getConvention()) + return {ABICompatibilityCheckResult::DifferingParameterConvention, i}; + if (!areABICompatibleParamsOrReturns( + param1.getSILStorageType(context.getModule(), this), + param2.getSILStorageType(context.getModule(), other), + &context)) + return {ABICompatibilityCheckResult::ABIIncompatibleParameterType, i}; + } + + // This needs to be checked last because the result implies everying else has + // already been checked and this is the only difference. + if (isNoEscape() != other->isNoEscape() && + (getRepresentation() == SILFunctionType::Representation::Thick)) + return ABICompatibilityCheckResult::ABIEscapeToNoEscapeConversion; + + return ABICompatibilityCheckResult::None; +} + +StringRef SILFunctionType::ABICompatibilityCheckResult::getMessage() const { + switch (kind) { + case innerty::None: + return "None"; + case innerty::DifferentFunctionRepresentations: + return "Different function representations"; + case innerty::DifferentNumberOfResults: + return "Different number of results"; + case innerty::DifferentReturnValueConventions: + return "Different return value conventions"; + case innerty::ABIIncompatibleReturnValues: + return "ABI incompatible return values"; + case innerty::DifferentErrorResultConventions: + return "Different error result conventions"; + case innerty::ABIIncompatibleErrorResults: + return "ABI incompatible error results"; + case innerty::DifferentNumberOfParameters: + return "Different number of parameters"; + + // These two have to do with specific parameters, so keep the error message + // non-plural. + case innerty::DifferingParameterConvention: + return "Differing parameter convention"; + case innerty::ABIIncompatibleParameterType: + return "ABI incompatible parameter type."; + case innerty::ABIEscapeToNoEscapeConversion: + return "Escape to no escape conversion"; + } + llvm_unreachable("Covered switch isn't completely covered?!"); +} + +static DeclContext *getDeclContextForExpansion(const SILFunction &f) { + auto *dc = f.getDeclContext(); + if (!dc) + dc = f.getModule().getSwiftModule(); + auto *currentModule = f.getModule().getSwiftModule(); + if (!dc || !dc->isChildContextOf(currentModule)) + dc = currentModule; + return dc; +} + +TypeExpansionContext::TypeExpansionContext(const SILFunction &f) + : expansion(f.getResilienceExpansion()), + inContext(getDeclContextForExpansion(f)), + isContextWholeModule(f.getModule().isWholeModule()) {} + +CanSILFunctionType SILFunction::getLoweredFunctionTypeInContext( + TypeExpansionContext context) const { + auto origFunTy = getLoweredFunctionType(); + auto &M = getModule(); + auto funTy = M.Types.getLoweredType(origFunTy , context); + return cast(funTy.getASTType()); +} diff --git a/test/CXXInterop/Inputs/cxx_constructors.h b/test/CXXInterop/Inputs/cxx_constructors.h new file mode 100644 index 0000000000000..497b1c6f0085a --- /dev/null +++ b/test/CXXInterop/Inputs/cxx_constructors.h @@ -0,0 +1,22 @@ +struct ExplicitDefaultConstructor { + ExplicitDefaultConstructor() : x(42) {} + int x; +}; + +struct ImplicitDefaultConstructor { + int x = 42; +}; + +struct MemberOfClassType { + ImplicitDefaultConstructor member; +}; + +struct DefaultConstructorDeleted { + DefaultConstructorDeleted() = delete; + int &a; +}; + +struct ConstructorWithParam { + ConstructorWithParam(int val) : x(val) {} + int x; +}; diff --git a/test/CXXInterop/Inputs/module.modulemap b/test/CXXInterop/Inputs/module.modulemap new file mode 100644 index 0000000000000..11f93f00a5fc2 --- /dev/null +++ b/test/CXXInterop/Inputs/module.modulemap @@ -0,0 +1,3 @@ +module CxxConstructors { + header "cxx_constructors.h" +} diff --git a/test/CXXInterop/cxx-constructors-executable.swift b/test/CXXInterop/cxx-constructors-executable.swift new file mode 100644 index 0000000000000..1a9531f35865b --- /dev/null +++ b/test/CXXInterop/cxx-constructors-executable.swift @@ -0,0 +1,37 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift %s -I %S/Inputs/ -o %t/cxx_interop -Xfrontend -enable-cxx-interop +// RUN: %target-codesign %t/cxx_interop +// RUN: %target-run %t/cxx_interop +// +// REQUIRES: executable_test + +import StdlibUnittest +import CxxConstructors + +var CxxConstructorTestSuite = TestSuite("CxxConstructors") + +CxxConstructorTestSuite.test("ExplicitDefaultConstructor") { + let instance = ExplicitDefaultConstructor() + + expectEqual(42, instance.x) +} + +CxxConstructorTestSuite.test("ImplicitDefaultConstructor") { + let instance = ImplicitDefaultConstructor() + + expectEqual(42, instance.x) +} + +CxxConstructorTestSuite.test("MemberOfClassType") { + let instance = MemberOfClassType() + + expectEqual(42, instance.member.x) +} + +CxxConstructorTestSuite.test("ConstructorWithParam") { + let instance = ConstructorWithParam(123456) + + expectEqual(123456, instance.x) +} + +runAllTests() diff --git a/test/CXXInterop/cxx-constructors-ir.swift b/test/CXXInterop/cxx-constructors-ir.swift new file mode 100644 index 0000000000000..cf1124505f9f2 --- /dev/null +++ b/test/CXXInterop/cxx-constructors-ir.swift @@ -0,0 +1,14 @@ +// RUN: %target-swift-frontend -I %S/Inputs -enable-cxx-interop -emit-ir %s | %FileCheck %s + +import CxxConstructors + +// Note: +// - The `this` parameter should carry a `noalias` attribute, as it is +// guaranteed that nothing will alias the object before it has been fully +// constructed. It should also carry an `sret` attribute to indicate that this +// is an out parameter for a structure being returned by the function. +// - The `this` parameter should _not_ carry a `nocapture` attribute (unlike +// Swift constructors that return their result indirectly) because the C++ has +// explicit access to `this` and may capture it. +// CHECK: call void @_ZN20ConstructorWithParamC2Ei(%struct.ConstructorWithParam* noalias sret %{{[0-9]+}}, i32 42) +let _ = ConstructorWithParam(42) diff --git a/test/CXXInterop/cxx-constructors-module-interface.swift b/test/CXXInterop/cxx-constructors-module-interface.swift new file mode 100644 index 0000000000000..5c2f0b2dff0a2 --- /dev/null +++ b/test/CXXInterop/cxx-constructors-module-interface.swift @@ -0,0 +1,20 @@ +// RUN: %target-swift-ide-test -print-module -module-to-print=CxxConstructors -I %S/Inputs/ -source-filename=x -enable-cxx-interop | %FileCheck %s + +// CHECK: struct ExplicitDefaultConstructor { +// CHECK-NEXT: var x: Int32 +// CHECK-NEXT: init() +// CHECK-NEXT: } +// CHECK-NEXT: struct ImplicitDefaultConstructor { +// CHECK-NEXT: var x: Int32 +// CHECK-NEXT: init() +// CHECK-NEXT: } +// CHECK-NEXT: struct MemberOfClassType { +// CHECK-NEXT: var member: ImplicitDefaultConstructor +// CHECK-NEXT: init() +// CHECK-NEXT: } +// CHECK-NEXT: struct DefaultConstructorDeleted { +// CHECK-NEXT: } +// CHECK-NEXT: struct ConstructorWithParam { +// CHECK-NEXT: var x: Int32 +// CHECK-NEXT: init(_ val: Int32) +// CHECK-NEXT: } diff --git a/test/CXXInterop/cxx-constructors-sil.swift b/test/CXXInterop/cxx-constructors-sil.swift new file mode 100644 index 0000000000000..adbf551eb73c9 --- /dev/null +++ b/test/CXXInterop/cxx-constructors-sil.swift @@ -0,0 +1,13 @@ +// RUN: %target-swift-frontend -I %S/Inputs -enable-cxx-interop -emit-sil %s | %FileCheck %s + +import CxxConstructors + +// The most important thing to test here is that the constructor result is returned +// with an @out attribute. +// CHECK: [[VAR:%[0-9]+]] = alloc_stack $ConstructorWithParam +// CHECK: [[TYPE:%[0-9]+]] = metatype $@thin ConstructorWithParam.Type +// CHECK: [[LITERAL:%[0-9]+]] = integer_literal $Builtin.Int32, 42 +// CHECK: [[INT:%[0-9]+]] = struct $Int32 ([[LITERAL]] : $Builtin.Int32) +// CHECK: [[FUNC:%[0-9]+]] = function_ref @_ZN20ConstructorWithParamC1Ei : $@convention(c) (Int32, @thin ConstructorWithParam.Type) -> @out ConstructorWithParam +// CHECK: %{{[0-9]+}} = apply [[FUNC]]([[VAR]], [[INT]], [[TYPE]]) : $@convention(c) (Int32, @thin ConstructorWithParam.Type) -> @out ConstructorWithParam +let _ = ConstructorWithParam(42) diff --git a/test/CXXInterop/cxx-constructors-typecheck.swift b/test/CXXInterop/cxx-constructors-typecheck.swift new file mode 100644 index 0000000000000..6da3a097ee6dc --- /dev/null +++ b/test/CXXInterop/cxx-constructors-typecheck.swift @@ -0,0 +1,13 @@ +// RUN: %target-typecheck-verify-swift -verify-ignore-unknown -I %S/Inputs -enable-cxx-interop + +import CxxConstructors + +let explicit = ExplicitDefaultConstructor() + +let implicit = ImplicitDefaultConstructor() + +let deletedImplicitly = ConstructorWithParam() // expected-error {{missing argument for parameter #1 in call}} + +let deletedExplicitly = DefaultConstructorDeleted() // expected-error {{cannot be constructed because it has no accessible initializers}} + +let withArg = ConstructorWithParam(42) From 7ad2eef26508ad92d8d92f2d5546913c0ced3bbd Mon Sep 17 00:00:00 2001 From: Martin Boehme Date: Thu, 26 Mar 2020 11:00:40 +0100 Subject: [PATCH 02/33] Only import constructors marked `noexcept`. --- lib/ClangImporter/ImportDecl.cpp | 7 ++++++- test/CXXInterop/Inputs/cxx_constructors.h | 8 ++++++-- test/CXXInterop/cxx-constructors-typecheck.swift | 3 +++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 9bf0a0e91f309..e5efce65fb99f 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -3893,7 +3893,12 @@ namespace { AbstractFunctionDecl *result = nullptr; if (auto *ctordecl = dyn_cast(decl)) { - // TODO: Is failable, throws etc. correct? + // For the time being, we only import `noexcept` constructors. + // TODO: Import throwing constructors too. + auto *prototype = decl->getType()->getAs(); + if (!prototype || !prototype->hasNoexceptExceptionSpec()) + return nullptr; + DeclName ctorName(Impl.SwiftContext, DeclBaseName::createConstructor(), bodyParams); result = Impl.createDeclWithClangNode( diff --git a/test/CXXInterop/Inputs/cxx_constructors.h b/test/CXXInterop/Inputs/cxx_constructors.h index 497b1c6f0085a..d98e4c47979aa 100644 --- a/test/CXXInterop/Inputs/cxx_constructors.h +++ b/test/CXXInterop/Inputs/cxx_constructors.h @@ -1,5 +1,5 @@ struct ExplicitDefaultConstructor { - ExplicitDefaultConstructor() : x(42) {} + ExplicitDefaultConstructor() noexcept : x(42) {} int x; }; @@ -17,6 +17,10 @@ struct DefaultConstructorDeleted { }; struct ConstructorWithParam { - ConstructorWithParam(int val) : x(val) {} + ConstructorWithParam(int val) noexcept : x(val) {} int x; }; + +struct PotentiallyThrowingConstructor { + PotentiallyThrowingConstructor() {} +}; diff --git a/test/CXXInterop/cxx-constructors-typecheck.swift b/test/CXXInterop/cxx-constructors-typecheck.swift index 6da3a097ee6dc..63f78aab39e66 100644 --- a/test/CXXInterop/cxx-constructors-typecheck.swift +++ b/test/CXXInterop/cxx-constructors-typecheck.swift @@ -11,3 +11,6 @@ let deletedImplicitly = ConstructorWithParam() // expected-error {{missing argum let deletedExplicitly = DefaultConstructorDeleted() // expected-error {{cannot be constructed because it has no accessible initializers}} let withArg = ConstructorWithParam(42) + +// For the time being, we only import constructors marked `noexcept`. +let potentiallyThrowing = PotentiallyThrowingConstructor() // expected-error {{cannot be constructed because it has no accessible initializers}} From 384854810a60a69c8df8a8c0248e209adc28c295 Mon Sep 17 00:00:00 2001 From: Martin Boehme Date: Tue, 7 Apr 2020 06:58:23 +0200 Subject: [PATCH 03/33] Revert "Only import constructors marked `noexcept`." This reverts commit 29650d8c1f302708a32304d49c703c9ddbf30b75. As discussed here, we want to import all constructors (whether they are marked `noexcept` or not) as non-throwing initializers; https://forums.swift.org/t/handling-c-exceptions/34823/50 --- lib/ClangImporter/ImportDecl.cpp | 7 +------ test/CXXInterop/Inputs/cxx_constructors.h | 8 ++------ test/CXXInterop/cxx-constructors-typecheck.swift | 3 --- 3 files changed, 3 insertions(+), 15 deletions(-) diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index e5efce65fb99f..9bf0a0e91f309 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -3893,12 +3893,7 @@ namespace { AbstractFunctionDecl *result = nullptr; if (auto *ctordecl = dyn_cast(decl)) { - // For the time being, we only import `noexcept` constructors. - // TODO: Import throwing constructors too. - auto *prototype = decl->getType()->getAs(); - if (!prototype || !prototype->hasNoexceptExceptionSpec()) - return nullptr; - + // TODO: Is failable, throws etc. correct? DeclName ctorName(Impl.SwiftContext, DeclBaseName::createConstructor(), bodyParams); result = Impl.createDeclWithClangNode( diff --git a/test/CXXInterop/Inputs/cxx_constructors.h b/test/CXXInterop/Inputs/cxx_constructors.h index d98e4c47979aa..497b1c6f0085a 100644 --- a/test/CXXInterop/Inputs/cxx_constructors.h +++ b/test/CXXInterop/Inputs/cxx_constructors.h @@ -1,5 +1,5 @@ struct ExplicitDefaultConstructor { - ExplicitDefaultConstructor() noexcept : x(42) {} + ExplicitDefaultConstructor() : x(42) {} int x; }; @@ -17,10 +17,6 @@ struct DefaultConstructorDeleted { }; struct ConstructorWithParam { - ConstructorWithParam(int val) noexcept : x(val) {} + ConstructorWithParam(int val) : x(val) {} int x; }; - -struct PotentiallyThrowingConstructor { - PotentiallyThrowingConstructor() {} -}; diff --git a/test/CXXInterop/cxx-constructors-typecheck.swift b/test/CXXInterop/cxx-constructors-typecheck.swift index 63f78aab39e66..6da3a097ee6dc 100644 --- a/test/CXXInterop/cxx-constructors-typecheck.swift +++ b/test/CXXInterop/cxx-constructors-typecheck.swift @@ -11,6 +11,3 @@ let deletedImplicitly = ConstructorWithParam() // expected-error {{missing argum let deletedExplicitly = DefaultConstructorDeleted() // expected-error {{cannot be constructed because it has no accessible initializers}} let withArg = ConstructorWithParam(42) - -// For the time being, we only import constructors marked `noexcept`. -let potentiallyThrowing = PotentiallyThrowingConstructor() // expected-error {{cannot be constructed because it has no accessible initializers}} From fd00bc1f01357ecd264b8216373c23014771c124 Mon Sep 17 00:00:00 2001 From: Martin Boehme Date: Wed, 13 May 2020 15:06:05 +0200 Subject: [PATCH 04/33] Move tests from `CXXInterop` to `Interop/Cxx`. This is the canonical location that we've agreed on. --- test/CXXInterop/Inputs/module.modulemap | 3 --- .../Cxx/class/Inputs/cxx-constructors.h} | 0 test/Interop/Cxx/class/Inputs/module.modulemap | 4 ++++ .../Cxx/class}/cxx-constructors-executable.swift | 0 .../Cxx/class}/cxx-constructors-ir.swift | 0 .../Cxx/class}/cxx-constructors-module-interface.swift | 0 .../Cxx/class}/cxx-constructors-sil.swift | 0 .../Cxx/class}/cxx-constructors-typecheck.swift | 0 8 files changed, 4 insertions(+), 3 deletions(-) delete mode 100644 test/CXXInterop/Inputs/module.modulemap rename test/{CXXInterop/Inputs/cxx_constructors.h => Interop/Cxx/class/Inputs/cxx-constructors.h} (100%) rename test/{CXXInterop => Interop/Cxx/class}/cxx-constructors-executable.swift (100%) rename test/{CXXInterop => Interop/Cxx/class}/cxx-constructors-ir.swift (100%) rename test/{CXXInterop => Interop/Cxx/class}/cxx-constructors-module-interface.swift (100%) rename test/{CXXInterop => Interop/Cxx/class}/cxx-constructors-sil.swift (100%) rename test/{CXXInterop => Interop/Cxx/class}/cxx-constructors-typecheck.swift (100%) diff --git a/test/CXXInterop/Inputs/module.modulemap b/test/CXXInterop/Inputs/module.modulemap deleted file mode 100644 index 11f93f00a5fc2..0000000000000 --- a/test/CXXInterop/Inputs/module.modulemap +++ /dev/null @@ -1,3 +0,0 @@ -module CxxConstructors { - header "cxx_constructors.h" -} diff --git a/test/CXXInterop/Inputs/cxx_constructors.h b/test/Interop/Cxx/class/Inputs/cxx-constructors.h similarity index 100% rename from test/CXXInterop/Inputs/cxx_constructors.h rename to test/Interop/Cxx/class/Inputs/cxx-constructors.h diff --git a/test/Interop/Cxx/class/Inputs/module.modulemap b/test/Interop/Cxx/class/Inputs/module.modulemap index 04c3bdedfda87..475c54c41a7e2 100644 --- a/test/Interop/Cxx/class/Inputs/module.modulemap +++ b/test/Interop/Cxx/class/Inputs/module.modulemap @@ -6,6 +6,10 @@ module TypeClassification { header "type-classification.h" } +module CxxConstructors { + header "cxx-constructors.h" +} + module MemberwiseInitializer { header "memberwise-initializer.h" } diff --git a/test/CXXInterop/cxx-constructors-executable.swift b/test/Interop/Cxx/class/cxx-constructors-executable.swift similarity index 100% rename from test/CXXInterop/cxx-constructors-executable.swift rename to test/Interop/Cxx/class/cxx-constructors-executable.swift diff --git a/test/CXXInterop/cxx-constructors-ir.swift b/test/Interop/Cxx/class/cxx-constructors-ir.swift similarity index 100% rename from test/CXXInterop/cxx-constructors-ir.swift rename to test/Interop/Cxx/class/cxx-constructors-ir.swift diff --git a/test/CXXInterop/cxx-constructors-module-interface.swift b/test/Interop/Cxx/class/cxx-constructors-module-interface.swift similarity index 100% rename from test/CXXInterop/cxx-constructors-module-interface.swift rename to test/Interop/Cxx/class/cxx-constructors-module-interface.swift diff --git a/test/CXXInterop/cxx-constructors-sil.swift b/test/Interop/Cxx/class/cxx-constructors-sil.swift similarity index 100% rename from test/CXXInterop/cxx-constructors-sil.swift rename to test/Interop/Cxx/class/cxx-constructors-sil.swift diff --git a/test/CXXInterop/cxx-constructors-typecheck.swift b/test/Interop/Cxx/class/cxx-constructors-typecheck.swift similarity index 100% rename from test/CXXInterop/cxx-constructors-typecheck.swift rename to test/Interop/Cxx/class/cxx-constructors-typecheck.swift From e6067275a6659cfab8640e68e93a5bba36ddca20 Mon Sep 17 00:00:00 2001 From: Martin Boehme Date: Thu, 14 May 2020 11:45:19 +0200 Subject: [PATCH 05/33] Duplicate changes to GenClangType in ClangTypeConverter. See discussion here: https://github.com/apple/swift/pull/30630#discussion_r398967412 --- lib/AST/ClangTypeConverter.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/AST/ClangTypeConverter.cpp b/lib/AST/ClangTypeConverter.cpp index 9fd13f797798d..d2316dd7415ea 100644 --- a/lib/AST/ClangTypeConverter.cpp +++ b/lib/AST/ClangTypeConverter.cpp @@ -461,7 +461,19 @@ clang::QualType ClangTypeConverter::visitProtocolType(ProtocolType *type) { // Metatypes can be converted to Class when they are metatypes for concrete // classes. https://github.com/apple/swift/pull/27479#discussion_r344418131 clang::QualType ClangTypeConverter::visitMetatypeType(MetatypeType *type) { - return getClangMetatypeType(ClangASTContext); + assert(type->hasRepresentation() && + "metatype should have been assigned a representation"); + switch (type->getRepresentation()) { + case MetatypeRepresentation::Thin: + return ClangASTContext.VoidTy; + + case MetatypeRepresentation::Thick: + llvm_unreachable("thick metatypes don't have a corresponding Clang type"); + + case MetatypeRepresentation::ObjC: + return getClangMetatypeType(ClangASTContext); + } + llvm_unreachable("bad representation"); } // TODO: [stronger-checking-in-clang-type-conversion] From b2c5a3eeed4e0d80c819f98c816481fbedc49526 Mon Sep 17 00:00:00 2001 From: Martin Boehme Date: Mon, 11 May 2020 15:14:29 +0200 Subject: [PATCH 06/33] Add a constructor thunk if required to add additional constructor arguments. Also add more IR tests and make various other changes. --- lib/ClangImporter/ImportDecl.cpp | 14 ++-- lib/IRGen/GenCall.cpp | 40 ++++++---- lib/IRGen/GenDecl.cpp | 78 +++++++++++++++++++ .../Cxx/class/Inputs/cxx-constructors.h | 14 +++- .../class/cxx-constructors-executable.swift | 9 +-- .../Cxx/class/cxx-constructors-ir.swift | 50 +++++++++--- .../cxx-constructors-module-interface.swift | 14 ++++ 7 files changed, 182 insertions(+), 37 deletions(-) diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 9bf0a0e91f309..2a5983d0a8733 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -3439,14 +3439,19 @@ namespace { bool hasReferenceableFields = !members.empty(); - if (hasZeroInitializableStorage && - !Impl.SwiftContext.LangOpts.EnableCXXInterop) { - // Add constructors for the struct. + const clang::CXXRecordDecl *cxxRecordDecl = + dyn_cast(decl); + if (hasZeroInitializableStorage && !cxxRecordDecl) { + // Add default constructor for the struct if compiling in C mode. + // If we're compiling for C++, we'll import the C++ default constructor + // (if there is one), so we don't need to synthesize one here. ctors.push_back(createDefaultConstructor(Impl, result)); } + bool hasUserDeclaredConstructor = + cxxRecordDecl && cxxRecordDecl->hasUserDeclaredConstructor(); if (hasReferenceableFields && hasMemberwiseInitializer && - !Impl.SwiftContext.LangOpts.EnableCXXInterop) { + !hasUserDeclaredConstructor) { // The default zero initializer suppresses the implicit value // constructor that would normally be formed, so we have to add that // explicitly as well. @@ -3893,7 +3898,6 @@ namespace { AbstractFunctionDecl *result = nullptr; if (auto *ctordecl = dyn_cast(decl)) { - // TODO: Is failable, throws etc. correct? DeclName ctorName(Impl.SwiftContext, DeclBaseName::createConstructor(), bodyParams); result = Impl.createDeclWithClangNode( diff --git a/lib/IRGen/GenCall.cpp b/lib/IRGen/GenCall.cpp index 3fa9365d3c04f..b051e860bd984 100644 --- a/lib/IRGen/GenCall.cpp +++ b/lib/IRGen/GenCall.cpp @@ -430,7 +430,7 @@ namespace { private: void expand(SILParameterInfo param); - llvm::Type *addIndirectResult(bool noCapture = true); + llvm::Type *addIndirectResult(); SILFunctionConventions getSILFuncConventions() const { return SILFunctionConventions(FnType, IGM.getSILModule()); @@ -484,8 +484,7 @@ llvm::Type *SignatureExpansion::addIndirectResult() { auto resultType = getSILFuncConventions().getSILResultType( IGM.getMaximalTypeExpansionContext()); const TypeInfo &resultTI = IGM.getTypeInfo(resultType); - addIndirectResultAttributes(IGM, Attrs, ParamIRTypes.size(), claimSRet(), - noCapture); + addIndirectResultAttributes(IGM, Attrs, ParamIRTypes.size(), claimSRet()); addPointerParameter(resultTI.getStorageType()); return IGM.VoidTy; } @@ -1272,6 +1271,16 @@ void SignatureExpansion::expandExternalSignatureTypes() { SmallVector paramTys; auto const &clangCtx = IGM.getClangASTContext(); + bool formalIndirectResult = FnType->getNumResults() > 0 && + FnType->getSingleResult().isFormalIndirect(); + if (formalIndirectResult) { + auto resultType = getSILFuncConventions().getSingleSILResultType( + IGM.getMaximalTypeExpansionContext()); + auto clangTy = + IGM.getClangASTContext().getPointerType(IGM.getClangType(resultType)); + paramTys.push_back(clangTy); + } + switch (FnType->getRepresentation()) { case SILFunctionTypeRepresentation::ObjCMethod: { // ObjC methods take their 'self' argument first, followed by an @@ -1336,17 +1345,8 @@ void SignatureExpansion::expandExternalSignatureTypes() { } // If we return indirectly, that is the first parameter type. - bool formalIndirect = FnType->getNumResults() > 0 && - FnType->getSingleResult().isFormalIndirect(); - if (formalIndirect || returnInfo.isIndirect()) { - // Specify "nocapture" if we're returning the result indirectly for - // low-level ABI reasons, as the called function never sees the implicit - // output parameter. - // On the other hand, if the result is a formal indirect result in SIL, that - // means that the Clang function has an explicit output parameter (e.g. it's - // a C++ constructor), which it might capture -- so don't specify - // "nocapture" in that case. - addIndirectResult(/* noCapture = */ returnInfo.isIndirect()); + if (returnInfo.isIndirect()) { + addIndirectResult(); } size_t firstParamToLowerNormally = 0; @@ -1432,6 +1432,13 @@ void SignatureExpansion::expandExternalSignatureTypes() { } } + if (formalIndirectResult) { + // If the result is a formal indirect result in SIL, that means that the + // Clang function has an explicit output parameter (e.g. it's a C++ + // constructor), which it might capture -- so don't specify "nocapture". + addIndirectResultAttributes(IGM, Attrs, 0, claimSRet(), /* nocapture = */ false); + } + if (returnInfo.isIndirect() || returnInfo.isIgnore()) { ResultIRType = IGM.VoidTy; } else { @@ -2812,6 +2819,11 @@ static void externalizeArguments(IRGenFunction &IGF, const Callee &callee, == SILFunctionTypeRepresentation::Block) { // Ignore the physical block-object parameter. firstParam += 1; + // Or the indirect result parameter. + } else if (fnType->getNumResults() > 0 && + fnType->getSingleResult().isFormalIndirect()) { + // Ignore the indirect result parameter. + firstParam += 1; } for (unsigned i = firstParam, e = FI.arg_size(); i != e; ++i) { diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 15e88148e0afe..e8aff92311183 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -38,6 +38,8 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/GlobalDecl.h" +#include "clang/CodeGen/CodeGenABITypes.h" +#include "clang/CodeGen/ModuleBuilder.h" #include "llvm/ADT/SmallString.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/GlobalAlias.h" @@ -2761,6 +2763,77 @@ void IRGenModule::emitDynamicReplacementOriginalFunctionThunk(SILFunction *f) { IGF.Builder.CreateRet(Res); } +/// If the calling convention for `ctor` doesn't match the calling convention +/// that we assumed for it when we imported it as `initializer`, emit and +/// return a thunk that conforms to the assumed calling convention. The thunk +/// is marked `alwaysinline`, so it doesn't generate any runtime overhead. +/// If the assumed calling convention was correct, just return `ctor`. +/// +/// See also comments in CXXMethodConventions in SIL/IR/SILFunctionType.cpp. +static llvm::Constant * +emitCXXConstructorThunkIfNeeded(IRGenModule &IGM, SILFunction *initializer, + const clang::CXXConstructorDecl *ctor, + const LinkEntity &entity, + llvm::Constant *ctorAddress) { + Signature signature = IGM.getSignature(initializer->getLoweredFunctionType()); + + llvm::FunctionType *assumedFnType = signature.getType(); + llvm::FunctionType *ctorFnType = + cast(ctorAddress->getType()->getPointerElementType()); + + if (assumedFnType == ctorFnType) { + return ctorAddress; + } + + // The thunk has private linkage, so it doesn't need to have a predictable + // mangled name -- we just need to make sure the name is unique. + llvm::SmallString<32> name; + llvm::raw_svector_ostream stream(name); + stream << "__swift_cxx_ctor"; + entity.mangle(stream); + + llvm::Function *thunk = llvm::Function::Create( + assumedFnType, llvm::Function::PrivateLinkage, name, &IGM.Module); + + thunk->setCallingConv(llvm::CallingConv::C); + + llvm::AttrBuilder attrBuilder; + IGM.constructInitialFnAttributes(attrBuilder); + attrBuilder.addAttribute(llvm::Attribute::AlwaysInline); + llvm::AttributeList attr = signature.getAttributes().addAttributes( + IGM.getLLVMContext(), llvm::AttributeList::FunctionIndex, attrBuilder); + thunk->setAttributes(attr); + + IRGenFunction subIGF(IGM, thunk); + if (IGM.DebugInfo) + IGM.DebugInfo->emitArtificialFunction(subIGF, thunk); + + SmallVector Args; + for (auto i = thunk->arg_begin(), e = thunk->arg_end(); i != e; ++i) { + auto *argTy = i->getType(); + auto *paramTy = ctorFnType->getParamType(i - thunk->arg_begin()); + if (paramTy != argTy) + Args.push_back(subIGF.coerceValue(i, paramTy, IGM.DataLayout)); + else + Args.push_back(i); + } + + clang::CodeGen::ImplicitCXXConstructorArgs implicitArgs = + clang::CodeGen::getImplicitCXXConstructorArgs(IGM.ClangCodeGen->CGM(), + ctor); + for (size_t i = 0; i < implicitArgs.Prefix.size(); ++i) { + Args.insert(Args.begin() + 1 + i, implicitArgs.Prefix[i]); + } + for (const auto &arg : implicitArgs.Suffix) { + Args.push_back(arg); + } + + subIGF.Builder.CreateCall(ctorFnType, ctorAddress, Args); + subIGF.Builder.CreateRetVoid(); + + return thunk; +} + /// Find the entry point for a SIL function. llvm::Function *IRGenModule::getAddrOfSILFunction( SILFunction *f, ForDefinition_t forDefinition, @@ -2789,6 +2862,11 @@ llvm::Function *IRGenModule::getAddrOfSILFunction( if (auto clangDecl = f->getClangDecl()) { auto globalDecl = getClangGlobalDeclForFunction(clangDecl); clangAddr = getAddrOfClangGlobalDecl(globalDecl, forDefinition); + + if (auto ctor = dyn_cast(clangDecl)) { + clangAddr = + emitCXXConstructorThunkIfNeeded(*this, f, ctor, entity, clangAddr); + } } bool isDefinition = f->isDefinition(); diff --git a/test/Interop/Cxx/class/Inputs/cxx-constructors.h b/test/Interop/Cxx/class/Inputs/cxx-constructors.h index 497b1c6f0085a..72da5a217ab81 100644 --- a/test/Interop/Cxx/class/Inputs/cxx-constructors.h +++ b/test/Interop/Cxx/class/Inputs/cxx-constructors.h @@ -17,6 +17,18 @@ struct DefaultConstructorDeleted { }; struct ConstructorWithParam { - ConstructorWithParam(int val) : x(val) {} + ConstructorWithParam(int val) : x(val + 42) {} int x; }; + +struct Base {}; + +struct ArgType { + int i = 42; +}; + +struct HasVirtualBase : public virtual Base { + HasVirtualBase() = delete; + HasVirtualBase(ArgType Arg) {} + int i; +}; diff --git a/test/Interop/Cxx/class/cxx-constructors-executable.swift b/test/Interop/Cxx/class/cxx-constructors-executable.swift index 1a9531f35865b..06417c3d1f731 100644 --- a/test/Interop/Cxx/class/cxx-constructors-executable.swift +++ b/test/Interop/Cxx/class/cxx-constructors-executable.swift @@ -1,7 +1,4 @@ -// RUN: %empty-directory(%t) -// RUN: %target-build-swift %s -I %S/Inputs/ -o %t/cxx_interop -Xfrontend -enable-cxx-interop -// RUN: %target-codesign %t/cxx_interop -// RUN: %target-run %t/cxx_interop +// RUN: %target-run-simple-swift(-I %S/Inputs/ -Xfrontend -enable-cxx-interop) // // REQUIRES: executable_test @@ -29,9 +26,9 @@ CxxConstructorTestSuite.test("MemberOfClassType") { } CxxConstructorTestSuite.test("ConstructorWithParam") { - let instance = ConstructorWithParam(123456) + let instance = ConstructorWithParam(2) - expectEqual(123456, instance.x) + expectEqual(44, instance.x) } runAllTests() diff --git a/test/Interop/Cxx/class/cxx-constructors-ir.swift b/test/Interop/Cxx/class/cxx-constructors-ir.swift index cf1124505f9f2..1e2d3f7dffeef 100644 --- a/test/Interop/Cxx/class/cxx-constructors-ir.swift +++ b/test/Interop/Cxx/class/cxx-constructors-ir.swift @@ -1,14 +1,42 @@ -// RUN: %target-swift-frontend -I %S/Inputs -enable-cxx-interop -emit-ir %s | %FileCheck %s +// Target-specific tests for C++ constructor call code generation. + +// RUN: %swift -module-name Swift -target x86_64-apple-macosx10.9 -dump-clang-diagnostics -I %S/Inputs -enable-cxx-interop -emit-ir %s -parse-stdlib -parse-as-library -disable-legacy-type-info | %FileCheck %s -check-prefix=ITANIUM_X64 +// RUN: %swift -module-name Swift -target armv7-none-linux-androideabi -dump-clang-diagnostics -I %S/Inputs -enable-cxx-interop -emit-ir %s -parse-stdlib -parse-as-library -disable-legacy-type-info | %FileCheck %s -check-prefix=ITANIUM_ARM +// RUN: %swift -module-name Swift -target x86_64-unknown-windows-msvc -dump-clang-diagnostics -I %S/Inputs -enable-cxx-interop -emit-ir %s -parse-stdlib -parse-as-library -disable-legacy-type-info | %FileCheck %s -check-prefix=MICROSOFT_X64 import CxxConstructors -// Note: -// - The `this` parameter should carry a `noalias` attribute, as it is -// guaranteed that nothing will alias the object before it has been fully -// constructed. It should also carry an `sret` attribute to indicate that this -// is an out parameter for a structure being returned by the function. -// - The `this` parameter should _not_ carry a `nocapture` attribute (unlike -// Swift constructors that return their result indirectly) because the C++ has -// explicit access to `this` and may capture it. -// CHECK: call void @_ZN20ConstructorWithParamC2Ei(%struct.ConstructorWithParam* noalias sret %{{[0-9]+}}, i32 42) -let _ = ConstructorWithParam(42) +typealias Void = () + +public func createHasVirtualBase() -> HasVirtualBase { + // - The `this` parameter should carry a `noalias` attribute, as it is + // guaranteed that nothing will alias the object before it has been fully + // constructed. It should also carry an `sret` attribute to indicate that + // this is an out parameter for a structure being returned by the function. + // Note that this doesn't apply on ABIs (Itanium ARM, Microsoft x64) + // where we insert an (inlined) thunk; in this case, we're getting the + // attributes of the constructor that was generated by Clang, which doesn't + // insert these attributes. + // + // - The `this` parameter should _not_ carry a `nocapture` attribute (unlike + // Swift constructors that return their result indirectly) because the C++ + // constructor has explicit access to `this` and may capture it. + // + // ITANIUM_X64: define swiftcc { i8*, i32 } @"$ss20createHasVirtualBaseSo0bcD0VyF"() + // ITANIUM_X64-NOT: define + // ITANIUM_X64: call void @_ZN14HasVirtualBaseC1E7ArgType(%struct.HasVirtualBase* noalias sret %{{[0-9]+}}, i32 %{{[0-9]+}}) + // + // ITANIUM_ARM: define protected swiftcc { i8*, i32 } @"$ss20createHasVirtualBaseSo0bcD0VyF"() + // To verify that the thunk is inlined, make sure there's no intervening + // `define`, i.e. the call to the C++ constructor happens in + // createHasVirtualBase(), not some later function. + // ITANIUM_ARM-NOT: define + // Note `this` return type. + // ITANIUM_ARM: call %struct.HasVirtualBase* @_ZN14HasVirtualBaseC1E7ArgType(%struct.HasVirtualBase* %{{[0-9]+}}, [1 x i32] %{{[0-9]+}}) + // + // MICROSOFT_X64: define dllexport swiftcc { i8*, i32 } @"$ss20createHasVirtualBaseSo0bcD0VyF"() + // MICROSOFT_X64-NOT: define + // Note `this` return type and implicit "most derived" argument. + // MICROSOFT_X64: call %struct.HasVirtualBase* @"??0HasVirtualBase@@QEAA@UArgType@@@Z"(%struct.HasVirtualBase* %{{[0-9]+}}, i32 %{{[0-9]+}}, i32 1) + return HasVirtualBase(ArgType()) +} diff --git a/test/Interop/Cxx/class/cxx-constructors-module-interface.swift b/test/Interop/Cxx/class/cxx-constructors-module-interface.swift index 5c2f0b2dff0a2..696b5ea49ba8e 100644 --- a/test/Interop/Cxx/class/cxx-constructors-module-interface.swift +++ b/test/Interop/Cxx/class/cxx-constructors-module-interface.swift @@ -7,10 +7,12 @@ // CHECK-NEXT: struct ImplicitDefaultConstructor { // CHECK-NEXT: var x: Int32 // CHECK-NEXT: init() +// CHECK-NEXT: init(x: Int32) // CHECK-NEXT: } // CHECK-NEXT: struct MemberOfClassType { // CHECK-NEXT: var member: ImplicitDefaultConstructor // CHECK-NEXT: init() +// CHECK-NEXT: init(member: ImplicitDefaultConstructor) // CHECK-NEXT: } // CHECK-NEXT: struct DefaultConstructorDeleted { // CHECK-NEXT: } @@ -18,3 +20,15 @@ // CHECK-NEXT: var x: Int32 // CHECK-NEXT: init(_ val: Int32) // CHECK-NEXT: } +// CHECK-NEXT: struct Base { +// CHECK-NEXT: init() +// CHECK-NEXT: } +// CHECK-NEXT: struct ArgType { +// CHECK-NEXT: var i: Int32 +// CHECK-NEXT: init() +// CHECK-NEXT: init(i: Int32) +// CHECK-NEXT: } +// CHECK-NEXT: struct HasVirtualBase { +// CHECK-NEXT: var i: Int32 +// CHECK-NEXT: init(_ Arg: ArgType) +// CHECK-NEXT: } From 3066e16c37e26a5fea370877409b4d0bd1c0fea6 Mon Sep 17 00:00:00 2001 From: Martin Boehme Date: Fri, 15 May 2020 14:11:54 +0200 Subject: [PATCH 07/33] Remove redundant "cxx" from test names. --- .../Cxx/class/Inputs/{cxx-constructors.h => constructors.h} | 0 test/Interop/Cxx/class/Inputs/module.modulemap | 4 ++-- ...ructors-executable.swift => constructors-executable.swift} | 2 +- .../{cxx-constructors-ir.swift => constructors-ir.swift} | 2 +- ...le-interface.swift => constructors-module-interface.swift} | 2 +- .../{cxx-constructors-sil.swift => constructors-sil.swift} | 2 +- ...ructors-typecheck.swift => constructors-typechecker.swift} | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) rename test/Interop/Cxx/class/Inputs/{cxx-constructors.h => constructors.h} (100%) rename test/Interop/Cxx/class/{cxx-constructors-executable.swift => constructors-executable.swift} (97%) rename test/Interop/Cxx/class/{cxx-constructors-ir.swift => constructors-ir.swift} (99%) rename test/Interop/Cxx/class/{cxx-constructors-module-interface.swift => constructors-module-interface.swift} (87%) rename test/Interop/Cxx/class/{cxx-constructors-sil.swift => constructors-sil.swift} (97%) rename test/Interop/Cxx/class/{cxx-constructors-typecheck.swift => constructors-typechecker.swift} (95%) diff --git a/test/Interop/Cxx/class/Inputs/cxx-constructors.h b/test/Interop/Cxx/class/Inputs/constructors.h similarity index 100% rename from test/Interop/Cxx/class/Inputs/cxx-constructors.h rename to test/Interop/Cxx/class/Inputs/constructors.h diff --git a/test/Interop/Cxx/class/Inputs/module.modulemap b/test/Interop/Cxx/class/Inputs/module.modulemap index 475c54c41a7e2..0370a978cb949 100644 --- a/test/Interop/Cxx/class/Inputs/module.modulemap +++ b/test/Interop/Cxx/class/Inputs/module.modulemap @@ -6,8 +6,8 @@ module TypeClassification { header "type-classification.h" } -module CxxConstructors { - header "cxx-constructors.h" +module Constructors { + header "constructors.h" } module MemberwiseInitializer { diff --git a/test/Interop/Cxx/class/cxx-constructors-executable.swift b/test/Interop/Cxx/class/constructors-executable.swift similarity index 97% rename from test/Interop/Cxx/class/cxx-constructors-executable.swift rename to test/Interop/Cxx/class/constructors-executable.swift index 06417c3d1f731..04a8b9912b926 100644 --- a/test/Interop/Cxx/class/cxx-constructors-executable.swift +++ b/test/Interop/Cxx/class/constructors-executable.swift @@ -3,7 +3,7 @@ // REQUIRES: executable_test import StdlibUnittest -import CxxConstructors +import Constructors var CxxConstructorTestSuite = TestSuite("CxxConstructors") diff --git a/test/Interop/Cxx/class/cxx-constructors-ir.swift b/test/Interop/Cxx/class/constructors-ir.swift similarity index 99% rename from test/Interop/Cxx/class/cxx-constructors-ir.swift rename to test/Interop/Cxx/class/constructors-ir.swift index 1e2d3f7dffeef..3838ba51b681c 100644 --- a/test/Interop/Cxx/class/cxx-constructors-ir.swift +++ b/test/Interop/Cxx/class/constructors-ir.swift @@ -4,7 +4,7 @@ // RUN: %swift -module-name Swift -target armv7-none-linux-androideabi -dump-clang-diagnostics -I %S/Inputs -enable-cxx-interop -emit-ir %s -parse-stdlib -parse-as-library -disable-legacy-type-info | %FileCheck %s -check-prefix=ITANIUM_ARM // RUN: %swift -module-name Swift -target x86_64-unknown-windows-msvc -dump-clang-diagnostics -I %S/Inputs -enable-cxx-interop -emit-ir %s -parse-stdlib -parse-as-library -disable-legacy-type-info | %FileCheck %s -check-prefix=MICROSOFT_X64 -import CxxConstructors +import Constructors typealias Void = () diff --git a/test/Interop/Cxx/class/cxx-constructors-module-interface.swift b/test/Interop/Cxx/class/constructors-module-interface.swift similarity index 87% rename from test/Interop/Cxx/class/cxx-constructors-module-interface.swift rename to test/Interop/Cxx/class/constructors-module-interface.swift index 696b5ea49ba8e..a41e120f0b301 100644 --- a/test/Interop/Cxx/class/cxx-constructors-module-interface.swift +++ b/test/Interop/Cxx/class/constructors-module-interface.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-ide-test -print-module -module-to-print=CxxConstructors -I %S/Inputs/ -source-filename=x -enable-cxx-interop | %FileCheck %s +// RUN: %target-swift-ide-test -print-module -module-to-print=Constructors -I %S/Inputs/ -source-filename=x -enable-cxx-interop | %FileCheck %s // CHECK: struct ExplicitDefaultConstructor { // CHECK-NEXT: var x: Int32 diff --git a/test/Interop/Cxx/class/cxx-constructors-sil.swift b/test/Interop/Cxx/class/constructors-sil.swift similarity index 97% rename from test/Interop/Cxx/class/cxx-constructors-sil.swift rename to test/Interop/Cxx/class/constructors-sil.swift index adbf551eb73c9..9eef642b22d0a 100644 --- a/test/Interop/Cxx/class/cxx-constructors-sil.swift +++ b/test/Interop/Cxx/class/constructors-sil.swift @@ -1,6 +1,6 @@ // RUN: %target-swift-frontend -I %S/Inputs -enable-cxx-interop -emit-sil %s | %FileCheck %s -import CxxConstructors +import Constructors // The most important thing to test here is that the constructor result is returned // with an @out attribute. diff --git a/test/Interop/Cxx/class/cxx-constructors-typecheck.swift b/test/Interop/Cxx/class/constructors-typechecker.swift similarity index 95% rename from test/Interop/Cxx/class/cxx-constructors-typecheck.swift rename to test/Interop/Cxx/class/constructors-typechecker.swift index 6da3a097ee6dc..3cc008807c6a1 100644 --- a/test/Interop/Cxx/class/cxx-constructors-typecheck.swift +++ b/test/Interop/Cxx/class/constructors-typechecker.swift @@ -1,6 +1,6 @@ // RUN: %target-typecheck-verify-swift -verify-ignore-unknown -I %S/Inputs -enable-cxx-interop -import CxxConstructors +import Constructors let explicit = ExplicitDefaultConstructor() From 5644137ea0696164c5b5835179b1ec450d508c88 Mon Sep 17 00:00:00 2001 From: Martin Boehme Date: Fri, 15 May 2020 14:22:11 +0200 Subject: [PATCH 08/33] Eliminate duplication of code for adding empty argument names. --- lib/ClangImporter/ImportName.cpp | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/lib/ClangImporter/ImportName.cpp b/lib/ClangImporter/ImportName.cpp index 65df344f664a0..1a02a454ede0d 100644 --- a/lib/ClangImporter/ImportName.cpp +++ b/lib/ClangImporter/ImportName.cpp @@ -1366,6 +1366,16 @@ static bool suppressFactoryMethodAsInit(const clang::ObjCMethodDecl *method, initKind == CtorInitializerKind::ConvenienceFactory); } +static void +addEmptyArgNamesForCxxFunc(const clang::FunctionDecl *funcDecl, + SmallVectorImpl &argumentNames) { + for (size_t i = 0; i < funcDecl->param_size(); ++i) { + argumentNames.push_back(StringRef()); + } + if (funcDecl->isVariadic()) + argumentNames.push_back(StringRef()); +} + ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D, ImportNameVersion version, clang::DeclarationName givenName) { @@ -1604,13 +1614,8 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D, isFunction = true; result.info.initKind = CtorInitializerKind::Designated; baseName = "init"; - // Add empty argument names. if (auto ctor = dyn_cast(D)) { - for (size_t i = 0; i < ctor->param_size(); ++i) { - argumentNames.push_back(StringRef()); - } - if (ctor->isVariadic()) - argumentNames.push_back(StringRef()); + addEmptyArgNamesForCxxFunc(ctor, argumentNames); } break; @@ -1684,16 +1689,9 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D, } } - // For C functions, create empty argument names. if (auto function = dyn_cast(D)) { isFunction = true; - params = {function->param_begin(), function->param_end()}; - for (auto param : params) { - (void)param; - argumentNames.push_back(StringRef()); - } - if (function->isVariadic()) - argumentNames.push_back(StringRef()); + addEmptyArgNamesForCxxFunc(function, argumentNames); } break; From bed26039446c189a82c453126e0a622e43c6256d Mon Sep 17 00:00:00 2001 From: Martin Boehme Date: Wed, 20 May 2020 07:47:20 +0200 Subject: [PATCH 09/33] Various changes after merging master: - Adapt tests to changes that have happened in the meantime (e.g. `HasVirtualBase` is rightly no longer considered loadable) - Don't import copy or move constructors (noticed this because references are now imported correctly, so copy and move constructors suddenly started showing up in the SIL test) - Don't try to define an implicitly-deleted default constructor (this previously broke loadable-types-silgen.swift) --- lib/ClangImporter/ImportDecl.cpp | 15 +++++++++++---- test/Interop/Cxx/class/Inputs/constructors.h | 5 +++++ test/Interop/Cxx/class/constructors-ir.swift | 6 +++--- .../Cxx/class/constructors-module-interface.swift | 3 +++ 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 2a5983d0a8733..46a135d9573d9 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -3482,8 +3482,9 @@ namespace { result->setHasUnreferenceableStorage(hasUnreferenceableStorage); - if (auto cxxRecordDecl = dyn_cast(decl)) { - result->setIsCxxNonTrivial(!cxxRecordDecl->isTriviallyCopyable()); + if (cxxRecordDecl) { + result->setIsCxxNonTrivial( + !cxxRecordDecl->isTriviallyCopyable()); for (auto ctor : cxxRecordDecl->ctors()) { if (ctor->isCopyConstructor() && @@ -3518,8 +3519,9 @@ namespace { clang::CXXConstructorDecl *ctor = clangSema.DeclareImplicitDefaultConstructor( const_cast(decl)); - clangSema.DefineImplicitDefaultConstructor(clang::SourceLocation(), - ctor); + if (!ctor->isDeleted()) + clangSema.DefineImplicitDefaultConstructor(clang::SourceLocation(), + ctor); } return VisitRecordDecl(decl); @@ -3898,6 +3900,11 @@ namespace { AbstractFunctionDecl *result = nullptr; if (auto *ctordecl = dyn_cast(decl)) { + // Don't import copy constructor or move constructor -- these will be + // provided through the value witness table. + if (ctordecl->isCopyConstructor() || ctordecl->isMoveConstructor()) + return nullptr; + DeclName ctorName(Impl.SwiftContext, DeclBaseName::createConstructor(), bodyParams); result = Impl.createDeclWithClangNode( diff --git a/test/Interop/Cxx/class/Inputs/constructors.h b/test/Interop/Cxx/class/Inputs/constructors.h index 72da5a217ab81..7959be4e0a4fe 100644 --- a/test/Interop/Cxx/class/Inputs/constructors.h +++ b/test/Interop/Cxx/class/Inputs/constructors.h @@ -21,6 +21,11 @@ struct ConstructorWithParam { int x; }; +struct CopyAndMoveConstructor { + CopyAndMoveConstructor(const CopyAndMoveConstructor &) = default; + CopyAndMoveConstructor(CopyAndMoveConstructor &&) = default; +}; + struct Base {}; struct ArgType { diff --git a/test/Interop/Cxx/class/constructors-ir.swift b/test/Interop/Cxx/class/constructors-ir.swift index 3838ba51b681c..27df20e161098 100644 --- a/test/Interop/Cxx/class/constructors-ir.swift +++ b/test/Interop/Cxx/class/constructors-ir.swift @@ -22,11 +22,11 @@ public func createHasVirtualBase() -> HasVirtualBase { // Swift constructors that return their result indirectly) because the C++ // constructor has explicit access to `this` and may capture it. // - // ITANIUM_X64: define swiftcc { i8*, i32 } @"$ss20createHasVirtualBaseSo0bcD0VyF"() + // ITANIUM_X64: define swiftcc void @"$ss20createHasVirtualBaseSo0bcD0VyF"(%TSo14HasVirtualBaseV* noalias nocapture sret %0) // ITANIUM_X64-NOT: define // ITANIUM_X64: call void @_ZN14HasVirtualBaseC1E7ArgType(%struct.HasVirtualBase* noalias sret %{{[0-9]+}}, i32 %{{[0-9]+}}) // - // ITANIUM_ARM: define protected swiftcc { i8*, i32 } @"$ss20createHasVirtualBaseSo0bcD0VyF"() + // ITANIUM_ARM: define protected swiftcc void @"$ss20createHasVirtualBaseSo0bcD0VyF"(%TSo14HasVirtualBaseV* noalias nocapture sret %0) // To verify that the thunk is inlined, make sure there's no intervening // `define`, i.e. the call to the C++ constructor happens in // createHasVirtualBase(), not some later function. @@ -34,7 +34,7 @@ public func createHasVirtualBase() -> HasVirtualBase { // Note `this` return type. // ITANIUM_ARM: call %struct.HasVirtualBase* @_ZN14HasVirtualBaseC1E7ArgType(%struct.HasVirtualBase* %{{[0-9]+}}, [1 x i32] %{{[0-9]+}}) // - // MICROSOFT_X64: define dllexport swiftcc { i8*, i32 } @"$ss20createHasVirtualBaseSo0bcD0VyF"() + // MICROSOFT_X64: define dllexport swiftcc void @"$ss20createHasVirtualBaseSo0bcD0VyF"(%TSo14HasVirtualBaseV* noalias nocapture sret %0) // MICROSOFT_X64-NOT: define // Note `this` return type and implicit "most derived" argument. // MICROSOFT_X64: call %struct.HasVirtualBase* @"??0HasVirtualBase@@QEAA@UArgType@@@Z"(%struct.HasVirtualBase* %{{[0-9]+}}, i32 %{{[0-9]+}}, i32 1) diff --git a/test/Interop/Cxx/class/constructors-module-interface.swift b/test/Interop/Cxx/class/constructors-module-interface.swift index a41e120f0b301..acc321c4bca4e 100644 --- a/test/Interop/Cxx/class/constructors-module-interface.swift +++ b/test/Interop/Cxx/class/constructors-module-interface.swift @@ -15,11 +15,14 @@ // CHECK-NEXT: init(member: ImplicitDefaultConstructor) // CHECK-NEXT: } // CHECK-NEXT: struct DefaultConstructorDeleted { +// CHECK-NEXT: var a: UnsafeMutablePointer // CHECK-NEXT: } // CHECK-NEXT: struct ConstructorWithParam { // CHECK-NEXT: var x: Int32 // CHECK-NEXT: init(_ val: Int32) // CHECK-NEXT: } +// CHECK-NEXT: struct CopyAndMoveConstructor { +// CHECK-NEXT: } // CHECK-NEXT: struct Base { // CHECK-NEXT: init() // CHECK-NEXT: } From beaaa742c3e774b6739de26bb1a3f0c8761512a5 Mon Sep 17 00:00:00 2001 From: Martin Boehme Date: Mon, 25 May 2020 16:06:18 +0200 Subject: [PATCH 10/33] Don't put an `sret` attribute on the `this` argument. --- lib/IRGen/GenCall.cpp | 9 +++++++-- test/Interop/Cxx/class/constructors-ir.swift | 15 ++++++++------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/lib/IRGen/GenCall.cpp b/lib/IRGen/GenCall.cpp index b051e860bd984..a2faf3b227c7b 100644 --- a/lib/IRGen/GenCall.cpp +++ b/lib/IRGen/GenCall.cpp @@ -1435,8 +1435,13 @@ void SignatureExpansion::expandExternalSignatureTypes() { if (formalIndirectResult) { // If the result is a formal indirect result in SIL, that means that the // Clang function has an explicit output parameter (e.g. it's a C++ - // constructor), which it might capture -- so don't specify "nocapture". - addIndirectResultAttributes(IGM, Attrs, 0, claimSRet(), /* nocapture = */ false); + // constructor). This means: + // - Don't mark it `sret`, as this should only be used for C++ return + // values. + // - The Clang function might capture the pointer, so don't specify + // `nocapture`. + addIndirectResultAttributes(IGM, Attrs, 0, /* allowSRet = */ false, + /* noCapture = */ false); } if (returnInfo.isIndirect() || returnInfo.isIgnore()) { diff --git a/test/Interop/Cxx/class/constructors-ir.swift b/test/Interop/Cxx/class/constructors-ir.swift index 27df20e161098..1886a95601861 100644 --- a/test/Interop/Cxx/class/constructors-ir.swift +++ b/test/Interop/Cxx/class/constructors-ir.swift @@ -11,12 +11,13 @@ typealias Void = () public func createHasVirtualBase() -> HasVirtualBase { // - The `this` parameter should carry a `noalias` attribute, as it is // guaranteed that nothing will alias the object before it has been fully - // constructed. It should also carry an `sret` attribute to indicate that - // this is an out parameter for a structure being returned by the function. - // Note that this doesn't apply on ABIs (Itanium ARM, Microsoft x64) - // where we insert an (inlined) thunk; in this case, we're getting the - // attributes of the constructor that was generated by Clang, which doesn't - // insert these attributes. + // constructed. Note that this doesn't apply on ABIs (Itanium ARM, + // Microsoft x64) where we insert an (inlined) thunk; in this case, we're + // getting the attributes of the constructor that was generated by Clang, + // which doesn't insert these attributes. + // + // - The `this` parameter should _not_ carry an `sret` attribute because the + // constructor doesn't return the constructed object as a return value. // // - The `this` parameter should _not_ carry a `nocapture` attribute (unlike // Swift constructors that return their result indirectly) because the C++ @@ -24,7 +25,7 @@ public func createHasVirtualBase() -> HasVirtualBase { // // ITANIUM_X64: define swiftcc void @"$ss20createHasVirtualBaseSo0bcD0VyF"(%TSo14HasVirtualBaseV* noalias nocapture sret %0) // ITANIUM_X64-NOT: define - // ITANIUM_X64: call void @_ZN14HasVirtualBaseC1E7ArgType(%struct.HasVirtualBase* noalias sret %{{[0-9]+}}, i32 %{{[0-9]+}}) + // ITANIUM_X64: call void @_ZN14HasVirtualBaseC1E7ArgType(%struct.HasVirtualBase* noalias %{{[0-9]+}}, i32 %{{[0-9]+}}) // // ITANIUM_ARM: define protected swiftcc void @"$ss20createHasVirtualBaseSo0bcD0VyF"(%TSo14HasVirtualBaseV* noalias nocapture sret %0) // To verify that the thunk is inlined, make sure there's no intervening From 8416ccfa06d05da67af70a8ed57a2f120ea251b2 Mon Sep 17 00:00:00 2001 From: Martin Boehme Date: Mon, 25 May 2020 16:11:03 +0200 Subject: [PATCH 11/33] Rename constructors-ir.swift to constructors-irgen.swift. --- .../Cxx/class/{constructors-ir.swift => constructors-irgen.swift} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/Interop/Cxx/class/{constructors-ir.swift => constructors-irgen.swift} (100%) diff --git a/test/Interop/Cxx/class/constructors-ir.swift b/test/Interop/Cxx/class/constructors-irgen.swift similarity index 100% rename from test/Interop/Cxx/class/constructors-ir.swift rename to test/Interop/Cxx/class/constructors-irgen.swift From 8f6042aa0870a527505262c7dbe89ec7ffe20e12 Mon Sep 17 00:00:00 2001 From: Martin Boehme Date: Mon, 25 May 2020 16:23:03 +0200 Subject: [PATCH 12/33] Add additional IR tests for a class without a virtual base class. --- test/Interop/Cxx/class/constructors-irgen.swift | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/Interop/Cxx/class/constructors-irgen.swift b/test/Interop/Cxx/class/constructors-irgen.swift index 1886a95601861..cb98844dbf3a2 100644 --- a/test/Interop/Cxx/class/constructors-irgen.swift +++ b/test/Interop/Cxx/class/constructors-irgen.swift @@ -41,3 +41,20 @@ public func createHasVirtualBase() -> HasVirtualBase { // MICROSOFT_X64: call %struct.HasVirtualBase* @"??0HasVirtualBase@@QEAA@UArgType@@@Z"(%struct.HasVirtualBase* %{{[0-9]+}}, i32 %{{[0-9]+}}, i32 1) return HasVirtualBase(ArgType()) } + +public func createImplicitDefaultConstructor() -> ImplicitDefaultConstructor { + // ITANIUM_X64: define swiftcc i32 @"$ss32createImplicitDefaultConstructorSo0bcD0VyF"() + // ITANIUM_X64-NOT: define + // ITANIUM_X64: call void @_ZN26ImplicitDefaultConstructorC1Ev(%struct.ImplicitDefaultConstructor* noalias %{{[0-9]+}}) + // + // ITANIUM_ARM: define protected swiftcc i32 @"$ss32createImplicitDefaultConstructorSo0bcD0VyF"() + // ITANIUM_ARM-NOT: define + // Note `this` return type. + // ITANIUM_ARM: call %struct.ImplicitDefaultConstructor* @_ZN26ImplicitDefaultConstructorC2Ev(%struct.ImplicitDefaultConstructor* %{{[0-9]+}}) + // + // MICROSOFT_X64: define dllexport swiftcc i32 @"$ss32createImplicitDefaultConstructorSo0bcD0VyF"() + // MICROSOFT_X64-NOT: define + // Note `this` return type but no implicit "most derived" argument. + // MICROSOFT_X64: call %struct.ImplicitDefaultConstructor* @"??0ImplicitDefaultConstructor@@QEAA@XZ"(%struct.ImplicitDefaultConstructor* %{{[0-9]+}}) + return ImplicitDefaultConstructor() +} From c9405fb7fc338f59db4386488245a3ce82227e00 Mon Sep 17 00:00:00 2001 From: Martin Boehme Date: Tue, 26 May 2020 06:48:17 +0200 Subject: [PATCH 13/33] Add Windows-name-mangled version of symbol to SIL test. --- test/Interop/Cxx/class/constructors-sil.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Interop/Cxx/class/constructors-sil.swift b/test/Interop/Cxx/class/constructors-sil.swift index 9eef642b22d0a..95b748ebb89eb 100644 --- a/test/Interop/Cxx/class/constructors-sil.swift +++ b/test/Interop/Cxx/class/constructors-sil.swift @@ -8,6 +8,6 @@ import Constructors // CHECK: [[TYPE:%[0-9]+]] = metatype $@thin ConstructorWithParam.Type // CHECK: [[LITERAL:%[0-9]+]] = integer_literal $Builtin.Int32, 42 // CHECK: [[INT:%[0-9]+]] = struct $Int32 ([[LITERAL]] : $Builtin.Int32) -// CHECK: [[FUNC:%[0-9]+]] = function_ref @_ZN20ConstructorWithParamC1Ei : $@convention(c) (Int32, @thin ConstructorWithParam.Type) -> @out ConstructorWithParam +// CHECK: [[FUNC:%[0-9]+]] = function_ref @{{_ZN20ConstructorWithParamC1Ei|\?\?0ConstructorWithParam@@QEAA@H@Z}} : $@convention(c) (Int32, @thin ConstructorWithParam.Type) -> @out ConstructorWithParam // CHECK: %{{[0-9]+}} = apply [[FUNC]]([[VAR]], [[INT]], [[TYPE]]) : $@convention(c) (Int32, @thin ConstructorWithParam.Type) -> @out ConstructorWithParam let _ = ConstructorWithParam(42) From cb4ddda6e2292c584cb83905f3f9df17a4e017f1 Mon Sep 17 00:00:00 2001 From: Martin Boehme Date: Tue, 2 Jun 2020 09:32:12 +0200 Subject: [PATCH 14/33] Avoid crashing if lldb imports C++ structs without enabling C++ interop. --- lib/ClangImporter/ImportDecl.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 46a135d9573d9..df44ddc2d4ba2 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -3505,6 +3505,13 @@ namespace { } Decl *VisitCXXRecordDecl(const clang::CXXRecordDecl *decl) { + // lldb can call this without enabling C++ interop. To avoid crashing in + // Clang's Sema, fall back to importing this as a plain RecordDecl. + // FIXME: Fix lldb to enable C++ interop when appropriate, then remove + // this fallback. + if (!Impl.SwiftContext.LangOpts.EnableCXXInterop) + return VisitRecordDecl(decl); + auto &clangSema = Impl.getClangSema(); // Make Clang define the implicit default constructor if the class needs // it. Make sure we only do this if the class has been fully defined and From 33e8c717f2682b913eb04e1c7746c84315be90ef Mon Sep 17 00:00:00 2001 From: Martin Boehme Date: Mon, 8 Jun 2020 13:56:37 +0200 Subject: [PATCH 15/33] Update comment in VisitCXXRecordDecl(). --- lib/ClangImporter/ImportDecl.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index df44ddc2d4ba2..7d2ebfe33929f 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -3505,10 +3505,11 @@ namespace { } Decl *VisitCXXRecordDecl(const clang::CXXRecordDecl *decl) { - // lldb can call this without enabling C++ interop. To avoid crashing in - // Clang's Sema, fall back to importing this as a plain RecordDecl. - // FIXME: Fix lldb to enable C++ interop when appropriate, then remove - // this fallback. + // This can be called from lldb without C++ interop being enabled: There + // may be C++ declarations in imported modules, but the interface for + // those modules may be a pure C or Objective-C interface. + // To avoid crashing in Clang's Sema, fall back to importing this as a + // plain RecordDecl. if (!Impl.SwiftContext.LangOpts.EnableCXXInterop) return VisitRecordDecl(decl); From 7e8ea120701b33958a1adca9e885a99f5d583607 Mon Sep 17 00:00:00 2001 From: Martin Boehme Date: Wed, 10 Jun 2020 09:53:55 +0200 Subject: [PATCH 16/33] Respond to review comments. --- test/Interop/Cxx/class/constructors-sil.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Interop/Cxx/class/constructors-sil.swift b/test/Interop/Cxx/class/constructors-sil.swift index 95b748ebb89eb..def974a1e9a3d 100644 --- a/test/Interop/Cxx/class/constructors-sil.swift +++ b/test/Interop/Cxx/class/constructors-sil.swift @@ -2,8 +2,8 @@ import Constructors -// The most important thing to test here is that the constructor result is returned -// with an @out attribute. +// The most important thing to test here is that the constructor result is +// returned with an @out attribute. // CHECK: [[VAR:%[0-9]+]] = alloc_stack $ConstructorWithParam // CHECK: [[TYPE:%[0-9]+]] = metatype $@thin ConstructorWithParam.Type // CHECK: [[LITERAL:%[0-9]+]] = integer_literal $Builtin.Int32, 42 From 1ce3753d08522cefe255f4acf498dba5085aa60a Mon Sep 17 00:00:00 2001 From: Martin Boehme Date: Wed, 10 Jun 2020 10:01:07 +0200 Subject: [PATCH 17/33] Another response to review comments. --- lib/IRGen/GenCall.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/IRGen/GenCall.cpp b/lib/IRGen/GenCall.cpp index a2faf3b227c7b..0166efb11799b 100644 --- a/lib/IRGen/GenCall.cpp +++ b/lib/IRGen/GenCall.cpp @@ -1318,6 +1318,8 @@ void SignatureExpansion::expandExternalSignatureTypes() { // Convert each parameter to a Clang type. for (auto param : params) { auto clangTy = IGM.getClangType(param, FnType); + // If a parameter type is lowered to void, this means it should be ignored. + // For example, this happens for thin metatypes. if (clangTy->isVoidType()) { continue; } From faca489c6f524096019fd124cba847949972e0db Mon Sep 17 00:00:00 2001 From: Martin Boehme Date: Wed, 10 Jun 2020 14:23:33 +0200 Subject: [PATCH 18/33] Add a test that Objective-C types passed to a C++ constructor are bridged correctly. --- test/Interop/Cxx/class/Inputs/constructors-objc.h | 5 +++++ test/Interop/Cxx/class/Inputs/module.modulemap | 8 ++++++++ .../Cxx/class/constructors-objc-module-interface.swift | 10 ++++++++++ 3 files changed, 23 insertions(+) create mode 100644 test/Interop/Cxx/class/Inputs/constructors-objc.h create mode 100644 test/Interop/Cxx/class/constructors-objc-module-interface.swift diff --git a/test/Interop/Cxx/class/Inputs/constructors-objc.h b/test/Interop/Cxx/class/Inputs/constructors-objc.h new file mode 100644 index 0000000000000..46d7667a0095d --- /dev/null +++ b/test/Interop/Cxx/class/Inputs/constructors-objc.h @@ -0,0 +1,5 @@ +#import + +struct ConstructorWithNSArrayParam { + ConstructorWithNSArrayParam(NSArray *array) {} +}; diff --git a/test/Interop/Cxx/class/Inputs/module.modulemap b/test/Interop/Cxx/class/Inputs/module.modulemap index 0370a978cb949..53ee329a23d7a 100644 --- a/test/Interop/Cxx/class/Inputs/module.modulemap +++ b/test/Interop/Cxx/class/Inputs/module.modulemap @@ -10,6 +10,14 @@ module Constructors { header "constructors.h" } +module ConstructorsObjC { + header "constructors-objc.h" +} + +module LoadableTypes { + header "loadable-types.h" +} + module MemberwiseInitializer { header "memberwise-initializer.h" } diff --git a/test/Interop/Cxx/class/constructors-objc-module-interface.swift b/test/Interop/Cxx/class/constructors-objc-module-interface.swift new file mode 100644 index 0000000000000..b636bfae24c64 --- /dev/null +++ b/test/Interop/Cxx/class/constructors-objc-module-interface.swift @@ -0,0 +1,10 @@ +// Test that Objective-C types passed to a C++ constructor are bridged +// correctly. + +// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -print-module -module-to-print=ConstructorsObjC -I %S/Inputs/ -source-filename=x -enable-cxx-interop | %FileCheck %s + +// REQUIRES: objc_interop + +// CHECK: struct ConstructorWithNSArrayParam { +// CHECK-NEXT: init(_ array: [Any]!) +// CHECK-NEXT: } From 83b51b95b534108494de1032bb4e098274fe606b Mon Sep 17 00:00:00 2001 From: Martin Boehme Date: Wed, 10 Jun 2020 15:36:11 +0200 Subject: [PATCH 19/33] Add SILGen and IRGen tests for passing Objective-C types to C++ constructors. --- .../Cxx/class/constructors-objc-irgen.swift | 16 ++++++++++++++++ .../Cxx/class/constructors-objc-silgen.swift | 12 ++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 test/Interop/Cxx/class/constructors-objc-irgen.swift create mode 100644 test/Interop/Cxx/class/constructors-objc-silgen.swift diff --git a/test/Interop/Cxx/class/constructors-objc-irgen.swift b/test/Interop/Cxx/class/constructors-objc-irgen.swift new file mode 100644 index 0000000000000..a5e8d4d162f87 --- /dev/null +++ b/test/Interop/Cxx/class/constructors-objc-irgen.swift @@ -0,0 +1,16 @@ +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -I %S/Inputs -enable-cxx-interop -emit-ir %s | %FileCheck %s + +// REQUIRES: CPU=x86_64 +// REQUIRES: objc_interop + +import ConstructorsObjC + +public func createConstructorWithNSArrayParam() -> ConstructorWithNSArrayParam { + // CHECK: define swiftcc void @"$s4main33createConstructorWithNSArrayParamSo0cdeF0VyF"() + // CHECK-NOT: define + // CHECK: [[VAR:%[0-9]+]] = alloca %TSo27ConstructorWithNSArrayParamV, align 1 + // CHECK: %{{[0-9]+}} = call swiftcc %TSo7NSArrayC* @"$sSa10FoundationE19_bridgeToObjectiveCSo7NSArrayCyF"(%swift.bridge* %{{[0-9]+}}, %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* @"$sypN", i32 0, i32 1)) + // CHECK: [[CAST_VAR:%[0-9]+]] = bitcast %TSo27ConstructorWithNSArrayParamV* [[VAR]] to %struct.ConstructorWithNSArrayParam* + // CHECK: call void @_ZN27ConstructorWithNSArrayParamC1EP7NSArray(%struct.ConstructorWithNSArrayParam* noalias [[CAST_VAR]], [[VAR]]* %{{[0-9]+}}) + return ConstructorWithNSArrayParam([]) +} diff --git a/test/Interop/Cxx/class/constructors-objc-silgen.swift b/test/Interop/Cxx/class/constructors-objc-silgen.swift new file mode 100644 index 0000000000000..c7199ee889811 --- /dev/null +++ b/test/Interop/Cxx/class/constructors-objc-silgen.swift @@ -0,0 +1,12 @@ +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -I %S/Inputs -enable-cxx-interop -emit-sil %s | %FileCheck %s + +// REQUIRES: objc_interop + +import ConstructorsObjC + +// CHECK: [[VAR:%[0-9]+]] = alloc_stack $ConstructorWithNSArrayParam +// CHECK: [[TYPE:%[0-9]+]] = metatype $@thin ConstructorWithNSArrayParam.Type +// CHECK: [[OPT_ARRAY:%[0-9]+]] = enum $Optional, #Optional.some!enumelt, %{{[0-9]+}} : $NSArray +// CHECK: [[FUNC:%[0-9]+]] = function_ref @_ZN27ConstructorWithNSArrayParamC1EP7NSArray : $@convention(c) (Optional, @thin ConstructorWithNSArrayParam.Type) -> @out ConstructorWithNSArrayParam +// CHECK: %{{[0-9]+}} = apply [[FUNC]]([[VAR]], [[OPT_ARRAY]], [[TYPE]]) : $@convention(c) (Optional, @thin ConstructorWithNSArrayParam.Type) -> @out ConstructorWithNSArrayParam +let _ = ConstructorWithNSArrayParam([]) From cc7564ecd1902901dc93844790a9ea11b3225df5 Mon Sep 17 00:00:00 2001 From: Martin Boehme Date: Wed, 10 Jun 2020 15:36:57 +0200 Subject: [PATCH 20/33] Rename constructors-sil.swift to constructors-silgen.swift. --- .../class/{constructors-sil.swift => constructors-silgen.swift} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/Interop/Cxx/class/{constructors-sil.swift => constructors-silgen.swift} (100%) diff --git a/test/Interop/Cxx/class/constructors-sil.swift b/test/Interop/Cxx/class/constructors-silgen.swift similarity index 100% rename from test/Interop/Cxx/class/constructors-sil.swift rename to test/Interop/Cxx/class/constructors-silgen.swift From 2713edb19ecd23a27ccadb524008b641f805d9fe Mon Sep 17 00:00:00 2001 From: zoecarver Date: Mon, 21 Sep 2020 13:22:24 -0700 Subject: [PATCH 21/33] [cxx-interop] Fix missing APIs and tests after rebase. * Update tests that relied on old behavior. * Use mangleCXXName instead of mangleCXXCtor. * Call VisitCXXRecordDecl not VisitRecordDecl from VisitClassTemplateSpecializationDecl. This allows template constructors to be imported and called correctly. --- lib/ClangImporter/ClangImporter.cpp | 4 +- lib/ClangImporter/ImportDecl.cpp | 6 +- lib/SIL/SILFunctionType.cpp | 4284 ----------------- .../Cxx/class/Inputs/type-classification.h | 5 + .../Cxx/class/constructors-irgen.swift | 34 + .../synthesized-initializers-silgen.swift | 42 +- ...ype-classification-non-trivial-irgen.swift | 38 +- ...pe-classification-non-trivial-silgen.swift | 78 +- .../type-classification-non-trivial.swift | 8 +- .../canonical-types-module-interface.swift | 25 +- ...ined-class-template-module-interface.swift | 24 +- .../using-directive-module-interface.swift | 24 +- 12 files changed, 148 insertions(+), 4424 deletions(-) delete mode 100644 lib/SIL/SILFunctionType.cpp diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 2aad8328ac8cd..370a3cdd1f91d 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -3590,7 +3590,9 @@ void ClangImporter::getMangledName(raw_ostream &os, Impl.Mangler.reset(Impl.getClangASTContext().createMangleContext()); if (auto ctor = dyn_cast(clangDecl)) { - Impl.Mangler->mangleCXXCtor(ctor, clang::Ctor_Complete, os); + auto ctorGlobalDecl = clang::GlobalDecl(ctor, + clang::CXXCtorType::Ctor_Complete); + Impl.Mangler->mangleCXXName(ctorGlobalDecl, os); } else { Impl.Mangler->mangleName(clangDecl, os); } diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 7d2ebfe33929f..8b5fb67fab9da 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -1241,6 +1241,10 @@ synthesizeStructDefaultConstructorBody(AbstractFunctionDecl *afd, ASTContext &ctx = constructor->getASTContext(); auto structDecl = static_cast(context); + // We should call into C++ constructors directly. + assert(!isa(structDecl->getClangDecl()) && + "Should not synthesize a C++ object constructor."); + // Use a builtin to produce a zero initializer, and assign it to self. // Construct the left-hand reference to self. @@ -3558,7 +3562,7 @@ namespace { Impl.getClangSema().InstantiateClassTemplateSpecializationMembers( def->getLocation(), def, clang::TSK_ExplicitInstantiationDefinition); - return VisitRecordDecl(def); + return VisitCXXRecordDecl(def); } Decl *VisitClassTemplatePartialSpecializationDecl( diff --git a/lib/SIL/SILFunctionType.cpp b/lib/SIL/SILFunctionType.cpp deleted file mode 100644 index e50568874f4e0..0000000000000 --- a/lib/SIL/SILFunctionType.cpp +++ /dev/null @@ -1,4284 +0,0 @@ -//===--- SILFunctionType.cpp - Giving SIL types to AST functions ----------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2017 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 -// -//===----------------------------------------------------------------------===// -// -// This file defines the native Swift ownership transfer conventions -// and works in concert with the importer to give the correct -// conventions to imported functions and types. -// -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "libsil" -#include "swift/AST/AnyFunctionRef.h" -#include "swift/AST/Decl.h" -#include "swift/AST/DiagnosticsSIL.h" -#include "swift/AST/ForeignInfo.h" -#include "swift/AST/GenericEnvironment.h" -#include "swift/AST/GenericSignatureBuilder.h" -#include "swift/AST/Module.h" -#include "swift/AST/ModuleLoader.h" -#include "swift/AST/ProtocolConformance.h" -#include "swift/SIL/SILModule.h" -#include "swift/SIL/SILType.h" -#include "clang/AST/Attr.h" -#include "clang/AST/DeclCXX.h" -#include "clang/AST/DeclObjC.h" -#include "clang/Analysis/DomainSpecific/CocoaConventions.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/SaveAndRestore.h" - -using namespace swift; -using namespace swift::Lowering; - -SILType SILFunctionType::substInterfaceType(SILModule &M, - SILType interfaceType) const { - // Apply pattern substitutions first, then invocation substitutions. - if (auto subs = getPatternSubstitutions()) - interfaceType = interfaceType.subst(M, subs); - if (auto subs = getInvocationSubstitutions()) - interfaceType = interfaceType.subst(M, subs); - return interfaceType; -} - -CanSILFunctionType SILFunctionType::getUnsubstitutedType(SILModule &M) const { - auto mutableThis = const_cast(this); - - // If we have no substitutions, there's nothing to do. - if (!hasPatternSubstitutions() && !hasInvocationSubstitutions()) - return CanSILFunctionType(mutableThis); - - // Otherwise, substitute the component types. - - SmallVector params; - SmallVector yields; - SmallVector results; - Optional errorResult; - - auto subs = getCombinedSubstitutions(); - auto substComponentType = [&](CanType type) { - if (!type->hasTypeParameter()) return type; - return SILType::getPrimitiveObjectType(type) - .subst(M, subs).getASTType(); - }; - - for (auto param : getParameters()) { - params.push_back(param.map(substComponentType)); - } - - for (auto yield : getYields()) { - yields.push_back(yield.map(substComponentType)); - } - - for (auto result : getResults()) { - results.push_back(result.map(substComponentType)); - } - - if (auto error = getOptionalErrorResult()) { - errorResult = error->map(substComponentType); - } - - auto signature = isPolymorphic() ? getInvocationGenericSignature() - : CanGenericSignature(); - return SILFunctionType::get(signature, - getExtInfo(), - getCoroutineKind(), - getCalleeConvention(), - params, yields, results, errorResult, - SubstitutionMap(), - SubstitutionMap(), - mutableThis->getASTContext(), - getWitnessMethodConformanceOrInvalid()); -} - -CanType SILParameterInfo::getArgumentType(SILModule &M, - const SILFunctionType *t) const { - // TODO: We should always require a function type. - if (t) - return t->substInterfaceType(M, - SILType::getPrimitiveAddressType(getInterfaceType())) - .getASTType(); - - return getInterfaceType(); -} - -CanType SILResultInfo::getReturnValueType(SILModule &M, - const SILFunctionType *t) const { - // TODO: We should always require a function type. - if (t) - return t->substInterfaceType(M, - SILType::getPrimitiveAddressType(getInterfaceType())) - .getASTType(); - - return getInterfaceType(); -} - -SILType SILFunctionType::getDirectFormalResultsType(SILModule &M) { - CanType type; - if (getNumDirectFormalResults() == 0) { - type = getASTContext().TheEmptyTupleType; - } else if (getNumDirectFormalResults() == 1) { - type = getSingleDirectFormalResult().getReturnValueType(M, this); - } else { - auto &cache = getMutableFormalResultsCache(); - if (cache) { - type = cache; - } else { - SmallVector elts; - for (auto result : getResults()) - if (!result.isFormalIndirect()) - elts.push_back(result.getReturnValueType(M, this)); - type = CanType(TupleType::get(elts, getASTContext())); - cache = type; - } - } - return SILType::getPrimitiveObjectType(type); -} - -SILType SILFunctionType::getAllResultsInterfaceType() { - CanType type; - if (getNumResults() == 0) { - type = getASTContext().TheEmptyTupleType; - } else if (getNumResults() == 1) { - type = getResults()[0].getInterfaceType(); - } else { - auto &cache = getMutableAllResultsCache(); - if (cache) { - type = cache; - } else { - SmallVector elts; - for (auto result : getResults()) - elts.push_back(result.getInterfaceType()); - type = CanType(TupleType::get(elts, getASTContext())); - cache = type; - } - } - return SILType::getPrimitiveObjectType(type); -} - -SILType SILFunctionType::getAllResultsSubstType(SILModule &M) { - return substInterfaceType(M, getAllResultsInterfaceType()); -} - -SILType SILFunctionType::getFormalCSemanticResult(SILModule &M) { - assert(getLanguage() == SILFunctionLanguage::C); - assert(getNumResults() <= 1); - return getDirectFormalResultsType(M); -} - -CanType SILFunctionType::getSelfInstanceType(SILModule &M) const { - auto selfTy = getSelfParameter().getArgumentType(M, this); - - // If this is a static method, get the instance type. - if (auto metaTy = dyn_cast(selfTy)) - return metaTy.getInstanceType(); - - return selfTy; -} - -ClassDecl * -SILFunctionType::getWitnessMethodClass(SILModule &M) const { - // TODO: When witnesses use substituted types, we'd get this from the - // substitution map. - auto selfTy = getSelfInstanceType(M); - auto genericSig = getSubstGenericSignature(); - if (auto paramTy = dyn_cast(selfTy)) { - assert(paramTy->getDepth() == 0 && paramTy->getIndex() == 0); - auto superclass = genericSig->getSuperclassBound(paramTy); - if (superclass) - return superclass->getClassOrBoundGenericClass(); - } - - return nullptr; -} - -IndexSubset * -SILFunctionType::getDifferentiabilityParameterIndices() { - assert(isDifferentiable() && "Must be a differentiable function"); - SmallVector result; - for (auto valueAndIndex : enumerate(getParameters())) - if (valueAndIndex.value().getDifferentiability() != - SILParameterDifferentiability::NotDifferentiable) - result.push_back(valueAndIndex.index()); - return IndexSubset::get(getASTContext(), getNumParameters(), result); -} - -CanSILFunctionType -SILFunctionType::getWithDifferentiability(DifferentiabilityKind kind, - IndexSubset *parameterIndices) { - assert(kind != DifferentiabilityKind::NonDifferentiable && - "Differentiability kind must be normal or linear"); - SmallVector newParameters; - for (auto paramAndIndex : enumerate(getParameters())) { - auto ¶m = paramAndIndex.value(); - unsigned index = paramAndIndex.index(); - newParameters.push_back(param.getWithDifferentiability( - index < parameterIndices->getCapacity() && - parameterIndices->contains(index) - ? SILParameterDifferentiability::DifferentiableOrNotApplicable - : SILParameterDifferentiability::NotDifferentiable)); - } - auto newExtInfo = getExtInfo().withDifferentiabilityKind(kind); - return get(getInvocationGenericSignature(), newExtInfo, getCoroutineKind(), - getCalleeConvention(), newParameters, getYields(), getResults(), - getOptionalErrorResult(), getPatternSubstitutions(), - getInvocationSubstitutions(), getASTContext(), - getWitnessMethodConformanceOrInvalid()); -} - -CanSILFunctionType SILFunctionType::getWithoutDifferentiability() { - if (!isDifferentiable()) - return CanSILFunctionType(this); - auto nondiffExtInfo = getExtInfo().withDifferentiabilityKind( - DifferentiabilityKind::NonDifferentiable); - SmallVector newParams; - for (auto ¶m : getParameters()) - newParams.push_back(param.getWithDifferentiability( - SILParameterDifferentiability::DifferentiableOrNotApplicable)); - return SILFunctionType::get(getInvocationGenericSignature(), nondiffExtInfo, - getCoroutineKind(), getCalleeConvention(), - newParams, getYields(), getResults(), - getOptionalErrorResult(), - getPatternSubstitutions(), - getInvocationSubstitutions(), - getASTContext()); -} - -/// Collects the differentiability parameters of the given original function -/// type in `diffParams`. -static void -getDifferentiabilityParameters(SILFunctionType *originalFnTy, - IndexSubset *parameterIndices, - SmallVectorImpl &diffParams) { - // Returns true if `index` is a differentiability parameter index. - auto isDiffParamIndex = [&](unsigned index) -> bool { - return index < parameterIndices->getCapacity() && - parameterIndices->contains(index); - }; - // Calculate differentiability parameter infos. - for (auto valueAndIndex : enumerate(originalFnTy->getParameters())) - if (isDiffParamIndex(valueAndIndex.index())) - diffParams.push_back(valueAndIndex.value()); -} - -/// Collects the semantic results of the given function type in -/// `originalResults`. The semantic results are formal results followed by -/// `inout` parameters, in type order. -// TODO(TF-983): Generalize to support multiple `inout` parameters. The current -// singular `inoutParam` and `isWrtInoutParameter` are hacky. -static void -getSemanticResults(SILFunctionType *functionType, IndexSubset *parameterIndices, - Optional &inoutParam, - bool &isWrtInoutParameter, - SmallVectorImpl &originalResults) { - inoutParam = None; - isWrtInoutParameter = false; - // Collect original formal results. - originalResults.append(functionType->getResults().begin(), - functionType->getResults().end()); - // Collect original `inout` parameters. - for (auto i : range(functionType->getNumParameters())) { - auto param = functionType->getParameters()[i]; - if (!param.isIndirectInOut()) - continue; - inoutParam = param; - isWrtInoutParameter = parameterIndices->contains(i); - originalResults.push_back( - SILResultInfo(param.getInterfaceType(), ResultConvention::Indirect)); - } -} - -/// Returns the differential type for the given original function type, -/// parameter indices, and result index. -static CanSILFunctionType -getAutoDiffDifferentialType(SILFunctionType *originalFnTy, - IndexSubset *parameterIndices, unsigned resultIndex, - LookupConformanceFn lookupConformance) { - auto &ctx = originalFnTy->getASTContext(); - SmallVector substGenericParams; - SmallVector substRequirements; - SmallVector substReplacements; - SmallVector substConformances; - - Optional inoutParam = None; - bool isWrtInoutParameter = false; - SmallVector originalResults; - getSemanticResults(originalFnTy, parameterIndices, inoutParam, - isWrtInoutParameter, originalResults); - - SmallVector diffParams; - getDifferentiabilityParameters(originalFnTy, parameterIndices, diffParams); - SmallVector differentialParams; - for (auto ¶m : diffParams) { - auto paramTan = - param.getInterfaceType()->getAutoDiffTangentSpace(lookupConformance); - assert(paramTan && "Parameter type does not have a tangent space?"); - auto paramTanType = paramTan->getCanonicalType(); - if (!paramTanType->hasArchetype() && !paramTanType->hasTypeParameter()) { - differentialParams.push_back( - {paramTan->getCanonicalType(), param.getConvention()}); - } else { - auto gpIndex = substGenericParams.size(); - auto gpType = CanGenericTypeParamType::get(0, gpIndex, ctx); - substGenericParams.push_back(gpType); - substReplacements.push_back(paramTanType); - differentialParams.push_back({gpType, param.getConvention()}); - } - } - SmallVector differentialResults; - if (!inoutParam || !isWrtInoutParameter) { - auto &result = originalResults[resultIndex]; - auto resultTan = - result.getInterfaceType()->getAutoDiffTangentSpace(lookupConformance); - assert(resultTan && "Result type does not have a tangent space?"); - auto resultTanType = resultTan->getCanonicalType(); - if (!resultTanType->hasArchetype() && !resultTanType->hasTypeParameter()) { - differentialResults.push_back( - {resultTan->getCanonicalType(), result.getConvention()}); - } else { - auto gpIndex = substGenericParams.size(); - auto gpType = CanGenericTypeParamType::get(0, gpIndex, ctx); - substGenericParams.push_back(gpType); - substReplacements.push_back(resultTanType); - differentialResults.push_back({gpType, result.getConvention()}); - } - } - SubstitutionMap substitutions; - if (!substGenericParams.empty()) { - auto genericSig = - GenericSignature::get(substGenericParams, substRequirements) - .getCanonicalSignature(); - substitutions = - SubstitutionMap::get(genericSig, llvm::makeArrayRef(substReplacements), - llvm::makeArrayRef(substConformances)); - } - return SILFunctionType::get( - GenericSignature(), SILFunctionType::ExtInfo(), SILCoroutineKind::None, - ParameterConvention::Direct_Guaranteed, differentialParams, {}, - differentialResults, None, substitutions, - /*invocationSubstitutions*/ SubstitutionMap(), ctx); -} - -/// Returns the pullback type for the given original function type, parameter -/// indices, and result index. -static CanSILFunctionType -getAutoDiffPullbackType(SILFunctionType *originalFnTy, - IndexSubset *parameterIndices, unsigned resultIndex, - LookupConformanceFn lookupConformance, - TypeConverter &TC) { - auto &ctx = originalFnTy->getASTContext(); - SmallVector substGenericParams; - SmallVector substRequirements; - SmallVector substReplacements; - SmallVector substConformances; - - Optional inoutParam = None; - bool isWrtInoutParameter = false; - SmallVector originalResults; - getSemanticResults(originalFnTy, parameterIndices, inoutParam, - isWrtInoutParameter, originalResults); - - // Given a type, returns its formal SIL parameter info. - auto getTangentParameterConventionForOriginalResult = - [&](CanType tanType, - ResultConvention origResConv) -> ParameterConvention { - tanType = - tanType->getCanonicalType(originalFnTy->getSubstGenericSignature()); - AbstractionPattern pattern(originalFnTy->getSubstGenericSignature(), - tanType); - auto &tl = - TC.getTypeLowering(pattern, tanType, TypeExpansionContext::minimal()); - ParameterConvention conv; - switch (origResConv) { - case ResultConvention::Owned: - case ResultConvention::Autoreleased: - if (tl.isAddressOnly()) { - conv = ParameterConvention::Indirect_In_Guaranteed; - } else { - conv = tl.isTrivial() ? ParameterConvention::Direct_Unowned - : ParameterConvention::Direct_Guaranteed; - } - break; - case ResultConvention::Unowned: - case ResultConvention::UnownedInnerPointer: - conv = ParameterConvention::Direct_Unowned; - break; - case ResultConvention::Indirect: - conv = ParameterConvention::Indirect_In_Guaranteed; - break; - } - return conv; - }; - - // Given a type, returns its formal SIL result info. - auto getTangentResultConventionForOriginalParameter = - [&](CanType tanType, - ParameterConvention origParamConv) -> ResultConvention { - tanType = - tanType->getCanonicalType(originalFnTy->getSubstGenericSignature()); - AbstractionPattern pattern(originalFnTy->getSubstGenericSignature(), - tanType); - auto &tl = - TC.getTypeLowering(pattern, tanType, TypeExpansionContext::minimal()); - ResultConvention conv; - switch (origParamConv) { - case ParameterConvention::Direct_Owned: - case ParameterConvention::Direct_Guaranteed: - case ParameterConvention::Direct_Unowned: - if (tl.isAddressOnly()) { - conv = ResultConvention::Indirect; - } else { - conv = tl.isTrivial() ? ResultConvention::Unowned - : ResultConvention::Owned; - } - break; - case ParameterConvention::Indirect_In: - case ParameterConvention::Indirect_Inout: - case ParameterConvention::Indirect_In_Constant: - case ParameterConvention::Indirect_In_Guaranteed: - case ParameterConvention::Indirect_InoutAliasable: - conv = ResultConvention::Indirect; - break; - } - return conv; - }; - - SmallVector pullbackParams; - if (inoutParam) { - auto paramTan = inoutParam->getInterfaceType()->getAutoDiffTangentSpace( - lookupConformance); - assert(paramTan && "Parameter type does not have a tangent space?"); - auto paramTanConvention = isWrtInoutParameter - ? inoutParam->getConvention() - : ParameterConvention::Indirect_In_Guaranteed; - auto paramTanType = paramTan->getCanonicalType(); - if (!paramTanType->hasArchetype() && !paramTanType->hasTypeParameter()) { - pullbackParams.push_back( - SILParameterInfo(paramTanType, paramTanConvention)); - } else { - auto gpIndex = substGenericParams.size(); - auto gpType = CanGenericTypeParamType::get(0, gpIndex, ctx); - substGenericParams.push_back(gpType); - substReplacements.push_back(paramTanType); - pullbackParams.push_back({gpType, paramTanConvention}); - } - } else { - auto &origRes = originalResults[resultIndex]; - auto resultTan = - origRes.getInterfaceType()->getAutoDiffTangentSpace(lookupConformance); - assert(resultTan && "Result type does not have a tangent space?"); - auto resultTanType = resultTan->getCanonicalType(); - auto paramTanConvention = getTangentParameterConventionForOriginalResult( - resultTanType, origRes.getConvention()); - if (!resultTanType->hasArchetype() && !resultTanType->hasTypeParameter()) { - auto resultTanType = resultTan->getCanonicalType(); - pullbackParams.push_back({resultTanType, paramTanConvention}); - } else { - auto gpIndex = substGenericParams.size(); - auto gpType = CanGenericTypeParamType::get(0, gpIndex, ctx); - substGenericParams.push_back(gpType); - substReplacements.push_back(resultTanType); - pullbackParams.push_back({gpType, paramTanConvention}); - } - } - SmallVector diffParams; - getDifferentiabilityParameters(originalFnTy, parameterIndices, diffParams); - SmallVector pullbackResults; - for (auto ¶m : diffParams) { - if (param.isIndirectInOut()) - continue; - auto paramTan = - param.getInterfaceType()->getAutoDiffTangentSpace(lookupConformance); - assert(paramTan && "Parameter type does not have a tangent space?"); - auto paramTanType = paramTan->getCanonicalType(); - auto resultTanConvention = getTangentResultConventionForOriginalParameter( - paramTanType, param.getConvention()); - if (!paramTanType->hasArchetype() && !paramTanType->hasTypeParameter()) { - pullbackResults.push_back({paramTanType, resultTanConvention}); - } else { - auto gpIndex = substGenericParams.size(); - auto gpType = CanGenericTypeParamType::get(0, gpIndex, ctx); - substGenericParams.push_back(gpType); - substReplacements.push_back(paramTanType); - pullbackResults.push_back({gpType, resultTanConvention}); - } - } - SubstitutionMap substitutions; - if (!substGenericParams.empty()) { - auto genericSig = - GenericSignature::get(substGenericParams, substRequirements) - .getCanonicalSignature(); - substitutions = - SubstitutionMap::get(genericSig, llvm::makeArrayRef(substReplacements), - llvm::makeArrayRef(substConformances)); - } - return SILFunctionType::get( - GenericSignature(), SILFunctionType::ExtInfo(), SILCoroutineKind::None, - ParameterConvention::Direct_Guaranteed, pullbackParams, {}, - pullbackResults, None, substitutions, - /*invocationSubstitutions*/ SubstitutionMap(), ctx); -} - -/// Constrains the `original` function type according to differentiability -/// requirements: -/// - All differentiability parameters are constrained to conform to -/// `Differentiable`. -/// - The invocation generic signature is replaced by the -/// `constrainedInvocationGenSig` argument. -static SILFunctionType *getConstrainedAutoDiffOriginalFunctionType( - SILFunctionType *original, IndexSubset *parameterIndices, - LookupConformanceFn lookupConformance, - CanGenericSignature constrainedInvocationGenSig) { - auto originalInvocationGenSig = original->getInvocationGenericSignature(); - if (!originalInvocationGenSig) { - assert(!constrainedInvocationGenSig || - constrainedInvocationGenSig->areAllParamsConcrete() && - "derivative function cannot have invocation generic signature " - "when original function doesn't"); - return original; - } - - assert(!original->getPatternSubstitutions() && - "cannot constrain substituted function type"); - if (!constrainedInvocationGenSig) - constrainedInvocationGenSig = originalInvocationGenSig; - if (!constrainedInvocationGenSig) - return original; - constrainedInvocationGenSig = - autodiff::getConstrainedDerivativeGenericSignature( - original, parameterIndices, constrainedInvocationGenSig, - lookupConformance) - .getCanonicalSignature(); - - SmallVector newParameters; - newParameters.reserve(original->getNumParameters()); - for (auto ¶m : original->getParameters()) { - newParameters.push_back( - param.getWithInterfaceType(param.getInterfaceType()->getCanonicalType( - constrainedInvocationGenSig))); - } - - SmallVector newResults; - newResults.reserve(original->getNumResults()); - for (auto &result : original->getResults()) { - newResults.push_back( - result.getWithInterfaceType(result.getInterfaceType()->getCanonicalType( - constrainedInvocationGenSig))); - } - return SILFunctionType::get( - constrainedInvocationGenSig->areAllParamsConcrete() - ? GenericSignature() - : constrainedInvocationGenSig, - original->getExtInfo(), original->getCoroutineKind(), - original->getCalleeConvention(), newParameters, original->getYields(), - newResults, original->getOptionalErrorResult(), - /*patternSubstitutions*/ SubstitutionMap(), - /*invocationSubstitutions*/ SubstitutionMap(), original->getASTContext(), - original->getWitnessMethodConformanceOrInvalid()); -} - -CanSILFunctionType SILFunctionType::getAutoDiffDerivativeFunctionType( - IndexSubset *parameterIndices, unsigned resultIndex, - AutoDiffDerivativeFunctionKind kind, TypeConverter &TC, - LookupConformanceFn lookupConformance, - CanGenericSignature derivativeFnInvocationGenSig, - bool isReabstractionThunk) { - auto &ctx = getASTContext(); - - // Look up result in cache. - auto *resultIndices = IndexSubset::get( - ctx, getNumResults() + getNumIndirectMutatingParameters(), {resultIndex}); - SILAutoDiffDerivativeFunctionKey key{this, - parameterIndices, - resultIndices, - kind, - derivativeFnInvocationGenSig, - isReabstractionThunk}; - auto insertion = - ctx.SILAutoDiffDerivativeFunctions.try_emplace(key, CanSILFunctionType()); - auto &cachedResult = insertion.first->getSecond(); - if (!insertion.second) - return cachedResult; - - SILFunctionType *constrainedOriginalFnTy = - getConstrainedAutoDiffOriginalFunctionType(this, parameterIndices, - lookupConformance, - derivativeFnInvocationGenSig); - // Compute closure type. - CanSILFunctionType closureType; - switch (kind) { - case AutoDiffDerivativeFunctionKind::JVP: - closureType = - getAutoDiffDifferentialType(constrainedOriginalFnTy, parameterIndices, - resultIndex, lookupConformance); - break; - case AutoDiffDerivativeFunctionKind::VJP: - closureType = - getAutoDiffPullbackType(constrainedOriginalFnTy, parameterIndices, - resultIndex, lookupConformance, TC); - break; - } - // Compute the derivative function parameters. - SmallVector newParameters; - newParameters.reserve(constrainedOriginalFnTy->getNumParameters()); - for (auto ¶m : constrainedOriginalFnTy->getParameters()) { - newParameters.push_back(param); - } - // Reabstraction thunks have a function-typed parameter (the function to - // reabstract) as their last parameter. Reabstraction thunk JVPs/VJPs have a - // `@differentiable` function-typed last parameter instead. - if (isReabstractionThunk) { - assert(!parameterIndices->contains(getNumParameters() - 1) && - "Function-typed parameter should not be wrt"); - auto fnParam = newParameters.back(); - auto fnParamType = dyn_cast(fnParam.getInterfaceType()); - assert(fnParamType); - auto diffFnType = fnParamType->getWithDifferentiability( - DifferentiabilityKind::Normal, parameterIndices); - newParameters.back() = fnParam.getWithInterfaceType(diffFnType); - } - - // Compute the derivative function results. - SmallVector newResults; - newResults.reserve(getNumResults() + 1); - for (auto &result : constrainedOriginalFnTy->getResults()) { - newResults.push_back(result); - } - newResults.push_back({closureType, ResultConvention::Owned}); - - // Compute the derivative function ExtInfo. - // If original function is `@convention(c)`, the derivative function should - // have `@convention(thin)`. IRGen does not support `@convention(c)` functions - // with multiple results. - auto extInfo = constrainedOriginalFnTy->getExtInfo(); - if (getRepresentation() == SILFunctionTypeRepresentation::CFunctionPointer) - extInfo = extInfo.withRepresentation(SILFunctionTypeRepresentation::Thin); - - // Put everything together to get the derivative function type. Then, store in - // cache and return. - cachedResult = SILFunctionType::get( - constrainedOriginalFnTy->getSubstGenericSignature(), extInfo, - constrainedOriginalFnTy->getCoroutineKind(), - constrainedOriginalFnTy->getCalleeConvention(), newParameters, - constrainedOriginalFnTy->getYields(), newResults, - constrainedOriginalFnTy->getOptionalErrorResult(), - /*patternSubstitutions*/ SubstitutionMap(), - /*invocationSubstitutions*/ SubstitutionMap(), - constrainedOriginalFnTy->getASTContext(), - constrainedOriginalFnTy->getWitnessMethodConformanceOrInvalid()); - return cachedResult; -} - -CanSILFunctionType SILFunctionType::getAutoDiffTransposeFunctionType( - IndexSubset *parameterIndices, Lowering::TypeConverter &TC, - LookupConformanceFn lookupConformance, - CanGenericSignature transposeFnGenSig) { - // Get the "constrained" transpose function generic signature. - if (!transposeFnGenSig) - transposeFnGenSig = getSubstGenericSignature(); - transposeFnGenSig = autodiff::getConstrainedDerivativeGenericSignature( - this, parameterIndices, transposeFnGenSig, - lookupConformance, /*isLinear*/ true) - .getCanonicalSignature(); - - // Given a type, returns its formal SIL parameter info. - auto getParameterInfoForOriginalResult = - [&](const SILResultInfo &result) -> SILParameterInfo { - AbstractionPattern pattern(transposeFnGenSig, result.getInterfaceType()); - auto &tl = TC.getTypeLowering(pattern, result.getInterfaceType(), - TypeExpansionContext::minimal()); - ParameterConvention newConv; - switch (result.getConvention()) { - case ResultConvention::Owned: - case ResultConvention::Autoreleased: - newConv = tl.isTrivial() ? ParameterConvention::Direct_Unowned - : ParameterConvention::Direct_Guaranteed; - break; - case ResultConvention::Unowned: - case ResultConvention::UnownedInnerPointer: - newConv = ParameterConvention::Direct_Unowned; - break; - case ResultConvention::Indirect: - newConv = ParameterConvention::Indirect_In_Guaranteed; - break; - } - return {result.getInterfaceType(), newConv}; - }; - - // Given a type, returns its formal SIL result info. - auto getResultInfoForOriginalParameter = - [&](const SILParameterInfo ¶m) -> SILResultInfo { - AbstractionPattern pattern(transposeFnGenSig, param.getInterfaceType()); - auto &tl = TC.getTypeLowering(pattern, param.getInterfaceType(), - TypeExpansionContext::minimal()); - ResultConvention newConv; - switch (param.getConvention()) { - case ParameterConvention::Direct_Owned: - case ParameterConvention::Direct_Guaranteed: - case ParameterConvention::Direct_Unowned: - newConv = - tl.isTrivial() ? ResultConvention::Unowned : ResultConvention::Owned; - break; - case ParameterConvention::Indirect_In: - case ParameterConvention::Indirect_Inout: - case ParameterConvention::Indirect_In_Constant: - case ParameterConvention::Indirect_In_Guaranteed: - case ParameterConvention::Indirect_InoutAliasable: - newConv = ResultConvention::Indirect; - break; - } - return {param.getInterfaceType(), newConv}; - }; - - SmallVector newParameters; - SmallVector newResults; - for (auto pair : llvm::enumerate(getParameters())) { - auto index = pair.index(); - auto param = pair.value(); - if (parameterIndices->contains(index)) - newResults.push_back(getResultInfoForOriginalParameter(param)); - else - newParameters.push_back(param); - } - for (auto &res : getResults()) - newParameters.push_back(getParameterInfoForOriginalResult(res)); - return SILFunctionType::get( - getInvocationGenericSignature(), getExtInfo(), getCoroutineKind(), - getCalleeConvention(), newParameters, getYields(), newResults, - getOptionalErrorResult(), getPatternSubstitutions(), - /*invocationSubstitutions*/ {}, getASTContext()); -} - -static CanType getKnownType(Optional &cacheSlot, ASTContext &C, - StringRef moduleName, StringRef typeName) { - if (!cacheSlot) { - cacheSlot = ([&] { - ModuleDecl *mod = C.getLoadedModule(C.getIdentifier(moduleName)); - if (!mod) - return CanType(); - - // Do a general qualified lookup instead of a direct lookupValue because - // some of the types we want are reexported through overlays and - // lookupValue would only give us types actually declared in the overlays - // themselves. - SmallVector decls; - mod->lookupQualified(mod, DeclNameRef(C.getIdentifier(typeName)), - NL_QualifiedDefault | NL_KnownNonCascadingDependency, - decls); - if (decls.size() != 1) - return CanType(); - - const auto *typeDecl = dyn_cast(decls.front()); - if (!typeDecl) - return CanType(); - - return typeDecl->getDeclaredInterfaceType()->getCanonicalType(); - })(); - } - CanType t = *cacheSlot; - - // It is possible that we won't find a bridging type (e.g. String) when we're - // parsing the stdlib itself. - if (t) { - LLVM_DEBUG(llvm::dbgs() << "Bridging type " << moduleName << '.' << typeName - << " mapped to "; - if (t) - t->print(llvm::dbgs()); - else - llvm::dbgs() << ""; - llvm::dbgs() << '\n'); - } - return t; -} - -#define BRIDGING_KNOWN_TYPE(BridgedModule,BridgedType) \ - CanType TypeConverter::get##BridgedType##Type() { \ - return getKnownType(BridgedType##Ty, Context, \ - #BridgedModule, #BridgedType); \ - } -#include "swift/SIL/BridgedTypes.def" - -/// Adjust a function type to have a slightly different type. -CanAnyFunctionType -Lowering::adjustFunctionType(CanAnyFunctionType t, - AnyFunctionType::ExtInfo extInfo) { - if (t->getExtInfo() == extInfo) - return t; - return CanAnyFunctionType(t->withExtInfo(extInfo)); -} - -/// Adjust a function type to have a slightly different type. -CanSILFunctionType -Lowering::adjustFunctionType(CanSILFunctionType type, - SILFunctionType::ExtInfo extInfo, - ParameterConvention callee, - ProtocolConformanceRef witnessMethodConformance) { - if (type->getExtInfo() == extInfo && type->getCalleeConvention() == callee && - type->getWitnessMethodConformanceOrInvalid() == witnessMethodConformance) - return type; - - return SILFunctionType::get(type->getInvocationGenericSignature(), - extInfo, type->getCoroutineKind(), callee, - type->getParameters(), type->getYields(), - type->getResults(), - type->getOptionalErrorResult(), - type->getPatternSubstitutions(), - type->getInvocationSubstitutions(), - type->getASTContext(), - witnessMethodConformance); -} - -CanSILFunctionType -SILFunctionType::getWithRepresentation(Representation repr) { - return getWithExtInfo(getExtInfo().withRepresentation(repr)); -} - -CanSILFunctionType SILFunctionType::getWithExtInfo(ExtInfo newExt) { - auto oldExt = getExtInfo(); - if (newExt == oldExt) - return CanSILFunctionType(this); - - auto calleeConvention = - (newExt.hasContext() - ? (oldExt.hasContext() - ? getCalleeConvention() - : Lowering::DefaultThickCalleeConvention) - : ParameterConvention::Direct_Unowned); - - return get(getInvocationGenericSignature(), newExt, getCoroutineKind(), - calleeConvention, getParameters(), getYields(), getResults(), - getOptionalErrorResult(), getPatternSubstitutions(), - getInvocationSubstitutions(), getASTContext(), - getWitnessMethodConformanceOrInvalid()); -} - -namespace { - -enum class ConventionsKind : uint8_t { - Default = 0, - DefaultBlock = 1, - ObjCMethod = 2, - CFunctionType = 3, - CFunction = 4, - ObjCSelectorFamily = 5, - Deallocator = 6, - Capture = 7, - CXXMethod = 8, -}; - -class Conventions { - ConventionsKind kind; - -protected: - virtual ~Conventions() = default; - -public: - Conventions(ConventionsKind k) : kind(k) {} - - ConventionsKind getKind() const { return kind; } - - virtual ParameterConvention - getIndirectParameter(unsigned index, - const AbstractionPattern &type, - const TypeLowering &substTL) const = 0; - virtual ParameterConvention - getDirectParameter(unsigned index, - const AbstractionPattern &type, - const TypeLowering &substTL) const = 0; - virtual ParameterConvention getCallee() const = 0; - virtual ResultConvention getResult(const TypeLowering &resultTL) const = 0; - virtual ParameterConvention - getIndirectSelfParameter(const AbstractionPattern &type) const = 0; - virtual ParameterConvention - getDirectSelfParameter(const AbstractionPattern &type) const = 0; - - // Helpers that branch based on a value ownership. - ParameterConvention getIndirect(ValueOwnership ownership, bool forSelf, - unsigned index, - const AbstractionPattern &type, - const TypeLowering &substTL) const { - switch (ownership) { - case ValueOwnership::Default: - if (forSelf) - return getIndirectSelfParameter(type); - return getIndirectParameter(index, type, substTL); - case ValueOwnership::InOut: - return ParameterConvention::Indirect_Inout; - case ValueOwnership::Shared: - return ParameterConvention::Indirect_In_Guaranteed; - case ValueOwnership::Owned: - return ParameterConvention::Indirect_In; - } - llvm_unreachable("unhandled ownership"); - } - - ParameterConvention getDirect(ValueOwnership ownership, bool forSelf, - unsigned index, const AbstractionPattern &type, - const TypeLowering &substTL) const { - switch (ownership) { - case ValueOwnership::Default: - if (forSelf) - return getDirectSelfParameter(type); - return getDirectParameter(index, type, substTL); - case ValueOwnership::InOut: - return ParameterConvention::Indirect_Inout; - case ValueOwnership::Shared: - return ParameterConvention::Direct_Guaranteed; - case ValueOwnership::Owned: - return ParameterConvention::Direct_Owned; - } - llvm_unreachable("unhandled ownership"); - } -}; - -/// A structure for building the substituted generic signature of a lowered type. -/// -/// Where the abstraction pattern for a lowered type involves substitutable types, we extract those positions -/// out into generic arguments. This signature only needs to consider the general calling convention, -/// so it can reduce away protocol and base class constraints aside from -/// `AnyObject`. We want similar-shaped generic function types to remain -/// canonically equivalent, like `(T, U) -> ()`, `(T, T) -> ()`, -/// `(U, T) -> ()` or `(T, T.A) -> ()` when given substitutions that produce -/// the same function types, so we also introduce a new generic argument for -/// each position where we see a dependent type, and canonicalize the order in -/// which we see independent generic arguments. -class SubstFunctionTypeCollector { -public: - TypeConverter &TC; - TypeExpansionContext Expansion; - CanGenericSignature GenericSig; - bool Enabled; - - SmallVector substGenericParams; - SmallVector substRequirements; - SmallVector substReplacements; - SmallVector substConformances; - - SubstFunctionTypeCollector(TypeConverter &TC, TypeExpansionContext context, - CanGenericSignature genericSig, bool enabled) - : TC(TC), Expansion(context), GenericSig(genericSig), Enabled(enabled) { - } - SubstFunctionTypeCollector(const SubstFunctionTypeCollector &) = delete; - - // Add a substitution for a fresh type variable, with the given replacement - // type and layout constraint. - CanType addSubstitution(LayoutConstraint layout, - CanType substType, - ArchetypeType *upperBound, - ArrayRef substTypeConformances) { - auto paramIndex = substGenericParams.size(); - auto param = CanGenericTypeParamType::get(0, paramIndex, TC.Context); - - // Expand the bound type according to the expansion context. - if (Expansion.shouldLookThroughOpaqueTypeArchetypes() - && substType->hasOpaqueArchetype()) { - substType = substOpaqueTypesWithUnderlyingTypes(substType, Expansion); - } - - substGenericParams.push_back(param); - substReplacements.push_back(substType); - - LayoutConstraint upperBoundLayout; - Type upperBoundSuperclass; - ArrayRef upperBoundConformances; - - // If the parameter is in a position with upper bound constraints, such - // as a generic nominal type with type constraints on its arguments, then - // preserve the constraints from that upper bound. - if (upperBound) { - upperBoundSuperclass = upperBound->getSuperclass(); - upperBoundConformances = upperBound->getConformsTo(); - upperBoundLayout = upperBound->getLayoutConstraint(); - } - - if (upperBoundSuperclass) { - upperBoundSuperclass = upperBoundSuperclass->mapTypeOutOfContext(); - substRequirements.push_back( - Requirement(RequirementKind::Superclass, param, upperBoundSuperclass)); - } - - // Preserve the layout constraint, if any, on the archetype in the - // generic signature, generalizing away some constraints that - // shouldn't affect ABI substitutability. - if (layout) { - switch (layout->getKind()) { - // Keep these layout constraints as is. - case LayoutConstraintKind::RefCountedObject: - case LayoutConstraintKind::TrivialOfAtMostSize: - break; - - case LayoutConstraintKind::UnknownLayout: - case LayoutConstraintKind::Trivial: - // These constraints don't really constrain the ABI, so we can - // eliminate them. - layout = LayoutConstraint(); - break; - - // Replace these specific constraints with one of the more general - // constraints above. - case LayoutConstraintKind::NativeClass: - case LayoutConstraintKind::Class: - case LayoutConstraintKind::NativeRefCountedObject: - // These can all be generalized to RefCountedObject. - layout = LayoutConstraint::getLayoutConstraint( - LayoutConstraintKind::RefCountedObject); - break; - - case LayoutConstraintKind::TrivialOfExactSize: - // Generalize to TrivialOfAtMostSize. - layout = LayoutConstraint::getLayoutConstraint( - LayoutConstraintKind::TrivialOfAtMostSize, - layout->getTrivialSizeInBits(), - layout->getAlignmentInBits(), - TC.Context); - break; - } - - if (layout) { - // Pick the more specific of the upper bound layout and the layout - // we chose above. - if (upperBoundLayout) { - layout = layout.merge(upperBoundLayout); - } - - substRequirements.push_back( - Requirement(RequirementKind::Layout, param, layout)); - } - } else { - (void)0; - } - - for (unsigned i : indices(upperBoundConformances)) { - auto proto = upperBoundConformances[i]; - auto conformance = substTypeConformances[i]; - substRequirements.push_back(Requirement(RequirementKind::Conformance, - param, proto->getDeclaredType())); - substConformances.push_back(conformance); - } - - return param; - } - - /// Given the destructured original abstraction pattern and substituted type for a destructured - /// parameter or result, introduce substituted generic parameters and requirements as needed for - /// the lowered type, and return the substituted type in terms of the substituted generic signature. - CanType getSubstitutedInterfaceType(AbstractionPattern origType, - CanType substType) { - if (!Enabled) - return substType; - - // Replace every dependent type we see with a fresh type variable in - // the substituted signature, substituted by the corresponding concrete - // type. - - // The entire original context could be a generic parameter. - if (origType.isTypeParameter()) { - return addSubstitution(origType.getLayoutConstraint(), substType, - nullptr, {}); - } - - auto origContextType = origType.getType(); - - // If the substituted type is a subclass of the abstraction pattern - // type, build substitutions for any type parameters in it. This only - // comes up when lowering override types for vtable entries. - auto areDifferentClasses = [](Type a, Type b) -> bool { - if (auto dynA = a->getAs()) { - a = dynA->getSelfType(); - } - if (auto dynB = b->getAs()) { - b = dynB->getSelfType(); - } - if (auto aClass = a->getClassOrBoundGenericClass()) { - if (auto bClass = b->getClassOrBoundGenericClass()) { - return aClass != bClass; - } - } - - return false; - }; - - bool substituteBindingsInSubstType = false; - if (areDifferentClasses(substType, origContextType)) { - substituteBindingsInSubstType = true; - } - if (auto substMeta = dyn_cast(substType)) { - if (auto origMeta = dyn_cast(origContextType)) { - if (areDifferentClasses(substMeta->getInstanceType(), - origMeta->getInstanceType())) { - substituteBindingsInSubstType = true; - } - } - } - - CanGenericSignature origSig = origType.getGenericSignature(); - if (substituteBindingsInSubstType) { - origContextType = substType; - origSig = TC.getCurGenericSignature(); - assert((!substType->hasTypeParameter() || origSig) && - "lowering mismatched interface types in a context without " - "a generic signature"); - } - - if (!origContextType->hasTypeParameter() - && !origContextType->hasArchetype()) { - // If the abstraction pattern doesn't have substitutable positions, nor - // should the concrete type. - assert(!substType->hasTypeParameter() - && !substType->hasArchetype()); - return substType; - } - - // Extract structural substitutions. - if (origContextType->hasTypeParameter()) { - origContextType = origSig->getGenericEnvironment() - ->mapTypeIntoContext(origContextType) - ->getCanonicalType(origSig); - } - - auto result = origContextType - ->substituteBindingsTo(substType, - [&](ArchetypeType *archetype, - CanType binding, - ArchetypeType *upperBound, - ArrayRef bindingConformances) -> CanType { - // TODO: ArchetypeType::getLayoutConstraint sometimes misses out on - // implied layout constraints. For now AnyObject is the only one we - // care about. - return addSubstitution(archetype->requiresClass() - ? LayoutConstraint::getLayoutConstraint(LayoutConstraintKind::Class) - : LayoutConstraint(), - binding, - upperBound, - bindingConformances); - }); - - assert(result && "substType was not bindable to abstraction pattern type?"); - return result; - } -}; - -/// A visitor for breaking down formal result types into a SILResultInfo -/// and possibly some number of indirect-out SILParameterInfos, -/// matching the abstraction patterns of the original type. -class DestructureResults { - TypeConverter &TC; - const Conventions &Convs; - SmallVectorImpl &Results; - TypeExpansionContext context; - SubstFunctionTypeCollector &Subst; - -public: - DestructureResults(TypeExpansionContext context, TypeConverter &TC, - const Conventions &conventions, - SmallVectorImpl &results, - SubstFunctionTypeCollector &subst) - : TC(TC), Convs(conventions), Results(results), context(context), - Subst(subst) {} - - void destructure(AbstractionPattern origType, CanType substType) { - // Recur into tuples. - if (origType.isTuple()) { - auto substTupleType = cast(substType); - for (auto eltIndex : indices(substTupleType.getElementTypes())) { - AbstractionPattern origEltType = - origType.getTupleElementType(eltIndex); - CanType substEltType = substTupleType.getElementType(eltIndex); - destructure(origEltType, substEltType); - } - return; - } - - auto substInterfaceType = Subst.getSubstitutedInterfaceType(origType, - substType); - - auto &substResultTLForConvention = TC.getTypeLowering( - origType, substInterfaceType, TypeExpansionContext::minimal()); - auto &substResultTL = TC.getTypeLowering(origType, substInterfaceType, - context); - - - // Determine the result convention. - ResultConvention convention; - if (isFormallyReturnedIndirectly(origType, substType, - substResultTLForConvention)) { - convention = ResultConvention::Indirect; - } else { - convention = Convs.getResult(substResultTLForConvention); - - // Reduce conventions for trivial types to an unowned convention. - if (substResultTL.isTrivial()) { - switch (convention) { - case ResultConvention::Indirect: - case ResultConvention::Unowned: - case ResultConvention::UnownedInnerPointer: - // Leave these as-is. - break; - - case ResultConvention::Autoreleased: - case ResultConvention::Owned: - // These aren't distinguishable from unowned for trivial types. - convention = ResultConvention::Unowned; - break; - } - } - } - - SILResultInfo result(substResultTL.getLoweredType().getASTType(), - convention); - Results.push_back(result); - } - - /// Query whether the original type is returned indirectly for the purpose - /// of reabstraction given complete lowering information about its - /// substitution. - bool isFormallyReturnedIndirectly(AbstractionPattern origType, - CanType substType, - const TypeLowering &substTL) { - // If the substituted type is returned indirectly, so must the - // unsubstituted type. - if ((origType.isTypeParameter() - && !origType.isConcreteType() - && !origType.requiresClass()) - || substTL.isAddressOnly()) { - return true; - - // If the substitution didn't change the type, then a negative - // response to the above is determinative as well. - } else if (origType.getType() == substType && - !origType.getType()->hasTypeParameter()) { - return false; - - // Otherwise, query specifically for the original type. - } else { - return SILType::isFormallyReturnedIndirectly( - origType.getType(), TC, origType.getGenericSignature()); - } - } -}; - -static bool isClangTypeMoreIndirectThanSubstType(TypeConverter &TC, - const clang::Type *clangTy, - CanType substTy) { - // A const pointer argument might have been imported as - // UnsafePointer, COpaquePointer, or a CF foreign class. - // (An ObjC class type wouldn't be const-qualified.) - if (clangTy->isPointerType() - && clangTy->getPointeeType().isConstQualified()) { - // Peek through optionals. - if (auto substObjTy = substTy.getOptionalObjectType()) - substTy = substObjTy; - - // Void pointers aren't usefully indirectable. - if (clangTy->isVoidPointerType()) - return false; - - if (auto eltTy = substTy->getAnyPointerElementType()) - return isClangTypeMoreIndirectThanSubstType(TC, - clangTy->getPointeeType().getTypePtr(), CanType(eltTy)); - - if (substTy->getAnyNominal() == - TC.Context.getOpaquePointerDecl()) - // TODO: We could conceivably have an indirect opaque ** imported - // as COpaquePointer. That shouldn't ever happen today, though, - // since we only ever indirect the 'self' parameter of functions - // imported as methods. - return false; - - if (clangTy->getPointeeType()->getAs()) { - // CF type as foreign class - if (substTy->getClassOrBoundGenericClass() && - substTy->getClassOrBoundGenericClass()->getForeignClassKind() == - ClassDecl::ForeignKind::CFType) { - return false; - } - } - - // swift_newtypes are always passed directly - if (auto typedefTy = clangTy->getAs()) { - if (typedefTy->getDecl()->getAttr()) - return false; - } - - return true; - } - return false; -} - -static bool isFormallyPassedIndirectly(TypeConverter &TC, - AbstractionPattern origType, - CanType substType, - const TypeLowering &substTL) { - // If the C type of the argument is a const pointer, but the Swift type - // isn't, treat it as indirect. - if (origType.isClangType() - && isClangTypeMoreIndirectThanSubstType(TC, origType.getClangType(), - substType)) { - return true; - } - - // If the substituted type is passed indirectly, so must the - // unsubstituted type. - if ((origType.isTypeParameter() && !origType.isConcreteType() - && !origType.requiresClass()) - || substTL.isAddressOnly()) { - return true; - - // If the substitution didn't change the type, then a negative - // response to the above is determinative as well. - } else if (origType.getType() == substType && - !origType.getType()->hasTypeParameter()) { - return false; - - // Otherwise, query specifically for the original type. - } else { - return SILType::isFormallyPassedIndirectly( - origType.getType(), TC, origType.getGenericSignature()); - } -} - -/// A visitor for turning formal input types into SILParameterInfos, matching -/// the abstraction patterns of the original type. -/// -/// If the original abstraction pattern is fully opaque, we must pass the -/// function's parameters and results indirectly, as if the original type were -/// the most general function signature (expressed entirely in generic -/// parameters) which can be substituted to equal the given signature. -/// -/// See the comment in AbstractionPattern.h for details. -class DestructureInputs { - TypeExpansionContext expansion; - TypeConverter &TC; - const Conventions &Convs; - const ForeignInfo &Foreign; - Optional> HandleForeignSelf; - SmallVectorImpl &Inputs; - SubstFunctionTypeCollector &Subst; - unsigned NextOrigParamIndex = 0; -public: - DestructureInputs(TypeExpansionContext expansion, TypeConverter &TC, - const Conventions &conventions, const ForeignInfo &foreign, - SmallVectorImpl &inputs, - SubstFunctionTypeCollector &subst) - : expansion(expansion), TC(TC), Convs(conventions), Foreign(foreign), - Inputs(inputs), Subst(subst) {} - - void destructure(AbstractionPattern origType, - CanAnyFunctionType::CanParamArrayRef params, - AnyFunctionType::ExtInfo extInfo) { - visitTopLevelParams(origType, params, extInfo); - } - -private: - /// Query whether the original type is address-only given complete - /// lowering information about its substitution. - bool isFormallyPassedIndirectly(AbstractionPattern origType, - CanType substType, - const TypeLowering &substTL) { - return ::isFormallyPassedIndirectly(TC, origType, substType, substTL); - } - - /// This is a special entry point that allows destructure inputs to handle - /// self correctly. - void visitTopLevelParams(AbstractionPattern origType, - CanAnyFunctionType::CanParamArrayRef params, - AnyFunctionType::ExtInfo extInfo) { - unsigned numEltTypes = params.size(); - - bool hasSelf = (extInfo.hasSelfParam() || Foreign.Self.isImportAsMember()); - unsigned numNonSelfParams = (hasSelf ? numEltTypes - 1 : numEltTypes); - - auto silRepresentation = extInfo.getSILRepresentation(); - - // We have to declare this out here so that the lambda scope lasts for - // the duration of the loop below. - auto handleForeignSelf = [&] { - // This is a "self", but it's not a Swift self, we handle it differently. - auto selfParam = params[numNonSelfParams]; - visit(selfParam.getValueOwnership(), - /*forSelf=*/false, - origType.getFunctionParamType(numNonSelfParams), - selfParam.getParameterType(), silRepresentation); - }; - - // If we have a foreign-self, install handleSelf as the handler. - if (Foreign.Self.isInstance()) { - assert(hasSelf && numEltTypes > 0); - // This is safe because function_ref just stores a pointer to the - // existing lambda object. - HandleForeignSelf = handleForeignSelf; - } - - // Add any leading foreign parameters. - maybeAddForeignParameters(); - - // Process all the non-self parameters. - for (unsigned i = 0; i != numNonSelfParams; ++i) { - auto ty = params[i].getParameterType(); - auto eltPattern = origType.getFunctionParamType(i); - auto flags = params[i].getParameterFlags(); - - visit(flags.getValueOwnership(), /*forSelf=*/false, eltPattern, ty, - silRepresentation, flags.isNoDerivative()); - } - - // Process the self parameter. Note that we implicitly drop self - // if this is a static foreign-self import. - if (hasSelf && !Foreign.Self.isImportAsMember()) { - auto selfParam = params[numNonSelfParams]; - auto ty = selfParam.getParameterType(); - auto eltPattern = origType.getFunctionParamType(numNonSelfParams); - auto flags = selfParam.getParameterFlags(); - - visit(flags.getValueOwnership(), /*forSelf=*/true, - eltPattern, ty, silRepresentation); - } - - // Clear the foreign-self handler for safety. - HandleForeignSelf.reset(); - } - - void visit(ValueOwnership ownership, bool forSelf, - AbstractionPattern origType, CanType substType, - SILFunctionTypeRepresentation rep, - bool isNonDifferentiable = false) { - assert(!isa(substType)); - - // Tuples get handled specially, in some cases: - CanTupleType substTupleTy = dyn_cast(substType); - if (substTupleTy && !origType.isTypeParameter()) { - assert(origType.getNumTupleElements() == substTupleTy->getNumElements()); - switch (ownership) { - case ValueOwnership::Default: - case ValueOwnership::Owned: - case ValueOwnership::Shared: - // Expand the tuple. - for (auto i : indices(substTupleTy.getElementTypes())) { - auto &elt = substTupleTy->getElement(i); - auto ownership = elt.getParameterFlags().getValueOwnership(); - assert(ownership == ValueOwnership::Default); - assert(!elt.isVararg()); - visit(ownership, forSelf, - origType.getTupleElementType(i), - CanType(elt.getRawType()), rep); - } - return; - case ValueOwnership::InOut: - // handled below - break; - } - } - - unsigned origParamIndex = NextOrigParamIndex++; - - auto substInterfaceType = - Subst.getSubstitutedInterfaceType(origType, substType); - - auto &substTLConv = TC.getTypeLowering(origType, substInterfaceType, - TypeExpansionContext::minimal()); - auto &substTL = TC.getTypeLowering(origType, substInterfaceType, expansion); - - ParameterConvention convention; - if (ownership == ValueOwnership::InOut) { - convention = ParameterConvention::Indirect_Inout; - } else if (isFormallyPassedIndirectly(origType, substType, substTLConv)) { - convention = Convs.getIndirect(ownership, forSelf, origParamIndex, - origType, substTLConv); - assert(isIndirectFormalParameter(convention)); - } else if (substTL.isTrivial()) { - convention = ParameterConvention::Direct_Unowned; - } else { - convention = Convs.getDirect(ownership, forSelf, origParamIndex, origType, - substTLConv); - assert(!isIndirectFormalParameter(convention)); - } - - SILParameterInfo param(substTL.getLoweredType().getASTType(), convention); - if (isNonDifferentiable) - param = param.getWithDifferentiability( - SILParameterDifferentiability::NotDifferentiable); - Inputs.push_back(param); - - maybeAddForeignParameters(); - } - - /// Given that we've just reached an argument index for the - /// first time, add any foreign parameters. - void maybeAddForeignParameters() { - while (maybeAddForeignErrorParameter() || - maybeAddForeignSelfParameter()) { - // Continue to see, just in case there are more parameters to add. - } - } - - bool maybeAddForeignErrorParameter() { - if (!Foreign.Error || - NextOrigParamIndex != Foreign.Error->getErrorParameterIndex()) - return false; - - auto foreignErrorTy = TC.getLoweredRValueType( - expansion, Foreign.Error->getErrorParameterType()); - - // Assume the error parameter doesn't have interesting lowering. - Inputs.push_back(SILParameterInfo(foreignErrorTy, - ParameterConvention::Direct_Unowned)); - NextOrigParamIndex++; - return true; - } - - bool maybeAddForeignSelfParameter() { - if (!Foreign.Self.isInstance() || - NextOrigParamIndex != Foreign.Self.getSelfIndex()) - return false; - - (*HandleForeignSelf)(); - return true; - } -}; - -} // end anonymous namespace - -static bool isPseudogeneric(SILDeclRef c) { - // FIXME: should this be integrated in with the Sema check that prevents - // illegal use of type arguments in pseudo-generic method bodies? - - // The implicitly-generated native initializer thunks for imported - // initializers are never pseudo-generic, because they may need - // to use their type arguments to bridge their value arguments. - if (!c.isForeign && - (c.kind == SILDeclRef::Kind::Allocator || - c.kind == SILDeclRef::Kind::Initializer) && - c.getDecl()->hasClangNode()) - return false; - - // Otherwise, we have to look at the entity's context. - DeclContext *dc; - if (c.hasDecl()) { - dc = c.getDecl()->getDeclContext(); - } else if (auto closure = c.getAbstractClosureExpr()) { - dc = closure->getParent(); - } else { - return false; - } - dc = dc->getInnermostTypeContext(); - if (!dc) return false; - - auto classDecl = dc->getSelfClassDecl(); - return (classDecl && classDecl->usesObjCGenericsModel()); -} - -/// Update the result type given the foreign error convention that we will be -/// using. -static std::pair updateResultTypeForForeignError( - ForeignErrorConvention convention, CanGenericSignature genericSig, - AbstractionPattern origResultType, CanType substFormalResultType) { - switch (convention.getKind()) { - // These conventions replace the result type. - case ForeignErrorConvention::ZeroResult: - case ForeignErrorConvention::NonZeroResult: - assert(substFormalResultType->isVoid()); - substFormalResultType = convention.getResultType(); - origResultType = AbstractionPattern(genericSig, substFormalResultType); - return {origResultType, substFormalResultType}; - - // These conventions wrap the result type in a level of optionality. - case ForeignErrorConvention::NilResult: - assert(!substFormalResultType->getOptionalObjectType()); - substFormalResultType = - OptionalType::get(substFormalResultType)->getCanonicalType(); - origResultType = - AbstractionPattern::getOptional(origResultType); - return {origResultType, substFormalResultType}; - - // These conventions don't require changes to the formal error type. - case ForeignErrorConvention::ZeroPreservedResult: - case ForeignErrorConvention::NonNilError: - return {origResultType, substFormalResultType}; - } - llvm_unreachable("unhandled kind"); -} - -/// Lower any/all capture context parameters. -/// -/// *NOTE* Currently default arg generators can not capture anything. -/// If we ever add that ability, it will be a different capture list -/// from the function to which the argument is attached. -static void -lowerCaptureContextParameters(TypeConverter &TC, SILDeclRef function, - CanGenericSignature genericSig, - TypeExpansionContext expansion, - SmallVectorImpl &inputs) { - - // NB: The generic signature may be elided from the lowered function type - // if the function is in a fully-specialized context, but we still need to - // canonicalize references to the generic parameters that may appear in - // non-canonical types in that context. We need the original generic - // signature from the AST for that. - auto origGenericSig = function.getAnyFunctionRef()->getGenericSignature(); - auto loweredCaptures = TC.getLoweredLocalCaptures(function); - - for (auto capture : loweredCaptures.getCaptures()) { - if (capture.isDynamicSelfMetadata()) { - ParameterConvention convention = ParameterConvention::Direct_Unowned; - auto dynamicSelfInterfaceType = - loweredCaptures.getDynamicSelfType()->mapTypeOutOfContext(); - - auto selfMetatype = MetatypeType::get(dynamicSelfInterfaceType, - MetatypeRepresentation::Thick); - - auto canSelfMetatype = selfMetatype->getCanonicalType(origGenericSig); - SILParameterInfo param(canSelfMetatype, convention); - inputs.push_back(param); - - continue; - } - - if (capture.isOpaqueValue()) { - OpaqueValueExpr *opaqueValue = capture.getOpaqueValue(); - auto canType = opaqueValue->getType()->mapTypeOutOfContext() - ->getCanonicalType(origGenericSig); - auto &loweredTL = - TC.getTypeLowering(AbstractionPattern(genericSig, canType), - canType, expansion); - auto loweredTy = loweredTL.getLoweredType(); - - ParameterConvention convention; - if (loweredTL.isAddressOnly()) { - convention = ParameterConvention::Indirect_In; - } else { - convention = ParameterConvention::Direct_Owned; - } - SILParameterInfo param(loweredTy.getASTType(), convention); - inputs.push_back(param); - - continue; - } - - auto *VD = capture.getDecl(); - auto type = VD->getInterfaceType(); - auto canType = type->getCanonicalType(origGenericSig); - - auto &loweredTL = - TC.getTypeLowering(AbstractionPattern(genericSig, canType), canType, - expansion); - auto loweredTy = loweredTL.getLoweredType(); - switch (TC.getDeclCaptureKind(capture, expansion)) { - case CaptureKind::Constant: { - // Constants are captured by value. - ParameterConvention convention; - assert (!loweredTL.isAddressOnly()); - if (loweredTL.isTrivial()) { - convention = ParameterConvention::Direct_Unowned; - } else { - convention = ParameterConvention::Direct_Guaranteed; - } - SILParameterInfo param(loweredTy.getASTType(), convention); - inputs.push_back(param); - break; - } - case CaptureKind::Box: { - // The type in the box is lowered in the minimal context. - auto minimalLoweredTy = - TC.getTypeLowering(AbstractionPattern(genericSig, canType), canType, - TypeExpansionContext::minimal()) - .getLoweredType(); - // Lvalues are captured as a box that owns the captured value. - auto boxTy = TC.getInterfaceBoxTypeForCapture( - VD, minimalLoweredTy.getASTType(), - /*mutable*/ true); - auto convention = ParameterConvention::Direct_Guaranteed; - auto param = SILParameterInfo(boxTy, convention); - inputs.push_back(param); - break; - } - case CaptureKind::StorageAddress: { - // Non-escaping lvalues are captured as the address of the value. - SILType ty = loweredTy.getAddressType(); - auto param = - SILParameterInfo(ty.getASTType(), - ParameterConvention::Indirect_InoutAliasable); - inputs.push_back(param); - break; - } - case CaptureKind::Immutable: { - // 'let' constants that are address-only are captured as the address of - // the value and will be consumed by the closure. - SILType ty = loweredTy.getAddressType(); - auto param = - SILParameterInfo(ty.getASTType(), - ParameterConvention::Indirect_In_Guaranteed); - inputs.push_back(param); - break; - } - } - } -} - -static AccessorDecl *getAsCoroutineAccessor(Optional constant) { - if (!constant || !constant->hasDecl()) - return nullptr;; - - auto accessor = dyn_cast(constant->getDecl()); - if (!accessor || !accessor->isCoroutine()) - return nullptr; - - return accessor; -} - -static void destructureYieldsForReadAccessor(TypeConverter &TC, - TypeExpansionContext expansion, - AbstractionPattern origType, - CanType valueType, - SmallVectorImpl &yields, - SubstFunctionTypeCollector &subst) { - // Recursively destructure tuples. - if (origType.isTuple()) { - auto valueTupleType = cast(valueType); - for (auto i : indices(valueTupleType.getElementTypes())) { - auto origEltType = origType.getTupleElementType(i); - auto valueEltType = valueTupleType.getElementType(i); - destructureYieldsForReadAccessor(TC, expansion, origEltType, valueEltType, - yields, subst); - } - return; - } - - auto valueInterfaceType = - subst.getSubstitutedInterfaceType(origType, valueType); - - auto &tlConv = - TC.getTypeLowering(origType, valueInterfaceType, - TypeExpansionContext::minimal()); - auto &tl = - TC.getTypeLowering(origType, valueInterfaceType, expansion); - auto convention = [&] { - if (isFormallyPassedIndirectly(TC, origType, valueInterfaceType, tlConv)) - return ParameterConvention::Indirect_In_Guaranteed; - if (tlConv.isTrivial()) - return ParameterConvention::Direct_Unowned; - return ParameterConvention::Direct_Guaranteed; - }(); - - yields.push_back(SILYieldInfo(tl.getLoweredType().getASTType(), - convention)); -} - -static void destructureYieldsForCoroutine(TypeConverter &TC, - TypeExpansionContext expansion, - Optional origConstant, - Optional constant, - Optional reqtSubs, - SmallVectorImpl &yields, - SILCoroutineKind &coroutineKind, - SubstFunctionTypeCollector &subst) { - assert(coroutineKind == SILCoroutineKind::None); - assert(yields.empty()); - - auto accessor = getAsCoroutineAccessor(constant); - if (!accessor) - return; - - auto origAccessor = cast(origConstant->getDecl()); - - // Coroutine accessors are implicitly yield-once coroutines, despite - // their function type. - coroutineKind = SILCoroutineKind::YieldOnce; - - // Coroutine accessors are always native, so fetch the native - // abstraction pattern. - auto origStorage = origAccessor->getStorage(); - auto origType = TC.getAbstractionPattern(origStorage, /*nonobjc*/ true) - .getReferenceStorageReferentType(); - - auto storage = accessor->getStorage(); - auto valueType = storage->getValueInterfaceType(); - if (reqtSubs) { - valueType = valueType.subst(*reqtSubs); - } - - auto canValueType = valueType->getCanonicalType( - accessor->getGenericSignature()); - - // 'modify' yields an inout of the target type. - if (accessor->getAccessorKind() == AccessorKind::Modify) { - auto valueInterfaceType = subst.getSubstitutedInterfaceType(origType, - canValueType); - auto loweredValueTy = - TC.getLoweredType(origType, valueInterfaceType, expansion); - yields.push_back(SILYieldInfo(loweredValueTy.getASTType(), - ParameterConvention::Indirect_Inout)); - return; - } - - // 'read' yields a borrowed value of the target type, destructuring - // tuples as necessary. - assert(accessor->getAccessorKind() == AccessorKind::Read); - destructureYieldsForReadAccessor(TC, expansion, origType, canValueType, - yields, subst); -} - -/// Create the appropriate SIL function type for the given formal type -/// and conventions. -/// -/// The lowering of function types is generally sensitive to the -/// declared abstraction pattern. We want to be able to take -/// advantage of declared type information in order to, say, pass -/// arguments separately and directly; but we also want to be able to -/// call functions from generic code without completely embarrassing -/// performance. Therefore, different abstraction patterns induce -/// different argument-passing conventions, and we must introduce -/// implicit reabstracting conversions where necessary to map one -/// convention to another. -/// -/// However, we actually can't reabstract arbitrary thin function -/// values while still leaving them thin, at least without costly -/// page-mapping tricks. Therefore, the representation must remain -/// consistent across all abstraction patterns. -/// -/// We could reabstract block functions in theory, but (1) we don't -/// really need to and (2) doing so would be problematic because -/// stuffing something in an Optional currently forces it to be -/// reabstracted to the most general type, which means that we'd -/// expect the wrong abstraction conventions on bridged block function -/// types. -/// -/// Therefore, we only honor abstraction patterns on thick or -/// polymorphic functions. -/// -/// FIXME: we shouldn't just drop the original abstraction pattern -/// when we can't reabstract. Instead, we should introduce -/// dynamic-indirect argument-passing conventions and map opaque -/// archetypes to that, then respect those conventions in IRGen by -/// using runtime call construction. -/// -/// \param conventions - conventions as expressed for the original type -static CanSILFunctionType getSILFunctionType( - TypeConverter &TC, TypeExpansionContext expansionContext, AbstractionPattern origType, - CanAnyFunctionType substFnInterfaceType, AnyFunctionType::ExtInfo extInfo, - const Conventions &conventions, const ForeignInfo &foreignInfo, - Optional origConstant, Optional constant, - Optional reqtSubs, - ProtocolConformanceRef witnessMethodConformance) { - // Find the generic parameters. - CanGenericSignature genericSig = - substFnInterfaceType.getOptGenericSignature(); - - Optional contextRAII; - if (genericSig) contextRAII.emplace(TC, genericSig); - - // Per above, only fully honor opaqueness in the abstraction pattern - // for thick or polymorphic functions. We don't need to worry about - // non-opaque patterns because the type-checker forbids non-thick - // function types from having generic parameters or results. - if (origType.isTypeParameter() && - substFnInterfaceType->getExtInfo().getSILRepresentation() - != SILFunctionType::Representation::Thick && - isa(substFnInterfaceType)) { - origType = AbstractionPattern(genericSig, - substFnInterfaceType); - } - - // Map 'throws' to the appropriate error convention. - Optional errorResult; - assert((!foreignInfo.Error || substFnInterfaceType->getExtInfo().throws()) && - "foreignError was set but function type does not throw?"); - if (substFnInterfaceType->getExtInfo().throws() && !foreignInfo.Error) { - assert(!origType.isForeign() && - "using native Swift error convention for foreign type!"); - SILType exnType = SILType::getExceptionType(TC.Context); - assert(exnType.isObject()); - errorResult = SILResultInfo(exnType.getASTType(), - ResultConvention::Owned); - } - - // Lower the result type. - AbstractionPattern origResultType = origType.getFunctionResultType(); - CanType substFormalResultType = substFnInterfaceType.getResult(); - - // If we have a foreign error convention, restore the original result type. - if (auto convention = foreignInfo.Error) { - std::tie(origResultType, substFormalResultType) = - updateResultTypeForForeignError(*convention, genericSig, origResultType, - substFormalResultType); - } - - bool shouldBuildSubstFunctionType = [&]{ - if (!TC.Context.LangOpts.EnableSubstSILFunctionTypesForFunctionValues) - return false; - - // We always use substituted function types for coroutines that are - // being lowered in the context of another coroutine, which is to say, - // for class override thunks. This is required to make the yields - // match in abstraction to the base method's yields, which is necessary - // to make the extracted continuation-function signatures match. - if (constant != origConstant && getAsCoroutineAccessor(constant)) - return true; - - // We don't currently use substituted function types for generic function - // type lowering, though we should for generic methods on classes and - // protocols. - if (genericSig) - return false; - - // We only currently use substituted function types for function values, - // which will have standard thin or thick representation. (Per the previous - // comment, it would be useful to do so for generic methods on classes and - // protocols too.) - auto rep = extInfo.getSILRepresentation(); - return (rep == SILFunctionTypeRepresentation::Thick || - rep == SILFunctionTypeRepresentation::Thin); - }(); - - SubstFunctionTypeCollector subst(TC, expansionContext, genericSig, - shouldBuildSubstFunctionType); - - // Destructure the input tuple type. - SmallVector inputs; - { - DestructureInputs destructurer(expansionContext, TC, conventions, - foreignInfo, inputs, subst); - destructurer.destructure(origType, - substFnInterfaceType.getParams(), - extInfo); - } - - // Destructure the coroutine yields. - SILCoroutineKind coroutineKind = SILCoroutineKind::None; - SmallVector yields; - destructureYieldsForCoroutine(TC, expansionContext, origConstant, constant, - reqtSubs, yields, coroutineKind, subst); - - // Destructure the result tuple type. - SmallVector results; - { - DestructureResults destructurer(expansionContext, TC, conventions, - results, subst); - destructurer.destructure(origResultType, substFormalResultType); - } - - // Lower the capture context parameters, if any. - if (constant && constant->getAnyFunctionRef()) { - auto expansion = TypeExpansionContext::maximal( - expansionContext.getContext(), expansionContext.isWholeModuleContext()); - if (constant->isSerialized()) - expansion = TypeExpansionContext::minimal(); - lowerCaptureContextParameters(TC, *constant, genericSig, expansion, inputs); - } - - auto calleeConvention = ParameterConvention::Direct_Unowned; - if (extInfo.hasContext()) - calleeConvention = conventions.getCallee(); - - bool pseudogeneric = genericSig && constant - ? isPseudogeneric(*constant) - : false; - - // NOTE: SILFunctionType::ExtInfo doesn't track everything that - // AnyFunctionType::ExtInfo tracks. For example: 'throws' or 'auto-closure' - auto silExtInfo = SILFunctionType::ExtInfo() - .withRepresentation(extInfo.getSILRepresentation()) - .withIsPseudogeneric(pseudogeneric) - .withNoEscape(extInfo.isNoEscape()) - .withDifferentiabilityKind(extInfo.getDifferentiabilityKind()); - - // Build the substituted generic signature we extracted. - SubstitutionMap substitutions; - if (subst.Enabled) { - if (!subst.substGenericParams.empty()) { - auto subSig = GenericSignature::get(subst.substGenericParams, - subst.substRequirements) - .getCanonicalSignature(); - substitutions = SubstitutionMap::get(subSig, - llvm::makeArrayRef(subst.substReplacements), - llvm::makeArrayRef(subst.substConformances)); - } - } - - return SILFunctionType::get(genericSig, silExtInfo, coroutineKind, - calleeConvention, inputs, yields, - results, errorResult, - substitutions, SubstitutionMap(), - TC.Context, witnessMethodConformance); -} - -//===----------------------------------------------------------------------===// -// Deallocator SILFunctionTypes -//===----------------------------------------------------------------------===// - -namespace { - -// The convention for general deallocators. -struct DeallocatorConventions : Conventions { - DeallocatorConventions() : Conventions(ConventionsKind::Deallocator) {} - - ParameterConvention getIndirectParameter(unsigned index, - const AbstractionPattern &type, - const TypeLowering &substTL) const override { - llvm_unreachable("Deallocators do not have indirect parameters"); - } - - ParameterConvention getDirectParameter(unsigned index, - const AbstractionPattern &type, - const TypeLowering &substTL) const override { - llvm_unreachable("Deallocators do not have non-self direct parameters"); - } - - ParameterConvention getCallee() const override { - llvm_unreachable("Deallocators do not have callees"); - } - - ResultConvention getResult(const TypeLowering &tl) const override { - // TODO: Put an unreachable here? - return ResultConvention::Owned; - } - - ParameterConvention - getDirectSelfParameter(const AbstractionPattern &type) const override { - // TODO: Investigate whether or not it is - return ParameterConvention::Direct_Owned; - } - - ParameterConvention - getIndirectSelfParameter(const AbstractionPattern &type) const override { - llvm_unreachable("Deallocators do not have indirect self parameters"); - } - - static bool classof(const Conventions *C) { - return C->getKind() == ConventionsKind::Deallocator; - } -}; - -} // end anonymous namespace - -//===----------------------------------------------------------------------===// -// Default Convention FunctionTypes -//===----------------------------------------------------------------------===// - -namespace { - -enum class NormalParameterConvention { Owned, Guaranteed }; - -/// The default Swift conventions. -class DefaultConventions : public Conventions { - NormalParameterConvention normalParameterConvention; - -public: - DefaultConventions(NormalParameterConvention normalParameterConvention) - : Conventions(ConventionsKind::Default), - normalParameterConvention(normalParameterConvention) {} - - bool isNormalParameterConventionGuaranteed() const { - return normalParameterConvention == NormalParameterConvention::Guaranteed; - } - - ParameterConvention getIndirectParameter(unsigned index, - const AbstractionPattern &type, - const TypeLowering &substTL) const override { - if (isNormalParameterConventionGuaranteed()) { - return ParameterConvention::Indirect_In_Guaranteed; - } - return ParameterConvention::Indirect_In; - } - - ParameterConvention getDirectParameter(unsigned index, - const AbstractionPattern &type, - const TypeLowering &substTL) const override { - if (isNormalParameterConventionGuaranteed()) - return ParameterConvention::Direct_Guaranteed; - return ParameterConvention::Direct_Owned; - } - - ParameterConvention getCallee() const override { - return DefaultThickCalleeConvention; - } - - ResultConvention getResult(const TypeLowering &tl) const override { - return ResultConvention::Owned; - } - - ParameterConvention - getDirectSelfParameter(const AbstractionPattern &type) const override { - return ParameterConvention::Direct_Guaranteed; - } - - ParameterConvention - getIndirectSelfParameter(const AbstractionPattern &type) const override { - return ParameterConvention::Indirect_In_Guaranteed; - } - - static bool classof(const Conventions *C) { - return C->getKind() == ConventionsKind::Default; - } -}; - -/// The default conventions for Swift initializing constructors. -/// -/// Initializing constructors take all parameters (including) self at +1. This -/// is because: -/// -/// 1. We are likely to be initializing fields of self implying that the -/// parameters are likely to be forwarded into memory without further -/// copies. -/// 2. Initializers must take 'self' at +1, since they will return it back -/// at +1, and may chain onto Objective-C initializers that replace the -/// instance. -struct DefaultInitializerConventions : DefaultConventions { - DefaultInitializerConventions() - : DefaultConventions(NormalParameterConvention::Owned) {} - - /// Initializers must take 'self' at +1, since they will return it back at +1, - /// and may chain onto Objective-C initializers that replace the instance. - ParameterConvention - getDirectSelfParameter(const AbstractionPattern &type) const override { - return ParameterConvention::Direct_Owned; - } - - ParameterConvention - getIndirectSelfParameter(const AbstractionPattern &type) const override { - return ParameterConvention::Indirect_In; - } -}; - -/// The convention used for allocating inits. Allocating inits take their normal -/// parameters at +1 and do not have a self parameter. -struct DefaultAllocatorConventions : DefaultConventions { - DefaultAllocatorConventions() - : DefaultConventions(NormalParameterConvention::Owned) {} - - ParameterConvention - getDirectSelfParameter(const AbstractionPattern &type) const override { - llvm_unreachable("Allocating inits do not have self parameters"); - } - - ParameterConvention - getIndirectSelfParameter(const AbstractionPattern &type) const override { - llvm_unreachable("Allocating inits do not have self parameters"); - } -}; - -/// The default conventions for Swift setter acccessors. -/// -/// These take self at +0, but all other parameters at +1. This is because we -/// assume that setter parameters are likely to be values to be forwarded into -/// memory. Thus by passing in the +1 value, we avoid a potential copy in that -/// case. -struct DefaultSetterConventions : DefaultConventions { - DefaultSetterConventions() - : DefaultConventions(NormalParameterConvention::Owned) {} -}; - -/// The default conventions for ObjC blocks. -struct DefaultBlockConventions : Conventions { - DefaultBlockConventions() : Conventions(ConventionsKind::DefaultBlock) {} - - ParameterConvention getIndirectParameter(unsigned index, - const AbstractionPattern &type, - const TypeLowering &substTL) const override { - llvm_unreachable("indirect block parameters unsupported"); - } - - ParameterConvention getDirectParameter(unsigned index, - const AbstractionPattern &type, - const TypeLowering &substTL) const override { - return ParameterConvention::Direct_Unowned; - } - - ParameterConvention getCallee() const override { - return ParameterConvention::Direct_Unowned; - } - - ResultConvention getResult(const TypeLowering &substTL) const override { - return ResultConvention::Autoreleased; - } - - ParameterConvention - getDirectSelfParameter(const AbstractionPattern &type) const override { - llvm_unreachable("objc blocks do not have a self parameter"); - } - - ParameterConvention - getIndirectSelfParameter(const AbstractionPattern &type) const override { - llvm_unreachable("objc blocks do not have a self parameter"); - } - - static bool classof(const Conventions *C) { - return C->getKind() == ConventionsKind::DefaultBlock; - } -}; - -} // end anonymous namespace - -static CanSILFunctionType -getSILFunctionTypeForAbstractCFunction(TypeConverter &TC, - AbstractionPattern origType, - CanAnyFunctionType substType, - AnyFunctionType::ExtInfo extInfo, - Optional constant); - -static CanSILFunctionType getNativeSILFunctionType( - TypeConverter &TC, TypeExpansionContext context, AbstractionPattern origType, - CanAnyFunctionType substInterfaceType, AnyFunctionType::ExtInfo extInfo, - Optional origConstant, Optional constant, - Optional reqtSubs, - ProtocolConformanceRef witnessMethodConformance) { - assert(bool(origConstant) == bool(constant)); - switch (extInfo.getSILRepresentation()) { - case SILFunctionType::Representation::Block: - case SILFunctionType::Representation::CFunctionPointer: - return getSILFunctionTypeForAbstractCFunction(TC, origType, - substInterfaceType, - extInfo, constant); - - case SILFunctionType::Representation::Thin: - case SILFunctionType::Representation::ObjCMethod: - case SILFunctionType::Representation::Thick: - case SILFunctionType::Representation::Method: - case SILFunctionType::Representation::Closure: - case SILFunctionType::Representation::WitnessMethod: { - switch (constant ? constant->kind : SILDeclRef::Kind::Func) { - case SILDeclRef::Kind::Initializer: - case SILDeclRef::Kind::EnumElement: - return getSILFunctionType(TC, context, origType, substInterfaceType, - extInfo, DefaultInitializerConventions(), - ForeignInfo(), origConstant, constant, reqtSubs, - witnessMethodConformance); - case SILDeclRef::Kind::Allocator: - return getSILFunctionType(TC, context, origType, substInterfaceType, - extInfo, DefaultAllocatorConventions(), - ForeignInfo(), origConstant, constant, reqtSubs, - witnessMethodConformance); - case SILDeclRef::Kind::Func: - // If we have a setter, use the special setter convention. This ensures - // that we take normal parameters at +1. - if (constant && constant->isSetter()) { - return getSILFunctionType(TC, context, origType, substInterfaceType, - extInfo, DefaultSetterConventions(), - ForeignInfo(), origConstant, constant, - reqtSubs, witnessMethodConformance); - } - LLVM_FALLTHROUGH; - case SILDeclRef::Kind::Destroyer: - case SILDeclRef::Kind::GlobalAccessor: - case SILDeclRef::Kind::DefaultArgGenerator: - case SILDeclRef::Kind::StoredPropertyInitializer: - case SILDeclRef::Kind::PropertyWrapperBackingInitializer: - case SILDeclRef::Kind::IVarInitializer: - case SILDeclRef::Kind::IVarDestroyer: { - auto conv = DefaultConventions(NormalParameterConvention::Guaranteed); - return getSILFunctionType(TC, context, origType, substInterfaceType, - extInfo, conv, ForeignInfo(), origConstant, - constant, reqtSubs, witnessMethodConformance); - } - case SILDeclRef::Kind::Deallocator: - return getSILFunctionType(TC, context, origType, substInterfaceType, - extInfo, DeallocatorConventions(), - ForeignInfo(), origConstant, constant, reqtSubs, - witnessMethodConformance); - } - } - } - - llvm_unreachable("Unhandled SILDeclRefKind in switch."); -} - -CanSILFunctionType swift::getNativeSILFunctionType( - TypeConverter &TC, TypeExpansionContext context, - AbstractionPattern origType, CanAnyFunctionType substType, - Optional origConstant, Optional substConstant, - Optional reqtSubs, - ProtocolConformanceRef witnessMethodConformance) { - AnyFunctionType::ExtInfo extInfo; - - // Preserve type information from the original type if possible. - if (auto origFnType = origType.getAs()) { - extInfo = origFnType->getExtInfo(); - - // Otherwise, preserve function type attributes from the substituted type. - } else { - extInfo = substType->getExtInfo(); - } - - return ::getNativeSILFunctionType(TC, context, origType, substType, extInfo, - origConstant, substConstant, reqtSubs, - witnessMethodConformance); -} - -//===----------------------------------------------------------------------===// -// Foreign SILFunctionTypes -//===----------------------------------------------------------------------===// - -static bool isCFTypedef(const TypeLowering &tl, clang::QualType type) { - // If we imported a C pointer type as a non-trivial type, it was - // a foreign class type. - return !tl.isTrivial() && type->isPointerType(); -} - -/// Given nothing but a formal C parameter type that's passed -/// indirectly, deduce the convention for it. -/// -/// Generally, whether the parameter is +1 is handled before this. -static ParameterConvention getIndirectCParameterConvention(clang::QualType type) { - // Non-trivial C++ types would be Indirect_Inout (at least in Itanium). - // A trivial const * parameter in C should be considered @in. - return ParameterConvention::Indirect_In; -} - -/// Given a C parameter declaration whose type is passed indirectly, -/// deduce the convention for it. -/// -/// Generally, whether the parameter is +1 is handled before this. -static ParameterConvention -getIndirectCParameterConvention(const clang::ParmVarDecl *param) { - return getIndirectCParameterConvention(param->getType()); -} - -/// Given nothing but a formal C parameter type that's passed -/// directly, deduce the convention for it. -/// -/// Generally, whether the parameter is +1 is handled before this. -static ParameterConvention getDirectCParameterConvention(clang::QualType type) { - return ParameterConvention::Direct_Unowned; -} - -/// Given a C parameter declaration whose type is passed directly, -/// deduce the convention for it. -static ParameterConvention -getDirectCParameterConvention(const clang::ParmVarDecl *param) { - if (param->hasAttr() || - param->hasAttr()) - return ParameterConvention::Direct_Owned; - return getDirectCParameterConvention(param->getType()); -} - -// FIXME: that should be Direct_Guaranteed -const auto ObjCSelfConvention = ParameterConvention::Direct_Unowned; - -namespace { - -class ObjCMethodConventions : public Conventions { - const clang::ObjCMethodDecl *Method; - -public: - const clang::ObjCMethodDecl *getMethod() const { return Method; } - - ObjCMethodConventions(const clang::ObjCMethodDecl *method) - : Conventions(ConventionsKind::ObjCMethod), Method(method) {} - - ParameterConvention getIndirectParameter(unsigned index, - const AbstractionPattern &type, - const TypeLowering &substTL) const override { - return getIndirectCParameterConvention(Method->param_begin()[index]); - } - - ParameterConvention getDirectParameter(unsigned index, - const AbstractionPattern &type, - const TypeLowering &substTL) const override { - return getDirectCParameterConvention(Method->param_begin()[index]); - } - - ParameterConvention getCallee() const override { - // Always thin. - return ParameterConvention::Direct_Unowned; - } - - /// Given that a method returns a CF type, infer its method - /// family. Unfortunately, Clang's getMethodFamily() never - /// considers a method to be in a special family if its result - /// doesn't satisfy isObjCRetainable(). - clang::ObjCMethodFamily getMethodFamilyForCFResult() const { - // Trust an explicit attribute. - if (auto attr = Method->getAttr()) { - switch (attr->getFamily()) { - case clang::ObjCMethodFamilyAttr::OMF_None: - return clang::OMF_None; - case clang::ObjCMethodFamilyAttr::OMF_alloc: - return clang::OMF_alloc; - case clang::ObjCMethodFamilyAttr::OMF_copy: - return clang::OMF_copy; - case clang::ObjCMethodFamilyAttr::OMF_init: - return clang::OMF_init; - case clang::ObjCMethodFamilyAttr::OMF_mutableCopy: - return clang::OMF_mutableCopy; - case clang::ObjCMethodFamilyAttr::OMF_new: - return clang::OMF_new; - } - llvm_unreachable("bad attribute value"); - } - - return Method->getSelector().getMethodFamily(); - } - - bool isImplicitPlusOneCFResult() const { - switch (getMethodFamilyForCFResult()) { - case clang::OMF_None: - case clang::OMF_dealloc: - case clang::OMF_finalize: - case clang::OMF_retain: - case clang::OMF_release: - case clang::OMF_autorelease: - case clang::OMF_retainCount: - case clang::OMF_self: - case clang::OMF_initialize: - case clang::OMF_performSelector: - return false; - - case clang::OMF_alloc: - case clang::OMF_new: - case clang::OMF_mutableCopy: - case clang::OMF_copy: - return true; - - case clang::OMF_init: - return Method->isInstanceMethod(); - } - llvm_unreachable("bad method family"); - } - - ResultConvention getResult(const TypeLowering &tl) const override { - // If we imported the result as something trivial, we need to - // use one of the unowned conventions. - if (tl.isTrivial()) { - if (Method->hasAttr()) - return ResultConvention::UnownedInnerPointer; - - auto type = tl.getLoweredType(); - if (type.unwrapOptionalType().getStructOrBoundGenericStruct() - == type.getASTContext().getUnmanagedDecl()) - return ResultConvention::UnownedInnerPointer; - return ResultConvention::Unowned; - } - - // Otherwise, the return type had better be a retainable object pointer. - auto resultType = Method->getReturnType(); - assert(resultType->isObjCRetainableType() || isCFTypedef(tl, resultType)); - - // If it's retainable for the purposes of ObjC ARC, we can trust - // the presence of ns_returns_retained, because Clang will add - // that implicitly based on the method family. - if (resultType->isObjCRetainableType()) { - if (Method->hasAttr()) - return ResultConvention::Owned; - return ResultConvention::Autoreleased; - } - - // Otherwise, it's a CF return type, which unfortunately means - // we can't just trust getMethodFamily(). We should really just - // change that, but that's an annoying change to make to Clang - // right now. - assert(isCFTypedef(tl, resultType)); - - // Trust the explicit attributes. - if (Method->hasAttr()) - return ResultConvention::Owned; - if (Method->hasAttr()) - return ResultConvention::Autoreleased; - - // Otherwise, infer based on the method family. - if (isImplicitPlusOneCFResult()) - return ResultConvention::Owned; - return ResultConvention::Autoreleased; - } - - ParameterConvention - getDirectSelfParameter(const AbstractionPattern &type) const override { - if (Method->hasAttr()) - return ParameterConvention::Direct_Owned; - - // The caller is supposed to take responsibility for ensuring - // that 'self' survives a method call. - return ObjCSelfConvention; - } - - ParameterConvention - getIndirectSelfParameter(const AbstractionPattern &type) const override { - llvm_unreachable("objc methods do not support indirect self parameters"); - } - - static bool classof(const Conventions *C) { - return C->getKind() == ConventionsKind::ObjCMethod; - } -}; - -/// Conventions based on a C function type. -class CFunctionTypeConventions : public Conventions { - const clang::FunctionType *FnType; - - clang::QualType getParamType(unsigned i) const { - return FnType->castAs()->getParamType(i); - } - -protected: - /// Protected constructor for subclasses to override the kind passed to the - /// super class. - CFunctionTypeConventions(ConventionsKind kind, - const clang::FunctionType *type) - : Conventions(kind), FnType(type) {} - -public: - CFunctionTypeConventions(const clang::FunctionType *type) - : Conventions(ConventionsKind::CFunctionType), FnType(type) {} - - ParameterConvention getIndirectParameter(unsigned index, - const AbstractionPattern &type, - const TypeLowering &substTL) const override { - return getIndirectCParameterConvention(getParamType(index)); - } - - ParameterConvention getDirectParameter(unsigned index, - const AbstractionPattern &type, - const TypeLowering &substTL) const override { - if (cast(FnType)->isParamConsumed(index)) - return ParameterConvention::Direct_Owned; - return getDirectCParameterConvention(getParamType(index)); - } - - ParameterConvention getCallee() const override { - // FIXME: blocks should be Direct_Guaranteed. - return ParameterConvention::Direct_Unowned; - } - - ResultConvention getResult(const TypeLowering &tl) const override { - if (tl.isTrivial()) - return ResultConvention::Unowned; - if (FnType->getExtInfo().getProducesResult()) - return ResultConvention::Owned; - return ResultConvention::Autoreleased; - } - - ParameterConvention - getDirectSelfParameter(const AbstractionPattern &type) const override { - llvm_unreachable("c function types do not have a self parameter"); - } - - ParameterConvention - getIndirectSelfParameter(const AbstractionPattern &type) const override { - llvm_unreachable("c function types do not have a self parameter"); - } - - static bool classof(const Conventions *C) { - return C->getKind() == ConventionsKind::CFunctionType; - } -}; - -/// Conventions based on C function declarations. -class CFunctionConventions : public CFunctionTypeConventions { - using super = CFunctionTypeConventions; - const clang::FunctionDecl *TheDecl; -public: - CFunctionConventions(const clang::FunctionDecl *decl) - : CFunctionTypeConventions(ConventionsKind::CFunction, - decl->getType()->castAs()), - TheDecl(decl) {} - - ParameterConvention getDirectParameter(unsigned index, - const AbstractionPattern &type, - const TypeLowering &substTL) const override { - if (auto param = TheDecl->getParamDecl(index)) - if (param->hasAttr()) - return ParameterConvention::Direct_Owned; - return super::getDirectParameter(index, type, substTL); - } - - ResultConvention getResult(const TypeLowering &tl) const override { - if (isCFTypedef(tl, TheDecl->getReturnType())) { - // The CF attributes aren't represented in the type, so we need - // to check them here. - if (TheDecl->hasAttr()) { - return ResultConvention::Owned; - } else if (TheDecl->hasAttr()) { - // Probably not actually autoreleased. - return ResultConvention::Autoreleased; - - // The CF Create/Copy rule only applies to functions that return - // a CF-runtime type; it does not apply to methods, and it does - // not apply to functions returning ObjC types. - } else if (clang::ento::coreFoundation::followsCreateRule(TheDecl)) { - return ResultConvention::Owned; - } else { - return ResultConvention::Autoreleased; - } - } - - // Otherwise, fall back on the ARC annotations, which are part - // of the type. - return super::getResult(tl); - } - - static bool classof(const Conventions *C) { - return C->getKind() == ConventionsKind::CFunction; - } -}; - -/// Conventions based on C++ method declarations. -class CXXMethodConventions : public CFunctionTypeConventions { - using super = CFunctionTypeConventions; - const clang::CXXMethodDecl *TheDecl; - -public: - CXXMethodConventions(const clang::CXXMethodDecl *decl) - : CFunctionTypeConventions( - ConventionsKind::CXXMethod, - decl->getType()->castAs()), - TheDecl(decl) {} - ParameterConvention - getIndirectSelfParameter(const AbstractionPattern &type) const override { - if (TheDecl->isConst()) - return ParameterConvention::Indirect_In_Guaranteed; - return ParameterConvention::Indirect_Inout; - } - ResultConvention getResult(const TypeLowering &resultTL) const override { - if (dyn_cast(TheDecl)) { - return ResultConvention::Indirect; - } - return CFunctionTypeConventions::getResult(resultTL); - } - static bool classof(const Conventions *C) { - return C->getKind() == ConventionsKind::CXXMethod; - } -}; - -} // end anonymous namespace - -/// Given that we have an imported Clang declaration, deduce the -/// ownership conventions for calling it and build the SILFunctionType. -static CanSILFunctionType -getSILFunctionTypeForClangDecl(TypeConverter &TC, const clang::Decl *clangDecl, - CanAnyFunctionType origType, - CanAnyFunctionType substInterfaceType, - AnyFunctionType::ExtInfo extInfo, - const ForeignInfo &foreignInfo, - Optional constant) { - if (auto method = dyn_cast(clangDecl)) { - auto origPattern = - AbstractionPattern::getObjCMethod(origType, method, foreignInfo.Error); - return getSILFunctionType(TC, TypeExpansionContext::minimal(), origPattern, - substInterfaceType, extInfo, - ObjCMethodConventions(method), foreignInfo, - constant, constant, None, - ProtocolConformanceRef()); - } - - if (auto method = dyn_cast(clangDecl)) { - AbstractionPattern origPattern = - AbstractionPattern::getCXXMethod(origType, method); - auto conventions = CXXMethodConventions(method); - return getSILFunctionType(TC, TypeExpansionContext::minimal(), origPattern, - substInterfaceType, extInfo, conventions, - foreignInfo, constant, constant, None, - ProtocolConformanceRef()); - } - - if (auto func = dyn_cast(clangDecl)) { - auto clangType = func->getType().getTypePtr(); - AbstractionPattern origPattern = - foreignInfo.Self.isImportAsMember() - ? AbstractionPattern::getCFunctionAsMethod(origType, clangType, - foreignInfo.Self) - : AbstractionPattern(origType, clangType); - return getSILFunctionType(TC, TypeExpansionContext::minimal(), origPattern, - substInterfaceType, extInfo, - CFunctionConventions(func), foreignInfo, constant, - constant, None, ProtocolConformanceRef()); - } - - llvm_unreachable("call to unknown kind of C function"); -} - -static CanSILFunctionType -getSILFunctionTypeForAbstractCFunction(TypeConverter &TC, - AbstractionPattern origType, - CanAnyFunctionType substType, - AnyFunctionType::ExtInfo extInfo, - Optional constant) { - if (origType.isClangType()) { - auto clangType = origType.getClangType(); - const clang::FunctionType *fnType; - if (auto blockPtr = clangType->getAs()) { - fnType = blockPtr->getPointeeType()->castAs(); - } else if (auto ptr = clangType->getAs()) { - fnType = ptr->getPointeeType()->getAs(); - } else if (auto ref = clangType->getAs()) { - fnType = ref->getPointeeType()->getAs(); - } else if (auto fn = clangType->getAs()) { - fnType = fn; - } else { - llvm_unreachable("unexpected type imported as a function type"); - } - if (fnType) { - return getSILFunctionType( - TC, TypeExpansionContext::minimal(), origType, substType, extInfo, - CFunctionTypeConventions(fnType), ForeignInfo(), constant, constant, - None, ProtocolConformanceRef()); - } - } - - // TODO: Ought to support captures in block funcs. - return getSILFunctionType(TC, TypeExpansionContext::minimal(), origType, - substType, extInfo, DefaultBlockConventions(), - ForeignInfo(), constant, constant, None, - ProtocolConformanceRef()); -} - -/// Try to find a clang method declaration for the given function. -static const clang::Decl *findClangMethod(ValueDecl *method) { - if (auto *methodFn = dyn_cast(method)) { - if (auto *decl = methodFn->getClangDecl()) - return decl; - - if (auto overridden = methodFn->getOverriddenDecl()) - return findClangMethod(overridden); - } - - if (auto *constructor = dyn_cast(method)) { - if (auto *decl = constructor->getClangDecl()) - return decl; - } - - return nullptr; -} - -//===----------------------------------------------------------------------===// -// Selector Family SILFunctionTypes -//===----------------------------------------------------------------------===// - -/// Derive the ObjC selector family from an identifier. -/// -/// Note that this will never derive the Init family, which is too dangerous -/// to leave to chance. Swift functions starting with "init" are always -/// emitted as if they are part of the "none" family. -static ObjCSelectorFamily getObjCSelectorFamily(ObjCSelector name) { - auto result = name.getSelectorFamily(); - - if (result == ObjCSelectorFamily::Init) - return ObjCSelectorFamily::None; - - return result; -} - -/// Get the ObjC selector family a foreign SILDeclRef belongs to. -static ObjCSelectorFamily getObjCSelectorFamily(SILDeclRef c) { - assert(c.isForeign); - switch (c.kind) { - case SILDeclRef::Kind::Func: { - if (!c.hasDecl()) - return ObjCSelectorFamily::None; - - auto *FD = cast(c.getDecl()); - if (auto accessor = dyn_cast(FD)) { - switch (accessor->getAccessorKind()) { - case AccessorKind::Get: - case AccessorKind::Set: - break; -#define OBJC_ACCESSOR(ID, KEYWORD) -#define ACCESSOR(ID) \ - case AccessorKind::ID: -#include "swift/AST/AccessorKinds.def" - llvm_unreachable("Unexpected AccessorKind of foreign FuncDecl"); - } - } - - return getObjCSelectorFamily(FD->getObjCSelector()); - } - case SILDeclRef::Kind::Initializer: - case SILDeclRef::Kind::IVarInitializer: - return ObjCSelectorFamily::Init; - - /// Currently IRGen wraps alloc/init methods into Swift constructors - /// with Swift conventions. - case SILDeclRef::Kind::Allocator: - /// These constants don't correspond to method families we care about yet. - case SILDeclRef::Kind::Destroyer: - case SILDeclRef::Kind::Deallocator: - case SILDeclRef::Kind::IVarDestroyer: - return ObjCSelectorFamily::None; - - case SILDeclRef::Kind::EnumElement: - case SILDeclRef::Kind::GlobalAccessor: - case SILDeclRef::Kind::DefaultArgGenerator: - case SILDeclRef::Kind::StoredPropertyInitializer: - case SILDeclRef::Kind::PropertyWrapperBackingInitializer: - llvm_unreachable("Unexpected Kind of foreign SILDeclRef"); - } - - llvm_unreachable("Unhandled SILDeclRefKind in switch."); -} - -namespace { - -class ObjCSelectorFamilyConventions : public Conventions { - ObjCSelectorFamily Family; - -public: - ObjCSelectorFamilyConventions(ObjCSelectorFamily family) - : Conventions(ConventionsKind::ObjCSelectorFamily), Family(family) {} - - ParameterConvention getIndirectParameter(unsigned index, - const AbstractionPattern &type, - const TypeLowering &substTL) const override { - return ParameterConvention::Indirect_In; - } - - ParameterConvention getDirectParameter(unsigned index, - const AbstractionPattern &type, - const TypeLowering &substTL) const override { - return ParameterConvention::Direct_Unowned; - } - - ParameterConvention getCallee() const override { - // Always thin. - return ParameterConvention::Direct_Unowned; - } - - ResultConvention getResult(const TypeLowering &tl) const override { - switch (Family) { - case ObjCSelectorFamily::Alloc: - case ObjCSelectorFamily::Copy: - case ObjCSelectorFamily::Init: - case ObjCSelectorFamily::MutableCopy: - case ObjCSelectorFamily::New: - return ResultConvention::Owned; - - case ObjCSelectorFamily::None: - // Defaults below. - break; - } - - // Get the underlying AST type, potentially stripping off one level of - // optionality while we do it. - CanType type = tl.getLoweredType().unwrapOptionalType().getASTType(); - if (type->hasRetainablePointerRepresentation() - || (type->getSwiftNewtypeUnderlyingType() && !tl.isTrivial())) - return ResultConvention::Autoreleased; - - return ResultConvention::Unowned; - } - - ParameterConvention - getDirectSelfParameter(const AbstractionPattern &type) const override { - if (Family == ObjCSelectorFamily::Init) - return ParameterConvention::Direct_Owned; - return ObjCSelfConvention; - } - - ParameterConvention - getIndirectSelfParameter(const AbstractionPattern &type) const override { - llvm_unreachable("selector family objc function types do not support " - "indirect self parameters"); - } - - static bool classof(const Conventions *C) { - return C->getKind() == ConventionsKind::ObjCSelectorFamily; - } -}; - -} // end anonymous namespace - -static CanSILFunctionType -getSILFunctionTypeForObjCSelectorFamily(TypeConverter &TC, ObjCSelectorFamily family, - CanAnyFunctionType origType, - CanAnyFunctionType substInterfaceType, - AnyFunctionType::ExtInfo extInfo, - const ForeignInfo &foreignInfo, - Optional constant) { - return getSILFunctionType( - TC, TypeExpansionContext::minimal(), AbstractionPattern(origType), - substInterfaceType, extInfo, ObjCSelectorFamilyConventions(family), - foreignInfo, constant, constant, - /*requirement subs*/ None, ProtocolConformanceRef()); -} - -static bool isImporterGeneratedAccessor(const clang::Decl *clangDecl, - SILDeclRef constant) { - // Must be an accessor. - auto accessor = dyn_cast(constant.getDecl()); - if (!accessor) - return false; - - // Must be a type member. - if (constant.getParameterListCount() != 2) - return false; - - // Must be imported from a function. - if (!isa(clangDecl)) - return false; - - return true; -} - -static CanSILFunctionType getUncachedSILFunctionTypeForConstant( - TypeConverter &TC, TypeExpansionContext context, SILDeclRef constant, - CanAnyFunctionType origLoweredInterfaceType) { - assert(origLoweredInterfaceType->getExtInfo().getSILRepresentation() - != SILFunctionTypeRepresentation::Thick - && origLoweredInterfaceType->getExtInfo().getSILRepresentation() - != SILFunctionTypeRepresentation::Block); - - auto extInfo = origLoweredInterfaceType->getExtInfo(); - - if (!constant.isForeign) { - ProtocolConformanceRef witnessMethodConformance; - - if (extInfo.getSILRepresentation() == - SILFunctionTypeRepresentation::WitnessMethod) { - auto proto = constant.getDecl()->getDeclContext()->getSelfProtocolDecl(); - witnessMethodConformance = ProtocolConformanceRef(proto); - } - - return ::getNativeSILFunctionType( - TC, context, AbstractionPattern(origLoweredInterfaceType), - origLoweredInterfaceType, extInfo, constant, constant, None, - witnessMethodConformance); - } - - ForeignInfo foreignInfo; - - // If we have a clang decl associated with the Swift decl, derive its - // ownership conventions. - if (constant.hasDecl()) { - auto decl = constant.getDecl(); - if (auto funcDecl = dyn_cast(decl)) { - foreignInfo.Error = funcDecl->getForeignErrorConvention(); - foreignInfo.Self = funcDecl->getImportAsMemberStatus(); - } - - if (auto clangDecl = findClangMethod(decl)) { - // The importer generates accessors that are not actually - // import-as-member but do involve the same gymnastics with the - // formal type. That's all that SILFunctionType cares about, so - // pretend that it's import-as-member. - if (!foreignInfo.Self.isImportAsMember() && - isImporterGeneratedAccessor(clangDecl, constant)) { - unsigned selfIndex = cast(decl)->isSetter() ? 1 : 0; - foreignInfo.Self.setSelfIndex(selfIndex); - } - - return getSILFunctionTypeForClangDecl(TC, clangDecl, - origLoweredInterfaceType, - origLoweredInterfaceType, - extInfo, foreignInfo, constant); - } - } - - // If the decl belongs to an ObjC method family, use that family's - // ownership conventions. - return getSILFunctionTypeForObjCSelectorFamily( - TC, getObjCSelectorFamily(constant), - origLoweredInterfaceType, origLoweredInterfaceType, - extInfo, foreignInfo, constant); -} - -CanSILFunctionType TypeConverter::getUncachedSILFunctionTypeForConstant( - TypeExpansionContext context, SILDeclRef constant, - CanAnyFunctionType origInterfaceType) { - auto origLoweredInterfaceType = - getLoweredFormalTypes(constant, origInterfaceType).Uncurried; - return ::getUncachedSILFunctionTypeForConstant(*this, context, constant, - origLoweredInterfaceType); -} - -static bool isClassOrProtocolMethod(ValueDecl *vd) { - if (!vd->getDeclContext()) - return false; - Type contextType = vd->getDeclContext()->getDeclaredInterfaceType(); - if (!contextType) - return false; - return contextType->getClassOrBoundGenericClass() - || contextType->isClassExistentialType(); -} - -SILFunctionTypeRepresentation -TypeConverter::getDeclRefRepresentation(SILDeclRef c) { - // If this is a foreign thunk, it always has the foreign calling convention. - if (c.isForeign) { - if (!c.hasDecl() || - c.getDecl()->isImportAsMember()) - return SILFunctionTypeRepresentation::CFunctionPointer; - - if (isClassOrProtocolMethod(c.getDecl()) || - c.kind == SILDeclRef::Kind::IVarInitializer || - c.kind == SILDeclRef::Kind::IVarDestroyer) - return SILFunctionTypeRepresentation::ObjCMethod; - - return SILFunctionTypeRepresentation::CFunctionPointer; - } - - // Anonymous functions currently always have Freestanding CC. - if (!c.hasDecl()) - return SILFunctionTypeRepresentation::Thin; - - // FIXME: Assert that there is a native entry point - // available. There's no great way to do this. - - // Protocol witnesses are called using the witness calling convention. - if (auto proto = dyn_cast(c.getDecl()->getDeclContext())) { - // Use the regular method convention for foreign-to-native thunks. - if (c.isForeignToNativeThunk()) - return SILFunctionTypeRepresentation::Method; - assert(!c.isNativeToForeignThunk() && "shouldn't be possible"); - return getProtocolWitnessRepresentation(proto); - } - - switch (c.kind) { - case SILDeclRef::Kind::GlobalAccessor: - case SILDeclRef::Kind::DefaultArgGenerator: - case SILDeclRef::Kind::StoredPropertyInitializer: - case SILDeclRef::Kind::PropertyWrapperBackingInitializer: - return SILFunctionTypeRepresentation::Thin; - - case SILDeclRef::Kind::Func: - if (c.getDecl()->getDeclContext()->isTypeContext()) - return SILFunctionTypeRepresentation::Method; - return SILFunctionTypeRepresentation::Thin; - - case SILDeclRef::Kind::Destroyer: - case SILDeclRef::Kind::Deallocator: - case SILDeclRef::Kind::Allocator: - case SILDeclRef::Kind::Initializer: - case SILDeclRef::Kind::EnumElement: - case SILDeclRef::Kind::IVarInitializer: - case SILDeclRef::Kind::IVarDestroyer: - return SILFunctionTypeRepresentation::Method; - } - - llvm_unreachable("Unhandled SILDeclRefKind in switch."); -} - -// Provide the ability to turn off the type converter cache to ease debugging. -static llvm::cl::opt - DisableConstantInfoCache("sil-disable-typelowering-constantinfo-cache", - llvm::cl::init(false)); - -const SILConstantInfo & -TypeConverter::getConstantInfo(TypeExpansionContext expansion, - SILDeclRef constant) { - if (!DisableConstantInfoCache) { - auto found = ConstantTypes.find(std::make_pair(expansion, constant)); - if (found != ConstantTypes.end()) - return *found->second; - } - - // First, get a function type for the constant. This creates the - // right type for a getter or setter. - auto formalInterfaceType = makeConstantInterfaceType(constant); - - // The formal type is just that with the right representation. - auto rep = getDeclRefRepresentation(constant); - formalInterfaceType = adjustFunctionType(formalInterfaceType, rep); - - // The lowered type is the formal type, but uncurried and with - // parameters automatically turned into their bridged equivalents. - auto bridgedTypes = getLoweredFormalTypes(constant, formalInterfaceType); - - CanAnyFunctionType loweredInterfaceType = bridgedTypes.Uncurried; - - // The SIL type encodes conventions according to the original type. - CanSILFunctionType silFnType = - ::getUncachedSILFunctionTypeForConstant(*this, expansion, constant, - loweredInterfaceType); - - // If the constant refers to a derivative function, get the SIL type of the - // original function and use it to compute the derivative SIL type. - // - // This is necessary because the "lowered AST derivative function type" (BC) - // may differ from the "derivative type of the lowered original function type" - // (AD): - // - // +--------------------+ lowering +--------------------+ - // | AST orig. fn type | -------(A)------> | SIL orig. fn type | - // +--------------------+ +--------------------+ - // | | - // (B, Sema) getAutoDiffDerivativeFunctionType (D, here) - // V V - // +--------------------+ lowering +--------------------+ - // | AST deriv. fn type | -------(C)------> | SIL deriv. fn type | - // +--------------------+ +--------------------+ - // - // (AD) does not always commute with (BC): - // - (BC) is the result of computing the AST derivative type (Sema), then - // lowering it via SILGen. This is the default lowering behavior, but may - // break SIL typing invariants because expected lowered derivative types are - // computed from lowered original function types. - // - (AD) is the result of lowering the original function type, then computing - // its derivative type. This is the expected lowered derivative type, - // preserving SIL typing invariants. - // - // Always use (AD) to compute lowered derivative function types. - if (auto *derivativeId = constant.derivativeFunctionIdentifier) { - // Get lowered original function type. - auto origFnConstantInfo = getConstantInfo( - TypeExpansionContext::minimal(), constant.asAutoDiffOriginalFunction()); - // Use it to compute lowered derivative function type. - auto *loweredIndices = autodiff::getLoweredParameterIndices( - derivativeId->getParameterIndices(), formalInterfaceType); - silFnType = origFnConstantInfo.SILFnType->getAutoDiffDerivativeFunctionType( - loweredIndices, /*resultIndex*/ 0, derivativeId->getKind(), *this, - LookUpConformanceInModule(&M)); - } - - LLVM_DEBUG(llvm::dbgs() << "lowering type for constant "; - constant.print(llvm::dbgs()); - llvm::dbgs() << "\n formal type: "; - formalInterfaceType.print(llvm::dbgs()); - llvm::dbgs() << "\n lowered AST type: "; - loweredInterfaceType.print(llvm::dbgs()); - llvm::dbgs() << "\n SIL type: "; - silFnType.print(llvm::dbgs()); - llvm::dbgs() << "\n Expansion context: " - << expansion.shouldLookThroughOpaqueTypeArchetypes(); - llvm::dbgs() << "\n"); - - auto resultBuf = Context.Allocate(sizeof(SILConstantInfo), - alignof(SILConstantInfo)); - - auto result = ::new (resultBuf) SILConstantInfo{formalInterfaceType, - bridgedTypes.Pattern, - loweredInterfaceType, - silFnType}; - if (DisableConstantInfoCache) - return *result; - - auto inserted = - ConstantTypes.insert({std::make_pair(expansion, constant), result}); - assert(inserted.second); - (void)inserted; - return *result; -} - -/// Returns the SILParameterInfo for the given declaration's `self` parameter. -/// `constant` must refer to a method. -SILParameterInfo -TypeConverter::getConstantSelfParameter(TypeExpansionContext context, - SILDeclRef constant) { - auto ty = getConstantFunctionType(context, constant); - - // In most cases the "self" parameter is lowered as the back parameter. - // The exception is C functions imported as methods. - if (!constant.isForeign) - return ty->getParameters().back(); - if (!constant.hasDecl()) - return ty->getParameters().back(); - auto fn = dyn_cast(constant.getDecl()); - if (!fn) - return ty->getParameters().back(); - if (fn->isImportAsStaticMember()) - return SILParameterInfo(); - if (fn->isImportAsInstanceMember()) - return ty->getParameters()[fn->getSelfIndex()]; - return ty->getParameters().back(); -} - -// This check duplicates TypeConverter::checkForABIDifferences(), -// but on AST types. The issue is we only want to introduce a new -// vtable thunk if the AST type changes, but an abstraction change -// is OK; we don't want a new entry if an @in parameter became -// @guaranteed or whatever. -static bool checkASTTypeForABIDifferences(CanType type1, - CanType type2) { - return !type1->matches(type2, TypeMatchFlags::AllowABICompatible); -} - -// FIXME: This makes me very upset. Can we do without this? -static CanType copyOptionalityFromDerivedToBase(TypeConverter &tc, - CanType derived, - CanType base) { - // Unwrap optionals, but remember that we did. - bool derivedWasOptional = false; - if (auto object = derived.getOptionalObjectType()) { - derivedWasOptional = true; - derived = object; - } - if (auto object = base.getOptionalObjectType()) { - base = object; - } - - // T? +> S = (T +> S)? - // T? +> S? = (T +> S)? - if (derivedWasOptional) { - base = copyOptionalityFromDerivedToBase(tc, derived, base); - - auto optDecl = tc.Context.getOptionalDecl(); - return CanType(BoundGenericEnumType::get(optDecl, Type(), base)); - } - - // (T1, T2, ...) +> (S1, S2, ...) = (T1 +> S1, T2 +> S2, ...) - if (auto derivedTuple = dyn_cast(derived)) { - if (auto baseTuple = dyn_cast(base)) { - assert(derivedTuple->getNumElements() == baseTuple->getNumElements()); - SmallVector elements; - for (unsigned i = 0, e = derivedTuple->getNumElements(); i < e; i++) { - elements.push_back( - baseTuple->getElement(i).getWithType( - copyOptionalityFromDerivedToBase( - tc, - derivedTuple.getElementType(i), - baseTuple.getElementType(i)))); - } - return CanType(TupleType::get(elements, tc.Context)); - } - } - - // (T1 -> T2) +> (S1 -> S2) = (T1 +> S1) -> (T2 +> S2) - if (auto derivedFunc = dyn_cast(derived)) { - if (auto baseFunc = dyn_cast(base)) { - SmallVector params; - - auto derivedParams = derivedFunc.getParams(); - auto baseParams = baseFunc.getParams(); - assert(derivedParams.size() == baseParams.size()); - for (unsigned i = 0, e = derivedParams.size(); i < e; i++) { - assert(derivedParams[i].getParameterFlags() == - baseParams[i].getParameterFlags()); - - params.emplace_back( - copyOptionalityFromDerivedToBase( - tc, - derivedParams[i].getPlainType(), - baseParams[i].getPlainType()), - Identifier(), - baseParams[i].getParameterFlags()); - } - - auto result = copyOptionalityFromDerivedToBase(tc, - derivedFunc.getResult(), - baseFunc.getResult()); - return CanAnyFunctionType::get(baseFunc.getOptGenericSignature(), - llvm::makeArrayRef(params), result, - baseFunc->getExtInfo()); - } - } - - return base; -} - -/// Returns the ConstantInfo corresponding to the VTable thunk for overriding. -/// Will be the same as getConstantInfo if the declaration does not override. -const SILConstantInfo & -TypeConverter::getConstantOverrideInfo(TypeExpansionContext context, - SILDeclRef derived, SILDeclRef base) { - // Foreign overrides currently don't need reabstraction. - if (derived.isForeign) - return getConstantInfo(context, derived); - - auto found = ConstantOverrideTypes.find({derived, base}); - if (found != ConstantOverrideTypes.end()) - return *found->second; - - assert(base.requiresNewVTableEntry() && "base must not be an override"); - - // Figure out the generic signature for the class method call. This is the - // signature of the derived class, with requirements transplanted from - // the base method. The derived method is allowed to have fewer - // requirements, in which case the thunk will translate the calling - // convention appropriately before calling the derived method. - bool hasGenericRequirementDifference = false; - - auto derivedSig = derived.getDecl()->getAsGenericContext() - ->getGenericSignature(); - auto genericSig = Context.getOverrideGenericSignature(base.getDecl(), - derived.getDecl()); - if (genericSig) { - hasGenericRequirementDifference = - !genericSig->requirementsNotSatisfiedBy(derivedSig).empty(); - } - - auto baseInfo = getConstantInfo(context, base); - auto derivedInfo = getConstantInfo(context, derived); - - auto params = derivedInfo.FormalType.getParams(); - assert(params.size() == 1); - auto selfInterfaceTy = params[0].getPlainType()->getMetatypeInstanceType(); - - auto overrideInterfaceTy = - cast( - selfInterfaceTy->adjustSuperclassMemberDeclType( - base.getDecl(), derived.getDecl(), baseInfo.FormalType) - ->getCanonicalType()); - - // Build the formal AST function type for the class method call. - auto basePattern = AbstractionPattern(baseInfo.LoweredType); - - if (!hasGenericRequirementDifference && - !checkASTTypeForABIDifferences(derivedInfo.FormalType, - overrideInterfaceTy)) { - - // The derived method is ABI-compatible with the base method. Let's - // just use the derived method's formal type. - basePattern = AbstractionPattern( - copyOptionalityFromDerivedToBase( - *this, - derivedInfo.LoweredType, - baseInfo.LoweredType)); - overrideInterfaceTy = derivedInfo.FormalType; - } - - if (genericSig && !genericSig->areAllParamsConcrete()) { - overrideInterfaceTy = - cast( - GenericFunctionType::get(genericSig, - overrideInterfaceTy->getParams(), - overrideInterfaceTy->getResult(), - overrideInterfaceTy->getExtInfo()) - ->getCanonicalType()); - } - - // Build the lowered AST function type for the class method call. - auto bridgedTypes = getLoweredFormalTypes(derived, overrideInterfaceTy); - - // Build the SILFunctionType for the class method call. - CanSILFunctionType fnTy = getNativeSILFunctionType( - *this, context, basePattern, bridgedTypes.Uncurried, base, derived, - /*reqt subs*/ None, ProtocolConformanceRef()); - - // Build the SILConstantInfo and cache it. - auto resultBuf = Context.Allocate(sizeof(SILConstantInfo), - alignof(SILConstantInfo)); - auto result = ::new (resultBuf) SILConstantInfo{ - overrideInterfaceTy, - basePattern, - bridgedTypes.Uncurried, - fnTy}; - - auto inserted = ConstantOverrideTypes.insert({{derived, base}, result}); - assert(inserted.second); - (void)inserted; - return *result; -} - -namespace { - -/// Given a lowered SIL type, apply a substitution to it to produce another -/// lowered SIL type which uses the same abstraction conventions. -class SILTypeSubstituter : - public CanTypeVisitor { - TypeConverter &TC; - TypeSubstitutionFn Subst; - LookupConformanceFn Conformances; - // The signature for the original type. - // - // Replacement types are lowered with respect to the current - // context signature. - CanGenericSignature Sig; - - TypeExpansionContext typeExpansionContext; - - bool shouldSubstituteOpaqueArchetypes; - -public: - SILTypeSubstituter(TypeConverter &TC, - TypeExpansionContext context, - TypeSubstitutionFn Subst, - LookupConformanceFn Conformances, - CanGenericSignature Sig, - bool shouldSubstituteOpaqueArchetypes) - : TC(TC), - Subst(Subst), - Conformances(Conformances), - Sig(Sig), - typeExpansionContext(context), - shouldSubstituteOpaqueArchetypes(shouldSubstituteOpaqueArchetypes) - {} - - // SIL type lowering only does special things to tuples and functions. - - // When a function appears inside of another type, we only perform - // substitutions if it is not polymorphic. - CanSILFunctionType visitSILFunctionType(CanSILFunctionType origType) { - return substSILFunctionType(origType, false); - } - - SubstitutionMap substSubstitutions(SubstitutionMap subs) { - // Substitute the substitutions. - SubstOptions options = None; - if (shouldSubstituteOpaqueArchetypes) - options |= SubstFlags::SubstituteOpaqueArchetypes; - - // Expand substituted type according to the expansion context. - auto newSubs = subs.subst(Subst, Conformances, options); - - // If we need to look through opaque types in this context, re-substitute - // according to the expansion context. - newSubs = substOpaqueTypes(newSubs); - - return newSubs; - } - - SubstitutionMap substOpaqueTypes(SubstitutionMap subs) { - if (!typeExpansionContext.shouldLookThroughOpaqueTypeArchetypes()) - return subs; - - return subs.subst([&](SubstitutableType *s) -> Type { - return substOpaqueTypesWithUnderlyingTypes(s->getCanonicalType(), - typeExpansionContext); - }, [&](CanType dependentType, - Type conformingReplacementType, - ProtocolDecl *conformedProtocol) -> ProtocolConformanceRef { - return substOpaqueTypesWithUnderlyingTypes( - ProtocolConformanceRef(conformedProtocol), - conformingReplacementType->getCanonicalType(), - typeExpansionContext); - }, SubstFlags::SubstituteOpaqueArchetypes); - } - - // Substitute a function type. - CanSILFunctionType substSILFunctionType(CanSILFunctionType origType, - bool isGenericApplication) { - assert((!isGenericApplication || origType->isPolymorphic()) && - "generic application without invocation signature or with " - "existing arguments"); - assert((!isGenericApplication || !shouldSubstituteOpaqueArchetypes) && - "generic application while substituting opaque archetypes"); - - // The general substitution rule is that we should only substitute - // into the free components of the type, i.e. the components that - // aren't inside a generic signature. That rule would say: - // - // - If there are invocation substitutions, just substitute those; - // the other components are necessarily inside the invocation - // generic signature. - // - // - Otherwise, if there's an invocation generic signature, - // substitute nothing. If we are applying generic arguments, - // add the appropriate invocation substitutions. - // - // - Otherwise, if there are pattern substitutions, just substitute - // those; the other components are inside the patttern generic - // signature. - // - // - Otherwise, substitute the basic components. - // - // There are two caveats here. The first is that we haven't yet - // written all the code that would be necessary in order to handle - // invocation substitutions everywhere, and so we never build those. - // Instead, we substitute into the pattern substitutions if present, - // or the components if not, and build a type with no invocation - // signature. As a special case, when substituting a coroutine type, - // we build pattern substitutions instead of substituting the - // component types in order to preserve the original yield structure, - // which factors into the continuation function ABI. - // - // The second is that this function is also used when substituting - // opaque archetypes. In this case, we may need to substitute - // into component types even within generic signatures. This is - // safe because the substitutions used in this case don't change - // generics, they just narrowly look through certain opaque archetypes. - // If substitutions are present, we still don't substitute into - // the basic components, in order to maintain the information about - // what was abstracted there. - - auto patternSubs = origType->getPatternSubstitutions(); - - // If we have an invocation signatture, we generally shouldn't - // substitute into the pattern substitutions and component types. - if (auto sig = origType->getInvocationGenericSignature()) { - // Substitute the invocation substitutions if present. - if (auto invocationSubs = origType->getInvocationSubstitutions()) { - assert(!isGenericApplication); - invocationSubs = substSubstitutions(invocationSubs); - auto substType = - origType->withInvocationSubstitutions(invocationSubs); - - // Also do opaque-type substitutions on the pattern substitutions - // if requested and applicable. - if (patternSubs) { - patternSubs = substOpaqueTypes(patternSubs); - substType = substType->withPatternSubstitutions(patternSubs); - } - - return substType; - } - - // Otherwise, we shouldn't substitute any components except - // when substituting opaque archetypes. - - // If we're doing a generic application, and there are pattern - // substitutions, substitute into the pattern substitutions; or if - // it's a coroutine, build pattern substitutions; or else, fall - // through to substitute the component types as discussed above. - if (isGenericApplication) { - if (patternSubs || origType->isCoroutine()) { - CanSILFunctionType substType = origType; - if (typeExpansionContext.shouldLookThroughOpaqueTypeArchetypes()) { - substType = - origType->substituteOpaqueArchetypes(TC, typeExpansionContext); - } - - SubstitutionMap subs; - if (patternSubs) { - subs = substSubstitutions(patternSubs); - } else { - subs = SubstitutionMap::get(sig, Subst, Conformances); - } - auto witnessConformance = substWitnessConformance(origType); - substType = substType->withPatternSpecialization(nullptr, subs, - witnessConformance); - - return substType; - } - // else fall down to component substitution - - // If we're substituting opaque archetypes, and there are pattern - // substitutions present, just substitute those and preserve the - // basic structure in the component types. Otherwise, fall through - // to substitute the component types. - } else if (shouldSubstituteOpaqueArchetypes) { - if (patternSubs) { - patternSubs = substOpaqueTypes(patternSubs); - auto witnessConformance = substWitnessConformance(origType); - return origType->withPatternSpecialization(sig, patternSubs, - witnessConformance); - } - // else fall down to component substitution - - // Otherwise, don't try to substitute bound components. - } else { - auto substType = origType; - if (patternSubs) { - patternSubs = substOpaqueTypes(patternSubs); - auto witnessConformance = substWitnessConformance(origType); - substType = substType->withPatternSpecialization(sig, patternSubs, - witnessConformance); - } - return substType; - } - - // Otherwise, if there are pattern substitutions, just substitute - // into those and don't touch the component types. - } else if (patternSubs) { - patternSubs = substSubstitutions(patternSubs); - auto witnessConformance = substWitnessConformance(origType); - return origType->withPatternSpecialization(nullptr, patternSubs, - witnessConformance); - } - - // Otherwise, we need to substitute component types. - - SmallVector substResults; - substResults.reserve(origType->getNumResults()); - for (auto origResult : origType->getResults()) { - substResults.push_back(substInterface(origResult)); - } - - auto substErrorResult = origType->getOptionalErrorResult(); - assert(!substErrorResult || - (!substErrorResult->getInterfaceType()->hasTypeParameter() && - !substErrorResult->getInterfaceType()->hasArchetype())); - - SmallVector substParams; - substParams.reserve(origType->getParameters().size()); - for (auto &origParam : origType->getParameters()) { - substParams.push_back(substInterface(origParam)); - } - - SmallVector substYields; - substYields.reserve(origType->getYields().size()); - for (auto &origYield : origType->getYields()) { - substYields.push_back(substInterface(origYield)); - } - - auto witnessMethodConformance = substWitnessConformance(origType); - - // The substituted type is no longer generic, so it'd never be - // pseudogeneric. - auto extInfo = origType->getExtInfo(); - if (!shouldSubstituteOpaqueArchetypes) - extInfo = extInfo.withIsPseudogeneric(false); - - auto genericSig = shouldSubstituteOpaqueArchetypes - ? origType->getInvocationGenericSignature() - : nullptr; - - return SILFunctionType::get(genericSig, extInfo, - origType->getCoroutineKind(), - origType->getCalleeConvention(), substParams, - substYields, substResults, substErrorResult, - SubstitutionMap(), SubstitutionMap(), - TC.Context, witnessMethodConformance); - } - - ProtocolConformanceRef substWitnessConformance(CanSILFunctionType origType) { - auto conformance = origType->getWitnessMethodConformanceOrInvalid(); - if (!conformance) return conformance; - - assert(origType->getExtInfo().hasSelfParam()); - auto selfType = origType->getSelfParameter().getInterfaceType(); - - // The Self type can be nested in a few layers of metatypes (etc.). - while (auto metatypeType = dyn_cast(selfType)) { - auto next = metatypeType.getInstanceType(); - if (next == selfType) - break; - selfType = next; - } - - auto substConformance = - conformance.subst(selfType, Subst, Conformances); - - // Substitute the underlying conformance of opaque type archetypes if we - // should look through opaque archetypes. - if (typeExpansionContext.shouldLookThroughOpaqueTypeArchetypes()) { - SubstOptions substOptions(None); - auto substType = selfType.subst(Subst, Conformances, substOptions) - ->getCanonicalType(); - if (substType->hasOpaqueArchetype()) { - substConformance = substOpaqueTypesWithUnderlyingTypes( - substConformance, substType, typeExpansionContext); - } - } - - return substConformance; - } - - SILType subst(SILType type) { - return SILType::getPrimitiveType(visit(type.getASTType()), - type.getCategory()); - } - - SILResultInfo substInterface(SILResultInfo orig) { - return SILResultInfo(visit(orig.getInterfaceType()), orig.getConvention()); - } - - SILYieldInfo substInterface(SILYieldInfo orig) { - return SILYieldInfo(visit(orig.getInterfaceType()), orig.getConvention()); - } - - SILParameterInfo substInterface(SILParameterInfo orig) { - return SILParameterInfo(visit(orig.getInterfaceType()), - orig.getConvention(), orig.getDifferentiability()); - } - - /// Tuples need to have their component types substituted by these - /// same rules. - CanType visitTupleType(CanTupleType origType) { - // Fast-path the empty tuple. - if (origType->getNumElements() == 0) return origType; - - SmallVector substElts; - substElts.reserve(origType->getNumElements()); - for (auto &origElt : origType->getElements()) { - auto substEltType = visit(CanType(origElt.getType())); - substElts.push_back(origElt.getWithType(substEltType)); - } - return CanType(TupleType::get(substElts, TC.Context)); - } - // Block storage types need to substitute their capture type by these same - // rules. - CanType visitSILBlockStorageType(CanSILBlockStorageType origType) { - auto substCaptureType = visit(origType->getCaptureType()); - return SILBlockStorageType::get(substCaptureType); - } - - /// Optionals need to have their object types substituted by these rules. - CanType visitBoundGenericEnumType(CanBoundGenericEnumType origType) { - // Only use a special rule if it's Optional. - if (!origType->getDecl()->isOptionalDecl()) { - return visitType(origType); - } - - CanType origObjectType = origType.getGenericArgs()[0]; - CanType substObjectType = visit(origObjectType); - return CanType(BoundGenericType::get(origType->getDecl(), Type(), - substObjectType)); - } - - /// Any other type would be a valid type in the AST. Just apply the - /// substitution on the AST level and then lower that. - CanType visitType(CanType origType) { - assert(!isa(origType)); - assert(!isa(origType) && !isa(origType)); - - SubstOptions substOptions(None); - if (shouldSubstituteOpaqueArchetypes) - substOptions = SubstFlags::SubstituteOpaqueArchetypes | - SubstFlags::AllowLoweredTypes; - auto substType = - origType.subst(Subst, Conformances, substOptions)->getCanonicalType(); - - // If the substitution didn't change anything, we know that the - // original type was a lowered type, so we're good. - if (origType == substType) { - return origType; - } - - AbstractionPattern abstraction(Sig, origType); - return TC.getLoweredRValueType(typeExpansionContext, abstraction, - substType); - } -}; - -} // end anonymous namespace - -SILType SILType::subst(TypeConverter &tc, TypeSubstitutionFn subs, - LookupConformanceFn conformances, - CanGenericSignature genericSig, - bool shouldSubstituteOpaqueArchetypes) const { - if (!hasArchetype() && !hasTypeParameter() && - (!shouldSubstituteOpaqueArchetypes || - !getASTType()->hasOpaqueArchetype())) - return *this; - - SILTypeSubstituter STST(tc, TypeExpansionContext::minimal(), subs, - conformances, genericSig, - shouldSubstituteOpaqueArchetypes); - return STST.subst(*this); -} - -SILType SILType::subst(SILModule &M, TypeSubstitutionFn subs, - LookupConformanceFn conformances, - CanGenericSignature genericSig, - bool shouldSubstituteOpaqueArchetypes) const { - return subst(M.Types, subs, conformances, genericSig, - shouldSubstituteOpaqueArchetypes); -} - -SILType SILType::subst(TypeConverter &tc, SubstitutionMap subs) const { - auto sig = subs.getGenericSignature(); - return subst(tc, QuerySubstitutionMap{subs}, - LookUpConformanceInSubstitutionMap(subs), - sig.getCanonicalSignature()); -} -SILType SILType::subst(SILModule &M, SubstitutionMap subs) const{ - return subst(M.Types, subs); -} - -/// Apply a substitution to this polymorphic SILFunctionType so that -/// it has the form of the normal SILFunctionType for the substituted -/// type, except using the original conventions. -CanSILFunctionType -SILFunctionType::substGenericArgs(SILModule &silModule, SubstitutionMap subs, - TypeExpansionContext context) { - if (!isPolymorphic()) { - return CanSILFunctionType(this); - } - - if (subs.empty()) { - return CanSILFunctionType(this); - } - - return substGenericArgs(silModule, - QuerySubstitutionMap{subs}, - LookUpConformanceInSubstitutionMap(subs), - context); -} - -CanSILFunctionType -SILFunctionType::substGenericArgs(SILModule &silModule, - TypeSubstitutionFn subs, - LookupConformanceFn conformances, - TypeExpansionContext context) { - if (!isPolymorphic()) return CanSILFunctionType(this); - SILTypeSubstituter substituter(silModule.Types, context, subs, conformances, - getSubstGenericSignature(), - /*shouldSubstituteOpaqueTypes*/ false); - return substituter.substSILFunctionType(CanSILFunctionType(this), true); -} - -CanSILFunctionType -SILFunctionType::substituteOpaqueArchetypes(TypeConverter &TC, - TypeExpansionContext context) { - if (!hasOpaqueArchetype() || - !context.shouldLookThroughOpaqueTypeArchetypes()) - return CanSILFunctionType(this); - - ReplaceOpaqueTypesWithUnderlyingTypes replacer( - context.getContext(), context.getResilienceExpansion(), - context.isWholeModuleContext()); - - SILTypeSubstituter substituter(TC, context, replacer, replacer, - getSubstGenericSignature(), - /*shouldSubstituteOpaqueTypes*/ true); - auto resTy = - substituter.substSILFunctionType(CanSILFunctionType(this), false); - - return resTy; -} - -/// Fast path for bridging types in a function type without uncurrying. -CanAnyFunctionType -TypeConverter::getBridgedFunctionType(AbstractionPattern pattern, - CanAnyFunctionType t, - AnyFunctionType::ExtInfo extInfo, - Bridgeability bridging) { - // Pull out the generic signature. - CanGenericSignature genericSig = t.getOptGenericSignature(); - - switch (auto rep = t->getExtInfo().getSILRepresentation()) { - case SILFunctionTypeRepresentation::Thick: - case SILFunctionTypeRepresentation::Thin: - case SILFunctionTypeRepresentation::Method: - case SILFunctionTypeRepresentation::Closure: - case SILFunctionTypeRepresentation::WitnessMethod: { - // No bridging needed for native functions. - if (t->getExtInfo() == extInfo) - return t; - return CanAnyFunctionType::get(genericSig, t.getParams(), t.getResult(), - extInfo); - } - - case SILFunctionTypeRepresentation::CFunctionPointer: - case SILFunctionTypeRepresentation::Block: - case SILFunctionTypeRepresentation::ObjCMethod: { - SmallVector params; - getBridgedParams(rep, pattern, t->getParams(), params, bridging); - - bool suppressOptional = pattern.hasForeignErrorStrippingResultOptionality(); - auto result = getBridgedResultType(rep, - pattern.getFunctionResultType(), - t.getResult(), - bridging, - suppressOptional); - - return CanAnyFunctionType::get(genericSig, llvm::makeArrayRef(params), - result, extInfo); - } - } - llvm_unreachable("bad calling convention"); -} - -static AbstractFunctionDecl *getBridgedFunction(SILDeclRef declRef) { - switch (declRef.kind) { - case SILDeclRef::Kind::Func: - case SILDeclRef::Kind::Allocator: - case SILDeclRef::Kind::Initializer: - return (declRef.hasDecl() - ? cast(declRef.getDecl()) - : nullptr); - - case SILDeclRef::Kind::EnumElement: - case SILDeclRef::Kind::Destroyer: - case SILDeclRef::Kind::Deallocator: - case SILDeclRef::Kind::GlobalAccessor: - case SILDeclRef::Kind::DefaultArgGenerator: - case SILDeclRef::Kind::StoredPropertyInitializer: - case SILDeclRef::Kind::PropertyWrapperBackingInitializer: - case SILDeclRef::Kind::IVarInitializer: - case SILDeclRef::Kind::IVarDestroyer: - return nullptr; - } - llvm_unreachable("bad SILDeclRef kind"); -} - -static AbstractionPattern -getAbstractionPatternForConstant(ASTContext &ctx, SILDeclRef constant, - CanAnyFunctionType fnType, - unsigned numParameterLists) { - if (!constant.isForeign) - return AbstractionPattern(fnType); - - auto bridgedFn = getBridgedFunction(constant); - if (!bridgedFn) - return AbstractionPattern(fnType); - const clang::Decl *clangDecl = bridgedFn->getClangDecl(); - if (!clangDecl) - return AbstractionPattern(fnType); - - // Don't implicitly turn non-optional results to optional if - // we're going to apply a foreign error convention that checks - // for nil results. - if (auto method = dyn_cast(clangDecl)) { - assert(numParameterLists == 2 && "getting curried ObjC method type?"); - auto foreignError = bridgedFn->getForeignErrorConvention(); - return AbstractionPattern::getCurriedObjCMethod(fnType, method, - foreignError); - } else if (auto value = dyn_cast(clangDecl)) { - if (numParameterLists == 1) { - // C function imported as a function. - return AbstractionPattern(fnType, value->getType().getTypePtr()); - } else { - assert(numParameterLists == 2); - if (auto method = dyn_cast(clangDecl)) { - // C++ method. - return AbstractionPattern::getCurriedCXXMethod(fnType, bridgedFn); - } else { - // C function imported as a method. - return AbstractionPattern::getCurriedCFunctionAsMethod(fnType, - bridgedFn); - } - } - } - - return AbstractionPattern(fnType); -} - -TypeConverter::LoweredFormalTypes -TypeConverter::getLoweredFormalTypes(SILDeclRef constant, - CanAnyFunctionType fnType) { - // We always use full bridging when importing a constant because we can - // directly bridge its arguments and results when calling it. - auto bridging = Bridgeability::Full; - - unsigned numParameterLists = constant.getParameterListCount(); - auto extInfo = fnType->getExtInfo(); - - // Form an abstraction pattern for bridging purposes. - AbstractionPattern bridgingFnPattern = - getAbstractionPatternForConstant(Context, constant, fnType, - numParameterLists); - - // Fast path: no uncurrying required. - if (numParameterLists == 1) { - auto bridgedFnType = - getBridgedFunctionType(bridgingFnPattern, fnType, extInfo, bridging); - bridgingFnPattern.rewriteType(bridgingFnPattern.getGenericSignature(), - bridgedFnType); - return { bridgingFnPattern, bridgedFnType }; - } - - SILFunctionTypeRepresentation rep = extInfo.getSILRepresentation(); - assert(rep != SILFunctionType::Representation::Block - && "objc blocks cannot be curried"); - - // The dependent generic signature. - CanGenericSignature genericSig = fnType.getOptGenericSignature(); - - // The 'self' parameter. - assert(fnType.getParams().size() == 1); - AnyFunctionType::Param selfParam = fnType.getParams()[0]; - - // The formal method parameters. - // If we actually partially-apply this, assume we'll need a thick function. - fnType = cast(fnType.getResult()); - auto innerExtInfo = - fnType->getExtInfo().withRepresentation(FunctionTypeRepresentation::Swift); - auto methodParams = fnType->getParams(); - - auto resultType = fnType.getResult(); - bool suppressOptionalResult = - bridgingFnPattern.hasForeignErrorStrippingResultOptionality(); - - // Bridge input and result types. - SmallVector bridgedParams; - CanType bridgedResultType; - - switch (rep) { - case SILFunctionTypeRepresentation::Thin: - case SILFunctionTypeRepresentation::Thick: - case SILFunctionTypeRepresentation::Method: - case SILFunctionTypeRepresentation::Closure: - case SILFunctionTypeRepresentation::WitnessMethod: - // Native functions don't need bridging. - bridgedParams.append(methodParams.begin(), methodParams.end()); - bridgedResultType = resultType; - break; - - case SILFunctionTypeRepresentation::ObjCMethod: - case SILFunctionTypeRepresentation::CFunctionPointer: { - if (rep == SILFunctionTypeRepresentation::ObjCMethod) { - // The "self" parameter should not get bridged unless it's a metatype. - if (selfParam.getPlainType()->is()) { - auto selfPattern = bridgingFnPattern.getFunctionParamType(0); - selfParam = getBridgedParam(rep, selfPattern, selfParam, bridging); - } - } - - auto partialFnPattern = bridgingFnPattern.getFunctionResultType(); - getBridgedParams(rep, partialFnPattern, methodParams, bridgedParams, - bridging); - - bridgedResultType = - getBridgedResultType(rep, - partialFnPattern.getFunctionResultType(), - resultType, bridging, suppressOptionalResult); - break; - } - - case SILFunctionTypeRepresentation::Block: - llvm_unreachable("Cannot uncurry native representation"); - } - - // Build the curried function type. - auto inner = - CanFunctionType::get(llvm::makeArrayRef(bridgedParams), - bridgedResultType, innerExtInfo); - - auto curried = - CanAnyFunctionType::get(genericSig, {selfParam}, inner, extInfo); - - // Replace the type in the abstraction pattern with the curried type. - bridgingFnPattern.rewriteType(genericSig, curried); - - // Build the uncurried function type. - if (innerExtInfo.throws()) - extInfo = extInfo.withThrows(true); - - bridgedParams.push_back(selfParam); - - auto uncurried = - CanAnyFunctionType::get(genericSig, - llvm::makeArrayRef(bridgedParams), - bridgedResultType, - extInfo); - - return { bridgingFnPattern, uncurried }; -} - -// TODO: We should compare generic signatures. Class and witness methods -// allow variance in "self"-fulfilled parameters; other functions must -// match exactly. -// TODO: More sophisticated param and return ABI compatibility rules could -// diverge. -static bool areABICompatibleParamsOrReturns(SILType a, SILType b, - SILFunction *inFunction) { - // Address parameters are all ABI-compatible, though the referenced - // values may not be. Assume whoever's doing this knows what they're - // doing. - if (a.isAddress() && b.isAddress()) - return true; - - // Addresses aren't compatible with values. - // TODO: An exception for pointerish types? - if (a.isAddress() || b.isAddress()) - return false; - - // Tuples are ABI compatible if their elements are. - // TODO: Should destructure recursively. - SmallVector aElements, bElements; - if (auto tup = a.getAs()) { - auto types = tup.getElementTypes(); - aElements.append(types.begin(), types.end()); - } else { - aElements.push_back(a.getASTType()); - } - if (auto tup = b.getAs()) { - auto types = tup.getElementTypes(); - bElements.append(types.begin(), types.end()); - } else { - bElements.push_back(b.getASTType()); - } - - if (aElements.size() != bElements.size()) - return false; - - for (unsigned i : indices(aElements)) { - auto aa = SILType::getPrimitiveObjectType(aElements[i]); - auto bb = SILType::getPrimitiveObjectType(bElements[i]); - // Equivalent types are always ABI-compatible. - if (aa == bb) - continue; - - // Opaque types are compatible with their substitution. - if (inFunction) { - auto opaqueTypesSubsituted = aa; - auto *dc = inFunction->getDeclContext(); - auto *currentModule = inFunction->getModule().getSwiftModule(); - if (!dc || !dc->isChildContextOf(currentModule)) - dc = currentModule; - ReplaceOpaqueTypesWithUnderlyingTypes replacer( - dc, inFunction->getResilienceExpansion(), - inFunction->getModule().isWholeModule()); - if (aa.getASTType()->hasOpaqueArchetype()) - opaqueTypesSubsituted = aa.subst(inFunction->getModule(), replacer, - replacer, CanGenericSignature(), true); - - auto opaqueTypesSubsituted2 = bb; - if (bb.getASTType()->hasOpaqueArchetype()) - opaqueTypesSubsituted2 = - bb.subst(inFunction->getModule(), replacer, replacer, - CanGenericSignature(), true); - if (opaqueTypesSubsituted == opaqueTypesSubsituted2) - continue; - } - - // FIXME: If one or both types are dependent, we can't accurately assess - // whether they're ABI-compatible without a generic context. We can - // do a better job here when dependent types are related to their - // generic signatures. - if (aa.hasTypeParameter() || bb.hasTypeParameter()) - continue; - - // Bridgeable object types are interchangeable. - if (aa.isBridgeableObjectType() && bb.isBridgeableObjectType()) - continue; - - // Optional and IUO are interchangeable if their elements are. - auto aObject = aa.getOptionalObjectType(); - auto bObject = bb.getOptionalObjectType(); - if (aObject && bObject && - areABICompatibleParamsOrReturns(aObject, bObject, inFunction)) - continue; - // Optional objects are ABI-interchangeable with non-optionals; - // None is represented by a null pointer. - if (aObject && aObject.isBridgeableObjectType() && - bb.isBridgeableObjectType()) - continue; - if (bObject && bObject.isBridgeableObjectType() && - aa.isBridgeableObjectType()) - continue; - - // Optional thick metatypes are ABI-interchangeable with non-optionals - // too. - if (aObject) - if (auto aObjMeta = aObject.getAs()) - if (auto bMeta = bb.getAs()) - if (aObjMeta->getRepresentation() == bMeta->getRepresentation() && - bMeta->getRepresentation() != MetatypeRepresentation::Thin) - continue; - if (bObject) - if (auto aMeta = aa.getAs()) - if (auto bObjMeta = bObject.getAs()) - if (aMeta->getRepresentation() == bObjMeta->getRepresentation() && - aMeta->getRepresentation() != MetatypeRepresentation::Thin) - continue; - - // Function types are interchangeable if they're also ABI-compatible. - if (auto aFunc = aa.getAs()) { - if (auto bFunc = bb.getAs()) { - // *NOTE* We swallow the specific error here for now. We will still get - // that the function types are incompatible though, just not more - // specific information. - return aFunc->isABICompatibleWith(bFunc, *inFunction).isCompatible(); - } - } - - // Metatypes are interchangeable with metatypes with the same - // representation. - if (auto aMeta = aa.getAs()) { - if (auto bMeta = bb.getAs()) { - if (aMeta->getRepresentation() == bMeta->getRepresentation()) - continue; - } - } - // Other types must match exactly. - return false; - } - - return true; -} - -namespace { -using ABICompatibilityCheckResult = - SILFunctionType::ABICompatibilityCheckResult; -} // end anonymous namespace - -ABICompatibilityCheckResult -SILFunctionType::isABICompatibleWith(CanSILFunctionType other, - SILFunction &context) const { - // The calling convention and function representation can't be changed. - if (getRepresentation() != other->getRepresentation()) - return ABICompatibilityCheckResult::DifferentFunctionRepresentations; - - // Check the results. - if (getNumResults() != other->getNumResults()) - return ABICompatibilityCheckResult::DifferentNumberOfResults; - - for (unsigned i : indices(getResults())) { - auto result1 = getResults()[i]; - auto result2 = other->getResults()[i]; - - if (result1.getConvention() != result2.getConvention()) - return ABICompatibilityCheckResult::DifferentReturnValueConventions; - - if (!areABICompatibleParamsOrReturns( - result1.getSILStorageType(context.getModule(), this), - result2.getSILStorageType(context.getModule(), other), - &context)) { - return ABICompatibilityCheckResult::ABIIncompatibleReturnValues; - } - } - - // Our error result conventions are designed to be ABI compatible - // with functions lacking error results. Just make sure that the - // actual conventions match up. - if (hasErrorResult() && other->hasErrorResult()) { - auto error1 = getErrorResult(); - auto error2 = other->getErrorResult(); - if (error1.getConvention() != error2.getConvention()) - return ABICompatibilityCheckResult::DifferentErrorResultConventions; - - if (!areABICompatibleParamsOrReturns( - error1.getSILStorageType(context.getModule(), this), - error2.getSILStorageType(context.getModule(), other), - &context)) - return ABICompatibilityCheckResult::ABIIncompatibleErrorResults; - } - - // Check the parameters. - // TODO: Could allow known-empty types to be inserted or removed, but SIL - // doesn't know what empty types are yet. - if (getParameters().size() != other->getParameters().size()) - return ABICompatibilityCheckResult::DifferentNumberOfParameters; - - for (unsigned i : indices(getParameters())) { - auto param1 = getParameters()[i]; - auto param2 = other->getParameters()[i]; - - if (param1.getConvention() != param2.getConvention()) - return {ABICompatibilityCheckResult::DifferingParameterConvention, i}; - if (!areABICompatibleParamsOrReturns( - param1.getSILStorageType(context.getModule(), this), - param2.getSILStorageType(context.getModule(), other), - &context)) - return {ABICompatibilityCheckResult::ABIIncompatibleParameterType, i}; - } - - // This needs to be checked last because the result implies everying else has - // already been checked and this is the only difference. - if (isNoEscape() != other->isNoEscape() && - (getRepresentation() == SILFunctionType::Representation::Thick)) - return ABICompatibilityCheckResult::ABIEscapeToNoEscapeConversion; - - return ABICompatibilityCheckResult::None; -} - -StringRef SILFunctionType::ABICompatibilityCheckResult::getMessage() const { - switch (kind) { - case innerty::None: - return "None"; - case innerty::DifferentFunctionRepresentations: - return "Different function representations"; - case innerty::DifferentNumberOfResults: - return "Different number of results"; - case innerty::DifferentReturnValueConventions: - return "Different return value conventions"; - case innerty::ABIIncompatibleReturnValues: - return "ABI incompatible return values"; - case innerty::DifferentErrorResultConventions: - return "Different error result conventions"; - case innerty::ABIIncompatibleErrorResults: - return "ABI incompatible error results"; - case innerty::DifferentNumberOfParameters: - return "Different number of parameters"; - - // These two have to do with specific parameters, so keep the error message - // non-plural. - case innerty::DifferingParameterConvention: - return "Differing parameter convention"; - case innerty::ABIIncompatibleParameterType: - return "ABI incompatible parameter type."; - case innerty::ABIEscapeToNoEscapeConversion: - return "Escape to no escape conversion"; - } - llvm_unreachable("Covered switch isn't completely covered?!"); -} - -static DeclContext *getDeclContextForExpansion(const SILFunction &f) { - auto *dc = f.getDeclContext(); - if (!dc) - dc = f.getModule().getSwiftModule(); - auto *currentModule = f.getModule().getSwiftModule(); - if (!dc || !dc->isChildContextOf(currentModule)) - dc = currentModule; - return dc; -} - -TypeExpansionContext::TypeExpansionContext(const SILFunction &f) - : expansion(f.getResilienceExpansion()), - inContext(getDeclContextForExpansion(f)), - isContextWholeModule(f.getModule().isWholeModule()) {} - -CanSILFunctionType SILFunction::getLoweredFunctionTypeInContext( - TypeExpansionContext context) const { - auto origFunTy = getLoweredFunctionType(); - auto &M = getModule(); - auto funTy = M.Types.getLoweredType(origFunTy , context); - return cast(funTy.getASTType()); -} diff --git a/test/Interop/Cxx/class/Inputs/type-classification.h b/test/Interop/Cxx/class/Inputs/type-classification.h index 09322bb5d0d1e..176e22e1701af 100644 --- a/test/Interop/Cxx/class/Inputs/type-classification.h +++ b/test/Interop/Cxx/class/Inputs/type-classification.h @@ -157,6 +157,8 @@ struct StructDeletedDestructor { struct StructWithCopyConstructorAndValue { int value; + StructWithCopyConstructorAndValue() : value(0) {} + StructWithCopyConstructorAndValue(int value) : value(value) {} StructWithCopyConstructorAndValue( const StructWithCopyConstructorAndValue &other) : value(other.value) {} @@ -168,6 +170,9 @@ struct StructWithSubobjectCopyConstructorAndValue { struct StructWithCopyConstructorAndSubobjectCopyConstructorAndValue { StructWithCopyConstructorAndValue member; + StructWithCopyConstructorAndSubobjectCopyConstructorAndValue( + StructWithCopyConstructorAndValue member) + : member(member) {} StructWithCopyConstructorAndSubobjectCopyConstructorAndValue( const StructWithCopyConstructorAndSubobjectCopyConstructorAndValue &other) : member(other.member) {} diff --git a/test/Interop/Cxx/class/constructors-irgen.swift b/test/Interop/Cxx/class/constructors-irgen.swift index cb98844dbf3a2..75b1c015c403a 100644 --- a/test/Interop/Cxx/class/constructors-irgen.swift +++ b/test/Interop/Cxx/class/constructors-irgen.swift @@ -5,8 +5,11 @@ // RUN: %swift -module-name Swift -target x86_64-unknown-windows-msvc -dump-clang-diagnostics -I %S/Inputs -enable-cxx-interop -emit-ir %s -parse-stdlib -parse-as-library -disable-legacy-type-info | %FileCheck %s -check-prefix=MICROSOFT_X64 import Constructors +import TypeClassification typealias Void = () +struct UnsafePointer { } +struct UnsafeMutablePointer { } public func createHasVirtualBase() -> HasVirtualBase { // - The `this` parameter should carry a `noalias` attribute, as it is @@ -58,3 +61,34 @@ public func createImplicitDefaultConstructor() -> ImplicitDefaultConstructor { // MICROSOFT_X64: call %struct.ImplicitDefaultConstructor* @"??0ImplicitDefaultConstructor@@QEAA@XZ"(%struct.ImplicitDefaultConstructor* %{{[0-9]+}}) return ImplicitDefaultConstructor() } + +public func createStructWithSubobjectCopyConstructorAndValue() { + // ITANIUM_X64-LABEL: define swiftcc void @"$ss48createStructWithSubobjectCopyConstructorAndValueyyF"() + // ITANIUM_X64: [[MEMBER:%.*]] = alloca %TSo33StructWithCopyConstructorAndValueV + // ITANIUM_X64: [[MEMBER_AS_STRUCT:%.*]] = bitcast %TSo33StructWithCopyConstructorAndValueV* %member to %struct.StructWithCopyConstructorAndValue* + // ITANIUM_X64: void @_ZN33StructWithCopyConstructorAndValueC1Ev(%struct.StructWithCopyConstructorAndValue* noalias [[MEMBER_AS_STRUCT]]) + // ITANIUM_X64: call %TSo33StructWithCopyConstructorAndValueV* @"$sSo33StructWithCopyConstructorAndValueVWOc"(%TSo33StructWithCopyConstructorAndValueV* [[MEMBER]], %TSo33StructWithCopyConstructorAndValueV* [[TMP:%.*]]) + // ITANIUM_X64: [[OBJ_MEMBER:%.*]] = getelementptr inbounds %TSo42StructWithSubobjectCopyConstructorAndValueV, %TSo42StructWithSubobjectCopyConstructorAndValueV* %obj, i32 0, i32 0 + // ITANIUM_X64: call %TSo33StructWithCopyConstructorAndValueV* @"$sSo33StructWithCopyConstructorAndValueVWOb"(%TSo33StructWithCopyConstructorAndValueV* [[TMP]], %TSo33StructWithCopyConstructorAndValueV* [[OBJ_MEMBER]]) + // ITANIUM_X64: ret void + + // ITANIUM_ARM-LABEL: define protected swiftcc void @"$ss48createStructWithSubobjectCopyConstructorAndValueyyF"() + // ITANIUM_ARM: [[MEMBER:%.*]] = alloca %TSo33StructWithCopyConstructorAndValueV + // ITANIUM_ARM: [[MEMBER_AS_STRUCT:%.*]] = bitcast %TSo33StructWithCopyConstructorAndValueV* %member to %struct.StructWithCopyConstructorAndValue* + // ITANIUM_ARM: call %struct.StructWithCopyConstructorAndValue* @_ZN33StructWithCopyConstructorAndValueC2Ev(%struct.StructWithCopyConstructorAndValue* [[MEMBER_AS_STRUCT]]) + // ITANIUM_ARM: call %TSo33StructWithCopyConstructorAndValueV* @"$sSo33StructWithCopyConstructorAndValueVWOc"(%TSo33StructWithCopyConstructorAndValueV* [[MEMBER]], %TSo33StructWithCopyConstructorAndValueV* [[TMP:%.*]]) + // ITANIUM_ARM: [[OBJ_MEMBER:%.*]] = getelementptr inbounds %TSo42StructWithSubobjectCopyConstructorAndValueV, %TSo42StructWithSubobjectCopyConstructorAndValueV* %obj, i32 0, i32 0 + // ITANIUM_ARM: call %TSo33StructWithCopyConstructorAndValueV* @"$sSo33StructWithCopyConstructorAndValueVWOb"(%TSo33StructWithCopyConstructorAndValueV* [[TMP]], %TSo33StructWithCopyConstructorAndValueV* [[OBJ_MEMBER]]) + // ITANIUM_ARM: ret void + + // MICROSOFT_X64-LABEL: define dllexport swiftcc void @"$ss48createStructWithSubobjectCopyConstructorAndValueyyF"() + // MICROSOFT_X64: [[MEMBER:%.*]] = alloca %TSo33StructWithCopyConstructorAndValueV + // MICROSOFT_X64: [[MEMBER_AS_STRUCT:%.*]] = bitcast %TSo33StructWithCopyConstructorAndValueV* %member to %struct.StructWithCopyConstructorAndValue* + // MICROSOFT_X64: call %struct.StructWithCopyConstructorAndValue* @"??0StructWithCopyConstructorAndValue@@QEAA@XZ"(%struct.StructWithCopyConstructorAndValue* [[MEMBER_AS_STRUCT]]) + // MICROSOFT_X64: call %TSo33StructWithCopyConstructorAndValueV* @"$sSo33StructWithCopyConstructorAndValueVWOc"(%TSo33StructWithCopyConstructorAndValueV* [[MEMBER]], %TSo33StructWithCopyConstructorAndValueV* [[TMP:%.*]]) + // MICROSOFT_X64: [[OBJ_MEMBER:%.*]] = getelementptr inbounds %TSo42StructWithSubobjectCopyConstructorAndValueV, %TSo42StructWithSubobjectCopyConstructorAndValueV* %obj, i32 0, i32 0 + // MICROSOFT_X64: call %TSo33StructWithCopyConstructorAndValueV* @"$sSo33StructWithCopyConstructorAndValueVWOb"(%TSo33StructWithCopyConstructorAndValueV* [[TMP]], %TSo33StructWithCopyConstructorAndValueV* [[OBJ_MEMBER]]) + // MICROSOFT_X64: ret void + let member = StructWithCopyConstructorAndValue() + let obj = StructWithSubobjectCopyConstructorAndValue(member: member) +} diff --git a/test/Interop/Cxx/class/synthesized-initializers-silgen.swift b/test/Interop/Cxx/class/synthesized-initializers-silgen.swift index ea74f8ab4eecb..8b84f18bb1569 100644 --- a/test/Interop/Cxx/class/synthesized-initializers-silgen.swift +++ b/test/Interop/Cxx/class/synthesized-initializers-silgen.swift @@ -2,36 +2,26 @@ import SynthesizedInitializers -// CHECK-LABEL: sil shared [transparent] [serializable] [ossa] @$sSo11EmptyStructVABycfC : $@convention(method) (@thin EmptyStruct.Type) -> EmptyStruct -// CHECK: bb0(%{{[0-9]+}} : $@thin EmptyStruct.Type): -// CHECK-NEXT: [[BOX:%.*]] = alloc_box ${ var EmptyStruct } -// CHECK-NEXT: [[UNINIT:%.*]] = mark_uninitialized [rootself] [[BOX]] : ${ var EmptyStruct } -// CHECK-NEXT: [[PTR:%.*]] = project_box [[UNINIT]] : ${ var EmptyStruct }, 0 -// CHECK-NEXT: [[OBJ:%.*]] = builtin "zeroInitializer"() : $EmptyStruct -// CHECK-NEXT: [[PA:%.*]] = begin_access [modify] [unknown] [[PTR]] : $*EmptyStruct -// CHECK-NEXT: assign [[OBJ]] to [[PA]] -// CHECK-NEXT: end_access [[PA]] -// CHECK-NEXT: [[OUT:%.*]] = load [trivial] [[PTR]] -// CHECK-NEXT: destroy_value [[UNINIT]] -// CHECK-NEXT: return [[OUT]] -// CHECK-LABEL: end sil function '$sSo11EmptyStructVABycfC' +// CHECK-LABEL: sil [ossa] @$s4main18emptyTypeNoArgInityyF : $@convention(thin) () -> () +// CHECK: [[AS:%.*]] = alloc_stack $EmptyStruct +// CHECK: [[META:%.*]] = metatype $@thin EmptyStruct.Type +// CHECK: [[FN:%.*]] = function_ref @{{_ZN11EmptyStructC1Ev|\?\?0EmptyStruct@@QEAA@XZ}} : $@convention(c) (@thin EmptyStruct.Type) -> @out EmptyStruct +// CHECK: apply [[FN]]([[AS]], [[META]]) : $@convention(c) (@thin EmptyStruct.Type) -> @out EmptyStruct +// CHECK-LABEL: end sil function '$s4main18emptyTypeNoArgInityyF' + +// CHECL-LABEL: sil [clang EmptyStruct.init] @{{_ZN11EmptyStructC1Ev|\?\?0EmptyStruct@@QEAA@XZ}} : $@convention(c) (@thin EmptyStruct.Type) -> @out EmptyStruct public func emptyTypeNoArgInit() { let e = EmptyStruct() } -// CHECK-LABEL: sil shared [transparent] [serializable] [ossa] @$sSo6IntBoxVABycfC : $@convention(method) (@thin IntBox.Type) -> IntBox -// CHECK: bb0(%{{[0-9]+}} : $@thin IntBox.Type): -// CHECK-NEXT: [[BOX:%.*]] = alloc_box ${ var IntBox } -// CHECK-NEXT: [[UNINIT:%.*]] = mark_uninitialized [rootself] [[BOX]] : ${ var IntBox } -// CHECK-NEXT: [[PTR:%.*]] = project_box [[UNINIT]] : ${ var IntBox }, 0 -// CHECK-NEXT: [[OBJ:%.*]] = builtin "zeroInitializer"() : $IntBox -// CHECK-NEXT: [[PA:%.*]] = begin_access [modify] [unknown] [[PTR]] : $*IntBox -// CHECK-NEXT: assign [[OBJ]] to [[PA]] -// CHECK-NEXT: end_access [[PA]] -// CHECK-NEXT: [[OUT:%.*]] = load [trivial] [[PTR]] -// CHECK-NEXT: destroy_value [[UNINIT]] -// CHECK-NEXT: return [[OUT]] -// CHECK-LABEL: end sil function '$sSo6IntBoxVABycfC' +// CHECK-LABEL: sil [ossa] @$s4main25singleMemberTypeNoArgInityyF : $@convention(thin) () -> () +// CHECK: [[AS:%.*]] = alloc_stack $IntBox +// CHECK: [[META:%.*]] = metatype $@thin IntBox.Type +// CHECK: [[FN:%.*]] = function_ref @{{_ZN6IntBoxC1Ev|\?\?0IntBox@@QEAA@XZ}} : $@convention(c) (@thin IntBox.Type) -> @out IntBox +// CHECK: apply [[FN]]([[AS]], [[META]]) : $@convention(c) (@thin IntBox.Type) -> @out IntBox +// CHECK-LABEL: end sil function '$s4main25singleMemberTypeNoArgInityyF' + +//CHECK-LABEL: sil [clang IntBox.init] @{{_ZN6IntBoxC1Ev|\?\?0IntBox@@QEAA@XZ}} : $@convention(c) (@thin IntBox.Type) -> @out IntBox public func singleMemberTypeNoArgInit() { let i = IntBox() } diff --git a/test/Interop/Cxx/class/type-classification-non-trivial-irgen.swift b/test/Interop/Cxx/class/type-classification-non-trivial-irgen.swift index c0a48574a1493..501b444fa4774 100644 --- a/test/Interop/Cxx/class/type-classification-non-trivial-irgen.swift +++ b/test/Interop/Cxx/class/type-classification-non-trivial-irgen.swift @@ -12,12 +12,15 @@ import TypeClassification // CHECK-LABEL: define {{.*}}i1 @"$s4main37testStructWithCopyConstructorAndValueSbyF" // CHECK: [[OBJ:%.*]] = alloca %TSo33StructWithCopyConstructorAndValueV -// CHECK: [[VAL_ELEMENT:%.*]] = getelementptr inbounds %TSo33StructWithCopyConstructorAndValueV, %TSo33StructWithCopyConstructorAndValueV* [[OBJ]], i32 0, i32 0 -// CHECK: [[VAL_INT:%.*]] = getelementptr inbounds %Ts5Int32V, %Ts5Int32V* [[VAL_ELEMENT]], i32 0, i32 0 -// CHECK: store i32 42, i32* [[VAL_INT]] -// CHECK: ret i1 true +// CHECK: [[STRUCT:%.*]] = bitcast %TSo33StructWithCopyConstructorAndValueV* [[OBJ]] to %struct.StructWithCopyConstructorAndValue* +// CHECK: call void @{{_ZN33StructWithCopyConstructorAndValueC(1|2)Ei|"\?\?0StructWithCopyConstructorAndValue@@QEAA@H@Z"}}(%struct.StructWithCopyConstructorAndValue* noalias [[STRUCT]], i32 42) +// CHECK: [[OBJ_VAL:%.*]] = getelementptr inbounds %TSo33StructWithCopyConstructorAndValueV, %TSo33StructWithCopyConstructorAndValueV* [[OBJ]], i32 0, i32 0 +// CHECK: [[I_VAL:%.*]] = getelementptr inbounds %Ts5Int32V, %Ts5Int32V* [[OBJ_VAL]], i32 0, i32 0 +// CHECK: [[I_VAL_VAL:%.*]] = load i32, i32* [[OBJ_VAL]] +// CHECK: [[OUT:%.*]] = icmp eq i32 [[I_VAL_VAL]], 42 +// CHECK: ret i1 [[OUT]] public func testStructWithCopyConstructorAndValue() -> Bool { - let obj = StructWithCopyConstructorAndValue(value: 42) + let obj = StructWithCopyConstructorAndValue(42) return obj.value == 42 } @@ -26,38 +29,39 @@ public func testStructWithCopyConstructorAndValue() -> Bool { // CHECK: [[OBJ:%.*]] = alloca %TSo42StructWithSubobjectCopyConstructorAndValueV // CHECK: alloca %TSo33StructWithCopyConstructorAndValueV // CHECK: [[TMP:%.*]] = alloca %TSo33StructWithCopyConstructorAndValueV -// CHECK: [[MEMBER_ELEMENT:%.*]] = getelementptr inbounds %TSo33StructWithCopyConstructorAndValueV, %TSo33StructWithCopyConstructorAndValueV* [[MEMBER]], i32 0, i32 0 -// CHECK: [[MEMBER_VALUE:%.*]] = getelementptr inbounds %Ts5Int32V, %Ts5Int32V* [[MEMBER_ELEMENT]], i32 0, i32 0 -// CHECK: store i32 42, i32* [[MEMBER_VALUE]] +// CHECK: [[MEMBER_STRUCT:%.*]] = bitcast %TSo33StructWithCopyConstructorAndValueV* %member to %struct.StructWithCopyConstructorAndValue* +// CHECK: call void @{{_ZN33StructWithCopyConstructorAndValueC(1|2)Ei|"\?\?0StructWithCopyConstructorAndValue@@QEAA@H@Z"}}(%struct.StructWithCopyConstructorAndValue* noalias [[MEMBER_STRUCT]], i32 42) // CHECK: [[TEMP_MEMBER:%.*]] = getelementptr inbounds %TSo33StructWithCopyConstructorAndValueV, %TSo33StructWithCopyConstructorAndValueV* [[TMP]], i32 0, i32 0 // CHECK: [[TEMP_MEMBER_VALUE:%.*]] = getelementptr inbounds %Ts5Int32V, %Ts5Int32V* [[TEMP_MEMBER]], i32 0, i32 0 // CHECK: [[LHS:%.*]] = load i32, i32* [[TEMP_MEMBER_VALUE]] // CHECK: [[OUT:%.*]] = icmp eq i32 [[LHS]], 42 // CHECK: ret i1 [[OUT]] public func testStructWithSubobjectCopyConstructorAndValue() -> Bool { - let member = StructWithCopyConstructorAndValue(value: 42) + let member = StructWithCopyConstructorAndValue(42) let obj = StructWithSubobjectCopyConstructorAndValue(member: member) return obj.member.value == 42 } // CHECK-LABEL: define {{.*}}i1 @"$s4main041testStructWithCopyConstructorAndSubobjectefG5ValueSbyF"() // CHECK: [[MEMBER:%.*]] = alloca %TSo33StructWithCopyConstructorAndValueV -// CHECK: alloca %TSo037StructWithCopyConstructorAndSubobjectcdE5ValueV -// CHECK: alloca %TSo33StructWithCopyConstructorAndValueV +// CHECK: [[OBJ:%.*]] = alloca %TSo037StructWithCopyConstructorAndSubobjectcdE5ValueV // CHECK: [[TEMP:%.*]] = alloca %TSo33StructWithCopyConstructorAndValueV -// CHECK: [[MEMBER_VAL:%.*]] = getelementptr inbounds %TSo33StructWithCopyConstructorAndValueV, %TSo33StructWithCopyConstructorAndValueV* [[MEMBER]], i32 0, i32 0 -// CHECK: [[MEMBER_VAL_VAL:%.*]] = getelementptr inbounds %Ts5Int32V, %Ts5Int32V* [[MEMBER_VAL]], i32 0, i32 0 -// CHECK: store i32 42, i32* [[MEMBER_VAL_VAL]] -// CHECK: [[TEMP_MEMBER:%.*]] = getelementptr inbounds %TSo33StructWithCopyConstructorAndValueV, %TSo33StructWithCopyConstructorAndValueV* [[TEMP]], i32 0, i32 0 +// CHECK: [[TEMP2:%.*]] = alloca %TSo33StructWithCopyConstructorAndValueV +// CHECK: [[MEMBER_STRUCT:%.*]] = bitcast %TSo33StructWithCopyConstructorAndValueV* %member to %struct.StructWithCopyConstructorAndValue* +// CHECK: call void @{{_ZN33StructWithCopyConstructorAndValueC(1|2)Ei|"\?\?0StructWithCopyConstructorAndValue@@QEAA@H@Z"}}(%struct.StructWithCopyConstructorAndValue* noalias [[MEMBER_STRUCT]], i32 42) +// CHECK: [[TEMP_AS_STRUCT:%.*]] = bitcast %TSo33StructWithCopyConstructorAndValueV* [[TEMP]] to %struct.StructWithCopyConstructorAndValue* +// CHECK: [[OBJ_AS_STRUCT:%.*]] = bitcast %TSo037StructWithCopyConstructorAndSubobjectcdE5ValueV* [[OBJ]] to %struct.StructWithCopyConstructorAndSubobjectCopyConstructorAndValue* +// CHECK: call void @{{_ZN60StructWithCopyConstructorAndSubobjectCopyConstructorAndValueC(1|2)E33StructWithCopyConstructorAndValue|"\?\?0StructWithCopyConstructorAndSubobjectCopyConstructorAndValue@@QEAA@UStructWithCopyConstructorAndValue@@@Z"}}(%struct.StructWithCopyConstructorAndSubobjectCopyConstructorAndValue* noalias [[OBJ_AS_STRUCT]], %struct.StructWithCopyConstructorAndValue* [[TEMP_AS_STRUCT]]) +// CHECK: [[TEMP_MEMBER:%.*]] = getelementptr inbounds %TSo33StructWithCopyConstructorAndValueV, %TSo33StructWithCopyConstructorAndValueV* [[TEMP2]], i32 0, i32 0 // CHECK: [[TEMP_MEMBER_VAL:%.*]] = getelementptr inbounds %Ts5Int32V, %Ts5Int32V* [[TEMP_MEMBER]], i32 0, i32 0 // CHECK: [[LHS:%.*]] = load i32, i32* [[TEMP_MEMBER_VAL]] // CHECK: [[OUT:%.*]] = icmp eq i32 [[LHS]], 42 // CHECK: ret i1 [[OUT]] public func testStructWithCopyConstructorAndSubobjectCopyConstructorAndValue() -> Bool { - let member = StructWithCopyConstructorAndValue(value: 42) + let member = StructWithCopyConstructorAndValue(42) let obj = StructWithCopyConstructorAndSubobjectCopyConstructorAndValue( - member: member + member ) return obj.member.value == 42 } diff --git a/test/Interop/Cxx/class/type-classification-non-trivial-silgen.swift b/test/Interop/Cxx/class/type-classification-non-trivial-silgen.swift index 87766b5a01bdb..88a7253e17f19 100644 --- a/test/Interop/Cxx/class/type-classification-non-trivial-silgen.swift +++ b/test/Interop/Cxx/class/type-classification-non-trivial-silgen.swift @@ -7,59 +7,37 @@ import TypeClassification // CHECK-LABEL: sil [ossa] @$s4main24testStructWithDestructoryyF // CHECK: [[AS:%.*]] = alloc_stack $StructWithDestructor // CHECK: [[META:%.*]] = metatype $@thin StructWithDestructor.Type -// CHECK: [[FN:%.*]] = function_ref @$sSo20StructWithDestructorVABycfC : $@convention(method) (@thin StructWithDestructor.Type) -> @out StructWithDestructor -// CHECK: apply [[FN]]([[AS]], [[META]]) : $@convention(method) (@thin StructWithDestructor.Type) -> @out StructWithDestructor +// CHECK: [[FN:%.*]] = function_ref @{{_ZN20StructWithDestructorC1Ev|\?\?0StructWithDestructor@@QEAA@XZ}} : $@convention(c) (@thin StructWithDestructor.Type) -> @out StructWithDestructor +// CHECK: apply [[FN]]([[AS]], [[META]]) : $@convention(c) (@thin StructWithDestructor.Type) -> @out StructWithDestructor // CHECK: destroy_addr [[AS]] // CHECK: dealloc_stack %0 : $*StructWithDestructor // CHECK-LABEL: end sil function '$s4main24testStructWithDestructoryyF' + +// CHECK-LABEL: sil [clang StructWithDestructor.init] @{{_ZN20StructWithDestructorC1Ev|\?\?0StructWithDestructor@@QEAA@XZ}} : $@convention(c) (@thin StructWithDestructor.Type) -> @out StructWithDestructor public func testStructWithDestructor() { let d = StructWithDestructor() } -// StructWithDestructor.init() -// CHECK-LABEL: sil shared [transparent] [serializable] [ossa] @$sSo20StructWithDestructorVABycfC : $@convention(method) (@thin StructWithDestructor.Type) -> @out StructWithDestructor -// CHECK: [[BOX:%.*]] = alloc_box ${ var StructWithDestructor } -// CHECK: [[UBOX:%.*]] = mark_uninitialized [rootself] [[BOX]] : ${ var StructWithDestructor } -// CHECK: [[BOX_ADDR:%.*]] = project_box [[UBOX]] : ${ var StructWithDestructor }, 0 -// CHECK: [[SA:%.*]] = alloc_stack $StructWithDestructor -// CHECK: builtin "zeroInitializer"([[SA]] : $*StructWithDestructor) : $() -// CHECK: [[BA:%.*]] = begin_access [modify] [unknown] [[BOX_ADDR]] : $*StructWithDestructor -// CHECK: copy_addr [take] [[SA]] to [[BA]] : $*StructWithDestructor -// CHECK: copy_addr [[BOX_ADDR]] to [initialization] %0 : $*StructWithDestructor -// CHECK: destroy_value [[UBOX]] : ${ var StructWithDestructor } -// CHECK-LABEL: end sil function '$sSo20StructWithDestructorVABycfC' - // Make sure that "HasMemberWithDestructor" is marked as non-trivial by checking // for a "destroy_addr". -// CHECK-LABEL: sil [ossa] @$s4main33testStructWithSubobjectDestructoryyF +// CHECK-LABEL: sil [ossa] @$s4main33testStructWithSubobjectDestructoryyF : $@convention(thin) () -> () // CHECK: [[AS:%.*]] = alloc_stack $StructWithSubobjectDestructor // CHECK: [[META:%.*]] = metatype $@thin StructWithSubobjectDestructor.Type -// CHECK: [[FN:%.*]] = function_ref @$sSo29StructWithSubobjectDestructorVABycfC : $@convention(method) (@thin StructWithSubobjectDestructor.Type) -> @out StructWithSubobjectDestructor -// CHECK: apply [[FN]]([[AS]], [[META]]) : $@convention(method) (@thin StructWithSubobjectDestructor.Type) -> @out StructWithSubobjectDestructor +// CHECK: [[FN:%.*]] = function_ref @{{_ZN29StructWithSubobjectDestructorC1Ev|\?\?1StructWithSubobjectDestructor@@QEAA@XZ}} : $@convention(c) (@thin StructWithSubobjectDestructor.Type) -> @out StructWithSubobjectDestructor +// CHECK: apply [[FN]]([[AS]], [[META]]) : $@convention(c) (@thin StructWithSubobjectDestructor.Type) -> @out StructWithSubobjectDestructor // CHECK: destroy_addr [[AS]] // CHECK-LABEL: end sil function '$s4main33testStructWithSubobjectDestructoryyF' + +// CHECK-LABEL: sil [clang StructWithSubobjectDestructor.init] @{{_ZN29StructWithSubobjectDestructorC1Ev|\?\?1StructWithSubobjectDestructor@@QEAA@XZ}} : $@convention(c) (@thin StructWithSubobjectDestructor.Type) -> @out StructWithSubobjectDestructor public func testStructWithSubobjectDestructor() { let d = StructWithSubobjectDestructor() } -// StructWithSubobjectDestructor.init() -// CHECK-LABEL: sil shared [transparent] [serializable] [ossa] @$sSo29StructWithSubobjectDestructorVABycfC : $@convention(method) (@thin StructWithSubobjectDestructor.Type) -> @out StructWithSubobjectDestructor -// CHECK: [[BOX:%.*]] = alloc_box ${ var StructWithSubobjectDestructor } -// CHECK: [[UBOX:%.*]] = mark_uninitialized [rootself] [[BOX]] : ${ var StructWithSubobjectDestructor } -// CHECK: [[ADDR:%.*]] = project_box [[UBOX]] : ${ var StructWithSubobjectDestructor }, 0 -// CHECK: [[AS:%.*]] = alloc_stack $StructWithSubobjectDestructor -// CHECK: builtin "zeroInitializer"([[AS]] : $*StructWithSubobjectDestructor) : $() -// CHECK: [[BA:%.*]] = begin_access [modify] [unknown] [[ADDR]] : $*StructWithSubobjectDestructor -// CHECK: copy_addr [take] [[AS]] to [[BA]] : $*StructWithSubobjectDestructor -// CHECK: copy_addr [[ADDR]] to [initialization] %0 : $*StructWithSubobjectDestructor -// CHECK: destroy_value [[UBOX]] : ${ var StructWithSubobjectDestructor } -// CHECK-LABEL: end sil function '$sSo29StructWithSubobjectDestructorVABycfC' - // CHECK-LABLE: sil [ossa] @$s4main37testStructWithCopyConstructorAndValueSbyF // CHECK: [[AS:%.*]] = alloc_stack $StructWithCopyConstructorAndValue // CHECK: [[META:%.*]] = metatype $@thin StructWithCopyConstructorAndValue.Type -// CHECK: [[FN:%.*]] = function_ref @$sSo33StructWithCopyConstructorAndValueV5valueABs5Int32V_tcfC : $@convention(method) (Int32, @thin StructWithCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndValue -// CHECK: apply [[FN]]([[AS]], %{{.*}}, [[META]]) : $@convention(method) (Int32, @thin StructWithCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndValue +// CHECK: [[FN:%.*]] = function_ref @{{_ZN33StructWithCopyConstructorAndValueC1Ei|\?\?0StructWithCopyConstructorAndValue@@QEAA@H@Z}} : $@convention(c) (Int32, @thin StructWithCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndValue +// CHECK: apply [[FN]]([[AS]], %{{.*}}, [[META]]) : $@convention(c) (Int32, @thin StructWithCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndValue // CHECK: [[OBJ_VAL_ADDR:%.*]] = struct_element_addr [[AS]] : $*StructWithCopyConstructorAndValue, #StructWithCopyConstructorAndValue.value // CHECK: [[OBJ_VAL:%.*]] = load [trivial] [[OBJ_VAL_ADDR]] : $*Int32 // CHECK: [[IL_42:%.*]] = integer_literal $Builtin.IntLiteral, 42 @@ -70,22 +48,18 @@ public func testStructWithSubobjectDestructor() { // CHECK: destroy_addr [[AS]] : $*StructWithCopyConstructorAndValue // CHECK: return [[OUT]] : $Bool // CHECK-LABLE: end sil function '$s4main37testStructWithCopyConstructorAndValueSbyF' + +// CHECK-LABEL: sil [clang StructWithCopyConstructorAndValue.init] @{{_ZN33StructWithCopyConstructorAndValueC1Ei|\?\?0StructWithCopyConstructorAndValue@@QEAA@H@Z}} : $@convention(c) (Int32, @thin StructWithCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndValue public func testStructWithCopyConstructorAndValue() -> Bool { - let obj = StructWithCopyConstructorAndValue(value: 42) + let obj = StructWithCopyConstructorAndValue(42) return obj.value == 42 } -// StructWithCopyConstructorAndValue.init(value:) -// CHECK-LABEL: sil shared [transparent] [serializable] [ossa] @$sSo33StructWithCopyConstructorAndValueV5valueABs5Int32V_tcfC : $@convention(method) (Int32, @thin StructWithCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndValue -// CHECK: [[VAL:%.*]] = struct_element_addr %0 : $*StructWithCopyConstructorAndValue, #StructWithCopyConstructorAndValue.value -// CHECK: store %1 to [trivial] [[VAL]] : $*Int32 -// CHECK-LABEL: end sil function '$sSo33StructWithCopyConstructorAndValueV5valueABs5Int32V_tcfC' - // CHECK-LABEL: sil [ossa] @$s4main46testStructWithSubobjectCopyConstructorAndValueSbyF : $@convention(thin) () -> Bool // CHECK: [[MEMBER_0:%.*]] = alloc_stack $StructWithCopyConstructorAndValue // CHECK: [[MEMBER_META:%.*]] = metatype $@thin StructWithCopyConstructorAndValue.Type -// CHECK: [[MAKE_MEMBER_FN:%.*]] = function_ref @$sSo33StructWithCopyConstructorAndValueV5valueABs5Int32V_tcfC : $@convention(method) (Int32, @thin StructWithCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndValue -// CHECK: apply [[MAKE_MEMBER_FN]]([[MEMBER_0]], %{{.*}}, [[MEMBER_META]]) : $@convention(method) (Int32, @thin StructWithCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndValue +// CHECK: [[MAKE_MEMBER_FN:%.*]] = function_ref @{{_ZN33StructWithCopyConstructorAndValueC1Ei|\?\?0StructWithCopyConstructorAndValue@@QEAA@H@Z}} : $@convention(c) (Int32, @thin StructWithCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndValue +// CHECK: apply [[MAKE_MEMBER_FN]]([[MEMBER_0]], %{{.*}}, [[MEMBER_META]]) : $@convention(c) (Int32, @thin StructWithCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndValue // CHECK: [[AS:%.*]] = alloc_stack $StructWithSubobjectCopyConstructorAndValue // CHECK: [[META:%.*]] = metatype $@thin StructWithSubobjectCopyConstructorAndValue.Type // CHECK: [[MEMBER_1:%.*]] = alloc_stack $StructWithCopyConstructorAndValue @@ -104,7 +78,7 @@ public func testStructWithCopyConstructorAndValue() -> Bool { // CHECK: return [[OUT]] : $Bool // CHECK-LABEL: end sil function '$s4main46testStructWithSubobjectCopyConstructorAndValueSbyF' public func testStructWithSubobjectCopyConstructorAndValue() -> Bool { - let member = StructWithCopyConstructorAndValue(value: 42) + let member = StructWithCopyConstructorAndValue(42) let obj = StructWithSubobjectCopyConstructorAndValue(member: member) return obj.member.value == 42 } @@ -119,14 +93,14 @@ public func testStructWithSubobjectCopyConstructorAndValue() -> Bool { // CHECK-LABEL: sil [ossa] @$s4main041testStructWithCopyConstructorAndSubobjectefG5ValueSbyF : $@convention(thin) () -> Bool // CHECK: [[MEMBER_0:%.*]] = alloc_stack $StructWithCopyConstructorAndValue // CHECK: [[META_MEMBER:%.*]] = metatype $@thin StructWithCopyConstructorAndValue.Type -// CHECK: [[CREATE_MEMBER_FN:%.*]] = function_ref @$sSo33StructWithCopyConstructorAndValueV5valueABs5Int32V_tcfC : $@convention(method) (Int32, @thin StructWithCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndValue -// CHECK: apply [[CREATE_MEMBER_FN]]([[MEMBER_0]], %{{.*}}, [[META_MEMBER]]) : $@convention(method) (Int32, @thin StructWithCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndValue +// CHECK: [[CREATE_MEMBER_FN:%.*]] = function_ref @{{_ZN33StructWithCopyConstructorAndValueC1Ei|\?\?0StructWithCopyConstructorAndValue@@QEAA@H@Z}} : $@convention(c) (Int32, @thin StructWithCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndValue +// CHECK: apply [[CREATE_MEMBER_FN]]([[MEMBER_0]], %{{.*}}, [[META_MEMBER]]) : $@convention(c) (Int32, @thin StructWithCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndValue // CHECK: [[AS:%.*]] = alloc_stack $StructWithCopyConstructorAndSubobjectCopyConstructorAndValue // CHECK: [[META:%.*]] = metatype $@thin StructWithCopyConstructorAndSubobjectCopyConstructorAndValue.Type // CHECK: [[MEMBER_1:%.*]] = alloc_stack $StructWithCopyConstructorAndValue // CHECK: copy_addr [[MEMBER_0]] to [initialization] [[MEMBER_1]] : $*StructWithCopyConstructorAndValue -// CHECK: [[FN:%.*]] = function_ref @$sSo037StructWithCopyConstructorAndSubobjectcdE5ValueV6memberABSo0abcdeG0V_tcfC : $@convention(method) (@in StructWithCopyConstructorAndValue, @thin StructWithCopyConstructorAndSubobjectCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndSubobjectCopyConstructorAndValue -// CHECK: apply [[FN]]([[AS]], [[MEMBER_1]], [[META]]) : $@convention(method) (@in StructWithCopyConstructorAndValue, @thin StructWithCopyConstructorAndSubobjectCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndSubobjectCopyConstructorAndValue +// CHECK: [[FN:%.*]] = function_ref @{{_ZN60StructWithCopyConstructorAndSubobjectCopyConstructorAndValueC1E33StructWithCopyConstructorAndValue|\?\?0StructWithCopyConstructorAndSubobjectCopyConstructorAndValue@@QEAA@UStructWithCopyConstructorAndValue@@@Z}} : $@convention(c) (@in StructWithCopyConstructorAndValue, @thin StructWithCopyConstructorAndSubobjectCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndSubobjectCopyConstructorAndValue +// CHECK: apply [[FN]]([[AS]], [[MEMBER_1]], [[META]]) : $@convention(c) (@in StructWithCopyConstructorAndValue, @thin StructWithCopyConstructorAndSubobjectCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndSubobjectCopyConstructorAndValue // CHECK: [[OBJ_MEMBER_ADDR:%.*]] = struct_element_addr [[AS]] : $*StructWithCopyConstructorAndSubobjectCopyConstructorAndValue, #StructWithCopyConstructorAndSubobjectCopyConstructorAndValue.member // CHECK: [[MEMBER_2:%.*]] = alloc_stack $StructWithCopyConstructorAndValue // CHECK: copy_addr [[OBJ_MEMBER_ADDR]] to [initialization] [[MEMBER_2]] : $*StructWithCopyConstructorAndValue @@ -138,19 +112,13 @@ public func testStructWithSubobjectCopyConstructorAndValue() -> Bool { // CHECK-LABEL: end sil function '$s4main041testStructWithCopyConstructorAndSubobjectefG5ValueSbyF' public func testStructWithCopyConstructorAndSubobjectCopyConstructorAndValue() -> Bool { - let member = StructWithCopyConstructorAndValue(value: 42) + let member = StructWithCopyConstructorAndValue(42) let obj = StructWithCopyConstructorAndSubobjectCopyConstructorAndValue( - member: member + member ) return obj.member.value == 42 } -// StructWithCopyConstructorAndSubobjectCopyConstructorAndValue.init(member:) -// CHECK-LABEL: sil shared [transparent] [serializable] [ossa] @$sSo037StructWithCopyConstructorAndSubobjectcdE5ValueV6memberABSo0abcdeG0V_tcfC : $@convention(method) (@in StructWithCopyConstructorAndValue, @thin StructWithCopyConstructorAndSubobjectCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndSubobjectCopyConstructorAndValue -// CHECK: [[MEMBER:%.*]] = struct_element_addr %0 : $*StructWithCopyConstructorAndSubobjectCopyConstructorAndValue, #StructWithCopyConstructorAndSubobjectCopyConstructorAndValue.member -// CHECK: copy_addr [take] %1 to [initialization] [[MEMBER]] : $*StructWithCopyConstructorAndValue -// CHECK-LABEL: end sil function '$sSo037StructWithCopyConstructorAndSubobjectcdE5ValueV6memberABSo0abcdeG0V_tcfC' - // CHECK-LABEL: sil [ossa] @$s4main4test3objSbSo33StructWithCopyConstructorAndValueV_tF : $@convention(thin) (@in_guaranteed StructWithCopyConstructorAndValue) -> Bool // CHECK: [[META_1:%.*]] = metatype $@thin Int32.Type // CHECK: [[OBJ_VAL_ADDR:%.*]] = struct_element_addr %0 : $*StructWithCopyConstructorAndValue, #StructWithCopyConstructorAndValue.value diff --git a/test/Interop/Cxx/class/type-classification-non-trivial.swift b/test/Interop/Cxx/class/type-classification-non-trivial.swift index 489e6f71c7a40..910651f7b5cb5 100644 --- a/test/Interop/Cxx/class/type-classification-non-trivial.swift +++ b/test/Interop/Cxx/class/type-classification-non-trivial.swift @@ -11,12 +11,12 @@ import StdlibUnittest var AddressOnlyTestSuite = TestSuite("Address Only Types") AddressOnlyTestSuite.test("Test struct with copy constructor") { - let obj = StructWithCopyConstructorAndValue(value: 42) + let obj = StructWithCopyConstructorAndValue(42) expectEqual(obj.value, 42) } AddressOnlyTestSuite.test("Test struct with member with copy constructor") { - let member = StructWithCopyConstructorAndValue(value: 42) + let member = StructWithCopyConstructorAndValue(42) let obj = StructWithSubobjectCopyConstructorAndValue(member: member) expectEqual(obj.member.value, 42) } @@ -24,9 +24,9 @@ AddressOnlyTestSuite.test("Test struct with member with copy constructor") { AddressOnlyTestSuite.test( "Test struct with copy constructor and member with copy constructor" ) { - let member = StructWithCopyConstructorAndValue(value: 42) + let member = StructWithCopyConstructorAndValue(42) let obj = StructWithCopyConstructorAndSubobjectCopyConstructorAndValue( - member: member + member ) expectEqual(obj.member.value, 42) } diff --git a/test/Interop/Cxx/templates/canonical-types-module-interface.swift b/test/Interop/Cxx/templates/canonical-types-module-interface.swift index 3a90d1d44311a..735e2dafe5257 100644 --- a/test/Interop/Cxx/templates/canonical-types-module-interface.swift +++ b/test/Interop/Cxx/templates/canonical-types-module-interface.swift @@ -1,15 +1,16 @@ // RUN: %target-swift-ide-test -print-module -module-to-print=CanonicalTypes -I %S/Inputs -source-filename=x -enable-cxx-interop | %FileCheck %s // CHECK: struct __CxxTemplateInst12MagicWrapperI10IntWrapperE { -// CHECK: var t: IntWrapper -// CHECK: init() -// CHECK: init(t: IntWrapper) -// CHECK: mutating func getValuePlusArg(_ arg: Int32) -> Int32 -// CHECK: } -// CHECK: struct IntWrapper { -// CHECK: var value: Int32 -// CHECK: init() -// CHECK: mutating func getValue() -> Int32 -// CHECK: } -// CHECK: typealias WrappedMagicNumberA = __CxxTemplateInst12MagicWrapperI10IntWrapperE -// CHECK: typealias WrappedMagicNumberB = __CxxTemplateInst12MagicWrapperI10IntWrapperE +// CHECK-NEXT: var t: IntWrapper +// CHECK-NEXT: init() +// CHECK-NEXT: init(t: IntWrapper) +// CHECK-NEXT: mutating func getValuePlusArg(_ arg: Int32) -> Int32 +// CHECK-NEXT: } +// CHECK-NEXT: struct IntWrapper { +// CHECK-NEXT: var value: Int32 +// CHECK-NEXT: init() +// CHECK-NEXT: init(value: Int32) +// CHECK-NEXT: mutating func getValue() -> Int32 +// CHECK-NEXT: } +// CHECK-NEXT: typealias WrappedMagicNumberA = __CxxTemplateInst12MagicWrapperI10IntWrapperE +// CHECK-NEXT: typealias WrappedMagicNumberB = __CxxTemplateInst12MagicWrapperI10IntWrapperE diff --git a/test/Interop/Cxx/templates/not-pre-defined-class-template-module-interface.swift b/test/Interop/Cxx/templates/not-pre-defined-class-template-module-interface.swift index 7fd6b7cc0efc1..0f2b7f7b57c6e 100644 --- a/test/Interop/Cxx/templates/not-pre-defined-class-template-module-interface.swift +++ b/test/Interop/Cxx/templates/not-pre-defined-class-template-module-interface.swift @@ -1,15 +1,15 @@ // RUN: %target-swift-ide-test -print-module -module-to-print=NotPreDefinedClassTemplate -I %S/Inputs -source-filename=x -enable-cxx-interop | %FileCheck %s // CHECK: struct __CxxTemplateInst12MagicWrapperI10IntWrapperE { -// CHECK: var t: IntWrapper -// CHECK: init() -// CHECK: init(t: IntWrapper) -// CHECK: mutating func getValuePlusArg(_ arg: Int32) -> Int32 -// CHECK: } -// CHECK: struct IntWrapper { -// CHECK: var value: Int32 -// CHECK: init() -// CHECK: init(value: Int32) -// CHECK: mutating func getValue() -> Int32 -// CHECK: } -// CHECK: typealias MagicallyWrappedIntWithoutDefinition = __CxxTemplateInst12MagicWrapperI10IntWrapperE +// CHECK-NEXT: var t: IntWrapper +// CHECK-NEXT: init() +// CHECK-NEXT: init(t: IntWrapper) +// CHECK-NEXT: mutating func getValuePlusArg(_ arg: Int32) -> Int32 +// CHECK-NEXT: } +// CHECK-NEXT: struct IntWrapper { +// CHECK-NEXT: var value: Int32 +// CHECK-NEXT: init() +// CHECK-NEXT: init(value: Int32) +// CHECK-NEXT: mutating func getValue() -> Int32 +// CHECK-NEXT: } +// CHECK-NEXT: typealias MagicallyWrappedIntWithoutDefinition = __CxxTemplateInst12MagicWrapperI10IntWrapperE diff --git a/test/Interop/Cxx/templates/using-directive-module-interface.swift b/test/Interop/Cxx/templates/using-directive-module-interface.swift index 81b445d21e3d7..cee692e4dc45c 100644 --- a/test/Interop/Cxx/templates/using-directive-module-interface.swift +++ b/test/Interop/Cxx/templates/using-directive-module-interface.swift @@ -1,15 +1,15 @@ // RUN: %target-swift-ide-test -print-module -module-to-print=UsingDirective -I %S/Inputs -source-filename=x -enable-cxx-interop | %FileCheck %s // CHECK: struct __CxxTemplateInst12MagicWrapperI10IntWrapperE { -// CHECK: var t: IntWrapper -// CHECK: init() -// CHECK: init(t: IntWrapper) -// CHECK: mutating func getValuePlusArg(_ arg: Int32) -> Int32 -// CHECK: } -// CHECK: struct IntWrapper { -// CHECK: var value: Int32 -// CHECK: init() -// CHECK: init(value: Int32) -// CHECK: mutating func getValue() -> Int32 -// CHECK: } -// CHECK: typealias UsingWrappedMagicNumber = __CxxTemplateInst12MagicWrapperI10IntWrapperE +// CHECK-NEXT: var t: IntWrapper +// CHECK-NEXT: init() +// CHECK-NEXT: init(t: IntWrapper) +// CHECK-NEXT: mutating func getValuePlusArg(_ arg: Int32) -> Int32 +// CHECK-NEXT: } +// CHECK-NEXT: struct IntWrapper { +// CHECK-NEXT: var value: Int32 +// CHECK-NEXT: init() +// CHECK-NEXT: init(value: Int32) +// CHECK-NEXT: mutating func getValue() -> Int32 +// CHECK-NEXT: } +// CHECK-NEXT: typealias UsingWrappedMagicNumber = __CxxTemplateInst12MagicWrapperI10IntWrapperE From 7399c20fbf7809a274d9b6819bfd6fe708d73582 Mon Sep 17 00:00:00 2001 From: zoecarver Date: Thu, 24 Sep 2020 11:48:46 -0700 Subject: [PATCH 22/33] [cxx-interop] Revert changes to ClangTypeConverter::visitMetatypeType. The old implementation should be sufficient. The C++ constructors we import should get their types from the imported decl, not a double conversion to a SILFunction type and then back again. --- lib/AST/ClangTypeConverter.cpp | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/lib/AST/ClangTypeConverter.cpp b/lib/AST/ClangTypeConverter.cpp index d2316dd7415ea..9fd13f797798d 100644 --- a/lib/AST/ClangTypeConverter.cpp +++ b/lib/AST/ClangTypeConverter.cpp @@ -461,19 +461,7 @@ clang::QualType ClangTypeConverter::visitProtocolType(ProtocolType *type) { // Metatypes can be converted to Class when they are metatypes for concrete // classes. https://github.com/apple/swift/pull/27479#discussion_r344418131 clang::QualType ClangTypeConverter::visitMetatypeType(MetatypeType *type) { - assert(type->hasRepresentation() && - "metatype should have been assigned a representation"); - switch (type->getRepresentation()) { - case MetatypeRepresentation::Thin: - return ClangASTContext.VoidTy; - - case MetatypeRepresentation::Thick: - llvm_unreachable("thick metatypes don't have a corresponding Clang type"); - - case MetatypeRepresentation::ObjC: - return getClangMetatypeType(ClangASTContext); - } - llvm_unreachable("bad representation"); + return getClangMetatypeType(ClangASTContext); } // TODO: [stronger-checking-in-clang-type-conversion] From 9e2d03e0a8a32f55c0c956e56ce63ae5d4a2bfba Mon Sep 17 00:00:00 2001 From: zoecarver Date: Tue, 29 Sep 2020 16:44:00 -0700 Subject: [PATCH 23/33] [cxx-interop] Skip void types in emitCXXConstructorThunkIfNeeded. emitCXXConstructorThunkIfNeeded receives a SIL function that may contain metatypes. If so, they will be converted to void and we need to skip them when emitting the thunk's args. --- lib/IRGen/GenDecl.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index e8aff92311183..a59533d2d4c6a 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -2812,6 +2812,10 @@ emitCXXConstructorThunkIfNeeded(IRGenModule &IGM, SILFunction *initializer, for (auto i = thunk->arg_begin(), e = thunk->arg_end(); i != e; ++i) { auto *argTy = i->getType(); auto *paramTy = ctorFnType->getParamType(i - thunk->arg_begin()); + // Thin metatypes are represented as "void". If we run across one of + // thesse, skip it. + if (paramTy == IGM.VoidTy) + continue; if (paramTy != argTy) Args.push_back(subIGF.coerceValue(i, paramTy, IGM.DataLayout)); else From 7635443915bbedec5adc55dd3325e5a223cc31a4 Mon Sep 17 00:00:00 2001 From: zoecarver Date: Sat, 3 Oct 2020 13:44:07 -0700 Subject: [PATCH 24/33] [cxx-interop] Update ABIArgInfo::Indirect case in expandExternalSignatureTypes to handle thin metatype parameters. Add second list of SILParameterInfos that excludes thin metatypes so that the "Indirect" argument path below will select the correct parameter info. --- lib/IRGen/GenCall.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/IRGen/GenCall.cpp b/lib/IRGen/GenCall.cpp index 0166efb11799b..677e6de51d8bd 100644 --- a/lib/IRGen/GenCall.cpp +++ b/lib/IRGen/GenCall.cpp @@ -1315,6 +1315,17 @@ void SignatureExpansion::expandExternalSignatureTypes() { // Swift parameters list? size_t clangToSwiftParamOffset = paramTys.size(); + // This is exactly the same as "params" but without thin metatypes. This must + // exist so that when the path for "Indirect" arguments looks for the + // SILParameterInfo for a given index, we get the parameter info for the + // coorisponding clang type's index and not a "random" parameter's info. + // + // This is only an issue in very rare cases when we have a constructor that + // looks like this: (T, @thin U.Type) -> @out U. In this case "params" will + // contain two elements and "paramTys" will contain two elements so the + // "Indirect" argument path gets confused and selects the second parameter + // (the thin metatype) instead of the first one. + SmallVector adjustedSILParams; // Convert each parameter to a Clang type. for (auto param : params) { auto clangTy = IGM.getClangType(param, FnType); @@ -1324,6 +1335,7 @@ void SignatureExpansion::expandExternalSignatureTypes() { continue; } paramTys.push_back(clangTy); + adjustedSILParams.push_back(param); } // Generate function info for this signature. @@ -1413,7 +1425,7 @@ void SignatureExpansion::expandExternalSignatureTypes() { case clang::CodeGen::ABIArgInfo::Indirect: { assert(i >= clangToSwiftParamOffset && "Unexpected index for indirect byval argument"); - auto ¶m = params[i - clangToSwiftParamOffset]; + auto ¶m = adjustedSILParams[i - clangToSwiftParamOffset]; auto paramTy = getSILFuncConventions().getSILType( param, IGM.getMaximalTypeExpansionContext()); auto ¶mTI = cast(IGM.getTypeInfo(paramTy)); From f04de9f12867bc388411cd8a4abf4028bf77db01 Mon Sep 17 00:00:00 2001 From: zoecarver Date: Sun, 4 Oct 2020 14:38:04 -0700 Subject: [PATCH 25/33] [cxx-interop] Skip metatypes when lowering C++ constructor SIL function type. When lowering a C++ constructor's function type to a SIL function type, skip over the "self" metatype parameter. --- lib/IRGen/GenCall.cpp | 19 +--------- lib/IRGen/GenClangType.cpp | 14 +------- lib/IRGen/GenDecl.cpp | 4 --- lib/SIL/IR/SILFunctionType.cpp | 12 ++++++- lib/SILGen/SILGenApply.cpp | 6 ++++ .../Cxx/class/constructors-objc-silgen.swift | 5 ++- .../Cxx/class/constructors-silgen.swift | 5 ++- .../synthesized-initializers-silgen.swift | 14 ++++---- ...pe-classification-non-trivial-silgen.swift | 36 ++++++++----------- 9 files changed, 44 insertions(+), 71 deletions(-) diff --git a/lib/IRGen/GenCall.cpp b/lib/IRGen/GenCall.cpp index 677e6de51d8bd..dd8b6bab50a7a 100644 --- a/lib/IRGen/GenCall.cpp +++ b/lib/IRGen/GenCall.cpp @@ -1315,27 +1315,10 @@ void SignatureExpansion::expandExternalSignatureTypes() { // Swift parameters list? size_t clangToSwiftParamOffset = paramTys.size(); - // This is exactly the same as "params" but without thin metatypes. This must - // exist so that when the path for "Indirect" arguments looks for the - // SILParameterInfo for a given index, we get the parameter info for the - // coorisponding clang type's index and not a "random" parameter's info. - // - // This is only an issue in very rare cases when we have a constructor that - // looks like this: (T, @thin U.Type) -> @out U. In this case "params" will - // contain two elements and "paramTys" will contain two elements so the - // "Indirect" argument path gets confused and selects the second parameter - // (the thin metatype) instead of the first one. - SmallVector adjustedSILParams; // Convert each parameter to a Clang type. for (auto param : params) { auto clangTy = IGM.getClangType(param, FnType); - // If a parameter type is lowered to void, this means it should be ignored. - // For example, this happens for thin metatypes. - if (clangTy->isVoidType()) { - continue; - } paramTys.push_back(clangTy); - adjustedSILParams.push_back(param); } // Generate function info for this signature. @@ -1425,7 +1408,7 @@ void SignatureExpansion::expandExternalSignatureTypes() { case clang::CodeGen::ABIArgInfo::Indirect: { assert(i >= clangToSwiftParamOffset && "Unexpected index for indirect byval argument"); - auto ¶m = adjustedSILParams[i - clangToSwiftParamOffset]; + auto ¶m = params[i - clangToSwiftParamOffset]; auto paramTy = getSILFuncConventions().getSILType( param, IGM.getMaximalTypeExpansionContext()); auto ¶mTI = cast(IGM.getTypeInfo(paramTy)); diff --git a/lib/IRGen/GenClangType.cpp b/lib/IRGen/GenClangType.cpp index c8f38d6038a65..8bc35dd99c134 100644 --- a/lib/IRGen/GenClangType.cpp +++ b/lib/IRGen/GenClangType.cpp @@ -403,19 +403,7 @@ clang::CanQualType GenClangType::visitProtocolType(CanProtocolType type) { } clang::CanQualType GenClangType::visitMetatypeType(CanMetatypeType type) { - assert(type->hasRepresentation() && - "metatype should have been assigned a representation by SIL"); - switch (type->getRepresentation()) { - case MetatypeRepresentation::Thin: - return getClangASTContext().VoidTy; - - case MetatypeRepresentation::Thick: - llvm_unreachable("thick metatypes don't have a corresponding Clang type"); - - case MetatypeRepresentation::ObjC: - return getClangMetatypeType(getClangASTContext()); - } - llvm_unreachable("bad representation"); + return getClangMetatypeType(getClangASTContext()); } clang::CanQualType diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index a59533d2d4c6a..e8aff92311183 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -2812,10 +2812,6 @@ emitCXXConstructorThunkIfNeeded(IRGenModule &IGM, SILFunction *initializer, for (auto i = thunk->arg_begin(), e = thunk->arg_end(); i != e; ++i) { auto *argTy = i->getType(); auto *paramTy = ctorFnType->getParamType(i - thunk->arg_begin()); - // Thin metatypes are represented as "void". If we run across one of - // thesse, skip it. - if (paramTy == IGM.VoidTy) - continue; if (paramTy != argTy) Args.push_back(subIGF.coerceValue(i, paramTy, IGM.DataLayout)); else diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index ff07a080d7c4f..b0d52ef84d46f 100644 --- a/lib/SIL/IR/SILFunctionType.cpp +++ b/lib/SIL/IR/SILFunctionType.cpp @@ -4222,7 +4222,17 @@ TypeConverter::getLoweredFormalTypes(SILDeclRef constant, if (innerExtInfo.isAsync()) extInfo = extInfo.withAsync(true); - bridgedParams.push_back(selfParam); + // If this is a C++ constructor, don't add the metatype "self" parameter + // because we'll never use it and it will cause problems in IRGen. + if (constant.getDecl()->getClangDecl() && + isa(constant.getDecl()->getClangDecl())) { + // But, make sure it is actually a metatype that we're not adding. If + // changes to the self parameter are made in the future, this logic may + // need to be updated. + assert(selfParam.getParameterType()->is()); + } else { + bridgedParams.push_back(selfParam); + } auto uncurried = CanAnyFunctionType::get(genericSig, diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp index 65c44598af668..bb4a47b7d1f95 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -38,6 +38,7 @@ #include "swift/SIL/PrettyStackTrace.h" #include "swift/SIL/SILArgument.h" #include "llvm/Support/Compiler.h" +#include "clang/AST/DeclCXX.h" using namespace swift; using namespace Lowering; @@ -559,6 +560,11 @@ class Callee { result.foreignError = func->getForeignErrorConvention(); result.foreignSelf = func->getImportAsMemberStatus(); + // Remove the metatype "self" parameter by making this a static member. + if (constant->getDecl()->getClangDecl() && + isa(constant->getDecl()->getClangDecl())) + result.foreignSelf.setStatic(); + return result; } diff --git a/test/Interop/Cxx/class/constructors-objc-silgen.swift b/test/Interop/Cxx/class/constructors-objc-silgen.swift index c7199ee889811..6e1b907d2b472 100644 --- a/test/Interop/Cxx/class/constructors-objc-silgen.swift +++ b/test/Interop/Cxx/class/constructors-objc-silgen.swift @@ -5,8 +5,7 @@ import ConstructorsObjC // CHECK: [[VAR:%[0-9]+]] = alloc_stack $ConstructorWithNSArrayParam -// CHECK: [[TYPE:%[0-9]+]] = metatype $@thin ConstructorWithNSArrayParam.Type // CHECK: [[OPT_ARRAY:%[0-9]+]] = enum $Optional, #Optional.some!enumelt, %{{[0-9]+}} : $NSArray -// CHECK: [[FUNC:%[0-9]+]] = function_ref @_ZN27ConstructorWithNSArrayParamC1EP7NSArray : $@convention(c) (Optional, @thin ConstructorWithNSArrayParam.Type) -> @out ConstructorWithNSArrayParam -// CHECK: %{{[0-9]+}} = apply [[FUNC]]([[VAR]], [[OPT_ARRAY]], [[TYPE]]) : $@convention(c) (Optional, @thin ConstructorWithNSArrayParam.Type) -> @out ConstructorWithNSArrayParam +// CHECK: [[FUNC:%[0-9]+]] = function_ref @_ZN27ConstructorWithNSArrayParamC1EP7NSArray : $@convention(c) (Optional) -> @out ConstructorWithNSArrayParam +// CHECK: %{{[0-9]+}} = apply [[FUNC]]([[VAR]], [[OPT_ARRAY]]) : $@convention(c) (Optional) -> @out ConstructorWithNSArrayParam let _ = ConstructorWithNSArrayParam([]) diff --git a/test/Interop/Cxx/class/constructors-silgen.swift b/test/Interop/Cxx/class/constructors-silgen.swift index def974a1e9a3d..9472ff3cc08aa 100644 --- a/test/Interop/Cxx/class/constructors-silgen.swift +++ b/test/Interop/Cxx/class/constructors-silgen.swift @@ -5,9 +5,8 @@ import Constructors // The most important thing to test here is that the constructor result is // returned with an @out attribute. // CHECK: [[VAR:%[0-9]+]] = alloc_stack $ConstructorWithParam -// CHECK: [[TYPE:%[0-9]+]] = metatype $@thin ConstructorWithParam.Type // CHECK: [[LITERAL:%[0-9]+]] = integer_literal $Builtin.Int32, 42 // CHECK: [[INT:%[0-9]+]] = struct $Int32 ([[LITERAL]] : $Builtin.Int32) -// CHECK: [[FUNC:%[0-9]+]] = function_ref @{{_ZN20ConstructorWithParamC1Ei|\?\?0ConstructorWithParam@@QEAA@H@Z}} : $@convention(c) (Int32, @thin ConstructorWithParam.Type) -> @out ConstructorWithParam -// CHECK: %{{[0-9]+}} = apply [[FUNC]]([[VAR]], [[INT]], [[TYPE]]) : $@convention(c) (Int32, @thin ConstructorWithParam.Type) -> @out ConstructorWithParam +// CHECK: [[FUNC:%[0-9]+]] = function_ref @{{_ZN20ConstructorWithParamC1Ei|\?\?0ConstructorWithParam@@QEAA@H@Z}} : $@convention(c) (Int32) -> @out ConstructorWithParam +// CHECK: %{{[0-9]+}} = apply [[FUNC]]([[VAR]], [[INT]]) : $@convention(c) (Int32) -> @out ConstructorWithParam let _ = ConstructorWithParam(42) diff --git a/test/Interop/Cxx/class/synthesized-initializers-silgen.swift b/test/Interop/Cxx/class/synthesized-initializers-silgen.swift index 8b84f18bb1569..379873c341222 100644 --- a/test/Interop/Cxx/class/synthesized-initializers-silgen.swift +++ b/test/Interop/Cxx/class/synthesized-initializers-silgen.swift @@ -4,24 +4,22 @@ import SynthesizedInitializers // CHECK-LABEL: sil [ossa] @$s4main18emptyTypeNoArgInityyF : $@convention(thin) () -> () // CHECK: [[AS:%.*]] = alloc_stack $EmptyStruct -// CHECK: [[META:%.*]] = metatype $@thin EmptyStruct.Type -// CHECK: [[FN:%.*]] = function_ref @{{_ZN11EmptyStructC1Ev|\?\?0EmptyStruct@@QEAA@XZ}} : $@convention(c) (@thin EmptyStruct.Type) -> @out EmptyStruct -// CHECK: apply [[FN]]([[AS]], [[META]]) : $@convention(c) (@thin EmptyStruct.Type) -> @out EmptyStruct +// CHECK: [[FN:%.*]] = function_ref @{{_ZN11EmptyStructC1Ev|\?\?0EmptyStruct@@QEAA@XZ}} : $@convention(c) () -> @out EmptyStruct +// CHECK: apply [[FN]]([[AS]]) : $@convention(c) () -> @out EmptyStruct // CHECK-LABEL: end sil function '$s4main18emptyTypeNoArgInityyF' -// CHECL-LABEL: sil [clang EmptyStruct.init] @{{_ZN11EmptyStructC1Ev|\?\?0EmptyStruct@@QEAA@XZ}} : $@convention(c) (@thin EmptyStruct.Type) -> @out EmptyStruct +// CHECL-LABEL: sil [clang EmptyStruct.init] @{{_ZN11EmptyStructC1Ev|\?\?0EmptyStruct@@QEAA@XZ}} : $@convention(c) () -> @out EmptyStruct public func emptyTypeNoArgInit() { let e = EmptyStruct() } // CHECK-LABEL: sil [ossa] @$s4main25singleMemberTypeNoArgInityyF : $@convention(thin) () -> () // CHECK: [[AS:%.*]] = alloc_stack $IntBox -// CHECK: [[META:%.*]] = metatype $@thin IntBox.Type -// CHECK: [[FN:%.*]] = function_ref @{{_ZN6IntBoxC1Ev|\?\?0IntBox@@QEAA@XZ}} : $@convention(c) (@thin IntBox.Type) -> @out IntBox -// CHECK: apply [[FN]]([[AS]], [[META]]) : $@convention(c) (@thin IntBox.Type) -> @out IntBox +// CHECK: [[FN:%.*]] = function_ref @{{_ZN6IntBoxC1Ev|\?\?0IntBox@@QEAA@XZ}} : $@convention(c) () -> @out IntBox +// CHECK: apply [[FN]]([[AS]]) : $@convention(c) () -> @out IntBox // CHECK-LABEL: end sil function '$s4main25singleMemberTypeNoArgInityyF' -//CHECK-LABEL: sil [clang IntBox.init] @{{_ZN6IntBoxC1Ev|\?\?0IntBox@@QEAA@XZ}} : $@convention(c) (@thin IntBox.Type) -> @out IntBox +//CHECK-LABEL: sil [clang IntBox.init] @{{_ZN6IntBoxC1Ev|\?\?0IntBox@@QEAA@XZ}} : $@convention(c) () -> @out IntBox public func singleMemberTypeNoArgInit() { let i = IntBox() } diff --git a/test/Interop/Cxx/class/type-classification-non-trivial-silgen.swift b/test/Interop/Cxx/class/type-classification-non-trivial-silgen.swift index 88a7253e17f19..51f00d5268432 100644 --- a/test/Interop/Cxx/class/type-classification-non-trivial-silgen.swift +++ b/test/Interop/Cxx/class/type-classification-non-trivial-silgen.swift @@ -6,14 +6,13 @@ import TypeClassification // "destroy_addr". // CHECK-LABEL: sil [ossa] @$s4main24testStructWithDestructoryyF // CHECK: [[AS:%.*]] = alloc_stack $StructWithDestructor -// CHECK: [[META:%.*]] = metatype $@thin StructWithDestructor.Type -// CHECK: [[FN:%.*]] = function_ref @{{_ZN20StructWithDestructorC1Ev|\?\?0StructWithDestructor@@QEAA@XZ}} : $@convention(c) (@thin StructWithDestructor.Type) -> @out StructWithDestructor -// CHECK: apply [[FN]]([[AS]], [[META]]) : $@convention(c) (@thin StructWithDestructor.Type) -> @out StructWithDestructor +// CHECK: [[FN:%.*]] = function_ref @{{_ZN20StructWithDestructorC1Ev|\?\?0StructWithDestructor@@QEAA@XZ}} : $@convention(c) () -> @out StructWithDestructor +// CHECK: apply [[FN]]([[AS]]) : $@convention(c) () -> @out StructWithDestructor // CHECK: destroy_addr [[AS]] // CHECK: dealloc_stack %0 : $*StructWithDestructor // CHECK-LABEL: end sil function '$s4main24testStructWithDestructoryyF' -// CHECK-LABEL: sil [clang StructWithDestructor.init] @{{_ZN20StructWithDestructorC1Ev|\?\?0StructWithDestructor@@QEAA@XZ}} : $@convention(c) (@thin StructWithDestructor.Type) -> @out StructWithDestructor +// CHECK-LABEL: sil [clang StructWithDestructor.init] @{{_ZN20StructWithDestructorC1Ev|\?\?0StructWithDestructor@@QEAA@XZ}} : $@convention(c) () -> @out StructWithDestructor public func testStructWithDestructor() { let d = StructWithDestructor() } @@ -22,22 +21,20 @@ public func testStructWithDestructor() { // for a "destroy_addr". // CHECK-LABEL: sil [ossa] @$s4main33testStructWithSubobjectDestructoryyF : $@convention(thin) () -> () // CHECK: [[AS:%.*]] = alloc_stack $StructWithSubobjectDestructor -// CHECK: [[META:%.*]] = metatype $@thin StructWithSubobjectDestructor.Type -// CHECK: [[FN:%.*]] = function_ref @{{_ZN29StructWithSubobjectDestructorC1Ev|\?\?1StructWithSubobjectDestructor@@QEAA@XZ}} : $@convention(c) (@thin StructWithSubobjectDestructor.Type) -> @out StructWithSubobjectDestructor -// CHECK: apply [[FN]]([[AS]], [[META]]) : $@convention(c) (@thin StructWithSubobjectDestructor.Type) -> @out StructWithSubobjectDestructor +// CHECK: [[FN:%.*]] = function_ref @{{_ZN29StructWithSubobjectDestructorC1Ev|\?\?1StructWithSubobjectDestructor@@QEAA@XZ}} : $@convention(c) () -> @out StructWithSubobjectDestructor +// CHECK: apply [[FN]]([[AS]]) : $@convention(c) () -> @out StructWithSubobjectDestructor // CHECK: destroy_addr [[AS]] // CHECK-LABEL: end sil function '$s4main33testStructWithSubobjectDestructoryyF' -// CHECK-LABEL: sil [clang StructWithSubobjectDestructor.init] @{{_ZN29StructWithSubobjectDestructorC1Ev|\?\?1StructWithSubobjectDestructor@@QEAA@XZ}} : $@convention(c) (@thin StructWithSubobjectDestructor.Type) -> @out StructWithSubobjectDestructor +// CHECK-LABEL: sil [clang StructWithSubobjectDestructor.init] @{{_ZN29StructWithSubobjectDestructorC1Ev|\?\?1StructWithSubobjectDestructor@@QEAA@XZ}} : $@convention(c) () -> @out StructWithSubobjectDestructor public func testStructWithSubobjectDestructor() { let d = StructWithSubobjectDestructor() } // CHECK-LABLE: sil [ossa] @$s4main37testStructWithCopyConstructorAndValueSbyF // CHECK: [[AS:%.*]] = alloc_stack $StructWithCopyConstructorAndValue -// CHECK: [[META:%.*]] = metatype $@thin StructWithCopyConstructorAndValue.Type -// CHECK: [[FN:%.*]] = function_ref @{{_ZN33StructWithCopyConstructorAndValueC1Ei|\?\?0StructWithCopyConstructorAndValue@@QEAA@H@Z}} : $@convention(c) (Int32, @thin StructWithCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndValue -// CHECK: apply [[FN]]([[AS]], %{{.*}}, [[META]]) : $@convention(c) (Int32, @thin StructWithCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndValue +// CHECK: [[FN:%.*]] = function_ref @{{_ZN33StructWithCopyConstructorAndValueC1Ei|\?\?0StructWithCopyConstructorAndValue@@QEAA@H@Z}} : $@convention(c) (Int32) -> @out StructWithCopyConstructorAndValue +// CHECK: apply [[FN]]([[AS]], %{{.*}}) : $@convention(c) (Int32) -> @out StructWithCopyConstructorAndValue // CHECK: [[OBJ_VAL_ADDR:%.*]] = struct_element_addr [[AS]] : $*StructWithCopyConstructorAndValue, #StructWithCopyConstructorAndValue.value // CHECK: [[OBJ_VAL:%.*]] = load [trivial] [[OBJ_VAL_ADDR]] : $*Int32 // CHECK: [[IL_42:%.*]] = integer_literal $Builtin.IntLiteral, 42 @@ -49,7 +46,7 @@ public func testStructWithSubobjectDestructor() { // CHECK: return [[OUT]] : $Bool // CHECK-LABLE: end sil function '$s4main37testStructWithCopyConstructorAndValueSbyF' -// CHECK-LABEL: sil [clang StructWithCopyConstructorAndValue.init] @{{_ZN33StructWithCopyConstructorAndValueC1Ei|\?\?0StructWithCopyConstructorAndValue@@QEAA@H@Z}} : $@convention(c) (Int32, @thin StructWithCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndValue +// CHECK-LABEL: sil [clang StructWithCopyConstructorAndValue.init] @{{_ZN33StructWithCopyConstructorAndValueC1Ei|\?\?0StructWithCopyConstructorAndValue@@QEAA@H@Z}} : $@convention(c) (Int32) -> @out StructWithCopyConstructorAndValue public func testStructWithCopyConstructorAndValue() -> Bool { let obj = StructWithCopyConstructorAndValue(42) return obj.value == 42 @@ -57,9 +54,8 @@ public func testStructWithCopyConstructorAndValue() -> Bool { // CHECK-LABEL: sil [ossa] @$s4main46testStructWithSubobjectCopyConstructorAndValueSbyF : $@convention(thin) () -> Bool // CHECK: [[MEMBER_0:%.*]] = alloc_stack $StructWithCopyConstructorAndValue -// CHECK: [[MEMBER_META:%.*]] = metatype $@thin StructWithCopyConstructorAndValue.Type -// CHECK: [[MAKE_MEMBER_FN:%.*]] = function_ref @{{_ZN33StructWithCopyConstructorAndValueC1Ei|\?\?0StructWithCopyConstructorAndValue@@QEAA@H@Z}} : $@convention(c) (Int32, @thin StructWithCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndValue -// CHECK: apply [[MAKE_MEMBER_FN]]([[MEMBER_0]], %{{.*}}, [[MEMBER_META]]) : $@convention(c) (Int32, @thin StructWithCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndValue +// CHECK: [[MAKE_MEMBER_FN:%.*]] = function_ref @{{_ZN33StructWithCopyConstructorAndValueC1Ei|\?\?0StructWithCopyConstructorAndValue@@QEAA@H@Z}} : $@convention(c) (Int32) -> @out StructWithCopyConstructorAndValue +// CHECK: apply [[MAKE_MEMBER_FN]]([[MEMBER_0]], %{{.*}}) : $@convention(c) (Int32) -> @out StructWithCopyConstructorAndValue // CHECK: [[AS:%.*]] = alloc_stack $StructWithSubobjectCopyConstructorAndValue // CHECK: [[META:%.*]] = metatype $@thin StructWithSubobjectCopyConstructorAndValue.Type // CHECK: [[MEMBER_1:%.*]] = alloc_stack $StructWithCopyConstructorAndValue @@ -92,15 +88,13 @@ public func testStructWithSubobjectCopyConstructorAndValue() -> Bool { // testStructWithCopyConstructorAndSubobjectCopyConstructorAndValue() // CHECK-LABEL: sil [ossa] @$s4main041testStructWithCopyConstructorAndSubobjectefG5ValueSbyF : $@convention(thin) () -> Bool // CHECK: [[MEMBER_0:%.*]] = alloc_stack $StructWithCopyConstructorAndValue -// CHECK: [[META_MEMBER:%.*]] = metatype $@thin StructWithCopyConstructorAndValue.Type -// CHECK: [[CREATE_MEMBER_FN:%.*]] = function_ref @{{_ZN33StructWithCopyConstructorAndValueC1Ei|\?\?0StructWithCopyConstructorAndValue@@QEAA@H@Z}} : $@convention(c) (Int32, @thin StructWithCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndValue -// CHECK: apply [[CREATE_MEMBER_FN]]([[MEMBER_0]], %{{.*}}, [[META_MEMBER]]) : $@convention(c) (Int32, @thin StructWithCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndValue +// CHECK: [[CREATE_MEMBER_FN:%.*]] = function_ref @{{_ZN33StructWithCopyConstructorAndValueC1Ei|\?\?0StructWithCopyConstructorAndValue@@QEAA@H@Z}} : $@convention(c) (Int32) -> @out StructWithCopyConstructorAndValue +// CHECK: apply [[CREATE_MEMBER_FN]]([[MEMBER_0]], %{{.*}}) : $@convention(c) (Int32) -> @out StructWithCopyConstructorAndValue // CHECK: [[AS:%.*]] = alloc_stack $StructWithCopyConstructorAndSubobjectCopyConstructorAndValue -// CHECK: [[META:%.*]] = metatype $@thin StructWithCopyConstructorAndSubobjectCopyConstructorAndValue.Type // CHECK: [[MEMBER_1:%.*]] = alloc_stack $StructWithCopyConstructorAndValue // CHECK: copy_addr [[MEMBER_0]] to [initialization] [[MEMBER_1]] : $*StructWithCopyConstructorAndValue -// CHECK: [[FN:%.*]] = function_ref @{{_ZN60StructWithCopyConstructorAndSubobjectCopyConstructorAndValueC1E33StructWithCopyConstructorAndValue|\?\?0StructWithCopyConstructorAndSubobjectCopyConstructorAndValue@@QEAA@UStructWithCopyConstructorAndValue@@@Z}} : $@convention(c) (@in StructWithCopyConstructorAndValue, @thin StructWithCopyConstructorAndSubobjectCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndSubobjectCopyConstructorAndValue -// CHECK: apply [[FN]]([[AS]], [[MEMBER_1]], [[META]]) : $@convention(c) (@in StructWithCopyConstructorAndValue, @thin StructWithCopyConstructorAndSubobjectCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndSubobjectCopyConstructorAndValue +// CHECK: [[FN:%.*]] = function_ref @{{_ZN60StructWithCopyConstructorAndSubobjectCopyConstructorAndValueC1E33StructWithCopyConstructorAndValue|\?\?0StructWithCopyConstructorAndSubobjectCopyConstructorAndValue@@QEAA@UStructWithCopyConstructorAndValue@@@Z}} : $@convention(c) (@in StructWithCopyConstructorAndValue) -> @out StructWithCopyConstructorAndSubobjectCopyConstructorAndValue +// CHECK: apply [[FN]]([[AS]], [[MEMBER_1]]) : $@convention(c) (@in StructWithCopyConstructorAndValue) -> @out StructWithCopyConstructorAndSubobjectCopyConstructorAndValue // CHECK: [[OBJ_MEMBER_ADDR:%.*]] = struct_element_addr [[AS]] : $*StructWithCopyConstructorAndSubobjectCopyConstructorAndValue, #StructWithCopyConstructorAndSubobjectCopyConstructorAndValue.member // CHECK: [[MEMBER_2:%.*]] = alloc_stack $StructWithCopyConstructorAndValue // CHECK: copy_addr [[OBJ_MEMBER_ADDR]] to [initialization] [[MEMBER_2]] : $*StructWithCopyConstructorAndValue From 4364af39ee107bca52aefb07ef461d6d2d7e246d Mon Sep 17 00:00:00 2001 From: zoecarver Date: Sun, 4 Oct 2020 15:15:08 -0700 Subject: [PATCH 26/33] [cxx-interop] Small fixes and cleanup based on review. * Check isAggregate instead of hasUserDeclaredConstructor. * Rename addEmptyArgNamesForCxxFunc -> addEmptyArgNamesForClangFunction. * Other minor fixes and cleanups. --- lib/ClangImporter/ImportDecl.cpp | 6 ++---- lib/ClangImporter/ImportName.cpp | 14 ++++++-------- .../Cxx/class/constructors-module-interface.swift | 1 + .../Cxx/class/constructors-typechecker.swift | 2 +- .../class/synthesized-initializers-silgen.swift | 10 ++++++++++ 5 files changed, 20 insertions(+), 13 deletions(-) diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 8b5fb67fab9da..e1712aa991ada 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -3452,10 +3452,8 @@ namespace { ctors.push_back(createDefaultConstructor(Impl, result)); } - bool hasUserDeclaredConstructor = - cxxRecordDecl && cxxRecordDecl->hasUserDeclaredConstructor(); - if (hasReferenceableFields && hasMemberwiseInitializer && - !hasUserDeclaredConstructor) { + bool isAggregate = cxxRecordDecl && cxxRecordDecl->isAggregate(); + if (hasReferenceableFields && hasMemberwiseInitializer && isAggregate) { // The default zero initializer suppresses the implicit value // constructor that would normally be formed, so we have to add that // explicitly as well. diff --git a/lib/ClangImporter/ImportName.cpp b/lib/ClangImporter/ImportName.cpp index 1a02a454ede0d..79fcd57ccc141 100644 --- a/lib/ClangImporter/ImportName.cpp +++ b/lib/ClangImporter/ImportName.cpp @@ -1367,11 +1367,10 @@ static bool suppressFactoryMethodAsInit(const clang::ObjCMethodDecl *method, } static void -addEmptyArgNamesForCxxFunc(const clang::FunctionDecl *funcDecl, - SmallVectorImpl &argumentNames) { - for (size_t i = 0; i < funcDecl->param_size(); ++i) { +addEmptyArgNamesForClangFunction(const clang::FunctionDecl *funcDecl, + SmallVectorImpl &argumentNames) { + for (size_t i = 0; i < funcDecl->param_size(); ++i) argumentNames.push_back(StringRef()); - } if (funcDecl->isVariadic()) argumentNames.push_back(StringRef()); } @@ -1614,9 +1613,8 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D, isFunction = true; result.info.initKind = CtorInitializerKind::Designated; baseName = "init"; - if (auto ctor = dyn_cast(D)) { - addEmptyArgNamesForCxxFunc(ctor, argumentNames); - } + addEmptyArgNamesForClangFunction(cast(D), + argumentNames); break; case clang::DeclarationName::CXXConversionFunctionName: @@ -1691,7 +1689,7 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D, if (auto function = dyn_cast(D)) { isFunction = true; - addEmptyArgNamesForCxxFunc(function, argumentNames); + addEmptyArgNamesForClangFunction(function, argumentNames); } break; diff --git a/test/Interop/Cxx/class/constructors-module-interface.swift b/test/Interop/Cxx/class/constructors-module-interface.swift index acc321c4bca4e..672c11692641c 100644 --- a/test/Interop/Cxx/class/constructors-module-interface.swift +++ b/test/Interop/Cxx/class/constructors-module-interface.swift @@ -16,6 +16,7 @@ // CHECK-NEXT: } // CHECK-NEXT: struct DefaultConstructorDeleted { // CHECK-NEXT: var a: UnsafeMutablePointer +// CHECK-NEXT: init(a: UnsafeMutablePointer) // CHECK-NEXT: } // CHECK-NEXT: struct ConstructorWithParam { // CHECK-NEXT: var x: Int32 diff --git a/test/Interop/Cxx/class/constructors-typechecker.swift b/test/Interop/Cxx/class/constructors-typechecker.swift index 3cc008807c6a1..c78328c2b39c3 100644 --- a/test/Interop/Cxx/class/constructors-typechecker.swift +++ b/test/Interop/Cxx/class/constructors-typechecker.swift @@ -8,6 +8,6 @@ let implicit = ImplicitDefaultConstructor() let deletedImplicitly = ConstructorWithParam() // expected-error {{missing argument for parameter #1 in call}} -let deletedExplicitly = DefaultConstructorDeleted() // expected-error {{cannot be constructed because it has no accessible initializers}} +let deletedExplicitly = DefaultConstructorDeleted() // expected-error {{missing argument for parameter 'a' in call}} let withArg = ConstructorWithParam(42) diff --git a/test/Interop/Cxx/class/synthesized-initializers-silgen.swift b/test/Interop/Cxx/class/synthesized-initializers-silgen.swift index 379873c341222..dac14a687a652 100644 --- a/test/Interop/Cxx/class/synthesized-initializers-silgen.swift +++ b/test/Interop/Cxx/class/synthesized-initializers-silgen.swift @@ -1,6 +1,7 @@ // RUN: %target-swift-frontend -I %S/Inputs -enable-cxx-interop -emit-silgen %s | %FileCheck %s import SynthesizedInitializers +import Constructors // CHECK-LABEL: sil [ossa] @$s4main18emptyTypeNoArgInityyF : $@convention(thin) () -> () // CHECK: [[AS:%.*]] = alloc_stack $EmptyStruct @@ -32,3 +33,12 @@ public func singleMemberTypeNoArgInit() { public func singleMemberTypeValueInit() { let i = IntBox(x: 42) } + +// CHECK-LABEL: sil shared [transparent] [serializable] [ossa] @$sSo25DefaultConstructorDeletedV1aABSpys5Int32VG_tcfC : $@convention(method) (UnsafeMutablePointer, @thin DefaultConstructorDeleted.Type) -> DefaultConstructorDeleted +// CHECK: bb0([[A:%.*]] : $UnsafeMutablePointer +// CHECK-NEXT: [[OUT:%.*]] = struct $DefaultConstructorDeleted ([[A]] : $UnsafeMutablePointer) +// CHECK-NEXT: return [[OUT]] : $DefaultConstructorDeleted +// CHECK-LABEL: end sil function '$sSo25DefaultConstructorDeletedV1aABSpys5Int32VG_tcfC' +public func deletedConstructor(a: UnsafeMutablePointer) { + let deletedExplicitly = DefaultConstructorDeleted(a: a) +} From 5774610eafd460023da4f0fac66442a4deceb023 Mon Sep 17 00:00:00 2001 From: zoecarver Date: Sun, 4 Oct 2020 15:21:00 -0700 Subject: [PATCH 27/33] [cxx-interop] Fix patch formatting with clang-format. Fix all formatting of the changes made by this patch. --- lib/ClangImporter/ClangImporter.cpp | 4 ++-- lib/ClangImporter/ImportDecl.cpp | 11 +++++------ lib/IRGen/GenCall.cpp | 2 +- lib/SIL/IR/SILFunctionType.cpp | 6 +++--- lib/SILGen/SILGenApply.cpp | 4 ++-- 5 files changed, 13 insertions(+), 14 deletions(-) diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 370a3cdd1f91d..5628cfe170c5b 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -3590,8 +3590,8 @@ void ClangImporter::getMangledName(raw_ostream &os, Impl.Mangler.reset(Impl.getClangASTContext().createMangleContext()); if (auto ctor = dyn_cast(clangDecl)) { - auto ctorGlobalDecl = clang::GlobalDecl(ctor, - clang::CXXCtorType::Ctor_Complete); + auto ctorGlobalDecl = + clang::GlobalDecl(ctor, clang::CXXCtorType::Ctor_Complete); Impl.Mangler->mangleCXXName(ctorGlobalDecl, os); } else { Impl.Mangler->mangleName(clangDecl, os); diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index e1712aa991ada..3e82783ef4b02 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -3485,8 +3485,7 @@ namespace { result->setHasUnreferenceableStorage(hasUnreferenceableStorage); if (cxxRecordDecl) { - result->setIsCxxNonTrivial( - !cxxRecordDecl->isTriviallyCopyable()); + result->setIsCxxNonTrivial(!cxxRecordDecl->isTriviallyCopyable()); for (auto ctor : cxxRecordDecl->ctors()) { if (ctor->isCopyConstructor() && @@ -3925,10 +3924,10 @@ namespace { } else { auto resultTy = importedType.getType(); - FuncDecl *func = createFuncOrAccessor( - Impl.SwiftContext, loc, accessorInfo, name, - nameLoc, bodyParams, resultTy, - /*async*/ false, /*throws*/ false, dc, decl); + FuncDecl *func = + createFuncOrAccessor(Impl.SwiftContext, loc, accessorInfo, name, + nameLoc, bodyParams, resultTy, + /*async*/ false, /*throws*/ false, dc, decl); result = func; if (!dc->isModuleScopeContext()) { diff --git a/lib/IRGen/GenCall.cpp b/lib/IRGen/GenCall.cpp index dd8b6bab50a7a..60f4de3fccac7 100644 --- a/lib/IRGen/GenCall.cpp +++ b/lib/IRGen/GenCall.cpp @@ -2821,7 +2821,7 @@ static void externalizeArguments(IRGenFunction &IGF, const Callee &callee, == SILFunctionTypeRepresentation::Block) { // Ignore the physical block-object parameter. firstParam += 1; - // Or the indirect result parameter. + // Or the indirect result parameter. } else if (fnType->getNumResults() > 0 && fnType->getSingleResult().isFormalIndirect()) { // Ignore the indirect result parameter. diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index b0d52ef84d46f..f1037df2b1550 100644 --- a/lib/SIL/IR/SILFunctionType.cpp +++ b/lib/SIL/IR/SILFunctionType.cpp @@ -2806,9 +2806,9 @@ class CXXMethodConventions : public CFunctionTypeConventions { // actual ABI doesn't match the assumed ABI, we try to get as close as // possible to make it easy for LLVM to optimize away the thunk. return ResultConvention::Indirect; - } - return CFunctionTypeConventions::getResult(resultTL); - } + } + return CFunctionTypeConventions::getResult(resultTL); + } static bool classof(const Conventions *C) { return C->getKind() == ConventionsKind::CXXMethod; } diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp index bb4a47b7d1f95..70a2611f44e37 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -27,9 +27,9 @@ #include "swift/AST/ForeignErrorConvention.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/GenericSignature.h" -#include "swift/AST/ParameterList.h" #include "swift/AST/Module.h" #include "swift/AST/ModuleLoader.h" +#include "swift/AST/ParameterList.h" #include "swift/AST/SubstitutionMap.h" #include "swift/Basic/ExternalUnion.h" #include "swift/Basic/Range.h" @@ -37,8 +37,8 @@ #include "swift/Basic/Unicode.h" #include "swift/SIL/PrettyStackTrace.h" #include "swift/SIL/SILArgument.h" -#include "llvm/Support/Compiler.h" #include "clang/AST/DeclCXX.h" +#include "llvm/Support/Compiler.h" using namespace swift; using namespace Lowering; From 4cb337a41fbe5bda820a2fa6cdb1170b1a848529 Mon Sep 17 00:00:00 2001 From: zoecarver Date: Sat, 10 Oct 2020 10:47:34 -0700 Subject: [PATCH 28/33] [cxx-interop] Generate memberwise initializers for non-C++ types. Previously, when we checked for `!hasUserDeclaredConstructor` rather than `isAggregate`, we would always generate memberwise initializers for C record types. This updates the isAggregate to be true for non-C++ types so we will generate memberwise initializers for them as well. --- lib/ClangImporter/ImportDecl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 3e82783ef4b02..2e05ff0f8190e 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -3452,7 +3452,7 @@ namespace { ctors.push_back(createDefaultConstructor(Impl, result)); } - bool isAggregate = cxxRecordDecl && cxxRecordDecl->isAggregate(); + bool isAggregate = !cxxRecordDecl || cxxRecordDecl->isAggregate(); if (hasReferenceableFields && hasMemberwiseInitializer && isAggregate) { // The default zero initializer suppresses the implicit value // constructor that would normally be formed, so we have to add that From 20222bb2ad2cb09778ee110cc80b3a2b945e9fdd Mon Sep 17 00:00:00 2001 From: zoecarver Date: Sat, 10 Oct 2020 15:07:30 -0700 Subject: [PATCH 29/33] [cxx-interop] Bail if trying to convert call result to void. Don't try to coerce the result of a call to void. If the "expected" result type is void, just bail. --- lib/IRGen/GenCall.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/IRGen/GenCall.cpp b/lib/IRGen/GenCall.cpp index 60f4de3fccac7..6795d41cbd7a6 100644 --- a/lib/IRGen/GenCall.cpp +++ b/lib/IRGen/GenCall.cpp @@ -1924,6 +1924,9 @@ class SyncCallEmission final : public CallEmission { // This can happen when calling C functions, or class method dispatch thunks // for methods that have covariant ABI-compatible overrides. auto expectedNativeResultType = nativeSchema.getExpandedType(IGF.IGM); + // If the expected result type is void, bail. + if (expectedNativeResultType->isVoidTy()) + return; if (result->getType() != expectedNativeResultType) { result = IGF.coerceValue(result, expectedNativeResultType, IGF.IGM.DataLayout); From b2bb47dee5330234c8eb2fb2d0a41d67949831ec Mon Sep 17 00:00:00 2001 From: zoecarver Date: Sat, 10 Oct 2020 16:08:49 -0700 Subject: [PATCH 30/33] [cxx-interop] Fix Windows tests for non-trivial C++ types. * Replace `??1` with `??0` prefix in SILGen tests. * Replace `call void ` with `call {{.*}} ` because Windows ABI sometimes returns a pointer from the constructor for non-trivial types. * Make `noalias` an optional check. --- .../Cxx/class/type-classification-non-trivial-irgen.swift | 8 ++++---- .../class/type-classification-non-trivial-silgen.swift | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/Interop/Cxx/class/type-classification-non-trivial-irgen.swift b/test/Interop/Cxx/class/type-classification-non-trivial-irgen.swift index 501b444fa4774..2939b78732840 100644 --- a/test/Interop/Cxx/class/type-classification-non-trivial-irgen.swift +++ b/test/Interop/Cxx/class/type-classification-non-trivial-irgen.swift @@ -13,7 +13,7 @@ import TypeClassification // CHECK-LABEL: define {{.*}}i1 @"$s4main37testStructWithCopyConstructorAndValueSbyF" // CHECK: [[OBJ:%.*]] = alloca %TSo33StructWithCopyConstructorAndValueV // CHECK: [[STRUCT:%.*]] = bitcast %TSo33StructWithCopyConstructorAndValueV* [[OBJ]] to %struct.StructWithCopyConstructorAndValue* -// CHECK: call void @{{_ZN33StructWithCopyConstructorAndValueC(1|2)Ei|"\?\?0StructWithCopyConstructorAndValue@@QEAA@H@Z"}}(%struct.StructWithCopyConstructorAndValue* noalias [[STRUCT]], i32 42) +// CHECK: call {{.*}}@{{_ZN33StructWithCopyConstructorAndValueC(1|2)Ei|"\?\?0StructWithCopyConstructorAndValue@@QEAA@H@Z"}}(%struct.StructWithCopyConstructorAndValue* {{(noalias )?}}[[STRUCT]], i32 42) // CHECK: [[OBJ_VAL:%.*]] = getelementptr inbounds %TSo33StructWithCopyConstructorAndValueV, %TSo33StructWithCopyConstructorAndValueV* [[OBJ]], i32 0, i32 0 // CHECK: [[I_VAL:%.*]] = getelementptr inbounds %Ts5Int32V, %Ts5Int32V* [[OBJ_VAL]], i32 0, i32 0 // CHECK: [[I_VAL_VAL:%.*]] = load i32, i32* [[OBJ_VAL]] @@ -30,7 +30,7 @@ public func testStructWithCopyConstructorAndValue() -> Bool { // CHECK: alloca %TSo33StructWithCopyConstructorAndValueV // CHECK: [[TMP:%.*]] = alloca %TSo33StructWithCopyConstructorAndValueV // CHECK: [[MEMBER_STRUCT:%.*]] = bitcast %TSo33StructWithCopyConstructorAndValueV* %member to %struct.StructWithCopyConstructorAndValue* -// CHECK: call void @{{_ZN33StructWithCopyConstructorAndValueC(1|2)Ei|"\?\?0StructWithCopyConstructorAndValue@@QEAA@H@Z"}}(%struct.StructWithCopyConstructorAndValue* noalias [[MEMBER_STRUCT]], i32 42) +// CHECK: call {{.*}}@{{_ZN33StructWithCopyConstructorAndValueC(1|2)Ei|"\?\?0StructWithCopyConstructorAndValue@@QEAA@H@Z"}}(%struct.StructWithCopyConstructorAndValue* {{(noalias )?}}[[MEMBER_STRUCT]], i32 42) // CHECK: [[TEMP_MEMBER:%.*]] = getelementptr inbounds %TSo33StructWithCopyConstructorAndValueV, %TSo33StructWithCopyConstructorAndValueV* [[TMP]], i32 0, i32 0 // CHECK: [[TEMP_MEMBER_VALUE:%.*]] = getelementptr inbounds %Ts5Int32V, %Ts5Int32V* [[TEMP_MEMBER]], i32 0, i32 0 // CHECK: [[LHS:%.*]] = load i32, i32* [[TEMP_MEMBER_VALUE]] @@ -48,10 +48,10 @@ public func testStructWithSubobjectCopyConstructorAndValue() -> Bool { // CHECK: [[TEMP:%.*]] = alloca %TSo33StructWithCopyConstructorAndValueV // CHECK: [[TEMP2:%.*]] = alloca %TSo33StructWithCopyConstructorAndValueV // CHECK: [[MEMBER_STRUCT:%.*]] = bitcast %TSo33StructWithCopyConstructorAndValueV* %member to %struct.StructWithCopyConstructorAndValue* -// CHECK: call void @{{_ZN33StructWithCopyConstructorAndValueC(1|2)Ei|"\?\?0StructWithCopyConstructorAndValue@@QEAA@H@Z"}}(%struct.StructWithCopyConstructorAndValue* noalias [[MEMBER_STRUCT]], i32 42) +// CHECK: call {{.*}}@{{_ZN33StructWithCopyConstructorAndValueC(1|2)Ei|"\?\?0StructWithCopyConstructorAndValue@@QEAA@H@Z"}}(%struct.StructWithCopyConstructorAndValue* {{(noalias )?}}[[MEMBER_STRUCT]], i32 42) // CHECK: [[TEMP_AS_STRUCT:%.*]] = bitcast %TSo33StructWithCopyConstructorAndValueV* [[TEMP]] to %struct.StructWithCopyConstructorAndValue* // CHECK: [[OBJ_AS_STRUCT:%.*]] = bitcast %TSo037StructWithCopyConstructorAndSubobjectcdE5ValueV* [[OBJ]] to %struct.StructWithCopyConstructorAndSubobjectCopyConstructorAndValue* -// CHECK: call void @{{_ZN60StructWithCopyConstructorAndSubobjectCopyConstructorAndValueC(1|2)E33StructWithCopyConstructorAndValue|"\?\?0StructWithCopyConstructorAndSubobjectCopyConstructorAndValue@@QEAA@UStructWithCopyConstructorAndValue@@@Z"}}(%struct.StructWithCopyConstructorAndSubobjectCopyConstructorAndValue* noalias [[OBJ_AS_STRUCT]], %struct.StructWithCopyConstructorAndValue* [[TEMP_AS_STRUCT]]) +// CHECK: call {{.*}}@{{_ZN60StructWithCopyConstructorAndSubobjectCopyConstructorAndValueC(1|2)E33StructWithCopyConstructorAndValue|"\?\?0StructWithCopyConstructorAndSubobjectCopyConstructorAndValue@@QEAA@UStructWithCopyConstructorAndValue@@@Z"}}(%struct.StructWithCopyConstructorAndSubobjectCopyConstructorAndValue* {{(noalias )?}}[[OBJ_AS_STRUCT]], %struct.StructWithCopyConstructorAndValue* [[TEMP_AS_STRUCT]]) // CHECK: [[TEMP_MEMBER:%.*]] = getelementptr inbounds %TSo33StructWithCopyConstructorAndValueV, %TSo33StructWithCopyConstructorAndValueV* [[TEMP2]], i32 0, i32 0 // CHECK: [[TEMP_MEMBER_VAL:%.*]] = getelementptr inbounds %Ts5Int32V, %Ts5Int32V* [[TEMP_MEMBER]], i32 0, i32 0 // CHECK: [[LHS:%.*]] = load i32, i32* [[TEMP_MEMBER_VAL]] diff --git a/test/Interop/Cxx/class/type-classification-non-trivial-silgen.swift b/test/Interop/Cxx/class/type-classification-non-trivial-silgen.swift index 51f00d5268432..156665a06912b 100644 --- a/test/Interop/Cxx/class/type-classification-non-trivial-silgen.swift +++ b/test/Interop/Cxx/class/type-classification-non-trivial-silgen.swift @@ -21,12 +21,12 @@ public func testStructWithDestructor() { // for a "destroy_addr". // CHECK-LABEL: sil [ossa] @$s4main33testStructWithSubobjectDestructoryyF : $@convention(thin) () -> () // CHECK: [[AS:%.*]] = alloc_stack $StructWithSubobjectDestructor -// CHECK: [[FN:%.*]] = function_ref @{{_ZN29StructWithSubobjectDestructorC1Ev|\?\?1StructWithSubobjectDestructor@@QEAA@XZ}} : $@convention(c) () -> @out StructWithSubobjectDestructor +// CHECK: [[FN:%.*]] = function_ref @{{_ZN29StructWithSubobjectDestructorC1Ev|\?\?0StructWithSubobjectDestructor@@QEAA@XZ}} : $@convention(c) () -> @out StructWithSubobjectDestructor // CHECK: apply [[FN]]([[AS]]) : $@convention(c) () -> @out StructWithSubobjectDestructor // CHECK: destroy_addr [[AS]] // CHECK-LABEL: end sil function '$s4main33testStructWithSubobjectDestructoryyF' -// CHECK-LABEL: sil [clang StructWithSubobjectDestructor.init] @{{_ZN29StructWithSubobjectDestructorC1Ev|\?\?1StructWithSubobjectDestructor@@QEAA@XZ}} : $@convention(c) () -> @out StructWithSubobjectDestructor +// CHECK-LABEL: sil [clang StructWithSubobjectDestructor.init] @{{_ZN29StructWithSubobjectDestructorC1Ev|\?\?0StructWithSubobjectDestructor@@QEAA@XZ}} : $@convention(c) () -> @out StructWithSubobjectDestructor public func testStructWithSubobjectDestructor() { let d = StructWithSubobjectDestructor() } From 1d3b051151adee97b51408159f8205e9f28fcb9d Mon Sep 17 00:00:00 2001 From: zoecarver Date: Tue, 13 Oct 2020 11:44:45 -0700 Subject: [PATCH 31/33] [cxx-interop] Remove logic around applying attributes. Removes the logic around applying attributes to C++ constructor's indirect results. Also fixes some commenting. --- lib/ClangImporter/ImportDecl.cpp | 5 +---- lib/IRGen/GenCall.cpp | 18 ++--------------- .../Cxx/class/constructors-irgen.swift | 20 +++---------------- .../Cxx/class/constructors-objc-irgen.swift | 2 +- 4 files changed, 7 insertions(+), 38 deletions(-) diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 2e05ff0f8190e..b2128bea8b732 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -3522,9 +3522,6 @@ namespace { if (decl->getDefinition() && !decl->isBeingDefined() && !decl->isDependentContext() && decl->needsImplicitDefaultConstructor()) { - // Casting away const here should be OK because - // SwiftDeclConverter::Visit() is in practice called with a non-const - // argument. clang::CXXConstructorDecl *ctor = clangSema.DeclareImplicitDefaultConstructor( const_cast(decl)); @@ -3927,7 +3924,7 @@ namespace { FuncDecl *func = createFuncOrAccessor(Impl.SwiftContext, loc, accessorInfo, name, nameLoc, bodyParams, resultTy, - /*async*/ false, /*throws*/ false, dc, decl); + /*async=*/false, /*throws=*/false, dc, decl); result = func; if (!dc->isModuleScopeContext()) { diff --git a/lib/IRGen/GenCall.cpp b/lib/IRGen/GenCall.cpp index 6795d41cbd7a6..b795d16d433d8 100644 --- a/lib/IRGen/GenCall.cpp +++ b/lib/IRGen/GenCall.cpp @@ -338,12 +338,10 @@ llvm::CallingConv::ID irgen::expandCallingConv(IRGenModule &IGM, static void addIndirectResultAttributes(IRGenModule &IGM, llvm::AttributeList &attrs, - unsigned paramIndex, bool allowSRet, - bool noCapture = true) { + unsigned paramIndex, bool allowSRet) { llvm::AttrBuilder b; b.addAttribute(llvm::Attribute::NoAlias); - if (noCapture) - b.addAttribute(llvm::Attribute::NoCapture); + b.addAttribute(llvm::Attribute::NoCapture); if (allowSRet) b.addAttribute(llvm::Attribute::StructRet); attrs = attrs.addAttributes(IGM.getLLVMContext(), @@ -1429,18 +1427,6 @@ void SignatureExpansion::expandExternalSignatureTypes() { } } - if (formalIndirectResult) { - // If the result is a formal indirect result in SIL, that means that the - // Clang function has an explicit output parameter (e.g. it's a C++ - // constructor). This means: - // - Don't mark it `sret`, as this should only be used for C++ return - // values. - // - The Clang function might capture the pointer, so don't specify - // `nocapture`. - addIndirectResultAttributes(IGM, Attrs, 0, /* allowSRet = */ false, - /* noCapture = */ false); - } - if (returnInfo.isIndirect() || returnInfo.isIgnore()) { ResultIRType = IGM.VoidTy; } else { diff --git a/test/Interop/Cxx/class/constructors-irgen.swift b/test/Interop/Cxx/class/constructors-irgen.swift index 75b1c015c403a..4c4999bac484e 100644 --- a/test/Interop/Cxx/class/constructors-irgen.swift +++ b/test/Interop/Cxx/class/constructors-irgen.swift @@ -12,23 +12,9 @@ struct UnsafePointer { } struct UnsafeMutablePointer { } public func createHasVirtualBase() -> HasVirtualBase { - // - The `this` parameter should carry a `noalias` attribute, as it is - // guaranteed that nothing will alias the object before it has been fully - // constructed. Note that this doesn't apply on ABIs (Itanium ARM, - // Microsoft x64) where we insert an (inlined) thunk; in this case, we're - // getting the attributes of the constructor that was generated by Clang, - // which doesn't insert these attributes. - // - // - The `this` parameter should _not_ carry an `sret` attribute because the - // constructor doesn't return the constructed object as a return value. - // - // - The `this` parameter should _not_ carry a `nocapture` attribute (unlike - // Swift constructors that return their result indirectly) because the C++ - // constructor has explicit access to `this` and may capture it. - // // ITANIUM_X64: define swiftcc void @"$ss20createHasVirtualBaseSo0bcD0VyF"(%TSo14HasVirtualBaseV* noalias nocapture sret %0) // ITANIUM_X64-NOT: define - // ITANIUM_X64: call void @_ZN14HasVirtualBaseC1E7ArgType(%struct.HasVirtualBase* noalias %{{[0-9]+}}, i32 %{{[0-9]+}}) + // ITANIUM_X64: call void @_ZN14HasVirtualBaseC1E7ArgType(%struct.HasVirtualBase* %{{[0-9]+}}, i32 %{{[0-9]+}}) // // ITANIUM_ARM: define protected swiftcc void @"$ss20createHasVirtualBaseSo0bcD0VyF"(%TSo14HasVirtualBaseV* noalias nocapture sret %0) // To verify that the thunk is inlined, make sure there's no intervening @@ -48,7 +34,7 @@ public func createHasVirtualBase() -> HasVirtualBase { public func createImplicitDefaultConstructor() -> ImplicitDefaultConstructor { // ITANIUM_X64: define swiftcc i32 @"$ss32createImplicitDefaultConstructorSo0bcD0VyF"() // ITANIUM_X64-NOT: define - // ITANIUM_X64: call void @_ZN26ImplicitDefaultConstructorC1Ev(%struct.ImplicitDefaultConstructor* noalias %{{[0-9]+}}) + // ITANIUM_X64: call void @_ZN26ImplicitDefaultConstructorC1Ev(%struct.ImplicitDefaultConstructor* %{{[0-9]+}}) // // ITANIUM_ARM: define protected swiftcc i32 @"$ss32createImplicitDefaultConstructorSo0bcD0VyF"() // ITANIUM_ARM-NOT: define @@ -66,7 +52,7 @@ public func createStructWithSubobjectCopyConstructorAndValue() { // ITANIUM_X64-LABEL: define swiftcc void @"$ss48createStructWithSubobjectCopyConstructorAndValueyyF"() // ITANIUM_X64: [[MEMBER:%.*]] = alloca %TSo33StructWithCopyConstructorAndValueV // ITANIUM_X64: [[MEMBER_AS_STRUCT:%.*]] = bitcast %TSo33StructWithCopyConstructorAndValueV* %member to %struct.StructWithCopyConstructorAndValue* - // ITANIUM_X64: void @_ZN33StructWithCopyConstructorAndValueC1Ev(%struct.StructWithCopyConstructorAndValue* noalias [[MEMBER_AS_STRUCT]]) + // ITANIUM_X64: void @_ZN33StructWithCopyConstructorAndValueC1Ev(%struct.StructWithCopyConstructorAndValue* [[MEMBER_AS_STRUCT]]) // ITANIUM_X64: call %TSo33StructWithCopyConstructorAndValueV* @"$sSo33StructWithCopyConstructorAndValueVWOc"(%TSo33StructWithCopyConstructorAndValueV* [[MEMBER]], %TSo33StructWithCopyConstructorAndValueV* [[TMP:%.*]]) // ITANIUM_X64: [[OBJ_MEMBER:%.*]] = getelementptr inbounds %TSo42StructWithSubobjectCopyConstructorAndValueV, %TSo42StructWithSubobjectCopyConstructorAndValueV* %obj, i32 0, i32 0 // ITANIUM_X64: call %TSo33StructWithCopyConstructorAndValueV* @"$sSo33StructWithCopyConstructorAndValueVWOb"(%TSo33StructWithCopyConstructorAndValueV* [[TMP]], %TSo33StructWithCopyConstructorAndValueV* [[OBJ_MEMBER]]) diff --git a/test/Interop/Cxx/class/constructors-objc-irgen.swift b/test/Interop/Cxx/class/constructors-objc-irgen.swift index a5e8d4d162f87..9b9a0c939708f 100644 --- a/test/Interop/Cxx/class/constructors-objc-irgen.swift +++ b/test/Interop/Cxx/class/constructors-objc-irgen.swift @@ -11,6 +11,6 @@ public func createConstructorWithNSArrayParam() -> ConstructorWithNSArrayParam { // CHECK: [[VAR:%[0-9]+]] = alloca %TSo27ConstructorWithNSArrayParamV, align 1 // CHECK: %{{[0-9]+}} = call swiftcc %TSo7NSArrayC* @"$sSa10FoundationE19_bridgeToObjectiveCSo7NSArrayCyF"(%swift.bridge* %{{[0-9]+}}, %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* @"$sypN", i32 0, i32 1)) // CHECK: [[CAST_VAR:%[0-9]+]] = bitcast %TSo27ConstructorWithNSArrayParamV* [[VAR]] to %struct.ConstructorWithNSArrayParam* - // CHECK: call void @_ZN27ConstructorWithNSArrayParamC1EP7NSArray(%struct.ConstructorWithNSArrayParam* noalias [[CAST_VAR]], [[VAR]]* %{{[0-9]+}}) + // CHECK: call void @_ZN27ConstructorWithNSArrayParamC1EP7NSArray(%struct.ConstructorWithNSArrayParam* [[CAST_VAR]], [[VAR]]* %{{[0-9]+}}) return ConstructorWithNSArrayParam([]) } From d9acaf353e5a25a4b5c01c46702407925ab5e2c7 Mon Sep 17 00:00:00 2001 From: zoecarver Date: Wed, 14 Oct 2020 21:12:22 -0700 Subject: [PATCH 32/33] [cxx-interop] Merge synthesized initializer tests into "constructors-silgen". We no longer synthesize initializers for C++ types so this name no longer makes sense. --- test/Interop/Cxx/class/Inputs/constructors.h | 6 +++ .../class/Inputs/synthesized-initializers.h | 5 -- .../Cxx/class/constructors-silgen.swift | 54 +++++++++++++++++-- .../synthesized-initializers-silgen.swift | 44 --------------- 4 files changed, 56 insertions(+), 53 deletions(-) delete mode 100644 test/Interop/Cxx/class/Inputs/synthesized-initializers.h delete mode 100644 test/Interop/Cxx/class/synthesized-initializers-silgen.swift diff --git a/test/Interop/Cxx/class/Inputs/constructors.h b/test/Interop/Cxx/class/Inputs/constructors.h index 7959be4e0a4fe..738b13472f70a 100644 --- a/test/Interop/Cxx/class/Inputs/constructors.h +++ b/test/Interop/Cxx/class/Inputs/constructors.h @@ -37,3 +37,9 @@ struct HasVirtualBase : public virtual Base { HasVirtualBase(ArgType Arg) {} int i; }; + +struct EmptyStruct {}; + +struct IntWrapper { + int x; +}; diff --git a/test/Interop/Cxx/class/Inputs/synthesized-initializers.h b/test/Interop/Cxx/class/Inputs/synthesized-initializers.h deleted file mode 100644 index da20bf036bd10..0000000000000 --- a/test/Interop/Cxx/class/Inputs/synthesized-initializers.h +++ /dev/null @@ -1,5 +0,0 @@ -struct EmptyStruct {}; - -struct IntBox { - int x; -}; diff --git a/test/Interop/Cxx/class/constructors-silgen.swift b/test/Interop/Cxx/class/constructors-silgen.swift index 9472ff3cc08aa..3e256b4746e7e 100644 --- a/test/Interop/Cxx/class/constructors-silgen.swift +++ b/test/Interop/Cxx/class/constructors-silgen.swift @@ -1,12 +1,58 @@ -// RUN: %target-swift-frontend -I %S/Inputs -enable-cxx-interop -emit-sil %s | %FileCheck %s +// RUN: %target-swift-frontend -I %S/Inputs -enable-cxx-interop -emit-silgen %s | %FileCheck %s import Constructors // The most important thing to test here is that the constructor result is // returned with an @out attribute. +// CHECK-LABEL: sil [ossa] @$s4main24testConstructorWithParamyyF : $@convention(thin) () -> () // CHECK: [[VAR:%[0-9]+]] = alloc_stack $ConstructorWithParam -// CHECK: [[LITERAL:%[0-9]+]] = integer_literal $Builtin.Int32, 42 -// CHECK: [[INT:%[0-9]+]] = struct $Int32 ([[LITERAL]] : $Builtin.Int32) +// CHECK: [[LITERAL:%[0-9]+]] = integer_literal $Builtin.IntLiteral, 42 +// CHECK: [[INT:%[0-9]+]] = apply %{{[0-9]+}}([[LITERAL]], %{{[0-9]+}}) // CHECK: [[FUNC:%[0-9]+]] = function_ref @{{_ZN20ConstructorWithParamC1Ei|\?\?0ConstructorWithParam@@QEAA@H@Z}} : $@convention(c) (Int32) -> @out ConstructorWithParam // CHECK: %{{[0-9]+}} = apply [[FUNC]]([[VAR]], [[INT]]) : $@convention(c) (Int32) -> @out ConstructorWithParam -let _ = ConstructorWithParam(42) +// CHECK-LABEL: end sil function '$s4main24testConstructorWithParamyyF' + +// CHECK-LABEL: sil [clang ConstructorWithParam.init] @{{_ZN20ConstructorWithParamC1Ei|\?\?0ConstructorWithParam@@QEAA@H@Z}} : $@convention(c) (Int32) -> @out ConstructorWithParam +public func testConstructorWithParam() { + let c = ConstructorWithParam(42) +} + +// CHECK-LABEL: sil [ossa] @$s4main18emptyTypeNoArgInityyF : $@convention(thin) () -> () +// CHECK: [[AS:%.*]] = alloc_stack $EmptyStruct +// CHECK: [[FN:%.*]] = function_ref @{{_ZN11EmptyStructC1Ev|\?\?0EmptyStruct@@QEAA@XZ}} : $@convention(c) () -> @out EmptyStruct +// CHECK: apply [[FN]]([[AS]]) : $@convention(c) () -> @out EmptyStruct +// CHECK-LABEL: end sil function '$s4main18emptyTypeNoArgInityyF' + +// CHECL-LABEL: sil [clang EmptyStruct.init] @{{_ZN11EmptyStructC1Ev|\?\?0EmptyStruct@@QEAA@XZ}} : $@convention(c) () -> @out EmptyStruct +public func emptyTypeNoArgInit() { + let e = EmptyStruct() +} + +// CHECK-LABEL: sil [ossa] @$s4main25singleMemberTypeNoArgInityyF : $@convention(thin) () -> () +// CHECK: [[AS:%.*]] = alloc_stack $IntWrapper +// CHECK: [[FN:%.*]] = function_ref @{{_ZN10IntWrapperC1Ev|\?\?0IntWrapper@@QEAA@XZ}} : $@convention(c) () -> @out IntWrapper +// CHECK: apply [[FN]]([[AS]]) : $@convention(c) () -> @out IntWrapper +// CHECK-LABEL: end sil function '$s4main25singleMemberTypeNoArgInityyF' + +//CHECK-LABEL: sil [clang IntWrapper.init] @{{_ZN10IntWrapperC1Ev|\?\?0IntWrapper@@QEAA@XZ}} : $@convention(c) () -> @out IntWrapper +public func singleMemberTypeNoArgInit() { + let i = IntWrapper() +} + +// CHECK-LABEL: sil shared [transparent] [serializable] [ossa] @$sSo10IntWrapperV1xABs5Int32V_tcfC : $@convention(method) (Int32, @thin IntWrapper.Type) -> IntWrapper +// CHECK: bb0([[I:%[0-9]+]] : $Int32, %{{[0-9]+}} : $@thin IntWrapper.Type): +// CHECK-NEXT: [[S:%.*]] = struct $IntWrapper ([[I]] : $Int32) +// CHECK-NEXT: return [[S]] +// CHECK-LABEL: end sil function '$sSo10IntWrapperV1xABs5Int32V_tcfC' +public func singleMemberTypeValueInit() { + let i = IntWrapper(x: 42) +} + +// CHECK-LABEL: sil shared [transparent] [serializable] [ossa] @$sSo25DefaultConstructorDeletedV1aABSpys5Int32VG_tcfC : $@convention(method) (UnsafeMutablePointer, @thin DefaultConstructorDeleted.Type) -> DefaultConstructorDeleted +// CHECK: bb0([[A:%.*]] : $UnsafeMutablePointer +// CHECK-NEXT: [[OUT:%.*]] = struct $DefaultConstructorDeleted ([[A]] : $UnsafeMutablePointer) +// CHECK-NEXT: return [[OUT]] : $DefaultConstructorDeleted +// CHECK-LABEL: end sil function '$sSo25DefaultConstructorDeletedV1aABSpys5Int32VG_tcfC' +public func deletedConstructor(a: UnsafeMutablePointer) { + let deletedExplicitly = DefaultConstructorDeleted(a: a) +} diff --git a/test/Interop/Cxx/class/synthesized-initializers-silgen.swift b/test/Interop/Cxx/class/synthesized-initializers-silgen.swift deleted file mode 100644 index dac14a687a652..0000000000000 --- a/test/Interop/Cxx/class/synthesized-initializers-silgen.swift +++ /dev/null @@ -1,44 +0,0 @@ -// RUN: %target-swift-frontend -I %S/Inputs -enable-cxx-interop -emit-silgen %s | %FileCheck %s - -import SynthesizedInitializers -import Constructors - -// CHECK-LABEL: sil [ossa] @$s4main18emptyTypeNoArgInityyF : $@convention(thin) () -> () -// CHECK: [[AS:%.*]] = alloc_stack $EmptyStruct -// CHECK: [[FN:%.*]] = function_ref @{{_ZN11EmptyStructC1Ev|\?\?0EmptyStruct@@QEAA@XZ}} : $@convention(c) () -> @out EmptyStruct -// CHECK: apply [[FN]]([[AS]]) : $@convention(c) () -> @out EmptyStruct -// CHECK-LABEL: end sil function '$s4main18emptyTypeNoArgInityyF' - -// CHECL-LABEL: sil [clang EmptyStruct.init] @{{_ZN11EmptyStructC1Ev|\?\?0EmptyStruct@@QEAA@XZ}} : $@convention(c) () -> @out EmptyStruct -public func emptyTypeNoArgInit() { - let e = EmptyStruct() -} - -// CHECK-LABEL: sil [ossa] @$s4main25singleMemberTypeNoArgInityyF : $@convention(thin) () -> () -// CHECK: [[AS:%.*]] = alloc_stack $IntBox -// CHECK: [[FN:%.*]] = function_ref @{{_ZN6IntBoxC1Ev|\?\?0IntBox@@QEAA@XZ}} : $@convention(c) () -> @out IntBox -// CHECK: apply [[FN]]([[AS]]) : $@convention(c) () -> @out IntBox -// CHECK-LABEL: end sil function '$s4main25singleMemberTypeNoArgInityyF' - -//CHECK-LABEL: sil [clang IntBox.init] @{{_ZN6IntBoxC1Ev|\?\?0IntBox@@QEAA@XZ}} : $@convention(c) () -> @out IntBox -public func singleMemberTypeNoArgInit() { - let i = IntBox() -} - -// CHECK-LABEL: sil shared [transparent] [serializable] [ossa] @$sSo6IntBoxV1xABs5Int32V_tcfC : $@convention(method) (Int32, @thin IntBox.Type) -> IntBox -// CHECK: bb0([[I:%[0-9]+]] : $Int32, %{{[0-9]+}} : $@thin IntBox.Type): -// CHECK-NEXT: [[S:%.*]] = struct $IntBox ([[I]] : $Int32) -// CHECK-NEXT: return [[S]] -// CHECK-LABEL: end sil function '$sSo6IntBoxV1xABs5Int32V_tcfC' -public func singleMemberTypeValueInit() { - let i = IntBox(x: 42) -} - -// CHECK-LABEL: sil shared [transparent] [serializable] [ossa] @$sSo25DefaultConstructorDeletedV1aABSpys5Int32VG_tcfC : $@convention(method) (UnsafeMutablePointer, @thin DefaultConstructorDeleted.Type) -> DefaultConstructorDeleted -// CHECK: bb0([[A:%.*]] : $UnsafeMutablePointer -// CHECK-NEXT: [[OUT:%.*]] = struct $DefaultConstructorDeleted ([[A]] : $UnsafeMutablePointer) -// CHECK-NEXT: return [[OUT]] : $DefaultConstructorDeleted -// CHECK-LABEL: end sil function '$sSo25DefaultConstructorDeletedV1aABSpys5Int32VG_tcfC' -public func deletedConstructor(a: UnsafeMutablePointer) { - let deletedExplicitly = DefaultConstructorDeleted(a: a) -} From 545b44e9c14f7423ec1c881c1450b8b3a568bf75 Mon Sep 17 00:00:00 2001 From: zoecarver Date: Fri, 16 Oct 2020 08:21:58 -0700 Subject: [PATCH 33/33] [cxx-interop] Look through template decl to find constructor when importing the function name. Sometimes, on windows, we get a function template wrapping the constructor decl. In this case, look through the function template to find the constructor decl. --- lib/ClangImporter/ImportName.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/ClangImporter/ImportName.cpp b/lib/ClangImporter/ImportName.cpp index 79fcd57ccc141..9e22535c2fddf 100644 --- a/lib/ClangImporter/ImportName.cpp +++ b/lib/ClangImporter/ImportName.cpp @@ -1608,14 +1608,18 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D, SmallString<16> selectorSplitScratch; ArrayRef params; switch (D->getDeclName().getNameKind()) { - case clang::DeclarationName::CXXConstructorName: + case clang::DeclarationName::CXXConstructorName: { isInitializer = true; isFunction = true; result.info.initKind = CtorInitializerKind::Designated; baseName = "init"; - addEmptyArgNamesForClangFunction(cast(D), - argumentNames); + auto ctor = dyn_cast(D); + if (auto templateCtor = dyn_cast(D)) + ctor = cast(templateCtor->getAsFunction()); + assert(ctor && "Unkown decl with CXXConstructorName."); + addEmptyArgNamesForClangFunction(ctor, argumentNames); break; + } case clang::DeclarationName::CXXConversionFunctionName: case clang::DeclarationName::CXXDestructorName: