]> granicus.if.org Git - clang/commitdiff
[c++1z] Implement nested-namespace-definitions.
authorRichard Smith <richard-llvm@metafoo.co.uk>
Sat, 8 Nov 2014 05:37:34 +0000 (05:37 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Sat, 8 Nov 2014 05:37:34 +0000 (05:37 +0000)
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.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@221574 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticParseKinds.td
lib/Parse/ParseDeclCXX.cpp
test/CXX/drs/dr3xx.cpp
test/Parser/cxx1z-nested-namespace-definition.cpp [new file with mode: 0644]
test/Parser/nested-namespaces-recovery.cpp [deleted file]
www/cxx_status.html

index 7c9ee21d0c21f900323a8e3a282fa5e86f226079..e9efc45fff2b0b347fd7dd724be95b57b4fd5d06 100644 (file)
@@ -200,8 +200,14 @@ def err_unexpected_namespace_attributes_alias : Error<
 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<
index e5cf84a74f97d03345be2c0ce1c1f0b2dee1dc8b..223046c90d92850d2585d0fd7b0ecae86c2f1c66 100644 (file)
@@ -110,39 +110,36 @@ Decl *Parser::ParseNamespace(unsigned Context,
 
   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 Context,
       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 Context,
 }
 
 /// 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, SourceLocationInlineLoc,
-                                 ParsedAttributesattrs,
+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::vector<SourceLocation>& IdentLoc,
     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(),
index 8b8bcf1ad98978f9f04d581b0301ffb231921a3d..59deacae3a67806dabb31c1787338bf6dab7a840 100644 (file)
@@ -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@-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@-2 {{define each namespace separately}}
+#endif
   }
   // FIXME: The diagnostics here are not very good.
   namespace ::dr311::X {} // expected-error 2+{{}} // expected-warning {{extra qual}}
diff --git a/test/Parser/cxx1z-nested-namespace-definition.cpp b/test/Parser/cxx1z-nested-namespace-definition.cpp
new file mode 100644 (file)
index 0000000..96f34c5
--- /dev/null
@@ -0,0 +1,38 @@
+// RUN: cp %s %t
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// 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 {
+#if __cplusplus <= 201400L
+// expected-warning@-2 {{nested namespace definition is a C++1z extension; define each namespace separately}}
+#else
+// expected-warning@-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);
+}
+
+namespace bar1 {
+  namespace bar2 {
+    namespace bar3 {
+      int bar(int x) { return x; }
+    }
+  }
+}
+
+int bar(int x) {
+  return bar1::bar2::bar3::bar(x);
+}
diff --git a/test/Parser/nested-namespaces-recovery.cpp b/test/Parser/nested-namespaces-recovery.cpp
deleted file mode 100644 (file)
index d45938b..0000000
+++ /dev/null
@@ -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);
-}
index 565349ab029efbd105d3b0d17e5a50f636a320c6..20617147f5275d8137747e0a1ecc9ac8b7cc2453 100644 (file)
@@ -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>