aaron.ballman 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:
> 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.


Repository:
  rG LLVM Github Monorepo

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