
For backwards compatiblity, we emit only a warning instead of an error if the attribute is one of the existing type attributes that we have historically allowed to "slide" to the `DeclSpec` just as if it had been specified in GNU syntax. (We will call these "legacy type attributes" below.) The high-level changes that achieve this are: - We introduce a new field `Declarator::DeclarationAttrs` (with appropriate accessors) to store C++11 attributes occurring in the attribute-specifier-seq at the beginning of a simple-declaration (and other similar declarations). Previously, these attributes were placed on the `DeclSpec`, which made it impossible to reconstruct later on whether the attributes had in fact been placed on the decl-specifier-seq or ahead of the declaration. - In the parser, we propgate declaration attributes and decl-specifier-seq attributes separately until we can place them in `Declarator::DeclarationAttrs` or `DeclSpec::Attrs`, respectively. - In `ProcessDeclAttributes()`, in addition to processing declarator attributes, we now also process the attributes from `Declarator::DeclarationAttrs` (except if they are legacy type attributes). - In `ConvertDeclSpecToType()`, in addition to processing `DeclSpec` attributes, we also process any legacy type attributes that occur in `Declarator::DeclarationAttrs` (and emit a warning). - We make `ProcessDeclAttribute` emit an error if it sees any non-declaration attributes in C++11 syntax, except in the following cases: - If it is being called for attributes on a `DeclSpec` or `DeclaratorChunk` - If the attribute is a legacy type attribute (in which case we only emit a warning) The standard justifies treating attributes at the beginning of a simple-declaration and attributes after a declarator-id the same. Here are some relevant parts of the standard: - The attribute-specifier-seq at the beginning of a simple-declaration "appertains to each of the entities declared by the declarators of the init-declarator-list" (https://eel.is/c++draft/dcl.dcl#dcl.pre-3) - "In the declaration for an entity, attributes appertaining to that entity can appear at the start of the declaration and after the declarator-id for that declaration." (https://eel.is/c++draft/dcl.dcl#dcl.pre-note-2) - "The optional attribute-specifier-seq following a declarator-id appertains to the entity that is declared." (https://eel.is/c++draft/dcl.dcl#dcl.meaning.general-1) The standard contains similar wording to that for a simple-declaration in other similar types of declarations, for example: - "The optional attribute-specifier-seq in a parameter-declaration appertains to the parameter." (https://eel.is/c++draft/dcl.fct#3) - "The optional attribute-specifier-seq in an exception-declaration appertains to the parameter of the catch clause" (https://eel.is/c++draft/except.pre#1) The new behavior is tested both on the newly added type attribute `annotate_type`, for which we emit errors, and for the legacy type attribute `address_space` (chosen somewhat randomly from the various legacy type attributes), for which we emit warnings. Depends On D111548 Reviewed By: aaron.ballman, rsmith Differential Revision: https://reviews.llvm.org/D126061
144 lines
4.4 KiB
C
144 lines
4.4 KiB
C
// RUN: %clang_cc1 -fsyntax-only -fdouble-square-bracket-attributes -verify=expected,notc2x -Wno-strict-prototypes %s
|
|
// RUN: %clang_cc1 -fsyntax-only -std=gnu2x -verify=expected,c2x %s
|
|
|
|
enum [[]] E {
|
|
One [[]],
|
|
Two,
|
|
Three [[]]
|
|
};
|
|
|
|
enum [[]] { Four };
|
|
[[]] enum E2 { Five }; // expected-error {{misplaced attributes}}
|
|
|
|
// FIXME: this diagnostic can be improved.
|
|
enum { [[]] Six }; // expected-error {{expected identifier}}
|
|
|
|
// FIXME: this diagnostic can be improved.
|
|
enum E3 [[]] { Seven }; // expected-error {{expected identifier or '('}}
|
|
|
|
[[deprecated([""])]] int WrongArgs; // expected-error {{expected expression}}
|
|
[[,,,,,]] int Commas1; // ok
|
|
[[,, maybe_unused]] int Commas2; // ok
|
|
[[maybe_unused,,,]] int Commas3; // ok
|
|
[[,,maybe_unused,]] int Commas4; // ok
|
|
[[foo bar]] int NoComma; // expected-error {{expected ','}} \
|
|
// expected-warning {{unknown attribute 'foo' ignored}}
|
|
|
|
struct [[]] S1 {
|
|
int i [[]];
|
|
int [[]] j;
|
|
int k[10] [[]];
|
|
int l[[]][10];
|
|
[[]] int m, n;
|
|
int o [[]] : 12;
|
|
int [[]] : 0; // OK, attribute applies to the type.
|
|
int p, [[]] : 0; // expected-error {{an attribute list cannot appear here}}
|
|
int q, [[]] r; // expected-error {{an attribute list cannot appear here}}
|
|
[[]] int; // expected-error {{an attribute list cannot appear here}} \
|
|
// expected-warning {{declaration does not declare anything}}
|
|
};
|
|
|
|
[[]] struct S2 { int a; }; // expected-error {{misplaced attributes}}
|
|
struct S3 [[]] { int a; }; // expected-error {{an attribute list cannot appear here}}
|
|
|
|
union [[]] U {
|
|
double d [[]];
|
|
[[]] int i;
|
|
};
|
|
|
|
[[]] union U2 { double d; }; // expected-error {{misplaced attributes}}
|
|
union U3 [[]] { double d; }; // expected-error {{an attribute list cannot appear here}}
|
|
|
|
struct [[]] IncompleteStruct;
|
|
union [[]] IncompleteUnion;
|
|
enum [[]] IncompleteEnum;
|
|
enum __attribute__((deprecated)) IncompleteEnum2;
|
|
|
|
[[]] void f1(void);
|
|
void [[]] f2(void);
|
|
void f3 [[]] (void);
|
|
void f4(void) [[]];
|
|
|
|
void f5(int i [[]], [[]] int j, int [[]] k);
|
|
|
|
void f6(a, b) [[]] int a; int b; { // notc2x-error {{an attribute list cannot appear here}} \
|
|
c2x-error {{unknown type name 'a'}} \
|
|
c2x-error {{unknown type name 'b'}} \
|
|
c2x-error {{expected ';' after top level declarator}} \
|
|
c2x-error {{expected identifier or '('}}
|
|
}
|
|
|
|
// FIXME: technically, an attribute list cannot appear here, but we currently
|
|
// parse it as part of the return type of the function, which is reasonable
|
|
// behavior given that we *don't* want to parse it as part of the K&R parameter
|
|
// declarations. It is disallowed to avoid a parsing ambiguity we already
|
|
// handle well.
|
|
int (*f7(a, b))(int, int) [[]] int a; int b; { // c2x-error {{unknown type name 'a'}} \
|
|
c2x-error {{unknown type name 'b'}} \
|
|
c2x-error {{expected ';' after top level declarator}} \
|
|
c2x-error {{expected identifier or '('}}
|
|
|
|
return 0;
|
|
}
|
|
|
|
[[]] int a, b;
|
|
int c [[]], d [[]];
|
|
|
|
void f8(void) [[]] {
|
|
[[]] int i, j;
|
|
int k, l [[]];
|
|
}
|
|
|
|
[[]] void f9(void) {
|
|
int i[10] [[]];
|
|
int (*fp1)(void)[[]];
|
|
int (*fp2 [[]])(void);
|
|
|
|
int * [[]] *ipp;
|
|
}
|
|
|
|
void f10(int j[static 10] [[]], int k[*] [[]]);
|
|
|
|
void f11(void) {
|
|
[[]] {}
|
|
[[]] if (1) {}
|
|
|
|
[[]] switch (1) {
|
|
[[]] case 1: [[]] break;
|
|
[[]] default: break;
|
|
}
|
|
|
|
goto foo;
|
|
[[]] foo: (void)1;
|
|
|
|
[[]] for (;;);
|
|
[[]] while (1);
|
|
[[]] do [[]] { } while(1);
|
|
|
|
[[]] (void)1;
|
|
|
|
[[]];
|
|
|
|
(void)sizeof(int [4][[]]);
|
|
(void)sizeof(struct [[]] S3 { int a [[]]; });
|
|
|
|
[[]] return;
|
|
}
|
|
|
|
[[attr]] void f12(void); // expected-warning {{unknown attribute 'attr' ignored}}
|
|
[[vendor::attr]] void f13(void); // expected-warning {{unknown attribute 'attr' ignored}}
|
|
|
|
// Ensure that asm statements properly handle double colons.
|
|
void test_asm(void) {
|
|
asm("ret" :::);
|
|
asm("foo" :: "r" (xx)); // expected-error {{use of undeclared identifier 'xx'}}
|
|
}
|
|
|
|
// Do not allow 'using' to introduce vendor attribute namespaces.
|
|
[[using vendor: attr1, attr2]] void f14(void); // expected-error {{expected ','}} \
|
|
// expected-warning {{unknown attribute 'using' ignored}}
|
|
|
|
struct [[]] S4 *s; // expected-error {{an attribute list cannot appear here}}
|
|
struct S5 {};
|
|
int c = sizeof(struct [[]] S5); // expected-error {{an attribute list cannot appear here}}
|