From patchwork Thu Dec 21 17:33:23 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nathan Sidwell X-Patchwork-Id: 852047 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-469729-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="Te4PCFs2"; 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 3z2dz72zWMz9s4s for ; Fri, 22 Dec 2017 04:33:38 +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:to:cc :from:subject:message-id:date:mime-version:content-type; q=dns; s=default; b=i+jwZpqDTuvrHqwfgqXSG6Mf3dRJ/E0srzZCCAI1VoVDoRBrAR J7nhK6U0D8fT8B3juW/UaBEvI+UeIM4nb6JIRv92auAD0ChXZ46fgCdBANFnxghd MgcGPnTSm0KxBPuq3UFKvGRdAbA0seMULMH3QuODxC142xL29DgbbRblY= 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:to:cc :from:subject:message-id:date:mime-version:content-type; s= default; bh=g9t12EgKU9RPJrv6HKazdnRLwj4=; b=Te4PCFs2aTfswPC2J872 1wXq65hWOrMtLRbn4vPogOYJs4aSTvlND3p6Mm5c8ZNl7m/MGpl6f0Kj1swrE2sv YrpXjN6aufufQjsDxwRllQ2N4WPYLSfS3o+hO81rxyVUAqhfQk+KxGcR8Yh57kda Dx1oMKpUiWiwrdw0ZJ83JSg= Received: (qmail 114489 invoked by alias); 21 Dec 2017 17:33:30 -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 114475 invoked by uid 89); 21 Dec 2017 17:33:29 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-9.1 required=5.0 tests=BAYES_00, FREEMAIL_FROM, GIT_PATCH_2, GIT_PATCH_3, KAM_ASCII_DIVIDERS, RCVD_IN_DNSWL_NONE, SPF_PASS, UNSUBSCRIBE_BODY autolearn=ham version=3.3.2 spammy=4.3, TT, idk, fco X-HELO: mail-yw0-f175.google.com Received: from mail-yw0-f175.google.com (HELO mail-yw0-f175.google.com) (209.85.161.175) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 21 Dec 2017 17:33:27 +0000 Received: by mail-yw0-f175.google.com with SMTP id r205so3215475ywb.3 for ; Thu, 21 Dec 2017 09:33:27 -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:to:cc:from:subject:message-id:date :user-agent:mime-version:content-language; bh=0y+MIsDm8Uh5gcduEQQY2p8wuPvpDbdQwwH1aWlr+aQ=; b=ik4yv9coUzVRU/rKJn/0atjEoNAg9rOiqz4gbcJUqoHo6XKR7kSgS9pAdAXQr7tIIA Jkc1N9bCrXjzMsTcqb4d5i8lboZhgWRkUuMnLYfz6HGxH0LJJaYv/pfPOqJtAPF9zFsA T1hwwcBALdVV1veOsdbudFlTgUJXyUuolcBq/gCf+/o2k7EAA82uaxxXBHSv/GaG+bSy 2CD8HYalJX5ToQECALLPS3sA52aPPSOP6nZNRur8jEvSdqx0+bZLciHAgHj0Ot3fQLlM pCcUI70o5/Tj8Nau/IftFV5RQbCKa6ZRkAuiNoWUxdGg/D1pstVJnTKbFLfN/hUXZpr/ v+3w== X-Gm-Message-State: AKGB3mL6vw6AfCY+JxqNBTPC2xlPhsfpU7mexAqPhc9G/D05K/65/cv9 0j7X4+vybyOoCTJ3Faf/T6s= X-Google-Smtp-Source: ACJfBoupeqyABUALKE1l6Iz900rrMbACb3/HKO+TGxzkRl8e+e7RG+uH/PrL2MjX+X1/35178EqImQ== X-Received: by 10.129.52.21 with SMTP id b21mr7829323ywa.309.1513877606027; Thu, 21 Dec 2017 09:33:26 -0800 (PST) Received: from ?IPv6:2620:10d:c0a3:20fb:7500:e7fb:4a6f:2254? ([2620:10d:c091:200::c808]) by smtp.googlemail.com with ESMTPSA id u194sm9575457ywe.71.2017.12.21.09.33.25 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 21 Dec 2017 09:33:25 -0800 (PST) To: Jason Merrill Cc: GCC Patches From: Nathan Sidwell Subject: [PR c++/83406] deducing lambda type Message-ID: <95555f6b-4822-da15-7ceb-717007a3b8ba@acm.org> Date: Thu, 21 Dec 2017 12:33:23 -0500 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.5.0 MIME-Version: 1.0 Jason, this needs a sanity check 83406 was exposed by Jason's recent patch removing return_type & closure from the tree_lambda_expr node: Remove unnecessary LAMBDA_EXPR fields. * cp-tree.h (LAMBDA_EXPR_CLOSURE): Use TREE_TYPE. (LAMBDA_EXPR_RETURN_TYPE): Remove. (struct tree_lambda_expr): Remove closure and return_type fields. * lambda.c (build_lambda_expr): Don't set LAMBDA_EXPR_RETURN_TYPE. * pt.c (tsubst_copy_and_build): Likewise. * parser.c (cp_parser_lambda_declarator_opt): Track return type. (cp_parser_lambda_body): Adjust unspecified return type check. * ptree.c (cxx_print_lambda_node): Don't print closure or return type. The culprit is cp_parser_lambda_body if (is_auto (TREE_TYPE (TREE_TYPE (fco))) ... is_auto is true for []() {...}, which is what we want and things like [] ()->decltype(auto) {...}, which we don't. The simple fix is to check TYPE_HAS_LATE_RETURN_TYPE instead, as that's only false in the former case. However, this whole if looks bogus. This quoted text is not in the std (even adjusting by +3 for the clause renumbering). It's not in the c++11 draft I have available either. > /* 5.1.1.4 of the standard says: > If a lambda-expression does not include a trailing-return-type, it > is as if the trailing-return-type denotes the following type: > * if the compound-statement is of the form > { return attribute-specifier [opt] expression ; } > the type of the returned expression after lvalue-to-rvalue > conversion (_conv.lval_ 4.1), array-to-pointer conversion > (_conv.array_ 4.2), and function-to-pointer conversion > (_conv.func_ 4.3); > * otherwise, void. */ And the next comment is confusing, the second sentence appears to be a total lie. > /* In a lambda that has neither a lambda-return-type-clause > nor a deducible form, errors should be reported for return statements > in the body. Since we used void as the placeholder return type, parsing > the body as usual will give such desired behavior. */ Removing it breaks nothing beyond changing the diagnostic that g++.dg/cpp0x/lambda/lambda-ice15.C expects. And fixes this regression. The introductory comment: > /* Finish the function call operator > - class_specifier > + late_parsing_for_member > + function_definition_after_declarator > + ctor_initializer_opt_and_function_body */ looks like the kind of development note I'd write to myself. It doesn't match the code (any more?). Jason, have I missed something? nathan 2017-12-21 Nathan Sidwell PR c++/83406 * parser.c (cp_parser_lambda_body): Remove obsolete single-return-statement handling. PR c++/83406 * g++.dg/cpp0x/lambda/lambda-ice15.C: Adjust error. * g++.dg/cpp1y/pr83406.C: New. Index: gcc/cp/parser.c =================================================================== --- gcc/cp/parser.c (revision 255940) +++ gcc/cp/parser.c (working copy) @@ -10578,98 +10578,38 @@ cp_parser_lambda_body (cp_parser* parser bool nested = (current_function_decl != NULL_TREE); bool local_variables_forbidden_p = parser->local_variables_forbidden_p; bool in_function_body = parser->in_function_body; + if (nested) push_function_context (); else /* Still increment function_depth so that we don't GC in the middle of an expression. */ ++function_depth; + vec omp_privatization_save; save_omp_privatization_clauses (omp_privatization_save); /* Clear this in case we're in the middle of a default argument. */ parser->local_variables_forbidden_p = false; parser->in_function_body = true; - /* Finish the function call operator - - class_specifier - + late_parsing_for_member - + function_definition_after_declarator - + ctor_initializer_opt_and_function_body */ { local_specialization_stack s (lss_copy); - tree fco = lambda_function (lambda_expr); tree body = start_lambda_function (fco, lambda_expr); - bool done = false; - tree compound_stmt; - matching_braces braces; - if (!braces.require_open (parser)) - goto out; - - compound_stmt = begin_compound_stmt (0); - /* 5.1.1.4 of the standard says: - If a lambda-expression does not include a trailing-return-type, it - is as if the trailing-return-type denotes the following type: - * if the compound-statement is of the form - { return attribute-specifier [opt] expression ; } - the type of the returned expression after lvalue-to-rvalue - conversion (_conv.lval_ 4.1), array-to-pointer conversion - (_conv.array_ 4.2), and function-to-pointer conversion - (_conv.func_ 4.3); - * otherwise, void. */ - - /* In a lambda that has neither a lambda-return-type-clause - nor a deducible form, errors should be reported for return statements - in the body. Since we used void as the placeholder return type, parsing - the body as usual will give such desired behavior. */ - if (is_auto (TREE_TYPE (TREE_TYPE (fco))) - && cp_lexer_peek_nth_token (parser->lexer, 1)->keyword == RID_RETURN - && cp_lexer_peek_nth_token (parser->lexer, 2)->type != CPP_SEMICOLON) + if (braces.require_open (parser)) { - tree expr = NULL_TREE; - cp_id_kind idk = CP_ID_KIND_NONE; + tree compound_stmt = begin_compound_stmt (0); - /* Parse tentatively in case there's more after the initial return - statement. */ - cp_parser_parse_tentatively (parser); - - cp_parser_require_keyword (parser, RID_RETURN, RT_RETURN); - - expr = cp_parser_expression (parser, &idk); - - cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); - braces.require_close (parser); - - if (cp_parser_parse_definitely (parser)) - { - if (!processing_template_decl) - { - tree type = lambda_return_type (expr); - apply_deduced_return_type (fco, type); - if (type == error_mark_node) - expr = error_mark_node; - } - - /* Will get error here if type not deduced yet. */ - finish_return_stmt (expr); - - done = true; - } - } - - if (!done) - { while (cp_lexer_next_token_is_keyword (parser->lexer, RID_LABEL)) cp_parser_label_declaration (parser); cp_parser_statement_seq_opt (parser, NULL_TREE); braces.require_close (parser); - } - finish_compound_stmt (compound_stmt); + finish_compound_stmt (compound_stmt); + } - out: finish_lambda_function (body); } Index: gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice15.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice15.C (revision 255940) +++ gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice15.C (working copy) @@ -5,6 +5,11 @@ class A { void foo () { - [=] { return foo; }; // { dg-error "invalid use of member function" } + [=] { return foo; }; // { dg-error "cannot convert" } + } + void bar () const; + void bar () + { + [=] { return bar; }; // { dg-error "unable to deduce" } } }; Index: gcc/testsuite/g++.dg/cpp1y/pr83406.C =================================================================== --- gcc/testsuite/g++.dg/cpp1y/pr83406.C (revision 0) +++ gcc/testsuite/g++.dg/cpp1y/pr83406.C (working copy) @@ -0,0 +1,41 @@ +// { dg-do compile { target c++14 } } +// PR 83406, lambda late returns are not the same as missing returns + +class Bar +{ +public: + const int& getter() const; + int& getter(); +}; + +auto one = [](const Bar& bar) -> decltype(auto) +{ + return bar.getter(); +}; + +auto two = [](const Bar& bar) -> auto +{ + return bar.getter(); +}; + +auto three = [](const Bar& bar) +{ + return bar.getter(); +}; + +template struct X +{ + static const bool same = false; +}; + +template struct X +{ + static const bool same = true; +}; + +void frob (Bar &x) +{ + static_assert (X::same, "not const int &"); + static_assert (X::same, "not int"); + static_assert (X::same, "not int"); +}