@@ -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+
470477void 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
483490void 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);
0 commit comments