Skip to content

Commit 2c7d209

Browse files
committed
Preserve existing printing/mangling behavior for C++ specializations.
Imported C++ template specializations receive identifiers that contain their type signature; e.g., `X<Y, Z>`. Since this means the identifier contains non-identifier characters, the new behavior was trying to escape them with backticks in ASTPrinter, ASTMangler, and the runtime metadata. This pulls that back to preserve the current behavior for specifically those types.
1 parent 6d08abd commit 2c7d209

File tree

5 files changed

+74
-33
lines changed

5 files changed

+74
-33
lines changed

include/swift/AST/ASTPrinter.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,8 @@ class ASTPrinter {
293293
void printEscapedStringLiteral(StringRef str);
294294

295295
void printName(Identifier Name,
296-
PrintNameContext Context = PrintNameContext::Normal);
296+
PrintNameContext Context = PrintNameContext::Normal,
297+
bool IsSpecializedCxxType = false);
297298

298299
void setIndent(unsigned NumSpaces) {
299300
CurrentIndentation = NumSpaces;
@@ -446,7 +447,8 @@ void printWithCompatibilityFeatureChecks(ASTPrinter &printer,
446447

447448
/// Determine whether we need to escape the given name within the given
448449
/// context, by wrapping it in backticks.
449-
bool escapeIdentifierInContext(Identifier name, PrintNameContext context);
450+
bool escapeIdentifierInContext(Identifier name, PrintNameContext context,
451+
bool isSpecializedCxxType = false);
450452

451453
} // namespace swift
452454

lib/AST/ASTMangler.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3047,7 +3047,8 @@ void ASTMangler::appendAnyGenericType(const GenericTypeDecl *decl,
30473047
// `ClassTemplateSpecializationDecl`'s name does not include information about
30483048
// template arguments, and in order to prevent name clashes we use the
30493049
// name of the Swift decl which does include template arguments.
3050-
appendIdentifier(nominal->getName().str());
3050+
appendIdentifier(nominal->getName().str(),
3051+
/*allowRawIdentifiers=*/false);
30513052
} else {
30523053
appendIdentifier(namedDecl->getName());
30533054
}
@@ -3072,7 +3073,8 @@ void ASTMangler::appendAnyGenericType(const GenericTypeDecl *decl,
30723073
// imported as enums, be consistent.
30733074
appendOperator("O");
30743075
} else if (isa<clang::ClassTemplateDecl>(namedDecl)) {
3075-
appendIdentifier(nominal->getName().str());
3076+
appendIdentifier(nominal->getName().str(),
3077+
/*allowRawIdentifiers=*/false);
30763078
} else {
30773079
llvm_unreachable("unknown imported Clang type");
30783080
}

lib/AST/ASTPrinter.cpp

Lines changed: 55 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,13 @@ void ASTPrinter::printEscapedStringLiteral(StringRef str) {
449449
printTextImpl(escapeBuf.str());
450450
}
451451

452+
// Returns true if the given declaration is backed by a C++ template
453+
// specialization.
454+
static bool isSpecializedCxxDecl(const Decl *D) {
455+
return D->hasClangNode() &&
456+
isa<clang::ClassTemplateSpecializationDecl>(D->getClangDecl());
457+
}
458+
452459
void ASTPrinter::printTypeRef(Type T, const TypeDecl *RefTo, Identifier Name,
453460
PrintNameContext Context) {
454461
if (isa<GenericTypeParamDecl>(RefTo)) {
@@ -459,7 +466,7 @@ void ASTPrinter::printTypeRef(Type T, const TypeDecl *RefTo, Identifier Name,
459466
Context = PrintNameContext::ClassDynamicSelf;
460467
}
461468

462-
printName(Name, Context);
469+
printName(Name, Context, isSpecializedCxxDecl(RefTo));
463470
}
464471

465472
void ASTPrinter::printModuleRef(ModuleEntity Mod, Identifier Name) {
@@ -558,19 +565,25 @@ ASTPrinter &operator<<(ASTPrinter &printer, tok keyword) {
558565
}
559566

560567
/// Determine whether to escape the given keyword in the given context.
561-
bool swift::escapeIdentifierInContext(Identifier name,
562-
PrintNameContext context) {
568+
bool swift::escapeIdentifierInContext(Identifier name, PrintNameContext context,
569+
bool isSpecializedCxxTemplate) {
563570
StringRef keyword = name.str();
564571
bool isKeyword = llvm::StringSwitch<bool>(keyword)
565572
#define KEYWORD(KW) \
566573
.Case(#KW, true)
567574
#include "swift/AST/TokenKinds.def"
568575
.Default(false);
569576

577+
// NB: ClangImporter synthesizes C++ template specializations with Identifiers
578+
// that contain the full type signature; e.g., a type named literally
579+
// `X<Y, Z>`. These would normally be interpreted as raw identifiers and
580+
// escaped with backticks, but we need to avoid that for those specific decls.
581+
570582
switch (context) {
571583
case PrintNameContext::Normal:
572584
case PrintNameContext::Attribute:
573-
return isKeyword || name.mustAlwaysBeEscaped();
585+
return isKeyword ||
586+
(!isSpecializedCxxTemplate && name.mustAlwaysBeEscaped());
574587
case PrintNameContext::Keyword:
575588
case PrintNameContext::IntroducerKeyword:
576589
return false;
@@ -580,18 +593,21 @@ bool swift::escapeIdentifierInContext(Identifier name,
580593
return isKeyword && keyword != "Self";
581594

582595
case PrintNameContext::TypeMember:
583-
return isKeyword || !canBeMemberName(keyword) || name.mustAlwaysBeEscaped();
596+
return isKeyword || !canBeMemberName(keyword) ||
597+
(!isSpecializedCxxTemplate && name.mustAlwaysBeEscaped());
584598

585599
case PrintNameContext::FunctionParameterExternal:
586600
case PrintNameContext::FunctionParameterLocal:
587601
case PrintNameContext::TupleElement:
588-
return !canBeArgumentLabel(keyword) || name.mustAlwaysBeEscaped();
602+
return !canBeArgumentLabel(keyword) ||
603+
(!isSpecializedCxxTemplate && name.mustAlwaysBeEscaped());
589604
}
590605

591606
llvm_unreachable("Unhandled PrintNameContext in switch.");
592607
}
593608

594-
void ASTPrinter::printName(Identifier Name, PrintNameContext Context) {
609+
void ASTPrinter::printName(Identifier Name, PrintNameContext Context,
610+
bool IsSpecializedCxxTemplate) {
595611
callPrintNamePre(Context);
596612

597613
if (Name.empty()) {
@@ -600,7 +616,8 @@ void ASTPrinter::printName(Identifier Name, PrintNameContext Context) {
600616
return;
601617
}
602618

603-
bool shouldEscapeIdentifier = escapeIdentifierInContext(Name, Context);
619+
bool shouldEscapeIdentifier =
620+
escapeIdentifierInContext(Name, Context, IsSpecializedCxxTemplate);
604621

605622
if (shouldEscapeIdentifier)
606623
*this << "`";
@@ -3566,12 +3583,16 @@ void PrintAST::visitEnumDecl(EnumDecl *decl) {
35663583
} else {
35673584
Printer.printIntroducerKeyword("enum", Options, " ");
35683585
printContextIfNeeded(decl);
3569-
recordDeclLoc(decl,
3570-
[&]{
3571-
Printer.printName(decl->getName(), getTypeMemberPrintNameContext(decl));
3572-
}, [&]{ // Signature
3573-
printGenericDeclGenericParams(decl);
3574-
});
3586+
recordDeclLoc(
3587+
decl,
3588+
[&] {
3589+
Printer.printName(decl->getName(),
3590+
getTypeMemberPrintNameContext(decl),
3591+
isSpecializedCxxDecl(decl));
3592+
},
3593+
[&] { // Signature
3594+
printGenericDeclGenericParams(decl);
3595+
});
35753596
printInherited(decl);
35763597
printDeclGenericRequirements(decl);
35773598
}
@@ -3593,12 +3614,16 @@ void PrintAST::visitStructDecl(StructDecl *decl) {
35933614
} else {
35943615
Printer.printIntroducerKeyword("struct", Options, " ");
35953616
printContextIfNeeded(decl);
3596-
recordDeclLoc(decl,
3597-
[&]{
3598-
Printer.printName(decl->getName(), getTypeMemberPrintNameContext(decl));
3599-
}, [&]{ // Signature
3600-
printGenericDeclGenericParams(decl);
3601-
});
3617+
recordDeclLoc(
3618+
decl,
3619+
[&] {
3620+
Printer.printName(decl->getName(),
3621+
getTypeMemberPrintNameContext(decl),
3622+
isSpecializedCxxDecl(decl));
3623+
},
3624+
[&] { // Signature
3625+
printGenericDeclGenericParams(decl);
3626+
});
36023627
printInherited(decl);
36033628
printDeclGenericRequirements(decl);
36043629
}
@@ -3621,12 +3646,16 @@ void PrintAST::visitClassDecl(ClassDecl *decl) {
36213646
Printer.printIntroducerKeyword(
36223647
decl->isExplicitActor() ? "actor" : "class", Options, " ");
36233648
printContextIfNeeded(decl);
3624-
recordDeclLoc(decl,
3625-
[&]{
3626-
Printer.printName(decl->getName(), getTypeMemberPrintNameContext(decl));
3627-
}, [&]{ // Signature
3628-
printGenericDeclGenericParams(decl);
3629-
});
3649+
recordDeclLoc(
3650+
decl,
3651+
[&] {
3652+
Printer.printName(decl->getName(),
3653+
getTypeMemberPrintNameContext(decl),
3654+
isSpecializedCxxDecl(decl));
3655+
},
3656+
[&] { // Signature
3657+
printGenericDeclGenericParams(decl);
3658+
});
36303659

36313660
printInherited(decl);
36323661
printDeclGenericRequirements(decl);

lib/IRGen/GenMeta.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1286,6 +1286,7 @@ namespace {
12861286
MetadataInitialization;
12871287

12881288
StringRef UserFacingName;
1289+
bool IsCxxSpecializedTemplate;
12891290
std::optional<TypeImportInfo<std::string>> ImportInfo;
12901291

12911292
using super::IGM;
@@ -1430,6 +1431,7 @@ namespace {
14301431
void computeIdentity() {
14311432
// Remember the user-facing name.
14321433
UserFacingName = Type->getName().str();
1434+
IsCxxSpecializedTemplate = false;
14331435

14341436
// For related entities, set the original type name as the ABI name
14351437
// and remember the related entity tag.
@@ -1450,9 +1452,11 @@ namespace {
14501452
// that each specialization gets its own metadata. A class template
14511453
// specialization's Swift name will always be the mangled name, so just
14521454
// use that.
1453-
if (auto spec = dyn_cast<clang::ClassTemplateSpecializationDecl>(clangDecl))
1455+
if (auto spec =
1456+
dyn_cast<clang::ClassTemplateSpecializationDecl>(clangDecl)) {
14541457
abiName = Type->getName().str();
1455-
else
1458+
IsCxxSpecializedTemplate = true;
1459+
} else
14561460
abiName = clangDecl->getName();
14571461

14581462
// Typedefs and compatibility aliases that have been promoted to
@@ -1482,7 +1486,8 @@ namespace {
14821486

14831487
void addName() {
14841488
SmallString<32> name;
1485-
if (Lexer::identifierMustAlwaysBeEscaped(UserFacingName)) {
1489+
if (!IsCxxSpecializedTemplate &&
1490+
Lexer::identifierMustAlwaysBeEscaped(UserFacingName)) {
14861491
Mangle::Mangler::appendRawIdentifierForRuntime(UserFacingName, name);
14871492
} else {
14881493
name += UserFacingName;

lib/Parse/Lexer.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -679,6 +679,9 @@ bool Lexer::isIdentifier(StringRef string) {
679679
}
680680

681681
bool Lexer::identifierMustAlwaysBeEscaped(StringRef str) {
682+
if (str.empty())
683+
return false;
684+
682685
bool mustEscape =
683686
!isOperator(str) && !isIdentifier(str) &&
684687
str.front() != '$'; // a property wrapper does not need to be escaped

0 commit comments

Comments
 (0)