https://github.com/akash-manna-sky updated 
https://github.com/llvm/llvm-project/pull/225662

>From e9421e5626c17bb257b0fa55e9dd64ad56b3ac7e Mon Sep 17 00:00:00 2001
From: Akash Manna <[email protected]>
Date: Wed, 23 Sep 2026 15:07:22 +0530
Subject: [PATCH] [Clang][C23] Fix tag compatibility for incomplete
 enumerations

The C23 tag compatibility check treated an enumeration without a
definition as equivalent to anything, so an incomplete `enum E` declared
in a parameter list was merged with a later file scope `enum E`. The
definition then carried a function type whose parameter is the
incomplete enumeration, and CodeGen asserted on its null underlying
type.

Only complete enumerations are compatible in C23 (6.2.7p1). Without a
definition an enumeration is complete only if it has a fixed underlying
type, so two such declarations are compatible only when those types
match.

Fixes #173477
---
 clang/docs/ReleaseNotes.md                 |  5 +++
 clang/lib/AST/ASTStructuralEquivalence.cpp | 19 +++++++---
 clang/test/C/C23/n3037.c                   | 44 ++++++++++++++++++++++
 3 files changed, 63 insertions(+), 5 deletions(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index f4a34a37aff52..b11453d5e9bdf 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -231,6 +231,11 @@ features cannot lower the translation-unit ABI level;
 
 #### C23 Feature Support
 
+- An incomplete enumeration is no longer treated as compatible with a complete
+  enumeration declared with the same tag in a different scope, as C23 6.2.7p1
+  only applies to complete types. This fixes a crash when generating code for a
+  function redeclared with such enumeration types as parameters. (#GH173477)
+
 ### Objective-C Language Changes
 
 ### Non-comprehensive list of changes in this release
diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp 
b/clang/lib/AST/ASTStructuralEquivalence.cpp
index 029e33ae0db76..3aca7b7b1382c 100644
--- a/clang/lib/AST/ASTStructuralEquivalence.cpp
+++ b/clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -2154,13 +2154,22 @@ static bool 
IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
   }
 
   // Compare the definitions of these two enums. If either or both are
-  // incomplete (i.e. forward declared), we assume that they are equivalent.
+  // incomplete (i.e. forward declared), we assume that they are equivalent,
+  // except in C23 mode, where only complete enumerations are compatible. An
+  // enumeration without a definition is complete only if its underlying type
+  // is fixed, and then only that type needs to be compared.
   // In C23, the order of the enumerations does not matter, only the names and
   // values do.
-  D1 = D1->getDefinition();
-  D2 = D2->getDefinition();
-  if (!D1 || !D2)
-    return true;
+  EnumDecl *Def1 = D1->getDefinition(), *Def2 = D2->getDefinition();
+  if (!Def1 || !Def2) {
+    if (!Context.LangOpts.C23)
+      return true;
+    return !Def1 && !Def2 && D1->isComplete() && D2->isComplete() &&
+           IsStructurallyEquivalent(Context, D1->getIntegerType(),
+                                    D2->getIntegerType());
+  }
+  D1 = Def1;
+  D2 = Def2;
 
   if (Context.LangOpts.C23 &&
       !CheckStructurallyEquivalentAttributes(Context, D1, D2))
diff --git a/clang/test/C/C23/n3037.c b/clang/test/C/C23/n3037.c
index 8dd46ef69b414..b3d21acdb842b 100644
--- a/clang/test/C/C23/n3037.c
+++ b/clang/test/C/C23/n3037.c
@@ -948,3 +948,47 @@ struct GH199417_3 {
     // it would be better to print the original type.
   } a;                                 // c23-note {{field 'a' has type 'int' 
here}}
 };
+
+// An incomplete enumeration declared in a parameter list is not compatible 
with
+// a file scope enumeration of the same name; only complete tag types can be.
+void GH173477_1(enum GH173477_E1 e); // both-warning {{ISO C forbids forward 
references to 'enum' types}} \
+                                        both-warning {{declaration of 'enum 
GH173477_E1' will not be visible outside of this function}} \
+                                        both-note {{previous declaration is 
here}}
+enum GH173477_E1 { GH173477_A };
+void GH173477_1(enum GH173477_E1 e) {} // both-error {{conflicting types for 
'GH173477_1'}}
+
+void GH173477_2(enum GH173477_E2 *e); // both-warning {{ISO C forbids forward 
references to 'enum' types}} \
+                                         both-warning {{declaration of 'enum 
GH173477_E2' will not be visible outside of this function}} \
+                                         both-note {{previous declaration is 
here}}
+enum GH173477_E2 { GH173477_B };
+void GH173477_2(enum GH173477_E2 *e) {} // both-error {{conflicting types for 
'GH173477_2'}}
+
+// A complete one is compatible in C23.
+void GH173477_3(enum GH173477_E3 { GH173477_C } e); // c17-warning 
{{declaration of 'enum GH173477_E3' will not be visible outside of this 
function}} \
+                                                       c17-note {{previous 
declaration is here}}
+enum GH173477_E3 { GH173477_C };
+void GH173477_3(enum GH173477_E3 e) {} // c17-error {{conflicting types for 
'GH173477_3'}}
+
+// An enumeration with a fixed underlying type is complete without a 
definition,
+// so it is compatible with one that is declared the same way, but not with a
+// definition or with a different underlying type.
+enum GH173477_E4 : int;
+void GH173477_4(enum GH173477_E4 e); // c17-note {{previous declaration is 
here}}
+void GH173477_4_test(void) {
+  enum GH173477_E4 : int;
+  void GH173477_4(enum GH173477_E4 e); // c17-error {{conflicting types for 
'GH173477_4'}}
+}
+
+enum GH173477_E5 : int;
+void GH173477_5(enum GH173477_E5 e); // both-note {{previous declaration is 
here}}
+void GH173477_5_test(void) {
+  enum GH173477_E5 : int { GH173477_D };
+  void GH173477_5(enum GH173477_E5 e); // both-error {{conflicting types for 
'GH173477_5'}}
+}
+
+enum GH173477_E6 : int;
+void GH173477_6(enum GH173477_E6 e); // both-note {{previous declaration is 
here}}
+void GH173477_6_test(void) {
+  enum GH173477_E6 : short;
+  void GH173477_6(enum GH173477_E6 e); // both-error {{conflicting types for 
'GH173477_6'}}
+}

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

Reply via email to