[clang] [CIR] Fix base-class index in const-record when there is a vbase (PR #228484)

Erich Keane via cfe-commits cfe-commits at lists.llvm.org
Fri Oct 2 11:50:48 PDT 2026


https://github.com/erichkeane updated https://github.com/llvm/llvm-project/pull/228484

>From 64681630d072590d800cacb6160c1ba0bc099d28 Mon Sep 17 00:00:00 2001
From: erichkeane <ekeane at nvidia.com>
Date: Fri, 2 Oct 2026 08:24:02 -0700
Subject: [PATCH] [CIR] Fix base-class index in const-record when there is a
 vbase

buidlRecordHelper didn't skip the 'virtual' bases like APValue did, so
the presence of a virtual base alone was enough to throw the index off.

This patch gets us slightly more in line with how this is done in
classic codegen.

It is really only reachable in C++26 because of the relaxed constexpr
rules iwth virtual bases, so it needs its own test.

Fixes: #228302
---
 clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp   |  7 +++++--
 .../test/CIR/CodeGen/const-init-multi-base.cpp | 18 ++++++++++++++++++
 2 files changed, 23 insertions(+), 2 deletions(-)
 create mode 100644 clang/test/CIR/CodeGen/const-init-multi-base.cpp

diff --git a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
index 46aabba5b567a..7543bfb75abf7 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
@@ -338,7 +338,8 @@ mlir::Attribute buildRecordHelper(ConstantEmitter &emitter,
                                    apOp.getNameAttr(), indices);
     }
 
-    for (auto [idx, base] : llvm::enumerate(cxxrd->bases())) {
+    unsigned baseNo = 0;
+    for (const CXXBaseSpecifier &base : cxxrd->bases()) {
       // Our init-list implementation here just skips bases because classic
       // compiler does (see the comment in buildRecord). We perhaps COULD do
       // this, but for now we'll skip them.
@@ -350,10 +351,12 @@ mlir::Attribute buildRecordHelper(ConstantEmitter &emitter,
 
       const auto *baseDecl = base.getType()->castAsCXXRecordDecl();
 
+      unsigned curBaseNo = baseNo++;
+
       if (!cirLayout.hasNonVirtualBaseCIRField(baseDecl))
         continue;
 
-      APValue baseValue = inits.getBase(idx);
+      APValue baseValue = inits.getBase(curBaseNo);
 
       const ASTRecordLayout &derivedLayout =
           cgm.getASTContext().getASTRecordLayout(cxxrd);
diff --git a/clang/test/CIR/CodeGen/const-init-multi-base.cpp b/clang/test/CIR/CodeGen/const-init-multi-base.cpp
new file mode 100644
index 0000000000000..aeb2368c97102
--- /dev/null
+++ b/clang/test/CIR/CodeGen/const-init-multi-base.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -emit-llvm %s -o %t.ll
+// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
+
+struct X { int a; };
+struct Y { int b; };
+struct Z : X, Y { int c; };
+
+Z z = {{1}, {2}, 3};
+
+// CIR: cir.global external @z = #cir.const_record<{#cir.const_record<{#cir.int<1> : !s32i}> : !rec_X, #cir.const_record<{#cir.int<2> : !s32i}> : !rec_Y, #cir.int<3> : !s32i}> : !rec_Z
+
+// LLVM: @z = global %struct.Z { %struct.X { i32 1 }, %struct.Y { i32 2 }, i32 3 }
+
+// OGCG: @z = global { i32, i32, i32 } { i32 1, i32 2, i32 3 }



More information about the cfe-commits mailing list