diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index 1c65067da2de6..66a200d711921 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -22,6 +22,7 @@ #include "swift/AST/Identifier.h" #include "swift/AST/SearchPathOptions.h" #include "swift/AST/Type.h" +#include "swift/AST/Types.h" #include "swift/AST/TypeAlignments.h" #include "swift/Basic/LangOptions.h" #include "swift/Basic/Malloc.h" @@ -557,6 +558,19 @@ class ASTContext final { Type getBridgedToObjC(const DeclContext *dc, Type type, Type *bridgedValueType = nullptr) const; + /// Get the Clang type corresponding to a Swift function type. + /// + /// \param params The function parameters. + /// \param resultTy The Swift result type. + /// \param incompleteExtInfo Used to convey escaping and throwing + /// 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 * + getClangFunctionType(ArrayRef params, Type resultTy, + const FunctionType::ExtInfo incompleteExtInfo, + FunctionTypeRepresentation trueRep); + /// Determine whether the given Swift type is representable in a /// given foreign language. ForeignRepresentationInfo diff --git a/include/swift/AST/ClangModuleLoader.h b/include/swift/AST/ClangModuleLoader.h index f3e3eee1fd31e..a3d53be0584a7 100644 --- a/include/swift/AST/ClangModuleLoader.h +++ b/include/swift/AST/ClangModuleLoader.h @@ -20,6 +20,7 @@ class ASTContext; class CompilerInstance; class Preprocessor; class Sema; +class TargetInfo; } // namespace clang namespace swift { @@ -46,6 +47,7 @@ class ClangModuleLoader : public ModuleLoader { using ModuleLoader::ModuleLoader; public: + virtual clang::TargetInfo &getTargetInfo() const = 0; virtual clang::ASTContext &getClangASTContext() const = 0; virtual clang::Preprocessor &getClangPreprocessor() const = 0; virtual clang::Sema &getClangSema() const = 0; diff --git a/include/swift/AST/ClangSwiftTypeCorrespondence.h b/include/swift/AST/ClangSwiftTypeCorrespondence.h new file mode 100644 index 0000000000000..244505516bd76 --- /dev/null +++ b/include/swift/AST/ClangSwiftTypeCorrespondence.h @@ -0,0 +1,36 @@ +//=- ClangSwiftTypeCorrespondence.h - Relations between Clang & Swift types -=// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2019 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 describes some common relations between Clang types and Swift +// types that are need by the ClangTypeConverter and parts of ClangImporter. +// +// Since ClangTypeConverter is an implementation detail, ClangImporter should +// not depend on ClangTypeConverter.h. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_AST_CLANG_SWIFT_TYPE_CORRESPONDENCE_H +#define SWIFT_AST_CLANG_SWIFT_TYPE_CORRESPONDENCE_H + +namespace clang { +class Type; +} + +namespace swift { +/// Checks whether a Clang type can be imported as a Swift Optional type. +/// +/// For example, a `const uint8_t *` could be imported as +/// `Optional>`. +bool canImportAsOptional(const clang::Type *type); +} + +#endif /* SWIFT_AST_CLANG_SWIFT_TYPE_CORRESPONDENCE_H */ diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 8162dc1d75e09..a719c39fbb074 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -42,6 +42,11 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/TrailingObjects.h" +namespace clang { +class Type; +class FunctionType; +} // namespace clang + namespace llvm { struct fltSemantics; } // namespace llvm @@ -332,11 +337,11 @@ class alignas(1 << TypeAlignInBits) TypeBase { Flags : NumFlagBits ); - SWIFT_INLINE_BITFIELD_FULL(AnyFunctionType, TypeBase, NumAFTExtInfoBits+16, + SWIFT_INLINE_BITFIELD_FULL(AnyFunctionType, TypeBase, NumAFTExtInfoBits+1+16, /// Extra information which affects how the function is called, like /// regparm and the calling convention. - ExtInfo : NumAFTExtInfoBits, - + ExtInfoBits : NumAFTExtInfoBits, + HasUncommonInfo : 1, : NumPadBits, NumParams : 16 ); @@ -357,8 +362,9 @@ class alignas(1 << TypeAlignInBits) TypeBase { ID : 32 ); - SWIFT_INLINE_BITFIELD(SILFunctionType, TypeBase, NumSILExtInfoBits+3+1+2, - ExtInfo : NumSILExtInfoBits, + SWIFT_INLINE_BITFIELD(SILFunctionType, TypeBase, NumSILExtInfoBits+1+3+1+2, + ExtInfoBits : NumSILExtInfoBits, + HasUncommonInfo : 1, CalleeConvention : 3, HasErrorResult : 1, CoroutineKind : 2 @@ -2897,30 +2903,59 @@ class AnyFunctionType : public TypeBase { unsigned Bits; // Naturally sized for speed. - ExtInfo(unsigned Bits) : Bits(Bits) {} + public: + class Uncommon { + friend ExtInfo; + friend class AnyFunctionType; + friend class FunctionType; + // We preserve a full clang::Type *, not a clang::FunctionType *, so + // we can keep sugar in case we need to present an error to the user. + const clang::Type *ClangFunctionType; + + bool empty() const { return !ClangFunctionType; } + Uncommon(const clang::Type *type) : ClangFunctionType(type) {} + }; + + private: + Uncommon Other; + + static void assertIsFunctionType(const clang::Type *); + + ExtInfo(unsigned Bits, Uncommon Other) : Bits(Bits), Other(Other) { + // TODO: [store-sil-clang-function-type] 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); + } + + friend AnyFunctionType; + friend class FunctionType; - friend class AnyFunctionType; - public: // Constructor with all defaults. - ExtInfo() : Bits(0) { - assert(getRepresentation() == Representation::Swift); + ExtInfo() + : ExtInfo(Representation::Swift, false, false, + DifferentiabilityKind::NonDifferentiable, + nullptr) { } // Constructor for polymorphic type. - ExtInfo(Representation Rep, bool Throws) { - Bits = ((unsigned) Rep) | (Throws ? ThrowsMask : 0); + ExtInfo(Representation Rep, bool Throws) + : ExtInfo(Rep, false, Throws, DifferentiabilityKind::NonDifferentiable, + nullptr) { } // Constructor with no defaults. - ExtInfo(Representation Rep, - bool IsNoEscape, - bool Throws, - DifferentiabilityKind DiffKind) - : ExtInfo(Rep, Throws) { - Bits |= (IsNoEscape ? NoEscapeMask : 0); - Bits |= ((unsigned)DiffKind << DifferentiabilityMaskOffset) & - DifferentiabilityMask; + ExtInfo(Representation Rep, bool IsNoEscape, bool Throws, + DifferentiabilityKind DiffKind, + const clang::Type *type) + : ExtInfo(((unsigned) Rep) + | (IsNoEscape ? NoEscapeMask : 0) + | (Throws ? ThrowsMask : 0) + | (((unsigned)DiffKind << DifferentiabilityMaskOffset) + & DifferentiabilityMask), + Uncommon(type)) { } bool isNoEscape() const { return Bits & NoEscapeMask; } @@ -2940,6 +2975,11 @@ 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; + } + bool hasSelfParam() const { switch (getSILRepresentation()) { case SILFunctionTypeRepresentation::Thick: @@ -2980,25 +3020,25 @@ class AnyFunctionType : public TypeBase { LLVM_NODISCARD ExtInfo withRepresentation(Representation Rep) const { return ExtInfo((Bits & ~RepresentationMask) - | (unsigned)Rep); + | (unsigned)Rep, Other); } LLVM_NODISCARD ExtInfo withNoEscape(bool NoEscape = true) const { - if (NoEscape) - return ExtInfo(Bits | NoEscapeMask); - else - return ExtInfo(Bits & ~NoEscapeMask); + return ExtInfo(NoEscape ? (Bits | NoEscapeMask) : (Bits & ~NoEscapeMask), + Other); } LLVM_NODISCARD ExtInfo withThrows(bool Throws = true) const { - if (Throws) - return ExtInfo(Bits | ThrowsMask); - else - return ExtInfo(Bits & ~ThrowsMask); + return ExtInfo(Throws ? (Bits | ThrowsMask) : (Bits & ~ThrowsMask), + Other); + } + LLVM_NODISCARD + ExtInfo withClangFunctionType(const clang::Type *type) const { + return ExtInfo(Bits, Uncommon(type)); } - unsigned getFuncAttrKey() const { - return Bits; + std::pair getFuncAttrKey() const { + return std::make_pair(Bits, Other.ClangFunctionType); } /// Put a SIL representation in the ExtInfo. @@ -3008,7 +3048,7 @@ class AnyFunctionType : public TypeBase { /// don't need to be parsed, printed, or serialized. ExtInfo withSILRepresentation(SILFunctionTypeRepresentation Rep) const { return ExtInfo((Bits & ~RepresentationMask) - | (unsigned)Rep); + | (unsigned)Rep, Other); } SILFunctionTypeRepresentation getSILRepresentation() const { @@ -3025,15 +3065,21 @@ class AnyFunctionType : public TypeBase { }; protected: + /// Create an AnyFunctionType. + /// + /// Subclasses are responsible for storing and retrieving the + /// ExtInfo::Uncommon value if one is present. AnyFunctionType(TypeKind Kind, const ASTContext *CanTypeContext, Type Output, RecursiveTypeProperties properties, unsigned NumParams, ExtInfo Info) : TypeBase(Kind, CanTypeContext, properties), Output(Output) { - Bits.AnyFunctionType.ExtInfo = Info.Bits; + Bits.AnyFunctionType.ExtInfoBits = Info.Bits; + Bits.AnyFunctionType.HasUncommonInfo = Info.getUncommonInfo().hasValue(); Bits.AnyFunctionType.NumParams = NumParams; assert(Bits.AnyFunctionType.NumParams == NumParams && "Params dropped!"); // The use of both assert() and static_assert() is intentional. - assert(Bits.AnyFunctionType.ExtInfo == Info.Bits && "Bits were dropped!"); + assert(Bits.AnyFunctionType.ExtInfoBits == Info.Bits + && "Bits were dropped!"); static_assert(ExtInfo::NumMaskBits == NumAFTExtInfoBits, "ExtInfo and AnyFunctionTypeBitfields must agree on bit size"); } @@ -3071,8 +3117,25 @@ class AnyFunctionType : public TypeBase { GenericSignature getOptGenericSignature() const; + bool hasClangFunctionType() const { + return Bits.AnyFunctionType.HasUncommonInfo; + } + + const clang::Type *getClangFunctionType() const; + const clang::Type *getCanonicalClangFunctionType() const; + ExtInfo getExtInfo() const { - return ExtInfo(Bits.AnyFunctionType.ExtInfo); + return ExtInfo(Bits.AnyFunctionType.ExtInfoBits, getClangFunctionType()); + } + + /// Get the canonical ExtInfo for the function type. + /// + /// The parameter useClangFunctionType is present only for staging purposes. + /// In the future, we will always use the canonical clang function type. + ExtInfo getCanonicalExtInfo(bool useClangFunctionType) const { + return ExtInfo(Bits.AnyFunctionType.ExtInfoBits, + useClangFunctionType ? getCanonicalClangFunctionType() + : nullptr); } /// Get the representation of the function type. @@ -3138,16 +3201,25 @@ END_CAN_TYPE_WRAPPER(AnyFunctionType, Type) inline AnyFunctionType::CanYield AnyFunctionType::Yield::getCanonical() const { return CanYield(getType()->getCanonicalType(), getFlags()); } - /// FunctionType - A monomorphic function type, specified with an arrow. /// /// For example: /// let x : (Float, Int) -> Int class FunctionType final : public AnyFunctionType, public llvm::FoldingSetNode, - private llvm::TrailingObjects { + private llvm::TrailingObjects { friend TrailingObjects; + + size_t numTrailingObjects(OverloadToken) const { + return getNumParams(); + } + + size_t numTrailingObjects(OverloadToken) const { + return hasClangFunctionType() ? 1 : 0; + } + public: /// 'Constructor' Factory Function static FunctionType *get(ArrayRef params, Type result, @@ -3158,6 +3230,14 @@ class FunctionType final : public AnyFunctionType, return {getTrailingObjects(), getNumParams()}; } + const clang::Type *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; + } + void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getParams(), getResult(), getExtInfo()); } @@ -3753,7 +3833,7 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode, // If bits are added or removed, then TypeBase::SILFunctionTypeBits // and NumMaskBits must be updated, and they must match. - // |representation|pseudogeneric| noescape |differentiability| + // |representation|pseudogeneric|noescape|differentiability| // | 0 .. 3 | 4 | 5 | 6 .. 7 | // enum : unsigned { @@ -3767,22 +3847,43 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode, unsigned Bits; // Naturally sized for speed. - ExtInfo(unsigned Bits) : Bits(Bits) {} + class Uncommon { + friend ExtInfo; + 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::FunctionType *ClangFunctionType; + + bool empty() const { return !ClangFunctionType; } + Uncommon(const clang::FunctionType *type) : ClangFunctionType(type) {} + }; + + Uncommon Other; + + ExtInfo(unsigned Bits, Uncommon Other) : Bits(Bits), Other(Other) {} friend class SILFunctionType; - public: // Constructor with all defaults. - ExtInfo() : Bits(0) { } + ExtInfo() : Bits(0), Other(Uncommon(nullptr)) { } // Constructor for polymorphic type. ExtInfo(Representation rep, bool isPseudogeneric, bool isNoEscape, - DifferentiabilityKind diffKind) { - Bits = ((unsigned) rep) | - (isPseudogeneric ? PseudogenericMask : 0) | - (isNoEscape ? NoEscapeMask : 0) | - (((unsigned)diffKind << DifferentiabilityMaskOffset) & - DifferentiabilityMask); + DifferentiabilityKind diffKind, + const clang::FunctionType *type) + : ExtInfo(((unsigned) rep) + | (isPseudogeneric ? PseudogenericMask : 0) + | (isNoEscape ? NoEscapeMask : 0) + | (((unsigned)diffKind << DifferentiabilityMaskOffset) + & DifferentiabilityMask), + Uncommon(type)) { + } + + static ExtInfo getThin() { + return ExtInfo(Representation::Thin, false, false, + DifferentiabilityKind::NonDifferentiable, nullptr); } /// Is this function pseudo-generic? A pseudo-generic function @@ -3849,23 +3950,21 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode, // the following with methods instead of mutating these objects. ExtInfo withRepresentation(Representation Rep) const { return ExtInfo((Bits & ~RepresentationMask) - | (unsigned)Rep); + | (unsigned)Rep, Other); } ExtInfo withIsPseudogeneric(bool isPseudogeneric = true) const { - if (isPseudogeneric) - return ExtInfo(Bits | PseudogenericMask); - else - return ExtInfo(Bits & ~PseudogenericMask); + return ExtInfo(isPseudogeneric + ? (Bits | PseudogenericMask) + : (Bits & ~PseudogenericMask), + Other); } ExtInfo withNoEscape(bool NoEscape = true) const { - if (NoEscape) - return ExtInfo(Bits | NoEscapeMask); - else - return ExtInfo(Bits & ~NoEscapeMask); + return ExtInfo(NoEscape ? (Bits | NoEscapeMask) : (Bits & ~NoEscapeMask), + Other); } - unsigned getFuncAttrKey() const { - return Bits; + std::pair getFuncAttrKey() const { + return std::make_pair(Bits, Other.ClangFunctionType); } bool operator==(ExtInfo Other) const { @@ -4176,7 +4275,11 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode, return WitnessMethodConformance; } - ExtInfo getExtInfo() const { return ExtInfo(Bits.SILFunctionType.ExtInfo); } + const clang::FunctionType *getClangFunctionType() const; + + ExtInfo getExtInfo() const { + return ExtInfo(Bits.SILFunctionType.ExtInfoBits, getClangFunctionType()); + } /// Returns the language-level calling convention of the function. Language getLanguage() const { diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index 56bcabfd5946e..1fb897e54d2ae 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -219,6 +219,13 @@ namespace swift { /// Build the ASTScope tree lazily bool LazyASTScopes = true; + /// Use Clang function types for computing canonical types. + /// If this option is false, the clang function types will still be computed + /// but will not be used for checking type equality. + /// FIXME: [clang-function-type-serialization] This option should be turned + /// on once we start serializing clang function types. + bool UseClangFunctionTypes = false; + /// Whether to use the import as member inference system /// /// When importing a global, try to infer whether we can import it as a diff --git a/include/swift/ClangImporter/ClangImporter.h b/include/swift/ClangImporter/ClangImporter.h index 4a2766d5a5264..9150852c0088a 100644 --- a/include/swift/ClangImporter/ClangImporter.h +++ b/include/swift/ClangImporter/ClangImporter.h @@ -362,7 +362,7 @@ class ClangImporter final : public ClangModuleLoader { void verifyAllModules() override; - clang::TargetInfo &getTargetInfo() const; + clang::TargetInfo &getTargetInfo() const override; clang::ASTContext &getClangASTContext() const override; clang::Preprocessor &getClangPreprocessor() const override; clang::Sema &getClangSema() const override; diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 563aa63e8fdaf..3e989ce40a604 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -151,6 +151,9 @@ def warn_if_astscope_lookup : Flag<["-"], "warn-if-astscope-lookup">, def lazy_astscopes : Flag<["-"], "lazy-astscopes">, HelpText<"Build ASTScopes lazily">; +def use_clang_function_types : Flag<["-"], "use-clang-function-types">, + HelpText<"Use stored Clang function types for computing canonical types.">; + def print_clang_stats : Flag<["-"], "print-clang-stats">, HelpText<"Print Clang importer statistics">; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 0c16ad4539312..810763df8b240 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -15,6 +15,7 @@ //===----------------------------------------------------------------------===// #include "swift/AST/ASTContext.h" +#include "ClangTypeConverter.h" #include "ForeignRepresentationInfo.h" #include "SubstitutionMapStorage.h" #include "swift/AST/ClangModuleLoader.h" @@ -463,6 +464,8 @@ struct ASTContext::Implementation { RC TheSyntaxArena; llvm::DenseMap overrideSigCache; + + Optional Converter; }; ASTContext::Implementation::Implementation() @@ -2975,7 +2978,9 @@ void FunctionType::Profile(llvm::FoldingSetNodeID &ID, ExtInfo info) { profileParams(ID, params); ID.AddPointer(result.getPointer()); - ID.AddInteger(info.getFuncAttrKey()); + auto infoKey = info.getFuncAttrKey(); + ID.AddInteger(infoKey.first); + ID.AddPointer(infoKey.second); } FunctionType *FunctionType::get(ArrayRef params, @@ -2995,11 +3000,17 @@ FunctionType *FunctionType::get(ArrayRef params, return funcTy; } - void *mem = ctx.Allocate(sizeof(FunctionType) + - sizeof(AnyFunctionType::Param) * params.size(), - alignof(FunctionType), arena); + Optional uncommon = info.getUncommonInfo(); + + size_t allocSize = + totalSizeToAlloc( + params.size(), uncommon.hasValue() ? 1 : 0); + void *mem = ctx.Allocate(allocSize, alignof(FunctionType), arena); bool isCanonical = isFunctionTypeCanonical(params, result); + if (uncommon.hasValue()) + isCanonical &= uncommon->ClangFunctionType->isCanonicalUnqualified(); + auto funcTy = new (mem) FunctionType(params, result, info, isCanonical ? &ctx : nullptr, properties); @@ -3016,6 +3027,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(); } void GenericFunctionType::Profile(llvm::FoldingSetNodeID &ID, @@ -3026,7 +3040,9 @@ void GenericFunctionType::Profile(llvm::FoldingSetNodeID &ID, ID.AddPointer(sig.getPointer()); profileParams(ID, params); ID.AddPointer(result.getPointer()); - ID.AddInteger(info.getFuncAttrKey()); + auto infoKey = info.getFuncAttrKey(); + ID.AddInteger(infoKey.first); + ID.AddPointer(infoKey.second); } GenericFunctionType *GenericFunctionType::get(GenericSignature sig, @@ -3059,9 +3075,8 @@ GenericFunctionType *GenericFunctionType::get(GenericSignature sig, return funcTy; } - void *mem = ctx.Allocate(sizeof(GenericFunctionType) + - sizeof(AnyFunctionType::Param) * params.size(), - alignof(GenericFunctionType)); + size_t allocSize = totalSizeToAlloc(params.size()); + void *mem = ctx.Allocate(allocSize, alignof(GenericFunctionType)); auto properties = getGenericFunctionRecursiveProperties(params, result); auto funcTy = new (mem) GenericFunctionType(sig, params, result, info, @@ -3121,7 +3136,9 @@ void SILFunctionType::Profile( bool isGenericSignatureImplied, SubstitutionMap substitutions) { id.AddPointer(genericParams.getPointer()); - id.AddInteger(info.getFuncAttrKey()); + auto infoKey = info.getFuncAttrKey(); + id.AddInteger(infoKey.first); + id.AddPointer(infoKey.second); id.AddInteger(unsigned(coroutineKind)); id.AddInteger(unsigned(calleeConvention)); id.AddInteger(params.size()); @@ -3165,9 +3182,10 @@ SILFunctionType::SILFunctionType( Substitutions(substitutions) { Bits.SILFunctionType.HasErrorResult = errorResult.hasValue(); - Bits.SILFunctionType.ExtInfo = ext.Bits; + Bits.SILFunctionType.ExtInfoBits = ext.Bits; + Bits.SILFunctionType.HasUncommonInfo = false; // The use of both assert() and static_assert() below is intentional. - assert(Bits.SILFunctionType.ExtInfo == ext.Bits && "Bits were dropped!"); + assert(Bits.SILFunctionType.ExtInfoBits == ext.Bits && "Bits were dropped!"); static_assert(ExtInfo::NumMaskBits == NumSILExtInfoBits, "ExtInfo and SILFunctionTypeBitfields must agree on bit size"); Bits.SILFunctionType.CoroutineKind = unsigned(coroutineKind); @@ -4316,6 +4334,19 @@ Type ASTContext::getBridgedToObjC(const DeclContext *dc, Type type, return Type(); } +const clang::Type * +ASTContext::getClangFunctionType(ArrayRef params, + Type resultTy, + FunctionType::ExtInfo incompleteExtInfo, + FunctionTypeRepresentation trueRep) { + auto &impl = getImpl(); + if (!impl.Converter) { + auto *cml = getClangModuleLoader(); + impl.Converter.emplace(*this, cml->getClangASTContext(), LangOpts.Target); + } + return impl.Converter.getValue().getFunctionType(params, resultTy, trueRep); +} + CanGenericSignature ASTContext::getSingleGenericParameterSignature() const { if (auto theSig = getImpl().SingleGenericParameterSignature) return theSig; diff --git a/lib/AST/ASTDemangler.cpp b/lib/AST/ASTDemangler.cpp index bc6fd217db0cc..4719d8702e81f 100644 --- a/lib/AST/ASTDemangler.cpp +++ b/lib/AST/ASTDemangler.cpp @@ -348,33 +348,6 @@ Type ASTBuilder::createTupleType(ArrayRef eltTypes, Type ASTBuilder::createFunctionType( ArrayRef> params, Type output, FunctionTypeFlags flags) { - FunctionTypeRepresentation representation; - switch (flags.getConvention()) { - case FunctionMetadataConvention::Swift: - representation = FunctionTypeRepresentation::Swift; - break; - case FunctionMetadataConvention::Block: - representation = FunctionTypeRepresentation::Block; - break; - case FunctionMetadataConvention::Thin: - representation = FunctionTypeRepresentation::Thin; - break; - case FunctionMetadataConvention::CFunctionPointer: - representation = FunctionTypeRepresentation::CFunctionPointer; - break; - } - - auto einfo = AnyFunctionType::ExtInfo(representation, - /*throws*/ flags.throws()); - - if (representation == FunctionTypeRepresentation::Swift || - representation == FunctionTypeRepresentation::Block) { - if (flags.isEscaping()) - einfo = einfo.withNoEscape(false); - else - einfo = einfo.withNoEscape(true); - } - // The result type must be materializable. if (!output->isMaterializable()) return Type(); @@ -397,6 +370,42 @@ Type ASTBuilder::createFunctionType( funcParams.push_back(AnyFunctionType::Param(type, label, parameterFlags)); } + FunctionTypeRepresentation representation; + switch (flags.getConvention()) { + case FunctionMetadataConvention::Swift: + representation = FunctionTypeRepresentation::Swift; + break; + case FunctionMetadataConvention::Block: + representation = FunctionTypeRepresentation::Block; + break; + case FunctionMetadataConvention::Thin: + representation = FunctionTypeRepresentation::Thin; + break; + case FunctionMetadataConvention::CFunctionPointer: + representation = FunctionTypeRepresentation::CFunctionPointer; + break; + } + + auto noescape = + (representation == FunctionTypeRepresentation::Swift + || representation == FunctionTypeRepresentation::Block) + && !flags.isEscaping(); + + FunctionType::ExtInfo incompleteExtInfo( + FunctionTypeRepresentation::Swift, + noescape, flags.throws(), + DifferentiabilityKind::NonDifferentiable, + /*clangFunctionType*/nullptr); + + const clang::Type *clangFunctionType = nullptr; + if (representation == FunctionTypeRepresentation::CFunctionPointer) + clangFunctionType = Ctx.getClangFunctionType(funcParams, output, + incompleteExtInfo, + representation); + + auto einfo = incompleteExtInfo.withRepresentation(representation) + .withClangFunctionType(clangFunctionType); + return FunctionType::get(funcParams, output, einfo); } @@ -479,9 +488,11 @@ Type ASTBuilder::createImplFunctionType( break; } + // TODO: [store-sil-clang-function-type] auto einfo = SILFunctionType::ExtInfo( representation, flags.isPseudogeneric(), !flags.isEscaping(), - DifferentiabilityKind::NonDifferentiable); + DifferentiabilityKind::NonDifferentiable, + /*clangFunctionType*/ nullptr); llvm::SmallVector funcParams; llvm::SmallVector funcYields; diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index e7923a716eade..e171d2c836308 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -27,6 +27,7 @@ #include "swift/Basic/Defer.h" #include "swift/Basic/QuotedString.h" #include "swift/Basic/STLExtras.h" +#include "clang/AST/Type.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallString.h" @@ -3607,6 +3608,12 @@ namespace { OS << "\n"; Indent += 2; + if (auto *cty = T->getClangFunctionType()) { + std::string s; + llvm::raw_string_ostream os(s); + cty->dump(os); + printField("clang_type", os.str()); + } printAnyFunctionParams(T->getParams(), "input"); Indent -=2; printRec("output", T->getResult()); diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index 6def9d8b5b96e..643463bf8c618 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -34,6 +34,8 @@ add_swift_host_library(swiftAST STATIC AvailabilitySpec.cpp Builtins.cpp CaptureInfo.cpp + ClangSwiftTypeCorrespondence.cpp + ClangTypeConverter.cpp ConcreteDeclRef.cpp ConformanceLookupTable.cpp Decl.cpp diff --git a/lib/AST/ClangSwiftTypeCorrespondence.cpp b/lib/AST/ClangSwiftTypeCorrespondence.cpp new file mode 100644 index 0000000000000..bebe31ed1463d --- /dev/null +++ b/lib/AST/ClangSwiftTypeCorrespondence.cpp @@ -0,0 +1,27 @@ +//- ClangSwiftTypeCorrespondence.cpp - Relations between Clang & Swift types -// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2019 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 +// +//===----------------------------------------------------------------------===// +// +// See description in ClangSwiftTypeCorrespondence.h. +// +//===----------------------------------------------------------------------===// + +#include "swift/AST/ClangSwiftTypeCorrespondence.h" +#include "clang/AST/Type.h" + +bool swift::canImportAsOptional(const clang::Type *type) { + // Note: this mimics ImportHint::canImportAsOptional. + + // Includes CoreFoundation types such as CFStringRef (== struct CFString *). + return type && (type->isPointerType() + || type->isBlockPointerType() + || type->isObjCObjectPointerType()); +} diff --git a/lib/AST/ClangTypeConverter.cpp b/lib/AST/ClangTypeConverter.cpp new file mode 100644 index 0000000000000..1af858ef82a6e --- /dev/null +++ b/lib/AST/ClangTypeConverter.cpp @@ -0,0 +1,722 @@ +//===--- ClangTypeConverter.cpp - Convert Swift types to C types ----------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2019 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 implements generation of Clang AST types from Swift AST types for +// types that are representable in Objective-C interfaces. +// Large chunks of the code are lightly modified versions of the code in +// IRGen/GenClangType.cpp (which should eventually go away), so make sure +// to keep the two in sync. +// The three major differences are that, in this file: +// 1. We fail gracefully instead of asserting/UB. +// 2. We try to keep clang sugar instead of discarding it. +// 3. We use getAs instead of cast as we handle Swift types with sugar. +// +//===----------------------------------------------------------------------===// + +#include "ClangTypeConverter.h" + +#include "swift/AST/ASTContext.h" +#include "swift/AST/ClangModuleLoader.h" +#include "swift/AST/ClangSwiftTypeCorrespondence.h" +#include "swift/AST/ExistentialLayout.h" +#include "swift/AST/Module.h" +#include "swift/AST/Type.h" +#include "swift/AST/TypeVisitor.h" +#include "swift/Basic/LLVM.h" + +#include "clang/AST/ASTContext.h" +#include "clang/Sema/Sema.h" + +using namespace swift; + +namespace { + +static Type getNamedSwiftType(ModuleDecl *stdlib, StringRef name) { + auto &ctx = stdlib->getASTContext(); + SmallVector results; + stdlib->lookupValue(ctx.getIdentifier(name), NLKind::QualifiedLookup, + results); + + // If we have one single type decl, and that decl has been + // type-checked, return its declared type. + // + // ...non-type-checked types should only ever show up here because + // of test cases using -enable-source-import, but unfortunately + // that's a real thing. + if (results.size() == 1) { + if (auto typeDecl = dyn_cast(results[0])) + return typeDecl->getDeclaredInterfaceType(); + } + return Type(); +} + +static clang::QualType +getClangBuiltinTypeFromKind(const clang::ASTContext &context, + clang::BuiltinType::Kind kind) { + switch (kind) { +#define BUILTIN_TYPE(Id, SingletonId) \ + case clang::BuiltinType::Id: \ + return context.SingletonId; +#include "clang/AST/BuiltinTypes.def" +#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ + case clang::BuiltinType::Id: \ + return context.SingletonId; +#include "clang/Basic/OpenCLImageTypes.def" +#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ + case clang::BuiltinType::Id: \ + return context.Id##Ty; +#include "clang/Basic/OpenCLExtensionTypes.def" +#define SVE_TYPE(Name, Id, SingletonId) \ + case clang::BuiltinType::Id: \ + return context.SingletonId; +#include "clang/Basic/AArch64SVEACLETypes.def" + } + + // Not a valid BuiltinType. + return clang::QualType(); +} + +static clang::QualType getClangSelectorType( + const clang::ASTContext &clangCtx) { + return clangCtx.getPointerType(clangCtx.ObjCBuiltinSelTy); +} + +static clang::QualType getClangMetatypeType( + const clang::ASTContext &clangCtx) { + clang::QualType clangType = + clangCtx.getObjCObjectType(clangCtx.ObjCBuiltinClassTy, nullptr, 0); + return clangCtx.getObjCObjectPointerType(clangType); +} + +static clang::QualType getClangIdType( + const clang::ASTContext &clangCtx) { + clang::QualType clangType = + clangCtx.getObjCObjectType(clangCtx.ObjCBuiltinIdTy, nullptr, 0); + return clangCtx.getObjCObjectPointerType(clangType); +} + +static clang::QualType getClangDecayedVaListType( +const clang::ASTContext &clangCtx) { + clang::QualType clangType = clangCtx.getBuiltinVaListType(); + if (clangType->isConstantArrayType()) + clangType = clangCtx.getDecayedType(clangType); + return clangType; +} + +} // end anonymous namespace + +const clang::Type *ClangTypeConverter::getFunctionType( + ArrayRef params, Type resultTy, + AnyFunctionType::Representation repr) { + + SmallVector paramsTy; + for (auto p : params) + paramsTy.push_back(p.getPlainType()); + + auto resultClangTy = convert(resultTy); + if (resultClangTy.isNull()) + return nullptr; + + SmallVector paramsClangTy; + for (auto p : paramsTy) { + auto pc = convert(p); + if (pc.isNull()) + return nullptr; + paramsClangTy.push_back(pc); + } + + clang::FunctionProtoType::ExtProtoInfo info(clang::CallingConv::CC_C); + auto fn = ClangASTContext.getFunctionType(resultClangTy, paramsClangTy, info); + if (fn.isNull()) + return nullptr; + + switch (repr) { + case AnyFunctionType::Representation::CFunctionPointer: + return fn.getTypePtr(); + case AnyFunctionType::Representation::Block: + return ClangASTContext.getBlockPointerType(fn).getTypePtrOrNull(); + case AnyFunctionType::Representation::Swift: + case AnyFunctionType::Representation::Thin: + llvm_unreachable("Expected a C-compatible representation."); + } +} + +clang::QualType ClangTypeConverter::convertMemberType(NominalTypeDecl *DC, + StringRef memberName) { + auto memberTypeDecl = cast( + DC->lookupDirect(Context.getIdentifier(memberName))[0]); + auto memberType = memberTypeDecl->getDeclaredInterfaceType(); + return convert(memberType); +} + +// TODO: It is unfortunate that we parse the name of a public library type +// in order to break it down into a vector component and length that in theory +// we could recover in some other way. +static clang::QualType getClangVectorType(const clang::ASTContext &ctx, + clang::BuiltinType::Kind eltKind, + clang::VectorType::VectorKind vecKind, + StringRef numEltsString) { + unsigned numElts; + bool failedParse = numEltsString.getAsInteger(10, numElts); + if (failedParse) + return clang::QualType(); + auto eltTy = getClangBuiltinTypeFromKind(ctx, eltKind); + if (eltTy.isNull()) + return clang::QualType(); + return ctx.getVectorType(eltTy, numElts, vecKind); +} + +clang::QualType ClangTypeConverter::visitStructType(StructType *type) { + auto &ctx = ClangASTContext; + + auto swiftDecl = type->getDecl(); + StringRef name = swiftDecl->getName().str(); + + // We assume that the importer translates all of the following types + // directly to structs in the standard library. + + // We want to recognize most of these types by name. +#define CHECK_NAMED_TYPE(NAME, CLANG_TYPE) do { \ + if (name == (NAME)) return CLANG_TYPE; \ + } while (false) + + CHECK_NAMED_TYPE("CGFloat", convertMemberType(swiftDecl, "NativeType")); + CHECK_NAMED_TYPE("OpaquePointer", ctx.VoidPtrTy); + CHECK_NAMED_TYPE("CVaListPointer", getClangDecayedVaListType(ctx)); + CHECK_NAMED_TYPE("DarwinBoolean", ctx.UnsignedCharTy); + CHECK_NAMED_TYPE(swiftDecl->getASTContext().getSwiftName( + KnownFoundationEntity::NSZone), + ctx.VoidPtrTy); + CHECK_NAMED_TYPE("WindowsBool", ctx.IntTy); + CHECK_NAMED_TYPE("ObjCBool", ctx.ObjCBuiltinBoolTy); + CHECK_NAMED_TYPE("Selector", getClangSelectorType(ctx)); + CHECK_NAMED_TYPE("UnsafeRawPointer", ctx.VoidPtrTy); + CHECK_NAMED_TYPE("UnsafeMutableRawPointer", ctx.VoidPtrTy); +#undef CHECK_NAMED_TYPE + + // Map vector types to the corresponding C vectors. +#define MAP_SIMD_TYPE(TYPE_NAME, _, BUILTIN_KIND) \ + if (name.startswith(#TYPE_NAME)) { \ + return getClangVectorType(ctx, clang::BuiltinType::BUILTIN_KIND, \ + clang::VectorType::GenericVector, \ + name.drop_front(sizeof(#TYPE_NAME)-1)); \ + } +#include "swift/ClangImporter/SIMDMappedTypes.def" + + // We might be looking at a builtin + auto ret = reverseBuiltinTypeMapping(type); + if (!ret.isNull()) + return ret; + + if (type->isPotentiallyBridgedValueType()) { + if (auto t = Context.getBridgedToObjC(type->getDecl(), type)) + return convert(t); + } + + // Out of ideas, there must've been some error. :( + return clang::QualType(); +} + +static clang::QualType +getClangBuiltinTypeFromTypedef(clang::Sema &sema, StringRef typedefName) { + auto &context = sema.getASTContext(); + auto identifier = &context.Idents.get(typedefName); + auto found = sema.LookupSingleName(sema.TUScope, identifier, + clang::SourceLocation(), + clang::Sema::LookupOrdinaryName); + auto typedefDecl = dyn_cast_or_null(found); + if (!typedefDecl) + return clang::QualType(); + + auto underlyingTy = + context.getCanonicalType(typedefDecl->getUnderlyingType()); + + if (underlyingTy->getAs()) + return underlyingTy; + return clang::QualType(); +} + +clang::QualType +ClangTypeConverter::reverseBuiltinTypeMapping(StructType *type) { + // Handle builtin types by adding entries to the cache that reverse + // the mapping done by the importer. We could try to look at the + // members of the struct instead, but even if that's ABI-equivalent + // (which it had better be!), it might erase interesting semantic + // differences like integers vs. characters. This is important + // because CC lowering isn't the only purpose of this conversion. + // + // The importer maps builtin types like 'int' to named types like + // 'CInt', which are generally typealiases. So what we do here is + // map the underlying types of those typealiases back to the builtin + // type. These typealiases frequently create a many-to-one mapping, + // so just use the first type that mapped to a particular underlying + // type. + // + // This is the last thing that happens before asserting that the + // struct type doesn't have a mapping. Furthermore, all of the + // builtin types are pre-built in the clang ASTContext. So it's not + // really a significant performance problem to just cache all them + // right here; it makes making a few more entries in the cache than + // we really need, but it also means we won't end up repeating these + // stdlib lookups multiple times, and we have to perform multiple + // lookups anyway because the MAP_BUILTIN_TYPE database uses + // typealias names (like 'CInt') that aren't obviously associated + // with the underlying C library type. + + auto stdlib = Context.getStdlibModule(); + assert(stdlib && "translating stdlib type to C without stdlib module?"); + auto &ctx = ClangASTContext; + + if (!StdlibTypesAreCached) { + auto cacheStdlibType = [&](StringRef swiftName, + clang::BuiltinType::Kind builtinKind) { + Type swiftType = getNamedSwiftType(stdlib, swiftName); + if (!swiftType) return; + + auto &sema = Context.getClangModuleLoader()->getClangSema(); + + if (Context.LangOpts.EnableObjCInterop) { + // Handle Int and UInt specially. On Apple platforms, these map to + // the NSInteger and NSUInteger typedefs. So try that if the typedefs + // are available, to ensure we get consistent ObjC @encode strings. + if (swiftType->getAnyNominal() == Context.getIntDecl()) { + auto NSIntegerTy = getClangBuiltinTypeFromTypedef(sema, "NSInteger"); + if (!NSIntegerTy.isNull()) { + Cache.insert({swiftType->getCanonicalType(), NSIntegerTy}); + return; + } + } else if (swiftType->getAnyNominal() == Context.getUIntDecl()) { + auto NSUIntegerTy = getClangBuiltinTypeFromTypedef(sema, "NSUInteger"); + if (!NSUIntegerTy.isNull()) { + Cache.insert({swiftType->getCanonicalType(), NSUIntegerTy}); + return; + } + } + } + + // For something like `typealias CInt = Int32`, reverseBuiltinTypeMapping + // will get Int32 as the input, so we need to record the desugared type. + Cache.insert({swiftType->getCanonicalType(), + getClangBuiltinTypeFromKind(ctx, builtinKind)}); + }; + +#define MAP_BUILTIN_TYPE(CLANG_BUILTIN_KIND, SWIFT_TYPE_NAME) \ + cacheStdlibType(#SWIFT_TYPE_NAME, clang::BuiltinType::CLANG_BUILTIN_KIND); +#include "swift/ClangImporter/BuiltinMappedTypes.def" + + // On 64-bit Windows, no C type is imported as an Int or UInt; CLong is + // imported as an Int32 and CLongLong as an Int64. Therefore, manually + // add mappings to C for Int and UInt. + // On 64-bit Cygwin, no manual mapping is required. + if (Triple.isOSWindows() && Triple.isArch64Bit() + && !Triple.isWindowsCygwinEnvironment()) { + // Map UInt to uintptr_t + auto swiftUIntType = getNamedSwiftType(stdlib, "UInt"); + auto clangUIntPtrType = ctx.getCanonicalType(ctx.getUIntPtrType()); + Cache.insert({swiftUIntType, clangUIntPtrType}); + + // Map Int to intptr_t + auto swiftIntType = getNamedSwiftType(stdlib, "Int"); + auto clangIntPtrType = ctx.getCanonicalType(ctx.getIntPtrType()); + Cache.insert({swiftIntType, clangIntPtrType}); + } + StdlibTypesAreCached = true; + } + + auto it = Cache.find(Type(type)); + if (it != Cache.end()) + return it->second; + + it = Cache.find(type->getCanonicalType()); + if (it != Cache.end()) { + Cache.insert({Type(type), it->second}); + return it->second; + } + + return clang::QualType(); +} + +clang::QualType ClangTypeConverter::visitTupleType(TupleType *type) { + unsigned tupleNumElements = type->getNumElements(); + if (tupleNumElements == 0) + return ClangASTContext.VoidTy; + + Type eltTy = type->getElementType(0); + for (unsigned i = 1; i < tupleNumElements; i++) { + if (!eltTy->isEqual(type->getElementType(i))) + // Only tuples where all element types are equal map to fixed-size + // arrays. + return clang::QualType(); + } + + auto clangEltTy = convert(eltTy); + if (clangEltTy.isNull()) + return clang::QualType(); + + APInt size(32, tupleNumElements); + return ClangASTContext.getConstantArrayType(clangEltTy, size, + clang::ArrayType::Normal, 0); +} + +clang::QualType ClangTypeConverter::visitProtocolType(ProtocolType *type) { + auto proto = type->getDecl(); + auto &clangCtx = ClangASTContext; + + if (!proto->isObjC()) + return clang::QualType(); + + assert(!cast_or_null(proto->getClangDecl()) + && "We shouldn't be creating duplicate decls; see `convert`"); + + // Single protocol -> id + clang::IdentifierInfo *name = &clangCtx.Idents.get(proto->getName().get()); + auto *PDecl = clang::ObjCProtocolDecl::Create( + const_cast(clangCtx), + clangCtx.getTranslationUnitDecl(), name, + clang::SourceLocation(), clang::SourceLocation(), nullptr); + + // Attach an objc_runtime_name attribute with the Objective-C name to use + // for this protocol. + SmallString<64> runtimeNameBuffer; + PDecl->addAttr(clang::ObjCRuntimeNameAttr::CreateImplicit( + PDecl->getASTContext(), + proto->getObjCRuntimeName(runtimeNameBuffer))); + + auto clangType = clangCtx.getObjCObjectType(clangCtx.ObjCBuiltinIdTy, + &PDecl, 1); + return clangCtx.getObjCObjectPointerType(clangType); +} + +// TODO: [stronger-checking-in-clang-type-conversion] +// 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); +} + +// TODO: [stronger-checking-in-clang-type-conversion] +// Existential metatypes where the base is a non-metatype existential can be +// converted to Class when the protocols are all ObjC. +// https://github.com/apple/swift/pull/27479#discussion_r344418131 +clang::QualType +ClangTypeConverter::visitExistentialMetatypeType(ExistentialMetatypeType *type) { + return getClangMetatypeType(ClangASTContext); +} + +clang::QualType ClangTypeConverter::visitClassType(ClassType *type) { + auto &clangCtx = ClangASTContext; + auto swiftDecl = type->getDecl(); + + // TODO: [non-objc-class-clang-type-conversion] + // See the corresponding note in GenClangType.cpp + if (!swiftDecl->isObjC()) + return getClangIdType(clangCtx); + + assert(!cast_or_null(swiftDecl->getClangDecl()) + && "We shouldn't be creating duplicate decls; see `convert`"); + + // produce the clang type INTF * if it is imported ObjC object. + clang::IdentifierInfo *ForwardClassId = + &clangCtx.Idents.get(swiftDecl->getName().get()); + auto *CDecl = clang::ObjCInterfaceDecl::Create( + clangCtx, clangCtx.getTranslationUnitDecl(), + clang::SourceLocation(), ForwardClassId, + /*typeParamList*/nullptr, /*PrevDecl=*/nullptr, + clang::SourceLocation()); + + // Attach an objc_runtime_name attribute with the Objective-C name to use + // for this class. + SmallString<64> runtimeNameBuffer; + CDecl->addAttr(clang::ObjCRuntimeNameAttr::CreateImplicit( + CDecl->getASTContext(), + swiftDecl->getObjCRuntimeName(runtimeNameBuffer))); + + auto clangType = clangCtx.getObjCInterfaceType(CDecl); + return clangCtx.getObjCObjectPointerType(clangType); +} + +// TODO: We should try to preserve type arguments on imported ObjC generic +// classes, instead of relying on our knowledge of clang's encoding. +// This would entail extracting the type arguments, calling `convert` to +// create clang types, extracting the ObjCProtocolDecls and then using +// getObjCObjectType with `id` as the base. +clang::QualType +ClangTypeConverter::visitBoundGenericClassType(BoundGenericClassType *type) { + // Any @objc class type in Swift that shows up in an @objc method maps 1-1 to + // "id "; with clang's encoding ignoring the protocol list. + return getClangIdType(ClangASTContext); +} + +clang::QualType +ClangTypeConverter::visitBoundGenericType(BoundGenericType *type) { + // The only possibilities are *Pointer, SIMD* and Optional. + + if (type->getDecl()->isOptionalDecl()) { + auto args = type->getGenericArgs(); + assert((args.size() == 1) && "Optional should have 1 generic argument."); + clang::QualType innerTy = convert(args[0]); + if (swift::canImportAsOptional(innerTy.getTypePtrOrNull())) + return innerTy; + return clang::QualType(); + } + + auto swiftStructDecl = type->getDecl(); + + enum class StructKind { + Invalid, + UnsafeMutablePointer, + UnsafePointer, + AutoreleasingUnsafeMutablePointer, + Unmanaged, + CFunctionPointer, + SIMD, + } kind = llvm::StringSwitch(swiftStructDecl->getName().str()) + .Case("UnsafeMutablePointer", StructKind::UnsafeMutablePointer) + .Case("UnsafePointer", StructKind::UnsafePointer) + .Case("AutoreleasingUnsafeMutablePointer", + StructKind::AutoreleasingUnsafeMutablePointer) + .Case("Unmanaged", StructKind::Unmanaged) + .Case("CFunctionPointer", StructKind::CFunctionPointer) + .StartsWith("SIMD", StructKind::SIMD) + .Default(StructKind::Invalid); + + auto args = type->getGenericArgs(); + if (args.size() != 1) + // Must've got something other than *Pointer or SIMD* + return clang::QualType(); + auto argCanonicalTy = args[0]->getCanonicalType(); + + switch (kind) { + case StructKind::Invalid: + return clang::QualType(); + + case StructKind::UnsafeMutablePointer: + case StructKind::Unmanaged: + case StructKind::AutoreleasingUnsafeMutablePointer: { + auto clangTy = convert(argCanonicalTy); + if (clangTy.isNull()) + return clang::QualType(); + return ClangASTContext.getPointerType(clangTy); + } + case StructKind::UnsafePointer: { + return ClangASTContext.getPointerType(convert(argCanonicalTy).withConst()); + } + + case StructKind::CFunctionPointer: { + auto &clangCtx = ClangASTContext; + + clang::QualType functionTy; + if (isa(argCanonicalTy->getCanonicalType())) { + functionTy = convert(argCanonicalTy); + if (functionTy.isNull()) + return clang::QualType(); + } else { + // Fall back to void(). + functionTy = clangCtx.getFunctionNoProtoType(clangCtx.VoidTy); + } + return clangCtx.getPointerType(functionTy); + } + + case StructKind::SIMD: { + clang::QualType scalarTy = convert(argCanonicalTy); + auto numEltsString = swiftStructDecl->getName().str(); + numEltsString.consume_front("SIMD"); + unsigned numElts; + bool failedParse = numEltsString.getAsInteger(10, numElts); + if (failedParse) + return clang::QualType(); + (void) failedParse; + auto vectorTy = ClangASTContext.getVectorType(scalarTy, numElts, + clang::VectorType::VectorKind::GenericVector); + return vectorTy; + } + } + + llvm_unreachable("Not a valid StructKind."); +} + +clang::QualType ClangTypeConverter::visitEnumType(EnumType *type) { + // Special case: Uninhabited enums are not @objc, so we don't + // know what to do below, but we can just convert to 'void'. + if (type->isUninhabited()) + return convert(Context.TheEmptyTupleType); + + if (!type->getDecl()->isObjC()) + // Can't translate something not marked with @objc + return clang::QualType(); + + // @objc enums lower to their raw types. + return convert(type->getDecl()->getRawType()); +} + +clang::QualType ClangTypeConverter::visitFunctionType(FunctionType *type) { + // We must've already computed it before if applicable. + return clang::QualType(type->getClangFunctionType(), 0); +} + +clang::QualType ClangTypeConverter::visitSILFunctionType(SILFunctionType *type) { + llvm::report_fatal_error("Expected only AST types but found a SIL function."); +} + +clang::QualType +ClangTypeConverter::visitSILBlockStorageType(SILBlockStorageType *type) { + llvm::report_fatal_error("Expected only AST types but found a SIL block."); +} + +clang::QualType +ClangTypeConverter::visitProtocolCompositionType(ProtocolCompositionType *type) { + // Any will be lowered to AnyObject, so we return the same result. + if (type->isAny()) + return getClangIdType(ClangASTContext); + + auto &clangCtx = ClangASTContext; + + // FIXME. Eventually, this will have its own helper routine. + SmallVector Protocols; + auto layout = type->getExistentialLayout(); + if (!layout.isObjC()) + // Cannot represent opaque existential in Clang + return clang::QualType(); + + // AnyObject -> id. + if (layout.isAnyObject()) + return getClangIdType(ClangASTContext); + + auto superclassTy = clangCtx.ObjCBuiltinIdTy; + if (auto layoutSuperclassTy = layout.getSuperclass()) { + auto clangTy = convert(layoutSuperclassTy); + if (clangTy.isNull()) + return clang::QualType(); + superclassTy = clangCtx.getCanonicalType( + clangTy->getAs()->getPointeeType()); + } + + for (Type t : layout.getProtocols()) { + auto clangTy = convert(t); + if (clangTy.isNull()) + return clang::QualType(); + for (auto p : clangTy->getAs()->quals()) + Protocols.push_back(p); + } + + if (Protocols.empty()) + return superclassTy; + + // id + clang::ObjCProtocolDecl **ProtoQuals = + new(clangCtx) clang::ObjCProtocolDecl*[Protocols.size()]; + memcpy(ProtoQuals, Protocols.data(), + sizeof(clang::ObjCProtocolDecl*)*Protocols.size()); + auto clangType = clangCtx.getObjCObjectType(superclassTy, + ProtoQuals, + Protocols.size()); + return clangCtx.getObjCObjectPointerType(clangType); +} + +clang::QualType +ClangTypeConverter::visitBuiltinRawPointerType(BuiltinRawPointerType *type) { + return ClangASTContext.VoidPtrTy; +} + +clang::QualType +ClangTypeConverter::visitBuiltinIntegerType(BuiltinIntegerType *type) { + auto &clangCtx = ClangASTContext; + if (type->getWidth().isPointerWidth()) { + return clangCtx.getUIntPtrType(); + } + assert(type->getWidth().isFixedWidth()); + auto width = type->getWidth().getFixedWidth(); + if (width == 1) + return clangCtx.BoolTy; + return clangCtx.getIntTypeForBitwidth(width, /*signed*/ 0); +} + +clang::QualType +ClangTypeConverter::visitBuiltinFloatType(BuiltinFloatType *type) { + auto &clangCtx = ClangASTContext; + auto &clangTargetInfo = clangCtx.getTargetInfo(); + const llvm::fltSemantics *format = &type->getAPFloatSemantics(); + if (format == &clangTargetInfo.getHalfFormat()) + return clangCtx.HalfTy; + if (format == &clangTargetInfo.getFloatFormat()) + return clangCtx.FloatTy; + if (format == &clangTargetInfo.getDoubleFormat()) + return clangCtx.DoubleTy; + if (format == &clangTargetInfo.getLongDoubleFormat()) + return clangCtx.LongDoubleTy; + llvm_unreachable("cannot translate floating-point format to C"); +} + +clang::QualType ClangTypeConverter::visitArchetypeType(ArchetypeType *type) { + // We see these in the case where we invoke an @objc function + // through a protocol. + return getClangIdType(ClangASTContext); +} + +clang::QualType ClangTypeConverter::visitDynamicSelfType(DynamicSelfType *type) { + // Dynamic Self is equivalent to 'instancetype', which is treated as + // 'id' within the Objective-C type system. + return getClangIdType(ClangASTContext); +} + +clang::QualType +ClangTypeConverter::visitGenericTypeParamType(GenericTypeParamType *type) { + // We see these in the case where we invoke an @objc function + // through a protocol argument that is a generic type. + return getClangIdType(ClangASTContext); +} + +clang::QualType +ClangTypeConverter::visitSugarType(SugarType *type) { + return convert(Type(type->getDesugaredType())); +} + +clang::QualType +ClangTypeConverter::visitType(TypeBase *type) { + // We only convert specific types. + return clang::QualType(); +} + +clang::QualType ClangTypeConverter::visit(Type type) { + return static_cast(this)->visit(type); +} + +clang::QualType ClangTypeConverter::convert(Type type) { + auto it = Cache.find(type); + if (it != Cache.end()) + return it->second; + + // Try to do this without making cache entries for obvious cases. + if (auto nominal = type->getAs()) { + auto decl = nominal->getDecl(); + if (auto clangDecl = decl->getClangDecl()) { + auto &ctx = ClangASTContext; + if (auto clangTypeDecl = dyn_cast(clangDecl)) { + return ctx.getTypeDeclType(clangTypeDecl).getUnqualifiedType(); + } else if (auto ifaceDecl = dyn_cast(clangDecl)) { + auto clangType = ctx.getObjCInterfaceType(ifaceDecl); + return ctx.getObjCObjectPointerType(clangType); + } else if (auto protoDecl = dyn_cast(clangDecl)){ + auto clangType = ctx.getObjCObjectType( + ctx.ObjCBuiltinIdTy, + const_cast(&protoDecl), + 1); + return ctx.getObjCObjectPointerType(clangType); + } + } + } + + // If that failed, convert the type, cache, and return. + clang::QualType result = visit(type); + Cache.insert({type, result}); + return result; +} diff --git a/lib/AST/ClangTypeConverter.h b/lib/AST/ClangTypeConverter.h new file mode 100644 index 0000000000000..b25f6b6dffb92 --- /dev/null +++ b/lib/AST/ClangTypeConverter.h @@ -0,0 +1,111 @@ +//===-- ClangTypeConverter.h - Converting Swift types to C types-*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2019 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 utilities for translating Swift types to C types. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_AST_CLANG_TYPE_CONVERTER_H +#define SWIFT_AST_CLANG_TYPE_CONVERTER_H + +#include "swift/AST/ASTContext.h" +#include "swift/AST/ClangModuleLoader.h" +#include "swift/AST/Type.h" +#include "swift/AST/TypeVisitor.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Type.h" + +namespace swift { + +/// Compute C types corresponding to Swift AST types. +class ClangTypeConverter : + public TypeVisitor { + + using super = TypeVisitor; + + llvm::DenseMap Cache; + + bool StdlibTypesAreCached = false; + + ASTContext &Context; + + clang::ASTContext &ClangASTContext; + + const llvm::Triple Triple; + + ClangTypeConverter(const ClangTypeConverter &) = delete; + ClangTypeConverter &operator=(const ClangTypeConverter &) = delete; + +public: + + /// Create a ClangTypeConverter. + ClangTypeConverter(ASTContext &ctx, clang::ASTContext &clangCtx, + llvm::Triple triple) + : Context(ctx), ClangASTContext(clangCtx), Triple(triple) + { + }; + + /// Compute the C function type for a Swift function type. + /// + /// It is the caller's responsibility to make sure this method is only + /// called in the appropriate context. For example, it makes sense to use + /// this method for the output type of a @convention(c) function. + /// + /// Since we do not check the context, the translation is unconditional. + /// For example, String will automatically get translated to NSString + /// when bridging is available. + /// + /// Additionally, the API is expected to be used only from + /// + /// \returns The appropriate clang type on success, nullptr on failure. + /// + /// Precondition: The representation argument must be C-compatible. + const clang::Type *getFunctionType( + ArrayRef params, Type resultTy, + AnyFunctionType::Representation repr); + +private: + clang::QualType convert(Type type); + clang::QualType convertMemberType(NominalTypeDecl *DC, + StringRef memberName); + + clang::QualType reverseBuiltinTypeMapping(StructType *type); + + friend TypeVisitor; + + clang::QualType visitStructType(StructType *type); + clang::QualType visitTupleType(TupleType *type); + clang::QualType visitMetatypeType(MetatypeType *type); + clang::QualType visitExistentialMetatypeType(ExistentialMetatypeType *type); + clang::QualType visitProtocolType(ProtocolType *type); + clang::QualType visitClassType(ClassType *type); + clang::QualType visitBoundGenericClassType(BoundGenericClassType *type); + clang::QualType visitBoundGenericType(BoundGenericType *type); + clang::QualType visitEnumType(EnumType *type); + clang::QualType visitFunctionType(FunctionType *type); + clang::QualType visitProtocolCompositionType(ProtocolCompositionType *type); + clang::QualType visitBuiltinRawPointerType(BuiltinRawPointerType *type); + clang::QualType visitBuiltinIntegerType(BuiltinIntegerType *type); + clang::QualType visitBuiltinFloatType(BuiltinFloatType *type); + clang::QualType visitArchetypeType(ArchetypeType *type); + clang::QualType visitSILFunctionType(SILFunctionType *type); + clang::QualType visitGenericTypeParamType(GenericTypeParamType *type); + clang::QualType visitDynamicSelfType(DynamicSelfType *type); + clang::QualType visitSILBlockStorageType(SILBlockStorageType *type); + clang::QualType visitSugarType(SugarType *type); + clang::QualType visitType(TypeBase *type); + clang::QualType visit(Type type); +}; + +} // end namespace swift + +#endif /* SWIFT_AST_CLANG_TYPE_CONVERTER_H */ diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index e3ac44fa33100..a424562db1919 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -31,6 +31,7 @@ #include "swift/AST/SubstitutionMap.h" #include "swift/AST/TypeLoc.h" #include "swift/AST/TypeRepr.h" +#include "clang/AST/Type.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" @@ -1203,12 +1204,14 @@ CanType TypeBase::computeCanonicalType() { getCanonicalParams(funcTy, genericSig, canParams); auto resultTy = funcTy->getResult()->getCanonicalType(genericSig); + bool useClangFunctionType = + resultTy->getASTContext().LangOpts.UseClangFunctionTypes; + auto extInfo = funcTy->getCanonicalExtInfo(useClangFunctionType); if (genericSig) { Result = GenericFunctionType::get(genericSig, canParams, resultTy, - funcTy->getExtInfo()); + extInfo); } else { - Result = FunctionType::get(canParams, resultTy, - funcTy->getExtInfo()); + Result = FunctionType::get(canParams, resultTy, extInfo); } assert(Result->isCanonical()); break; @@ -3111,6 +3114,40 @@ Type ProtocolCompositionType::get(const ASTContext &C, return build(C, CanTypes, HasExplicitAnyObject); } +void +AnyFunctionType::ExtInfo::assertIsFunctionType(const clang::Type *type) { +#ifndef NDEBUG + if (!type->isFunctionType()) { + llvm::errs() << "Expected a Clang function type but found\n"; + type->dump(llvm::errs()); + llvm_unreachable(""); + } +#endif + return; +} + +const clang::Type *AnyFunctionType::getClangFunctionType() const { + switch (getKind()) { + case TypeKind::Function: + return cast(this)->getClangFunctionType(); + case TypeKind::GenericFunction: + // Generic functions do not have C types. + return nullptr; + default: + llvm_unreachable("Illegal type kind for AnyFunctionType."); + } +} + +const clang::Type *AnyFunctionType::getCanonicalClangFunctionType() const { + auto *ty = getClangFunctionType(); + return ty ? ty->getCanonicalTypeInternal().getTypePtr() : nullptr; +} + +// TODO: [store-sil-clang-function-type] +const clang::FunctionType *SILFunctionType::getClangFunctionType() const { + return nullptr; +} + FunctionType * GenericFunctionType::substGenericArgs(SubstitutionMap subs) { return substGenericArgs( diff --git a/lib/ClangImporter/ImportName.cpp b/lib/ClangImporter/ImportName.cpp index b81f0257517f3..2200bd6d78509 100644 --- a/lib/ClangImporter/ImportName.cpp +++ b/lib/ClangImporter/ImportName.cpp @@ -21,6 +21,7 @@ #include "ClangDiagnosticConsumer.h" #include "swift/Subsystems.h" #include "swift/AST/ASTContext.h" +#include "swift/AST/ClangSwiftTypeCorrespondence.h" #include "swift/AST/DiagnosticEngine.h" #include "swift/AST/DiagnosticsClangImporter.h" #include "swift/AST/Module.h" @@ -170,19 +171,6 @@ static bool isIntegerType(clang::QualType clangType) { return false; } -/// Whether the given Objective-C type can be imported as an optional type. -static bool canImportAsOptional(clang::ASTContext &ctx, clang::QualType type) { - // Note: this mimics ImportHint::canImportAsOptional. - - // Objective-C object pointers. - if (type->getAs()) return true; - - // Block and C pointers, including CF types. - if (type->isBlockPointerType() || type->isPointerType()) return true; - - return false; -} - static Optional classifyMethodErrorHandling(const clang::ObjCMethodDecl *clangDecl, OptionalTypeKind resultOptionality) { @@ -202,7 +190,8 @@ classifyMethodErrorHandling(const clang::ObjCMethodDecl *clangDecl, // non-optional type. case clang::SwiftErrorAttr::NullResult: if (resultOptionality != OTK_None && - canImportAsOptional(clangCtx, clangDecl->getReturnType())) + swift::canImportAsOptional( + clangDecl->getReturnType().getTypePtrOrNull())) return ForeignErrorConvention::NilResult; return None; @@ -235,7 +224,8 @@ classifyMethodErrorHandling(const clang::ObjCMethodDecl *clangDecl, // For optional reference results, a nil value is normally an error. if (resultOptionality != OTK_None && - canImportAsOptional(clangCtx, clangDecl->getReturnType())) { + swift::canImportAsOptional( + clangDecl->getReturnType().getTypePtrOrNull())) { return ForeignErrorConvention::NilResult; } diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index 0519170ab8ea2..94425388d6516 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -418,8 +418,10 @@ namespace { auto funcTy = pointeeType->castTo(); return { FunctionType::get(funcTy->getParams(), funcTy->getResult(), - funcTy->getExtInfo().withRepresentation( - AnyFunctionType::Representation::CFunctionPointer)), + funcTy->getExtInfo() + .withRepresentation( + AnyFunctionType::Representation::CFunctionPointer) + .withClangFunctionType(pointeeQualType.getTypePtr())), ImportHint::CFunctionPointer }; } @@ -573,7 +575,7 @@ namespace { } // Form the function type. - return FunctionType::get(params, resultTy); + return FunctionType::get(params, resultTy, FunctionType::ExtInfo()); } ImportResult diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 78dab4a0f526e..8c17ab586adcf 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -349,6 +349,7 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.StressASTScopeLookup |= Args.hasArg(OPT_stress_astscope_lookup); Opts.WarnIfASTScopeLookup |= Args.hasArg(OPT_warn_if_astscope_lookup); Opts.LazyASTScopes |= Args.hasArg(OPT_lazy_astscopes); + Opts.UseClangFunctionTypes |= Args.hasArg(OPT_use_clang_function_types); Opts.NamedLazyMemberLoading &= !Args.hasArg(OPT_disable_named_lazy_member_loading); diff --git a/lib/IRGen/GenClangType.cpp b/lib/IRGen/GenClangType.cpp index 14beaa4bce220..3eaed562469c5 100644 --- a/lib/IRGen/GenClangType.cpp +++ b/lib/IRGen/GenClangType.cpp @@ -12,6 +12,8 @@ // // This file implements generation of Clang AST types from Swift AST types // for types that are representable in Objective-C interfaces. +// AST/ClangTypeConverter.cpp duplicates a bunch of code from here, so make +// sure to keep the two in sync. // //===----------------------------------------------------------------------===// @@ -191,7 +193,7 @@ static clang::CanQualType getClangVectorType(const clang::ASTContext &ctx, clang::VectorType::VectorKind vecKind, StringRef numEltsString) { unsigned numElts; - bool failedParse = numEltsString.getAsInteger(10, numElts); + bool failedParse = numEltsString.getAsInteger(10, numElts); assert(!failedParse && "vector type name didn't end in count?"); (void) failedParse; @@ -366,36 +368,38 @@ clang::CanQualType GenClangType::visitTupleType(CanTupleType type) { return ctx.getCanonicalType( ctx.getConstantArrayType(clangEltTy, size, clang::ArrayType::Normal, 0)); - - llvm_unreachable("Unexpected tuple type in Clang type generation!"); } clang::CanQualType GenClangType::visitProtocolType(CanProtocolType type) { auto proto = type->getDecl(); + auto &clangCtx = getClangASTContext(); - // Single protocol -> id - if (proto->isObjC()) { - auto &clangCtx = getClangASTContext(); - clang::IdentifierInfo *name = &clangCtx.Idents.get(proto->getName().get()); - auto *PDecl = clang::ObjCProtocolDecl::Create( - const_cast(clangCtx), - clangCtx.getTranslationUnitDecl(), name, - clang::SourceLocation(), clang::SourceLocation(), nullptr); - - // Attach an objc_runtime_name attribute with the Objective-C name to use - // for this protocol. - SmallString<64> runtimeNameBuffer; - PDecl->addAttr(clang::ObjCRuntimeNameAttr::CreateImplicit( - PDecl->getASTContext(), - proto->getObjCRuntimeName(runtimeNameBuffer))); - - auto clangType = clangCtx.getObjCObjectType(clangCtx.ObjCBuiltinIdTy, - &PDecl, 1); - auto ptrTy = clangCtx.getObjCObjectPointerType(clangType); - return clangCtx.getCanonicalType(ptrTy); + if (!proto->isObjC()) { + std::string s; + llvm::raw_string_ostream err(s); + err << "Trying to compute the clang type for a non-ObjC protocol type\n"; + proto->dump(err); + llvm::report_fatal_error(err.str()); } - return getClangIdType(getClangASTContext()); + // Single protocol -> id + clang::IdentifierInfo *name = &clangCtx.Idents.get(proto->getName().get()); + auto *PDecl = clang::ObjCProtocolDecl::Create( + const_cast(clangCtx), + clangCtx.getTranslationUnitDecl(), name, + clang::SourceLocation(), clang::SourceLocation(), nullptr); + + // Attach an objc_runtime_name attribute with the Objective-C name to use + // for this protocol. + SmallString<64> runtimeNameBuffer; + PDecl->addAttr(clang::ObjCRuntimeNameAttr::CreateImplicit( + PDecl->getASTContext(), + proto->getObjCRuntimeName(runtimeNameBuffer))); + + auto clangType = clangCtx.getObjCObjectType(clangCtx.ObjCBuiltinIdTy, + &PDecl, 1); + auto ptrTy = clangCtx.getObjCObjectPointerType(clangType); + return clangCtx.getCanonicalType(ptrTy); } clang::CanQualType GenClangType::visitMetatypeType(CanMetatypeType type) { @@ -409,29 +413,33 @@ GenClangType::visitExistentialMetatypeType(CanExistentialMetatypeType type) { clang::CanQualType GenClangType::visitClassType(CanClassType type) { auto &clangCtx = getClangASTContext(); - // produce the clang type INTF * if it is imported ObjC object. auto swiftDecl = type->getDecl(); - if (swiftDecl->isObjC()) { - clang::IdentifierInfo *ForwardClassId = - &clangCtx.Idents.get(swiftDecl->getName().get()); - auto *CDecl = clang::ObjCInterfaceDecl::Create( - clangCtx, clangCtx.getTranslationUnitDecl(), - clang::SourceLocation(), ForwardClassId, - /*typeParamList*/nullptr, /*PrevDecl=*/nullptr, - clang::SourceLocation()); - - // Attach an objc_runtime_name attribute with the Objective-C name to use - // for this class. - SmallString<64> runtimeNameBuffer; - CDecl->addAttr(clang::ObjCRuntimeNameAttr::CreateImplicit( - CDecl->getASTContext(), - swiftDecl->getObjCRuntimeName(runtimeNameBuffer))); - - auto clangType = clangCtx.getObjCInterfaceType(CDecl); - auto ptrTy = clangCtx.getObjCObjectPointerType(clangType); - return clangCtx.getCanonicalType(ptrTy); - } - return getClangIdType(clangCtx); + + // TODO: [non-objc-class-clang-type-conversion] + // Crashing here instead of returning a bogus 'id' leads to test failures, + // which is surprising. + if (!swiftDecl->isObjC()) + return getClangIdType(clangCtx); + + // produce the clang type INTF * if it is imported ObjC object. + clang::IdentifierInfo *ForwardClassId = + &clangCtx.Idents.get(swiftDecl->getName().get()); + auto *CDecl = clang::ObjCInterfaceDecl::Create( + clangCtx, clangCtx.getTranslationUnitDecl(), + clang::SourceLocation(), ForwardClassId, + /*typeParamList*/nullptr, /*PrevDecl=*/nullptr, + clang::SourceLocation()); + + // Attach an objc_runtime_name attribute with the Objective-C name to use + // for this class. + SmallString<64> runtimeNameBuffer; + CDecl->addAttr(clang::ObjCRuntimeNameAttr::CreateImplicit( + CDecl->getASTContext(), + swiftDecl->getObjCRuntimeName(runtimeNameBuffer))); + + auto clangType = clangCtx.getObjCInterfaceType(CDecl); + auto ptrTy = clangCtx.getObjCObjectPointerType(clangType); + return clangCtx.getCanonicalType(ptrTy); } clang::CanQualType GenClangType::visitBoundGenericClassType( @@ -443,8 +451,7 @@ clang::CanQualType GenClangType::visitBoundGenericClassType( clang::CanQualType GenClangType::visitBoundGenericType(CanBoundGenericType type) { - // We only expect *Pointer, ImplicitlyUnwrappedOptional, and Optional. - // The first two are structs; the last is an enum. + // We only expect *Pointer, SIMD* and Optional. if (auto underlyingTy = SILType::getPrimitiveObjectType(type).getOptionalObjectType()) { // The underlying type could be a bridged type, which makes any @@ -685,15 +692,13 @@ clang::CanQualType GenClangType::visitBuiltinRawPointerType( clang::CanQualType GenClangType::visitBuiltinIntegerType( CanBuiltinIntegerType type) { auto &ctx = getClangASTContext(); - if (type->getWidth().isPointerWidth()) { + if (type->getWidth().isPointerWidth()) return ctx.getCanonicalType(ctx.getUIntPtrType()); - } - if (type->getWidth().isFixedWidth()) { - auto width = type->getWidth().getFixedWidth(); - if (width == 1) return ctx.BoolTy; - return ctx.getCanonicalType(ctx.getIntTypeForBitwidth(width, /*signed*/ 0)); - } - llvm_unreachable(""); + assert(type->getWidth().isFixedWidth()); + auto width = type->getWidth().getFixedWidth(); + if (width == 1) + return ctx.BoolTy; + return ctx.getCanonicalType(ctx.getIntTypeForBitwidth(width, /*signed*/ 0)); } clang::CanQualType GenClangType::visitBuiltinFloatType( @@ -732,21 +737,25 @@ clang::CanQualType GenClangType::visitType(CanType type) { } clang::CanQualType ClangTypeConverter::convert(IRGenModule &IGM, CanType type) { + // Look in the cache. + auto it = Cache.find(type); + if (it != Cache.end()) { + return it->second; + } + // Try to do this without making cache entries for obvious cases. if (auto nominal = dyn_cast(type)) { auto decl = nominal->getDecl(); if (auto clangDecl = decl->getClangDecl()) { + auto &ctx = IGM.getClangASTContext(); if (auto clangTypeDecl = dyn_cast(clangDecl)) { - auto &ctx = IGM.getClangASTContext(); return ctx.getCanonicalType(ctx.getTypeDeclType(clangTypeDecl)) .getUnqualifiedType(); } else if (auto ifaceDecl = dyn_cast(clangDecl)) { - auto &ctx = IGM.getClangASTContext(); auto clangType = ctx.getObjCInterfaceType(ifaceDecl); auto ptrTy = ctx.getObjCObjectPointerType(clangType); return ctx.getCanonicalType(ptrTy); } else if (auto protoDecl = dyn_cast(clangDecl)){ - auto &ctx = IGM.getClangASTContext(); auto clangType = ctx.getObjCObjectType( ctx.ObjCBuiltinIdTy, const_cast(&protoDecl), @@ -757,12 +766,6 @@ clang::CanQualType ClangTypeConverter::convert(IRGenModule &IGM, CanType type) { } } - // Look in the cache. - auto it = Cache.find(type); - if (it != Cache.end()) { - return it->second; - } - // If that failed, convert the type, cache, and return. clang::CanQualType result = GenClangType(IGM, *this).visit(type); Cache.insert({type, result}); diff --git a/lib/PrintAsObjC/DeclAndTypePrinter.cpp b/lib/PrintAsObjC/DeclAndTypePrinter.cpp index 240e83d8a2ff8..2846068ef40e7 100644 --- a/lib/PrintAsObjC/DeclAndTypePrinter.cpp +++ b/lib/PrintAsObjC/DeclAndTypePrinter.cpp @@ -14,6 +14,7 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/ASTVisitor.h" +#include "swift/AST/ClangSwiftTypeCorrespondence.h" #include "swift/AST/Comment.h" #include "swift/AST/Decl.h" #include "swift/AST/ExistentialLayout.h" @@ -1559,8 +1560,7 @@ class DeclAndTypePrinter::Implementation ASTContext &ctx = getASTContext(); auto &clangASTContext = ctx.getClangModuleLoader()->getClangASTContext(); clang::QualType clangTy = clangASTContext.getTypeDeclType(clangTypeDecl); - return clangTy->isPointerType() || clangTy->isBlockPointerType() || - clangTy->isObjCObjectPointerType(); + return swift::canImportAsOptional(clangTy.getTypePtr()); } bool printImportedAlias(const TypeAliasDecl *alias, diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp index a3dced1451974..c61711255a40c 100644 --- a/lib/SILGen/SILGen.cpp +++ b/lib/SILGen/SILGen.cpp @@ -419,7 +419,9 @@ SILGenModule::getKeyPathProjectionCoroutine(bool isReadAccess, auto extInfo = SILFunctionType::ExtInfo( SILFunctionTypeRepresentation::Thin, /*pseudogeneric*/ false, - /*non-escaping*/ false, DifferentiabilityKind::NonDifferentiable); + /*non-escaping*/ false, + DifferentiabilityKind::NonDifferentiable, + /*clangFunctionType*/ nullptr); auto functionTy = SILFunctionType::get(sig, extInfo, SILCoroutineKind::YieldOnce, diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index 5323894fcb2fd..b66769ac86aa5 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -2682,10 +2682,7 @@ static SILFunction *getOrCreateKeyPathGetter(SILGenModule &SGM, SILResultInfo result(loweredPropTy, ResultConvention::Indirect); auto signature = SILFunctionType::get(genericSig, - SILFunctionType::ExtInfo(SILFunctionType::Representation::Thin, - /*pseudogeneric*/ false, - /*noescape*/ false, - DifferentiabilityKind::NonDifferentiable), + SILFunctionType::ExtInfo::getThin(), SILCoroutineKind::None, ParameterConvention::Direct_Unowned, params, {}, result, None, @@ -2827,10 +2824,7 @@ static SILFunction *getOrCreateKeyPathSetter(SILGenModule &SGM, ParameterConvention::Direct_Unowned}); auto signature = SILFunctionType::get(genericSig, - SILFunctionType::ExtInfo(SILFunctionType::Representation::Thin, - /*pseudogeneric*/ false, - /*noescape*/ false, - DifferentiabilityKind::NonDifferentiable), + SILFunctionType::ExtInfo::getThin(), SILCoroutineKind::None, ParameterConvention::Direct_Unowned, params, {}, {}, None, @@ -3004,10 +2998,7 @@ getOrCreateKeyPathEqualsAndHash(SILGenModule &SGM, results.push_back({boolTy, ResultConvention::Unowned}); auto signature = SILFunctionType::get(genericSig, - SILFunctionType::ExtInfo(SILFunctionType::Representation::Thin, - /*pseudogeneric*/ false, - /*noescape*/ false, - DifferentiabilityKind::NonDifferentiable), + SILFunctionType::ExtInfo::getThin(), SILCoroutineKind::None, ParameterConvention::Direct_Unowned, params, /*yields*/ {}, results, None, @@ -3181,10 +3172,7 @@ getOrCreateKeyPathEqualsAndHash(SILGenModule &SGM, results.push_back({intTy, ResultConvention::Unowned}); auto signature = SILFunctionType::get(genericSig, - SILFunctionType::ExtInfo(SILFunctionType::Representation::Thin, - /*pseudogeneric*/ false, - /*noescape*/ false, - DifferentiabilityKind::NonDifferentiable), + SILFunctionType::ExtInfo::getThin(), SILCoroutineKind::None, ParameterConvention::Direct_Unowned, params, /*yields*/ {}, results, None, diff --git a/lib/SILOptimizer/Transforms/Outliner.cpp b/lib/SILOptimizer/Transforms/Outliner.cpp index d350a63081a55..9a0fe538905d8 100644 --- a/lib/SILOptimizer/Transforms/Outliner.cpp +++ b/lib/SILOptimizer/Transforms/Outliner.cpp @@ -289,7 +289,8 @@ CanSILFunctionType BridgedProperty::getOutlinedFunctionType(SILModule &M) { auto ExtInfo = SILFunctionType::ExtInfo(SILFunctionType::Representation::Thin, /*pseudogeneric*/ false, /*noescape*/ false, - DifferentiabilityKind::NonDifferentiable); + DifferentiabilityKind::NonDifferentiable, + /*clangFunctionType*/ nullptr); auto FunctionType = SILFunctionType::get( nullptr, ExtInfo, SILCoroutineKind::None, ParameterConvention::Direct_Unowned, Parameters, /*yields*/ {}, @@ -1112,7 +1113,9 @@ CanSILFunctionType ObjCMethodCall::getOutlinedFunctionType(SILModule &M) { auto ExtInfo = SILFunctionType::ExtInfo( SILFunctionType::Representation::Thin, /*pseudogeneric*/ false, - /*noescape*/ false, DifferentiabilityKind::NonDifferentiable); + /*noescape*/ false, + DifferentiabilityKind::NonDifferentiable, + /*clangFunctionType*/ nullptr); SmallVector Results; // If we don't have a bridged return we changed from @autoreleased to @owned diff --git a/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp b/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp index 5ac534a26e9fa..c01d47a8ff74b 100644 --- a/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp +++ b/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp @@ -86,7 +86,8 @@ class BugReducerTester : public SILFunctionTransform { nullptr, SILFunctionType::ExtInfo(SILFunctionType::Representation::Thin, false /*isPseudoGeneric*/, false /*noescape*/, - DifferentiabilityKind::NonDifferentiable), + DifferentiabilityKind::NonDifferentiable, + nullptr /*clangFunctionType*/), SILCoroutineKind::None, ParameterConvention::Direct_Unowned, ArrayRef(), ArrayRef(), ResultInfoArray, None, SubstitutionMap(), false, diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 2b42cc489f1b2..0abf390465a78 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -5977,6 +5977,11 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType, } } + auto &err = llvm::errs(); + err << "fromType->getCanonicalType() = "; + fromType->getCanonicalType()->dump(err); + err << "toType->getCanonicalType() = "; + toType->getCanonicalType()->dump(err); llvm_unreachable("Should be handled above"); } diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 9c97fce37f48a..63916b900c8d6 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -109,7 +109,7 @@ bool ConstraintSystem::hasFreeTypeVariables() { void ConstraintSystem::addTypeVariable(TypeVariableType *typeVar) { TypeVariables.insert(typeVar); - + // Notify the constraint graph. (void)CG[typeVar]; } @@ -575,7 +575,7 @@ Type ConstraintSystem::openUnboundGenericType(UnboundGenericType *unbound, locator); } } - + // Map the generic parameters to their corresponding type variables. llvm::SmallVector arguments; for (auto gp : unboundDecl->getInnermostGenericParamTypes()) { @@ -834,7 +834,7 @@ static bool doesStorageProduceLValue(AbstractStorageDecl *storage, // Unsettable storage decls always produce rvalues. if (!storage->isSettable(useDC, base)) return false; - + if (!storage->isSetterAccessibleFrom(useDC)) return false; @@ -934,7 +934,7 @@ void ConstraintSystem::recordOpenedTypes( }) == OpenedTypes.end() && "already registered opened types for this locator"); #endif - + OpenedType* openedTypes = Allocator.Allocate(replacements.size()); std::copy(replacements.begin(), replacements.end(), openedTypes); @@ -1664,7 +1664,7 @@ static std::pair getTypeOfReferenceWithSpecialTypeCheckingSemantics( FunctionType::Param inputArg(input, CS.getASTContext().getIdentifier("of")); - + CS.addConstraint(ConstraintKind::DynamicTypeOf, output, input, CS.getConstraintLocator(locator, ConstraintLocator::RValueAdjustment)); auto refType = FunctionType::get({inputArg}, output); @@ -1691,18 +1691,19 @@ static std::pair getTypeOfReferenceWithSpecialTypeCheckingSemantics( FunctionType::ExtInfo(FunctionType::Representation::Swift, /*noescape*/ true, /*throws*/ true, - DifferentiabilityKind::NonDifferentiable)); + DifferentiabilityKind::NonDifferentiable, + /*clangFunctionType*/ nullptr)); FunctionType::Param args[] = { FunctionType::Param(noescapeClosure), FunctionType::Param(bodyClosure, CS.getASTContext().getIdentifier("do")), }; - auto refType = FunctionType::get( - args, result, - FunctionType::ExtInfo(FunctionType::Representation::Swift, - /*noescape*/ false, - /*throws*/ true, - DifferentiabilityKind::NonDifferentiable)); + auto refType = FunctionType::get(args, result, + FunctionType::ExtInfo(FunctionType::Representation::Swift, + /*noescape*/ false, + /*throws*/ true, + DifferentiabilityKind::NonDifferentiable, + /*clangFunctionType*/ nullptr)); return {refType, refType}; } case DeclTypeCheckingSemantics::OpenExistential: { @@ -1725,17 +1726,18 @@ static std::pair getTypeOfReferenceWithSpecialTypeCheckingSemantics( FunctionType::ExtInfo(FunctionType::Representation::Swift, /*noescape*/ true, /*throws*/ true, - DifferentiabilityKind::NonDifferentiable)); + DifferentiabilityKind::NonDifferentiable, + /*clangFunctionType*/ nullptr)); FunctionType::Param args[] = { FunctionType::Param(existentialTy), FunctionType::Param(bodyClosure, CS.getASTContext().getIdentifier("do")), }; - auto refType = FunctionType::get( - args, result, - FunctionType::ExtInfo(FunctionType::Representation::Swift, - /*noescape*/ false, - /*throws*/ true, - DifferentiabilityKind::NonDifferentiable)); + auto refType = FunctionType::get(args, result, + FunctionType::ExtInfo(FunctionType::Representation::Swift, + /*noescape*/ false, + /*throws*/ true, + DifferentiabilityKind::NonDifferentiable, + /*clangFunctionType*/ nullptr)); return {refType, refType}; } } @@ -2437,7 +2439,7 @@ DeclName OverloadChoice::getName() const { case OverloadChoiceKind::TupleIndex: llvm_unreachable("no name!"); } - + llvm_unreachable("Unhandled OverloadChoiceKind in switch."); } @@ -3526,4 +3528,4 @@ Expr *ConstraintSystem::buildAutoClosureExpr(Expr *expr, cacheExprTypes(result); return result; -} \ No newline at end of file +} diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index ddcd749cbc010..9cc97b96b5508 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -1760,7 +1760,7 @@ namespace { public: explicit TypeResolver(TypeResolution resolution) - : Context(resolution.getDeclContext()->getASTContext()), + : Context(resolution.getASTContext()), resolution(resolution), DC(resolution.getDeclContext()) { @@ -1781,8 +1781,11 @@ namespace { TypeResolutionOptions options); Type resolveASTFunctionType(FunctionTypeRepr *repr, TypeResolutionOptions options, - FunctionType::ExtInfo extInfo - = FunctionType::ExtInfo()); + AnyFunctionType::Representation representation + = AnyFunctionType::Representation::Swift, + bool noescape = false, + DifferentiabilityKind diffKind + = DifferentiabilityKind::NonDifferentiable); bool resolveASTFunctionTypeParams(TupleTypeRepr *inputRepr, TypeResolutionOptions options, @@ -1848,11 +1851,11 @@ namespace { Type TypeResolution::resolveType(TypeRepr *TyR, TypeResolutionOptions options) { auto &ctx = getASTContext(); - FrontendStatsTracer StatsTracer(ctx.Stats, "resolve-type", TyR); PrettyStackTraceTypeRepr stackTrace(ctx, "resolving", TyR); TypeResolver typeResolver(*this); + auto result = typeResolver.resolveType(TyR, options); if (result) { @@ -2208,8 +2211,10 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, } // Resolve the function type directly with these attributes. + // TODO: [store-sil-clang-function-type] SILFunctionType::ExtInfo extInfo(rep, attrs.has(TAK_pseudogeneric), - attrs.has(TAK_noescape), diffKind); + attrs.has(TAK_noescape), diffKind, + nullptr); ty = resolveSILFunctionType(fnRepr, options, coroutineKind, extInfo, calleeConvention, witnessMethodProtocol); @@ -2271,11 +2276,8 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, : DifferentiabilityKind::Normal; } - // Resolve the function type directly with these attributes. - FunctionType::ExtInfo extInfo(rep, /*noescape=*/false, fnRepr->throws(), - diffKind); - - ty = resolveASTFunctionType(fnRepr, options, extInfo); + ty = resolveASTFunctionType(fnRepr, options, rep, /*noescape=*/false, + diffKind); if (!ty || ty->hasError()) return ty; } @@ -2519,9 +2521,11 @@ Type TypeResolver::resolveOpaqueReturnType(TypeRepr *repr, return ty; } -Type TypeResolver::resolveASTFunctionType(FunctionTypeRepr *repr, - TypeResolutionOptions parentOptions, - FunctionType::ExtInfo extInfo) { +Type TypeResolver::resolveASTFunctionType( + FunctionTypeRepr *repr, TypeResolutionOptions parentOptions, + AnyFunctionType::Representation representation, bool noescape, + DifferentiabilityKind diffKind) { + TypeResolutionOptions options = None; options |= parentOptions.withoutContext().getFlags(); @@ -2534,8 +2538,6 @@ Type TypeResolver::resolveASTFunctionType(FunctionTypeRepr *repr, Type outputTy = resolveType(repr->getResultTypeRepr(), options); if (!outputTy || outputTy->hasError()) return outputTy; - extInfo = extInfo.withThrows(repr->throws()); - // If this is a function type without parens around the parameter list, // diagnose this and produce a fixit to add them. if (!repr->isWarnedAbout()) { @@ -2555,6 +2557,19 @@ Type TypeResolver::resolveASTFunctionType(FunctionTypeRepr *repr, } } + FunctionType::ExtInfo incompleteExtInfo(FunctionTypeRepresentation::Swift, + noescape, repr->throws(), diffKind, + /*clangFunctionType*/nullptr); + + const clang::Type *clangFnType = nullptr; + if (representation == AnyFunctionType::Representation::CFunctionPointer) + clangFnType = Context.getClangFunctionType( + params, outputTy, incompleteExtInfo, + AnyFunctionType::Representation::CFunctionPointer); + + auto extInfo = incompleteExtInfo.withRepresentation(representation) + .withClangFunctionType(clangFnType); + // SIL uses polymorphic function types to resolve overloaded member functions. if (auto genericEnv = repr->getGenericEnvironment()) { outputTy = outputTy->mapTypeOutOfContext(); @@ -2565,12 +2580,14 @@ Type TypeResolver::resolveASTFunctionType(FunctionTypeRepr *repr, auto fnTy = FunctionType::get(params, outputTy, extInfo); // If the type is a block or C function pointer, it must be representable in // ObjC. - switch (auto rep = extInfo.getRepresentation()) { + switch (representation) { case AnyFunctionType::Representation::Block: case AnyFunctionType::Representation::CFunctionPointer: if (!fnTy->isRepresentableIn(ForeignLanguage::ObjectiveC, DC)) { StringRef strName = - rep == AnyFunctionType::Representation::Block ? "block" : "c"; + (representation == AnyFunctionType::Representation::Block) + ? "block" + : "c"; auto extInfo2 = extInfo.withRepresentation(AnyFunctionType::Representation::Swift); auto simpleFnTy = FunctionType::get(params, outputTy, extInfo2); diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 56e23d273fc8f..fdb9fc0f06453 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -4631,7 +4631,10 @@ class swift::TypeDeserializer { uint8_t rawRepresentation, rawDiffKind; bool noescape = false, throws; GenericSignature genericSig = GenericSignature(); + clang::Type *clangFunctionType = nullptr; + // FIXME: [clang-function-type-serialization] Deserialize a clang::Type out + // of the record. if (!isGeneric) { decls_block::FunctionTypeLayout::readRecord( scratch, resultID, rawRepresentation, noescape, throws, rawDiffKind); @@ -4651,8 +4654,9 @@ class swift::TypeDeserializer { if (!diffKind.hasValue()) MF.fatal(); - auto info = - FunctionType::ExtInfo(*representation, noescape, throws, *diffKind); + auto info = FunctionType::ExtInfo(*representation, noescape, throws, + *diffKind, clangFunctionType); + auto resultTy = MF.getTypeChecked(resultID); if (!resultTy) @@ -4986,7 +4990,10 @@ class swift::TypeDeserializer { unsigned numResults; GenericSignatureID rawGenericSig; ArrayRef variableData; + clang::FunctionType *clangFunctionType = nullptr; + // FIXME: [clang-function-type-serialization] Deserialize a + // clang::FunctionType out of the record. decls_block::SILFunctionTypeLayout::readRecord(scratch, rawCoroutineKind, rawCalleeConvention, @@ -5006,11 +5013,13 @@ class swift::TypeDeserializer { = getActualSILFunctionTypeRepresentation(rawRepresentation); if (!representation.hasValue()) MF.fatal(); + auto diffKind = getActualDifferentiabilityKind(rawDiffKind); if (!diffKind.hasValue()) MF.fatal(); + SILFunctionType::ExtInfo extInfo(*representation, pseudogeneric, noescape, - *diffKind); + *diffKind, clangFunctionType); // Process the coroutine kind. auto coroutineKind = getActualSILCoroutineKind(rawCoroutineKind); diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index c490924d422e5..b6ebae44720fa 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -3943,6 +3943,8 @@ class Serializer::TypeSerializer : public TypeVisitor { void visitFunctionType(const FunctionType *fnTy) { using namespace decls_block; + + // FIXME: [clang-function-type-serialization] Serialize the clang type here unsigned abbrCode = S.DeclTypeAbbrCodes[FunctionTypeLayout::Code]; FunctionTypeLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, S.addTypeRef(fnTy->getResult()), diff --git a/test/Sema/clang_types_in_ast.swift b/test/Sema/clang_types_in_ast.swift new file mode 100644 index 0000000000000..c81679fbc4208 --- /dev/null +++ b/test/Sema/clang_types_in_ast.swift @@ -0,0 +1,36 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend %s -typecheck -DNOCRASH1 +// RUN: %target-swift-frontend %s -typecheck -DNOCRASH1 -use-clang-function-types +// RUN: %target-swift-frontend %s -typecheck -DNOCRASH2 -sdk %clang-importer-sdk +// RUN: %target-swift-frontend %s -typecheck -DNOCRASH2 -sdk %clang-importer-sdk -use-clang-function-types +// RUN: %target-swift-frontend %s -DAUXMODULE -module-name Foo -emit-module -o %t + +// FIXME: [clang-function-type-serialization] This should stop crashing once we +// start serializing clang function types. +// RUN: not --crash %target-swift-frontend %s -typecheck -DCRASH -I %t -use-clang-function-types + +#if NOCRASH1 +public func my_signal() -> Optional<@convention(c) (Int32) -> Void> { + let s : Optional<@convention(c) (Int32) -> Void> = .none; + var s2 : Optional<@convention(c) (Int32) -> Void> = s; + return s2; +} +#endif + +#if NOCRASH2 +import ctypes +func f() { + _ = getFunctionPointer() as (@convention(c) (CInt) -> CInt)? +} +#endif + +#if AUXMODULE +public var DUMMY_SIGNAL : Optional<@convention(c) (Int32) -> Void> = .none +#endif + +#if CRASH +import Foo +public func my_signal() -> Optional<@convention(c) (Int32) -> Void> { + return Foo.DUMMY_SIGNAL +} +#endif