Rollup merge of #30761 - nagisa:mir-fix-destination, r=michaelwoerister
Previously it was returning a clone, mostly for the two reasons: * Cloning Lvalue is very cheap most of the time (i.e. when Lvalue is not a Projection); * There’s users who want &mut lvalue and there’s users who want &lvalue. Returning a value allows to make either one easier when pattern matching (i.e. Some(ref dest) or Some(ref mut dest)). However, I’m now convinced this is an invalid approach. Namely the users which want a mutable reference may modify the Lvalue in-place, but the changes won’t be reflected in the final MIR, since the Lvalue modified is merely a clone. Instead, we have two accessors `destination` and `destination_mut` which return a reference to the destination in desired mode. r? @nikomatsakis
This commit is contained in:
commit
04906061d8
@ -314,10 +314,19 @@ pub fn successors_mut(&mut self) -> &mut [BasicBlock] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn destination(&self) -> Option<Lvalue<'tcx>> {
|
pub fn destination(&self) -> Option<&Lvalue<'tcx>> {
|
||||||
match *self {
|
match *self {
|
||||||
CallKind::Converging { ref destination, .. } |
|
CallKind::Converging { ref destination, .. } |
|
||||||
CallKind::ConvergingCleanup { ref destination, .. } => Some(destination.clone()),
|
CallKind::ConvergingCleanup { ref destination, .. } => Some(destination),
|
||||||
|
CallKind::Diverging |
|
||||||
|
CallKind::DivergingCleanup(_) => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destination_mut(&mut self) -> Option<&mut Lvalue<'tcx>> {
|
||||||
|
match *self {
|
||||||
|
CallKind::Converging { ref mut destination, .. } |
|
||||||
|
CallKind::ConvergingCleanup { ref mut destination, .. } => Some(destination),
|
||||||
CallKind::Diverging |
|
CallKind::Diverging |
|
||||||
CallKind::DivergingCleanup(_) => None
|
CallKind::DivergingCleanup(_) => None
|
||||||
}
|
}
|
||||||
|
@ -94,7 +94,7 @@ fn erase_regions_terminator(&mut self,
|
|||||||
*switch_ty = self.tcx.erase_regions(switch_ty);
|
*switch_ty = self.tcx.erase_regions(switch_ty);
|
||||||
},
|
},
|
||||||
Terminator::Call { ref mut func, ref mut args, ref mut kind } => {
|
Terminator::Call { ref mut func, ref mut args, ref mut kind } => {
|
||||||
if let Some(ref mut destination) = kind.destination() {
|
if let Some(destination) = kind.destination_mut() {
|
||||||
self.erase_regions_lvalue(destination);
|
self.erase_regions_lvalue(destination);
|
||||||
}
|
}
|
||||||
self.erase_regions_operand(func);
|
self.erase_regions_operand(func);
|
||||||
|
@ -100,7 +100,7 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
|
|||||||
let mut llargs = Vec::with_capacity(args.len() + 1);
|
let mut llargs = Vec::with_capacity(args.len() + 1);
|
||||||
|
|
||||||
// Prepare the return value destination
|
// Prepare the return value destination
|
||||||
let (ret_dest_ty, must_copy_dest) = if let Some(ref d) = kind.destination() {
|
let (ret_dest_ty, must_copy_dest) = if let Some(d) = kind.destination() {
|
||||||
let dest = self.trans_lvalue(bcx, d);
|
let dest = self.trans_lvalue(bcx, d);
|
||||||
let ret_ty = dest.ty.to_ty(bcx.tcx());
|
let ret_ty = dest.ty.to_ty(bcx.tcx());
|
||||||
if type_of::return_uses_outptr(bcx.ccx(), ret_ty) {
|
if type_of::return_uses_outptr(bcx.ccx(), ret_ty) {
|
||||||
|
Loading…
Reference in New Issue
Block a user