Hi,
for reference I decided to start a new thread with a preliminary
implementation of this idea:
http://gcc.gnu.org/ml/gcc-patches/2013-08/msg00519.html
I know Gaby doesn't like it much, would like to see something more
ambitious in this area.
IMHO, within its limits, the idea works as I expected it would, both the
mentioned bugs are fixed and we produce a sensible diagnostic. No
regressions, testsuite changes, nothing changes in terms of rejecting
testcases which exceed in SFINAE context the recursive instantiation /
substitution limit.
I'm thus attaching the draft below, let me known if you can imagine ways
to incrementally improve it in the near future.
Thanks!
Paolo.
/////////////////////////
Index: cp/call.c
===================================================================
--- cp/call.c (revision 201631)
+++ cp/call.c (working copy)
@@ -2919,7 +2919,8 @@ add_template_candidate_real (struct z_candidate **
args_without_in_chrg,
nargs_without_in_chrg,
return_type, strict, flags, false,
- complain & tf_decltype);
+ complain & tf_decltype,
+ complain & tf_diagnostic);
if (fn == error_mark_node)
{
@@ -3235,7 +3236,7 @@ print_z_candidate (location_t loc, const char *msg
r->u.template_unification.return_type,
r->u.template_unification.strict,
r->u.template_unification.flags,
- true, false);
+ true, false, false);
break;
case rr_invalid_copy:
inform (cloc,
Index: cp/class.c
===================================================================
--- cp/class.c (revision 201631)
+++ cp/class.c (working copy)
@@ -7363,7 +7363,8 @@ resolve_address_of_overloaded_function (tree targe
instantiation = fn_type_unification (fn, explicit_targs, targs, args,
nargs, ret,
DEDUCE_EXACT, LOOKUP_NORMAL,
- false, false);
+ false, false,
+ flags & tf_diagnostic);
if (instantiation == error_mark_node)
/* Instantiation failed. */
continue;
Index: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h (revision 201631)
+++ cp/cp-tree.h (working copy)
@@ -4251,6 +4251,7 @@ enum tsubst_flags {
for calls in decltype (5.2.2/11). */
tf_partial = 1 << 8, /* Doing initial explicit argument
substitution in fn_type_unification. */
+ tf_diagnostic = 1 << 9, /* Diagnostic ctx, see push_tinst_level. */
/* Convenient substitution flags combinations. */
tf_warning_or_error = tf_warning | tf_error
};
@@ -5479,7 +5480,7 @@ extern tree instantiate_template (tree, tree, tsu
extern tree fn_type_unification (tree, tree, tree,
const tree *, unsigned int,
tree, unification_kind_t, int,
- bool, bool);
+ bool, bool, bool);
extern void mark_decl_instantiated (tree, int);
extern int more_specialized_fn (tree, tree, int);
extern void do_decl_instantiation (tree, tree);
@@ -5541,7 +5542,7 @@ extern tree fold_non_dependent_expr_sfinae (tree,
extern bool alias_type_or_template_p (tree);
extern bool alias_template_specialization_p (const_tree);
extern bool explicit_class_specialization_p (tree);
-extern int push_tinst_level (tree);
+extern int push_tinst_level (tree, bool);
extern void pop_tinst_level (void);
extern struct tinst_level *outermost_tinst_level(void);
extern void init_template_processing (void);
Index: cp/error.c
===================================================================
--- cp/error.c (revision 201631)
+++ cp/error.c (working copy)
@@ -321,7 +321,7 @@ dump_template_bindings (tree parms, tree args, vec
pp_equal (cxx_pp);
pp_cxx_whitespace (cxx_pp);
push_deferring_access_checks (dk_no_check);
- t = tsubst (t, args, tf_none, NULL_TREE);
+ t = tsubst (t, args, tf_diagnostic, NULL_TREE);
pop_deferring_access_checks ();
/* Strip typedefs. We can't just use TFF_CHASE_TYPEDEF because
pp_simple_type_specifier doesn't know about it. */
Index: cp/mangle.c
===================================================================
--- cp/mangle.c (revision 201631)
+++ cp/mangle.c (working copy)
@@ -3429,7 +3429,7 @@ mangle_decl_string (const tree decl)
{
struct tinst_level *tl = current_instantiation ();
if ((!tl || tl->decl != decl)
- && push_tinst_level (decl))
+ && push_tinst_level (decl, /*diagnostic_p=*/false))
{
template_p = true;
saved_fn = current_function_decl;
Index: cp/pt.c
===================================================================
--- cp/pt.c (revision 201631)
+++ cp/pt.c (working copy)
@@ -6995,7 +6995,7 @@ add_pending_template (tree d)
level = !current_tinst_level || current_tinst_level->decl != d;
if (level)
- push_tinst_level (d);
+ push_tinst_level (d, /*diagnostic_p=*/false);
pt = ggc_alloc_pending_template ();
pt->next = NULL;
@@ -8021,24 +8021,28 @@ static GTY(()) struct tinst_level *last_error_tins
for diagnostics and to restore it later. */
int
-push_tinst_level (tree d)
+push_tinst_level (tree d, bool diagnostic_p)
{
struct tinst_level *new_level;
if (tinst_depth >= max_tinst_depth)
{
last_error_tinst_level = current_tinst_level;
- if (TREE_CODE (d) == TREE_LIST)
- error ("template instantiation depth exceeds maximum of %d (use "
- "-ftemplate-depth= to increase the maximum) substituting %qS",
- max_tinst_depth, d);
- else
- error ("template instantiation depth exceeds maximum of %d (use "
- "-ftemplate-depth= to increase the maximum) instantiating %qD",
- max_tinst_depth, d);
- print_instantiation_context ();
+ if (!diagnostic_p)
+ {
+ if (TREE_CODE (d) == TREE_LIST)
+ error ("template instantiation depth exceeds maximum of %d (use "
+ "-ftemplate-depth= to increase the maximum) "
+ "substituting %qS", max_tinst_depth, d);
+ else
+ error ("emplate instantiation depth exceeds maximum of %d (use "
+ "-ftemplate-depth= to increase the maximum) "
+ "instantiating %qD", max_tinst_depth, d);
+ print_instantiation_context ();
+ }
+
return 0;
}
@@ -8691,7 +8695,7 @@ instantiate_class_template_1 (tree type)
return type;
/* If we've recursively instantiated too many templates, stop. */
- if (! push_tinst_level (type))
+ if (! push_tinst_level (type, /*diagnostic_p=*/false))
return type;
/* Now we're really doing the instantiation. Mark the type as in
@@ -15005,7 +15009,7 @@ instantiate_alias_template (tree tmpl, tree args,
if (tmpl == error_mark_node || args == error_mark_node)
return error_mark_node;
tree tinst = build_tree_list (tmpl, args);
- if (!push_tinst_level (tinst))
+ if (!push_tinst_level (tinst, complain & tf_diagnostic))
{
ggc_free (tinst);
return error_mark_node;
@@ -15103,7 +15107,8 @@ fn_type_unification (tree fn,
unification_kind_t strict,
int flags,
bool explain_p,
- bool decltype_p)
+ bool decltype_p,
+ bool diagnostic_p)
{
tree parms;
tree fntype;
@@ -15120,6 +15125,9 @@ fn_type_unification (tree fn,
if (decltype_p)
complain |= tf_decltype;
+ if (diagnostic_p)
+ complain |= tf_diagnostic;
+
/* 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
@@ -15219,7 +15227,7 @@ fn_type_unification (tree fn,
}
TREE_VALUE (tinst) = explicit_targs;
- if (!push_tinst_level (tinst))
+ if (!push_tinst_level (tinst, diagnostic_p))
{
excessive_deduction_depth = true;
goto fail;
@@ -15270,7 +15278,7 @@ fn_type_unification (tree fn,
any errors (e.g. from class instantiations triggered by instantiation
of default template arguments) come from. If we are explaining, this
context is redundant. */
- if (!explain_p && !push_tinst_level (tinst))
+ if (!explain_p && !push_tinst_level (tinst, diagnostic_p))
{
excessive_deduction_depth = true;
goto fail;
@@ -15327,7 +15335,7 @@ fn_type_unification (tree fn,
substitution results in an invalid type, as described above,
type deduction fails. */
TREE_VALUE (tinst) = targs;
- if (!push_tinst_level (tinst))
+ if (!push_tinst_level (tinst, diagnostic_p))
{
excessive_deduction_depth = true;
goto fail;
@@ -17982,7 +17990,7 @@ get_bindings (tree fn, tree decl, tree explicit_ar
(check_rettype || DECL_CONV_FN_P (fn)
? TREE_TYPE (decl_type) : NULL_TREE),
DEDUCE_EXACT, LOOKUP_NORMAL, /*explain_p=*/false,
- /*decltype*/false)
+ /*decltype*/false, /*diagnostic_p=*/false)
== error_mark_node)
return NULL_TREE;
@@ -18876,7 +18884,7 @@ maybe_instantiate_noexcept (tree fn)
if (TREE_CODE (noex) == DEFERRED_NOEXCEPT)
{
- if (push_tinst_level (fn))
+ if (push_tinst_level (fn, /*diagnostic_p=*/false))
{
push_access_scope (fn);
push_deferring_access_checks (dk_no_deferred);
@@ -19000,7 +19008,7 @@ instantiate_decl (tree d, int defer_ok,
|| spec == NULL_TREE);
/* This needs to happen before any tsubsting. */
- if (! push_tinst_level (d))
+ if (! push_tinst_level (d, /*diagnostic_p=*/false))
return d;
timevar_push (TV_TEMPLATE_INST);
Index: cp/typeck.c
===================================================================
--- cp/typeck.c (revision 201631)
+++ cp/typeck.c (working copy)
@@ -1560,7 +1560,7 @@ cxx_sizeof_or_alignof_type (tree type, enum tree_c
return c_sizeof_or_alignof_type (input_location, complete_type (type),
op == SIZEOF_EXPR,
- complain);
+ complain & tf_warning_or_error);
}
/* Return the size of the type, without producing any warnings for
Index: cp/typeck2.c
===================================================================
--- cp/typeck2.c (revision 201631)
+++ cp/typeck2.c (working copy)
@@ -1564,7 +1564,7 @@ build_x_arrow (location_t loc, tree expr, tsubst_f
return error_mark_node;
if (fn && DECL_USE_TEMPLATE (fn))
- push_tinst_level (fn);
+ push_tinst_level (fn, complain & tf_diagnostic);
fn = NULL;
if (vec_member (TREE_TYPE (expr), types_memoized))