From patchwork Tue Mar 26 16:02:10 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Merrill X-Patchwork-Id: 1065759 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-498463-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="BmNbkjgn"; 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 44TG9c5KXQz9sNw for ; Wed, 27 Mar 2019 03:02:26 +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=tm+izYWDSIsSJmCt M6Ic7oSOv+hg58FQHAmpTs1Soc0FFR8hk4SH2ipmRAhhx5Tx3SjT9mv/B5MSMw77 lsmjO1C4Po3EHUCTanGd/LnA1H2LkFBpNlWcdoEjPJ9faQOoRyiudH3O7uvYA6Xv t9Ga5zJdxQnMrxCRgxoxky35et0= 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=5eMG1511ZFFrxXZDILOh+p uglBU=; b=BmNbkjgnV54lyYcrCztwcakex2xW/fe7+Uoceu0Pd/GsCatcQxk1sn dhIKyTqLJ2klm0IGfy8+u7mYhvfwrqrGlsVUr+XvxR844vkA5Xb3HELJAKNjU7LH pUyGZ9FiNTuH7x1jTNC+LMUA4De8tXdxCBCkoRCmnVysS4ISk8W/I= Received: (qmail 98146 invoked by alias); 26 Mar 2019 16:02:17 -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 98092 invoked by uid 89); 26 Mar 2019 16:02:16 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-19.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.1 spammy=constexpr.c, UD:constexpr.c, constexprc, HX-Languages-Length:4553 X-HELO: mail-qt1-f195.google.com Received: from mail-qt1-f195.google.com (HELO mail-qt1-f195.google.com) (209.85.160.195) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 26 Mar 2019 16:02:14 +0000 Received: by mail-qt1-f195.google.com with SMTP id k14so15228163qtb.0 for ; Tue, 26 Mar 2019 09:02:14 -0700 (PDT) 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 g34sm1981137qtc.9.2019.03.26.09.02.11 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 26 Mar 2019 09:02:11 -0700 (PDT) From: Jason Merrill To: gcc-patches@gcc.gnu.org Subject: [C++ PATCH] PR c++/86429 - constexpr variable in lambda. Date: Tue, 26 Mar 2019 12:02:10 -0400 Message-Id: <20190326160210.17304-1-jason@redhat.com> MIME-Version: 1.0 X-IsSubscribed: yes When we refer to a captured variable from a constant-expression context inside a lambda, the closure (like any function parameter) is not constant because we aren't in a call, so we don't have an argument. So the capture is non-constant. But if the captured variable is constant, we might be able to use it directly in constexpr evaluation. Tested x86_64-pc-linux-gnu, applying to trunk. PR c++/82643 PR c++/87327 * constexpr.c (cxx_eval_constant_expression): In a lambda function, try evaluating the captured variable directly. --- gcc/cp/constexpr.c | 25 +++++++++++++++++-- .../g++.dg/cpp1y/lambda-generic-const10.C | 24 ++++++++++++++++++ .../g++.dg/cpp1y/lambda-generic-const9.C | 16 ++++++++++++ .../g++.dg/cpp1z/constexpr-lambda24.C | 23 +++++++++++++++++ gcc/cp/ChangeLog | 8 ++++++ 5 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-const10.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-const9.C create mode 100644 gcc/testsuite/g++.dg/cpp1z/constexpr-lambda24.C base-commit: 7237dce709ba3deef79bd146a009cf0e727476d8 diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index e92ec55317b..c00d642fcfe 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -4442,8 +4442,29 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, case VAR_DECL: if (DECL_HAS_VALUE_EXPR_P (t)) - return cxx_eval_constant_expression (ctx, DECL_VALUE_EXPR (t), - lval, non_constant_p, overflow_p); + { + if (is_normal_capture_proxy (t) + && current_function_decl == DECL_CONTEXT (t)) + { + /* Function parms aren't constexpr within the function + definition, so don't try to look at the closure. But if the + captured variable is constant, try to evaluate it directly. */ + r = DECL_CAPTURED_VARIABLE (t); + tree type = TREE_TYPE (t); + if (TYPE_REF_P (type) != TYPE_REF_P (TREE_TYPE (r))) + { + /* Adjust r to match the reference-ness of t. */ + if (TYPE_REF_P (type)) + r = build_address (r); + else + r = convert_from_reference (r); + } + } + else + r = DECL_VALUE_EXPR (t); + return cxx_eval_constant_expression (ctx, r, lval, non_constant_p, + overflow_p); + } /* fall through */ case CONST_DECL: /* We used to not check lval for CONST_DECL, but darwin.c uses diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const10.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const10.C new file mode 100644 index 00000000000..e0080b3d4f6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const10.C @@ -0,0 +1,24 @@ +// PR c++/82643 +// { dg-do compile { target c++14 } } + +int main() +{ + struct A { + constexpr int operator()() const { return 42; } + }; + + auto f = A(); + constexpr auto x = f(); //ok, call constexpr const non-static method + + [](auto const &f) { + constexpr auto x = f(); /*ok*/ + }(f); + + [&]() { + constexpr auto x = f(); //ko, __closure is not a constant expression + }; + + [=]() { + constexpr auto x = f(); //same ko, __closure is not a constant expression + }; +} diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const9.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const9.C new file mode 100644 index 00000000000..491c7c322c3 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const9.C @@ -0,0 +1,16 @@ +// PR c++/86429 +// { dg-do compile { target c++14 } } + +struct A +{ + int i; + constexpr int f(const int&) const { return i; } +}; + +void g() +{ + constexpr A a = { 42 }; + [&](auto x) { + constexpr auto y = a.f(x); + }(24); +} diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda24.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda24.C new file mode 100644 index 00000000000..2edb24e41ac --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda24.C @@ -0,0 +1,23 @@ +// PR c++/87327 +// { dg-do compile { target c++17 } } + +template +struct Foo { + constexpr auto size() const { + return N; + } +}; + +constexpr int foo() { + constexpr auto a = Foo<5>{}; + + [&] { + Foo it = {}; + + return it; + }(); + + return 42; +} + +constexpr int i = foo(); diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 80d4ae3f1b9..550b7541d9f 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +2019-03-26 Jason Merrill + + PR c++/86429 - constexpr variable in lambda. + PR c++/82643 + PR c++/87327 + * constexpr.c (cxx_eval_constant_expression): In a lambda function, + try evaluating the captured variable directly. + 2019-03-26 Jakub Jelinek PR c++/89796