From: Richard Smith Date: Thu, 5 Dec 2013 07:51:02 +0000 (+0000) Subject: Implement DR482: namespace members can be redeclared with a qualified name X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=fb8139fbf765f0c10b102d6fcd0d911d4c384d08;p=clang Implement DR482: namespace members can be redeclared with a qualified name within their namespace, and such a redeclaration isn't required to be a definition any more. Update DR status page to say Clang 3.4 instead of SVN and add new Clang 3.5 category (but keep Clang 3.4 yellow for now). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@196481 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 4f92d95944..07c6cbbdff 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -4458,6 +4458,9 @@ def warn_member_extra_qualification : Warning< "extra qualification on member %0">, InGroup; def err_member_extra_qualification : Error< "extra qualification on member %0">; +def warn_namespace_member_extra_qualification : Warning< + "extra qualification on member %0">, + InGroup>; 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">; diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 17f19dc206..451ebd254f 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -4115,33 +4115,31 @@ bool Sema::DiagnoseClassNameShadow(DeclContext *DC, /// \returns true if we cannot safely recover from this error, false otherwise. bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC, DeclarationName Name, - SourceLocation Loc) { + SourceLocation Loc) { DeclContext *Cur = CurContext; while (isa(Cur) || isa(Cur)) Cur = Cur->getParent(); - - // C++ [dcl.meaning]p1: - // A declarator-id shall not be qualified except for the definition - // of a member function (9.3) or static data member (9.4) outside of - // its class, the definition or explicit instantiation of a function - // or variable member of a namespace outside of its namespace, or the - // definition of an explicit specialization outside of its namespace, - // or the declaration of a friend function that is a member of - // another class or namespace (11.3). [...] - - // The user provided a superfluous scope specifier that refers back to the - // class or namespaces in which the entity is already declared. + + // If the user provided a superfluous scope specifier that refers back to the + // class in which the entity is already declared, diagnose and ignore it. // // class X { // void X::f(); // }; + // + // Note, it was once ill-formed to give redundant qualification in all + // contexts, but that rule was removed by DR482. if (Cur->Equals(DC)) { - Diag(Loc, LangOpts.MicrosoftExt? diag::warn_member_extra_qualification - : diag::err_member_extra_qualification) - << Name << FixItHint::CreateRemoval(SS.getRange()); - SS.clear(); + if (Cur->isRecord()) { + Diag(Loc, LangOpts.MicrosoftExt ? diag::warn_member_extra_qualification + : diag::err_member_extra_qualification) + << Name << FixItHint::CreateRemoval(SS.getRange()); + SS.clear(); + } else { + Diag(Loc, diag::warn_namespace_member_extra_qualification) << Name; + } return false; - } + } // Check whether the qualifying scope encloses the scope of the original // declaration. @@ -7248,11 +7246,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } } - } else if (!D.isFunctionDefinition() && D.getCXXScopeSpec().isSet() && + } else if (!D.isFunctionDefinition() && + isa(NewFD) && NewFD->isOutOfLine() && !isFriend && !isFunctionTemplateSpecialization && !isExplicitSpecialization) { // An out-of-line member function declaration must also be a - // definition (C++ [dcl.meaning]p1). + // definition (C++ [class.mfct]p2). // Note that this is not the case for explicit specializations of // function templates or member functions of class templates, per // C++ [temp.expl.spec]p2. We also allow these declarations as an diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 0491267614..162e46ecab 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -12133,11 +12133,13 @@ void Sema::ActOnCXXEnterDeclInitializer(Scope *S, Decl *D) { // If there is no declaration, there was an error parsing it. if (D == 0 || D->isInvalidDecl()) return; - // We should only get called for declarations with scope specifiers, like: - // int foo::bar; - assert(D->isOutOfLine()); - EnterDeclaratorContext(S, D->getDeclContext()); - + // We will always have a nested name specifier here, but this declaration + // might not be out of line if the specifier names the current namespace: + // extern int n; + // int ::n = 0; + if (D->isOutOfLine()) + EnterDeclaratorContext(S, D->getDeclContext()); + // If we are parsing the initializer for a static data member, push a // new expression evaluation context that is associated with this static // data member. @@ -12152,10 +12154,10 @@ void Sema::ActOnCXXExitDeclInitializer(Scope *S, Decl *D) { if (D == 0 || D->isInvalidDecl()) return; if (isStaticDataMember(D)) - PopExpressionEvaluationContext(); + PopExpressionEvaluationContext(); - assert(D->isOutOfLine()); - ExitDeclaratorContext(S); + if (D->isOutOfLine()) + ExitDeclaratorContext(S); } /// ActOnCXXConditionDeclarationExpr - Parsed a condition declaration of a diff --git a/test/CXX/dcl.decl/dcl.meaning/p1.cpp b/test/CXX/dcl.decl/dcl.meaning/p1.cpp index ec9a261187..5747380f28 100644 --- a/test/CXX/dcl.decl/dcl.meaning/p1.cpp +++ b/test/CXX/dcl.decl/dcl.meaning/p1.cpp @@ -29,9 +29,17 @@ namespace NS { template void wibble(T); } namespace NS { - void NS::foo() {} // expected-error{{extra qualification on member 'foo'}} - int NS::bar; // expected-error{{extra qualification on member 'bar'}} - struct NS::X { }; // expected-error{{extra qualification on member 'X'}} - template struct NS::Y; // expected-error{{extra qualification on member 'Y'}} - template void NS::wibble(T) { } // expected-error{{extra qualification on member 'wibble'}} + // Under DR482, these are all valid, except for forward-declaring a struct + // with a nested-name-specifier. + void NS::foo(); // expected-warning {{extra qualification}} + extern int NS::bar; // expected-warning {{extra qualification}} + struct NS::X; // expected-error {{forward declaration of struct cannot have a nested name specifier}} expected-warning {{extra qualification}} + template struct NS::Y; // expected-error {{forward declaration of struct cannot have a nested name specifier}} expected-warning {{extra qualification}} + template void NS::wibble(T); // expected-warning {{extra qualification}} + + void NS::foo() {} // expected-warning{{extra qualification on member 'foo'}} + int NS::bar; // expected-warning{{extra qualification on member 'bar'}} + struct NS::X { }; // expected-warning{{extra qualification on member 'X'}} + template struct NS::Y { }; // expected-warning{{extra qualification on member 'Y'}} + template void NS::wibble(T) { } // expected-warning{{extra qualification on member 'wibble'}} } diff --git a/test/CXX/drs/dr1xx.cpp b/test/CXX/drs/dr1xx.cpp index 7045148034..f65638561f 100644 --- a/test/CXX/drs/dr1xx.cpp +++ b/test/CXX/drs/dr1xx.cpp @@ -592,11 +592,10 @@ namespace dr155 { // dr155: dup 632 struct S { int n; } s = { { 1 } }; // expected-warning {{braces around scalar initializer}} } -namespace dr159 { // dr159: no +namespace dr159 { // dr159: 3.5 namespace X { void f(); } void f(); - // FIXME: This should be accepted. - void dr159::f() {} // expected-error {{extra qualification}} + void dr159::f() {} // expected-warning {{extra qualification}} void dr159::X::f() {} } diff --git a/test/CXX/drs/dr4xx.cpp b/test/CXX/drs/dr4xx.cpp index 1d3b94064c..f295431125 100644 --- a/test/CXX/drs/dr4xx.cpp +++ b/test/CXX/drs/dr4xx.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors // RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -// expected-no-diagnostics +// RUN: %clang_cc1 -std=c++1y %s -verify -fexceptions -fcxx-exceptions -pedantic-errors namespace dr408 { // dr408: 3.4 template void g() { int arr[N != 1 ? 1 : -1]; } @@ -30,3 +30,37 @@ namespace dr408 { // dr408: 3.4 template<> int R::arr[2]; template void R::f(); } + +namespace dr482 { // dr482: 3.5 + extern int a; + void f(); + + int dr482::a = 0; // expected-warning {{extra qualification}} + void dr482::f() {} // expected-warning {{extra qualification}} + + inline namespace X { // expected-error 0-1{{C++11 feature}} + extern int b; + void g(); + struct S; + } + int dr482::b = 0; // expected-warning {{extra qualification}} + void dr482::g() {} // expected-warning {{extra qualification}} + struct dr482::S {}; // expected-warning {{extra qualification}} + + void dr482::f(); // expected-warning {{extra qualification}} + void dr482::g(); // expected-warning {{extra qualification}} + + // FIXME: The following are valid in DR482's wording, but these are bugs in + // the wording which we deliberately don't implement. + namespace N { typedef int type; } + typedef int N::type; // expected-error {{typedef declarator cannot be qualified}} + struct A { + struct B; + struct A::B {}; // expected-error {{extra qualification}} + +#if __cplusplus >= 201103L + enum class C; + enum class A::C {}; // expected-error {{extra qualification}} +#endif + }; +} diff --git a/test/CXX/temp/p3.cpp b/test/CXX/temp/p3.cpp index 11f72de918..e9fd8a3090 100644 --- a/test/CXX/temp/p3.cpp +++ b/test/CXX/temp/p3.cpp @@ -8,7 +8,8 @@ template int S::a, S::b; // expected-error {{can only declare template struct A { static A a; } A::a; // expected-error {{expected ';' after struct}} \ expected-error {{use of undeclared identifier 'T'}} \ - expected-error{{extra qualification}} + expected-error {{no member named 'a'}} \ + expected-warning {{extra qualification}} template struct B { } f(); // expected-error {{expected ';' after struct}} \ expected-error {{requires a type specifier}} diff --git a/test/SemaCXX/nested-name-spec.cpp b/test/SemaCXX/nested-name-spec.cpp index df4f1b269d..f1f9bbb507 100644 --- a/test/SemaCXX/nested-name-spec.cpp +++ b/test/SemaCXX/nested-name-spec.cpp @@ -160,7 +160,7 @@ namespace N { void f(); // FIXME: if we move this to a separate definition of N, things break! } -void ::global_func2(int) { } // expected-error{{extra qualification on member 'global_func2'}} +void ::global_func2(int) { } // expected-warning{{extra qualification on member 'global_func2'}} void N::f() { } // okay diff --git a/www/cxx_dr_status.html b/www/cxx_dr_status.html index a360ace7fe..c9f95a18bb 100644 --- a/www/cxx_dr_status.html +++ b/www/cxx_dr_status.html @@ -212,7 +212,7 @@ 29 CD1 Linkage of locally declared functions - SVN + Clang 3.4 30 @@ -523,7 +523,7 @@ 81 NAD - Null pointers and C compatibility + Null pointers and C compatability N/A @@ -854,7 +854,7 @@ 136 CD1 Default arguments and friend declarations - SVN + Clang 3.4 137 @@ -992,7 +992,7 @@ 159 TC1 Namespace qualification in declarators - No + SVN 160 @@ -2488,7 +2488,7 @@ of class templates 408 CD2 sizeof applied to unknown-bound array static data member of template - SVN + Clang 3.4 409 @@ -2932,7 +2932,7 @@ of class templates 482 DRWP Qualified declarators in redeclarations - Unknown + SVN 483 @@ -8159,7 +8159,7 @@ and POD class 1391 drafting - Conversions to parameter types with non-deduced template arguments + Conversions to parameter types with non deduced template arguments Not resolved diff --git a/www/make_cxx_dr_status b/www/make_cxx_dr_status index 4750e1b2cb..54f3b7e208 100755 --- a/www/make_cxx_dr_status +++ b/www/make_cxx_dr_status @@ -101,9 +101,12 @@ def availability(issue): if status == 'unknown': avail = 'Unknown' avail_style = ' class="none"' - elif status == '3.4': + elif status == '3.5': avail = 'SVN' avail_style = ' class="svn"' + elif status == '3.4': + avail = 'Clang %s' % status + avail_style = ' class="svn"' elif status in ('3.1', '3.2', '3.3'): avail = 'Clang %s' % status avail_style = ' class="full"'