Skip to content

Commit 97d9ca1

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 a68347f commit 97d9ca1

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
@@ -3066,7 +3066,8 @@ void ASTMangler::appendAnyGenericType(const GenericTypeDecl *decl,
30663066
// `ClassTemplateSpecializationDecl`'s name does not include information about
30673067
// template arguments, and in order to prevent name clashes we use the
30683068
// name of the Swift decl which does include template arguments.
3069-
appendIdentifier(nominal->getName().str());
3069+
appendIdentifier(nominal->getName().str(),
3070+
/*allowRawIdentifiers=*/false);
30703071
} else {
30713072
appendIdentifier(namedDecl->getName());
30723073
}
@@ -3091,7 +3092,8 @@ void ASTMangler::appendAnyGenericType(const GenericTypeDecl *decl,
30913092
// imported as enums, be consistent.
30923093
appendOperator("O");
30933094
} else if (isa<clang::ClassTemplateDecl>(namedDecl)) {
3094-
appendIdentifier(nominal->getName().str());
3095+
appendIdentifier(nominal->getName().str(),
3096+
/*allowRawIdentifiers=*/false);
30953097
} else {
30963098
llvm_unreachable("unknown imported Clang type");
30973099
}

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 << "`";
@@ -3634,12 +3651,16 @@ void PrintAST::visitEnumDecl(EnumDecl *decl) {
36343651
} else {
36353652
Printer.printIntroducerKeyword("enum", Options, " ");
36363653
printContextIfNeeded(decl);
3637-
recordDeclLoc(decl,
3638-
[&]{
3639-
Printer.printName(decl->getName(), getTypeMemberPrintNameContext(decl));
3640-
}, [&]{ // Signature
3641-
printGenericDeclGenericParams(decl);
3642-
});
3654+
recordDeclLoc(
3655+
decl,
3656+
[&] {
3657+
Printer.printName(decl->getName(),
3658+
getTypeMemberPrintNameContext(decl),
3659+
isSpecializedCxxDecl(decl));
3660+
},
3661+
[&] { // Signature
3662+
printGenericDeclGenericParams(decl);
3663+
});
36433664
printInherited(decl);
36443665
printDeclGenericRequirements(decl);
36453666
}
@@ -3661,12 +3682,16 @@ void PrintAST::visitStructDecl(StructDecl *decl) {
36613682
} else {
36623683
Printer.printIntroducerKeyword("struct", Options, " ");
36633684
printContextIfNeeded(decl);
3664-
recordDeclLoc(decl,
3665-
[&]{
3666-
Printer.printName(decl->getName(), getTypeMemberPrintNameContext(decl));
3667-
}, [&]{ // Signature
3668-
printGenericDeclGenericParams(decl);
3669-
});
3685+
recordDeclLoc(
3686+
decl,
3687+
[&] {
3688+
Printer.printName(decl->getName(),
3689+
getTypeMemberPrintNameContext(decl),
3690+
isSpecializedCxxDecl(decl));
3691+
},
3692+
[&] { // Signature
3693+
printGenericDeclGenericParams(decl);
3694+
});
36703695
printInherited(decl);
36713696
printDeclGenericRequirements(decl);
36723697
}
@@ -3689,12 +3714,16 @@ void PrintAST::visitClassDecl(ClassDecl *decl) {
36893714
Printer.printIntroducerKeyword(
36903715
decl->isExplicitActor() ? "actor" : "class", Options, " ");
36913716
printContextIfNeeded(decl);
3692-
recordDeclLoc(decl,
3693-
[&]{
3694-
Printer.printName(decl->getName(), getTypeMemberPrintNameContext(decl));
3695-
}, [&]{ // Signature
3696-
printGenericDeclGenericParams(decl);
3697-
});
3717+
recordDeclLoc(
3718+
decl,
3719+
[&] {
3720+
Printer.printName(decl->getName(),
3721+
getTypeMemberPrintNameContext(decl),
3722+
isSpecializedCxxDecl(decl));
3723+
},
3724+
[&] { // Signature
3725+
printGenericDeclGenericParams(decl);
3726+
});
36983727

36993728
printInherited(decl);
37003729
printDeclGenericRequirements(decl);

lib/IRGen/GenMeta.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1297,6 +1297,7 @@ namespace {
12971297
MetadataInitialization;
12981298

12991299
StringRef UserFacingName;
1300+
bool IsCxxSpecializedTemplate;
13001301
std::optional<TypeImportInfo<std::string>> ImportInfo;
13011302

13021303
using super::IGM;
@@ -1441,6 +1442,7 @@ namespace {
14411442
void computeIdentity() {
14421443
// Remember the user-facing name.
14431444
UserFacingName = Type->getName().str();
1445+
IsCxxSpecializedTemplate = false;
14441446

14451447
// For related entities, set the original type name as the ABI name
14461448
// and remember the related entity tag.
@@ -1461,9 +1463,11 @@ namespace {
14611463
// that each specialization gets its own metadata. A class template
14621464
// specialization's Swift name will always be the mangled name, so just
14631465
// use that.
1464-
if (auto spec = dyn_cast<clang::ClassTemplateSpecializationDecl>(clangDecl))
1466+
if (auto spec =
1467+
dyn_cast<clang::ClassTemplateSpecializationDecl>(clangDecl)) {
14651468
abiName = Type->getName().str();
1466-
else
1469+
IsCxxSpecializedTemplate = true;
1470+
} else
14671471
abiName = clangDecl->getQualifiedNameAsString();
14681472

14691473
// Typedefs and compatibility aliases that have been promoted to
@@ -1493,7 +1497,8 @@ namespace {
14931497

14941498
void addName() {
14951499
SmallString<32> name;
1496-
if (Lexer::identifierMustAlwaysBeEscaped(UserFacingName)) {
1500+
if (!IsCxxSpecializedTemplate &&
1501+
Lexer::identifierMustAlwaysBeEscaped(UserFacingName)) {
14971502
Mangle::Mangler::appendRawIdentifierForRuntime(UserFacingName, name);
14981503
} else {
14991504
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)