mirror of git://gcc.gnu.org/git/gcc.git
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
This commit is contained in:
parent
f581a987e3
commit
cd057e3af0
|
|
@ -1,5 +1,22 @@
|
||||||
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 {
|
||||||
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 {
|
||||||
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,
|
||||||
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;
|
||||||
|
|
@ -705,15 +704,6 @@ template_unification_error_rejection (void)
|
||||||
return alloc_rejection (rr_template_unification);
|
return alloc_rejection (rr_template_unification);
|
||||||
}
|
}
|
||||||
|
|
||||||
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 *
|
static struct rejection_reason *
|
||||||
invalid_copy_with_fn_template_rejection (void)
|
invalid_copy_with_fn_template_rejection (void)
|
||||||
{
|
{
|
||||||
|
|
@ -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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
/* 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);
|
||||||
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);
|
||||||
|
|
|
||||||
249
gcc/cp/pt.c
249
gcc/cp/pt.c
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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,
|
||||||
{
|
{
|
||||||
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,
|
||||||
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,
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
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);
|
|
||||||
|
|
||||||
if (result == 0)
|
|
||||||
/* All is well so far. Now, check:
|
|
||||||
|
|
||||||
[temp.deduct]
|
|
||||||
|
|
||||||
When all template arguments have been deduced, all uses of
|
|
||||||
template parameters in nondeduced contexts are replaced with
|
|
||||||
the corresponding deduced argument values. If the
|
|
||||||
substitution results in an invalid type, as described above,
|
|
||||||
type deduction fails. */
|
|
||||||
{
|
{
|
||||||
tree substed = deduction_tsubst_fntype (fn, targs,
|
unify_inconsistent_template_template_parameters (explain_p);
|
||||||
(explain_p
|
goto fail;
|
||||||
? 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
|
|
||||||
is indeed an exact match. It might not be if some template
|
|
||||||
parameters are used in non-deduced contexts. */
|
|
||||||
if (strict == DEDUCE_EXACT)
|
|
||||||
{
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
tree sarg
|
|
||||||
= skip_artificial_parms_for (fn, TYPE_ARG_TYPES (substed));
|
|
||||||
if (return_type)
|
|
||||||
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;
|
/* All is well so far. Now, check:
|
||||||
|
|
||||||
|
[temp.deduct]
|
||||||
|
|
||||||
|
When all template arguments have been deduced, all uses of
|
||||||
|
template parameters in nondeduced contexts are replaced with
|
||||||
|
the corresponding deduced argument values. If the
|
||||||
|
substitution results in an invalid type, as described above,
|
||||||
|
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 = TREE_TYPE (decl);
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
tree sarg
|
||||||
|
= skip_artificial_parms_for (decl, TYPE_ARG_TYPES (substed));
|
||||||
|
if (return_type)
|
||||||
|
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)))
|
||||||
|
{
|
||||||
|
unify_type_mismatch (explain_p, args[i],
|
||||||
|
TREE_VALUE (sarg));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
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)
|
||||||
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;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
// { 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" }
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue