Fix matching of rvalues with destructors

Fixes #4542.
This commit is contained in:
Niko Matsakis 2013-05-29 18:33:30 -04:00
parent c492a2126f
commit 5209709e46
3 changed files with 38 additions and 1 deletions

View File

@ -1701,7 +1701,7 @@ pub fn trans_match_inner(scope_cx: block,
None
}
};
let lldiscr = discr_datum.to_ref_llval(bcx);
let lldiscr = discr_datum.to_zeroable_ref_llval(bcx);
compile_submatch(bcx, matches, [lldiscr], chk);
let mut arm_cxs = ~[];

View File

@ -471,6 +471,31 @@ pub impl Datum {
}
}
fn to_zeroable_ref_llval(&self, bcx: 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
}
}
}
fn appropriate_mode(&self) -> DatumMode {
/*! See the `appropriate_mode()` function */

View File

@ -0,0 +1,12 @@
// Tests that matching rvalues with drops does not crash.
fn main() {
match ~[1, 2, 3] {
x => {
assert_eq!(x.len(), 3);
assert_eq!(x[0], 1);
assert_eq!(x[1], 2);
assert_eq!(x[2], 3);
}
}
}