From: Anders Carlsson Date: Tue, 2 Feb 2010 05:17:25 +0000 (+0000) Subject: Improve handling of emitting 'null' pointers to data members. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2c12d0319a267b844cb7d569d84426cd344b90f7;p=clang Improve handling of emitting 'null' pointers to data members. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@95066 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index fba70cb88f..d843d023f7 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -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()) { + const CXXRecordDecl *RD = cast(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()) 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 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 Array(NumElements); + for (unsigned i = 0; i != NumElements; ++i) + Array[i] = Element; - const llvm::ArrayType *ATy = - cast(getTypes().ConvertTypeForMem(T)); - return llvm::ConstantArray::get(ATy, Array); - } + const llvm::ArrayType *ATy = + cast(getTypes().ConvertTypeForMem(T)); + return llvm::ConstantArray::get(ATy, Array); } if (const RecordType *RT = T->getAs()) { - 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 CGRecordLayout &Layout = Types.getCGRecordLayout(RD); - if (Layout.containsMemberPointer()) { - assert(0 && "FIXME: No support for structs with member pointers yet!"); + const CXXRecordDecl *RD = cast(RT->getDecl()); + assert(!RD->getNumBases() && + "FIXME: Handle zero-initializing structs with bases and " + "pointers to data members."); + const llvm::StructType *STy = + cast(getTypes().ConvertTypeForMem(T)); + unsigned NumElements = STy->getNumElements(); + std::vector Elements(NumElements); + + 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()->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 * diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp index cc474033c1..baafd6836c 100644 --- a/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -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()) { + if (!MPT->getPointeeType()->isFunctionType()) { + // We have a pointer to data member. + ContainsPointerToDataMember = true; + } + } else if (const RecordType *RT = T->getAs()) { + const CXXRecordDecl *RD = cast(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); } diff --git a/lib/CodeGen/CGRecordLayoutBuilder.h b/lib/CodeGen/CGRecordLayoutBuilder.h index cf84053e19..eb60ed7b5b 100644 --- a/lib/CodeGen/CGRecordLayoutBuilder.h +++ b/lib/CodeGen/CGRecordLayoutBuilder.h @@ -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 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. diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h index 7e342526e8..aa1880b41f 100644 --- a/lib/CodeGen/CodeGenTypes.h +++ b/lib/CodeGen/CodeGenTypes.h @@ -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; } }; diff --git a/test/CodeGenCXX/pointers-to-data-members.cpp b/test/CodeGenCXX/pointers-to-data-members.cpp index 79a631c93c..3a10cb1fcf 100644 --- a/test/CodeGenCXX/pointers-to-data-members.cpp +++ b/test/CodeGenCXX/pointers-to-data-members.cpp @@ -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