forked from OSchip/llvm-project
PR12067: When emitting an evaluated constant structure in C++11 mode, don't
forget the vptrs. llvm-svn: 151245
This commit is contained in:
parent
f320be8521
commit
c899892485
|
@ -53,9 +53,14 @@ private:
|
||||||
NextFieldOffsetInChars(CharUnits::Zero()),
|
NextFieldOffsetInChars(CharUnits::Zero()),
|
||||||
LLVMStructAlignment(CharUnits::One()) { }
|
LLVMStructAlignment(CharUnits::One()) { }
|
||||||
|
|
||||||
|
void AppendVTablePointer(BaseSubobject Base, llvm::Constant *VTable,
|
||||||
|
const CXXRecordDecl *VTableClass);
|
||||||
|
|
||||||
void AppendField(const FieldDecl *Field, uint64_t FieldOffset,
|
void AppendField(const FieldDecl *Field, uint64_t FieldOffset,
|
||||||
llvm::Constant *InitExpr);
|
llvm::Constant *InitExpr);
|
||||||
|
|
||||||
|
void AppendBytes(CharUnits FieldOffsetInChars, llvm::Constant *InitCst);
|
||||||
|
|
||||||
void AppendBitField(const FieldDecl *Field, uint64_t FieldOffset,
|
void AppendBitField(const FieldDecl *Field, uint64_t FieldOffset,
|
||||||
llvm::ConstantInt *InitExpr);
|
llvm::ConstantInt *InitExpr);
|
||||||
|
|
||||||
|
@ -66,7 +71,9 @@ private:
|
||||||
void ConvertStructToPacked();
|
void ConvertStructToPacked();
|
||||||
|
|
||||||
bool Build(InitListExpr *ILE);
|
bool Build(InitListExpr *ILE);
|
||||||
void Build(const APValue &Val, QualType ValTy);
|
void Build(const APValue &Val, const RecordDecl *RD, bool IsPrimaryBase,
|
||||||
|
llvm::Constant *VTable, const CXXRecordDecl *VTableClass,
|
||||||
|
CharUnits BaseOffset);
|
||||||
llvm::Constant *Finalize(QualType Ty);
|
llvm::Constant *Finalize(QualType Ty);
|
||||||
|
|
||||||
CharUnits getAlignment(const llvm::Constant *C) const {
|
CharUnits getAlignment(const llvm::Constant *C) const {
|
||||||
|
@ -81,14 +88,36 @@ private:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void ConstStructBuilder::AppendVTablePointer(BaseSubobject Base,
|
||||||
|
llvm::Constant *VTable,
|
||||||
|
const CXXRecordDecl *VTableClass) {
|
||||||
|
// Find the appropriate vtable within the vtable group.
|
||||||
|
uint64_t AddressPoint =
|
||||||
|
CGM.getVTableContext().getVTableLayout(VTableClass).getAddressPoint(Base);
|
||||||
|
llvm::Value *Indices[] = {
|
||||||
|
llvm::ConstantInt::get(CGM.Int64Ty, 0),
|
||||||
|
llvm::ConstantInt::get(CGM.Int64Ty, AddressPoint)
|
||||||
|
};
|
||||||
|
llvm::Constant *VTableAddressPoint =
|
||||||
|
llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, Indices);
|
||||||
|
|
||||||
|
// Add the vtable at the start of the object.
|
||||||
|
AppendBytes(CharUnits::Zero(), VTableAddressPoint);
|
||||||
|
}
|
||||||
|
|
||||||
void ConstStructBuilder::
|
void ConstStructBuilder::
|
||||||
AppendField(const FieldDecl *Field, uint64_t FieldOffset,
|
AppendField(const FieldDecl *Field, uint64_t FieldOffset,
|
||||||
llvm::Constant *InitCst) {
|
llvm::Constant *InitCst) {
|
||||||
|
|
||||||
const ASTContext &Context = CGM.getContext();
|
const ASTContext &Context = CGM.getContext();
|
||||||
|
|
||||||
CharUnits FieldOffsetInChars = Context.toCharUnitsFromBits(FieldOffset);
|
CharUnits FieldOffsetInChars = Context.toCharUnitsFromBits(FieldOffset);
|
||||||
|
|
||||||
|
AppendBytes(FieldOffsetInChars, InitCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConstStructBuilder::
|
||||||
|
AppendBytes(CharUnits FieldOffsetInChars, llvm::Constant *InitCst) {
|
||||||
|
|
||||||
assert(NextFieldOffsetInChars <= FieldOffsetInChars
|
assert(NextFieldOffsetInChars <= FieldOffsetInChars
|
||||||
&& "Field offset mismatch!");
|
&& "Field offset mismatch!");
|
||||||
|
|
||||||
|
@ -399,23 +428,56 @@ bool ConstStructBuilder::Build(InitListExpr *ILE) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConstStructBuilder::Build(const APValue &Val, QualType ValTy) {
|
namespace {
|
||||||
RecordDecl *RD = ValTy->getAs<RecordType>()->getDecl();
|
struct BaseInfo {
|
||||||
|
BaseInfo(const CXXRecordDecl *Decl, CharUnits Offset, unsigned Index)
|
||||||
|
: Decl(Decl), Offset(Offset), Index(Index) {
|
||||||
|
}
|
||||||
|
|
||||||
|
const CXXRecordDecl *Decl;
|
||||||
|
CharUnits Offset;
|
||||||
|
unsigned Index;
|
||||||
|
|
||||||
|
bool operator<(const BaseInfo &O) const { return Offset < O.Offset; }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD,
|
||||||
|
bool IsPrimaryBase, llvm::Constant *VTable,
|
||||||
|
const CXXRecordDecl *VTableClass,
|
||||||
|
CharUnits Offset) {
|
||||||
const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
|
const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
|
||||||
|
|
||||||
if (CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD)) {
|
if (const CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD)) {
|
||||||
|
// Add a vtable pointer, if we need one and it hasn't already been added.
|
||||||
|
if (CD->isDynamicClass() && !IsPrimaryBase)
|
||||||
|
AppendVTablePointer(BaseSubobject(CD, Offset), VTable, VTableClass);
|
||||||
|
|
||||||
|
// Accumulate and sort bases, in order to visit them in address order, which
|
||||||
|
// may not be the same as declaration order.
|
||||||
|
llvm::SmallVector<BaseInfo, 8> Bases;
|
||||||
|
Bases.reserve(CD->getNumBases());
|
||||||
unsigned BaseNo = 0;
|
unsigned BaseNo = 0;
|
||||||
for (CXXRecordDecl::base_class_iterator Base = CD->bases_begin(),
|
for (CXXRecordDecl::base_class_const_iterator Base = CD->bases_begin(),
|
||||||
BaseEnd = CD->bases_end(); Base != BaseEnd; ++Base, ++BaseNo) {
|
BaseEnd = CD->bases_end(); Base != BaseEnd; ++Base, ++BaseNo) {
|
||||||
// Build the base class subobject at the appropriately-offset location
|
assert(!Base->isVirtual() && "should not have virtual bases here");
|
||||||
// within this object.
|
|
||||||
const CXXRecordDecl *BD = Base->getType()->getAsCXXRecordDecl();
|
const CXXRecordDecl *BD = Base->getType()->getAsCXXRecordDecl();
|
||||||
CharUnits BaseOffset = Layout.getBaseClassOffset(BD);
|
CharUnits BaseOffset = Layout.getBaseClassOffset(BD);
|
||||||
NextFieldOffsetInChars -= BaseOffset;
|
Bases.push_back(BaseInfo(BD, BaseOffset, BaseNo));
|
||||||
|
}
|
||||||
|
std::stable_sort(Bases.begin(), Bases.end());
|
||||||
|
|
||||||
Build(Val.getStructBase(BaseNo), Base->getType());
|
for (unsigned I = 0, N = Bases.size(); I != N; ++I) {
|
||||||
|
BaseInfo &Base = Bases[I];
|
||||||
|
// Build the base class subobject at the appropriately-offset location
|
||||||
|
// within this object.
|
||||||
|
NextFieldOffsetInChars -= Base.Offset;
|
||||||
|
|
||||||
NextFieldOffsetInChars += BaseOffset;
|
bool IsPrimaryBase = Layout.getPrimaryBase() == Base.Decl;
|
||||||
|
Build(Val.getStructBase(Base.Index), Base.Decl, IsPrimaryBase,
|
||||||
|
VTable, VTableClass, Offset + Base.Offset);
|
||||||
|
|
||||||
|
NextFieldOffsetInChars += Base.Offset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -532,7 +594,15 @@ llvm::Constant *ConstStructBuilder::BuildStruct(CodeGenModule &CGM,
|
||||||
const APValue &Val,
|
const APValue &Val,
|
||||||
QualType ValTy) {
|
QualType ValTy) {
|
||||||
ConstStructBuilder Builder(CGM, CGF);
|
ConstStructBuilder Builder(CGM, CGF);
|
||||||
Builder.Build(Val, ValTy);
|
|
||||||
|
const RecordDecl *RD = ValTy->castAs<RecordType>()->getDecl();
|
||||||
|
const CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD);
|
||||||
|
llvm::Constant *VTable = 0;
|
||||||
|
if (CD && CD->isDynamicClass())
|
||||||
|
VTable = CGM.getVTables().GetAddrOfVTable(CD);
|
||||||
|
|
||||||
|
Builder.Build(Val, RD, false, VTable, CD, CharUnits::Zero());
|
||||||
|
|
||||||
return Builder.Finalize(ValTy);
|
return Builder.Finalize(ValTy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -254,6 +254,42 @@ namespace NonLiteralConstexpr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PR12067
|
||||||
|
namespace VirtualMembers {
|
||||||
|
struct A {
|
||||||
|
constexpr A(double d) : d(d) {}
|
||||||
|
virtual void f();
|
||||||
|
double d;
|
||||||
|
};
|
||||||
|
struct B : A {
|
||||||
|
constexpr B() : A(2.0), c{'h', 'e', 'l', 'l', 'o'} {}
|
||||||
|
constexpr B(int n) : A(n), c{'w', 'o', 'r', 'l', 'd'} {}
|
||||||
|
virtual void g();
|
||||||
|
char c[5];
|
||||||
|
};
|
||||||
|
struct C {
|
||||||
|
constexpr C() : n(64) {}
|
||||||
|
int n;
|
||||||
|
};
|
||||||
|
struct D : C, A, B {
|
||||||
|
constexpr D() : A(1.0), B(), s(5) {}
|
||||||
|
short s;
|
||||||
|
};
|
||||||
|
struct E : D, B {
|
||||||
|
constexpr E() : B(3), c{'b','y','e'} {}
|
||||||
|
char c[3];
|
||||||
|
};
|
||||||
|
|
||||||
|
// CHECK: @_ZN14VirtualMembers1eE = global { i8**, double, i32, i8**, double, [5 x i8], i16, i8**, double, [5 x i8], [3 x i8] } { i8** getelementptr inbounds ([11 x i8*]* @_ZTVN14VirtualMembers1EE, i64 0, i64 2), double 1.000000e+00, i32 64, i8** getelementptr inbounds ([11 x i8*]* @_ZTVN14VirtualMembers1EE, i64 0, i64 5), double 2.000000e+00, [5 x i8] c"hello", i16 5, i8** getelementptr inbounds ([11 x i8*]* @_ZTVN14VirtualMembers1EE, i64 0, i64 9), double 3.000000e+00, [5 x i8] c"world", [3 x i8] c"bye" }
|
||||||
|
E e;
|
||||||
|
|
||||||
|
struct nsMemoryImpl {
|
||||||
|
virtual void f();
|
||||||
|
};
|
||||||
|
// CHECK: @_ZN14VirtualMembersL13sGlobalMemoryE = internal global { i8** } { i8** getelementptr inbounds ([3 x i8*]* @_ZTVN14VirtualMembers12nsMemoryImplE, i64 0, i64 2) }
|
||||||
|
static nsMemoryImpl sGlobalMemory;
|
||||||
|
}
|
||||||
|
|
||||||
// Constant initialization tests go before this point,
|
// Constant initialization tests go before this point,
|
||||||
// dynamic initialization tests go after.
|
// dynamic initialization tests go after.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue