Hi all,

would be nice to have nested namespace definitions in gcc. I'm not
sure if this if it's possible to merge stuff like this at this stage.

2015-2-13 Andrea Azzarone <azzaro...@gmail.com>
  PR c++/65047

  * gcc/cp/cp-tree.h Declare maybe_warn_cpp1z.
  * gcc/cp/error.c Define maybe_warn_cpp1z.
  * gcc/cp/parser.c (cp_parser_namespace_definition) Add support for
nested namespace definitions.

I did a full boostrap + full make check.

Thanks.

-- 
Andrea Azzarone
Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h    (revision 220454)
+++ gcc/cp/cp-tree.h    (working copy)
@@ -467,6 +467,13 @@ typedef enum cpp0x_warn_str
   CPP0X_REF_QUALIFIER
 } cpp0x_warn_str;
 
+/* The various kinds of C++1z warnings we ecounter. */
+typedef enum cpp1z_warn_str
+{
+  /* nested namespace definitions. */
+  CPP1Z_NESTED_NAMESPACE_DEFINITIONS
+} cpp1z_warn_str;
+
 /* The various kinds of operation used by composite_pointer_type. */
 
 typedef enum composite_pointer_operation
@@ -5518,6 +5525,7 @@ extern const char *language_to_string             (
 extern const char *class_key_or_enum_as_string (tree);
 extern void maybe_warn_variadic_templates       (void);
 extern void maybe_warn_cpp0x                   (cpp0x_warn_str str);
+extern void maybe_warn_cpp1z                   (cpp1z_warn_str str);
 extern bool pedwarn_cxx98                       (location_t, int, const char 
*, ...) ATTRIBUTE_GCC_DIAG(3,4);
 extern location_t location_of                   (tree);
 extern void qualified_name_lookup_error                (tree, tree, tree,
Index: gcc/cp/error.c
===================================================================
--- gcc/cp/error.c      (revision 220454)
+++ gcc/cp/error.c      (working copy)
@@ -3611,6 +3611,24 @@ maybe_warn_cpp0x (cpp0x_warn_str str)
       }
 }
 
+void
+maybe_warn_cpp1z (cpp1z_warn_str str)
+{
+  if (cxx_dialect >= cxx1z)
+    return;
+
+  switch (str)
+    {
+    case CPP1Z_NESTED_NAMESPACE_DEFINITIONS:
+      pedwarn (input_location, 0,
+              "nested namespace definitions "
+              "only available with -std=c++1z or -std=gnu=c++1z");
+      break;
+    default:
+      gcc_unreachable ();
+    }
+}
+
 /* Warn about the use of variadic templates when appropriate.  */
 void
 maybe_warn_variadic_templates (void)
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c     (revision 220454)
+++ gcc/cp/parser.c     (working copy)
@@ -16169,6 +16169,7 @@ cp_parser_namespace_name (cp_parser* par
    namespace-definition:
      named-namespace-definition
      unnamed-namespace-definition
+     nested-namespace-definition
 
    named-namespace-definition:
      original-namespace-definition
@@ -16181,24 +16182,32 @@ cp_parser_namespace_name (cp_parser* par
      namespace original-namespace-name { namespace-body }
 
    unnamed-namespace-definition:
-     namespace { namespace-body } */
+     namespace { namespace-body }
+
+   nested-namespace-definition:
+     namespace enclosing-namespace-specifier :: identifier { namespace-body } 
+
+   enclosing-namespace-specifier:
+     identifier
+     enclosing-namespace-specifier :: identifier */
 
 static void
 cp_parser_namespace_definition (cp_parser* parser)
 {
+  vec<tree, va_heap> extra_identifiers;
   tree identifier, attribs;
   bool has_visibility;
-  bool is_inline;
+  location_t inline_location;
+  unsigned ns_deepness;
 
   cp_ensure_no_omp_declare_simd (parser);
   if (cp_lexer_next_token_is_keyword (parser->lexer, RID_INLINE))
     {
       maybe_warn_cpp0x (CPP0X_INLINE_NAMESPACES);
-      is_inline = true;
-      cp_lexer_consume_token (parser->lexer);
+      inline_location = cp_lexer_consume_token (parser->lexer)->location;
     }
   else
-    is_inline = false;
+    inline_location = UNKNOWN_LOCATION;
 
   /* Look for the `namespace' keyword.  */
   cp_parser_require_keyword (parser, RID_NAMESPACE, RT_NAMESPACE);
@@ -16207,22 +16216,64 @@ cp_parser_namespace_definition (cp_parse
      between an original-namespace-definition and an
      extension-namespace-definition at this point.  The semantic
      analysis routines are responsible for that.  */
+  extra_identifiers.create(0);
   if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
-    identifier = cp_parser_identifier (parser);
+    {
+      /* named-namespace-definition. */
+      identifier = cp_parser_identifier (parser);
+
+      while (cp_lexer_next_token_is (parser->lexer, CPP_SCOPE)
+            && cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_NAME)
+       {
+         /* nested-namespace-definition */
+         cp_lexer_consume_token (parser->lexer);
+         extra_identifiers.safe_insert (0, cp_parser_identifier (parser));
+       }
+    }
   else
-    identifier = NULL_TREE;
+    {
+       /* unnamed-namespace-definition. */
+       identifier = NULL_TREE;
+    }
+
+  if (!extra_identifiers.is_empty ())
+    maybe_warn_cpp1z (CPP1Z_NESTED_NAMESPACE_DEFINITIONS);
+
+  /* Nested namespace definitions cannot be inline. */
+  if (inline_location && !extra_identifiers.is_empty ())
+    {
+      error_at (inline_location, "nested namespace definition cannot be 
%<inline%>");
+      extra_identifiers.release ();
+      cp_parser_skip_to_end_of_block_or_statement (parser);
+      return;
+    }
 
   /* Parse any specified attributes.  */
   attribs = cp_parser_attributes_opt (parser);
 
+  /* Attributes cannot be specified on a nested namespace definition. */
+  if (attribs && !extra_identifiers.is_empty ())
+    {
+      error_at (location_of (attribs), "attributes cannot be specified on a 
nested namespace definition");
+      extra_identifiers.release ();
+      cp_parser_skip_to_end_of_block_or_statement (parser);
+      return;
+    }
+
   /* Look for the `{' to start the namespace.  */
-  cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE);
+  if (!cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE))
+    {
+      cp_parser_skip_to_end_of_block_or_statement (parser);
+      extra_identifiers.release ();
+      return;
+    }
+
   /* Start the namespace.  */
   push_namespace (identifier);
 
   /* "inline namespace" is equivalent to a stub namespace definition
      followed by a strong using directive.  */
-  if (is_inline)
+  if (inline_location)
     {
       tree name_space = current_namespace;
       /* Set up namespace association.  */
@@ -16237,6 +16288,10 @@ cp_parser_namespace_definition (cp_parse
 
   has_visibility = handle_namespace_attrs (current_namespace, attribs);
 
+  ns_deepness = extra_identifiers.length () + 1;
+  while (extra_identifiers.length ())
+    push_namespace (extra_identifiers.pop ());
+
   /* Parse the body of the namespace.  */
   cp_parser_namespace_body (parser);
 
@@ -16244,9 +16299,12 @@ cp_parser_namespace_definition (cp_parse
     pop_visibility (1);
 
   /* Finish the namespace.  */
-  pop_namespace ();
+  while (ns_deepness--)
+    pop_namespace ();
+
   /* Look for the final `}'.  */
   cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE);
+  extra_identifiers.release ();
 }
 
 /* Parse a namespace-body.
Index: gcc/testsuite/g++.dg/cpp1z/nested-namespace-definition1.C
===================================================================
--- gcc/testsuite/g++.dg/cpp1z/nested-namespace-definition1.C   (revision 0)
+++ gcc/testsuite/g++.dg/cpp1z/nested-namespace-definition1.C   (working copy)
@@ -0,0 +1,13 @@
+// { dg-do run }
+// { dg-options "-fpermissive" }
+
+#include <cassert>
+
+namespace A::B::C { // { dg-warning "nested namespace definitions only 
available with" "" { target { ! c++1z } } }
+  int var;
+}
+
+int main () {
+  A::B::C::var = 10;
+  assert (A::B::C::var == 10);
+}
Index: gcc/testsuite/g++.dg/cpp1z/nested-namespace-definition2.C
===================================================================
--- gcc/testsuite/g++.dg/cpp1z/nested-namespace-definition2.C   (revision 0)
+++ gcc/testsuite/g++.dg/cpp1z/nested-namespace-definition2.C   (working copy)
@@ -0,0 +1,11 @@
+// { dg-do compile }
+// { dg-options "-fpermissive" }
+// { dg-prune-output "nested namespace definitions only available with" }
+
+inline namespace A::B::C { // { dg-error "nested namespace definition cannot 
be | inline" }
+  int var;
+}
+
+int main () {
+  A::B::C::var = 10; // { dg-error "has not been declared" }
+}
Index: gcc/testsuite/g++.dg/cpp1z/nested-namespace-definition3.C
===================================================================
--- gcc/testsuite/g++.dg/cpp1z/nested-namespace-definition3.C   (revision 0)
+++ gcc/testsuite/g++.dg/cpp1z/nested-namespace-definition3.C   (working copy)
@@ -0,0 +1,11 @@
+// { dg-do compile }
+// { dg-options "-fpermissive" }
+// { dg-prune-output "nested namespace definitions only available with" }
+
+namespace A::B::C __attribute__((visibility("hidden"))) { // { dg-error 
"attributes cannot be specified on a nested namespace definition" }
+  int var;
+}
+
+int main () {
+  A::B::C::var = 10; // { dg-error "has not been declared" }
+}
Index: gcc/testsuite/g++.dg/cpp1z/nested-namespace-definition4.C
===================================================================
--- gcc/testsuite/g++.dg/cpp1z/nested-namespace-definition4.C   (revision 0)
+++ gcc/testsuite/g++.dg/cpp1z/nested-namespace-definition4.C   (working copy)
@@ -0,0 +1,16 @@
+// { dg-do compile }
+// { dg-options "-fpermissive" }
+// { dg-prune-output "nested namespace definitions only available with" }
+
+namespace A:B { // { dg-error "expected '\{' before ':' token" }
+  int var1;
+}
+
+namespace A::B:C { // { dg-error "expected '\{' before ':' token" }
+  int var2;
+}
+
+int main () {
+  A::B::var1 = 0; // { dg-error "has not been declared" }
+  A::B::C::var2 = 0; // { dg-error "has not been declared" }
+}
Index: gcc/testsuite/lib/g++-dg.exp
===================================================================
--- gcc/testsuite/lib/g++-dg.exp        (revision 220454)
+++ gcc/testsuite/lib/g++-dg.exp        (working copy)
@@ -43,9 +43,9 @@ proc g++-dg-runtest { testcases flags de
        # if there's a dg-options line.
        if ![search_for $test "-std=*++"] {
            if [search_for $test "dg-options"] {
-               set option_list { -std=gnu++98 -std=gnu++11 -std=gnu++14 }
+               set option_list { -std=gnu++98 -std=gnu++11 -std=gnu++14 
-std=gnu++17}
            } else {
-               set option_list { -std=c++98 -std=c++11 -std=c++14 }
+               set option_list { -std=c++98 -std=c++11 -std=c++14 -std=c++17}
            }
        } else {
            set option_list { "" }
Index: gcc/testsuite/lib/target-supports.exp
===================================================================
--- gcc/testsuite/lib/target-supports.exp       (revision 220454)
+++ gcc/testsuite/lib/target-supports.exp       (working copy)
@@ -5827,7 +5827,7 @@ proc check_effective_target_c++ { } {
 }
 
 # Check whether the current active language standard supports the features
-# of C++11/C++14 by checking for the presence of one of the -std
+# of C++11/C++14/C++17 by checking for the presence of one of the -std
 # flags.  This assumes that the default for the compiler is C++98, and that
 # there will never be multiple -std= arguments on the command line.
 proc check_effective_target_c++11_only { } {
@@ -5880,7 +5880,7 @@ proc check_effective_target_c++1z_only {
     if ![check_effective_target_c++] {
        return 0
     }
-    return [check-flags { { } { } { -std=c++1z -std=gnu++1z } }]
+    return [check-flags { { } { } { -std=c++1z -std=gnu++1z -std=c++17 
-std=gnu++17} }]
 }
 proc check_effective_target_c++1z { } {
     return [check_effective_target_c++1z_only]

Reply via email to