https://gcc.gnu.org/g:cb0b42290642c021cab5f66075a38b15d5f2772d

commit r17-5519-gcb0b42290642c021cab5f66075a38b15d5f2772d
Author: Marek Polacek <[email protected]>
Date:   Thu Sep 10 17:17:06 2026 -0400

    c++/reflection: spliced namespace in using directive [PR126653]
    
    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.
    
    Reviewed-by: Jason Merrill <[email protected]>

Diff:
---
 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(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 4201eb2d2aba..01df92d7e095 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 3b3adc0f09a7..b30d3e7f6755 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -24731,7 +24731,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);
@@ -25219,8 +25227,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.  */
@@ -25231,8 +25249,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 3738b1c477dc..26bc7c21db31 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -30414,6 +30414,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 47ec9647de8b..be3f29b9507f 100644
--- a/gcc/cp/reflect.cc
+++ b/gcc/cp/reflect.cc
@@ -9259,7 +9259,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,
@@ -9486,6 +9486,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 000000000000..c68d4e97a0c8
--- /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> ();

Reply via email to