@@ -2113,6 +2113,48 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
2113
2113
!CheckStructurallyEquivalentAttributes (Context, D1, D2))
2114
2114
return false ;
2115
2115
2116
+ // In C23, if one enumeration has a fixed underlying type, the other shall
2117
+ // have a compatible fixed underlying type (6.2.7).
2118
+ if (Context.LangOpts .C23 ) {
2119
+ if (D1->isFixed () != D2->isFixed ()) {
2120
+ if (Context.Complain ) {
2121
+ Context.Diag2 (D2->getLocation (),
2122
+ Context.getApplicableDiagnostic (
2123
+ diag::err_odr_tag_type_inconsistent))
2124
+ << Context.ToCtx .getTypeDeclType (D2)
2125
+ << (&Context.FromCtx != &Context.ToCtx );
2126
+ Context.Diag1 (D1->getLocation (),
2127
+ D1->isFixed ()
2128
+ ? diag::note_odr_fixed_underlying_type
2129
+ : diag::note_odr_missing_fixed_underlying_type)
2130
+ << D1;
2131
+ Context.Diag2 (D2->getLocation (),
2132
+ D2->isFixed ()
2133
+ ? diag::note_odr_fixed_underlying_type
2134
+ : diag::note_odr_missing_fixed_underlying_type)
2135
+ << D2;
2136
+ }
2137
+ return false ;
2138
+ }
2139
+ if (D1->isFixed ()) {
2140
+ assert (D2->isFixed () && " enums expected to have fixed underlying types" );
2141
+ if (!IsStructurallyEquivalent (Context, D1->getIntegerType (),
2142
+ D2->getIntegerType ())) {
2143
+ if (Context.Complain ) {
2144
+ Context.Diag2 (D2->getLocation (),
2145
+ Context.getApplicableDiagnostic (
2146
+ diag::err_odr_tag_type_inconsistent))
2147
+ << Context.ToCtx .getTypeDeclType (D2)
2148
+ << (&Context.FromCtx != &Context.ToCtx );
2149
+ Context.Diag2 (D2->getLocation (),
2150
+ diag::note_odr_incompatible_fixed_underlying_type)
2151
+ << D2 << D2->getIntegerType () << D1->getIntegerType ();
2152
+ }
2153
+ return false ;
2154
+ }
2155
+ }
2156
+ }
2157
+
2116
2158
llvm::SmallVector<const EnumConstantDecl *, 8 > D1Enums, D2Enums;
2117
2159
auto CopyEnumerators =
2118
2160
[](auto &&Range, llvm::SmallVectorImpl<const EnumConstantDecl *> &Cont) {
0 commit comments