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:
Anders Carlsson 2010-05-18 16:51:41 +00:00
parent 86ad085b40
commit be48c548c5
3 changed files with 156 additions and 15 deletions

View File

@ -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!");

View File

@ -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);

View File

@ -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() {}
}