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
