aaron.ballman added a comment. In D126061#3577054 <https://reviews.llvm.org/D126061#3577054>, @mboehme wrote:
> @aaron.ballman Any further comments from you on this change? Mostly just nits from me at this point, plus some answers to questions I had missed previously. > There is some breakage in the pre-merge checks, but it looks as if it's > pre-existing breakage. See the comment-only change here that looks as if it > exhibits similar breakage: > > https://reviews.llvm.org/D127494 I agree that the precommit CI failures look unrelated to this patch. ================ Comment at: clang/include/clang/Basic/AttributeCommonInfo.h:153 // FIXME: Use a better mechanism to determine this. + // We use this in `isCXX11Attribute` below, so it _should_ only return + // true for the `alignas` spelling, but it currently also returns true ---------------- Now that C23 has attributes, it's also not clear whether `_Alignas` will be handled slightly differently in the future as an attribute rather than a declaration specifier as happened with `_Noreturn` for C23. So agreed this is a tricky area. ================ Comment at: clang/include/clang/Sema/DeclSpec.h:1916 + /// declaration, i.e. `x` and `y` in this case. + Declarator(const DeclSpec &ds, const ParsedAttributesView &DeclarationAttrs, + DeclaratorContext C) ---------------- I know it's pre-existing code, but since you're updating the parameters and adding some great comments, can you rename `ds` to `DS` per coding style guides? ================ Comment at: clang/include/clang/Sema/DeclSpec.h:1928-1930 + assert(llvm::all_of(DeclarationAttrs, [](const ParsedAttr &AL) { + return AL.isStandardAttributeSyntax(); + })); ---------------- Can you add an `&& "and this is what the assert is testing for"` message here so when the assertion fails there's more details as to what went sideways? ================ Comment at: clang/include/clang/Sema/ParsedAttr.h:1126 +/// `Result`. Sets `Result.Range` to the combined range of `First` and `Second`. +void ConcatenateAttributes(ParsedAttributes &First, ParsedAttributes &Second, + ParsedAttributes &Result); ---------------- I think `Concatenate` implies that `First` and `Second` are untouched, but that's not really the case here. Perhaps `takeAndConcatenateAll()` or something along those lines instead? Also, the function should start with a lowercase letter per the usual coding style rules. ================ Comment at: clang/include/clang/Sema/ParsedAttr.h:664 + /// This may only be called if isStandardAttributeSyntax() returns true. + bool slidesFromDeclToDeclSpec() const; + ---------------- mboehme wrote: > aaron.ballman wrote: > > Because this is now specific to standard attributes, and those don't > > "slide" under normal circumstances, it might be nice to rename this method > > to make it more clear that this should not be called normally. I don't have > > a strong opinion on what a *good* name is, but even something like > > `improperlySlidesFromDeclToDeclSpec()` would make me happy. > I've decided to add `LegacyBehavior` at the end -- WDYT? Works for me ================ Comment at: clang/lib/Parse/ParseStmt.cpp:229 default: { + auto isStmtAttr = [](ParsedAttr &Attr) { return Attr.isStmtAttr(); }; if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt || ---------------- Coding style nit. ================ Comment at: clang/lib/Parse/ParseStmt.cpp:230-237 if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt || (StmtCtx & ParsedStmtContext::AllowDeclarationsInC) != ParsedStmtContext()) && ((GNUAttributeLoc.isValid() && - !(!Attrs.empty() && - llvm::all_of( - Attrs, [](ParsedAttr &Attr) { return Attr.isStmtAttr(); }))) || + !(!(CXX11Attrs.empty() && GNUAttrs.empty()) && + llvm::all_of(CXX11Attrs, isStmtAttr) && + llvm::all_of(GNUAttrs, isStmtAttr))) || ---------------- The logic is correct here, but this predicate has gotten really difficult to understand. If you wanted to split some of those conditions out into named variables for clarity, I would not be sad (but I also don't insist either). ================ Comment at: clang/lib/Parse/ParseStmt.cpp:248-251 + if (CXX11Attrs.Range.getBegin().isValid()) + DeclStart = CXX11Attrs.Range.getBegin(); + else if (GNUAttrs.Range.getBegin().isValid()) + DeclStart = GNUAttrs.Range.getBegin(); ---------------- Do CXX attributes always precede GNU ones, or do we need to do a source location comparison here to see which location is lexically earlier? ================ Comment at: clang/lib/Parse/ParseStmt.cpp:317-318 case tok::kw_asm: { - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); bool msAsm = false; ---------------- mboehme wrote: > aaron.ballman wrote: > > mboehme wrote: > > > aaron.ballman wrote: > > > > It seems like we might have a pre-existing bug here for [[]] > > > > attributes? http://eel.is/c++draft/dcl.dcl#nt:asm-declaration > > > Yes, we do! > > > > > > Fixed, and tests added in test/Parser/asm.c and test/Parser/asm.cpp. > > I think we should prohibit this for all `[[]]` attributes. C doesn't have > > an asm statement as part of the standard, but it lists it as a common > > extension in Annex J and uses the same syntax as the C++ feature. Might as > > well keep it consistent between the languages. > My rationale for handling C and C++ differently here was because they treat > `asm` differently. > > In C++, the standard requires us to allow attributes, so we merely warn that > they will be ignored. (Also, `asm` is formally a declaration, not a statement > in C++, though I’m not sure that makes a difference to the syntax.) > > In C, J.5.10 in “Common extensions” says “The most common implementation is > via a statement [...]”. C permits attributes only on declarations, though > since `asm` is an extension, that’s not really relevant anyway. Since this is > our extension and we wouldn’t do anything with the attributes anyway, it > seemed best to me to prohibit them outright. > > OTOH, I’ve just checked and GCC appears to accept attributes in this position > even in C mode. Is the compatibility argument strong enough that we should do > this too? > In C, J.5.10 in “Common extensions” says “The most common implementation is > via a statement [...]”. C permits attributes only on declarations, though > since asm is an extension, that’s not really relevant anyway. Since this is > our extension and we wouldn’t do anything with the attributes anyway, it > seemed best to me to prohibit them outright. C permits attributes on statements as well. I think it would be a bit odd to prohibit on assembly statements but still allow on other kinds of extensions like GNU ranged case labels. I think we should go ahead and accept despite it being a bit useless. ================ Comment at: clang/lib/Sema/ParsedAttr.cpp:240-243 + case AT_Regparm: + case AT_NoDeref: + case AT_ObjCGC: + case AT_VectorSize: ---------------- mboehme wrote: > rsmith wrote: > > mboehme wrote: > > > rsmith wrote: > > > > Many of these were previously not permitted in type attribute position, > > > > despite being declared in Attr.td as `TypeAttr`s. Do they actually work > > > > in type attribute position after this patch? At least `matrix_type` > > > > currently expects to be applied only to a typedef declaration, so I'd > > > > expect that one does not work as a type attribute. > > > > Many of these were previously not permitted in type attribute position, > > > > despite being declared in Attr.td as `TypeAttr`s. Do they actually work > > > > in type attribute position after this patch? > > > > > > Good point -- should have thought to test this myself. > > > > > > I have now added tests for all of the "sliding attributes". It was good > > > thing I did, because I realized that the logic in `processTypeAttrs()` > > > was only letting very specific attributes through. The new logic is now > > > much more generic (see SemaType.cpp:8278 and following). > > > > > > I also discovered some interesting special cases that I needed to add > > > extra code for. > > > > > > > At least `matrix_type` currently expects to be applied only to a > > > > typedef declaration, so I'd expect that one does not work as a type > > > > attribute. > > > > > > Thanks for pointing this out -- I had completely overlooked this. This is > > > the first of the special cases I referred to above. It has unfortunately > > > required adding some special-case code (SemaType.cpp:1819 and > > > SemaDeclAttr.cpp:9311) to make sure we emit the right diagnostics. I've > > > also added tests to make sure we emit the right diagnostics. The > > > redeeming factor is that I think it will be possible to remove this code > > > once we eliminate the "legacy sliding" behavior. > > > > > > I have to say I find it unusual that a type attribute restricts itself to > > > being used only on certain kinds of declarations; this seems a bit > > > non-orthogonal. Is there a good reason for this, or could the attribute > > > be "opened up" for use on types regardless of the context in which > > > they're used? > > > > > > I've confirmed by the way that none of the other "sliding" attributes is > > > restricted to being used in a typedef, and I've added tests that > > > demonstrate this if they didn't exist already. > > > > > > The other two special cases are: > > > > > > # `regparm`. This is a case where it's actually not correct to slide > > > the attribute to the `DeclSpec` because it should instead be applied to > > > the function type. Again, this attribute requires some special-case code; > > > see SemaDeclAttr.cpp:8397 and SemaType.cpp:8467. The comments there > > > explain the situation in more detail. Because the attribute doesn't > > > actually "slide", I've removed it from the list of attributes in > > > `slidesFromDeclToDeclSpecLegacyBehavior()`. > > > > > > # `noderef`. It turns out that this attribute currently does not work > > > at all in the `[[]]` spelling; I've written up a > > > [bug](https://github.com/llvm/llvm-project/issues/55790) with the > > > details. Because of this, there is no legacy behavior that needs to be > > > preserved. Instead, for the time being, I have chosen to simply emit an > > > "attribute ignored" warning when the attribute is encountered in `[[]]` > > > spelling. Again, I have removed the attribute from the list of attributes > > > in `slidesFromDeclToDeclSpecLegacyBehavior()`. > > > > > > I have added tests that check the specific behavior of the `regparm` and > > > `noderef` attributes. > > > I have to say I find it unusual that a type attribute restricts itself to > > > being used only on certain kinds of declarations; this seems a bit > > > non-orthogonal. Is there a good reason for this, or could the attribute > > > be "opened up" for use on types regardless of the context in which > > > they're used? > > > > We historically didn't have type attributes at all, only declaration > > attributes (and I suspect GCC was once the same in this regard), so a lot > > of the attributes that notionally *should* be treated as type attributes > > actually behave syntactically as declaration attributes instead. An obvious > > example of this is the `aligned` attribute, which notionally produces a > > different type -- that attribute appertains to `typedef` declarations (so > > that the typedef-name names a different type than the type that it's a > > typedef for) rather than appertaining to the type. Logically, I think we > > *should* provide versions of these attributes that appertain to types > > instead, but that will require a separate proposal and discussion, and is > > certainly outside the scope of this change. > > > > There are even cases of declaration attributes that logically *should* be > > type attributes, and are listed in the .td file as `TypeAttr`, but are > > actually declaration attributes. `MatrixType` is an example: > > - It's given a `SubjectList` in the .td file that contains only > > `TypedefName` because it can syntactically appertain only to a > > `TypedefNameDecl` -- it's syntactically a declaration attribute, not a type > > attribute > > - It's modeled in the .td file as a `TypeAttr`, possibly because it gets > > semantically modeled as part of an `AttributedType` -- it's semantically > > *both* a declaration attribute (we find it on `TypedefNameDecl`s) and a > > type attribute (we find it on `AttributedType`s) > > > > I'm not entirely convinced that's the right way to model this in the .td > > file -- the documentation for `TypeAttr` certainly suggests that it's about > > the syntactic form. Maybe there's room for improvement there -- > > @aaron.ballman, what do you think? > > We historically didn't have type attributes at all, only declaration > > attributes (and I suspect GCC was once the same in this regard), so a lot > > of the attributes that notionally *should* be treated as type attributes > > actually behave syntactically as declaration attributes instead. > [snip] > > Thanks for the context! > > > Logically, I think we *should* provide versions of these attributes that > > appertain to types instead, but that will require a separate proposal and > > discussion, and is certainly outside the scope of this change. > > Agree. In case it was unclear: I certainly wasn't proposing doing this as > part of this patch (not sure if that was unclear) -- this was more of a > question about principles / intended direction. > > > There are even cases of declaration attributes that logically *should* be > > type attributes, and are listed in the .td file as `TypeAttr`, but are > > actually declaration attributes. `MatrixType` is an example: > > - It's given a `SubjectList` in the .td file that contains only > > `TypedefName` because it can syntactically appertain only to a > > `TypedefNameDecl` -- it's syntactically a declaration attribute, not a type > > attribute > > - It's modeled in the .td file as a `TypeAttr`, possibly because it gets > > semantically modeled as part of an `AttributedType` -- it's semantically > > *both* a declaration attribute (we find it on `TypedefNameDecl`s) and a > > type attribute (we find it on `AttributedType`s) > > Yes, this is the particular example that I found confusing. Good point about > there being a tension between this being a declaration attribute > syntactically but a type attribute (among other things) semantically. > > > I'm not entirely convinced that's the right way to model this in the .td > > file -- the documentation for `TypeAttr` certainly suggests that it's about > > the syntactic form. Maybe there's room for improvement there -- > > @aaron.ballman, what do you think? > > I would also be interested in this, though certainly any changes would be > outside the scope of this patch. > We historically didn't have type attributes at all, only declaration > attributes (and I suspect GCC was once the same in this regard), so a lot of > the attributes that notionally *should* be treated as type attributes > actually behave syntactically as declaration attributes instead. This is why we have `DeclOrTypeAttr` in Attr.td -- largely for the calling convention attributes. It's a newer construct and I don't think it's been applied everywhere it should (it sounds like `MatrixType` is a good example). > I'm not entirely convinced that's the right way to model this in the .td file > -- the documentation for TypeAttr certainly suggests that it's about the > syntactic form. Maybe there's room for improvement there -- @aaron.ballman, > what do you think? There is quite a bit of room for improvement there. IIRC, we also got away with a lot of laxity here because automated checking for type attributes is basically nonexistent. However, I think those cleanups can all happen separately from this patch. ================ Comment at: clang/lib/Sema/ParsedAttr.cpp:224 + // property is consciously not defined as a flag in Attr.td because we don't + // want new attributes to specify it. + switch (getParsedKind()) { ---------------- mboehme wrote: > aaron.ballman wrote: > > mboehme wrote: > > > aaron.ballman wrote: > > > > Thoughts on the additional comment? And should we start to issue that > > > > deprecation warning now (perhaps as a separate follow-up commit)? > > > > Thoughts on the additional comment? > > > > > > Yes, good point, we should point this out explicitly. > > > > > > I've worded the comment slightly differently: we can definitely deprecate > > > the "sliding" behavior for attributes in the `clang::` namespace, as we > > > own them, but there may be compatibility concerns for other attributes. > > > This may mean that we can never reduce this list to nothing, but we > > > should try. > > > > > > > And should we start to issue that deprecation warning now (perhaps as a > > > > separate follow-up commit)? > > > > > > We're already doing this (see the tests in > > > test/SemaCXX/adress-space-placement.cpp), though again only for > > > attributes in the `clang::` namespace, as we don't really have the > > > authority to deprecate this usage for other attributes. > > > > > > I think the other question here is whether, by default, this should be an > > > error, not a warning, but this would then presumably require a > > > command-line flag to downgrade the error to a warning if needed (I > > > believe @rsmith raised this point on https://reviews.llvm.org/D111548). > > > If we do decide to make this an error by default, I'd like to do this in > > > a followup change if possible, as a) this change is already a strict > > > improvement over the status quo; b) adding a command-line flag with > > > associated tests would further increase the scope of this change, and c) > > > this change is a blocker for https://reviews.llvm.org/D111548, which > > > others on my team are waiting to be able to use. > > > ... but there may be compatibility concerns for other attributes. This > > > may mean that we can never reduce this list to nothing, but we should try. > > > > I would be pretty aggressive there and break compatibility over this, > > unless the uses were in system headers or something where the break would > > be too onerous to justify. > > > > > I think the other question here is whether, by default, this should be an > > > error, not a warning, but this would then presumably require a > > > command-line flag to downgrade the error to a warning if needed > > > > You put `DefaultError` onto the warning diagnostic to have it automatically > > upgraded as if the user did `-Werror=whatever-warning`, which allows the > > user to downgrade it back into a warning with `-Wno-error=whatever-warning`. > > > I think the other question here is whether, by default, this should be an > > > error, not a warning, but this would then presumably require a > > > command-line flag to downgrade the error to a warning if needed > > > > You put `DefaultError` onto the warning diagnostic to have it automatically > > upgraded as if the user did `-Werror=whatever-warning`, which allows the > > user to downgrade it back into a warning with `-Wno-error=whatever-warning`. > > Oh nice -- I didn't realize it was this easy! > > I haven't made a change yet because I wanted to give @rsmith an opportunity > to weigh in -- do you have an opinion on whether this should be a warning or > an error by default? I'm not certain if @rsmith has opinions here or not, but I think an error which can be downgraded to a warning is a reasonable approach. We should hear pretty quickly if this causes significant problems (in system headers or the like). ================ Comment at: clang/lib/Sema/SemaDeclAttr.cpp:8387 + if (AL.slidesFromDeclToDeclSpecLegacyBehavior() && + (clang::isa<DeclaratorDecl, TypeAliasDecl>(D))) { + // Suggest moving the attribute to the type instead, but only for our ---------------- This shouldn't need to be qualified and the extra parens aren't needed. ================ Comment at: clang/lib/Sema/SemaDeclAttr.cpp:8385 + // portability. + if (AL.isClangScope()) { + S.Diag(AL.getLoc(), diag::warn_type_attribute_deprecated_on_decl) ---------------- mboehme wrote: > aaron.ballman wrote: > > I do wonder how much code we break if we tighten this up regardless of > > which vendor namespace the attribute belongs to. I believe the sliding > > behavior is not conforming behavior unless we issue a diagnostic about it > > because we're extending the behavior of the language. > > I do wonder how much code we break if we tighten this up regardless of > > which vendor namespace the attribute belongs to. > > I think this is unfortunately hard to determine? > > > I believe the sliding behavior is not conforming behavior unless we issue a > > diagnostic about it because we're extending the behavior of the language. > > It might not conform with the spirit of the standard, but I think it conforms > with the letter. All of the attributes in question are vendor extensions > anyway, so if we want to, we can define their behavior as “when applied to a > declaration, changes the type of the declared entity in a certain way”. This > is essentially what all of the `DeclOrTypeAttr` attributes do when applied to > a declaration. > > And GCC certainly allows putting some of these attributes on declarations. > Here’s an example for `vector_size`: > > https://godbolt.org/z/1nhjPs3PP > > Maybe this means that `vector_size` should actually be a `DeclOrTypeAttr`, > not a pure `TypeAttr`. But I’d like to defer that decision to a potential > later cleanup dedicated to `vector_size` and leave it as a `TypeAttr` for now. > It might not conform with the spirit of the standard, but I think it conforms > with the letter. All of the attributes in question are vendor extensions > anyway, so if we want to, we can define their behavior as “when applied to a > declaration, changes the type of the declared entity in a certain way”. This > is essentially what all of the DeclOrTypeAttr attributes do when applied to a > declaration. The goal is for us to eventually conform to the spirit of the standard. Yes, vendor attributes have a lot of latitude in terms of their semantics, but the reason why we needed to devise the `[[]]` syntax in the first place was because the sliding behavior of `__attribute__(())` caused far too many problems in practice and we needed a much tighter notion of appertainment. > Maybe this means that vector_size should actually be a DeclOrTypeAttr, not a > pure TypeAttr. But I’d like to defer that decision to a potential later > cleanup dedicated to vector_size and leave it as a TypeAttr for now. Fine by me, I think that can be cleaned up later. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D126061/new/ https://reviews.llvm.org/D126061 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits