forked from OSchip/llvm-project
Correctly initialize bases with member pointers. This should fix PR6441 but that test case is a bit weird and I'd like to investigate further before closing that bug.
llvm-svn: 104025
This commit is contained in:
parent
86ad085b40
commit
be48c548c5
|
@ -984,6 +984,79 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
|
|||
return C;
|
||||
}
|
||||
|
||||
static void
|
||||
FillInNullDataMemberPointers(CodeGenModule &CGM, QualType T,
|
||||
std::vector<llvm::Constant *> &Elements,
|
||||
uint64_t StartOffset) {
|
||||
assert(StartOffset % 8 == 0 && "StartOffset not byte aligned!");
|
||||
|
||||
if (!CGM.getTypes().ContainsPointerToDataMember(T))
|
||||
return;
|
||||
|
||||
if (const ConstantArrayType *CAT =
|
||||
CGM.getContext().getAsConstantArrayType(T)) {
|
||||
QualType ElementTy = CAT->getElementType();
|
||||
uint64_t ElementSize = CGM.getContext().getTypeSize(ElementTy);
|
||||
|
||||
for (uint64_t I = 0, E = CAT->getSize().getZExtValue(); I != E; ++I) {
|
||||
FillInNullDataMemberPointers(CGM, ElementTy, Elements,
|
||||
StartOffset + I * ElementSize);
|
||||
}
|
||||
} else if (const RecordType *RT = T->getAs<RecordType>()) {
|
||||
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
|
||||
const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
|
||||
|
||||
// Go through all bases and fill in any null pointer to data members.
|
||||
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
|
||||
E = RD->bases_end(); I != E; ++I) {
|
||||
assert(!I->isVirtual() && "Should not see virtual bases here!");
|
||||
|
||||
const CXXRecordDecl *BaseDecl =
|
||||
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
|
||||
|
||||
// Ignore empty bases.
|
||||
if (BaseDecl->isEmpty())
|
||||
continue;
|
||||
|
||||
// Ignore bases that don't have any pointer to data members.
|
||||
if (!CGM.getTypes().ContainsPointerToDataMember(BaseDecl))
|
||||
continue;
|
||||
|
||||
uint64_t BaseOffset = Layout.getBaseClassOffset(BaseDecl);
|
||||
FillInNullDataMemberPointers(CGM, I->getType(),
|
||||
Elements, StartOffset + BaseOffset);
|
||||
}
|
||||
|
||||
// Visit all fields.
|
||||
unsigned FieldNo = 0;
|
||||
for (RecordDecl::field_iterator I = RD->field_begin(),
|
||||
E = RD->field_end(); I != E; ++I, ++FieldNo) {
|
||||
QualType FieldType = I->getType();
|
||||
|
||||
if (!CGM.getTypes().ContainsPointerToDataMember(FieldType))
|
||||
continue;
|
||||
|
||||
uint64_t FieldOffset = StartOffset + Layout.getFieldOffset(FieldNo);
|
||||
FillInNullDataMemberPointers(CGM, FieldType, Elements, FieldOffset);
|
||||
}
|
||||
} else {
|
||||
assert(T->isMemberPointerType() && "Should only see member pointers here!");
|
||||
assert(!T->getAs<MemberPointerType>()->getPointeeType()->isFunctionType() &&
|
||||
"Should only see pointers to data members here!");
|
||||
|
||||
uint64_t StartIndex = StartOffset / 8;
|
||||
uint64_t EndIndex = StartIndex + CGM.getContext().getTypeSize(T) / 8;
|
||||
|
||||
llvm::Constant *NegativeOne =
|
||||
llvm::ConstantInt::get(llvm::Type::getInt8Ty(CGM.getLLVMContext()),
|
||||
-1ULL, /*isSigned=*/true);
|
||||
|
||||
// Fill in the null data member pointer.
|
||||
for (uint64_t I = StartIndex; I != EndIndex; ++I)
|
||||
Elements[I] = NegativeOne;
|
||||
}
|
||||
}
|
||||
|
||||
llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) {
|
||||
if (!getTypes().ContainsPointerToDataMember(T))
|
||||
return llvm::Constant::getNullValue(getTypes().ConvertTypeForMem(T));
|
||||
|
@ -1005,21 +1078,60 @@ llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) {
|
|||
|
||||
if (const RecordType *RT = T->getAs<RecordType>()) {
|
||||
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
|
||||
assert(!RD->getNumBases() &&
|
||||
"FIXME: Handle zero-initializing structs with bases and "
|
||||
"pointers to data members.");
|
||||
const llvm::StructType *STy =
|
||||
cast<llvm::StructType>(getTypes().ConvertTypeForMem(T));
|
||||
unsigned NumElements = STy->getNumElements();
|
||||
std::vector<llvm::Constant *> Elements(NumElements);
|
||||
|
||||
const CGRecordLayout &Layout = getTypes().getCGRecordLayout(RD);
|
||||
|
||||
// Go through all bases and fill in any null pointer to data members.
|
||||
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
|
||||
E = RD->bases_end(); I != E; ++I) {
|
||||
assert(!I->isVirtual() && "Should not see virtual bases here!");
|
||||
|
||||
const CXXRecordDecl *BaseDecl =
|
||||
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
|
||||
|
||||
// Ignore empty bases.
|
||||
if (BaseDecl->isEmpty())
|
||||
continue;
|
||||
|
||||
// Ignore bases that don't have any pointer to data members.
|
||||
if (!getTypes().ContainsPointerToDataMember(BaseDecl))
|
||||
continue;
|
||||
|
||||
// Currently, all bases are arrays of i8. Figure out how many elements
|
||||
// this base array has.
|
||||
unsigned BaseFieldNo = Layout.getNonVirtualBaseLLVMFieldNo(BaseDecl);
|
||||
const llvm::ArrayType *BaseArrayTy =
|
||||
cast<llvm::ArrayType>(STy->getElementType(BaseFieldNo));
|
||||
|
||||
unsigned NumBaseElements = BaseArrayTy->getNumElements();
|
||||
std::vector<llvm::Constant *> BaseElements(NumBaseElements);
|
||||
|
||||
// Now fill in null data member pointers.
|
||||
FillInNullDataMemberPointers(*this, I->getType(), BaseElements, 0);
|
||||
|
||||
// Now go through all other elements and zero them out.
|
||||
if (NumBaseElements) {
|
||||
llvm::Constant *Zero =
|
||||
llvm::ConstantInt::get(llvm::Type::getInt8Ty(getLLVMContext()), 0);
|
||||
|
||||
for (unsigned I = 0; I != NumBaseElements; ++I) {
|
||||
if (!BaseElements[I])
|
||||
BaseElements[I] = Zero;
|
||||
}
|
||||
}
|
||||
|
||||
Elements[BaseFieldNo] = llvm::ConstantArray::get(BaseArrayTy,
|
||||
BaseElements);
|
||||
}
|
||||
|
||||
for (RecordDecl::field_iterator I = RD->field_begin(),
|
||||
E = RD->field_end(); I != E; ++I) {
|
||||
const FieldDecl *FD = *I;
|
||||
|
||||
const CGRecordLayout &RL =
|
||||
getTypes().getCGRecordLayout(FD->getParent());
|
||||
unsigned FieldNo = RL.getLLVMFieldNo(FD);
|
||||
unsigned FieldNo = Layout.getLLVMFieldNo(FD);
|
||||
Elements[FieldNo] = EmitNullConstant(FD->getType());
|
||||
}
|
||||
|
||||
|
@ -1032,6 +1144,7 @@ llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) {
|
|||
return llvm::ConstantStruct::get(STy, Elements);
|
||||
}
|
||||
|
||||
assert(T->isMemberPointerType() && "Should only see member pointers here!");
|
||||
assert(!T->getAs<MemberPointerType>()->getPointeeType()->isFunctionType() &&
|
||||
"Should only see pointers to data members here!");
|
||||
|
||||
|
|
|
@ -118,6 +118,7 @@ private:
|
|||
/// CheckForPointerToDataMember - Check if the given type contains a pointer
|
||||
/// to data member.
|
||||
void CheckForPointerToDataMember(QualType T);
|
||||
void CheckForPointerToDataMember(const CXXRecordDecl *RD);
|
||||
|
||||
public:
|
||||
CGRecordLayoutBuilder(CodeGenTypes &Types)
|
||||
|
@ -456,6 +457,8 @@ void CGRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *BaseDecl,
|
|||
return;
|
||||
}
|
||||
|
||||
CheckForPointerToDataMember(BaseDecl);
|
||||
|
||||
// FIXME: Actually use a better type than [sizeof(BaseDecl) x i8] when we can.
|
||||
AppendPadding(BaseOffset / 8, 1);
|
||||
|
||||
|
@ -618,17 +621,26 @@ void CGRecordLayoutBuilder::CheckForPointerToDataMember(QualType T) {
|
|||
} else if (const RecordType *RT = T->getAs<RecordType>()) {
|
||||
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
|
||||
|
||||
// FIXME: It would be better if there was a way to explicitly compute the
|
||||
// record layout instead of converting to a type.
|
||||
Types.ConvertTagDeclType(RD);
|
||||
|
||||
const CGRecordLayout &Layout = Types.getCGRecordLayout(RD);
|
||||
|
||||
if (Layout.containsPointerToDataMember())
|
||||
ContainsPointerToDataMember = true;
|
||||
return CheckForPointerToDataMember(RD);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CGRecordLayoutBuilder::CheckForPointerToDataMember(const CXXRecordDecl *RD) {
|
||||
// This record already contains a member pointer.
|
||||
if (ContainsPointerToDataMember)
|
||||
return;
|
||||
|
||||
// FIXME: It would be better if there was a way to explicitly compute the
|
||||
// record layout instead of converting to a type.
|
||||
Types.ConvertTagDeclType(RD);
|
||||
|
||||
const CGRecordLayout &Layout = Types.getCGRecordLayout(RD);
|
||||
|
||||
if (Layout.containsPointerToDataMember())
|
||||
ContainsPointerToDataMember = true;
|
||||
}
|
||||
|
||||
CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) {
|
||||
CGRecordLayoutBuilder Builder(*this);
|
||||
|
||||
|
|
|
@ -35,6 +35,21 @@ namespace ZeroInit {
|
|||
int A::*pa;
|
||||
} s;
|
||||
} ss;
|
||||
|
||||
struct A {
|
||||
int A::*a;
|
||||
int b;
|
||||
};
|
||||
|
||||
struct B {
|
||||
A a[10];
|
||||
char c;
|
||||
int B::*b;
|
||||
};
|
||||
|
||||
struct C : A, B { int j; };
|
||||
// CHECK: @_ZN8ZeroInit1cE = global %"struct.ZeroInit::C" { [16 x i8] c"\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00", [176 x i8] c"\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF", i32 0, [4 x i8] zeroinitializer }
|
||||
C c;
|
||||
}
|
||||
|
||||
// PR5674
|
||||
|
@ -102,3 +117,4 @@ struct A {
|
|||
A::A() : a() {}
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue