From patchwork Wed May 16 15:15:29 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Polacek X-Patchwork-Id: 914691 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-477772-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="ikSYq4TC"; 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 40mJ0y2Rqdz9s2L for ; Thu, 17 May 2018 01:16:02 +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:date :from:to:subject:message-id:mime-version:content-type; q=dns; s= default; b=M0u8MfXvoLxu8kKn3mzTSfzpabmYf4PhQ0AzCRhBgiCm2iLiaJFN0 vDUg7sOwHDYY+8AY6CCiwUI7c9Vox4Je/ujzfhgGDlh7HoTGMdMaAN07xr+DhFoM Q/803G+1hN8Sd4WPBEjHGiTT0vsI5jowI6JTsA+m1NAtYKqAfiXtcU= 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:date :from:to:subject:message-id:mime-version:content-type; s= default; bh=4pJ6SOt8PpCJ2IkRGllI1wzYaVc=; b=ikSYq4TC+d3chVgEbm7f L872zaGQrV4oeB7NYyYIDK1MFz2qkjjpIkHWtg+92uUpjyMLREKX5+C7pftB7NF7 74C8sJFJVXKCFG+c2fVM9w09L4YQtByAv6/zxbm2lKM13BYcf6QBNBY3mSmW0m4s 48DpoX9FWCZenZoHvy1QRmc= Received: (qmail 92627 invoked by alias); 16 May 2018 15:15:53 -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 92419 invoked by uid 89); 16 May 2018 15:15:36 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-25.8 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy= X-HELO: mx1.redhat.com Received: from mx3-rdu2.redhat.com (HELO mx1.redhat.com) (66.187.233.73) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 16 May 2018 15:15:34 +0000 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 4380E40201A1; Wed, 16 May 2018 15:15:31 +0000 (UTC) Received: from redhat.com (dhcp-17-171.bos.redhat.com [10.18.17.171]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 0BE1E2166BAD; Wed, 16 May 2018 15:15:30 +0000 (UTC) Date: Wed, 16 May 2018 11:15:29 -0400 From: Marek Polacek To: GCC Patches , Jason Merrill , Nathan Sidwell Subject: C++ PATCH for c++/85363, wrong-code with throwing list-initializer Message-ID: <20180516151529.GA3573@redhat.com> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.9.5 (2018-04-13) This PR has been on my mind for quite some time but I've not found a solution that I'd like. Maybe one of you can think of something better. The problem in this test is that in C++11, .eh optimizes out the catch, so the exception is never caught. That is because lower_catch doesn't think that the region may throw (eh_region_may_contain_throw). That's so because P::P () is marked as TREE_NOTHROW, which is wrong, because it calls X::X() which calls init() with throw. TREE_NOTHROW is set in finish_function: /* If this function can't throw any exceptions, remember that. */ if (!processing_template_decl && !cp_function_chain->can_throw && !flag_non_call_exceptions && !decl_replaceable_p (fndecl)) TREE_NOTHROW (fndecl) = 1; P::P() should have been marked as can_throw in set_flags_from_callee, but when processing X::X() cfun is null, so we can't set it. P::P() is created only later via implicitly_declare_fn. So one way to fix it would be to remember that the class has a subobject whose constructor may throw, so the class's constructor can throw, too. I added a test with more nested classes, too. I dislike adding a new flag for this scenario; anybody see a better way to approach this? Bootstrapped/regtested on x86_64-linux. 2018-05-16 Marek Polacek PR c++/85363 * cp-tree.h (struct lang_type): Add ctor_may_throw. (CLASSTYPE_CTOR_MAY_THROW): New. * call.c (set_flags_from_callee): Set it. * decl.c (finish_function): Check it. * g++.dg/cpp0x/initlist-throw1.C: New test. * g++.dg/cpp0x/initlist-throw2.C: New test. diff --git gcc/cp/call.c gcc/cp/call.c index 09a3618b007..f839d943443 100644 --- gcc/cp/call.c +++ gcc/cp/call.c @@ -332,6 +332,8 @@ set_flags_from_callee (tree call) if (!nothrow && at_function_scope_p () && cfun && cp_function_chain) cp_function_chain->can_throw = 1; + else if (!nothrow && at_class_scope_p () && decl && DECL_CONSTRUCTOR_P (decl)) + CLASSTYPE_CTOR_MAY_THROW (current_class_type) = true; if (decl && TREE_THIS_VOLATILE (decl) && cfun && cp_function_chain) current_function_returns_abnormally = 1; diff --git gcc/cp/cp-tree.h gcc/cp/cp-tree.h index cab926028b8..7a781a9a8a3 100644 --- gcc/cp/cp-tree.h +++ gcc/cp/cp-tree.h @@ -2025,6 +2025,7 @@ struct GTY(()) lang_type { unsigned has_constexpr_ctor : 1; unsigned unique_obj_representations : 1; unsigned unique_obj_representations_set : 1; + unsigned ctor_may_throw : 1; /* When adding a flag here, consider whether or not it ought to apply to a template instance if it applies to the template. If @@ -2033,7 +2034,7 @@ struct GTY(()) lang_type { /* There are some bits left to fill out a 32-bit word. Keep track of this by updating the size of this bitfield whenever you add or remove a flag. */ - unsigned dummy : 4; + unsigned dummy : 3; tree primary_base; vec *vcall_indices; @@ -2105,6 +2106,10 @@ struct GTY(()) lang_type { #define CLASSTYPE_LAZY_DESTRUCTOR(NODE) \ (LANG_TYPE_CLASS_CHECK (NODE)->lazy_destructor) +/* Nonzero means that NODE (a class type) has a constructor that can throw. */ +#define CLASSTYPE_CTOR_MAY_THROW(NODE) \ + (LANG_TYPE_CLASS_CHECK (NODE)->ctor_may_throw) + /* Nonzero means that NODE (a class type) is final */ #define CLASSTYPE_FINAL(NODE) \ TYPE_FINAL_P (NODE) diff --git gcc/cp/decl.c gcc/cp/decl.c index 10e3079beed..c5799459210 100644 --- gcc/cp/decl.c +++ gcc/cp/decl.c @@ -15651,7 +15651,11 @@ finish_function (bool inline_p) if (!processing_template_decl && !cp_function_chain->can_throw && !flag_non_call_exceptions - && !decl_replaceable_p (fndecl)) + && !decl_replaceable_p (fndecl) + /* If FNDECL is a constructor of a class that can call a throwing + constructor, don't mark it as non-throwing. */ + && (!DECL_CONSTRUCTOR_P (fndecl) + || !CLASSTYPE_CTOR_MAY_THROW (DECL_CONTEXT (fndecl)))) TREE_NOTHROW (fndecl) = 1; /* This must come after expand_function_end because cleanups might diff --git gcc/testsuite/g++.dg/cpp0x/initlist-throw1.C gcc/testsuite/g++.dg/cpp0x/initlist-throw1.C index e69de29bb2d..264c6c7a7a0 100644 --- gcc/testsuite/g++.dg/cpp0x/initlist-throw1.C +++ gcc/testsuite/g++.dg/cpp0x/initlist-throw1.C @@ -0,0 +1,29 @@ +// PR c++/85363 +// { dg-do run { target c++11 } } + +int +init (int f) +{ + throw f; +} + +struct X { + X (int f) : n {init (f)} {} + int n; +}; + +struct P { + X x{20}; +}; + +int +main () +{ + try { + P p {}; + } + catch (int n) { + return 0; + } + return 1; +} diff --git gcc/testsuite/g++.dg/cpp0x/initlist-throw2.C gcc/testsuite/g++.dg/cpp0x/initlist-throw2.C index e69de29bb2d..24906374fa4 100644 --- gcc/testsuite/g++.dg/cpp0x/initlist-throw2.C +++ gcc/testsuite/g++.dg/cpp0x/initlist-throw2.C @@ -0,0 +1,33 @@ +// PR c++/85363 +// { dg-do run { target c++11 } } + +int +init (int f) +{ + throw f; +} + +struct X { + X () : n {init (42)} {} + int n; +}; + +struct P { + struct R { + struct Q { + X x = {}; + } q; + } r; +}; + +int +main () +{ + try { + P p {}; + } + catch (int n) { + return 0; + } + return 1; +}