https://github.com/AaronBallman updated https://github.com/llvm/llvm-project/pull/201650
>From eed996545c9804da7aff1d76a190614943906a8f Mon Sep 17 00:00:00 2001 From: Aaron Ballman <[email protected]> Date: Thu, 4 Jun 2026 13:34:45 -0400 Subject: [PATCH] [C23] Fix failing assertion on structural equivalence checks This assertion was added in 6a22580305d779e2d712900d49578de9a5cb14e8 as a sanity check and it turns out that the assertion was false in two different ways. 1) An enumeration might not have an underlying type in our AST; this happens for a forward declared enumeration without a fixed underlying type. 2) When comparing the members, we could compare a member of enumeration type with a member of a non-integral type like a union or structure. We now account for both cases. Fixes #190227 --- clang/docs/ReleaseNotes.rst | 2 ++ clang/lib/AST/ASTStructuralEquivalence.cpp | 17 ++++++++-- clang/test/C/C23/n3037.c | 38 ++++++++++++++++++++++ 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 9e4a47a5b18fc..2b7db1bf6a689 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -235,6 +235,8 @@ C2y Feature Support C23 Feature Support ^^^^^^^^^^^^^^^^^^^ - Clang now allows C23 ``constexpr`` struct member access through the dot operator in constant expressions. (#GH178349) +- Fixed a failing assertion when validating an invalid structure redefinition + with a member which uses an incomplete enumeration type. (#GH190227) Objective-C Language Changes ----------------------------- diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp index 9d970651a9e65..e0b62591a6a73 100644 --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -925,13 +925,24 @@ bool ASTStructuralEquivalence::isEquivalent( // type of the enumeration. // // Treat the enumeration as its underlying type and use the builtin type - // class comparison. + // class comparison. If the enumeration is invalid, e.g., it could be a + // forward declaration of an enumeration without a fixed underlying type, + // we'll default to 'int' for error recovery. If one type is an + // enumeration, the other must be an enumeration or integral, otherwise + // they're not structurally equivalent. e.g., it could be an enum in one + // struct and a union in another. if (T1->getTypeClass() == Type::Enum) { + if (!T2->isBuiltinType() && !T2->isEnumeralType()) + return false; T1 = cast<EnumType>(T1)->getDecl()->getIntegerType(); - assert(T2->isBuiltinType() && !T1.isNull()); // Sanity check + if (T1.isNull()) + T1 = Context.FromCtx.IntTy; } else if (T2->getTypeClass() == Type::Enum) { + if (!T1->isBuiltinType() && !T1->isEnumeralType()) + return false; T2 = cast<EnumType>(T2)->getDecl()->getIntegerType(); - assert(T1->isBuiltinType() && !T2.isNull()); // Sanity check + if (T2.isNull()) + T2 = Context.ToCtx.IntTy; } TC = Type::Builtin; } else diff --git a/clang/test/C/C23/n3037.c b/clang/test/C/C23/n3037.c index 7cb2655f7c21c..198f0487bead1 100644 --- a/clang/test/C/C23/n3037.c +++ b/clang/test/C/C23/n3037.c @@ -892,3 +892,41 @@ struct __attribute__((annotate("abc", &baz, &g0, 2))) Annotate1 { // c23-note@-3 {{attribute 'annotate' here}} int a; }; + +// This was previously causing an assertion when checking structural +// equivalence due to the the foward declared enum being invalid. +struct GH199417_1 { // c17-note {{previous definition is here}} + // both-error@+3 {{field has incomplete type 'enum GH199417_E1'}} + // both-warning@+2 {{ISO C forbids forward references to 'enum' types}} + // both-note@+1 {{forward declaration of 'enum GH199417_E1'}} + enum GH199417_E1 e; +}; +// FIXME: This should be rejected in C23 mode as well; because it is a +// tag type, the members have to have *the same* type, not merely +// compatible ones. See GH201647. +struct GH199417_1 { // c17-error {{redefinition of 'GH199417_1'}} + int e; +}; + +struct GH190227_1 { // c17-note {{previous definition is here}} + unsigned m; // c23-note {{field 'm' has type 'unsigned int' here}} +}; + +// c23-error@+2 {{type 'struct GH190227_1' has incompatible definitions}} +// c17-error@+1 {{redefinition of 'GH190227_1'}} +struct GH190227_1 { + // both-error@+3 {{field has incomplete type 'enum GH190227_E1'}} + // both-warning@+2 {{ISO C forbids forward references to 'enum' types}} + // both-note@+1 {{forward declaration of 'enum GH190227_E1'}} + enum GH190227_E1 m; // c23-note {{field 'm' has type 'enum GH190227_E1' here}} +}; + +struct GH199417_2 { // c17-note {{previous definition is here}} + union { int i; } u; // c23-note-re {{field 'u' has type 'union (unnamed at {{.*}})' here}} +}; + +// c23-error@+2 {{type 'struct GH199417_2' has incompatible definitions}} +// c17-error@+1 {{redefinition of 'GH199417_2'}} +struct GH199417_2 { + enum GH199417_E2 { eGH199417 } u; // c23-note {{field 'u' has type 'enum GH199417_E2' here}} +}; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
