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
This commit is contained in:
Argyrios Kyrtzidis 2011-01-31 07:04:29 +00:00
parent 1ce7755c35
commit 8322b426a5
4 changed files with 65 additions and 14 deletions

View File

@ -1784,6 +1784,7 @@ public:
const CXXScopeSpec *SS = 0);
ExprResult
BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
const CXXScopeSpec &SS,
IndirectFieldDecl *IndirectField,
Expr *BaseObjectExpr = 0,
SourceLocation OpLoc = SourceLocation());

View File

@ -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);
}

View File

@ -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<FieldDecl>(*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<IndirectFieldDecl>())
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<IndirectFieldDecl>(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<IndirectFieldDecl>(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<VarDecl>(MemberDecl)) {
@ -7346,6 +7356,8 @@ static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp,
return QualType();
}
while (cast<RecordDecl>(Ctx)->isAnonymousStructOrUnion())
Ctx = Ctx->getParent();
return S.Context.getMemberPointerType(op->getType(),
S.Context.getTypeDeclType(cast<RecordDecl>(Ctx)).getTypePtr());
}

View File

@ -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;