[clang] [clang] Instantiate attributes on LabelDecls (PR #115924)

Eric Astor via cfe-commits cfe-commits at lists.llvm.org
Fri Nov 15 09:33:20 PST 2024


https://github.com/ericastor updated https://github.com/llvm/llvm-project/pull/115924

>From da2e66a6a2636bf1a1ab2e25afdbd29095b6db3f Mon Sep 17 00:00:00 2001
From: Eric Astor <epastor at google.com>
Date: Tue, 12 Nov 2024 17:37:42 +0000
Subject: [PATCH 1/8] [clang] Instantiate attributes on other decl types

Start propagating attributes on (e.g.) labels inside of templated functions to their instances.
---
 clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 16 +++++++++++++---
 clang/test/SemaCXX/attr-mode-tmpl.cpp          |  4 ++--
 2 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 5a001843e2ba46..bfc5913dbafd0f 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -990,6 +990,7 @@ Decl *
 TemplateDeclInstantiator::VisitLabelDecl(LabelDecl *D) {
   LabelDecl *Inst = LabelDecl::Create(SemaRef.Context, Owner, D->getLocation(),
                                       D->getIdentifier());
+  SemaRef.InstantiateAttrs(TemplateArgs, D, Inst, LateAttrs, StartingScope);
   Owner->addDecl(Inst);
   return Inst;
 }
@@ -1009,6 +1010,7 @@ TemplateDeclInstantiator::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
                                  D->getQualifierLoc(),
                                  D->getTargetNameLoc(),
                                  D->getNamespace());
+  SemaRef.InstantiateAttrs(TemplateArgs, D, Inst, LateAttrs, StartingScope);
   Owner->addDecl(Inst);
   return Inst;
 }
@@ -1095,15 +1097,21 @@ Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D,
 
 Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
   Decl *Typedef = InstantiateTypedefNameDecl(D, /*IsTypeAlias=*/false);
-  if (Typedef)
+  if (Typedef) {
+    SemaRef.InstantiateAttrs(TemplateArgs, D, Typedef, LateAttrs,
+                             StartingScope);
     Owner->addDecl(Typedef);
+  }
   return Typedef;
 }
 
 Decl *TemplateDeclInstantiator::VisitTypeAliasDecl(TypeAliasDecl *D) {
   Decl *Typedef = InstantiateTypedefNameDecl(D, /*IsTypeAlias=*/true);
-  if (Typedef)
+  if (Typedef) {
+    SemaRef.InstantiateAttrs(TemplateArgs, D, Typedef, LateAttrs,
+                             StartingScope);
     Owner->addDecl(Typedef);
+  }
   return Typedef;
 }
 
@@ -1160,8 +1168,10 @@ Decl *TemplateDeclInstantiator::InstantiateTypeAliasTemplateDecl(
 Decl *
 TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
   Decl *Inst = InstantiateTypeAliasTemplateDecl(D);
-  if (Inst)
+  if (Inst) {
+    SemaRef.InstantiateAttrs(TemplateArgs, D, Inst, LateAttrs, StartingScope);
     Owner->addDecl(Inst);
+  }
 
   return Inst;
 }
diff --git a/clang/test/SemaCXX/attr-mode-tmpl.cpp b/clang/test/SemaCXX/attr-mode-tmpl.cpp
index f665b1ba491237..58266f947051c5 100644
--- a/clang/test/SemaCXX/attr-mode-tmpl.cpp
+++ b/clang/test/SemaCXX/attr-mode-tmpl.cpp
@@ -9,7 +9,7 @@ void CheckEnumerations() {
   // Check that non-vector 'mode' attribute is OK with enumeration types.
   typedef T __attribute__((mode(QI))) T1;
   typedef T T2 __attribute__((mode(HI)));
-  typedef T __attribute__((mode(V8SI))) T3; // expected-error{{mode 'V8SI' is not supported for enumeration types}}
+  typedef T __attribute__((mode(V8SI))) T3; // expected-error2{{mode 'V8SI' is not supported for enumeration types}}
   // expected-warning at -1{{specifying vector types with the 'mode' attribute is deprecated}}
 
   typedef enum __attribute__((mode(HI))) { A4, B4 } T4;
@@ -62,7 +62,7 @@ struct TemplatedStruct {
 
   // Check typedefs.
   typedef T __attribute__((mode(DI)))   T1;
-  typedef T __attribute__((mode(V8DI))) T2;   // expected-error{{mode 'V8DI' is not supported for enumeration types}}
+  typedef T __attribute__((mode(V8DI))) T2;   // expected-error2{{mode 'V8DI' is not supported for enumeration types}}
                                               // expected-warning at -1{{deprecated}}
 
   // Check parameters.

>From eb4b3a2d1e25b9fc63048e5f2d71d62a3cbd2bde Mon Sep 17 00:00:00 2001
From: Eric Astor <epastor at google.com>
Date: Thu, 14 Nov 2024 19:24:45 +0000
Subject: [PATCH 2/8] Include attributes on LabelStmts (forwarding from decls)
 in AST dumps

We apply this to add a test of the new label attribute instantiation support.
---
 clang/examples/Attribute/Attribute.cpp     | 6 +++---
 clang/include/clang/AST/ASTNodeTraverser.h | 5 +++++
 clang/test/Frontend/plugin-attribute.cpp   | 8 ++++++++
 3 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/clang/examples/Attribute/Attribute.cpp b/clang/examples/Attribute/Attribute.cpp
index 3b90724ad22205..59446a15a6925d 100644
--- a/clang/examples/Attribute/Attribute.cpp
+++ b/clang/examples/Attribute/Attribute.cpp
@@ -41,9 +41,9 @@ struct ExampleAttrInfo : public ParsedAttrInfo {
   bool diagAppertainsToDecl(Sema &S, const ParsedAttr &Attr,
                             const Decl *D) const override {
     // This attribute appertains to functions only.
-    if (!isa<FunctionDecl>(D)) {
+    if (!isa<FunctionDecl>(D) && !isa<LabelDecl>(D)) {
       S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type_str)
-          << Attr << Attr.isRegularKeywordAttribute() << "functions";
+          << Attr << Attr.isRegularKeywordAttribute() << "functions or labels";
       return false;
     }
     return true;
@@ -52,7 +52,7 @@ struct ExampleAttrInfo : public ParsedAttrInfo {
   AttrHandling handleDeclAttribute(Sema &S, Decl *D,
                                    const ParsedAttr &Attr) const override {
     // Check if the decl is at file scope.
-    if (!D->getDeclContext()->isFileContext()) {
+    if (!D->getDeclContext()->isFileContext() && !isa<LabelDecl>(D)) {
       unsigned ID = S.getDiagnostics().getCustomDiagID(
           DiagnosticsEngine::Error,
           "'example' attribute only allowed at file scope");
diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h
index a443a88bab1f2d..876dcb647b27b4 100644
--- a/clang/include/clang/AST/ASTNodeTraverser.h
+++ b/clang/include/clang/AST/ASTNodeTraverser.h
@@ -800,6 +800,11 @@ class ASTNodeTraverser
       Visit(A);
   }
 
+  void VisitLabelStmt(const LabelStmt *Node) {
+    for (const auto *A : Node->getDecl()->getAttrs())
+      Visit(A);
+  }
+
   void VisitCXXCatchStmt(const CXXCatchStmt *Node) {
     Visit(Node->getExceptionDecl());
   }
diff --git a/clang/test/Frontend/plugin-attribute.cpp b/clang/test/Frontend/plugin-attribute.cpp
index 094ce9f5cbb85f..943ae3f95178d5 100644
--- a/clang/test/Frontend/plugin-attribute.cpp
+++ b/clang/test/Frontend/plugin-attribute.cpp
@@ -18,6 +18,9 @@ void fn2() __attribute__((example("somestring", 1, 2.0))) {
 }
 template <int N> void template_fn() __attribute__((example("template", N))) {
   __attribute__((example("def", N + 1))) for (int i = 0; i < 9; ++i) {}
+  __attribute__((example("ghi", N + 2)))
+label1:
+  for (int i = 0; i < 9; ++i) {}
 }
 void fn3() { template_fn<5>(); }
 // CHECK: -AttributedStmt 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}}
@@ -44,6 +47,11 @@ void fn3() { template_fn<5>(); }
 // CHECK: -IntegerLiteral 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}} 'int' 5
 // CHECK: -IntegerLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'int' 1
 // CHECK: -AnnotateAttr 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}} "example"
+// CHECK: -StringLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'const char[{{[0-9]+}}]' lvalue "ghi"
+// CHECK: -BinaryOperator 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'int' '+'
+// CHECK: -IntegerLiteral 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}} 'int' 5
+// CHECK: -IntegerLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'int' 2
+// CHECK: -AnnotateAttr 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}} "example"
 // CHECK: -StringLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'const char[{{[0-9]+}}]' lvalue "template"
 // CHECK: -IntegerLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'int' 5
 

>From 6ba54c4760f943402d3ae47282ebd1502e59afb9 Mon Sep 17 00:00:00 2001
From: Eric Astor <epastor at google.com>
Date: Thu, 14 Nov 2024 19:37:39 +0000
Subject: [PATCH 3/8] Scope this change back to just applying to LabelDecls

---
 clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 15 +++------------
 1 file changed, 3 insertions(+), 12 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index bfc5913dbafd0f..4529eb99377e78 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1010,7 +1010,6 @@ TemplateDeclInstantiator::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
                                  D->getQualifierLoc(),
                                  D->getTargetNameLoc(),
                                  D->getNamespace());
-  SemaRef.InstantiateAttrs(TemplateArgs, D, Inst, LateAttrs, StartingScope);
   Owner->addDecl(Inst);
   return Inst;
 }
@@ -1097,21 +1096,15 @@ Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D,
 
 Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
   Decl *Typedef = InstantiateTypedefNameDecl(D, /*IsTypeAlias=*/false);
-  if (Typedef) {
-    SemaRef.InstantiateAttrs(TemplateArgs, D, Typedef, LateAttrs,
-                             StartingScope);
+  if (Typedef)
     Owner->addDecl(Typedef);
-  }
   return Typedef;
 }
 
 Decl *TemplateDeclInstantiator::VisitTypeAliasDecl(TypeAliasDecl *D) {
   Decl *Typedef = InstantiateTypedefNameDecl(D, /*IsTypeAlias=*/true);
-  if (Typedef) {
-    SemaRef.InstantiateAttrs(TemplateArgs, D, Typedef, LateAttrs,
-                             StartingScope);
+  if (Typedef)
     Owner->addDecl(Typedef);
-  }
   return Typedef;
 }
 
@@ -1168,10 +1161,8 @@ Decl *TemplateDeclInstantiator::InstantiateTypeAliasTemplateDecl(
 Decl *
 TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
   Decl *Inst = InstantiateTypeAliasTemplateDecl(D);
-  if (Inst) {
-    SemaRef.InstantiateAttrs(TemplateArgs, D, Inst, LateAttrs, StartingScope);
+  if (Inst)
     Owner->addDecl(Inst);
-  }
 
   return Inst;
 }

>From 627a4d2a575f8377e22fbc1e19760d38cc278f1d Mon Sep 17 00:00:00 2001
From: Eric Astor <epastor at google.com>
Date: Thu, 14 Nov 2024 22:10:37 +0000
Subject: [PATCH 4/8] Add test using standard attribute

---
 clang/test/SemaCXX/attr-annotate.cpp  | 62 ++++++++++++++++++++++++++-
 clang/test/SemaCXX/attr-mode-tmpl.cpp |  4 +-
 2 files changed, 63 insertions(+), 3 deletions(-)

diff --git a/clang/test/SemaCXX/attr-annotate.cpp b/clang/test/SemaCXX/attr-annotate.cpp
index 846ef4119f1d7c..9975200426a9ba 100644
--- a/clang/test/SemaCXX/attr-annotate.cpp
+++ b/clang/test/SemaCXX/attr-annotate.cpp
@@ -1,4 +1,64 @@
-// RUN: %clang_cc1 -std=gnu++20 -fsyntax-only -verify %s
+// RUN: split-file %s %t
+// RUN: %clang_cc1 -std=gnu++20 -fsyntax-only -ast-dump -verify %t/good_annotate.cpp | FileCheck %s
+// RUN: %clang_cc1 -std=gnu++20 -fsyntax-only -verify %t/bad_annotate.cpp
+//--- good_annotate.cpp
+// expected-no-diagnostics
+
+void f() {
+  [[clang::annotate("decl", 1)]] int i = 0;
+  [[clang::annotate("stmt", 2)]] i += 1;
+[[clang::annotate("label", 3)]] label1:
+  i += 2;
+}
+
+// CHECK: -FunctionDecl 0x{{[0-9a-z]+}} {{.*:[0-9]+:[0-9]+, line:[0-9]+:[0-9]+> line:[0-9]+:[0-9]+}} f 'void ()'
+// CHECK: -VarDecl 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?> col:[0-9]+}} used i 'int'
+// CHECK: -AnnotateAttr 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} "decl"
+// CHECK: -IntegerLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'int' 1
+// CHECK: -AttributedStmt 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}}
+// CHECK: -AnnotateAttr 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} "stmt"
+// CHECK: -IntegerLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'int' 2
+// CHECK: -LabelStmt 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, line:[0-9]+:[0-9]+)?>}} 'label1'
+// CHECK: -AnnotateAttr 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}} "label"
+// CHECK: -IntegerLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'int' 3
+// CHECK: -CompoundAssignOperator 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}}
+
+template <typename T> void g() {
+  [[clang::annotate("tmpl_decl", 4)]] T j = 0;
+  [[clang::annotate("tmpl_stmt", 5)]] j += 1;
+[[clang::annotate("tmpl_label", 6)]] label2:
+  j += 2;
+}
+
+// CHECK: -FunctionTemplateDecl 0x{{[0-9a-z]+}} {{.*:[0-9]+:[0-9]+, line:[0-9]+:[0-9]+> line:[0-9]+:[0-9]+}} g
+// CHECK: -VarDecl 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?> col:[0-9]+}} referenced j 'T'
+// CHECK: -AnnotateAttr 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} "tmpl_decl"
+// CHECK: -IntegerLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'int' 4
+// CHECK: -AttributedStmt 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}}
+// CHECK: -AnnotateAttr 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} "tmpl_stmt"
+// CHECK: -IntegerLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'int' 5
+// CHECK: -LabelStmt 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, line:[0-9]+:[0-9]+)?>}} 'label2'
+// CHECK: -AnnotateAttr 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}} "tmpl_label"
+// CHECK: -IntegerLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'int' 6
+// CHECK: -CompoundAssignOperator 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}}
+
+void h() {
+  g<int>();
+}
+
+// CHECK: -FunctionDecl 0x{{[0-9a-z]+}} {{.*:[0-9]+:[0-9]+, line:[0-9]+:[0-9]+> line:[0-9]+:[0-9]+}} used g 'void ()' implicit_instantiation
+// CHECK: -VarDecl 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?> col:[0-9]+}} used j 'int'
+// CHECK: -AnnotateAttr 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} "tmpl_decl"
+// CHECK: -IntegerLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'int' 4
+// CHECK: -AttributedStmt 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}}
+// CHECK: -AnnotateAttr 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} Implicit "tmpl_stmt"
+// CHECK: -IntegerLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'int' 5
+// CHECK: -LabelStmt 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, line:[0-9]+:[0-9]+)?>}} 'label2'
+// CHECK: -AnnotateAttr 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}} "tmpl_label"
+// CHECK: -IntegerLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'int' 6
+// CHECK: -CompoundAssignOperator 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}}
+
+//--- bad_annotate.cpp
 
 template<bool If, typename Type>
 struct enable_if {
diff --git a/clang/test/SemaCXX/attr-mode-tmpl.cpp b/clang/test/SemaCXX/attr-mode-tmpl.cpp
index 58266f947051c5..f665b1ba491237 100644
--- a/clang/test/SemaCXX/attr-mode-tmpl.cpp
+++ b/clang/test/SemaCXX/attr-mode-tmpl.cpp
@@ -9,7 +9,7 @@ void CheckEnumerations() {
   // Check that non-vector 'mode' attribute is OK with enumeration types.
   typedef T __attribute__((mode(QI))) T1;
   typedef T T2 __attribute__((mode(HI)));
-  typedef T __attribute__((mode(V8SI))) T3; // expected-error2{{mode 'V8SI' is not supported for enumeration types}}
+  typedef T __attribute__((mode(V8SI))) T3; // expected-error{{mode 'V8SI' is not supported for enumeration types}}
   // expected-warning at -1{{specifying vector types with the 'mode' attribute is deprecated}}
 
   typedef enum __attribute__((mode(HI))) { A4, B4 } T4;
@@ -62,7 +62,7 @@ struct TemplatedStruct {
 
   // Check typedefs.
   typedef T __attribute__((mode(DI)))   T1;
-  typedef T __attribute__((mode(V8DI))) T2;   // expected-error2{{mode 'V8DI' is not supported for enumeration types}}
+  typedef T __attribute__((mode(V8DI))) T2;   // expected-error{{mode 'V8DI' is not supported for enumeration types}}
                                               // expected-warning at -1{{deprecated}}
 
   // Check parameters.

>From e0d76989721609b516d93d8f69672d9a1e552257 Mon Sep 17 00:00:00 2001
From: Eric Astor <epastor at google.com>
Date: Thu, 14 Nov 2024 22:13:11 +0000
Subject: [PATCH 5/8] Remove unnecessary use of plugins for testing

---
 clang/examples/Attribute/Attribute.cpp   | 6 +++---
 clang/test/Frontend/plugin-attribute.cpp | 8 --------
 2 files changed, 3 insertions(+), 11 deletions(-)

diff --git a/clang/examples/Attribute/Attribute.cpp b/clang/examples/Attribute/Attribute.cpp
index 59446a15a6925d..3b90724ad22205 100644
--- a/clang/examples/Attribute/Attribute.cpp
+++ b/clang/examples/Attribute/Attribute.cpp
@@ -41,9 +41,9 @@ struct ExampleAttrInfo : public ParsedAttrInfo {
   bool diagAppertainsToDecl(Sema &S, const ParsedAttr &Attr,
                             const Decl *D) const override {
     // This attribute appertains to functions only.
-    if (!isa<FunctionDecl>(D) && !isa<LabelDecl>(D)) {
+    if (!isa<FunctionDecl>(D)) {
       S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type_str)
-          << Attr << Attr.isRegularKeywordAttribute() << "functions or labels";
+          << Attr << Attr.isRegularKeywordAttribute() << "functions";
       return false;
     }
     return true;
@@ -52,7 +52,7 @@ struct ExampleAttrInfo : public ParsedAttrInfo {
   AttrHandling handleDeclAttribute(Sema &S, Decl *D,
                                    const ParsedAttr &Attr) const override {
     // Check if the decl is at file scope.
-    if (!D->getDeclContext()->isFileContext() && !isa<LabelDecl>(D)) {
+    if (!D->getDeclContext()->isFileContext()) {
       unsigned ID = S.getDiagnostics().getCustomDiagID(
           DiagnosticsEngine::Error,
           "'example' attribute only allowed at file scope");
diff --git a/clang/test/Frontend/plugin-attribute.cpp b/clang/test/Frontend/plugin-attribute.cpp
index 943ae3f95178d5..094ce9f5cbb85f 100644
--- a/clang/test/Frontend/plugin-attribute.cpp
+++ b/clang/test/Frontend/plugin-attribute.cpp
@@ -18,9 +18,6 @@ void fn2() __attribute__((example("somestring", 1, 2.0))) {
 }
 template <int N> void template_fn() __attribute__((example("template", N))) {
   __attribute__((example("def", N + 1))) for (int i = 0; i < 9; ++i) {}
-  __attribute__((example("ghi", N + 2)))
-label1:
-  for (int i = 0; i < 9; ++i) {}
 }
 void fn3() { template_fn<5>(); }
 // CHECK: -AttributedStmt 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}}
@@ -47,11 +44,6 @@ void fn3() { template_fn<5>(); }
 // CHECK: -IntegerLiteral 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}} 'int' 5
 // CHECK: -IntegerLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'int' 1
 // CHECK: -AnnotateAttr 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}} "example"
-// CHECK: -StringLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'const char[{{[0-9]+}}]' lvalue "ghi"
-// CHECK: -BinaryOperator 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'int' '+'
-// CHECK: -IntegerLiteral 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}} 'int' 5
-// CHECK: -IntegerLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'int' 2
-// CHECK: -AnnotateAttr 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}} "example"
 // CHECK: -StringLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'const char[{{[0-9]+}}]' lvalue "template"
 // CHECK: -IntegerLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'int' 5
 

>From fb705ad9008d29c3f3efa9199342e38512410ee5 Mon Sep 17 00:00:00 2001
From: Eric Astor <epastor at google.com>
Date: Thu, 14 Nov 2024 23:12:27 +0000
Subject: [PATCH 6/8] Fix the no-attributes case

---
 clang/include/clang/AST/ASTNodeTraverser.h | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h
index 876dcb647b27b4..3d63d581a9be60 100644
--- a/clang/include/clang/AST/ASTNodeTraverser.h
+++ b/clang/include/clang/AST/ASTNodeTraverser.h
@@ -801,8 +801,10 @@ class ASTNodeTraverser
   }
 
   void VisitLabelStmt(const LabelStmt *Node) {
-    for (const auto *A : Node->getDecl()->getAttrs())
-      Visit(A);
+    if (Node->getDecl()->hasAttrs()) {
+      for (const auto *A : Node->getDecl()->getAttrs())
+        Visit(A);
+    }
   }
 
   void VisitCXXCatchStmt(const CXXCatchStmt *Node) {

>From 96224998e2b5fac90183413df497e8e8308489e2 Mon Sep 17 00:00:00 2001
From: Eric Astor <epastor at google.com>
Date: Fri, 15 Nov 2024 14:52:10 +0000
Subject: [PATCH 7/8] Clean up & simplify tests

---
 clang/test/SemaCXX/attr-annotate.cpp | 62 +---------------------------
 1 file changed, 1 insertion(+), 61 deletions(-)

diff --git a/clang/test/SemaCXX/attr-annotate.cpp b/clang/test/SemaCXX/attr-annotate.cpp
index 9975200426a9ba..846ef4119f1d7c 100644
--- a/clang/test/SemaCXX/attr-annotate.cpp
+++ b/clang/test/SemaCXX/attr-annotate.cpp
@@ -1,64 +1,4 @@
-// RUN: split-file %s %t
-// RUN: %clang_cc1 -std=gnu++20 -fsyntax-only -ast-dump -verify %t/good_annotate.cpp | FileCheck %s
-// RUN: %clang_cc1 -std=gnu++20 -fsyntax-only -verify %t/bad_annotate.cpp
-//--- good_annotate.cpp
-// expected-no-diagnostics
-
-void f() {
-  [[clang::annotate("decl", 1)]] int i = 0;
-  [[clang::annotate("stmt", 2)]] i += 1;
-[[clang::annotate("label", 3)]] label1:
-  i += 2;
-}
-
-// CHECK: -FunctionDecl 0x{{[0-9a-z]+}} {{.*:[0-9]+:[0-9]+, line:[0-9]+:[0-9]+> line:[0-9]+:[0-9]+}} f 'void ()'
-// CHECK: -VarDecl 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?> col:[0-9]+}} used i 'int'
-// CHECK: -AnnotateAttr 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} "decl"
-// CHECK: -IntegerLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'int' 1
-// CHECK: -AttributedStmt 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}}
-// CHECK: -AnnotateAttr 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} "stmt"
-// CHECK: -IntegerLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'int' 2
-// CHECK: -LabelStmt 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, line:[0-9]+:[0-9]+)?>}} 'label1'
-// CHECK: -AnnotateAttr 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}} "label"
-// CHECK: -IntegerLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'int' 3
-// CHECK: -CompoundAssignOperator 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}}
-
-template <typename T> void g() {
-  [[clang::annotate("tmpl_decl", 4)]] T j = 0;
-  [[clang::annotate("tmpl_stmt", 5)]] j += 1;
-[[clang::annotate("tmpl_label", 6)]] label2:
-  j += 2;
-}
-
-// CHECK: -FunctionTemplateDecl 0x{{[0-9a-z]+}} {{.*:[0-9]+:[0-9]+, line:[0-9]+:[0-9]+> line:[0-9]+:[0-9]+}} g
-// CHECK: -VarDecl 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?> col:[0-9]+}} referenced j 'T'
-// CHECK: -AnnotateAttr 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} "tmpl_decl"
-// CHECK: -IntegerLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'int' 4
-// CHECK: -AttributedStmt 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}}
-// CHECK: -AnnotateAttr 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} "tmpl_stmt"
-// CHECK: -IntegerLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'int' 5
-// CHECK: -LabelStmt 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, line:[0-9]+:[0-9]+)?>}} 'label2'
-// CHECK: -AnnotateAttr 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}} "tmpl_label"
-// CHECK: -IntegerLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'int' 6
-// CHECK: -CompoundAssignOperator 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}}
-
-void h() {
-  g<int>();
-}
-
-// CHECK: -FunctionDecl 0x{{[0-9a-z]+}} {{.*:[0-9]+:[0-9]+, line:[0-9]+:[0-9]+> line:[0-9]+:[0-9]+}} used g 'void ()' implicit_instantiation
-// CHECK: -VarDecl 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?> col:[0-9]+}} used j 'int'
-// CHECK: -AnnotateAttr 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} "tmpl_decl"
-// CHECK: -IntegerLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'int' 4
-// CHECK: -AttributedStmt 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}}
-// CHECK: -AnnotateAttr 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} Implicit "tmpl_stmt"
-// CHECK: -IntegerLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'int' 5
-// CHECK: -LabelStmt 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, line:[0-9]+:[0-9]+)?>}} 'label2'
-// CHECK: -AnnotateAttr 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}} "tmpl_label"
-// CHECK: -IntegerLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'int' 6
-// CHECK: -CompoundAssignOperator 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}}
-
-//--- bad_annotate.cpp
+// RUN: %clang_cc1 -std=gnu++20 -fsyntax-only -verify %s
 
 template<bool If, typename Type>
 struct enable_if {

>From fe5f3616f282d54fb21b25368908271d237971ff Mon Sep 17 00:00:00 2001
From: Eric Astor <epastor at google.com>
Date: Fri, 15 Nov 2024 15:13:16 +0000
Subject: [PATCH 8/8] Add actual test (missed in previous commit)

---
 clang/test/SemaCXX/attr-annotate-ast.cpp | 55 ++++++++++++++++++++++++
 1 file changed, 55 insertions(+)
 create mode 100644 clang/test/SemaCXX/attr-annotate-ast.cpp

diff --git a/clang/test/SemaCXX/attr-annotate-ast.cpp b/clang/test/SemaCXX/attr-annotate-ast.cpp
new file mode 100644
index 00000000000000..ad8e2c26e666fd
--- /dev/null
+++ b/clang/test/SemaCXX/attr-annotate-ast.cpp
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -std=gnu++20 -fsyntax-only -ast-dump %s | FileCheck %s
+
+void f() {
+  [[clang::annotate("decl", 1)]] int i = 0;
+  [[clang::annotate("stmt", 2)]] i += 1;
+[[clang::annotate("label", 3)]] label1:
+  i += 2;
+}
+
+// CHECK: -FunctionDecl {{.*}} f 'void ()'
+// CHECK: -VarDecl {{.*}} used i 'int'
+// CHECK: -AnnotateAttr {{.*}} "decl"
+// CHECK: -IntegerLiteral {{.*}} 'int' 1
+// CHECK: -AttributedStmt
+// CHECK: -AnnotateAttr {{.*}} "stmt"
+// CHECK: -IntegerLiteral {{.*}} 'int' 2
+// CHECK: -LabelStmt {{.*}} 'label1'
+// CHECK: -AnnotateAttr {{.*}} "label"
+// CHECK: -IntegerLiteral {{.*}} 'int' 3
+// CHECK: -CompoundAssignOperator
+
+template <typename T> void g() {
+  [[clang::annotate("tmpl_decl", 4)]] T j = 0;
+  [[clang::annotate("tmpl_stmt", 5)]] j += 1;
+[[clang::annotate("tmpl_label", 6)]] label2:
+  j += 2;
+}
+
+// CHECK: -FunctionTemplateDecl {{.*}} g
+// CHECK: -VarDecl {{.*}} referenced j 'T'
+// CHECK: -AnnotateAttr {{.*}} "tmpl_decl"
+// CHECK: -IntegerLiteral {{.*}} 'int' 4
+// CHECK: -AttributedStmt
+// CHECK: -AnnotateAttr {{.*}} "tmpl_stmt"
+// CHECK: -IntegerLiteral {{.*}} 'int' 5
+// CHECK: -LabelStmt {{.*}} 'label2'
+// CHECK: -AnnotateAttr {{.*}} "tmpl_label"
+// CHECK: -IntegerLiteral {{.*}} 'int' 6
+// CHECK: -CompoundAssignOperator
+
+void h() {
+  g<int>();
+}
+
+// CHECK: -FunctionDecl {{.*}} used g 'void ()' implicit_instantiation
+// CHECK: -VarDecl {{.*}} used j 'int'
+// CHECK: -AnnotateAttr {{.*}} "tmpl_decl"
+// CHECK: -IntegerLiteral {{.*}} 'int' 4
+// CHECK: -AttributedStmt
+// CHECK: -AnnotateAttr {{.*}} Implicit "tmpl_stmt"
+// CHECK: -IntegerLiteral {{.*}} 'int' 5
+// CHECK: -LabelStmt {{.*}} 'label2'
+// CHECK: -AnnotateAttr {{.*}} "tmpl_label"
+// CHECK: -IntegerLiteral {{.*}} 'int' 6
+// CHECK: -CompoundAssignOperator



More information about the cfe-commits mailing list