Skip to content

Commit 75f53a9

Browse files
authored
Merge pull request #62989 from zoecarver/class-template-name-mangling
[cxx-interop] Re-implement template mangling.
2 parents 5406f1a + 048a381 commit 75f53a9

35 files changed

+251
-217
lines changed

include/swift/AST/ASTContext.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1455,6 +1455,8 @@ class ASTContext final {
14551455
/// Finds the address of the given symbol. If `libraryHandleHint` is non-null,
14561456
/// search within the library.
14571457
void *getAddressOfSymbol(const char *name, void *libraryHandleHint = nullptr);
1458+
1459+
Type getNamedSwiftType(ModuleDecl *module, StringRef name);
14581460

14591461
private:
14601462
friend Decl;

include/swift/Parse/Parser.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2001,10 +2001,12 @@ struct ParsedDeclName {
20012001
}
20022002

20032003
/// Form a declaration name from this parsed declaration name.
2004-
DeclName formDeclName(ASTContext &ctx, bool isSubscript = false) const;
2004+
DeclName formDeclName(ASTContext &ctx, bool isSubscript = false,
2005+
bool isCxxClassTemplateSpec = false) const;
20052006

20062007
/// Form a declaration name from this parsed declaration name.
2007-
DeclNameRef formDeclNameRef(ASTContext &ctx, bool isSubscript = false) const;
2008+
DeclNameRef formDeclNameRef(ASTContext &ctx, bool isSubscript = false,
2009+
bool isCxxClassTemplateSpec = false) const;
20082010
};
20092011

20102012
/// To assist debugging parser crashes, tell us the location of the
@@ -2026,15 +2028,17 @@ DeclName formDeclName(ASTContext &ctx,
20262028
ArrayRef<StringRef> argumentLabels,
20272029
bool isFunctionName,
20282030
bool isInitializer,
2029-
bool isSubscript = false);
2031+
bool isSubscript = false,
2032+
bool isCxxClassTemplateSpec = false);
20302033

20312034
/// Form a Swift declaration name reference from its constituent parts.
20322035
DeclNameRef formDeclNameRef(ASTContext &ctx,
20332036
StringRef baseName,
20342037
ArrayRef<StringRef> argumentLabels,
20352038
bool isFunctionName,
20362039
bool isInitializer,
2037-
bool isSubscript = false);
2040+
bool isSubscript = false,
2041+
bool isCxxClassTemplateSpec = false);
20382042

20392043
/// Whether a given token can be the start of a decl.
20402044
bool isKeywordPossibleDeclStart(const Token &Tok);

lib/AST/ASTContext.cpp

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
#include "swift/Basic/SourceManager.h"
5656
#include "swift/Basic/Statistic.h"
5757
#include "swift/Basic/StringExtras.h"
58+
#include "swift/ClangImporter/ClangModule.h"
5859
#include "swift/Strings.h"
5960
#include "swift/Subsystems.h"
6061
#include "swift/SymbolGraphGen/SymbolGraphOptions.h"
@@ -5306,8 +5307,6 @@ ASTContext::getForeignRepresentationInfo(NominalTypeDecl *nominal,
53065307
}
53075308

53085309
// Pull SIMD types of size 2...4 from the SIMD module, if it exists.
5309-
// FIXME: Layering violation to use the ClangImporter's define.
5310-
const unsigned SWIFT_MAX_IMPORTED_SIMD_ELEMENTS = 4;
53115310
if (auto simd = getLoadedModule(Id_simd)) {
53125311
#define MAP_SIMD_TYPE(BASENAME, _, __) \
53135312
{ \
@@ -5354,7 +5353,6 @@ ASTContext::getForeignRepresentationInfo(NominalTypeDecl *nominal,
53545353
conditionallyAddTrivial(nominal, getSwiftId(KnownFoundationEntity::NSZone), Id_ObjectiveC, true);
53555354
conditionallyAddTrivial(nominal, Id_CGFloat, getIdentifier("CoreGraphics"));
53565355
conditionallyAddTrivial(nominal, Id_CGFloat, getIdentifier("CoreFoundation"));
5357-
const unsigned SWIFT_MAX_IMPORTED_SIMD_ELEMENTS = 4;
53585356
#define MAP_SIMD_TYPE(BASENAME, _, __) \
53595357
{ \
53605358
char name[] = #BASENAME "0"; \
@@ -6252,3 +6250,39 @@ void *ASTContext::getAddressOfSymbol(const char *name,
62526250
#endif
62536251
return address;
62546252
}
6253+
6254+
Type ASTContext::getNamedSwiftType(ModuleDecl *module, StringRef name) {
6255+
if (!module)
6256+
return Type();
6257+
6258+
// Look for the type.
6259+
Identifier identifier = getIdentifier(name);
6260+
SmallVector<ValueDecl *, 2> results;
6261+
6262+
// Check if the lookup we're about to perform a lookup within is
6263+
// a Clang module.
6264+
for (auto *file : module->getFiles()) {
6265+
if (auto clangUnit = dyn_cast<ClangModuleUnit>(file)) {
6266+
// If we have an overlay, look in the overlay. Otherwise, skip
6267+
// the lookup to avoid infinite recursion.
6268+
if (auto module = clangUnit->getOverlayModule())
6269+
module->lookupValue(identifier, NLKind::UnqualifiedLookup, results);
6270+
} else {
6271+
file->lookupValue(identifier, NLKind::UnqualifiedLookup, results);
6272+
}
6273+
}
6274+
6275+
if (results.size() != 1)
6276+
return Type();
6277+
6278+
auto decl = dyn_cast<TypeDecl>(results.front());
6279+
if (!decl)
6280+
return Type();
6281+
6282+
assert(!decl->hasClangNode() && "picked up the original type?");
6283+
6284+
if (auto *nominalDecl = dyn_cast<NominalTypeDecl>(decl))
6285+
return nominalDecl->getDeclaredType();
6286+
return decl->getDeclaredInterfaceType();
6287+
}
6288+

lib/AST/ClangTypeConverter.cpp

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -43,22 +43,7 @@ using namespace swift;
4343
namespace {
4444

4545
static Type getNamedSwiftType(ModuleDecl *stdlib, StringRef name) {
46-
auto &ctx = stdlib->getASTContext();
47-
SmallVector<ValueDecl*, 1> results;
48-
stdlib->lookupValue(ctx.getIdentifier(name), NLKind::QualifiedLookup,
49-
results);
50-
51-
// If we have one single type decl, and that decl has been
52-
// type-checked, return its declared type.
53-
//
54-
// ...non-type-checked types should only ever show up here because
55-
// of test cases using -enable-source-import, but unfortunately
56-
// that's a real thing.
57-
if (results.size() == 1) {
58-
if (auto typeDecl = dyn_cast<TypeDecl>(results[0]))
59-
return typeDecl->getDeclaredInterfaceType();
60-
}
61-
return Type();
46+
return stdlib->getASTContext().getNamedSwiftType(stdlib, name);
6247
}
6348

6449
static clang::QualType

lib/ClangImporter/ImportName.cpp

Lines changed: 56 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1658,7 +1658,9 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
16581658

16591659
if (!skipCustomName) {
16601660
result.info.hasCustomName = true;
1661-
result.declName = parsedName.formDeclName(swiftCtx);
1661+
result.declName = parsedName.formDeclName(
1662+
swiftCtx, /*isSubscript=*/false,
1663+
isa<clang::ClassTemplateSpecializationDecl>(D));
16621664

16631665
// Handle globals treated as members.
16641666
if (parsedName.isMember()) {
@@ -1713,7 +1715,8 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
17131715
// Update the name to reflect the new parameter labels.
17141716
result.declName = formDeclName(
17151717
swiftCtx, parsedName.BaseName, parsedName.ArgumentLabels,
1716-
/*isFunction=*/true, isInitializer);
1718+
/*isFunction=*/true, isInitializer, /*isSubscript=*/false,
1719+
isa<clang::ClassTemplateSpecializationDecl>(D));
17171720
} else if (nameAttr->isAsync) {
17181721
// The custom name was for an async import, but we didn't in fact
17191722
// import as async for some reason. Ignore this import.
@@ -2179,29 +2182,58 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
21792182
return importNameImpl(classTemplateSpecDecl->getSpecializedTemplate(),
21802183
version, givenName);
21812184
if (!isa<clang::ClassTemplatePartialSpecializationDecl>(D)) {
2182-
2183-
auto &astContext = classTemplateSpecDecl->getASTContext();
2184-
// Itanium mangler produces valid Swift identifiers, use it to generate a name for
2185-
// this instantiation.
2186-
std::unique_ptr<clang::MangleContext> mangler{
2187-
clang::ItaniumMangleContext::create(astContext,
2188-
astContext.getDiagnostics())};
2185+
// When constructing the name of a C++ template, don't expand all the
2186+
// template, only expand one layer. Here we want to prioritize
2187+
// readability over total completeness.
21892188
llvm::SmallString<128> storage;
21902189
llvm::raw_svector_ostream buffer(storage);
2191-
mangler->mangleTypeName(astContext.getRecordType(classTemplateSpecDecl),
2192-
buffer);
2193-
2194-
// The Itanium mangler does not provide a way to get the mangled
2195-
// representation of a type. Instead, we call mangleTypeName() that
2196-
// returns the name of the RTTI typeinfo symbol, and remove the _ZTS
2197-
// prefix. Then we prepend __CxxTemplateInst to reduce chances of conflict
2198-
// with regular C and C++ structs.
2199-
llvm::SmallString<128> mangledNameStorage;
2200-
llvm::raw_svector_ostream mangledName(mangledNameStorage);
2201-
assert(buffer.str().take_front(4) == "_ZTS");
2202-
mangledName << CXX_TEMPLATE_INST_PREFIX << buffer.str().drop_front(4);
2190+
D->printName(buffer);
2191+
buffer << "<";
2192+
llvm::interleaveComma(classTemplateSpecDecl->getTemplateArgs().asArray(),
2193+
buffer,
2194+
[&buffer, this, version](const clang::TemplateArgument& arg) {
2195+
// Use import name here so builtin types such as "int" map to their
2196+
// Swift equivalent ("Int32").
2197+
if (arg.getKind() == clang::TemplateArgument::Type) {
2198+
auto ty = arg.getAsType().getTypePtr();
2199+
if (auto builtin = dyn_cast<clang::BuiltinType>(ty)) {
2200+
auto &ctx = swiftCtx;
2201+
Type swiftType = nullptr;
2202+
switch (builtin->getKind()) {
2203+
case clang::BuiltinType::Void:
2204+
swiftType = ctx.getNamedSwiftType(ctx.getStdlibModule(), "Void");
2205+
break;
2206+
#define MAP_BUILTIN_TYPE(CLANG_BUILTIN_KIND, SWIFT_TYPE_NAME) \
2207+
case clang::BuiltinType::CLANG_BUILTIN_KIND: \
2208+
swiftType = ctx.getNamedSwiftType(ctx.getStdlibModule(), \
2209+
#SWIFT_TYPE_NAME); \
2210+
break;
2211+
#define MAP_BUILTIN_CCHAR_TYPE(CLANG_BUILTIN_KIND, SWIFT_TYPE_NAME) \
2212+
case clang::BuiltinType::CLANG_BUILTIN_KIND: \
2213+
swiftType = ctx.getNamedSwiftType(ctx.getStdlibModule(), \
2214+
#SWIFT_TYPE_NAME); \
2215+
break;
2216+
#include "swift/ClangImporter/BuiltinMappedTypes.def"
2217+
default:
2218+
break;
2219+
}
2220+
2221+
if (swiftType) {
2222+
if (auto nominal = dyn_cast<NominalType>(swiftType->getCanonicalType())) {
2223+
buffer << nominal->getDecl()->getNameStr();
2224+
return;
2225+
}
2226+
}
2227+
} else if (auto namedArg = dyn_cast_or_null<clang::NamedDecl>(ty->getAsTagDecl())) {
2228+
importNameImpl(namedArg, version, clang::DeclarationName()).getDeclName().print(buffer);
2229+
return;
2230+
}
2231+
}
2232+
buffer << "_";
2233+
});
2234+
buffer << ">";
22032235

2204-
baseName = swiftCtx.getIdentifier(mangledName.str()).get();
2236+
baseName = swiftCtx.getIdentifier(buffer.str()).get();
22052237
}
22062238
}
22072239

@@ -2327,7 +2359,8 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
23272359
baseName = renameUnsafeMethod(swiftCtx, D, baseName);
23282360

23292361
result.declName = formDeclName(swiftCtx, baseName, argumentNames, isFunction,
2330-
isInitializer);
2362+
isInitializer, /*isSubscript=*/false,
2363+
isa<clang::ClassTemplateSpecializationDecl>(D));
23312364
return result;
23322365
}
23332366

lib/ClangImporter/ImportType.cpp

Lines changed: 1 addition & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3261,38 +3261,7 @@ bool ClangImporter::Implementation::canImportFoundationModule() {
32613261

32623262
Type ClangImporter::Implementation::getNamedSwiftType(ModuleDecl *module,
32633263
StringRef name) {
3264-
if (!module)
3265-
return Type();
3266-
3267-
// Look for the type.
3268-
Identifier identifier = SwiftContext.getIdentifier(name);
3269-
SmallVector<ValueDecl *, 2> results;
3270-
3271-
// Check if the lookup we're about to perform a lookup within is
3272-
// a Clang module.
3273-
for (auto *file : module->getFiles()) {
3274-
if (auto clangUnit = dyn_cast<ClangModuleUnit>(file)) {
3275-
// If we have an overlay, look in the overlay. Otherwise, skip
3276-
// the lookup to avoid infinite recursion.
3277-
if (auto module = clangUnit->getOverlayModule())
3278-
module->lookupValue(identifier, NLKind::UnqualifiedLookup, results);
3279-
} else {
3280-
file->lookupValue(identifier, NLKind::UnqualifiedLookup, results);
3281-
}
3282-
}
3283-
3284-
if (results.size() != 1)
3285-
return Type();
3286-
3287-
auto decl = dyn_cast<TypeDecl>(results.front());
3288-
if (!decl)
3289-
return Type();
3290-
3291-
assert(!decl->hasClangNode() && "picked up the original type?");
3292-
3293-
if (auto *nominalDecl = dyn_cast<NominalTypeDecl>(decl))
3294-
return nominalDecl->getDeclaredType();
3295-
return decl->getDeclaredInterfaceType();
3264+
return SwiftContext.getNamedSwiftType(module, name);
32963265
}
32973266

32983267
Type ClangImporter::Implementation::getNamedSwiftType(StringRef moduleName,

lib/Parse/Parser.cpp

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1331,36 +1331,44 @@ ParsedDeclName swift::parseDeclName(StringRef name) {
13311331
return result;
13321332
}
13331333

1334-
DeclName ParsedDeclName::formDeclName(ASTContext &ctx, bool isSubscript) const {
1335-
return formDeclNameRef(ctx, isSubscript).getFullName();
1334+
DeclName ParsedDeclName::formDeclName(ASTContext &ctx, bool isSubscript,
1335+
bool isCxxClassTemplateSpec) const {
1336+
return formDeclNameRef(ctx, isSubscript, isCxxClassTemplateSpec).getFullName();
13361337
}
13371338

13381339
DeclNameRef ParsedDeclName::formDeclNameRef(ASTContext &ctx,
1339-
bool isSubscript) const {
1340+
bool isSubscript,
1341+
bool isCxxClassTemplateSpec) const {
13401342
return swift::formDeclNameRef(ctx, BaseName, ArgumentLabels, IsFunctionName,
1341-
/*IsInitializer=*/true, isSubscript);
1343+
/*IsInitializer=*/true, isSubscript,
1344+
isCxxClassTemplateSpec);
13421345
}
13431346

13441347
DeclName swift::formDeclName(ASTContext &ctx,
13451348
StringRef baseName,
13461349
ArrayRef<StringRef> argumentLabels,
13471350
bool isFunctionName,
13481351
bool isInitializer,
1349-
bool isSubscript) {
1352+
bool isSubscript,
1353+
bool isCxxClassTemplateSpec) {
13501354
return formDeclNameRef(ctx, baseName, argumentLabels, isFunctionName,
1351-
isInitializer, isSubscript).getFullName();
1355+
isInitializer, isSubscript,
1356+
isCxxClassTemplateSpec).getFullName();
13521357
}
13531358

13541359
DeclNameRef swift::formDeclNameRef(ASTContext &ctx,
13551360
StringRef baseName,
13561361
ArrayRef<StringRef> argumentLabels,
13571362
bool isFunctionName,
13581363
bool isInitializer,
1359-
bool isSubscript) {
1364+
bool isSubscript,
1365+
bool isCxxClassTemplateSpec) {
13601366
// We cannot import when the base name is not an identifier.
13611367
if (baseName.empty())
13621368
return DeclNameRef();
1363-
if (!Lexer::isIdentifier(baseName) && !Lexer::isOperator(baseName))
1369+
1370+
if (!Lexer::isIdentifier(baseName) && !Lexer::isOperator(baseName) &&
1371+
!isCxxClassTemplateSpec)
13641372
return DeclNameRef();
13651373

13661374
// Get the identifier for the base name. Special-case `init`.

test/Interop/Cxx/namespace/class-inline-namespace-irgen.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ extension Parent.TypedefInInlineChild {
4848
return ""
4949
}
5050
}
51-
// CHECK: define hidden swiftcc {{.*}} @"$sSo6ParentO11InlineChildO027__CxxTemplateInstN6Parent11b7Child21e2InbC4IcEEV4testE6stringSSvg"()
51+
// CHECK: define hidden swiftcc {{.*}} @"$sSo6ParentO11InlineChildO0033TemplateInInlineChildInt8_ehGIixbV4testE6stringSSvg"()
5252

5353
extension Parent.InInlineChild {
5454
func doSomething() {
@@ -70,22 +70,22 @@ extension Parent.InlineChild.InSecondInlineChild {
7070
}
7171
// define hidden swiftcc {{.*}} @"$sSo6ParentO11InlineChildO06SecondbC0O02IndbC0V4testE1ySivg"()
7272

73-
// CHECK: define hidden swiftcc {{.*}} @"$s4test3useySSSo6ParentO11InlineChildO027__CxxTemplateInstN6Parent11d7Child21g2IndE4IcEEVF"()
74-
// CHECK: call swiftcc {{.*}} @"$sSo6ParentO11InlineChildO027__CxxTemplateInstN6Parent11b7Child21e2InbC4IcEEV4testE6stringSSvg"
73+
// CHECK: define hidden swiftcc {{.*}} @"$s4test3useySSSo6ParentO11InlineChildO0033TemplateInInlineChildInt8_ehGIixbVF"()
74+
// CHECK: call swiftcc {{.*}} @"$sSo6ParentO11InlineChildO0033TemplateInInlineChildInt8_ehGIixbV4testE6stringSSvg"
7575
func use(_ x: Parent.TypedefInInlineChild) -> String {
7676
let s = x.string
7777
return s
7878
}
7979

80-
// CHECK: define hidden swiftcc {{.*}} @"$s4test4use2ySSSo6ParentO11InlineChildO027__CxxTemplateInstN6Parent11d7Child21g2IndE4IcEEVF"()
81-
// CHECK: call swiftcc {{.*}} @"$sSo6ParentO11InlineChildO027__CxxTemplateInstN6Parent11b7Child21e2InbC4IcEEV4testE6stringSSvg"
80+
// CHECK: define hidden swiftcc {{.*}} @"$s4test4use2ySSSo6ParentO11InlineChildO0033TemplateInInlineChildInt8_ehGIixbVF"()
81+
// CHECK: call swiftcc {{.*}} @"$sSo6ParentO11InlineChildO0033TemplateInInlineChildInt8_ehGIixbV4testE6stringSSvg"
8282
func use2(_ x: Parent.InlineChild.TypedefInInlineChild) -> String {
8383
let s = x.string
8484
return s
8585
}
8686

8787
// define swiftcc void @"$s4testAAyySo6ParentO11InlineChildO02IncD0VF"()
88-
// CHECK: alloca %TSo6ParentO11InlineChildO027__CxxTemplateInstN6Parent11b7Child21e2InbC4IcEEV
88+
// CHECK: alloca %TSo6ParentO11InlineChildO0033TemplateInInlineChildInt8_ehGIixbV
8989
// CHECK: call {{.*}} @{{_ZN6Parent11InlineChild21TemplateInInlineChildIcEC|"\?\?0\?\$TemplateInInlineChild@D@InlineChild@Parent@@QEAA@XZ"}}
9090
// CHECK: call swiftcc void @"$sSo6ParentO11InlineChildO02InbC0V4testE11doSomethingyyF"(
9191
// CHECK: call swiftcc {{.*}} @"$sSo6ParentO11InlineChildO06SecondbC0O02IndbC0V4testE1xSivg"(

0 commit comments

Comments
 (0)