https://gcc.gnu.org/g:1fe23226498c2a8f78fae304cac20277cefba618
commit r16-9740-g1fe23226498c2a8f78fae304cac20277cefba618 Author: Marek Polacek <[email protected]> Date: Tue Oct 6 12:20:13 2026 -0400 c++/reflection: using typename [:ns:]::X; should declare a type [PR127707] This fixes a bogus error for namespace N { struct S {}; } template<auto ns> void f () { using typename [:ns:]::S; S s; } It is a failure to propagate USING_DECL_TYPENAME_P to the USING_DECL in case we are not at_class_scope_p. With that flag set, the dependent USING_DECL will be treated as naming a type. PR c++/127707 gcc/cp/ChangeLog: * name-lookup.cc (finish_nonmember_using_decl): New bool parameter. Set USING_DECL_TYPENAME_P if it's true. * name-lookup.h (finish_nonmember_using_decl): Adjust declaration. * parser.cc (finish_using_decl): Pass typename_p to finish_nonmember_using_decl. * pt.cc (tsubst_stmt) <case DECL_EXPR>: Pass USING_DECL_TYPENAME_P to finish_nonmember_using_decl. gcc/testsuite/ChangeLog: * g++.dg/reflect/ns12.C: New test. Reviewed-by: Jason Merrill <[email protected]> (cherry picked from commit 1b961bf9d7e76de9a36f93d8749dbe7fae302246) Diff: --- gcc/cp/name-lookup.cc | 9 ++++-- gcc/cp/name-lookup.h | 3 +- gcc/cp/parser.cc | 2 +- gcc/cp/pt.cc | 3 +- gcc/testsuite/g++.dg/reflect/ns12.C | 63 +++++++++++++++++++++++++++++++++++++ 5 files changed, 75 insertions(+), 5 deletions(-) diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index 1db4a314571a..09c83e18d6f7 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -6994,10 +6994,12 @@ push_using_decl_bindings (tree name, tree value) push_using_decl_bindings (nullptr, name, value); } -/* Process a using declaration in non-class scope. */ +/* Process a using declaration in non-class scope. TYPENAME_P is true if + the using decl had the typename keyword; this is important to record for + a block-scope using declaration with a dependent scope (using a splice). */ void -finish_nonmember_using_decl (tree scope, tree name) +finish_nonmember_using_decl (tree scope, tree name, bool typename_p/*=false*/) { gcc_checking_assert (current_binding_level->kind != sk_class); @@ -7010,6 +7012,9 @@ finish_nonmember_using_decl (tree scope, tree name) if (!using_decl) return; + if (typename_p) + USING_DECL_TYPENAME_P (using_decl) = true; + /* Emit debug info. */ if (!processing_template_decl) cp_emit_debug_info_for_using (lookup.value, diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h index cd0799a80ded..284fbf9f1602 100644 --- a/gcc/cp/name-lookup.h +++ b/gcc/cp/name-lookup.h @@ -503,7 +503,8 @@ extern bool decl_in_scope_p (tree); extern cxx_binding *outer_binding (tree, cxx_binding *, bool); extern void cp_emit_debug_info_for_using (tree, tree); -extern void finish_nonmember_using_decl (tree scope, tree name); +extern void finish_nonmember_using_decl (tree scope, tree name, + bool typename_p = false); extern void finish_using_directive (tree target, tree attribs); void push_local_extern_decl_alias (tree decl); extern tree pushdecl (tree, bool hiding = false); diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index bf981945aa05..790e0296e3a3 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -24592,7 +24592,7 @@ finish_using_decl (tree qscope, tree identifier, bool typename_p = false) finish_member_declaration (decl); } else - finish_nonmember_using_decl (qscope, identifier); + finish_nonmember_using_decl (qscope, identifier, typename_p); return decl; } diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index f5cb7f6bb41b..59ba8ea9f63a 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -19749,7 +19749,8 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl) "class, namespace, or enumeration", scope); return error_mark_node; } - finish_nonmember_using_decl (scope, DECL_NAME (decl)); + finish_nonmember_using_decl (scope, DECL_NAME (decl), + USING_DECL_TYPENAME_P (decl)); } else { diff --git a/gcc/testsuite/g++.dg/reflect/ns12.C b/gcc/testsuite/g++.dg/reflect/ns12.C new file mode 100644 index 000000000000..fcb06eb33a63 --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/ns12.C @@ -0,0 +1,63 @@ +// PR c++/127707 +// { dg-do compile { target c++26 } } +// { dg-additional-options "-freflection" } + +namespace N { + struct S {}; + struct R {}; +} +namespace A = N; +struct S {}; + +using typename [:^^N:]::R; +R r; + +template<auto ns> +void +f () +{ + using typename [:ns:]::S; + S s; +} + +template<auto ns> +void +f2 () +{ + [] (auto) { + using typename [:ns:]::S; + S s; + } (0); +} + +template<auto ns> +void +f3 () +{ + [] <auto ns2> () { + using typename [:ns2:]::S; + S s; + }.template operator()<ns>(); +} + +template<auto ns> +void +fbad () +{ + using [:ns:]::S; + S s; // { dg-error "expected" } +} + +void +g () +{ + f<^^::>(); + f<^^N>(); + f<^^A>(); + f2<^^::>(); + f2<^^N>(); + f2<^^A>(); + f3<^^::>(); + f3<^^N>(); + f3<^^A>(); +}
