https://gcc.gnu.org/g:e65b3092ce078418632186b7d67c3e443f6657fd
commit r17-4860-ge65b3092ce078418632186b7d67c3e443f6657fd Author: Marek Polacek <[email protected]> Date: Fri Sep 11 15:40:37 2026 -0400 c++/reflection: ICE with ns splice scope in ns alias [PR127344] 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. Reviewed-by: Jason Merrill <[email protected]> Diff: --- gcc/cp/parser.cc | 17 ++++++++----- gcc/testsuite/g++.dg/reflect/ns9.C | 52 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 6 deletions(-) diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 373d3358c25f..3c84f6e335fc 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 000000000000..3f2141f6271f --- /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>(); +}
