diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h index a443a88bab1f2..3d63d581a9be6 100644 --- a/clang/include/clang/AST/ASTNodeTraverser.h +++ b/clang/include/clang/AST/ASTNodeTraverser.h @@ -800,6 +800,13 @@ class ASTNodeTraverser Visit(A); } + void VisitLabelStmt(const LabelStmt *Node) { + if (Node->getDecl()->hasAttrs()) { + for (const auto *A : Node->getDecl()->getAttrs()) + Visit(A); + } + } + void VisitCXXCatchStmt(const CXXCatchStmt *Node) { Visit(Node->getExceptionDecl()); } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 5a001843e2ba4..4529eb99377e7 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; } diff --git a/clang/test/SemaCXX/attr-annotate-ast.cpp b/clang/test/SemaCXX/attr-annotate-ast.cpp new file mode 100644 index 0000000000000..ad8e2c26e666f --- /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 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(); +} + +// 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