c++/reflection: ICE with ns splice scope in ns alias [PR127344]

Message ID 20260930161254.1080718-1-polacek@redhat.com
State Committed
Commit e65b3092ce078418632186b7d67c3e443f6657fd
Headers
Series c++/reflection: ICE with ns splice scope in ns alias [PR127344] |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_gcc_check--master-arm success Test passed
linaro-tcwg-bot/tcwg_simplebootstrap_build--master-arm-bootstrap success Build passed
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 success Build passed

Commit Message

Marek Polacek Sept. 30, 2026, 4:12 p.m. UTC
  Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

-- >8 --
This fixes another problem when using namespace splice scopes,
this time in a namespace alias like this:

  template<auto ns> void f () {
    namespace A = [:ns:];
    int i = A::N::x;
  }

where we crash in make_typename_type or make_unbound_class_template
because they expect a type but get a NAMESPACE_DECL built for the
A alias with ORIGINAL_NAMESPACE being a SPLICE_EXPR.  The decl is
coming from cp_parser_namespace_alias_definition -> do_namespace_alias.

We want a SPLICE_SCOPE which is a type, so build one with
make_splice_scope.

I considered changing cp_parser_namespace_alias_definition to build
the SPLICE_SCOPE there but that brought so many other issues that it
wasn't worth it.

	PR c++/127344

gcc/cp/ChangeLog:

	* parser.cc (cp_parser_lookup_name): Call make_splice_scope for
	dependent_namespace_p.  Use the result for make_typename_type
	and make_unbound_class_template.

gcc/testsuite/ChangeLog:

	* g++.dg/reflect/ns9.C: New test.
---
 gcc/cp/parser.cc                   | 17 ++++++----
 gcc/testsuite/g++.dg/reflect/ns9.C | 52 ++++++++++++++++++++++++++++++
 2 files changed, 63 insertions(+), 6 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/reflect/ns9.C


base-commit: f4d32f612a3c43e9d0a861b7dae7bb67139c9ab0
  

Comments

Jason Merrill Oct. 3, 2026, 7:55 a.m. UTC | #1
On 9/30/26 6:12 PM, Marek Polacek wrote:
> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

OK.
> -- >8 --
> This fixes another problem when using namespace splice scopes,
> this time in a namespace alias like this:
> 
>    template<auto ns> void f () {
>      namespace A = [:ns:];
>      int i = A::N::x;
>    }
> 
> where we crash in make_typename_type or make_unbound_class_template
> because they expect a type but get a NAMESPACE_DECL built for the
> A alias with ORIGINAL_NAMESPACE being a SPLICE_EXPR.  The decl is
> coming from cp_parser_namespace_alias_definition -> do_namespace_alias.
> 
> We want a SPLICE_SCOPE which is a type, so build one with
> make_splice_scope.
> 
> I considered changing cp_parser_namespace_alias_definition to build
> the SPLICE_SCOPE there but that brought so many other issues that it
> wasn't worth it.
> 
> 	PR c++/127344
> 
> gcc/cp/ChangeLog:
> 
> 	* parser.cc (cp_parser_lookup_name): Call make_splice_scope for
> 	dependent_namespace_p.  Use the result for make_typename_type
> 	and make_unbound_class_template.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/reflect/ns9.C: New test.
> ---
>   gcc/cp/parser.cc                   | 17 ++++++----
>   gcc/testsuite/g++.dg/reflect/ns9.C | 52 ++++++++++++++++++++++++++++++
>   2 files changed, 63 insertions(+), 6 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/reflect/ns9.C
> 
> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> index 373d3358c25..3c84f6e335f 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -35608,15 +35608,21 @@ cp_parser_lookup_name (cp_parser *parser, tree name,
>   	       && dependentish_scope_p (parser->scope))
>   	      || dependent_namespace_p (parser->scope)))
>   	{
> +	  tree scope = parser->scope;
> +	  /* The make_* functions below expect something that's a type.  SCOPE
> +	     is a NAMESPACE_DECL when we are dealing with a dependent namespace
> +	     alias like "namespace A = [:ns:];".  */
> +	  if (dependent_namespace_p (scope))
> +	    scope = make_splice_scope (ORIGINAL_NAMESPACE (scope),
> +				       /*type_p=*/false);
> +
>   	  if (tag_type)
>   	    {
> -	      tree type;
> -
>   	      /* The resolution to Core Issue 180 says that `struct
>   		 A::B' should be considered a type-name, even if `A'
>   		 is dependent.  */
> -	      type = make_typename_type (parser->scope, name, tag_type,
> -					 /*complain=*/tf_error);
> +	      tree type = make_typename_type (scope, name, tag_type,
> +					      /*complain=*/tf_error);
>   	      if (type != error_mark_node)
>   		decl = TYPE_NAME (type);
>   	    }
> @@ -35624,8 +35630,7 @@ cp_parser_lookup_name (cp_parser *parser, tree name,
>   		   && (cp_parser_next_token_ends_template_argument_p (parser)
>   		       || cp_lexer_next_token_is (parser->lexer,
>   						  CPP_CLOSE_PAREN)))
> -	    decl = make_unbound_class_template (parser->scope,
> -						name, NULL_TREE,
> +	    decl = make_unbound_class_template (scope, name, NULL_TREE,
>   						/*complain=*/tf_error);
>   	  else
>   	    decl = build_qualified_name (/*type=*/NULL_TREE,
> diff --git a/gcc/testsuite/g++.dg/reflect/ns9.C b/gcc/testsuite/g++.dg/reflect/ns9.C
> new file mode 100644
> index 00000000000..3f2141f6271
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/reflect/ns9.C
> @@ -0,0 +1,52 @@
> +// PR c++/127344
> +// { dg-do compile { target c++26 } }
> +// { dg-additional-options "-freflection" }
> +
> +template<class, class> struct same_type;
> +template<class T> struct same_type<T, T> {};
> +
> +namespace X { struct N { static constexpr int x = 42; }; }
> +
> +template<auto ns>
> +int
> +f ()
> +{
> +  namespace A = [:ns:];
> +  int i = A::N::x;
> +  int j = [:ns:]::N::x;
> +  return i + j;
> +}
> +
> +namespace N { template<class> struct X {}; }
> +template<template<class> class> struct S {};
> +
> +template<auto ns>
> +void
> +h ()
> +{
> +  namespace A = [:ns:];
> +  S<A::template X> s;
> +}
> +
> +namespace Y { int y = 1; void fn (); namespace N { int x = 2; } }
> +
> +template<auto ns>
> +int
> +k ()
> +{
> +  namespace A = [:ns:];
> +  namespace B = A;
> +  auto p = &A::fn;
> +  same_type<decltype(p), void (*) ()>();
> +  auto q = &[:ns:]::fn;
> +  same_type<decltype(q), void (*) ()>();
> +  return A::y + B::N::x;
> +}
> +
> +void
> +g ()
> +{
> +  f<^^X>();
> +  h<^^N>();
> +  k<^^Y>();
> +}
> 
> base-commit: f4d32f612a3c43e9d0a861b7dae7bb67139c9ab0
  

Patch

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 373d3358c25..3c84f6e335f 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -35608,15 +35608,21 @@  cp_parser_lookup_name (cp_parser *parser, tree name,
 	       && dependentish_scope_p (parser->scope))
 	      || dependent_namespace_p (parser->scope)))
 	{
+	  tree scope = parser->scope;
+	  /* The make_* functions below expect something that's a type.  SCOPE
+	     is a NAMESPACE_DECL when we are dealing with a dependent namespace
+	     alias like "namespace A = [:ns:];".  */
+	  if (dependent_namespace_p (scope))
+	    scope = make_splice_scope (ORIGINAL_NAMESPACE (scope),
+				       /*type_p=*/false);
+
 	  if (tag_type)
 	    {
-	      tree type;
-
 	      /* The resolution to Core Issue 180 says that `struct
 		 A::B' should be considered a type-name, even if `A'
 		 is dependent.  */
-	      type = make_typename_type (parser->scope, name, tag_type,
-					 /*complain=*/tf_error);
+	      tree type = make_typename_type (scope, name, tag_type,
+					      /*complain=*/tf_error);
 	      if (type != error_mark_node)
 		decl = TYPE_NAME (type);
 	    }
@@ -35624,8 +35630,7 @@  cp_parser_lookup_name (cp_parser *parser, tree name,
 		   && (cp_parser_next_token_ends_template_argument_p (parser)
 		       || cp_lexer_next_token_is (parser->lexer,
 						  CPP_CLOSE_PAREN)))
-	    decl = make_unbound_class_template (parser->scope,
-						name, NULL_TREE,
+	    decl = make_unbound_class_template (scope, name, NULL_TREE,
 						/*complain=*/tf_error);
 	  else
 	    decl = build_qualified_name (/*type=*/NULL_TREE,
diff --git a/gcc/testsuite/g++.dg/reflect/ns9.C b/gcc/testsuite/g++.dg/reflect/ns9.C
new file mode 100644
index 00000000000..3f2141f6271
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/ns9.C
@@ -0,0 +1,52 @@ 
+// PR c++/127344
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+template<class, class> struct same_type;
+template<class T> struct same_type<T, T> {};
+
+namespace X { struct N { static constexpr int x = 42; }; }
+
+template<auto ns>
+int
+f ()
+{
+  namespace A = [:ns:];
+  int i = A::N::x;
+  int j = [:ns:]::N::x;
+  return i + j;
+}
+
+namespace N { template<class> struct X {}; }
+template<template<class> class> struct S {};
+
+template<auto ns>
+void
+h ()
+{
+  namespace A = [:ns:];
+  S<A::template X> s;
+}
+
+namespace Y { int y = 1; void fn (); namespace N { int x = 2; } }
+
+template<auto ns>
+int
+k ()
+{
+  namespace A = [:ns:];
+  namespace B = A;
+  auto p = &A::fn;
+  same_type<decltype(p), void (*) ()>();
+  auto q = &[:ns:]::fn;
+  same_type<decltype(q), void (*) ()>();
+  return A::y + B::N::x;
+}
+
+void
+g ()
+{
+  f<^^X>();
+  h<^^N>();
+  k<^^Y>();
+}