Skip to content

Update function type mangling to use Clang type when applicable. #34057

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion docs/ABI/Mangling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -523,15 +523,20 @@ 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
FUNCTION-KIND ::= 'G' // @differentiable function type (escaping)
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
Expand Down Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions include/swift/AST/ASTMangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <typename FnType>
void appendClangType(FnType *fn, llvm::raw_svector_ostream &os);

void appendFunctionSignature(AnyFunctionType *fn,
const ValueDecl *forDecl = nullptr);
Expand Down
1 change: 1 addition & 0 deletions include/swift/AST/ExtInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
23 changes: 23 additions & 0 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
Expand Down Expand Up @@ -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)`
Expand Down
3 changes: 3 additions & 0 deletions include/swift/Demangling/DemangleNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ NODE(BoundGenericTypeAlias)
NODE(BoundGenericFunction)
NODE(BuiltinTypeName)
NODE(CFunctionPointer)
NODE(ClangType)
CONTEXT_NODE(Class)
NODE(ClassMetadataBaseOffset)
NODE(ConcreteProtocolConformance)
Expand Down Expand Up @@ -119,6 +120,8 @@ NODE(ImplEscaping)
NODE(ImplConvention)
NODE(ImplDifferentiability)
NODE(ImplFunctionAttribute)
NODE(ImplFunctionConvention)
NODE(ImplFunctionConventionName)
NODE(ImplFunctionType)
NODE(ImplInvocationSubstitutions)
CONTEXT_NODE(ImplicitClosure)
Expand Down
3 changes: 2 additions & 1 deletion include/swift/Demangling/Demangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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);
Expand Down
32 changes: 24 additions & 8 deletions include/swift/Demangling/TypeDecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down
57 changes: 54 additions & 3 deletions lib/AST/ASTMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <memory>

using namespace swift;
using namespace swift::Mangle;
Expand Down Expand Up @@ -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');
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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 <typename FnType>
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<clang::ItaniumMangleContext> 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);
Expand Down
32 changes: 18 additions & 14 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4037,7 +4037,9 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
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;

Expand Down Expand Up @@ -4074,13 +4076,13 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
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";
Expand All @@ -4101,9 +4103,12 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
}
}

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;

Expand Down Expand Up @@ -4140,12 +4145,12 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
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:
Expand Down Expand Up @@ -4220,7 +4225,7 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
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);
Expand Down Expand Up @@ -4260,7 +4265,7 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
Printer.printStructurePost(PrintStructureKind::FunctionType);
};

printFunctionExtInfo(T->getASTContext(), T->getExtInfo());
printFunctionExtInfo(T);
printGenericSignature(T->getGenericSignature(),
PrintAST::PrintParams |
PrintAST::PrintRequirements);
Expand Down Expand Up @@ -4322,8 +4327,7 @@ class TypePrinter : public TypeVisitor<TypePrinter> {

void visitSILFunctionType(SILFunctionType *T) {
printSILCoroutineKind(T->getCoroutineKind());
printFunctionExtInfo(T->getASTContext(), T->getExtInfo(),
T->getWitnessMethodConformanceOrInvalid());
printFunctionExtInfo(T);
printCalleeConvention(T->getCalleeConvention());

if (auto sig = T->getInvocationGenericSignature()) {
Expand Down
4 changes: 4 additions & 0 deletions lib/AST/ExtInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Loading