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] 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; +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
