Allow partial specialization of variable templates.

* cp-tree.h (TINFO_USED_TEMPLATE_ID): New.
	* decl.c (duplicate_decls): Copy it.
	* error.c (dump_decl) [TEMPLATE_ID_EXPR]: Handle variables.
	* parser.c (cp_parser_decltype_expr): Do call finish_id_expression
	on template-ids.
	* pt.c (register_specialization): Remember variable template insts.
	(instantiate_template_1): Find the matching partial specialization.
	(check_explicit_specialization): Allow variable partial specialization.
	(process_partial_specialization): Likewise.
	(push_template_decl_real): Likewise.
	(more_specialized_partial_spec): Rename from more_specialized_class.
	(most_specialized_partial_spec): Rename from most_specialized_class.
	(get_partial_spec_bindings): Rename from get_class_bindings.

From-SVN: r218104
This commit is contained in:
Jason Merrill 2014-11-26 16:58:38 -05:00 committed by Jason Merrill
parent d896cc4d45
commit a2033ab107
10 changed files with 214 additions and 76 deletions

View File

@ -1,3 +1,20 @@
2014-11-26 Jason Merrill <jason@redhat.com>
Allow partial specialization of variable templates.
* cp-tree.h (TINFO_USED_TEMPLATE_ID): New.
* decl.c (duplicate_decls): Copy it.
* error.c (dump_decl) [TEMPLATE_ID_EXPR]: Handle variables.
* parser.c (cp_parser_decltype_expr): Do call finish_id_expression
on template-ids.
* pt.c (register_specialization): Remember variable template insts.
(instantiate_template_1): Find the matching partial specialization.
(check_explicit_specialization): Allow variable partial specialization.
(process_partial_specialization): Likewise.
(push_template_decl_real): Likewise.
(more_specialized_partial_spec): Rename from more_specialized_class.
(most_specialized_partial_spec): Rename from most_specialized_class.
(get_partial_spec_bindings): Rename from get_class_bindings.
2014-11-26 Paolo Carlini <paolo.carlini@oracle.com> 2014-11-26 Paolo Carlini <paolo.carlini@oracle.com>
PR c++/63757 PR c++/63757

View File

@ -99,6 +99,7 @@ c-common.h, not after.
QUALIFIED_NAME_IS_TEMPLATE (in SCOPE_REF) QUALIFIED_NAME_IS_TEMPLATE (in SCOPE_REF)
DECLTYPE_FOR_INIT_CAPTURE (in DECLTYPE_TYPE) DECLTYPE_FOR_INIT_CAPTURE (in DECLTYPE_TYPE)
CONSTRUCTOR_NO_IMPLICIT_ZERO (in CONSTRUCTOR) CONSTRUCTOR_NO_IMPLICIT_ZERO (in CONSTRUCTOR)
TINFO_USED_TEMPLATE_ID (in TEMPLATE_INFO)
2: IDENTIFIER_OPNAME_P (in IDENTIFIER_NODE) 2: IDENTIFIER_OPNAME_P (in IDENTIFIER_NODE)
ICS_THIS_FLAG (in _CONV) ICS_THIS_FLAG (in _CONV)
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL) DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL)
@ -801,6 +802,12 @@ typedef struct qualified_typedef_usage_s qualified_typedef_usage_t;
#define FNDECL_HAS_ACCESS_ERRORS(NODE) \ #define FNDECL_HAS_ACCESS_ERRORS(NODE) \
(TINFO_HAS_ACCESS_ERRORS (DECL_TEMPLATE_INFO (NODE))) (TINFO_HAS_ACCESS_ERRORS (DECL_TEMPLATE_INFO (NODE)))
/* Non-zero if this variable template specialization was specified using a
template-id, so it's a partial or full specialization and not a definition
of the member template of a particular class specialization. */
#define TINFO_USED_TEMPLATE_ID(NODE) \
(TREE_LANG_FLAG_1 (TEMPLATE_INFO_CHECK (NODE)))
struct GTY(()) tree_template_info { struct GTY(()) tree_template_info {
struct tree_common common; struct tree_common common;
vec<qualified_typedef_usage_t, va_gc> *typedefs_needing_access_checking; vec<qualified_typedef_usage_t, va_gc> *typedefs_needing_access_checking;

View File

@ -2137,7 +2137,14 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
DECL_LANG_SPECIFIC (newdecl)->u.min.u2 = DECL_LANG_SPECIFIC (newdecl)->u.min.u2 =
DECL_LANG_SPECIFIC (olddecl)->u.min.u2; DECL_LANG_SPECIFIC (olddecl)->u.min.u2;
if (DECL_TEMPLATE_INFO (newdecl)) if (DECL_TEMPLATE_INFO (newdecl))
new_template_info = DECL_TEMPLATE_INFO (newdecl); {
new_template_info = DECL_TEMPLATE_INFO (newdecl);
if (DECL_TEMPLATE_INSTANTIATION (olddecl)
&& DECL_TEMPLATE_SPECIALIZATION (newdecl))
/* Remember the presence of explicit specialization args. */
TINFO_USED_TEMPLATE_ID (DECL_TEMPLATE_INFO (olddecl))
= TINFO_USED_TEMPLATE_ID (new_template_info);
}
DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl); DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl);
} }
/* Only functions have these fields. */ /* Only functions have these fields. */

View File

@ -1212,7 +1212,9 @@ dump_decl (cxx_pretty_printer *pp, tree t, int flags)
tree args = TREE_OPERAND (t, 1); tree args = TREE_OPERAND (t, 1);
if (is_overloaded_fn (name)) if (is_overloaded_fn (name))
name = DECL_NAME (get_first_fn (name)); name = get_first_fn (name);
if (DECL_P (name))
name = DECL_NAME (name);
dump_decl (pp, name, flags); dump_decl (pp, name, flags);
pp_cxx_begin_template_argument_list (pp); pp_cxx_begin_template_argument_list (pp);
if (args == error_mark_node) if (args == error_mark_node)

View File

@ -12175,7 +12175,6 @@ cp_parser_decltype_expr (cp_parser *parser,
if (expr if (expr
&& expr != error_mark_node && expr != error_mark_node
&& TREE_CODE (expr) != TEMPLATE_ID_EXPR
&& TREE_CODE (expr) != TYPE_DECL && TREE_CODE (expr) != TYPE_DECL
&& (TREE_CODE (expr) != BIT_NOT_EXPR && (TREE_CODE (expr) != BIT_NOT_EXPR
|| !TYPE_P (TREE_OPERAND (expr, 0))) || !TYPE_P (TREE_OPERAND (expr, 0)))

View File

@ -129,7 +129,7 @@ static int unify (tree, tree, tree, tree, int, bool);
static void add_pending_template (tree); static void add_pending_template (tree);
static tree reopen_tinst_level (struct tinst_level *); static tree reopen_tinst_level (struct tinst_level *);
static tree tsubst_initializer_list (tree, tree); static tree tsubst_initializer_list (tree, tree);
static tree get_class_bindings (tree, tree, tree, tree); static tree get_partial_spec_bindings (tree, tree, tree, tree);
static tree coerce_template_parms (tree, tree, tree, tsubst_flags_t, static tree coerce_template_parms (tree, tree, tree, tsubst_flags_t,
bool, bool); bool, bool);
static tree coerce_innermost_template_parms (tree, tree, tree, tsubst_flags_t, static tree coerce_innermost_template_parms (tree, tree, tree, tsubst_flags_t,
@ -173,7 +173,7 @@ static tree tsubst_template_arg (tree, tree, tsubst_flags_t, tree);
static tree tsubst_template_args (tree, tree, tsubst_flags_t, tree); static tree tsubst_template_args (tree, tree, tsubst_flags_t, tree);
static tree tsubst_template_parms (tree, tree, tsubst_flags_t); static tree tsubst_template_parms (tree, tree, tsubst_flags_t);
static void regenerate_decl_from_template (tree, tree); static void regenerate_decl_from_template (tree, tree);
static tree most_specialized_class (tree, tsubst_flags_t); static tree most_specialized_partial_spec (tree, tsubst_flags_t);
static tree tsubst_aggr_type (tree, tree, tsubst_flags_t, tree, int); static tree tsubst_aggr_type (tree, tree, tsubst_flags_t, tree, int);
static tree tsubst_arg_types (tree, tree, tree, tsubst_flags_t, tree); static tree tsubst_arg_types (tree, tree, tree, tsubst_flags_t, tree);
static tree tsubst_function_type (tree, tree, tsubst_flags_t, tree); static tree tsubst_function_type (tree, tree, tsubst_flags_t, tree);
@ -1485,12 +1485,17 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend,
gcc_assert (tmpl && args && spec); gcc_assert (tmpl && args && spec);
*entry = elt; *entry = elt;
*slot = entry; *slot = entry;
if (TREE_CODE (spec) == FUNCTION_DECL && DECL_NAMESPACE_SCOPE_P (spec) if ((TREE_CODE (spec) == FUNCTION_DECL && DECL_NAMESPACE_SCOPE_P (spec)
&& PRIMARY_TEMPLATE_P (tmpl) && PRIMARY_TEMPLATE_P (tmpl)
&& DECL_SAVED_TREE (DECL_TEMPLATE_RESULT (tmpl)) == NULL_TREE) && DECL_SAVED_TREE (DECL_TEMPLATE_RESULT (tmpl)) == NULL_TREE)
/* TMPL is a forward declaration of a template function; keep a list || variable_template_p (tmpl))
/* If TMPL is a forward declaration of a template function, keep a list
of all specializations in case we need to reassign them to a friend of all specializations in case we need to reassign them to a friend
template later in tsubst_friend_function. */ template later in tsubst_friend_function.
Also keep a list of all variable template instantiations so that
process_partial_specialization can check whether a later partial
specialization would have used it. */
DECL_TEMPLATE_INSTANTIATIONS (tmpl) DECL_TEMPLATE_INSTANTIATIONS (tmpl)
= tree_cons (args, spec, DECL_TEMPLATE_INSTANTIATIONS (tmpl)); = tree_cons (args, spec, DECL_TEMPLATE_INSTANTIATIONS (tmpl));
} }
@ -2471,13 +2476,24 @@ check_explicit_specialization (tree declarator,
/* This case handles bogus declarations like template <> /* This case handles bogus declarations like template <>
template <class T> void f<int>(); */ template <class T> void f<int>(); */
if (uses_template_parms (declarator)) if (!uses_template_parms (declarator))
error ("template-id %qD in declaration of primary template",
declarator);
else if (variable_template_p (TREE_OPERAND (declarator, 0)))
{
/* Partial specialization of variable template. */
SET_DECL_TEMPLATE_SPECIALIZATION (decl);
specialization = 1;
goto ok;
}
else if (cxx_dialect < cxx14)
error ("non-type partial specialization %qD " error ("non-type partial specialization %qD "
"is not allowed", declarator); "is not allowed", declarator);
else else
error ("template-id %qD in declaration of primary template", error ("non-class, non-variable partial specialization %qD "
declarator); "is not allowed", declarator);
return decl; return decl;
ok:;
} }
if (ctype && CLASSTYPE_TEMPLATE_INSTANTIATION (ctype)) if (ctype && CLASSTYPE_TEMPLATE_INSTANTIATION (ctype))
@ -2516,9 +2532,10 @@ check_explicit_specialization (tree declarator,
{ {
tree tmpl = NULL_TREE; tree tmpl = NULL_TREE;
tree targs = NULL_TREE; tree targs = NULL_TREE;
bool was_template_id = (TREE_CODE (declarator) == TEMPLATE_ID_EXPR);
/* Make sure that the declarator is a TEMPLATE_ID_EXPR. */ /* Make sure that the declarator is a TEMPLATE_ID_EXPR. */
if (TREE_CODE (declarator) != TEMPLATE_ID_EXPR) if (!was_template_id)
{ {
tree fns; tree fns;
@ -2585,7 +2602,7 @@ check_explicit_specialization (tree declarator,
else if (ctype != NULL_TREE else if (ctype != NULL_TREE
&& (identifier_p (TREE_OPERAND (declarator, 0)))) && (identifier_p (TREE_OPERAND (declarator, 0))))
{ {
// Ignore variable templates. // We'll match variable templates in start_decl.
if (VAR_P (decl)) if (VAR_P (decl))
return decl; return decl;
@ -2722,7 +2739,7 @@ check_explicit_specialization (tree declarator,
/* If this is a specialization of a member template of a /* If this is a specialization of a member template of a
template class, we want to return the TEMPLATE_DECL, not template class, we want to return the TEMPLATE_DECL, not
the specialization of it. */ the specialization of it. */
if (tsk == tsk_template) if (tsk == tsk_template && !was_template_id)
{ {
tree result = DECL_TEMPLATE_RESULT (tmpl); tree result = DECL_TEMPLATE_RESULT (tmpl);
SET_DECL_TEMPLATE_SPECIALIZATION (tmpl); SET_DECL_TEMPLATE_SPECIALIZATION (tmpl);
@ -2747,6 +2764,9 @@ check_explicit_specialization (tree declarator,
/* Set up the DECL_TEMPLATE_INFO for DECL. */ /* Set up the DECL_TEMPLATE_INFO for DECL. */
DECL_TEMPLATE_INFO (decl) = build_template_info (tmpl, targs); DECL_TEMPLATE_INFO (decl) = build_template_info (tmpl, targs);
if (was_template_id)
TINFO_USED_TEMPLATE_ID (DECL_TEMPLATE_INFO (decl)) = true;
/* Inherit default function arguments from the template /* Inherit default function arguments from the template
DECL is specializing. */ DECL is specializing. */
if (DECL_FUNCTION_TEMPLATE_P (tmpl)) if (DECL_FUNCTION_TEMPLATE_P (tmpl))
@ -4087,8 +4107,9 @@ static tree
process_partial_specialization (tree decl) process_partial_specialization (tree decl)
{ {
tree type = TREE_TYPE (decl); tree type = TREE_TYPE (decl);
tree maintmpl = CLASSTYPE_TI_TEMPLATE (type); tree tinfo = get_template_info (decl);
tree specargs = CLASSTYPE_TI_ARGS (type); tree maintmpl = TI_TEMPLATE (tinfo);
tree specargs = TI_ARGS (tinfo);
tree inner_args = INNERMOST_TEMPLATE_ARGS (specargs); tree inner_args = INNERMOST_TEMPLATE_ARGS (specargs);
tree main_inner_parms = DECL_INNERMOST_TEMPLATE_PARMS (maintmpl); tree main_inner_parms = DECL_INNERMOST_TEMPLATE_PARMS (maintmpl);
tree inner_parms; tree inner_parms;
@ -4173,11 +4194,11 @@ process_partial_specialization (tree decl)
The argument list of the specialization shall not be identical to The argument list of the specialization shall not be identical to
the implicit argument list of the primary template. */ the implicit argument list of the primary template. */
if (comp_template_args tree main_args
(inner_args, = TI_ARGS (get_template_info (DECL_TEMPLATE_RESULT (maintmpl)));
INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (TREE_TYPE if (comp_template_args (inner_args, INNERMOST_TEMPLATE_ARGS (main_args)))
(maintmpl))))) error ("partial specialization %qD does not specialize "
error ("partial specialization %qT does not specialize any template arguments", type); "any template arguments", decl);
/* A partial specialization that replaces multiple parameters of the /* A partial specialization that replaces multiple parameters of the
primary template with a pack expansion is less specialized for those primary template with a pack expansion is less specialized for those
@ -4317,7 +4338,8 @@ process_partial_specialization (tree decl)
} }
/* We should only get here once. */ /* We should only get here once. */
gcc_assert (!COMPLETE_TYPE_P (type)); if (TREE_CODE (decl) == TYPE_DECL)
gcc_assert (!COMPLETE_TYPE_P (type));
tree tmpl = build_template_decl (decl, current_template_parms, tree tmpl = build_template_decl (decl, current_template_parms,
DECL_MEMBER_TEMPLATE_P (maintmpl)); DECL_MEMBER_TEMPLATE_P (maintmpl));
@ -4335,15 +4357,21 @@ process_partial_specialization (tree decl)
for (inst = DECL_TEMPLATE_INSTANTIATIONS (maintmpl); inst; for (inst = DECL_TEMPLATE_INSTANTIATIONS (maintmpl); inst;
inst = TREE_CHAIN (inst)) inst = TREE_CHAIN (inst))
{ {
tree inst_type = TREE_VALUE (inst); tree instance = TREE_VALUE (inst);
if (COMPLETE_TYPE_P (inst_type) if (TYPE_P (instance)
&& CLASSTYPE_IMPLICIT_INSTANTIATION (inst_type)) ? (COMPLETE_TYPE_P (instance)
&& CLASSTYPE_IMPLICIT_INSTANTIATION (instance))
: DECL_TEMPLATE_INSTANTIATION (instance))
{ {
tree spec = most_specialized_class (inst_type, tf_none); tree spec = most_specialized_partial_spec (instance, tf_none);
if (spec && TREE_TYPE (spec) == type) if (spec && TREE_VALUE (spec) == tmpl)
permerror (input_location, {
"partial specialization of %qT after instantiation " tree inst_decl = (DECL_P (instance)
"of %qT", type, inst_type); ? instance : TYPE_NAME (instance));
permerror (input_location,
"partial specialization of %qD after instantiation "
"of %qD", decl, inst_decl);
}
} }
} }
@ -4692,9 +4720,13 @@ push_template_decl_real (tree decl, bool is_friend)
return error_mark_node; return error_mark_node;
/* See if this is a partial specialization. */ /* See if this is a partial specialization. */
is_partial = (DECL_IMPLICIT_TYPEDEF_P (decl) is_partial = ((DECL_IMPLICIT_TYPEDEF_P (decl)
&& TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE && TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE
&& CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (decl))); && CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (decl)))
|| (TREE_CODE (decl) == VAR_DECL
&& DECL_LANG_SPECIFIC (decl)
&& DECL_TEMPLATE_SPECIALIZATION (decl)
&& TINFO_USED_TEMPLATE_ID (DECL_TEMPLATE_INFO (decl))));
if (TREE_CODE (decl) == FUNCTION_DECL && DECL_FRIEND_P (decl)) if (TREE_CODE (decl) == FUNCTION_DECL && DECL_FRIEND_P (decl))
is_friend = true; is_friend = true;
@ -9057,7 +9089,7 @@ instantiate_class_template_1 (tree type)
/* Determine what specialization of the original template to /* Determine what specialization of the original template to
instantiate. */ instantiate. */
t = most_specialized_class (type, tf_warning_or_error); t = most_specialized_partial_spec (type, tf_warning_or_error);
if (t == error_mark_node) if (t == error_mark_node)
{ {
TYPE_BEING_DEFINED (type) = 1; TYPE_BEING_DEFINED (type) = 1;
@ -10519,7 +10551,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
if (new_type == error_mark_node) if (new_type == error_mark_node)
RETURN (error_mark_node); RETURN (error_mark_node);
/* If we get a real template back, return it. This can happen in /* If we get a real template back, return it. This can happen in
the context of most_specialized_class. */ the context of most_specialized_partial_spec. */
if (TREE_CODE (new_type) == TEMPLATE_DECL) if (TREE_CODE (new_type) == TEMPLATE_DECL)
return new_type; return new_type;
@ -15878,9 +15910,28 @@ instantiate_template_1 (tree tmpl, tree orig_args, tsubst_flags_t complain)
complain, gen_tmpl, true); complain, gen_tmpl, true);
push_nested_class (ctx); push_nested_class (ctx);
} }
tree pattern = DECL_TEMPLATE_RESULT (gen_tmpl);
if (VAR_P (pattern))
{
/* We need to determine if we're using a partial or explicit
specialization now, because the type of the variable could be
different. */
tree tid = lookup_template_variable (gen_tmpl, targ_ptr);
tree elt = most_specialized_partial_spec (tid, complain);
if (elt == error_mark_node)
pattern = error_mark_node;
else if (elt)
{
tmpl = TREE_VALUE (elt);
pattern = DECL_TEMPLATE_RESULT (tmpl);
targ_ptr = TREE_PURPOSE (elt);
}
}
/* Substitute template parameters to obtain the specialization. */ /* Substitute template parameters to obtain the specialization. */
fndecl = tsubst (DECL_TEMPLATE_RESULT (gen_tmpl), fndecl = tsubst (pattern, targ_ptr, complain, gen_tmpl);
targ_ptr, complain, gen_tmpl);
if (DECL_CLASS_SCOPE_P (gen_tmpl)) if (DECL_CLASS_SCOPE_P (gen_tmpl))
pop_nested_class (); pop_nested_class ();
pop_from_top_level (); pop_from_top_level ();
@ -18881,8 +18932,8 @@ more_specialized_fn (tree pat1, tree pat2, int len)
/* Determine which of two partial specializations of TMPL is more /* Determine which of two partial specializations of TMPL is more
specialized. specialized.
PAT1 is a TREE_LIST whose TREE_TYPE is the _TYPE node corresponding PAT1 is a TREE_LIST whose TREE_VALUE is the TEMPLATE_DECL corresponding
to the first partial specialization. The TREE_VALUE is the to the first partial specialization. The TREE_PURPOSE is the
innermost set of template parameters for the partial innermost set of template parameters for the partial
specialization. PAT2 is similar, but for the second template. specialization. PAT2 is similar, but for the second template.
@ -18894,33 +18945,32 @@ more_specialized_fn (tree pat1, tree pat2, int len)
two templates is more specialized. */ two templates is more specialized. */
static int static int
more_specialized_class (tree tmpl, tree pat1, tree pat2) more_specialized_partial_spec (tree tmpl, tree pat1, tree pat2)
{ {
tree targs; tree targs;
tree tmpl1, tmpl2;
int winner = 0; int winner = 0;
bool any_deductions = false; bool any_deductions = false;
tmpl1 = TREE_TYPE (pat1); tree tmpl1 = TREE_VALUE (pat1);
tmpl2 = TREE_TYPE (pat2); tree tmpl2 = TREE_VALUE (pat2);
tree parms1 = DECL_INNERMOST_TEMPLATE_PARMS (tmpl1);
tree parms2 = DECL_INNERMOST_TEMPLATE_PARMS (tmpl2);
tree specargs1 = TI_ARGS (get_template_info (DECL_TEMPLATE_RESULT (tmpl1)));
tree specargs2 = TI_ARGS (get_template_info (DECL_TEMPLATE_RESULT (tmpl2)));
/* Just like what happens for functions, if we are ordering between /* Just like what happens for functions, if we are ordering between
different class template specializations, we may encounter dependent different template specializations, we may encounter dependent
types in the arguments, and we need our dependency check functions types in the arguments, and we need our dependency check functions
to behave correctly. */ to behave correctly. */
++processing_template_decl; ++processing_template_decl;
targs = get_class_bindings (tmpl, TREE_VALUE (pat1), targs = get_partial_spec_bindings (tmpl, parms1, specargs1, specargs2);
CLASSTYPE_TI_ARGS (tmpl1),
CLASSTYPE_TI_ARGS (tmpl2));
if (targs) if (targs)
{ {
--winner; --winner;
any_deductions = true; any_deductions = true;
} }
targs = get_class_bindings (tmpl, TREE_VALUE (pat2), targs = get_partial_spec_bindings (tmpl, parms2, specargs2, specargs1);
CLASSTYPE_TI_ARGS (tmpl2),
CLASSTYPE_TI_ARGS (tmpl1));
if (targs) if (targs)
{ {
++winner; ++winner;
@ -18928,7 +18978,7 @@ more_specialized_class (tree tmpl, tree pat1, tree pat2)
} }
--processing_template_decl; --processing_template_decl;
/* In the case of a tie where at least one of the class templates /* In the case of a tie where at least one of the templates
has a parameter pack at the end, the template with the most has a parameter pack at the end, the template with the most
non-packed parameters wins. */ non-packed parameters wins. */
if (winner == 0 if (winner == 0
@ -19014,7 +19064,7 @@ get_bindings (tree fn, tree decl, tree explicit_args, bool check_rettype)
is bound to `double'. */ is bound to `double'. */
static tree static tree
get_class_bindings (tree tmpl, tree tparms, tree spec_args, tree args) get_partial_spec_bindings (tree tmpl, tree tparms, tree spec_args, tree args)
{ {
int i, ntparms = TREE_VEC_LENGTH (tparms); int i, ntparms = TREE_VEC_LENGTH (tparms);
tree deduced_args; tree deduced_args;
@ -19197,20 +19247,20 @@ most_general_template (tree decl)
return decl; return decl;
} }
/* Return the most specialized of the class template partial /* Return the most specialized of the template partial specializations
specializations which can produce TYPE, a specialization of some class which can produce TARGET, a specialization of some class or variable
template. The value returned is actually a TREE_LIST; the TREE_TYPE is template. The value returned is actually a TREE_LIST; the TREE_VALUE is
a _TYPE node corresponding to the partial specialization, while the a TEMPLATE_DECL node corresponding to the partial specialization, while
TREE_PURPOSE is the set of template arguments that must be the TREE_PURPOSE is the set of template arguments that must be
substituted into the TREE_TYPE in order to generate TYPE. substituted into the template pattern in order to generate TARGET.
If the choice of partial specialization is ambiguous, a diagnostic If the choice of partial specialization is ambiguous, a diagnostic
is issued, and the error_mark_node is returned. If there are no is issued, and the error_mark_node is returned. If there are no
partial specializations matching TYPE, then NULL_TREE is partial specializations matching TARGET, then NULL_TREE is
returned, indicating that the primary template should be used. */ returned, indicating that the primary template should be used. */
static tree static tree
most_specialized_class (tree type, tsubst_flags_t complain) most_specialized_partial_spec (tree target, tsubst_flags_t complain)
{ {
tree list = NULL_TREE; tree list = NULL_TREE;
tree t; tree t;
@ -19218,10 +19268,29 @@ most_specialized_class (tree type, tsubst_flags_t complain)
int fate; int fate;
bool ambiguous_p; bool ambiguous_p;
tree outer_args = NULL_TREE; tree outer_args = NULL_TREE;
tree tmpl, args;
if (TYPE_P (target))
{
tree tinfo = CLASSTYPE_TEMPLATE_INFO (target);
tmpl = TI_TEMPLATE (tinfo);
args = TI_ARGS (tinfo);
}
else if (TREE_CODE (target) == TEMPLATE_ID_EXPR)
{
tmpl = TREE_OPERAND (target, 0);
args = TREE_OPERAND (target, 1);
}
else if (VAR_P (target))
{
tree tinfo = DECL_TEMPLATE_INFO (target);
tmpl = TI_TEMPLATE (tinfo);
args = TI_ARGS (tinfo);
}
else
gcc_unreachable ();
tree tmpl = CLASSTYPE_TI_TEMPLATE (type);
tree main_tmpl = most_general_template (tmpl); tree main_tmpl = most_general_template (tmpl);
tree args = CLASSTYPE_TI_ARGS (type);
/* For determining which partial specialization to use, only the /* For determining which partial specialization to use, only the
innermost args are interesting. */ innermost args are interesting. */
@ -19236,9 +19305,8 @@ most_specialized_class (tree type, tsubst_flags_t complain)
tree partial_spec_args; tree partial_spec_args;
tree spec_args; tree spec_args;
tree spec_tmpl = 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)); partial_spec_args = TREE_PURPOSE (t);
++processing_template_decl; ++processing_template_decl;
@ -19269,14 +19337,14 @@ most_specialized_class (tree type, tsubst_flags_t complain)
return error_mark_node; return error_mark_node;
tree parms = DECL_INNERMOST_TEMPLATE_PARMS (spec_tmpl); tree parms = DECL_INNERMOST_TEMPLATE_PARMS (spec_tmpl);
spec_args = get_class_bindings (tmpl, parms, spec_args = get_partial_spec_bindings (tmpl, parms,
partial_spec_args, partial_spec_args,
args); args);
if (spec_args) if (spec_args)
{ {
if (outer_args) if (outer_args)
spec_args = add_to_template_args (outer_args, spec_args); spec_args = add_to_template_args (outer_args, spec_args);
list = tree_cons (spec_args, orig_parms, list); list = tree_cons (spec_args, TREE_VALUE (t), list);
TREE_TYPE (list) = TREE_TYPE (t); TREE_TYPE (list) = TREE_TYPE (t);
} }
} }
@ -19290,7 +19358,7 @@ most_specialized_class (tree type, tsubst_flags_t complain)
t = TREE_CHAIN (t); t = TREE_CHAIN (t);
for (; t; t = TREE_CHAIN (t)) for (; t; t = TREE_CHAIN (t))
{ {
fate = more_specialized_class (tmpl, champ, t); fate = more_specialized_partial_spec (tmpl, champ, t);
if (fate == 1) if (fate == 1)
; ;
else else
@ -19311,7 +19379,7 @@ most_specialized_class (tree type, tsubst_flags_t complain)
if (!ambiguous_p) if (!ambiguous_p)
for (t = list; t && t != champ; t = TREE_CHAIN (t)) for (t = list; t && t != champ; t = TREE_CHAIN (t))
{ {
fate = more_specialized_class (tmpl, champ, t); fate = more_specialized_partial_spec (tmpl, champ, t);
if (fate != 1) if (fate != 1)
{ {
ambiguous_p = true; ambiguous_p = true;
@ -19325,11 +19393,16 @@ most_specialized_class (tree type, tsubst_flags_t complain)
char *spaces = NULL; char *spaces = NULL;
if (!(complain & tf_error)) if (!(complain & tf_error))
return error_mark_node; return error_mark_node;
error ("ambiguous class template instantiation for %q#T", type); if (TYPE_P (target))
error ("ambiguous template instantiation for %q#T", target);
else
error ("ambiguous template instantiation for %q#D", target);
str = ngettext ("candidate is:", "candidates are:", list_length (list)); str = ngettext ("candidate is:", "candidates are:", list_length (list));
for (t = list; t; t = TREE_CHAIN (t)) for (t = list; t; t = TREE_CHAIN (t))
{ {
error ("%s %+#T", spaces ? spaces : str, TREE_TYPE (t)); tree subst = build_tree_list (TREE_VALUE (t), TREE_PURPOSE (t));
inform (DECL_SOURCE_LOCATION (TREE_VALUE (t)),
"%s %#S", spaces ? spaces : str, subst);
spaces = spaces ? spaces : get_spaces (str); spaces = spaces ? spaces : get_spaces (str);
} }
free (spaces); free (spaces);

View File

@ -13,25 +13,25 @@ struct metatuple<add_pointer> {
}; };
template<template<class T> class Meta> template<template<class T> class Meta>
struct metatuple<Meta, Meta> { // { dg-error "candidates" } struct metatuple<Meta, Meta> { // { dg-message "candidates" }
static const int value = 2; static const int value = 2;
}; };
template<template<class T> class... Metafunctions> template<template<class T> class... Metafunctions>
struct metatuple<add_pointer, Metafunctions...> { // { dg-error "" } struct metatuple<add_pointer, Metafunctions...> { // { dg-message "" }
static const int value = 3; static const int value = 3;
}; };
template<template<class T> class First, template<template<class T> class First,
template<class T> class... Metafunctions> template<class T> class... Metafunctions>
struct metatuple<First, Metafunctions...> { // { dg-error "struct" } struct metatuple<First, Metafunctions...> { // { dg-message "struct" }
static const int value = 4; static const int value = 4;
}; };
template<template<class T> class First, template<template<class T> class First,
template<class T> class Second, template<class T> class Second,
template<class T> class... Metafunctions> template<class T> class... Metafunctions>
struct metatuple<First, Second, Metafunctions...> { // { dg-error "struct" } struct metatuple<First, Second, Metafunctions...> { // { dg-message "struct" }
static const int value = 5; static const int value = 5;
}; };

View File

@ -0,0 +1,6 @@
// { dg-do compile { target c++14 } }
template <class T> T t = 42;
template <class T> T* t<T*> = nullptr;
void *p = t<void*>;

View File

@ -0,0 +1,9 @@
// DR 1727: a specialization doesn't need to have the same type
// { dg-do compile { target c++14 } }
template <class T> T t = 42;
template <class T> int t<T*> = 0;
template<class T, class U> struct same;
template<class T> struct same<T,T> {};
same<int,decltype(t<void*>)> s;

View File

@ -0,0 +1,18 @@
// { dg-do compile { target c++14 } }
template <class T> T t1 = 42;
template <class T> T* t1<T> = nullptr; // { dg-error "partial" }
template <class T> T t2 = 42;
template <class T> T* t2<T*> = nullptr;
template <class T> T* t2<T*> = nullptr; // { dg-error "redefinition" }
template <class T, class U> T t3 = U();
template <class T> T t3<T,int> = 42;
template <class U> int t3<int,U> = U();
int i = t3<int,int>; // { dg-error "ambiguous" }
template <class T> T t4 = T();
void *p = t4<void*>;
template <class T> T* t4<T*> = nullptr; // { dg-error "after instantiation" }