r221574 - [c++1z] Implement nested-namespace-definitions.

Richard Smith richard-llvm at metafoo.co.uk
Fri Nov 7 21:37:35 PST 2014


Author: rsmith
Date: Fri Nov  7 23:37:34 2014
New Revision: 221574

URL: http://llvm.org/viewvc/llvm-project?rev=221574&view=rev
Log:
[c++1z] Implement nested-namespace-definitions.

This allows 'namespace A::B { ... }' as a shorthand for 'namespace A {
namespace B { ... } }'. We already supported this correctly for error recovery;
promote that support to a full implementation.

This is not the right implementation: we do not maintain source fidelity
because we desugar the nested namespace definition in the parser. This is
tricky to avoid, since the definition genuinely does inject one named
entity per level in the namespace name.

Added:
    cfe/trunk/test/Parser/cxx1z-nested-namespace-definition.cpp
      - copied, changed from r221540, cfe/trunk/test/Parser/nested-namespaces-recovery.cpp
Removed:
    cfe/trunk/test/Parser/nested-namespaces-recovery.cpp
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
    cfe/trunk/lib/Parse/ParseDeclCXX.cpp
    cfe/trunk/test/CXX/drs/dr3xx.cpp
    cfe/trunk/www/cxx_status.html

Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=221574&r1=221573&r2=221574&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Fri Nov  7 23:37:34 2014
@@ -200,8 +200,14 @@ def err_unexpected_namespace_attributes_
 def err_inline_namespace_alias : Error<"namespace alias cannot be inline">;
 def err_namespace_nonnamespace_scope : Error<
   "namespaces can only be defined in global or namespace scope">;
-def err_nested_namespaces_with_double_colon : Error<
-  "nested namespace definition must define each namespace separately">;
+def ext_nested_namespace_definition : ExtWarn<
+  "nested namespace definition is a C++1z extension; "
+  "define each namespace separately">, InGroup<CXX1z>;
+def warn_cxx14_compat_nested_namespace_definition : Warning<
+  "nested namespace definition is incompatible with C++ standards before C++1z">,
+  InGroup<CXXPre1zCompat>, DefaultIgnore;
+def err_inline_nested_namespace_definition : Error<
+  "nested namespace definition cannot be 'inline'">;
 def err_expected_semi_after_attribute_list : Error<
   "expected ';' after attribute list">;
 def err_expected_semi_after_static_assert : Error<

Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=221574&r1=221573&r2=221574&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Fri Nov  7 23:37:34 2014
@@ -110,39 +110,36 @@ Decl *Parser::ParseNamespace(unsigned Co
 
   BalancedDelimiterTracker T(*this, tok::l_brace);
   if (T.consumeOpen()) {
-    if (!ExtraIdent.empty()) {
-      Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon)
-          << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back());
-    }
-
     if (Ident)
       Diag(Tok, diag::err_expected) << tok::l_brace;
     else
       Diag(Tok, diag::err_expected_either) << tok::identifier << tok::l_brace;
-
     return nullptr;
   }
 
   if (getCurScope()->isClassScope() || getCurScope()->isTemplateParamScope() || 
       getCurScope()->isInObjcMethodScope() || getCurScope()->getBlockParent() || 
       getCurScope()->getFnParent()) {
-    if (!ExtraIdent.empty()) {
-      Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon)
-          << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back());
-    }
     Diag(T.getOpenLocation(), diag::err_namespace_nonnamespace_scope);
     SkipUntil(tok::r_brace);
     return nullptr;
   }
 
-  if (!ExtraIdent.empty()) {
+  if (ExtraIdent.empty()) {
+    // Normal namespace definition, not a nested-namespace-definition.
+  } else if (InlineLoc.isValid()) {
+    Diag(InlineLoc, diag::err_inline_nested_namespace_definition);
+  } else if (getLangOpts().CPlusPlus1z) {
+    Diag(ExtraNamespaceLoc[0],
+         diag::warn_cxx14_compat_nested_namespace_definition);
+  } else {
     TentativeParsingAction TPA(*this);
     SkipUntil(tok::r_brace, StopBeforeMatch);
     Token rBraceToken = Tok;
     TPA.Revert();
 
     if (!rBraceToken.is(tok::r_brace)) {
-      Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon)
+      Diag(ExtraNamespaceLoc[0], diag::ext_nested_namespace_definition)
           << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back());
     } else {
       std::string NamespaceFix;
@@ -156,7 +153,7 @@ Decl *Parser::ParseNamespace(unsigned Co
       for (unsigned i = 0, e = ExtraIdent.size(); i != e; ++i)
         RBraces +=  "} ";
 
-      Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon)
+      Diag(ExtraNamespaceLoc[0], diag::ext_nested_namespace_definition)
           << FixItHint::CreateReplacement(SourceRange(ExtraNamespaceLoc.front(),
                                                       ExtraIdentLoc.back()),
                                           NamespaceFix)
@@ -195,11 +192,11 @@ Decl *Parser::ParseNamespace(unsigned Co
 }
 
 /// ParseInnerNamespace - Parse the contents of a namespace.
-void Parser::ParseInnerNamespace(std::vector<SourceLocation>& IdentLoc,
-                                 std::vector<IdentifierInfo*>& Ident,
-                                 std::vector<SourceLocation>& NamespaceLoc,
-                                 unsigned int index, SourceLocation& InlineLoc,
-                                 ParsedAttributes& attrs,
+void Parser::ParseInnerNamespace(std::vector<SourceLocation> &IdentLoc,
+                                 std::vector<IdentifierInfo *> &Ident,
+                                 std::vector<SourceLocation> &NamespaceLoc,
+                                 unsigned int index, SourceLocation &InlineLoc,
+                                 ParsedAttributes &attrs,
                                  BalancedDelimiterTracker &Tracker) {
   if (index == Ident.size()) {
     while (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
@@ -216,7 +213,9 @@ void Parser::ParseInnerNamespace(std::ve
     return;
   }
 
-  // Parse improperly nested namespaces.
+  // Handle a nested namespace definition.
+  // FIXME: Preserve the source information through to the AST rather than
+  // desugaring it here.
   ParseScope NamespaceScope(this, Scope::DeclScope);
   Decl *NamespcDecl =
     Actions.ActOnStartNamespaceDef(getCurScope(), SourceLocation(),

Modified: cfe/trunk/test/CXX/drs/dr3xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr3xx.cpp?rev=221574&r1=221573&r2=221574&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr3xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr3xx.cpp Fri Nov  7 23:37:34 2014
@@ -182,9 +182,15 @@ namespace dr308 { // dr308: yes
 
 namespace dr311 { // dr311: yes
   namespace X { namespace Y {} }
-  namespace X::Y {} // expected-error {{must define each namespace separately}}
+  namespace X::Y {}
+#if __cplusplus <= 201402L
+  // expected-error at -2 {{define each namespace separately}}
+#endif
   namespace X {
-    namespace X::Y {} // expected-error {{must define each namespace separately}}
+    namespace X::Y {}
+#if __cplusplus <= 201402L
+  // expected-error at -2 {{define each namespace separately}}
+#endif
   }
   // FIXME: The diagnostics here are not very good.
   namespace ::dr311::X {} // expected-error 2+{{}} // expected-warning {{extra qual}}

Copied: cfe/trunk/test/Parser/cxx1z-nested-namespace-definition.cpp (from r221540, cfe/trunk/test/Parser/nested-namespaces-recovery.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx1z-nested-namespace-definition.cpp?p2=cfe/trunk/test/Parser/cxx1z-nested-namespace-definition.cpp&p1=cfe/trunk/test/Parser/nested-namespaces-recovery.cpp&r1=221540&r2=221574&rev=221574&view=diff
==============================================================================
--- cfe/trunk/test/Parser/nested-namespaces-recovery.cpp (original)
+++ cfe/trunk/test/Parser/cxx1z-nested-namespace-definition.cpp Fri Nov  7 23:37:34 2014
@@ -1,12 +1,26 @@
 // RUN: cp %s %t
 // RUN: %clang_cc1 -fsyntax-only -verify %s
-// RUN: not %clang_cc1 -x c++ -fixit %t
-// RUN: %clang_cc1 -x c++ %t
+// RUN: not %clang_cc1 -x c++ -fixit %t -Werror -DFIXIT
+// RUN: %clang_cc1 -x c++ %t -DFIXIT
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1z -Wc++14-compat
 
-namespace foo1::foo2::foo3 { // expected-error {{nested namespace definition must define each namespace separately}}
+namespace foo1::foo2::foo3 {
+#if __cplusplus <= 201400L
+// expected-warning at -2 {{nested namespace definition is a C++1z extension; define each namespace separately}}
+#else
+// expected-warning at -4 {{nested namespace definition is incompatible with C++ standards before C++1z}}
+#endif
   int foo(int x) { return x; }
 }
 
+#ifndef FIXIT
+inline namespace goo::bar { // expected-error {{nested namespace definition cannot be 'inline'}} expected-warning 0-1{{C++11 feature}}
+  int n;
+}
+
+int m = goo::bar::n;
+#endif
+
 int foo(int x) {
   return foo1::foo2::foo3::foo(x);
 }

Removed: cfe/trunk/test/Parser/nested-namespaces-recovery.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/nested-namespaces-recovery.cpp?rev=221573&view=auto
==============================================================================
--- cfe/trunk/test/Parser/nested-namespaces-recovery.cpp (original)
+++ cfe/trunk/test/Parser/nested-namespaces-recovery.cpp (removed)
@@ -1,24 +0,0 @@
-// RUN: cp %s %t
-// RUN: %clang_cc1 -fsyntax-only -verify %s
-// RUN: not %clang_cc1 -x c++ -fixit %t
-// RUN: %clang_cc1 -x c++ %t
-
-namespace foo1::foo2::foo3 { // expected-error {{nested namespace definition must define each namespace separately}}
-  int foo(int x) { return x; }
-}
-
-int foo(int x) {
-  return foo1::foo2::foo3::foo(x);
-}
-
-namespace bar1 {
-  namespace bar2 {
-    namespace bar3 {
-      int bar(int x) { return x; }
-    }
-  }
-}
-
-int bar(int x) {
-  return bar1::bar2::bar3::bar(x);
-}

Modified: cfe/trunk/www/cxx_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=221574&r1=221573&r2=221574&view=diff
==============================================================================
--- cfe/trunk/www/cxx_status.html (original)
+++ cfe/trunk/www/cxx_status.html Fri Nov  7 23:37:34 2014
@@ -552,6 +552,11 @@ as the draft C++1z standard evolves.</p>
       <td><!--<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4051.html">-->N4295<!--</a>--></td>
       <td class="svn" align="center">SVN</td>
     </tr>
+    <tr>
+      <td>Nested namespace definition</td>
+      <td><!--<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4051.html">-->N4230<!--</a>--></td>
+      <td class="svn" align="center">SVN</td>
+    </tr>
 </table>
 
 <h2 id="ts">Technical specifications and standing documents</h2>





More information about the cfe-commits mailing list