From 8322b426a56db0ecaf99c565746ed04448cd29b1 Mon Sep 17 00:00:00 2001 From: Argyrios Kyrtzidis Date: Mon, 31 Jan 2011 07:04:29 +0000 Subject: 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. llvm-svn: 124575 --- clang/lib/CodeGen/ItaniumCXXABI.cpp | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) (limited to 'clang/lib/CodeGen') diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index ef5455c2869..8a7ac0a83a4 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/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(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(*lookup.first); + + uint64_t Offset = 0; + for (IndirectFieldDecl::chain_iterator + I= indirectFD->chain_begin(), E= indirectFD->chain_end(); I!=E; ++I) { + Offset += getFieldOffset(cast(*I), CGM); + } return llvm::ConstantInt::get(getPtrDiffTy(), Offset); } -- cgit v1.2.3