Skip to content
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

[clang][frontend] Support applying the annotate attribute to statements #111841

Merged
merged 8 commits into from
Oct 10, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions clang/include/clang/AST/Attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
7 changes: 6 additions & 1 deletion clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -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]>;
Expand Down Expand Up @@ -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
Expand Down
7 changes: 4 additions & 3 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -4528,9 +4528,10 @@ class Sema final : public SemaBase {
/// declaration.
void AddAlignValueAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E);

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

bool checkMSInheritanceAttrOnDefinition(CXXRecordDecl *RD, SourceRange Range,
bool BestCase,
Expand Down
28 changes: 28 additions & 0 deletions clang/lib/Sema/Sema.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2777,3 +2777,31 @@ bool Sema::isDeclaratorFunctionLike(Declarator &D) {
});
return Result;
}

Attr *Sema::CreateAnnotationAttr(const AttributeCommonInfo &CI, StringRef Annot,
MutableArrayRef<Expr *> Args) {

auto *A = AnnotateAttr::Create(Context, Annot, Args.data(), Args.size(), CI);
if (!ConstantFoldAttrArgs(
CI, MutableArrayRef<Expr *>(A->args_begin(), A->args_end()))) {
return nullptr;
}
return A;
}

Attr *Sema::CreateAnnotationAttr(const ParsedAttr &AL) {
// Make sure that there is a string literal as the annotation's first
// argument.
StringRef Str;
if (!checkStringLiteralArgumentAttr(AL, 0, Str))
return nullptr;

llvm::SmallVector<Expr *, 4> Args;
Args.reserve(AL.getNumArgs() - 1);
for (unsigned Idx = 1; Idx < AL.getNumArgs(); Idx++) {
assert(!AL.isArgIdent(Idx));
Args.push_back(AL.getArgAsExpr(Idx));
}

return CreateAnnotationAttr(AL, Str, Args);
}
25 changes: 3 additions & 22 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3958,30 +3958,11 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
RD->addAttr(::new (S.Context) TransparentUnionAttr(S.Context, AL));
}

void Sema::AddAnnotationAttr(Decl *D, const AttributeCommonInfo &CI,
StringRef Str, MutableArrayRef<Expr *> Args) {
auto *Attr = AnnotateAttr::Create(Context, Str, Args.data(), Args.size(), CI);
if (ConstantFoldAttrArgs(
CI, MutableArrayRef<Expr *>(Attr->args_begin(), Attr->args_end()))) {
D->addAttr(Attr);
}
}

static void handleAnnotateAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// Make sure that there is a string literal as the annotation's first
// argument.
StringRef Str;
if (!S.checkStringLiteralArgumentAttr(AL, 0, Str))
return;

llvm::SmallVector<Expr *, 4> Args;
Args.reserve(AL.getNumArgs() - 1);
for (unsigned Idx = 1; Idx < AL.getNumArgs(); Idx++) {
assert(!AL.isArgIdent(Idx));
Args.push_back(AL.getArgAsExpr(Idx));
auto *Attr = S.CreateAnnotationAttr(AL);
if (Attr) {
D->addAttr(Attr);
}

S.AddAnnotationAttr(D, AL, Str, Args);
}

static void handleAlignValueAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Sema/SemaStmtAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -679,6 +679,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 S.CreateAnnotationAttr(A);
default:
// N.B., ClangAttrEmitter.cpp emits a diagnostic helper that ensures a
// declaration attribute is not written on a statement, but this code is
Expand Down
13 changes: 13 additions & 0 deletions clang/lib/Sema/SemaTemplateInstantiate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1552,6 +1552,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,
Expand Down Expand Up @@ -2182,6 +2183,18 @@ 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())
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());
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,10 @@ static void instantiateDependentAnnotationAttr(
ActualArgs.insert(ActualArgs.begin(), Args.begin() + 1, Args.end());
std::swap(Args, ActualArgs);
}
S.AddAnnotationAttr(New, *Attr, Str, Args);
auto *AA = S.CreateAnnotationAttr(*Attr, Str, Args);
if (AA) {
New->addAttr(AA);
}
}

static Expr *instantiateDependentFunctionAttrCondition(
Expand Down
3 changes: 3 additions & 0 deletions clang/test/AST/attr-print-emit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions clang/test/Sema/annotate.c
Original file line number Diff line number Diff line change
Expand Up @@ -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}}
Expand All @@ -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}}
}
38 changes: 38 additions & 0 deletions clang/test/SemaTemplate/attributes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 ()'
Expand Down Expand Up @@ -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() {
Expand Down
11 changes: 7 additions & 4 deletions clang/utils/TableGen/ClangAttrEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3289,6 +3289,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"}
};
Expand Down Expand Up @@ -4319,10 +4320,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;

Expand Down
Loading