re PR c++/79369 (namespace definition with qualified id)
authorNathan Sidwell <nathan@gcc.gnu.org>
Mon, 15 May 2017 19:35:52 +0000 (19:35 +0000)
committerNathan Sidwell <nathan@gcc.gnu.org>
Mon, 15 May 2017 19:35:52 +0000 (19:35 +0000)
gcc/cp/
PR c++/79369
* cp-tree.h (DECL_NAMESPACE_INLINE_P): New.
* name-lookup.h (push_namespace): Return int, add make_inline arg.
* name-lookup.c (push_namespace): Deal with inline directly.
Return pushed count.
* parser.c (cp_parser_namespace_definition): Adjust for
push_namespace change.

gcc/testsuite/
* g++.dg/cpp0x/pr65558.C: Adjust diagnostic location.
* g++.dg/cpp0x/pr79369.C: New.

From-SVN: r248073

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/name-lookup.c
gcc/cp/name-lookup.h
gcc/cp/parser.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/pr65558.C
gcc/testsuite/g++.dg/cpp0x/pr79369.C [new file with mode: 0644]

index 94ad0442d2d78d65a73ba35a418a46d0e7fa4c2a..fe99fa779ec1578e66205b3162cf83889c2dbec6 100644 (file)
@@ -1,3 +1,13 @@
+2017-05-15  Nathan Sidwell  <nathan@acm.org>
+
+       PR c++/79369
+       * cp-tree.h (DECL_NAMESPACE_INLINE_P): New.
+       * name-lookup.h (push_namespace): Return int, add make_inline arg.
+       * name-lookup.c (push_namespace): Deal with inline directly.
+       Return pushed count.
+       * parser.c (cp_parser_namespace_definition): Adjust for
+       push_namespace change.
+
 2017-05-11  Nathan Sidwell  <nathan@acm.org>
 
        * cp-lang.c (get_global_decls, cxx_pushdecl, LANG_HOOK_GETDECLS,
index 9596886226f15a0973fb15138932a4aceda37f9e..85cdf07cb91905263197cbc1897cb4e4a549119f 100644 (file)
@@ -333,6 +333,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
       FOLD_EXPR_MODOP_P (*_FOLD_EXPR)
       IF_STMT_CONSTEXPR_P (IF_STMT)
       TEMPLATE_TYPE_PARM_FOR_CLASS (TEMPLATE_TYPE_PARM)
+      DECL_NAMESPACE_INLINE_P (in NAMESPACE_DECL)
    1: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE)
       TI_PENDING_TEMPLATE_FLAG.
       TEMPLATE_PARMS_FOR_INLINE.
@@ -2916,6 +2917,10 @@ struct GTY(()) lang_decl {
 #define LOCAL_CLASS_P(NODE)                            \
   (decl_function_context (TYPE_MAIN_DECL (NODE)) != NULL_TREE)
 
+/* Whether the namepace is an inline namespace.  */
+#define DECL_NAMESPACE_INLINE_P(NODE) \
+  TREE_LANG_FLAG_0 (NAMESPACE_DECL_CHECK (NODE))
+
 /* For a NAMESPACE_DECL: the list of using namespace directives
    The PURPOSE is the used namespace, the value is the namespace
    that is the common ancestor.  */
index 885ced5a75a1b945130db19c522e765e63e2a2df..375376a89a8d1c47ec6e1817d9d8d8573c3d4286 100644 (file)
@@ -6441,107 +6441,112 @@ pop_from_top_level (void)
   timevar_cond_stop (TV_NAME_LOOKUP, subtime);
 }
 
-/* Push into the scope of the NAME namespace.  If NAME is NULL_TREE, then we
-   select a name that is unique to this compilation unit.  Returns FALSE if
-   pushdecl fails, TRUE otherwise.  */
+/* Push into the scope of the NAME namespace.  If NAME is NULL_TREE,
+   then we enter an anonymous namespace.  If MAKE_INLINE is true, then
+   we create an inline namespace (it is up to the caller to check upon
+   redefinition). Return the number of namespaces entered.  */
 
-bool
-push_namespace (tree name)
+int
+push_namespace (tree name, bool make_inline)
 {
-  tree d = NULL_TREE;
-  bool need_new = true;
-  bool implicit_use = false;
-  bool anon = !name;
-
   bool subtime = timevar_cond_start (TV_NAME_LOOKUP);
+  int count = 0;
 
   /* We should not get here if the global_namespace is not yet constructed
      nor if NAME designates the global namespace:  The global scope is
      constructed elsewhere.  */
   gcc_assert (global_namespace != NULL && name != global_identifier);
 
-  if (anon)
-    {
-      name = anon_identifier;
-      d = get_namespace_binding (current_namespace, name);
-      if (d)
-       /* Reopening anonymous namespace.  */
-       need_new = false;
-      implicit_use = true;
-    }
-  else
+  if (!name)
+    name = anon_identifier;
+
+  /* Check whether this is an extended namespace definition.  */
+  tree ns = get_namespace_binding (current_namespace, name);
+  if (ns && TREE_CODE (ns) == NAMESPACE_DECL)
     {
-      /* Check whether this is an extended namespace definition.  */
-      d = get_namespace_binding (current_namespace, name);
-      if (d != NULL_TREE && TREE_CODE (d) == NAMESPACE_DECL)
+      if (tree dna = DECL_NAMESPACE_ALIAS (ns))
        {
-         tree dna = DECL_NAMESPACE_ALIAS (d);
-         if (dna)
-           {
-             /* We do some error recovery for, eg, the redeclaration
-                of M here:
-
-                namespace N {}
-                namespace M = N;
-                namespace M {}
-
-                However, in nasty cases like:
-
-                namespace N
-                {
-                  namespace M = N;
-                  namespace M {}
-                }
-
-                we just error out below, in duplicate_decls.  */
-             if (NAMESPACE_LEVEL (dna)->level_chain
-                 == current_binding_level)
-               {
-                 error ("namespace alias %qD not allowed here, "
-                        "assuming %qD", d, dna);
-                 d = dna;
-                 need_new = false;
-               }
+         /* We do some error recovery for, eg, the redeclaration of M
+            here:
+
+            namespace N {}
+            namespace M = N;
+            namespace M {}
+
+            However, in nasty cases like:
+
+            namespace N
+            {
+              namespace M = N;
+              namespace M {}
+            }
+
+            we just error out below, in duplicate_decls.  */
+         if (NAMESPACE_LEVEL (dna)->level_chain == current_binding_level)
+           {
+             error ("namespace alias %qD not allowed here, "
+                    "assuming %qD", ns, dna);
+             ns = dna;
            }
          else
-           need_new = false;
+           ns = NULL_TREE;
        }
     }
+  else
+    ns = NULL_TREE;
 
-  if (need_new)
+  bool new_ns = false;
+  if (!ns)
     {
-      /* Make a new namespace, binding the name to it.  */
-      d = build_lang_decl (NAMESPACE_DECL, name, void_type_node);
-      DECL_CONTEXT (d) = FROB_CONTEXT (current_namespace);
-      /* The name of this namespace is not visible to other translation
-        units if it is an anonymous namespace or member thereof.  */
-      if (anon || decl_anon_ns_mem_p (current_namespace))
-       TREE_PUBLIC (d) = 0;
+      ns = build_lang_decl (NAMESPACE_DECL, name, void_type_node);
+      DECL_CONTEXT (ns) = FROB_CONTEXT (current_namespace);
+      new_ns = true;
+
+      if (pushdecl (ns) == error_mark_node)
+       ns = NULL_TREE;
       else
-       TREE_PUBLIC (d) = 1;
-      if (pushdecl (d) == error_mark_node)
        {
-         timevar_cond_stop (TV_NAME_LOOKUP, subtime);
-         return false;
+         if (name == anon_identifier)
+           {
+             /* Clear DECL_NAME for the benefit of debugging back ends.  */
+             SET_DECL_ASSEMBLER_NAME (ns, name);
+             DECL_NAME (ns) = NULL_TREE;
+
+             if (!make_inline)
+               do_using_directive (ns);
+           }
+         else if (TREE_PUBLIC (current_namespace))
+           TREE_PUBLIC (ns) = 1;
+
+         if (make_inline)
+           {
+             DECL_NAMESPACE_INLINE_P (ns) = true;
+             /* Set up namespace association.  */
+             DECL_NAMESPACE_ASSOCIATIONS (ns)
+               = tree_cons (current_namespace, NULL_TREE, NULL_TREE);
+             /* Import the contents of the inline namespace.  */
+             do_using_directive (ns);
+           }
        }
-      if (anon)
+    }
+
+  if (ns)
+    {
+      if (make_inline && !DECL_NAMESPACE_INLINE_P (ns))
        {
-         /* Clear DECL_NAME for the benefit of debugging back ends.  */
-         SET_DECL_ASSEMBLER_NAME (d, name);
-         DECL_NAME (d) = NULL_TREE;
+         error ("inline namespace must be specified at initial definition");
+         inform (DECL_SOURCE_LOCATION (ns), "%qD defined here", ns);
        }
-      begin_scope (sk_namespace, d);
+      if (new_ns)
+       begin_scope (sk_namespace, ns);
+      else
+       resume_scope (NAMESPACE_LEVEL (ns));
+      current_namespace = ns;
+      count++;
     }
-  else
-    resume_scope (NAMESPACE_LEVEL (d));
-
-  if (implicit_use)
-    do_using_directive (d);
-  /* Enter the name space.  */
-  current_namespace = d;
 
   timevar_cond_stop (TV_NAME_LOOKUP, subtime);
-  return true;
+  return count;
 }
 
 /* Pop from the scope of the current namespace.  */
index 9755884026b8ab6bd70421ef49d936fddd2e6088..824ea3386a70eda0a66749e9a87a78ac07a0323f 100644 (file)
@@ -340,7 +340,7 @@ extern tree pushdecl (tree, bool is_friend = false);
 extern tree pushdecl_top_level (tree, bool is_friend = false);
 extern tree pushdecl_top_level_and_finish (tree, tree);
 extern tree pushtag (tree, tree, tag_scope);
-extern bool push_namespace (tree);
+extern int push_namespace (tree, bool make_inline = false);
 extern void pop_namespace (void);
 extern void push_nested_namespace (tree);
 extern void pop_nested_namespace (tree);
index f82a90c43d2f58127507e69022d4662c8c667a1d..99c742f72e9586b195dfe9c381b8db8a277789f6 100644 (file)
@@ -18172,114 +18172,88 @@ cp_parser_namespace_name (cp_parser* parser)
 static void
 cp_parser_namespace_definition (cp_parser* parser)
 {
-  tree identifier, attribs;
-  bool has_visibility;
-  bool is_inline;
-  cp_token* token;
+  tree identifier;
   int nested_definition_count = 0;
 
   cp_ensure_no_omp_declare_simd (parser);
   cp_ensure_no_oacc_routine (parser);
-  if (cp_lexer_next_token_is_keyword (parser->lexer, RID_INLINE))
+
+  bool is_inline = cp_lexer_next_token_is_keyword (parser->lexer, RID_INLINE);
+
+  if (is_inline)
     {
       maybe_warn_cpp0x (CPP0X_INLINE_NAMESPACES);
-      is_inline = true;
       cp_lexer_consume_token (parser->lexer);
     }
-  else
-    is_inline = false;
 
   /* Look for the `namespace' keyword.  */
-  token = cp_parser_require_keyword (parser, RID_NAMESPACE, RT_NAMESPACE);
+  cp_token* token
+    = cp_parser_require_keyword (parser, RID_NAMESPACE, RT_NAMESPACE);
 
   /* Parse any specified attributes before the identifier.  */
-  attribs = cp_parser_attributes_opt (parser);
+  tree attribs = cp_parser_attributes_opt (parser);
 
-  /* Get the name of the namespace.  We do not attempt to distinguish
-     between an original-namespace-definition and an
-     extension-namespace-definition at this point.  The semantic
-     analysis routines are responsible for that.  */
-  if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
-    identifier = cp_parser_identifier (parser);
-  else
-    identifier = NULL_TREE;
-
-  /* Parse any specified attributes after the identifier.  */
-  tree post_ident_attribs = cp_parser_attributes_opt (parser);
-  if (post_ident_attribs)
+  for (;;)
     {
-      if (attribs)
-        attribs = chainon (attribs, post_ident_attribs);
-      else
-        attribs = post_ident_attribs;
-    }
+      identifier = NULL_TREE;
+      
+      if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+       {
+         identifier = cp_parser_identifier (parser);
 
-  /* Start the namespace.  */
-  bool ok = push_namespace (identifier);
+         /* Parse any attributes specified after the identifier.  */
+         attribs = chainon (attribs, cp_parser_attributes_opt (parser));
+       }
 
-  /* Parse any nested namespace definition. */
-  if (cp_lexer_next_token_is (parser->lexer, CPP_SCOPE))
-    {
-      if (attribs)
-        error_at (token->location, "a nested namespace definition cannot have attributes");
-      if (cxx_dialect < cxx1z)
+      if (cp_lexer_next_token_is_not (parser->lexer, CPP_SCOPE))
+       break;
+  
+      if (!nested_definition_count && cxx_dialect < cxx1z)
         pedwarn (input_location, OPT_Wpedantic,
                  "nested namespace definitions only available with "
                  "-std=c++1z or -std=gnu++1z");
-      if (is_inline)
-        error_at (token->location, "a nested namespace definition cannot be inline");
-      while (cp_lexer_next_token_is (parser->lexer, CPP_SCOPE))
-        {
-          cp_lexer_consume_token (parser->lexer);
-          if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
-            identifier = cp_parser_identifier (parser);
-          else
-            {
-              cp_parser_error (parser, "nested identifier required");
-              break;
-            }
-         if (push_namespace (identifier))
-           ++nested_definition_count;
-        }
+
+      /* Nested namespace names can create new namespaces (unlike
+        other qualified-ids).  */
+      if (int count = identifier ? push_namespace (identifier) : 0)
+       nested_definition_count += count;
+      else
+       cp_parser_error (parser, "nested namespace name required");
+      cp_lexer_consume_token (parser->lexer);
     }
 
-  /* Look for the `{' to validate starting the namespace.  */
-  cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE);
+  if (nested_definition_count && !identifier)
+    cp_parser_error (parser, "namespace name required");
+  
+  if (nested_definition_count && attribs)
+    error_at (token->location,
+             "a nested namespace definition cannot have attributes");
+  if (nested_definition_count && is_inline)
+    error_at (token->location,
+             "a nested namespace definition cannot be inline");
 
-  /* "inline namespace" is equivalent to a stub namespace definition
-     followed by a strong using directive.  */
-  if (is_inline && ok)
-    {
-      tree name_space = current_namespace;
-      /* Set up namespace association.  */
-      DECL_NAMESPACE_ASSOCIATIONS (name_space)
-       = tree_cons (CP_DECL_CONTEXT (name_space), NULL_TREE,
-                    DECL_NAMESPACE_ASSOCIATIONS (name_space));
-      /* Import the contents of the inline namespace.  */
-      pop_namespace ();
-      do_using_directive (name_space);
-      push_namespace (identifier);
-    }
+  /* Start the namespace.  */
+  nested_definition_count += push_namespace (identifier, is_inline);
 
-  has_visibility = handle_namespace_attrs (current_namespace, attribs);
+  bool has_visibility = handle_namespace_attrs (current_namespace, attribs);
 
   warning  (OPT_Wnamespaces, "namespace %qD entered", current_namespace);
 
+  /* Look for the `{' to validate starting the namespace.  */
+  cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE);
+
   /* Parse the body of the namespace.  */
   cp_parser_namespace_body (parser);
 
+  /* Look for the final `}'.  */
+  cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE);
+
   if (has_visibility)
     pop_visibility (1);
 
-  /* Finish the nested namespace definitions.  */
+  /* Pop the nested namespace definitions.  */
   while (nested_definition_count--)
     pop_namespace ();
-
-  /* Finish the namespace.  */
-  if (ok)
-    pop_namespace ();
-  /* Look for the final `}'.  */
-  cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE);
 }
 
 /* Parse a namespace-body.
index 0082e857f37272ed79c7117b92d06a30f0168baf..65fe9e336bd952256a0e53ecefdc08ad690e7c7c 100644 (file)
@@ -1,7 +1,13 @@
+2017-05-15  Nathan Sidwell  <nathan@acm.org>
+
+       PR c++/79369
+       * g++.dg/cpp0x/pr65558.C: Adjust diagnostic location.
+       * g++.dg/cpp0x/pr79369.C: New.
+
 2017-05-15  Steven G. Kargl  <kargl@gcc.gnu.org>
 
        PR fortran/80752
-       gfortran.dg/pr80752.f90: New test.
+       gfortran.dg/pr80752.f90: New test.
 
 2017-05-15  Uros Bizjak  <ubizjak@gmail.com>
 
index 5437e509ed96e813dded99883232d478b0f8d32a..d294c95a657ecb7146065cd4b3130c5d7c4c732e 100644 (file)
@@ -1,6 +1,7 @@
 // PR c++/65558
 // { dg-do compile { target c++11 } }
 
-inline namespace __attribute__((__abi_tag__))
-{ // { dg-warning "ignoring .__abi_tag__. attribute on anonymous namespace" }
+inline namespace
+__attribute__((__abi_tag__)) // { dg-warning "ignoring .__abi_tag__. attribute on anonymous namespace" }
+{
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr79369.C b/gcc/testsuite/g++.dg/cpp0x/pr79369.C
new file mode 100644 (file)
index 0000000..58116f2
--- /dev/null
@@ -0,0 +1,9 @@
+// { dg-do compile { target c++11 } }
+// PR c++/79369 accept late inline of namespace
+
+namespace X {}
+inline namespace X {} // { dg-error "must be specified" }
+
+inline namespace Y {}
+namespace Y {} // OK
+inline namespace Y {} // also Ok