diff options
Diffstat (limited to 'clang/lib/AST/ASTStructuralEquivalence.cpp')
-rw-r--r-- | clang/lib/AST/ASTStructuralEquivalence.cpp | 54 |
1 files changed, 48 insertions, 6 deletions
diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp index f113b32..22bb4cb 100644 --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -456,7 +456,9 @@ CheckStructurallyEquivalentAttributes(StructuralEquivalenceContext &Context, const Decl *D1, const Decl *D2, const Decl *PrimaryDecl = nullptr) { // If either declaration has an attribute on it, we treat the declarations - // as not being structurally equivalent. + // as not being structurally equivalent unless both declarations are implicit + // (ones generated by the compiler like __NSConstantString_tag). + // // FIXME: this should be handled on a case-by-case basis via tablegen in // Attr.td. There are multiple cases to consider: one declaration with the // attribute, another without it; different attribute syntax|spellings for @@ -468,7 +470,7 @@ CheckStructurallyEquivalentAttributes(StructuralEquivalenceContext &Context, D1Attr = *D1->getAttrs().begin(); if (D2->hasAttrs()) D2Attr = *D2->getAttrs().begin(); - if (D1Attr || D2Attr) { + if ((D1Attr || D2Attr) && !D1->isImplicit() && !D2->isImplicit()) { const auto *DiagnoseDecl = cast<TypeDecl>(PrimaryDecl ? PrimaryDecl : D2); Context.Diag2(DiagnoseDecl->getLocation(), diag::warn_odr_tag_type_with_attributes) @@ -884,12 +886,10 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, // class comparison. if (T1->getTypeClass() == Type::Enum) { T1 = T1->getAs<EnumType>()->getDecl()->getIntegerType(); - if (!T2->isBuiltinType() || T1.isNull()) // Sanity check - return false; + assert(T2->isBuiltinType() && !T1.isNull()); // Sanity check } else if (T2->getTypeClass() == Type::Enum) { T2 = T2->getAs<EnumType>()->getDecl()->getIntegerType(); - if (!T1->isBuiltinType() || T2.isNull()) // Sanity check - return false; + assert(T1->isBuiltinType() && !T2.isNull()); // Sanity check } TC = Type::Builtin; } else @@ -2093,6 +2093,48 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, !CheckStructurallyEquivalentAttributes(Context, D1, D2)) return false; + // In C23, if one enumeration has a fixed underlying type, the other shall + // have a compatible fixed underlying type (6.2.7). + if (Context.LangOpts.C23) { + if (D1->isFixed() != D2->isFixed()) { + if (Context.Complain) { + Context.Diag2(D2->getLocation(), + Context.getApplicableDiagnostic( + diag::err_odr_tag_type_inconsistent)) + << Context.ToCtx.getTypeDeclType(D2) + << (&Context.FromCtx != &Context.ToCtx); + Context.Diag1(D1->getLocation(), + D1->isFixed() + ? diag::note_odr_fixed_underlying_type + : diag::note_odr_missing_fixed_underlying_type) + << D1; + Context.Diag2(D2->getLocation(), + D2->isFixed() + ? diag::note_odr_fixed_underlying_type + : diag::note_odr_missing_fixed_underlying_type) + << D2; + } + return false; + } + if (D1->isFixed()) { + assert(D2->isFixed() && "enums expected to have fixed underlying types"); + if (!IsStructurallyEquivalent(Context, D1->getIntegerType(), + D2->getIntegerType())) { + if (Context.Complain) { + Context.Diag2(D2->getLocation(), + Context.getApplicableDiagnostic( + diag::err_odr_tag_type_inconsistent)) + << Context.ToCtx.getTypeDeclType(D2) + << (&Context.FromCtx != &Context.ToCtx); + Context.Diag2(D2->getLocation(), + diag::note_odr_incompatible_fixed_underlying_type) + << D2 << D2->getIntegerType() << D1->getIntegerType(); + } + return false; + } + } + } + llvm::SmallVector<const EnumConstantDecl *, 8> D1Enums, D2Enums; auto CopyEnumerators = [](auto &&Range, llvm::SmallVectorImpl<const EnumConstantDecl *> &Cont) { |