Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

-- >8 --
Now that r17-4860, r17-4232, and r17-4789 are all in, I can finally
fix the PR that prompted all of the above.

The problem here is that we are not detecting any of:

[namespace.udir]/1: The splice-specifier (if any) shall designate
a namespace that is not the global namespace.  The nested-name-specifier,
namespace-name, and splice-specifier shall not be dependent.

Do so, then.  And likewise for [namespace.alias]/2.  Moreover,

  using namespace [: ^^:: :]::N;

should work but currently doesn't.  The problem is that when
global_namespace is created with void_type_node, void_type_node is
still a NULL_TREE; it only becomes a thing after
c_common_nodes_and_builtins.  And since global_namespace's type is
null, it is wrongly considered dependent, and so the using above does
not work as expected.  Since this is true for not just :: but also for
std::, I've adjusted type_dependent_expression_p instead.

        PR c++/126653

gcc/cp/ChangeLog:

        * cp-tree.h (check_namespace_splice): Declare.
        * parser.cc (cp_parser_namespace_alias_definition): Call
        check_namespace_splice.
        (cp_parser_using_directive): Likewise.  Give an error if the
        nested-name-specifier, namespace-name, or splice-specifier is
        dependent.
        * pt.cc (type_dependent_expression_p): Return false for
        NAMESPACE_DECL.
        * reflect.cc (check_namespace_splice): New.

gcc/testsuite/ChangeLog:

        * g++.dg/reflect/ns10.C: New test.
---
 gcc/cp/cp-tree.h                    |  1 +
 gcc/cp/parser.cc                    | 44 +++++++++++++++++++--
 gcc/cp/pt.cc                        |  6 +++
 gcc/cp/reflect.cc                   | 25 +++++++++++-
 gcc/testsuite/g++.dg/reflect/ns10.C | 61 +++++++++++++++++++++++++++++
 5 files changed, 132 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/reflect/ns10.C

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 947bf62ff98..3a88352b02c 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -9560,6 +9560,7 @@ extern bool dependent_splice_p (const_tree) 
ATTRIBUTE_PURE;
 extern tree reflection_mangle_prefix (tree, char [3]);
 extern bool reflection_function_template_p (const_tree) ATTRIBUTE_PURE;
 extern void dump_data_member_spec (pretty_printer *, tree);
+extern bool check_namespace_splice (cp_expr);
 
 /* Inline bodies.  */
 
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 3c84f6e335f..1ec5a13cfe0 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -24637,7 +24637,15 @@ cp_parser_namespace_alias_definition (cp_parser* 
parser)
     }
   cp_parser_require (parser, CPP_EQ, RT_EQ);
   if (cp_parser_nth_token_starts_splice_without_nns_p (parser, 1))
-    namespace_specifier = cp_parser_splice_specifier (parser);
+    {
+      cp_expr splice = cp_parser_splice_specifier (parser);
+      /* [namespace.alias]/2: The splice-specifier (if any) shall designate
+        a namespace that is not the global namespace.  */
+      if (check_namespace_splice (splice))
+       namespace_specifier = splice;
+      else
+       namespace_specifier = error_mark_node;
+    }
   else
     /* Look for the qualified-namespace-specifier.  */
     namespace_specifier = cp_parser_qualified_namespace_specifier (parser);
@@ -25125,8 +25133,18 @@ cp_parser_using_directive (cp_parser* parser)
   cp_parser_require_keyword (parser, RID_USING, RT_USING);
   /* And the `namespace' keyword.  */
   cp_parser_require_keyword (parser, RID_NAMESPACE, RT_NAMESPACE);
+  const location_t loc = cp_lexer_peek_token (parser->lexer)->location;
+  bool dep_error = false;
   if (cp_parser_nth_token_starts_splice_without_nns_p (parser, 1))
-    namespace_decl = cp_parser_splice_specifier (parser);
+    {
+      cp_expr splice = cp_parser_splice_specifier (parser);
+      /* [namespace.udir]/1: The splice-specifier (if any) shall designate
+        a namespace that is not the global namespace.  */
+      if (check_namespace_splice (splice))
+       namespace_decl = splice;
+      else
+       namespace_decl = error_mark_node;
+    }
   else
     {
       /* Look for the optional `::' operator.  */
@@ -25137,8 +25155,26 @@ cp_parser_using_directive (cp_parser* parser)
                                           /*check_dependency_p=*/true,
                                           /*type_p=*/false,
                                           /*is_declaration=*/true);
-      /* Get the namespace being used.  */
-      namespace_decl = cp_parser_namespace_name (parser);
+      if (parser->scope
+         && parser->scope != error_mark_node
+         && (dependent_namespace_p (parser->scope)
+             || (TYPE_P (parser->scope) && dependent_type_p (parser->scope))))
+       {
+         /* Don't emit the "not a namespace-name" error.  */
+         cp_parser_identifier (parser);
+         dep_error = true;
+       }
+      else
+       /* Get the namespace being used.  */
+       namespace_decl = cp_parser_namespace_name (parser);
+    }
+  /* [namespace.udir]/1: The nested-name-specifier, namespace-name, and
+     splice-specifier shall not be dependent.  */
+  if (dep_error || dependent_namespace_p (namespace_decl))
+    {
+      error_at (loc, "dependent namespaces cannot appear in a using "
+               "directive");
+      namespace_decl = error_mark_node;
     }
   cp_warn_deprecated_use_scopes (namespace_decl);
   /* And any specified GNU attributes.  */
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 2b68ceb0cd2..80148f78b03 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -30405,6 +30405,12 @@ type_dependent_expression_p (tree expression)
       || TREE_CODE (expression) == USING_DECL)
     return true;
 
+  /* Most namespaces have void type and so wouldn't be considered
+     dependent, but some (::, std) have no type.  They are still not
+     dependent, though.  */
+  if (TREE_CODE (expression) == NAMESPACE_DECL)
+    return false;
+
   /* A lambda-expression in template context is dependent.  dependent_type_p is
      true for a lambda in the scope of a class or function template, but that
      doesn't cover all template contexts, like a default template argument.  */
diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.cc
index 8bf518df64f..ccf075b73c1 100644
--- a/gcc/cp/reflect.cc
+++ b/gcc/cp/reflect.cc
@@ -9253,7 +9253,7 @@ valid_splice_for_member_access_p (const_tree t, bool 
decls_only_p/*=true*/)
    splice is used in foo.[: bar :] or foo->[: bar :] context.  TEMPLATE_P is
    true if the splice-expression was preceded by 'template'.  TARGS_P is true
    if there were template arguments.  COMPLAIN_P is true if any errors should
-   be emitted.  Returns true is no problems are found, false otherwise.  */
+   be emitted.  Returns true if no problems are found, false otherwise.  */
 
 bool
 check_splice_expr (location_t loc, location_t start_loc, tree t,
@@ -9480,6 +9480,29 @@ dependent_splice_p (const_tree t)
              && TREE_CODE (TREE_OPERAND (t, 0)) == SPLICE_EXPR));
 }
 
+/* Check if SPLICE is a valid namespace splice.  Returns true if no problems
+   are found, false otherwise.  */
+
+bool
+check_namespace_splice (cp_expr splice)
+{
+  if (TREE_CODE (splice) != NAMESPACE_DECL && !dependent_namespace_p (splice))
+    {
+      auto_diagnostic_group d;
+      error_at (splice.get_location (), "expected a reflection of "
+               "a namespace");
+      inform_tree_category (splice);
+      return false;
+    }
+  else if (splice == global_namespace)
+    {
+      error_at (splice.get_location (), "splice of the global namespace "
+               "can only appear in a nested-name-specifier");
+      return false;
+    }
+  return true;
+}
+
 /* Annotation index for mangling.  */
 
 static GTY(()) int annotation_idx;
diff --git a/gcc/testsuite/g++.dg/reflect/ns10.C 
b/gcc/testsuite/g++.dg/reflect/ns10.C
new file mode 100644
index 00000000000..c68d4e97a0c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/ns10.C
@@ -0,0 +1,61 @@
+// PR c++/126653
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+namespace std { }
+struct S { };
+namespace N { int foo; };
+
+namespace GS = [: ^^:: :];     // { dg-error "splice of the global namespace" }
+using namespace [: ^^GS :];    // { dg-error "declared|expected" }
+
+using namespace [: ^^int :];   // { dg-error "expected a reflection of a 
namespace" }
+namespace X = [: ^^void :];    // { dg-error "expected a reflection of a 
namespace" }
+
+using namespace S::T;          // { dg-error ".T. is not a namespace-name" }
+
+template<auto ns>
+void
+bad ()
+{
+  using namespace [:ns:];      // { dg-error "dependent namespaces cannot 
appear in a using directive" }
+  using namespace ::[:ns:];    // { dg-error "expected" }
+  using namespace N::[:ns:];   // { dg-error "expected" }
+  using namespace [:ns:]::N;   // { dg-error "dependent namespaces cannot 
appear in a using directive" }
+  using namespace [: ^^:: :];  // { dg-error "splice of the global namespace 
can only appear in a nested-name-specifier" }
+  using namespace ::;          // { dg-error "expected identifier before" }
+
+  namespace A = [:ns:];
+  using namespace A::N;                // { dg-error "dependent namespaces 
cannot appear in a using directive" }
+  using namespace A::N::M;     // { dg-error "dependent namespaces cannot 
appear in a using directive" }
+}
+
+template<typename T>
+void
+also_bad ()
+{
+  using namespace T::N;                // { dg-error "dependent namespaces 
cannot appear in a using directive" }
+}
+
+int
+ok ()
+{
+  using namespace [: ^^:: :]::N;
+  using namespace [: ^^N :];
+  using namespace [: ^^::N :];
+  using namespace ::N;
+  using namespace [: ^^std :];
+  namespace B = [: ^^N :];
+  using namespace B;
+  return foo;
+}
+
+template<typename>
+void
+also_ok ()
+{
+  namespace B = [: ^^N :];
+  using namespace B;
+  using namespace [: ^^N :];
+}
+template void also_ok<int> ();

base-commit: 962723b046ae6406c0c457bfdb76318b3652673f
-- 
2.55.0

Reply via email to