Commit cd057e3a by Jason Merrill Committed by Jason Merrill

PR c++/51213 (again)

	PR c++/51213 (again)
	* pt.c (deduction_tsubst_fntype): Remove.
	(fn_type_unification): Check deduction depth and call
	instantiate_template here.  Handle default argument access checks.
	(determine_specialization): Suppress access control.
	(tsubst_decl): Check for excessive deduction depth.
	(recheck_decl_substitution): Make sure access control is on.
	(type_unification_real): Don't mess with access deferring here.
	(get_bindings): Adjust for fn_type_unification return type.
	* call.c (enum rejection_reason_code): Drop rr_template_instantiation.
	(template_instantiation_rejection): Remove.
	(struct rejection_reason): Change targs to num_targs.
	(template_unification_rejection, print_z_candidate): Adjust.
	(add_template_candidate_real): Adjust for fn_type_unification change.
	* class.c (resolve_address_of_overloaded_function): Likewise.
	* cp-tree.h: Adjust declaration.

From-SVN: r190664
parent f581a987
2012-08-24 Jason Merrill <jason@redhat.com> 2012-08-24 Jason Merrill <jason@redhat.com>
PR c++/51213 (again)
* pt.c (deduction_tsubst_fntype): Remove.
(fn_type_unification): Check deduction depth and call
instantiate_template here. Handle default argument access checks.
(determine_specialization): Suppress access control.
(tsubst_decl): Check for excessive deduction depth.
(recheck_decl_substitution): Make sure access control is on.
(type_unification_real): Don't mess with access deferring here.
(get_bindings): Adjust for fn_type_unification return type.
* call.c (enum rejection_reason_code): Drop rr_template_instantiation.
(template_instantiation_rejection): Remove.
(struct rejection_reason): Change targs to num_targs.
(template_unification_rejection, print_z_candidate): Adjust.
(add_template_candidate_real): Adjust for fn_type_unification change.
* class.c (resolve_address_of_overloaded_function): Likewise.
* cp-tree.h: Adjust declaration.
* pt.c (tsubst_default_argument): Indicate where the default * pt.c (tsubst_default_argument): Indicate where the default
argument is being instantiated for. argument is being instantiated for.
(tsubst_expr): Restore previous location. (tsubst_expr): Restore previous location.
......
...@@ -451,7 +451,6 @@ enum rejection_reason_code { ...@@ -451,7 +451,6 @@ enum rejection_reason_code {
rr_arg_conversion, rr_arg_conversion,
rr_bad_arg_conversion, rr_bad_arg_conversion,
rr_template_unification, rr_template_unification,
rr_template_instantiation,
rr_invalid_copy rr_invalid_copy
}; };
...@@ -485,7 +484,7 @@ struct rejection_reason { ...@@ -485,7 +484,7 @@ struct rejection_reason {
struct { struct {
tree tmpl; tree tmpl;
tree explicit_targs; tree explicit_targs;
tree targs; int num_targs;
const tree *args; const tree *args;
unsigned int nargs; unsigned int nargs;
tree return_type; tree return_type;
...@@ -688,7 +687,7 @@ template_unification_rejection (tree tmpl, tree explicit_targs, tree targs, ...@@ -688,7 +687,7 @@ template_unification_rejection (tree tmpl, tree explicit_targs, tree targs,
struct rejection_reason *r = alloc_rejection (rr_template_unification); struct rejection_reason *r = alloc_rejection (rr_template_unification);
r->u.template_unification.tmpl = tmpl; r->u.template_unification.tmpl = tmpl;
r->u.template_unification.explicit_targs = explicit_targs; r->u.template_unification.explicit_targs = explicit_targs;
r->u.template_unification.targs = targs; r->u.template_unification.num_targs = TREE_VEC_LENGTH (targs);
/* Copy args to our own storage. */ /* Copy args to our own storage. */
memcpy (args1, args, args_n_bytes); memcpy (args1, args, args_n_bytes);
r->u.template_unification.args = args1; r->u.template_unification.args = args1;
...@@ -706,15 +705,6 @@ template_unification_error_rejection (void) ...@@ -706,15 +705,6 @@ template_unification_error_rejection (void)
} }
static struct rejection_reason * static struct rejection_reason *
template_instantiation_rejection (tree tmpl, tree targs)
{
struct rejection_reason *r = alloc_rejection (rr_template_instantiation);
r->u.template_instantiation.tmpl = tmpl;
r->u.template_instantiation.targs = targs;
return r;
}
static struct rejection_reason *
invalid_copy_with_fn_template_rejection (void) invalid_copy_with_fn_template_rejection (void)
{ {
struct rejection_reason *r = alloc_rejection (rr_invalid_copy); struct rejection_reason *r = alloc_rejection (rr_invalid_copy);
...@@ -2873,7 +2863,6 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl, ...@@ -2873,7 +2863,6 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl,
unsigned int ia, ix; unsigned int ia, ix;
tree arg; tree arg;
struct z_candidate *cand; struct z_candidate *cand;
int i;
tree fn; tree fn;
struct rejection_reason *reason = NULL; struct rejection_reason *reason = NULL;
int errs; int errs;
...@@ -2920,12 +2909,12 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl, ...@@ -2920,12 +2909,12 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl,
gcc_assert (ia == nargs_without_in_chrg); gcc_assert (ia == nargs_without_in_chrg);
errs = errorcount+sorrycount; errs = errorcount+sorrycount;
i = fn_type_unification (tmpl, explicit_targs, targs, fn = fn_type_unification (tmpl, explicit_targs, targs,
args_without_in_chrg, args_without_in_chrg,
nargs_without_in_chrg, nargs_without_in_chrg,
return_type, strict, flags, false); return_type, strict, flags, false);
if (i != 0) if (fn == error_mark_node)
{ {
/* Don't repeat unification later if it already resulted in errors. */ /* Don't repeat unification later if it already resulted in errors. */
if (errorcount+sorrycount == errs) if (errorcount+sorrycount == errs)
...@@ -2938,13 +2927,6 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl, ...@@ -2938,13 +2927,6 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl,
goto fail; goto fail;
} }
fn = instantiate_template (tmpl, targs, tf_none);
if (fn == error_mark_node)
{
reason = template_instantiation_rejection (tmpl, targs);
goto fail;
}
/* In [class.copy]: /* In [class.copy]:
A member function template is never instantiated to perform the A member function template is never instantiated to perform the
...@@ -3239,7 +3221,8 @@ print_z_candidate (location_t loc, const char *msgstr, ...@@ -3239,7 +3221,8 @@ print_z_candidate (location_t loc, const char *msgstr,
inform (cloc, " template argument deduction/substitution failed:"); inform (cloc, " template argument deduction/substitution failed:");
fn_type_unification (r->u.template_unification.tmpl, fn_type_unification (r->u.template_unification.tmpl,
r->u.template_unification.explicit_targs, r->u.template_unification.explicit_targs,
r->u.template_unification.targs, (make_tree_vec
(r->u.template_unification.num_targs)),
r->u.template_unification.args, r->u.template_unification.args,
r->u.template_unification.nargs, r->u.template_unification.nargs,
r->u.template_unification.return_type, r->u.template_unification.return_type,
...@@ -3247,12 +3230,6 @@ print_z_candidate (location_t loc, const char *msgstr, ...@@ -3247,12 +3230,6 @@ print_z_candidate (location_t loc, const char *msgstr,
r->u.template_unification.flags, r->u.template_unification.flags,
true); true);
break; break;
case rr_template_instantiation:
/* Re-run template instantiation with diagnostics. */
instantiate_template (r->u.template_instantiation.tmpl,
r->u.template_instantiation.targs,
tf_warning_or_error);
break;
case rr_invalid_copy: case rr_invalid_copy:
inform (cloc, inform (cloc,
" a constructor taking a single argument of its own " " a constructor taking a single argument of its own "
......
...@@ -7033,14 +7033,10 @@ resolve_address_of_overloaded_function (tree target_type, ...@@ -7033,14 +7033,10 @@ resolve_address_of_overloaded_function (tree target_type,
/* Try to do argument deduction. */ /* Try to do argument deduction. */
targs = make_tree_vec (DECL_NTPARMS (fn)); targs = make_tree_vec (DECL_NTPARMS (fn));
if (fn_type_unification (fn, explicit_targs, targs, args, nargs, instantiation = fn_type_unification (fn, explicit_targs, targs, args,
target_ret_type, DEDUCE_EXACT, nargs, target_ret_type,
LOOKUP_NORMAL, false)) DEDUCE_EXACT, LOOKUP_NORMAL,
/* Argument deduction failed. */ false);
continue;
/* Instantiate the template. */
instantiation = instantiate_template (fn, targs, flags);
if (instantiation == error_mark_node) if (instantiation == error_mark_node)
/* Instantiation failed. */ /* Instantiation failed. */
continue; continue;
......
...@@ -5340,7 +5340,7 @@ extern int uses_template_parms_level (tree, int); ...@@ -5340,7 +5340,7 @@ extern int uses_template_parms_level (tree, int);
extern bool in_template_function (void); extern bool in_template_function (void);
extern tree instantiate_class_template (tree); extern tree instantiate_class_template (tree);
extern tree instantiate_template (tree, tree, tsubst_flags_t); extern tree instantiate_template (tree, tree, tsubst_flags_t);
extern int fn_type_unification (tree, tree, tree, extern tree fn_type_unification (tree, tree, tree,
const tree *, unsigned int, const tree *, unsigned int,
tree, unification_kind_t, int, tree, unification_kind_t, int,
bool); bool);
......
...@@ -80,6 +80,9 @@ static tree cur_stmt_expr; ...@@ -80,6 +80,9 @@ static tree cur_stmt_expr;
local variables. */ local variables. */
static struct pointer_map_t *local_specializations; static struct pointer_map_t *local_specializations;
/* True if we've recursed into fn_type_unification too many times. */
static bool excessive_deduction_depth;
typedef struct GTY(()) spec_entry typedef struct GTY(()) spec_entry
{ {
tree tmpl; tree tmpl;
...@@ -1920,8 +1923,12 @@ determine_specialization (tree template_id, ...@@ -1920,8 +1923,12 @@ determine_specialization (tree template_id,
} }
/* See whether this function might be a specialization of this /* See whether this function might be a specialization of this
template. */ template. Suppress access control because we might be trying
to make this specialization a friend, and we have already done
access control for the declaration of the specialization. */
push_deferring_access_checks (dk_no_check);
targs = get_bindings (fn, decl, explicit_targs, /*check_ret=*/true); targs = get_bindings (fn, decl, explicit_targs, /*check_ret=*/true);
pop_deferring_access_checks ();
if (!targs) if (!targs)
/* We cannot deduce template arguments that when used to /* We cannot deduce template arguments that when used to
...@@ -9963,6 +9970,11 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) ...@@ -9963,6 +9970,11 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
if (type == error_mark_node) if (type == error_mark_node)
RETURN (error_mark_node); RETURN (error_mark_node);
/* If we hit excessive deduction depth, the type is bogus even if
it isn't error_mark_node, so don't build a decl. */
if (excessive_deduction_depth)
RETURN (error_mark_node);
/* We do NOT check for matching decls pushed separately at this /* We do NOT check for matching decls pushed separately at this
point, as they may not represent instantiations of this point, as they may not represent instantiations of this
template, and in any case are considered separate under the template, and in any case are considered separate under the
...@@ -14260,66 +14272,6 @@ check_instantiated_args (tree tmpl, tree args, tsubst_flags_t complain) ...@@ -14260,66 +14272,6 @@ check_instantiated_args (tree tmpl, tree args, tsubst_flags_t complain)
return result; return result;
} }
/* In C++0x, it's possible to have a function template whose type depends
on itself recursively. This is most obvious with decltype, but can also
occur with enumeration scope (c++/48969). So we need to catch infinite
recursion and reject the substitution at deduction time; this function
will return error_mark_node for any repeated substitution.
This also catches excessive recursion such as when f<N> depends on
f<N-1> across all integers, and returns error_mark_node for all the
substitutions back up to the initial one.
This is, of course, not reentrant. */
static tree
deduction_tsubst_fntype (tree fn, tree targs, tsubst_flags_t complain)
{
static bool excessive_deduction_depth;
static int deduction_depth;
struct pending_template *old_last_pend = last_pending_template;
struct tinst_level *old_error_tinst = last_error_tinst_level;
tree fntype = TREE_TYPE (fn);
tree tinst;
tree r;
if (excessive_deduction_depth)
return error_mark_node;
tinst = build_tree_list (fn, targs);
if (!push_tinst_level (tinst))
{
excessive_deduction_depth = true;
ggc_free (tinst);
return error_mark_node;
}
input_location = DECL_SOURCE_LOCATION (fn);
++deduction_depth;
/* We will do access checks in instantiate_template. */
push_deferring_access_checks (dk_deferred);
r = tsubst (fntype, targs, complain, NULL_TREE);
pop_deferring_access_checks ();
--deduction_depth;
if (excessive_deduction_depth)
{
r = error_mark_node;
if (deduction_depth == 0)
/* Reset once we're all the way out. */
excessive_deduction_depth = false;
}
pop_tinst_level ();
/* We can't free this if a pending_template entry or last_error_tinst_level
is pointing at it. */
if (last_pending_template == old_last_pend
&& last_error_tinst_level == old_error_tinst)
ggc_free (tinst);
return r;
}
/* We're out of SFINAE context now, so generate diagnostics for the access /* We're out of SFINAE context now, so generate diagnostics for the access
errors we saw earlier when instantiating D from TMPL and ARGS. */ errors we saw earlier when instantiating D from TMPL and ARGS. */
...@@ -14331,9 +14283,11 @@ recheck_decl_substitution (tree d, tree tmpl, tree args) ...@@ -14331,9 +14283,11 @@ recheck_decl_substitution (tree d, tree tmpl, tree args)
location_t loc = input_location; location_t loc = input_location;
push_access_scope (d); push_access_scope (d);
push_deferring_access_checks (dk_no_deferred);
input_location = DECL_SOURCE_LOCATION (pattern); input_location = DECL_SOURCE_LOCATION (pattern);
tsubst (type, args, tf_warning_or_error, d); tsubst (type, args, tf_warning_or_error, d);
input_location = loc; input_location = loc;
pop_deferring_access_checks ();
pop_access_scope (d); pop_access_scope (d);
} }
...@@ -14547,7 +14501,7 @@ pack_deducible_p (tree parm, tree fn) ...@@ -14547,7 +14501,7 @@ pack_deducible_p (tree parm, tree fn)
as in [temp.expl.spec], or when taking the address of a function as in [temp.expl.spec], or when taking the address of a function
template, as in [temp.deduct.funcaddr]. */ template, as in [temp.deduct.funcaddr]. */
int tree
fn_type_unification (tree fn, fn_type_unification (tree fn,
tree explicit_targs, tree explicit_targs,
tree targs, tree targs,
...@@ -14560,7 +14514,38 @@ fn_type_unification (tree fn, ...@@ -14560,7 +14514,38 @@ fn_type_unification (tree fn,
{ {
tree parms; tree parms;
tree fntype; tree fntype;
int result; tree decl = NULL_TREE;
tsubst_flags_t complain = (explain_p ? tf_warning_or_error : tf_none);
bool ok;
static int deduction_depth;
struct pending_template *old_last_pend = last_pending_template;
struct tinst_level *old_error_tinst = last_error_tinst_level;
tree tinst;
tree r = error_mark_node;
if (excessive_deduction_depth)
return error_mark_node;
/* In C++0x, it's possible to have a function template whose type depends
on itself recursively. This is most obvious with decltype, but can also
occur with enumeration scope (c++/48969). So we need to catch infinite
recursion and reject the substitution at deduction time; this function
will return error_mark_node for any repeated substitution.
This also catches excessive recursion such as when f<N> depends on
f<N-1> across all integers, and returns error_mark_node for all the
substitutions back up to the initial one.
This is, of course, not reentrant. */
tinst = build_tree_list (fn, targs);
if (!push_tinst_level (tinst))
{
excessive_deduction_depth = true;
ggc_free (tinst);
return error_mark_node;
}
++deduction_depth;
push_deferring_access_checks (dk_deferred);
gcc_assert (TREE_CODE (fn) == TEMPLATE_DECL); gcc_assert (TREE_CODE (fn) == TEMPLATE_DECL);
...@@ -14586,21 +14571,20 @@ fn_type_unification (tree fn, ...@@ -14586,21 +14571,20 @@ fn_type_unification (tree fn,
template results in an invalid type, type deduction fails. */ template results in an invalid type, type deduction fails. */
tree tparms = DECL_INNERMOST_TEMPLATE_PARMS (fn); tree tparms = DECL_INNERMOST_TEMPLATE_PARMS (fn);
int i, len = TREE_VEC_LENGTH (tparms); int i, len = TREE_VEC_LENGTH (tparms);
location_t loc = input_location;
tree converted_args; tree converted_args;
bool incomplete = false; bool incomplete = false;
if (explicit_targs == error_mark_node) if (explicit_targs == error_mark_node)
return unify_invalid (explain_p); goto fail;
converted_args converted_args
= (coerce_template_parms (tparms, explicit_targs, NULL_TREE, = (coerce_template_parms (tparms, explicit_targs, NULL_TREE,
(explain_p complain,
? tf_warning_or_error
: tf_none),
/*require_all_args=*/false, /*require_all_args=*/false,
/*use_default_args=*/false)); /*use_default_args=*/false));
if (converted_args == error_mark_node) if (converted_args == error_mark_node)
return 1; goto fail;
/* Substitute the explicit args into the function type. This is /* Substitute the explicit args into the function type. This is
necessary so that, for instance, explicitly declared function necessary so that, for instance, explicitly declared function
...@@ -14649,14 +14633,14 @@ fn_type_unification (tree fn, ...@@ -14649,14 +14633,14 @@ fn_type_unification (tree fn,
} }
processing_template_decl += incomplete; processing_template_decl += incomplete;
fntype = deduction_tsubst_fntype (fn, converted_args, input_location = DECL_SOURCE_LOCATION (fn);
(explain_p fntype = tsubst (TREE_TYPE (fn), converted_args,
? tf_warning_or_error complain | tf_partial, NULL_TREE);
: tf_none) | tf_partial); input_location = loc;
processing_template_decl -= incomplete; processing_template_decl -= incomplete;
if (fntype == error_mark_node) if (fntype == error_mark_node)
return 1; goto fail;
/* Place the explicitly specified arguments in TARGS. */ /* Place the explicitly specified arguments in TARGS. */
for (i = NUM_TMPL_ARGS (converted_args); i--;) for (i = NUM_TMPL_ARGS (converted_args); i--;)
...@@ -14682,9 +14666,14 @@ fn_type_unification (tree fn, ...@@ -14682,9 +14666,14 @@ fn_type_unification (tree fn,
because the standard doesn't seem to explicitly prohibit it. Our because the standard doesn't seem to explicitly prohibit it. Our
callers must be ready to deal with unification failures in any callers must be ready to deal with unification failures in any
event. */ event. */
result = type_unification_real (DECL_INNERMOST_TEMPLATE_PARMS (fn),
targs, parms, args, nargs, /*subr=*/0, pop_tinst_level ();
strict, flags, explain_p); ok = !type_unification_real (DECL_INNERMOST_TEMPLATE_PARMS (fn),
targs, parms, args, nargs, /*subr=*/0,
strict, flags, explain_p);
push_tinst_level (tinst);
if (!ok)
goto fail;
/* Now that we have bindings for all of the template arguments, /* Now that we have bindings for all of the template arguments,
ensure that the arguments deduced for the template template ensure that the arguments deduced for the template template
...@@ -14707,48 +14696,75 @@ fn_type_unification (tree fn, ...@@ -14707,48 +14696,75 @@ fn_type_unification (tree fn,
parameter 'T', but 'C' is deduced to 'X' before 'T' is deduced to parameter 'T', but 'C' is deduced to 'X' before 'T' is deduced to
'long'. Thus, we can't check that 'C' cannot bind to 'X' at the 'long'. Thus, we can't check that 'C' cannot bind to 'X' at the
time that we deduce 'C'. */ time that we deduce 'C'. */
if (result == 0 if (!template_template_parm_bindings_ok_p
&& !template_template_parm_bindings_ok_p
(DECL_INNERMOST_TEMPLATE_PARMS (fn), targs)) (DECL_INNERMOST_TEMPLATE_PARMS (fn), targs))
return unify_inconsistent_template_template_parameters (explain_p); {
unify_inconsistent_template_template_parameters (explain_p);
goto fail;
}
if (result == 0) /* All is well so far. Now, check:
/* All is well so far. Now, check:
[temp.deduct] [temp.deduct]
When all template arguments have been deduced, all uses of When all template arguments have been deduced, all uses of
template parameters in nondeduced contexts are replaced with template parameters in nondeduced contexts are replaced with
the corresponding deduced argument values. If the the corresponding deduced argument values. If the
substitution results in an invalid type, as described above, substitution results in an invalid type, as described above,
type deduction fails. */ type deduction fails. */
decl = instantiate_template (fn, targs, complain);
if (decl == error_mark_node)
goto fail;
/* Now perform any access checks encountered during deduction, such as
for default template arguments. */
push_access_scope (decl);
ok = perform_deferred_access_checks (complain);
pop_access_scope (decl);
if (!ok)
goto fail;
/* If we're looking for an exact match, check that what we got
is indeed an exact match. It might not be if some template
parameters are used in non-deduced contexts. */
if (strict == DEDUCE_EXACT)
{ {
tree substed = deduction_tsubst_fntype (fn, targs, tree substed = TREE_TYPE (decl);
(explain_p unsigned int i;
? tf_warning_or_error
: tf_none));
if (substed == error_mark_node)
return 1;
/* If we're looking for an exact match, check that what we got tree sarg
is indeed an exact match. It might not be if some template = skip_artificial_parms_for (decl, TYPE_ARG_TYPES (substed));
parameters are used in non-deduced contexts. */ if (return_type)
if (strict == DEDUCE_EXACT) sarg = tree_cons (NULL_TREE, TREE_TYPE (substed), sarg);
{ for (i = 0; i < nargs && sarg; ++i, sarg = TREE_CHAIN (sarg))
unsigned int i; if (!same_type_p (args[i], TREE_VALUE (sarg)))
{
tree sarg unify_type_mismatch (explain_p, args[i],
= skip_artificial_parms_for (fn, TYPE_ARG_TYPES (substed)); TREE_VALUE (sarg));
if (return_type) goto fail;
sarg = tree_cons (NULL_TREE, TREE_TYPE (substed), sarg); }
for (i = 0; i < nargs && sarg; ++i, sarg = TREE_CHAIN (sarg))
if (!same_type_p (args[i], TREE_VALUE (sarg)))
return unify_type_mismatch (explain_p, args[i],
TREE_VALUE (sarg));
}
} }
return result; r = decl;
fail:
pop_deferring_access_checks ();
--deduction_depth;
if (excessive_deduction_depth)
{
if (deduction_depth == 0)
/* Reset once we're all the way out. */
excessive_deduction_depth = false;
}
pop_tinst_level ();
/* We can't free this if a pending_template entry or last_error_tinst_level
is pointing at it. */
if (last_pending_template == old_last_pend
&& last_error_tinst_level == old_error_tinst)
ggc_free (tinst);
return r;
} }
/* Adjust types before performing type deduction, as described in /* Adjust types before performing type deduction, as described in
...@@ -15159,11 +15175,9 @@ type_unification_real (tree tparms, ...@@ -15159,11 +15175,9 @@ type_unification_real (tree tparms,
location_t save_loc = input_location; location_t save_loc = input_location;
if (DECL_P (parm)) if (DECL_P (parm))
input_location = DECL_SOURCE_LOCATION (parm); input_location = DECL_SOURCE_LOCATION (parm);
push_deferring_access_checks (dk_no_deferred);
arg = tsubst_template_arg (arg, targs, complain, NULL_TREE); arg = tsubst_template_arg (arg, targs, complain, NULL_TREE);
arg = convert_template_argument (parm, arg, targs, complain, arg = convert_template_argument (parm, arg, targs, complain,
i, NULL_TREE); i, NULL_TREE);
pop_deferring_access_checks ();
input_location = save_loc; input_location = save_loc;
if (arg == error_mark_node) if (arg == error_mark_node)
return 1; return 1;
...@@ -17180,7 +17194,8 @@ get_bindings (tree fn, tree decl, tree explicit_args, bool check_rettype) ...@@ -17180,7 +17194,8 @@ get_bindings (tree fn, tree decl, tree explicit_args, bool check_rettype)
args, ix, args, ix,
(check_rettype || DECL_CONV_FN_P (fn) (check_rettype || DECL_CONV_FN_P (fn)
? TREE_TYPE (decl_type) : NULL_TREE), ? TREE_TYPE (decl_type) : NULL_TREE),
DEDUCE_EXACT, LOOKUP_NORMAL, /*explain_p=*/false)) DEDUCE_EXACT, LOOKUP_NORMAL, /*explain_p=*/false)
== error_mark_node)
return NULL_TREE; return NULL_TREE;
return targs; return targs;
......
// { dg-do compile { target c++11 } }
template <class T, class = typename T::I> void f(T) {}
template <class T, class = typename T::I> void g(T) {}
// template <class T, class = typename T::I> void h(T) {}
// template <class T, class = typename T::I> void i(T) {}
template <class T, class = typename T::I> void j(T) {} // { dg-error "this context" }
class A
{
typedef int I; // { dg-error "private" }
template <class T, class> friend void f(T);
friend void g<A,I>(A);
// friend void h<A>(A);
// friend void i<>(A);
};
int main()
{
A a;
f(a);
g(a);
// h(a);
// i(a);
j(a); // { dg-error "no match" }
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment