@@ -467,6 +467,13 @@ void ASTPrinter::printEscapedStringLiteral(StringRef str) {
467
467
printTextImpl (escapeBuf.str ());
468
468
}
469
469
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
+
470
477
void ASTPrinter::printTypeRef (Type T, const TypeDecl *RefTo, Identifier Name,
471
478
PrintNameContext Context) {
472
479
if (isa<GenericTypeParamDecl>(RefTo)) {
@@ -477,7 +484,7 @@ void ASTPrinter::printTypeRef(Type T, const TypeDecl *RefTo, Identifier Name,
477
484
Context = PrintNameContext::ClassDynamicSelf;
478
485
}
479
486
480
- printName (Name, Context);
487
+ printName (Name, Context, isSpecializedCxxDecl (RefTo) );
481
488
}
482
489
483
490
void ASTPrinter::printModuleRef (ModuleEntity Mod, Identifier Name) {
@@ -576,19 +583,25 @@ ASTPrinter &operator<<(ASTPrinter &printer, tok keyword) {
576
583
}
577
584
578
585
// / 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 ) {
581
588
StringRef keyword = name.str ();
582
589
bool isKeyword = llvm::StringSwitch<bool >(keyword)
583
590
#define KEYWORD (KW ) \
584
591
.Case (#KW, true )
585
592
#include " swift/AST/TokenKinds.def"
586
593
.Default (false );
587
594
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
+
588
600
switch (context) {
589
601
case PrintNameContext::Normal:
590
602
case PrintNameContext::Attribute:
591
- return isKeyword || name.mustAlwaysBeEscaped ();
603
+ return isKeyword ||
604
+ (!isSpecializedCxxTemplate && name.mustAlwaysBeEscaped ());
592
605
case PrintNameContext::Keyword:
593
606
case PrintNameContext::IntroducerKeyword:
594
607
return false ;
@@ -598,18 +611,21 @@ bool swift::escapeIdentifierInContext(Identifier name,
598
611
return isKeyword && keyword != " Self" ;
599
612
600
613
case PrintNameContext::TypeMember:
601
- return isKeyword || !canBeMemberName (keyword) || name.mustAlwaysBeEscaped ();
614
+ return isKeyword || !canBeMemberName (keyword) ||
615
+ (!isSpecializedCxxTemplate && name.mustAlwaysBeEscaped ());
602
616
603
617
case PrintNameContext::FunctionParameterExternal:
604
618
case PrintNameContext::FunctionParameterLocal:
605
619
case PrintNameContext::TupleElement:
606
- return !canBeArgumentLabel (keyword) || name.mustAlwaysBeEscaped ();
620
+ return !canBeArgumentLabel (keyword) ||
621
+ (!isSpecializedCxxTemplate && name.mustAlwaysBeEscaped ());
607
622
}
608
623
609
624
llvm_unreachable (" Unhandled PrintNameContext in switch." );
610
625
}
611
626
612
- void ASTPrinter::printName (Identifier Name, PrintNameContext Context) {
627
+ void ASTPrinter::printName (Identifier Name, PrintNameContext Context,
628
+ bool IsSpecializedCxxTemplate) {
613
629
callPrintNamePre (Context);
614
630
615
631
if (Name.empty ()) {
@@ -618,7 +634,8 @@ void ASTPrinter::printName(Identifier Name, PrintNameContext Context) {
618
634
return ;
619
635
}
620
636
621
- bool shouldEscapeIdentifier = escapeIdentifierInContext (Name, Context);
637
+ bool shouldEscapeIdentifier =
638
+ escapeIdentifierInContext (Name, Context, IsSpecializedCxxTemplate);
622
639
623
640
if (shouldEscapeIdentifier)
624
641
*this << " `" ;
@@ -3645,12 +3662,16 @@ void PrintAST::visitEnumDecl(EnumDecl *decl) {
3645
3662
} else {
3646
3663
Printer.printIntroducerKeyword (" enum" , Options, " " );
3647
3664
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
+ });
3654
3675
printInherited (decl);
3655
3676
printDeclGenericRequirements (decl);
3656
3677
}
@@ -3672,12 +3693,16 @@ void PrintAST::visitStructDecl(StructDecl *decl) {
3672
3693
} else {
3673
3694
Printer.printIntroducerKeyword (" struct" , Options, " " );
3674
3695
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
+ });
3681
3706
printInherited (decl);
3682
3707
printDeclGenericRequirements (decl);
3683
3708
}
@@ -3700,12 +3725,16 @@ void PrintAST::visitClassDecl(ClassDecl *decl) {
3700
3725
Printer.printIntroducerKeyword (
3701
3726
decl->isExplicitActor () ? " actor" : " class" , Options, " " );
3702
3727
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
+ });
3709
3738
3710
3739
printInherited (decl);
3711
3740
printDeclGenericRequirements (decl);
0 commit comments