blob: ed6a6e66da0173d0f50c1e8259463a7fdf18b08c [file] [edit]
// 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 {
};
// Test 1: Diamond inheritance in a template that triggers the bug
template<typename T>
class Derived : public Diamond {
public:
// CHECK-LABEL: define {{.*}} @"??0?$Derived@H@test@@QEAA@XZ"
// Layout of Derived<int>:
// offset 0: vbptr for Left (8 bytes)
// offset 8: vbptr for Right (8 bytes)
// offset 16+: virtual base Base
// CHECK: call {{.*}} @"??0Diamond@test@@QEAA@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@H@test@@QEAA@XZ"
//
// Layout of DerivedWithData<int>:
// offset 0: vbptr for Left (8 bytes)
// offset 8: vbptr for Right (8 bytes)
// offset 16: x (4 bytes)
// offset 20: y (4 bytes)
// offset 24+: virtual base Base
//
// EmitNullBaseClassInitialization zero-initializes the data members [16, 24)
// while skipping both vbptrs [0, 16)
//
// 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() {
}
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@H@test@@QEAA@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@test@@QEAA@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@H@test@@QEAA@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() {}
};
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@test@@QEAA@XZ"
// Layout of DerivedClass:
// offset 0: vbptr for Base1If (8 bytes)
// offset 8: vbptr for Base2If (8 bytes)
// offset 16+: virtual base Interface
// CHECK: call {{.*}} @"??0BaseIf@test@@QEAA@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@test@@QEAA@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@test@@QEAA@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