From patchwork Tue Nov 13 04:34:34 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Merrill X-Patchwork-Id: 996778 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-489821-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="CfzTPZ7U"; 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 42vFCY0RN8z9s5c for ; Tue, 13 Nov 2018 15:34:48 +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:from :to:subject:date:message-id; q=dns; s=default; b=yyO4lzW5WW7kqSH MwiVV9gNvHQbGuc91pp/Bhcm6Cr3ZghFcsaB5KEKD1LSSxJlO0jSLp9h0Yd1i2oG fYebu7HyIa9XqNqzc6GtIbifVDgMeNjKaSfJQXcAp4Og2Ms72MG7Ch/7DKCFuV7H z+Ec0NxMuCkowBkmUmeU1Th4SLns= 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:from :to:subject:date:message-id; s=default; bh=2s8mBzoupL+nUR862Gwxb lsMllM=; b=CfzTPZ7UWLOlCGY/GfjmPcL/+XdCqlMVmGg1gWtl7ztA4PePv2HEZ Be2cpjl+YyMzmaX5kyUhE4Pgtmuy0SMZ7PVUUcNQ8KoyO4Cc+h9MCppWH7jZY6cu RMHFNE5UiAgFiepCqIenoE5ebdcs3Vhu5U+WCKyKgyKUH+yQvmz/1g= Received: (qmail 16757 invoked by alias); 13 Nov 2018 04:34:41 -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 16740 invoked by uid 89); 13 Nov 2018 04:34:41 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-25.2 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.2 spammy=proxy, cname X-HELO: mail-qk1-f196.google.com Received: from mail-qk1-f196.google.com (HELO mail-qk1-f196.google.com) (209.85.222.196) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 13 Nov 2018 04:34:39 +0000 Received: by mail-qk1-f196.google.com with SMTP id m5so17362763qka.9 for ; Mon, 12 Nov 2018 20:34:39 -0800 (PST) Received: from orpheus.redhat.com (209-6-216-142.s141.c3-0.smr-cbr1.sbo-smr.ma.cable.rcncustomer.com. [209.6.216.142]) by smtp.gmail.com with ESMTPSA id i26sm13769020qtc.13.2018.11.12.20.34.36 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Mon, 12 Nov 2018 20:34:36 -0800 (PST) From: Jason Merrill To: gcc-patches@gcc.gnu.org Subject: [C++ PATCH] Implement P0780R2, pack expansion in lambda init-capture. Date: Mon, 12 Nov 2018 23:34:34 -0500 Message-Id: <20181113043434.8860-1-jason@redhat.com> X-IsSubscribed: yes Mostly this was straightforward; the tricky bit was finding, in the instantiation, the set of capture proxies built when instantiating the init-capture. The comment in lookup_init_capture_pack goes into detail. Tested x86_64-pc-linux-gnu, applying to trunk. * parser.c (cp_parser_lambda_introducer): Parse pack init-capture. * pt.c (tsubst_pack_expansion): Handle init-capture packs. (lookup_init_capture_pack): New. (tsubst_expr) [DECL_EXPR]: Use it. (tsubst_lambda_expr): Remember field pack expansions for init-captures. --- gcc/cp/parser.c | 13 +++ gcc/cp/pt.c | 93 ++++++++++++++++--- .../g++.dg/cpp2a/lambda-pack-init1.C | 17 ++++ gcc/cp/ChangeLog | 10 ++ 4 files changed, 122 insertions(+), 11 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-pack-init1.C base-commit: 4daed3b3d5561c30ad430f35a260fbcdf06e397d diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 465ab8fdbae..0428f6dda90 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -10395,6 +10395,17 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr) continue; } + bool init_pack_expansion = false; + if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS)) + { + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + if (cxx_dialect < cxx2a) + pedwarn (loc, 0, "pack init-capture only available with " + "-std=c++2a or -std=gnu++2a"); + cp_lexer_consume_token (parser->lexer); + init_pack_expansion = true; + } + /* Remember whether we want to capture as a reference or not. */ if (cp_lexer_next_token_is (parser->lexer, CPP_AND)) { @@ -10438,6 +10449,8 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr) error ("empty initializer for lambda init-capture"); capture_init_expr = error_mark_node; } + if (init_pack_expansion) + capture_init_expr = make_pack_expansion (capture_init_expr); } else { diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 4cb8238ba12..0c33c8e1527 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -12151,7 +12151,7 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain, where it isn't expected). */ unsubstituted_fn_pack = true; } - else if (is_normal_capture_proxy (parm_pack)) + else if (is_capture_proxy (parm_pack)) { arg_pack = retrieve_local_specialization (parm_pack); if (argument_pack_element_is_expansion_p (arg_pack, 0)) @@ -16769,6 +16769,55 @@ tsubst_decomp_names (tree decl, tree pattern_decl, tree args, return decl; } +/* Return the proper local_specialization for init-capture pack DECL. */ + +static tree +lookup_init_capture_pack (tree decl) +{ + /* We handle normal pack captures by forwarding to the specialization of the + captured parameter. We can't do that for pack init-captures; we need them + to have their own local_specialization. We created the individual + VAR_DECLs (if any) under build_capture_proxy, and we need to collect them + when we process the DECL_EXPR for the pack init-capture in the template. + So, how do we find them? We don't know the capture proxy pack when + building the individual resulting proxies, and we don't know the + individual proxies when instantiating the pack. What we have in common is + the FIELD_DECL. + + So...when we instantiate the FIELD_DECL, we stick the result in + local_specializations. Then at the DECL_EXPR we look up that result, see + how many elements it has, synthesize the names, and look them up. */ + + tree cname = DECL_NAME (decl); + tree val = DECL_VALUE_EXPR (decl); + tree field = TREE_OPERAND (val, 1); + gcc_assert (TREE_CODE (field) == FIELD_DECL); + tree fpack = retrieve_local_specialization (field); + if (fpack == error_mark_node) + return error_mark_node; + + int len = 1; + tree vec = NULL_TREE; + tree r = NULL_TREE; + if (TREE_CODE (fpack) == TREE_VEC) + { + len = TREE_VEC_LENGTH (fpack); + vec = make_tree_vec (len); + r = make_node (NONTYPE_ARGUMENT_PACK); + SET_ARGUMENT_PACK_ARGS (r, vec); + } + for (int i = 0; i < len; ++i) + { + tree ename = vec ? make_ith_pack_parameter_name (cname, i) : cname; + tree elt = lookup_name_real (ename, 0, 0, true, 0, LOOKUP_NORMAL); + if (vec) + TREE_VEC_ELT (vec, i) = elt; + else + r = elt; + } + return r; +} + /* Like tsubst_copy for expressions, etc. but also does semantic processing. */ @@ -16854,18 +16903,21 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, /* We're in tsubst_lambda_expr, we've already inserted a new capture proxy, so look it up and register it. */ tree inst; - if (DECL_PACK_P (decl)) + if (!DECL_PACK_P (decl)) + { + inst = lookup_name_real (DECL_NAME (decl), 0, 0, + /*block_p=*/true, 0, LOOKUP_HIDDEN); + gcc_assert (inst != decl && is_capture_proxy (inst)); + } + else if (is_normal_capture_proxy (decl)) { inst = (retrieve_local_specialization (DECL_CAPTURED_VARIABLE (decl))); gcc_assert (TREE_CODE (inst) == NONTYPE_ARGUMENT_PACK); } else - { - inst = lookup_name_real (DECL_NAME (decl), 0, 0, - /*block_p=*/true, 0, LOOKUP_HIDDEN); - gcc_assert (inst != decl && is_capture_proxy (inst)); - } + inst = lookup_init_capture_pack (decl); + register_local_specialization (inst, decl); break; } @@ -17812,13 +17864,22 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) gcc_assert (LAMBDA_EXPR_THIS_CAPTURE (t) == NULL_TREE && LAMBDA_EXPR_PENDING_PROXIES (t) == NULL); + vec* field_packs = NULL; + for (tree cap = LAMBDA_EXPR_CAPTURE_LIST (t); cap; cap = TREE_CHAIN (cap)) { - tree field = TREE_PURPOSE (cap); - if (PACK_EXPANSION_P (field)) - field = PACK_EXPANSION_PATTERN (field); - field = tsubst_decl (field, args, complain); + tree ofield = TREE_PURPOSE (cap); + if (PACK_EXPANSION_P (ofield)) + ofield = PACK_EXPANSION_PATTERN (ofield); + tree field = tsubst_decl (ofield, args, complain); + + if (DECL_PACK_P (ofield) && !DECL_NORMAL_CAPTURE_P (ofield)) + { + /* Remember these for when we've pushed local_specializations. */ + vec_safe_push (field_packs, ofield); + vec_safe_push (field_packs, field); + } if (field == error_mark_node) return error_mark_node; @@ -17908,6 +17969,16 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) tree body = start_lambda_function (fn, r); + /* Now record them for lookup_init_capture_pack. */ + int fplen = vec_safe_length (field_packs); + for (int i = 0; i < fplen; ) + { + tree pack = (*field_packs)[i++]; + tree inst = (*field_packs)[i++]; + register_local_specialization (inst, pack); + } + release_tree_vector (field_packs); + register_parameter_specializations (oldfn, fn); if (oldtmpl) diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-pack-init1.C b/gcc/testsuite/g++.dg/cpp2a/lambda-pack-init1.C new file mode 100644 index 00000000000..89c63532831 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/lambda-pack-init1.C @@ -0,0 +1,17 @@ +// { dg-do compile { target c++2a } } + +void bar(); +void bar(int); + +template +void foo(Args... args) { + [...xs=args]{ + bar(xs...); // xs is an init-capture pack + }; +} + +int main() +{ + foo(); // OK: xs contains zero init-captures + foo(1); // OK: xs contains one init-capture +} diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 066d293e531..864d47cf17a 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,13 @@ +2018-11-09 Jason Merrill + + Implement P0780R2, pack expansion in lambda init-capture. + * parser.c (cp_parser_lambda_introducer): Parse pack init-capture. + * pt.c (tsubst_pack_expansion): Handle init-capture packs. + (lookup_init_capture_pack): New. + (tsubst_expr) [DECL_EXPR]: Use it. + (tsubst_lambda_expr): Remember field pack expansions for + init-captures. + 2018-11-12 Jason Merrill * cp-tree.h (struct cp_evaluated): New.