Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
-- >8 --
std::meta::template_of (r) gives us a reflection of the template of the
specialization represented by r. Consider
template<typename T>
struct TS {
template<typename U>
void fn (T) { }
};
then template_of (^^TS<int>::fn<int>) gives us ^^TS<int>::fn.
template_of is implemented in terms of DECL_TI_TEMPLATE which gives us
the immediate parent, not the most general template, so for
void TS<T>::fn(T) [with U = int; T = int]
we get
template<class U> void TS<T>::fn(T) [with T = int]
The DECL_TI_TEMPLATE is set in instantiate_template:
/* The DECL_TI_TEMPLATE should always be the immediate parent
template, not the most general template. */
DECL_TI_TEMPLATE (fndecl) = tmpl;
and fn_type_unification passes tmpl which is
template<class U> void TS<T>::fn(T) [with T = int].
So far so good. But for alias templates, instantiate_template is
called from instantiate_alias_template and both calls to i_a_t
get the most general template as tmpl. Thus, for
template<typename T>
struct TS {
template<typename TT>
using U = int;
};
TI_TEMPLATE is set to:
template<class T> template<class TT> using TS<T>::U = int
so eval_template_of gives the wrong result; it should be ^^TS<int>::U.
This seems like an undocumented quirk. We can deal with this by
doing a substitution into the most general template in eval_template_of
and documenting the behavior, or fix it more generally, which is
riskier. This patch takes the more general approach.
The any_dependent_template_arguments_p guard is there due to pr71655.C.
PR c++/124245
gcc/cp/ChangeLog:
* pt.cc (instantiate_template): For an alias template,
substitute the most general template so that we get the
immediate parent template for DECL_TI_TEMPLATE.
gcc/testsuite/ChangeLog:
* g++.dg/reflect/template_of2.C: Uncomment test. Add more
nested testing.
---
gcc/cp/pt.cc | 20 +++++++++++++-----
gcc/testsuite/g++.dg/reflect/template_of2.C | 23 +++++++++++++++++----
2 files changed, 34 insertions(+), 9 deletions(-)
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 2a703330173..42b562149c5 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -24060,11 +24060,21 @@ instantiate_template (tree tmpl, tree orig_args,
tsubst_flags_t complain)
if (fndecl == error_mark_node)
return error_mark_node;
- /* Substituting the type might have recursively instantiated this
- same alias (c++/117530). */
- if (DECL_ALIAS_TEMPLATE_P (gen_tmpl)
- && (spec = retrieve_specialization (gen_tmpl, targ_ptr, hash)))
- return spec;
+ if (DECL_ALIAS_TEMPLATE_P (gen_tmpl))
+ {
+ /* Substituting the type might have recursively instantiated this
+ same alias (c++/117530). */
+ if ((spec = retrieve_specialization (gen_tmpl, targ_ptr, hash)))
+ return spec;
+ /* instantiate_alias_template gets the most general template,
+ but for DECL_TI_TEMPLATE we want the immediate parent template. */
+ if (tmpl == gen_tmpl && TMPL_ARGS_DEPTH (targ_ptr) > 1)
+ {
+ tree outer = strip_innermost_template_args (targ_ptr, 1);
+ if (!any_dependent_template_arguments_p (outer))
+ tmpl = tsubst (gen_tmpl, outer, tf_none, NULL_TREE);
+ }
+ }
/* The DECL_TI_TEMPLATE should always be the immediate parent
template, not the most general template. */
diff --git a/gcc/testsuite/g++.dg/reflect/template_of2.C
b/gcc/testsuite/g++.dg/reflect/template_of2.C
index 73aa0bcb019..51d9a565185 100644
--- a/gcc/testsuite/g++.dg/reflect/template_of2.C
+++ b/gcc/testsuite/g++.dg/reflect/template_of2.C
@@ -23,10 +23,25 @@ struct TS {
using U = int;
};
+template<typename T>
+struct TS2 {
+ template<typename U>
+ struct Inner {
+ template<typename V>
+ using A = int;
+ };
+ struct N {
+ template<typename V>
+ using A = int;
+ };
+ template<typename U> struct M { };
+};
+
static_assert (template_of (^^S::fn<int>) == ^^S::fn);
static_assert (template_of (^^TS<int>::fn<int>) == ^^TS<int>::fn);
static_assert (template_of (^^S::U<int>) == ^^S::U);
-// FIXME
-// template<class T> template<class U> using TS<T>::W = int
-// template<class U> using TS<int>::W = int
-//static_assert (template_of (^^TS<int>::U<int>) == ^^TS<int>::U);
+static_assert (template_of (^^TS<int>::U<int>) == ^^TS<int>::U);
+static_assert (template_of (^^TS2<int>::Inner<long>::A<char>)
+ == ^^TS2<int>::Inner<long>::A);
+static_assert (template_of (^^TS2<int>::N::A<char>) == ^^TS2<int>::N::A);
+static_assert (template_of (^^TS2<int>::M<char>) == ^^TS2<int>::M);
base-commit: 946f1fefc6d44afad2d3ff1e6a5fe74387bb3aea
--
2.56.0