[clang] [clang][codegen] Additional tests for vbptr memory size calculation (PR #185703)

via cfe-commits cfe-commits at lists.llvm.org
Tue Mar 10 10:47:35 PDT 2026


https://github.com/schittir updated https://github.com/llvm/llvm-project/pull/185703

>From bf7598321ad421a753ade1241822e379a56e2246 Mon Sep 17 00:00:00 2001
From: Sindhu Chittireddy <sindhu.chittireddy at intel.com>
Date: Tue, 10 Mar 2026 10:40:14 -0700
Subject: [PATCH] Additional tests for
 https://github.com/llvm/llvm-project/pull/184558

This patch adds three vbptr and 32 bit test cases
---
 ...diamond-template-multiple-vbptrs-32bit.cpp | 212 ++++++++++++++++++
 ...t-abi-diamond-template-multiple-vbptrs.cpp |  91 +++++++-
 2 files changed, 302 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/CodeGenCXX/microsoft-abi-diamond-template-multiple-vbptrs-32bit.cpp

diff --git a/clang/test/CodeGenCXX/microsoft-abi-diamond-template-multiple-vbptrs-32bit.cpp b/clang/test/CodeGenCXX/microsoft-abi-diamond-template-multiple-vbptrs-32bit.cpp
new file mode 100644
index 0000000000000..610ed8903003f
--- /dev/null
+++ b/clang/test/CodeGenCXX/microsoft-abi-diamond-template-multiple-vbptrs-32bit.cpp
@@ -0,0 +1,212 @@
+// RUN: %clang_cc1 -triple i686-windows-msvc -std=c++17 -emit-llvm -o - %s | FileCheck %s
+
+// Test for the fix in EmitNullBaseClassInitialization where the calculation
+// of SplitAfterSize was incorrect when multiple vbptrs are present.
+// This is the 32-bit version of the test.
+
+namespace test {
+
+class Base {
+public:
+  virtual ~Base() {}
+};
+
+class Left : public virtual Base {
+};
+
+class Right : public virtual Base {
+};
+
+class Diamond : public Left, public Right {
+};
+
+// Test 1: Diamond inheritance in a template that triggers the bug
+template<typename T>
+class Derived : public Diamond {
+public:
+  // CHECK-LABEL: define {{.*}} @"??0?$Derived at H@test@@QAE at XZ"
+
+  // Layout of Derived<int> (32-bit):
+  // offset 0: vbptr for Left (4 bytes)
+  // offset 4: vbptr for Right (4 bytes)
+  // offset 8+: virtual base Base
+
+  // CHECK: call {{.*}} @"??0Diamond at test@@QAE at XZ"
+  // EmitNullBaseClassInitialization now correctly calculates memory regions
+  // around the vbptrs without hitting negative size assertion
+
+  // No memset is generated since there are no gaps to zero
+  // CHECK-NOT: call void @llvm.memset
+  // CHECK: ret
+
+  Derived() : Diamond() {}
+};
+
+// Explicit instantiation to trigger code generation
+template class Derived<int>;
+
+// Test 2: Diamond in a template, with data members (calls memset)
+class DiamondWithData : public Left, public Right {
+public:
+  int x;
+  int y;
+};
+
+template<typename T>
+class DerivedWithData : public DiamondWithData {
+public:
+  DerivedWithData();
+};
+
+// CHECK-LABEL: define {{.*}} @"??0?$DerivedWithData at H@test@@QAE at XZ"
+//
+// Layout of DerivedWithData<int> (32-bit):
+// offset 0: vbptr for Left (4 bytes)
+// offset 4: vbptr for Right (4 bytes)
+// offset 8: x (4 bytes)
+// offset 12: y (4 bytes)
+// offset 16+: virtual base Base
+//
+// EmitNullBaseClassInitialization zero-initializes the data members [8, 16)
+// while skipping both vbptrs [0, 8)
+//
+// memset zeros 8 bytes for x and y at offset 8
+// CHECK: call void @llvm.memset.p0.i32(ptr {{.*}}, i8 0, i32 8, i1 false)
+// CHECK: ret
+
+template<typename T>
+DerivedWithData<T>::DerivedWithData() : DiamondWithData() {
+}
+
+template struct DerivedWithData<int>;
+
+// Test 3: Three vbptrs test case
+
+// Three separate classes that virtually inherit from Base
+class Middle : public virtual Base {
+};
+
+// TriDiamond has three vbptrs - one from each base class
+class TriDiamond : public Left, public Middle, public Right {
+};
+
+// Test 3a: Template instantiation with three vbptrs (no data members)
+template<typename T>
+class TriDerived : public TriDiamond {
+public:
+  // CHECK-LABEL: define {{.*}} @"??0?$TriDerived at H@test@@QAE at XZ"
+
+  // Layout of TriDerived<int> (32-bit):
+  // offset 0:  vbptr for Left (4 bytes)
+  // offset 4:  vbptr for Middle (4 bytes)
+  // offset 8:  vbptr for Right (4 bytes)
+  // offset 12+: virtual base Base
+
+  // CHECK: call {{.*}} @"??0TriDiamond at test@@QAE at XZ"
+  // No memset is generated since there are no gaps to zero
+  // CHECK-NOT: call void @llvm.memset
+  // CHECK: ret
+
+  TriDerived() : TriDiamond() {}
+};
+
+// Explicit instantiation to trigger code generation
+template class TriDerived<int>;
+
+// Test 3b: Three vbptrs with data members (calls memset)
+class TriDiamondWithData : public Left, public Middle, public Right {
+public:
+  int a;
+  int b;
+};
+
+template<typename T>
+class TriDerivedWithData : public TriDiamondWithData {
+public:
+  TriDerivedWithData();
+};
+
+// CHECK-LABEL: define {{.*}} @"??0?$TriDerivedWithData at H@test@@QAE at XZ"
+//
+// Layout of TriDerivedWithData<int> (32-bit):
+// offset 0:  vbptr for Left (4 bytes)
+// offset 4:  vbptr for Middle (4 bytes)
+// offset 8:  vbptr for Right (4 bytes)
+// offset 12: a (4 bytes)
+// offset 16: b (4 bytes)
+// offset 20+: virtual base Base
+
+// memset zeros 8 bytes [12, 20)
+// CHECK: call void @llvm.memset.p0.i32(ptr {{.*}}, i8 0, i32 8, i1 false)
+// CHECK: ret
+
+template<typename T>
+TriDerivedWithData<T>::TriDerivedWithData() : TriDiamondWithData() {
+}
+
+template struct TriDerivedWithData<int>;
+
+// Test 4: Another case which triggers the bug (similar to Test 1, non-template)
+class Interface {
+public:
+  virtual ~Interface() {}
+};
+
+class Base1If : public virtual Interface {
+};
+
+class Base2If : public virtual Interface {
+};
+
+class BaseIf : public Base1If, public Base2If {
+};
+
+class DerivedClass : public BaseIf {
+public:
+  // CHECK-LABEL: define {{.*}} @"??0DerivedClass at test@@QAE at XZ"
+
+  // Layout of DerivedClass (32-bit):
+  // offset 0: vbptr for Base1If (4 bytes)
+  // offset 4: vbptr for Base2If (4 bytes)
+  // offset 8+: virtual base Interface
+
+  // CHECK: call {{.*}} @"??0BaseIf at test@@QAE at XZ"
+  // EmitNullBaseClassInitialization now correctly calculates memory regions
+  // around the vbptrs without hitting negative size assertion
+
+  // No memset is generated since there are no gaps to zero
+  // CHECK-NOT: call void @llvm.memset
+  // CHECK: ret
+
+  DerivedClass()
+  : BaseIf()
+  { }
+};
+
+// Instantiate to trigger code generation
+DerivedClass d;
+
+// Test 4c: Non-template version with three vbptrs
+class TriConcreteClass : public TriDiamond {
+public:
+  // CHECK-LABEL: define {{.*}} @"??0TriConcreteClass at test@@QAE at XZ"
+
+  // Layout of TriConcreteClass (32-bit):
+  // offset 0:  vbptr for Left (4 bytes)
+  // offset 4:  vbptr for Middle (4 bytes)
+  // offset 8:  vbptr for Right (4 bytes)
+  // offset 12+: virtual base Base
+
+  // CHECK: call {{.*}} @"??0TriDiamond at test@@QAE at XZ"
+  // No memset is generated since there are no gaps to zero
+  // CHECK-NOT: call void @llvm.memset
+  // CHECK: ret
+
+  TriConcreteClass() : TriDiamond() {}
+};
+
+// Instantiate to trigger code generation
+TriConcreteClass tc;
+
+
+} // namespace test
diff --git a/clang/test/CodeGenCXX/microsoft-abi-diamond-template-multiple-vbptrs.cpp b/clang/test/CodeGenCXX/microsoft-abi-diamond-template-multiple-vbptrs.cpp
index 072cfc088e713..ed6a6e66da017 100644
--- a/clang/test/CodeGenCXX/microsoft-abi-diamond-template-multiple-vbptrs.cpp
+++ b/clang/test/CodeGenCXX/microsoft-abi-diamond-template-multiple-vbptrs.cpp
@@ -71,6 +71,7 @@ class DerivedWithData : public DiamondWithData {
 //
 // memset zeros 8 bytes for x and y at offset 16
 // CHECK: call void @llvm.memset.p0.i64(ptr {{.*}}, i8 0, i64 8, i1 false)
+// CHECK: ret
 
 template<typename T>
 DerivedWithData<T>::DerivedWithData() : DiamondWithData() {
@@ -78,7 +79,73 @@ DerivedWithData<T>::DerivedWithData() : DiamondWithData() {
 
 template struct DerivedWithData<int>;
 
-// Test 3: Another case which triggers the bug (similar to Test 1, non-template)
+// Test 3: Three vbptrs test case
+
+// Three separate classes that virtually inherit from Base
+class Middle : public virtual Base {
+};
+
+// TriDiamond has three vbptrs - one from each base class
+class TriDiamond : public Left, public Middle, public Right {
+};
+
+// Test 3a: Template instantiation with three vbptrs (no data members)
+template<typename T>
+class TriDerived : public TriDiamond {
+public:
+  // CHECK-LABEL: define {{.*}} @"??0?$TriDerived at H@test@@QEAA at XZ"
+
+  // Layout of TriDerived<int>:
+  // offset 0:  vbptr for Left (8 bytes)
+  // offset 8:  vbptr for Middle (8 bytes)
+  // offset 16: vbptr for Right (8 bytes)
+  // offset 24+: virtual base Base
+
+  // CHECK: call {{.*}} @"??0TriDiamond at test@@QEAA at XZ"
+  // No memset is generated since there are no gaps to zero
+  // CHECK-NOT: call void @llvm.memset
+  // CHECK: ret
+
+  TriDerived() : TriDiamond() {}
+};
+
+// Explicit instantiation to trigger code generation
+template class TriDerived<int>;
+
+// Test 3b: Three vbptrs with data members (calls memset)
+class TriDiamondWithData : public Left, public Middle, public Right {
+public:
+  int a;
+  int b;
+};
+
+template<typename T>
+class TriDerivedWithData : public TriDiamondWithData {
+public:
+  TriDerivedWithData();
+};
+
+// CHECK-LABEL: define {{.*}} @"??0?$TriDerivedWithData at H@test@@QEAA at XZ"
+//
+// Layout of TriDerivedWithData<int>:
+// offset 0:  vbptr for Left (8 bytes)
+// offset 8:  vbptr for Middle (8 bytes)
+// offset 16: vbptr for Right (8 bytes)
+// offset 24: a (4 bytes)
+// offset 28: b (4 bytes)
+// offset 32+: virtual base Base
+
+// memset zeros 8 bytes [24, 32)
+// CHECK: call void @llvm.memset.p0.i64(ptr {{.*}}, i8 0, i64 8, i1 false)
+// CHECK: ret
+
+template<typename T>
+TriDerivedWithData<T>::TriDerivedWithData() : TriDiamondWithData() {
+}
+
+template struct TriDerivedWithData<int>;
+
+// Test 4: Another case which triggers the bug (similar to Test 1, non-template)
 class Interface {
 public:
   virtual ~Interface() {}
@@ -118,5 +185,27 @@ class DerivedClass : public BaseIf {
 // Instantiate to trigger code generation
 DerivedClass d;
 
+// Test 4c: Non-template version with three vbptrs
+class TriConcreteClass : public TriDiamond {
+public:
+  // CHECK-LABEL: define {{.*}} @"??0TriConcreteClass at test@@QEAA at XZ"
+
+  // Layout of TriConcreteClass:
+  // offset 0:  vbptr for Left (8 bytes)
+  // offset 8:  vbptr for Middle (8 bytes)
+  // offset 16: vbptr for Right (8 bytes)
+  // offset 24+: virtual base Base
+
+  // CHECK: call {{.*}} @"??0TriDiamond at test@@QEAA at XZ"
+  // No memset is generated since there are no gaps to zero
+  // CHECK-NOT: call void @llvm.memset
+  // CHECK: ret
+
+  TriConcreteClass() : TriDiamond() {}
+};
+
+// Instantiate to trigger code generation
+TriConcreteClass tc;
+
 
 } // namespace test



More information about the cfe-commits mailing list