Hi, this is in fact a Regression in the 4_8-branch too.
For the testcase, when we try to produce at instantiation time the warning about the unused parameter we re-enter the diagnostic routines because cp_convert_to_pointer doesn't get, as it should, a tf_none - the propagation breaks between convert_default_arg and tsubst_default_argument - and maybe_warn_zero_as_null_pointer_constant is called. Propagating fixes the issue.
Thanks, Paolo. //////////////////////
/cp 2013-07-25 Paolo Carlini <paolo.carl...@oracle.com> PR c++/57981 * decl.c (check_default_argument): Take a tsubst_flags_t parameter. (grokparms): Adjust. * parser.c (cp_parser_late_parse_one_default_arg): Likewise. * cvt.c (cp_convert_to_pointer, ocp_convert): Likewise. * pt.c (tsubst_default_argument, tsubst_default_arguments): Take a tsubst_flags_t parameter. (tsubst_decl): Adjust. * call.c (convert_default_arg): Likewise. * cp-tree.h (check_default_argument, tsubst_default_argument, maybe_warn_zero_as_null_pointer_constant): Update declarations. /testsuite 2013-07-25 Paolo Carlini <paolo.carl...@oracle.com> PR c++/57981 * g++.dg/cpp0x/pr57981.C: New.
Index: cp/call.c =================================================================== --- cp/call.c (revision 201239) +++ cp/call.c (working copy) @@ -6439,7 +6439,7 @@ convert_default_arg (tree type, tree arg, tree fn, push_defarg_context (fn); if (fn && DECL_TEMPLATE_INFO (fn)) - arg = tsubst_default_argument (fn, type, arg); + arg = tsubst_default_argument (fn, type, arg, complain); /* Due to: Index: cp/cp-tree.h =================================================================== --- cp/cp-tree.h (revision 201239) +++ cp/cp-tree.h (working copy) @@ -5222,7 +5222,7 @@ extern tree static_fn_type (tree); extern void revert_static_member_fn (tree); extern void fixup_anonymous_aggr (tree); extern tree compute_array_index_type (tree, tree, tsubst_flags_t); -extern tree check_default_argument (tree, tree); +extern tree check_default_argument (tree, tree, tsubst_flags_t); typedef int (*walk_namespaces_fn) (tree, void *); extern int walk_namespaces (walk_namespaces_fn, void *); @@ -5504,7 +5504,8 @@ extern tree maybe_process_partial_specialization ( extern tree most_specialized_instantiation (tree); extern void print_candidates (tree); extern void instantiate_pending_templates (int); -extern tree tsubst_default_argument (tree, tree, tree); +extern tree tsubst_default_argument (tree, tree, tree, + tsubst_flags_t); extern tree tsubst (tree, tree, tsubst_flags_t, tree); extern tree tsubst_copy_and_build (tree, tree, tsubst_flags_t, tree, bool, bool); Index: cp/decl.c =================================================================== --- cp/decl.c (revision 201239) +++ cp/decl.c (working copy) @@ -10883,7 +10883,7 @@ local_variable_p_walkfn (tree *tp, int *walk_subtr DECL, if there is no DECL available. */ tree -check_default_argument (tree decl, tree arg) +check_default_argument (tree decl, tree arg, tsubst_flags_t complain) { tree var; tree decl_type; @@ -10915,13 +10915,14 @@ tree A default argument expression is implicitly converted to the parameter type. */ ++cp_unevaluated_operand; - perform_implicit_conversion_flags (decl_type, arg, tf_warning_or_error, + perform_implicit_conversion_flags (decl_type, arg, complain, LOOKUP_IMPLICIT); --cp_unevaluated_operand; if (warn_zero_as_null_pointer_constant && TYPE_PTR_OR_PTRMEM_P (decl_type) && null_ptr_cst_p (arg) + && (complain & tf_warning) && maybe_warn_zero_as_null_pointer_constant (arg, input_location)) return nullptr_node; @@ -10935,10 +10936,14 @@ tree var = cp_walk_tree_without_duplicates (&arg, local_variable_p_walkfn, NULL); if (var) { - if (DECL_NAME (var) == this_identifier) - permerror (input_location, "default argument %qE uses %qD", arg, var); - else - error ("default argument %qE uses local variable %qD", arg, var); + if (complain & tf_warning_or_error) + { + if (DECL_NAME (var) == this_identifier) + permerror (input_location, "default argument %qE uses %qD", + arg, var); + else + error ("default argument %qE uses local variable %qD", arg, var); + } return error_mark_node; } @@ -11089,7 +11094,7 @@ grokparms (tree parmlist, tree *parms) if (any_error) init = NULL_TREE; else if (init && !processing_template_decl) - init = check_default_argument (decl, init); + init = check_default_argument (decl, init, tf_warning_or_error); } DECL_CHAIN (decl) = decls; Index: cp/parser.c =================================================================== --- cp/parser.c (revision 201239) +++ cp/parser.c (working copy) @@ -22996,7 +22999,8 @@ cp_parser_late_parse_one_default_arg (cp_parser *p /* In a non-template class, check conversions now. In a template, we'll wait and instantiate these as needed. */ if (TREE_CODE (decl) == PARM_DECL) - parsed_arg = check_default_argument (parmtype, parsed_arg); + parsed_arg = check_default_argument (parmtype, parsed_arg, + tf_warning_or_error); else { int flags = LOOKUP_IMPLICIT; Index: cp/pt.c =================================================================== --- cp/pt.c (revision 201239) +++ cp/pt.c (working copy) @@ -184,7 +184,7 @@ static int coerce_template_template_parms (tree, t tree, tree); static bool template_template_parm_bindings_ok_p (tree, tree); static int template_args_equal (tree, tree); -static void tsubst_default_arguments (tree); +static void tsubst_default_arguments (tree, tsubst_flags_t); static tree for_each_template_parm_r (tree *, int *, void *); static tree copy_default_args_to_explicit_spec_1 (tree, tree); static void copy_default_args_to_explicit_spec (tree); @@ -9875,7 +9875,7 @@ tsubst_aggr_type (tree t, FN), which has the indicated TYPE. */ tree -tsubst_default_argument (tree fn, tree type, tree arg) +tsubst_default_argument (tree fn, tree type, tree arg, tsubst_flags_t complain) { tree saved_class_ptr = NULL_TREE; tree saved_class_ref = NULL_TREE; @@ -9915,7 +9915,7 @@ tree stack. */ ++function_depth; arg = tsubst_expr (arg, DECL_TI_ARGS (fn), - tf_warning_or_error, NULL_TREE, + complain, NULL_TREE, /*integral_constant_expression_p=*/false); --function_depth; pop_deferring_access_checks(); @@ -9927,12 +9927,13 @@ tree cp_function_chain->x_current_class_ref = saved_class_ref; } - if (errorcount+sorrycount > errs) + if (errorcount+sorrycount > errs + && (complain & tf_warning_or_error)) inform (input_location, " when instantiating default argument for call to %D", fn); /* Make sure the default argument is reasonable. */ - arg = check_default_argument (type, arg); + arg = check_default_argument (type, arg, complain); pop_access_scope (fn); @@ -9942,7 +9943,7 @@ tree /* Substitute into all the default arguments for FN. */ static void -tsubst_default_arguments (tree fn) +tsubst_default_arguments (tree fn, tsubst_flags_t complain) { tree arg; tree tmpl_args; @@ -9963,7 +9964,8 @@ static void if (TREE_PURPOSE (arg)) TREE_PURPOSE (arg) = tsubst_default_argument (fn, TREE_VALUE (arg), - TREE_PURPOSE (arg)); + TREE_PURPOSE (arg), + complain); } /* Substitute the ARGS into the T, which is a _DECL. Return the @@ -10323,7 +10325,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t com if (!member && !PRIMARY_TEMPLATE_P (gen_tmpl) && !uses_template_parms (argvec)) - tsubst_default_arguments (r); + tsubst_default_arguments (r, complain); } else DECL_TEMPLATE_INFO (r) = NULL_TREE; Index: testsuite/g++.dg/cpp0x/pr57981.C =================================================================== --- testsuite/g++.dg/cpp0x/pr57981.C (revision 0) +++ testsuite/g++.dg/cpp0x/pr57981.C (working copy) @@ -0,0 +1,17 @@ +// { dg-options "-std=c++11 -Wall -Wextra" } + +template<class T> +void f(T t, void* = 0) // { dg-warning "unused parameter" } +{ +} + +template<class T> +auto g(T t) -> decltype(f(t)) +{ + f(t); +} + +int main() +{ + g(0); +}