On 9/30/26 1:06 AM, Marek Polacek wrote:
Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
OK.
-- >8 -- This patch fixes the missing part of 127349 when we have a namespace splice scope in a template template argument: namespace N { template<class> struct X {}; } template<template<class> class> struct S {}; template<auto ns> void f () { S<[:ns:]::template X> s; } void h () { f<^^N>(); } which currently wrongly errors with "no class template named 'X' in 'N'". The problem is that we don't handle the case when the context in tsubst's UNBOUND_CLASS_TEMPLATE case substitutes into a NAMESPACE_DECL. We already handle it correctly in the TYPENAME_TYPE case. In the UNBOUND_CLASS_TEMPLATE case we only want a DECL_TYPE_TEMPLATE_P as the result, so there is no shared routine. This patch also fixes ICEs on the lambdas in h2/h3, where we crash because dependent_type_p gets a NAMESPACE_DECL but it only wants types. PR c++/127349 gcc/cp/ChangeLog: * pt.cc (tsubst) <case UNBOUND_CLASS_TEMPLATE>: Handle the case when the context was substituted into a NAMESPACE_DECL. gcc/testsuite/ChangeLog: * g++.dg/reflect/ns7.C: Remove unused declarations. * g++.dg/reflect/ns8.C: New test. --- gcc/cp/pt.cc | 22 +++++++++++++++ gcc/testsuite/g++.dg/reflect/ns7.C | 3 -- gcc/testsuite/g++.dg/reflect/ns8.C | 44 ++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/g++.dg/reflect/ns8.C diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 5696828673d..6c8d0e2de71 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -18064,6 +18064,28 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) if (ctx == error_mark_node) return error_mark_node;+ /* We had [:X:]::template NAME where X was substituted into+ a NAMESPACE_DECL and not a type. */ + if (TREE_CODE (ctx) == NAMESPACE_DECL) + { + tree decl = lookup_qualified_name (ctx, name); + if (decl == error_mark_node || TREE_CODE (decl) == TREE_LIST) + { + if (complain & tf_error) + qualified_name_lookup_error (ctx, name, decl, input_location); + return error_mark_node; + } + /* As in make_unbound_class_template, we want only a class or + alias template. */ + if (!DECL_TYPE_TEMPLATE_P (decl)) + { + if (complain & tf_error) + error ("%qD is not a class template", decl); + return error_mark_node; + } + return decl; + } + return make_unbound_class_template (ctx, name, parm_list, complain); }diff --git a/gcc/testsuite/g++.dg/reflect/ns7.C b/gcc/testsuite/g++.dg/reflect/ns7.Cindex a9ba862d77b..faf59f8b116 100644 --- a/gcc/testsuite/g++.dg/reflect/ns7.C +++ b/gcc/testsuite/g++.dg/reflect/ns7.C @@ -9,13 +9,10 @@ namespace N { template<class T> using A = X<T>; inline namespace I { template<class> struct V {}; } using namespace M; - template<class, class> struct Z {}; int v; template<class T> void fn (); }-template<template<class> class> struct S {};- template<auto ns> void f () diff --git a/gcc/testsuite/g++.dg/reflect/ns8.C b/gcc/testsuite/g++.dg/reflect/ns8.C new file mode 100644 index 00000000000..faca9d15a06 --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/ns8.C @@ -0,0 +1,44 @@ +// PR c++/127349 +// { dg-do compile { target c++26 } } +// { dg-additional-options "-freflection" } + +template<class> struct Y {}; +namespace M { template<class> struct W {}; } +namespace N { + template<class> struct X {}; + template<class T> using A = X<T>; + inline namespace I { template<class> struct V {}; } + using namespace M; + template<class, class> struct Z {}; + int v; + template<class T> void fn (); +} + +template<template<class> class> struct S {}; + +template<auto ns> +void +f () +{ + S<[:ns:]::template X> s1; + S<[:ns:]::template A> s2; + S<[:ns:]::template V> s3; + S<[:ns:]::template W> s4; + S<[:ns:]::template Y> s5; // { dg-error "'Y' is not a member of 'N'" } + S<[:ns:]::template v> s6; // { dg-error "'N::v' is not a class template" } + S<[:ns:]::template fn> s7; // { dg-error "not a class template" } + S<[:ns:]::template Z> s8; // { dg-error "mismatch" } +} +void h () { f<^^N>(); } + +template<auto ns> +void h2 () { + [] <class T> () { S<[:ns:]::template X> s; }.template operator()<int> (); +} +void f2 () { h2<^^N>(); } + +template<auto ns> +void h3 () { + [] <auto r> () { S<[:r:]::template X> s; }.template operator()<ns> (); +} +void f3 () { h3<^^N>(); } base-commit: fa82fc957bccc0f29f2b41e66d1881ba821369ea
