From 922fff2c9ef458fc04839e45a79552513f41ec7e Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Wed, 13 Oct 2010 22:19:53 +0000 Subject: [PATCH] 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 --- include/clang/Basic/DiagnosticSemaKinds.td | 2 ++ lib/Sema/SemaDecl.cpp | 41 +++++++++++++--------- lib/Sema/SemaDeclCXX.cpp | 21 +++++++++++ test/SemaCXX/nested-name-spec.cpp | 10 ++++++ 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, 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(DC) && !cast(DC)->hasDefinition()) { - Diag(D.getIdentifierLoc(), - diag::err_member_def_undefined_record) - << Name << DC << D.getCXXScopeSpec().getRange(); - D.setInvalidType(); + if (isa(DC)) { + if (!cast(DC)->hasDefinition()) { + Diag(D.getIdentifierLoc(), + diag::err_member_def_undefined_record) + << Name << DC << D.getCXXScopeSpec().getRange(); + D.setInvalidType(); + } else if (isa(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(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(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}} + }; +} -- 2.40.0