NextFieldOffsetInChars(CharUnits::Zero()),
LLVMStructAlignment(CharUnits::One()) { }
+ void AppendVTablePointer(BaseSubobject Base, llvm::Constant *VTable,
+ const CXXRecordDecl *VTableClass);
+
void AppendField(const FieldDecl *Field, uint64_t FieldOffset,
llvm::Constant *InitExpr);
+ void AppendBytes(CharUnits FieldOffsetInChars, llvm::Constant *InitCst);
+
void AppendBitField(const FieldDecl *Field, uint64_t FieldOffset,
llvm::ConstantInt *InitExpr);
void ConvertStructToPacked();
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);
CharUnits getAlignment(const llvm::Constant *C) const {
}
};
+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::
AppendField(const FieldDecl *Field, uint64_t FieldOffset,
llvm::Constant *InitCst) {
-
const ASTContext &Context = CGM.getContext();
CharUnits FieldOffsetInChars = Context.toCharUnitsFromBits(FieldOffset);
+ AppendBytes(FieldOffsetInChars, InitCst);
+}
+
+void ConstStructBuilder::
+AppendBytes(CharUnits FieldOffsetInChars, llvm::Constant *InitCst) {
+
assert(NextFieldOffsetInChars <= FieldOffsetInChars
&& "Field offset mismatch!");
return true;
}
-void ConstStructBuilder::Build(const APValue &Val, QualType ValTy) {
- RecordDecl *RD = ValTy->getAs<RecordType>()->getDecl();
+namespace {
+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);
- 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;
- 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) {
- // Build the base class subobject at the appropriately-offset location
- // within this object.
+ assert(!Base->isVirtual() && "should not have virtual bases here");
const CXXRecordDecl *BD = Base->getType()->getAsCXXRecordDecl();
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;
+
+ bool IsPrimaryBase = Layout.getPrimaryBase() == Base.Decl;
+ Build(Val.getStructBase(Base.Index), Base.Decl, IsPrimaryBase,
+ VTable, VTableClass, Offset + Base.Offset);
- NextFieldOffsetInChars += BaseOffset;
+ NextFieldOffsetInChars += Base.Offset;
}
}
const APValue &Val,
QualType ValTy) {
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);
}
}
}
+// 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,
// dynamic initialization tests go after.