PR24559 brings up a long-standing issue in Clang where attribute order with differing syntax impacts whether a parse will succeed or fail with poor diagnostics. For instance:
struct attribute((lockable)) declspec(dllexport) S { }; ok
struct declspec(dllexport) attribute((lockable)) T { }; error about declaring anonymous structs and a warning about declarations not declaring anything
When you consider attributes as extraneous semantic information to attach to entities, ordering of the attributes really should not matter between the various attribute syntaxes we support -- they all serve the same purpose.
This patch begins to address the issue by providing a MaybeParseAttributes() function accepting a mask of what attribute syntaxes are allowed and parses the various syntaxes in a loop.
However, this patch is not complete, as the test cases for function attributes currently fail for the C++11-style attributes.
[[noreturn]] attribute((cdecl)) __declspec(dllexport) void f();
In this case, the [[noreturn]] is parsed as part of the top-level declaration, while the GNU and declspec attributes are parsed as part of the declaration specifier, and everything is accepted.
attribute((cdecl)) [[noreturn]] __declspec(dllexport) void f();
In this case, nothing is parsed as part of the top-level declaration, and everything is parsed as part of the declaration specifier. However, the C++ attribute is prohibited from appearing on a declaration specifier and so is diagnosed.
I think ParseDeclarationSpecifiers() needs to accept a ParsedAttributesWithRange object representing the top-level declaration attributes, and the parser needs to attach the C++ attributes to it up until we the first non-attribute token is found. But I'm not 100% certain that's the right approach.
Before taking the process further, I was wondering about two things:
- Is the direction with MaybeParseAttributes() an acceptable approach?
- If it is, is it reasonable to commit that, and work on the ParseDeclarationSpecifiers() portion in a follow-up commit?
Thanks!
~Aaron
This seems wrong: given [[foo]] [[bar]], we'll now parse the second one as an MS attribute in a context where both are allowed.