Skip to content

Commit 73e74e4

Browse files
authored
[clang][frontend] Support applying the annotate attribute to statements (#111841)
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.
1 parent 2190ffa commit 73e74e4

File tree

12 files changed

+137
-41
lines changed

12 files changed

+137
-41
lines changed

clang/include/clang/AST/Attr.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,23 @@ class InheritableParamAttr : public InheritableAttr {
197197
}
198198
};
199199

200+
class InheritableParamOrStmtAttr : public InheritableParamAttr {
201+
protected:
202+
InheritableParamOrStmtAttr(ASTContext &Context,
203+
const AttributeCommonInfo &CommonInfo,
204+
attr::Kind AK, bool IsLateParsed,
205+
bool InheritEvenIfAlreadyPresent)
206+
: InheritableParamAttr(Context, CommonInfo, AK, IsLateParsed,
207+
InheritEvenIfAlreadyPresent) {}
208+
209+
public:
210+
// Implement isa/cast/dyncast/etc.
211+
static bool classof(const Attr *A) {
212+
return A->getKind() >= attr::FirstInheritableParamOrStmtAttr &&
213+
A->getKind() <= attr::LastInheritableParamOrStmtAttr;
214+
}
215+
};
216+
200217
class HLSLAnnotationAttr : public InheritableAttr {
201218
protected:
202219
HLSLAnnotationAttr(ASTContext &Context, const AttributeCommonInfo &CommonInfo,

clang/include/clang/Basic/Attr.td

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -759,6 +759,11 @@ class TargetSpecificAttr<TargetSpec target> {
759759
/// redeclarations, even when it's written on a parameter.
760760
class InheritableParamAttr : InheritableAttr;
761761

762+
/// A attribute that is either a declaration attribute or a statement attribute,
763+
/// and if used as a declaration attribute, is inherited by later
764+
/// redeclarations, even when it's written on a parameter.
765+
class InheritableParamOrStmtAttr : InheritableParamAttr;
766+
762767
/// An attribute which changes the ABI rules for a specific parameter.
763768
class ParameterABIAttr : InheritableParamAttr {
764769
let Subjects = SubjectList<[ParmVar]>;
@@ -928,7 +933,7 @@ def AnalyzerNoReturn : InheritableAttr {
928933
let Documentation = [Undocumented];
929934
}
930935

931-
def Annotate : InheritableParamAttr {
936+
def Annotate : InheritableParamOrStmtAttr {
932937
let Spellings = [Clang<"annotate">];
933938
let Args = [StringArgument<"Annotation">, VariadicExprArgument<"Args">];
934939
// Ensure that the annotate attribute can be used with

clang/include/clang/Sema/Sema.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4528,9 +4528,10 @@ class Sema final : public SemaBase {
45284528
/// declaration.
45294529
void AddAlignValueAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E);
45304530

4531-
/// AddAnnotationAttr - Adds an annotation Annot with Args arguments to D.
4532-
void AddAnnotationAttr(Decl *D, const AttributeCommonInfo &CI,
4533-
StringRef Annot, MutableArrayRef<Expr *> Args);
4531+
/// CreateAnnotationAttr - Creates an annotation Annot with Args arguments.
4532+
Attr *CreateAnnotationAttr(const AttributeCommonInfo &CI, StringRef Annot,
4533+
MutableArrayRef<Expr *> Args);
4534+
Attr *CreateAnnotationAttr(const ParsedAttr &AL);
45344535

45354536
bool checkMSInheritanceAttrOnDefinition(CXXRecordDecl *RD, SourceRange Range,
45364537
bool BestCase,

clang/lib/Sema/Sema.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2777,3 +2777,31 @@ bool Sema::isDeclaratorFunctionLike(Declarator &D) {
27772777
});
27782778
return Result;
27792779
}
2780+
2781+
Attr *Sema::CreateAnnotationAttr(const AttributeCommonInfo &CI, StringRef Annot,
2782+
MutableArrayRef<Expr *> Args) {
2783+
2784+
auto *A = AnnotateAttr::Create(Context, Annot, Args.data(), Args.size(), CI);
2785+
if (!ConstantFoldAttrArgs(
2786+
CI, MutableArrayRef<Expr *>(A->args_begin(), A->args_end()))) {
2787+
return nullptr;
2788+
}
2789+
return A;
2790+
}
2791+
2792+
Attr *Sema::CreateAnnotationAttr(const ParsedAttr &AL) {
2793+
// Make sure that there is a string literal as the annotation's first
2794+
// argument.
2795+
StringRef Str;
2796+
if (!checkStringLiteralArgumentAttr(AL, 0, Str))
2797+
return nullptr;
2798+
2799+
llvm::SmallVector<Expr *, 4> Args;
2800+
Args.reserve(AL.getNumArgs() - 1);
2801+
for (unsigned Idx = 1; Idx < AL.getNumArgs(); Idx++) {
2802+
assert(!AL.isArgIdent(Idx));
2803+
Args.push_back(AL.getArgAsExpr(Idx));
2804+
}
2805+
2806+
return CreateAnnotationAttr(AL, Str, Args);
2807+
}

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3958,30 +3958,11 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
39583958
RD->addAttr(::new (S.Context) TransparentUnionAttr(S.Context, AL));
39593959
}
39603960

3961-
void Sema::AddAnnotationAttr(Decl *D, const AttributeCommonInfo &CI,
3962-
StringRef Str, MutableArrayRef<Expr *> Args) {
3963-
auto *Attr = AnnotateAttr::Create(Context, Str, Args.data(), Args.size(), CI);
3964-
if (ConstantFoldAttrArgs(
3965-
CI, MutableArrayRef<Expr *>(Attr->args_begin(), Attr->args_end()))) {
3966-
D->addAttr(Attr);
3967-
}
3968-
}
3969-
39703961
static void handleAnnotateAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
3971-
// Make sure that there is a string literal as the annotation's first
3972-
// argument.
3973-
StringRef Str;
3974-
if (!S.checkStringLiteralArgumentAttr(AL, 0, Str))
3975-
return;
3976-
3977-
llvm::SmallVector<Expr *, 4> Args;
3978-
Args.reserve(AL.getNumArgs() - 1);
3979-
for (unsigned Idx = 1; Idx < AL.getNumArgs(); Idx++) {
3980-
assert(!AL.isArgIdent(Idx));
3981-
Args.push_back(AL.getArgAsExpr(Idx));
3962+
auto *Attr = S.CreateAnnotationAttr(AL);
3963+
if (Attr) {
3964+
D->addAttr(Attr);
39823965
}
3983-
3984-
S.AddAnnotationAttr(D, AL, Str, Args);
39853966
}
39863967

39873968
static void handleAlignValueAttr(Sema &S, Decl *D, const ParsedAttr &AL) {

clang/lib/Sema/SemaStmtAttr.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -679,6 +679,8 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A,
679679
return handleMSConstexprAttr(S, St, A, Range);
680680
case ParsedAttr::AT_NoConvergent:
681681
return handleNoConvergentAttr(S, St, A, Range);
682+
case ParsedAttr::AT_Annotate:
683+
return S.CreateAnnotationAttr(A);
682684
default:
683685
// N.B., ClangAttrEmitter.cpp emits a diagnostic helper that ensures a
684686
// declaration attribute is not written on a statement, but this code is

clang/lib/Sema/SemaTemplateInstantiate.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1552,6 +1552,7 @@ namespace {
15521552
NamedDecl *FirstQualifierInScope = nullptr,
15531553
bool AllowInjectedClassName = false);
15541554

1555+
const AnnotateAttr *TransformAnnotateAttr(const AnnotateAttr *AA);
15551556
const CXXAssumeAttr *TransformCXXAssumeAttr(const CXXAssumeAttr *AA);
15561557
const LoopHintAttr *TransformLoopHintAttr(const LoopHintAttr *LH);
15571558
const NoInlineAttr *TransformStmtNoInlineAttr(const Stmt *OrigS,
@@ -2182,6 +2183,18 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
21822183
Arg, PackIndex);
21832184
}
21842185

2186+
const AnnotateAttr *
2187+
TemplateInstantiator::TransformAnnotateAttr(const AnnotateAttr *AA) {
2188+
SmallVector<Expr *> Args;
2189+
for (Expr *Arg : AA->args()) {
2190+
ExprResult Res = getDerived().TransformExpr(Arg);
2191+
if (Res.isUsable())
2192+
Args.push_back(Res.get());
2193+
}
2194+
return AnnotateAttr::CreateImplicit(getSema().Context, AA->getAnnotation(),
2195+
Args.data(), Args.size(), AA->getRange());
2196+
}
2197+
21852198
const CXXAssumeAttr *
21862199
TemplateInstantiator::TransformCXXAssumeAttr(const CXXAssumeAttr *AA) {
21872200
ExprResult Res = getDerived().TransformExpr(AA->getAssumption());

clang/lib/Sema/SemaTemplateInstantiateDecl.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,10 @@ static void instantiateDependentAnnotationAttr(
230230
ActualArgs.insert(ActualArgs.begin(), Args.begin() + 1, Args.end());
231231
std::swap(Args, ActualArgs);
232232
}
233-
S.AddAnnotationAttr(New, *Attr, Str, Args);
233+
auto *AA = S.CreateAnnotationAttr(*Attr, Str, Args);
234+
if (AA) {
235+
New->addAttr(AA);
236+
}
234237
}
235238

236239
static Expr *instantiateDependentFunctionAttrCondition(

clang/test/AST/attr-print-emit.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ class C {
7878
ANNOTATE_ATTR int annotated_attr ANNOTATE_ATTR = 0;
7979
// CHECK: __attribute__((annotate("Annotated"))) int annotated_attr __attribute__((annotate("Annotated"))) = 0;
8080

81+
void increment() { [[clang::annotate("Annotated")]] annotated_attr++; }
82+
// CHECK: {{\[\[}}clang::annotate("Annotated")]] annotated_attr++;
83+
8184
// FIXME: We do not print the attribute as written after the type specifier.
8285
int ANNOTATE_ATTR annotated_attr_fixme = 0;
8386
// CHECK: __attribute__((annotate("Annotated"))) int annotated_attr_fixme = 0;

clang/test/Sema/annotate.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
void __attribute__((annotate("foo"))) foo(float *a) {
44
__attribute__((annotate("bar"))) int x;
55
[[clang::annotate("bar")]] int x2;
6+
[[clang::annotate("bar")]] x2 += 1;
67
__attribute__((annotate(1))) int y; // expected-error {{expected string literal as argument of 'annotate' attribute}}
78
[[clang::annotate(1)]] int y2; // expected-error {{expected string literal as argument of 'annotate' attribute}}
89
__attribute__((annotate("bar", 1))) int z;
910
[[clang::annotate("bar", 1)]] int z2;
11+
[[clang::annotate("bar", 1)]] z2 += 1;
1012

1113
int u = __builtin_annotation(z, (char*) 0); // expected-error {{second argument to __builtin_annotation must be a non-wide string constant}}
1214
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) {
1517

1618
__attribute__((annotate())) int c; // expected-error {{'annotate' attribute takes at least 1 argument}}
1719
[[clang::annotate()]] int c2; // expected-error {{'annotate' attribute takes at least 1 argument}}
20+
[[clang::annotate()]] c2 += 1; // expected-error {{'annotate' attribute takes at least 1 argument}}
1821
}

clang/test/SemaTemplate/attributes.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,17 @@ namespace attribute_annotate {
6565
template<typename T> [[clang::annotate("ANNOTATE_FOO"), clang::annotate("ANNOTATE_BAR")]] void HasAnnotations();
6666
void UseAnnotations() { HasAnnotations<int>(); }
6767

68+
// CHECK: FunctionTemplateDecl {{.*}} HasStmtAnnotations
69+
// CHECK: AnnotateAttr {{.*}} "ANNOTATE_BAZ"
70+
// CHECK: FunctionDecl {{.*}} HasStmtAnnotations
71+
// CHECK: TemplateArgument type 'int'
72+
// CHECK: AnnotateAttr {{.*}} "ANNOTATE_BAZ"
73+
template<typename T> void HasStmtAnnotations() {
74+
int x = 0;
75+
[[clang::annotate("ANNOTATE_BAZ")]] x++;
76+
}
77+
void UseStmtAnnotations() { HasStmtAnnotations<int>(); }
78+
6879
// CHECK: FunctionTemplateDecl {{.*}} HasPackAnnotations
6980
// CHECK-NEXT: NonTypeTemplateParmDecl {{.*}} referenced 'int' depth 0 index 0 ... Is
7081
// CHECK-NEXT: FunctionDecl {{.*}} HasPackAnnotations 'void ()'
@@ -95,6 +106,33 @@ void UseAnnotations() { HasAnnotations<int>(); }
95106
template <int... Is> [[clang::annotate("ANNOTATE_BAZ", Is...)]] void HasPackAnnotations();
96107
void UsePackAnnotations() { HasPackAnnotations<1, 2, 3>(); }
97108

109+
// CHECK: FunctionTemplateDecl {{.*}} HasStmtPackAnnotations
110+
// CHECK-NEXT: NonTypeTemplateParmDecl {{.*}} referenced 'int' depth 0 index 0 ... Is
111+
// CHECK-NEXT: FunctionDecl {{.*}} HasStmtPackAnnotations 'void ()'
112+
// CHECK: AttributedStmt {{.*}}
113+
// CHECK-NEXT: AnnotateAttr {{.*}} "ANNOTATE_QUUX"
114+
// CHECK-NEXT: PackExpansionExpr {{.*}} '<dependent type>'
115+
// CHECK-NEXT: DeclRefExpr {{.*}} 'int' NonTypeTemplateParm {{.*}} 'Is' 'int'
116+
// CHECK: FunctionDecl {{.*}} used HasStmtPackAnnotations 'void ()'
117+
// CHECK-NEXT: TemplateArgument{{.*}} pack
118+
// CHECK-NEXT: TemplateArgument{{.*}} integral '1'
119+
// CHECK-NEXT: TemplateArgument{{.*}} integral '2'
120+
// CHECK-NEXT: TemplateArgument{{.*}} integral '3'
121+
// CHECK: AttributedStmt {{.*}}
122+
// CHECK-NEXT: AnnotateAttr {{.*}} "ANNOTATE_QUUX"
123+
// CHECK-NEXT: PackExpansionExpr {{.*}}
124+
// CHECK-NEXT: SubstNonTypeTemplateParmPackExpr {{.*}}
125+
// CHECK-NEXT: NonTypeTemplateParmDecl {{.*}} referenced 'int' depth 0 index 0 ... Is
126+
// CHECK-NEXT: TemplateArgument pack '<1, 2, 3>'
127+
// CHECK-NEXT: TemplateArgument integral '1'
128+
// CHECK-NEXT: TemplateArgument integral '2'
129+
// CHECK-NEXT: TemplateArgument integral '3'
130+
template <int... Is> void HasStmtPackAnnotations() {
131+
int x = 0;
132+
[[clang::annotate("ANNOTATE_QUUX", Is...)]] x++;
133+
}
134+
void UseStmtPackAnnotations() { HasStmtPackAnnotations<1, 2, 3>(); }
135+
98136
template <int... Is> [[clang::annotate(Is...)]] void HasOnlyPackAnnotation() {} // expected-error {{expected string literal as argument of 'annotate' attribute}}
99137

100138
void UseOnlyPackAnnotations() {

clang/utils/TableGen/ClangAttrEmitter.cpp

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3282,16 +3282,16 @@ namespace {
32823282
} // end anonymous namespace
32833283

32843284
static const AttrClassDescriptor AttrClassDescriptors[] = {
3285-
{ "ATTR", "Attr" },
3286-
{ "TYPE_ATTR", "TypeAttr" },
3287-
{ "STMT_ATTR", "StmtAttr" },
3288-
{ "DECL_OR_STMT_ATTR", "DeclOrStmtAttr" },
3289-
{ "INHERITABLE_ATTR", "InheritableAttr" },
3290-
{ "DECL_OR_TYPE_ATTR", "DeclOrTypeAttr" },
3291-
{ "INHERITABLE_PARAM_ATTR", "InheritableParamAttr" },
3292-
{ "PARAMETER_ABI_ATTR", "ParameterABIAttr" },
3293-
{ "HLSL_ANNOTATION_ATTR", "HLSLAnnotationAttr"}
3294-
};
3285+
{"ATTR", "Attr"},
3286+
{"TYPE_ATTR", "TypeAttr"},
3287+
{"STMT_ATTR", "StmtAttr"},
3288+
{"DECL_OR_STMT_ATTR", "DeclOrStmtAttr"},
3289+
{"INHERITABLE_ATTR", "InheritableAttr"},
3290+
{"DECL_OR_TYPE_ATTR", "DeclOrTypeAttr"},
3291+
{"INHERITABLE_PARAM_ATTR", "InheritableParamAttr"},
3292+
{"INHERITABLE_PARAM_OR_STMT_ATTR", "InheritableParamOrStmtAttr"},
3293+
{"PARAMETER_ABI_ATTR", "ParameterABIAttr"},
3294+
{"HLSL_ANNOTATION_ATTR", "HLSLAnnotationAttr"}};
32953295

32963296
static void emitDefaultDefine(raw_ostream &OS, StringRef name,
32973297
const char *superName) {
@@ -4319,10 +4319,12 @@ static void GenerateMutualExclusionsChecks(const Record &Attr,
43194319

43204320
// This means the attribute is either a statement attribute, a decl
43214321
// attribute, or both; find out which.
4322-
bool CurAttrIsStmtAttr =
4323-
Attr.isSubClassOf("StmtAttr") || Attr.isSubClassOf("DeclOrStmtAttr");
4324-
bool CurAttrIsDeclAttr =
4325-
!CurAttrIsStmtAttr || Attr.isSubClassOf("DeclOrStmtAttr");
4322+
bool CurAttrIsStmtAttr = Attr.isSubClassOf("StmtAttr") ||
4323+
Attr.isSubClassOf("DeclOrStmtAttr") ||
4324+
Attr.isSubClassOf("InheritableParamOrStmtAttr");
4325+
bool CurAttrIsDeclAttr = !CurAttrIsStmtAttr ||
4326+
Attr.isSubClassOf("DeclOrStmtAttr") ||
4327+
Attr.isSubClassOf("InheritableParamOrStmtAttr");
43264328

43274329
std::vector<std::string> DeclAttrs, StmtAttrs;
43284330

0 commit comments

Comments
 (0)