diff --git a/include/swift/AST/ExtInfo.h b/include/swift/AST/ExtInfo.h index 6f258723fb887..4216002504520 100644 --- a/include/swift/AST/ExtInfo.h +++ b/include/swift/AST/ExtInfo.h @@ -41,6 +41,7 @@ class FunctionType; class SILExtInfo; class SILExtInfoBuilder; class SILFunctionType; +enum class SILFunctionTypeRepresentation : uint8_t; } // namespace swift namespace swift { @@ -54,6 +55,7 @@ class ClangTypeInfo { friend ASTExtInfoBuilder; friend SILExtInfoBuilder; + // [NOTE: ClangTypeInfo-contents] // 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 // (for AnyFunctionType). @@ -81,6 +83,26 @@ class ClangTypeInfo { void dump(llvm::raw_ostream &os, const clang::ASTContext &ctx) const; }; +// MARK: - UnexpectedClangTypeError +/// Potential errors when trying to store a Clang type in an ExtInfo. +struct UnexpectedClangTypeError { + enum class Kind { + NullForCOrBlock, + NonnullForNonCOrBlock, + NotBlockPointer, + NotFunctionPointerOrReference, + NonCanonical, + }; + const Kind errorKind; + const clang::Type *type; + + static Optional checkClangType( + SILFunctionTypeRepresentation fnRep, const clang::Type *type, + bool expectNonnullForCOrBlock, bool expectCanonical); + + void dump(); +}; + // MARK: - FunctionTypeRepresentation /// The representation form of a function. enum class FunctionTypeRepresentation : uint8_t { @@ -146,6 +168,41 @@ enum class SILFunctionTypeRepresentation : uint8_t { Closure, }; +constexpr SILFunctionTypeRepresentation +convertRepresentation(FunctionTypeRepresentation rep) { + switch (rep) { + case FunctionTypeRepresentation::Swift: + return SILFunctionTypeRepresentation::Thick; + case FunctionTypeRepresentation::Block: + return SILFunctionTypeRepresentation::Block; + case FunctionTypeRepresentation::Thin: + return SILFunctionTypeRepresentation::Thin; + case FunctionTypeRepresentation::CFunctionPointer: + return SILFunctionTypeRepresentation::CFunctionPointer; + } + llvm_unreachable("Unhandled FunctionTypeRepresentation!"); +}; + +inline Optional +convertRepresentation(SILFunctionTypeRepresentation rep) { + switch (rep) { + case SILFunctionTypeRepresentation::Thick: + return {FunctionTypeRepresentation::Swift}; + case SILFunctionTypeRepresentation::Block: + return {FunctionTypeRepresentation::Block}; + case SILFunctionTypeRepresentation::Thin: + return {FunctionTypeRepresentation::Thin}; + case SILFunctionTypeRepresentation::CFunctionPointer: + return {FunctionTypeRepresentation::CFunctionPointer}; + case SILFunctionTypeRepresentation::Method: + case SILFunctionTypeRepresentation::ObjCMethod: + case SILFunctionTypeRepresentation::WitnessMethod: + case SILFunctionTypeRepresentation::Closure: + return None; + } + llvm_unreachable("Unhandled SILFunctionTypeRepresentation!"); +}; + /// Can this calling convention result in a function being called indirectly /// through the runtime. constexpr bool canBeCalledIndirectly(SILFunctionTypeRepresentation rep) { @@ -165,6 +222,25 @@ constexpr bool canBeCalledIndirectly(SILFunctionTypeRepresentation rep) { llvm_unreachable("Unhandled SILFunctionTypeRepresentation in switch."); } +template constexpr bool shouldStoreClangType(Repr repr) { + static_assert(std::is_same::value || + std::is_same::value, + "Expected a Representation type as the argument type."); + switch (static_cast(repr)) { + case SILFunctionTypeRepresentation::CFunctionPointer: + case SILFunctionTypeRepresentation::Block: + return true; + case SILFunctionTypeRepresentation::ObjCMethod: + case SILFunctionTypeRepresentation::Thick: + case SILFunctionTypeRepresentation::Thin: + case SILFunctionTypeRepresentation::Method: + case SILFunctionTypeRepresentation::WitnessMethod: + case SILFunctionTypeRepresentation::Closure: + return false; + } + llvm_unreachable("Unhandled SILFunctionTypeRepresentation."); +} + // MARK: - ASTExtInfoBuilder /// A builder type for creating an \c ASTExtInfo. /// @@ -292,7 +368,8 @@ class ASTExtInfoBuilder { LLVM_NODISCARD ASTExtInfoBuilder withRepresentation(Representation rep) const { return ASTExtInfoBuilder((bits & ~RepresentationMask) | (unsigned)rep, - clangTypeInfo); + shouldStoreClangType(rep) ? clangTypeInfo + : ClangTypeInfo()); } LLVM_NODISCARD ASTExtInfoBuilder withNoEscape(bool noEscape = true) const { @@ -333,7 +410,8 @@ class ASTExtInfoBuilder { ASTExtInfoBuilder withSILRepresentation(SILFunctionTypeRepresentation rep) const { return ASTExtInfoBuilder((bits & ~RepresentationMask) | (unsigned)rep, - clangTypeInfo); + shouldStoreClangType(rep) ? clangTypeInfo + : ClangTypeInfo()); } bool isEqualTo(ASTExtInfoBuilder other, bool useClangTypes) const { @@ -360,12 +438,16 @@ class ASTExtInfo { ASTExtInfoBuilder builder; + // Only for use by ASTExtInfoBuilder::build. Don't use it elsewhere! ASTExtInfo(ASTExtInfoBuilder builder) : builder(builder) {} + ASTExtInfo(unsigned bits, ClangTypeInfo clangTypeInfo) - : builder(bits, clangTypeInfo){}; + : builder(bits, clangTypeInfo) { + builder.checkInvariants(); + }; public: - ASTExtInfo() : builder(){}; + ASTExtInfo() : builder() { builder.checkInvariants(); }; /// Create a builder with the same state as \c this. ASTExtInfoBuilder intoBuilder() const { return builder; } @@ -504,7 +586,7 @@ class SILExtInfoBuilder { using Representation = SILFunctionTypeRepresentation; SILExtInfoBuilder(unsigned bits, ClangTypeInfo clangTypeInfo) - : bits(bits), clangTypeInfo(clangTypeInfo) {} + : bits(bits), clangTypeInfo(clangTypeInfo.getCanonical()) {} static constexpr unsigned makeBits(Representation rep, bool isPseudogeneric, bool isNoEscape, bool isAsync, @@ -606,7 +688,8 @@ class SILExtInfoBuilder { // the following with methods instead of mutating these objects. SILExtInfoBuilder withRepresentation(Representation rep) const { return SILExtInfoBuilder((bits & ~RepresentationMask) | (unsigned)rep, - clangTypeInfo); + shouldStoreClangType(rep) ? clangTypeInfo + : ClangTypeInfo()); } SILExtInfoBuilder withIsPseudogeneric(bool isPseudogeneric = true) const { return SILExtInfoBuilder(isPseudogeneric ? (bits | PseudogenericMask) @@ -629,6 +712,10 @@ class SILExtInfoBuilder { ((unsigned)differentiability << DifferentiabilityMaskOffset), clangTypeInfo); } + LLVM_NODISCARD + SILExtInfoBuilder withClangFunctionType(const clang::Type *type) const { + return SILExtInfoBuilder(bits, ClangTypeInfo(type).getCanonical()); + } bool isEqualTo(SILExtInfoBuilder other, bool useClangTypes) const { return bits == other.bits && @@ -654,12 +741,21 @@ class SILExtInfo { SILExtInfoBuilder builder; + // Only for use by SILExtInfoBuilder::build. Don't use it elsewhere! SILExtInfo(SILExtInfoBuilder builder) : builder(builder) {} + SILExtInfo(unsigned bits, ClangTypeInfo clangTypeInfo) - : builder(bits, clangTypeInfo){}; + : builder(bits, clangTypeInfo) { + builder.checkInvariants(); + }; public: - SILExtInfo() : builder(){}; + SILExtInfo() : builder() { builder.checkInvariants(); }; + + SILExtInfo(ASTExtInfo info, bool isPseudogeneric) + : builder(info.intoBuilder(), isPseudogeneric) { + builder.checkInvariants(); + } static SILExtInfo getThin() { return SILExtInfoBuilder(SILExtInfoBuilder::Representation::Thin, false, @@ -722,6 +818,8 @@ class SILExtInfo { constexpr std::pair getFuncAttrKey() const { return builder.getFuncAttrKey(); } + + Optional checkClangType() const; }; /// Helper function to obtain the useClangTypes parameter for checking equality diff --git a/include/swift/AST/PrintOptions.h b/include/swift/AST/PrintOptions.h index 2b99e4ac1e66b..9fb65e5a7d7a0 100644 --- a/include/swift/AST/PrintOptions.h +++ b/include/swift/AST/PrintOptions.h @@ -594,7 +594,7 @@ struct PrintOptions { static PrintOptions printDocInterface(); /// Retrieve the set of options suitable for printing SIL functions. - static PrintOptions printSIL() { + static PrintOptions printSIL(bool printFullConvention = false) { PrintOptions result; result.PrintLongAttrsOnSeparateLines = true; result.PrintStorageRepresentationAttrs = true; @@ -605,6 +605,9 @@ struct PrintOptions { result.PrintIfConfig = false; result.OpaqueReturnTypePrinting = OpaqueReturnTypePrintingMode::StableReference; + if (printFullConvention) + result.PrintFunctionRepresentationAttrs = + PrintOptions::FunctionRepresentationMode::Full; return result; } diff --git a/include/swift/AST/SILOptions.h b/include/swift/AST/SILOptions.h index 5eaac7a1cf721..bb4e3b7ad1db0 100644 --- a/include/swift/AST/SILOptions.h +++ b/include/swift/AST/SILOptions.h @@ -78,6 +78,9 @@ class SILOptions { /// variables by name when we print it out. This eases diffing of SIL files. bool EmitSortedSIL = false; + /// See \ref FrontendOptions.PrintFullConvention + bool PrintFullConvention = false; + /// Whether to stop the optimization pipeline after serializing SIL. bool StopOptimizationAfterSerialization = false; diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 328f4c0aff762..e62a8fe2e2a29 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -3888,7 +3888,7 @@ class SILFunctionType final public llvm::FoldingSetNode, private llvm::TrailingObjects { + SubstitutionMap, CanType, ClangTypeInfo> { friend TrailingObjects; size_t numTrailingObjects(OverloadToken) const { @@ -3912,6 +3912,10 @@ class SILFunctionType final size_t(hasInvocationSubstitutions()); } + size_t numTrailingObjects(OverloadToken) const { + return Bits.SILFunctionType.HasClangTypeInfo ? 1 : 0; + } + public: using ExtInfo = SILExtInfo; using ExtInfoBuilder = SILExtInfoBuilder; diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h index c961794d35582..3921e9d4df412 100644 --- a/include/swift/Frontend/FrontendOptions.h +++ b/include/swift/Frontend/FrontendOptions.h @@ -239,6 +239,9 @@ class FrontendOptions { /// output path is configured. Optional IntermoduleDependencyTracking; + /// Should we emit the cType when printing @convention(c) or no? + bool PrintFullConvention = false; + /// Should we serialize the hashes of dependencies (vs. the modification /// times) when compiling a module interface? bool SerializeModuleInterfaceDependencyHashes = false; diff --git a/include/swift/Frontend/ModuleInterfaceSupport.h b/include/swift/Frontend/ModuleInterfaceSupport.h index f4c97c66c8f62..6bbabd76c2efa 100644 --- a/include/swift/Frontend/ModuleInterfaceSupport.h +++ b/include/swift/Frontend/ModuleInterfaceSupport.h @@ -32,7 +32,7 @@ struct ModuleInterfaceOptions { /// interface, or should we fully-qualify them? bool PreserveTypesAsWritten = false; - /// Should we emit the cType when printing @convention(c) or no? + /// See \ref FrontendOptions.PrintFullConvention. /// [TODO: Clang-type-plumbing] This check should go away. bool PrintFullConvention = false; diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index cf788d081253d..d304a32216c1e 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -659,10 +659,12 @@ def experimental_spi_imports : Flag<["-"], "experimental-spi-imports">, HelpText<"Enable experimental support for SPI imports">; +// [FIXME: Clang-type-plumbing] Make this a SIL-only option once we start +// unconditionally emitting non-canonical Clang types in swiftinterfaces. def experimental_print_full_convention : Flag<["-"], "experimental-print-full-convention">, - HelpText<"When emitting a module interface, emit additional @convention " - "arguments, regardless of whether they were written in the source">; + HelpText<"When emitting a module interface or SIL, emit additional @convention" + " arguments, regardless of whether they were written in the source">; def experimental_one_way_closure_params : Flag<["-"], "experimental-one-way-closure-params">, diff --git a/include/swift/SIL/SILModule.h b/include/swift/SIL/SILModule.h index 988fe9fe61ece..fa2857308f1ff 100644 --- a/include/swift/SIL/SILModule.h +++ b/include/swift/SIL/SILModule.h @@ -671,8 +671,7 @@ class SILModule { /// \param Opts The SIL options, used to determine printing verbosity and /// and sorting. /// \param PrintASTDecls If set to true print AST decls. - void print(raw_ostream& OS, - ModuleDecl *M = nullptr, + void print(raw_ostream &OS, ModuleDecl *M = nullptr, const SILOptions &Opts = SILOptions(), bool PrintASTDecls = true) const { SILPrintContext PrintCtx(OS, Opts); diff --git a/include/swift/SIL/SILPrintContext.h b/include/swift/SIL/SILPrintContext.h index f4d8a19860d5d..0b9c2c1448b44 100644 --- a/include/swift/SIL/SILPrintContext.h +++ b/include/swift/SIL/SILPrintContext.h @@ -66,20 +66,23 @@ class SILPrintContext { /// Print debug locations and scopes. bool DebugInfo; + /// See \ref FrontendOptions.PrintFullConvention. + bool PrintFullConvention; + public: /// Constructor with default values for options. /// /// DebugInfo will be set according to the -sil-print-debuginfo option. SILPrintContext(llvm::raw_ostream &OS, bool Verbose = false, - bool SortedSIL = false); + bool SortedSIL = false, bool PrintFullConvention = false); /// Constructor based on SILOptions. /// /// DebugInfo will be set according to the -sil-print-debuginfo option. SILPrintContext(llvm::raw_ostream &OS, const SILOptions &Opts); - SILPrintContext(llvm::raw_ostream &OS, bool Verbose, - bool SortedSIL, bool DebugInfo); + SILPrintContext(llvm::raw_ostream &OS, bool Verbose, bool SortedSIL, + bool DebugInfo, bool PrintFullConvention); virtual ~SILPrintContext(); @@ -100,6 +103,9 @@ class SILPrintContext { /// Returns true if debug locations and scopes should be printed. bool printDebugInfo() const { return DebugInfo; } + /// Returns true if the entire @convention(c, cType: ..) should be printed. + bool printFullConvention() const { return PrintFullConvention; } + SILPrintContext::ID getID(const SILBasicBlock *Block); SILPrintContext::ID getID(const SILNode *node); diff --git a/include/swift/SIL/SILType.h b/include/swift/SIL/SILType.h index f36f27177223c..99794dfa9e514 100644 --- a/include/swift/SIL/SILType.h +++ b/include/swift/SIL/SILType.h @@ -611,7 +611,8 @@ class SILType { std::string getAsString() const; void dump() const; - void print(raw_ostream &OS) const; + void print(raw_ostream &OS, + const PrintOptions &PO = PrintOptions::printSIL()) const; }; // Statically prevent SILTypes from being directly cast to a type diff --git a/include/swift/SIL/TypeLowering.h b/include/swift/SIL/TypeLowering.h index 344087f0a1aaf..ed135eccf8e2f 100644 --- a/include/swift/SIL/TypeLowering.h +++ b/include/swift/SIL/TypeLowering.h @@ -55,20 +55,17 @@ CanAnyFunctionType adjustFunctionType(CanAnyFunctionType type, AnyFunctionType::ExtInfo extInfo); /// Change the given function type's representation. -inline CanAnyFunctionType adjustFunctionType(CanAnyFunctionType t, - SILFunctionType::Representation rep) { - auto extInfo = - t->getExtInfo().intoBuilder().withSILRepresentation(rep).build(); - return adjustFunctionType(t, extInfo); +inline CanAnyFunctionType +adjustFunctionType(CanAnyFunctionType t, AnyFunctionType::Representation rep, + ClangTypeInfo clangTypeInfo) { + auto extInfo = t->getExtInfo() + .intoBuilder() + .withRepresentation(rep) + .withClangFunctionType(clangTypeInfo.getType()) + .build(); + return adjustFunctionType(t, extInfo); } -/// Change the given function type's representation. -inline CanAnyFunctionType adjustFunctionType(CanAnyFunctionType t, - AnyFunctionType::Representation rep) { - auto extInfo = t->getExtInfo().withRepresentation(rep); - return adjustFunctionType(t, extInfo); -} - /// Given a SIL function type, return a type that is identical except /// for using the given ExtInfo. CanSILFunctionType @@ -992,7 +989,8 @@ class TypeConverter { /// Given a function type, yield its bridged formal type. CanAnyFunctionType getBridgedFunctionType(AbstractionPattern fnPattern, CanAnyFunctionType fnType, - Bridgeability bridging); + Bridgeability bridging, + SILFunctionTypeRepresentation rep); /// Given a referenced value and the substituted formal type of a /// resulting l-value expression, produce the substituted formal @@ -1121,7 +1119,7 @@ class TypeConverter { CanSILFunctionType getNativeSILFunctionType( Lowering::TypeConverter &TC, TypeExpansionContext context, Lowering::AbstractionPattern origType, CanAnyFunctionType substType, - Optional origConstant = None, + SILExtInfo silExtInfo, Optional origConstant = None, Optional constant = None, Optional reqtSubs = None, ProtocolConformanceRef witnessMethodConformance = ProtocolConformanceRef()); diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 21703f4929ce9..727c9917bb467 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -3246,6 +3246,9 @@ GenericFunctionType *GenericFunctionType::get(GenericSignature sig, // point. bool isCanonical = isGenericFunctionTypeCanonical(sig, params, result); + assert(info.getClangTypeInfo().empty() && + "Generic functions do not have Clang types at the moment."); + if (auto funcTy = ctx.getImpl().GenericFunctionTypes.FindNodeOrInsertPos(id, insertPos)) { return funcTy; @@ -3365,6 +3368,7 @@ SILFunctionType::SILFunctionType( "Bits were dropped!"); static_assert(SILExtInfoBuilder::NumMaskBits == NumSILExtInfoBits, "ExtInfo and SILFunctionTypeBitfields must agree on bit size"); + Bits.SILFunctionType.HasClangTypeInfo = !ext.getClangTypeInfo().empty(); Bits.SILFunctionType.CoroutineKind = unsigned(coroutineKind); NumParameters = params.size(); if (coroutineKind == SILCoroutineKind::None) { @@ -3402,6 +3406,9 @@ SILFunctionType::SILFunctionType( getMutableFormalResultsCache() = CanType(); getMutableAllResultsCache() = CanType(); } + if (!ext.getClangTypeInfo().empty()) + *getTrailingObjects() = ext.getClangTypeInfo(); + #ifndef NDEBUG if (ext.getRepresentation() == Representation::WitnessMethod) assert(!WitnessMethodConformance.isInvalid() && @@ -3524,6 +3531,21 @@ CanSILFunctionType SILFunctionType::get( patternSubs = patternSubs.getCanonical(); invocationSubs = invocationSubs.getCanonical(); + + // [FIXME: Clang-type-plumbing] + if (ctx.LangOpts.UseClangFunctionTypes) { + if (auto error = ext.checkClangType()) { + error.getValue().dump(); + llvm_unreachable("Unexpected Clang type in SILExtInfo."); + } + } else if (!ext.getClangTypeInfo().empty()) { + // Unlike AnyFunctionType, SILFunctionType is always canonical. Hence, + // conditionalizing canonical type computation based on + // UseClangFunctionTypes like AnyFunctionType is not feasible. It is simpler + // to drop the Clang type altogether. + ext = ext.intoBuilder().withClangFunctionType(nullptr).build(); + } + llvm::FoldingSetNodeID id; SILFunctionType::Profile(id, genericSig, ext, coroutineKind, callee, params, @@ -3541,12 +3563,11 @@ CanSILFunctionType SILFunctionType::get( // See [NOTE: SILFunctionType-layout] bool hasResultCache = normalResults.size() > 1; - size_t bytes = - totalSizeToAlloc( + size_t bytes = totalSizeToAlloc( params.size(), normalResults.size() + (errorResult ? 1 : 0), yields.size(), (patternSubs ? 1 : 0) + (invocationSubs ? 1 : 0), - hasResultCache ? 2 : 0); + hasResultCache ? 2 : 0, ext.getClangTypeInfo().empty() ? 0 : 1); void *mem = ctx.Allocate(bytes, alignof(SILFunctionType)); diff --git a/lib/AST/ASTDemangler.cpp b/lib/AST/ASTDemangler.cpp index d5fbfa63f56ae..8c31aec8bc35e 100644 --- a/lib/AST/ASTDemangler.cpp +++ b/lib/AST/ASTDemangler.cpp @@ -396,7 +396,7 @@ Type ASTBuilder::createFunctionType( && !flags.isEscaping(); const clang::Type *clangFunctionType = nullptr; - if (representation == FunctionTypeRepresentation::CFunctionPointer) + if (shouldStoreClangType(representation)) clangFunctionType = Ctx.getClangFunctionType(funcParams, output, representation); @@ -523,12 +523,6 @@ Type ASTBuilder::createImplFunctionType( break; } - // [TODO: Store-SIL-Clang-type] - auto einfo = SILExtInfoBuilder(representation, flags.isPseudogeneric(), - !flags.isEscaping(), flags.isAsync(), diffKind, - /*clangFunctionType*/ nullptr) - .build(); - llvm::SmallVector funcParams; llvm::SmallVector funcYields; llvm::SmallVector funcResults; @@ -553,6 +547,21 @@ Type ASTBuilder::createImplFunctionType( auto conv = getResultConvention(errorResult->getConvention()); funcErrorResult.emplace(type, conv); } + + const clang::Type *clangFnType = nullptr; + if (shouldStoreClangType(representation)) { + assert(funcResults.size() <= 1 && funcYields.size() == 0 && + "C functions and blocks have at most 1 result and 0 yields."); + auto result = + funcResults.empty() ? Optional() : funcResults[0]; + clangFnType = getASTContext().getCanonicalClangFunctionType( + funcParams, result, representation); + } + auto einfo = SILFunctionType::ExtInfoBuilder( + representation, flags.isPseudogeneric(), !flags.isEscaping(), + flags.isAsync(), diffKind, clangFnType) + .build(); + return SILFunctionType::get(genericSig, einfo, funcCoroutineKind, funcCalleeConvention, funcParams, funcYields, funcResults, funcErrorResult, diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index caf25cf5dada0..7bc4f56539c33 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -3831,6 +3831,14 @@ namespace { OS << '\n'; T->getInvocationSubstitutions().dump(OS, SubstitutionMap::DumpStyle::Full, Indent+2); + if (!T->getClangTypeInfo().empty()) { + std::string s; + llvm::raw_string_ostream os(s); + auto &ctx = + T->getASTContext().getClangModuleLoader()->getClangASTContext(); + T->getClangTypeInfo().dump(os, ctx); + printField("clang_type", os.str()); + } PrintWithColorRAII(OS, ParenthesisColor) << ')'; } diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 65b3ea8af59a9..bba551e3decf1 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -4053,8 +4053,8 @@ class TypePrinter : public TypeVisitor { info.getSILRepresentation() == SILFunctionType::Representation::Thick) return; - bool printNameOnly = Options.PrintFunctionRepresentationAttrs == - PrintOptions::FunctionRepresentationMode::NameOnly; + bool printClangType = Options.PrintFunctionRepresentationAttrs == + PrintOptions::FunctionRepresentationMode::Full; Printer.callPrintStructurePre(PrintStructureKind::BuiltinAttribute); Printer.printAttrName("@convention"); Printer << "("; @@ -4067,13 +4067,13 @@ class TypePrinter : public TypeVisitor { break; case SILFunctionType::Representation::Block: Printer << "block"; + if (printClangType && !info.getClangTypeInfo().empty()) + printCType(Ctx, Printer, info); break; case SILFunctionType::Representation::CFunctionPointer: Printer << "c"; - // [TODO: Clang-type-plumbing] Remove the second check. - if (printNameOnly || info.getClangTypeInfo().empty()) - break; - printCType(Ctx, Printer, info); + if (printClangType && !info.getClangTypeInfo().empty()) + printCType(Ctx, Printer, info); break; case SILFunctionType::Representation::Method: Printer << "method"; @@ -4120,8 +4120,8 @@ class TypePrinter : public TypeVisitor { info.getRepresentation() == SILFunctionType::Representation::Thick) break; - bool printNameOnly = Options.PrintFunctionRepresentationAttrs == - PrintOptions::FunctionRepresentationMode::NameOnly; + bool printClangType = Options.PrintFunctionRepresentationAttrs == + PrintOptions::FunctionRepresentationMode::Full; Printer.callPrintStructurePre(PrintStructureKind::BuiltinAttribute); Printer.printAttrName("@convention"); Printer << "("; @@ -4133,13 +4133,13 @@ class TypePrinter : public TypeVisitor { break; case SILFunctionType::Representation::Block: Printer << "block"; + if (printClangType) + printCType(Ctx, Printer, info); break; case SILFunctionType::Representation::CFunctionPointer: Printer << "c"; - // [TODO: Clang-type-plumbing] Remove the second check. - if (printNameOnly || info.getClangTypeInfo().empty()) - break; - printCType(Ctx, Printer, info); + if (printClangType) + printCType(Ctx, Printer, info); break; case SILFunctionType::Representation::Method: Printer << "method"; diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp index f49276266cfce..a9aee16dac5be 100644 --- a/lib/AST/Builtins.cpp +++ b/lib/AST/Builtins.cpp @@ -1540,19 +1540,25 @@ static ValueDecl *getOnceOperation(ASTContext &Context, auto HandleTy = Context.TheRawPointerType; auto VoidTy = Context.TheEmptyTupleType; + SmallVector CFuncParams; + swift::CanType ContextTy; + if (withContext) { + ContextTy = Context.TheRawPointerType; + auto ContextArg = FunctionType::Param(ContextTy); + CFuncParams.push_back(ContextArg); + } + auto Rep = FunctionTypeRepresentation::CFunctionPointer; + auto ClangType = Context.getClangFunctionType(CFuncParams, VoidTy, Rep); auto Thin = FunctionType::ExtInfoBuilder(FunctionTypeRepresentation::CFunctionPointer, /*throws*/ false) + .withClangFunctionType(ClangType) .build(); - if (withContext) { - auto ContextTy = Context.TheRawPointerType; - auto ContextArg = FunctionType::Param(ContextTy); - auto BlockTy = FunctionType::get({ContextArg}, VoidTy, Thin); - return getBuiltinFunction(Id, {HandleTy, BlockTy, ContextTy}, VoidTy); - } else { - auto BlockTy = FunctionType::get({}, VoidTy, Thin); - return getBuiltinFunction(Id, {HandleTy, BlockTy}, VoidTy); - } + auto BlockTy = FunctionType::get(CFuncParams, VoidTy, Thin); + SmallVector ArgTypes = {HandleTy, BlockTy}; + if (withContext) + ArgTypes.push_back(ContextTy); + return getBuiltinFunction(Id, ArgTypes, VoidTy); } static ValueDecl *getPolymorphicBinaryOperation(ASTContext &ctx, diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 03c3111ad8e31..afc94a052c765 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -2592,6 +2592,7 @@ mapSignatureExtInfo(AnyFunctionType::ExtInfo info, .withRepresentation(info.getRepresentation()) .withAsync(info.isAsync()) .withThrows(info.isThrowing()) + .withClangFunctionType(info.getClangTypeInfo().getType()) .build(); } diff --git a/lib/AST/ExtInfo.cpp b/lib/AST/ExtInfo.cpp index aba9bb2577ce0..1fb30adc6af16 100644 --- a/lib/AST/ExtInfo.cpp +++ b/lib/AST/ExtInfo.cpp @@ -19,17 +19,7 @@ #include "clang/AST/Type.h" -static void assertIsFunctionType(const clang::Type *type) { -#ifndef NDEBUG - if (!(type->isFunctionPointerType() || type->isBlockPointerType() || - type->isFunctionReferenceType())) { - llvm::errs() << "Expected a Clang function type wrapped in a pointer type " - << "or a block pointer type but found:\n"; - type->dump(); - llvm_unreachable("\nUnexpected Clang type when creating ExtInfo!"); - } -#endif -} +#include "llvm/ADT/Optional.h" namespace swift { @@ -64,14 +54,99 @@ void ClangTypeInfo::dump(llvm::raw_ostream &os, } } +// MARK: - UnexpectedClangTypeError + +Optional UnexpectedClangTypeError::checkClangType( + SILFunctionTypeRepresentation silRep, + const clang::Type *type, bool expectNonnullForCOrBlock, bool expectCanonical) { +#ifdef NDEBUG + return None; +#else + bool isBlock = true; + switch (silRep) { + case SILFunctionTypeRepresentation::CFunctionPointer: + isBlock = false; + LLVM_FALLTHROUGH; + case SILFunctionTypeRepresentation::Block: { + if (!type) { + if (expectNonnullForCOrBlock) + return {{Kind::NullForCOrBlock, type}}; + return None; + } + if (expectCanonical && !type->isCanonicalUnqualified()) + return {{Kind::NonCanonical, type}}; + if (isBlock && !type->isBlockPointerType()) + return {{Kind::NotBlockPointer, type}}; + if (!isBlock && !(type->isFunctionPointerType() + || type->isFunctionReferenceType())) + return {{Kind::NotFunctionPointerOrReference, type}}; + return None; + } + default: { + if (type) + return {{Kind::NonnullForNonCOrBlock, type}}; + return None; + } + } +#endif +} + +void UnexpectedClangTypeError::dump() { + auto &e = llvm::errs(); + using Kind = UnexpectedClangTypeError::Kind; + switch (errorKind) { + case Kind::NullForCOrBlock: { + e << "Expected non-null Clang type for @convention(c)/@convention(block)" + << " function but found nullptr."; + return; + } + case Kind::NonnullForNonCOrBlock: { + e << ("Expected null Clang type for non-@convention(c)," + " non-@convention(block) function but found:\n"); + type->dump(); + return; + } + case Kind::NotBlockPointer: { + e << ("Expected block pointer type for @convention(block) function but" + " found:\n"); + type->dump(); + return; + } + case Kind::NotFunctionPointerOrReference: { + e << ("Expected function pointer/reference type for @convention(c) function" + " but found:\n"); + type->dump(); + return; + } + case Kind::NonCanonical: { + e << "Expected canonicalized Clang type but found:\n"; + type->dump(); + return; + } + } + llvm_unreachable("Unhandled case for UnexpectedClangTypeError"); +} + +// [NOTE: ExtInfo-Clang-type-invariant] +// At the SIL level, all @convention(c) and @convention(block) function types +// are expected to carry a ClangTypeInfo. This is not enforced at the AST level +// because we may synthesize types which are not convertible to Clang types. +// 1. Type errors: If we have a type error, we may end up generating (say) a +// @convention(c) function type that has an ErrorType as a parameter. +// 2. Bridging: The representation can change during bridging. For example, an +// @convention(swift) function can be bridged to an @convention(block) +// function. Since this happens during SILGen, we may see a "funny" type +// like @convention(c) () -> @convention(swift) () -> () at the AST level. + // MARK: - ASTExtInfoBuilder void ASTExtInfoBuilder::checkInvariants() const { - // 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) && clangTypeInfo.type) - assertIsFunctionType(clangTypeInfo.type); + // See [NOTE: ExtInfo-Clang-type-invariant] + if (auto error = UnexpectedClangTypeError::checkClangType( + getSILRepresentation(), clangTypeInfo.getType(), false, false)) { + error.getValue().dump(); + llvm_unreachable("Ill-formed ASTExtInfoBuilder."); + } } // MARK: - ASTExtInfo @@ -84,7 +159,14 @@ ASTExtInfo ASTExtInfoBuilder::build() const { // MARK: - SILExtInfoBuilder void SILExtInfoBuilder::checkInvariants() const { - // TODO: Add validation checks here while making sure things don't blow up. + // See [NOTE: ExtInfo-Clang-type-invariant] + // [FIXME: Clang-type-plumbing] Strengthen check when UseClangFunctionTypes + // is removed. + if (auto error = UnexpectedClangTypeError::checkClangType( + getRepresentation(), clangTypeInfo.getType(), false, true)) { + error.getValue().dump(); + llvm_unreachable("Ill-formed SILExtInfoBuilder."); + } } SILExtInfo SILExtInfoBuilder::build() const { @@ -92,4 +174,11 @@ SILExtInfo SILExtInfoBuilder::build() const { return SILExtInfo(*this); } +// MARK: - SILExtInfo + +Optional SILExtInfo::checkClangType() const { + return UnexpectedClangTypeError::checkClangType( + getRepresentation(), getClangTypeInfo().getType(), true, true); +} + } // end namespace swift diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 402a33ab65356..35c7a62ebcab3 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -3428,9 +3428,13 @@ bool AnyFunctionType::hasSameExtInfoAs(const AnyFunctionType *otherFn) { return getExtInfo().isEqualTo(otherFn->getExtInfo(), useClangTypes(this)); } -// [TODO: Store-SIL-Clang-type] ClangTypeInfo SILFunctionType::getClangTypeInfo() const { - return ClangTypeInfo(); + if (!Bits.SILFunctionType.HasClangTypeInfo) + return ClangTypeInfo(); + auto *info = getTrailingObjects(); + assert(!info->empty() && + "If the ClangTypeInfo was empty, we shouldn't have stored it."); + return *info; } bool SILFunctionType::hasSameExtInfoAs(const SILFunctionType *otherFn) { diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index b386d03579cef..9d0b89356c348 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -487,11 +487,15 @@ namespace { if (!pointeeType) return Type(); FunctionType *fTy = pointeeType->castTo(); - - auto rep = FunctionType::Representation::Block; + + auto extInfo = + fTy->getExtInfo() + .intoBuilder() + .withRepresentation(FunctionType::Representation::Block) + .withClangFunctionType(type) + .build(); auto funcTy = - FunctionType::get(fTy->getParams(), fTy->getResult(), - fTy->getExtInfo().withRepresentation(rep)); + FunctionType::get(fTy->getParams(), fTy->getResult(), extInfo); return { funcTy, ImportHint::Block }; } @@ -1407,7 +1411,14 @@ static ImportedType adjustTypeForConcreteImport( auto fTy = importedType->castTo(); FunctionType::ExtInfo einfo = fTy->getExtInfo(); if (einfo.getRepresentation() != requiredFunctionTypeRepr) { - einfo = einfo.withRepresentation(requiredFunctionTypeRepr); + const clang::Type *clangType = nullptr; + if (shouldStoreClangType(requiredFunctionTypeRepr)) + clangType = fTy->getASTContext().getClangFunctionType( + fTy->getParams(), fTy->getResult(), requiredFunctionTypeRepr); + einfo = einfo.intoBuilder() + .withRepresentation(requiredFunctionTypeRepr) + .withClangFunctionType(clangType) + .build(); importedType = fTy->withExtInfo(einfo); } break; diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp index c876a44f87383..cc67bca7d6121 100644 --- a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp +++ b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp @@ -71,6 +71,8 @@ bool ArgsToFrontendOptionsConverter::convert( Opts.EmitVerboseSIL |= Args.hasArg(OPT_emit_verbose_sil); Opts.EmitSortedSIL |= Args.hasArg(OPT_emit_sorted_sil); + Opts.PrintFullConvention |= + Args.hasArg(OPT_experimental_print_full_convention); Opts.EnableTesting |= Args.hasArg(OPT_enable_testing); Opts.EnablePrivateImports |= Args.hasArg(OPT_enable_private_imports); diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index eab504f229858..9f11344a267f1 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -1162,6 +1162,8 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args, Opts.DebugSerialization |= Args.hasArg(OPT_sil_debug_serialization); Opts.EmitVerboseSIL |= Args.hasArg(OPT_emit_verbose_sil); Opts.EmitSortedSIL |= Args.hasArg(OPT_emit_sorted_sil); + Opts.PrintFullConvention |= + Args.hasArg(OPT_experimental_print_full_convention); Opts.PrintInstCounts |= Args.hasArg(OPT_print_inst_counts); if (const Arg *A = Args.getLastArg(OPT_external_pass_pipeline_filename)) Opts.ExternalPassPipelineFilename = A->getValue(); diff --git a/lib/IRGen/IRGenDebugInfo.cpp b/lib/IRGen/IRGenDebugInfo.cpp index e93c525ca0008..ce1cbbab7d4bf 100644 --- a/lib/IRGen/IRGenDebugInfo.cpp +++ b/lib/IRGen/IRGenDebugInfo.cpp @@ -24,6 +24,7 @@ #include "swift/AST/Module.h" #include "swift/AST/ModuleLoader.h" #include "swift/AST/Pattern.h" +#include "swift/AST/TypeDifferenceVisitor.h" #include "swift/Basic/Dwarf.h" #include "swift/Basic/SourceManager.h" #include "swift/Basic/Version.h" @@ -73,6 +74,26 @@ namespace { using TrackingDIRefMap = llvm::DenseMap; +class EqualUpToClangTypes + : public CanTypeDifferenceVisitor { +public: + bool visitDifferentTypeStructure(CanType t1, CanType t2) { +#define COMPARE_UPTO_CLANG_TYPE(CLASS) \ + if (auto f1 = dyn_cast(t1)) { \ + auto f2 = cast(t2); \ + return !f1->getExtInfo().isEqualTo(f2->getExtInfo(), \ + /*useClangTypes*/ false); \ + } + COMPARE_UPTO_CLANG_TYPE(FunctionType); + COMPARE_UPTO_CLANG_TYPE(SILFunctionType); +#undef COMPARE_UPTO_CLANG_TYPE + return true; + } + bool check(Type t1, Type t2) { + return !visit(t1->getCanonicalType(), t2->getCanonicalType()); + }; +}; + class IRGenDebugInfoImpl : public IRGenDebugInfo { friend class IRGenDebugInfoImpl; const IRGenOptions &Opts; @@ -815,7 +836,9 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { llvm::errs() << "Original type:\n"; Ty->dump(llvm::errs()); abort(); - } else if (!Reconstructed->isEqual(Ty)) { + } else if (!Reconstructed->isEqual(Ty) && + !EqualUpToClangTypes().check(Reconstructed, Ty)) { + // [FIXME: Include-Clang-type-in-mangling] Remove second check llvm::errs() << "Incorrect reconstructed type for " << Result << "\n"; llvm::errs() << "Original type:\n"; Ty->dump(llvm::errs()); diff --git a/lib/SIL/IR/Bridging.cpp b/lib/SIL/IR/Bridging.cpp index 053a00de71c7a..4d8430c9509c0 100644 --- a/lib/SIL/IR/Bridging.cpp +++ b/lib/SIL/IR/Bridging.cpp @@ -205,11 +205,15 @@ Type TypeConverter::getLoweredCBridgedType(AbstractionPattern pattern, bridging, /*non-optional*/false); + auto clangType = Context.getClangFunctionType( + newParams, {newResult}, FunctionTypeRepresentation::Block); + return FunctionType::get( newParams, newResult, funTy->getExtInfo() .intoBuilder() - .withSILRepresentation(SILFunctionType::Representation::Block) + .withRepresentation(FunctionType::Representation::Block) + .withClangFunctionType(clangType) .build()); } } diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index 2fc920638e98f..daee62ff2e37e 100644 --- a/lib/SIL/IR/SILFunctionType.cpp +++ b/lib/SIL/IR/SILFunctionType.cpp @@ -27,8 +27,10 @@ #include "swift/AST/Module.h" #include "swift/AST/ModuleLoader.h" #include "swift/AST/ProtocolConformance.h" +#include "swift/ClangImporter/ClangImporter.h" #include "swift/SIL/SILModule.h" #include "swift/SIL/SILType.h" +#include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" @@ -1532,8 +1534,8 @@ class DestructureInputs { void destructure(AbstractionPattern origType, CanAnyFunctionType::CanParamArrayRef params, - AnyFunctionType::ExtInfo extInfo) { - visitTopLevelParams(origType, params, extInfo); + SILExtInfoBuilder extInfoBuilder) { + visitTopLevelParams(origType, params, extInfoBuilder); } private: @@ -1549,13 +1551,14 @@ class DestructureInputs { /// self correctly. void visitTopLevelParams(AbstractionPattern origType, CanAnyFunctionType::CanParamArrayRef params, - AnyFunctionType::ExtInfo extInfo) { + SILExtInfoBuilder extInfoBuilder) { unsigned numEltTypes = params.size(); - bool hasSelf = (extInfo.hasSelfParam() || Foreign.Self.isImportAsMember()); + bool hasSelf = + (extInfoBuilder.hasSelfParam() || Foreign.Self.isImportAsMember()); unsigned numNonSelfParams = (hasSelf ? numEltTypes - 1 : numEltTypes); - auto silRepresentation = extInfo.getSILRepresentation(); + auto silRepresentation = extInfoBuilder.getRepresentation(); // We have to declare this out here so that the lambda scope lasts for // the duration of the loop below. @@ -2020,11 +2023,11 @@ static void destructureYieldsForCoroutine(TypeConverter &TC, /// /// \param conventions - conventions as expressed for the original type static CanSILFunctionType getSILFunctionType( - TypeConverter &TC, TypeExpansionContext expansionContext, AbstractionPattern origType, - CanAnyFunctionType substFnInterfaceType, AnyFunctionType::ExtInfo extInfo, - const Conventions &conventions, const ForeignInfo &foreignInfo, - Optional origConstant, Optional constant, - Optional reqtSubs, + TypeConverter &TC, TypeExpansionContext expansionContext, + AbstractionPattern origType, CanAnyFunctionType substFnInterfaceType, + SILExtInfoBuilder extInfoBuilder, const Conventions &conventions, + const ForeignInfo &foreignInfo, Optional origConstant, + Optional constant, Optional reqtSubs, ProtocolConformanceRef witnessMethodConformance) { // Find the generic parameters. CanGenericSignature genericSig = @@ -2092,7 +2095,7 @@ static CanSILFunctionType getSILFunctionType( // which will have standard thin or thick representation. (Per the previous // comment, it would be useful to do so for generic methods on classes and // protocols too.) - auto rep = extInfo.getSILRepresentation(); + auto rep = extInfoBuilder.getRepresentation(); return (rep == SILFunctionTypeRepresentation::Thick || rep == SILFunctionTypeRepresentation::Thin); }(); @@ -2105,9 +2108,8 @@ static CanSILFunctionType getSILFunctionType( { DestructureInputs destructurer(expansionContext, TC, conventions, foreignInfo, inputs, subst); - destructurer.destructure(origType, - substFnInterfaceType.getParams(), - extInfo); + destructurer.destructure(origType, substFnInterfaceType.getParams(), + extInfoBuilder); } // Destructure the coroutine yields. @@ -2134,23 +2136,33 @@ static CanSILFunctionType getSILFunctionType( } auto calleeConvention = ParameterConvention::Direct_Unowned; - if (extInfo.hasContext()) + if (extInfoBuilder.hasContext()) calleeConvention = conventions.getCallee(); bool pseudogeneric = genericSig && constant ? isPseudogeneric(*constant) : false; - // NOTE: SILFunctionType::ExtInfo doesn't track everything that - // AnyFunctionType::ExtInfo tracks. For example: 'throws' or 'auto-closure' - auto silExtInfo = - SILFunctionType::ExtInfoBuilder() - .withRepresentation(extInfo.getSILRepresentation()) - .withIsPseudogeneric(pseudogeneric) - .withNoEscape(extInfo.isNoEscape()) - .withDifferentiabilityKind(extInfo.getDifferentiabilityKind()) - .build(); - + auto silRep = extInfoBuilder.getRepresentation(); + const clang::Type *clangType = extInfoBuilder.getClangTypeInfo().getType(); + if (shouldStoreClangType(silRep) && !clangType) { + // If we have invalid code in the source like + // do { let x = 0; let _ : @convention(c) () -> Int = { x } } + // we will fail to convert the corresponding SIL function type, as it will + // have a sil_box_type { Int } parameter reflecting the capture. So we + // convert the AST type instead. + // N.B. The `do` is necessary; the code compiles at global scope. + SmallVector params; + for (auto ty : substFnInterfaceType.getParams()) + params.push_back(ty); + clangType = TC.Context.getClangFunctionType( + params, substFnInterfaceType.getResult(), + convertRepresentation(silRep).getValue()); + } + auto silExtInfo = extInfoBuilder.withClangFunctionType(clangType) + .withIsPseudogeneric(pseudogeneric) + .build(); + // Build the substituted generic signature we extracted. SubstitutionMap substitutions; if (subst.Enabled) { @@ -2378,32 +2390,30 @@ struct DefaultBlockConventions : Conventions { } // end anonymous namespace -static CanSILFunctionType -getSILFunctionTypeForAbstractCFunction(TypeConverter &TC, - AbstractionPattern origType, - CanAnyFunctionType substType, - AnyFunctionType::ExtInfo extInfo, - Optional constant); +static CanSILFunctionType getSILFunctionTypeForAbstractCFunction( + TypeConverter &TC, AbstractionPattern origType, + CanAnyFunctionType substType, SILExtInfoBuilder extInfoBuilder, + Optional constant); static CanSILFunctionType getNativeSILFunctionType( - TypeConverter &TC, TypeExpansionContext context, AbstractionPattern origType, - CanAnyFunctionType substInterfaceType, AnyFunctionType::ExtInfo extInfo, - Optional origConstant, Optional constant, - Optional reqtSubs, + TypeConverter &TC, TypeExpansionContext context, + AbstractionPattern origType, CanAnyFunctionType substInterfaceType, + SILExtInfoBuilder extInfoBuilder, Optional origConstant, + Optional constant, Optional reqtSubs, ProtocolConformanceRef witnessMethodConformance) { assert(bool(origConstant) == bool(constant)); auto getSILFunctionTypeForConventions = [&](const Conventions &convs) -> CanSILFunctionType { return getSILFunctionType(TC, context, origType, substInterfaceType, - extInfo, convs, ForeignInfo(), origConstant, - constant, reqtSubs, witnessMethodConformance); + extInfoBuilder, convs, ForeignInfo(), + origConstant, constant, reqtSubs, + witnessMethodConformance); }; - switch (extInfo.getSILRepresentation()) { + switch (extInfoBuilder.getRepresentation()) { case SILFunctionType::Representation::Block: case SILFunctionType::Representation::CFunctionPointer: - return getSILFunctionTypeForAbstractCFunction(TC, origType, - substInterfaceType, - extInfo, constant); + return getSILFunctionTypeForAbstractCFunction( + TC, origType, substInterfaceType, extInfoBuilder, constant); case SILFunctionType::Representation::Thin: case SILFunctionType::Representation::ObjCMethod: @@ -2447,23 +2457,13 @@ static CanSILFunctionType getNativeSILFunctionType( CanSILFunctionType swift::getNativeSILFunctionType( TypeConverter &TC, TypeExpansionContext context, AbstractionPattern origType, CanAnyFunctionType substType, - Optional origConstant, Optional substConstant, - Optional reqtSubs, + SILExtInfo silExtInfo, Optional origConstant, + Optional substConstant, Optional reqtSubs, ProtocolConformanceRef witnessMethodConformance) { - AnyFunctionType::ExtInfo extInfo; - - // Preserve type information from the original type if possible. - if (auto origFnType = origType.getAs()) { - extInfo = origFnType->getExtInfo(); - // Otherwise, preserve function type attributes from the substituted type. - } else { - extInfo = substType->getExtInfo(); - } - - return ::getNativeSILFunctionType(TC, context, origType, substType, extInfo, - origConstant, substConstant, reqtSubs, - witnessMethodConformance); + return ::getNativeSILFunctionType( + TC, context, origType, substType, silExtInfo.intoBuilder(), origConstant, + substConstant, reqtSubs, witnessMethodConformance); } //===----------------------------------------------------------------------===// @@ -2798,21 +2798,18 @@ class CXXMethodConventions : public CFunctionTypeConventions { /// Given that we have an imported Clang declaration, deduce the /// ownership conventions for calling it and build the SILFunctionType. -static CanSILFunctionType -getSILFunctionTypeForClangDecl(TypeConverter &TC, const clang::Decl *clangDecl, - CanAnyFunctionType origType, - CanAnyFunctionType substInterfaceType, - AnyFunctionType::ExtInfo extInfo, - const ForeignInfo &foreignInfo, - Optional constant) { +static CanSILFunctionType getSILFunctionTypeForClangDecl( + TypeConverter &TC, const clang::Decl *clangDecl, + CanAnyFunctionType origType, CanAnyFunctionType substInterfaceType, + SILExtInfoBuilder extInfoBuilder, const ForeignInfo &foreignInfo, + Optional constant) { if (auto method = dyn_cast(clangDecl)) { auto origPattern = AbstractionPattern::getObjCMethod(origType, method, foreignInfo.Error); - return getSILFunctionType(TC, TypeExpansionContext::minimal(), origPattern, - substInterfaceType, extInfo, - ObjCMethodConventions(method), foreignInfo, - constant, constant, None, - ProtocolConformanceRef()); + return getSILFunctionType( + TC, TypeExpansionContext::minimal(), origPattern, substInterfaceType, + extInfoBuilder, ObjCMethodConventions(method), foreignInfo, constant, + constant, None, ProtocolConformanceRef()); } if (auto method = dyn_cast(clangDecl)) { @@ -2821,7 +2818,7 @@ getSILFunctionTypeForClangDecl(TypeConverter &TC, const clang::Decl *clangDecl, AbstractionPattern::getCXXMethod(origType, method); auto conventions = CXXMethodConventions(method); return getSILFunctionType(TC, TypeExpansionContext::minimal(), origPattern, - substInterfaceType, extInfo, conventions, + substInterfaceType, extInfoBuilder, conventions, foreignInfo, constant, constant, None, ProtocolConformanceRef()); } @@ -2834,7 +2831,7 @@ getSILFunctionTypeForClangDecl(TypeConverter &TC, const clang::Decl *clangDecl, foreignInfo.Self) : AbstractionPattern(origType, clangType); return getSILFunctionType(TC, TypeExpansionContext::minimal(), origPattern, - substInterfaceType, extInfo, + substInterfaceType, extInfoBuilder, CFunctionConventions(func), foreignInfo, constant, constant, None, ProtocolConformanceRef()); } @@ -2842,12 +2839,10 @@ getSILFunctionTypeForClangDecl(TypeConverter &TC, const clang::Decl *clangDecl, llvm_unreachable("call to unknown kind of C function"); } -static CanSILFunctionType -getSILFunctionTypeForAbstractCFunction(TypeConverter &TC, - AbstractionPattern origType, - CanAnyFunctionType substType, - AnyFunctionType::ExtInfo extInfo, - Optional constant) { +static CanSILFunctionType getSILFunctionTypeForAbstractCFunction( + TypeConverter &TC, AbstractionPattern origType, + CanAnyFunctionType substType, SILExtInfoBuilder extInfoBuilder, + Optional constant) { if (origType.isClangType()) { auto clangType = origType.getClangType(); const clang::FunctionType *fnType; @@ -2864,17 +2859,17 @@ getSILFunctionTypeForAbstractCFunction(TypeConverter &TC, } if (fnType) { return getSILFunctionType( - TC, TypeExpansionContext::minimal(), origType, substType, extInfo, - CFunctionTypeConventions(fnType), ForeignInfo(), constant, constant, - None, ProtocolConformanceRef()); + TC, TypeExpansionContext::minimal(), origType, substType, + extInfoBuilder, CFunctionTypeConventions(fnType), ForeignInfo(), + constant, constant, None, ProtocolConformanceRef()); } } // TODO: Ought to support captures in block funcs. return getSILFunctionType(TC, TypeExpansionContext::minimal(), origType, - substType, extInfo, DefaultBlockConventions(), - ForeignInfo(), constant, constant, None, - ProtocolConformanceRef()); + substType, extInfoBuilder, + DefaultBlockConventions(), ForeignInfo(), constant, + constant, None, ProtocolConformanceRef()); } /// Try to find a clang method declaration for the given function. @@ -3031,16 +3026,13 @@ class ObjCSelectorFamilyConventions : public Conventions { } // end anonymous namespace -static CanSILFunctionType -getSILFunctionTypeForObjCSelectorFamily(TypeConverter &TC, ObjCSelectorFamily family, - CanAnyFunctionType origType, - CanAnyFunctionType substInterfaceType, - AnyFunctionType::ExtInfo extInfo, - const ForeignInfo &foreignInfo, - Optional constant) { +static CanSILFunctionType getSILFunctionTypeForObjCSelectorFamily( + TypeConverter &TC, ObjCSelectorFamily family, CanAnyFunctionType origType, + CanAnyFunctionType substInterfaceType, SILExtInfoBuilder extInfoBuilder, + const ForeignInfo &foreignInfo, Optional constant) { return getSILFunctionType( TC, TypeExpansionContext::minimal(), AbstractionPattern(origType), - substInterfaceType, extInfo, ObjCSelectorFamilyConventions(family), + substInterfaceType, extInfoBuilder, ObjCSelectorFamilyConventions(family), foreignInfo, constant, constant, /*requirement subs*/ None, ProtocolConformanceRef()); } @@ -3065,26 +3057,47 @@ static bool isImporterGeneratedAccessor(const clang::Decl *clangDecl, static CanSILFunctionType getUncachedSILFunctionTypeForConstant( TypeConverter &TC, TypeExpansionContext context, SILDeclRef constant, - CanAnyFunctionType origLoweredInterfaceType) { - assert(origLoweredInterfaceType->getExtInfo().getSILRepresentation() - != SILFunctionTypeRepresentation::Thick - && origLoweredInterfaceType->getExtInfo().getSILRepresentation() - != SILFunctionTypeRepresentation::Block); + TypeConverter::LoweredFormalTypes bridgedTypes) { + auto silRep = TC.getDeclRefRepresentation(constant); + assert(silRep != SILFunctionTypeRepresentation::Thick && + silRep != SILFunctionTypeRepresentation::Block); + auto origLoweredInterfaceType = bridgedTypes.Uncurried; auto extInfo = origLoweredInterfaceType->getExtInfo(); + auto extInfoBuilder = + SILExtInfo(extInfo, false).intoBuilder().withRepresentation(silRep); + + if (shouldStoreClangType(silRep)) { + const clang::Type *clangType = nullptr; + if (bridgedTypes.Pattern.isClangType()) { + clangType = bridgedTypes.Pattern.getClangType(); + } + if (clangType) { + // According to [NOTE: ClangTypeInfo-contents], we need to wrap a function + // type in an additional clang::PointerType. + if (clangType->isFunctionType()) { + clangType = + static_cast(TC.Context.getClangModuleLoader()) + ->getClangASTContext() + .getPointerType(clang::QualType(clangType, 0)) + .getTypePtr(); + } + extInfoBuilder = extInfoBuilder.withClangFunctionType(clangType); + } + } + if (!constant.isForeign) { ProtocolConformanceRef witnessMethodConformance; - if (extInfo.getSILRepresentation() == - SILFunctionTypeRepresentation::WitnessMethod) { + if (silRep == SILFunctionTypeRepresentation::WitnessMethod) { auto proto = constant.getDecl()->getDeclContext()->getSelfProtocolDecl(); witnessMethodConformance = ProtocolConformanceRef(proto); } return ::getNativeSILFunctionType( TC, context, AbstractionPattern(origLoweredInterfaceType), - origLoweredInterfaceType, extInfo, constant, constant, None, + origLoweredInterfaceType, extInfoBuilder, constant, constant, None, witnessMethodConformance); } @@ -3110,28 +3123,25 @@ static CanSILFunctionType getUncachedSILFunctionTypeForConstant( foreignInfo.Self.setSelfIndex(selfIndex); } - return getSILFunctionTypeForClangDecl(TC, clangDecl, - origLoweredInterfaceType, - origLoweredInterfaceType, - extInfo, foreignInfo, constant); + return getSILFunctionTypeForClangDecl( + TC, clangDecl, origLoweredInterfaceType, origLoweredInterfaceType, + extInfoBuilder, foreignInfo, constant); } } // If the decl belongs to an ObjC method family, use that family's // ownership conventions. return getSILFunctionTypeForObjCSelectorFamily( - TC, getObjCSelectorFamily(constant), - origLoweredInterfaceType, origLoweredInterfaceType, - extInfo, foreignInfo, constant); + TC, getObjCSelectorFamily(constant), origLoweredInterfaceType, + origLoweredInterfaceType, extInfoBuilder, foreignInfo, constant); } CanSILFunctionType TypeConverter::getUncachedSILFunctionTypeForConstant( TypeExpansionContext context, SILDeclRef constant, CanAnyFunctionType origInterfaceType) { - auto origLoweredInterfaceType = - getLoweredFormalTypes(constant, origInterfaceType).Uncurried; + auto bridgedTypes = getLoweredFormalTypes(constant, origInterfaceType); return ::getUncachedSILFunctionTypeForConstant(*this, context, constant, - origLoweredInterfaceType); + bridgedTypes); } static bool isClassOrProtocolMethod(ValueDecl *vd) { @@ -3219,10 +3229,6 @@ TypeConverter::getConstantInfo(TypeExpansionContext expansion, // right type for a getter or setter. auto formalInterfaceType = makeConstantInterfaceType(constant); - // The formal type is just that with the right representation. - auto rep = getDeclRefRepresentation(constant); - formalInterfaceType = adjustFunctionType(formalInterfaceType, rep); - // The lowered type is the formal type, but uncurried and with // parameters automatically turned into their bridged equivalents. auto bridgedTypes = getLoweredFormalTypes(constant, formalInterfaceType); @@ -3230,9 +3236,8 @@ TypeConverter::getConstantInfo(TypeExpansionContext expansion, CanAnyFunctionType loweredInterfaceType = bridgedTypes.Uncurried; // The SIL type encodes conventions according to the original type. - CanSILFunctionType silFnType = - ::getUncachedSILFunctionTypeForConstant(*this, expansion, constant, - loweredInterfaceType); + CanSILFunctionType silFnType = ::getUncachedSILFunctionTypeForConstant( + *this, expansion, constant, bridgedTypes); // If the constant refers to a derivative function, get the SIL type of the // original function and use it to compute the derivative SIL type. @@ -3490,7 +3495,8 @@ TypeConverter::getConstantOverrideInfo(TypeExpansionContext context, // Build the SILFunctionType for the class method call. CanSILFunctionType fnTy = getNativeSILFunctionType( - *this, context, basePattern, bridgedTypes.Uncurried, base, derived, + *this, context, basePattern, bridgedTypes.Uncurried, + derivedInfo.SILFnType->getExtInfo(), base, derived, /*reqt subs*/ None, ProtocolConformanceRef()); // Build the SILConstantInfo and cache it. @@ -3979,14 +3985,12 @@ SILFunctionType::substituteOpaqueArchetypes(TypeConverter &TC, } /// Fast path for bridging types in a function type without uncurrying. -CanAnyFunctionType -TypeConverter::getBridgedFunctionType(AbstractionPattern pattern, - CanAnyFunctionType t, - Bridgeability bridging) { +CanAnyFunctionType TypeConverter::getBridgedFunctionType( + AbstractionPattern pattern, CanAnyFunctionType t, Bridgeability bridging, + SILFunctionTypeRepresentation rep) { // Pull out the generic signature. CanGenericSignature genericSig = t.getOptGenericSignature(); - auto rep = t->getExtInfo().getSILRepresentation(); switch (getSILFunctionLanguage(rep)) { case SILFunctionLanguage::Swift: { // No bridging needed for native functions. @@ -4092,20 +4096,20 @@ TypeConverter::getLoweredFormalTypes(SILDeclRef constant, getAbstractionPatternForConstant(Context, constant, fnType, numParameterLists); + auto extInfo = fnType->getExtInfo(); + SILFunctionTypeRepresentation rep = getDeclRefRepresentation(constant); + assert(rep != SILFunctionType::Representation::Block && + "objc blocks cannot be curried"); + // Fast path: no uncurrying required. if (numParameterLists == 1) { auto bridgedFnType = - getBridgedFunctionType(bridgingFnPattern, fnType, bridging); + getBridgedFunctionType(bridgingFnPattern, fnType, bridging, rep); bridgingFnPattern.rewriteType(bridgingFnPattern.getGenericSignature(), bridgedFnType); return { bridgingFnPattern, bridgedFnType }; } - auto extInfo = fnType->getExtInfo(); - SILFunctionTypeRepresentation rep = extInfo.getSILRepresentation(); - assert(rep != SILFunctionType::Representation::Block - && "objc blocks cannot be curried"); - // The dependent generic signature. CanGenericSignature genericSig = fnType.getOptGenericSignature(); diff --git a/lib/SIL/IR/SILPrinter.cpp b/lib/SIL/IR/SILPrinter.cpp index 17c3810556b77..3fe377a57792e 100644 --- a/lib/SIL/IR/SILPrinter.cpp +++ b/lib/SIL/IR/SILPrinter.cpp @@ -440,13 +440,12 @@ static void printSILTypeColorAndSigil(raw_ostream &OS, SILType t) { // Potentially add a leading sigil for the value category. ::print(OS, t.getCategory()); } - -void SILType::print(raw_ostream &OS) const { + +void SILType::print(raw_ostream &OS, const PrintOptions &PO) const { printSILTypeColorAndSigil(OS, *this); // Print other types as their Swift representation. - PrintOptions SubPrinter = PrintOptions::printSIL(); - getASTType().print(OS, SubPrinter); + getASTType().print(OS, PO); } void SILType::dump() const { @@ -459,7 +458,8 @@ void SILType::dump() const { /// result in `sugaredTypeNames`. static void printSILFunctionNameAndType( llvm::raw_ostream &OS, const SILFunction *function, - llvm::DenseMap &sugaredTypeNames) { + llvm::DenseMap &sugaredTypeNames, + bool printFullConvention = false) { function->printName(OS); OS << " : $"; auto *genEnv = function->getGenericEnvironment(); @@ -496,7 +496,7 @@ static void printSILFunctionNameAndType( sugaredTypeNames[archetypeTy->getCanonicalType()] = name; } } - auto printOptions = PrintOptions::printSIL(); + auto printOptions = PrintOptions::printSIL(printFullConvention); printOptions.GenericSig = genSig; printOptions.AlternativeTypeNames = sugaredTypeNames.empty() ? nullptr : &sugaredTypeNames; @@ -570,8 +570,9 @@ class SILPrinter : public SILInstructionVisitor { SILPrinter( SILPrintContext &PrintCtx, llvm::DenseMap *AlternativeTypeNames = nullptr) - : Ctx(PrintCtx), - PrintState{{PrintCtx.OS()}, PrintOptions::printSIL()}, + : Ctx(PrintCtx), PrintState{{PrintCtx.OS()}, + PrintOptions::printSIL( + PrintCtx.printFullConvention())}, LastBufferID(0) { PrintState.ASTOptions.AlternativeTypeNames = AlternativeTypeNames; PrintState.ASTOptions.PrintForSIL = true; @@ -2684,7 +2685,8 @@ void SILFunction::print(SILPrintContext &PrintCtx) const { OS << "[ossa] "; llvm::DenseMap sugaredTypeNames; - printSILFunctionNameAndType(OS, this, sugaredTypeNames); + printSILFunctionNameAndType(OS, this, sugaredTypeNames, + PrintCtx.printFullConvention()); if (!isExternalDeclaration()) { if (auto eCount = getEntryCount()) { @@ -2702,9 +2704,7 @@ void SILFunction::print(SILPrintContext &PrintCtx) const { /// Pretty-print the SILFunction's name using SIL syntax, /// '@function_mangled_name'. -void SILFunction::printName(raw_ostream &OS) const { - OS << "@" << Name; -} +void SILFunction::printName(raw_ostream &OS) const { OS << "@" << Name; } /// Pretty-print a global variable to the designated stream. void SILGlobalVariable::print(llvm::raw_ostream &OS, bool Verbose) const { @@ -2971,8 +2971,8 @@ static void printFileIDMap(SILPrintContext &Ctx, const FileIDMap map) { } void SILProperty::print(SILPrintContext &Ctx) const { - PrintOptions Options = PrintOptions::printSIL(); - + PrintOptions Options = PrintOptions::printSIL(Ctx.printFullConvention()); + auto &OS = Ctx.OS(); OS << "sil_property "; if (isSerialized()) @@ -3495,19 +3495,20 @@ void SILSpecializeAttr::print(llvm::raw_ostream &OS) const { //===----------------------------------------------------------------------===// SILPrintContext::SILPrintContext(llvm::raw_ostream &OS, bool Verbose, - bool SortedSIL) : - OutStream(OS), Verbose(Verbose), SortedSIL(SortedSIL), - DebugInfo(SILPrintDebugInfo) { } + bool SortedSIL, bool PrintFullConvention) + : OutStream(OS), Verbose(Verbose), SortedSIL(SortedSIL), + DebugInfo(SILPrintDebugInfo), PrintFullConvention(PrintFullConvention) {} -SILPrintContext::SILPrintContext(llvm::raw_ostream &OS, - const SILOptions &Opts) : - OutStream(OS), Verbose(Opts.EmitVerboseSIL), SortedSIL(Opts.EmitSortedSIL), - DebugInfo(SILPrintDebugInfo) {} +SILPrintContext::SILPrintContext(llvm::raw_ostream &OS, const SILOptions &Opts) + : OutStream(OS), Verbose(Opts.EmitVerboseSIL), + SortedSIL(Opts.EmitSortedSIL), DebugInfo(SILPrintDebugInfo), + PrintFullConvention(Opts.PrintFullConvention) {} SILPrintContext::SILPrintContext(llvm::raw_ostream &OS, bool Verbose, - bool SortedSIL, bool DebugInfo) : - OutStream(OS), Verbose(Verbose), SortedSIL(SortedSIL), - DebugInfo(DebugInfo) { } + bool SortedSIL, bool DebugInfo, + bool PrintFullConvention) + : OutStream(OS), Verbose(Verbose), SortedSIL(SortedSIL), + DebugInfo(DebugInfo), PrintFullConvention(PrintFullConvention) {} void SILPrintContext::setContext(const void *FunctionOrBlock) { if (FunctionOrBlock != ContextFunctionOrBlock) { diff --git a/lib/SIL/IR/TypeLowering.cpp b/lib/SIL/IR/TypeLowering.cpp index 45a725074cb8d..d63785e08851c 100644 --- a/lib/SIL/IR/TypeLowering.cpp +++ b/lib/SIL/IR/TypeLowering.cpp @@ -1953,18 +1953,18 @@ TypeConverter::computeLoweredRValueType(TypeExpansionContext forExpansion, // If the formal type uses a C convention, it is not formally // abstractable, and it may be subject to implicit bridging. auto extInfo = substFnType->getExtInfo(); - if (getSILFunctionLanguage(extInfo.getSILRepresentation()) == - SILFunctionLanguage::C) { + auto rep = extInfo.getRepresentation(); + SILFunctionTypeRepresentation silRep = convertRepresentation(rep); + if (getSILFunctionLanguage(silRep) == SILFunctionLanguage::C) { // The importer only applies fully-reversible bridging to the // component types of C function pointers. auto bridging = Bridgeability::Full; - if (extInfo.getSILRepresentation() == - SILFunctionTypeRepresentation::CFunctionPointer) + if (silRep == SILFunctionTypeRepresentation::CFunctionPointer) bridging = Bridgeability::None; // Bridge the parameters and result of the function type. auto bridgedFnType = - TC.getBridgedFunctionType(origType, substFnType, bridging); + TC.getBridgedFunctionType(origType, substFnType, bridging, silRep); substFnType = bridgedFnType; // Also rewrite the type of the abstraction pattern. @@ -1976,8 +1976,24 @@ TypeConverter::computeLoweredRValueType(TypeExpansionContext forExpansion, } } - return ::getNativeSILFunctionType(TC, forExpansion, origType, - substFnType); + AnyFunctionType::ExtInfo baseExtInfo; + if (auto origFnType = origType.getAs()) { + baseExtInfo = origFnType->getExtInfo(); + } else { + baseExtInfo = substFnType->getExtInfo(); + } + const clang::Type *clangType = baseExtInfo.getClangTypeInfo().getType(); + if (shouldStoreClangType(rep) && !clangType) { + clangType = TC.Context.getClangFunctionType( + substFnType->getParams(), substFnType->getResult(), rep); + } + auto silExtInfo = + SILExtInfoBuilder( + baseExtInfo.intoBuilder().withClangFunctionType(clangType), false) + .build(); + + return ::getNativeSILFunctionType(TC, forExpansion, origType, substFnType, + silExtInfo); } // Ignore dynamic self types. diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp index 4943330220262..e6996d02e9d06 100644 --- a/lib/SILGen/SILGen.cpp +++ b/lib/SILGen/SILGen.cpp @@ -450,8 +450,6 @@ SILGenModule::getKeyPathProjectionCoroutine(bool isReadAccess, SILFunction *SILGenModule::emitTopLevelFunction(SILLocation Loc) { ASTContext &C = getASTContext(); - auto extInfo = SILFunctionType::ExtInfo() - .withRepresentation(SILFunctionType::Representation::CFunctionPointer); // Use standard library types if we have them; otherwise, fall back to // builtins. @@ -481,6 +479,14 @@ SILFunction *SILGenModule::emitTopLevelFunction(SILLocation Loc) { SILParameterInfo(Int32Ty, ParameterConvention::Direct_Unowned), SILParameterInfo(PtrPtrInt8Ty, ParameterConvention::Direct_Unowned), }; + SILResultInfo results[] = {SILResultInfo(Int32Ty, ResultConvention::Unowned)}; + + auto rep = SILFunctionType::Representation::CFunctionPointer; + auto *clangTy = C.getCanonicalClangFunctionType(params, results[0], rep); + auto extInfo = SILFunctionType::ExtInfoBuilder() + .withRepresentation(rep) + .withClangFunctionType(clangTy) + .build(); CanSILFunctionType topLevelType = SILFunctionType::get(nullptr, extInfo, SILCoroutineKind::None, diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp index 22d3136ca776c..65c44598af668 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -74,9 +74,10 @@ getIndirectApplyAbstractionPattern(SILGenFunction &SGF, case FunctionTypeRepresentation::Block: { // C and block function parameters and results are implicitly // bridged to a foreign type. - auto bridgedType = - SGF.SGM.Types.getBridgedFunctionType(pattern, fnType, - Bridgeability::Full); + auto silRep = + SILFunctionTypeRepresentation(fnType->getExtInfo().getRepresentation()); + auto bridgedType = SGF.SGM.Types.getBridgedFunctionType( + pattern, fnType, Bridgeability::Full, silRep); pattern.rewriteType(CanGenericSignature(), bridgedType); return pattern; } diff --git a/lib/SILGen/SILGenBridging.cpp b/lib/SILGen/SILGenBridging.cpp index 0c1bb7d417a89..e48750a4ccc05 100644 --- a/lib/SILGen/SILGenBridging.cpp +++ b/lib/SILGen/SILGenBridging.cpp @@ -347,10 +347,11 @@ getParameterTypes(AnyFunctionType::CanParamArrayRef params) { return results; } -static CanAnyFunctionType getBridgedBlockType(SILGenModule &SGM, - CanAnyFunctionType blockType) { - return SGM.Types.getBridgedFunctionType(AbstractionPattern(blockType), - blockType, Bridgeability::Full); +static CanAnyFunctionType +getBridgedBlockType(SILGenModule &SGM, CanAnyFunctionType blockType, + SILFunctionTypeRepresentation silRep) { + return SGM.Types.getBridgedFunctionType( + AbstractionPattern(blockType), blockType, Bridgeability::Full, silRep); } static void buildFuncToBlockInvokeBody(SILGenFunction &SGF, @@ -367,7 +368,8 @@ static void buildFuncToBlockInvokeBody(SILGenFunction &SGF, SILFunctionConventions funcConv(funcTy, SGF.SGM.M); // Make sure we lower the component types of the formal block type. - formalBlockType = getBridgedBlockType(SGF.SGM, formalBlockType); + formalBlockType = getBridgedBlockType(SGF.SGM, formalBlockType, + blockTy->getRepresentation()); // Set up the indirect result. SILType blockResultTy = @@ -551,9 +553,16 @@ ManagedValue SILGenFunction::emitFuncToBlock(SILLocation loc, blockInterfaceTy->getParameters().end(), std::back_inserter(params)); - auto extInfo = - SILFunctionType::ExtInfo() - .withRepresentation(SILFunctionType::Representation::CFunctionPointer); + auto results = blockInterfaceTy->getResults(); + auto representation = SILFunctionType::Representation::CFunctionPointer; + auto *clangFnType = getASTContext().getCanonicalClangFunctionType( + params, results.empty() ? Optional() : results[0], + representation); + + auto extInfo = SILFunctionType::ExtInfoBuilder() + .withRepresentation(representation) + .withClangFunctionType(clangFnType) + .build(); CanGenericSignature genericSig; GenericEnvironment *genericEnv = nullptr; @@ -821,7 +830,8 @@ static void buildBlockToFuncThunkBody(SILGenFunction &SGF, Scope scope(SGF.Cleanups, CleanupLocation::get(loc)); // Make sure we lower the component types of the formal block type. - formalBlockTy = getBridgedBlockType(SGF.SGM, formalBlockTy); + formalBlockTy = + getBridgedBlockType(SGF.SGM, formalBlockTy, blockTy->getRepresentation()); assert(blockTy->getNumParameters() == funcTy->getNumParameters() && "block and function types don't match"); diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index cb8273d129e1e..6a3b8bde0cf57 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -1773,14 +1773,14 @@ RValue RValueEmitter::visitFunctionConversionExpr(FunctionConversionExpr *e, case AnyFunctionType::Representation::Swift: case AnyFunctionType::Representation::Thin: // Source is native, so we can convert signature first. - destTy = adjustFunctionType(destRepTy, - srcTy->getRepresentation()); + destTy = adjustFunctionType(destRepTy, srcTy->getRepresentation(), + srcTy->getClangTypeInfo()); break; case AnyFunctionType::Representation::Block: case AnyFunctionType::Representation::CFunctionPointer: // Source is foreign, so do the representation change first. - srcTy = adjustFunctionType(srcRepTy, - destRepTy->getRepresentation()); + srcTy = adjustFunctionType(srcRepTy, destRepTy->getRepresentation(), + destRepTy->getClangTypeInfo()); } auto result = SGF.emitRValueAsSingleValue(e->getSubExpr()); diff --git a/lib/SILGen/SILGenFunction.cpp b/lib/SILGen/SILGenFunction.cpp index d9acdc516f6ac..7980d698d19b9 100644 --- a/lib/SILGen/SILGenFunction.cpp +++ b/lib/SILGen/SILGenFunction.cpp @@ -598,20 +598,23 @@ void SILGenFunction::emitArtificialTopLevel(Decl *mainDecl) { CanType anyObjectMetaTy = CanExistentialMetatypeType::get(anyObjectTy, MetatypeRepresentation::ObjC); - auto NSStringFromClassType = SILFunctionType::get(nullptr, - SILFunctionType::ExtInfo() - .withRepresentation(SILFunctionType::Representation:: - CFunctionPointer), - SILCoroutineKind::None, - ParameterConvention::Direct_Unowned, - SILParameterInfo(anyObjectMetaTy, - ParameterConvention::Direct_Unowned), - /*yields*/ {}, - SILResultInfo(OptNSStringTy, - ResultConvention::Autoreleased), - /*error result*/ None, - SubstitutionMap(), SubstitutionMap(), - ctx); + auto paramConvention = ParameterConvention::Direct_Unowned; + auto params = {SILParameterInfo(anyObjectMetaTy, paramConvention)}; + std::array resultInfos = { + SILResultInfo(OptNSStringTy, ResultConvention::Autoreleased)}; + auto repr = SILFunctionType::Representation::CFunctionPointer; + auto *clangFnType = + ctx.getCanonicalClangFunctionType(params, resultInfos[0], repr); + auto extInfo = SILFunctionType::ExtInfoBuilder() + .withRepresentation(repr) + .withClangFunctionType(clangFnType) + .build(); + + auto NSStringFromClassType = SILFunctionType::get( + nullptr, extInfo, SILCoroutineKind::None, paramConvention, params, + /*yields*/ {}, resultInfos, /*error result*/ None, SubstitutionMap(), + SubstitutionMap(), ctx); + auto NSStringFromClassFn = builder.getOrCreateFunction( mainClass, "NSStringFromClass", SILLinkage::PublicExternal, NSStringFromClassType, IsBare, IsTransparent, IsNotSerialized, diff --git a/lib/SILGen/SILGenType.cpp b/lib/SILGen/SILGenType.cpp index d30a74087fc3e..2dd3de4156090 100644 --- a/lib/SILGen/SILGenType.cpp +++ b/lib/SILGen/SILGenType.cpp @@ -733,8 +733,8 @@ SILFunction *SILGenModule::emitProtocolWitness( // Lower the witness thunk type with the requirement's abstraction level. auto witnessSILFnType = getNativeSILFunctionType( M.Types, TypeExpansionContext::minimal(), AbstractionPattern(reqtOrigTy), - reqtSubstTy, requirement, witnessRef, witnessSubsForTypeLowering, - conformance); + reqtSubstTy, requirementInfo.SILFnType->getExtInfo(), requirement, + witnessRef, witnessSubsForTypeLowering, conformance); // Mangle the name of the witness thunk. Mangle::ASTMangler NewMangler; diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 6e3dc8a61aa4e..15351c382bb24 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -1765,15 +1765,13 @@ namespace { TupleTypeRepr *inputRepr, TypeResolutionOptions options, bool requiresMappingOut, DifferentiabilityKind diffKind); - Type resolveSILFunctionType(FunctionTypeRepr *repr, - TypeResolutionOptions options, - SILCoroutineKind coroutineKind - = SILCoroutineKind::None, - SILFunctionType::ExtInfo extInfo - = SILFunctionType::ExtInfo(), - ParameterConvention calleeConvention - = DefaultParameterConvention, - TypeRepr *witnessmethodProtocol = nullptr); + Type resolveSILFunctionType( + FunctionTypeRepr *repr, TypeResolutionOptions options, + SILCoroutineKind coroutineKind = SILCoroutineKind::None, + SILFunctionType::ExtInfoBuilder extInfoBuilder = + SILFunctionType::ExtInfoBuilder(), + ParameterConvention calleeConvention = DefaultParameterConvention, + TypeRepr *witnessmethodProtocol = nullptr); SILParameterInfo resolveSILParameter(TypeRepr *repr, TypeResolutionOptions options); SILYieldInfo resolveSILYield(TypeAttributes &remainingAttrs, @@ -2207,11 +2205,8 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, rep = SILFunctionType::Representation::Thin; } else { rep = *parsedRep; - bool isCOrBlock = - rep == SILFunctionTypeRepresentation::CFunctionPointer - || rep == SILFunctionTypeRepresentation::Block; - parsedClangFunctionType = - tryParseClangType(attrs.ConventionArguments.getValue(), isCOrBlock); + parsedClangFunctionType = tryParseClangType( + attrs.ConventionArguments.getValue(), shouldStoreClangType(rep)); } if (rep == SILFunctionType::Representation::WitnessMethod) { @@ -2238,16 +2233,13 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, } } - // Resolve the function type directly with these attributes. - // [TODO: Store-SIL-Clang-type] - auto extInfo = SILFunctionType::ExtInfoBuilder( - rep, attrs.has(TAK_pseudogeneric), - attrs.has(TAK_noescape), attrs.has(TAK_async), - diffKind, nullptr) - .build(); + auto extInfoBuilder = SILFunctionType::ExtInfoBuilder( + rep, attrs.has(TAK_pseudogeneric), attrs.has(TAK_noescape), + attrs.has(TAK_async), diffKind, parsedClangFunctionType); - ty = resolveSILFunctionType(fnRepr, options, coroutineKind, extInfo, - calleeConvention, witnessMethodProtocol); + ty = + resolveSILFunctionType(fnRepr, options, coroutineKind, extInfoBuilder, + calleeConvention, witnessMethodProtocol); if (!ty || ty->hasError()) return ty; } else { @@ -2269,10 +2261,8 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, } else { rep = *parsedRep; - bool isCOrBlock = rep == FunctionTypeRepresentation::CFunctionPointer - || rep == FunctionTypeRepresentation::Block; - parsedClangFunctionType = - tryParseClangType(attrs.ConventionArguments.getValue(), isCOrBlock); + parsedClangFunctionType = tryParseClangType( + attrs.ConventionArguments.getValue(), shouldStoreClangType(rep)); } } @@ -2714,11 +2704,10 @@ Type TypeResolver::resolveASTFunctionType( /*clangFunctionType*/ nullptr); const clang::Type *clangFnType = parsedClangFunctionType; - if (representation == AnyFunctionType::Representation::CFunctionPointer && - !clangFnType) { - clangFnType = getASTContext().getClangFunctionType( - params, outputTy, AnyFunctionType::Representation::CFunctionPointer); - } + if (shouldStoreClangType(representation) && !clangFnType) + clangFnType = + getASTContext().getClangFunctionType(params, outputTy, representation); + auto extInfo = extInfoBuilder.withRepresentation(representation) .withAsync(repr->isAsync()) .withClangFunctionType(clangFnType) @@ -2859,12 +2848,11 @@ Type TypeResolver::resolveSILBoxType(SILBoxTypeRepr *repr, return SILBoxType::get(getASTContext(), layout, subMap); } -Type TypeResolver::resolveSILFunctionType(FunctionTypeRepr *repr, - TypeResolutionOptions options, - SILCoroutineKind coroutineKind, - SILFunctionType::ExtInfo extInfo, - ParameterConvention callee, - TypeRepr *witnessMethodProtocol) { +Type TypeResolver::resolveSILFunctionType( + FunctionTypeRepr *repr, TypeResolutionOptions options, + SILCoroutineKind coroutineKind, + SILFunctionType::ExtInfoBuilder extInfoBuilder, ParameterConvention callee, + TypeRepr *witnessMethodProtocol) { options.setContext(None); bool hasError = false; @@ -3055,8 +3043,19 @@ Type TypeResolver::resolveSILFunctionType(FunctionTypeRepr *repr, "found witness_method without matching conformance"); } - return SILFunctionType::get(genericSig, extInfo, coroutineKind, callee, - interfaceParams, interfaceYields, + auto representation = extInfoBuilder.getRepresentation(); + const clang::Type *clangFnType = extInfoBuilder.getClangTypeInfo().getType(); + if (shouldStoreClangType(representation) && !clangFnType) { + assert(results.size() <= 1 && yields.size() == 0 && + "C functions and blocks have at most 1 result and 0 yields."); + auto result = results.empty() ? Optional() : results[0]; + clangFnType = getASTContext().getCanonicalClangFunctionType( + interfaceParams, result, representation); + extInfoBuilder = extInfoBuilder.withClangFunctionType(clangFnType); + } + + return SILFunctionType::get(genericSig, extInfoBuilder.build(), coroutineKind, + callee, interfaceParams, interfaceYields, interfaceResults, interfaceErrorResult, interfacePatternSubs, invocationSubs, getASTContext(), witnessMethodConformance); diff --git a/test/SIL/clang-function-types.swift b/test/SIL/clang-function-types.swift new file mode 100644 index 0000000000000..6ed5268a9268a --- /dev/null +++ b/test/SIL/clang-function-types.swift @@ -0,0 +1,8 @@ +// RUN: %target-swift-frontend %s -emit-sil -swift-version 5 -use-clang-function-types -experimental-print-full-convention -o - | %FileCheck %s + +public func f(g: @convention(c) () -> ()) { g() } + +// CHECK: sil @$s4main1f1gyyyXC_tF : $@convention(thin) (@convention(c, cType: "void (*)(void)") @noescape () -> ()) -> () { +// CHECK: bb0(%0 : $@convention(c, cType: "void (*)(void)") @noescape () -> ()): +// CHECK: debug_value %0 : $@convention(c, cType: "void (*)(void)") @noescape () -> (), let, name "g", argno 1 // id: %1 +// CHECK: %2 = apply %0() : $@convention(c, cType: "void (*)(void)") @noescape () -> () diff --git a/test/Serialization/clang-function-types.swift b/test/Serialization/clang-function-types.swift index d85eadf358fe7..195343c08b1a8 100644 --- a/test/Serialization/clang-function-types.swift +++ b/test/Serialization/clang-function-types.swift @@ -11,7 +11,7 @@ import def_clang_function_types // CHECK-LABEL: sil hidden @$s4main5test1yyF func test1() { // FIXME: this mangling will have to change - // CHECK: global_addr @$s24def_clang_function_types11has_fp_types13OpaquePointerVSgyXCSgvp : $*Optional<@convention(c) () -> Optional> + // CHECK: global_addr @$s24def_clang_function_types11has_fp_types13OpaquePointerVSgyXCSgvp : $*Optional<@convention(c, cType: "struct ForwardInTypedefForFP *(*)(void)") () -> Optional> let fp = has_fp_type _ = fp?() } @@ -24,7 +24,7 @@ func test2() { // CHECK-LABEL: } // end sil function '$s4main5test2yyF' // CHECK-LABEL: sil public_external [canonical] @$s24def_clang_function_types17use_fp_internallyyyF -// CHECK: enum $Optional<@convention(c) () -> Optional>, #Optional.none!enumelt +// CHECK: enum $Optional<@convention(c, cType: "struct ForwardInTypedefForFP2 *(*)(void)") () -> Optional>, #Optional.none!enumelt // CHECK: [[FN:%.*]] = function_ref @$s24def_clang_function_types9use_inout3argyxz_tlF : $@convention(thin) <τ_0_0> (@inout τ_0_0) -> () -// CHECK: apply [[FN]]<(@convention(c) () -> OpaquePointer?)?> +// CHECK: apply [[FN]]<(@convention(c, cType: "OpaqueTypedefForFP2 (*)(void)") () -> OpaquePointer?)?> // CHECK-LABEL: } // end sil function '$s24def_clang_function_types17use_fp_internallyyyF' diff --git a/tools/sil-func-extractor/SILFunctionExtractor.cpp b/tools/sil-func-extractor/SILFunctionExtractor.cpp index ee3711f4bb6f8..c5a62c2a45315 100644 --- a/tools/sil-func-extractor/SILFunctionExtractor.cpp +++ b/tools/sil-func-extractor/SILFunctionExtractor.cpp @@ -101,10 +101,9 @@ static llvm::cl::opt Triple("target", llvm::cl::desc("target triple")); static llvm::cl::opt -EnableSILSortOutput("emit-sorted-sil", llvm::cl::Hidden, - llvm::cl::init(false), - llvm::cl::desc("Sort Functions, VTables, Globals, " - "WitnessTables by name to ease diffing.")); + EmitSortedSIL("emit-sorted-sil", llvm::cl::Hidden, llvm::cl::init(false), + llvm::cl::desc("Sort Functions, VTables, Globals, " + "WitnessTables by name to ease diffing.")); static llvm::cl::opt DisableASTDump("sil-disable-ast-dump", llvm::cl::Hidden, @@ -245,6 +244,10 @@ int main(int argc, char **argv) { Invocation.getLangOptions().EnableAccessControl = false; Invocation.getLangOptions().EnableObjCAttrRequiresFoundation = false; + SILOptions &Opts = Invocation.getSILOptions(); + Opts.EmitVerboseSIL = EmitVerboseSIL; + Opts.EmitSortedSIL = EmitSortedSIL; + serialization::ExtendedValidationInfo extendedInfo; llvm::ErrorOr> FileBufOrErr = Invocation.setUpInputForSILTool(InputFilename, ModuleName, @@ -340,7 +343,7 @@ int main(int argc, char **argv) { auto SILOpts = SILOptions(); SILOpts.EmitVerboseSIL = EmitVerboseSIL; - SILOpts.EmitSortedSIL = EnableSILSortOutput; + SILOpts.EmitSortedSIL = EmitSortedSIL; if (OutputFile == "-") { SILMod->print(llvm::outs(), CI.getMainModule(), SILOpts, !DisableASTDump); diff --git a/tools/sil-opt/SILOpt.cpp b/tools/sil-opt/SILOpt.cpp index f4d2b4490cf3b..2c864cc7d4da5 100644 --- a/tools/sil-opt/SILOpt.cpp +++ b/tools/sil-opt/SILOpt.cpp @@ -199,10 +199,9 @@ static llvm::cl::opt ModuleCachePath("module-cache-path", llvm::cl::desc("Clang module cache path")); static llvm::cl::opt -EnableSILSortOutput("emit-sorted-sil", llvm::cl::Hidden, - llvm::cl::init(false), - llvm::cl::desc("Sort Functions, VTables, Globals, " - "WitnessTables by name to ease diffing.")); + EmitSortedSIL("emit-sorted-sil", llvm::cl::Hidden, llvm::cl::init(false), + llvm::cl::desc("Sort Functions, VTables, Globals, " + "WitnessTables by name to ease diffing.")); static llvm::cl::opt DisableASTDump("sil-disable-ast-dump", llvm::cl::Hidden, @@ -401,6 +400,8 @@ int main(int argc, char **argv) { break; } } + SILOpts.EmitVerboseSIL |= EmitVerboseSIL; + SILOpts.EmitSortedSIL |= EmitSortedSIL; SILOpts.EnableSpeculativeDevirtualization = EnableSpeculativeDevirtualization; SILOpts.IgnoreAlwaysInline = IgnoreAlwaysInline; @@ -530,7 +531,7 @@ int main(int argc, char **argv) { StringRef(OutputFilename) : "-"; auto SILOpts = SILOptions(); SILOpts.EmitVerboseSIL = EmitVerboseSIL; - SILOpts.EmitSortedSIL = EnableSILSortOutput; + SILOpts.EmitSortedSIL = EmitSortedSIL; if (OutputFile == "-") { SILMod->print(llvm::outs(), CI.getMainModule(), SILOpts, !DisableASTDump); } else {