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
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to