Page MenuHomePhabricator

[PATCH] Relax parse ordering rules for attributes
AbandonedPublic

Authored by aaron.ballman on Aug 26 2015, 11:27 AM.

Details

Reviewers
hans
rsmith
Summary

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:

  1. Is the direction with MaybeParseAttributes() an acceptable approach?
  2. If it is, is it reasonable to commit that, and work on the ParseDeclarationSpecifiers() portion in a follow-up commit?

Thanks!

~Aaron

Diff Detail

Event Timeline

aaron.ballman retitled this revision from to [PATCH] Relax parse ordering rules for attributes.
aaron.ballman updated this object.
aaron.ballman added reviewers: rsmith, hans.
aaron.ballman added a subscriber: cfe-commits.

I've updated the patch to disallow reordering of C++11 attributes with relation to other attribute syntaxes. Additionally, if there is a reordering issue found, we now warn the user.

rsmith added inline comments.Aug 27 2015, 2:34 PM
lib/Parse/ParseDeclCXX.cpp
3923

Please provide an inlineable wrapper for this that checks if the current token is [, __declspec, or __attribute__ before calling into this, as we do for the existing MaybeParse* functions.

3942–3946

I'm not convinced this is right. It seems like there are two different cases:

  1. Some context accepts a sequence of attributes before other things, such as:

    struct attribute((blah)) [[blah]] S;

There doesn't seem to be a principled reason to reject this.

  1. Different attributes appear as different components of the grammar, such as:

    [[before_declaration]] attribute((im_a_decl_specifier)) int n; attribute((im_a_decl_specifier)) [[i_dont_go_here]] int n;

Only the second case should be rejected here. (And I think we should provide an error not just a warning if we don't like this case.)

I think the right thing to do is probably to always parse all attribute syntaxes (except for MS attributes, which are ambiguous with other constructs), and give a nicely-worded error if we see an unexpected syntax.

3956–3959

This seems wrong: given [[foo]] [[bar]], we'll now parse the second one as an MS attribute in a context where both are allowed.

aaron.ballman abandoned this revision.Jun 1 2017, 10:52 AM