[C++] [PATCH] - Nested namespace defintions

Andrea Azzarone azzaronea@gmail.com
Thu Feb 12 23:58:00 GMT 2015


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 <azzaronea@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
-------------- next part --------------
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]


More information about the Gcc-patches mailing list