ChuanqiXu accepted this revision. ChuanqiXu added a comment. This revision is now accepted and ready to land.
LGTM basically. Our discussion is mainly about the future work in Attr.td and not this patch. So I think they are not blocking issues. ================ Comment at: clang/lib/AST/ODRDiagsEmitter.cpp:337-354 + if (!LHS || !RHS || LHS->getKind() != RHS->getKind()) { + DiagError(AttributeKind) + << (LHS != nullptr) << LHS << FirstDecl->getSourceRange(); + DiagNoteAttrLoc(LHS); + DiagNote(AttributeKind) + << (RHS != nullptr) << RHS << SecondDecl->getSourceRange(); + DiagNoteAttrLoc(RHS); ---------------- vsapsai wrote: > ChuanqiXu wrote: > > vsapsai wrote: > > > ChuanqiXu wrote: > > > > I feel like we can merge these two statements. > > > Sorry, I don't really get what two statements you are talking about. Is > > > it > > > * `!LHS || !RHS || LHS->getKind() != RHS->getKind()` > > > * `ComputeAttrODRHash(LHS) != ComputeAttrODRHash(RHS)` > > > ? > > Sorry for the ambiguity. Since `LHS->getKind() != RHS->getKind()` is > > covered by `ComputeAttrODRHash(LHS) != ComputeAttrODRHash(RHS)`. I feel > > like it is reasonable to: > > > > ``` > > if (!LHS || !RHS || ComputeAttrODRHash(LHS) != ComputeAttrODRHash(RHS)) { > > DiagError(); > > DiagNote(); > > DiagNote(); > > DiagNoteAttrLoc(); > > return true; > > } > > ``` > There are 2 separate cases to improve the diagnostic. In the first case we'd > have > ``` > ... first difference is definition in module 'FirstModule' found attribute > 'enum_extensibility' > attribute specified here > but in 'SecondModule' found no attribute > ``` > > And if we reach the second ones, it implies the kind of attributes is the > same and the only difference is attribute arguments, so the diagnostics are > like > ``` > first difference is definition in module 'FirstModule' found attribute ' > __attribute__((enum_extensibility("open")))' > attribute specified here > but in 'SecondModule' found different attribute argument ' > __attribute__((enum_extensibility("closed")))' > attribute specified here > ``` > > From my limited experience, it is actually useful to have more details than > trying to figure out the difference in attributes. Agreed. I just wanted to say the codes can be further be shorten by making the diagnostic kinds contains more cases: ``` %select { | | ... } ``` We have some such examples before. But this is not required. Since it actually moves the complexity from the source codes to the table gen. And the implementation doesn't look bad. ================ Comment at: clang/lib/AST/ODRHash.cpp:479-480 + + llvm::copy_if(D->attrs(), std::back_inserter(HashableAttrs), + [](const Attr *A) { return !A->isImplicit(); }); +} ---------------- aaron.ballman wrote: > ChuanqiXu wrote: > > aaron.ballman wrote: > > > ChuanqiXu wrote: > > > > vsapsai wrote: > > > > > vsapsai wrote: > > > > > > erichkeane wrote: > > > > > > > aaron.ballman wrote: > > > > > > > > ChuanqiXu wrote: > > > > > > > > > vsapsai wrote: > > > > > > > > > > I'm not sure `isImplicit` is the best indicator of > > > > > > > > > > attributes to check, so suggestions in this area are > > > > > > > > > > welcome. I think we can start strict and relax some of the > > > > > > > > > > checks if needed. > > > > > > > > > > > > > > > > > > > > If people have strong opinions that some attributes > > > > > > > > > > shouldn't be ignored, we can add them to the tests to avoid > > > > > > > > > > regressions. Personally, I believe that alignment and > > > > > > > > > > packed attributes should never be silently ignored. > > > > > > > > > Agreed. I feel `isImplicit` is enough for now. > > > > > > > > The tricky part is -- sometimes certain attributes add > > > > > > > > additional implicit attributes and those implicit attributes > > > > > > > > matter > > > > > > > > (https://github.com/llvm/llvm-project/blob/main/clang/lib/Sema/SemaDeclAttr.cpp#L9380). > > > > > > > > And some attributes seem to just do the wrong thing entirely: > > > > > > > > https://github.com/llvm/llvm-project/blob/main/clang/lib/Sema/SemaDeclAttr.cpp#L7344 > > > > > > > > > > > > > > > > So I think `isImplicit()` is a good approximation, but I'm more > > > > > > > > wondering what the principle is for whether an attribute should > > > > > > > > or should not be considered part of the ODR hash. Type > > > > > > > > attributes, attributes that impact object layout, etc all seem > > > > > > > > like they should almost certainly be part of ODR hashing. > > > > > > > > Others are a bit more questionable though. > > > > > > > > > > > > > > > > I think this is something that may need a per-attribute flag in > > > > > > > > Attr.td so attributes can opt in or out of it because I'm not > > > > > > > > certain what ODR issues could stem from `[[maybe_unused]]` or > > > > > > > > `[[deprecated]]` disagreements across module boundaries. > > > > > > > I don't think 'isImplicit' is particularly good. I think the > > > > > > > idea of auto-adding 'type' attributes and having the 'rest' be > > > > > > > analyzed to figure out which are important. > > > > > > > > > > > > > > Alternatively, I wonder if we're better off just adding ALL > > > > > > > attributes and seeing what the fallout is. We can later decide > > > > > > > when we don't want them to be ODR significant (which, might be > > > > > > > OTHERWISE meaningful later!). > > > > > > One criteria to decide which attributes should be hashed is if they > > > > > > affect IRGen. But that's not exhaustive and I'm not sure how > > > > > > practical it is. > > > > > > > > > > > > The rule I'm trying to follow right now is if declarations with > > > > > > different attributes can be substituted instead of each other. For > > > > > > example, structs with different memory layout cannot be > > > > > > interchanged, so it is reasonable to reject them. > > > > > > > > > > > > But maybe we should review attributes on case-by-case basis. For > > > > > > example, for `[[deprecated]]` I think the best for developers is > > > > > > not to complain about it but merge the attributes and then have > > > > > > regular diagnostic about using a deprecated entity. > > > > > One option was to hash `isa<InheritedAttr>` attributes as they are > > > > > "sticky" and should be more significant, so shouldn't be ignored. But > > > > > I don't think this argument is particularly convincing. > > > > > > > > > > At this stage I think we can still afford to add all attributes and > > > > > exclude some as-needed because modules adoption is still limited. > > > > > Though I don't have strong feelings about this approach, just getting > > > > > more restrictive later can be hard. > > > > It looks not a bad idea to add all attributes as experiments, @vsapsai > > > > how do you feel about this? > > > My intuition is that we're going to want this to be controlled from > > > Attr.td on a case-by-case basis and to automatically generate the ODR > > > hash code for attribute arguments. > > > > > > We can either force every attribute to decide explicitly (this seems > > > pretty disruptive as a final design but would be a really good way to > > > ensure we audit all attributes if done as an experiment), or we can pick > > > a default behavior to ODR hash/not. I suspect we're going to want to pick > > > a default behavior based on whatever the audit tells us the most common > > > situation is. > > > > > > I think we're going to need something a bit more nuanced than "this > > > attribute matters for ODR" because there are attribute arguments that > > > don't always contribute to the entity (for example, we have "fake" > > > arguments that are used to give the semantic attribute more information, > > > there may also be cases where one argument matter and another argument > > > does not such as `enable_if` where the condition matters greatly but the > > > message doesn't matter much). So we might need a marking on the attribute > > > level *and* on the parameter level to determine what all factors into > > > attribute identity for generating the ODR hashing code. Hopefully we can > > > avoid needing more granularity than that. > > I feel the default behavior would be to do ODR hashes. I just took a quick > > look in Attr.td. And I feel most of them affecting the code generation. For > > example, there're a lot of attributes which is hardware related. > > > > > because there are attribute arguments that don't always contribute to the > > > entity > > > > When you're talking about "entities", I'm not sure if you're talking the > > "entities" in the language spec or a general abstract ones. I mean, for > > example, the `always_inline` attribute doesn't contribute to the > > declaration from the language perspective. But it'll be super odd if we > > lost it. So I feel it may be better to change the requirement to be > > "affecting code generation" > > > > Also, to be honest, I am even not sure if we should take "affecting code > > generation " as the requirement. For example, for the `preferred_name` > > attribute, this is used for better printing names. It doesn't affect code > > generation nor the entity you mentioned. But if we drop it, then the > > printing name may not be what users want. I'm not sure if this is desired. > > I feel the default behavior would be to do ODR hashes. I just took a quick > > look in Attr.td. And I feel most of them affecting the code generation. For > > example, there're a lot of attributes which is hardware related. > > Hmmm, I'm seeing a reasonably even split. We definitely have a ton of > attributes like multiversioning, interrupts, calling conventions, > availability, etc that I think all should be part of an ODR hash. We also > have a ton of other ones that don't seem like they should matter for ODR > hashing like hot/cold, consumed/returns retained, constructor/destructor, > deprecated, nodiscard, maybe_unused, etc. > > Then we have the really fun ones where I think we'll want them to be in the > ODR hash but maybe we don't, like `[[clang::annotate]]`, restrict, etc. > > So I think we really do need an actual audit of the attributes to decide what > the default should be (if there should even be one). > > > When you're talking about "entities", I'm not sure if you're talking the > > "entities" in the language spec or a general abstract ones. I mean, for > > example, the always_inline attribute doesn't contribute to the declaration > > from the language perspective. But it'll be super odd if we lost it. So I > > feel it may be better to change the requirement to be "affecting code > > generation" > > Not in a language spec meaning -- I meant mostly that there's some notion of > identify for the one definition rule and not all attribute arguments > contribute to that identity the same way. > > I don't know that "affecting code gen" really captures the whole of it. For > example, whether a function is/is not marked hot or cold affects codegen, but > really has nothing to do with the identity of the function (it's the same > function whether the hint is there or not). `preferred_name` is another > example -- do we really think a structure with that attribute is > fundamentally a different thing than one without that attribute? I don't > think so. > > To me, it's more about what cross-TU behaviors you'll get if the attribute is > only present on one side. Things like ABI tags, calling conventions, > attributes that behave like qualifiers, etc all contribute to the identity of > something where a mismatch will impact the correctness of the program. But > things like optimization hints and diagnostic hints don't seem like they > contribute to the identity of something because they don't impact correctness. I got your point. But from my developing experience, I want to say the optimization hints matters too. And I am wondering how about checking the ODR for all attributes. It would emit error if the attributes that affecting the correctness mismatches. And if the other attributes mismatches, a warning enough. (If we worry about the compile time performance, I feel it won't take too long. And we can have an option to control it actually.) Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D135472/new/ https://reviews.llvm.org/D135472 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits