https://github.com/IvyXu420 created 
https://github.com/llvm/llvm-project/pull/235265

The bug comes from `IsStructurallyEquivalent(Context, Field1->getBitWidth(), 
Field2->getBitWidth())`
returning true when both `Field1->getBitWidth()` and `Field2->getBitWidth()` 
are ConstantExpr types. Two bit fields were treated as structurally equivalent 
even though their widths are different.

This PR makes sure that two bit-fields with different bit-field width are 
treated as structurally unequivalent under `-std=c23`.

Fixes #232748.



>From 8c565c58747c72691a15110575d147a27b84fb90 Mon Sep 17 00:00:00 2001
From: Ivy Xu <[email protected]>
Date: Sat, 24 Oct 2026 15:40:04 +0800
Subject: [PATCH] Fix `IsStructurallyEquivalent` for constexpr BitField

---
 clang/lib/AST/ASTStructuralEquivalence.cpp | 11 ++++++-----
 clang/test/C/C23/n3037.c                   | 13 +++++++++++++
 2 files changed, 19 insertions(+), 5 deletions(-)

diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp 
b/clang/lib/AST/ASTStructuralEquivalence.cpp
index 029e33ae0db760..f6fa067810550f 100644
--- a/clang/lib/AST/ASTStructuralEquivalence.cpp
+++ b/clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -1664,13 +1664,13 @@ static bool 
IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
     return false;
   }
 
-  if ((Field1->isBitField() || Field2->isBitField()) &&
-      !IsStructurallyEquivalent(Context, Field1->getBitWidth(),
-                                Field2->getBitWidth())) {
+  if ((Field1->isBitField() || Field2->isBitField())) {
     // Two bit-fields can be structurally unequivalent but still be okay for
     // the purposes of C where they simply need to have the same values, not
     // the same token sequences.
-    bool Diagnose = true;
+    bool Diagnose = false;
+    if (!IsStructurallyEquivalent(Context, Field1->getBitWidth(), 
Field2->getBitWidth()))
+        Diagnose = true;
     if (Context.LangOpts.C23 && Field1->isBitField() && Field2->isBitField())
       Diagnose = Field1->getBitWidthValue() != Field2->getBitWidthValue();
 
@@ -1695,7 +1695,8 @@ static bool 
IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
       DiagNote(Field2, &StructuralEquivalenceContext::Diag2);
       DiagNote(Field1, &StructuralEquivalenceContext::Diag1);
     }
-    return false;
+    if (Diagnose)
+      return false;
   }
 
   return true;
diff --git a/clang/test/C/C23/n3037.c b/clang/test/C/C23/n3037.c
index 8dd46ef69b4146..97320820a3eeba 100644
--- a/clang/test/C/C23/n3037.c
+++ b/clang/test/C/C23/n3037.c
@@ -948,3 +948,16 @@ struct GH199417_3 {
     // it would be better to print the original type.
   } a;                                 // c23-note {{field 'a' has type 'int' 
here}}
 };
+
+#if __STDC_VERSION__ >= 202311L
+constexpr int n = 1;
+constexpr int m = 2;
+struct GH232748 {
+  struct S { int i : n; } s1; // c23-note {{bit-field 'i' has bit-width 1 
here}}
+  struct S { int i : m; } s2; // c23-error {{type 'struct S' has incompatible 
definitions}}
+                              // c23-note@-1 {{bit-field 'i' has bit-width 2 
here}}
+
+  struct M { int i : n; } m1;
+  struct M { int i : n; } m2;
+};
+#endif

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to