diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 97aaa1c082830a16fceb48c15ff2362f2688061e..69105685bab42009eec2bbe1e82d87f5d96390c4 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -573,7 +573,9 @@ public: /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with /// no declarator (e.g. "struct foo;") is parsed. - virtual DeclPtrTy ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { + virtual DeclPtrTy ParsedFreeStandingDeclSpec(Scope *S, + AccessSpecifier Access, + DeclSpec &DS) { return DeclPtrTy(); } diff --git a/lib/Frontend/PrintParserCallbacks.cpp b/lib/Frontend/PrintParserCallbacks.cpp index 258d352452ee9a8487f21b152bb80ffce4608d96..b032233b3d3ba40966829ee5743e36efcad52164 100644 --- a/lib/Frontend/PrintParserCallbacks.cpp +++ b/lib/Frontend/PrintParserCallbacks.cpp @@ -161,7 +161,8 @@ namespace { /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with /// no declarator (e.g. "struct foo;") is parsed. - virtual DeclPtrTy ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { + virtual DeclPtrTy ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, + DeclSpec &DS) { Out << __FUNCTION__ << "\n"; return DeclPtrTy(); } diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index ec485d2d964682d7d7569bb44c30537fac429a45..e7650eae84625aeefb9d9452db8f234a1d146517 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -364,7 +364,8 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context, // declaration-specifiers init-declarator-list[opt] ';' if (Tok.is(tok::semi)) { if (RequireSemi) ConsumeToken(); - DeclPtrTy TheDecl = Actions.ParsedFreeStandingDeclSpec(CurScope, DS); + DeclPtrTy TheDecl = Actions.ParsedFreeStandingDeclSpec(CurScope, AS_none, + DS); DS.complete(TheDecl); return Actions.ConvertDeclToDeclGroup(TheDecl); } @@ -1676,7 +1677,7 @@ ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) { // If there are no declarators, this is a free-standing declaration // specifier. Let the actions module cope with it. if (Tok.is(tok::semi)) { - Actions.ParsedFreeStandingDeclSpec(CurScope, DS); + Actions.ParsedFreeStandingDeclSpec(CurScope, AS_none, DS); return; } diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 3d74d4dc7dfaece2bb256bb5aa4e276180ebd8a4..b276db6beed26ef1a67fb60d3bf20eff897889fc 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -1307,7 +1307,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, if (Tok.is(tok::semi)) { ConsumeToken(); - Actions.ParsedFreeStandingDeclSpec(CurScope, DS); + Actions.ParsedFreeStandingDeclSpec(CurScope, AS, DS); return; } diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index ff6995340151c2775f39eb3e7c8ed2cd6b0e8c5d..93197816ced3f306a5eb0f1a50afbc38f81007f0 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -201,7 +201,7 @@ Parser::ParseSingleDeclarationAfterTemplate( if (Tok.is(tok::semi)) { DeclEnd = ConsumeToken(); - DeclPtrTy Decl = Actions.ParsedFreeStandingDeclSpec(CurScope, DS); + DeclPtrTy Decl = Actions.ParsedFreeStandingDeclSpec(CurScope, AS, DS); DS.complete(Decl); return Decl; } diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 6dbb99e395f903c188e9d9618ece78e6d798ae2e..bfcb6e7ee764622d9480be2833b790fd560b77f8 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -538,7 +538,7 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsingDeclSpec &DS, // declaration-specifiers init-declarator-list[opt] ';' if (Tok.is(tok::semi)) { ConsumeToken(); - DeclPtrTy TheDecl = Actions.ParsedFreeStandingDeclSpec(CurScope, DS); + DeclPtrTy TheDecl = Actions.ParsedFreeStandingDeclSpec(CurScope, AS, DS); DS.complete(TheDecl); return Actions.ConvertDeclToDeclGroup(TheDecl); } diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 4d9463f6523826e73197938e8c30d2d227fc87b1..0870431a0dec57919dde44b6d4576ec9c765eeb5 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -907,11 +907,11 @@ public: /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with /// no declarator (e.g. "struct foo;") is parsed. - virtual DeclPtrTy ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS); + virtual DeclPtrTy ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, + DeclSpec &DS); - bool InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner, - RecordDecl *AnonRecord); virtual DeclPtrTy BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, + AccessSpecifier AS, RecordDecl *Record); bool isAcceptableTagRedeclaration(const TagDecl *Previous, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index b86284d1afb6c76555cf75c444e37a6c523687f6..b94f3d754006ed30dc41f598dc665a5c33001083 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1455,7 +1455,8 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with /// no declarator (e.g. "struct foo;") is parsed. -Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { +Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, + DeclSpec &DS) { // FIXME: Error on auto/register at file scope // FIXME: Error on inline/virtual/explicit // FIXME: Warn on useless __thread @@ -1505,7 +1506,7 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { DS.getStorageClassSpec() != DeclSpec::SCS_typedef) { if (getLangOptions().CPlusPlus || Record->getDeclContext()->isRecord()) - return BuildAnonymousStructOrUnion(S, DS, Record); + return BuildAnonymousStructOrUnion(S, DS, AS, Record); Diag(DS.getSourceRange().getBegin(), diag::ext_no_declarators) << DS.getSourceRange(); @@ -1583,8 +1584,10 @@ static bool CheckAnonMemberRedeclaration(Sema &SemaRef, /// /// This routine is recursive, injecting the names of nested anonymous /// structs/unions into the owning context and scope as well. -bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner, - RecordDecl *AnonRecord) { +static bool InjectAnonymousStructOrUnionMembers(Sema &SemaRef, Scope *S, + DeclContext *Owner, + RecordDecl *AnonRecord, + AccessSpecifier AS) { unsigned diagKind = AnonRecord->isUnion() ? diag::err_anonymous_union_member_redecl : diag::err_anonymous_struct_member_redecl; @@ -1594,7 +1597,7 @@ bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner, FEnd = AnonRecord->field_end(); F != FEnd; ++F) { if ((*F)->getDeclName()) { - if (CheckAnonMemberRedeclaration(*this, S, Owner, (*F)->getDeclName(), + if (CheckAnonMemberRedeclaration(SemaRef, S, Owner, (*F)->getDeclName(), (*F)->getLocation(), diagKind)) { // C++ [class.union]p2: // The names of the members of an anonymous union shall be @@ -1608,15 +1611,19 @@ bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner, // considered to have been defined in the scope in which the // anonymous union is declared. Owner->makeDeclVisibleInContext(*F); - S->AddDecl(DeclPtrTy::make(*F)); - IdResolver.AddDecl(*F); + S->AddDecl(Sema::DeclPtrTy::make(*F)); + SemaRef.IdResolver.AddDecl(*F); + + // That includes picking up the appropriate access specifier. + if (AS != AS_none) (*F)->setAccess(AS); } } else if (const RecordType *InnerRecordType = (*F)->getType()->getAs<RecordType>()) { RecordDecl *InnerRecord = InnerRecordType->getDecl(); if (InnerRecord->isAnonymousStructOrUnion()) Invalid = Invalid || - InjectAnonymousStructOrUnionMembers(S, Owner, InnerRecord); + InjectAnonymousStructOrUnionMembers(SemaRef, S, Owner, + InnerRecord, AS); } } @@ -1686,6 +1693,7 @@ StorageClassSpecToFunctionDeclStorageClass(DeclSpec::SCS StorageClassSpec, /// (C++ [class.union]) and a GNU C extension; anonymous structures /// are a GNU C and GNU C++ extension. Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, + AccessSpecifier AS, RecordDecl *Record) { DeclContext *Owner = Record->getDeclContext(); @@ -1740,7 +1748,8 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, // C++ [class.union]p3: // An anonymous union shall not have private or protected // members (clause 11). - if (FD->getAccess() == AS_protected || FD->getAccess() == AS_private) { + assert(FD->getAccess() != AS_none); + if (FD->getAccess() != AS_public) { Diag(FD->getLocation(), diag::err_anonymous_record_nonpublic_member) << (int)Record->isUnion() << (int)(FD->getAccess() == AS_protected); Invalid = true; @@ -1797,7 +1806,7 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, Context.getTypeDeclType(Record), TInfo, /*BitWidth=*/0, /*Mutable=*/false); - Anon->setAccess(AS_public); + Anon->setAccess(AS); if (getLangOptions().CPlusPlus) { FieldCollector->Add(cast<FieldDecl>(Anon)); if (!cast<CXXRecordDecl>(Record)->isEmpty()) @@ -1834,7 +1843,7 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, // Inject the members of the anonymous struct/union into the owning // context and into the identifier resolver chain for name lookup // purposes. - if (InjectAnonymousStructOrUnionMembers(S, Owner, Record)) + if (InjectAnonymousStructOrUnionMembers(*this, S, Owner, Record, AS)) Invalid = true; // Mark this as an anonymous struct/union type. Note that we do not diff --git a/test/SemaCXX/anonymous-union.cpp b/test/SemaCXX/anonymous-union.cpp index 5c34e016e57de19ebe57c6e76853d3d67d3b92e1..5f84bcca28db50ed73c7e64ca6c4a9725be1b310 100644 --- a/test/SemaCXX/anonymous-union.cpp +++ b/test/SemaCXX/anonymous-union.cpp @@ -121,3 +121,37 @@ typedef struct _s { int Foo; }; } s, *ps; + +// <rdar://problem/7987650> +namespace test4 { + class A { + struct { + int s0; // expected-note {{declared private here}} + double s1; // expected-note {{declared private here}} + union { + int su0; // expected-note {{declared private here}} + double su1; // expected-note {{declared private here}} + }; + }; + union { + int u0; // expected-note {{declared private here}} + double u1; // expected-note {{declared private here}} + struct { + int us0; // expected-note {{declared private here}} + double us1; // expected-note {{declared private here}} + }; + }; + }; + + void test() { + A a; + (void) a.s0; // expected-error {{private member}} + (void) a.s1; // expected-error {{private member}} + (void) a.su0; // expected-error {{private member}} + (void) a.su1; // expected-error {{private member}} + (void) a.u0; // expected-error {{private member}} + (void) a.u1; // expected-error {{private member}} + (void) a.us0; // expected-error {{private member}} + (void) a.us1; // expected-error {{private member}} + } +}