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 {
----------------
mboehme wrote:
> mboehme wrote:
> > 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).
> @rsmith I have a draft implementation of the idea we discussed above here:
> 
> https://reviews.llvm.org/D126061
> 
> (All tests pass.)
> 
> I'd appreciate your feedback. Does this look like what you had in mind?
> 
> There's one main point I'd like to discuss. I've chosen to store the 
> declaration attributes in a new field on the `Declarator`, so we now have 
> `Declarator::Attrs` and `Declarator::DeclarationAttrs` (and I believe this is 
> what we had discussed before). This makes sense from a semantic point of view 
> because attributes in both positions have the same meaning.
> 
> However there's one point I'm not completely satisfied with: Because a single 
> declaration can have multiple declarators, we need to make sure that we 
> preserve the declaration attributes when we reuse a `Declarator` for multiple 
> declarators in a single declaration. This gives rise to the slightly 
> unfortunate `Declarator::clearExceptDeclarationAttrs()`.
> 
> All in all, I feel the implementation would be cleaner if we put the 
> declaration attributes on the `DeclSpec` instead of the `Declarator`, even if 
> the declaration attributes are semantically less related to the `DeclSpec` 
> than the `Declarator`. What do you think?
PS Another option would be to introduce a `Declaration` class and put the 
declaration attributes on that. The `Declarator` would hold a reference to the 
`Declaration`.

This solution would represent the actual entities in the grammar best, but I 
wonder if it's worth introducing a `Declarator` class for this purpose alone. 
There might also be potential for confusion because we already have a `Decl` 
class in the AST.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D111548/new/

https://reviews.llvm.org/D111548

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to