From patchwork Thu Aug 15 21:45:50 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Merrill X-Patchwork-Id: 1147863 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-507091-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="jJ95VIpU"; 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 468g4Y4NKSz9s3Z for ; Fri, 16 Aug 2019 07:46:03 +1000 (AEST) 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=MY4O0axRRfUcNOD0 ZFaD/pzgsxyWD6JCw97P6UO+GvxLEUdudVvpJUcoGbTihZaF3GFnwx62yzU2sJAo Cdl/4t/JsKYg8vckqlO4bOSKQuhSl+qBs2/ZiIQWrB5gbPyrXKyciimnaOGTkOfd X3CDU+mW6m4z0J9tJ+AoXUJF0p4= 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=HGynfoLAvgzlssybKf+Poj khRIU=; b=jJ95VIpUoBmevra6BftMOpf+pNxXjh8u3QE/q4cuTZHgVkdORn1+BH oCCjQ3JrsDuflLiZsZIlfYFcow5CLY+dymteXu+ermxhjQ6/EZMuNV3uY1KBoQ0U V6OzjaE9QenWrOmVSxhhxRWBFV5SNaV9XDmhXgCfoastM9MS2wsWQ= Received: (qmail 104828 invoked by alias); 15 Aug 2019 21:45:56 -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 104818 invoked by uid 89); 15 Aug 2019 21:45:56 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-18.4 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= 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; Thu, 15 Aug 2019 21:45:54 +0000 Received: by mail-qt1-f195.google.com with SMTP id 44so3938281qtg.11 for ; Thu, 15 Aug 2019 14:45:54 -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 o200sm2077631qke.66.2019.08.15.14.45.51 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 15 Aug 2019 14:45:51 -0700 (PDT) From: Jason Merrill To: gcc-patches@gcc.gnu.org Subject: [C++ PATCH] PR c++/90393 - ICE with thow in ?: Date: Thu, 15 Aug 2019 17:45:50 -0400 Message-Id: <20190815214550.27290-1-jason@redhat.com> MIME-Version: 1.0 X-IsSubscribed: yes My previous patch for 64372 was incomplete: it only stopped making the non-throw argument into an rvalue, lvalue_kind still considered the ?: expression to be an rvalue, leaving us worse than before. For GCC 9 I lean toward reverting the earlier patch rather than applying this one and thus changing the meaning of well-formed code in the middle of a release series. Tested x86_64-pc-linux-gnu, applying to trunk. PR c++/64372, DR 1560 - Gratuitous lvalue-to-rvalue conversion in ?: * tree.c (lvalue_kind): Handle throw in one arm. * typeck.c (rationalize_conditional_expr): Likewise. (cp_build_modify_expr): Likewise. --- gcc/cp/tree.c | 21 ++++++++++++---- gcc/cp/typeck.c | 24 +++++++++++-------- gcc/testsuite/g++.dg/abi/mangle53.C | 5 ++-- gcc/testsuite/g++.dg/expr/cond15.C | 13 ++++++++++ gcc/testsuite/g++.dg/expr/cond16.C | 25 ++++++++++++++++++++ gcc/testsuite/g++.old-deja/g++.eh/cond1.C | 4 ++-- gcc/testsuite/g++.old-deja/g++.other/cond5.C | 4 ++-- gcc/cp/ChangeLog | 9 +++++++ 8 files changed, 85 insertions(+), 20 deletions(-) create mode 100644 gcc/testsuite/g++.dg/expr/cond15.C create mode 100644 gcc/testsuite/g++.dg/expr/cond16.C base-commit: 2d923c00b6664a5388556f14f2a3be8eb4084c1b diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index bca92100621..17a4df380c1 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -236,10 +236,23 @@ lvalue_kind (const_tree ref) gcc_assert (!type_dependent_expression_p (CONST_CAST_TREE (ref))); goto default_; } - op1_lvalue_kind = lvalue_kind (TREE_OPERAND (ref, 1) - ? TREE_OPERAND (ref, 1) - : TREE_OPERAND (ref, 0)); - op2_lvalue_kind = lvalue_kind (TREE_OPERAND (ref, 2)); + { + tree op1 = TREE_OPERAND (ref, 1); + if (!op1) op1 = TREE_OPERAND (ref, 0); + tree op2 = TREE_OPERAND (ref, 2); + op1_lvalue_kind = lvalue_kind (op1); + op2_lvalue_kind = lvalue_kind (op2); + if (!op1_lvalue_kind != !op2_lvalue_kind) + { + /* The second or the third operand (but not both) is a + throw-expression; the result is of the type + and value category of the other. */ + if (op1_lvalue_kind && TREE_CODE (op2) == THROW_EXPR) + op2_lvalue_kind = op1_lvalue_kind; + else if (op2_lvalue_kind && TREE_CODE (op1) == THROW_EXPR) + op1_lvalue_kind = op2_lvalue_kind; + } + } break; case MODOP_EXPR: diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 4cc0ee0128d..e2a4f285a72 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -2308,13 +2308,15 @@ rationalize_conditional_expr (enum tree_code code, tree t, complain); } + tree op1 = TREE_OPERAND (t, 1); + if (TREE_CODE (op1) != THROW_EXPR) + op1 = cp_build_unary_op (code, op1, false, complain); + tree op2 = TREE_OPERAND (t, 2); + if (TREE_CODE (op2) != THROW_EXPR) + op2 = cp_build_unary_op (code, op2, false, complain); + return - build_conditional_expr (loc, TREE_OPERAND (t, 0), - cp_build_unary_op (code, TREE_OPERAND (t, 1), false, - complain), - cp_build_unary_op (code, TREE_OPERAND (t, 2), false, - complain), - complain); + build_conditional_expr (loc, TREE_OPERAND (t, 0), op1, op2, complain); } /* Given the TYPE of an anonymous union field inside T, return the @@ -8160,8 +8162,9 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, if (!lvalue_or_else (lhs, lv_assign, complain)) return error_mark_node; - tree op1 = cp_build_modify_expr (loc, TREE_OPERAND (lhs, 1), - modifycode, rhs, complain); + tree op1 = TREE_OPERAND (lhs, 1); + if (TREE_CODE (op1) != THROW_EXPR) + op1 = cp_build_modify_expr (loc, op1, modifycode, rhs, complain); /* When sanitizing undefined behavior, even when rhs doesn't need stabilization at this point, the sanitization might add extra SAVE_EXPRs in there and so make sure there is no tree sharing @@ -8170,8 +8173,9 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, if (sanitize_flags_p (SANITIZE_UNDEFINED | SANITIZE_UNDEFINED_NONDEFAULT)) rhs = unshare_expr (rhs); - tree op2 = cp_build_modify_expr (loc, TREE_OPERAND (lhs, 2), - modifycode, rhs, complain); + tree op2 = TREE_OPERAND (lhs, 2); + if (TREE_CODE (op2) != THROW_EXPR) + op2 = cp_build_modify_expr (loc, op2, modifycode, rhs, complain); tree cond = build_conditional_expr (input_location, TREE_OPERAND (lhs, 0), op1, op2, complain); diff --git a/gcc/testsuite/g++.dg/abi/mangle53.C b/gcc/testsuite/g++.dg/abi/mangle53.C index 13f9e711c10..727fd7586f3 100644 --- a/gcc/testsuite/g++.dg/abi/mangle53.C +++ b/gcc/testsuite/g++.dg/abi/mangle53.C @@ -1,10 +1,11 @@ // { dg-do compile { target c++11 } } bool b; +int i; // { dg-final { scan-assembler "_Z1fIiEDTquL_Z1bEfp_twLi42EET_" } } -template auto f (T t) -> decltype(b?t:throw 42) { return 0; } +template auto f (T t) -> decltype(b?t:throw 42) { return i; } // { dg-final { scan-assembler "_Z2f2IiEDTquL_Z1bEfp_trET_" } } -template auto f2 (T t) -> decltype(b?t:throw) { return 0; } +template auto f2 (T t) -> decltype(b?t:throw) { return i; } int main() { diff --git a/gcc/testsuite/g++.dg/expr/cond15.C b/gcc/testsuite/g++.dg/expr/cond15.C new file mode 100644 index 00000000000..4a9d057a757 --- /dev/null +++ b/gcc/testsuite/g++.dg/expr/cond15.C @@ -0,0 +1,13 @@ +// PR c++/90393 + +struct S { + S(); + S(const S&) {} +}; + +S f() { + const S m; + return true ? m : throw 0; +} + +int main() {} diff --git a/gcc/testsuite/g++.dg/expr/cond16.C b/gcc/testsuite/g++.dg/expr/cond16.C new file mode 100644 index 00000000000..796828b25c0 --- /dev/null +++ b/gcc/testsuite/g++.dg/expr/cond16.C @@ -0,0 +1,25 @@ +// PR c++/90393 +// { dg-do run } + +int c, d; + +struct string { + string(const char *p): s(p) { ++c; } + ~string() { ++d; } + string(const string& str): s(str.s) { ++c; } + const char* s; + bool empty() const { return !s; } +}; + +string foo() +{ + string s("foo"); + return s.empty() ? throw "empty" : s; +} + +int main() +{ + foo(); + if (c != d) + __builtin_abort(); +} diff --git a/gcc/testsuite/g++.old-deja/g++.eh/cond1.C b/gcc/testsuite/g++.old-deja/g++.eh/cond1.C index 1b2de1d10e8..fe6d4296ab5 100644 --- a/gcc/testsuite/g++.old-deja/g++.eh/cond1.C +++ b/gcc/testsuite/g++.old-deja/g++.eh/cond1.C @@ -22,8 +22,8 @@ void fn(int i) (i ? throw X() : throw X()); // ok, void (i ? i : j) = 1; // ok, int & - (i ? throw X() : j) = 1; // { dg-error "" } non-lvalue - (i ? j : throw X()) = 1; // { dg-error "" } non-lvalue + (i ? throw X() : j) = 1; // ok, int & + (i ? j : throw X()) = 1; // ok, int & (i ? throw X() : throw X()) = 1; // { dg-error "" } void (i ? (void)1 : i++); // { dg-error "" } ANSI forbids diff --git a/gcc/testsuite/g++.old-deja/g++.other/cond5.C b/gcc/testsuite/g++.old-deja/g++.other/cond5.C index f4d16e9760b..0d2baf9edf7 100644 --- a/gcc/testsuite/g++.old-deja/g++.other/cond5.C +++ b/gcc/testsuite/g++.old-deja/g++.other/cond5.C @@ -35,8 +35,8 @@ void fn(int i) (i ? throw X() : throw X()); // ok, void (i ? i : j) = 1; // ok, int & - (i ? throw X() : j) = 1; // { dg-error "lvalue" } - (i ? j : throw X()) = 1; // { dg-error "lvalue" } + (i ? throw X() : j) = 1; // ok, int & + (i ? j : throw X()) = 1; // ok, int & (i ? throw X() : throw X()) = 1; // { dg-error "lvalue" } (i ? (void)1 : i++); // { dg-error "throw-expression" } diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 25172ace36f..938ec486d9c 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,12 @@ +2019-08-15 Jason Merrill + + PR c++/90393 - ICE with thow in ?: + + PR c++/64372, DR 1560 - Gratuitous lvalue-to-rvalue conversion in ?: + * tree.c (lvalue_kind): Handle throw in one arm. + * typeck.c (rationalize_conditional_expr): Likewise. + (cp_build_modify_expr): Likewise. + 2019-08-14 Jason Merrill Implement P0848R3, Conditionally Trivial Special Member Functions.