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

Reply via email to