diff options
author | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2011-01-31 07:04:29 +0000 |
---|---|---|
committer | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2011-01-31 07:04:29 +0000 |
commit | 0413db4a26b0a1577b75c2979b0eb21f3490d17a (patch) | |
tree | 2b37d0d4244ef9ea4f370e6e2fa8149b008b7028 /lib/CodeGen/ItaniumCXXABI.cpp | |
parent | d4d3ce6ed8d4981a18d013f8694c762c47b44c77 (diff) |
Amazing that there are still issues with the fields of anonymous struct/unions..
Allow taking the address of such a field for a pointer-to-member constant. Fixes rdar://8818236.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@124575 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/ItaniumCXXABI.cpp')
-rw-r--r-- | lib/CodeGen/ItaniumCXXABI.cpp | 34 |
1 files changed, 29 insertions, 5 deletions
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index ef5455c286..8a7ac0a83a 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -493,17 +493,41 @@ ItaniumCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) { /*Packed=*/false); } +static uint64_t getFieldOffset(const FieldDecl *FD, CodeGenModule &CGM) { + const CGRecordLayout &RL = CGM.getTypes().getCGRecordLayout(FD->getParent()); + const llvm::StructType *ClassLTy = RL.getLLVMType(); + + unsigned FieldNo = RL.getLLVMFieldNo(FD); + return + CGM.getTargetData().getStructLayout(ClassLTy)->getElementOffset(FieldNo); +} + llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const FieldDecl *FD) { // Itanium C++ ABI 2.3: // A pointer to data member is an offset from the base address of // the class object containing it, represented as a ptrdiff_t - const CGRecordLayout &RL = CGM.getTypes().getCGRecordLayout(FD->getParent()); - const llvm::StructType *ClassLTy = RL.getLLVMType(); + const RecordDecl *parent = FD->getParent(); + if (!parent->isAnonymousStructOrUnion()) + return llvm::ConstantInt::get(getPtrDiffTy(), getFieldOffset(FD, CGM)); - unsigned FieldNo = RL.getLLVMFieldNo(FD); - uint64_t Offset = - CGM.getTargetData().getStructLayout(ClassLTy)->getElementOffset(FieldNo); + // Handle a field injected from an anonymous struct or union. + + assert(FD->getDeclName() && "Requested pointer to member with no name!"); + + // Find the record which the field was injected into. + while (parent->isAnonymousStructOrUnion()) + parent = cast<RecordDecl>(parent->getParent()); + + RecordDecl::lookup_const_result lookup = parent->lookup(FD->getDeclName()); + assert(lookup.first != lookup.second && "Didn't find the field!"); + const IndirectFieldDecl *indirectFD = cast<IndirectFieldDecl>(*lookup.first); + + uint64_t Offset = 0; + for (IndirectFieldDecl::chain_iterator + I= indirectFD->chain_begin(), E= indirectFD->chain_end(); I!=E; ++I) { + Offset += getFieldOffset(cast<FieldDecl>(*I), CGM); + } return llvm::ConstantInt::get(getPtrDiffTy(), Offset); } |