[llvm-branch-commits] [clang] [CIR] Propagate initializer type adjustment failures (PR #224238)

Akimasa Watanuki via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Sat Sep 26 22:49:08 PDT 2026


https://github.com/Men-cotton updated https://github.com/llvm/llvm-project/pull/224238

>From ff0e4e8665fc2b9202eac283a558e9a451108323 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 4996037ea5f56..0b38b10592547 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -3516,7 +3516,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 bfd1182aa6489..77640359f4e0a 100644
--- a/clang/include/clang/CIR/LoweringHelpers.h
+++ b/clang/include/clang/CIR/LoweringHelpers.h
@@ -49,7 +49,8 @@ std::optional<mlir::Attribute> lowerConstRecordAttr(
 /// \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 3aa0dcdb70dcb..b9f12aeabd329 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -811,6 +811,8 @@ mlir::Value CIRAttrToValue::visitCirAttr(cir::ConstArrayAttr attr) {
   mlir::Type llvmTy = converter->convertType(attr.getType());
   mlir::DataLayout dataLayout(parentOp->getParentOfType<mlir::ModuleOp>());
   llvmTy = adjustGlobalTypeForInit(llvmTy, attr, *converter, dataLayout);
+  if (!llvmTy)
+    return {};
   mlir::Location loc = parentOp->getLoc();
   mlir::Value result;
 
@@ -860,6 +862,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);
 
@@ -3023,7 +3027,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());
@@ -3033,6 +3038,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
@@ -3060,6 +3067,7 @@ void CIRToLLVMGlobalOpLowering::setupRegionInitializedLLVMGlobalOp(
           isDsoLocal, threadLocalMode, comdatAttr, attributes);
   newGlobalOp.getRegion().emplaceBlock();
   rewriter.setInsertionPointToEnd(newGlobalOp.getInitializerBlock());
+  return mlir::success();
 }
 
 mlir::LogicalResult
@@ -3077,7 +3085,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
@@ -3122,6 +3131,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 83d6ef6d935ab..671ade1a14d42 100644
--- a/clang/lib/CIR/Lowering/LoweringHelpers.cpp
+++ b/clang/lib/CIR/Lowering/LoweringHelpers.cpp
@@ -571,6 +571,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]) {
@@ -623,6 +625,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;
@@ -672,6 +676,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,
@@ -716,6 +722,8 @@ static mlir::Type adjustGlobalArrayTypeForInit(
   for (auto [idx, elt] : llvm::enumerate(elts)) {
     mlir::Type adjusted =
         adjustGlobalTypeForInit(origEltTy, elt, converter, dataLayout);
+    if (!adjusted)
+      return {};
 
     if (idx >= arrayTy.getNumElements()) {
       adjustedElts.push_back(adjusted);
@@ -744,6 +752,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)
@@ -817,6 +827,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 llvm-branch-commits mailing list