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

>From b19f14a588d3e5e7b47713c9081bd1b6ee2c9ba1 Mon Sep 17 00:00:00 2001
From: mencotton <[email protected]>
Date: Wed, 17 Dec 2025 23:03:09 +0900
Subject: [PATCH 1/6] [CIR] Handle empty unions in record lowering

---
 clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp |  2 ++
 clang/test/CIR/Lowering/union.cir                   | 10 ++++++++++
 2 files changed, 12 insertions(+)
 create mode 100644 clang/test/CIR/Lowering/union.cir

diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 7d854997848aa..06cce00a9aca4 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -2969,6 +2969,8 @@ static void prepareTypeConverter(mlir::LLVMTypeConverter 
&converter,
       break;
     // Unions are lowered as only the largest member.
     case cir::RecordType::Union:
+      if (type.getMembers().empty())
+        break;
       if (auto largestMember = type.getLargestMember(dataLayout))
         llvmMembers.push_back(
             convertTypeForMemory(converter, dataLayout, largestMember));
diff --git a/clang/test/CIR/Lowering/union.cir 
b/clang/test/CIR/Lowering/union.cir
new file mode 100644
index 0000000000000..c7bb8efccadcd
--- /dev/null
+++ b/clang/test/CIR/Lowering/union.cir
@@ -0,0 +1,10 @@
+// RUN: cir-opt %s --cir-to-llvm | FileCheck %s
+
+!u_empty = !cir.record<union {}>
+
+module {
+  cir.func @empty_union(%u: !u_empty) {
+    // CHECK-LABEL:   llvm.func @empty_union
+    cir.return
+  }
+}

>From f92afec2d910b9bcd2cb5fcec2c74ac307934efa Mon Sep 17 00:00:00 2001
From: mencotton <[email protected]>
Date: Fri, 19 Dec 2025 23:56:32 +0900
Subject: [PATCH 2/6] fix: correct getLargestMember crash and lower padded
 empty unions

---
 clang/lib/CIR/Dialect/IR/CIRTypes.cpp                 |  9 +++++++--
 clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp   |  6 +++++-
 clang/test/CIR/Lowering/empty-union-padded.cir        | 11 +++++++++++
 .../test/CIR/Lowering/{union.cir => empty-union.cir}  |  0
 4 files changed, 23 insertions(+), 3 deletions(-)
 create mode 100644 clang/test/CIR/Lowering/empty-union-padded.cir
 rename clang/test/CIR/Lowering/{union.cir => empty-union.cir} (100%)

diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp 
b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
index 9a37a4f4e3996..becb5696ec196 100644
--- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
@@ -297,11 +297,16 @@ void RecordType::complete(ArrayRef<Type> members, bool 
packed, bool padded) {
 Type RecordType::getLargestMember(const ::mlir::DataLayout &dataLayout) const {
   assert(isUnion() && "Only call getLargestMember on unions");
   llvm::ArrayRef<Type> members = getMembers();
+  if (members.empty())
+    return {};
+
   // If the union is padded, we need to ignore the last member,
   // which is the padding.
+  auto endIt = getPadded() ? std::prev(members.end()) : members.end();
+  if (endIt == members.begin())
+    return {};
   return *std::max_element(
-      members.begin(), getPadded() ? members.end() - 1 : members.end(),
-      [&](Type lhs, Type rhs) {
+      members.begin(), endIt, [&](Type lhs, Type rhs) {
         return dataLayout.getTypeABIAlignment(lhs) <
                    dataLayout.getTypeABIAlignment(rhs) ||
                (dataLayout.getTypeABIAlignment(lhs) ==
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 06cce00a9aca4..ede1c656c66d9 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -2969,8 +2969,12 @@ static void prepareTypeConverter(mlir::LLVMTypeConverter 
&converter,
       break;
     // Unions are lowered as only the largest member.
     case cir::RecordType::Union:
-      if (type.getMembers().empty())
+      if (type.getMembers().empty()) {
+        if (type.getPadded())
+          llvmMembers.push_back(
+              mlir::IntegerType::get(&converter.getContext(), 8));
         break;
+      }
       if (auto largestMember = type.getLargestMember(dataLayout))
         llvmMembers.push_back(
             convertTypeForMemory(converter, dataLayout, largestMember));
diff --git a/clang/test/CIR/Lowering/empty-union-padded.cir 
b/clang/test/CIR/Lowering/empty-union-padded.cir
new file mode 100644
index 0000000000000..266368a11ed36
--- /dev/null
+++ b/clang/test/CIR/Lowering/empty-union-padded.cir
@@ -0,0 +1,11 @@
+// RUN: cir-opt %s --cir-to-llvm | FileCheck %s
+
+!u_padded = !cir.record<union padded {}>
+
+module {
+  cir.func @test_empty_padded_union(%arg0: !u_padded) {
+    // CHECK-LABEL: llvm.func @test_empty_padded_union
+    // CHECK-SAME: ({{.*}}: !llvm.struct<(i8)>)
+    cir.return
+  }
+}
diff --git a/clang/test/CIR/Lowering/union.cir 
b/clang/test/CIR/Lowering/empty-union.cir
similarity index 100%
rename from clang/test/CIR/Lowering/union.cir
rename to clang/test/CIR/Lowering/empty-union.cir

>From 8311330336a8dc64448db221f762e8a45f046268 Mon Sep 17 00:00:00 2001
From: mencotton <[email protected]>
Date: Sat, 20 Dec 2025 01:34:38 +0900
Subject: [PATCH 3/6] fix: implement empty union support in CIRGen

---
 .../CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp | 12 ++++++--
 clang/test/CIR/CodeGen/empty-union.c          | 28 ++++++++++++++++++
 clang/test/CIR/CodeGen/empty-union.cpp        | 29 +++++++++++++++++++
 3 files changed, 66 insertions(+), 3 deletions(-)
 create mode 100644 clang/test/CIR/CodeGen/empty-union.c
 create mode 100644 clang/test/CIR/CodeGen/empty-union.cpp

diff --git a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp 
b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
index 87f23409e8e4b..a23a625eea911 100644
--- a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
@@ -811,9 +811,15 @@ void CIRRecordLowering::lowerUnion() {
     fieldTypes.push_back(fieldType);
   }
 
-  if (!storageType)
-    cirGenTypes.getCGModule().errorNYI(recordDecl->getSourceRange(),
-                                       "No-storage Union NYI");
+  if (!storageType) {
+    if (layoutSize.isZero())
+      return;
+    // C++ empty unions can have non-zero size/alignment, so use an integer 
type
+    // sized to the required alignment.
+    CharUnits requiredAlign = astRecordLayout.getAlignment();
+    storageType = getUIntNType(astContext.toBits(requiredAlign));
+    fieldTypes.push_back(storageType);
+  }
 
   if (layoutSize < getSize(storageType))
     storageType = getByteArrayType(layoutSize);
diff --git a/clang/test/CIR/CodeGen/empty-union.c 
b/clang/test/CIR/CodeGen/empty-union.c
new file mode 100644
index 0000000000000..79fa029748b81
--- /dev/null
+++ b/clang/test/CIR/CodeGen/empty-union.c
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o 
- | FileCheck %s --check-prefix=CIR
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o 
- | FileCheck %s --check-prefix=LLVM
+
+// Empty union (no padding, size 0 in CIR)
+union Empty {};
+// CIR: !rec_Empty = !cir.record<union "Empty" {}>
+// LLVM: %union.Empty = type {}
+
+// Aligned empty union (size 0, alignment 16)
+union EmptyAligned {} __attribute__((aligned(16)));
+// CIR: !rec_EmptyAligned = !cir.record<union "EmptyAligned" {}>
+// LLVM: %union.EmptyAligned = type {}
+
+void useEmpty() {
+  union Empty e;
+}
+// CIR: cir.func {{.*}}@useEmpty()
+// CIR:   cir.alloca !rec_Empty, !cir.ptr<!rec_Empty>, ["e"] {alignment = 1 : 
i64}
+// LLVM: define {{.*}} void @useEmpty()
+// LLVM:   alloca %union.Empty, i64 1, align 1
+
+void useEmptyAligned() {
+  union EmptyAligned e;
+}
+// CIR: cir.func {{.*}}@useEmptyAligned()
+// CIR:   cir.alloca !rec_EmptyAligned, !cir.ptr<!rec_EmptyAligned>, ["e"] 
{alignment = 16 : i64}
+// LLVM: define {{.*}} void @useEmptyAligned()
+// LLVM:   alloca %union.EmptyAligned, i64 1, align 16
diff --git a/clang/test/CIR/CodeGen/empty-union.cpp 
b/clang/test/CIR/CodeGen/empty-union.cpp
new file mode 100644
index 0000000000000..030287c9782e8
--- /dev/null
+++ b/clang/test/CIR/CodeGen/empty-union.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o 
- | FileCheck %s --check-prefix=CIR
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o 
- | FileCheck %s --check-prefix=LLVM
+
+// Empty union (should be padded to size 1)
+union Empty {};
+// CIR: ![[INT128:.*]] = !cir.int<u, 128>
+// CIR: !rec_Empty = !cir.record<union "Empty" {!u8i}>
+// LLVM: %union.Empty = type { i8 }
+
+// Aligned empty union (should have aligned integer member in CIR)
+union alignas(16) EmptyAligned {};
+// CIR: !rec_EmptyAligned = !cir.record<union "EmptyAligned" {![[INT128]]}>
+// LLVM: %union.EmptyAligned = type { i128 }
+
+void useEmpty() {
+  Empty e;
+}
+// CIR: cir.func {{.*}}@_Z8useEmptyv()
+// CIR:   cir.alloca !rec_Empty, !cir.ptr<!rec_Empty>, ["e"] {alignment = 1 : 
i64}
+// LLVM: define {{.*}} void @_Z8useEmptyv()
+// LLVM:   alloca %union.Empty, i64 1, align 1
+
+void useEmptyAligned() {
+  EmptyAligned e;
+}
+// CIR: cir.func {{.*}}@_Z15useEmptyAlignedv()
+// CIR:   cir.alloca !rec_EmptyAligned, !cir.ptr<!rec_EmptyAligned>, ["e"] 
{alignment = 16 : i64}
+// LLVM: define {{.*}} void @_Z15useEmptyAlignedv()
+// LLVM:   alloca %union.EmptyAligned, i64 1, align 16

>From ba841c26432f6890cbb691c5c40bce0718878599 Mon Sep 17 00:00:00 2001
From: mencotton <[email protected]>
Date: Wed, 7 Jan 2026 14:07:44 +0900
Subject: [PATCH 4/6] fix: delete redundant tests

---
 clang/test/CIR/Lowering/empty-union-padded.cir | 11 -----------
 clang/test/CIR/Lowering/empty-union.cir        | 10 ----------
 2 files changed, 21 deletions(-)
 delete mode 100644 clang/test/CIR/Lowering/empty-union-padded.cir
 delete mode 100644 clang/test/CIR/Lowering/empty-union.cir

diff --git a/clang/test/CIR/Lowering/empty-union-padded.cir 
b/clang/test/CIR/Lowering/empty-union-padded.cir
deleted file mode 100644
index 266368a11ed36..0000000000000
--- a/clang/test/CIR/Lowering/empty-union-padded.cir
+++ /dev/null
@@ -1,11 +0,0 @@
-// RUN: cir-opt %s --cir-to-llvm | FileCheck %s
-
-!u_padded = !cir.record<union padded {}>
-
-module {
-  cir.func @test_empty_padded_union(%arg0: !u_padded) {
-    // CHECK-LABEL: llvm.func @test_empty_padded_union
-    // CHECK-SAME: ({{.*}}: !llvm.struct<(i8)>)
-    cir.return
-  }
-}
diff --git a/clang/test/CIR/Lowering/empty-union.cir 
b/clang/test/CIR/Lowering/empty-union.cir
deleted file mode 100644
index c7bb8efccadcd..0000000000000
--- a/clang/test/CIR/Lowering/empty-union.cir
+++ /dev/null
@@ -1,10 +0,0 @@
-// RUN: cir-opt %s --cir-to-llvm | FileCheck %s
-
-!u_empty = !cir.record<union {}>
-
-module {
-  cir.func @empty_union(%u: !u_empty) {
-    // CHECK-LABEL:   llvm.func @empty_union
-    cir.return
-  }
-}

>From 435484c8061371e3707648ef988ec70ea3f6aa52 Mon Sep 17 00:00:00 2001
From: mencotton <[email protected]>
Date: Wed, 7 Jan 2026 14:11:10 +0900
Subject: [PATCH 5/6] fix: use `appendPaddingBytes`

---
 clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp | 9 ++-------
 clang/test/CIR/CodeGen/empty-union.cpp              | 7 +++----
 2 files changed, 5 insertions(+), 11 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp 
b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
index a23a625eea911..29eda175c208c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
@@ -812,13 +812,8 @@ void CIRRecordLowering::lowerUnion() {
   }
 
   if (!storageType) {
-    if (layoutSize.isZero())
-      return;
-    // C++ empty unions can have non-zero size/alignment, so use an integer 
type
-    // sized to the required alignment.
-    CharUnits requiredAlign = astRecordLayout.getAlignment();
-    storageType = getUIntNType(astContext.toBits(requiredAlign));
-    fieldTypes.push_back(storageType);
+    appendPaddingBytes(layoutSize);
+    return;
   }
 
   if (layoutSize < getSize(storageType))
diff --git a/clang/test/CIR/CodeGen/empty-union.cpp 
b/clang/test/CIR/CodeGen/empty-union.cpp
index 030287c9782e8..cb17159adc55f 100644
--- a/clang/test/CIR/CodeGen/empty-union.cpp
+++ b/clang/test/CIR/CodeGen/empty-union.cpp
@@ -3,14 +3,13 @@
 
 // Empty union (should be padded to size 1)
 union Empty {};
-// CIR: ![[INT128:.*]] = !cir.int<u, 128>
-// CIR: !rec_Empty = !cir.record<union "Empty" {!u8i}>
+// CIR: !rec_Empty = !cir.record<union "Empty" padded {!u8i}>
 // LLVM: %union.Empty = type { i8 }
 
 // Aligned empty union (should have aligned integer member in CIR)
 union alignas(16) EmptyAligned {};
-// CIR: !rec_EmptyAligned = !cir.record<union "EmptyAligned" {![[INT128]]}>
-// LLVM: %union.EmptyAligned = type { i128 }
+// CIR: !rec_EmptyAligned = !cir.record<union "EmptyAligned" padded 
{!cir.array<!u8i x 16>}>
+// LLVM: %union.EmptyAligned = type { [16 x i8] }
 
 void useEmpty() {
   Empty e;

>From 43cce10384755669f22b221345c802564876bacf Mon Sep 17 00:00:00 2001
From: mencotton <[email protected]>
Date: Wed, 7 Jan 2026 14:55:36 +0900
Subject: [PATCH 6/6] fix: add OGCG test

---
 clang/test/CIR/CodeGen/empty-union.c   | 7 +++++++
 clang/test/CIR/CodeGen/empty-union.cpp | 7 +++++++
 2 files changed, 14 insertions(+)

diff --git a/clang/test/CIR/CodeGen/empty-union.c 
b/clang/test/CIR/CodeGen/empty-union.c
index 79fa029748b81..87cc012706160 100644
--- a/clang/test/CIR/CodeGen/empty-union.c
+++ b/clang/test/CIR/CodeGen/empty-union.c
@@ -1,15 +1,18 @@
 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o 
- | FileCheck %s --check-prefix=CIR
 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o 
- | FileCheck %s --check-prefix=LLVM
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o - | 
FileCheck %s --check-prefix=OGCG
 
 // Empty union (no padding, size 0 in CIR)
 union Empty {};
 // CIR: !rec_Empty = !cir.record<union "Empty" {}>
 // LLVM: %union.Empty = type {}
+// OGCG: %union.Empty = type {}
 
 // Aligned empty union (size 0, alignment 16)
 union EmptyAligned {} __attribute__((aligned(16)));
 // CIR: !rec_EmptyAligned = !cir.record<union "EmptyAligned" {}>
 // LLVM: %union.EmptyAligned = type {}
+// OGCG: %union.EmptyAligned = type {}
 
 void useEmpty() {
   union Empty e;
@@ -18,6 +21,8 @@ void useEmpty() {
 // CIR:   cir.alloca !rec_Empty, !cir.ptr<!rec_Empty>, ["e"] {alignment = 1 : 
i64}
 // LLVM: define {{.*}} void @useEmpty()
 // LLVM:   alloca %union.Empty, i64 1, align 1
+// OGCG: define {{.*}} void @useEmpty()
+// OGCG:   alloca %union.Empty, align 1
 
 void useEmptyAligned() {
   union EmptyAligned e;
@@ -26,3 +31,5 @@ void useEmptyAligned() {
 // CIR:   cir.alloca !rec_EmptyAligned, !cir.ptr<!rec_EmptyAligned>, ["e"] 
{alignment = 16 : i64}
 // LLVM: define {{.*}} void @useEmptyAligned()
 // LLVM:   alloca %union.EmptyAligned, i64 1, align 16
+// OGCG: define {{.*}} void @useEmptyAligned()
+// OGCG:   alloca %union.EmptyAligned, align 16
diff --git a/clang/test/CIR/CodeGen/empty-union.cpp 
b/clang/test/CIR/CodeGen/empty-union.cpp
index cb17159adc55f..e1d7e793cac39 100644
--- a/clang/test/CIR/CodeGen/empty-union.cpp
+++ b/clang/test/CIR/CodeGen/empty-union.cpp
@@ -1,15 +1,18 @@
 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o 
- | FileCheck %s --check-prefix=CIR
 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o 
- | FileCheck %s --check-prefix=LLVM
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o - | 
FileCheck %s --check-prefix=OGCG
 
 // Empty union (should be padded to size 1)
 union Empty {};
 // CIR: !rec_Empty = !cir.record<union "Empty" padded {!u8i}>
 // LLVM: %union.Empty = type { i8 }
+// OGCG: %union.Empty = type { i8 }
 
 // Aligned empty union (should have aligned integer member in CIR)
 union alignas(16) EmptyAligned {};
 // CIR: !rec_EmptyAligned = !cir.record<union "EmptyAligned" padded 
{!cir.array<!u8i x 16>}>
 // LLVM: %union.EmptyAligned = type { [16 x i8] }
+// OGCG: %union.EmptyAligned = type { [16 x i8] }
 
 void useEmpty() {
   Empty e;
@@ -18,6 +21,8 @@ void useEmpty() {
 // CIR:   cir.alloca !rec_Empty, !cir.ptr<!rec_Empty>, ["e"] {alignment = 1 : 
i64}
 // LLVM: define {{.*}} void @_Z8useEmptyv()
 // LLVM:   alloca %union.Empty, i64 1, align 1
+// OGCG: define {{.*}} void @_Z8useEmptyv()
+// OGCG:   alloca %union.Empty, align 1
 
 void useEmptyAligned() {
   EmptyAligned e;
@@ -26,3 +31,5 @@ void useEmptyAligned() {
 // CIR:   cir.alloca !rec_EmptyAligned, !cir.ptr<!rec_EmptyAligned>, ["e"] 
{alignment = 16 : i64}
 // LLVM: define {{.*}} void @_Z15useEmptyAlignedv()
 // LLVM:   alloca %union.EmptyAligned, i64 1, align 16
+// OGCG: define {{.*}} void @_Z15useEmptyAlignedv()
+// OGCG:   alloca %union.EmptyAligned, align 16

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

Reply via email to