Skip to content

[clang] improve print / dump of anonymous declarations #124605

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 28, 2025

Conversation

mizvekov
Copy link
Contributor

@mizvekov mizvekov commented Jan 27, 2025

ast-print: A DeclRef to an anonymous NTTP will print 'value-parameter-DEPTH-INDEX',
similar to how type parameters are printed.

ast-dump: A bareDeclRef to an anonymous entity will print some extra identifying information,
instead of an empty name, like indexes.
Falls back to source locations if nothing else is available.

@mizvekov mizvekov self-assigned this Jan 27, 2025
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:modules C++20 modules and Clang Header Modules HLSL HLSL Language Support labels Jan 27, 2025
@llvmbot
Copy link
Member

llvmbot commented Jan 27, 2025

@llvm/pr-subscribers-clang
@llvm/pr-subscribers-clang-modules

@llvm/pr-subscribers-hlsl

Author: Matheus Izvekov (mizvekov)

Changes

ast-print: A DeclRef to an anonymous NTTP will print 'value-parameter-<Depth>-<Index>',
similar to how type parameters are printed.

ast-dump: A bareDeclRef to an anonymous entity will print some extra identifying information,
instead of an empty name, like indexes.
Falls back to source locations if nothing else is available.


Patch is 66.90 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/124605.diff

20 Files Affected:

  • (modified) clang/lib/AST/StmtPrinter.cpp (+23-9)
  • (modified) clang/lib/AST/TextNodeDumper.cpp (+35-1)
  • (modified) clang/test/AST/HLSL/StructuredBuffers-AST.hlsl (+222-222)
  • (modified) clang/test/AST/HLSL/TypedBuffers-AST.hlsl (+2-2)
  • (modified) clang/test/AST/ast-dump-decl.c (+1-1)
  • (modified) clang/test/AST/ast-dump-records.c (+8-8)
  • (modified) clang/test/AST/ast-dump-records.cpp (+8-8)
  • (modified) clang/test/AST/attr-counted-by-late-parsed-struct-ptrs.c (+1-1)
  • (modified) clang/test/AST/attr-counted-by-or-null-late-parsed-struct-ptrs.c (+1-1)
  • (modified) clang/test/AST/attr-counted-by-or-null-struct-ptrs.c (+3-3)
  • (modified) clang/test/AST/attr-counted-by-struct-ptrs.c (+3-3)
  • (modified) clang/test/AST/attr-sized-by-late-parsed-struct-ptrs.c (+1-1)
  • (modified) clang/test/AST/attr-sized-by-or-null-late-parsed-struct-ptrs.c (+1-1)
  • (modified) clang/test/AST/attr-sized-by-or-null-struct-ptrs.c (+3-3)
  • (modified) clang/test/AST/attr-sized-by-struct-ptrs.c (+3-3)
  • (modified) clang/test/Import/cxx-anon-namespace/test.cpp (+4-4)
  • (modified) clang/test/Modules/odr_hash.cpp (+1-1)
  • (modified) clang/test/SemaTemplate/aggregate-deduction-candidate.cpp (+2-2)
  • (modified) clang/test/SemaTemplate/deduction-crash.cpp (+8-8)
  • (modified) clang/test/SemaTemplate/deduction-guide.cpp (+4-4)
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index b5def6fbe525c3..2db5e7936041b7 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -1257,11 +1257,12 @@ void StmtPrinter::VisitConstantExpr(ConstantExpr *Node) {
 }
 
 void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) {
-  if (const auto *OCED = dyn_cast<OMPCapturedExprDecl>(Node->getDecl())) {
+  ValueDecl *VD = Node->getDecl();
+  if (const auto *OCED = dyn_cast<OMPCapturedExprDecl>(VD)) {
     OCED->getInit()->IgnoreImpCasts()->printPretty(OS, nullptr, Policy);
     return;
   }
-  if (const auto *TPOD = dyn_cast<TemplateParamObjectDecl>(Node->getDecl())) {
+  if (const auto *TPOD = dyn_cast<TemplateParamObjectDecl>(VD)) {
     TPOD->printAsExpr(OS, Policy);
     return;
   }
@@ -1269,16 +1270,29 @@ void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) {
     Qualifier->print(OS, Policy);
   if (Node->hasTemplateKeyword())
     OS << "template ";
-  if (Policy.CleanUglifiedParameters &&
-      isa<ParmVarDecl, NonTypeTemplateParmDecl>(Node->getDecl()) &&
-      Node->getDecl()->getIdentifier())
-    OS << Node->getDecl()->getIdentifier()->deuglifiedName();
-  else
-    Node->getNameInfo().printName(OS, Policy);
+  DeclarationNameInfo NameInfo = Node->getNameInfo();
+  if (IdentifierInfo *ID = NameInfo.getName().getAsIdentifierInfo();
+      ID || NameInfo.getName().getNameKind() != DeclarationName::Identifier) {
+    if (Policy.CleanUglifiedParameters &&
+        isa<ParmVarDecl, NonTypeTemplateParmDecl>(VD) && ID)
+      OS << ID->deuglifiedName();
+    else
+      NameInfo.printName(OS, Policy);
+  } else {
+    switch (VD->getKind()) {
+    case Decl::NonTypeTemplateParm: {
+      auto *TD = cast<NonTypeTemplateParmDecl>(VD);
+      OS << "value-parameter-" << TD->getDepth() << '-' << TD->getIndex() << "";
+      break;
+    }
+    default:
+      llvm_unreachable("Unhandled anonymous declaration kind");
+    }
+  }
   if (Node->hasExplicitTemplateArgs()) {
     const TemplateParameterList *TPL = nullptr;
     if (!Node->hadMultipleCandidates())
-      if (auto *TD = dyn_cast<TemplateDecl>(Node->getDecl()))
+      if (auto *TD = dyn_cast<TemplateDecl>(VD))
         TPL = TD->getTemplateParameters();
     printTemplateArgumentList(OS, Node->template_arguments(), Policy, TPL);
   }
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index 670641242cae2f..f5e40ff6db9eff 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -875,7 +875,41 @@ void TextNodeDumper::dumpBareDeclRef(const Decl *D) {
 
   if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
     ColorScope Color(OS, ShowColors, DeclNameColor);
-    OS << " '" << ND->getDeclName() << '\'';
+    if (DeclarationName Name = ND->getDeclName())
+      OS << " '" << Name << '\'';
+    else
+      switch (ND->getKind()) {
+      case Decl::Decomposition: {
+        auto *DD = cast<DecompositionDecl>(ND);
+        OS << " first_binding '" << DD->bindings()[0]->getDeclName() << '\'';
+        break;
+      }
+      case Decl::Field: {
+        auto *FD = cast<FieldDecl>(ND);
+        OS << " index " << FD->getFieldIndex();
+        break;
+      }
+      case Decl::ParmVar: {
+        auto *PD = cast<ParmVarDecl>(ND);
+        OS << " depth " << PD->getFunctionScopeDepth() << " index "
+           << PD->getFunctionScopeIndex();
+        break;
+      }
+      case Decl::TemplateTypeParm: {
+        auto *TD = cast<TemplateTypeParmDecl>(ND);
+        OS << " depth " << TD->getDepth() << " index " << TD->getIndex();
+        break;
+      }
+      case Decl::NonTypeTemplateParm: {
+        auto *TD = cast<NonTypeTemplateParmDecl>(ND);
+        OS << " depth " << TD->getDepth() << " index " << TD->getIndex();
+        break;
+      }
+      default:
+        // Var, Namespace, (CXX)Record: Nothing else besides source location.
+        dumpSourceRange(ND->getSourceRange());
+        break;
+      }
   }
 
   if (const ValueDecl *VD = dyn_cast<ValueDecl>(D))
diff --git a/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl b/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl
index db3f2d405e686e..11be67d45a14c2 100644
--- a/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl
+++ b/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl
@@ -1,222 +1,222 @@
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump -DEMPTY \
-// RUN:  -DRESOURCE=StructuredBuffer %s | FileCheck -DRESOURCE=StructuredBuffer \
-// RUN:  -check-prefix=EMPTY %s
-//
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump \
-// RUN:   -DRESOURCE=StructuredBuffer %s | FileCheck -DRESOURCE=StructuredBuffer \
-// RUN:   -check-prefixes=CHECK,CHECK-SRV,CHECK-SUBSCRIPT,CHECK-LOAD %s
-//
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump -DEMPTY \
-// RUN:  -DRESOURCE=RWStructuredBuffer %s | FileCheck -DRESOURCE=RWStructuredBuffer \
-// RUN:  -check-prefix=EMPTY %s
-//
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump \
-// RUN:   -DRESOURCE=RWStructuredBuffer %s | FileCheck -DRESOURCE=RWStructuredBuffer \
-// RUN:   -check-prefixes=CHECK,CHECK-UAV,CHECK-SUBSCRIPT,CHECK-COUNTER,CHECK-LOAD %s
-//
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump -DEMPTY \
-// RUN:  -DRESOURCE=AppendStructuredBuffer %s | FileCheck -DRESOURCE=AppendStructuredBuffer \
-// RUN:  -check-prefix=EMPTY %s
-//
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump \
-// RUN:   -DRESOURCE=AppendStructuredBuffer %s | FileCheck -DRESOURCE=AppendStructuredBuffer \
-// RUN:   -check-prefixes=CHECK,CHECK-UAV,CHECK-NOSUBSCRIPT,CHECK-APPEND %s
-//
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump -DEMPTY \
-// RUN:  -DRESOURCE=ConsumeStructuredBuffer %s | FileCheck -DRESOURCE=ConsumeStructuredBuffer \
-// RUN:  -check-prefix=EMPTY %s
-//
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump \
-// RUN:   -DRESOURCE=ConsumeStructuredBuffer %s | FileCheck -DRESOURCE=ConsumeStructuredBuffer \
-// RUN:   -check-prefixes=CHECK,CHECK-UAV,CHECK-NOSUBSCRIPT,CHECK-CONSUME %s
-//
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump -DEMPTY \
-// RUN:  -DRESOURCE=RasterizerOrderedStructuredBuffer %s | FileCheck -DRESOURCE=RasterizerOrderedStructuredBuffer \
-// RUN:  -check-prefix=EMPTY %s
-//
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump \
-// RUN:   -DRESOURCE=RasterizerOrderedStructuredBuffer %s | FileCheck -DRESOURCE=RasterizerOrderedStructuredBuffer \
-// RUN:   -check-prefixes=CHECK,CHECK-UAV,CHECK-ROV,CHECK-SUBSCRIPT,CHECK-LOAD %s
-
-// This test tests two different AST generations for each structured buffer.
-// The "EMPTY" test mode verifies the AST generated by forward declaration
-// of the HLSL types which happens on initializing the HLSL external AST with
-// an AST Context.
-
-// The non-empty mode has a use that requires the resource type be complete,
-// which results in the AST being populated by the external AST source. That
-// case covers the full implementation of the template declaration and the
-// instantiated specialization.
-
-// EMPTY: ClassTemplateDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit [[RESOURCE]]
-// EMPTY-NEXT: TemplateTypeParmDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> typename depth 0 index 0 element_type
-// EMPTY-NEXT: ConceptSpecializationExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'bool' Concept 0x{{[0-9A-Fa-f]+}} '__is_structured_resource_element_compatible'
-// EMPTY-NEXT: ImplicitConceptSpecializationDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc>
-// EMPTY-NEXT: TemplateArgument type 'type-parameter-0-0'
-// EMPTY-NEXT: TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'type-parameter-0-0' dependent depth 0 index 0
-// EMPTY-NEXT: TemplateTypeParm 0x{{[0-9A-Fa-f]+}} ''
-// EMPTY-NEXT: TemplateArgument type 'element_type':'type-parameter-0-0'
-// EMPTY-NEXT: TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'element_type' dependent depth 0 index 0
-// EMPTY-NEXT: TemplateTypeParm 0x{{[0-9A-Fa-f]+}} 'element_type'
-// EMPTY-NEXT: CXXRecordDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit <undeserialized declarations> class [[RESOURCE]]
-// EMPTY-NEXT: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final
-
-// There should be no more occurrences of [[RESOURCE]]
-// EMPTY-NOT: {{[^[:alnum:]]}}[[RESOURCE]]
-
-#ifndef EMPTY
-
-RESOURCE<float> Buffer;
-
-#endif
-
-// CHECK: ClassTemplateDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit [[RESOURCE]]
-// CHECK-NEXT: TemplateTypeParmDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> typename depth 0 index 0 element_type
-// CHECK-NEXT: ConceptSpecializationExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'bool' Concept 0x{{[0-9A-Fa-f]+}} '__is_structured_resource_element_compatible'
-// CHECK-NEXT: ImplicitConceptSpecializationDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc>
-// CHECK-NEXT: TemplateArgument type 'type-parameter-0-0'
-// CHECK-NEXT: TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'type-parameter-0-0' dependent depth 0 index 0
-// CHECK-NEXT: TemplateTypeParm 0x{{[0-9A-Fa-f]+}} ''
-// CHECK-NEXT: TemplateArgument type 'element_type':'type-parameter-0-0'
-// CHECK-NEXT: TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'element_type' dependent depth 0 index 0
-// CHECK-NEXT: TemplateTypeParm 0x{{[0-9A-Fa-f]+}} 'element_type'
-// CHECK-NEXT: CXXRecordDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit class [[RESOURCE]] definition
-
-// CHECK: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final
-// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit __handle '__hlsl_resource_t
-// CHECK-SRV-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
-// CHECK-UAV-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
-// CHECK-SAME{LITERAL}: [[hlsl::raw_buffer]]
-// CHECK-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
-// CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit RawBuffer
-
-// CHECK-SUBSCRIPT: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> operator[] 'const element_type &(unsigned int) const'
-// CHECK-SUBSCRIPT-NEXT: ParmVarDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> Index 'unsigned int'
-// CHECK-SUBSCRIPT-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
-// CHECK-SUBSCRIPT-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
-// CHECK-SUBSCRIPT-NEXT: UnaryOperator 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' prefix '*' cannot overflow
-// CHECK-SUBSCRIPT-NEXT: CallExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type *'
-// CHECK-SUBSCRIPT-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '<builtin fn type>' Function 0x{{[0-9A-Fa-f]+}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
-// CHECK-SUBSCRIPT-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '__hlsl_resource_t
-// CHECK-SUBSCRIPT-SAME{LITERAL}: [[hlsl::resource_class(
-// CHECK-SUBSCRIPT-SAME{LITERAL}: [[hlsl::raw_buffer]]
-// CHECK-SUBSCRIPT-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
-// CHECK-SUBSCRIPT-SAME: ' lvalue .__handle 0x{{[0-9A-Fa-f]+}}
-// CHECK-SUBSCRIPT-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'const [[RESOURCE]]<element_type>' lvalue implicit this
-// CHECK-SUBSCRIPT-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'unsigned int' ParmVar 0x{{[0-9A-Fa-f]+}} 'Index' 'unsigned int'
-// CHECK-SUBSCRIPT-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit always_inline
-
-// CHECK-SUBSCRIPT-NEXT: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> operator[] 'element_type &(unsigned int)'
-// CHECK-SUBSCRIPT-NEXT: ParmVarDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> Index 'unsigned int'
-// CHECK-SUBSCRIPT-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
-// CHECK-SUBSCRIPT-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
-// CHECK-SUBSCRIPT-NEXT: UnaryOperator 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' prefix '*' cannot overflow
-// CHECK-SUBSCRIPT-NEXT: CallExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type *'
-// CHECK-SUBSCRIPT-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '<builtin fn type>' Function 0x{{[0-9A-Fa-f]+}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
-// CHECK-SUBSCRIPT-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '__hlsl_resource_t
-// CHECK-SUBSCRIPT-SAME{LITERAL}: [[hlsl::resource_class(
-// CHECK-SUBSCRIPT-SAME{LITERAL}: [[hlsl::raw_buffer]]
-// CHECK-SUBSCRIPT-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
-// CHECK-SUBSCRIPT-SAME: ' lvalue .__handle 0x{{[0-9A-Fa-f]+}}
-// CHECK-SUBSCRIPT-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '[[RESOURCE]]<element_type>' lvalue implicit this
-// CHECK-SUBSCRIPT-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'unsigned int' ParmVar 0x{{[0-9A-Fa-f]+}} 'Index' 'unsigned int'
-// CHECK-SUBSCRIPT-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit always_inline
-
-// CHECK-NOSUBSCRIPT-NOT: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> operator[] 'const element_type &(unsigned int) const'
-// CHECK-NOSUBSCRIPT-NOT: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> operator[] 'element_type &(unsigned int)'
-
-// CHECK-LOAD: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> Load 'element_type (unsigned int)'
-// CHECK-LOAD-NEXT: ParmVarDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> Index 'unsigned int'
-// CHECK-LOAD-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
-// CHECK-LOAD-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
-// CHECK-LOAD-NEXT: UnaryOperator 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' prefix '*' cannot overflow
-// CHECK-LOAD-NEXT: CallExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type *'
-// CHECK-LOAD-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '<builtin fn type>' Function 0x{{[0-9A-Fa-f]+}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
-// CHECK-LOAD-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '__hlsl_resource_t
-// CHECK-LOAD-SAME{LITERAL}: [[hlsl::resource_class(
-// CHECK-LOAD-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
-// CHECK-LOAD-SAME: ' lvalue .__handle 0x{{[0-9A-Fa-f]+}}
-// CHECK-LOAD-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '[[RESOURCE]]<element_type>' lvalue implicit this
-// CHECK-LOAD-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'unsigned int' ParmVar 0x{{[0-9A-Fa-f]+}} 'Index' 'unsigned int'
-// CHECK-LOAD-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit always_inline
-
-// CHECK-COUNTER: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> IncrementCounter 'unsigned int ()'
-// CHECK-COUNTER-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
-// CHECK-COUNTER-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
-// CHECK-COUNTER-NEXT: CallExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'unsigned int'
-// CHECK-COUNTER-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '<builtin fn type>' Function 0x{{[0-9A-Fa-f]+}} '__builtin_hlsl_buffer_update_counter' 'unsigned int (...) noexcept'
-// CHECK-COUNTER-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '__hlsl_resource_t
-// CHECK-COUNTER-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
-// CHECK-COUNTER-SAME{LITERAL}: [[hlsl::raw_buffer]]
-// CHECK-COUNTER-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]' lvalue .__handle
-// CHECK-COUNTER-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'RWStructuredBuffer<element_type>' lvalue implicit this
-// CHECK-COUNTER-NEXT: IntegerLiteral 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'int' 1
-// CHECK-COUNTER-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit always_inline
-
-// CHECK-COUNTER-NEXT: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> DecrementCounter 'unsigned int ()'
-// CHECK-COUNTER-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
-// CHECK-COUNTER-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
-// CHECK-COUNTER-NEXT: CallExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'unsigned int'
-// CHECK-COUNTER-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '<builtin fn type>' Function 0x{{[0-9A-Fa-f]+}} '__builtin_hlsl_buffer_update_counter' 'unsigned int (...) noexcept'
-// CHECK-COUNTER-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '__hlsl_resource_t
-// CHECK-COUNTER-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
-// CHECK-COUNTER-SAME{LITERAL}: [[hlsl::raw_buffer]]
-// CHECK-COUNTER-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]' lvalue .__handle
-// CHECK-COUNTER-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'RWStructuredBuffer<element_type>' lvalue implicit this
-// CHECK-COUNTER-NEXT: IntegerLiteral 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'int' -1
-// CHECK-COUNTER-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit always_inline
-
-// CHECK-APPEND: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> Append 'void (element_type)'
-// CHECK-APPEND-NEXT: ParmVarDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> value 'element_type'
-// CHECK-APPEND-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
-// CHECK-APPEND-NEXT: BinaryOperator 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' '='
-// CHECK-APPEND-NEXT: UnaryOperator 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' prefix '*' cannot overflow
-// CHECK-APPEND-NEXT: CallExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type *'
-// CHECK-APPEND-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '<builtin fn type>' Function 0x{{[0-9A-Fa-f]+}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
-// CHECK-APPEND-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '__hlsl_resource_t
-// CHECK-APPEND-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
-// CHECK-APPEND-SAME{LITERAL}: [[hlsl::raw_buffer]]
-// CHECK-APPEND-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]' lvalue .__handle
-// CHECK-APPEND-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '[[RESOURCE]]<element_type>' lvalue implicit this
-// CHECK-APPEND-NEXT: CallExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'unsigned int'
-// CHECK-APPEND-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '<builtin fn type>' Function 0x{{[0-9A-Fa-f]+}} '__builtin_hlsl_buffer_update_counter' 'unsigned int (...) noexcept'
-// CHECK-APPEND-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '__hlsl_resource_t
-// CHECK-APPEND-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
-// CHECK-APPEND-SAME{LITERAL}: [[hlsl::raw_buffer]]
-// CHECK-APPEND-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]' lvalue .__handle
-// CHECK-APPEND-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '[[RESOURCE]]<element_type>' lvalue implicit this
-// CHECK-APPEND-NEXT: IntegerLiteral 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'int' 1
-// CHECK-APPEND-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' ParmVar 0x{{[0-9A-Fa-f]+}} 'value' 'element_type'
-
-// CHECK-CONSUME: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> Consume 'element_type ()'
-// CHECK-CONSUME-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
-// CHECK-CONSUME-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
-// CHECK-CONSUME-NEXT: UnaryOperator 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' prefix '*' cannot overflow
-// CHECK-CONSUME-NEXT: CallExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type *'
-// CHECK-CONSUME-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '<builtin fn type>' Function 0x{{[0-9A-Fa-f]+}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
-// CHECK-CONSUME-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '__hlsl_resource_t
-// CHECK-CONSUME-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
-// CHECK-CONSUME-SAME{LITERAL}: [[hlsl::raw_buffer]]
-// CHECK-CONSUME-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]' lvalue .__handle
-// CHECK-CONSUME-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '[[RESOURCE]]<element_type>' lvalue implicit this
-// CHECK-CONSUME-NEXT: CallExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'unsigned int'...
[truncated]

ast-print: A DeclRef to an anonymous NTTP will print
'value-parameter-<Depth>-<Index>', similar to how we print type
parameters.

ast-dump: A bareDeclRef to an anonymous entity will print some extra
identifying information, instead of an empty name, like indexes.
Falls back to source locations if nothing else is available.
@mizvekov mizvekov force-pushed the users/mizvekov/clang-dump-print-anonymous-declarations branch from c86ebb0 to b83292d Compare January 27, 2025 19:17
@mizvekov mizvekov merged commit f949f87 into main Jan 28, 2025
8 checks passed
@mizvekov mizvekov deleted the users/mizvekov/clang-dump-print-anonymous-declarations branch January 28, 2025 00:36
@gribozavr
Copy link
Collaborator

@mizvekov It looks like this PR introduces a crash, I'm going to revert it. Here is a reproducer:

$ cat parser_test-42bc8e.cpp
enum a : char;
class b {
public:
  static b c;
  friend bool operator==(b, b) = default;
  a d;
};
void e() {
  b f;
  f == b::c;
}
$ clang  "-cc1" "-triple" "x86_64-grtev4-linux-gnu" "-std=gnu++20"  "-x" "c++" -analyze  -analyzer-checker=debug.DumpCFG parser_test-42bc8e.cpp
parser_test-42bc8e.cpp:10:5: warning: equality comparison result unused [-Wunused-comparison]
   10 |   f == b::c;
      |   ~~^~~~~~~
bool operator==(b, b) noexcept = default
 [B2 (ENTRY)]
   Succs (1): B1

 [B1]
   1: Unhandled anonymous declaration kind
UNREACHABLE executed at [redacted]/llvm-project/clang/lib/AST/StmtPrinter.cpp:1289!
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script.
Stack dump:
0.      Program arguments: [redacted]/bin/clang -cc1 -triple x86_64-grtev4-linux-gnu -std=gnu++20 -x c++ -analyze -analyzer-checker=debug.DumpCFG parser_test-42bc8e.cpp
1.      <eof> parser at end of file
 #0 0x000055f6a75d30c8 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) ([redacted]/bin/clang+0x3e1d0c8)
 #1 0x000055f6a75d0c7e llvm::sys::RunSignalHandlers() ([redacted]/bin/clang+0x3e1ac7e)
 #2 0x000055f6a75d3758 SignalHandler(int) Signals.cpp:0:0
 #3 0x00007fcab9e56590 (/lib/x86_64-linux-gnu/libc.so.6+0x3f590)
 #4 0x00007fcab9ea53ac __pthread_kill_implementation ./nptl/pthread_kill.c:44:76
 #5 0x00007fcab9e564f2 raise ./signal/../sysdeps/posix/raise.c:27:6
 #6 0x00007fcab9e3f4ed abort ./stdlib/abort.c:81:7
 #7 0x000055f6a754a360 llvm::install_out_of_memory_new_handler() ([redacted]/bin/clang+0x3d94360)
 #8 0x000055f6aaadd675 ([redacted]/bin/clang+0x7327675)
 #9 0x000055f6aaad49ec clang::Stmt::printPretty(llvm::raw_ostream&, clang::PrinterHelper*, clang::PrintingPolicy const&, unsigned int, llvm::StringRef, clang::ASTContext const*) const ([redacted]/bin/clang
+0x731e9ec)
#10 0x000055f6aa31d7b7 print_elem(llvm::raw_ostream&, (anonymous namespace)::StmtPrinterHelper&, clang::CFGElement const&) CFG.cpp:0:0
#11 0x000055f6aa31f641 print_block(llvm::raw_ostream&, clang::CFG const*, clang::CFGBlock const&, (anonymous namespace)::StmtPrinterHelper&, bool, bool) CFG.cpp:0:0
#12 0x000055f6aa31ebaf clang::CFG::print(llvm::raw_ostream&, clang::LangOptions const&, bool) const ([redacted]/bin/clang+0x6b68baf)
#13 0x000055f6a94d7b01 void clang::ento::check::ASTCodeBody::_checkBody<(anonymous namespace)::CFGDumper>(void*, clang::Decl const*, clang::ento::AnalysisManager&, clang::ento::BugReporter&) DebugCheckers.cpp:0:0
#14 0x000055f6a96dbda1 clang::ento::CheckerManager::runCheckersOnASTBody(clang::Decl const*, clang::ento::AnalysisManager&, clang::ento::BugReporter&) ([redacted]/bin/clang+0x5f25da1)
#15 0x000055f6a9441fa1 (anonymous namespace)::AnalysisConsumer::HandleCode(clang::Decl*, unsigned int, clang::ento::ExprEngine::InliningModes, llvm::DenseSet<clang::Decl const*, llvm::DenseMapInfo<clang::Decl const*, void>>*) AnalysisConsumer.cp
p:0:0
#16 0x000055f6a943f860 (anonymous namespace)::AnalysisConsumer::VisitFunctionDecl(clang::FunctionDecl*) AnalysisConsumer.cpp:0:0
#17 0x000055f6a943fd9a non-virtual thunk to (anonymous namespace)::AnalysisConsumer::VisitFunctionDecl(clang::FunctionDecl*) AnalysisConsumer.cpp:0:0
#18 0x000055f6aa73a9b6 clang::DynamicRecursiveASTVisitor::TraverseFunctionDecl(clang::FunctionDecl*) ([redacted]/bin/clang+0x6f849b6)
#19 0x000055f6aa734fe7 clang::DynamicRecursiveASTVisitor::TraverseDecl(clang::Decl*) ([redacted]/bin/clang+0x6f7efe7)
#20 0x000055f6aa741ba0 clang::DynamicRecursiveASTVisitor::TraverseFriendDecl(clang::FriendDecl*) ([redacted]/bin/clang+0x6f8bba0)
#21 0x000055f6aa735340 clang::DynamicRecursiveASTVisitor::TraverseDecl(clang::Decl*) ([redacted]/bin/clang+0x6f7f340)
#22 0x000055f6aa73e138 clang::DynamicRecursiveASTVisitor::TraverseCXXRecordDecl(clang::CXXRecordDecl*) ([redacted]/bin/clang+0x6f88138)
#23 0x000055f6aa735205 clang::DynamicRecursiveASTVisitor::TraverseDecl(clang::Decl*) ([redacted]/bin/clang+0x6f7f205)
#24 0x000055f6a943e408 (anonymous namespace)::AnalysisConsumer::HandleTranslationUnit(clang::ASTContext&) AnalysisConsumer.cpp:0:0
#25 0x000055f6a9814bb9 clang::ParseAST(clang::Sema&, bool, bool) ([redacted]/bin/clang+0x605ebb9)
#26 0x000055f6a805ed36 clang::FrontendAction::Execute() ([redacted]/bin/clang+0x48a8d36)
#27 0x000055f6a7fcbe3d clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) ([redacted]/bin/clang+0x4815e3d)
#28 0x000055f6a8145ae7 clang::ExecuteCompilerInvocation(clang::CompilerInstance*) ([redacted]/bin/clang+0x498fae7)
#29 0x000055f6a4c88f6a cc1_main(llvm::ArrayRef<char const*>, char const*, void*) ([redacted]/bin/clang+0x14d2f6a)
#30 0x000055f6a4c854ce ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&, llvm::ToolContext const&) driver.cpp:0:0
#31 0x000055f6a4c844e6 clang_main(int, char**, llvm::ToolContext const&) ([redacted]/bin/clang+0x14ce4e6)
#32 0x000055f6a4c947b7 main ([redacted]/bin/clang+0x14de7b7)
#33 0x00007fcab9e40c8a __libc_start_call_main ./csu/../sysdeps/nptl/libc_start_call_main.h:74:3
#34 0x00007fcab9e40d45 call_init ./csu/../csu/libc-start.c:128:20
#35 0x00007fcab9e40d45 __libc_start_main ./csu/../csu/libc-start.c:347:5
#36 0x000055f6a4c83031 _start ([redacted]/bin/clang+0x14cd031)
Aborted

gribozavr added a commit that referenced this pull request Jan 28, 2025
…)"

This reverts commit f949f87.

This commit introduces an llvm_unreachable call that is actually
reachable. I posted a reproducer on the pull request discussion.
@gribozavr
Copy link
Collaborator

I reverted this PR in e38f4f6.

OS << "value-parameter-" << TD->getDepth() << '-' << TD->getIndex() << "";
break;
}
default:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The crash observed happens here. VD->getKind() is Decl::ParmVar. I wonder if this, for defensive purposes, should at least handle all of the kinds in the TextNodeDumper.

@erichkeane
Copy link
Collaborator

f == b::c;
}
$ clang "-cc1" "-triple" "x86_64-grtev4-linux-gnu" "-std=gnu++20" "-x" "c++" -analyze -analyzer-checker=debug.DumpCFG parser_test-42bc8e.cpp
parser_test-42bc8e.cpp:10:5: warning: equality comparison result unused [-Wunused-comparison]
10 | f == b::c;

Hmm... This only repro's in the CFG printer (that is, AST-Print and AST-Dump have no problem with this).

This happens when doing a printPretty call to the StmtPrinter with expression: DeclRefExpr 0x159c2030 'b':'class b' lvalue ParmVar 0x159a0308 depth 0 index 0 'b':'class b'

So it is failing on the new 1289 in StmtPrinter.cpp, since it is trying to refer to an unnamed ParmVar. IMO, we should probably make sure that TextNodeDumper there is handling all of the decls we do elsewhere.

@mizvekov
Copy link
Contributor Author

The test case provided shows a bug in the original implementation of the analyzer anyway.

Here is the clang output for the slightly reduced repro:

struct A {
  static A a;
  char b;
  friend bool operator==(A, A) = default;
};
bool _ = A() == A::a;

Original clang outputs:

bool operator==(A, A) noexcept = default
 [B2 (ENTRY)]
   Succs (1): B1

 [B1]
   1: 
   2: [B1.1].b
   3: [B1.2] (ImplicitCastExpr, LValueToRValue, char)
   4: [B1.3] (ImplicitCastExpr, IntegralCast, int)
   5: 
   6: [B1.5].b
   7: [B1.6] (ImplicitCastExpr, LValueToRValue, char)
   8: [B1.7] (ImplicitCastExpr, IntegralCast, int)
   9: [B1.4] == [B1.8]
  10: return [B1.9];
   Preds (1): B2
   Succs (1): B0

 [B0 (EXIT)]
   Preds (1): B1

Notice how steps 1 and 5 are empty.

After my next changes to this patch, here is how it will print:

bool operator==(A, A) noexcept = default
 [B2 (ENTRY)]
   Succs (1): B1

 [B1]
   1: function-parameter-0-0
   2: [B1.1].b
   3: [B1.2] (ImplicitCastExpr, LValueToRValue, char)
   4: [B1.3] (ImplicitCastExpr, IntegralCast, int)
   5: function-parameter-0-1
   6: [B1.5].b
   7: [B1.6] (ImplicitCastExpr, LValueToRValue, char)
   8: [B1.7] (ImplicitCastExpr, IntegralCast, int)
   9: [B1.4] == [B1.8]
  10: return [B1.9];
   Preds (1): B2
   Succs (1): B0

 [B0 (EXIT)]
   Preds (1): B1

At least it will print the parameter depth and indexes, but this still should be fixed in the analyzer somehow.

I still think leaving the assert was the right call, it led us to finding bugs as expected :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:modules C++20 modules and Clang Header Modules clang Clang issues not falling into any other category HLSL HLSL Language Support
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants