Propagate access specifiers to anonymous union members nested within classes.

Fixes <rdar://problem/7987650>.

llvm-svn: 104376
This commit is contained in:
John McCall 2010-05-21 20:45:30 +00:00
parent 304a9537e1
commit b54367d2f8
9 changed files with 68 additions and 21 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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