aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2010-10-13 22:19:53 +0000
committerDouglas Gregor <dgregor@apple.com>2010-10-13 22:19:53 +0000
commit922fff2c9ef458fc04839e45a79552513f41ec7e (patch)
tree0420dec1722138a7d5d9fa3cf1e0a2b034c6d076
parent096428b351ebf5de9871ce11e06ba6f2d8276ab5 (diff)
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@116445 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--lib/Sema/SemaDecl.cpp41
-rw-r--r--lib/Sema/SemaDeclCXX.cpp21
-rw-r--r--test/SemaCXX/nested-name-spec.cpp10
4 files changed, 57 insertions, 17 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index f3541eaba3..bff8c054f1 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -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">;
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index a34d7ecf63..10785270e5 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -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()))
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 55f668b5c5..a63f057ae0 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -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);
diff --git a/test/SemaCXX/nested-name-spec.cpp b/test/SemaCXX/nested-name-spec.cpp
index bef8570bff..8d33f819af 100644
--- a/test/SemaCXX/nested-name-spec.cpp
+++ b/test/SemaCXX/nested-name-spec.cpp
@@ -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}}
+ };
+}