diff --git a/docs/ABI/Mangling.rst b/docs/ABI/Mangling.rst index bc0b78d5c1edf..094745b7df02a 100644 --- a/docs/ABI/Mangling.rst +++ b/docs/ABI/Mangling.rst @@ -523,8 +523,10 @@ Types FUNCTION-KIND ::= 'U' // uncurried function type (currently not used) FUNCTION-KIND ::= 'K' // @auto_closure function type (noescape) FUNCTION-KIND ::= 'B' // objc block function type - FUNCTION-KIND ::= 'L' // objc block function type (escaping) (DWARF only; otherwise use 'B') + FUNCTION-KIND ::= 'zB' C-TYPE // objc block type with non-canonical C type + FUNCTION-KIND ::= 'L' // objc block function type with canonical C type (escaping) (DWARF only; otherwise use 'B' or 'zB' C-TYPE) FUNCTION-KIND ::= 'C' // C function pointer type + FUNCTION-KIND ::= 'zC' C-TYPE // C function pointer type with with non-canonical C type FUNCTION-KIND ::= 'A' // @auto_closure function type (escaping) FUNCTION-KIND ::= 'E' // function type (noescape) FUNCTION-KIND ::= 'F' // @differentiable function type @@ -532,6 +534,9 @@ Types FUNCTION-KIND ::= 'H' // @differentiable(linear) function type FUNCTION-KIND ::= 'I' // @differentiable(linear) function type (escaping) + C-TYPE is mangled according to the Itanium ABI, and prefixed with the length. + Non-ASCII identifiers are preserved as-is; we do not use Punycode. + function-signature ::= params-type params-type async? throws? // results and parameters params-type ::= type 'z'? 'h'? // tuple in case of multiple parameters or a single parameter with a single tuple type @@ -618,7 +623,9 @@ mangled in to disambiguate. CALLEE-CONVENTION ::= 't' // thin FUNC-REPRESENTATION ::= 'B' // C block invocation function + FUNC-REPRESENTATION ::= 'zB' C-TYPE // C block invocation function with non-canonical C type FUNC-REPRESENTATION ::= 'C' // C global function + FUNC-REPRESENTATION ::= 'zC' C-TYPE // C global function with non-canonical C type FUNC-REPRESENTATION ::= 'M' // Swift method FUNC-REPRESENTATION ::= 'J' // ObjC method FUNC-REPRESENTATION ::= 'K' // closure diff --git a/include/swift/AST/ASTMangler.h b/include/swift/AST/ASTMangler.h index b244e766ffc52..af7294875332e 100644 --- a/include/swift/AST/ASTMangler.h +++ b/include/swift/AST/ASTMangler.h @@ -318,6 +318,9 @@ class ASTMangler : public Mangler { const ValueDecl *forDecl = nullptr); void appendFunctionType(AnyFunctionType *fn, bool isAutoClosure = false, const ValueDecl *forDecl = nullptr); + void appendClangType(AnyFunctionType *fn); + template + void appendClangType(FnType *fn, llvm::raw_svector_ostream &os); void appendFunctionSignature(AnyFunctionType *fn, const ValueDecl *forDecl = nullptr); diff --git a/include/swift/AST/ExtInfo.h b/include/swift/AST/ExtInfo.h index ffea1db284b01..0620c14285a0c 100644 --- a/include/swift/AST/ExtInfo.h +++ b/include/swift/AST/ExtInfo.h @@ -70,6 +70,7 @@ class ClangTypeInfo { constexpr ClangTypeInfo(const clang::Type *type) : type(type) {} friend bool operator==(ClangTypeInfo lhs, ClangTypeInfo rhs); + friend bool operator!=(ClangTypeInfo lhs, ClangTypeInfo rhs); ClangTypeInfo getCanonical() const; public: diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 12c2643de24ea..1374b073ec8dc 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -2928,6 +2928,24 @@ class AnyFunctionType : public TypeBase { ClangTypeInfo getClangTypeInfo() const; ClangTypeInfo getCanonicalClangTypeInfo() const; + /// Returns true if the function type stores a Clang type that cannot + /// be derived from its Swift type. Returns false otherwise, including if + /// the function type is not @convention(c) or @convention(block). + /// + /// For example, if you have a function pointer from C getting imported with + /// the following type: + /// + /// @convention(c, cType: "void (*)(size_t (*)(size_t))") + /// (@convention(c, cType: "size_t (*)(size_t)") (Int) -> Int)) -> Void + /// + /// The parameter's function type will have hasNonDerivableClangType() = true, + /// but the outer function type will have hasNonDerivableClangType() = false, + /// because the parameter and result type are sufficient to correctly derive + /// the Clang type for the outer function type. In terms of mangling, + /// the parameter type's mangling will incorporate the Clang type but the + /// outer function type's mangling doesn't need to duplicate that information. + bool hasNonDerivableClangType(); + ExtInfo getExtInfo() const { return ExtInfo(Bits.AnyFunctionType.ExtInfoBits, getClangTypeInfo()); } @@ -4309,6 +4327,11 @@ class SILFunctionType final ClangTypeInfo getClangTypeInfo() const; + /// Returns true if the function type stores a Clang type that cannot + /// be derived from its Swift type. Returns false otherwise, including if + /// the function type is not @convention(c) or @convention(block). + bool hasNonDerivableClangType(); + bool hasSameExtInfoAs(const SILFunctionType *otherFn); /// Given that `this` is a `@differentiable` or `@differentiable(linear)` diff --git a/include/swift/Demangling/DemangleNodes.def b/include/swift/Demangling/DemangleNodes.def index 1c3c612f9e98a..b74eb68485802 100644 --- a/include/swift/Demangling/DemangleNodes.def +++ b/include/swift/Demangling/DemangleNodes.def @@ -44,6 +44,7 @@ NODE(BoundGenericTypeAlias) NODE(BoundGenericFunction) NODE(BuiltinTypeName) NODE(CFunctionPointer) +NODE(ClangType) CONTEXT_NODE(Class) NODE(ClassMetadataBaseOffset) NODE(ConcreteProtocolConformance) @@ -119,6 +120,8 @@ NODE(ImplEscaping) NODE(ImplConvention) NODE(ImplDifferentiability) NODE(ImplFunctionAttribute) +NODE(ImplFunctionConvention) +NODE(ImplFunctionConventionName) NODE(ImplFunctionType) NODE(ImplInvocationSubstitutions) CONTEXT_NODE(ImplicitClosure) diff --git a/include/swift/Demangling/Demangler.h b/include/swift/Demangling/Demangler.h index 3616ff426af86..afe1bce8f0a83 100644 --- a/include/swift/Demangling/Demangler.h +++ b/include/swift/Demangling/Demangler.h @@ -505,7 +505,7 @@ class Demangler : public NodeFactory { NodePointer demangleAnyGenericType(Node::Kind kind); NodePointer demangleExtensionContext(); NodePointer demanglePlainFunction(); - NodePointer popFunctionType(Node::Kind kind); + NodePointer popFunctionType(Node::Kind kind, bool hasClangType = false); NodePointer popFunctionParams(Node::Kind kind); NodePointer popFunctionParamLabels(NodePointer FuncType); NodePointer popTuple(); @@ -522,6 +522,7 @@ class Demangler : public NodeFactory { NodePointer demangleImplResultConvention(Node::Kind ConvKind); NodePointer demangleImplDifferentiability(); NodePointer demangleImplFunctionType(); + NodePointer demangleClangType(); NodePointer demangleMetatype(); NodePointer demanglePrivateContextDescriptor(); NodePointer createArchetypeRef(int depth, int i); diff --git a/include/swift/Demangling/TypeDecoder.h b/include/swift/Demangling/TypeDecoder.h index fb33edf878252..932c42d54ce35 100644 --- a/include/swift/Demangling/TypeDecoder.h +++ b/include/swift/Demangling/TypeDecoder.h @@ -631,6 +631,12 @@ class TypeDecoder { } unsigned firstChildIdx = 0; + if (Node->getChild(firstChildIdx)->getKind() == NodeKind::ClangType) { + // [TODO: synthesize-Clang-type-from-mangled-name] Use the first child + // to create a ClangTypeInfo. + ++firstChildIdx; + } + bool isThrow = false; if (Node->getChild(firstChildIdx)->getKind() == NodeKind::ThrowsAnnotation) { @@ -695,18 +701,28 @@ class TypeDecoder { } else if (child->getText() == "@callee_guaranteed") { calleeConvention = ImplParameterConvention::Direct_Guaranteed; } - } else if (child->getKind() == NodeKind::ImplFunctionAttribute) { - if (!child->hasText()) - return MAKE_NODE_TYPE_ERROR0(child, "expected text"); - - StringRef text = child->getText(); - if (text == "@convention(c)") { + } else if (child->getKind() == NodeKind::ImplFunctionConvention) { + if (child->getNumChildren() == 0) + return MAKE_NODE_TYPE_ERROR0(child, "expected grandchildren"); + if ((child->getFirstChild()->getKind() != + NodeKind::ImplFunctionConventionName) || + !child->getFirstChild()->hasText()) + return MAKE_NODE_TYPE_ERROR0(child, "expected convention name"); + + // [TODO: synthesize-Clang-type-from-mangled-name] If there are two + // grand-children, the second is going to be the mangled Clang type. + StringRef text = child->getFirstChild()->getText(); + if (text == "c") { flags = flags.withRepresentation(ImplFunctionRepresentation::CFunctionPointer); - } else if (text == "@convention(block)") { + } else if (text == "block") { flags = flags.withRepresentation(ImplFunctionRepresentation::Block); - } else if (text == "@async") { + } + } else if (child->getKind() == NodeKind::ImplFunctionAttribute) { + if (!child->hasText()) + return MAKE_NODE_TYPE_ERROR0(child, "expected text"); + if (child->getText() == "@async") { flags = flags.withAsync(); } } else if (child->getKind() == NodeKind::ImplDifferentiable) { diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index 48fb9337f6459..490385afbe1a1 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -30,24 +30,27 @@ #include "swift/AST/ProtocolConformanceRef.h" #include "swift/AST/SILLayout.h" #include "swift/Basic/Defer.h" +#include "swift/ClangImporter/ClangImporter.h" +#include "swift/Demangling/Demangler.h" #include "swift/Demangling/ManglingMacros.h" #include "swift/Demangling/ManglingUtils.h" -#include "swift/Demangling/Demangler.h" #include "swift/Strings.h" #include "clang/AST/ASTContext.h" -#include "clang/Basic/CharInfo.h" #include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Mangle.h" +#include "clang/Basic/CharInfo.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Support/CommandLine.h" + +#include using namespace swift; using namespace swift::Mangle; @@ -1653,15 +1656,35 @@ void ASTMangler::appendImplFunctionType(SILFunctionType *fn) { OpArgs.push_back('t'); } + bool mangleClangType = fn->getASTContext().LangOpts.UseClangFunctionTypes && + fn->hasNonDerivableClangType(); + + auto appendClangTypeToVec = [this, fn](auto &Vec) { + llvm::raw_svector_ostream OpArgsOS(Vec); + appendClangType(fn, OpArgsOS); + }; + switch (fn->getRepresentation()) { case SILFunctionTypeRepresentation::Thick: case SILFunctionTypeRepresentation::Thin: break; case SILFunctionTypeRepresentation::Block: + if (!mangleClangType) { + OpArgs.push_back('B'); + break; + } + OpArgs.push_back('z'); OpArgs.push_back('B'); + appendClangTypeToVec(OpArgs); break; case SILFunctionTypeRepresentation::CFunctionPointer: + if (!mangleClangType) { + OpArgs.push_back('C'); + break; + } + OpArgs.push_back('z'); OpArgs.push_back('C'); + appendClangTypeToVec(OpArgs); break; case SILFunctionTypeRepresentation::ObjCMethod: OpArgs.push_back('O'); @@ -2244,6 +2267,9 @@ void ASTMangler::appendFunctionType(AnyFunctionType *fn, bool isAutoClosure, appendFunctionSignature(fn, forDecl); + bool mangleClangType = fn->getASTContext().LangOpts.UseClangFunctionTypes && + fn->hasNonDerivableClangType(); + // Note that we do not currently use thin representations in the AST // for the types of function decls. This may need to change at some // point, in which case the uncurry logic can probably migrate to that @@ -2256,6 +2282,10 @@ void ASTMangler::appendFunctionType(AnyFunctionType *fn, bool isAutoClosure, // changes to better support thin functions. switch (fn->getRepresentation()) { case AnyFunctionType::Representation::Block: + if (mangleClangType) { + appendOperator("XzB"); + return appendClangType(fn); + } // We distinguish escaping and non-escaping blocks, but only in the DWARF // mangling, because the ABI is already set. if (!fn->isNoEscape() && DWARFMangling) @@ -2287,10 +2317,31 @@ void ASTMangler::appendFunctionType(AnyFunctionType *fn, bool isAutoClosure, return appendOperator("c"); case AnyFunctionType::Representation::CFunctionPointer: + if (mangleClangType) { + appendOperator("XzC"); + return appendClangType(fn); + } return appendOperator("XC"); } } +template +void ASTMangler::appendClangType(FnType *fn, llvm::raw_svector_ostream &out) { + auto clangType = fn->getClangTypeInfo().getType(); + SmallString<64> scratch; + llvm::raw_svector_ostream scratchOS(scratch); + clang::ASTContext &clangCtx = + fn->getASTContext().getClangModuleLoader()->getClangASTContext(); + std::unique_ptr mangler{ + clang::ItaniumMangleContext::create(clangCtx, clangCtx.getDiagnostics())}; + mangler->mangleTypeName(clang::QualType(clangType, 0), scratchOS); + out << scratchOS.str().size() << scratchOS.str(); +} + +void ASTMangler::appendClangType(AnyFunctionType *fn) { + appendClangType(fn, Buffer); +} + void ASTMangler::appendFunctionSignature(AnyFunctionType *fn, const ValueDecl *forDecl) { appendFunctionResultType(fn->getResult(), forDecl); diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index e07febf037f29..2425dc6eaf324 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -4037,7 +4037,9 @@ class TypePrinter : public TypeVisitor { visit(staticSelfT); } - void printFunctionExtInfo(ASTContext &Ctx, AnyFunctionType::ExtInfo info) { + void printFunctionExtInfo(AnyFunctionType *fnType) { + auto &ctx = fnType->getASTContext(); + auto info = fnType->getExtInfo(); if (Options.SkipAttributes) return; @@ -4074,13 +4076,13 @@ class TypePrinter : public TypeVisitor { break; case SILFunctionType::Representation::Block: Printer << "block"; - if (printClangType && !info.getClangTypeInfo().empty()) - printCType(Ctx, Printer, info); + if (printClangType && fnType->hasNonDerivableClangType()) + printCType(ctx, Printer, info); break; case SILFunctionType::Representation::CFunctionPointer: Printer << "c"; - if (printClangType && !info.getClangTypeInfo().empty()) - printCType(Ctx, Printer, info); + if (printClangType && fnType->hasNonDerivableClangType()) + printCType(ctx, Printer, info); break; case SILFunctionType::Representation::Method: Printer << "method"; @@ -4101,9 +4103,12 @@ class TypePrinter : public TypeVisitor { } } - void printFunctionExtInfo(ASTContext &Ctx, - SILFunctionType::ExtInfo info, - ProtocolConformanceRef witnessMethodConformance) { + void printFunctionExtInfo(SILFunctionType *fnType) { + auto &Ctx = fnType->getASTContext(); + auto info = fnType->getExtInfo(); + auto witnessMethodConformance = + fnType->getWitnessMethodConformanceOrInvalid(); + if (Options.SkipAttributes) return; @@ -4140,12 +4145,12 @@ class TypePrinter : public TypeVisitor { break; case SILFunctionType::Representation::Block: Printer << "block"; - if (printClangType) + if (printClangType && fnType->hasNonDerivableClangType()) printCType(Ctx, Printer, info); break; case SILFunctionType::Representation::CFunctionPointer: Printer << "c"; - if (printClangType) + if (printClangType && fnType->hasNonDerivableClangType()) printCType(Ctx, Printer, info); break; case SILFunctionType::Representation::Method: @@ -4220,7 +4225,7 @@ class TypePrinter : public TypeVisitor { Printer.printStructurePost(PrintStructureKind::FunctionType); }; - printFunctionExtInfo(T->getASTContext(), T->getExtInfo()); + printFunctionExtInfo(T); // If we're stripping argument labels from types, do it when printing. visitAnyFunctionTypeParams(T->getParams(), /*printLabels*/false); @@ -4260,7 +4265,7 @@ class TypePrinter : public TypeVisitor { Printer.printStructurePost(PrintStructureKind::FunctionType); }; - printFunctionExtInfo(T->getASTContext(), T->getExtInfo()); + printFunctionExtInfo(T); printGenericSignature(T->getGenericSignature(), PrintAST::PrintParams | PrintAST::PrintRequirements); @@ -4322,8 +4327,7 @@ class TypePrinter : public TypeVisitor { void visitSILFunctionType(SILFunctionType *T) { printSILCoroutineKind(T->getCoroutineKind()); - printFunctionExtInfo(T->getASTContext(), T->getExtInfo(), - T->getWitnessMethodConformanceOrInvalid()); + printFunctionExtInfo(T); printCalleeConvention(T->getCalleeConvention()); if (auto sig = T->getInvocationGenericSignature()) { diff --git a/lib/AST/ExtInfo.cpp b/lib/AST/ExtInfo.cpp index 1fb30adc6af16..f4cf5db268b1c 100644 --- a/lib/AST/ExtInfo.cpp +++ b/lib/AST/ExtInfo.cpp @@ -34,6 +34,10 @@ bool operator==(ClangTypeInfo lhs, ClangTypeInfo rhs) { return false; } +bool operator!=(ClangTypeInfo lhs, ClangTypeInfo rhs) { + return !(lhs == rhs); +} + ClangTypeInfo ClangTypeInfo::getCanonical() const { if (!type) return ClangTypeInfo(); diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 129efae29ed8c..71563ca68ec1e 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -3424,6 +3424,16 @@ ClangTypeInfo AnyFunctionType::getCanonicalClangTypeInfo() const { return getClangTypeInfo().getCanonical(); } +bool AnyFunctionType::hasNonDerivableClangType() { + auto clangTypeInfo = getClangTypeInfo(); + if (clangTypeInfo.empty()) + return false; + auto computedClangType = getASTContext().getClangFunctionType( + getParams(), getResult(), getRepresentation()); + assert(computedClangType && "Failed to compute Clang type."); + return clangTypeInfo != ClangTypeInfo(computedClangType); +} + bool AnyFunctionType::hasSameExtInfoAs(const AnyFunctionType *otherFn) { return getExtInfo().isEqualTo(otherFn->getExtInfo(), useClangTypes(this)); } @@ -3437,6 +3447,20 @@ ClangTypeInfo SILFunctionType::getClangTypeInfo() const { return *info; } +bool SILFunctionType::hasNonDerivableClangType() { + auto clangTypeInfo = getClangTypeInfo(); + if (clangTypeInfo.empty()) + return false; + auto results = getResults(); + auto computedClangType = + getASTContext().getCanonicalClangFunctionType( + getParameters(), + results.empty() ? None : Optional(results[0]), + getRepresentation()); + assert(computedClangType && "Failed to compute Clang type."); + return clangTypeInfo != ClangTypeInfo(computedClangType); +} + bool SILFunctionType::hasSameExtInfoAs(const SILFunctionType *otherFn) { return getExtInfo().isEqualTo(otherFn->getExtInfo(), useClangTypes(this)); } diff --git a/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp index d6a06b003f6da..83519d1152c8d 100644 --- a/lib/Demangling/Demangler.cpp +++ b/lib/Demangling/Demangler.cpp @@ -1228,8 +1228,13 @@ NodePointer Demangler::demanglePlainFunction() { return createWithChildren(Node::Kind::Function, Ctx, Name, Type); } -NodePointer Demangler::popFunctionType(Node::Kind kind) { +NodePointer Demangler::popFunctionType(Node::Kind kind, bool hasClangType) { NodePointer FuncType = createNode(kind); + NodePointer ClangType = nullptr; + if (hasClangType) { + ClangType = demangleClangType(); + } + addChild(FuncType, ClangType); addChild(FuncType, popNode(Node::Kind::ThrowsAnnotation)); addChild(FuncType, popNode(Node::Kind::AsyncAnnotation)); @@ -1748,6 +1753,16 @@ NodePointer Demangler::demangleImplDifferentiability() { return createNode(Node::Kind::ImplDifferentiability, attr); } +NodePointer Demangler::demangleClangType() { + int numChars = demangleNatural(); + if (numChars <= 0 || Pos + numChars > Text.size()) + return nullptr; + CharVector mangledClangType; + mangledClangType.append(StringRef(Text.data() + Pos, numChars), *this); + Pos = Pos + numChars; + return createNode(Node::Kind::ClangType, mangledClangType); +} + NodePointer Demangler::demangleImplFunctionType() { NodePointer type = createNode(Node::Kind::ImplFunctionType); @@ -1806,20 +1821,33 @@ NodePointer Demangler::demangleImplFunctionType() { } type->addChild(createNode(Node::Kind::ImplConvention, CAttr), *this); - const char *FAttr = nullptr; + const char *FConv = nullptr; + bool hasClangType = false; switch (nextChar()) { - case 'B': FAttr = "@convention(block)"; break; - case 'C': FAttr = "@convention(c)"; break; - case 'M': FAttr = "@convention(method)"; break; - case 'O': FAttr = "@convention(objc_method)"; break; - case 'K': FAttr = "@convention(closure)"; break; - case 'W': FAttr = "@convention(witness_method)"; break; - default: - pushBack(); - break; + case 'B': FConv = "block"; break; + case 'C': FConv = "c"; break; + case 'z': { + switch (nextChar()) { + case 'B': hasClangType = true; FConv = "block"; break; + case 'C': hasClangType = true; FConv = "c"; break; + default: pushBack(); pushBack(); break; + } + break; + } + case 'M': FConv = "method"; break; + case 'O': FConv = "objc_method"; break; + case 'K': FConv = "closure"; break; + case 'W': FConv = "witness_method"; break; + default: pushBack(); break; + } + if (FConv) { + auto FAttrNode = createNode(Node::Kind::ImplFunctionConvention); + FAttrNode->addChild( + createNode(Node::Kind::ImplFunctionConventionName, FConv), *this); + if (hasClangType) + FAttrNode->addChild(demangleClangType(), *this); + type->addChild(FAttrNode, *this); } - if (FAttr) - type->addChild(createNode(Node::Kind::ImplFunctionAttribute, FAttr), *this); const char *CoroAttr = nullptr; if (nextIf('A')) @@ -2863,6 +2891,15 @@ NodePointer Demangler::demangleSpecialType() { return popFunctionType(Node::Kind::ObjCBlock); case 'C': return popFunctionType(Node::Kind::CFunctionPointer); + case 'z': + switch (auto cchar = nextChar()) { + case 'B': + return popFunctionType(Node::Kind::ObjCBlock, true); + case 'C': + return popFunctionType(Node::Kind::CFunctionPointer, true); + default: + return nullptr; + } case 'F': return popFunctionType(Node::Kind::DifferentiableFunctionType); case 'G': diff --git a/lib/Demangling/NodePrinter.cpp b/lib/Demangling/NodePrinter.cpp index 5287239caffc5..03023b0a9c990 100644 --- a/lib/Demangling/NodePrinter.cpp +++ b/lib/Demangling/NodePrinter.cpp @@ -338,6 +338,7 @@ class NodePrinter { case Node::Kind::AutoClosureType: case Node::Kind::BaseConformanceDescriptor: case Node::Kind::BaseWitnessTableAccessor: + case Node::Kind::ClangType: case Node::Kind::ClassMetadataBaseOffset: case Node::Kind::CFunctionPointer: case Node::Kind::Constructor: @@ -403,6 +404,8 @@ class NodePrinter { case Node::Kind::ImplConvention: case Node::Kind::ImplDifferentiability: case Node::Kind::ImplFunctionAttribute: + case Node::Kind::ImplFunctionConvention: + case Node::Kind::ImplFunctionConventionName: case Node::Kind::ImplFunctionType: case Node::Kind::ImplInvocationSubstitutions: case Node::Kind::ImplPatternSubstitutions: @@ -750,11 +753,22 @@ class NodePrinter { } void printFunctionType(NodePointer LabelList, NodePointer node) { - if (node->getNumChildren() < 2 || node->getNumChildren() > 4) { + if (node->getNumChildren() < 2 || node->getNumChildren() > 5) { setInvalid(); return; } + auto printConventionWithMangledCType = [this, + node](const char *convention) { + Printer << "@convention(" << convention; + if (node->getFirstChild()->getKind() == Node::Kind::ClangType) { + Printer << ", mangledCType: \""; + print(node->getFirstChild()); + Printer << '"'; + } + Printer << ") "; + }; + switch (node->getKind()) { case Node::Kind::FunctionType: case Node::Kind::UncurriedFunctionType: @@ -766,11 +780,14 @@ class NodePrinter { case Node::Kind::ThinFunctionType: Printer << "@convention(thin) "; break; case Node::Kind::CFunctionPointer: - Printer << "@convention(c) "; break; - case Node::Kind::ObjCBlock: - Printer << "@convention(block) "; break; + printConventionWithMangledCType("c"); + break; case Node::Kind::EscapingObjCBlock: - Printer << "@escaping @convention(block) "; break; + Printer << "@escaping "; + LLVM_FALLTHROUGH; + case Node::Kind::ObjCBlock: + printConventionWithMangledCType("block"); + break; case Node::Kind::DifferentiableFunctionType: Printer << "@differentiable "; break; case Node::Kind::EscapingDifferentiableFunctionType: @@ -785,6 +802,10 @@ class NodePrinter { unsigned startIndex = 0; bool isAsync = false, isThrows = false; + if (node->getChild(startIndex)->getKind() == Node::Kind::ClangType) { + // handled earlier + ++startIndex; + } if (node->getChild(startIndex)->getKind() == Node::Kind::ThrowsAnnotation) { ++startIndex; isThrows = true; @@ -1301,6 +1322,9 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) { case Node::Kind::EscapingLinearFunctionType: printFunctionType(nullptr, Node); return nullptr; + case Node::Kind::ClangType: + Printer << Node->getText(); + return nullptr; case Node::Kind::ArgumentTuple: printFunctionParameters(nullptr, Node, Options.ShowFunctionArgumentTypes); return nullptr; @@ -2096,6 +2120,24 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) { case Node::Kind::ImplFunctionAttribute: Printer << Node->getText(); return nullptr; + case Node::Kind::ImplFunctionConvention: + Printer << "@convention("; + switch (Node->getNumChildren()) { + case 1: + Printer << Node->getChild(0)->getText(); + break; + case 2: + Printer << Node->getChild(0)->getText() << ", mangledCType: \""; + print(Node->getChild(1)); + Printer << '"'; + break; + default: + assert(false && "Unexpected numChildren for ImplFunctionConvention"); + } + Printer << ')'; + return nullptr; + case Node::Kind::ImplFunctionConventionName: + assert(false && "Already handled in ImplFunctionConvention"); case Node::Kind::ImplErrorResult: Printer << "@error "; printChildren(Node, " "); diff --git a/lib/Demangling/OldDemangler.cpp b/lib/Demangling/OldDemangler.cpp index 575750012f1c7..f7ed9400adf42 100644 --- a/lib/Demangling/OldDemangler.cpp +++ b/lib/Demangling/OldDemangler.cpp @@ -2135,15 +2135,15 @@ class OldDemangler { if (Mangled.nextIf('C')) { if (Mangled.nextIf('b')) - addImplFunctionAttribute(type, "@convention(block)"); + addImplFunctionConvention(type, "block"); else if (Mangled.nextIf('c')) - addImplFunctionAttribute(type, "@convention(c)"); + addImplFunctionConvention(type, "c"); else if (Mangled.nextIf('m')) - addImplFunctionAttribute(type, "@convention(method)"); + addImplFunctionConvention(type, "method"); else if (Mangled.nextIf('O')) - addImplFunctionAttribute(type, "@convention(objc_method)"); + addImplFunctionConvention(type, "objc_method"); else if (Mangled.nextIf('w')) - addImplFunctionAttribute(type, "@convention(witness_method)"); + addImplFunctionConvention(type, "witness_method"); else return nullptr; } @@ -2234,6 +2234,14 @@ class OldDemangler { parent->addChild(Factory.createNode(kind, attr), Factory); } + void addImplFunctionConvention(NodePointer parent, StringRef attr) { + auto attrNode = Factory.createNode(Node::Kind::ImplFunctionConvention); + attrNode->addChild( + Factory.createNode(Node::Kind::ImplFunctionConventionName, attr), + Factory); + parent->addChild(attrNode, Factory); + } + // impl-parameter ::= impl-convention type bool demangleImplParameters(NodePointer parent) { while (!Mangled.nextIf('_')) { diff --git a/lib/Demangling/OldRemangler.cpp b/lib/Demangling/OldRemangler.cpp index d402cc7bcbb0f..a9176efa0a57b 100644 --- a/lib/Demangling/OldRemangler.cpp +++ b/lib/Demangling/OldRemangler.cpp @@ -1241,17 +1241,7 @@ void Remangler::mangleImplFunctionType(Node *node) { void Remangler::mangleImplFunctionAttribute(Node *node) { StringRef text = node->getText(); - if (text == "@convention(block)") { - Buffer << "Cb"; - } else if (text == "@convention(c)") { - Buffer << "Cc"; - } else if (text == "@convention(method)") { - Buffer << "Cm"; - } else if (text == "@convention(objc_method)") { - Buffer << "CO"; - } else if (text == "@convention(witness_method)") { - Buffer << "Cw"; - } else if (text == "@yield_once") { + if (text == "@yield_once") { Buffer << "A"; } else if (text == "@yield_many") { Buffer << "G"; @@ -1262,6 +1252,29 @@ void Remangler::mangleImplFunctionAttribute(Node *node) { } } +void Remangler::mangleImplFunctionConvention(Node *node) { + mangle(node->getChild(0)); +} + +void Remangler::mangleImplFunctionConventionName(Node *node) { + StringRef text = node->getText(); + if (text == "block") { + Buffer << "Cb"; + } else if (text == "c") { + Buffer << "Cc"; + } else if (text == "method") { + Buffer << "Cm"; + } else if (text == "objc_method") { + Buffer << "CO"; + } else if (text == "witness_method") { + Buffer << "Cw"; + } else { + unreachable("bad impl-function-convention-name"); + } +} + +void Remangler::mangleClangType(Node *node) { unreachable("unsupported"); } + void Remangler::mangleImplParameter(Node *node) { assert(node->getNumChildren() == 2); mangleChildNodes(node); // impl convention, type diff --git a/lib/Demangling/Remangler.cpp b/lib/Demangling/Remangler.cpp index 0b0fdec171717..1692558a5e2cf 100644 --- a/lib/Demangling/Remangler.cpp +++ b/lib/Demangling/Remangler.cpp @@ -774,6 +774,15 @@ void Remangler::mangleBuiltinTypeName(Node *node) { } void Remangler::mangleCFunctionPointer(Node *node) { + if (node->getNumChildren() > 0 && + node->getFirstChild()->getKind() == Node::Kind::ClangType) { + for (size_t Idx = node->getNumChildren() - 1; Idx >= 1; --Idx) { + mangleChildNode(node, Idx); + } + Buffer << "XzC"; + mangleClangType(node->getFirstChild()); + return; + } mangleChildNodesReversed(node); // argument tuple, result type Buffer << "XC"; } @@ -1436,6 +1445,37 @@ void Remangler::mangleImplFunctionAttribute(Node *node) { unreachable("handled inline"); } +void Remangler::mangleImplFunctionConvention(Node *node) { + StringRef text = + (node->getNumChildren() > 0 && node->getFirstChild()->hasText()) + ? node->getFirstChild()->getText() + : ""; + char FuncAttr = llvm::StringSwitch(text) + .Case("block", 'B') + .Case("c", 'C') + .Case("method", 'M') + .Case("objc_method", 'O') + .Case("closure", 'K') + .Case("witness_method", 'W') + .Default(0); + assert(FuncAttr && "invalid impl function convention"); + if ((FuncAttr == 'B' || FuncAttr == 'C') && node->getNumChildren() > 1 && + node->getChild(1)->getKind() == Node::Kind::ClangType) { + Buffer << 'z' << FuncAttr; + mangleClangType(node->getChild(1)); + return; + } + Buffer << FuncAttr; +} + +void Remangler::mangleImplFunctionConventionName(Node *node) { + unreachable("handled inline"); +} + +void Remangler::mangleClangType(Node *node) { + Buffer << node->getText().size() << node->getText(); +} + void Remangler::mangleImplInvocationSubstitutions(Node *node) { unreachable("handled inline"); } @@ -1527,14 +1567,12 @@ void Remangler::mangleImplFunctionType(Node *node) { Buffer << ConvCh; break; } + case Node::Kind::ImplFunctionConvention: { + mangleImplFunctionConvention(Child); + break; + } case Node::Kind::ImplFunctionAttribute: { char FuncAttr = llvm::StringSwitch(Child->getText()) - .Case("@convention(block)", 'B') - .Case("@convention(c)", 'C') - .Case("@convention(method)", 'M') - .Case("@convention(objc_method)", 'O') - .Case("@convention(closure)", 'K') - .Case("@convention(witness_method)", 'W') .Case("@yield_once", 'A') .Case("@yield_many", 'G') .Case("@async", 'H') @@ -1783,6 +1821,15 @@ void Remangler::mangleObjCAttribute(Node *node) { } void Remangler::mangleObjCBlock(Node *node) { + if (node->getNumChildren() > 0 && + node->getFirstChild()->getKind() == Node::Kind::ClangType) { + for (size_t Idx = node->getNumChildren() - 1; Idx >= 1; --Idx) { + mangleChildNode(node, Idx); + } + Buffer << "XzB"; + mangleClangType(node->getFirstChild()); + return; + } mangleChildNodesReversed(node); Buffer << "XB"; } diff --git a/test/ClangImporter/clang-function-types.swift b/test/ClangImporter/clang-function-types.swift index 52d7dae1dd75a..0afd8221d5709 100644 --- a/test/ClangImporter/clang-function-types.swift +++ b/test/ClangImporter/clang-function-types.swift @@ -2,11 +2,11 @@ import ctypes -// CHECK: f1: (@convention(c, cType: "int (*)(int)") (Swift.Int32) -> Swift.Int32)? +// CHECK: f1: (@convention(c, cType: "size_t (*)(size_t)") (Swift.Int) -> Swift.Int)? 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)?)? +// CHECK: f2: (@convention(c) ((@convention(c, cType: "size_t (*)(size_t)") (Swift.Int) -> Swift.Int)?) -> (@convention(c, cType: "size_t (*)(size_t)") (Swift.Int) -> Swift.Int)?)? public let f2 = getHigherOrderFunctionPointer() -// CHECK: f3: () -> (@convention(c, cType: "Dummy *(*)(Dummy *)") (Swift.UnsafeMutablePointer?) -> Swift.UnsafeMutablePointer?)? +// CHECK: f3: () -> (@convention(c) (Swift.UnsafeMutablePointer?) -> Swift.UnsafeMutablePointer?)? public let f3 = getFunctionPointer3 diff --git a/test/ClangImporter/ctypes_parse.swift b/test/ClangImporter/ctypes_parse.swift index 9cf79bf690379..fd6aa6ea11776 100644 --- a/test/ClangImporter/ctypes_parse.swift +++ b/test/ClangImporter/ctypes_parse.swift @@ -205,7 +205,7 @@ func testFunctionPointers() { useFunctionPointer(wrapper.a) _ = wrapper.b as (@convention(c) (CInt) -> CInt) - var anotherFP: @convention(c) (CInt, CLong, UnsafeMutableRawPointer?) -> Void + var anotherFP: @convention(c) (Int, CLong, UnsafeMutableRawPointer?) -> Void = getFunctionPointer2() var sizedFP: (@convention(c) (CInt, CInt, UnsafeMutableRawPointer?) -> Void)? diff --git a/test/Demangle/Inputs/manglings-with-clang-types.txt b/test/Demangle/Inputs/manglings-with-clang-types.txt new file mode 100644 index 0000000000000..2dca7def1cc42 --- /dev/null +++ b/test/Demangle/Inputs/manglings-with-clang-types.txt @@ -0,0 +1,2 @@ +$s3tmp1fyySiyXzC9_ZTSPFmvEF ---> tmp.f(@convention(c, mangledCType: "_ZTSPFmvE") () -> Swift.Int) -> () +$s3tmp1hyyySbXzB24_ZTSU13block_pointerFvaEF ---> tmp.h(@convention(block, mangledCType: "_ZTSU13block_pointerFvaE") (Swift.Bool) -> ()) -> () diff --git a/test/Demangle/clang-function-types.swift b/test/Demangle/clang-function-types.swift new file mode 100644 index 0000000000000..df7a4993febcc --- /dev/null +++ b/test/Demangle/clang-function-types.swift @@ -0,0 +1,39 @@ +// NOTE: manglings.txt should be kept in sync with the manglings in this file. + +// Make sure we are testing the right manglings. +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) %s -emit-sil -o - -I %S/../Inputs/custom-modules -use-clang-function-types -module-name tmp -enable-objc-interop | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-os-%target-cpu + +// Check that demangling works. + +// %t.input: "A ---> B" ==> "A" +// RUN: sed -ne '/--->/s/ *--->.*$//p' < %S/Inputs/manglings-with-clang-types.txt > %t.input +// %t.check: "A ---> B" ==> "B" +// RUN: sed -ne '/--->/s/^.*---> *//p' < %S/Inputs/manglings-with-clang-types.txt > %t.check +// RUN: swift-demangle -classify < %t.input > %t.output +// RUN: diff %t.check %t.output + +// Other tests already check mangling for Windows, so we don't need to +// check that here again. + +// UNSUPPORTED: OS=windows-msvc + +import ctypes + +#if os(macOS) && arch(x86_64) +import ObjectiveC + +// BOOL == signed char on x86_64 macOS +public func h(_ k: @convention(block, cType: "void (^)(BOOL)") (Bool) -> ()) { + let _ = k(true) +} +h(A.setGlobal) // OK: check that importing preserves Clang types + +// CHECK-macosx-x86_64: sil @$s3tmp1hyyySbXzB24_ZTSU13block_pointerFvaEF +#endif + +public func f(_ k: @convention(c, cType: "size_t (*)(void)") () -> Int) { + let _ = k() +} +f(ctypes.returns_size_t) // OK: check that importing preserves Clang type + +// CHECK: sil @$s3tmp1fyySiyXzC9_ZTSPFmvEF diff --git a/test/Inputs/clang-importer-sdk/usr/include/ctypes.h b/test/Inputs/clang-importer-sdk/usr/include/ctypes.h index 5898fd4bbb9c4..dfe17a3dfdca8 100644 --- a/test/Inputs/clang-importer-sdk/usr/include/ctypes.h +++ b/test/Inputs/clang-importer-sdk/usr/include/ctypes.h @@ -205,18 +205,18 @@ typedef int (*fptr)(int); fptr getFunctionPointer(void); void useFunctionPointer(fptr); -int (*getFunctionPointer_(void))(int); +size_t (*getFunctionPointer_(void))(size_t); struct FunctionPointerWrapper { fptr a; fptr b; }; -typedef void (*fptr2)(int, long, void *); +typedef void (*fptr2)(size_t, long, void *); fptr2 getFunctionPointer2(void); void useFunctionPointer2(fptr2); -int (*(*getHigherOrderFunctionPointer(void))(int (*)(int)))(int); +size_t (*(*getHigherOrderFunctionPointer(void))(size_t (*)(size_t)))(size_t); typedef struct Dummy { int x; @@ -232,6 +232,10 @@ typedef OpaqueTypedefForFP (*FunctionPointerReturningOpaqueTypedef)(void); typedef struct ForwardInTypedefForFP2 *OpaqueTypedefForFP2; typedef OpaqueTypedefForFP2 (*FunctionPointerReturningOpaqueTypedef2)(void); +// Functions that get Swift types which cannot be used to re-derive the +// Clang type. +size_t returns_size_t(); + // This will probably never be serializable. typedef struct { int x; int y; } *(*UnserializableFunctionPointer)(void); diff --git a/test/Inputs/clang-importer-sdk/usr/include/objc/NSObject.h b/test/Inputs/clang-importer-sdk/usr/include/objc/NSObject.h index a86f7b8851669..e80887d8165f0 100644 --- a/test/Inputs/clang-importer-sdk/usr/include/objc/NSObject.h +++ b/test/Inputs/clang-importer-sdk/usr/include/objc/NSObject.h @@ -136,6 +136,7 @@ @interface A(BoolStuff) - setEnabled:(BOOL)enabled; ++ (void)setGlobal:(BOOL)global; @end @interface AlmostSubscriptable diff --git a/test/ModuleInterface/full-convention.swift b/test/ModuleInterface/full-convention.swift index 950ad95402ba6..d4d51e2a07eb1 100644 --- a/test/ModuleInterface/full-convention.swift +++ b/test/ModuleInterface/full-convention.swift @@ -1,32 +1,52 @@ -// RUN: %target-swift-frontend -typecheck -swift-version 5 -emit-module-interface-path - -enable-library-evolution %s -experimental-print-full-convention | %FileCheck %s +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -swift-version 5 -emit-module-interface-path - -enable-library-evolution %s -experimental-print-full-convention | %FileCheck %s + +import ctypes public func f( - // CHECK: g: @convention(c, cType: "void (*)(void)") + // CHECK: g: @convention(c) g: @convention(c) () -> (), - // CHECK: h0: @convention(c, cType: "int (*)(long long)") + // CHECK: h0: @convention(c) h0: @convention(c) (Int64) -> Int32, - // CHECK: h1: @convention(c, cType: "int (*)(long long)") + // CHECK: h1: @convention(c) h1: @convention(c, cType: "int (*)(long long)") (Int64) -> Int32, - // CHECK: i0: @convention(c, cType: "int *(*)(long long, int)") + // CHECK: h1c: @convention(c, cType: "intptr_t (*)(size_t)") + h1c: @convention(c, cType: "intptr_t (*)(size_t)") (Int) -> Int, + + // CHECK: i0: @convention(c) i0: @convention(c) (Int64, Int32) -> Optional>, - // CHECK: i1: @convention(c, cType: "int *(*)(long long, int)") + // CHECK: i1: @convention(c) i1: @convention(c, cType: "int *(*)(long long, int)") (Int64, Int32) -> Optional>, - // CHECK: p0: @convention(c, cType: "void (*)(void (*)(int))") - // CHECK: @convention(c, cType: "void (*)(int)") + // CHECK: i1c: @convention(c, cType: "size_t *(*)(intptr_t, ptrdiff_t)") + i1c: @convention(c, cType: "size_t *(*)(intptr_t, ptrdiff_t)") (Int, Int) -> Optional>, + + // CHECK: p0: @convention(c) + // CHECK: @convention(c) p0: @convention(c) (@convention(c) (Int32) -> Void) -> Void, - // CHECK: p1: @convention(c, cType: "void (*)(void (*)(int))") - // CHECK: @convention(c, cType: "void (*)(int)") + // CHECK: p1: @convention(c) + // CHECK: @convention(c) p1: @convention(c, cType: "void (*)(void (*)(int))") (@convention(c) (Int32) -> Void) -> Void, - // CHECK: p2: @convention(c, cType: "void (*)(void (*)(int))") - // CHECK: @convention(c, cType: "void (*)(int)") + // CHECK: p1c: @convention(c, cType: "void (*)(void (*)(size_t))") + // CHECK: @convention(c) + p1c: @convention(c, cType: "void (*)(void (*)(size_t))") (@convention(c) (Int) -> Void) -> Void, + + // CHECK: p2: @convention(c) + // CHECK: @convention(c) p2: @convention(c) (@convention(c, cType: "void (*)(int)") (Int32) -> Void) -> Void, - // CHECK: p3: @convention(c, cType: "void (*)(void (*)(int))") - // CHECK: @convention(c, cType: "void (*)(int)") - p3: @convention(c, cType: "void (*)(void (*)(int))") (@convention(c, cType: "void (*)(int)") (Int32) -> Void) -> Void + // CHECK: p2c: @convention(c) + // CHECK: @convention(c, cType: "void (*)(size_t)") + p2c: @convention(c) (@convention(c, cType: "void (*)(size_t)") (Int) -> Void) -> Void, + + // CHECK: p3: @convention(c) + // CHECK: @convention(c) + p3: @convention(c, cType: "void (*)(void (*)(int))") (@convention(c, cType: "void (*)(int)") (Int32) -> Void) -> Void, + + // CHECK: p3c: @convention(c) + // CHECK: @convention(c, cType: "void (*)(size_t)") + p3c: @convention(c, cType: "void (*)(void (*)(size_t))") (@convention(c, cType: "void (*)(size_t)") (Int) -> Void) -> Void ) {} diff --git a/test/SIL/clang-function-type-windows.swift b/test/SIL/clang-function-type-windows.swift new file mode 100644 index 0000000000000..6fcf84b196a44 --- /dev/null +++ b/test/SIL/clang-function-type-windows.swift @@ -0,0 +1,11 @@ +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) %s -emit-sil -swift-version 5 -use-clang-function-types -experimental-print-full-convention -o - | %FileCheck %s + +// REQUIRES: OS=windows-msvc + +import ctypes + +public func f(g: @convention(c, cType: "void (*)(size_t)") (Int) -> ()) { g(0) } + +// CHECK: sil @$s4main1f1gyySiXzC9_ZTSPFvyE_tF : $@convention(thin) (@convention(c, cType: "void (*)(unsigned long long)") @noescape (Int) -> ()) -> () { +// CHECK: bb0(%0 : $@convention(c, cType: "void (*)(unsigned long long)") @noescape (Int) -> ()): +// CHECK: debug_value %0 : $@convention(c, cType: "void (*)(unsigned long long)") @noescape (Int) -> (), let, name "g", argno 1 // id: %1 diff --git a/test/SIL/clang-function-types-nonwindows.swift b/test/SIL/clang-function-types-nonwindows.swift new file mode 100644 index 0000000000000..013e0f4c86d05 --- /dev/null +++ b/test/SIL/clang-function-types-nonwindows.swift @@ -0,0 +1,11 @@ +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) %s -emit-sil -swift-version 5 -use-clang-function-types -experimental-print-full-convention -o - | %FileCheck %s + +// UNSUPPORTED: OS=windows-msvc + +import ctypes + +public func f(g: @convention(c, cType: "void (*)(size_t)") (Int) -> ()) { g(0) } + +// CHECK: sil @$s4main1f1gyySiXzC9_ZTSPFvmE_tF : $@convention(thin) (@convention(c, cType: "void (*)(unsigned long)") @noescape (Int) -> ()) -> () { +// CHECK: bb0(%0 : $@convention(c, cType: "void (*)(unsigned long)") @noescape (Int) -> ()): +// CHECK: debug_value %0 : $@convention(c, cType: "void (*)(unsigned long)") @noescape (Int) -> (), let, name "g", argno 1 // id: %1 diff --git a/test/SIL/clang-function-types.swift b/test/SIL/clang-function-types.swift deleted file mode 100644 index 6ed5268a9268a..0000000000000 --- a/test/SIL/clang-function-types.swift +++ /dev/null @@ -1,8 +0,0 @@ -// 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 195343c08b1a8..61d0ff0a628be 100644 --- a/test/Serialization/clang-function-types.swift +++ b/test/Serialization/clang-function-types.swift @@ -10,8 +10,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, cType: "struct ForwardInTypedefForFP *(*)(void)") () -> Optional> + // CHECK: global_addr @$s24def_clang_function_types11has_fp_types13OpaquePointerVSgyXzC32_ZTSPFP21ForwardInTypedefForFPvESgvp : $*Optional<@convention(c, cType: "struct ForwardInTypedefForFP *(*)(void)") () -> Optional> let fp = has_fp_type _ = fp?() }