From patchwork Wed Jan 4 13:52:43 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nathan Sidwell X-Patchwork-Id: 89855 Delivered-To: patch@linaro.org Received: by 10.140.20.101 with SMTP id 92csp8496676qgi; Wed, 4 Jan 2017 05:53:14 -0800 (PST) X-Received: by 10.84.169.36 with SMTP id g33mr148018914plb.174.1483537994621; Wed, 04 Jan 2017 05:53:14 -0800 (PST) Return-Path: Received: from sourceware.org (server1.sourceware.org. [209.132.180.131]) by mx.google.com with ESMTPS id z70si72559628pff.228.2017.01.04.05.53.14 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 04 Jan 2017 05:53:14 -0800 (PST) Received-SPF: pass (google.com: domain of gcc-patches-return-445355-patch=linaro.org@gcc.gnu.org designates 209.132.180.131 as permitted sender) client-ip=209.132.180.131; Authentication-Results: mx.google.com; dkim=pass header.i=@gcc.gnu.org; spf=pass (google.com: domain of gcc-patches-return-445355-patch=linaro.org@gcc.gnu.org designates 209.132.180.131 as permitted sender) smtp.mailfrom=gcc-patches-return-445355-patch=linaro.org@gcc.gnu.org DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :subject:to:references:cc:message-id:date:mime-version :in-reply-to:content-type; q=dns; s=default; b=dch/53Mm5PHVwl8Pz O6tkTIyIciLa0+d2TApaMpbLdzcHzYDUyexTemIyTm2JkKh+laGg/ZZ/bXMyck5g B8IPV4Ge7g70Uk+zNGN+WzmucI+DZXrjTkjSgfGVrzGOXlOPyVMzlJ296agMJoQj c4Ts/Hvpkkcp0eHqxKlvK5B52c= 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 :subject:to:references:cc:message-id:date:mime-version :in-reply-to:content-type; s=default; bh=6UwQw6EPlV5Aa6sWyYxosWv ZkoY=; b=u3r2U2ApTJnZ2jgb8ijTmfn4tc7Jy+b4fo9RIxu252N/IA5husVux+7 nZTP+IGJWdayoBjV3Je1spGhLD99jcOtcKRFlewWmJRMgg1o0+WvkqKFz9qbw7cK 5XOXstJq0vDDe6hVbShrpjhwg6awfvdHsgCVie4G9QxkGvLolojs= Received: (qmail 35051 invoked by alias); 4 Jan 2017 13:52:59 -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 35032 invoked by uid 89); 4 Jan 2017 13:52:57 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=2.1 required=5.0 tests=BAYES_50, FREEMAIL_FROM, KAM_ASCII_DIVIDERS, RCVD_IN_DNSWL_NONE, RCVD_IN_SORBS_SPAM, SPF_PASS autolearn=no version=3.3.2 spammy=U*nathan, nathan@acm.org, nathanacmorg, lambda.c X-HELO: mail-yw0-f196.google.com Received: from mail-yw0-f196.google.com (HELO mail-yw0-f196.google.com) (209.85.161.196) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 04 Jan 2017 13:52:47 +0000 Received: by mail-yw0-f196.google.com with SMTP id b66so41586986ywh.2 for ; Wed, 04 Jan 2017 05:52:47 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:subject:to:references:cc:message-id :date:user-agent:mime-version:in-reply-to; bh=hHxNIOvAW9oOdNAO6Z3JAuZVLRIrhxlB8j5xscmMCY4=; b=RnsdUKsgQQ3t5LFCB13jY7J5Gt+mLNO+Czn8qYSnS/7tWa3OT431j5G+2RKulkdgoJ bSyGM60U+ToV5rQkzGzowl/Q+vUmVnnorqakr8AkeWCAgxvX2Ue3go65TVV5eborFb2L YF92QpkAnmtnWPbVstrxaEN27nmrdd/vwtL7D8Oh+JvKqRJOXzK1BCf4v7cYjeGp/O6/ +GqsanFi99ZpmXQkwJOSNfjhhXE5u68dzzId30MkJhxpVXIvRpXhDCOUcw5WdmT6vb76 miWlg6abpQnfhNp7qme9NX1HzcWUgU8ncTjKmS06YTgKittuspegaDOkhv4qxL/yOVz+ fVYQ== X-Gm-Message-State: AIkVDXLOd3vtFNg/AgML+JA0bk4MW5HmNrsc74M02h8fKIfeZR2HTVFunx0bMur0C3udQg== X-Received: by 10.13.196.134 with SMTP id g128mr62363626ywd.301.1483537965794; Wed, 04 Jan 2017 05:52:45 -0800 (PST) Received: from ?IPv6:2620:10d:c0a3:20fb:f6d0:5ac5:64cd:f102? ([2620:10d:c091:200::e:a6d2]) by smtp.googlemail.com with ESMTPSA id z193sm30179151ywg.43.2017.01.04.05.52.44 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 04 Jan 2017 05:52:45 -0800 (PST) From: Nathan Sidwell Subject: Re: [PATCH] PR c++/66735 lambda capture by reference To: Jason Merrill References: <3d7dc3ce-201b-2bde-27aa-63e979df0341@acm.org> <592e2f05-071f-9cb9-0d82-4ed8ca44340f@redhat.com> Cc: GCC Patches Message-ID: <0b6654de-8dbe-0e93-cc9e-771c08e6325b@acm.org> Date: Wed, 4 Jan 2017 08:52:43 -0500 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.5.1 MIME-Version: 1.0 In-Reply-To: <592e2f05-071f-9cb9-0d82-4ed8ca44340f@redhat.com> On 01/04/2017 12:36 AM, Jason Merrill wrote: > On 01/03/2017 08:57 AM, Nathan Sidwell wrote: >> + type = auto_node; >> + if (by_reference_p) >> + type = build_reference_type (type); >> + by_reference_p = false; ^^^ here >> + if (!is_this && by_reference_p) >> + type = build_reference_type (type); > > This looks like it will call build_reference_type twice in the explicit > init case, producing a reference to reference. Note the clearing of by_reference_p just above in this case, but I admit that's confusing. Anyway, it's rendered moot by this patch which addresses: >> if (DECLTYPE_FOR_LAMBDA_CAPTURE (t)) >> type = lambda_capture_field_type (type, >> - DECLTYPE_FOR_INIT_CAPTURE (t)); >> + DECLTYPE_FOR_INIT_CAPTURE (t), >> + /*by_reference_p=*/false); > > Always passing false seems unlikely to be correct. I wondered about that, but obviously failed to come up with a testcase to expose it. This patch adds such a case, and exposes the need to add another flag to DECLTYPE to indicate reference capture -- rather than wrap the dependent capture in a reference type itself, as was previously the case. ok? nathan -- Nathan Sidwell 2017-01-04 Nathan Sidwell cp/ PR c++/66735 * cp-tree.h (DECLTYPE_FOR_REF_CAPTURE): New. (lambda_capture_field_type): Update prototype. * lambda.c (lambda_capture_field_type): Add is_reference parm. Add referenceness here. (add_capture): Adjust lambda_capture_field_type call, refactor error checking. * pt.c (tsubst): Adjust lambda_capture_field_type call. testsuite/ PR c++/66735 * g++.dg/cpp1y/pr66735.C: New. Index: cp/cp-tree.h =================================================================== --- cp/cp-tree.h (revision 244054) +++ cp/cp-tree.h (working copy) @@ -181,6 +181,7 @@ operator == (const cp_expr &lhs, tree rh BIND_EXPR_BODY_BLOCK (in BIND_EXPR) DECL_NON_TRIVIALLY_INITIALIZED_P (in VAR_DECL) CALL_EXPR_ORDERED_ARGS (in CALL_EXPR, AGGR_INIT_EXPR) + DECLTYPE_FOR_REF_CAPTURE (in DECLTYPE_TYPE) 4: TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR, CALL_EXPR, or FIELD_DECL). IDENTIFIER_TYPENAME_P (in IDENTIFIER_NODE) @@ -4103,6 +4104,8 @@ more_aggr_init_expr_args_p (const aggr_i TREE_LANG_FLAG_1 (DECLTYPE_TYPE_CHECK (NODE)) #define DECLTYPE_FOR_LAMBDA_PROXY(NODE) \ TREE_LANG_FLAG_2 (DECLTYPE_TYPE_CHECK (NODE)) +#define DECLTYPE_FOR_REF_CAPTURE(NODE) \ + TREE_LANG_FLAG_3 (DECLTYPE_TYPE_CHECK (NODE)) /* Nonzero for VAR_DECL and FUNCTION_DECL node means that `extern' was specified in its declaration. This can also be set for an @@ -6528,7 +6531,7 @@ extern tree finish_trait_expr (enum cp extern tree build_lambda_expr (void); extern tree build_lambda_object (tree); extern tree begin_lambda_type (tree); -extern tree lambda_capture_field_type (tree, bool); +extern tree lambda_capture_field_type (tree, bool, bool); extern tree lambda_return_type (tree); extern tree lambda_proxy_type (tree); extern tree lambda_function (tree); Index: cp/lambda.c =================================================================== --- cp/lambda.c (revision 244054) +++ cp/lambda.c (working copy) @@ -211,29 +211,45 @@ lambda_function (tree lambda) } /* Returns the type to use for the FIELD_DECL corresponding to the - capture of EXPR. - The caller should add REFERENCE_TYPE for capture by reference. */ + capture of EXPR. EXPLICIT_INIT_P indicates whether this is a + C++14 init capture, and BY_REFERENCE_P indicates whether we're + capturing by reference. */ tree -lambda_capture_field_type (tree expr, bool explicit_init_p) +lambda_capture_field_type (tree expr, bool explicit_init_p, + bool by_reference_p) { tree type; bool is_this = is_this_parameter (tree_strip_nop_conversions (expr)); + if (!is_this && type_dependent_expression_p (expr)) { type = cxx_make_type (DECLTYPE_TYPE); DECLTYPE_TYPE_EXPR (type) = expr; DECLTYPE_FOR_LAMBDA_CAPTURE (type) = true; DECLTYPE_FOR_INIT_CAPTURE (type) = explicit_init_p; + DECLTYPE_FOR_REF_CAPTURE (type) = by_reference_p; SET_TYPE_STRUCTURAL_EQUALITY (type); } else if (!is_this && explicit_init_p) { - type = make_auto (); - type = do_auto_deduction (type, expr, type); + tree auto_node = make_auto (); + + type = auto_node; + if (by_reference_p) + /* Add the reference now, so deduction doesn't lose + outermost CV qualifiers of EXPR. */ + type = build_reference_type (type); + type = do_auto_deduction (type, expr, auto_node); } else - type = non_reference (unlowered_expr_type (expr)); + { + type = non_reference (unlowered_expr_type (expr)); + + if (!is_this && by_reference_p) + type = build_reference_type (type); + } + return type; } @@ -504,9 +520,11 @@ add_capture (tree lambda, tree id, tree } else { - type = lambda_capture_field_type (initializer, explicit_init_p); + type = lambda_capture_field_type (initializer, explicit_init_p, + by_reference_p); if (type == error_mark_node) return error_mark_node; + if (id == this_identifier && !by_reference_p) { gcc_assert (POINTER_TYPE_P (type)); @@ -514,17 +532,19 @@ add_capture (tree lambda, tree id, tree initializer = cp_build_indirect_ref (initializer, RO_NULL, tf_warning_or_error); } - if (id != this_identifier && by_reference_p) + + if (dependent_type_p (type)) + ; + else if (id != this_identifier && by_reference_p) { - type = build_reference_type (type); - if (!dependent_type_p (type) && !lvalue_p (initializer)) + if (!lvalue_p (initializer)) error ("cannot capture %qE by reference", initializer); } else { /* Capture by copy requires a complete type. */ type = complete_type (type); - if (!dependent_type_p (type) && !COMPLETE_TYPE_P (type)) + if (!COMPLETE_TYPE_P (type)) { error ("capture by copy of incomplete type %qT", type); cxx_incomplete_type_inform (type); Index: cp/pt.c =================================================================== --- cp/pt.c (revision 244054) +++ cp/pt.c (working copy) @@ -13988,7 +13988,8 @@ tsubst (tree t, tree args, tsubst_flags_ if (DECLTYPE_FOR_LAMBDA_CAPTURE (t)) type = lambda_capture_field_type (type, - DECLTYPE_FOR_INIT_CAPTURE (t)); + DECLTYPE_FOR_INIT_CAPTURE (t), + DECLTYPE_FOR_REF_CAPTURE (t)); else if (DECLTYPE_FOR_LAMBDA_PROXY (t)) type = lambda_proxy_type (type); else Index: testsuite/g++.dg/cpp1y/pr66735.C =================================================================== --- testsuite/g++.dg/cpp1y/pr66735.C (revision 0) +++ testsuite/g++.dg/cpp1y/pr66735.C (working copy) @@ -0,0 +1,22 @@ +// { dg-do compile { target c++14 } } + +// PR c++/66735, lost constness on reference capture + +template void Foo () +{ + T const x = 5; + + auto l = [&rx = x]() {}; + + l (); +} + +void Baz () +{ + int const x = 5; + auto l = [&rx = x]() {}; + + + l (); + Foo (); +}