@@ -2089,6 +2089,48 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
20892089 !CheckStructurallyEquivalentAttributes (Context, D1, D2))
20902090 return false ;
20912091
2092+ // In C23, if one enumeration has a fixed underlying type, the other shall
2093+ // have a compatible fixed underlying type (6.2.7).
2094+ if (Context.LangOpts .C23 ) {
2095+ if (D1->isFixed () != D2->isFixed ()) {
2096+ if (Context.Complain ) {
2097+ Context.Diag2 (D2->getLocation (),
2098+ Context.getApplicableDiagnostic (
2099+ diag::err_odr_tag_type_inconsistent))
2100+ << Context.ToCtx .getTypeDeclType (D2)
2101+ << (&Context.FromCtx != &Context.ToCtx );
2102+ Context.Diag1 (D1->getLocation (),
2103+ D1->isFixed ()
2104+ ? diag::note_odr_fixed_underlying_type
2105+ : diag::note_odr_missing_fixed_underlying_type)
2106+ << D1;
2107+ Context.Diag2 (D2->getLocation (),
2108+ D2->isFixed ()
2109+ ? diag::note_odr_fixed_underlying_type
2110+ : diag::note_odr_missing_fixed_underlying_type)
2111+ << D2;
2112+ }
2113+ return false ;
2114+ }
2115+ if (D1->isFixed ()) {
2116+ assert (D2->isFixed () && " enums expected to have fixed underlying types" );
2117+ if (!IsStructurallyEquivalent (Context, D1->getIntegerType (),
2118+ D2->getIntegerType ())) {
2119+ if (Context.Complain ) {
2120+ Context.Diag2 (D2->getLocation (),
2121+ Context.getApplicableDiagnostic (
2122+ diag::err_odr_tag_type_inconsistent))
2123+ << Context.ToCtx .getTypeDeclType (D2)
2124+ << (&Context.FromCtx != &Context.ToCtx );
2125+ Context.Diag2 (D2->getLocation (),
2126+ diag::note_odr_incompatible_fixed_underlying_type)
2127+ << D2 << D2->getIntegerType () << D1->getIntegerType ();
2128+ }
2129+ return false ;
2130+ }
2131+ }
2132+ }
2133+
20922134 llvm::SmallVector<const EnumConstantDecl *, 8 > D1Enums, D2Enums;
20932135 auto CopyEnumerators =
20942136 [](auto &&Range, llvm::SmallVectorImpl<const EnumConstantDecl *> &Cont) {
0 commit comments