@@ -192,6 +192,7 @@ static tree listify (tree);
static tree listify_autos (tree, tree);
static tree template_parm_to_arg (tree t);
static tree current_template_args (void);
+static bool incomplete_args_for_template_parm_fixup_p (tree, tree);
static tree fixup_template_type_parm_type (tree, int);
static tree fixup_template_parm_index (tree, tree, int);
static void fixup_template_parms (void);
@@ -3774,21 +3775,16 @@ fixup_template_parm (tree parm_desc,
{
/* PARM is a template template parameter. This is going to
be interesting. */
- tree tparms, targs, innermost_args;
+ tree tparms, targs, innermost_args, t;
int j;
- /* First, fix up the type of the parm. */
+ /* First, fix up the parms of the template template parm
+ because the parms are involved in defining the new canonical
+ type of the template template parm. */
- tree t =
- fixup_template_type_parm_type (TREE_TYPE (parm), num_parms);
- TREE_TYPE (parm) = t;
-
- TREE_VEC_ELT (fixedup_args, idx) =
- template_parm_to_arg (parm_desc);
-
- /* Now we need to substitute the template parm types that
- have been fixed up so far into the non-type template
- parms of this template template parm. E.g, consider this:
+ /* So we need to substitute the template parm types that have
+ been fixed up so far into the template parms of this template
+ template parm. E.g, consider this:
template<class T, template<T u> class TT> class S;
@@ -3827,9 +3823,40 @@ fixup_template_parm (tree parm_desc,
TREE_VEC_LENGTH (tparms),
targs);
}
+
+ /* Now fix up the type of the template template parm. */
+
+ t = fixup_template_type_parm_type (TREE_TYPE (parm), num_parms);
+ TREE_TYPE (parm) = t;
+
+ TREE_VEC_ELT (fixedup_args, idx) =
+ template_parm_to_arg (parm_desc);
}
else if (TREE_CODE (parm) == PARM_DECL)
{
+ tree index, pushed_decl, fixed_up_index;
+
+ if (incomplete_args_for_template_parm_fixup_p (arglist, parm))
+ /* If arglist is incomplete for fixing up PARM, that might mean
+ PARM is a non-type parameter of a template template
+ parameter that we are attempting to fixup too early. E.g:
+
+ template <int> class A;
+ template <class Key, class T, template <T p> class TC = A> class B;
+
+ The first time we see the parm p, {Key, T, TC} have
+ obviously not been added to the current_template_parameters
+ yet. So the implicit ARGLIST returned by
+ current_template_args to substitute into p is
+ [{NULL,NULL,NULL}, {NULL}] instead of [{Key, T, NULL},
+ {NULL}].
+
+ We cannot use that incomplete ARGLIST then. So let's bail
+ out for now, and when and Key and T have been fixed up, we
+ will be called again to fixup p and that time with the
+ complete set of implicit arguments. */
+ goto end;
+
/* PARM is a non-type template parameter. We need to:
* Fix up its TEMPLATE_PARM_INDEX to make it carry the
@@ -3843,7 +3870,7 @@ fixup_template_parm (tree parm_desc,
* into the type of PARM. */
- tree index = DECL_INITIAL (parm);
+ index = DECL_INITIAL (parm);
/* PUSHED_DECL is the decl added to the symbol table with
the name of the parameter. E,g:
@@ -3856,12 +3883,12 @@ fixup_template_parm (tree parm_desc,
PUSHED_DECL is. We need to replace the reference to the
old TEMPLATE_PARM_INDEX carried by PUSHED_DECL by the
fixed-up TEMPLATE_PARM_INDEX. */
- tree pushed_decl = TEMPLATE_PARM_DECL (index);
-
+ pushed_decl = TEMPLATE_PARM_DECL (index);
+
/* Let's fix up the TEMPLATE_PARM_INDEX then. Note that we must
fixup the type of PUSHED_DECL as well and luckily
fixup_template_parm_index does it for us too. */
- tree fixed_up_index =
+ fixed_up_index =
fixup_template_parm_index (index, arglist, num_parms);
DECL_INITIAL (pushed_decl) = DECL_INITIAL (parm) = fixed_up_index;
@@ -3875,14 +3902,84 @@ fixup_template_parm (tree parm_desc,
tf_none, NULL_TREE);
}
- TREE_PURPOSE (parm_desc) =
- tsubst_template_arg (TREE_PURPOSE (parm_desc),
- arglist, tf_none, parm);
-
+ /* Don't try to substitute the implicit arguments ARGLIST into the
+ default parameter of a template template parameter too early,
+ e.g:
+
+ template < typename > class A;
+ template <class Key,
+ class T,
+ template<typename TF = T> class TC = A> class B;
+
+ The first time we see TF, we should not attempt to substitute
+ ARGLIST into it because ARGLIST is not complete yet. It will be
+ complete when all the template parameters of B are processed and
+ passed to end_template_parm_list to update
+ current_template_parms.
+
+ It's that point that ARGLIST will be [{Key, T, NULL} {NULL}] thus
+ suitable to be substituted into the default argument of TF. */
+ if (!incomplete_args_for_template_parm_fixup_p (arglist,
+ TREE_VALUE (parm_desc)))
+ TREE_PURPOSE (parm_desc) =
+ tsubst_template_arg (TREE_PURPOSE (parm_desc),
+ arglist, tf_none, parm);
+ end:
pop_deferring_access_checks ();
}
-/* Walk current the template parms and properly compute the canonical
+/*
+ This is a subroutine of fixup_template_parm.
+
+ Return TRUE if the full list of template arguments [a vector of
+ vector as described in the comments of
+ TMPL_ARGS_HAVE_MULTIPLE_LEVELS] is incomplete to be used to
+ substitute into the template parameter PARM, for the purpose of
+ fixing up PARM with fixup_template_parm. ARGLIST is considered
+ complete if all the template levels preceding the level of PARM are
+ filled with arguments. Please read the comments of the places of
+ this function is used to understand more. */
+
+static bool
+incomplete_args_for_template_parm_fixup_p (tree arglist, tree parm)
+{
+ int i, level, index;
+ tree args;
+
+ if (TREE_CODE (parm) == TYPE_DECL
+ || TREE_CODE (parm) == TEMPLATE_DECL)
+ {
+ level = TEMPLATE_TYPE_LEVEL (TREE_TYPE (parm));
+ index = TEMPLATE_TYPE_IDX (TREE_TYPE (parm));
+ }
+ else if (TREE_CODE (parm) == PARM_DECL)
+ {
+ level = TEMPLATE_PARM_LEVEL (DECL_INITIAL (parm));
+ index = TEMPLATE_PARM_IDX (DECL_INITIAL (parm));
+ }
+ else
+ return false;
+
+ if (TMPL_ARGS_DEPTH (arglist) == 1
+ && index < 1)
+ /* Fixing up the first template parm should always be possible
+ with a template arguments set of depth 1. */
+ return false;
+
+ for (i = 0; i < level - 1; ++i)
+ {
+ args = TREE_VEC_ELT (arglist, i);
+ gcc_assert (args != NULL_TREE);
+
+ if (TREE_CODE (args) == TREE_VEC
+ && tree_vec_empty_p (args))
+ return true;
+ }
+
+ return false;
+}
+
+/* Walk the current template parms and properly compute the canonical
types of the dependent types created during
cp_parser_template_parameter_list. */
@@ -3911,8 +4008,6 @@ fixup_template_parms (void)
arglist = current_template_args ();
arglist = add_outermost_template_args (arglist, fixedup_args);
- fixedup_args = INNERMOST_TEMPLATE_ARGS (arglist);
-
/* Let's do the proper fixup now. */
for (i = 0; i < num_parms; ++i)
fixup_template_parm (TREE_VEC_ELT (parameter_vec, i),
new file mode 100644
@@ -0,0 +1,8 @@
+// Origin PR c++/47311
+// { dg-do compile }
+
+template < typename > class A0;
+template <class Key, class T, template < typename TF = T> class TC = A0> class B0;
+
+template <int> class A1;
+template <class Key, class T, template <T p> class TC = A1> class B1;
@@ -1694,6 +1694,25 @@ make_tree_vec_stat (int len MEM_STAT_DECL)
return t;
}
+
+/* Return TRUE if T is a TREE_VEC filled with NULL_TREE or a TREE_VEC
+ of size zero. */
+
+bool
+tree_vec_empty_p (const_tree t)
+{
+ int i;
+
+ if (t == NULL_TREE || TREE_CODE (t) != TREE_VEC)
+ return false;
+
+ for (i = 0; i < TREE_VEC_LENGTH (t); ++i)
+ if (TREE_VEC_ELT (t, i) != NULL_TREE)
+ return false;
+
+ return true;
+}
+
/* Return 1 if EXPR is the integer constant zero or a complex constant
of zero. */
@@ -3988,6 +3988,8 @@ extern tree make_tree_binfo_stat (unsigned MEM_STAT_DECL);
extern tree make_tree_vec_stat (int MEM_STAT_DECL);
#define make_tree_vec(t) make_tree_vec_stat (t MEM_STAT_INFO)
+bool tree_vec_empty_p (const_tree t);
+
/* Return the (unique) IDENTIFIER_NODE node for a given name.
The name is supplied as a char *. */