From patchwork Sat Dec 8 22:12:10 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dodji Seketeli X-Patchwork-Id: 204678 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id B31C62C01C2 for ; Sun, 9 Dec 2012 09:12:40 +1100 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1355609561; h=Comment: DomainKey-Signature:Received:Received:Received:Received:Received: Received:From:To:Cc:Subject:References:Date:In-Reply-To: Message-ID:User-Agent:MIME-Version:Content-Type:Mailing-List: Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:Sender:Delivered-To; bh=CM06/TbFXy5qlU6kn2/IUnJlLrU=; b=Yk0XFb9Zq2UYcOnWWzZPflX8HZpTUjnc0FPchT1DfcGdskBF9dDLJ40lRPi5Bf ez4x04fAdvAIYDgP73KPMaoofZmHGb4uk00Za3vI8kqXARsltENBf7ydVYXuhGwM Ob5TQWwWfgL1cg0go6zegYoQnspJ94I8uEkVCOfr/ddUg= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:Received:Received:Received:From:To:Cc:Subject:References:X-URL:Date:In-Reply-To:Message-ID:User-Agent:MIME-Version:Content-Type:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=nc0hpienbn+k6PURtBcbDBJsGUJUQUkNkXF1LcBgg3bsThl47WQ0Uwlgtlp9t1 XdUMzgWX4q2+7/a5rINnSwQHelxDyNt3J/CqkrBf7VFmGblGW060bTajxlzaj31E nVz/Nj5mN5BPRPv8yhVBmSrVyHZtkiknBtUkSBjPwzC+c=; Received: (qmail 31556 invoked by alias); 8 Dec 2012 22:12:30 -0000 Received: (qmail 31540 invoked by uid 22791); 8 Dec 2012 22:12:26 -0000 X-SWARE-Spam-Status: No, hits=-6.0 required=5.0 tests=AWL, BAYES_00, KHOP_RCVD_UNTRUST, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, SPF_HELO_PASS X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sat, 08 Dec 2012 22:12:14 +0000 Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id qB8MCDAa007101 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Sat, 8 Dec 2012 17:12:13 -0500 Received: from localhost (ovpn-116-20.ams2.redhat.com [10.36.116.20]) by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id qB8MCC7C003436 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Sat, 8 Dec 2012 17:12:13 -0500 Received: by localhost (Postfix, from userid 1000) id 4A0712C00CC; Sat, 8 Dec 2012 23:12:11 +0100 (CET) From: Dodji Seketeli To: Jason Merrill Cc: GCC Patches Subject: Re: [PATCH] PR c++/53609 - Wrong argument deduction for pack expansion in argument pack References: <50A6C0B0.8070407@redhat.com> <87vccjclke.fsf@redhat.com> <50BF6FCC.90907@redhat.com> X-URL: http://www.redhat.com Date: Sat, 08 Dec 2012 23:12:10 +0100 In-Reply-To: <50BF6FCC.90907@redhat.com> (Jason Merrill's message of "Wed, 05 Dec 2012 11:01:16 -0500") Message-ID: <87ip8cb3d1.fsf@redhat.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.1 (gnu/linux) MIME-Version: 1.0 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 Jason Merrill writes: > On 12/03/2012 08:27 AM, Dodji Seketeli wrote: > > + - HAS_EXPANSION_ARG_P: Set to TRUE iff at least one parameter > > + pack has got an argument that is an expansion. > > The "got" is unnecessary, just "has an argument" is better. Removed, thanks. > > + Setup APS, which is an instance of an ARGUMENT_PACK_SELECT tree, so > > + that it selects the Ith element out of the argument pack ARG_PACK. > > + If the Ith element is a pack expansion, then just select its > > + pattern. Otherwise, select the whole element. > > I wonder if, rather than set up a temporary pack at this point, it > makes sense to look through pack expansions when we use an > ARGUMENT_PACK_SELECT. Yeah, good point. > Is there any case where we actually want an ARGUMENT_PACK_SELECT to > be an expansion? I did the change to look through pack expansions in tsubst and nothing in the testsuite seems to be wanting an ARGUMENT_PACK_SELECT to resolve to an expansion. > > > + /* If we have one parameter pack whose matching argument pack is > > + just what template_parm_to_arg returned when passed the > > + parameter pack, or if we only have empty arguments ... */ > > + else if (arg_from_pack_level_to_prune || has_empty_arg) > > + { > > + /* ... we just return a pack expansion which pattern is PATTERN > > + into which ARGS has been substituted. */ > > + *instantiation_yields_no_list_p = true; > > + } > > I was thinking we wouldn't need to recognize this case specifically, > that the code following it would work the way we want. If callers get > a vector with a single pack expansion element rather than just a pack > expansion, is that a problem? Alternately, if len == 1, maybe we > should always just return the single element. Right, I made the change to do away with the need of the instantiation_yields_no_list_p variable. Though I think it would still be appropriate to keep this 'if' just to avoid going into the 'else' block for cases where we know that looping over the parameter packs (and do the ARGUMENT_PACK_SELECT dance) is unnecessary; all we want is to go straight to the point where we substitute args into the pattern, build a pack expansion and return it. Or isn't what you meant? > > > + /* We could not find any argument packs that work, so we'll just > > + return an unsubstituted pack expansion. The caller must be > > + prepared to deal with this. */ > > if (len < 0) > > - return error_mark_node; > > + len = 1; > > Why this change? Why is returning error_mark_node no longer the right > thing to do? My understanding is that in practise, we never hit this point in the previous code. The reason why len would still be negative at this point would be if we didn't find any (good) argument pack. But in that case, we would have considered that we have unsubstituted packs and would have returned an unsubstituted pack expansion before we reach this point. So I believe this new code follows the same logic. Am I missing something? Also, I just tried returning error_mark_node, (just to make sure) and it broke quite some tests of the suite. Tested on x86_64-unknown-linux-gnu against trunk. gcc/cp/ * pt.c (argument_pack_element_is_expansion_p) (make_argument_pack_select, scan_parm_packs) (gen_elem_of_pack_expansion_instantiation): New static functions. (has_bare_parameter_packs): Factorized out of ... (check_for_bare_parameter_packs): ... here. (tsubst): When looking through an ARGUMENT_PACK_SELECT tree node, look through the possibly resulting pack expansion as well. (tsubst_pack_expansion): Now this function is clearly organized in two parts: a part that maps each parameter pack with its matching argument pack, and a part that walks that map to build the result of substituting each element of the argument packs into the parameter packs. Use gen_elem_of_pack_expansion_instantiation for the latter part. gcc/testsuite/ * g++.dg/cpp0x/variadic139.C: New test. * g++.dg/cpp0x/variadic140.C: Likewise. * g++.dg/cpp0x/variadic141.C: Likewise. --- gcc/cp/pt.c | 459 +++++++++++++++++++++---------- gcc/testsuite/g++.dg/cpp0x/variadic139.C | 14 + gcc/testsuite/g++.dg/cpp0x/variadic140.C | 22 ++ gcc/testsuite/g++.dg/cpp0x/variadic141.C | 22 ++ 4 files changed, 373 insertions(+), 144 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic139.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic140.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic141.C diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index ecb013e..1436721 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -3308,6 +3308,29 @@ make_pack_expansion (tree arg) return result; } +/* Return NULL_TREE iff T contains *NO* unexpanded parameter packs. + Return the TREE_LIST of unexpanded parameter packs otherwise. */ + +static tree +has_bare_parameter_packs (tree t) +{ + tree parameter_packs = NULL_TREE; + struct find_parameter_pack_data ppd; + + if (!processing_template_decl || !t || t == error_mark_node) + return NULL_TREE; + + if (TREE_CODE (t) == TYPE_DECL) + t = TREE_TYPE (t); + + ppd.parameter_packs = ¶meter_packs; + ppd.visited = pointer_set_create (); + cp_walk_tree (&t, &find_parameter_packs_r, &ppd, ppd.visited); + pointer_set_destroy (ppd.visited); + + return parameter_packs; +} + /* Checks T for any "bare" parameter packs, which have not yet been expanded, and issues an error if any are found. This operation can only be done on full expressions or types (e.g., an expression @@ -3325,19 +3348,7 @@ make_pack_expansion (tree arg) bool check_for_bare_parameter_packs (tree t) { - tree parameter_packs = NULL_TREE; - struct find_parameter_pack_data ppd; - - if (!processing_template_decl || !t || t == error_mark_node) - return false; - - if (TREE_CODE (t) == TYPE_DECL) - t = TREE_TYPE (t); - - ppd.parameter_packs = ¶meter_packs; - ppd.visited = pointer_set_create (); - cp_walk_tree (&t, &find_parameter_packs_r, &ppd, ppd.visited); - pointer_set_destroy (ppd.visited); + tree parameter_packs = has_bare_parameter_packs (t); if (parameter_packs) { @@ -9095,6 +9106,256 @@ make_fnparm_pack (tree spec_parm) return extract_fnparm_pack (NULL_TREE, &spec_parm); } +/* Return true iff the Ith element of the argument pack ARG_PACK is a + pack expansion. */ + +static bool +argument_pack_element_is_expansion_p (tree arg_pack, int i) +{ + tree vec = ARGUMENT_PACK_ARGS (arg_pack); + if (i >= TREE_VEC_LENGTH (vec)) + return false; + return PACK_EXPANSION_P (TREE_VEC_ELT (vec, i)); +} + + +/* Creates and return an ARGUMENT_PACK_SELECT tree node. */ + +static tree +make_argument_pack_select (tree arg_pack, unsigned index) +{ + tree aps = make_node (ARGUMENT_PACK_SELECT); + + ARGUMENT_PACK_SELECT_FROM_PACK (aps) = arg_pack; + ARGUMENT_PACK_SELECT_INDEX (aps) = index; + + return aps; +} + +/* This is a subroutine of gen_elem_of_pack_expansion_instantiation, + which is itself a subroutine of tsubst_pack_expansion. + + For a given INDEX of an argument pack, this function scans the + list of parameter packs PARM_PACKS and reports some interesting + properties about them. Note that PARM_PACKS must be an instance of + TREE_LIST where TREE_PURPOSE is a parameter pack, and TREE_VALUE + is the argument for that pack. + + The properties returned about the scanned parameter packs + are the following: + + - HAS_EXPANSION_ARG_P: Set to TRUE iff at least one parameter + pack has an argument that is an expansion. + - HAS_NON_EXPANSION_ARG_P: Set to TRUE iff at least one + parameter pack has an argument that is not an expansion. + - HAS_EMPTY_ARG_P: Set to TRUE iff at least one parameter pack has + no argument. + - ARG_FROM_PACK_LEVEL_TO_PRUNE: is non-zero iff the argument of + the parameter pack is the result of calling template_parm_to_arg + on the pack. In that case, this is set to the parameter level + of that pack. */ + +static void +scan_parm_packs (tree parm_packs, + unsigned index, + bool *has_expansion_arg_p, + bool *has_non_expansion_arg_p, + bool *has_empty_arg_p, + int *arg_from_pack_level_to_prune) +{ + + if (parm_packs == NULL_TREE) + { + if (has_empty_arg_p) + *has_empty_arg_p = true; + return ; + } + + for (tree parm_pack = parm_packs; + parm_pack; + parm_pack = TREE_CHAIN (parm_pack)) + { + tree arg = TREE_VALUE (parm_pack); + tree parm = TREE_PURPOSE (parm_pack); + + if (arg == NULL_TREE) + { + if (has_empty_arg_p) + *has_empty_arg_p = true; + continue; + } + + if (arg_from_pack_level_to_prune != NULL + && arg_from_parm_pack_p (arg, parm)) + { + int level = 0, idx = 0; + if (TREE_CODE (parm) == PARM_DECL) + parm = DECL_INITIAL (parm); + template_parm_level_and_index (parm, &level, &idx); + if (*arg_from_pack_level_to_prune == 0 + || *arg_from_pack_level_to_prune > level) + *arg_from_pack_level_to_prune = level; + return; + } + + if (argument_pack_element_is_expansion_p (arg, index)) + { + if (has_expansion_arg_p != NULL) + *has_expansion_arg_p = true; + } + else + { + if (has_non_expansion_arg_p != NULL) + *has_non_expansion_arg_p = true; + } + } +} + +/* [temp.variadic]/6 says that: + + The instantiation of a pack expansion [...] + produces a list E1,E2, ..., En, where N is the number of elements + in the pack expansion parameters. + + This subroutine of tsubst_pack_expansion produces one of these Ei. + + PATTERN is the pattern of the pack expansion. PARM_PACKS is a + TREE_LIST in which each TREE_PURPOSE is a parameter pack of + PATTERN, and each TREE_VALUE is its corresponding argument pack. + INDEX is the index 'i' of the element Ei to produce. ARGS, + COMPLAIN, and IN_DECL are the same parameters as for the + tsubst_pack_expansion function. + + The function returns the resulting Ei upon successful completion, + or error_mark_node. + + Note that this function possibly modifies the ARGS parameter, so + it's the responsibility of the caller to restore it. */ + +static tree +gen_elem_of_pack_expansion_instantiation (tree pattern, + tree parm_packs, + unsigned index, + tree args /* This parm gets + modified. */, + tsubst_flags_t complain, + tree in_decl) +{ + /* The boolean below is TRUE if at least one parameter pack doesn't + yet have all argument packs to really perform the + susbtituting. */ + bool use_pack_expansion_extra = false, + has_expansion_arg = false, + has_non_expansion_arg = false, + has_empty_arg = false; + int arg_from_pack_level_to_prune = 0; + tree t; + + scan_parm_packs (parm_packs, index, + &has_expansion_arg, + &has_non_expansion_arg, + &has_empty_arg, + &arg_from_pack_level_to_prune); + + if ((has_expansion_arg && has_non_expansion_arg) + || (has_empty_arg && (has_expansion_arg || has_non_expansion_arg))) + use_pack_expansion_extra = true; + + if (use_pack_expansion_extra) + { + /* 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. */ + + int levels = TMPL_ARGS_DEPTH (args); + tree save_args; + + /* The call to add_to_template_args in tsubst_pack_expansion + assumes no overlap between saved args and new args, so prune + away any fake args, i.e. those that satisfied + arg_from_parm_pack_p in scan_parm_packs above. */ + if (arg_from_pack_level_to_prune != 0 + && levels >= arg_from_pack_level_to_prune) + { + gcc_assert (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args) + && arg_from_pack_level_to_prune > 1); + TREE_VEC_LENGTH (args) = arg_from_pack_level_to_prune - 1; + save_args = copy_node (args); + TREE_VEC_LENGTH (args) = levels; + } + else + save_args = args; + + t = make_pack_expansion (pattern); + PACK_EXPANSION_EXTRA_ARGS (t) = save_args; + + return t; + } + /* If we have one parameter pack whose matching argument pack is + just what template_parm_to_arg returned when passed the + parameter pack, or if we only have empty arguments ... */ + else if (arg_from_pack_level_to_prune || has_empty_arg) + /* ... we just return a pack expansion which pattern is PATTERN + into which ARGS has been substituted. */; + else + { + /* For each parameter pack, change the substitution of the parameter + pack to the ith argument in its argument pack, then expand the + pattern. */ + for (tree pack = parm_packs; pack; pack = TREE_CHAIN (pack)) + { + tree parm = TREE_PURPOSE (pack); + tree arg_pack = TREE_VALUE (pack); + tree aps; /* instance of ARGUMENT_PACK_SELECT + tree. */ + + /* Select the Ith argument from the pack. */ + if (TREE_CODE (parm) == PARM_DECL) + { + if (index == 0) + { + aps = make_argument_pack_select (arg_pack, index); + mark_used (parm); + register_local_specialization (aps, parm); + } + else + aps = retrieve_local_specialization (parm); + } + else + { + int idx, level; + template_parm_level_and_index (parm, &level, &idx); + + if (index == 0) + { + aps = make_argument_pack_select (arg_pack, index); + /* Update the corresponding argument. */ + TMPL_ARG (args, level, idx) = aps; + } + else + /* Re-use the ARGUMENT_PACK_SELECT. */ + aps = TMPL_ARG (args, level, idx); + } + ARGUMENT_PACK_SELECT_INDEX (aps) = index; + } + } + + /* Substitute into the PATTERN with the (possibly altered) + arguments. */ + if (!TYPE_P (pattern)) + t = tsubst_expr (pattern, args, complain, in_decl, + /*integral_constant_expression_p=*/false); + else + t = tsubst (pattern, args, complain, in_decl); + + /* If the Ith argument pack element is a pack expansion, then + the Ith element resulting from the substituting is going to + be a pack expansion as well. */ + if (has_bare_parameter_packs (t)) + t = make_pack_expansion (t); + + return t; +} + /* Substitute ARGS into T, which is an pack expansion (i.e. TYPE_PACK_EXPANSION or EXPR_PACK_EXPANSION). Returns a TREE_VEC with the substituted arguments, a PACK_EXPANSION_* node @@ -9106,9 +9367,6 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain, { tree pattern; tree pack, packs = NULL_TREE; - bool unsubstituted_packs = false; - bool real_packs = false; - int missing_level = 0; int i, len = -1; tree result; struct pointer_map_t *saved_local_specializations = NULL; @@ -9187,14 +9445,6 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain, return result; } - if (arg_from_parm_pack_p (arg_pack, parm_pack)) - /* The argument pack that the parameter maps to is just an - expansion of the parameter itself, such as one would find - in the implicit typedef of a class inside the class itself. - Consider this parameter "unsubstituted", so that we will - maintain the outer pack expansion. */ - arg_pack = NULL_TREE; - if (arg_pack) { int my_len = @@ -9221,77 +9471,19 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain, pattern); return error_mark_node; } - - if (TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg_pack)) == 1 - && PACK_EXPANSION_P (TREE_VEC_ELT (ARGUMENT_PACK_ARGS (arg_pack), - 0))) - /* This isn't a real argument pack yet. */; - else - real_packs = true; - - /* Keep track of the parameter packs and their corresponding - argument packs. */ - packs = tree_cons (parm_pack, arg_pack, packs); - TREE_TYPE (packs) = orig_arg; } - else - { - /* We can't substitute for this parameter pack. We use a flag as - well as the missing_level counter because function parameter - packs don't have a level. */ - unsubstituted_packs = true; - if (!missing_level || missing_level > level) - missing_level = level; - } - } - - /* We cannot expand this expansion expression, because we don't have - all of the argument packs we need. */ - if (unsubstituted_packs) - { - if (real_packs) - { - /* 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. */ - tree save_args; - - t = make_pack_expansion (pattern); - /* The call to add_to_template_args above assumes no overlap - between saved args and new args, so prune away any fake - args, i.e. those that satisfied arg_from_parm_pack_p above. */ - if (missing_level && levels >= missing_level) - { - gcc_assert (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args) - && missing_level > 1); - TREE_VEC_LENGTH (args) = missing_level - 1; - save_args = copy_node (args); - TREE_VEC_LENGTH (args) = levels; - } - else - save_args = args; - - PACK_EXPANSION_EXTRA_ARGS (t) = save_args; - } - else - { - /* There were no real arguments, we're just replacing a parameter - pack with another version of itself. Substitute into the - pattern and return a PACK_EXPANSION_*. The caller will need to - deal with that. */ - if (TREE_CODE (t) == EXPR_PACK_EXPANSION) - t = tsubst_expr (pattern, args, complain, in_decl, - /*integral_constant_expression_p=*/false); - else - t = tsubst (pattern, args, complain, in_decl); - t = make_pack_expansion (t); - } - return t; + /* Keep track of the parameter packs and their corresponding + argument packs. */ + packs = tree_cons (parm_pack, arg_pack, packs); + TREE_TYPE (packs) = orig_arg; } - /* We could not find any argument packs that work. */ + /* We could not find any argument packs that work, so we'll just + return an unsubstituted pack expansion. The caller must be + prepared to deal with this. */ if (len < 0) - return error_mark_node; + len = 1; if (need_local_specializations) { @@ -9306,60 +9498,19 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain, /* For each argument in each argument pack, substitute into the pattern. */ result = make_tree_vec (len); - for (i = 0; i < len; ++i) + if (len > 0) { - /* For parameter pack, change the substitution of the parameter - pack to the ith argument in its argument pack, then expand - the pattern. */ - for (pack = packs; pack; pack = TREE_CHAIN (pack)) - { - tree parm = TREE_PURPOSE (pack); - tree arg; - - /* Select the Ith argument from the pack. */ - if (TREE_CODE (parm) == PARM_DECL) - { - if (i == 0) - { - arg = make_node (ARGUMENT_PACK_SELECT); - ARGUMENT_PACK_SELECT_FROM_PACK (arg) = TREE_VALUE (pack); - mark_used (parm); - register_local_specialization (arg, parm); - } - else - arg = retrieve_local_specialization (parm); - } - else - { - int idx, level; - template_parm_level_and_index (parm, &level, &idx); - - if (i == 0) - { - arg = make_node (ARGUMENT_PACK_SELECT); - ARGUMENT_PACK_SELECT_FROM_PACK (arg) = TREE_VALUE (pack); - /* Update the corresponding argument. */ - TMPL_ARG (args, level, idx) = arg; - } - else - /* Re-use the ARGUMENT_PACK_SELECT. */ - arg = TMPL_ARG (args, level, idx); - } - ARGUMENT_PACK_SELECT_INDEX (arg) = i; - } - - /* Substitute into the PATTERN with the altered arguments. */ - if (!TYPE_P (pattern)) - TREE_VEC_ELT (result, i) = - tsubst_expr (pattern, args, complain, in_decl, - /*integral_constant_expression_p=*/false); - else - TREE_VEC_ELT (result, i) = tsubst (pattern, args, complain, in_decl); - - if (TREE_VEC_ELT (result, i) == error_mark_node) + for (i = 0; i < len; ++i) { - result = error_mark_node; - break; + t = gen_elem_of_pack_expansion_instantiation (pattern, packs, i, + args, complain, + in_decl); + TREE_VEC_ELT (result, i) = t; + if (t == error_mark_node) + { + result = error_mark_node; + break; + } } } @@ -9374,6 +9525,10 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain, else { int idx, level; + + if (TREE_VALUE (pack) == NULL_TREE) + continue; + template_parm_level_and_index (parm, &level, &idx); /* Update the corresponding argument. */ @@ -11102,8 +11257,24 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) arg = TMPL_ARG (args, level, idx); if (arg && TREE_CODE (arg) == ARGUMENT_PACK_SELECT) - /* See through ARGUMENT_PACK_SELECT arguments. */ - arg = ARGUMENT_PACK_SELECT_ARG (arg); + { + /* See through ARGUMENT_PACK_SELECT arguments. */ + arg = ARGUMENT_PACK_SELECT_ARG (arg); + /* If the selected argument is an expansion E, that most + likely means we were called from + gen_elem_of_pack_expansion_instantiation during the + substituting of pack an argument pack (which Ith + element is a pack expansion, where I is + ARGUMENT_PACK_SELECT_INDEX) into a pack expansion. + In this case, the Ith element resulting from this + substituting is going to be a pack expansion, which + pattern is the pattern of E. Let's return the + pattern of E, and + gen_elem_of_pack_expansion_instantiation will + build the resulting pack expansion from it. */ + if (PACK_EXPANSION_P (arg)) + arg = PACK_EXPANSION_PATTERN (arg); + } } if (arg == error_mark_node) diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic139.C b/gcc/testsuite/g++.dg/cpp0x/variadic139.C new file mode 100644 index 0000000..a1c64f3 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/variadic139.C @@ -0,0 +1,14 @@ +// Origin: PR c++/53609 +// { dg-do compile { target c++11 } } + +template struct List {}; +template struct Z {static const int value = T;}; +template using LZ = List...>; + +template +struct F +{ + using N = LZ; +}; + +F, Z<2> >::N A; diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic140.C b/gcc/testsuite/g++.dg/cpp0x/variadic140.C new file mode 100644 index 0000000..17ca9e5 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/variadic140.C @@ -0,0 +1,22 @@ +// Origin: PR c++/53609 +// { dg-do compile { target c++11 } } + +template struct List{ static const bool is_ok = false;}; +template struct Z +{ + static const int value = T; + static const int value_square = T * T; +}; + +template class U> +struct List, U<3>, U<4>, U<9>> { static const bool is_ok = true;}; + +template using LZ = List...>; + +template +struct F +{ + using N = LZ; +}; + +static_assert (F, Z<3>>::N::is_ok, ""); diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic141.C b/gcc/testsuite/g++.dg/cpp0x/variadic141.C new file mode 100644 index 0000000..6b893a7 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/variadic141.C @@ -0,0 +1,22 @@ +// Origin: PR c++/53609 +// { dg-do compile { target c++11 } } + +template struct List{ static const bool is_ok = false;}; +template struct Z +{ + static const int value = T; + static const int value_square = T * T; +}; + +template class U> +struct List, U<3>, U<4>, U<9>> { static const bool is_ok = true;}; + +template using LZ = List...>; + +template +struct F +{ + using N = LZ::value, Z<9>::value>; +}; + +static_assert (F, Z<3>>::N::is_ok, "");