Generalize the checking for qualification of (non-friend) class

members. Provide a hard error when the qualification doesn't match the
current class type, or a warning + Fix-it if it does match the current
class type. Fixes PR8159.

llvm-svn: 116445
This commit is contained in:
Douglas Gregor
2010-10-13 22:19:53 +00:00
parent 16db3287c0
commit a007d36c1b
4 changed files with 57 additions and 17 deletions

View File

@@ -2167,6 +2167,8 @@ def ext_out_of_line_declaration : ExtWarn<
InGroup<OutOfLineDeclaration>, DefaultError;
def warn_member_extra_qualification : Warning<
"extra qualification on member %0">;
def err_member_qualification : Error<
"non-friend class member %0 cannot have a qualified name">;
def note_member_def_close_match : Note<"member declaration nearly matches">;
def err_typecheck_ivar_variable_size : Error<
"instance variables must have a constant size">;

View File

@@ -2265,11 +2265,30 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
RequireCompleteDeclContext(D.getCXXScopeSpec(), DC))
return 0;
if (isa<CXXRecordDecl>(DC) && !cast<CXXRecordDecl>(DC)->hasDefinition()) {
Diag(D.getIdentifierLoc(),
diag::err_member_def_undefined_record)
<< Name << DC << D.getCXXScopeSpec().getRange();
D.setInvalidType();
if (isa<CXXRecordDecl>(DC)) {
if (!cast<CXXRecordDecl>(DC)->hasDefinition()) {
Diag(D.getIdentifierLoc(),
diag::err_member_def_undefined_record)
<< Name << DC << D.getCXXScopeSpec().getRange();
D.setInvalidType();
} else if (isa<CXXRecordDecl>(CurContext) &&
!D.getDeclSpec().isFriendSpecified()) {
// The user provided a superfluous scope specifier inside a class
// definition:
//
// class X {
// void X::f();
// };
if (CurContext->Equals(DC))
Diag(D.getIdentifierLoc(), diag::warn_member_extra_qualification)
<< Name << FixItHint::CreateRemoval(D.getCXXScopeSpec().getRange());
else
Diag(D.getIdentifierLoc(), diag::err_member_qualification)
<< Name << D.getCXXScopeSpec().getRange();
// Pretend that this qualifier was not here.
D.getCXXScopeSpec().clear();
}
}
// Check whether we need to rebuild the type of the given
@@ -3684,18 +3703,6 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (NewFD->isInvalidDecl()) {
// Ignore all the rest of this.
} else if (CurContext->isRecord() && D.getCXXScopeSpec().isSet() &&
!isFriend) {
// The user provided a superfluous scope specifier inside a class
// definition:
//
// class X {
// void X::f();
// };
Diag(NewFD->getLocation(), diag::warn_member_extra_qualification)
<< Name << FixItHint::CreateRemoval(D.getCXXScopeSpec().getRange());
} else if (!Redeclaration) {
// Fake up an access specifier if it's supposed to be a class member.
if (isa<CXXRecordDecl>(NewFD->getDeclContext()))

View File

@@ -896,6 +896,27 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
Decl *Member;
if (isInstField) {
CXXScopeSpec &SS = D.getCXXScopeSpec();
if (SS.isSet() && !SS.isInvalid()) {
// The user provided a superfluous scope specifier inside a class
// definition:
//
// class X {
// int X::member;
// };
DeclContext *DC = 0;
if ((DC = computeDeclContext(SS, false)) && DC->Equals(CurContext))
Diag(D.getIdentifierLoc(), diag::warn_member_extra_qualification)
<< Name << FixItHint::CreateRemoval(SS.getRange());
else
Diag(D.getIdentifierLoc(), diag::err_member_qualification)
<< Name << SS.getRange();
SS.clear();
}
// FIXME: Check for template parameters!
Member = HandleField(S, cast<CXXRecordDecl>(CurContext), Loc, D, BitWidth,
AS);

View File

@@ -248,3 +248,13 @@ namespace PR7133 {
class CLASS {
void CLASS::foo2(); // expected-warning {{extra qualification on member 'foo2'}}
};
namespace PR8159 {
class B { };
class A {
int A::a; // expected-warning{{extra qualification on member 'a'}}
static int A::b; // expected-warning{{extra qualification on member 'b'}}
int ::c; // expected-error{{non-friend class member 'c' cannot have a qualified name}}
};
}