From patchwork Tue Oct 31 09:45:42 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Carlini X-Patchwork-Id: 832304 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-465569-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="gip37fUg"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3yR61F6KyDz9t3C for ; Tue, 31 Oct 2017 20:46:09 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:to:cc :from:subject:message-id:date:mime-version:content-type; q=dns; s=default; b=oopgYo/XOCm3/pkjS3dq096yXlaBuYJ1IlbmR7tTFYrMwX7lAx VaCFdbFTXkdwxTsLxu6J06Wn7HBdTDa1J7CfYpUW9IL+bgVhLCQFKYrUP11+8d4g 0rQoIiDTxr5cMha/hK0NH7rQsNC5upyhgSdjfUNIYRlVADYRAMs3BRkGc= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:to:cc :from:subject:message-id:date:mime-version:content-type; s= default; bh=Brz10BoEZQSqflJ8f/KJMgBqf98=; b=gip37fUgzitDK411817I qC5zoaXThAY/zBmVhVyWXqcNfslksDG3x01tK3QZcdQ++LExBxcbdDhagCu/25gb hA7/XvdOBnlpA3mRsOxkjlOTGXy3eD4E+rfOPHxBwqA7vchTt1G8+mmP88b8fyBm Nkv5r9g9PkI4vk1NagOsQzU= Received: (qmail 74501 invoked by alias); 31 Oct 2017 09:45:56 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 74357 invoked by uid 89); 31 Oct 2017 09:45:56 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-10.1 required=5.0 tests=BAYES_00, GIT_PATCH_2, GIT_PATCH_3, KAM_ASCII_DIVIDERS, KAM_LAZY_DOMAIN_SECURITY, RP_MATCHES_RCVD autolearn=ham version=3.3.2 spammy=sta, onto, packs, sk:argumen X-HELO: userp1040.oracle.com Received: from userp1040.oracle.com (HELO userp1040.oracle.com) (156.151.31.81) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 31 Oct 2017 09:45:52 +0000 Received: from userv0022.oracle.com (userv0022.oracle.com [156.151.31.74]) by userp1040.oracle.com (Sentrion-MTA-4.3.2/Sentrion-MTA-4.3.2) with ESMTP id v9V9jlCw025066 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 31 Oct 2017 09:45:47 GMT Received: from userv0121.oracle.com (userv0121.oracle.com [156.151.31.72]) by userv0022.oracle.com (8.14.4/8.14.4) with ESMTP id v9V9jljW028192 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 31 Oct 2017 09:45:47 GMT Received: from abhmp0006.oracle.com (abhmp0006.oracle.com [141.146.116.12]) by userv0121.oracle.com (8.14.4/8.13.8) with ESMTP id v9V9jlZn020438; Tue, 31 Oct 2017 09:45:47 GMT Received: from [192.168.1.4] (/82.61.149.169) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Tue, 31 Oct 2017 02:45:46 -0700 To: "gcc-patches@gcc.gnu.org" Cc: Jason Merrill From: Paolo Carlini Subject: [C++ Patch] PR 81957 ("ICE decltype") Message-ID: <4736faa9-8a5d-2f2f-5822-525265b795c1@oracle.com> Date: Tue, 31 Oct 2017 10:45:42 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.4.0 MIME-Version: 1.0 X-IsSubscribed: yes Hi, this ICE on valid seems rather easy to fix, one of those bugs where we aren't propagating the tsubst_flags_t argument. In this case, we aren't propagating from tsubst_pack_expansion to make_pack_expansion. Doing it, fixes the ICE and we actually accept the code as we should. In general, make_pack_expansion is also called from many other places, eg, the parser, thus I'm using a default tf_warning_or_error for it. Similarly to other past fixes, I ended up adding tsubst_flags_t parameters to a few other functions in pt.c, eg template_parms_to_args, which eventually use make_pack_expansion without propagating. There are a couple of places where I'm proposing passing a /tf_none/ to template_parms_to_args: is_compatible_template_arg, which is currently calling template_parms_to_args and passing the result together with a tf_none to tsubst_constraint_info; convert_generic_types_to_packs, which is currently calling template_parms_to_args and passing the result (via add_to_template_args) together with tf_none to tsubst. Of course the "conservative" choice would be instead passing tf_warning_or_error. Tested x86_64-linux. Thanks, Paolo. ////////////////////////// /cp 2017-10-31 Paolo Carlini PR c++/81957 * pt.c (make_pack_expansion): Add tsubst_flags_t parameter. (template_parm_to_arg): Likewise. (template_parms_level_to_args): Likewise. (template_parms_to_args): Likewise. (current_template_args): Likewise. (get_underlying_template): Likewise. (expand_integer_pack, template_parm_to_arg, template_parms_level_to_args, template_parms_to_args, current_template_args, add_inherited_template_parms, get_underlying_template, coerce_template_args_for_ttp, coerce_template_template_parms, is_compatible_template_arg, convert_template_argument, coerce_template_parms, lookup_template_class_1, tsubst_pack_expansion, tsubst_template_decl, unify, rewrite_template_parm, build_deduction_guide, do_auto_deduction, convert_generic_types_to_packs): Adjust calls. * tree.c (cp_build_qualified_type_real): Likewise. * constraint.cc (finish_shorthand_constraint, finish_template_introduction): Likewise. * cp-tree.h (make_pack_expansion, template_parm_to_arg): Adjust declarations. /testsuite 2017-10-31 Paolo Carlini PR c++/81957 * g++.dg/cpp0x/variadic-crash5.C: New. Index: cp/constraint.cc =================================================================== --- cp/constraint.cc (revision 254249) +++ cp/constraint.cc (working copy) @@ -1272,7 +1272,8 @@ finish_shorthand_constraint (tree decl, tree const /* Get the argument and overload used for the requirement and adjust it if we're going to expand later. */ - tree arg = template_parm_to_arg (build_tree_list (NULL_TREE, decl)); + tree arg = template_parm_to_arg (build_tree_list (NULL_TREE, decl), + tf_warning_or_error); if (apply_to_all_p) arg = PACK_EXPANSION_PATTERN (TREE_VEC_ELT (ARGUMENT_PACK_ARGS (arg), 0)); @@ -1420,7 +1421,8 @@ finish_template_introduction (tree tmpl_decl, tree for (; n < TREE_VEC_LENGTH (parm_list); ++n) { tree parm = TREE_VEC_ELT (parm_list, n); - TREE_VEC_ELT (check_args, n) = template_parm_to_arg (parm); + TREE_VEC_ELT (check_args, n) + = template_parm_to_arg (parm, tf_warning_or_error); } SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (check_args, n); Index: cp/cp-tree.h =================================================================== --- cp/cp-tree.h (revision 254249) +++ cp/cp-tree.h (working copy) @@ -6435,7 +6435,7 @@ extern bool uses_parameter_packs (t extern bool template_parameter_pack_p (const_tree); extern bool function_parameter_pack_p (const_tree); extern bool function_parameter_expanded_from_pack_p (tree, tree); -extern tree make_pack_expansion (tree); +extern tree make_pack_expansion (tree, tsubst_flags_t = tf_warning_or_error); extern bool check_for_bare_parameter_packs (tree); extern tree build_template_info (tree, tree); extern tree get_template_info (const_tree); @@ -6517,7 +6517,7 @@ extern tree coerce_template_parms (t extern void register_local_specialization (tree, tree); extern tree retrieve_local_specialization (tree); extern tree extract_fnparm_pack (tree, tree *); -extern tree template_parm_to_arg (tree); +extern tree template_parm_to_arg (tree, tsubst_flags_t); extern tree dguide_name (tree); extern bool dguide_name_p (tree); extern bool deduction_guide_p (const_tree); Index: cp/pt.c =================================================================== --- cp/pt.c (revision 254249) +++ cp/pt.c (working copy) @@ -3435,7 +3435,7 @@ expand_integer_pack (tree call, tree args, tsubst_ call = copy_node (call); CALL_EXPR_ARG (call, 0) = hi; } - tree ex = make_pack_expansion (call); + tree ex = make_pack_expansion (call, complain); tree vec = make_tree_vec (1); TREE_VEC_ELT (vec, 0) = ex; return vec; @@ -3724,7 +3724,7 @@ uses_parameter_packs (tree t) EXPR_PACK_EXPANSION, TYPE_PACK_EXPANSION, or TREE_LIST, respectively. */ tree -make_pack_expansion (tree arg) +make_pack_expansion (tree arg, tsubst_flags_t complain) { tree result; tree parameter_packs = NULL_TREE; @@ -3770,7 +3770,9 @@ tree if (parameter_packs == NULL_TREE) { - error ("base initializer expansion %qT contains no parameter packs", arg); + if (complain & tf_error) + error ("base initializer expansion %qT contains no parameter packs", + arg); delete ppd.visited; return error_mark_node; } @@ -3834,10 +3836,13 @@ tree /* Make sure we found some parameter packs. */ if (parameter_packs == NULL_TREE) { - if (TYPE_P (arg)) - error ("expansion pattern %qT contains no argument packs", arg); - else - error ("expansion pattern %qE contains no argument packs", arg); + if (complain & tf_error) + { + if (TYPE_P (arg)) + error ("expansion pattern %qT contains no argument packs", arg); + else + error ("expansion pattern %qE contains no argument packs", arg); + } return error_mark_node; } PACK_EXPANSION_PARAMETER_PACKS (result) = parameter_packs; @@ -4330,7 +4335,7 @@ end_template_decl (void) node, the returned argument is error_mark_node. */ tree -template_parm_to_arg (tree t) +template_parm_to_arg (tree t, tsubst_flags_t complain) { if (t == NULL_TREE @@ -4355,7 +4360,7 @@ tree if (CHECKING_P) SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (vec, TREE_VEC_LENGTH (vec)); - TREE_VEC_ELT (vec, 0) = make_pack_expansion (t); + TREE_VEC_ELT (vec, 0) = make_pack_expansion (t, complain); t = cxx_make_type (TYPE_ARGUMENT_PACK); SET_ARGUMENT_PACK_ARGS (t, vec); @@ -4374,7 +4379,7 @@ tree SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (vec, TREE_VEC_LENGTH (vec)); t = convert_from_reference (t); - TREE_VEC_ELT (vec, 0) = make_pack_expansion (t); + TREE_VEC_ELT (vec, 0) = make_pack_expansion (t, complain); t = make_node (NONTYPE_ARGUMENT_PACK); SET_ARGUMENT_PACK_ARGS (t, vec); @@ -4389,12 +4394,13 @@ tree as a set of template arguments. */ static tree -template_parms_level_to_args (tree parms) +template_parms_level_to_args (tree parms, tsubst_flags_t complain) { tree a = copy_node (parms); TREE_TYPE (a) = NULL_TREE; for (int i = TREE_VEC_LENGTH (a) - 1; i >= 0; --i) - TREE_VEC_ELT (a, i) = template_parm_to_arg (TREE_VEC_ELT (a, i)); + TREE_VEC_ELT (a, i) = template_parm_to_arg (TREE_VEC_ELT (a, i), + complain); if (CHECKING_P) SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (a, TREE_VEC_LENGTH (a)); @@ -4407,7 +4413,7 @@ static tree the form documented in cp-tree.h for template arguments. */ static tree -template_parms_to_args (tree parms) +template_parms_to_args (tree parms, tsubst_flags_t complain) { tree header; tree args = NULL_TREE; @@ -4422,7 +4428,8 @@ static tree for (header = parms; header; header = TREE_CHAIN (header)) { - tree a = template_parms_level_to_args (TREE_VALUE (header)); + tree a = template_parms_level_to_args (TREE_VALUE (header), + complain); if (length > 1) TREE_VEC_ELT (args, --l) = a; @@ -4437,9 +4444,9 @@ static tree template parameters as an argument TREE_VEC. */ static tree -current_template_args (void) +current_template_args (tsubst_flags_t complain = tf_warning_or_error) { - return template_parms_to_args (current_template_parms); + return template_parms_to_args (current_template_parms, complain); } /* Update the declared TYPE by doing any lookups which were thought to be @@ -5670,7 +5677,7 @@ add_inherited_template_parms (tree fn, tree inheri = tree_cons (size_int (processing_template_decl + 1), inner_parms, current_template_parms); tree tmpl = build_template_decl (fn, parms, /*member*/true); - tree args = template_parms_to_args (parms); + tree args = template_parms_to_args (parms, tf_warning_or_error); DECL_TEMPLATE_INFO (fn) = build_template_info (tmpl, args); TREE_TYPE (tmpl) = TREE_TYPE (fn); DECL_TEMPLATE_RESULT (tmpl) = fn; @@ -5995,7 +6002,7 @@ num_innermost_template_parms (tree tmpl) the other template. */ static tree -get_underlying_template (tree tmpl) +get_underlying_template (tree tmpl, tsubst_flags_t complain) { gcc_assert (TREE_CODE (tmpl) == TEMPLATE_DECL); while (DECL_ALIAS_TEMPLATE_P (tmpl)) @@ -6013,7 +6020,8 @@ static tree break; tree alias_args = INNERMOST_TEMPLATE_ARGS - (template_parms_to_args (DECL_TEMPLATE_PARMS (tmpl))); + (template_parms_to_args (DECL_TEMPLATE_PARMS (tmpl), + complain)); if (!comp_template_args (TI_ARGS (tinfo), alias_args)) break; @@ -7006,7 +7014,7 @@ coerce_template_args_for_ttp (tree templ, tree arg if (DECL_TEMPLATE_SPECIALIZATION (outer)) /* We want arguments for the partial specialization, not arguments for the primary template. */ - outer = template_parms_to_args (DECL_TEMPLATE_PARMS (outer)); + outer = template_parms_to_args (DECL_TEMPLATE_PARMS (outer), complain); else outer = TI_ARGS (get_template_info (DECL_TEMPLATE_RESULT (outer))); } @@ -7023,7 +7031,7 @@ coerce_template_args_for_ttp (tree templ, tree arg != TEMPLATE_TYPE_LEVEL (TREE_TYPE (templ))) relevant_template_parms = TREE_CHAIN (relevant_template_parms); - outer = template_parms_to_args (relevant_template_parms); + outer = template_parms_to_args (relevant_template_parms, complain); } if (outer) @@ -7267,7 +7275,7 @@ coerce_template_template_parms (tree parm_parms, /* So coerce P's args to apply to A's parms, and then deduce between A's args and the converted args. If that succeeds, A is at least as specialized as P, so they match.*/ - tree pargs = template_parms_level_to_args (parm_parms); + tree pargs = template_parms_level_to_args (parm_parms, complain); ++processing_template_decl; pargs = coerce_template_parms (arg_parms, pargs, NULL_TREE, tf_none, /*require_all*/true, /*use_default*/true); @@ -7275,7 +7283,7 @@ coerce_template_template_parms (tree parm_parms, if (pargs != error_mark_node) { tree targs = make_tree_vec (nargs); - tree aargs = template_parms_level_to_args (arg_parms); + tree aargs = template_parms_level_to_args (arg_parms, complain); if (!unify (arg_parms, targs, aargs, pargs, UNIFY_ALLOW_NONE, /*explain*/false)) return 1; @@ -7493,7 +7501,8 @@ is_compatible_template_arg (tree parm, tree arg) // words, because coercion is successful, this conversion will be valid. if (parm_cons) { - tree args = template_parms_to_args (DECL_TEMPLATE_PARMS (arg)); + tree args = template_parms_to_args (DECL_TEMPLATE_PARMS (arg), + tf_none); parm_cons = tsubst_constraint_info (parm_cons, INNERMOST_TEMPLATE_ARGS (args), tf_none, NULL_TREE); @@ -7678,7 +7687,7 @@ convert_template_argument (tree parm, /* Strip alias templates that are equivalent to another template. */ - arg = get_underlying_template (arg); + arg = get_underlying_template (arg, complain); argparm = DECL_INNERMOST_TEMPLATE_PARMS (arg); if (coerce_template_template_parms (parmparm, argparm, @@ -7694,7 +7703,7 @@ convert_template_argument (tree parm, if (DECL_TEMPLATE_TEMPLATE_PARM_P (val)) val = TREE_TYPE (val); if (TREE_CODE (orig_arg) == TYPE_PACK_EXPANSION) - val = make_pack_expansion (val); + val = make_pack_expansion (val, complain); } } else @@ -8188,7 +8197,7 @@ coerce_template_parms (tree parms, else if (TYPE_P (conv) && !TYPE_P (pattern)) /* Recover from missing typename. */ TREE_VEC_ELT (inner_args, arg_idx) - = make_pack_expansion (conv); + = make_pack_expansion (conv, complain); /* We don't know how many args we have yet, just use the unconverted ones for now. */ @@ -8697,7 +8706,7 @@ lookup_template_class_1 (tree d1, tree arglist, tr the alias to avoid problems with a pack expansion passed to a non-pack alias template parameter (DR 1430). */ if (pack_expansion_args_count (INNERMOST_TEMPLATE_ARGS (arglist))) - templ = get_underlying_template (templ); + templ = get_underlying_template (templ, complain); if (DECL_TEMPLATE_TEMPLATE_PARM_P (templ)) { @@ -11161,7 +11170,7 @@ gen_elem_of_pack_expansion_instantiation (tree pat the Ith element resulting from the substituting is going to be a pack expansion as well. */ if (ith_elem_is_expansion) - t = make_pack_expansion (t); + t = make_pack_expansion (t, complain); return t; } @@ -11573,7 +11582,7 @@ tsubst_pack_expansion (tree t, tree args, tsubst_f /* We got some full packs, but we can't substitute them in until we have values for all the packs. So remember these until then. */ - t = make_pack_expansion (pattern); + t = make_pack_expansion (pattern, complain); PACK_EXPANSION_EXTRA_ARGS (t) = args; return t; } @@ -11588,7 +11597,7 @@ tsubst_pack_expansion (tree t, tree args, tsubst_f /*integral_constant_expression_p=*/false); else t = tsubst (pattern, args, complain, in_decl); - t = make_pack_expansion (t); + t = make_pack_expansion (t, complain); return t; } @@ -12551,7 +12560,8 @@ tsubst_template_decl (tree t, tree args, tsubst_fl DECL_CONTEXT (r) = DECL_CONTEXT (new_decl); if (lambda_fntype) { - tree args = template_parms_to_args (DECL_TEMPLATE_PARMS (r)); + tree args = template_parms_to_args (DECL_TEMPLATE_PARMS (r), + complain); DECL_TEMPLATE_INFO (new_decl) = build_template_info (r, args); } else @@ -21323,7 +21333,7 @@ unify (tree tparms, tree targs, tree parm, tree ar if (REFERENCE_REF_P (arg)) arg = TREE_OPERAND (arg, 0); if (pexp) - arg = make_pack_expansion (arg); + arg = make_pack_expansion (arg, complain); return unify (tparms, targs, TREE_OPERAND (parm, 0), arg, strict, explain_p); } @@ -25378,7 +25388,7 @@ rewrite_template_parm (tree olddecl, unsigned inde for (int i = 0; i < depth; ++i) TREE_VEC_ELT (ttargs, i) = TREE_VEC_ELT (tsubst_args, i); TREE_VEC_ELT (ttargs, depth) - = template_parms_level_to_args (ttparms); + = template_parms_level_to_args (ttparms, complain); // Substitute ttargs into ttparms to fix references to // other template parameters. ttparms = tsubst_template_parms_level (ttparms, ttargs, @@ -25385,7 +25395,7 @@ rewrite_template_parm (tree olddecl, unsigned inde complain); // Now substitute again with args based on tparms, to reduce // the level of the ttparms. - ttargs = current_template_args (); + ttargs = current_template_args (complain); ttparms = tsubst_template_parms_level (ttparms, ttargs, complain); // Finally, tack the adjusted parms onto tparms. @@ -25527,12 +25537,13 @@ build_deduction_guide (tree ctor, tree outer_args, = tsubst_constraint_info (TEMPLATE_PARM_CONSTRAINTS (oldelt), tsubst_args, complain, ctor); TREE_VEC_ELT (new_vec, index) = list; - TMPL_ARG (tsubst_args, depth, i) = template_parm_to_arg (list); + TMPL_ARG (tsubst_args, depth, i) + = template_parm_to_arg (list, complain); } /* Now we have a final set of template parms to substitute into the function signature. */ - targs = template_parms_to_args (tparms); + targs = template_parms_to_args (tparms, complain); fparms = tsubst_arg_types (fparms, tsubst_args, NULL_TREE, complain, ctor); fargs = tsubst (fargs, tsubst_args, complain, ctor); @@ -25950,7 +25961,7 @@ do_auto_deduction (tree type, tree init, tree auto } if (processing_template_decl && context != adc_unify) - outer_targs = current_template_args (); + outer_targs = current_template_args (complain); targs = add_to_template_args (outer_targs, targs); return tsubst (type, targs, complain, NULL_TREE); } @@ -26187,7 +26198,8 @@ convert_generic_types_to_packs (tree parm, int sta template parms. */ if (depth > 1) replacement = add_to_template_args (template_parms_to_args - (TREE_CHAIN (current_template_parms)), + (TREE_CHAIN (current_template_parms), + tf_none), replacement); return tsubst (parm, replacement, tf_none, NULL_TREE); Index: cp/tree.c =================================================================== --- cp/tree.c (revision 254249) +++ cp/tree.c (working copy) @@ -1208,7 +1208,7 @@ cp_build_qualified_type_real (tree type, tree t = PACK_EXPANSION_PATTERN (type); t = cp_build_qualified_type_real (t, type_quals, complain); - return make_pack_expansion (t); + return make_pack_expansion (t, complain); } /* A reference or method type shall not be cv-qualified. Index: testsuite/g++.dg/cpp0x/variadic-crash5.C =================================================================== --- testsuite/g++.dg/cpp0x/variadic-crash5.C (nonexistent) +++ testsuite/g++.dg/cpp0x/variadic-crash5.C (working copy) @@ -0,0 +1,28 @@ +// PR c++/81957 +// { dg-do compile { target c++11 } } + +template +struct integral_constant { }; + +struct f { + template + void operator()(integral_constant, Int i) { + } +}; + +template +auto dispatch(F f, T...t) -> decltype(f(integral_constant()..., t...)) { + return f(integral_constant()..., t...); +} + +template +auto dispatch(F f, bool b, T...t) -> decltype(dispatch(f, t...)) { + if (b) + return dispatch(f, t...); + else + return dispatch(f, t...); +} + +int main() { + dispatch(f(), true, 5); +}