From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 84507 invoked by alias); 15 Apr 2015 21:15:58 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 84492 invoked by uid 89); 15 Apr 2015 21:15:57 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-3.6 required=5.0 tests=AWL,BAYES_00,SPF_HELO_PASS,SPF_PASS,T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Wed, 15 Apr 2015 21:15:56 +0000 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) by mx1.redhat.com (Postfix) with ESMTPS id 47806C79C0 for ; Wed, 15 Apr 2015 21:15:55 +0000 (UTC) Received: from [10.10.116.22] ([10.10.116.22]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t3FLFpsk025446 for ; Wed, 15 Apr 2015 17:15:52 -0400 Message-ID: <552ED505.1040503@redhat.com> Date: Wed, 15 Apr 2015 21:15:00 -0000 From: Jason Merrill User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.5.0 MIME-Version: 1.0 To: gcc-patches List Subject: C++ PATCH to clobber objects on constructor entry Content-Type: multipart/mixed; boundary="------------050301040709030801080000" X-SW-Source: 2015-04/txt/msg00782.txt.bz2 This is a multi-part message in MIME format. --------------050301040709030801080000 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit Content-length: 465 Currently we clobber objects at the end of the destructor to express that the language guarantees nothing about the state of storage after an object is destroyed. The same is true at the other end: when a constructor begins the object has indeterminate value, so any stores to the underlying storage before that can be considered dead. Like the destructor clobber, this can be disabled with -fno-lifetime-dse. Tested x86_64-pc-linux-gnu, applying to trunk. --------------050301040709030801080000 Content-Type: text/x-patch; name="ctor-lifetime-dse.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="ctor-lifetime-dse.patch" Content-length: 3554 commit b5ddc7d2b7bea43f0108e3eca1013ecec1ceda89 Author: Jason Merrill Date: Tue Feb 10 23:49:14 2015 -0500 * constexpr.c (cxx_eval_store_expression): Ignore clobbers. (build_constexpr_constructor_member_initializers): Loop to find the BIND_EXPR. * decl.c (start_preparsed_function): Clobber the object at the beginning of a constructor. diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 2952cbe..1f9ba3e 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -543,7 +543,16 @@ build_constexpr_constructor_member_initializers (tree type, tree body) || TREE_CODE (body) == EH_SPEC_BLOCK) body = TREE_OPERAND (body, 0); if (TREE_CODE (body) == STATEMENT_LIST) - body = STATEMENT_LIST_HEAD (body)->stmt; + { + tree_stmt_iterator i = tsi_start (body); + while (true) + { + body = tsi_stmt (i); + if (TREE_CODE (body) == BIND_EXPR) + break; + tsi_next (&i); + } + } body = BIND_EXPR_BODY (body); if (TREE_CODE (body) == CLEANUP_POINT_EXPR) { @@ -2603,6 +2612,11 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, { constexpr_ctx new_ctx = *ctx; + tree init = TREE_OPERAND (t, 1); + if (TREE_CLOBBER_P (init)) + /* Just ignore clobbers. */ + return void_node; + /* First we figure out where we're storing to. */ tree target = TREE_OPERAND (t, 0); target = cxx_eval_constant_expression (ctx, target, @@ -2684,9 +2698,8 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, new_ctx.object = target; } - tree init = cxx_eval_constant_expression (&new_ctx, TREE_OPERAND (t, 1), - false, - non_constant_p, overflow_p); + init = cxx_eval_constant_expression (&new_ctx, init, false, + non_constant_p, overflow_p); if (target == object) /* The hash table might have moved since the get earlier. */ ctx->values->put (object, init); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 0538570..965f07c 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -13708,6 +13708,20 @@ start_preparsed_function (tree decl1, tree attrs, int flags) store_parm_decls (current_function_parms); + if (!processing_template_decl + && flag_lifetime_dse && DECL_CONSTRUCTOR_P (decl1)) + { + /* Insert a clobber to let the back end know that the object storage + is dead when we enter the constructor. */ + tree btype = CLASSTYPE_AS_BASE (current_class_type); + tree clobber = build_constructor (btype, NULL); + TREE_THIS_VOLATILE (clobber) = true; + tree bref = build_nop (build_reference_type (btype), current_class_ptr); + bref = convert_from_reference (bref); + tree exprstmt = build2 (MODIFY_EXPR, btype, bref, clobber); + finish_expr_stmt (exprstmt); + } + return true; } diff --git a/gcc/testsuite/g++.dg/opt/flifetime-dse2.C b/gcc/testsuite/g++.dg/opt/flifetime-dse2.C new file mode 100644 index 0000000..16d9a74 --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/flifetime-dse2.C @@ -0,0 +1,27 @@ +// { dg-options "-O3 -flifetime-dse" } +// { dg-do run } + +typedef __SIZE_TYPE__ size_t; +inline void * operator new (size_t, void *p) { return p; } + +struct A +{ + int i; + A() {} + ~A() {} +}; + +int main() +{ + int ar[1] = { 42 }; + A* ap = new(ar) A; + + // When the constructor starts the object has indeterminate value. + if (ap->i == 42) __builtin_abort(); + + ap->i = 42; + ap->~A(); + + // When the destructor ends the object no longer exists. + if (ar[0] == 42) __builtin_abort(); +} --------------050301040709030801080000--