From 699bf489b4f38a13d073a82b6f73758b493a3663 Mon Sep 17 00:00:00 2001 From: Argiris Kirtzidis Date: Mon, 31 Jan 2011 07:04:29 +0000 Subject: [PATCH] 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 --- include/clang/Sema/Sema.h | 1 + lib/CodeGen/ItaniumCXXABI.cpp | 34 ++++++++++++++++++---- lib/Sema/SemaExpr.cpp | 30 +++++++++++++------ .../anonymous-union-member-initializer.cpp | 14 +++++++++ 4 files changed, 65 insertions(+), 14 deletions(-) diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 781e3588e..d3b43c450 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1784,6 +1784,7 @@ public: const CXXScopeSpec *SS = 0); ExprResult BuildAnonymousStructUnionMemberReference(SourceLocation Loc, + const CXXScopeSpec &SS, IndirectFieldDecl *IndirectField, Expr *BaseObjectExpr = 0, SourceLocation OpLoc = SourceLocation()); diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index ef5455c28..8a7ac0a83 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(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); } diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 098f5396b..2429c7588 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -853,6 +853,7 @@ BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow, ExprResult Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, + const CXXScopeSpec &SS, IndirectFieldDecl *IndirectField, Expr *BaseObjectExpr, SourceLocation OpLoc) { @@ -911,9 +912,21 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, BaseQuals = Qualifiers::fromCVRMask(MD->getTypeQualifiers()); } - if (!BaseObjectExpr) - return ExprError(Diag(Loc, diag::err_invalid_non_static_member_use) - << IndirectField->getDeclName()); + if (!BaseObjectExpr) { + // The field is referenced for a pointer-to-member expression, e.g: + // + // struct S { + // union { + // char c; + // }; + // }; + // char S::*foo = &S::c; + // + FieldDecl *field = IndirectField->getAnonField(); + DeclarationNameInfo NameInfo(field->getDeclName(), Loc); + return BuildDeclRefExpr(field, field->getType().getNonReferenceType(), + VK_LValue, NameInfo, &SS); + } } // Build the implicit member references to the field of the @@ -929,9 +942,6 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, for (; FI != FEnd; FI++) { FieldDecl *Field = cast(*FI); - // FIXME: the first access can be qualified - CXXScopeSpec SS; - // FIXME: these are somewhat meaningless DeclarationNameInfo MemberNameInfo(Field->getDeclName(), Loc); DeclAccessPair FoundDecl = DeclAccessPair::make(Field, Field->getAccess()); @@ -2035,7 +2045,7 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS, // FIXME: This needs to happen post-isImplicitMemberReference? // FIXME: template-ids inside anonymous structs? if (IndirectFieldDecl *FD = R.getAsSingle()) - return BuildAnonymousStructUnionMemberReference(Loc, FD); + return BuildAnonymousStructUnionMemberReference(Loc, SS, FD); // If this is known to be an instance access, go ahead and build a @@ -2228,7 +2238,7 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, // Handle anonymous. if (IndirectFieldDecl *FD = dyn_cast(VD)) - return BuildAnonymousStructUnionMemberReference(Loc, FD); + return BuildAnonymousStructUnionMemberReference(Loc, SS, FD); ExprValueKind VK = getValueKindForDecl(Context, VD); @@ -3400,7 +3410,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, if (IndirectFieldDecl *FD = dyn_cast(MemberDecl)) // We may have found a field within an anonymous union or struct // (C++ [class.union]). - return BuildAnonymousStructUnionMemberReference(MemberLoc, FD, + return BuildAnonymousStructUnionMemberReference(MemberLoc, SS, FD, BaseExpr, OpLoc); if (VarDecl *Var = dyn_cast(MemberDecl)) { @@ -7346,6 +7356,8 @@ static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp, return QualType(); } + while (cast(Ctx)->isAnonymousStructOrUnion()) + Ctx = Ctx->getParent(); return S.Context.getMemberPointerType(op->getType(), S.Context.getTypeDeclType(cast(Ctx)).getTypePtr()); } diff --git a/test/CodeGenCXX/anonymous-union-member-initializer.cpp b/test/CodeGenCXX/anonymous-union-member-initializer.cpp index 87d3fcc6c..d97a2ae36 100644 --- a/test/CodeGenCXX/anonymous-union-member-initializer.cpp +++ b/test/CodeGenCXX/anonymous-union-member-initializer.cpp @@ -1,5 +1,19 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s +// rdar://8818236 +namespace rdar8818236 { +struct S { + char c2; + union { + char c; + int i; + }; +}; + +// CHECK: @_ZN11rdar88182363fooE = global i64 4 +char S::*foo = &S::c; +} + struct A { union { int a; -- 2.11.4.GIT