Author: Steffen Larsen
Date: 2026-10-20T07:48:31Z
New Revision: 28fccd180016caccb7cd021eff9da8fa1f98af18

URL: 
https://github.com/llvm/llvm-project/commit/28fccd180016caccb7cd021eff9da8fa1f98af18
DIFF: 
https://github.com/llvm/llvm-project/commit/28fccd180016caccb7cd021eff9da8fa1f98af18.diff

LOG: [CIR] Reject a record redefined with a different body (#230547)

A context holds a single record per kind and name, so parsing a named
record returns any earlier definition of that name. When the earlier
definition was complete, the parser kept it and silently dropped the new
body, so a global declared with a different layout was given the first
one. Report the mismatch instead.

Assisted-by: Claude Opus 5.5

---------

Signed-off-by: Steffen Holst Larsen <[email protected]>

Added: 
    clang/test/CIR/IR/invalid-record-redefinition.cir

Modified: 
    clang/lib/CIR/Dialect/IR/CIRTypes.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp 
b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
index c6296180cfb02..ecdd5fd8584d0 100644
--- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
@@ -321,9 +321,13 @@ Type StructType::parse(mlir::AsmParser &parser) {
                                   is_class, kindsRef);
     if (!type)
       return {};
-    if (auto structTy = mlir::dyn_cast<StructType>(type))
-      if (structTy.isIncomplete())
-        structTy.complete(membersRef, packed, kindsRef);
+    if (auto structTy = mlir::dyn_cast<StructType>(type)) {
+      if (failed(structTy.mutate(membersRef, packed, kindsRef))) {
+        parser.emitError(loc, "record '")
+            << name.getValue() << "' redefined with a 
diff erent body";
+        return {};
+      }
+    }
     assert(!cir::MissingFeatures::astRecordDeclAttr());
   } else {
     parser.emitError(loc, "anonymous records must be complete");
@@ -486,9 +490,13 @@ Type UnionType::parse(mlir::AsmParser &parser) {
                                  padding, kindsRef);
     if (!type)
       return {};
-    if (auto unionTy = mlir::dyn_cast<UnionType>(type))
-      if (unionTy.isIncomplete())
-        unionTy.complete(membersRef, packed, padding, kindsRef);
+    if (auto unionTy = mlir::dyn_cast<UnionType>(type)) {
+      if (failed(unionTy.mutate(membersRef, packed, padding, kindsRef))) {
+        parser.emitError(loc, "record '")
+            << name.getValue() << "' redefined with a 
diff erent body";
+        return {};
+      }
+    }
     assert(!cir::MissingFeatures::astRecordDeclAttr());
   } else {
     parser.emitError(loc, "anonymous records must be complete");

diff  --git a/clang/test/CIR/IR/invalid-record-redefinition.cir 
b/clang/test/CIR/IR/invalid-record-redefinition.cir
new file mode 100644
index 0000000000000..24e41fb3c35ff
--- /dev/null
+++ b/clang/test/CIR/IR/invalid-record-redefinition.cir
@@ -0,0 +1,63 @@
+// RUN: cir-opt %s -verify-diagnostics -split-input-file
+
+// A context holds a single record per kind and name, so a second definition of
+// a name must have the same body as the first.
+
+!s32i = !cir.int<s, 32>
+module {
+  cir.global external @a = #cir.zero : !cir.struct<"S" {data !s32i}>
+  // expected-error @below {{record 'S' redefined with a 
diff erent body}}
+  cir.global external @b = #cir.zero : !cir.struct<"S" {data !cir.double, data 
!s32i}>
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+module {
+  cir.global external @a = #cir.zero : !cir.struct<"S" {data !s32i}>
+  // expected-error @below {{record 'S' redefined with a 
diff erent body}}
+  cir.global external @b = #cir.zero : !cir.struct<"S" packed {data !s32i}>
+}
+
+// -----
+
+!u8i = !cir.int<u, 8>
+module {
+  cir.global external @a = #cir.zero : !cir.struct<"S" {data !u8i}>
+  // expected-error @below {{record 'S' redefined with a 
diff erent body}}
+  cir.global external @b = #cir.zero : !cir.struct<"S" {pad !u8i}>
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+module {
+  cir.global external @a = #cir.zero : !cir.union<"U" {data !s32i}>
+  // expected-error @below {{record 'U' redefined with a 
diff erent body}}
+  cir.global external @b = #cir.zero : !cir.union<"U" {data !s32i, data 
!cir.float}>
+}
+
+// -----
+
+!u8i = !cir.int<u, 8>
+!s32i = !cir.int<s, 32>
+module {
+  cir.global external @a = #cir.zero : !cir.union<"U" {data !s32i}>
+  // expected-error @below {{record 'U' redefined with a 
diff erent body}}
+  cir.global external @b = #cir.zero : !cir.union<"U" {data !s32i}, padding = 
{!cir.array<!u8i x 4>}>
+}
+
+// -----
+
+// Still accepted: an identical redefinition, completing a record first seen
+// incomplete, and a struct, a class and a union that share a name, which are
+// distinct records.
+!s32i = !cir.int<s, 32>
+module {
+  cir.global external @a = #cir.zero : !cir.struct<"S" {data !s32i}>
+  cir.global external @b = #cir.zero : !cir.struct<"S" {data !s32i}>
+  cir.global external @p = #cir.ptr<null> : !cir.ptr<!cir.struct<"F" 
incomplete>>
+  cir.global external @f = #cir.zero : !cir.struct<"F" {data !s32i}>
+  cir.global external @c = #cir.zero : !cir.struct<class "S" {data 
!cir.double}>
+  cir.global external @u = #cir.zero : !cir.union<"S" {data !s32i, data 
!cir.float}>
+}


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

Reply via email to