Author: Henrich Lauko
Date: 2026-10-23T13:57:06+02:00
New Revision: 7a2f8807a21566d1af96303106d50cdaa7321233

URL: 
https://github.com/llvm/llvm-project/commit/7a2f8807a21566d1af96303106d50cdaa7321233
DIFF: 
https://github.com/llvm/llvm-project/commit/7a2f8807a21566d1af96303106d50cdaa7321233.diff

LOG: [CIR] Restrict union tail padding to integers (#233897)

CIRGen pads a union's tail with !u8i or !cir.array<!u8i x N>, but the
verifier accepted any padding type. Other types broke consumers that
size the union: incomplete-record padding asserted in
computeStructSize, and scalable-vector padding made CallConvLowering
emit a byval of meaningless size.

The verifier now requires the padding to be an integer or an array of
integers. This also covers the earlier void-padding check.

Assisted-by: Claude Code (Claude Opus 5.5)

Added: 
    clang/test/CIR/IR/invalid-union-padding.cir

Modified: 
    clang/include/clang/CIR/Dialect/IR/CIRTypes.td
    clang/lib/CIR/Dialect/IR/CIRTypes.cpp
    clang/test/CIR/IR/invalid-void-member.cir
    clang/unittests/CIR/UnionTypeSizeTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td 
b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
index d3392521b16e4..9fce018046e44 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
@@ -1079,9 +1079,10 @@ def CIR_UnionType : CIR_Type<"Union", "union", [
      - Anonymous: no name and a known body.
 
     Padded unions carry an explicit tail-padding type to ensure the LLVM struct
-    that models the union has the correct byte size.  That slot is separate
-    from the per-member kinds described by `CIR_RecordMemberKind`, which say
-    what each variant holds.  The parser rejects a mark on that slot.
+    that models the union has the correct byte size.  The padding type is
+    `!u8i` or an array of `!u8i`.  That slot is separate from the
+    per-member kinds described by `CIR_RecordMemberKind`, which say what each
+    variant holds.  The parser rejects a mark on that slot.
 
     Examples:
 

diff  --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp 
b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
index 0b1c405812012..ea5bf1c50a48e 100644
--- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
@@ -539,8 +539,17 @@ UnionType::verify(function_ref<mlir::InFlightDiagnostic()> 
emitError,
     return emitError() << "a union member cannot be marked pad";
   if (failed(verifyRecordMemberTypes(emitError, members)))
     return mlir::failure();
-  if (mlir::isa_and_nonnull<cir::VoidType>(padding))
-    return emitError() << "union padding cannot be void";
+  // CIRGen pads a union's tail with a char or an array of chars.
+  if (padding) {
+    mlir::Type charTy = padding;
+    if (auto arrTy = mlir::dyn_cast<cir::ArrayType>(padding))
+      charTy = arrTy.getElementType();
+    auto intTy = mlir::dyn_cast<cir::IntType>(charTy);
+    if (!intTy || intTy.getWidth() != 8 || intTy.isSigned() || 
intTy.isBitInt())
+      return emitError()
+             << "union padding must be !u8i or an array of !u8i, got "
+             << padding;
+  }
   // Every variant starts at offset zero, so a bit-field variant is an access
   // unit of its own.  There is no run for a zero-width bit-field to end, so a
   // variant always has storage.

diff  --git a/clang/test/CIR/IR/invalid-union-padding.cir 
b/clang/test/CIR/IR/invalid-union-padding.cir
new file mode 100644
index 0000000000000..1afc91c2c4a01
--- /dev/null
+++ b/clang/test/CIR/IR/invalid-union-padding.cir
@@ -0,0 +1,32 @@
+// RUN: cir-opt %s -verify-diagnostics -split-input-file
+
+!s32i = !cir.int<s, 32>
+!rec_Incomplete = !cir.struct<"Incomplete" incomplete>
+// expected-error @below {{union padding must be !u8i or an array of !u8i}}
+!rec_U = !cir.union<"U" {data !s32i}, padding = {!rec_Incomplete}>
+
+module {}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+// expected-error @below {{union padding must be !u8i or an array of !u8i}}
+!rec_U = !cir.union<"U" {data !s32i}, padding = {!cir.vector<[4] x !s32i>}>
+
+module {}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+// expected-error @below {{union padding must be !u8i or an array of !u8i}}
+!rec_U = !cir.union<"U" {data !s32i}, padding = {!cir.array<!cir.int<u, 16> x 
2>}>
+
+module {}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+// expected-error @below {{union padding must be !u8i or an array of !u8i}}
+!rec_U = !cir.union<"U" {data !s32i}, padding = {!cir.int<s, 8>}>
+
+module {}

diff  --git a/clang/test/CIR/IR/invalid-void-member.cir 
b/clang/test/CIR/IR/invalid-void-member.cir
index e5eb295a3efa1..aa7c2348159c9 100644
--- a/clang/test/CIR/IR/invalid-void-member.cir
+++ b/clang/test/CIR/IR/invalid-void-member.cir
@@ -18,7 +18,7 @@ module {}
 // -----
 
 !s32i = !cir.int<s, 32>
-// expected-error @below {{union padding cannot be void}}
+// expected-error @below {{union padding must be !u8i or an array of !u8i}}
 !rec_U = !cir.union<"U" {data !s32i}, padding = {!cir.void}>
 
 module {}

diff  --git a/clang/unittests/CIR/UnionTypeSizeTest.cpp 
b/clang/unittests/CIR/UnionTypeSizeTest.cpp
index ffbf53000a148..b115980aa4ab9 100644
--- a/clang/unittests/CIR/UnionTypeSizeTest.cpp
+++ b/clang/unittests/CIR/UnionTypeSizeTest.cpp
@@ -98,13 +98,13 @@ TEST_F(UnionTypeSizeTest, IsLayoutIdenticalNoPadding) {
 TEST_F(UnionTypeSizeTest, IsLayoutIdenticalDifferentPadding) {
   IntType i32 = IntType::get(&context, 32, true);
   IntType i8 = IntType::get(&context, 8, false);
-  IntType i16 = IntType::get(&context, 16, false);
+  cir::ArrayType i8x2 = cir::ArrayType::get(i8, 2);
   mlir::Type members[] = {i32};
   auto ty1 = UnionType::get(&context, getName("Upad1"));
   ty1.complete(members, /*packed=*/false, /*padding=*/i8,
                RecordType::getAllDataKinds(members));
   auto ty2 = UnionType::get(&context, getName("Upad2"));
-  ty2.complete(members, /*packed=*/false, /*padding=*/i16,
+  ty2.complete(members, /*packed=*/false, /*padding=*/i8x2,
                RecordType::getAllDataKinds(members));
   EXPECT_FALSE(ty1.isLayoutIdentical(ty2));
 }


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

Reply via email to