From 34ae5d70ac459be9cef362eb684e17f3e490b869 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Thu, 17 Oct 2013 03:43:22 -0400 Subject: [PATCH] partially fix immediate rvalues The code generation previously assumed a reference could not alter the value in a way the destructor would notice. This is an incorrect assumption for `&mut`, and is also incorrect for an `&` pointer to a non-`Freeze` type. Closes #7972 --- src/librustc/middle/trans/_match.rs | 4 +- src/librustc/middle/trans/datum.rs | 37 ++++++------------- .../cancel-clean-via-immediate-rvalue-ref.rs | 17 +++++++++ 3 files changed, 31 insertions(+), 27 deletions(-) create mode 100644 src/test/run-pass/cancel-clean-via-immediate-rvalue-ref.rs diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index dbcfb4eebbf..89dfa64511f 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -1917,7 +1917,7 @@ fn trans_match_inner(scope_cx: @mut Block, Infallible } }; - let lldiscr = discr_datum.to_zeroable_ref_llval(bcx); + let lldiscr = discr_datum.to_ref_llval(bcx); compile_submatch(bcx, matches, [lldiscr], chk); let mut arm_cxs = ~[]; @@ -1996,7 +1996,7 @@ pub fn store_local(bcx: @mut Block, if bcx.sess().asm_comments() { add_comment(bcx, "creating zeroable ref llval"); } - let llptr = init_datum.to_zeroable_ref_llval(bcx); + let llptr = init_datum.to_ref_llval(bcx); return bind_irrefutable_pat(bcx, pat, llptr, BindLocal); } } diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index 6411283b79d..294f3379f84 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -473,38 +473,25 @@ impl Datum { C_null(type_of::type_of(bcx.ccx(), self.ty).ptr_to()) } else { let slot = alloc_ty(bcx, self.ty, ""); + // The store created here can be modified through a reference, for example: + // + // // free the old allocation, and change the pointer to a new allocation + // fn foo(x: &mut ~u8) { + // *x = ~5; + // } + // + // foo(&mut ~5); Store(bcx, self.val, slot); + // The old cleanup needs to be cancelled, in order for the destructor to observe + // any changes made through the reference. + self.cancel_clean(bcx); + add_clean_temp_mem(bcx, slot, self.ty); slot } } } } - pub fn to_zeroable_ref_llval(&self, bcx: @mut Block) -> ValueRef { - /*! - * Returns a by-ref llvalue that can be zeroed in order to - * cancel cleanup. This is a kind of hokey bridge used - * to adapt to the match code. Please don't use it for new code. - */ - - match self.mode { - // All by-ref datums are zeroable, even if we *could* just - // cancel the cleanup. - ByRef(_) => self.val, - - // By value datums can't be zeroed (where would you store - // the zero?) so we have to spill them. Add a temp cleanup - // for this spilled value and cancel the cleanup on this - // current value. - ByValue => { - let slot = self.to_ref_llval(bcx); - self.cancel_clean(bcx); - add_clean_temp_mem(bcx, slot, self.ty); - slot - } - } - } - pub fn appropriate_mode(&self, ccx: &mut CrateContext) -> DatumMode { /*! See the `appropriate_mode()` function */ diff --git a/src/test/run-pass/cancel-clean-via-immediate-rvalue-ref.rs b/src/test/run-pass/cancel-clean-via-immediate-rvalue-ref.rs new file mode 100644 index 00000000000..2b9e97be2c7 --- /dev/null +++ b/src/test/run-pass/cancel-clean-via-immediate-rvalue-ref.rs @@ -0,0 +1,17 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn foo(x: &mut ~u8) { + *x = ~5; +} + +pub fn main() { + foo(&mut ~4); +}