Improve handling of emitting 'null' pointers to data members.
llvm-svn: 95066
This commit is contained in:
parent
a4a2e5dd5b
commit
e8bfe412ec
|
@ -911,7 +911,24 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
|
|||
return C;
|
||||
}
|
||||
|
||||
static inline bool isDataMemberPointerType(QualType T) {
|
||||
static bool containsPointerToDataMember(CodeGenTypes &Types, QualType T) {
|
||||
// No need to check for member pointers when not compiling C++.
|
||||
if (!Types.getContext().getLangOptions().CPlusPlus)
|
||||
return false;
|
||||
|
||||
T = Types.getContext().getBaseElementType(T);
|
||||
|
||||
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);
|
||||
return Layout.containsPointerToDataMember();
|
||||
}
|
||||
|
||||
if (const MemberPointerType *MPT = T->getAs<MemberPointerType>())
|
||||
return !MPT->getPointeeType()->isFunctionType();
|
||||
|
||||
|
@ -919,45 +936,58 @@ static inline bool isDataMemberPointerType(QualType T) {
|
|||
}
|
||||
|
||||
llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) {
|
||||
// No need to check for member pointers when not compiling C++.
|
||||
if (!getContext().getLangOptions().CPlusPlus)
|
||||
if (!containsPointerToDataMember(getTypes(), T))
|
||||
return llvm::Constant::getNullValue(getTypes().ConvertTypeForMem(T));
|
||||
|
||||
|
||||
if (const ConstantArrayType *CAT = Context.getAsConstantArrayType(T)) {
|
||||
|
||||
QualType ElementTy = CAT->getElementType();
|
||||
|
||||
// FIXME: Handle arrays of structs that contain member pointers.
|
||||
if (isDataMemberPointerType(Context.getBaseElementType(ElementTy))) {
|
||||
llvm::Constant *Element = EmitNullConstant(ElementTy);
|
||||
uint64_t NumElements = CAT->getSize().getZExtValue();
|
||||
std::vector<llvm::Constant *> Array(NumElements);
|
||||
for (uint64_t i = 0; i != NumElements; ++i)
|
||||
Array[i] = Element;
|
||||
llvm::Constant *Element = EmitNullConstant(ElementTy);
|
||||
unsigned NumElements = CAT->getSize().getZExtValue();
|
||||
std::vector<llvm::Constant *> Array(NumElements);
|
||||
for (unsigned i = 0; i != NumElements; ++i)
|
||||
Array[i] = Element;
|
||||
|
||||
const llvm::ArrayType *ATy =
|
||||
cast<llvm::ArrayType>(getTypes().ConvertTypeForMem(T));
|
||||
return llvm::ConstantArray::get(ATy, Array);
|
||||
}
|
||||
const llvm::ArrayType *ATy =
|
||||
cast<llvm::ArrayType>(getTypes().ConvertTypeForMem(T));
|
||||
return llvm::ConstantArray::get(ATy, Array);
|
||||
}
|
||||
|
||||
if (const RecordType *RT = T->getAs<RecordType>()) {
|
||||
const RecordDecl *RD = 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 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 = Types.getCGRecordLayout(RD);
|
||||
if (Layout.containsMemberPointer()) {
|
||||
assert(0 && "FIXME: No support for structs with member pointers yet!");
|
||||
for (RecordDecl::field_iterator I = RD->field_begin(),
|
||||
E = RD->field_end(); I != E; ++I) {
|
||||
const FieldDecl *FD = *I;
|
||||
|
||||
unsigned FieldNo = getTypes().getLLVMFieldNo(FD);
|
||||
Elements[FieldNo] = EmitNullConstant(FD->getType());
|
||||
}
|
||||
|
||||
// Now go through all other fields and zero them out.
|
||||
for (unsigned i = 0; i != NumElements; ++i) {
|
||||
if (!Elements[i])
|
||||
Elements[i] = llvm::Constant::getNullValue(STy->getElementType(i));
|
||||
}
|
||||
|
||||
return llvm::ConstantStruct::get(STy, Elements);
|
||||
}
|
||||
|
||||
// FIXME: Handle structs that contain member pointers.
|
||||
if (isDataMemberPointerType(T))
|
||||
return llvm::Constant::getAllOnesValue(getTypes().ConvertTypeForMem(T));
|
||||
|
||||
return llvm::Constant::getNullValue(getTypes().ConvertTypeForMem(T));
|
||||
assert(!T->getAs<MemberPointerType>()->getPointeeType()->isFunctionType() &&
|
||||
"Should only see pointers to data members here!");
|
||||
|
||||
// Itanium C++ ABI 2.3:
|
||||
// A NULL pointer is represented as -1.
|
||||
return llvm::ConstantInt::get(getTypes().ConvertTypeForMem(T), -1,
|
||||
/*isSigned=*/true);
|
||||
}
|
||||
|
||||
llvm::Constant *
|
||||
|
|
|
@ -108,6 +108,9 @@ bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D,
|
|||
return true;
|
||||
}
|
||||
|
||||
// Check if we have a pointer to data member in this field.
|
||||
CheckForPointerToDataMember(D->getType());
|
||||
|
||||
assert(FieldOffset % 8 == 0 && "FieldOffset is not on a byte boundary!");
|
||||
uint64_t FieldOffsetInBytes = FieldOffset / 8;
|
||||
|
||||
|
@ -338,23 +341,34 @@ uint64_t CGRecordLayoutBuilder::getTypeSizeInBytes(const llvm::Type *Ty) const {
|
|||
return Types.getTargetData().getTypeAllocSize(Ty);
|
||||
}
|
||||
|
||||
void CGRecordLayoutBuilder::CheckForMemberPointer(const FieldDecl *FD) {
|
||||
void CGRecordLayoutBuilder::CheckForPointerToDataMember(QualType T) {
|
||||
// This record already contains a member pointer.
|
||||
if (ContainsMemberPointer)
|
||||
if (ContainsPointerToDataMember)
|
||||
return;
|
||||
|
||||
// Can only have member pointers if we're compiling C++.
|
||||
if (!Types.getContext().getLangOptions().CPlusPlus)
|
||||
return;
|
||||
|
||||
QualType Ty = FD->getType();
|
||||
|
||||
if (Ty->isMemberPointerType()) {
|
||||
// We have a member pointer!
|
||||
ContainsMemberPointer = true;
|
||||
return;
|
||||
}
|
||||
T = Types.getContext().getBaseElementType(T);
|
||||
|
||||
if (const MemberPointerType *MPT = T->getAs<MemberPointerType>()) {
|
||||
if (!MPT->getPointeeType()->isFunctionType()) {
|
||||
// We have a pointer to data member.
|
||||
ContainsPointerToDataMember = true;
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
||||
CGRecordLayout *
|
||||
|
@ -386,5 +400,5 @@ CGRecordLayoutBuilder::ComputeLayout(CodeGenTypes &Types,
|
|||
Types.addBitFieldInfo(Info.FD, Info.FieldNo, Info.Start, Info.Size);
|
||||
}
|
||||
|
||||
return new CGRecordLayout(Ty, Builder.ContainsMemberPointer);
|
||||
return new CGRecordLayout(Ty, Builder.ContainsPointerToDataMember);
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ namespace clang {
|
|||
class CXXRecordDecl;
|
||||
class FieldDecl;
|
||||
class RecordDecl;
|
||||
class QualType;
|
||||
|
||||
namespace CodeGen {
|
||||
class CGRecordLayout;
|
||||
|
@ -38,9 +39,10 @@ class CGRecordLayoutBuilder {
|
|||
/// Packed - Whether the resulting LLVM struct will be packed or not.
|
||||
bool Packed;
|
||||
|
||||
/// ContainsMemberPointer - Whether one of the fields is a member pointer
|
||||
/// or is a struct that contains a member pointer.
|
||||
bool ContainsMemberPointer;
|
||||
/// ContainsPointerToDataMember - Whether one of the fields in this record
|
||||
/// layout is a pointer to data member, or a struct that contains pointer to
|
||||
/// data member.
|
||||
bool ContainsPointerToDataMember;
|
||||
|
||||
/// Alignment - Contains the alignment of the RecordDecl.
|
||||
unsigned Alignment;
|
||||
|
@ -78,7 +80,7 @@ class CGRecordLayoutBuilder {
|
|||
llvm::SmallVector<LLVMBitFieldInfo, 16> LLVMBitFields;
|
||||
|
||||
CGRecordLayoutBuilder(CodeGenTypes &Types)
|
||||
: Types(Types), Packed(false), ContainsMemberPointer(false)
|
||||
: Types(Types), Packed(false), ContainsPointerToDataMember(false)
|
||||
, Alignment(0), AlignmentAsLLVMStruct(1)
|
||||
, BitsAvailableInLastField(0), NextFieldOffsetInBytes(0) { }
|
||||
|
||||
|
@ -123,8 +125,9 @@ class CGRecordLayoutBuilder {
|
|||
unsigned getTypeAlignment(const llvm::Type *Ty) const;
|
||||
uint64_t getTypeSizeInBytes(const llvm::Type *Ty) const;
|
||||
|
||||
/// CheckForMemberPointer - Check if the field contains a member pointer.
|
||||
void CheckForMemberPointer(const FieldDecl *FD);
|
||||
/// CheckForPointerToDataMember - Check if the given type contains a pointer
|
||||
/// to data member.
|
||||
void CheckForPointerToDataMember(QualType T);
|
||||
|
||||
public:
|
||||
/// ComputeLayout - Return the right record layout for a given record decl.
|
||||
|
|
|
@ -60,21 +60,24 @@ namespace CodeGen {
|
|||
/// LLVMType - The LLVMType corresponding to this record layout.
|
||||
const llvm::Type *LLVMType;
|
||||
|
||||
/// ContainsMemberPointer - Whether one of the fields in this record layout
|
||||
/// is a member pointer, or a struct that contains a member pointer.
|
||||
bool ContainsMemberPointer;
|
||||
/// ContainsPointerToDataMember - Whether one of the fields in this record
|
||||
/// layout is a pointer to data member, or a struct that contains pointer to
|
||||
/// data member.
|
||||
bool ContainsPointerToDataMember;
|
||||
|
||||
public:
|
||||
CGRecordLayout(const llvm::Type *T, bool ContainsMemberPointer)
|
||||
: LLVMType(T), ContainsMemberPointer(ContainsMemberPointer) { }
|
||||
CGRecordLayout(const llvm::Type *T, bool ContainsPointerToDataMember)
|
||||
: LLVMType(T), ContainsPointerToDataMember(ContainsPointerToDataMember) { }
|
||||
|
||||
/// getLLVMType - Return llvm type associated with this record.
|
||||
const llvm::Type *getLLVMType() const {
|
||||
return LLVMType;
|
||||
}
|
||||
|
||||
bool containsMemberPointer() const {
|
||||
return ContainsMemberPointer;
|
||||
/// containsPointerToDataMember - Whether this struct contains pointers to
|
||||
/// data members.
|
||||
bool containsPointerToDataMember() const {
|
||||
return ContainsPointerToDataMember;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -17,6 +17,23 @@ namespace ZeroInit {
|
|||
|
||||
// CHECK: @_ZN8ZeroInit1bE = global i64 -1,
|
||||
int A::* b = 0;
|
||||
|
||||
// CHECK: @_ZN8ZeroInit2saE = global %struct.anon { i64 -1 }
|
||||
struct {
|
||||
int A::*a;
|
||||
} sa;
|
||||
|
||||
// CHECK: @_ZN8ZeroInit3ssaE = global [2 x %0] [%0 { [2 x i64] [i64 -1, i64 -1] }
|
||||
struct {
|
||||
int A::*aa[2];
|
||||
} ssa[2];
|
||||
|
||||
// CHECK: @_ZN8ZeroInit2ssE = global %1 { %struct.anon { i64 -1 } }
|
||||
struct {
|
||||
struct {
|
||||
int A::*pa;
|
||||
} s;
|
||||
} ss;
|
||||
}
|
||||
|
||||
// PR5674
|
||||
|
|
Loading…
Reference in New Issue