mboehme added inline comments.
================
Comment at: clang/test/SemaCXX/annotate-type.cpp:2
+// RUN: %clang_cc1 %s -std=c++17 -fsyntax-only -verify
+
+struct S1 {
----------------
rsmith wrote:
> mboehme wrote:
> > rsmith wrote:
> > > mboehme wrote:
> > > > aaron.ballman wrote:
> > > > > mboehme wrote:
> > > > > > aaron.ballman wrote:
> > > > > > > mboehme wrote:
> > > > > > > > aaron.ballman wrote:
> > > > > > > > > mboehme wrote:
> > > > > > > > > > aaron.ballman wrote:
> > > > > > > > > > > mboehme wrote:
> > > > > > > > > > > > aaron.ballman wrote:
> > > > > > > > > > > > > mboehme wrote:
> > > > > > > > > > > > > > aaron.ballman wrote:
> > > > > > > > > > > > > > > Can you also add some test coverage for applying
> > > > > > > > > > > > > > > the attribute to a declaration instead of a type
> > > > > > > > > > > > > > > or not giving it any arguments? Also, should test
> > > > > > > > > > > > > > > arguments which are not a constant expression.
> > > > > > > > > > > > > > I've added tests as you suggested, though I put
> > > > > > > > > > > > > > most of them in Sema/annotate-type.c, as they're
> > > > > > > > > > > > > > not specific to C++.
> > > > > > > > > > > > > >
> > > > > > > > > > > > > > Thanks for prompting me to do this -- the tests
> > > > > > > > > > > > > > caused me to notice and fix a number of bugs.
> > > > > > > > > > > > > >
> > > > > > > > > > > > > > I haven't managed to diagnose the case when the
> > > > > > > > > > > > > > attribute appears at the beginning of the
> > > > > > > > > > > > > > declaration. It seems to me that, at the point
> > > > > > > > > > > > > > where I've added the check, this case is
> > > > > > > > > > > > > > indistinguishable from an attribute that appears on
> > > > > > > > > > > > > > the type. In both cases, the `TAL` is
> > > > > > > > > > > > > > `TAL_DeclSpec`, and the attribute is contained in
> > > > > > > > > > > > > > `DeclSpec::getAttributes()`. This is because
> > > > > > > > > > > > > > `Parser::ParseSimpleDeclaration` forwards the
> > > > > > > > > > > > > > declaration attributes to the `DeclSpec`:
> > > > > > > > > > > > > >
> > > > > > > > > > > > > > https://github.com/llvm/llvm-project/blob/main/clang/lib/Parse/ParseDecl.cpp#L1851
> > > > > > > > > > > > > >
> > > > > > > > > > > > > > I believe if I wanted to prohibit this case, I
> > > > > > > > > > > > > > would need to add a check to
> > > > > > > > > > > > > > `Parser::ParseStatementOrDeclaration` and prohibit
> > > > > > > > > > > > > > any occurrences of `annotate_type` there. However,
> > > > > > > > > > > > > > this seems the wrong place to do this because it
> > > > > > > > > > > > > > doesn't contain any specific processing for other
> > > > > > > > > > > > > > attributes.
> > > > > > > > > > > > > >
> > > > > > > > > > > > > > I've noticed that Clang also doesn't prohibit other
> > > > > > > > > > > > > > type attributes (even ones with C++ 11 syntax) from
> > > > > > > > > > > > > > being applied to declarations. For example:
> > > > > > > > > > > > > > https://godbolt.org/z/Yj1zWY7nn
> > > > > > > > > > > > > >
> > > > > > > > > > > > > > How do you think I should proceed here? I think the
> > > > > > > > > > > > > > underlying issue is that Clang doesn't always
> > > > > > > > > > > > > > distinguish cleanly between declaration attributes
> > > > > > > > > > > > > > and type attributes, and fixing this might be
> > > > > > > > > > > > > > nontrivial.
> > > > > > > > > > > > > > How do you think I should proceed here? I think the
> > > > > > > > > > > > > > underlying issue is that Clang doesn't always
> > > > > > > > > > > > > > distinguish cleanly between declaration attributes
> > > > > > > > > > > > > > and type attributes, and fixing this might be
> > > > > > > > > > > > > > nontrivial.
> > > > > > > > > > > > >
> > > > > > > > > > > > > This is a general issue with attribute processing. I
> > > > > > > > > > > > > would imagine that SemaDeclAttr.cpp should be able to
> > > > > > > > > > > > > diagnose that case when the attribute only applies to
> > > > > > > > > > > > > types and not declarations, but it'd take some
> > > > > > > > > > > > > investigation for me to be sure.
> > > > > > > > > > > > >
> > > > > > > > > > > > > Because this issue isn't new to your situation, I'd
> > > > > > > > > > > > > recommend filing an issue about the general problem
> > > > > > > > > > > > > and then we can solve that later.
> > > > > > > > > > > > I've done some more investigation myself, and I think
> > > > > > > > > > > > I've come up with a solution; actually, two potential
> > > > > > > > > > > > solutions. I have draft patches for both of these; I
> > > > > > > > > > > > wanted to run these by you here first, so I haven't
> > > > > > > > > > > > opened a bug yet.
> > > > > > > > > > > >
> > > > > > > > > > > > I'd appreciate your input on how you'd prefer me to
> > > > > > > > > > > > proceed with this. I do think it makes sense to do this
> > > > > > > > > > > > work now because otherwise, people will start putting
> > > > > > > > > > > > `annotate_type` in places where it doesn't belong, and
> > > > > > > > > > > > then we'll have to keep supporting that in the future.
> > > > > > > > > > > >
> > > > > > > > > > > > **My preferred solution**
> > > > > > > > > > > >
> > > > > > > > > > > > https://reviews.llvm.org/D124081
> > > > > > > > > > > >
> > > > > > > > > > > > This adds a function `DiagnoseCXX11NonDeclAttrs()` and
> > > > > > > > > > > > calls it in all places where we should reject
> > > > > > > > > > > > attributes that can't be put on declarations. (As part
> > > > > > > > > > > > of this work, I noticed that `gsl::suppress` should be
> > > > > > > > > > > > a `DeclOrStmtAttr`, not just a `StmtAttr`.)
> > > > > > > > > > > >
> > > > > > > > > > > > Advantages:
> > > > > > > > > > > > - Not very invasive.
> > > > > > > > > > > > Disadvantages:
> > > > > > > > > > > > - Need to make sure we call
> > > > > > > > > > > > `DiagnoseCXX11NonDeclAttrs()` everywhere that
> > > > > > > > > > > > non-declaration attributes should be rejected. (Not
> > > > > > > > > > > > sure if I've identified all of those places yet?)
> > > > > > > > > > > >
> > > > > > > > > > > > **Alternative solution**
> > > > > > > > > > > >
> > > > > > > > > > > > https://reviews.llvm.org/D124083
> > > > > > > > > > > >
> > > > > > > > > > > > This adds an `appertainsTo` parameter to
> > > > > > > > > > > > `ParseCXX11Attributes()` and other "parse attributes"
> > > > > > > > > > > > functions that call it. This parameter specifies
> > > > > > > > > > > > whether the attributes in the place where they're
> > > > > > > > > > > > currently being parsed appertain to a declaration,
> > > > > > > > > > > > statement or type. If `ParseCXX11Attributes()`
> > > > > > > > > > > > encounters an attribute that is not compatible with
> > > > > > > > > > > > `appertainsTo`, it outputs a diagnostic.
> > > > > > > > > > > >
> > > > > > > > > > > > Advantages:
> > > > > > > > > > > > - Every call to `ParseCXX11Attributes()` _has_ to
> > > > > > > > > > > > specify `appertainsTo` -- so there's no risk of missing
> > > > > > > > > > > > some case where we have to output diagnostics
> > > > > > > > > > > > Disadvantages:
> > > > > > > > > > > > - This change is _much_ more invasive.
> > > > > > > > > > > > - It's not always clear what value to specify for
> > > > > > > > > > > > `appertainsTo`. The poster child for this is
> > > > > > > > > > > > `Parser::ParseStatementOrDeclaration()`: As the name
> > > > > > > > > > > > says, we don't yet know whether we're parsing a
> > > > > > > > > > > > statement or a declaration. As a result, we need to be
> > > > > > > > > > > > able to specify `AppertainsToUnknown` and would need to
> > > > > > > > > > > > add additional logic deeper in the call stack to
> > > > > > > > > > > > produce diagnostics once we know for sure whether we're
> > > > > > > > > > > > dealing with a statement or declaration. (This isn't
> > > > > > > > > > > > yet implemented.) This makes the solution less elegant
> > > > > > > > > > > > that it initially seems.
> > > > > > > > > > > > - There's a tension between this new functionality and
> > > > > > > > > > > > the existing `ParsedAttr::diagnoseAppertainsTo()`.
> > > > > > > > > > > > However, we unfortunately can't extend the existing
> > > > > > > > > > > > `ParsedAttr::diagnoseAppertainsTo()` because it is
> > > > > > > > > > > > called from `ProcessDeclAttribute()` and (despite the
> > > > > > > > > > > > name) that function is also processes some legitimate
> > > > > > > > > > > > type attributes.
> > > > > > > > > > > > I do think it makes sense to do this work now because
> > > > > > > > > > > > otherwise, people will start putting annotate_type in
> > > > > > > > > > > > places where it doesn't belong, and then we'll have to
> > > > > > > > > > > > keep supporting that in the future.
> > > > > > > > > > >
> > > > > > > > > > > Thank you for working on this now, I agree that'd be good
> > > > > > > > > > > to avoid.
> > > > > > > > > > >
> > > > > > > > > > > My concern with both of those approaches is that they
> > > > > > > > > > > impact *parsing* rather than *semantics* and that seems
> > > > > > > > > > > wrong. As far as the parser is concerned, attributes
> > > > > > > > > > > really only exist as one particular form of syntax or
> > > > > > > > > > > another, but it shouldn't care about whether an attribute
> > > > > > > > > > > is allowed to appertain to a particular thing or not.
> > > > > > > > > > > e.g., an attribute list can either appear somewhere in
> > > > > > > > > > > the syntax or it can't, but what particular attributes
> > > > > > > > > > > are specified do not matter at parsing time. Parsing
> > > > > > > > > > > determine what the attribute is associated with (a
> > > > > > > > > > > declaration, a type, a statement, etc). After we've
> > > > > > > > > > > finished parsing the attributes in the list, we convert
> > > > > > > > > > > the attributes into their semantic form and that's the
> > > > > > > > > > > time at which we care about whether the attribute may be
> > > > > > > > > > > written on the thing it appertains to.
> > > > > > > > > > >
> > > > > > > > > > > I think we handle all of the parsing correctly today
> > > > > > > > > > > already, but the issue is on the semantic side of things.
> > > > > > > > > > > An attribute at the start of a line can only be one of
> > > > > > > > > > > two things: a statement attribute or a declaration
> > > > > > > > > > > attribute, it can never be a type attribute. So what I
> > > > > > > > > > > think should happen is that `ProcessDeclAttribute()`
> > > > > > > > > > > needs to get smarter when it's given an attribute that
> > > > > > > > > > > can only appertain to a type. I don't think we should
> > > > > > > > > > > have to touch the parser at all, especially because you
> > > > > > > > > > > can specify multiple attributes in one list, as in:
> > > > > > > > > > > ```
> > > > > > > > > > > void func() {
> > > > > > > > > > > [[decl_attr, type_attr]] int foo;
> > > > > > > > > > > }
> > > > > > > > > > > ```
> > > > > > > > > > > and we'd want to diagnose `type_attr` but still allow
> > > > > > > > > > > `decl_attr`.
> > > > > > > > > > > I think we handle all of the parsing correctly today
> > > > > > > > > > > already
> > > > > > > > > >
> > > > > > > > > > I'm not sure about this. For example, take a look at
> > > > > > > > > > `Parser::ParseSimpleDeclaration`, which does this at the
> > > > > > > > > > end:
> > > > > > > > > >
> > > > > > > > > > ```
> > > > > > > > > > DS.takeAttributesFrom(Attrs);
> > > > > > > > > > ```
> > > > > > > > > >
> > > > > > > > > > Here, `DS` is a `ParsingDeclSpec`, and `Attrs` are the
> > > > > > > > > > attributes that were seen on the declaration (I believe).
> > > > > > > > > >
> > > > > > > > > > If my understanding of the code is correct (which it very
> > > > > > > > > > well may not be), this is putting the attributes that were
> > > > > > > > > > seen on the declaration in the same place
> > > > > > > > > > (`DeclSpec::Attrs`) that will later receive the attributes
> > > > > > > > > > seen on the decl-specifier-seq. Once we've put them there,
> > > > > > > > > > it is no longer possible to tell whether those attributes
> > > > > > > > > > were seen on the declaration (where type attributes are not
> > > > > > > > > > allowed) or on the decl-specifier-seq (where type
> > > > > > > > > > attributes _are_ allowed).
> > > > > > > > > >
> > > > > > > > > > (This is why https://reviews.llvm.org/D124081 adds a
> > > > > > > > > > `DiagnoseCXX11NonDeclAttrs(Attrs)` just before the
> > > > > > > > > > `DS.takeAttributesFrom(Attrs)` call -- because this is the
> > > > > > > > > > last point at which we haven't lumped declaration and
> > > > > > > > > > decl-specifier-seq attributes together.)
> > > > > > > > > >
> > > > > > > > > > `ProcessDeclAttribute()`, when called through
> > > > > > > > > > `Sema::ProcessDeclAttributes()` (which I think is the
> > > > > > > > > > relevant call stack), only sees attributes after they have
> > > > > > > > > > been put in `DeclSpec::Attrs`. (It therefore sees, and
> > > > > > > > > > ignores, all of the type attributes that were put on the
> > > > > > > > > > decl-specifier-seq.) So I think it isn't possible to tell
> > > > > > > > > > there whether we put a type attribute on a declaration.
> > > > > > > > > >
> > > > > > > > > > It might be possible to fix this by giving `DeclSpec` two
> > > > > > > > > > lists of attributes, one containing the attributes for the
> > > > > > > > > > declaration, and another containing the attributes for the
> > > > > > > > > > decl-specifier-seq itself. However, this is a pretty
> > > > > > > > > > invasive change, as everything that consumes attributes
> > > > > > > > > > from the `DeclSpec` potentially needs to be changed (I
> > > > > > > > > > tried and shied away from it).
> > > > > > > > > >
> > > > > > > > > > Am I misunderstanding something about the code? If not,
> > > > > > > > > > what are your thoughts on how best to proceed?
> > > > > > > > > > Am I misunderstanding something about the code? If not,
> > > > > > > > > > what are your thoughts on how best to proceed?
> > > > > > > > >
> > > > > > > > > I think your understanding is correct and I was imprecise. I
> > > > > > > > > meant that we generally parse the `[[]]` in all the expected
> > > > > > > > > locations in the parser. However, I think you're correct that
> > > > > > > > > the bits which determine what chunks in a declaration may
> > > > > > > > > need to be updated. That code largely exists because
> > > > > > > > > GNU-style attributes "slide" sometimes to other chunks, but
> > > > > > > > > that's not the case for [[]]-style attributes. It sounds like
> > > > > > > > > we are likely lacking expressivity for the `[[]]` type
> > > > > > > > > attributes in the hookup between what we parsed and when we
> > > > > > > > > form the semantic attribute because we need to convert the
> > > > > > > > > parsed type into a real type.
> > > > > > > > > It sounds like we are likely lacking expressivity for the
> > > > > > > > > [[]] type attributes in the hookup between what we parsed and
> > > > > > > > > when we form the semantic attribute because we need to
> > > > > > > > > convert the parsed type into a real type.
> > > > > > > >
> > > > > > > > OK, good, sounds like we're on the same page!
> > > > > > > >
> > > > > > > > I'll look at what we can do to retain the information of
> > > > > > > > whether an attribute was added to the declaration or the
> > > > > > > > decl-specifier-seq, so that Sema can then issue the correct
> > > > > > > > diagnostics. I'll look at changing `DeclSpec` so that it
> > > > > > > > retains not one, but two lists of attributes, for the
> > > > > > > > declaration and the decl-specifier-seq respectively. There are
> > > > > > > > likely to be some devils in the details -- `DeclSpec` allows
> > > > > > > > direct write access to its `Attrs` member variable through the
> > > > > > > > non-const version of `getAttributes()`, and there are quite a
> > > > > > > > few places in the code that call this. Does this seem like the
> > > > > > > > right direction to you in principle though?
> > > > > > > >
> > > > > > > > Apart from all of this, are there any outstanding issues that
> > > > > > > > you see with this change? It does of course make sense to
> > > > > > > > prohibit type attributes on declarations before I land this
> > > > > > > > change, but I wanted to check whether there's anything else
> > > > > > > > that would need to happen here.
> > > > > > > > Does this seem like the right direction to you in principle
> > > > > > > > though?
> > > > > > >
> > > > > > > Maybe. In terms of the standards concepts, a `decl-specifier-seq`
> > > > > > > can have attributes associated with it
> > > > > > > (https://eel.is/c++draft/dcl.dcl#dcl.spec.general-1.sentence-2)
> > > > > > > and so from that perspective, a `DeclSpec` seems like it should
> > > > > > > have only one list of attributes (those for the entire sequence
> > > > > > > of declaration specifiers). However, GNU-style attributes
> > > > > > > "slide" around to other things, so it's possible that the
> > > > > > > behavior in `ParseSimpleDeclaration()` is correct for that
> > > > > > > particular syntax but incorrect for `[[]]` style attributes. So,
> > > > > > > depending on which devilish details are learned while working on
> > > > > > > this, it may turn out that the best approach is a secondary list,
> > > > > > > or it may turn out that we want to add a new `takeAll` variant
> > > > > > > that takes only the correct attributes while leaving others. (It
> > > > > > > may be useful to summon @rsmith for opinions on the right
> > > > > > > approach to take here.)
> > > > > > >
> > > > > > > > Apart from all of this, are there any outstanding issues that
> > > > > > > > you see with this change? It does of course make sense to
> > > > > > > > prohibit type attributes on declarations before I land this
> > > > > > > > change, but I wanted to check whether there's anything else
> > > > > > > > that would need to happen here.
> > > > > > >
> > > > > > > Nothing else is jumping out at me as missing or needing
> > > > > > > additional work aside from some formatting nits. I'm going to add
> > > > > > > another reviewer just to make sure I've not missed something, but
> > > > > > > I think this is about ready to go.
> > > > > > Thanks for the input!
> > > > > >
> > > > > > I've looked at this more closely, and I've concluded that adding a
> > > > > > second list of attributes to the `DeclSpec` isn't really the right
> > > > > > way to go. For one thing, as you say, the attributes we're
> > > > > > discussing don't really belong on the decl-specifier-seq.
> > > > > >
> > > > > > But I _have_ come up with an alternative solution that I like
> > > > > > better than the alternatives I had considered so far and that, as
> > > > > > you suggest, emits the diagnostics from Sema, not the Parser. The
> > > > > > solution is not just more concise than the other options I had
> > > > > > explored but also just feels like the right way of doing things.
> > > > > >
> > > > > > Taking a look at the standard, attributes in the location in
> > > > > > question (at the beginning of a simple-declaration) have the same
> > > > > > semantics as attributes that appear after a declarator-id, and we
> > > > > > already have a location to store the latter, namely
> > > > > > `Declarator::Attr`. It therefore seems the right thing to do also
> > > > > > put attributes from the simple-declaration in `Declarator::Attr`.
> > > > > > We can then take advantage of the fact that there is existing code
> > > > > > already in place to deal with attributes in this location.
> > > > > >
> > > > > > The other part of the solution is to make `ProcessDeclAttribute`
> > > > > > warn about C++11 attributes that don’t “slide” to the DeclSpec
> > > > > > (except, of course, if `ProcessDeclAttribute` is actually being
> > > > > > called for attributes on a `DeclSpec` or `Declarator`).
> > > > > >
> > > > > > Here’s a draft change that implements this:
> > > > > >
> > > > > > https://reviews.llvm.org/D124919
> > > > > >
> > > > > > (The change description contains more details on the attribute
> > > > > > semantics from the standard that I alluded to above.)
> > > > > >
> > > > > > The change still contains a few TODOs, but all of the hard bits are
> > > > > > done. Specifically, all of the tests pass too. I feel pretty good
> > > > > > about this change, but before I work on it further to get it ready
> > > > > > for review, I wanted to get your reaction: Do you agree that this
> > > > > > is the right general direction?
> > > > > > The change still contains a few TODOs, but all of the hard bits are
> > > > > > done. Specifically, all of the tests pass too. I feel pretty good
> > > > > > about this change, but before I work on it further to get it ready
> > > > > > for review, I wanted to get your reaction: Do you agree that this
> > > > > > is the right general direction?
> > > > >
> > > > > Thank you for your continued work on this, I *really* appreciate it!
> > > > > I think your newest approach is the one I'm happiest with, though
> > > > > there are still parts of it I hope we can find ways to improve. My
> > > > > biggest concern is with having to sprinkle
> > > > > `ExtractDefiniteDeclAttrs()` in the "correct" places, as that's
> > > > > likely to be fragile. If there was a way we only had to do that once
> > > > > instead of 8 times, I'd be much happier. My worry is mostly with
> > > > > someone forgetting to call it when they should or thinking they need
> > > > > to call it when modeling new code on existing code.
> > > > >
> > > > > Aside from that, I think the approach you've got is quite reasonable,
> > > > > though I'd be curious if @rsmith or @rjmccall have additional
> > > > > thoughts or concerns that I might not be seeing yet.
> > > > > My biggest concern is with having to sprinkle
> > > > > `ExtractDefiniteDeclAttrs()` in the "correct" places, as that's
> > > > > likely to be fragile. If there was a way we only had to do that once
> > > > > instead of 8 times, I'd be much happier. My worry is mostly with
> > > > > someone forgetting to call it when they should or thinking they need
> > > > > to call it when modeling new code on existing code.
> > > >
> > > > Agree. I would also prefer it if we could only do this in once place --
> > > > but I can't really come up with a good way to do this.
> > > >
> > > > The underlying reason for why we're doing this in multiple places is
> > > > that there are multiple places in the C++ grammar where an
> > > > attribute-specifier-seq can occur that appertains to a declaration
> > > > (e.g. in a simple-declaration, parameter-declaration,
> > > > exception-declaration, and so on). These are parsed in different places
> > > > in the code, and so we also need to add `ExtractDefiniteDeclAttrs()` in
> > > > those different places. If a future change to the language adds another
> > > > type of declaration that can contain an attribute-specifier-seq, we'll
> > > > have to add a new `ExtractDefiniteDeclAttrs()` there as well -- but
> > > > that's really just a part of saying that we need to write code that
> > > > parses that entire type of declaration correctly.
> > > >
> > > > Unfortunately, I don't really see what we could do to make sure people
> > > > don't get this wrong. The motivation behind my previous attempt in
> > > > https://reviews.llvm.org/D124083 was to try and make errors impossible
> > > > by making callers of `ParseCXX11Attributes` (and related functions)
> > > > specify what entity (type, statement, or declaration) the attributes
> > > > appertain to in the current position. Unfortunately, this can't be done
> > > > consistently, as we don't actually always know what entity the
> > > > attributes should appertain to (e.g. in
> > > > `Parser::ParseStatementOrDeclaration`), and the approach has other
> > > > downsides, as we've discussed before.
> > > >
> > > > > Aside from that, I think the approach you've got is quite reasonable,
> > > > > though I'd be curious if @rsmith or @rjmccall have additional
> > > > > thoughts or concerns that I might not be seeing yet.
> > > >
> > > > I'd like to hear their input too! Besides your mentioning them here, is
> > > > there anything else we need to do to make sure they see this? (Should I
> > > > reach out to @rsmith internally?)
> > > >
> > > > By the way, https://reviews.llvm.org/D124919 currently depends on this
> > > > change (https://reviews.llvm.org/D111548), so that we can show the
> > > > effect that it has on the tests for `annotate_type`, but if we agree
> > > > that https://reviews.llvm.org/D124919 is what we want to proceed with,
> > > > I would plan to submit it first so that we have the "protections" it
> > > > provides in place before adding the new attribute.
> > > I think the right approach here is that `ParseDeclaration`,
> > > `ParseExternalDeclaration`, and friends should only be given an attribute
> > > list that includes declaration attributes (that is, C++11 attribute
> > > syntax attributes), and that list should not be muddled into the list of
> > > decl specifier attributes.
> > >
> > > As far as I can see, that is in fact already the case with only two
> > > exceptions;
> > >
> > > 1) `ParseExportDeclaration` parses MS attributes before recursing into
> > > `ParseExternalDeclaration`. That looks like it's simply a bug as far as I
> > > can tell, and that call can be removed. MS attributes will be parsed as
> > > part of the decl specifier sequence as needed and don't need to be parsed
> > > as declaration attributes.
> > > 2) `ParseStatementOrDeclarationAfterAttributes` is called after parsing
> > > an initial sequence of GNU attributes that might be part of the
> > > decl-specifier-seq, or might precede a label. In this case, we should
> > > simply have two attribute lists: the C++11-syntax declaration attributes,
> > > and the GNU decl-specifier-seq attributes that we've effectively
> > > tentatively parsed past.
> > >
> > > All other code paths into `ParseExternalDeclaration` / `ParseDeclaration`
> > > / `ParseSimpleDeclaration` parse only C++11 attribute syntax before
> > > getting there.
> > >
> > > With those two exceptions changed, we should be able to keep the
> > > declaration attributes entirely separate from the decl-specifier-seq
> > > attributes. We can then carefully re-implement the "sliding" of
> > > declaration attributes onto the type in the cases where we want to do so
> > > for compatibility.
> > > I think the right approach here is that ParseDeclaration,
> > > ParseExternalDeclaration, and friends should only be given an attribute
> > > list that includes declaration attributes (that is, C++11 attribute
> > > syntax attributes), and that list should not be muddled into the list of
> > > decl specifier attributes.
> >
> > I think this makes sense, but I'm not sure how we would do this in the
> > specific case of `ParseStatementOrDeclarationAfterAttributes` -- see
> > discussion below.
> >
> > Also, I wanted to make sure we're on the same page about a specific point:
> > For backwards compatibility, we need to continue to "slide" some C++11
> > attributes to the `DeclSpec`, namely those type attributes for which we
> > have allowed this so far. Do you agree?
> >
> > > 1. ParseExportDeclaration parses MS attributes before recursing into
> > > ParseExternalDeclaration. That looks like it's simply a bug as far as I
> > > can tell, and that call can be removed. MS attributes will be parsed as
> > > part of the decl specifier sequence as needed and don't need to be parsed
> > > as declaration attributes
> >
> > That makes sense -- and indeed none of the other callers of
> > `ParseExternalDeclaration` parse MS attributes before calling it.
> >
> > I've tried removing the two calls to `MaybeParseMicrosoftAttributes` in
> > `ParseExportDeclaration`, and all of the tests still pass.
> >
> > I'm not sure though if this may produce new errors on some invalid code
> > that we used to allow, namely those cases in `ParseExternalDeclaration`
> > that call through to `ParseDeclaration` rather than
> > `ParseDeclOrFunctionDefInternal`. From looking at the code, one erroneous
> > code sample that I expected the current code to allow is `export
> > __declspec(deprecated) namespace foo {}`, but it appears that we don't
> > (https://godbolt.org/z/b4sE8E8GG). So maybe there's no concern here?
> >
> > If we don't think there are any issues with this, I would prepare a small
> > patch that removes these two calls to `MaybeParseMicrosoftAttributes`. (I
> > think this can and should be a separate patch as it's otherwise independent
> > of the wider issue we're discussing here.)
> >
> > > 2. ParseStatementOrDeclarationAfterAttributes is called after parsing an
> > > initial sequence of GNU attributes that might be part of the
> > > decl-specifier-seq, or might precede a label. In this case, we should
> > > simply have two attribute lists: the C++11-syntax declaration attributes,
> > > and the GNU decl-specifier-seq attributes that we've effectively
> > > tentatively parsed past.
> >
> > To make sure I understand: What you're saying is that
> > `ParseStatementOrDeclarationAfterAttributes` should take two
> > `ParsedAttributes` arguments, one for the C++11 attributes and one for the
> > GNU attributes?
> >
> > What I'm not quite clear on is how
> > `ParseStatementOrDeclarationAfterAttributes` should handle these two
> > attribute lists further. There are two places in this function that call
> > through to `ParseDeclaration` and I think you're saying that you'd like
> > `ParseDeclaration` to only take a list of C++11 attributes. But what should
> > `ParseStatementOrDeclarationAfterAttributes` then do with the GNU
> > attributes -- it can't simply drop them on the floor?
> >
> > Or does this mean that `ParseDeclaration` also needs to take two
> > `ParsedAttributes` arguments (and similarly for any other `Parse*`
> > functions it passes the attributes on to)? This is certainly doable, but
> > I'm not sure that we get much benefit from it. As noted at the beginning of
> > this comment, some "legacy" C++11 type attributes will also need to "slide"
> > to the `DeclSpec` for backwards compatibility, so we can't simply put all
> > the C++11 attributes on the declaration (which would be the attraction of
> > having separate lists). At that point, it doesn't seem too harmful to me to
> > have a single `ParsedAttributes` argument containing all of the attributes
> > (C++11 and GNU) that were specified at the beginning of the declaration.
> >
> > > With those two exceptions changed, we should be able to keep the
> > > declaration attributes entirely separate from the decl-specifier-seq
> > > attributes. We can then carefully re-implement the "sliding" of
> > > declaration attributes onto the type in the cases where we want to do so
> > > for compatibility.
> >
> > This is essentially what https://reviews.llvm.org/D124919 does. To
> > emphasize this (and simplify the code slightly at the same time), I've
> > replaced the previous `ExtractDefiniteDeclAttrs()` with a function called
> > `SlideAttrsToDeclSpec()` that moves the "sliding" attributes from the
> > original `ParsedAttributes` directly to the `DeclSpec`. Is this along the
> > lines of what you were thinking of?
> > For backwards compatibility, we need to continue to "slide" some C++11
> > attributes to the `DeclSpec`, namely those type attributes for which we
> > have allowed this so far. Do you agree?
>
> I think we should allow this in the short term, but aim to remove it after
> we've been warning on it for a release or two. I'd even be OK with the
> warning being an error by default when it lands.
>
> > From looking at the code, one erroneous code sample that I expected the
> > current code to allow is `export __declspec(deprecated) namespace foo {}`,
> > but it appears that we don't (https://godbolt.org/z/b4sE8E8GG). So maybe
> > there's no concern here?
>
> MS attributes are `[`...`]` attributes, so the testcase would be `export
> [blah] namespace foo {}`, which we do currently erroneously accept. Still, I
> think that's highly unlikely to be a concern. Our support for C++20 modules
> is new, experimental, and incomplete; there's no need to worry about
> backwards-incompatibility here.
>
> > To make sure I understand: What you're saying is that
> > `ParseStatementOrDeclarationAfterAttributes` should take two
> > `ParsedAttributes` arguments, one for the C++11 attributes and one for the
> > GNU attributes?
>
> I would phrase that as: one for declaration attributes, and one for
> decl-specifier attributes (put another way: one parameter for declaration
> attributes, and one parameter for the portion of a decl-specifier-seq that we
> parsed while looking for a label, which happens to be only GNU attributes).
> But yes.
>
> > What I'm not quite clear on is how
> > `ParseStatementOrDeclarationAfterAttributes` should handle these two
> > attribute lists further. There are two places in this function that call
> > through to `ParseDeclaration` and I think you're saying that you'd like
> > `ParseDeclaration` to only take a list of C++11 attributes. But what should
> > `ParseStatementOrDeclarationAfterAttributes` then do with the GNU
> > attributes -- it can't simply drop them on the floor?
> >
> > Or does this mean that `ParseDeclaration` also needs to take two
> > `ParsedAttributes` arguments (and similarly for any other `Parse*`
> > functions it passes the attributes on to)? This is certainly doable, but
> > I'm not sure that we get much benefit from it. As noted at the beginning of
> > this comment, some "legacy" C++11 type attributes will also need to "slide"
> > to the `DeclSpec` for backwards compatibility, so we can't simply put all
> > the C++11 attributes on the declaration (which would be the attraction of
> > having separate lists).
>
> Yes, we should propagate the two lists into `ParseDeclaration` and
> `ParseSimpleDeclaration`. That should be the end of it:
> `ParseSimpleDeclaration` forms a `ParsingDeclSpec`, which can be handed the
> decl-specifier attributes. The other cases that `ParseDeclaration` can reach
> should all prohibit decl-specifier attributes.
>
> > At that point, it doesn't seem too harmful to me to have a single
> > `ParsedAttributes` argument containing all of the attributes (C++11 and
> > GNU) that were specified at the beginning of the declaration.
>
> I think it will be best for ongoing maintenance if we model the grammar in
> the parser as it is -- C++11 declaration attributes are a separate list
> that's not part of the decl-specifier-seq, and I expect we will have emergent
> bugs and confusion if we try to combine them. Attribute handling in
> declaration parsing is already made confusing because we don't clearly
> distinguish between these two lists, leading to bugs like parsing MS
> attributes in `ParseExportDeclaration`.
>
> > > With those two exceptions changed, we should be able to keep the
> > > declaration attributes entirely separate from the decl-specifier-seq
> > > attributes. We can then carefully re-implement the "sliding" of
> > > declaration attributes onto the type in the cases where we want to do so
> > > for compatibility.
> >
> > This is essentially what https://reviews.llvm.org/D124919 does. To
> > emphasize this (and simplify the code slightly at the same time), I've
> > replaced the previous `ExtractDefiniteDeclAttrs()` with a function called
> > `SlideAttrsToDeclSpec()` that moves the "sliding" attributes from the
> > original `ParsedAttributes` directly to the `DeclSpec`. Is this along the
> > lines of what you were thinking of?
>
> Approximately. I also think we should avoid moving attributes around between
> attribute lists entirely, and instead preserve the distinct attribute lists
> until we reach the point where we can apply them to a declaration in `Sema`.
> I would note that the approach in that patch seems like it'll reorder
> attributes, and we have attributes where the order matters (eg,
> `[[clang::enable_if(a, "")]] void f [[clang::enable_if(b, "")]]()`). Also,
> moving attributes around makes it hard to properly handle source locations /
> ranges for attributes.
>
> In particular: I would make the `ParsingDeclarator` have a pointer to the
> declaration attributes in addition to its list of attributes on the
> declarator-id. Then, when we apply those attributes to the declaration, pull
> them from both places (declaration attributes then declarator-id attributes,
> to preserve source order, skipping "slided" type attributes in the former
> list). And when we form the type for the declarator, also apply any
> attributes from the declaration's attribute list that should be "slided" on
> the type.
(Oops -- only just realized that I wrote up this comment in draft form last
week but never sent it.)
Thank you for the really in-depth reply!
> > For backwards compatibility, we need to continue to "slide" some C++11
> > attributes to the `DeclSpec`, namely those type attributes for which we
> > have allowed this so far. Do you agree?
>
> I think we should allow this in the short term, but aim to remove it after
> we've been warning on it for a release or two. I'd even be OK with the
> warning being an error by default when it lands.
And there would be a command-line flag that would allow "downgrading" the error
to a warning?
> > From looking at the code, one erroneous code sample that I expected the
> > current code to allow is `export __declspec(deprecated) namespace foo {}`,
> > but it appears that we don't (https://godbolt.org/z/b4sE8E8GG). So maybe
> > there's no concern here?
>
> MS attributes are `[`...`]` attributes,
Oops *facepalm* A closer look at `ParseMicrosoftAttributes` could have told me
that. I didn't even know of these until now TBH.
> so the testcase would be `export [blah] namespace foo {}`, which we do
> currently erroneously accept. Still, I think that's highly unlikely to be a
> concern. Our support for C++20 modules is new, experimental, and incomplete;
> there's no need to worry about backwards-incompatibility here.
Got it. I'll submit a separate small patch that removes those two calls to
`MaybeParseMicrosoftAttributes` then.
> > To make sure I understand: What you're saying is that
> > `ParseStatementOrDeclarationAfterAttributes` should take two
> > `ParsedAttributes` arguments, one for the C++11 attributes and one for the
> > GNU attributes?
>
> I would phrase that as: one for declaration attributes, and one for
> decl-specifier attributes (put another way: one parameter for declaration
> attributes, and one parameter for the portion of a decl-specifier-seq that we
> parsed while looking for a label, which happens to be only GNU attributes).
> But yes.
Got it, that makes sense.
[snip]
> > This is essentially what https://reviews.llvm.org/D124919 does. To
> > emphasize this (and simplify the code slightly at the same time), I've
> > replaced the previous `ExtractDefiniteDeclAttrs()` with a function called
> > `SlideAttrsToDeclSpec()` that moves the "sliding" attributes from the
> > original `ParsedAttributes` directly to the `DeclSpec`. Is this along the
> > lines of what you were thinking of?
>
> Approximately. I also think we should avoid moving attributes around between
> attribute lists entirely, and instead preserve the distinct attribute lists
> until we reach the point where we can apply them to a declaration in `Sema`.
> I would note that the approach in that patch seems like it'll reorder
> attributes, and we have attributes where the order matters (eg,
> `[[clang::enable_if(a, "")]] void f [[clang::enable_if(b, "")]]()`). Also,
> moving attributes around makes it hard to properly handle source locations /
> ranges for attributes.
Thanks for pointing out the importance of ordering. I did notice some ordering
issues while working on https://reviews.llvm.org/D124919 (see comments in
SlideAttrsToDeclSpec() if you're interested), but this drives home the point
that we need to be careful about ordering.
> In particular: I would make the `ParsingDeclarator` have a pointer to the
> declaration attributes in addition to its list of attributes on the
> declarator-id. Then, when we apply those attributes to the declaration, pull
> them from both places (declaration attributes then declarator-id attributes,
> to preserve source order, skipping "slided" type attributes in the former
> list). And when we form the type for the declarator, also apply any
> attributes from the declaration's attribute list that should be "slided" on
> the type.
Thanks, I think I can see how that's going to work.
I'll attempt to implement this, which will likely take a few days, and will
report back when I have something that works and that I'd like to get feedback
on. I may also have some followup questions if I run into unanticipated
problems (which is more likely than not, I assume).
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D111548/new/
https://reviews.llvm.org/D111548
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits