diff --git a/include/swift/AST/ASTPrinter.h b/include/swift/AST/ASTPrinter.h index a9e9b89a99005..98d665b1fd728 100644 --- a/include/swift/AST/ASTPrinter.h +++ b/include/swift/AST/ASTPrinter.h @@ -14,6 +14,7 @@ #define SWIFT_AST_ASTPRINTER_H #include "swift/Basic/LLVM.h" +#include "swift/Basic/QuotedString.h" #include "swift/Basic/UUID.h" #include "swift/AST/Identifier.h" #include "llvm/ADT/StringRef.h" @@ -185,6 +186,8 @@ class ASTPrinter { return *this; } + ASTPrinter &operator<<(QuotedString s); + ASTPrinter &operator<<(unsigned long long N); ASTPrinter &operator<<(UUID UU); diff --git a/include/swift/AST/ClangModuleLoader.h b/include/swift/AST/ClangModuleLoader.h index a3d53be0584a7..0e3d109226fd0 100644 --- a/include/swift/AST/ClangModuleLoader.h +++ b/include/swift/AST/ClangModuleLoader.h @@ -21,6 +21,7 @@ class CompilerInstance; class Preprocessor; class Sema; class TargetInfo; +class Type; } // namespace clang namespace swift { @@ -100,6 +101,16 @@ class ClangModuleLoader : public ModuleLoader { lookupRelatedEntity(StringRef clangName, ClangTypeKind kind, StringRef relatedEntityKind, llvm::function_ref receiver) = 0; + + /// Try to parse the string as a Clang function type. + /// + /// Returns null if there was a parsing failure. + virtual const clang::Type *parseClangFunctionType(StringRef type, + SourceLoc loc) const = 0; + + /// Print the Clang type. + virtual void printClangType(const clang::Type *type, + llvm::raw_ostream &os) const = 0; }; } // namespace swift diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 990e072795f72..af4de2c836114 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -3924,6 +3924,13 @@ ERROR(unsupported_convention,none, "convention '%0' not supported", (StringRef)) ERROR(unreferenced_generic_parameter,none, "generic parameter '%0' is not used in function signature", (StringRef)) +ERROR(unexpected_ctype_for_non_c_convention,none, + "convention '%0' does not support the 'cType' argument label, did you " + "mean @convention(c, cType: \"%1\") or @convention(block, cType: \"%1\") " + "instead?", (StringRef, StringRef)) +ERROR(unable_to_parse_c_function_type,none, + "unable to parse '%0'; it should be a C function pointer type or a " + "block pointer type", (StringRef)) // Opaque types ERROR(unsupported_opaque_type,none, diff --git a/include/swift/AST/PrintOptions.h b/include/swift/AST/PrintOptions.h index 329136a29b222..6a142e02da510 100644 --- a/include/swift/AST/PrintOptions.h +++ b/include/swift/AST/PrintOptions.h @@ -306,8 +306,21 @@ struct PrintOptions { /// List of decls that should be printed even if they are implicit and \c SkipImplicit is set to true. std::vector TreatAsExplicitDeclList; + enum class FunctionRepresentationMode : uint8_t { + /// Print the entire convention, including an arguments. + /// For example, this will print a cType argument label if applicable. + Full, + /// Print only the name of the convention, skipping extra argument labels. + NameOnly, + /// Skip printing the @convention(..) altogether. + None + }; + /// Whether to print function @convention attribute on function types. - bool PrintFunctionRepresentationAttrs = true; + // FIXME: [clang-function-type-serialization] Once we start serializing Clang + // types, we should also start printing the full type in the swiftinterface. + FunctionRepresentationMode PrintFunctionRepresentationAttrs = + FunctionRepresentationMode::NameOnly; /// Whether to print storage representation attributes on types, e.g. /// '@sil_weak', '@sil_unmanaged'. @@ -502,7 +515,8 @@ struct PrintOptions { /// consistent and well-formed. /// /// \see swift::emitSwiftInterface - static PrintOptions printSwiftInterfaceFile(bool preferTypeRepr); + static PrintOptions printSwiftInterfaceFile(bool preferTypeRepr, + bool printFullConvention); /// Retrieve the set of options suitable for "Generated Interfaces", which /// are a prettified representation of the public API of a module, to be @@ -585,7 +599,8 @@ struct PrintOptions { PO.SkipUnderscoredKeywords = true; PO.EnumRawValues = EnumRawValueMode::Print; PO.PrintImplicitAttrs = false; - PO.PrintFunctionRepresentationAttrs = false; + PO.PrintFunctionRepresentationAttrs = + PrintOptions::FunctionRepresentationMode::None; PO.PrintDocumentationComments = false; PO.ExcludeAttrList.push_back(DAK_Available); PO.SkipPrivateStdlibDecls = true; diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index c03a523d0ae40..bf066910de272 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -59,6 +59,7 @@ class AssociatedTypeDecl; class ASTContext; enum BufferPointerTypeKind : unsigned; class ClassDecl; +class ClangModuleLoader; class DependentMemberType; class GenericTypeParamDecl; class GenericTypeParamType; @@ -2950,6 +2951,11 @@ class AnyFunctionType : public TypeBase { bool empty() const { return !ClangFunctionType; } Uncommon(const clang::Type *type) : ClangFunctionType(type) {} + + public: + /// Use the ClangModuleLoader to print the Clang type as a string. + void printClangFunctionType(ClangModuleLoader *cml, + llvm::raw_ostream &os); }; private: @@ -3894,6 +3900,11 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode, bool empty() const { return !ClangFunctionType; } Uncommon(const clang::FunctionType *type) : ClangFunctionType(type) {} + + public: + /// Analog of AnyFunctionType::ExtInfo::Uncommon::printClangFunctionType. + void printClangFunctionType(ClangModuleLoader *cml, + llvm::raw_ostream &os) const; }; Uncommon Other; @@ -3947,6 +3958,11 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode, return getSILFunctionLanguage(getRepresentation()); } + /// Return the underlying Uncommon value if it is not the default value. + Optional getUncommonInfo() const { + return Other.empty() ? Optional() : Other; + } + bool hasSelfParam() const { switch (getRepresentation()) { case Representation::Thick: diff --git a/include/swift/ClangImporter/ClangImporter.h b/include/swift/ClangImporter/ClangImporter.h index 9150852c0088a..ee9f94c406d85 100644 --- a/include/swift/ClangImporter/ClangImporter.h +++ b/include/swift/ClangImporter/ClangImporter.h @@ -40,6 +40,7 @@ namespace clang { class NamedDecl; class Sema; class TargetInfo; + class Type; class VisibleDeclConsumer; class DeclarationName; } @@ -416,6 +417,11 @@ class ClangImporter final : public ClangModuleLoader { /// with -import-objc-header option. getPCHFilename(const ClangImporterOptions &ImporterOptions, StringRef SwiftPCHHash, bool &isExplicit); + + const clang::Type *parseClangFunctionType(StringRef type, + SourceLoc loc) const override; + void printClangType(const clang::Type *type, + llvm::raw_ostream &os) const override; }; ImportDecl *createImportDecl(ASTContext &Ctx, DeclContext *DC, ClangNode ClangN, diff --git a/include/swift/Frontend/ModuleInterfaceSupport.h b/include/swift/Frontend/ModuleInterfaceSupport.h index 7a3e54ee8bc64..4289150c14554 100644 --- a/include/swift/Frontend/ModuleInterfaceSupport.h +++ b/include/swift/Frontend/ModuleInterfaceSupport.h @@ -31,6 +31,10 @@ struct ModuleInterfaceOptions { /// interface, or should we fully-qualify them? bool PreserveTypesAsWritten = false; + /// Should we emit the cType when printing @convention(c) or no? + /// FIXME: [clang-function-type-serialization] This check should go away. + bool PrintFullConvention = false; + /// Copy of all the command-line flags passed at .swiftinterface /// generation time, re-applied to CompilerInvocation when reading /// back .swiftinterface and reconstructing .swiftmodule. diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 711dbd7dcf0a4..a19bd5f383b96 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -602,6 +602,11 @@ def module_interface_preserve_types_as_written : HelpText<"When emitting a module interface, preserve types as they were " "written in the source">; +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">; + def prebuilt_module_cache_path : Separate<["-"], "prebuilt-module-cache-path">, HelpText<"Directory of prebuilt modules for loading module interfaces">; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index ec5c403dc5775..aa419a463a9ee 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -3156,6 +3156,11 @@ ArrayRef GenericFunctionType::getRequirements() const { return Signature->getRequirements(); } +void SILFunctionType::ExtInfo::Uncommon::printClangFunctionType( + ClangModuleLoader *cml, llvm::raw_ostream &os) const { + cml->printClangType(ClangFunctionType, os); +} + void SILFunctionType::Profile( llvm::FoldingSetNodeID &id, GenericSignature genericParams, diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index e4e038947fc01..63e138ee686f6 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -19,6 +19,7 @@ #include "swift/AST/ASTMangler.h" #include "swift/AST/ASTVisitor.h" #include "swift/AST/Attr.h" +#include "swift/AST/ClangModuleLoader.h" #include "swift/AST/Comment.h" #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" @@ -98,7 +99,8 @@ static bool contributesToParentTypeStorage(const AbstractStorageDecl *ASD) { return !ND->isResilient() && ASD->hasStorage() && !ASD->isStatic(); } -PrintOptions PrintOptions::printSwiftInterfaceFile(bool preferTypeRepr) { +PrintOptions PrintOptions::printSwiftInterfaceFile(bool preferTypeRepr, + bool printFullConvention) { PrintOptions result; result.PrintLongAttrsOnSeparateLines = true; result.TypeDefinitions = true; @@ -115,6 +117,9 @@ PrintOptions PrintOptions::printSwiftInterfaceFile(bool preferTypeRepr) { result.OpaqueReturnTypePrinting = OpaqueReturnTypePrintingMode::StableReference; result.PreferTypeRepr = preferTypeRepr; + if (printFullConvention) + result.PrintFunctionRepresentationAttrs = + PrintOptions::FunctionRepresentationMode::Full; // We should print __consuming, __owned, etc for the module interface file. result.SkipUnderscoredKeywords = false; @@ -321,6 +326,14 @@ void ASTPrinter::callPrintDeclPre(const Decl *D, printDeclPre(D, Bracket); } +ASTPrinter &ASTPrinter::operator<<(QuotedString s) { + llvm::SmallString<32> Str; + llvm::raw_svector_ostream OS(Str); + OS << s; + printTextImpl(OS.str()); + return *this; +} + ASTPrinter &ASTPrinter::operator<<(unsigned long long N) { llvm::SmallString<32> Str; llvm::raw_svector_ostream OS(Str); @@ -3462,6 +3475,15 @@ void Pattern::print(llvm::raw_ostream &OS, const PrintOptions &Options) const { // Type Printing //===----------------------------------------------------------------------===// +template +void printCType(ASTContext &Ctx, ASTPrinter &Printer, ExtInfo &info) { + auto *cml = Ctx.getClangModuleLoader(); + SmallString<64> buf; + llvm::raw_svector_ostream os(buf); + info.getUncommonInfo().getValue().printClangFunctionType(cml, os); + Printer << ", cType: " << QuotedString(os.str()); +} + namespace { class TypePrinter : public TypeVisitor { using super = TypeVisitor; @@ -3824,7 +3846,7 @@ class TypePrinter : public TypeVisitor { visit(staticSelfT); } - void printFunctionExtInfo(AnyFunctionType::ExtInfo info) { + void printFunctionExtInfo(ASTContext &Ctx, AnyFunctionType::ExtInfo info) { if (Options.SkipAttributes) return; @@ -3837,9 +3859,18 @@ class TypePrinter : public TypeVisitor { } } - if (Options.PrintFunctionRepresentationAttrs && - !Options.excludeAttrKind(TAK_convention) && - info.getSILRepresentation() != SILFunctionType::Representation::Thick) { + SmallString<64> buf; + switch (Options.PrintFunctionRepresentationAttrs) { + case PrintOptions::FunctionRepresentationMode::None: + return; + case PrintOptions::FunctionRepresentationMode::Full: + case PrintOptions::FunctionRepresentationMode::NameOnly: + if (Options.excludeAttrKind(TAK_convention) || + info.getSILRepresentation() == SILFunctionType::Representation::Thick) + return; + + bool printNameOnly = Options.PrintFunctionRepresentationAttrs == + PrintOptions::FunctionRepresentationMode::NameOnly; Printer.callPrintStructurePre(PrintStructureKind::BuiltinAttribute); Printer.printAttrName("@convention"); Printer << "("; @@ -3855,6 +3886,11 @@ class TypePrinter : public TypeVisitor { break; case SILFunctionType::Representation::CFunctionPointer: Printer << "c"; + // FIXME: [clang-function-type-serialization] Once we start serializing + // Clang function types, we should be able to remove the second check. + if (printNameOnly || !info.getUncommonInfo().hasValue()) + break; + printCType(Ctx, Printer, info); break; case SILFunctionType::Representation::Method: Printer << "method"; @@ -3875,7 +3911,8 @@ class TypePrinter : public TypeVisitor { } } - void printFunctionExtInfo(SILFunctionType::ExtInfo info, + void printFunctionExtInfo(ASTContext &Ctx, + SILFunctionType::ExtInfo info, ProtocolConformanceRef witnessMethodConformance) { if (Options.SkipAttributes) return; @@ -3889,9 +3926,19 @@ class TypePrinter : public TypeVisitor { } } - if (Options.PrintFunctionRepresentationAttrs && - !Options.excludeAttrKind(TAK_convention) && - info.getRepresentation() != SILFunctionType::Representation::Thick) { + + SmallString<64> buf; + switch (Options.PrintFunctionRepresentationAttrs) { + case PrintOptions::FunctionRepresentationMode::None: + break; + case PrintOptions::FunctionRepresentationMode::NameOnly: + case PrintOptions::FunctionRepresentationMode::Full: + if (Options.excludeAttrKind(TAK_convention) || + info.getRepresentation() == SILFunctionType::Representation::Thick) + break; + + bool printNameOnly = Options.PrintFunctionRepresentationAttrs == + PrintOptions::FunctionRepresentationMode::NameOnly; Printer.callPrintStructurePre(PrintStructureKind::BuiltinAttribute); Printer.printAttrName("@convention"); Printer << "("; @@ -3906,6 +3953,11 @@ class TypePrinter : public TypeVisitor { break; case SILFunctionType::Representation::CFunctionPointer: Printer << "c"; + // FIXME: [clang-function-type-serialization] Once we start serializing + // Clang function types, we should be able to remove the second check. + if (printNameOnly || !info.getUncommonInfo().hasValue()) + break; + printCType(Ctx, Printer, info); break; case SILFunctionType::Representation::Method: Printer << "method"; @@ -3975,7 +4027,7 @@ class TypePrinter : public TypeVisitor { Printer.printStructurePost(PrintStructureKind::FunctionType); }; - printFunctionExtInfo(T->getExtInfo()); + printFunctionExtInfo(T->getASTContext(), T->getExtInfo()); // If we're stripping argument labels from types, do it when printing. visitAnyFunctionTypeParams(T->getParams(), /*printLabels*/false); @@ -4012,7 +4064,7 @@ class TypePrinter : public TypeVisitor { Printer.printStructurePost(PrintStructureKind::FunctionType); }; - printFunctionExtInfo(T->getExtInfo()); + printFunctionExtInfo(T->getASTContext(), T->getExtInfo()); printGenericSignature(T->getGenericSignature(), PrintAST::PrintParams | PrintAST::PrintRequirements); @@ -4065,7 +4117,7 @@ class TypePrinter : public TypeVisitor { void visitSILFunctionType(SILFunctionType *T) { printSILCoroutineKind(T->getCoroutineKind()); - printFunctionExtInfo(T->getExtInfo(), + printFunctionExtInfo(T->getASTContext(), T->getExtInfo(), T->getWitnessMethodConformanceOrInvalid()); printCalleeConvention(T->getCalleeConvention()); diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index d63b809756ac4..31f898b14addc 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -17,6 +17,7 @@ #include "swift/AST/Types.h" #include "ForeignRepresentationInfo.h" #include "swift/AST/ASTContext.h" +#include "swift/AST/ClangModuleLoader.h" #include "swift/AST/ExistentialLayout.h" #include "swift/AST/ReferenceCounting.h" #include "swift/AST/TypeCheckRequests.h" @@ -3239,6 +3240,11 @@ Type ProtocolCompositionType::get(const ASTContext &C, return build(C, CanTypes, HasExplicitAnyObject); } +void AnyFunctionType::ExtInfo::Uncommon::printClangFunctionType( + ClangModuleLoader *cml, llvm::raw_ostream &os) { + cml->printClangType(ClangFunctionType, os); +} + void AnyFunctionType::ExtInfo::assertIsFunctionType(const clang::Type *type) { #ifndef NDEBUG diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index e74b691817ed7..c7120ea0eb835 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -3275,6 +3275,29 @@ void ClangImporter::verifyAllModules() { #endif } +const clang::Type * +ClangImporter::parseClangFunctionType(StringRef typeStr, + SourceLoc loc) const { + auto &sema = Impl.getClangSema(); + StringRef filename = Impl.SwiftContext.SourceMgr.getDisplayNameForLoc(loc); + // TODO: Obtain a clang::SourceLocation from the swift::SourceLoc we have + auto parsedType = sema.ParseTypeFromStringCallback(typeStr, filename, {}); + if (!parsedType.isUsable()) + return nullptr; + clang::QualType resultType = clang::Sema::GetTypeFromParser(parsedType.get()); + auto *typePtr = resultType.getTypePtrOrNull(); + if (typePtr && (typePtr->isFunctionPointerType() + || typePtr->isBlockPointerType())) + return typePtr; + return nullptr; +} + +void ClangImporter::printClangType(const clang::Type *type, + llvm::raw_ostream &os) const { + auto policy = clang::PrintingPolicy(getClangASTContext().getLangOpts()); + clang::QualType(type, 0).print(os, policy); +} + //===----------------------------------------------------------------------===// // ClangModule Implementation //===----------------------------------------------------------------------===// diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 355aeff500586..2eeee7f96f54d 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -227,6 +227,8 @@ static void ParseModuleInterfaceArgs(ModuleInterfaceOptions &Opts, Opts.PreserveTypesAsWritten |= Args.hasArg(OPT_module_interface_preserve_types_as_written); + Opts.PrintFullConvention |= + Args.hasArg(OPT_experimental_print_full_convention); } /// Save a copy of any flags marked as ModuleInterfaceOption, if running diff --git a/lib/Frontend/ModuleInterfaceSupport.cpp b/lib/Frontend/ModuleInterfaceSupport.cpp index 7fa40c3a94b5f..a17f33f3bfe87 100644 --- a/lib/Frontend/ModuleInterfaceSupport.cpp +++ b/lib/Frontend/ModuleInterfaceSupport.cpp @@ -440,7 +440,7 @@ bool swift::emitSwiftInterface(raw_ostream &out, printImports(out, M); const PrintOptions printOptions = PrintOptions::printSwiftInterfaceFile( - Opts.PreserveTypesAsWritten); + Opts.PreserveTypesAsWritten, Opts.PrintFullConvention); InheritedProtocolCollector::PerTypeMap inheritedProtocolMap; SmallVector topLevelDecls; diff --git a/lib/IDE/CodeCompletionResultBuilder.h b/lib/IDE/CodeCompletionResultBuilder.h index a56e8eee1dada..cc4793d9eb1ba 100644 --- a/lib/IDE/CodeCompletionResultBuilder.h +++ b/lib/IDE/CodeCompletionResultBuilder.h @@ -400,7 +400,8 @@ class CodeCompletionResultBuilder { if (auto AFT = Ty->getAs()) { // If this is a closure type, add ChunkKind::CallParameterClosureType. PrintOptions PO; - PO.PrintFunctionRepresentationAttrs = false; + PO.PrintFunctionRepresentationAttrs = + PrintOptions::FunctionRepresentationMode::None; PO.SkipAttributes = true; PO.OpaqueReturnTypePrinting = PrintOptions::OpaqueReturnTypePrintingMode::WithoutOpaqueKeyword; diff --git a/lib/IDE/IDETypeChecking.cpp b/lib/IDE/IDETypeChecking.cpp index 0b719b59c85e8..6d4050743df8f 100644 --- a/lib/IDE/IDETypeChecking.cpp +++ b/lib/IDE/IDETypeChecking.cpp @@ -85,7 +85,8 @@ PrintOptions PrintOptions::printDocInterface() { PrintOptions::ArgAndParamPrintingMode::BothAlways; result.PrintDocumentationComments = false; result.PrintRegularClangComments = false; - result.PrintFunctionRepresentationAttrs = false; + result.PrintFunctionRepresentationAttrs = + PrintOptions::FunctionRepresentationMode::None; return result; } diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 7f3563f4f6b0a..a53d8c2724498 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -1799,6 +1799,8 @@ namespace { AnyFunctionType::Representation representation = AnyFunctionType::Representation::Swift, bool noescape = false, + const clang::Type *parsedClangFunctionType + = nullptr, DifferentiabilityKind diffKind = DifferentiabilityKind::NonDifferentiable); bool @@ -2166,7 +2168,31 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, // Function attributes require a syntactic function type. auto *fnRepr = dyn_cast(repr); + auto tryParseClangType = [this](TypeAttributes::Convention &conv, + bool hasConventionCOrBlock) + -> const clang::Type * { + if (conv.ClangType.empty()) + return nullptr; + if (!hasConventionCOrBlock) { + diagnose(conv.ClangTypeLoc, + diag::unexpected_ctype_for_non_c_convention, + conv.Name, conv.ClangType); + return nullptr; + } + + StringRef filename = + Context.SourceMgr.getDisplayNameForLoc(conv.ClangTypeLoc); + const clang::Type *type = Context.getClangModuleLoader() + ->parseClangFunctionType(conv.ClangType, + conv.ClangTypeLoc); + if (!type) + diagnose(conv.ClangTypeLoc, diag::unable_to_parse_c_function_type, + conv.ClangType); + return type; + }; + if (fnRepr && hasFunctionAttr) { + const clang::Type *parsedClangFunctionType = nullptr; if (options & TypeResolutionFlags::SILType) { SILFunctionType::Representation rep; TypeRepr *witnessMethodProtocol = nullptr; @@ -2214,6 +2240,11 @@ 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); } if (rep == SILFunctionType::Representation::WitnessMethod) { @@ -2264,6 +2295,11 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, rep = FunctionType::Representation::Swift; } else { rep = *parsedRep; + + bool isCOrBlock = rep == FunctionTypeRepresentation::CFunctionPointer + || rep == FunctionTypeRepresentation::Block; + parsedClangFunctionType = + tryParseClangType(attrs.ConventionArguments.getValue(), isCOrBlock); } } @@ -2280,6 +2316,7 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, } ty = resolveASTFunctionType(fnRepr, options, rep, /*noescape=*/false, + parsedClangFunctionType, diffKind); if (!ty || ty->hasError()) return ty; @@ -2593,6 +2630,7 @@ Type TypeResolver::resolveOpaqueReturnType(TypeRepr *repr, Type TypeResolver::resolveASTFunctionType( FunctionTypeRepr *repr, TypeResolutionOptions parentOptions, AnyFunctionType::Representation representation, bool noescape, + const clang::Type *parsedClangFunctionType, DifferentiabilityKind diffKind) { TypeResolutionOptions options = None; @@ -2631,8 +2669,9 @@ Type TypeResolver::resolveASTFunctionType( noescape, repr->throws(), diffKind, /*clangFunctionType*/nullptr); - const clang::Type *clangFnType = nullptr; - if (representation == AnyFunctionType::Representation::CFunctionPointer) + const clang::Type *clangFnType = parsedClangFunctionType; + if (representation == AnyFunctionType::Representation::CFunctionPointer + && !clangFnType) clangFnType = Context.getClangFunctionType( params, outputTy, incompleteExtInfo, AnyFunctionType::Representation::CFunctionPointer); diff --git a/test/ClangImporter/clang-function-types.swift b/test/ClangImporter/clang-function-types.swift new file mode 100644 index 0000000000000..88b50655eb237 --- /dev/null +++ b/test/ClangImporter/clang-function-types.swift @@ -0,0 +1,12 @@ +// RUN: %target-swift-frontend -typecheck -swift-version 5 -emit-module-interface-path - -sdk %clang-importer-sdk -enable-library-evolution %s -experimental-print-full-convention | tee ~/tmp.si | %FileCheck %s + +import ctypes + +// CHECK: f1: (@convention(c, cType: "int (*)(int)") (Swift.Int32) -> Swift.Int32)? +public let f1 = getFunctionPointer_() + +// CHECK: f2: (@convention(c, cType: "int (*(*)(int (*)(int)))(int)") ((@convention(c, cType: "int (*)(int)") (Swift.Int32) -> Swift.Int32)?) -> (@convention(c, cType: "int (*)(int)") (Swift.Int32) -> Swift.Int32)?)? +public let f2 = getHigherOrderFunctionPointer() + +// CHECK: f3: () -> (@convention(c, cType: "Dummy *(*)(Dummy *)") (Swift.UnsafeMutablePointer?) -> Swift.UnsafeMutablePointer?)? +public let f3 = getFunctionPointer3 diff --git a/test/Inputs/clang-importer-sdk/usr/include/ctypes.h b/test/Inputs/clang-importer-sdk/usr/include/ctypes.h index c055b48ebff88..4d4a7cf018575 100644 --- a/test/Inputs/clang-importer-sdk/usr/include/ctypes.h +++ b/test/Inputs/clang-importer-sdk/usr/include/ctypes.h @@ -205,6 +205,8 @@ typedef int (*fptr)(int); fptr getFunctionPointer(void); void useFunctionPointer(fptr); +int (*getFunctionPointer_(void))(int); + struct FunctionPointerWrapper { fptr a; fptr b; @@ -214,6 +216,14 @@ typedef void (*fptr2)(int, long, void *); fptr2 getFunctionPointer2(void); void useFunctionPointer2(fptr2); +int (*(*getHigherOrderFunctionPointer(void))(int (*)(int)))(int); + +typedef struct Dummy { + int x; +} Dummy; + +Dummy * (*getFunctionPointer3(void))(Dummy *); + //===--- // Unions //===--- diff --git a/test/ModuleInterface/full-convention.swift b/test/ModuleInterface/full-convention.swift new file mode 100644 index 0000000000000..e65c2fe427ca6 --- /dev/null +++ b/test/ModuleInterface/full-convention.swift @@ -0,0 +1,32 @@ +// RUN: %target-swift-frontend -typecheck -swift-version 5 -emit-module-interface-path - -enable-library-evolution %s -experimental-print-full-convention | %FileCheck %s + +public func f( + // CHECK: g: @convention(c, cType: "void (*)(void)") + g: @convention(c) () -> (), + + // CHECK: h0: @convention(c, cType: "int (*)(long long)") + h0: @convention(c) (Int64) -> Int32, + // CHECK: h1: @convention(c, cType: "int (*)(long long)") + h1: @convention(c, cType: "int (*)(long long)") (Int64) -> Int32, + + // CHECK: i0: @convention(c, cType: "int *(*)(long long, int)") + i0: @convention(c) (Int64, Int32) -> Optional>, + // CHECK: i1: @convention(c, cType: "int *(*)(long long, int)") + i1: @convention(c, cType: "int *(*)(long long, int)") (Int64, Int32) -> Optional>, + + // CHECK: p0: @convention(c, cType: "void (*)(void (*)(long))") + // CHECK: @convention(c, cType: "void (*)(long)") + p0: @convention(c) (@convention(c) (Int) -> Void) -> Void, + + // CHECK: p1: @convention(c, cType: "void (*)(void (*)(long))") + // CHECK: @convention(c, cType: "void (*)(long)") + p1: @convention(c, cType: "void (*)(void (*)(long))") (@convention(c) (Int) -> Void) -> Void, + + // CHECK: p2: @convention(c, cType: "void (*)(void (*)(long))") + // CHECK: @convention(c, cType: "void (*)(long)") + p2: @convention(c) (@convention(c, cType: "void (*)(long)") (Int) -> Void) -> Void, + + // CHECK: p3: @convention(c, cType: "void (*)(void (*)(long))") + // CHECK: @convention(c, cType: "void (*)(long)") + p3: @convention(c, cType: "void (*)(void (*)(long))") (@convention(c, cType: "void (*)(long)") (Int) -> Void) -> Void +) {} diff --git a/test/Parse/c_function_pointers.swift b/test/Parse/c_function_pointers.swift index 3d51e63098b5f..188634808dfac 100644 --- a/test/Parse/c_function_pointers.swift +++ b/test/Parse/c_function_pointers.swift @@ -50,8 +50,8 @@ let f: @convention(c) (Int) -> Int = genericFunc // expected-error{{cannot be fo func ct1() -> () { print("") } -let ct1ref0 : @convention(c, cType: "void *(void)") () -> () = ct1 -let ct1ref1 : @convention(c, cType: "void *(void)") = ct1 // expected-error{{expected type}} +let ct1ref0 : @convention(c, cType: "void (*)(void)") () -> () = ct1 +let ct1ref1 : @convention(c, cType: "void (*)(void)") = ct1 // expected-error{{expected type}} let ct1ref2 : @convention(c, ) () -> () = ct1 // expected-error{{expected 'cType' label in 'convention' attribute}} let ct1ref3 : @convention(c, cType) () -> () = ct1 // expected-error{{expected ':' after 'cType' for 'convention' attribute}} let ct1ref4 : @convention(c, cType: ) () -> () = ct1 // expected-error{{expected string literal containing clang type for 'cType' in 'convention' attribute}} diff --git a/test/attr/attr_convention.swift b/test/attr/attr_convention.swift index 7ee849bdb3079..83048435363fc 100644 --- a/test/attr/attr_convention.swift +++ b/test/attr/attr_convention.swift @@ -2,8 +2,12 @@ let f1: (Int) -> Int = { $0 } let f2: @convention(swift) (Int) -> Int = { $0 } +let f2a: @convention(swift, cType: "int *(int)") (Int32) -> Int32 = { $0 } // expected-error{{convention 'swift' does not support the 'cType' argument label, did you mean @convention(c, cType: "int *(int)") or @convention(block, cType: "int *(int)") instead?}} let f3: @convention(block) (Int) -> Int = { $0 } let f4: @convention(c) (Int) -> Int = { $0 } +let f4a: @convention(c, cType: "int (int)") (Int32) -> Int32 = { $0 } // expected-error{{unable to parse 'int (int)'; it should be a C function pointer type or a block pointer type}} +let f4b: @convention(c, cType: "void *") (Int32) -> Int32 = { $0 } // expected-error{{unable to parse 'void *'; it should be a C function pointer type or a block pointer type}} +let f4c: @convention(c, cType: "int (*)(int)") (Int32) -> Int32 = { $0 } let f5: @convention(INTERCAL) (Int) -> Int = { $0 } // expected-error{{convention 'INTERCAL' not supported}}