From cccd06487d473f2ede4fde7f869c4a85943a082b Mon Sep 17 00:00:00 2001 From: Eli Friedman Date: Tue, 16 Jul 2013 00:01:31 +0000 Subject: [PATCH] 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 --- clang/include/clang/Sema/Sema.h | 13 ++++++++----- clang/lib/Sema/SemaExprMember.cpp | 24 ++++++++++++++---------- clang/test/SemaCXX/anonymous-union.cpp | 9 +++++++++ 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 6b4079e36e58..6edb9ddbc24f 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -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, diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index 7151fc550414..29e91e173dfe 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -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(*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 @@ -799,14 +800,15 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS, while (FI != FEnd) { FieldDecl *field = cast(*FI++); - + // 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(); + (FI == FEnd? SS : EmptySS), field, + 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(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()) - 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. diff --git a/clang/test/SemaCXX/anonymous-union.cpp b/clang/test/SemaCXX/anonymous-union.cpp index 9c2cf24a83fc..fde27b049d88 100644 --- a/clang/test/SemaCXX/anonymous-union.cpp +++ b/clang/test/SemaCXX/anonymous-union.cpp @@ -197,3 +197,12 @@ namespace PR8326 { Foo 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'}} + } +}