Skip to content

Commit

Permalink
auto merge of #9902 : thestinger/rust/immediate, r=nikomatsakis
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bors committed Oct 17, 2013
2 parents d773a02 + 34ae5d7 commit 3fd0e3a
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 27 deletions.
4 changes: 2 additions & 2 deletions src/librustc/middle/trans/_match.rs
Expand Up @@ -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 = ~[];
Expand Down Expand Up @@ -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);
}
}
Expand Down
37 changes: 12 additions & 25 deletions src/librustc/middle/trans/datum.rs
Expand Up @@ -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 */

Expand Down
17 changes: 17 additions & 0 deletions 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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);
}

0 comments on commit 3fd0e3a

Please sign in to comment.