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] Add support for attribute plugins for statement attributes #110334

Merged
merged 26 commits into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
0411b29
[clang][frontend] Add support for attribute plugins for statement att…
ericastor Sep 27, 2024
293bc12
Merge branch 'main' into stmt-attributes
ericastor Sep 30, 2024
2398a73
Fix desync'd comment
ericastor Sep 30, 2024
5a5ff13
Add support for template-instantiations of AnnotateAttr
ericastor Oct 9, 2024
a445081
Merge branch 'main' into stmt-attributes
ericastor Oct 10, 2024
b7394ba
Merge branch 'llvm:main' into stmt-attributes
ericastor Oct 10, 2024
8fba347
[libc] Fix missing namespace declarations
jhuber6 Oct 10, 2024
3d2cac4
[clang][frontend] Support applying the annotate attribute to statemen…
ericastor Oct 10, 2024
ec7e46a
[libc] Add missing config include
jhuber6 Oct 10, 2024
8297051
[mlir][tosa] Change the type of profile option to ListOption (#111214)
tatwaichong Oct 10, 2024
865cae5
[lldb] Fix a variety of LLDB_LOG format strings
JDevlieghere Oct 10, 2024
51a2d67
[alpha.webkit.UncountedCallArgsChecker] Skip std::forward in tryToFin…
rniwa Oct 10, 2024
4839e50
[alpha.webkit.UncountedCallArgsChecker] Add the support for trivial C…
rniwa Oct 10, 2024
842314f
isUncountedPtr should take QualType as an argument. (#110213)
rniwa Oct 10, 2024
00095b5
[mlir][debug] Support DICommonBlock. (#111706)
abidh Oct 10, 2024
953dd25
[runtimes][NFC] Reindent CMake files (#111821)
ldionne Oct 10, 2024
9c1d96f
[NVPTX] Prefer prmt.b32 over bfi.b32 (#110766)
justinfargnoli Oct 10, 2024
2b6b0ad
[flang][runtime] Fix runtime crash after bad recoverable OPEN (#111454)
klausler Oct 10, 2024
6faaa65
[flang] Fix references to destroyed objects (#111582)
klausler Oct 10, 2024
9cc0e48
[flang] Minor cleanup (move function into /tools.cpp) (#111587)
klausler Oct 10, 2024
af9a8f4
[lldb][libc++] Hide all libc++ implementation details from stacktrace…
vogelsgesang Oct 10, 2024
b32398e
[flang][runtime][NFC] Fix header guard typo (#111741)
clementval Oct 10, 2024
a31c1f4
Fix GCC build problem with 03483737a7a2
rengolin Oct 10, 2024
7862d15
Merge branch 'main' into stmt-attributes
ericastor Oct 10, 2024
e7f7104
Add release note
ericastor Oct 11, 2024
19544a5
Merge branch 'main' into stmt-attributes
ericastor Oct 11, 2024
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: 12 additions & 5 deletions clang/docs/ClangPlugins.rst
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,6 @@ The members of ``ParsedAttrInfo`` that a plugin attribute must define are:
attribute, each of which consists of an attribute syntax and how the
attribute name is spelled for that syntax. If the syntax allows a scope then
the spelling must be "scope::attr" if a scope is present or "::attr" if not.
* ``handleDeclAttribute``, which is the function that applies the attribute to
a declaration. It is responsible for checking that the attribute's arguments
are valid, and typically applies the attribute by adding an ``Attr`` to the
``Decl``. It returns either ``AttributeApplied``, to indicate that the
attribute was successfully applied, or ``AttributeNotApplied`` if it wasn't.

The members of ``ParsedAttrInfo`` that may need to be defined, depending on the
attribute, are:
Expand All @@ -105,6 +100,18 @@ attribute, are:
arguments to the attribute.
* ``diagAppertainsToDecl``, which checks if the attribute has been used on the
right kind of declaration and issues a diagnostic if not.
* ``handleDeclAttribute``, which is the function that applies the attribute to
a declaration. It is responsible for checking that the attribute's arguments
are valid, and typically applies the attribute by adding an ``Attr`` to the
``Decl``. It returns either ``AttributeApplied``, to indicate that the
attribute was successfully applied, or ``AttributeNotApplied`` if it wasn't.
* ``diagAppertainsToStmt``, which checks if the attribute has been used on the
right kind of statement and issues a diagnostic if not.
* ``handleStmtAttribute``, which is the function that applies the attribute to
a statement. It is responsible for checking that the attribute's arguments
are valid, and typically applies the attribute by adding an ``Attr`` to the
``Stmt``. It returns either ``AttributeApplied``, to indicate that the
attribute was successfully applied, or ``AttributeNotApplied`` if it wasn't.
* ``diagLangOpts``, which checks if the attribute is permitted for the current
language mode and issues a diagnostic if not.
* ``existsInTarget``, which checks if the attribute is permitted for the given
Expand Down
48 changes: 48 additions & 0 deletions clang/examples/Attribute/Attribute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,54 @@ struct ExampleAttrInfo : public ParsedAttrInfo {
}
return AttributeApplied;
}

bool diagAppertainsToStmt(Sema &S, const ParsedAttr &Attr,
const Stmt *St) const override {
// This attribute appertains to for loop statements only.
if (!isa<ForStmt>(St)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type_str)
<< Attr << Attr.isRegularKeywordAttribute() << "for loop statements";
return false;
}
return true;
}

AttrHandling handleStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &Attr,
class Attr *&Result) const override {
// We make some rules here:
// 1. Only accept at most 3 arguments here.
// 2. The first argument must be a string literal if it exists.
if (Attr.getNumArgs() > 3) {
unsigned ID = S.getDiagnostics().getCustomDiagID(
DiagnosticsEngine::Error,
"'example' attribute only accepts at most three arguments");
S.Diag(Attr.getLoc(), ID);
return AttributeNotApplied;
}
// If there are arguments, the first argument should be a string literal.
if (Attr.getNumArgs() > 0) {
auto *Arg0 = Attr.getArgAsExpr(0);
StringLiteral *Literal =
dyn_cast<StringLiteral>(Arg0->IgnoreParenCasts());
if (!Literal) {
unsigned ID = S.getDiagnostics().getCustomDiagID(
DiagnosticsEngine::Error, "first argument to the 'example' "
"attribute must be a string literal");
S.Diag(Attr.getLoc(), ID);
return AttributeNotApplied;
}
SmallVector<Expr *, 16> ArgsBuf;
for (unsigned i = 0; i < Attr.getNumArgs(); i++) {
ArgsBuf.push_back(Attr.getArgAsExpr(i));
}
Result = AnnotateAttr::Create(S.Context, "example", ArgsBuf.data(),
ArgsBuf.size(), Attr.getRange());
} else {
Result = AnnotateAttr::Create(S.Context, "example", nullptr, 0,
Attr.getRange());
}
return AttributeApplied;
}
};

} // namespace
Expand Down
10 changes: 10 additions & 0 deletions clang/include/clang/Basic/ParsedAttrInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

namespace clang {

class Attr;
class Decl;
class LangOptions;
class ParsedAttr;
Expand Down Expand Up @@ -154,6 +155,15 @@ struct ParsedAttrInfo {
const ParsedAttr &Attr) const {
return NotHandled;
}
/// If this ParsedAttrInfo knows how to handle this ParsedAttr applied to this
/// Stmt then do so (referencing the resulting Attr in Result) and return
/// either AttributeApplied if it was applied or AttributeNotApplied if it
/// wasn't. Otherwise return NotHandled.
virtual AttrHandling handleStmtAttribute(Sema &S, Stmt *St,
const ParsedAttr &Attr,
class Attr *&Result) const {
return NotHandled;
}

static const ParsedAttrInfo &get(const AttributeCommonInfo &A);
static ArrayRef<const ParsedAttrInfo *> getAllBuiltin();
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Sema/SemaStmtAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,10 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A,
case ParsedAttr::AT_NoConvergent:
return handleNoConvergentAttr(S, St, A, Range);
default:
if (Attr *AT = nullptr; A.getInfo().handleStmtAttribute(S, St, A, AT) !=
ParsedAttrInfo::NotHandled) {
return AT;
}
// N.B., ClangAttrEmitter.cpp emits a diagnostic helper that ensures a
// declaration attribute is not written on a statement, but this code is
// needed for attributes in Attr.td that do not list any subjects.
Expand Down
40 changes: 33 additions & 7 deletions clang/test/Frontend/plugin-attribute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,33 @@
// REQUIRES: plugins, examples
//--- good_attr.cpp
// expected-no-diagnostics
void fn1a() __attribute__((example)) {}
[[example]] void fn1b() {}
[[plugin::example]] void fn1c() {}
void fn2() __attribute__((example("somestring", 1, 2.0))) {}
// CHECK-COUNT-4: -AnnotateAttr 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} "example"
void fn1a() __attribute__((example)) {
__attribute__((example)) for (int i = 0; i < 10; ++i) {}
}
[[example]] void fn1b() {
[[example]] for (int i = 0; i < 10; ++i) {}
}
[[plugin::example]] void fn1c() {
[[plugin::example]] for (int i = 0; i < 10; ++i) {}
}
void fn2() __attribute__((example("somestring", 1, 2.0))) {
__attribute__((example("abc", 3, 4.0))) for (int i = 0; i < 10; ++i) {}
}
// 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]+)?>}} "example"
// CHECK: -AnnotateAttr 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}} "example"
// 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]+)?>}} "example"
// CHECK: -AnnotateAttr 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}} "example"
// 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]+)?>}} "example"
// CHECK: -AnnotateAttr 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}} "example"
// 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]+)?>}} "example"
// CHECK: -StringLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'const char[{{[0-9]+}}]' lvalue "abc"
// CHECK: -IntegerLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'int' 3
// CHECK: -FloatingLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'double' 4.000000e+00
// 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 "somestring"
// CHECK: -IntegerLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'int' 1
// CHECK: -FloatingLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'double' 2.000000e+00
Expand All @@ -18,5 +40,9 @@ int var1 __attribute__((example("otherstring"))) = 1; // expected-warning {{'exa
class Example {
void __attribute__((example)) fn3(); // expected-error {{'example' attribute only allowed at file scope}}
};
void fn4() __attribute__((example(123))) { } // expected-error {{first argument to the 'example' attribute must be a string literal}}
void fn5() __attribute__((example("a","b", 3, 4.0))) { } // expected-error {{'example' attribute only accepts at most three arguments}}
void fn4() __attribute__((example(123))) { // expected-error {{first argument to the 'example' attribute must be a string literal}}
__attribute__((example("somestring"))) while (true); // expected-warning {{'example' attribute only applies to for loop statements}}
}
void fn5() __attribute__((example("a","b", 3, 4.0))) { // expected-error {{'example' attribute only accepts at most three arguments}}
__attribute__((example("a","b", 3, 4.0))) for (int i = 0; i < 10; ++i) {} // expected-error {{'example' attribute only accepts at most three arguments}}
}
Loading