[clang] 81a9707 - [Attr] Apply GNU-style attributes to expression statements
Valeriy Savchenko via cfe-commits
cfe-commits at lists.llvm.org
Thu Feb 11 05:45:33 PST 2021
Author: Valeriy Savchenko
Date: 2021-02-11T16:44:41+03:00
New Revision: 81a9707723845a5b880245da24633c519493205c
URL: https://github.com/llvm/llvm-project/commit/81a9707723845a5b880245da24633c519493205c
DIFF: https://github.com/llvm/llvm-project/commit/81a9707723845a5b880245da24633c519493205c.diff
LOG: [Attr] Apply GNU-style attributes to expression statements
Before this commit, expression statements could not be annotated
with statement attributes. Whenever parser found attribute, it
unconditionally assumed that it was followed by a declaration.
This not only doesn't allow expression attributes to have attributes,
but also produces spurious error diagnostics.
In order to maintain all previously compiled code, we still assume
that GNU attributes are followed by declarations unless ALL of those
are statement attributes. And even in this case we are not forcing
the parser to think that it should parse a statement, but rather
let it proceed as if no attributes were found.
Differential Revision: https://reviews.llvm.org/D93630
Added:
clang/test/Parser/stmt-attributes.c
clang/test/Parser/stmt-attributes.cpp
clang/test/Parser/stmt-attributes.m
Modified:
clang/include/clang/Basic/Features.def
clang/lib/Parse/ParseStmt.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def
index 5424da67b62da..32830a3a532cc 100644
--- a/clang/include/clang/Basic/Features.def
+++ b/clang/include/clang/Basic/Features.def
@@ -253,6 +253,7 @@ EXTENSION(cxx_variable_templates, LangOpts.CPlusPlus)
EXTENSION(overloadable_unmarked, true)
EXTENSION(pragma_clang_attribute_namespaces, true)
EXTENSION(pragma_clang_attribute_external_declaration, true)
+EXTENSION(statement_attributes_with_gnu_syntax, true)
EXTENSION(gnu_asm, LangOpts.GNUAsm)
EXTENSION(gnu_asm_goto_with_outputs, LangOpts.GNUAsm)
EXTENSION(matrix_types, LangOpts.MatrixTypes)
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 71344ff101552..f59271c458488 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -20,6 +20,8 @@
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/TypoCorrection.h"
+#include "llvm/ADT/STLExtras.h"
+
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -215,7 +217,11 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt ||
(StmtCtx & ParsedStmtContext::AllowDeclarationsInC) !=
ParsedStmtContext()) &&
- (GNUAttributeLoc.isValid() || isDeclarationStatement())) {
+ ((GNUAttributeLoc.isValid() &&
+ !(!Attrs.empty() &&
+ llvm::all_of(
+ Attrs, [](ParsedAttr &Attr) { return Attr.isStmtAttr(); }))) ||
+ isDeclarationStatement())) {
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
DeclGroupPtrTy Decl;
if (GNUAttributeLoc.isValid()) {
diff --git a/clang/test/Parser/stmt-attributes.c b/clang/test/Parser/stmt-attributes.c
new file mode 100644
index 0000000000000..d142ce1b5b954
--- /dev/null
+++ b/clang/test/Parser/stmt-attributes.c
@@ -0,0 +1,90 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+#if !__has_extension(statement_attributes_with_gnu_syntax)
+#error "We should have statement attributes with GNU syntax support"
+#endif
+
+void foo(int i) {
+
+ __attribute__((unknown_attribute)); // expected-warning {{unknown attribute 'unknown_attribute' ignored}}
+ __attribute__(()) {}
+ __attribute__(()) if (0) {}
+ __attribute__(()) for (;;);
+ __attribute__(()) do {
+ __attribute__(()) continue;
+ }
+ while (0)
+ ;
+ __attribute__(()) while (0);
+
+ __attribute__(()) switch (i) {
+ __attribute__(()) case 0 :
+ __attribute__(()) default :
+ __attribute__(()) break;
+ }
+
+ __attribute__(()) goto here;
+ __attribute__(()) here :
+
+ __attribute__(()) return;
+
+ __attribute__((noreturn)) {} // expected-error {{'noreturn' attribute cannot be applied to a statement}}
+ __attribute__((noreturn)) if (0) {} // expected-error {{'noreturn' attribute cannot be applied to a statement}}
+ __attribute__((noreturn)) for (;;); // expected-error {{'noreturn' attribute cannot be applied to a statement}}
+ __attribute__((noreturn)) do { // expected-error {{'noreturn' attribute cannot be applied to a statement}}
+ __attribute__((unavailable)) continue; // expected-error {{'unavailable' attribute cannot be applied to a statement}}
+ }
+ while (0)
+ ;
+ __attribute__((unknown_attribute)) while (0); // expected-warning {{unknown attribute 'unknown_attribute' ignored}}
+
+ __attribute__((unused)) switch (i) { // expected-error {{'unused' attribute cannot be applied to a statement}}
+ __attribute__((uuid)) case 0: // expected-warning {{unknown attribute 'uuid' ignored}}
+ __attribute__((visibility)) default: // expected-error {{'visibility' attribute cannot be applied to a statement}}
+ __attribute__((carries_dependency)) break; // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
+ }
+
+ __attribute__((fastcall)) goto there; // expected-error {{'fastcall' attribute cannot be applied to a statement}}
+ __attribute__((noinline)) there : // expected-warning {{'noinline' attribute only applies to functions}}
+
+ __attribute__((weakref)) return; // expected-error {{'weakref' attribute only applies to variables and functions}}
+
+ __attribute__((carries_dependency)); // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
+ __attribute__((carries_dependency)) {} // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
+ __attribute__((carries_dependency)) if (0) {} // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
+ __attribute__((carries_dependency)) for (;;); // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
+ __attribute__((carries_dependency)) do { // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
+ __attribute__((carries_dependency)) continue; // expected-error {{'carries_dependency' attribute cannot be applied to a statement}} ignored}}
+ }
+ while (0)
+ ;
+ __attribute__((carries_dependency)) while (0); // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
+
+ __attribute__((carries_dependency)) switch (i) { // expected-error {{'carries_dependency' attribute cannot be applied to a statement}} ignored}}
+ __attribute__((carries_dependency)) case 0: // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
+ __attribute__((carries_dependency)) default: // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
+ __attribute__((carries_dependency)) break; // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
+ }
+
+ __attribute__((carries_dependency)) goto here; // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
+
+ __attribute__((carries_dependency)) return; // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
+}
+
+void bar();
+
+void foobar() {
+ __attribute__((nomerge)) bar();
+ __attribute__(()) bar(); // expected-error {{expected identifier or '('}}
+ __attribute__((unused, nomerge)) bar(); // expected-error {{expected identifier or '('}}
+ __attribute__((nomerge, unused)) bar(); // expected-error {{expected identifier or '('}}
+ __attribute__((nomerge(1, 2))) bar(); // expected-error {{'nomerge' attribute takes no arguments}}
+ int x;
+ __attribute__((nomerge)) x = 10; // expected-warning {{nomerge attribute is ignored because there exists no call expression inside the statement}}
+
+ __attribute__((nomerge)) label : bar(); // expected-error {{'nomerge' attribute only applies to functions and statements}}
+}
+
+int f();
+
+__attribute__((nomerge)) static int i; // expected-error {{'nomerge' attribute only applies to functions and statements}}
diff --git a/clang/test/Parser/stmt-attributes.cpp b/clang/test/Parser/stmt-attributes.cpp
new file mode 100644
index 0000000000000..74192ea68141d
--- /dev/null
+++ b/clang/test/Parser/stmt-attributes.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -fexceptions -fsyntax-only -verify %s
+
+#if !__has_extension(statement_attributes_with_gnu_syntax)
+#error "We should have statement attributes with GNU syntax support"
+#endif
+
+template <typename T = void>
+class __attribute__((nomerge)) A {
+ // expected-error at -1 {{'nomerge' attribute only applies to functions and statements}}
+};
+
+class B : public A<> {
+public:
+ void bar();
+};
+
+void bar();
+
+void foo(A<> *obj) {
+ __attribute__((nomerge)) static_cast<B *>(obj)->bar();
+ __attribute__((nomerge))[obj]() { static_cast<B *>(obj)->bar(); }
+ ();
+ __attribute__(()) try {
+ bar();
+ } catch (...) {
+ }
+}
diff --git a/clang/test/Parser/stmt-attributes.m b/clang/test/Parser/stmt-attributes.m
new file mode 100644
index 0000000000000..550781b5311a9
--- /dev/null
+++ b/clang/test/Parser/stmt-attributes.m
@@ -0,0 +1,57 @@
+// RUN: %clang_cc1 -verify %s \
+// RUN: -fblocks -fobjc-exceptions -fexceptions -fsyntax-only \
+// RUN: -Wno-unused-value -Wno-unused-getter-return-value
+
+#if !__has_extension(statement_attributes_with_gnu_syntax)
+#error "We should have statement attributes with GNU syntax support"
+#endif
+
+ at interface Base
+ at end
+
+ at interface Test : Base
+ at property(getter=hasFoobar) int foobar;
+- (void)foo;
+- (void)bar;
+ at end
+
+Test *getTest();
+
+ at implementation Test
+- (void)foo __attribute__((nomerge)) {
+ // expected-error at -1 {{'nomerge' attribute only applies to functions and statements}}
+}
+
+- (void)bar {
+ __attribute__(()) [self foo];
+ // expected-error at -1 {{missing '[' at start of message send expression}}
+ // expected-error at -2 {{expected ']'}}
+ // expected-error at -3 {{expected identifier or '('}}
+ // expected-note at -4 {{to match this '['}}
+ __attribute__((nomerge)) [self foo];
+ // expected-warning at -1 {{nomerge attribute is ignored because there exists no call expression inside the statement}}
+ __attribute__((nomerge)) [getTest() foo];
+
+ __attribute__(()) ^{};
+ // expected-error at -1 {{expected identifier or '('}}
+ __attribute__((nomerge)) ^{};
+ // expected-warning at -1 {{nomerge attribute is ignored because there exists no call expression inside the statement}}
+ __attribute__((nomerge)) ^{ [self foo]; }();
+
+ __attribute__(()) @try {
+ [self foo];
+ } @finally {
+ }
+
+ __attribute__((nomerge)) @try {
+ [getTest() foo];
+ } @finally {
+ }
+
+ __attribute__((nomerge)) (__bridge void *)self;
+ // expected-warning at -1 {{nomerge attribute is ignored because there exists no call expression inside the statement}}
+
+ __attribute__((nomerge)) self.hasFoobar;
+ // expected-warning at -1 {{nomerge attribute is ignored because there exists no call expression inside the statement}}
+}
+ at end
More information about the cfe-commits
mailing list