Skip to content

Commit cb900a6

Browse files
authored
Merge pull request #34057 from varungandhi-apple/vg-track-isDerivable-update-mangling
2 parents be73343 + 6cb71c6 commit cb900a6

27 files changed

+462
-99
lines changed

docs/ABI/Mangling.rst

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -523,15 +523,20 @@ Types
523523
FUNCTION-KIND ::= 'U' // uncurried function type (currently not used)
524524
FUNCTION-KIND ::= 'K' // @auto_closure function type (noescape)
525525
FUNCTION-KIND ::= 'B' // objc block function type
526-
FUNCTION-KIND ::= 'L' // objc block function type (escaping) (DWARF only; otherwise use 'B')
526+
FUNCTION-KIND ::= 'zB' C-TYPE // objc block type with non-canonical C type
527+
FUNCTION-KIND ::= 'L' // objc block function type with canonical C type (escaping) (DWARF only; otherwise use 'B' or 'zB' C-TYPE)
527528
FUNCTION-KIND ::= 'C' // C function pointer type
529+
FUNCTION-KIND ::= 'zC' C-TYPE // C function pointer type with with non-canonical C type
528530
FUNCTION-KIND ::= 'A' // @auto_closure function type (escaping)
529531
FUNCTION-KIND ::= 'E' // function type (noescape)
530532
FUNCTION-KIND ::= 'F' // @differentiable function type
531533
FUNCTION-KIND ::= 'G' // @differentiable function type (escaping)
532534
FUNCTION-KIND ::= 'H' // @differentiable(linear) function type
533535
FUNCTION-KIND ::= 'I' // @differentiable(linear) function type (escaping)
534536

537+
C-TYPE is mangled according to the Itanium ABI, and prefixed with the length.
538+
Non-ASCII identifiers are preserved as-is; we do not use Punycode.
539+
535540
function-signature ::= params-type params-type async? throws? // results and parameters
536541

537542
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.
618623
CALLEE-CONVENTION ::= 't' // thin
619624

620625
FUNC-REPRESENTATION ::= 'B' // C block invocation function
626+
FUNC-REPRESENTATION ::= 'zB' C-TYPE // C block invocation function with non-canonical C type
621627
FUNC-REPRESENTATION ::= 'C' // C global function
628+
FUNC-REPRESENTATION ::= 'zC' C-TYPE // C global function with non-canonical C type
622629
FUNC-REPRESENTATION ::= 'M' // Swift method
623630
FUNC-REPRESENTATION ::= 'J' // ObjC method
624631
FUNC-REPRESENTATION ::= 'K' // closure

include/swift/AST/ASTMangler.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,9 @@ class ASTMangler : public Mangler {
318318
const ValueDecl *forDecl = nullptr);
319319
void appendFunctionType(AnyFunctionType *fn, bool isAutoClosure = false,
320320
const ValueDecl *forDecl = nullptr);
321+
void appendClangType(AnyFunctionType *fn);
322+
template <typename FnType>
323+
void appendClangType(FnType *fn, llvm::raw_svector_ostream &os);
321324

322325
void appendFunctionSignature(AnyFunctionType *fn,
323326
const ValueDecl *forDecl = nullptr);

include/swift/AST/ExtInfo.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ class ClangTypeInfo {
7070
constexpr ClangTypeInfo(const clang::Type *type) : type(type) {}
7171

7272
friend bool operator==(ClangTypeInfo lhs, ClangTypeInfo rhs);
73+
friend bool operator!=(ClangTypeInfo lhs, ClangTypeInfo rhs);
7374
ClangTypeInfo getCanonical() const;
7475

7576
public:

include/swift/AST/Types.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2926,6 +2926,24 @@ class AnyFunctionType : public TypeBase {
29262926
ClangTypeInfo getClangTypeInfo() const;
29272927
ClangTypeInfo getCanonicalClangTypeInfo() const;
29282928

2929+
/// Returns true if the function type stores a Clang type that cannot
2930+
/// be derived from its Swift type. Returns false otherwise, including if
2931+
/// the function type is not @convention(c) or @convention(block).
2932+
///
2933+
/// For example, if you have a function pointer from C getting imported with
2934+
/// the following type:
2935+
///
2936+
/// @convention(c, cType: "void (*)(size_t (*)(size_t))")
2937+
/// (@convention(c, cType: "size_t (*)(size_t)") (Int) -> Int)) -> Void
2938+
///
2939+
/// The parameter's function type will have hasNonDerivableClangType() = true,
2940+
/// but the outer function type will have hasNonDerivableClangType() = false,
2941+
/// because the parameter and result type are sufficient to correctly derive
2942+
/// the Clang type for the outer function type. In terms of mangling,
2943+
/// the parameter type's mangling will incorporate the Clang type but the
2944+
/// outer function type's mangling doesn't need to duplicate that information.
2945+
bool hasNonDerivableClangType();
2946+
29292947
ExtInfo getExtInfo() const {
29302948
return ExtInfo(Bits.AnyFunctionType.ExtInfoBits, getClangTypeInfo());
29312949
}
@@ -4307,6 +4325,11 @@ class SILFunctionType final
43074325

43084326
ClangTypeInfo getClangTypeInfo() const;
43094327

4328+
/// Returns true if the function type stores a Clang type that cannot
4329+
/// be derived from its Swift type. Returns false otherwise, including if
4330+
/// the function type is not @convention(c) or @convention(block).
4331+
bool hasNonDerivableClangType();
4332+
43104333
bool hasSameExtInfoAs(const SILFunctionType *otherFn);
43114334

43124335
/// Given that `this` is a `@differentiable` or `@differentiable(linear)`

include/swift/Demangling/DemangleNodes.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ NODE(BoundGenericTypeAlias)
4444
NODE(BoundGenericFunction)
4545
NODE(BuiltinTypeName)
4646
NODE(CFunctionPointer)
47+
NODE(ClangType)
4748
CONTEXT_NODE(Class)
4849
NODE(ClassMetadataBaseOffset)
4950
NODE(ConcreteProtocolConformance)
@@ -120,6 +121,8 @@ NODE(ImplEscaping)
120121
NODE(ImplConvention)
121122
NODE(ImplDifferentiability)
122123
NODE(ImplFunctionAttribute)
124+
NODE(ImplFunctionConvention)
125+
NODE(ImplFunctionConventionName)
123126
NODE(ImplFunctionType)
124127
NODE(ImplInvocationSubstitutions)
125128
CONTEXT_NODE(ImplicitClosure)

include/swift/Demangling/Demangler.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,7 @@ class Demangler : public NodeFactory {
505505
NodePointer demangleAnyGenericType(Node::Kind kind);
506506
NodePointer demangleExtensionContext();
507507
NodePointer demanglePlainFunction();
508-
NodePointer popFunctionType(Node::Kind kind);
508+
NodePointer popFunctionType(Node::Kind kind, bool hasClangType = false);
509509
NodePointer popFunctionParams(Node::Kind kind);
510510
NodePointer popFunctionParamLabels(NodePointer FuncType);
511511
NodePointer popTuple();
@@ -522,6 +522,7 @@ class Demangler : public NodeFactory {
522522
NodePointer demangleImplResultConvention(Node::Kind ConvKind);
523523
NodePointer demangleImplDifferentiability();
524524
NodePointer demangleImplFunctionType();
525+
NodePointer demangleClangType();
525526
NodePointer demangleMetatype();
526527
NodePointer demanglePrivateContextDescriptor();
527528
NodePointer createArchetypeRef(int depth, int i);

include/swift/Demangling/TypeDecoder.h

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,12 @@ class TypeDecoder {
631631
}
632632

633633
unsigned firstChildIdx = 0;
634+
if (Node->getChild(firstChildIdx)->getKind() == NodeKind::ClangType) {
635+
// [TODO: synthesize-Clang-type-from-mangled-name] Use the first child
636+
// to create a ClangTypeInfo.
637+
++firstChildIdx;
638+
}
639+
634640
bool isThrow = false;
635641
if (Node->getChild(firstChildIdx)->getKind()
636642
== NodeKind::ThrowsAnnotation) {
@@ -695,18 +701,28 @@ class TypeDecoder {
695701
} else if (child->getText() == "@callee_guaranteed") {
696702
calleeConvention = ImplParameterConvention::Direct_Guaranteed;
697703
}
698-
} else if (child->getKind() == NodeKind::ImplFunctionAttribute) {
699-
if (!child->hasText())
700-
return MAKE_NODE_TYPE_ERROR0(child, "expected text");
701-
702-
StringRef text = child->getText();
703-
if (text == "@convention(c)") {
704+
} else if (child->getKind() == NodeKind::ImplFunctionConvention) {
705+
if (child->getNumChildren() == 0)
706+
return MAKE_NODE_TYPE_ERROR0(child, "expected grandchildren");
707+
if ((child->getFirstChild()->getKind() !=
708+
NodeKind::ImplFunctionConventionName) ||
709+
!child->getFirstChild()->hasText())
710+
return MAKE_NODE_TYPE_ERROR0(child, "expected convention name");
711+
712+
// [TODO: synthesize-Clang-type-from-mangled-name] If there are two
713+
// grand-children, the second is going to be the mangled Clang type.
714+
StringRef text = child->getFirstChild()->getText();
715+
if (text == "c") {
704716
flags =
705717
flags.withRepresentation(ImplFunctionRepresentation::CFunctionPointer);
706-
} else if (text == "@convention(block)") {
718+
} else if (text == "block") {
707719
flags =
708720
flags.withRepresentation(ImplFunctionRepresentation::Block);
709-
} else if (text == "@async") {
721+
}
722+
} else if (child->getKind() == NodeKind::ImplFunctionAttribute) {
723+
if (!child->hasText())
724+
return MAKE_NODE_TYPE_ERROR0(child, "expected text");
725+
if (child->getText() == "@async") {
710726
flags = flags.withAsync();
711727
}
712728
} else if (child->getKind() == NodeKind::ImplDifferentiable) {

lib/AST/ASTMangler.cpp

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,24 +30,27 @@
3030
#include "swift/AST/ProtocolConformanceRef.h"
3131
#include "swift/AST/SILLayout.h"
3232
#include "swift/Basic/Defer.h"
33+
#include "swift/ClangImporter/ClangImporter.h"
34+
#include "swift/Demangling/Demangler.h"
3335
#include "swift/Demangling/ManglingMacros.h"
3436
#include "swift/Demangling/ManglingUtils.h"
35-
#include "swift/Demangling/Demangler.h"
3637
#include "swift/Strings.h"
3738
#include "clang/AST/ASTContext.h"
38-
#include "clang/Basic/CharInfo.h"
3939
#include "clang/AST/Attr.h"
4040
#include "clang/AST/Decl.h"
4141
#include "clang/AST/DeclObjC.h"
4242
#include "clang/AST/DeclTemplate.h"
4343
#include "clang/AST/Mangle.h"
44+
#include "clang/Basic/CharInfo.h"
4445
#include "llvm/ADT/DenseMap.h"
4546
#include "llvm/ADT/SmallString.h"
4647
#include "llvm/ADT/StringRef.h"
48+
#include "llvm/Support/CommandLine.h"
4749
#include "llvm/Support/ErrorHandling.h"
4850
#include "llvm/Support/SaveAndRestore.h"
4951
#include "llvm/Support/raw_ostream.h"
50-
#include "llvm/Support/CommandLine.h"
52+
53+
#include <memory>
5154

5255
using namespace swift;
5356
using namespace swift::Mangle;
@@ -1653,15 +1656,35 @@ void ASTMangler::appendImplFunctionType(SILFunctionType *fn) {
16531656
OpArgs.push_back('t');
16541657
}
16551658

1659+
bool mangleClangType = fn->getASTContext().LangOpts.UseClangFunctionTypes &&
1660+
fn->hasNonDerivableClangType();
1661+
1662+
auto appendClangTypeToVec = [this, fn](auto &Vec) {
1663+
llvm::raw_svector_ostream OpArgsOS(Vec);
1664+
appendClangType(fn, OpArgsOS);
1665+
};
1666+
16561667
switch (fn->getRepresentation()) {
16571668
case SILFunctionTypeRepresentation::Thick:
16581669
case SILFunctionTypeRepresentation::Thin:
16591670
break;
16601671
case SILFunctionTypeRepresentation::Block:
1672+
if (!mangleClangType) {
1673+
OpArgs.push_back('B');
1674+
break;
1675+
}
1676+
OpArgs.push_back('z');
16611677
OpArgs.push_back('B');
1678+
appendClangTypeToVec(OpArgs);
16621679
break;
16631680
case SILFunctionTypeRepresentation::CFunctionPointer:
1681+
if (!mangleClangType) {
1682+
OpArgs.push_back('C');
1683+
break;
1684+
}
1685+
OpArgs.push_back('z');
16641686
OpArgs.push_back('C');
1687+
appendClangTypeToVec(OpArgs);
16651688
break;
16661689
case SILFunctionTypeRepresentation::ObjCMethod:
16671690
OpArgs.push_back('O');
@@ -2244,6 +2267,9 @@ void ASTMangler::appendFunctionType(AnyFunctionType *fn, bool isAutoClosure,
22442267

22452268
appendFunctionSignature(fn, forDecl);
22462269

2270+
bool mangleClangType = fn->getASTContext().LangOpts.UseClangFunctionTypes &&
2271+
fn->hasNonDerivableClangType();
2272+
22472273
// Note that we do not currently use thin representations in the AST
22482274
// for the types of function decls. This may need to change at some
22492275
// point, in which case the uncurry logic can probably migrate to that
@@ -2256,6 +2282,10 @@ void ASTMangler::appendFunctionType(AnyFunctionType *fn, bool isAutoClosure,
22562282
// changes to better support thin functions.
22572283
switch (fn->getRepresentation()) {
22582284
case AnyFunctionType::Representation::Block:
2285+
if (mangleClangType) {
2286+
appendOperator("XzB");
2287+
return appendClangType(fn);
2288+
}
22592289
// We distinguish escaping and non-escaping blocks, but only in the DWARF
22602290
// mangling, because the ABI is already set.
22612291
if (!fn->isNoEscape() && DWARFMangling)
@@ -2287,10 +2317,31 @@ void ASTMangler::appendFunctionType(AnyFunctionType *fn, bool isAutoClosure,
22872317
return appendOperator("c");
22882318

22892319
case AnyFunctionType::Representation::CFunctionPointer:
2320+
if (mangleClangType) {
2321+
appendOperator("XzC");
2322+
return appendClangType(fn);
2323+
}
22902324
return appendOperator("XC");
22912325
}
22922326
}
22932327

2328+
template <typename FnType>
2329+
void ASTMangler::appendClangType(FnType *fn, llvm::raw_svector_ostream &out) {
2330+
auto clangType = fn->getClangTypeInfo().getType();
2331+
SmallString<64> scratch;
2332+
llvm::raw_svector_ostream scratchOS(scratch);
2333+
clang::ASTContext &clangCtx =
2334+
fn->getASTContext().getClangModuleLoader()->getClangASTContext();
2335+
std::unique_ptr<clang::ItaniumMangleContext> mangler{
2336+
clang::ItaniumMangleContext::create(clangCtx, clangCtx.getDiagnostics())};
2337+
mangler->mangleTypeName(clang::QualType(clangType, 0), scratchOS);
2338+
out << scratchOS.str().size() << scratchOS.str();
2339+
}
2340+
2341+
void ASTMangler::appendClangType(AnyFunctionType *fn) {
2342+
appendClangType(fn, Buffer);
2343+
}
2344+
22942345
void ASTMangler::appendFunctionSignature(AnyFunctionType *fn,
22952346
const ValueDecl *forDecl) {
22962347
appendFunctionResultType(fn->getResult(), forDecl);

lib/AST/ASTPrinter.cpp

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4039,7 +4039,9 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
40394039
visit(staticSelfT);
40404040
}
40414041

4042-
void printFunctionExtInfo(ASTContext &Ctx, AnyFunctionType::ExtInfo info) {
4042+
void printFunctionExtInfo(AnyFunctionType *fnType) {
4043+
auto &ctx = fnType->getASTContext();
4044+
auto info = fnType->getExtInfo();
40434045
if (Options.SkipAttributes)
40444046
return;
40454047

@@ -4076,13 +4078,13 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
40764078
break;
40774079
case SILFunctionType::Representation::Block:
40784080
Printer << "block";
4079-
if (printClangType && !info.getClangTypeInfo().empty())
4080-
printCType(Ctx, Printer, info);
4081+
if (printClangType && fnType->hasNonDerivableClangType())
4082+
printCType(ctx, Printer, info);
40814083
break;
40824084
case SILFunctionType::Representation::CFunctionPointer:
40834085
Printer << "c";
4084-
if (printClangType && !info.getClangTypeInfo().empty())
4085-
printCType(Ctx, Printer, info);
4086+
if (printClangType && fnType->hasNonDerivableClangType())
4087+
printCType(ctx, Printer, info);
40864088
break;
40874089
case SILFunctionType::Representation::Method:
40884090
Printer << "method";
@@ -4103,9 +4105,12 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
41034105
}
41044106
}
41054107

4106-
void printFunctionExtInfo(ASTContext &Ctx,
4107-
SILFunctionType::ExtInfo info,
4108-
ProtocolConformanceRef witnessMethodConformance) {
4108+
void printFunctionExtInfo(SILFunctionType *fnType) {
4109+
auto &Ctx = fnType->getASTContext();
4110+
auto info = fnType->getExtInfo();
4111+
auto witnessMethodConformance =
4112+
fnType->getWitnessMethodConformanceOrInvalid();
4113+
41094114
if (Options.SkipAttributes)
41104115
return;
41114116

@@ -4142,12 +4147,12 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
41424147
break;
41434148
case SILFunctionType::Representation::Block:
41444149
Printer << "block";
4145-
if (printClangType)
4150+
if (printClangType && fnType->hasNonDerivableClangType())
41464151
printCType(Ctx, Printer, info);
41474152
break;
41484153
case SILFunctionType::Representation::CFunctionPointer:
41494154
Printer << "c";
4150-
if (printClangType)
4155+
if (printClangType && fnType->hasNonDerivableClangType())
41514156
printCType(Ctx, Printer, info);
41524157
break;
41534158
case SILFunctionType::Representation::Method:
@@ -4222,7 +4227,7 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
42224227
Printer.printStructurePost(PrintStructureKind::FunctionType);
42234228
};
42244229

4225-
printFunctionExtInfo(T->getASTContext(), T->getExtInfo());
4230+
printFunctionExtInfo(T);
42264231

42274232
// If we're stripping argument labels from types, do it when printing.
42284233
visitAnyFunctionTypeParams(T->getParams(), /*printLabels*/false);
@@ -4262,7 +4267,7 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
42624267
Printer.printStructurePost(PrintStructureKind::FunctionType);
42634268
};
42644269

4265-
printFunctionExtInfo(T->getASTContext(), T->getExtInfo());
4270+
printFunctionExtInfo(T);
42664271
printGenericSignature(T->getGenericSignature(),
42674272
PrintAST::PrintParams |
42684273
PrintAST::PrintRequirements);
@@ -4324,8 +4329,7 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
43244329

43254330
void visitSILFunctionType(SILFunctionType *T) {
43264331
printSILCoroutineKind(T->getCoroutineKind());
4327-
printFunctionExtInfo(T->getASTContext(), T->getExtInfo(),
4328-
T->getWitnessMethodConformanceOrInvalid());
4332+
printFunctionExtInfo(T);
43294333
printCalleeConvention(T->getCalleeConvention());
43304334

43314335
if (auto sig = T->getInvocationGenericSignature()) {

lib/AST/ExtInfo.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ bool operator==(ClangTypeInfo lhs, ClangTypeInfo rhs) {
3434
return false;
3535
}
3636

37+
bool operator!=(ClangTypeInfo lhs, ClangTypeInfo rhs) {
38+
return !(lhs == rhs);
39+
}
40+
3741
ClangTypeInfo ClangTypeInfo::getCanonical() const {
3842
if (!type)
3943
return ClangTypeInfo();

0 commit comments

Comments
 (0)