Fix member refs with using decl + anonymous union.

Make sure we call BuildFieldReferenceExpr with the appropriate decl
when a member of an anonymous union is made public with a using decl.
Also, fix a crash on invalid field access into an anonymous union.

Fixes PR16630.

llvm-svn: 186367
This commit is contained in:
Eli Friedman 2013-07-16 00:01:31 +00:00
parent 66c0a65ba1
commit cccd06487d
3 changed files with 31 additions and 15 deletions

View File

@ -3150,11 +3150,14 @@ public:
const CXXScopeSpec *SS = 0,
NamedDecl *FoundD = 0);
ExprResult
BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
SourceLocation nameLoc,
IndirectFieldDecl *indirectField,
Expr *baseObjectExpr = 0,
SourceLocation opLoc = SourceLocation());
BuildAnonymousStructUnionMemberReference(
const CXXScopeSpec &SS,
SourceLocation nameLoc,
IndirectFieldDecl *indirectField,
DeclAccessPair FoundDecl = DeclAccessPair::make(0, AS_none),
Expr *baseObjectExpr = 0,
SourceLocation opLoc = SourceLocation());
ExprResult BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
LookupResult &R,

View File

@ -703,6 +703,7 @@ ExprResult
Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
SourceLocation loc,
IndirectFieldDecl *indirectField,
DeclAccessPair foundDecl,
Expr *baseObjectExpr,
SourceLocation opLoc) {
// First, build the expression that refers to the base object.
@ -780,15 +781,15 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
if (!baseVariable) {
FieldDecl *field = cast<FieldDecl>(*FI);
// FIXME: use the real found-decl info!
DeclAccessPair foundDecl = DeclAccessPair::make(field, field->getAccess());
// Make a nameInfo that properly uses the anonymous name.
DeclarationNameInfo memberNameInfo(field->getDeclName(), loc);
result = BuildFieldReferenceExpr(*this, result, baseObjectIsPointer,
EmptySS, field, foundDecl,
memberNameInfo).take();
if (!result)
return ExprError();
baseObjectIsPointer = false;
// FIXME: check qualified member access
@ -802,11 +803,12 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
// FIXME: these are somewhat meaningless
DeclarationNameInfo memberNameInfo(field->getDeclName(), loc);
DeclAccessPair foundDecl = DeclAccessPair::make(field, field->getAccess());
DeclAccessPair fakeFoundDecl =
DeclAccessPair::make(field, field->getAccess());
result = BuildFieldReferenceExpr(*this, result, /*isarrow*/ false,
(FI == FEnd? SS : EmptySS), field,
foundDecl, memberNameInfo).take();
fakeFoundDecl, memberNameInfo).take();
}
return Owned(result);
@ -990,7 +992,8 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
// We may have found a field within an anonymous union or struct
// (C++ [class.union]).
return BuildAnonymousStructUnionMemberReference(SS, MemberLoc, FD,
BaseExpr, OpLoc);
FoundDecl, BaseExpr,
OpLoc);
if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) {
return Owned(BuildMemberExpr(*this, Context, BaseExpr, IsArrow, SS,
@ -1688,7 +1691,8 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS,
// (C++ [class.union]).
// FIXME: template-ids inside anonymous structs?
if (IndirectFieldDecl *FD = R.getAsSingle<IndirectFieldDecl>())
return BuildAnonymousStructUnionMemberReference(SS, R.getNameLoc(), FD);
return BuildAnonymousStructUnionMemberReference(SS, R.getNameLoc(), FD,
R.begin().getPair());
// If this is known to be an instance access, go ahead and build an
// implicit 'this' expression now.

View File

@ -197,3 +197,12 @@ namespace PR8326 {
Foo<int> baz;
}
namespace PR16630 {
struct A { union { int x; float y; }; }; // expected-note {{member is declared here}}
struct B : private A { using A::x; } b; // expected-note 2 {{private}}
void foo () {
b.x = 10;
b.y = 0; // expected-error {{cannot cast 'struct B' to its private base class 'PR16630::A'}} expected-error {{'y' is a private member of 'PR16630::A'}}
}
}