================ @@ -450,6 +453,116 @@ class StmtComparer { }; } // namespace +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + const Attr *Attr1, const Attr *Attr2) { + // Two attributes are structurally equivalent if they are the same kind + // of attribute, spelled with the same spelling kind, and have the same + // arguments. This means that [[noreturn]] and __attribute__((noreturn)) are + // not structurally equivalent, nor are [[nodiscard("foo")]] and + // [[nodiscard("bar")]]. + if (Attr1->getKind() != Attr2->getKind()) + return false; + + if (Attr1->getSyntax() != Attr2->getSyntax()) + return false; + + if (Attr1->getSpellingListIndex() != Attr2->getSpellingListIndex()) + return false; + + auto GetAttrName = [](const Attr *A) { + if (const IdentifierInfo *II = A->getAttrName()) + return II->getName(); + return StringRef{}; + }; + + if (GetAttrName(Attr1) != GetAttrName(Attr2)) + return false; + + // FIXME: check the attribute arguments. Attr does not track the arguments on + // the base class, which makes this awkward. We may want to tablegen a + // comparison function for attributes? In the meantime, we're doing this the + // cheap way by pretty printing the attributes and checking they produce ---------------- AaronBallman wrote:
> If we treat two types as incompatible when they ought to be compatible, it > potentially could result in silent miscompilation of a valid program Except this is about compatibility of types *within* the same TU, so there's no miscompile possible because the user gets an error about redefining the same type twice. https://github.com/llvm/llvm-project/pull/132939 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits