From patchwork Sat Nov 5 03:24:58 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jason Merrill X-Patchwork-Id: 123816 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 26C44B71A0 for ; Sat, 5 Nov 2011 14:25:23 +1100 (EST) Received: (qmail 9570 invoked by alias); 5 Nov 2011 03:25:21 -0000 Received: (qmail 9560 invoked by uid 22791); 5 Nov 2011 03:25:20 -0000 X-SWARE-Spam-Status: No, hits=-7.1 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, SPF_HELO_PASS X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sat, 05 Nov 2011 03:25:00 +0000 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id pA53P05x014576 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Fri, 4 Nov 2011 23:25:00 -0400 Received: from ns3.rdu.redhat.com (ns3.rdu.redhat.com [10.11.255.199]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id pA53P0Uh008944 for ; Fri, 4 Nov 2011 23:25:00 -0400 Received: from [0.0.0.0] (ovpn-113-72.phx2.redhat.com [10.3.113.72]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id pA53Owpt027836 for ; Fri, 4 Nov 2011 23:24:59 -0400 Message-ID: <4EB4AC8A.1070607@redhat.com> Date: Fri, 04 Nov 2011 23:24:58 -0400 From: Jason Merrill User-Agent: Mozilla/5.0 (X11; Linux i686; rv:7.0.1) Gecko/20111001 Thunderbird/7.0.1 MIME-Version: 1.0 To: gcc-patches List Subject: C++ PATCH for c++/26714 (lifetime of temps in mem-initializers for reference members) 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 After my previous patch for 48370 which adds extend_ref_init_temps, it is straightforward to fix this issue as well by extending ref init mem-initializers to match the lifetime of 'this'. Tested x86_64-pc-linux-gnu, applying to trunk. commit 30ed5835a92df18afef71802b5fa95899ceca227 Author: Jason Merrill Date: Fri Nov 4 14:59:20 2011 -0400 PR c++/26714 * init.c (perform_member_init): Strip TARGET_EXPR around NSDMI. Do temporary lifetime extension. diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 3881275..ca4f590 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -507,7 +507,15 @@ perform_member_init (tree member, tree init) tf_warning_or_error, member, /*function_p=*/false, /*integral_constant_expression_p=*/false)); else - init = break_out_target_exprs (DECL_INITIAL (member)); + { + init = DECL_INITIAL (member); + /* Strip redundant TARGET_EXPR so we don't need to remap it, and + so the aggregate init code below will see a CONSTRUCTOR. */ + if (init && TREE_CODE (init) == TARGET_EXPR + && !VOID_TYPE_P (TREE_TYPE (TARGET_EXPR_INITIAL (init)))) + init = TARGET_EXPR_INITIAL (init); + init = break_out_target_exprs (init); + } } /* Effective C++ rule 12 requires that all data members be @@ -565,6 +573,42 @@ perform_member_init (tree member, tree init) finish_expr_stmt (init); } } + else if (init + && (TREE_CODE (type) == REFERENCE_TYPE + /* Pre-digested NSDMI. */ + || (((TREE_CODE (init) == CONSTRUCTOR + && TREE_TYPE (init) == type) + /* { } mem-initializer. */ + || (TREE_CODE (init) == TREE_LIST + && TREE_CODE (TREE_VALUE (init)) == CONSTRUCTOR + && CONSTRUCTOR_IS_DIRECT_INIT (TREE_VALUE (init)))) + && (CP_AGGREGATE_TYPE_P (type) + || is_std_init_list (type))))) + { + /* With references and list-initialization, we need to deal with + extending temporary lifetimes. 12.2p5: "A temporary bound to a + reference member in a constructor’s ctor-initializer (12.6.2) + persists until the constructor exits." */ + unsigned i; tree t; + VEC(tree,gc) *cleanups = make_tree_vector (); + if (TREE_CODE (init) == TREE_LIST) + init = build_x_compound_expr_from_list (init, ELK_MEM_INIT, + tf_warning_or_error); + if (TREE_TYPE (init) != type) + init = digest_init (type, init, tf_warning_or_error); + if (init == error_mark_node) + return; + /* Use 'this' as the decl, as it has the lifetime we want. */ + init = extend_ref_init_temps (current_class_ptr, init, &cleanups); + if (TREE_CODE (type) == ARRAY_TYPE + && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (type))) + init = build_vec_init_expr (type, init, tf_warning_or_error); + init = build2 (INIT_EXPR, type, decl, init); + finish_expr_stmt (init); + FOR_EACH_VEC_ELT (tree, cleanups, i, t) + push_cleanup (decl, t, false); + release_tree_vector (cleanups); + } else if (type_build_ctor_call (type) || (init && CLASS_TYPE_P (strip_array_types (type)))) { diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-lifetime2.C b/gcc/testsuite/g++.dg/cpp0x/initlist-lifetime2.C new file mode 100644 index 0000000..16ae1ac --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/initlist-lifetime2.C @@ -0,0 +1,64 @@ +// Test that we properly extend the lifetime of the initializer_list +// array even if the initializer_list is a subobject. +// { dg-options -std=c++0x } +// { dg-do run } + +#include + +extern "C" void abort(); +bool ok; + +bool do_throw; + +struct A { + A(int) { if (do_throw) throw 42; } + ~A() { if (!ok) abort(); } +}; + +typedef std::initializer_list AL; +typedef std::initializer_list AL2; +typedef std::initializer_list AL3; + +struct B { + AL al; + const AL& alr; +}; + +struct A2 +{ + const A& a1; + const A& a2; +}; + +struct C { + AL ar[2]; + B b; + AL3 al3; + A2 a2; + A2 a2r[2]; + C(): + ar{{1,2},{3,4}}, + b{{5,6},{7,8}}, + al3{{{1},{2},{3}}}, + a2{1,2}, + a2r{{1,2},{3,4}} + { ok = true; } +}; + +struct D { + AL ar[2] = {{1,2},{3,4}}; + B b = {{5,6},{7,8}}; + AL3 al3 = {{{1},{2},{3}}}; + A2 a2 = {1,2}; + A2 a2r[2] = {{1,2},{3,4}}; + D() { ok = true; } +}; + +int main(int argc, const char** argv) +{ + do_throw = (argc > 1); // always false, but optimizer can't tell + ok = false; + C c; + ok = false; + D d; +} diff --git a/gcc/testsuite/g++.dg/init/lifetime2.C b/gcc/testsuite/g++.dg/init/lifetime2.C new file mode 100644 index 0000000..293bd69 --- /dev/null +++ b/gcc/testsuite/g++.dg/init/lifetime2.C @@ -0,0 +1,23 @@ +// PR c++/26714 +// { dg-do run } + +extern "C" void abort(); + +bool ok = false; +struct A +{ + A() { } + ~A() { if (!ok) abort(); } +}; + +struct B +{ + const A &a1; + const A &a2; + B() : a1(A()),a2(A()) { ok = true; } +}; + +int main() +{ + B b; +}