[clang] [CIR] Propagate initializer type adjustment failures (PR #224238)
Akimasa Watanuki via cfe-commits
cfe-commits at lists.llvm.org
Tue Oct 20 14:51:03 PDT 2026
https://github.com/Men-cotton updated https://github.com/llvm/llvm-project/pull/224238
>From 3d9322033554e4c3685882a3dce75e9083b38199 Mon Sep 17 00:00:00 2001
From: mencotton <mencotton0410 at gmail.com>
Date: Tue, 15 Sep 2026 20:49:43 +0900
Subject: [PATCH] [CIR] Propagate initializer type adjustment failures
Reject initializers whose active members have no LLVM representation, including when an enclosing union's storage type is convertible. Propagate recursive adjustment failures before querying data layout or constructing LLVM operations.
Assisted-by: Codex / GPT-6
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 2 +-
clang/include/clang/CIR/LoweringHelpers.h | 3 +-
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 15 ++++-
clang/lib/CIR/Lowering/LoweringHelpers.cpp | 12 ++++
.../unsupported-initializer-types.cir | 66 +++++++++++++++++++
5 files changed, 94 insertions(+), 4 deletions(-)
create mode 100644 clang/test/CIR/Lowering/unsupported-initializer-types.cir
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 6039e1f49a3ee..614133eb1e300 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -3578,7 +3578,7 @@ def CIR_GlobalOp : CIR_RegionBranchOpBase<"global", [
cir::GlobalOp op, mlir::Attribute init,
mlir::ConversionPatternRewriter &rewriter) const;
- void setupRegionInitializedLLVMGlobalOp(
+ mlir::LogicalResult setupRegionInitializedLLVMGlobalOp(
cir::GlobalOp op, mlir::ConversionPatternRewriter &rewriter) const;
llvm::SmallVector<mlir::NamedAttribute> lowerGlobalAttributes(
diff --git a/clang/include/clang/CIR/LoweringHelpers.h b/clang/include/clang/CIR/LoweringHelpers.h
index c2ee778908565..bf2c029fa2c9e 100644
--- a/clang/include/clang/CIR/LoweringHelpers.h
+++ b/clang/include/clang/CIR/LoweringHelpers.h
@@ -55,7 +55,8 @@ mlir::Attribute spellOutSplitTrailingZeros(mlir::Attribute attr);
/// \p llvmType unchanged when no adjustment is needed. This is the single
/// source of truth for the shape of a lowered record constant; the
/// value-producing paths (the insertvalue visitor and lowerConstRecordAttr)
-/// conform to it.
+/// conform to it. Returns null if the input type or an initializer type cannot
+/// be lowered.
mlir::Type adjustGlobalTypeForInit(mlir::Type llvmType, mlir::Attribute init,
const mlir::TypeConverter &converter,
const mlir::DataLayout &dataLayout);
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 541d4de60a337..66d87b7ee35c7 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -919,6 +919,8 @@ mlir::Value CIRAttrToValue::visitCirAttr(cir::ConstArrayAttr attr) {
mlir::DataLayout dataLayout(moduleOp);
mlir::Type llvmTy =
adjustGlobalTypeForInit(convertedTy, attr, *converter, dataLayout);
+ if (!llvmTy)
+ return {};
mlir::Location loc = parentOp->getLoc();
mlir::Value result;
@@ -993,6 +995,8 @@ mlir::Value CIRAttrToValue::visitCirAttr(cir::ConstRecordAttr constRecord) {
llvm::SmallVector<unsigned> paddingAddedIndexes;
llvmTy = adjustGlobalTypeForInit(llvmTy, constRecord, *converter, dataLayout,
paddingAddedIndexes);
+ if (!llvmTy)
+ return {};
const mlir::Location loc = parentOp->getLoc();
mlir::Value result = mlir::LLVM::UndefOp::create(rewriter, loc, llvmTy);
@@ -3300,7 +3304,8 @@ convertTlsModelAttrToLLVM(TLSModelAttr attr) {
/// Replace CIR global with a region initialized LLVM global and update
/// insertion point to the end of the initializer block.
-void CIRToLLVMGlobalOpLowering::setupRegionInitializedLLVMGlobalOp(
+mlir::LogicalResult
+CIRToLLVMGlobalOpLowering::setupRegionInitializedLLVMGlobalOp(
cir::GlobalOp op, mlir::ConversionPatternRewriter &rewriter) const {
mlir::Type llvmType =
convertTypeForMemory(*getTypeConverter(), dataLayout, op.getSymType());
@@ -3310,6 +3315,8 @@ void CIRToLLVMGlobalOpLowering::setupRegionInitializedLLVMGlobalOp(
if (std::optional<mlir::Attribute> init = op.getInitialValue())
llvmType = adjustGlobalTypeForInit(llvmType, *init, *getTypeConverter(),
dataLayout);
+ if (!llvmType)
+ return mlir::failure();
// FIXME: These default values are placeholders until the the equivalent
// attributes are available on cir.global ops. This duplicates code
@@ -3337,6 +3344,7 @@ void CIRToLLVMGlobalOpLowering::setupRegionInitializedLLVMGlobalOp(
isDsoLocal, threadLocalMode, comdatAttr, attributes);
newGlobalOp.getRegion().emplaceBlock();
rewriter.setInsertionPointToEnd(newGlobalOp.getInitializerBlock());
+ return mlir::success();
}
mlir::LogicalResult
@@ -3354,7 +3362,8 @@ CIRToLLVMGlobalOpLowering::matchAndRewriteRegionInitializedGlobal(
// should be updated. For now, we use a custom op to initialize globals
// to the appropriate value.
const mlir::Location loc = op.getLoc();
- setupRegionInitializedLLVMGlobalOp(op, rewriter);
+ if (failed(setupRegionInitializedLLVMGlobalOp(op, rewriter)))
+ return mlir::failure();
// Pass blockInfoAddr so that block address initializers (either as the whole
// initializer or nested inside an aggregate) can be resolved by the
@@ -3399,6 +3408,8 @@ mlir::LogicalResult CIRToLLVMGlobalOpLowering::matchAndRewrite(
if (init.has_value())
llvmType = adjustGlobalTypeForInit(llvmType, *init, *getTypeConverter(),
dataLayout);
+ if (!llvmType)
+ return mlir::failure();
// FIXME: These default values are placeholders until the the equivalent
// attributes are available on cir.global ops.
diff --git a/clang/lib/CIR/Lowering/LoweringHelpers.cpp b/clang/lib/CIR/Lowering/LoweringHelpers.cpp
index 988e50c3dc9ed..4918850dd4e53 100644
--- a/clang/lib/CIR/Lowering/LoweringHelpers.cpp
+++ b/clang/lib/CIR/Lowering/LoweringHelpers.cpp
@@ -673,6 +673,8 @@ static mlir::Type adjustGlobalStructTypeForInit(
break;
mlir::Type adjusted =
adjustGlobalTypeForInit(origBody[idx], member, converter, dataLayout);
+ if (!adjusted)
+ return {};
unsigned adjustedAlign = dataLayout.getTypeABIAlignment(adjusted);
if (adjusted != origBody[idx]) {
@@ -725,6 +727,8 @@ static mlir::Type adjustGlobalStructTypeForInit(
newBody.back() =
adjustGlobalTypeForInit(converter.convertType(lastInitType),
initMembers.back(), converter, dataLayout);
+ if (!newBody.back())
+ return {};
packed = packed || shouldPackFAMStruct(dataLayout, newBody);
widenedFAM = true;
changed = true;
@@ -774,6 +778,8 @@ static mlir::Type adjustGlobalUnionTypeForInit(
// The active member may itself need adjusting (e.g. it is a nested union, or
// a struct containing one), so recurse before using its type below.
memberTy = adjustGlobalTypeForInit(memberTy, member, converter, dataLayout);
+ if (!memberTy)
+ return {};
// The converted union type is { storage, [padding] }, where storage is the
// union's most-aligned member. When the active member IS that storage type,
@@ -823,6 +829,8 @@ static mlir::Type adjustGlobalArrayTypeForInit(
for (mlir::Attribute elt : elts) {
mlir::Type adjusted =
adjustGlobalTypeForInit(origEltTy, elt, converter, dataLayout);
+ if (!adjusted)
+ return {};
changed |= adjusted != origEltTy;
adjustedElts.push_back(adjusted);
}
@@ -865,6 +873,8 @@ adjustGlobalTypeForInit(mlir::Type llvmType, mlir::Attribute init,
const mlir::TypeConverter &converter,
const mlir::DataLayout &dataLayout,
llvm::SmallVectorImpl<unsigned> &paddingAddedIndexes) {
+ if (!llvmType)
+ return {};
if (auto arrayInit = mlir::dyn_cast_if_present<cir::ConstArrayAttr>(init)) {
auto arrayTy = mlir::dyn_cast<mlir::LLVM::LLVMArrayType>(llvmType);
if (!arrayTy)
@@ -938,6 +948,8 @@ std::optional<mlir::Attribute> lowerConstRecordAttr(
mlir::Type adjustedTy = adjustGlobalTypeForInit(
converter->convertType(constRecord.getType()), constRecord, *converter,
mlir::DataLayout(moduleOp), paddingAddedIndexes);
+ if (!adjustedTy)
+ return std::nullopt;
// This handles #3 from above. adjustGlobalTypeForInit ensures the
// indexes are in increasing order, so we can insert 'backwards' without
diff --git a/clang/test/CIR/Lowering/unsupported-initializer-types.cir b/clang/test/CIR/Lowering/unsupported-initializer-types.cir
new file mode 100644
index 0000000000000..43b34f3994b93
--- /dev/null
+++ b/clang/test/CIR/Lowering/unsupported-initializer-types.cir
@@ -0,0 +1,66 @@
+// RUN: cir-opt %s --split-input-file --cir-to-llvm -verify-diagnostics | FileCheck %s
+
+// Vector-of-_BitInt conversion is unsupported; propagate its failure to the
+// enclosing operation instead of constructing invalid LLVM operations.
+
+!vec = !cir.vector<4 x !cir.int<s, 7, bitint>>
+!union = !cir.union<"U" {data !cir.int<s, 128>, data !vec}>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+ // The union's integer storage converts, but its active initializer does not.
+ // expected-error @below {{failed to legalize operation 'cir.global'}}
+ cir.global external @global_union = #cir.const_record<{#cir.zero : !vec}> : !union
+}
+
+// -----
+
+!vec = !cir.vector<4 x !cir.int<s, 7, bitint>>
+!union = !cir.union<"U" {data !cir.int<s, 128>, data !vec}>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+ cir.func @constant_union() {
+ // expected-error @below {{failed to legalize operation 'cir.const'}}
+ %0 = cir.const #cir.const_record<{#cir.zero : !vec}> : !union
+ cir.return
+ }
+}
+
+// -----
+
+!vec = !cir.vector<4 x !cir.int<s, 7, bitint>>
+!union = !cir.union<"U" {data !cir.int<s, 128>, data !vec}>
+!outer = !cir.union<"Outer" {data !cir.int<s, 128>, data !union}>
+!record = !cir.struct<"Record" {data !outer}>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+ // Propagate adjustment failure through both the enclosing union and struct.
+ cir.func @nested_union() {
+ // expected-error @below {{failed to legalize operation 'cir.const'}}
+ %0 = cir.const #cir.const_record<{#cir.const_record<{#cir.const_record<{#cir.zero : !vec}> : !union}> : !outer}> : !record
+ cir.return
+ }
+}
+
+// -----
+
+!vec = !cir.vector<4 x !cir.int<s, 7, bitint>>
+!union = !cir.union<"U" {data !cir.int<s, 128>, data !vec}>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+ cir.func @array_union() {
+ // expected-error @below {{failed to legalize operation 'cir.const'}}
+ %0 = cir.const #cir.const_array<[#cir.const_record<{#cir.zero : !vec}> : !union]> : !cir.array<!union x 1>
+ cir.return
+ }
+}
+
+// -----
+
+!vec = !cir.vector<4 x !cir.int<s, 7, bitint>>
+!union = !cir.union<"U" {data !cir.int<s, 128>, data !vec}>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+ // An inactive unsupported member does not prevent lowering integer storage.
+ // CHECK: llvm.mlir.global external @integer_initializer
+ cir.global external @integer_initializer = #cir.const_record<{#cir.int<0> : !cir.int<s, 128>}> : !union
+}
More information about the cfe-commits
mailing list