diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index b3093cfb426d5..88b6867ecf705 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -594,7 +594,7 @@ class ASTContext final { /// information, in case it is needed. /// \param trueRep The actual calling convention, which must be C-compatible. /// The calling convention in \p incompleteExtInfo is ignored. - const clang::Type * + ClangTypeWrapper getClangFunctionType(ArrayRef params, Type resultTy, const FunctionType::ExtInfo incompleteExtInfo, FunctionTypeRepresentation trueRep); @@ -602,7 +602,7 @@ class ASTContext final { /// Get the canonical Clang type corresponding to a SIL function type. /// /// SIL analog of \c ASTContext::getClangFunctionType . - const clang::Type * + ClangTypeWrapper getCanonicalClangFunctionType( ArrayRef params, Optional result, const SILFunctionType::ExtInfo incompleteExtInfo, diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index cacf039e53743..a57a157cb9bca 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -341,7 +341,7 @@ class alignas(1 << TypeAlignInBits) TypeBase { /// Extra information which affects how the function is called, like /// regparm and the calling convention. ExtInfoBits : NumAFTExtInfoBits, - HasUncommonInfo : 1, + HasClangType : 1, : NumPadBits, NumParams : 16 ); @@ -364,7 +364,7 @@ class alignas(1 << TypeAlignInBits) TypeBase { SWIFT_INLINE_BITFIELD(SILFunctionType, TypeBase, NumSILExtInfoBits+1+3+1+2, ExtInfoBits : NumSILExtInfoBits, - HasUncommonInfo : 1, + HasClangType : 1, CalleeConvention : 3, HasErrorResult : 1, CoroutineKind : 2 @@ -2759,6 +2759,90 @@ getSILFunctionLanguage(SILFunctionTypeRepresentation rep) { llvm_unreachable("Unhandled SILFunctionTypeRepresentation in switch."); } +/// A wrapper over a `const clang::Type *` which additionally tracks a +/// "is this derivable from a Swift type" bit. +/// +/// This is useful for propagating Clang types through the AST and SIL until +/// IRGen, where we may need the Clang type and derivability information for +/// computing the mangled name. +// {ptr != 0, bool = true} -> Has Clang type, derivable from Swift type +// {ptr != 0, bool = false} -> Has Clang type, not derivable from Swift type +// {ptr == 0, bool = true} -> Impossible +// {ptr == 0, bool = false} -> No Clang type, no derivability information +class ClangTypeWrapper { + // We can't use const clang::Type * because PointerIntPair needs the alignment + // for clang::Type. We could forward-declare the alignment in TypeAlignment.h, + // but that creates an error + // redefinition of 'PointerLikeTypeTraits' + // in files that include both TypeAlignment.h and clang/AST/Type.h, since the + // latter also defines that template. + llvm::PointerIntPair inner; + + ClangTypeWrapper(const clang::Type *ty, bool b) : + inner(reinterpret_cast(const_cast(ty)), b) {} + + const void *getOpaqueValue() const { + return inner.getOpaqueValue(); + } + + const clang::Type *getType() const { + return reinterpret_cast(inner.getPointer()); + } + + ClangTypeWrapper getCanonicalType() const; + bool isCanonical() const; + + friend class AnyFunctionType; + friend class FunctionType; + friend class SILFunctionType; + friend class ClangTypeConverter; + +public: + ClangTypeWrapper(std::nullptr_t) : ClangTypeWrapper(nullptr, false) {} + + bool empty() const { + return !getType(); + } + + bool isDerivableFromSwiftType() const { + return inner.getInt(); + } + + static ClangTypeWrapper derivableFromSwiftType(const clang::Type *ty) { + assert(ty && "Use the ClangTypeWrapper(nullptr) overload."); + return ClangTypeWrapper(ty, true); + } + + static ClangTypeWrapper notDerivableFromSwiftType(const clang::Type *ty) { + assert(ty && "Use the ClangTypeWrapper(nullptr) overload."); + return ClangTypeWrapper(ty, false); + } + + /// Check if we should prefer the parsed type for storage in an ExtInfo. + /// + /// Prefer the parsed type over the computed type (this) in case they are + /// not exactly equivalent, since the parsed type will have greater fidelity + /// (sugar and attributes). + /// + /// NOTE: Sometimes, two Clang (canonical) types may differ in a way that + /// doesn't really matter from a Swift perspective. For example, the parsed + /// type may have a "__kindof" which is never part of a computed type. + /// We don't strip such attributes. Instead, we return the parsed type marked + /// non-derivable (even if it is derivable upto differences of + /// "__kindof". + static ClangTypeWrapper pickForExtInfo(const clang::Type *parsed, + ClangTypeWrapper computed); + + void printType(ClangModuleLoader *cml, + llvm::raw_ostream &os) const; + + /// Check that the type is a function pointer or block pointer (in debug). + void assertIsFunctionType() const; + + bool operator==(ClangTypeWrapper other) const; + bool operator!=(ClangTypeWrapper other) const { return !(*this == other); } +}; + /// AnyFunctionType - A function type has zero or more input parameters and a /// single result. The result type may be a tuple. For example: /// "(int) -> int" or "(a : int, b : int) -> (int, int)". @@ -2941,39 +3025,21 @@ class AnyFunctionType : public TypeBase { unsigned Bits; // Naturally sized for speed. - public: - class Uncommon { - friend ExtInfo; - friend class AnyFunctionType; - friend class FunctionType; - friend class SILUncommonInfo; - // We preserve a full clang::Type *, not a clang::FunctionType * as: - // 1. We need to keep sugar in case we need to present an error to the user. - // 2. The actual type being stored is [ignoring sugar] either a - // clang::PointerType or a clang::BlockPointerType which points to a - // clang::FunctionType. - const clang::Type *ClangFunctionType; - - bool empty() const { return !ClangFunctionType; } - Uncommon(const clang::Type *type) : ClangFunctionType(type) {} - - public: - /// Use the ClangModuleLoader to print the Clang type as a string. - void printClangFunctionType(ClangModuleLoader *cml, - llvm::raw_ostream &os); - }; - private: - Uncommon Other; - - static void assertIsFunctionType(const clang::Type *); - - ExtInfo(unsigned Bits, Uncommon Other) : Bits(Bits), Other(Other) { + // Keeps track of a clang::Type * (not a clang::FunctionType *) as: + // 1. We need to keep sugar in case we need to present an error to the user. + // 2. The actual type being stored is (ignoring sugar) either a + // clang::PointerType or a clang::BlockPointerType which points to a + // clang::FunctionType. + ClangTypeWrapper Other; + + ExtInfo(unsigned Bits, ClangTypeWrapper Other) : Bits(Bits), + Other(Other) { // TODO: [clang-function-type-serialization] Once we start serializing // the Clang type, we should also assert that the pointer is non-null. auto Rep = Representation(Bits & RepresentationMask); - if ((Rep == Representation::CFunctionPointer) && Other.ClangFunctionType) - assertIsFunctionType(Other.ClangFunctionType); + if ((Rep == Representation::CFunctionPointer) && !Other.empty()) + Other.assertIsFunctionType(); } friend AnyFunctionType; @@ -2996,13 +3062,13 @@ class AnyFunctionType : public TypeBase { // Constructor with no defaults. ExtInfo(Representation Rep, bool IsNoEscape, bool Throws, DifferentiabilityKind DiffKind, - const clang::Type *type) + ClangTypeWrapper clangTy) : ExtInfo(((unsigned) Rep) | (IsNoEscape ? NoEscapeMask : 0) | (Throws ? ThrowsMask : 0) | (((unsigned)DiffKind << DifferentiabilityMaskOffset) & DifferentiabilityMask), - Uncommon(type)) { + clangTy) { } bool isNoEscape() const { return Bits & NoEscapeMask; } @@ -3022,9 +3088,9 @@ class AnyFunctionType : public TypeBase { return Representation(rawRep); } - /// Return the underlying Uncommon value if it is not the default value. - Optional getUncommonInfo() const { - return Other.empty() ? Optional() : Other; + /// Return the underlying Clang type if it is not the default value. + Optional getClangTypeWrapper() const { + return Other.empty() ? Optional() : Other; } bool hasSelfParam() const { @@ -3080,12 +3146,12 @@ class AnyFunctionType : public TypeBase { Other); } LLVM_NODISCARD - ExtInfo withClangFunctionType(const clang::Type *type) const { - return ExtInfo(Bits, Uncommon(type)); + ExtInfo withClangFunctionType(ClangTypeWrapper ty) const { + return ExtInfo(Bits, ty); } std::pair getFuncAttrKey() const { - return std::make_pair(Bits, Other.ClangFunctionType); + return std::make_pair(Bits, Other.inner.getOpaqueValue()); } /// Put a SIL representation in the ExtInfo. @@ -3103,11 +3169,11 @@ class AnyFunctionType : public TypeBase { return SILFunctionTypeRepresentation(rawRep); } - bool operator==(ExtInfo Other) const { - return Bits == Other.Bits; + bool operator==(ExtInfo OtherExt) const { + return Bits == OtherExt.Bits && Other == OtherExt.Other; } - bool operator!=(ExtInfo Other) const { - return Bits != Other.Bits; + bool operator!=(ExtInfo OtherExt) const { + return !(*this == OtherExt); } }; @@ -3121,7 +3187,7 @@ class AnyFunctionType : public TypeBase { unsigned NumParams, ExtInfo Info) : TypeBase(Kind, CanTypeContext, properties), Output(Output) { Bits.AnyFunctionType.ExtInfoBits = Info.Bits; - Bits.AnyFunctionType.HasUncommonInfo = Info.getUncommonInfo().hasValue(); + Bits.AnyFunctionType.HasClangType = Info.getClangTypeWrapper().hasValue(); Bits.AnyFunctionType.NumParams = NumParams; assert(Bits.AnyFunctionType.NumParams == NumParams && "Params dropped!"); // The use of both assert() and static_assert() is intentional. @@ -3165,11 +3231,11 @@ class AnyFunctionType : public TypeBase { GenericSignature getOptGenericSignature() const; bool hasClangFunctionType() const { - return Bits.AnyFunctionType.HasUncommonInfo; + return Bits.AnyFunctionType.HasClangType; } - const clang::Type *getClangFunctionType() const; - const clang::Type *getCanonicalClangFunctionType() const; + ClangTypeWrapper getClangFunctionType() const; + ClangTypeWrapper getCanonicalClangFunctionType() const; ExtInfo getExtInfo() const { return ExtInfo(Bits.AnyFunctionType.ExtInfoBits, getClangFunctionType()); @@ -3325,15 +3391,14 @@ inline AnyFunctionType::CanYield AnyFunctionType::Yield::getCanonical() const { class FunctionType final : public AnyFunctionType, public llvm::FoldingSetNode, private llvm::TrailingObjects { + ClangTypeWrapper> { friend TrailingObjects; - size_t numTrailingObjects(OverloadToken) const { return getNumParams(); } - size_t numTrailingObjects(OverloadToken) const { + size_t numTrailingObjects(OverloadToken) const { return hasClangFunctionType() ? 1 : 0; } @@ -3347,12 +3412,12 @@ class FunctionType final : public AnyFunctionType, return {getTrailingObjects(), getNumParams()}; } - const clang::Type *getClangFunctionType() const { + ClangTypeWrapper getClangFunctionType() const { if (!hasClangFunctionType()) return nullptr; - auto *type = getTrailingObjects()->ClangFunctionType; - assert(type && "If the pointer was null, we shouldn't have stored it."); - return type; + auto cty = *getTrailingObjects(); + assert(cty.getType() && "Shouldn't have stored a null pointer."); + return cty; } void Profile(llvm::FoldingSetNodeID &ID) { @@ -3917,24 +3982,6 @@ namespace Lowering { class TypeConverter; }; -class SILUncommonInfo { - friend class SILFunctionType; - - // Invariant: The FunctionType is canonical. - // We store a clang::FunctionType * instead of a clang::CanQualType to - // avoid depending on the Clang AST in this header. - const clang::Type *ClangFunctionType; - - bool empty() const { return !ClangFunctionType; } - SILUncommonInfo(const clang::Type *type) : ClangFunctionType(type) {} - SILUncommonInfo(AnyFunctionType::ExtInfo::Uncommon uncommon); - -public: - /// Analog of AnyFunctionType::ExtInfo::Uncommon::printClangFunctionType. - void printClangFunctionType(ClangModuleLoader *cml, - llvm::raw_ostream &os) const; -}; - /// SILFunctionType - The lowered type of a function value, suitable /// for use by SIL. /// @@ -3944,7 +3991,7 @@ class SILUncommonInfo { class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode, private llvm::TrailingObjects { + ClangTypeWrapper> { friend TrailingObjects; size_t numTrailingObjects(OverloadToken) const { @@ -3963,8 +4010,8 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode, return hasResultCache() ? 2 : 0; } - size_t numTrailingObjects(OverloadToken) const { - return Bits.SILFunctionType.HasUncommonInfo ? 1 : 0; + size_t numTrailingObjects(OverloadToken) const { + return Bits.SILFunctionType.HasClangType ? 1 : 0; } public: @@ -3992,18 +4039,16 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode, unsigned Bits; // Naturally sized for speed. // For symmetry with AnyFunctionType::Uncommon - using Uncommon = SILUncommonInfo; + using Uncommon = ClangTypeWrapper; Uncommon Other; - static void assertIsFunctionType(const clang::Type *); - ExtInfo(unsigned Bits, Uncommon Other) : Bits(Bits), Other(Other) { auto Rep = Representation(Bits & RepresentationMask); // TODO: [clang-function-type-serialization] Once we start serializing // the Clang type, we should also assert that the pointer is non-null. - if ((Rep == Representation::CFunctionPointer) && Other.ClangFunctionType) - assertIsFunctionType(Other.ClangFunctionType); + if ((Rep == Representation::CFunctionPointer) && !Other.empty()) + Other.assertIsFunctionType(); } static constexpr unsigned makeBits(Representation rep, @@ -4025,9 +4070,9 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode, // Constructor for polymorphic type. ExtInfo(Representation rep, bool isPseudogeneric, bool isNoEscape, DifferentiabilityKind diffKind, - const clang::Type *type) + ClangTypeWrapper type) : ExtInfo(makeBits(rep, isPseudogeneric, isNoEscape, diffKind), - Uncommon(type)) { + type) { } ExtInfo(AnyFunctionType::ExtInfo info, bool isPseudogeneric) @@ -4035,8 +4080,8 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode, isPseudogeneric, info.isNoEscape(), info.getDifferentiabilityKind()), - info.getUncommonInfo().hasValue() - ? Uncommon(info.getUncommonInfo().getValue()) + info.getClangTypeWrapper().hasValue() + ? Uncommon(info.getClangTypeWrapper().getValue()) : Uncommon(nullptr)) { } @@ -4071,8 +4116,8 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode, } /// Return the underlying Uncommon value if it is not the default value. - Optional getUncommonInfo() const { - return Other.empty() ? Optional() : Other; + Optional getClangTypeWrapper() const { + return Other.empty() ? Optional() : Other; } bool hasSelfParam() const { @@ -4126,19 +4171,19 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode, return ExtInfo(NoEscape ? (Bits | NoEscapeMask) : (Bits & ~NoEscapeMask), Other); } - ExtInfo withClangFunctionType(const clang::Type *type) const { - return ExtInfo(Bits, Uncommon(type)); + ExtInfo withClangFunctionType(ClangTypeWrapper Type) const { + return ExtInfo(Bits, Type); } std::pair getFuncAttrKey() const { - return std::make_pair(Bits, Other.ClangFunctionType); + return std::make_pair(Bits, Other.getOpaqueValue()); } - bool operator==(ExtInfo Other) const { - return Bits == Other.Bits; + bool operator==(ExtInfo OtherExt) const { + return Bits == OtherExt.Bits && Other == OtherExt.Other; } - bool operator!=(ExtInfo Other) const { - return Bits != Other.Bits; + bool operator!=(ExtInfo OtherExt) const { + return !(*this == OtherExt); } }; @@ -4424,7 +4469,7 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode, return WitnessMethodConformance; } - const clang::Type *getClangFunctionType() const; + ClangTypeWrapper getClangFunctionType() const; ExtInfo getExtInfo() const { return ExtInfo(Bits.SILFunctionType.ExtInfoBits, getClangFunctionType()); diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index f7ad4fb5792da..b85aaba218dbc 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -3032,17 +3032,17 @@ FunctionType *FunctionType::get(ArrayRef params, return funcTy; } - Optional uncommon = info.getUncommonInfo(); + Optional clangType = info.getClangTypeWrapper(); size_t allocSize = - totalSizeToAlloc( - params.size(), uncommon.hasValue() ? 1 : 0); + totalSizeToAlloc( + params.size(), clangType.hasValue() ? 1 : 0); void *mem = ctx.Allocate(allocSize, alignof(FunctionType), arena); bool isCanonical = isFunctionTypeCanonical(params, result); - if (uncommon.hasValue()) { + if (clangType.hasValue()) { if (ctx.LangOpts.UseClangFunctionTypes) - isCanonical &= uncommon->ClangFunctionType->isCanonicalUnqualified(); + isCanonical &= clangType->isCanonical(); else isCanonical = false; } @@ -3063,9 +3063,9 @@ FunctionType::FunctionType(ArrayRef params, output, properties, params.size(), info) { std::uninitialized_copy(params.begin(), params.end(), getTrailingObjects()); - Optional uncommon = info.getUncommonInfo(); - if (uncommon.hasValue()) - *getTrailingObjects() = uncommon.getValue(); + Optional clangType = info.getClangTypeWrapper(); + if (clangType.hasValue()) + *getTrailingObjects() = clangType.getValue(); } void GenericFunctionType::Profile(llvm::FoldingSetNodeID &ID, @@ -3158,17 +3158,6 @@ ArrayRef GenericFunctionType::getRequirements() const { return Signature->getRequirements(); } -SILUncommonInfo::SILUncommonInfo(AnyFunctionType::ExtInfo::Uncommon uncommon) { - auto *ty = uncommon.ClangFunctionType; - ClangFunctionType = ty ? ty->getCanonicalTypeInternal().getTypePtr() - : nullptr; -} - -void SILUncommonInfo::printClangFunctionType( - ClangModuleLoader *cml, llvm::raw_ostream &os) const { - cml->printClangType(ClangFunctionType, os); -} - void SILFunctionType::Profile( llvm::FoldingSetNodeID &id, GenericSignature genericParams, @@ -3234,7 +3223,7 @@ SILFunctionType::SILFunctionType( assert(Bits.SILFunctionType.ExtInfoBits == ext.Bits && "Bits were dropped!"); static_assert(ExtInfo::NumMaskBits == NumSILExtInfoBits, "ExtInfo and SILFunctionTypeBitfields must agree on bit size"); - Bits.SILFunctionType.HasUncommonInfo = ext.getUncommonInfo().hasValue(); + Bits.SILFunctionType.HasClangType = ext.getClangTypeWrapper().hasValue(); Bits.SILFunctionType.CoroutineKind = unsigned(coroutineKind); NumParameters = params.size(); if (coroutineKind == SILCoroutineKind::None) { @@ -3267,8 +3256,8 @@ SILFunctionType::SILFunctionType( getMutableFormalResultsCache() = CanType(); getMutableAllResultsCache() = CanType(); } - if (auto uncommon = ext.getUncommonInfo()) - *getTrailingObjects() = uncommon.getValue(); + if (auto clangType = ext.getClangTypeWrapper()) + *getTrailingObjects() = clangType.getValue(); #ifndef NDEBUG if (ext.getRepresentation() == Representation::WitnessMethod) @@ -3390,10 +3379,10 @@ CanSILFunctionType SILFunctionType::get( // See [SILFunctionType-layout] bool hasResultCache = normalResults.size() > 1; size_t bytes = totalSizeToAlloc( + CanType, ClangTypeWrapper>( params.size(), normalResults.size() + (errorResult ? 1 : 0), yields.size(), hasResultCache ? 2 : 0, - ext.getUncommonInfo().hasValue() ? 1 : 0); + ext.getClangTypeWrapper().hasValue() ? 1 : 0); void *mem = ctx.Allocate(bytes, alignof(SILFunctionType)); @@ -4395,17 +4384,18 @@ ASTContext::initializeClangTypeConverter() { } } -const clang::Type * +ClangTypeWrapper ASTContext::getClangFunctionType(ArrayRef params, Type resultTy, FunctionType::ExtInfo incompleteExtInfo, FunctionTypeRepresentation trueRep) { initializeClangTypeConverter(); - return getImpl().Converter.getValue().getFunctionType(params, resultTy, - trueRep); + auto *ty = getImpl().Converter.getValue().getFunctionType(params, resultTy, + trueRep); + return ty ? ClangTypeWrapper::derivableFromSwiftType(ty) : nullptr; } -const clang::Type * +ClangTypeWrapper ASTContext::getCanonicalClangFunctionType( ArrayRef params, Optional result, @@ -4414,7 +4404,7 @@ ASTContext::getCanonicalClangFunctionType( initializeClangTypeConverter(); auto *ty = getImpl().Converter.getValue().getFunctionType(params, result, trueRep); - return ty ? ty->getCanonicalTypeInternal().getTypePtr() : nullptr; + return ty ? ClangTypeWrapper::derivableFromSwiftType(ty) : nullptr; } CanGenericSignature ASTContext::getSingleGenericParameterSignature() const { diff --git a/lib/AST/ASTDemangler.cpp b/lib/AST/ASTDemangler.cpp index 86fbd7b5e8af2..be7df52218eca 100644 --- a/lib/AST/ASTDemangler.cpp +++ b/lib/AST/ASTDemangler.cpp @@ -397,7 +397,7 @@ Type ASTBuilder::createFunctionType( DifferentiabilityKind::NonDifferentiable, /*clangFunctionType*/nullptr); - const clang::Type *clangFunctionType = nullptr; + ClangTypeWrapper clangFunctionType(nullptr); if (representation == FunctionTypeRepresentation::CFunctionPointer) clangFunctionType = Ctx.getClangFunctionType(funcParams, output, incompleteExtInfo, @@ -511,7 +511,7 @@ Type ASTBuilder::createImplFunctionType( funcErrorResult.emplace(type, conv); } - const clang::Type *clangFnType = nullptr; + ClangTypeWrapper clangFnType(nullptr); auto incompleteExtInfo = SILFunctionType::ExtInfo( SILFunctionType::Representation::Thick, flags.isPseudogeneric(), !flags.isEscaping(), DifferentiabilityKind::NonDifferentiable, diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 413f54db7cc79..49ee94b01bcc2 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -3633,11 +3633,13 @@ namespace { OS << "\n"; Indent += 2; - if (auto *cty = T->getClangFunctionType()) { + auto cty = T->getClangFunctionType(); + if (!cty.empty()) { std::string s; llvm::raw_string_ostream os(s); - cty->dump(os); - printField("clang_type", os.str()); + cty.printType(T->getASTContext().getClangModuleLoader(), os); + printField("clang_type", QuotedString(os.str())); + printFlag(cty.isDerivableFromSwiftType(), "derivable_from_swift_type"); } printAnyFunctionParams(T->getParams(), "input"); Indent -=2; diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 1fe355d76bc47..378efcb010ba8 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -3499,7 +3499,7 @@ void printCType(ASTContext &Ctx, ASTPrinter &Printer, ExtInfo &info) { auto *cml = Ctx.getClangModuleLoader(); SmallString<64> buf; llvm::raw_svector_ostream os(buf); - info.getUncommonInfo().getValue().printClangFunctionType(cml, os); + info.getClangTypeWrapper().getValue().printType(cml, os); Printer << ", cType: " << QuotedString(os.str()); } @@ -3907,7 +3907,7 @@ class TypePrinter : public TypeVisitor { Printer << "c"; // FIXME: [clang-function-type-serialization] Once we start serializing // Clang function types, we should be able to remove the second check. - if (printNameOnly || !info.getUncommonInfo().hasValue()) + if (printNameOnly || !info.getClangTypeWrapper().hasValue()) break; printCType(Ctx, Printer, info); break; @@ -3974,7 +3974,7 @@ class TypePrinter : public TypeVisitor { Printer << "c"; // FIXME: [clang-function-type-serialization] Once we start serializing // Clang function types, we should be able to remove the second check. - if (printNameOnly || !info.getUncommonInfo().hasValue()) + if (printNameOnly || !info.getClangTypeWrapper().hasValue()) break; printCType(Ctx, Printer, info); break; diff --git a/lib/AST/ClangTypeConverter.cpp b/lib/AST/ClangTypeConverter.cpp index 8ebc7816ebcae..5cc3e8d431c0e 100644 --- a/lib/AST/ClangTypeConverter.cpp +++ b/lib/AST/ClangTypeConverter.cpp @@ -617,12 +617,12 @@ clang::QualType ClangTypeConverter::visitEnumType(EnumType *type) { clang::QualType ClangTypeConverter::visitFunctionType(FunctionType *type) { // We must've already computed it before if applicable. - return clang::QualType(type->getClangFunctionType(), 0); + return clang::QualType(type->getClangFunctionType().getType(), 0); } clang::QualType ClangTypeConverter::visitSILFunctionType(SILFunctionType *type) { // We must've already computed it before if applicable. - return clang::QualType(type->getClangFunctionType(), 0); + return clang::QualType(type->getClangFunctionType().getType(), 0); } clang::QualType diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 577d8e025b7d8..7bb72cc3d7e56 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -3224,13 +3224,54 @@ Type ProtocolCompositionType::get(const ASTContext &C, return build(C, CanTypes, HasExplicitAnyObject); } -void AnyFunctionType::ExtInfo::Uncommon::printClangFunctionType( - ClangModuleLoader *cml, llvm::raw_ostream &os) { - cml->printClangType(ClangFunctionType, os); +static_assert( + llvm::PointerLikeTypeTraits::NumLowBitsAvailable + >= llvm::detail::ConstantLog2::value, + "We rely on this in ClangTypeWrapper's implementation"); + +bool ClangTypeWrapper::isCanonical() const { + assert(!empty() && "Can't talk about canonicity without having a Clang type"); + return isDerivableFromSwiftType() && getType()->isCanonicalUnqualified(); } -static void assertIsFunctionType(const clang::Type *type) { +ClangTypeWrapper ClangTypeWrapper::getCanonicalType() const { + if (empty()) + return nullptr; + // We mark "derivable" as being the canonical one because most of the + // @convention(c) functions we encounter will not be annotated with a cType, + // hence, we can avoid creating a separate canonical type if the existing + // type is already canonical otherwise. + return ClangTypeWrapper::derivableFromSwiftType( + getType()->getCanonicalTypeInternal().getTypePtr()); +} + +void ClangTypeWrapper::printType(ClangModuleLoader *cml, + llvm::raw_ostream &os) const { + cml->printClangType(getType(), os); +} + +ClangTypeWrapper +ClangTypeWrapper::pickForExtInfo(const clang::Type *parsed, + ClangTypeWrapper computed) { + if (!parsed) + return computed; + if (computed.empty()) + return notDerivableFromSwiftType(parsed); + assert(computed.isDerivableFromSwiftType()); + auto parsedType = clang::QualType(parsed, 0); + auto computedType = clang::QualType(computed.getType(), 0); + if (parsedType == computedType) + return computed; + if (parsedType.getCanonicalType() == computedType.getCanonicalType()) + // Preserve type with more sugar and att. + return ClangTypeWrapper::derivableFromSwiftType(parsed); + return ClangTypeWrapper::notDerivableFromSwiftType(parsed); +} + + +void ClangTypeWrapper::assertIsFunctionType() const { #ifndef NDEBUG + auto *type = getType()->getCanonicalTypeInternal().getTypePtr(); if (!(type->isFunctionPointerType() || type->isBlockPointerType())) { SmallString<256> buf; llvm::raw_svector_ostream os(buf); @@ -3243,11 +3284,12 @@ static void assertIsFunctionType(const clang::Type *type) { return; } -void AnyFunctionType::ExtInfo::assertIsFunctionType(const clang::Type *type) { - ::assertIsFunctionType(type); +bool ClangTypeWrapper::operator==(ClangTypeWrapper other) const { + return inner.getInt() == other.inner.getInt() + && clang::QualType(getType(), 0) == clang::QualType(other.getType(), 0); } -const clang::Type *AnyFunctionType::getClangFunctionType() const { +ClangTypeWrapper AnyFunctionType::getClangFunctionType() const { switch (getKind()) { case TypeKind::Function: return cast(this)->getClangFunctionType(); @@ -3259,21 +3301,19 @@ const clang::Type *AnyFunctionType::getClangFunctionType() const { } } -const clang::Type *AnyFunctionType::getCanonicalClangFunctionType() const { - auto *ty = getClangFunctionType(); - return ty ? ty->getCanonicalTypeInternal().getTypePtr() : nullptr; +ClangTypeWrapper AnyFunctionType::getCanonicalClangFunctionType() const { + auto cty = getClangFunctionType(); + if (cty.empty()) + return cty; + return cty.getCanonicalType(); } -void SILFunctionType::ExtInfo::assertIsFunctionType(const clang::Type *type) { - ::assertIsFunctionType(type); -} - -const clang::Type *SILFunctionType::getClangFunctionType() const { - if (!Bits.SILFunctionType.HasUncommonInfo) +ClangTypeWrapper SILFunctionType::getClangFunctionType() const { + if (!Bits.SILFunctionType.HasClangType) return nullptr; - auto *type = getTrailingObjects()->ClangFunctionType; - assert(type && "If the pointer was null, we shouldn't have stored it."); - return type; + auto cty = *getTrailingObjects(); + assert(cty.getType() && "Shouldn't have stored a null pointer."); + return cty; } FunctionType * diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index 9db87d47b901d..c9f8df87dfd69 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -416,9 +416,12 @@ namespace { if (pointeeQualType->isFunctionType()) { auto funcTy = pointeeType->castTo(); - auto extInfo = funcTy->getExtInfo().withRepresentation( - AnyFunctionType::Representation::CFunctionPointer) - .withClangFunctionType(type); + auto rep = AnyFunctionType::Representation::CFunctionPointer; + auto computedClangTy = funcTy->getASTContext().getClangFunctionType( + funcTy->getParams(), funcTy->getResult(), funcTy->getExtInfo(), rep); + auto clangTy = ClangTypeWrapper::pickForExtInfo(type, computedClangTy); + auto extInfo = funcTy->getExtInfo().withRepresentation(rep) + .withClangFunctionType(clangTy); return { FunctionType::get(funcTy->getParams(), funcTy->getResult(), extInfo), ImportHint::CFunctionPointer diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp index d682dcbba732f..f59c545465d8d 100644 --- a/lib/SILGen/SILGen.cpp +++ b/lib/SILGen/SILGen.cpp @@ -486,8 +486,8 @@ SILFunction *SILGenModule::emitTopLevelFunction(SILLocation Loc) { auto rep = SILFunctionType::Representation::CFunctionPointer; auto incompleteExtInfo = SILFunctionType::ExtInfo(); - auto *clangTy = C.getCanonicalClangFunctionType(params, results[0], - incompleteExtInfo, rep); + auto clangTy = C.getCanonicalClangFunctionType(params, results[0], + incompleteExtInfo, rep); auto extInfo = incompleteExtInfo.withRepresentation(rep) .withClangFunctionType(clangTy); diff --git a/lib/SILGen/SILGenBridging.cpp b/lib/SILGen/SILGenBridging.cpp index ccadd0370dbdb..d00090146f59d 100644 --- a/lib/SILGen/SILGenBridging.cpp +++ b/lib/SILGen/SILGenBridging.cpp @@ -543,7 +543,7 @@ ManagedValue SILGenFunction::emitFuncToBlock(SILLocation loc, auto results = blockInterfaceTy->getResults(); auto incompleteExtInfo = SILFunctionType::ExtInfo(); - auto *clangFnType = getASTContext().getCanonicalClangFunctionType( + auto clangFnType = getASTContext().getCanonicalClangFunctionType( params, results.empty() ? Optional() : results[0], incompleteExtInfo, SILFunctionType::Representation::CFunctionPointer); diff --git a/lib/SILGen/SILGenFunction.cpp b/lib/SILGen/SILGenFunction.cpp index be314c5fbe551..4122fcc9fff29 100644 --- a/lib/SILGen/SILGenFunction.cpp +++ b/lib/SILGen/SILGenFunction.cpp @@ -583,7 +583,7 @@ void SILGenFunction::emitArtificialTopLevel(ClassDecl *mainClass) { {SILResultInfo(OptNSStringTy, ResultConvention::Autoreleased)}; auto incompleteExtInfo = SILFunctionType::ExtInfo(); auto repr = SILFunctionType::Representation::CFunctionPointer; - auto *clangFnType = ctx.getCanonicalClangFunctionType(params, + auto clangFnType = ctx.getCanonicalClangFunctionType(params, resultInfos[0], incompleteExtInfo, repr); auto extInfo = incompleteExtInfo.withRepresentation(repr) .withClangFunctionType(clangFnType); diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 06a46cd75c70e..c30eba8140068 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -2671,14 +2671,17 @@ Type TypeResolver::resolveASTFunctionType( FunctionType::ExtInfo incompleteExtInfo(FunctionTypeRepresentation::Swift, noescape, repr->throws(), diffKind, /*clangFunctionType*/nullptr); - - const clang::Type *clangFnType = parsedClangFunctionType; - if (representation == AnyFunctionType::Representation::CFunctionPointer - && !clangFnType) - clangFnType = Context.getClangFunctionType( + + ClangTypeWrapper computedType(nullptr); + if (representation == AnyFunctionType::Representation::CFunctionPointer) + computedType = Context.getClangFunctionType( params, outputTy, incompleteExtInfo, AnyFunctionType::Representation::CFunctionPointer); + ClangTypeWrapper clangFnType = + ClangTypeWrapper::pickForExtInfo(parsedClangFunctionType, + computedType); + auto extInfo = incompleteExtInfo.withRepresentation(representation) .withClangFunctionType(clangFnType); @@ -2930,17 +2933,20 @@ Type TypeResolver::resolveSILFunctionType( "found witness_method without matching conformance"); } - const clang::Type *clangFnType = parsedClangType; - if ((representation == SILFunctionType::Representation::CFunctionPointer) - && !clangFnType) { + ClangTypeWrapper computedType(nullptr); + if (representation == SILFunctionType::Representation::CFunctionPointer) { assert(results.size() <= 1 && yields.size() == 0 && "@convention(c) functions have at most 1 result and 0 yields."); auto result = results.empty() ? Optional() : results[0]; - clangFnType = Context.getCanonicalClangFunctionType(interfaceParams, result, - incompleteExtInfo, - representation); + computedType = + Context.getCanonicalClangFunctionType(interfaceParams, result, + incompleteExtInfo, + representation); } + ClangTypeWrapper clangFnType = + ClangTypeWrapper::pickForExtInfo(parsedClangType, computedType); + auto extInfo = incompleteExtInfo.withRepresentation(representation) .withClangFunctionType(clangFnType); diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index fc0abb60f83b7..f76228054142a 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -4741,7 +4741,7 @@ class TypeDeserializer { uint8_t rawRepresentation, rawDiffKind; bool noescape = false, throws; GenericSignature genericSig; - clang::Type *clangFunctionType = nullptr; + ClangTypeWrapper clangFunctionType(nullptr); // FIXME: [clang-function-type-serialization] Deserialize a clang::Type out // of the record. @@ -5101,7 +5101,7 @@ class TypeDeserializer { GenericSignatureID rawGenericSig; SubstitutionMapID rawSubs; ArrayRef variableData; - clang::FunctionType *clangFunctionType = nullptr; + ClangTypeWrapper clangFunctionType(nullptr); // FIXME: [clang-function-type-serialization] Deserialize a // clang::FunctionType out of the record.