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

>From 47babc5ed2d405bcc9a330b44b619967919d6a46 Mon Sep 17 00:00:00 2001
From: Sindhu Chittireddy <[email protected]>
Date: Tue, 3 Mar 2026 21:00:28 -0800
Subject: [PATCH 1/2] Fix bug in the calculation of vbptr memory region split.

This is an x86_64 MSVC issue where "Negative store size!" assert fails
because SplitAfterSize is negative, i.e., the memory regions after second
(or subsequent) vbptrs are calculated incorrectly.

The old calculation was:
    SplitAfterSize = LastStoreSize - SplitAfterOffset;

The correct size should be:
    SplitAfterSize = (LastStoreOffset + LastStoreSize) -
SplitAfterOffset;

Since all store regions extend to the end of the non-virtual portion
(NVSize), this patch simplifies it to:
    SplitAfterSize = NVSize - SplitAfterOffset;
---
 clang/lib/CodeGen/CGExprCXX.cpp               |  3 +-
 .../microsoft-abi-multiple-vbptrs.cpp         | 86 +++++++++++++++++++
 2 files changed, 87 insertions(+), 2 deletions(-)
 create mode 100644 clang/test/CodeGenCXX/microsoft-abi-multiple-vbptrs.cpp

diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp
index 074c124dbf01b..c202d3612f734 100644
--- a/clang/lib/CodeGen/CGExprCXX.cpp
+++ b/clang/lib/CodeGen/CGExprCXX.cpp
@@ -539,7 +539,6 @@ static void EmitNullBaseClassInitialization(CodeGenFunction 
&CGF,
       break;
     std::pair<CharUnits, CharUnits> LastStore = Stores.pop_back_val();
     CharUnits LastStoreOffset = LastStore.first;
-    CharUnits LastStoreSize = LastStore.second;
 
     CharUnits SplitBeforeOffset = LastStoreOffset;
     CharUnits SplitBeforeSize = VBPtrOffset - SplitBeforeOffset;
@@ -548,7 +547,7 @@ static void EmitNullBaseClassInitialization(CodeGenFunction 
&CGF,
       Stores.emplace_back(SplitBeforeOffset, SplitBeforeSize);
 
     CharUnits SplitAfterOffset = VBPtrOffset + VBPtrWidth;
-    CharUnits SplitAfterSize = LastStoreSize - SplitAfterOffset;
+    CharUnits SplitAfterSize = NVSize - SplitAfterOffset;
     assert(!SplitAfterSize.isNegative() && "negative store size!");
     if (!SplitAfterSize.isZero())
       Stores.emplace_back(SplitAfterOffset, SplitAfterSize);
diff --git a/clang/test/CodeGenCXX/microsoft-abi-multiple-vbptrs.cpp 
b/clang/test/CodeGenCXX/microsoft-abi-multiple-vbptrs.cpp
new file mode 100644
index 0000000000000..f89c1a3f5c3a0
--- /dev/null
+++ b/clang/test/CodeGenCXX/microsoft-abi-multiple-vbptrs.cpp
@@ -0,0 +1,86 @@
+// RUN: %clang_cc1 -triple x86_64-windows-msvc -std=c++11 -emit-llvm -o - %s | 
FileCheck %s
+
+// Test for the fix in EmitNullBaseClassInitialization where the calculation
+// of SplitAfterSize was incorrect when multiple vbptrs are present.
+
+struct VBase1 {
+  virtual ~VBase1();
+  int x;
+};
+
+struct VBase2 {
+  virtual ~VBase2();
+  int y;
+};
+
+// Base class with two virtual base classes.
+struct Base : virtual VBase1, virtual VBase2 {
+  int data;
+};
+
+// Derived class that needs to initialize Base.
+// The constructor will call EmitNullBaseClassInitialization for Base.
+struct Derived : Base {
+  Derived();
+  int more_data;
+};
+
+// CHECK-LABEL: define dso_local noundef ptr @"??0Derived@@QEAA@XZ"
+// Check that memory initialization (memset or memcpy) correctly covers
+// the non-virtual portion of the base class, properly handling vbptrs.
+
+// CHECK: call void @llvm.memset
+
+Derived::Derived() : Base() {
+  // Constructor body
+  data = 42;
+  more_data = 100;
+}
+
+// Test case with three virtual bases.
+struct VBase3 {
+  virtual ~VBase3();
+  int z;
+};
+
+struct ComplexBase : virtual VBase1, virtual VBase2, virtual VBase3 {
+  int a, b, c;
+};
+
+struct ComplexDerived : ComplexBase {
+  ComplexDerived();
+  int d;
+};
+
+// CHECK-LABEL: define dso_local noundef ptr @"??0ComplexDerived@@QEAA@XZ"
+// CHECK: call void @llvm.memset
+
+ComplexDerived::ComplexDerived() : ComplexBase() {
+  a = 1;
+  b = 2;
+  c = 3;
+  d = 4;
+}
+
+// Test case with data members initialized using memcpy
+struct VBase4 {
+  virtual ~VBase4();
+  int w;
+};
+
+struct BaseWithPtrToMember : virtual VBase1, virtual VBase4 {
+  int Base::*member_ptr;
+  int value;
+};
+
+struct DerivedWithPtrToMember : BaseWithPtrToMember {
+  DerivedWithPtrToMember();
+};
+
+// CHECK-LABEL: define dso_local noundef ptr 
@"??0DerivedWithPtrToMember@@QEAA@XZ"
+// This should use memcpy instead of memset due to the pointer-to-member.
+// CHECK: call void @llvm.memcpy
+
+DerivedWithPtrToMember::DerivedWithPtrToMember() : BaseWithPtrToMember() {
+  value = 50;
+}

>From 5cd4efba6e96097a6e4144fe944b23989a2467cd Mon Sep 17 00:00:00 2001
From: Sindhu Chittireddy <[email protected]>
Date: Thu, 5 Mar 2026 13:00:26 -0800
Subject: [PATCH 2/2] Fix test case and remove the old one

---
 ...t-abi-diamond-template-multiple-vbptrs.cpp | 39 +++++++++
 .../microsoft-abi-multiple-vbptrs.cpp         | 86 -------------------
 2 files changed, 39 insertions(+), 86 deletions(-)
 create mode 100644 
clang/test/CodeGenCXX/microsoft-abi-diamond-template-multiple-vbptrs.cpp
 delete mode 100644 clang/test/CodeGenCXX/microsoft-abi-multiple-vbptrs.cpp

diff --git 
a/clang/test/CodeGenCXX/microsoft-abi-diamond-template-multiple-vbptrs.cpp 
b/clang/test/CodeGenCXX/microsoft-abi-diamond-template-multiple-vbptrs.cpp
new file mode 100644
index 0000000000000..d271c9d357a8f
--- /dev/null
+++ b/clang/test/CodeGenCXX/microsoft-abi-diamond-template-multiple-vbptrs.cpp
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -triple x86_64-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.
+
+namespace test {
+
+class Base {
+public:
+    virtual ~Base() {}
+};
+
+class Left : public virtual Base {
+};
+
+class Right : public virtual Base {
+};
+
+class Diamond : public Left, public Right {
+};
+
+// Template class that triggers the bug
+template<typename T>
+class Derived : public Diamond {
+public:
+    // CHECK-LABEL: define {{.*}} @"??0?$Derived@H@test@@QEAA@XZ"
+    // CHECK: call {{.*}} @"??0Diamond@test@@QEAA@XZ"
+    // EmitNullBaseClassInitialization now correctly calculates memory regions
+    // around the vbptrs without hitting negative size assertion
+
+    // CHECK: ret
+
+    Derived() : Diamond() {}
+};
+
+// Explicit instantiation to trigger code generation
+template class Derived<int>;
+
+} // namespace test
diff --git a/clang/test/CodeGenCXX/microsoft-abi-multiple-vbptrs.cpp 
b/clang/test/CodeGenCXX/microsoft-abi-multiple-vbptrs.cpp
deleted file mode 100644
index f89c1a3f5c3a0..0000000000000
--- a/clang/test/CodeGenCXX/microsoft-abi-multiple-vbptrs.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-// RUN: %clang_cc1 -triple x86_64-windows-msvc -std=c++11 -emit-llvm -o - %s | 
FileCheck %s
-
-// Test for the fix in EmitNullBaseClassInitialization where the calculation
-// of SplitAfterSize was incorrect when multiple vbptrs are present.
-
-struct VBase1 {
-  virtual ~VBase1();
-  int x;
-};
-
-struct VBase2 {
-  virtual ~VBase2();
-  int y;
-};
-
-// Base class with two virtual base classes.
-struct Base : virtual VBase1, virtual VBase2 {
-  int data;
-};
-
-// Derived class that needs to initialize Base.
-// The constructor will call EmitNullBaseClassInitialization for Base.
-struct Derived : Base {
-  Derived();
-  int more_data;
-};
-
-// CHECK-LABEL: define dso_local noundef ptr @"??0Derived@@QEAA@XZ"
-// Check that memory initialization (memset or memcpy) correctly covers
-// the non-virtual portion of the base class, properly handling vbptrs.
-
-// CHECK: call void @llvm.memset
-
-Derived::Derived() : Base() {
-  // Constructor body
-  data = 42;
-  more_data = 100;
-}
-
-// Test case with three virtual bases.
-struct VBase3 {
-  virtual ~VBase3();
-  int z;
-};
-
-struct ComplexBase : virtual VBase1, virtual VBase2, virtual VBase3 {
-  int a, b, c;
-};
-
-struct ComplexDerived : ComplexBase {
-  ComplexDerived();
-  int d;
-};
-
-// CHECK-LABEL: define dso_local noundef ptr @"??0ComplexDerived@@QEAA@XZ"
-// CHECK: call void @llvm.memset
-
-ComplexDerived::ComplexDerived() : ComplexBase() {
-  a = 1;
-  b = 2;
-  c = 3;
-  d = 4;
-}
-
-// Test case with data members initialized using memcpy
-struct VBase4 {
-  virtual ~VBase4();
-  int w;
-};
-
-struct BaseWithPtrToMember : virtual VBase1, virtual VBase4 {
-  int Base::*member_ptr;
-  int value;
-};
-
-struct DerivedWithPtrToMember : BaseWithPtrToMember {
-  DerivedWithPtrToMember();
-};
-
-// CHECK-LABEL: define dso_local noundef ptr 
@"??0DerivedWithPtrToMember@@QEAA@XZ"
-// This should use memcpy instead of memset due to the pointer-to-member.
-// CHECK: call void @llvm.memcpy
-
-DerivedWithPtrToMember::DerivedWithPtrToMember() : BaseWithPtrToMember() {
-  value = 50;
-}

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

Reply via email to