[clang] [clang][frontend] Support applying the annotate attribute to statements (PR #111841)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Oct 10 07:16:23 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Eric Astor (ericastor)
<details>
<summary>Changes</summary>
By allowing AnnotateAttr to be applied to statements, users can place arbitrary information in the AST for later use.
For example, this can be used for HW-targeted language extensions that involve specialized loop annotations.
---
Full diff: https://github.com/llvm/llvm-project/pull/111841.diff
8 Files Affected:
- (modified) clang/include/clang/AST/Attr.h (+17)
- (modified) clang/include/clang/Basic/Attr.td (+6-1)
- (modified) clang/lib/Sema/SemaStmtAttr.cpp (+20)
- (modified) clang/lib/Sema/SemaTemplateInstantiate.cpp (+14)
- (modified) clang/test/AST/attr-print-emit.cpp (+3)
- (modified) clang/test/Sema/annotate.c (+3)
- (modified) clang/test/SemaTemplate/attributes.cpp (+38)
- (modified) clang/utils/TableGen/ClangAttrEmitter.cpp (+7-4)
``````````diff
diff --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h
index ac44e9fdd7c4e9..725498e132fc28 100644
--- a/clang/include/clang/AST/Attr.h
+++ b/clang/include/clang/AST/Attr.h
@@ -197,6 +197,23 @@ class InheritableParamAttr : public InheritableAttr {
}
};
+class InheritableParamOrStmtAttr : public InheritableParamAttr {
+protected:
+ InheritableParamOrStmtAttr(ASTContext &Context,
+ const AttributeCommonInfo &CommonInfo,
+ attr::Kind AK, bool IsLateParsed,
+ bool InheritEvenIfAlreadyPresent)
+ : InheritableParamAttr(Context, CommonInfo, AK, IsLateParsed,
+ InheritEvenIfAlreadyPresent) {}
+
+public:
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Attr *A) {
+ return A->getKind() >= attr::FirstInheritableParamOrStmtAttr &&
+ A->getKind() <= attr::LastInheritableParamOrStmtAttr;
+ }
+};
+
class HLSLAnnotationAttr : public InheritableAttr {
protected:
HLSLAnnotationAttr(ASTContext &Context, const AttributeCommonInfo &CommonInfo,
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index fbcbf0ed416416..ec3d6e0079f630 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -759,6 +759,11 @@ class TargetSpecificAttr<TargetSpec target> {
/// redeclarations, even when it's written on a parameter.
class InheritableParamAttr : InheritableAttr;
+/// A attribute that is either a declaration attribute or a statement attribute,
+/// and if used as a declaration attribute, is inherited by later
+/// redeclarations, even when it's written on a parameter.
+class InheritableParamOrStmtAttr : InheritableParamAttr;
+
/// An attribute which changes the ABI rules for a specific parameter.
class ParameterABIAttr : InheritableParamAttr {
let Subjects = SubjectList<[ParmVar]>;
@@ -928,7 +933,7 @@ def AnalyzerNoReturn : InheritableAttr {
let Documentation = [Undocumented];
}
-def Annotate : InheritableParamAttr {
+def Annotate : InheritableParamOrStmtAttr {
let Spellings = [Clang<"annotate">];
let Args = [StringArgument<"Annotation">, VariadicExprArgument<"Args">];
// Ensure that the annotate attribute can be used with
diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp
index b9b3b4063bc383..ee6630bdb429c6 100644
--- a/clang/lib/Sema/SemaStmtAttr.cpp
+++ b/clang/lib/Sema/SemaStmtAttr.cpp
@@ -242,6 +242,24 @@ static Attr *handleNoConvergentAttr(Sema &S, Stmt *St, const ParsedAttr &A,
return ::new (S.Context) NoConvergentAttr(S.Context, A);
}
+static Attr *handleAnnotateAttr(Sema &S, Stmt *St, const ParsedAttr &A,
+ SourceRange Range) {
+ // Make sure that there is a string literal as the annotation's first
+ // argument.
+ StringRef Str;
+ if (!S.checkStringLiteralArgumentAttr(A, 0, Str))
+ return nullptr;
+
+ llvm::SmallVector<Expr *, 4> Args;
+ Args.reserve(A.getNumArgs() - 1);
+ for (unsigned Idx = 1; Idx < A.getNumArgs(); Idx++) {
+ assert(!A.isArgIdent(Idx));
+ Args.push_back(A.getArgAsExpr(Idx));
+ }
+
+ return AnnotateAttr::Create(S.Context, Str, Args.data(), Args.size(), A);
+}
+
template <typename OtherAttr, int DiagIdx>
static bool CheckStmtInlineAttr(Sema &SemaRef, const Stmt *OrigSt,
const Stmt *CurSt,
@@ -679,6 +697,8 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A,
return handleMSConstexprAttr(S, St, A, Range);
case ParsedAttr::AT_NoConvergent:
return handleNoConvergentAttr(S, St, A, Range);
+ case ParsedAttr::AT_Annotate:
+ return handleAnnotateAttr(S, St, A, Range);
default:
// N.B., ClangAttrEmitter.cpp emits a diagnostic helper that ensures a
// declaration attribute is not written on a statement, but this code is
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index fd51fa4afcacbf..00a5f81dbca8fe 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1537,6 +1537,7 @@ namespace {
NamedDecl *FirstQualifierInScope = nullptr,
bool AllowInjectedClassName = false);
+ const AnnotateAttr *TransformAnnotateAttr(const AnnotateAttr *AA);
const CXXAssumeAttr *TransformCXXAssumeAttr(const CXXAssumeAttr *AA);
const LoopHintAttr *TransformLoopHintAttr(const LoopHintAttr *LH);
const NoInlineAttr *TransformStmtNoInlineAttr(const Stmt *OrigS,
@@ -2125,6 +2126,19 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
Arg, PackIndex);
}
+const AnnotateAttr *
+TemplateInstantiator::TransformAnnotateAttr(const AnnotateAttr *AA) {
+ SmallVector<Expr *> Args;
+ for (Expr *Arg : AA->args()) {
+ ExprResult Res = getDerived().TransformExpr(Arg);
+ if (!Res.isUsable())
+ return AA;
+ Args.push_back(Res.get());
+ }
+ return AnnotateAttr::CreateImplicit(getSema().Context, AA->getAnnotation(),
+ Args.data(), Args.size(), AA->getRange());
+}
+
const CXXAssumeAttr *
TemplateInstantiator::TransformCXXAssumeAttr(const CXXAssumeAttr *AA) {
ExprResult Res = getDerived().TransformExpr(AA->getAssumption());
diff --git a/clang/test/AST/attr-print-emit.cpp b/clang/test/AST/attr-print-emit.cpp
index d8e62ed5f6cd11..a9bca6778d0f1a 100644
--- a/clang/test/AST/attr-print-emit.cpp
+++ b/clang/test/AST/attr-print-emit.cpp
@@ -78,6 +78,9 @@ class C {
ANNOTATE_ATTR int annotated_attr ANNOTATE_ATTR = 0;
// CHECK: __attribute__((annotate("Annotated"))) int annotated_attr __attribute__((annotate("Annotated"))) = 0;
+void increment() { [[clang::annotate("Annotated")]] annotated_attr++; }
+// CHECK: {{\[\[}}clang::annotate("Annotated")]] annotated_attr++;
+
// FIXME: We do not print the attribute as written after the type specifier.
int ANNOTATE_ATTR annotated_attr_fixme = 0;
// CHECK: __attribute__((annotate("Annotated"))) int annotated_attr_fixme = 0;
diff --git a/clang/test/Sema/annotate.c b/clang/test/Sema/annotate.c
index b4551a102e6174..f2ef08d6378975 100644
--- a/clang/test/Sema/annotate.c
+++ b/clang/test/Sema/annotate.c
@@ -3,10 +3,12 @@
void __attribute__((annotate("foo"))) foo(float *a) {
__attribute__((annotate("bar"))) int x;
[[clang::annotate("bar")]] int x2;
+ [[clang::annotate("bar")]] x2 += 1;
__attribute__((annotate(1))) int y; // expected-error {{expected string literal as argument of 'annotate' attribute}}
[[clang::annotate(1)]] int y2; // expected-error {{expected string literal as argument of 'annotate' attribute}}
__attribute__((annotate("bar", 1))) int z;
[[clang::annotate("bar", 1)]] int z2;
+ [[clang::annotate("bar", 1)]] z2 += 1;
int u = __builtin_annotation(z, (char*) 0); // expected-error {{second argument to __builtin_annotation must be a non-wide string constant}}
int v = __builtin_annotation(z, (char*) L"bar"); // expected-error {{second argument to __builtin_annotation must be a non-wide string constant}}
@@ -15,4 +17,5 @@ void __attribute__((annotate("foo"))) foo(float *a) {
__attribute__((annotate())) int c; // expected-error {{'annotate' attribute takes at least 1 argument}}
[[clang::annotate()]] int c2; // expected-error {{'annotate' attribute takes at least 1 argument}}
+ [[clang::annotate()]] c2 += 1; // expected-error {{'annotate' attribute takes at least 1 argument}}
}
diff --git a/clang/test/SemaTemplate/attributes.cpp b/clang/test/SemaTemplate/attributes.cpp
index f6c9f13f0842d2..dea19d09745ca2 100644
--- a/clang/test/SemaTemplate/attributes.cpp
+++ b/clang/test/SemaTemplate/attributes.cpp
@@ -65,6 +65,17 @@ namespace attribute_annotate {
template<typename T> [[clang::annotate("ANNOTATE_FOO"), clang::annotate("ANNOTATE_BAR")]] void HasAnnotations();
void UseAnnotations() { HasAnnotations<int>(); }
+// CHECK: FunctionTemplateDecl {{.*}} HasStmtAnnotations
+// CHECK: AnnotateAttr {{.*}} "ANNOTATE_BAZ"
+// CHECK: FunctionDecl {{.*}} HasStmtAnnotations
+// CHECK: TemplateArgument type 'int'
+// CHECK: AnnotateAttr {{.*}} "ANNOTATE_BAZ"
+template<typename T> void HasStmtAnnotations() {
+ int x = 0;
+ [[clang::annotate("ANNOTATE_BAZ")]] x++;
+}
+void UseStmtAnnotations() { HasStmtAnnotations<int>(); }
+
// CHECK: FunctionTemplateDecl {{.*}} HasPackAnnotations
// CHECK-NEXT: NonTypeTemplateParmDecl {{.*}} referenced 'int' depth 0 index 0 ... Is
// CHECK-NEXT: FunctionDecl {{.*}} HasPackAnnotations 'void ()'
@@ -95,6 +106,33 @@ void UseAnnotations() { HasAnnotations<int>(); }
template <int... Is> [[clang::annotate("ANNOTATE_BAZ", Is...)]] void HasPackAnnotations();
void UsePackAnnotations() { HasPackAnnotations<1, 2, 3>(); }
+// CHECK: FunctionTemplateDecl {{.*}} HasStmtPackAnnotations
+// CHECK-NEXT: NonTypeTemplateParmDecl {{.*}} referenced 'int' depth 0 index 0 ... Is
+// CHECK-NEXT: FunctionDecl {{.*}} HasStmtPackAnnotations 'void ()'
+// CHECK: AttributedStmt {{.*}}
+// CHECK-NEXT: AnnotateAttr {{.*}} "ANNOTATE_QUUX"
+// CHECK-NEXT: PackExpansionExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int' NonTypeTemplateParm {{.*}} 'Is' 'int'
+// CHECK: FunctionDecl {{.*}} used HasStmtPackAnnotations 'void ()'
+// CHECK-NEXT: TemplateArgument{{.*}} pack
+// CHECK-NEXT: TemplateArgument{{.*}} integral '1'
+// CHECK-NEXT: TemplateArgument{{.*}} integral '2'
+// CHECK-NEXT: TemplateArgument{{.*}} integral '3'
+// CHECK: AttributedStmt {{.*}}
+// CHECK-NEXT: AnnotateAttr {{.*}} "ANNOTATE_QUUX"
+// CHECK-NEXT: PackExpansionExpr {{.*}}
+// CHECK-NEXT: SubstNonTypeTemplateParmPackExpr {{.*}}
+// CHECK-NEXT: NonTypeTemplateParmDecl {{.*}} referenced 'int' depth 0 index 0 ... Is
+// CHECK-NEXT: TemplateArgument pack '<1, 2, 3>'
+// CHECK-NEXT: TemplateArgument integral '1'
+// CHECK-NEXT: TemplateArgument integral '2'
+// CHECK-NEXT: TemplateArgument integral '3'
+template <int... Is> void HasStmtPackAnnotations() {
+ int x = 0;
+ [[clang::annotate("ANNOTATE_QUUX", Is...)]] x++;
+}
+void UseStmtPackAnnotations() { HasStmtPackAnnotations<1, 2, 3>(); }
+
template <int... Is> [[clang::annotate(Is...)]] void HasOnlyPackAnnotation() {} // expected-error {{expected string literal as argument of 'annotate' attribute}}
void UseOnlyPackAnnotations() {
diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp
index 87be48c215e230..cee47fa8a283f2 100644
--- a/clang/utils/TableGen/ClangAttrEmitter.cpp
+++ b/clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -3295,6 +3295,7 @@ static const AttrClassDescriptor AttrClassDescriptors[] = {
{ "INHERITABLE_ATTR", "InheritableAttr" },
{ "DECL_OR_TYPE_ATTR", "DeclOrTypeAttr" },
{ "INHERITABLE_PARAM_ATTR", "InheritableParamAttr" },
+ { "INHERITABLE_PARAM_OR_STMT_ATTR", "InheritableParamOrStmtAttr" },
{ "PARAMETER_ABI_ATTR", "ParameterABIAttr" },
{ "HLSL_ANNOTATION_ATTR", "HLSLAnnotationAttr"}
};
@@ -4328,10 +4329,12 @@ static void GenerateMutualExclusionsChecks(const Record &Attr,
// This means the attribute is either a statement attribute, a decl
// attribute, or both; find out which.
- bool CurAttrIsStmtAttr =
- Attr.isSubClassOf("StmtAttr") || Attr.isSubClassOf("DeclOrStmtAttr");
- bool CurAttrIsDeclAttr =
- !CurAttrIsStmtAttr || Attr.isSubClassOf("DeclOrStmtAttr");
+ bool CurAttrIsStmtAttr = Attr.isSubClassOf("StmtAttr") ||
+ Attr.isSubClassOf("DeclOrStmtAttr") ||
+ Attr.isSubClassOf("InheritableParamOrStmtAttr");
+ bool CurAttrIsDeclAttr = !CurAttrIsStmtAttr ||
+ Attr.isSubClassOf("DeclOrStmtAttr") ||
+ Attr.isSubClassOf("InheritableParamOrStmtAttr");
std::vector<std::string> DeclAttrs, StmtAttrs;
``````````
</details>
https://github.com/llvm/llvm-project/pull/111841
More information about the cfe-commits
mailing list