forked from OSchip/llvm-project
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:
parent
1ce7755c35
commit
8322b426a5
|
@ -1784,6 +1784,7 @@ public:
|
|||
const CXXScopeSpec *SS = 0);
|
||||
ExprResult
|
||||
BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
|
||||
const CXXScopeSpec &SS,
|
||||
IndirectFieldDecl *IndirectField,
|
||||
Expr *BaseObjectExpr = 0,
|
||||
SourceLocation OpLoc = SourceLocation());
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue