From a2033ab1071bd77d1bde659c9b1a0f00e85cc6bf Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 26 Nov 2014 16:58:38 -0500 Subject: 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 --- gcc/cp/ChangeLog | 17 +++++ gcc/cp/cp-tree.h | 7 ++ gcc/cp/decl.c | 9 ++- gcc/cp/error.c | 4 +- gcc/cp/parser.c | 1 - gcc/cp/pt.c | 211 +++++++++++++++++++++++++++++++++++++------------------ 6 files changed, 177 insertions(+), 72 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 756c8d8..9c64279 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,20 @@ +2014-11-26 Jason Merrill + + 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 PR c++/63757 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index f1064e9..edd1d5d 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -99,6 +99,7 @@ c-common.h, not after. QUALIFIED_NAME_IS_TEMPLATE (in SCOPE_REF) DECLTYPE_FOR_INIT_CAPTURE (in DECLTYPE_TYPE) CONSTRUCTOR_NO_IMPLICIT_ZERO (in CONSTRUCTOR) + TINFO_USED_TEMPLATE_ID (in TEMPLATE_INFO) 2: IDENTIFIER_OPNAME_P (in IDENTIFIER_NODE) ICS_THIS_FLAG (in _CONV) 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) \ (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 tree_common common; vec *typedefs_needing_access_checking; diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 4ce4645..455097e 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -2137,7 +2137,14 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) DECL_LANG_SPECIFIC (newdecl)->u.min.u2 = DECL_LANG_SPECIFIC (olddecl)->u.min.u2; 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); } /* Only functions have these fields. */ diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 7d79771..5dcc149 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -1212,7 +1212,9 @@ dump_decl (cxx_pretty_printer *pp, tree t, int flags) tree args = TREE_OPERAND (t, 1); 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); pp_cxx_begin_template_argument_list (pp); if (args == error_mark_node) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index b8e182a..d1cd63f 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -12175,7 +12175,6 @@ cp_parser_decltype_expr (cp_parser *parser, if (expr && expr != error_mark_node - && TREE_CODE (expr) != TEMPLATE_ID_EXPR && TREE_CODE (expr) != TYPE_DECL && (TREE_CODE (expr) != BIT_NOT_EXPR || !TYPE_P (TREE_OPERAND (expr, 0))) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 29fb2e1..8e71fcb 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -129,7 +129,7 @@ static int unify (tree, tree, tree, tree, int, bool); static void add_pending_template (tree); static tree reopen_tinst_level (struct tinst_level *); 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, bool, bool); 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_parms (tree, tree, tsubst_flags_t); 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_arg_types (tree, 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); *entry = elt; *slot = entry; - if (TREE_CODE (spec) == FUNCTION_DECL && DECL_NAMESPACE_SCOPE_P (spec) - && PRIMARY_TEMPLATE_P (tmpl) - && DECL_SAVED_TREE (DECL_TEMPLATE_RESULT (tmpl)) == NULL_TREE) - /* TMPL is a forward declaration of a template function; keep a list + if ((TREE_CODE (spec) == FUNCTION_DECL && DECL_NAMESPACE_SCOPE_P (spec) + && PRIMARY_TEMPLATE_P (tmpl) + && DECL_SAVED_TREE (DECL_TEMPLATE_RESULT (tmpl)) == NULL_TREE) + || 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 - 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) = tree_cons (args, spec, DECL_TEMPLATE_INSTANTIATIONS (tmpl)); } @@ -2471,13 +2476,24 @@ check_explicit_specialization (tree declarator, /* This case handles bogus declarations like template <> template void f(); */ - 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 " "is not allowed", declarator); else - error ("template-id %qD in declaration of primary template", - declarator); + error ("non-class, non-variable partial specialization %qD " + "is not allowed", declarator); return decl; + ok:; } if (ctype && CLASSTYPE_TEMPLATE_INSTANTIATION (ctype)) @@ -2516,9 +2532,10 @@ check_explicit_specialization (tree declarator, { tree tmpl = 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. */ - if (TREE_CODE (declarator) != TEMPLATE_ID_EXPR) + if (!was_template_id) { tree fns; @@ -2585,7 +2602,7 @@ check_explicit_specialization (tree declarator, else if (ctype != NULL_TREE && (identifier_p (TREE_OPERAND (declarator, 0)))) { - // Ignore variable templates. + // We'll match variable templates in start_decl. if (VAR_P (decl)) return decl; @@ -2722,7 +2739,7 @@ check_explicit_specialization (tree declarator, /* If this is a specialization of a member template of a template class, we want to return the TEMPLATE_DECL, not the specialization of it. */ - if (tsk == tsk_template) + if (tsk == tsk_template && !was_template_id) { tree result = DECL_TEMPLATE_RESULT (tmpl); SET_DECL_TEMPLATE_SPECIALIZATION (tmpl); @@ -2747,6 +2764,9 @@ check_explicit_specialization (tree declarator, /* Set up the DECL_TEMPLATE_INFO for DECL. */ 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 DECL is specializing. */ if (DECL_FUNCTION_TEMPLATE_P (tmpl)) @@ -4087,8 +4107,9 @@ static tree process_partial_specialization (tree decl) { tree type = TREE_TYPE (decl); - tree maintmpl = CLASSTYPE_TI_TEMPLATE (type); - tree specargs = CLASSTYPE_TI_ARGS (type); + tree tinfo = get_template_info (decl); + tree maintmpl = TI_TEMPLATE (tinfo); + tree specargs = TI_ARGS (tinfo); tree inner_args = INNERMOST_TEMPLATE_ARGS (specargs); tree main_inner_parms = DECL_INNERMOST_TEMPLATE_PARMS (maintmpl); tree inner_parms; @@ -4173,11 +4194,11 @@ process_partial_specialization (tree decl) The argument list of the specialization shall not be identical to the implicit argument list of the primary template. */ - if (comp_template_args - (inner_args, - INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (TREE_TYPE - (maintmpl))))) - error ("partial specialization %qT does not specialize any template arguments", type); + tree main_args + = TI_ARGS (get_template_info (DECL_TEMPLATE_RESULT (maintmpl))); + if (comp_template_args (inner_args, INNERMOST_TEMPLATE_ARGS (main_args))) + error ("partial specialization %qD does not specialize " + "any template arguments", decl); /* A partial specialization that replaces multiple parameters of the 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. */ - 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, DECL_MEMBER_TEMPLATE_P (maintmpl)); @@ -4335,15 +4357,21 @@ process_partial_specialization (tree decl) for (inst = DECL_TEMPLATE_INSTANTIATIONS (maintmpl); inst; inst = TREE_CHAIN (inst)) { - tree inst_type = TREE_VALUE (inst); - if (COMPLETE_TYPE_P (inst_type) - && CLASSTYPE_IMPLICIT_INSTANTIATION (inst_type)) + tree instance = TREE_VALUE (inst); + if (TYPE_P (instance) + ? (COMPLETE_TYPE_P (instance) + && CLASSTYPE_IMPLICIT_INSTANTIATION (instance)) + : DECL_TEMPLATE_INSTANTIATION (instance)) { - tree spec = most_specialized_class (inst_type, tf_none); - if (spec && TREE_TYPE (spec) == type) - permerror (input_location, - "partial specialization of %qT after instantiation " - "of %qT", type, inst_type); + tree spec = most_specialized_partial_spec (instance, tf_none); + if (spec && TREE_VALUE (spec) == tmpl) + { + tree inst_decl = (DECL_P (instance) + ? 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; /* See if this is a partial specialization. */ - is_partial = (DECL_IMPLICIT_TYPEDEF_P (decl) - && TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE - && CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (decl))); + is_partial = ((DECL_IMPLICIT_TYPEDEF_P (decl) + && TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE + && 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)) is_friend = true; @@ -9057,7 +9089,7 @@ instantiate_class_template_1 (tree type) /* Determine what specialization of the original template to 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) { 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) RETURN (error_mark_node); /* 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) return new_type; @@ -15878,9 +15910,28 @@ instantiate_template_1 (tree tmpl, tree orig_args, tsubst_flags_t complain) complain, gen_tmpl, true); 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. */ - fndecl = tsubst (DECL_TEMPLATE_RESULT (gen_tmpl), - targ_ptr, complain, gen_tmpl); + fndecl = tsubst (pattern, targ_ptr, complain, gen_tmpl); if (DECL_CLASS_SCOPE_P (gen_tmpl)) pop_nested_class (); 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 specialized. - PAT1 is a TREE_LIST whose TREE_TYPE is the _TYPE node corresponding - to the first partial specialization. The TREE_VALUE is the + PAT1 is a TREE_LIST whose TREE_VALUE is the TEMPLATE_DECL corresponding + to the first partial specialization. The TREE_PURPOSE is the innermost set of template parameters for the partial 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. */ static int -more_specialized_class (tree tmpl, tree pat1, tree pat2) +more_specialized_partial_spec (tree tmpl, tree pat1, tree pat2) { tree targs; - tree tmpl1, tmpl2; int winner = 0; bool any_deductions = false; - tmpl1 = TREE_TYPE (pat1); - tmpl2 = TREE_TYPE (pat2); + tree tmpl1 = TREE_VALUE (pat1); + 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 - 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 to behave correctly. */ ++processing_template_decl; - targs = get_class_bindings (tmpl, TREE_VALUE (pat1), - CLASSTYPE_TI_ARGS (tmpl1), - CLASSTYPE_TI_ARGS (tmpl2)); + targs = get_partial_spec_bindings (tmpl, parms1, specargs1, specargs2); if (targs) { --winner; any_deductions = true; } - targs = get_class_bindings (tmpl, TREE_VALUE (pat2), - CLASSTYPE_TI_ARGS (tmpl2), - CLASSTYPE_TI_ARGS (tmpl1)); + targs = get_partial_spec_bindings (tmpl, parms2, specargs2, specargs1); if (targs) { ++winner; @@ -18928,7 +18978,7 @@ more_specialized_class (tree tmpl, tree pat1, tree pat2) } --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 non-packed parameters wins. */ if (winner == 0 @@ -19014,7 +19064,7 @@ get_bindings (tree fn, tree decl, tree explicit_args, bool check_rettype) is bound to `double'. */ 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); tree deduced_args; @@ -19197,20 +19247,20 @@ most_general_template (tree decl) return decl; } -/* Return the most specialized of the class template partial - specializations which can produce TYPE, a specialization of some class - template. The value returned is actually a TREE_LIST; the TREE_TYPE is - a _TYPE node corresponding to the partial specialization, while the - TREE_PURPOSE is the set of template arguments that must be - substituted into the TREE_TYPE in order to generate TYPE. +/* Return the most specialized of the template partial specializations + which can produce TARGET, a specialization of some class or variable + template. The value returned is actually a TREE_LIST; the TREE_VALUE is + a TEMPLATE_DECL node corresponding to the partial specialization, while + the TREE_PURPOSE is the set of template arguments that must be + substituted into the template pattern in order to generate TARGET. If the choice of partial specialization is ambiguous, a diagnostic 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. */ 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 t; @@ -19218,10 +19268,29 @@ most_specialized_class (tree type, tsubst_flags_t complain) int fate; bool ambiguous_p; 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 args = CLASSTYPE_TI_ARGS (type); /* For determining which partial specialization to use, only the innermost args are interesting. */ @@ -19236,9 +19305,8 @@ most_specialized_class (tree type, tsubst_flags_t complain) tree partial_spec_args; tree spec_args; 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; @@ -19269,14 +19337,14 @@ most_specialized_class (tree type, tsubst_flags_t complain) return error_mark_node; 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, args); if (spec_args) { if (outer_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); } } @@ -19290,7 +19358,7 @@ most_specialized_class (tree type, tsubst_flags_t complain) 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) ; else @@ -19311,7 +19379,7 @@ most_specialized_class (tree type, tsubst_flags_t complain) if (!ambiguous_p) 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) { ambiguous_p = true; @@ -19325,11 +19393,16 @@ most_specialized_class (tree type, tsubst_flags_t complain) char *spaces = NULL; if (!(complain & tf_error)) 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)); 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); } free (spaces); -- cgit v1.1