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
Now that C23 has attributes, it's also not clear whether _Alignas will be handled slightly differently in the future as an attribute rather than a declaration specifier as happened with _Noreturn for C23. So agreed this is a tricky area.