[clang] [CIR] Diagnose failed initializer type adjustments (PR #234348)

Akimasa Watanuki via cfe-commits cfe-commits at lists.llvm.org
Wed Oct 21 13:00:26 PDT 2026


https://github.com/Men-cotton created https://github.com/llvm/llvm-project/pull/234348

Report the CIR initializer type whose conversion fails during recursive layout adjustment, including active union members nested in structs and arrays. Carry that type to the lowering operation so diagnostics identify the unsupported initializer type even when the enclosing storage type converts successfully.

Extend the initializer and language address space tests to check the type-specific diagnostics while retaining coverage for inactive unsupported members.

Assisted-by: Codex / GPT-6

>From d8f78cf85653d3939119a17fe9617404d8f7bab4 Mon Sep 17 00:00:00 2001
From: mencotton <mencotton0410 at gmail.com>
Date: Tue, 20 Oct 2026 16:58:28 -0500
Subject: [PATCH] [CIR] Diagnose failed initializer type adjustments

Report the CIR initializer type whose conversion fails during recursive layout adjustment, including active union members nested in structs and arrays. Carry that type to the lowering operation so diagnostics identify the unsupported initializer type even when the enclosing storage type converts successfully.

Extend the initializer and language address space tests to check the type-specific diagnostics while retaining coverage for inactive unsupported members.

Assisted-by: Codex / GPT-6
---
 clang/include/clang/CIR/LoweringHelpers.h     |  9 ++--
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 26 ++++++----
 clang/lib/CIR/Lowering/LoweringHelpers.cpp    | 47 ++++++++++++-------
 .../CIR/Lowering/unlowered-address-spaces.cir |  4 ++
 .../unsupported-initializer-types.cir         |  6 ++-
 5 files changed, 61 insertions(+), 31 deletions(-)

diff --git a/clang/include/clang/CIR/LoweringHelpers.h b/clang/include/clang/CIR/LoweringHelpers.h
index 18e4c5cd31a62e..fcbbcba906b93d 100644
--- a/clang/include/clang/CIR/LoweringHelpers.h
+++ b/clang/include/clang/CIR/LoweringHelpers.h
@@ -56,10 +56,12 @@ mlir::Attribute spellOutSplitTrailingZeros(mlir::Attribute attr);
 /// source of truth for the shape of a lowered record constant; the
 /// value-producing paths (the insertvalue visitor and lowerConstRecordAttr)
 /// conform to it. Returns null if the input type or an initializer type cannot
-/// be lowered.
+/// be lowered. If provided, \p failedType receives the CIR initializer type
+/// whose conversion failed, including in nested aggregates.
 mlir::Type adjustGlobalTypeForInit(mlir::Type llvmType, mlir::Attribute init,
                                    const mlir::TypeConverter &converter,
-                                   const mlir::DataLayout &dataLayout);
+                                   const mlir::DataLayout &dataLayout,
+                                   mlir::Type *failedType = nullptr);
 
 // A version of adjustGlobalTypeForInit which records where additional padding
 // was added in the middle, so we can properly adjust field indexes.
@@ -67,7 +69,8 @@ mlir::Type
 adjustGlobalTypeForInit(mlir::Type llvmType, mlir::Attribute init,
                         const mlir::TypeConverter &converter,
                         const mlir::DataLayout &dataLayout,
-                        llvm::SmallVectorImpl<unsigned> &paddingAddedIndexes);
+                        llvm::SmallVectorImpl<unsigned> &paddingAddedIndexes,
+                        mlir::Type *failedType = nullptr);
 
 mlir::Value getConstAPInt(mlir::OpBuilder &bld, mlir::Location loc,
                           mlir::Type typ, const llvm::APInt &val);
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 719ec9ac184ff6..4b698e6e1b86a4 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -922,10 +922,13 @@ mlir::Value CIRAttrToValue::visitCirAttr(cir::ConstArrayAttr attr) {
   mlir::Type convertedTy = converter->convertType(attr.getType());
   auto moduleOp = parentOp->getParentOfType<mlir::ModuleOp>();
   mlir::DataLayout dataLayout(moduleOp);
-  mlir::Type llvmTy =
-      adjustGlobalTypeForInit(convertedTy, attr, *converter, dataLayout);
-  if (!llvmTy)
+  mlir::Type failedType = attr.getType();
+  mlir::Type llvmTy = adjustGlobalTypeForInit(convertedTy, attr, *converter,
+                                              dataLayout, &failedType);
+  if (!llvmTy) {
+    emitTypeConversionError(parentOp, failedType);
     return {};
+  }
   mlir::Location loc = parentOp->getLoc();
   mlir::Value result;
 
@@ -998,10 +1001,13 @@ mlir::Value CIRAttrToValue::visitCirAttr(cir::ConstRecordAttr constRecord) {
   mlir::Type llvmTy = converter->convertType(constRecord.getType());
   mlir::DataLayout dataLayout(parentOp->getParentOfType<mlir::ModuleOp>());
   llvm::SmallVector<unsigned> paddingAddedIndexes;
+  mlir::Type failedType = constRecord.getType();
   llvmTy = adjustGlobalTypeForInit(llvmTy, constRecord, *converter, dataLayout,
-                                   paddingAddedIndexes);
-  if (!llvmTy)
+                                   paddingAddedIndexes, &failedType);
+  if (!llvmTy) {
+    emitTypeConversionError(parentOp, failedType);
     return {};
+  }
   const mlir::Location loc = parentOp->getLoc();
   mlir::Value result = mlir::LLVM::UndefOp::create(rewriter, loc, llvmTy);
 
@@ -3351,11 +3357,12 @@ CIRToLLVMGlobalOpLowering::setupRegionInitializedLLVMGlobalOp(
 
   // Keep the global's type in sync with the value built by CIRAttrToValue: a
   // flexible array member initializer requires an oversized anonymous struct.
+  mlir::Type failedType = op.getSymType();
   if (std::optional<mlir::Attribute> init = op.getInitialValue())
     llvmType = adjustGlobalTypeForInit(llvmType, *init, *getTypeConverter(),
-                                       dataLayout);
+                                       dataLayout, &failedType);
   if (!llvmType)
-    return mlir::failure();
+    return emitTypeConversionError(op, failedType);
 
   // FIXME: These default values are placeholders until the the equivalent
   //        attributes are available on cir.global ops. This duplicates code
@@ -3444,11 +3451,12 @@ mlir::LogicalResult CIRToLLVMGlobalOpLowering::matchAndRewrite(
   // A flexible array member initializer makes the constant larger than the
   // record's declared type, so the global must use an oversized anonymous
   // struct instead.
+  mlir::Type failedType = cirSymType;
   if (init.has_value())
     llvmType = adjustGlobalTypeForInit(llvmType, *init, *getTypeConverter(),
-                                       dataLayout);
+                                       dataLayout, &failedType);
   if (!llvmType)
-    return mlir::failure();
+    return emitTypeConversionError(op, failedType);
 
   // 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 1ab147c0f96396..b0d7ee69664310 100644
--- a/clang/lib/CIR/Lowering/LoweringHelpers.cpp
+++ b/clang/lib/CIR/Lowering/LoweringHelpers.cpp
@@ -655,7 +655,8 @@ static bool shouldPackFAMStruct(const mlir::DataLayout &dataLayout,
 static mlir::Type adjustGlobalStructTypeForInit(
     mlir::LLVM::LLVMStructType structTy, cir::ConstRecordAttr constRecord,
     const mlir::TypeConverter &converter, const mlir::DataLayout &dataLayout,
-    llvm::SmallVectorImpl<unsigned> &paddingAddedIndexes) {
+    llvm::SmallVectorImpl<unsigned> &paddingAddedIndexes,
+    mlir::Type *failedType) {
   assert(paddingAddedIndexes.empty() &&
          "Not for accumulation, just single depth");
   llvm::ArrayRef<mlir::Attribute> initMembers =
@@ -673,8 +674,8 @@ static mlir::Type adjustGlobalStructTypeForInit(
   for (auto [idx, member] : llvm::enumerate(initMembers)) {
     if (idx >= origBody.size())
       break;
-    mlir::Type adjusted =
-        adjustGlobalTypeForInit(origBody[idx], member, converter, dataLayout);
+    mlir::Type adjusted = adjustGlobalTypeForInit(
+        origBody[idx], member, converter, dataLayout, failedType);
     if (!adjusted)
       return {};
     unsigned adjustedAlign = dataLayout.getTypeABIAlignment(adjusted);
@@ -726,9 +727,9 @@ static mlir::Type adjustGlobalStructTypeForInit(
     mlir::Type lastInitType =
         mlir::cast<mlir::TypedAttr>(initMembers.back()).getType();
     if (mlir::cast<cir::ArrayType>(lastInitType).getSize() != 0) {
-      newBody.back() =
-          adjustGlobalTypeForInit(converter.convertType(lastInitType),
-                                  initMembers.back(), converter, dataLayout);
+      newBody.back() = adjustGlobalTypeForInit(
+          converter.convertType(lastInitType), initMembers.back(), converter,
+          dataLayout, failedType);
       if (!newBody.back())
         return {};
       packed = packed || shouldPackFAMStruct(dataLayout, newBody);
@@ -767,7 +768,8 @@ static mlir::Type adjustGlobalStructTypeForInit(
 // size, mirroring classic codegen.
 static mlir::Type adjustGlobalUnionTypeForInit(
     mlir::LLVM::LLVMStructType structTy, cir::ConstRecordAttr constRecord,
-    const mlir::TypeConverter &converter, const mlir::DataLayout &dataLayout) {
+    const mlir::TypeConverter &converter, const mlir::DataLayout &dataLayout,
+    mlir::Type *failedType) {
 
   auto unionTy = mlir::cast<cir::UnionType>(constRecord.getType());
 
@@ -779,7 +781,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);
+  memberTy = adjustGlobalTypeForInit(memberTy, member, converter, dataLayout,
+                                     failedType);
   if (!memberTy)
     return {};
 
@@ -817,7 +820,8 @@ static mlir::Type adjustGlobalUnionTypeForInit(
 //   <{ [M x T], [N x T] }>
 static mlir::Type adjustGlobalArrayTypeForInit(
     mlir::LLVM::LLVMArrayType arrayTy, cir::ConstArrayAttr arrayInit,
-    const mlir::TypeConverter &converter, const mlir::DataLayout &dataLayout) {
+    const mlir::TypeConverter &converter, const mlir::DataLayout &dataLayout,
+    mlir::Type *failedType) {
   auto elts = mlir::dyn_cast<mlir::ArrayAttr>(arrayInit.getElts());
 
   if (!elts)
@@ -829,8 +833,8 @@ static mlir::Type adjustGlobalArrayTypeForInit(
   bool changed = elts.size() > arrayTy.getNumElements();
 
   for (mlir::Attribute elt : elts) {
-    mlir::Type adjusted =
-        adjustGlobalTypeForInit(origEltTy, elt, converter, dataLayout);
+    mlir::Type adjusted = adjustGlobalTypeForInit(origEltTy, elt, converter,
+                                                  dataLayout, failedType);
     if (!adjusted)
       return {};
     changed |= adjusted != origEltTy;
@@ -874,15 +878,20 @@ mlir::Type
 adjustGlobalTypeForInit(mlir::Type llvmType, mlir::Attribute init,
                         const mlir::TypeConverter &converter,
                         const mlir::DataLayout &dataLayout,
-                        llvm::SmallVectorImpl<unsigned> &paddingAddedIndexes) {
-  if (!llvmType)
+                        llvm::SmallVectorImpl<unsigned> &paddingAddedIndexes,
+                        mlir::Type *failedType) {
+  if (!llvmType) {
+    if (failedType)
+      if (auto typedInit = mlir::dyn_cast_if_present<mlir::TypedAttr>(init))
+        *failedType = typedInit.getType();
     return {};
+  }
   if (auto arrayInit = mlir::dyn_cast_if_present<cir::ConstArrayAttr>(init)) {
     auto arrayTy = mlir::dyn_cast<mlir::LLVM::LLVMArrayType>(llvmType);
     if (!arrayTy)
       return llvmType;
     return adjustGlobalArrayTypeForInit(arrayTy, arrayInit, converter,
-                                        dataLayout);
+                                        dataLayout, failedType);
   }
 
   // Conversions for both only happen if we have a record init.
@@ -899,19 +908,21 @@ adjustGlobalTypeForInit(mlir::Type llvmType, mlir::Attribute init,
   // Structs can have a flexible array member, adjust that.
   if (mlir::isa<cir::StructType>(constRecord.getType()))
     return adjustGlobalStructTypeForInit(structTy, constRecord, converter,
-                                         dataLayout, paddingAddedIndexes);
+                                         dataLayout, paddingAddedIndexes,
+                                         failedType);
   if (mlir::isa<cir::UnionType>(constRecord.getType()))
     return adjustGlobalUnionTypeForInit(structTy, constRecord, converter,
-                                        dataLayout);
+                                        dataLayout, failedType);
   return llvmType;
 }
 
 mlir::Type adjustGlobalTypeForInit(mlir::Type llvmType, mlir::Attribute init,
                                    const mlir::TypeConverter &converter,
-                                   const mlir::DataLayout &dataLayout) {
+                                   const mlir::DataLayout &dataLayout,
+                                   mlir::Type *failedType) {
   llvm::SmallVector<unsigned> ignoredAddedIndexes;
   return adjustGlobalTypeForInit(llvmType, init, converter, dataLayout,
-                                 ignoredAddedIndexes);
+                                 ignoredAddedIndexes, failedType);
 }
 
 std::optional<mlir::Attribute> lowerConstRecordAttr(
diff --git a/clang/test/CIR/Lowering/unlowered-address-spaces.cir b/clang/test/CIR/Lowering/unlowered-address-spaces.cir
index 32a80f537d503b..48886f5fd672f4 100644
--- a/clang/test/CIR/Lowering/unlowered-address-spaces.cir
+++ b/clang/test/CIR/Lowering/unlowered-address-spaces.cir
@@ -38,6 +38,7 @@ module attributes {cir.triple = "spirv64-unknown-unknown"} {
 
 module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
   // The union's integer storage converts, but its active initializer does not.
+  // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.ptr<!cir.void, lang_address_space(offload_global)>'}}
   // expected-error @below {{failed to legalize operation 'cir.global'}}
   cir.global external @union_active_initializer_language_address_space = #cir.const_record<{#cir.ptr<null> : !langptr}> : !rec_U
 }
@@ -286,6 +287,7 @@ module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
 
 module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
   cir.func @constant_union_active_initializer_language_address_space() {
+    // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.ptr<!cir.void, lang_address_space(offload_global)>'}}
     // expected-error @below {{failed to legalize operation 'cir.const'}}
     %0 = cir.const #cir.const_record<{#cir.ptr<null> : !langptr}> : !rec_U
     cir.return
@@ -303,6 +305,7 @@ module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
 module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
   // Propagate adjustment failure through both the enclosing union and struct.
   cir.func @constant_nested_union_initializer_language_address_space() {
+    // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.ptr<!cir.void, lang_address_space(offload_global)>'}}
     // expected-error @below {{failed to legalize operation 'cir.const'}}
     %0 = cir.const #cir.const_record<{#cir.const_record<{#cir.const_record<{#cir.ptr<null> : !langptr}> : !rec_U}> : !rec_Outer}> : !rec_S
     cir.return
@@ -318,6 +321,7 @@ module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
 
 module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
   cir.func @constant_union_array_initializer_language_address_space() {
+    // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.ptr<!cir.void, lang_address_space(offload_global)>'}}
     // expected-error @below {{failed to legalize operation 'cir.const'}}
     %0 = cir.const #cir.const_array<[#cir.const_record<{#cir.ptr<null> : !langptr}> : !rec_U]> : !array
     cir.return
diff --git a/clang/test/CIR/Lowering/unsupported-initializer-types.cir b/clang/test/CIR/Lowering/unsupported-initializer-types.cir
index 43b34f3994b934..850bb8c7b486ff 100644
--- a/clang/test/CIR/Lowering/unsupported-initializer-types.cir
+++ b/clang/test/CIR/Lowering/unsupported-initializer-types.cir
@@ -1,13 +1,14 @@
 // 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.
+// enclosing operation and diagnose the active initializer's type.
 
 !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 {{ClangIR lowering NYI: cannot convert '!cir.vector<4 x !cir.int<s, 7, bitint>>'}}
   // expected-error @below {{failed to legalize operation 'cir.global'}}
   cir.global external @global_union = #cir.const_record<{#cir.zero : !vec}> : !union
 }
@@ -19,6 +20,7 @@ module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
 
 module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
   cir.func @constant_union() {
+    // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.vector<4 x !cir.int<s, 7, bitint>>'}}
     // expected-error @below {{failed to legalize operation 'cir.const'}}
     %0 = cir.const #cir.const_record<{#cir.zero : !vec}> : !union
     cir.return
@@ -35,6 +37,7 @@ module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
 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 {{ClangIR lowering NYI: cannot convert '!cir.vector<4 x !cir.int<s, 7, bitint>>'}}
     // 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
@@ -48,6 +51,7 @@ module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
 
 module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
   cir.func @array_union() {
+    // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.vector<4 x !cir.int<s, 7, bitint>>'}}
     // 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



More information about the cfe-commits mailing list