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
