[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
This commit is contained in:
parent
7df4eaaa93
commit
81a9707723
|
@ -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)
|
||||
|
|
|
@ -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()) {
|
||||
|
|
90
clang/test/Parser/stmt-attributes.c
Normal file
90
clang/test/Parser/stmt-attributes.c
Normal file
|
@ -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}}
|
27
clang/test/Parser/stmt-attributes.cpp
Normal file
27
clang/test/Parser/stmt-attributes.cpp
Normal file
|
@ -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@-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 (...) {
|
||||
}
|
||||
}
|
57
clang/test/Parser/stmt-attributes.m
Normal file
57
clang/test/Parser/stmt-attributes.m
Normal file
|
@ -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
|
Loading…
Reference in a new issue