Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
-- >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.C
index 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
--
2.55.0