Geoff Chappell - Software Analyst
ROUGH DRAFT
An attribute statement names the attribute and optionally provides either or both an attribute argument list and an attribute value list (if both, then necessarily in that order).
The attribute argument list is enclosed by parentheses and consists of one or more attribute arguments separated by commas, with an optional trailing comma.
The attribute value list is announced by an equals sign and is enclosed by braces (curly brackets). It consists of one or more attribute values separated by commas, but with the provisions that attribute values may be empty and that a trailing comma implies that an empty attribute value follows. An attribute value list that contains just the one non-empty value may be given without braces.
attribute-statement:
attribute-name [ ( attribute-argument-list [,] ) ] [ = { attribute-value-list } ]
attribute-name [ ( attribute-argument-list [,] ) ] [ = attribute-value ]
attribute-name:
identifier
attribute-argument-list:
attribute-argument-list , attribute-argument
attribute-value-list:
[ attribute-value ]
attribute-value-list , [ attribute-value ]
It is an error (C3400) for an attribute statement to begin with anything other than an identifier to name the attribute. The error message cites the unexpected token only by type. For example,
[ 1234 // C3400 ];
produces
TEST.CPP(3) : error C3400: 'string': unexpected token/character encountered in attribute block
Note that this error also applies to what might otherwise be regarded as empty attribute statements. These are treated as attribute statements that begin erroneously with a comma, which is then cited as the unexpected token.
The attribute name is deliberately not subject to macro expansion. If the identifier that names the attribute is defined as a macro, a warning is issued (C4044, at level 1). Thus, in
#define coclass [ coclass, ] // C4044 class Test;
the coclass attribute is not defined away to nothing.
More typical in practice would be that the macro is not itself the name of any recognised attribute but the programmer means it to stand for an attribute, perhaps also with arguments for that attribute. When the macro is in fact not expanded, it remains as an identifier, which the compiler will try to interpret as an attribute. Thus, warning C4044 will typically be followed by error C2337:
#define MODULE_ATTRIBUTES module (type = dll, name = test) [ MODULE_ATTRIBUTES ]; // C4044 and C2337
It may be as well to note here that macros are not useless in attribute blocks. For instance, they are expanded when given as attribute argument values, and the preceding example is reworkable as
#define MODULE_TYPE dll #define MODULE_NAME test [ module (type = MODULE_TYPE, name = MODULE_NAME) ];
It is an error (C3406) if the argument list is empty, meaning specifically that the token immediately after the left parenthesis is a right parenthesis. The error message cites the attribute. For example,
[ cpp_quote () // C3406 ];
produces
TEST.CPP(2) : error C3406: 'cpp_quote': empty attribute argument list is not allowed
It is an error (C2143) for an attribute argument to be followed by anything other than a comma or a right parenthesis. The error message in this case complains of missing a right parenthesis.