diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def index 5424da67b62d..32830a3a532c 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 71344ff10155..f59271c45848 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 @@ Retry: 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 000000000000..d142ce1b5b95 --- /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 000000000000..74192ea68141 --- /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 +class __attribute__((nomerge)) A { + // expected-error@-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(obj)->bar(); + __attribute__((nomerge))[obj]() { static_cast(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 000000000000..550781b5311a --- /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 + +@interface Base +@end + +@interface Test : Base +@property(getter=hasFoobar) int foobar; +- (void)foo; +- (void)bar; +@end + +Test *getTest(); + +@implementation Test +- (void)foo __attribute__((nomerge)) { + // expected-error@-1 {{'nomerge' attribute only applies to functions and statements}} +} + +- (void)bar { + __attribute__(()) [self foo]; + // expected-error@-1 {{missing '[' at start of message send expression}} + // expected-error@-2 {{expected ']'}} + // expected-error@-3 {{expected identifier or '('}} + // expected-note@-4 {{to match this '['}} + __attribute__((nomerge)) [self foo]; + // expected-warning@-1 {{nomerge attribute is ignored because there exists no call expression inside the statement}} + __attribute__((nomerge)) [getTest() foo]; + + __attribute__(()) ^{}; + // expected-error@-1 {{expected identifier or '('}} + __attribute__((nomerge)) ^{}; + // expected-warning@-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@-1 {{nomerge attribute is ignored because there exists no call expression inside the statement}} + + __attribute__((nomerge)) self.hasFoobar; + // expected-warning@-1 {{nomerge attribute is ignored because there exists no call expression inside the statement}} +} +@end