It has always seemed odd that we didn't build a TEMPLATE_DECL for a
partial specialization, and with the ongoing concepts work it has become
more important to have one so that we can attach any requirements to it.
Note that there is still no way to get from the type of a partial
specialization to its template other than by way of the primary
template's list of partial specializations.
The second patch adds some missing _CHECK uses.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit 5961bf601b6e2cf859d0cedf9b6a730e2160d8f4
Author: Jason Merrill <ja...@redhat.com>
Date: Wed Jun 19 14:39:17 2013 -0400
* pt.c (process_partial_specialization): Build a TEMPLATE_DECL for
a partial specialization.
(tsubst_decl): Don't clobber CLASSTYPE_TI_TEMPLATE of a partial
specialization.
(most_specialized_class): Adjust.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 7896386..cf54acf 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -3739,11 +3739,10 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
specializations of this template. (Full specializations are not
recorded on this list.) The TREE_PURPOSE holds the arguments used
in the partial specialization (e.g., for `template <class T> struct
- S<T*, int>' this will be `T*'.) The arguments will also include
- any outer template arguments. The TREE_VALUE holds the innermost
- template parameters for the specialization (e.g., `T' in the
- example above.) The TREE_TYPE is the _TYPE node for the partial
- specialization.
+ S<T*, int>' this will be `T*, int'.) The arguments will also include
+ any outer template arguments. The TREE_VALUE holds the TEMPLATE_DECL
+ for the partial specialization. The TREE_TYPE is the _TYPE node for
+ the partial specialization.
This list is not used for other templates. */
#define DECL_TEMPLATE_SPECIALIZATIONS(NODE) \
@@ -3813,9 +3812,10 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
#define SET_DECL_SELF_REFERENCE_P(NODE) \
(DECL_LANG_FLAG_4 (NODE) = 1)
-/* A `primary' template is one that has its own template header. A
- member function of a class template is a template, but not primary.
- A member template is primary. Friend templates are primary, too. */
+/* A `primary' template is one that has its own template header and is not
+ a partial specialization. A member function of a class template is a
+ template, but not primary. A member template is primary. Friend
+ templates are primary, too. */
/* Returns the primary template corresponding to these parameters. */
#define DECL_PRIMARY_TEMPLATE(NODE) \
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 5e3cf07..4a0f411 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -4246,8 +4246,16 @@ process_partial_specialization (tree decl)
/* We should only get here once. */
gcc_assert (!COMPLETE_TYPE_P (type));
+ tree tmpl = build_template_decl (decl, current_template_parms,
+ DECL_MEMBER_TEMPLATE_P (maintmpl));
+ TREE_TYPE (tmpl) = type;
+ DECL_TEMPLATE_RESULT (tmpl) = decl;
+ SET_DECL_TEMPLATE_SPECIALIZATION (tmpl);
+ DECL_TEMPLATE_INFO (tmpl) = build_template_info (maintmpl, specargs);
+ DECL_PRIMARY_TEMPLATE (tmpl) = maintmpl;
+
DECL_TEMPLATE_SPECIALIZATIONS (maintmpl)
- = tree_cons (specargs, inner_parms,
+ = tree_cons (specargs, tmpl,
DECL_TEMPLATE_SPECIALIZATIONS (maintmpl));
TREE_TYPE (DECL_TEMPLATE_SPECIALIZATIONS (maintmpl)) = type;
@@ -10091,7 +10099,10 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
RETURN (error_mark_node);
TREE_TYPE (r) = new_type;
- CLASSTYPE_TI_TEMPLATE (new_type) = r;
+ /* For a partial specialization, we need to keep pointing to
+ the primary template. */
+ if (!DECL_TEMPLATE_SPECIALIZATION (t))
+ CLASSTYPE_TI_TEMPLATE (new_type) = r;
DECL_TEMPLATE_RESULT (r) = TYPE_MAIN_DECL (new_type);
DECL_TI_ARGS (r) = CLASSTYPE_TI_ARGS (new_type);
DECL_CONTEXT (r) = TYPE_CONTEXT (new_type);
@@ -18115,7 +18126,8 @@ most_specialized_class (tree type, tree tmpl, tsubst_flags_t complain)
{
tree partial_spec_args;
tree spec_args;
- tree parms = TREE_VALUE (t);
+ tree spec_tmpl = TREE_VALUE (t);
+ tree orig_parms = DECL_INNERMOST_TEMPLATE_PARMS (spec_tmpl);
partial_spec_args = CLASSTYPE_TI_ARGS (TREE_TYPE (t));
@@ -18123,24 +18135,14 @@ most_specialized_class (tree type, tree tmpl, tsubst_flags_t complain)
if (outer_args)
{
- int i;
-
/* Discard the outer levels of args, and then substitute in the
template args from the enclosing class. */
partial_spec_args = INNERMOST_TEMPLATE_ARGS (partial_spec_args);
partial_spec_args = tsubst_template_args
(partial_spec_args, outer_args, tf_none, NULL_TREE);
- /* PARMS already refers to just the innermost parms, but the
- template parms in partial_spec_args had their levels lowered
- by tsubst, so we need to do the same for the parm list. We
- can't just tsubst the TREE_VEC itself, as tsubst wants to
- treat a TREE_VEC as an argument vector. */
- parms = copy_node (parms);
- for (i = TREE_VEC_LENGTH (parms) - 1; i >= 0; --i)
- TREE_VEC_ELT (parms, i) =
- tsubst (TREE_VEC_ELT (parms, i), outer_args, tf_none, NULL_TREE);
-
+ /* And the same for the partial specialization TEMPLATE_DECL. */
+ spec_tmpl = tsubst (spec_tmpl, outer_args, tf_none, NULL_TREE);
}
partial_spec_args =
@@ -18155,7 +18157,10 @@ most_specialized_class (tree type, tree tmpl, tsubst_flags_t complain)
if (partial_spec_args == error_mark_node)
return error_mark_node;
+ if (spec_tmpl == error_mark_node)
+ return error_mark_node;
+ tree parms = DECL_INNERMOST_TEMPLATE_PARMS (spec_tmpl);
spec_args = get_class_bindings (tmpl, parms,
partial_spec_args,
args);
@@ -18163,7 +18168,7 @@ most_specialized_class (tree type, tree tmpl, tsubst_flags_t complain)
{
if (outer_args)
spec_args = add_to_template_args (outer_args, spec_args);
- list = tree_cons (spec_args, TREE_VALUE (t), list);
+ list = tree_cons (spec_args, orig_parms, list);
TREE_TYPE (list) = TREE_TYPE (t);
}
}
commit 7e584dc2dbbfc6e4615601e432547b5325071197
Author: Jason Merrill <ja...@redhat.com>
Date: Wed Jun 19 14:35:45 2013 -0400
* cp-tree.h (DECL_TEMPLATE_PARMS, DECL_TEMPLATE_RESULT)
(DECL_TEMPLATE_INSTANTIATIONS, DECL_TEMPLATE_SPECIALIZATIONS): Use
TEMPLATE_DECL_CHECK.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 2931ac5..41ef24d 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -3683,13 +3683,15 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
TEMPLATE_PARM_INDEX for the parameter is available as the
DECL_INITIAL (for a PARM_DECL) or as the TREE_TYPE (for a
TYPE_DECL). */
-#define DECL_TEMPLATE_PARMS(NODE) DECL_NON_COMMON_CHECK (NODE)->decl_non_common.arguments
+#define DECL_TEMPLATE_PARMS(NODE) \
+ TEMPLATE_DECL_CHECK (NODE)->decl_non_common.arguments
#define DECL_INNERMOST_TEMPLATE_PARMS(NODE) \
INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (NODE))
#define DECL_NTPARMS(NODE) \
TREE_VEC_LENGTH (DECL_INNERMOST_TEMPLATE_PARMS (NODE))
/* For function, method, class-data templates. */
-#define DECL_TEMPLATE_RESULT(NODE) DECL_RESULT_FLD (NODE)
+#define DECL_TEMPLATE_RESULT(NODE) \
+ DECL_RESULT_FLD (TEMPLATE_DECL_CHECK (NODE))
/* For a function template at namespace scope, DECL_TEMPLATE_INSTANTIATIONS
lists all instantiations and specializations of the function so that
tsubst_friend_function can reassign them to another template if we find
@@ -3718,7 +3720,9 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
<class U> struct S1<T>::S2'.
This list is not used for other templates. */
-#define DECL_TEMPLATE_INSTANTIATIONS(NODE) DECL_VINDEX (NODE)
+#define DECL_TEMPLATE_INSTANTIATIONS(NODE) \
+ DECL_VINDEX (TEMPLATE_DECL_CHECK (NODE))
+
/* For a class template, this list contains the partial
specializations of this template. (Full specializations are not
recorded on this list.) The TREE_PURPOSE holds the arguments used
@@ -3730,7 +3734,8 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
specialization.
This list is not used for other templates. */
-#define DECL_TEMPLATE_SPECIALIZATIONS(NODE) DECL_SIZE (NODE)
+#define DECL_TEMPLATE_SPECIALIZATIONS(NODE) \
+ DECL_SIZE (TEMPLATE_DECL_CHECK (NODE))
/* Nonzero for a DECL which is actually a template parameter. Keep
these checks in ascending tree code order. */