Skip to content

Commit 9515da8

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 10e242e commit 9515da8

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
@@ -3062,7 +3062,8 @@ void ASTMangler::appendAnyGenericType(const GenericTypeDecl *decl,
30623062
// `ClassTemplateSpecializationDecl`'s name does not include information about
30633063
// template arguments, and in order to prevent name clashes we use the
30643064
// name of the Swift decl which does include template arguments.
3065-
appendIdentifier(nominal->getName().str());
3065+
appendIdentifier(nominal->getName().str(),
3066+
/*allowRawIdentifiers=*/false);
30663067
} else {
30673068
appendIdentifier(namedDecl->getName());
30683069
}
@@ -3087,7 +3088,8 @@ void ASTMangler::appendAnyGenericType(const GenericTypeDecl *decl,
30873088
// imported as enums, be consistent.
30883089
appendOperator("O");
30893090
} else if (isa<clang::ClassTemplateDecl>(namedDecl)) {
3090-
appendIdentifier(nominal->getName().str());
3091+
appendIdentifier(nominal->getName().str(),
3092+
/*allowRawIdentifiers=*/false);
30913093
} else {
30923094
llvm_unreachable("unknown imported Clang type");
30933095
}

lib/AST/ASTPrinter.cpp

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

470+
// Returns true if the given declaration is backed by a C++ template
471+
// specialization.
472+
static bool isSpecializedCxxDecl(const Decl *D) {
473+
return D->hasClangNode() &&
474+
isa<clang::ClassTemplateSpecializationDecl>(D->getClangDecl());
475+
}
476+
470477
void ASTPrinter::printTypeRef(Type T, const TypeDecl *RefTo, Identifier Name,
471478
PrintNameContext Context) {
472479
if (isa<GenericTypeParamDecl>(RefTo)) {
@@ -477,7 +484,7 @@ void ASTPrinter::printTypeRef(Type T, const TypeDecl *RefTo, Identifier Name,
477484
Context = PrintNameContext::ClassDynamicSelf;
478485
}
479486

480-
printName(Name, Context);
487+
printName(Name, Context, isSpecializedCxxDecl(RefTo));
481488
}
482489

483490
void ASTPrinter::printModuleRef(ModuleEntity Mod, Identifier Name) {
@@ -576,19 +583,25 @@ ASTPrinter &operator<<(ASTPrinter &printer, tok keyword) {
576583
}
577584

578585
/// Determine whether to escape the given keyword in the given context.
579-
bool swift::escapeIdentifierInContext(Identifier name,
580-
PrintNameContext context) {
586+
bool swift::escapeIdentifierInContext(Identifier name, PrintNameContext context,
587+
bool isSpecializedCxxTemplate) {
581588
StringRef keyword = name.str();
582589
bool isKeyword = llvm::StringSwitch<bool>(keyword)
583590
#define KEYWORD(KW) \
584591
.Case(#KW, true)
585592
#include "swift/AST/TokenKinds.def"
586593
.Default(false);
587594

595+
// NB: ClangImporter synthesizes C++ template specializations with Identifiers
596+
// that contain the full type signature; e.g., a type named literally
597+
// `X<Y, Z>`. These would normally be interpreted as raw identifiers and
598+
// escaped with backticks, but we need to avoid that for those specific decls.
599+
588600
switch (context) {
589601
case PrintNameContext::Normal:
590602
case PrintNameContext::Attribute:
591-
return isKeyword || name.mustAlwaysBeEscaped();
603+
return isKeyword ||
604+
(!isSpecializedCxxTemplate && name.mustAlwaysBeEscaped());
592605
case PrintNameContext::Keyword:
593606
case PrintNameContext::IntroducerKeyword:
594607
return false;
@@ -598,18 +611,21 @@ bool swift::escapeIdentifierInContext(Identifier name,
598611
return isKeyword && keyword != "Self";
599612

600613
case PrintNameContext::TypeMember:
601-
return isKeyword || !canBeMemberName(keyword) || name.mustAlwaysBeEscaped();
614+
return isKeyword || !canBeMemberName(keyword) ||
615+
(!isSpecializedCxxTemplate && name.mustAlwaysBeEscaped());
602616

603617
case PrintNameContext::FunctionParameterExternal:
604618
case PrintNameContext::FunctionParameterLocal:
605619
case PrintNameContext::TupleElement:
606-
return !canBeArgumentLabel(keyword) || name.mustAlwaysBeEscaped();
620+
return !canBeArgumentLabel(keyword) ||
621+
(!isSpecializedCxxTemplate && name.mustAlwaysBeEscaped());
607622
}
608623

609624
llvm_unreachable("Unhandled PrintNameContext in switch.");
610625
}
611626

612-
void ASTPrinter::printName(Identifier Name, PrintNameContext Context) {
627+
void ASTPrinter::printName(Identifier Name, PrintNameContext Context,
628+
bool IsSpecializedCxxTemplate) {
613629
callPrintNamePre(Context);
614630

615631
if (Name.empty()) {
@@ -618,7 +634,8 @@ void ASTPrinter::printName(Identifier Name, PrintNameContext Context) {
618634
return;
619635
}
620636

621-
bool shouldEscapeIdentifier = escapeIdentifierInContext(Name, Context);
637+
bool shouldEscapeIdentifier =
638+
escapeIdentifierInContext(Name, Context, IsSpecializedCxxTemplate);
622639

623640
if (shouldEscapeIdentifier)
624641
*this << "`";
@@ -3645,12 +3662,16 @@ void PrintAST::visitEnumDecl(EnumDecl *decl) {
36453662
} else {
36463663
Printer.printIntroducerKeyword("enum", Options, " ");
36473664
printContextIfNeeded(decl);
3648-
recordDeclLoc(decl,
3649-
[&]{
3650-
Printer.printName(decl->getName(), getTypeMemberPrintNameContext(decl));
3651-
}, [&]{ // Signature
3652-
printGenericDeclGenericParams(decl);
3653-
});
3665+
recordDeclLoc(
3666+
decl,
3667+
[&] {
3668+
Printer.printName(decl->getName(),
3669+
getTypeMemberPrintNameContext(decl),
3670+
isSpecializedCxxDecl(decl));
3671+
},
3672+
[&] { // Signature
3673+
printGenericDeclGenericParams(decl);
3674+
});
36543675
printInherited(decl);
36553676
printDeclGenericRequirements(decl);
36563677
}
@@ -3672,12 +3693,16 @@ void PrintAST::visitStructDecl(StructDecl *decl) {
36723693
} else {
36733694
Printer.printIntroducerKeyword("struct", Options, " ");
36743695
printContextIfNeeded(decl);
3675-
recordDeclLoc(decl,
3676-
[&]{
3677-
Printer.printName(decl->getName(), getTypeMemberPrintNameContext(decl));
3678-
}, [&]{ // Signature
3679-
printGenericDeclGenericParams(decl);
3680-
});
3696+
recordDeclLoc(
3697+
decl,
3698+
[&] {
3699+
Printer.printName(decl->getName(),
3700+
getTypeMemberPrintNameContext(decl),
3701+
isSpecializedCxxDecl(decl));
3702+
},
3703+
[&] { // Signature
3704+
printGenericDeclGenericParams(decl);
3705+
});
36813706
printInherited(decl);
36823707
printDeclGenericRequirements(decl);
36833708
}
@@ -3700,12 +3725,16 @@ void PrintAST::visitClassDecl(ClassDecl *decl) {
37003725
Printer.printIntroducerKeyword(
37013726
decl->isExplicitActor() ? "actor" : "class", Options, " ");
37023727
printContextIfNeeded(decl);
3703-
recordDeclLoc(decl,
3704-
[&]{
3705-
Printer.printName(decl->getName(), getTypeMemberPrintNameContext(decl));
3706-
}, [&]{ // Signature
3707-
printGenericDeclGenericParams(decl);
3708-
});
3728+
recordDeclLoc(
3729+
decl,
3730+
[&] {
3731+
Printer.printName(decl->getName(),
3732+
getTypeMemberPrintNameContext(decl),
3733+
isSpecializedCxxDecl(decl));
3734+
},
3735+
[&] { // Signature
3736+
printGenericDeclGenericParams(decl);
3737+
});
37093738

37103739
printInherited(decl);
37113740
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)