@@ -2089,6 +2089,48 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
2089
2089
!CheckStructurallyEquivalentAttributes (Context, D1, D2))
2090
2090
return false ;
2091
2091
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
+
2092
2134
llvm::SmallVector<const EnumConstantDecl *, 8 > D1Enums, D2Enums;
2093
2135
auto CopyEnumerators =
2094
2136
[](auto &&Range, llvm::SmallVectorImpl<const EnumConstantDecl *> &Cont) {
0 commit comments