From fabcce0d7a4a1633b4d5ed49cb78fdf441e3c11e Mon Sep 17 00:00:00 2001 From: Matheus Izvekov Date: Fri, 24 May 2024 12:22:55 -0300 Subject: [PATCH] [clang] Improve ast-dumper text printing of TemplateArgument This improves and unifies our approach to printing all template arguments. The same approach to printing types is extended to all TemplateArguments: A sugared version is printed in quotes, followed by printing the canonical form, unless they would print the same. Special improvements are done to add more detail to template template arguments. It's planned in a future patch to use this improved TemplateName printer for other places besides TemplateArguments. Note: The sugared/desugared printing does not show up for TemplateNames in tests yet, because we do a poor job of preserving their type sugar. This will be improved in a future patch. --- clang/docs/ReleaseNotes.rst | 2 + clang/include/clang/AST/TextNodeDumper.h | 2 + clang/lib/AST/TextNodeDumper.cpp | 104 +++++++++++++++--- clang/test/AST/ast-dump-decl.cpp | 25 +++-- ...penmp-begin-declare-variant_template_2.cpp | 6 +- clang/test/AST/ast-dump-template-name.cpp | 54 +++++++++ clang/test/AST/ast-dump-using-template.cpp | 8 +- .../constraints-explicit-instantiation.cpp | 6 +- clang/test/OpenMP/align_clause_ast_print.cpp | 2 +- clang/test/OpenMP/generic_loop_ast_print.cpp | 2 +- clang/test/OpenMP/interop_ast_print.cpp | 2 +- clang/test/SemaOpenACC/sub-array-ast.cpp | 2 +- .../aggregate-deduction-candidate.cpp | 18 +-- clang/test/SemaTemplate/attributes.cpp | 64 +++++------ clang/test/SemaTemplate/deduction-guide.cpp | 19 ++-- clang/test/SemaTemplate/make_integer_seq.cpp | 68 +++++++----- clang/test/SemaTemplate/type_pack_element.cpp | 20 ++-- 17 files changed, 276 insertions(+), 128 deletions(-) create mode 100644 clang/test/AST/ast-dump-template-name.cpp diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index bd92818f0c09d..e1c6d55eeeacd 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -98,6 +98,8 @@ ABI Changes in This Version AST Dumping Potentially Breaking Changes ---------------------------------------- +- The text ast-dumper has improved printing of TemplateArguments. + Clang Frontend Potentially Breaking Changes ------------------------------------------- - Removed support for constructing on-stack ``TemplateArgumentList``\ s; interfaces should instead diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h index 1fede6e462e92..63fa16c9ec47c 100644 --- a/clang/include/clang/AST/TextNodeDumper.h +++ b/clang/include/clang/AST/TextNodeDumper.h @@ -213,6 +213,8 @@ class TextNodeDumper void dumpTemplateSpecializationKind(TemplateSpecializationKind TSK); void dumpNestedNameSpecifier(const NestedNameSpecifier *NNS); void dumpConceptReference(const ConceptReference *R); + void dumpTemplateArgument(const TemplateArgument &TA); + void dumpTemplateName(TemplateName TN); void dumpDeclRef(const Decl *D, StringRef Label = {}); diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index 4a1e94ffe283b..627f8d3477d4e 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -947,6 +947,26 @@ void TextNodeDumper::dumpDeclRef(const Decl *D, StringRef Label) { }); } +void TextNodeDumper::dumpTemplateArgument(const TemplateArgument &TA) { + llvm::SmallString<128> Str; + { + llvm::raw_svector_ostream SS(Str); + TA.print(PrintPolicy, SS, /*IncludeType=*/true); + } + OS << " '" << Str << "'"; + + if (TemplateArgument CanonTA = Context->getCanonicalTemplateArgument(TA); + !CanonTA.structurallyEquals(TA)) { + llvm::SmallString<128> CanonStr; + { + llvm::raw_svector_ostream SS(CanonStr); + CanonTA.print(PrintPolicy, SS, /*IncludeType=*/true); + } + if (CanonStr != Str) + OS << ":'" << CanonStr << "'"; + } +} + const char *TextNodeDumper::getCommandName(unsigned CommandID) { if (Traits) return Traits->getCommandInfo(CommandID)->Name; @@ -1086,45 +1106,101 @@ void TextNodeDumper::VisitNullTemplateArgument(const TemplateArgument &) { void TextNodeDumper::VisitTypeTemplateArgument(const TemplateArgument &TA) { OS << " type"; - dumpType(TA.getAsType()); + dumpTemplateArgument(TA); } void TextNodeDumper::VisitDeclarationTemplateArgument( const TemplateArgument &TA) { OS << " decl"; + dumpTemplateArgument(TA); dumpDeclRef(TA.getAsDecl()); } -void TextNodeDumper::VisitNullPtrTemplateArgument(const TemplateArgument &) { +void TextNodeDumper::VisitNullPtrTemplateArgument(const TemplateArgument &TA) { OS << " nullptr"; + dumpTemplateArgument(TA); } void TextNodeDumper::VisitIntegralTemplateArgument(const TemplateArgument &TA) { - OS << " integral " << TA.getAsIntegral(); + OS << " integral"; + dumpTemplateArgument(TA); +} + +void TextNodeDumper::dumpTemplateName(TemplateName TN) { + switch (TN.getKind()) { + case TemplateName::Template: + AddChild([=] { Visit(TN.getAsTemplateDecl()); }); + return; + case TemplateName::UsingTemplate: { + const UsingShadowDecl *USD = TN.getAsUsingShadowDecl(); + AddChild([=] { Visit(USD); }); + AddChild("target", [=] { Visit(USD->getTargetDecl()); }); + return; + } + case TemplateName::QualifiedTemplate: { + OS << " qualified"; + const QualifiedTemplateName *QTN = TN.getAsQualifiedTemplateName(); + if (QTN->hasTemplateKeyword()) + OS << " keyword"; + dumpNestedNameSpecifier(QTN->getQualifier()); + dumpTemplateName(QTN->getUnderlyingTemplate()); + return; + } + case TemplateName::DependentTemplate: { + OS << " dependent"; + const DependentTemplateName *DTN = TN.getAsDependentTemplateName(); + dumpNestedNameSpecifier(DTN->getQualifier()); + return; + } + case TemplateName::SubstTemplateTemplateParm: { + OS << " subst"; + const SubstTemplateTemplateParmStorage *STS = + TN.getAsSubstTemplateTemplateParm(); + OS << " index " << STS->getIndex(); + if (std::optional PackIndex = STS->getPackIndex()) + OS << " pack_index " << *PackIndex; + if (const TemplateTemplateParmDecl *P = STS->getParameter()) + AddChild("parameter", [=] { Visit(P); }); + dumpDeclRef(STS->getAssociatedDecl(), "associated"); + AddChild("replacement", [=] { dumpTemplateName(STS->getReplacement()); }); + return; + } + // FIXME: Implement these. + case TemplateName::OverloadedTemplate: + OS << " overloaded"; + return; + case TemplateName::AssumedTemplate: + OS << " assumed"; + return; + case TemplateName::SubstTemplateTemplateParmPack: + OS << " subst_pack"; + return; + } + llvm_unreachable("Unexpected TemplateName Kind"); } void TextNodeDumper::VisitTemplateTemplateArgument(const TemplateArgument &TA) { - if (TA.getAsTemplate().getKind() == TemplateName::UsingTemplate) - OS << " using"; - OS << " template "; - TA.getAsTemplate().dump(OS); + OS << " template"; + dumpTemplateArgument(TA); + dumpTemplateName(TA.getAsTemplate()); } void TextNodeDumper::VisitTemplateExpansionTemplateArgument( const TemplateArgument &TA) { - if (TA.getAsTemplateOrTemplatePattern().getKind() == - TemplateName::UsingTemplate) - OS << " using"; - OS << " template expansion "; - TA.getAsTemplateOrTemplatePattern().dump(OS); + OS << " template expansion"; + dumpTemplateArgument(TA); + dumpTemplateName(TA.getAsTemplateOrTemplatePattern()); } -void TextNodeDumper::VisitExpressionTemplateArgument(const TemplateArgument &) { +void TextNodeDumper::VisitExpressionTemplateArgument( + const TemplateArgument &TA) { OS << " expr"; + dumpTemplateArgument(TA); } -void TextNodeDumper::VisitPackTemplateArgument(const TemplateArgument &) { +void TextNodeDumper::VisitPackTemplateArgument(const TemplateArgument &TA) { OS << " pack"; + dumpTemplateArgument(TA); } static void dumpBasePath(raw_ostream &OS, const CastExpr *Node) { diff --git a/clang/test/AST/ast-dump-decl.cpp b/clang/test/AST/ast-dump-decl.cpp index e062d4f068a40..b861ba8be15b5 100644 --- a/clang/test/AST/ast-dump-decl.cpp +++ b/clang/test/AST/ast-dump-decl.cpp @@ -459,21 +459,23 @@ namespace testClassTemplateDecl { // CHECK: ClassTemplateDecl 0x{{.+}} <{{.+}}:[[@LINE-148]]:3, col:31> col:31 TestTemplateDefaultNonType{{$}} // CHECK-NEXT: |-NonTypeTemplateParmDecl 0x{{.+}} col:16 'int' depth 0 index 0 I{{$}} -// CHECK-NEXT: | `-TemplateArgument expr{{$}} +// CHECK-NEXT: | `-TemplateArgument expr '42'{{$}} // CHECK-NEXT: | `-IntegerLiteral 0x{{.+}} 'int' 42{{$}} // CHECK-NEXT: `-CXXRecordDecl 0x{{.+}} col:31 struct TestTemplateDefaultNonType{{$}} // CHECK: ClassTemplateDecl 0x{{.+}} <{{.+}}:{{.*}}:3, col:68> col:68 TestTemplateTemplateDefaultType{{$}} // CHECK-NEXT: |-TemplateTemplateParmDecl 0x{{.+}} col:37 depth 0 index 0 TT{{$}} // CHECK-NEXT: | |-TemplateTypeParmDecl 0x{{.+}} col:29 typename depth 1 index 0{{$}} -// CHECK-NEXT: | `-TemplateArgument template TestClassTemplate{{$}} -// CHECK-NEXT: `-CXXRecordDecl 0x{{.+}} col:68 struct TestTemplateTemplateDefaultType{{$}} +// CHECK-NEXT: | `-TemplateArgument template 'testClassTemplateDecl::TestClassTemplate'{{$}} +// CHECK-NEXT: | `-ClassTemplateDecl 0x{{.+}} line:{{.+}}:30 TestClassTemplate{{$}} +// CHECK-NEXT: `-CXXRecordDecl 0x{{.+}} col:68 struct TestTemplateTemplateDefaultType{{$}} // CHECK: ClassTemplateDecl 0x{{.+}} prev 0x{{.+}} <{{.+}}:{{.*}}:3, col:82> col:48 TestTemplateTemplateDefaultType{{$}} // CHECK-NEXT: |-TemplateTemplateParmDecl 0x{{.+}} col:37 depth 0 index 0 TT{{$}} // CHECK-NEXT: | |-TemplateTypeParmDecl 0x{{.+}} col:29 typename depth 1 index 0{{$}} -// CHECK-NEXT: | `-TemplateArgument template TestClassTemplate{{$}} -// CHECK-NEXT: | `-inherited from TemplateTemplateParm 0x{{.+}} 'TT'{{$}} +// CHECK-NEXT: | `-TemplateArgument template 'testClassTemplateDecl::TestClassTemplate'{{$}} +// CHECK-NEXT: | |-inherited from TemplateTemplateParm 0x{{.+}} 'TT'{{$}} +// CHECK-NEXT: | `-ClassTemplateDecl 0x{{.+}} line:{{.+}}:30 TestClassTemplate // CHECK-NEXT: `-CXXRecordDecl 0x{{.+}} prev 0x{{.+}} col:48 struct TestTemplateTemplateDefaultType definition{{$}} // CHECK-NEXT: |-DefinitionData empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init{{$}} // CHECK-NEXT: | |-DefaultConstructor exists trivial constexpr needs_implicit defaulted_is_constexpr{{$}} @@ -683,7 +685,8 @@ namespace TestTemplateTemplateParmDecl { // CHECK: FunctionTemplateDecl // CHECK-NEXT: TemplateTemplateParmDecl{{.*}} T // CHECK-NEXT: TemplateTypeParmDecl{{.*}} typename -// CHECK-NEXT: TemplateArgument{{.*}} template A +// CHECK-NEXT: TemplateArgument{{.*}} template 'TestTemplateTemplateParmDecl::A' +// CHECK-NEXT: ClassTemplateDecl {{.*}} A // CHECK-NEXT: TemplateTemplateParmDecl{{.*}} ... U // CHECK-NEXT: TemplateTypeParmDecl{{.*}} typename @@ -710,12 +713,12 @@ namespace TestTemplateArgument { template class testIntegral { }; template class testIntegral<1>; // CHECK: ClassTemplateSpecializationDecl{{.*}} class testIntegral - // CHECK: TemplateArgument{{.*}} integral 1 + // CHECK: TemplateArgument{{.*}} integral '1' template class> class testTemplate { }; template class testTemplate; // CHECK: ClassTemplateSpecializationDecl{{.*}} class testTemplate - // CHECK: TemplateArgument{{.*}} A + // CHECK: TemplateArgument{{.*}} 'TestTemplateArgument::A' template class ...T> class C { B testTemplateExpansion; @@ -731,10 +734,10 @@ namespace TestTemplateArgument { template class testPack { }; template class testPack<0, 1, 2>; // CHECK: ClassTemplateSpecializationDecl{{.*}} class testPack - // CHECK: TemplateArgument{{.*}} integral 0 + // CHECK: TemplateArgument{{.*}} integral '0' // CHECK-NEXT: TemplateArgument{{.*}} pack - // CHECK-NEXT: TemplateArgument{{.*}} integral 1 - // CHECK-NEXT: TemplateArgument{{.*}} integral 2 + // CHECK-NEXT: TemplateArgument{{.*}} integral '1' + // CHECK-NEXT: TemplateArgument{{.*}} integral '2' } namespace testUsingDecl { diff --git a/clang/test/AST/ast-dump-openmp-begin-declare-variant_template_2.cpp b/clang/test/AST/ast-dump-openmp-begin-declare-variant_template_2.cpp index da46cef7f3f1b..6fe05e33a5fb8 100644 --- a/clang/test/AST/ast-dump-openmp-begin-declare-variant_template_2.cpp +++ b/clang/test/AST/ast-dump-openmp-begin-declare-variant_template_2.cpp @@ -79,7 +79,7 @@ int test() { // CHECK-NEXT: | | `-ReturnStmt [[ADDR_22:0x[a-z0-9]*]] // CHECK-NEXT: | | `-IntegerLiteral [[ADDR_23:0x[a-z0-9]*]] 'int' 0 // CHECK-NEXT: | `-FunctionDecl [[ADDR_24:0x[a-z0-9]*]] line:9:5 used also_before_mismatch 'int ({{.*}})' -// CHECK-NEXT: | |-TemplateArgument integral 0 +// CHECK-NEXT: | |-TemplateArgument integral '0' // CHECK-NEXT: | `-CompoundStmt [[ADDR_25:0x[a-z0-9]*]] // CHECK-NEXT: | `-ReturnStmt [[ADDR_26:0x[a-z0-9]*]] // CHECK-NEXT: | `-IntegerLiteral [[ADDR_23]] 'int' 0 @@ -179,7 +179,7 @@ int test() { // CHECK-NEXT: | | `-OMPDeclareVariantAttr [[ADDR_101:0x[a-z0-9]*]] <> Implicit implementation={extension(allow_templates)} // CHECK-NEXT: | | `-DeclRefExpr [[ADDR_102:0x[a-z0-9]*]] 'int ({{.*}})' {{.*}}Function [[ADDR_103:0x[a-z0-9]*]] 'only_def[implementation={extension(allow_templates)}]' 'int ({{.*}})' // CHECK-NEXT: | `-FunctionDecl [[ADDR_104:0x[a-z0-9]*]] col:5 used only_def 'int ({{.*}})' -// CHECK-NEXT: | |-TemplateArgument integral 0 +// CHECK-NEXT: | |-TemplateArgument integral '0' // CHECK-NEXT: | `-OMPDeclareVariantAttr [[ADDR_105:0x[a-z0-9]*]] <> Implicit implementation={extension(allow_templates)} // CHECK-NEXT: | `-DeclRefExpr [[ADDR_106:0x[a-z0-9]*]] 'int ({{.*}})' {{.*}}Function [[ADDR_107:0x[a-z0-9]*]] 'only_def[implementation={extension(allow_templates)}]' 'int ({{.*}})' // CHECK-NEXT: |-FunctionTemplateDecl [[ADDR_108:0x[a-z0-9]*]] line:38:1 only_def[implementation={extension(allow_templates)}] @@ -189,7 +189,7 @@ int test() { // CHECK-NEXT: | | `-ReturnStmt [[ADDR_110:0x[a-z0-9]*]] // CHECK-NEXT: | | `-IntegerLiteral [[ADDR_111:0x[a-z0-9]*]] 'int' 0 // CHECK-NEXT: | `-FunctionDecl [[ADDR_107]] line:38:1 only_def[implementation={extension(allow_templates)}] 'int ({{.*}})' -// CHECK-NEXT: | |-TemplateArgument integral 0 +// CHECK-NEXT: | |-TemplateArgument integral '0' // CHECK-NEXT: | `-CompoundStmt [[ADDR_112:0x[a-z0-9]*]] // CHECK-NEXT: | `-ReturnStmt [[ADDR_113:0x[a-z0-9]*]] // CHECK-NEXT: | `-IntegerLiteral [[ADDR_111]] 'int' 0 diff --git a/clang/test/AST/ast-dump-template-name.cpp b/clang/test/AST/ast-dump-template-name.cpp new file mode 100644 index 0000000000000..39100711b60a1 --- /dev/null +++ b/clang/test/AST/ast-dump-template-name.cpp @@ -0,0 +1,54 @@ +// RUN: %clang_cc1 -std=c++26 -ast-dump -ast-dump-filter=Test %s | FileCheck %s + +template