From patchwork Wed Feb 27 21:54:08 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Merrill X-Patchwork-Id: 1049157 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-497134-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="ykh3fyHb"; 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 448qGC5rvCz9sBL for ; Thu, 28 Feb 2019 08:54:25 +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:mime-version :content-transfer-encoding; q=dns; s=default; b=jMhpttkZSeFcLzzm z++xJEQaoSyrtP6X6UtcEOpGjibW+xExPSFZ11JyatXO4qtAdHShwe8Clp3dQ0zo RrZ2G8kB1IVA0FIFR0KOLTmfCJHowLRgaBHUfUzZBY2Clxaqp0DUbOe6JThHR7a0 4HR04vjZYksw9iBX+87/MUeRW+c= 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:mime-version :content-transfer-encoding; s=default; bh=zVJdDvZxPEFCmoTmfwnsNI WJgM8=; b=ykh3fyHb2MTZWNRP56jb06280KrLkFzhOuGRQfmImEEFqBlR0Xg6ON AdyPeHM/D8iSKLAzdcNJv2WDoCDVP28MNNuzXkX/qgxbDEbg/cszwi6A9RrcmDO8 NiYoW3RGQ4hWUY+mT2icg5bawnxi/N2b31nSTc6M3+vyH+l5dQIeg= Received: (qmail 83134 invoked by alias); 27 Feb 2019 21:54:14 -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 83112 invoked by uid 89); 27 Feb 2019 21:54:14 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=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=Hx-spam-relays-external:209.85.160.196, cpp1z, deciding, H*RU:209.85.160.196 X-HELO: mail-qt1-f196.google.com Received: from mail-qt1-f196.google.com (HELO mail-qt1-f196.google.com) (209.85.160.196) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 27 Feb 2019 21:54:12 +0000 Received: by mail-qt1-f196.google.com with SMTP id w4so21218197qtc.1 for ; Wed, 27 Feb 2019 13:54:12 -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 z190sm9131228qkb.9.2019.02.27.13.54.09 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Wed, 27 Feb 2019 13:54:09 -0800 (PST) From: Jason Merrill To: gcc-patches@gcc.gnu.org Subject: [C++ PATCH] PR c++/86969 - ICE with constexpr if and recursive generic lambdas. Date: Wed, 27 Feb 2019 16:54:08 -0500 Message-Id: <20190227215408.21678-1-jason@redhat.com> MIME-Version: 1.0 X-IsSubscribed: yes Here, the problem was that extract_local_specs wasn't seeing that we use 'self' inside the lambda in the else of the inner constexpr if, because we don't walk into lambda bodies and we didn't capture it in the lambda because 'self' is still dependent. Marek recently changed process_outer_var_ref to do more implicit capture in templates; this example shows that we should always capture non-packs, so that we can continue to not walk into lambda bodies. We do walk into lambda bodies for pack expansions, so we can delay deciding whether we're capturing a single element or the entire pack. Immediately capturing a VLA means we need to create a dependent VLA capture type, and not in the context of the lambda op(), since trying to look up the instantiation of the op() while we're substituting into the capture list would crash. So I force TYPE_CONTEXT and the binding level out to the enclosing function before pushtag, avoid adding a TAG_DEFN, and instead force the type to be complete in tsubst_lambda_expr. Tested x86_64-pc-linux-gnu, applying to trunk. * semantics.c (process_outer_var_ref): Do capture dependent vars. * class.c (finish_struct): Only add TAG_DEFN if T is in current_function_decl. * lambda.c (vla_capture_type): Force the capture type out into the lambda's enclosing function. (add_capture): Pass in the lambda. * pt.c (tsubst_lambda_expr): complete_type a VLA capture type. --- gcc/cp/class.c | 1 + gcc/cp/lambda.c | 28 ++++++++++++++++++--- gcc/cp/pt.c | 4 +++ gcc/cp/semantics.c | 8 +++--- gcc/testsuite/g++.dg/cpp1z/constexpr-if27.C | 22 ++++++++++++++++ gcc/cp/ChangeLog | 11 ++++++++ 6 files changed, 68 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1z/constexpr-if27.C base-commit: c70a6d7d64938ac4d2fe4b6364819b1cffd5c136 diff --git a/gcc/cp/class.c b/gcc/cp/class.c index f44acfd62b5..830ede56af8 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -7246,6 +7246,7 @@ finish_struct (tree t, tree attributes) error ("trying to finish struct, but kicked out due to previous parse errors"); if (processing_template_decl && at_function_scope_p () + && TYPE_CONTEXT (t) == current_function_decl /* Lambdas are defined by the LAMBDA_EXPR. */ && !LAMBDA_TYPE_P (t)) add_stmt (build_min (TAG_DEFN, t)); diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index d178f15a4da..c25df2fbc0e 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -479,9 +479,31 @@ static GTY(()) tree max_id; an array of runtime length. */ static tree -vla_capture_type (tree array_type) +vla_capture_type (tree array_type, tree lambda) { - tree type = xref_tag (record_type, make_anon_name (), ts_current, false); + tree closure = LAMBDA_EXPR_CLOSURE (lambda); + tree type = make_class_type (RECORD_TYPE); + cp_binding_level *slev = current_binding_level; + if (closure) + { + /* If we're already inside the lambda body, force the capture type out + into the enclosing context, so we don't crash trying to instantiate + the capture field in tsubst_lambda_expr. We won't have a TAG_DEFN + from finish_struct in the enclosing context, which we work around in + tsubst_lambda_expr. */ + TYPE_CONTEXT (type) = TYPE_CONTEXT (closure); + cp_binding_level *b = current_binding_level; + for (;; b = b->level_chain) + if (b->this_entity == closure) + { + while (b->this_entity == closure) + b = b->level_chain; + break; + } + current_binding_level = b; + } + type = pushtag (make_anon_name (), type, ts_current); + current_binding_level = slev; xref_basetypes (type, NULL_TREE); type = begin_class_definition (type); if (!ptr_id) @@ -541,7 +563,7 @@ add_capture (tree lambda, tree id, tree orig_init, bool by_reference_p, initializer = build_constructor_va (init_list_type_node, 2, NULL_TREE, build_address (elt), NULL_TREE, array_type_nelts (type)); - type = vla_capture_type (type); + type = vla_capture_type (type, lambda); } else if (!dependent_type_p (type) && variably_modified_type_p (type, NULL_TREE)) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index d678e278078..673ea8e2258 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -17989,6 +17989,10 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) if (PACK_EXPANSION_P (ofield)) ofield = PACK_EXPANSION_PATTERN (ofield); tree field = tsubst_decl (ofield, args, complain); + if (DECL_VLA_CAPTURE_P (ofield)) + /* The type of a VLA capture might not have a TAG_DEFN in the enclosing + context, so complete it here. */ + complete_type (TREE_TYPE (field)); if (DECL_PACK_P (ofield) && !DECL_NORMAL_CAPTURE_P (ofield)) { diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index da814bdd655..d1a378acd98 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -3469,10 +3469,12 @@ process_outer_var_ref (tree decl, tsubst_flags_t complain, bool odr_use) = decl_function_context (containing_function); } - /* In a lambda within a template, wait until instantiation - time to implicitly capture a dependent type. */ + /* In a lambda within a template, wait until instantiation time to implicitly + capture a parameter pack. We want to wait because we don't know if we're + capturing the whole pack or a single element, and it's OK to wait because + find_parameter_packs_r walks into the lambda body. */ if (context == containing_function - && dependent_type_p (TREE_TYPE (decl))) + && DECL_PACK_P (decl)) return decl; if (lambda_expr && VAR_P (decl) diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-if27.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-if27.C new file mode 100644 index 00000000000..a1a6e0b78f6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-if27.C @@ -0,0 +1,22 @@ +// PR c++/86969 +// { dg-do compile { target c++17 } } + +auto compose = [](auto... fs) { + if constexpr (sizeof...(fs) == 0) { + return [](auto x) { return x; }; + } else { + auto fn = [](auto self, auto f, auto... fs) { + if constexpr (sizeof...(fs) == 0) return f; + else return [=](auto x) { + return f(self(self, fs...)(x)); + }; + }; + return fn(fn, fs...); + } +}; + +static_assert(compose( + [](auto x) { return x * 3; }, + [](auto x) { return x + 1; }, + [](auto x) { return x / 2; } + )(6) == 12); diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a2d16e15b4a..e4d876b4c0b 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,14 @@ +2019-02-27 Jason Merrill + + PR c++/86969 - ICE with constexpr if and recursive generic lambdas. + * semantics.c (process_outer_var_ref): Do capture dependent vars. + * class.c (finish_struct): Only add TAG_DEFN if T is in + current_function_decl. + * lambda.c (vla_capture_type): Force the capture type out into the + lambda's enclosing function. + (add_capture): Pass in the lambda. + * pt.c (tsubst_lambda_expr): complete_type a VLA capture type. + 2019-02-27 Marek Polacek PR c++/89511 - ICE with using-declaration and unscoped enumerator.