Hi! fn_type_unification does: /* 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); because sometimes tinst (and targs) is added to pending templates or tinst level and thus still GC reachable, but often it isn't and it is called often enough that it creates too much garbage. But, the resolve_address_of_overloaded_function caller also calls ggc_free (targs); for similar reasons, but without checking if it might be stored somewhere.
The options I see: 1) drop the ggc_free (targs); call from resolve_address_of_overloaded_function altogether 2) remember and check last_pending_template/last_error_tinst_level also in resolve_address_of_overloaded_function for the same purposes as fn_type_unification does; the problem with that is that those vars are private to pt.c 3) what the patch does, add another parameter to fn_type_unification which will tell the caller whether it is safe to ggc_free targs or not The following patch implements 3), and adds a bunch of ggc_free calls to other callers of fn_type_unification when it has that info already. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2013-12-11 Jakub Jelinek <ja...@redhat.com> PR c++/58627 * cp-tree.h (fn_type_unification): Add bool * argument. * pt.c (fn_type_unification): Add targs_unused_p argument, set what it points to to true if targs argument isn't stored anywhere. (get_bindings): Adjust fn_type_unification caller. If targs_unused_p, ggc_free targs. * call.c (add_template_candidate_real): Likewise. (print_z_candidate): Likewise. * class.c (resolve_address_of_overloaded_function): Don't ggc_free targs if targs_unused_p is false. --- gcc/cp/cp-tree.h.jj 2013-11-25 10:20:12.000000000 +0100 +++ gcc/cp/cp-tree.h 2013-12-10 09:13:55.202703361 +0100 @@ -5495,7 +5495,7 @@ extern tree instantiate_template (tree, 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); --- gcc/cp/call.c.jj 2013-11-25 10:20:12.000000000 +0100 +++ gcc/cp/call.c 2013-12-10 09:19:20.034025608 +0100 @@ -2919,22 +2919,25 @@ add_template_candidate_real (struct z_ca gcc_assert (ia == nargs_without_in_chrg); errs = errorcount+sorrycount; + bool targs_unused_p; fn = fn_type_unification (tmpl, explicit_targs, targs, args_without_in_chrg, nargs_without_in_chrg, return_type, strict, flags, false, - complain & tf_decltype); + complain & tf_decltype, &targs_unused_p); if (fn == error_mark_node) { /* Don't repeat unification later if it already resulted in errors. */ - if (errorcount+sorrycount == errs) + if (errorcount + sorrycount == errs) reason = template_unification_rejection (tmpl, explicit_targs, targs, args_without_in_chrg, nargs_without_in_chrg, return_type, strict, flags); else reason = template_unification_error_rejection (); + if (targs_unused_p) + ggc_free (targs); goto fail; } @@ -3230,16 +3233,19 @@ print_z_candidate (location_t loc, const } /* Re-run template unification with diagnostics. */ inform (cloc, " template argument deduction/substitution failed:"); + bool targs_unused_p; + tree targs; + targs = make_tree_vec (r->u.template_unification.num_targs); fn_type_unification (r->u.template_unification.tmpl, - r->u.template_unification.explicit_targs, - (make_tree_vec - (r->u.template_unification.num_targs)), + r->u.template_unification.explicit_targs, targs, r->u.template_unification.args, r->u.template_unification.nargs, r->u.template_unification.return_type, r->u.template_unification.strict, r->u.template_unification.flags, - true, false); + true, false, &targs_unused_p); + if (targs_unused_p) + ggc_free (targs); break; case rr_invalid_copy: inform (cloc, --- gcc/cp/class.c.jj 2013-11-28 08:18:58.000000000 +0100 +++ gcc/cp/class.c 2013-12-10 09:05:33.020297356 +0100 @@ -7454,10 +7454,11 @@ resolve_address_of_overloaded_function ( /* Try to do argument deduction. */ targs = make_tree_vec (DECL_NTPARMS (fn)); + bool targs_unused_p; instantiation = fn_type_unification (fn, explicit_targs, targs, args, nargs, ret, - DEDUCE_EXACT, LOOKUP_NORMAL, - false, false); + DEDUCE_EXACT, LOOKUP_NORMAL, + false, false, &targs_unused_p); if (instantiation == error_mark_node) /* Instantiation failed. */ continue; @@ -7476,7 +7477,8 @@ resolve_address_of_overloaded_function ( if (same_type_p (target_fn_type, static_fn_type (instantiation))) matches = tree_cons (instantiation, fn, matches); - ggc_free (targs); + if (targs_unused_p) + ggc_free (targs); } /* Now, remove all but the most specialized of the matches. */ --- gcc/cp/pt.c.jj 2013-12-06 21:34:05.000000000 +0100 +++ gcc/cp/pt.c 2013-12-10 09:15:49.317114177 +0100 @@ -15451,7 +15451,8 @@ fn_type_unification (tree fn, unification_kind_t strict, int flags, bool explain_p, - bool decltype_p) + bool decltype_p, + bool *targs_unused_p) { tree parms; tree fntype; @@ -15467,6 +15468,7 @@ fn_type_unification (tree fn, if (decltype_p) complain |= tf_decltype; + *targs_unused_p = true; /* 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 @@ -15738,6 +15740,9 @@ fn_type_unification (tree fn, if (last_pending_template == old_last_pend && last_error_tinst_level == old_error_tinst) ggc_free (tinst); + /* If we can't free tinst, also tell the caller that it can't free targs. */ + else + *targs_unused_p = false; return r; } @@ -18350,14 +18355,19 @@ get_bindings (tree fn, tree decl, tree e arg = TREE_CHAIN (arg), ++ix) args[ix] = TREE_VALUE (arg); + bool targs_unused_p; if (fn_type_unification (fn, explicit_args, targs, args, ix, (check_rettype || DECL_CONV_FN_P (fn) ? TREE_TYPE (decl_type) : NULL_TREE), DEDUCE_EXACT, LOOKUP_NORMAL, /*explain_p=*/false, - /*decltype*/false) + /*decltype*/false, &targs_unused_p) == error_mark_node) - return NULL_TREE; + { + if (targs_unused_p) + ggc_free (targs); + return NULL_TREE; + } return targs; } Jakub