Use let else to reduce indentation
This commit is contained in:
parent
d19980e1ce
commit
525a64fa81
1 changed files with 131 additions and 132 deletions
|
@ -541,142 +541,141 @@ impl<'tcx> Inliner<'tcx> {
|
||||||
mut callee_body: Body<'tcx>,
|
mut callee_body: Body<'tcx>,
|
||||||
) {
|
) {
|
||||||
let terminator = caller_body[callsite.block].terminator.take().unwrap();
|
let terminator = caller_body[callsite.block].terminator.take().unwrap();
|
||||||
match terminator.kind {
|
let TerminatorKind::Call { args, destination, unwind, .. } = terminator.kind else {
|
||||||
TerminatorKind::Call { args, destination, unwind, .. } => {
|
bug!("unexpected terminator kind {:?}", terminator.kind);
|
||||||
// If the call is something like `a[*i] = f(i)`, where
|
};
|
||||||
// `i : &mut usize`, then just duplicating the `a[*i]`
|
|
||||||
// Place could result in two different locations if `f`
|
|
||||||
// writes to `i`. To prevent this we need to create a temporary
|
|
||||||
// borrow of the place and pass the destination as `*temp` instead.
|
|
||||||
fn dest_needs_borrow(place: Place<'_>) -> bool {
|
|
||||||
for elem in place.projection.iter() {
|
|
||||||
match elem {
|
|
||||||
ProjectionElem::Deref | ProjectionElem::Index(_) => return true,
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
false
|
// If the call is something like `a[*i] = f(i)`, where
|
||||||
|
// `i : &mut usize`, then just duplicating the `a[*i]`
|
||||||
|
// Place could result in two different locations if `f`
|
||||||
|
// writes to `i`. To prevent this we need to create a temporary
|
||||||
|
// borrow of the place and pass the destination as `*temp` instead.
|
||||||
|
fn dest_needs_borrow(place: Place<'_>) -> bool {
|
||||||
|
for elem in place.projection.iter() {
|
||||||
|
match elem {
|
||||||
|
ProjectionElem::Deref | ProjectionElem::Index(_) => return true,
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
let dest = if dest_needs_borrow(destination) {
|
|
||||||
trace!("creating temp for return destination");
|
|
||||||
let dest = Rvalue::Ref(
|
|
||||||
self.tcx.lifetimes.re_erased,
|
|
||||||
BorrowKind::Mut { kind: MutBorrowKind::Default },
|
|
||||||
destination,
|
|
||||||
);
|
|
||||||
let dest_ty = dest.ty(caller_body, self.tcx);
|
|
||||||
let temp = Place::from(self.new_call_temp(caller_body, &callsite, dest_ty));
|
|
||||||
caller_body[callsite.block].statements.push(Statement {
|
|
||||||
source_info: callsite.source_info,
|
|
||||||
kind: StatementKind::Assign(Box::new((temp, dest))),
|
|
||||||
});
|
|
||||||
self.tcx.mk_place_deref(temp)
|
|
||||||
} else {
|
|
||||||
destination
|
|
||||||
};
|
|
||||||
|
|
||||||
// Always create a local to hold the destination, as `RETURN_PLACE` may appear
|
|
||||||
// where a full `Place` is not allowed.
|
|
||||||
let (remap_destination, destination_local) = if let Some(d) = dest.as_local() {
|
|
||||||
(false, d)
|
|
||||||
} else {
|
|
||||||
(
|
|
||||||
true,
|
|
||||||
self.new_call_temp(
|
|
||||||
caller_body,
|
|
||||||
&callsite,
|
|
||||||
destination.ty(caller_body, self.tcx).ty,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Copy the arguments if needed.
|
|
||||||
let args: Vec<_> = self.make_call_args(args, &callsite, caller_body, &callee_body);
|
|
||||||
|
|
||||||
let mut integrator = Integrator {
|
|
||||||
args: &args,
|
|
||||||
new_locals: Local::new(caller_body.local_decls.len())..,
|
|
||||||
new_scopes: SourceScope::new(caller_body.source_scopes.len())..,
|
|
||||||
new_blocks: BasicBlock::new(caller_body.basic_blocks.len())..,
|
|
||||||
destination: destination_local,
|
|
||||||
callsite_scope: caller_body.source_scopes[callsite.source_info.scope].clone(),
|
|
||||||
callsite,
|
|
||||||
cleanup_block: unwind,
|
|
||||||
in_cleanup_block: false,
|
|
||||||
tcx: self.tcx,
|
|
||||||
always_live_locals: BitSet::new_filled(callee_body.local_decls.len()),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Map all `Local`s, `SourceScope`s and `BasicBlock`s to new ones
|
|
||||||
// (or existing ones, in a few special cases) in the caller.
|
|
||||||
integrator.visit_body(&mut callee_body);
|
|
||||||
|
|
||||||
// If there are any locals without storage markers, give them storage only for the
|
|
||||||
// duration of the call.
|
|
||||||
for local in callee_body.vars_and_temps_iter() {
|
|
||||||
if integrator.always_live_locals.contains(local) {
|
|
||||||
let new_local = integrator.map_local(local);
|
|
||||||
caller_body[callsite.block].statements.push(Statement {
|
|
||||||
source_info: callsite.source_info,
|
|
||||||
kind: StatementKind::StorageLive(new_local),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(block) = callsite.target {
|
|
||||||
// To avoid repeated O(n) insert, push any new statements to the end and rotate
|
|
||||||
// the slice once.
|
|
||||||
let mut n = 0;
|
|
||||||
if remap_destination {
|
|
||||||
caller_body[block].statements.push(Statement {
|
|
||||||
source_info: callsite.source_info,
|
|
||||||
kind: StatementKind::Assign(Box::new((
|
|
||||||
dest,
|
|
||||||
Rvalue::Use(Operand::Move(destination_local.into())),
|
|
||||||
))),
|
|
||||||
});
|
|
||||||
n += 1;
|
|
||||||
}
|
|
||||||
for local in callee_body.vars_and_temps_iter().rev() {
|
|
||||||
if integrator.always_live_locals.contains(local) {
|
|
||||||
let new_local = integrator.map_local(local);
|
|
||||||
caller_body[block].statements.push(Statement {
|
|
||||||
source_info: callsite.source_info,
|
|
||||||
kind: StatementKind::StorageDead(new_local),
|
|
||||||
});
|
|
||||||
n += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
caller_body[block].statements.rotate_right(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert all of the (mapped) parts of the callee body into the caller.
|
|
||||||
caller_body.local_decls.extend(callee_body.drain_vars_and_temps());
|
|
||||||
caller_body.source_scopes.extend(&mut callee_body.source_scopes.drain(..));
|
|
||||||
caller_body.var_debug_info.append(&mut callee_body.var_debug_info);
|
|
||||||
caller_body.basic_blocks_mut().extend(callee_body.basic_blocks_mut().drain(..));
|
|
||||||
|
|
||||||
caller_body[callsite.block].terminator = Some(Terminator {
|
|
||||||
source_info: callsite.source_info,
|
|
||||||
kind: TerminatorKind::Goto { target: integrator.map_block(START_BLOCK) },
|
|
||||||
});
|
|
||||||
|
|
||||||
// Copy only unevaluated constants from the callee_body into the caller_body.
|
|
||||||
// Although we are only pushing `ConstKind::Unevaluated` consts to
|
|
||||||
// `required_consts`, here we may not only have `ConstKind::Unevaluated`
|
|
||||||
// because we are calling `instantiate_and_normalize_erasing_regions`.
|
|
||||||
caller_body.required_consts.extend(
|
|
||||||
callee_body.required_consts.iter().copied().filter(|&ct| match ct.const_ {
|
|
||||||
Const::Ty(_) => {
|
|
||||||
bug!("should never encounter ty::UnevaluatedConst in `required_consts`")
|
|
||||||
}
|
|
||||||
Const::Val(..) | Const::Unevaluated(..) => true,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
kind => bug!("unexpected terminator kind {:?}", kind),
|
|
||||||
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let dest = if dest_needs_borrow(destination) {
|
||||||
|
trace!("creating temp for return destination");
|
||||||
|
let dest = Rvalue::Ref(
|
||||||
|
self.tcx.lifetimes.re_erased,
|
||||||
|
BorrowKind::Mut { kind: MutBorrowKind::Default },
|
||||||
|
destination,
|
||||||
|
);
|
||||||
|
let dest_ty = dest.ty(caller_body, self.tcx);
|
||||||
|
let temp = Place::from(self.new_call_temp(caller_body, &callsite, dest_ty));
|
||||||
|
caller_body[callsite.block].statements.push(Statement {
|
||||||
|
source_info: callsite.source_info,
|
||||||
|
kind: StatementKind::Assign(Box::new((temp, dest))),
|
||||||
|
});
|
||||||
|
self.tcx.mk_place_deref(temp)
|
||||||
|
} else {
|
||||||
|
destination
|
||||||
|
};
|
||||||
|
|
||||||
|
// Always create a local to hold the destination, as `RETURN_PLACE` may appear
|
||||||
|
// where a full `Place` is not allowed.
|
||||||
|
let (remap_destination, destination_local) = if let Some(d) = dest.as_local() {
|
||||||
|
(false, d)
|
||||||
|
} else {
|
||||||
|
(
|
||||||
|
true,
|
||||||
|
self.new_call_temp(
|
||||||
|
caller_body,
|
||||||
|
&callsite,
|
||||||
|
destination.ty(caller_body, self.tcx).ty,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Copy the arguments if needed.
|
||||||
|
let args: Vec<_> = self.make_call_args(args, &callsite, caller_body, &callee_body);
|
||||||
|
|
||||||
|
let mut integrator = Integrator {
|
||||||
|
args: &args,
|
||||||
|
new_locals: Local::new(caller_body.local_decls.len())..,
|
||||||
|
new_scopes: SourceScope::new(caller_body.source_scopes.len())..,
|
||||||
|
new_blocks: BasicBlock::new(caller_body.basic_blocks.len())..,
|
||||||
|
destination: destination_local,
|
||||||
|
callsite_scope: caller_body.source_scopes[callsite.source_info.scope].clone(),
|
||||||
|
callsite,
|
||||||
|
cleanup_block: unwind,
|
||||||
|
in_cleanup_block: false,
|
||||||
|
tcx: self.tcx,
|
||||||
|
always_live_locals: BitSet::new_filled(callee_body.local_decls.len()),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Map all `Local`s, `SourceScope`s and `BasicBlock`s to new ones
|
||||||
|
// (or existing ones, in a few special cases) in the caller.
|
||||||
|
integrator.visit_body(&mut callee_body);
|
||||||
|
|
||||||
|
// If there are any locals without storage markers, give them storage only for the
|
||||||
|
// duration of the call.
|
||||||
|
for local in callee_body.vars_and_temps_iter() {
|
||||||
|
if integrator.always_live_locals.contains(local) {
|
||||||
|
let new_local = integrator.map_local(local);
|
||||||
|
caller_body[callsite.block].statements.push(Statement {
|
||||||
|
source_info: callsite.source_info,
|
||||||
|
kind: StatementKind::StorageLive(new_local),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(block) = callsite.target {
|
||||||
|
// To avoid repeated O(n) insert, push any new statements to the end and rotate
|
||||||
|
// the slice once.
|
||||||
|
let mut n = 0;
|
||||||
|
if remap_destination {
|
||||||
|
caller_body[block].statements.push(Statement {
|
||||||
|
source_info: callsite.source_info,
|
||||||
|
kind: StatementKind::Assign(Box::new((
|
||||||
|
dest,
|
||||||
|
Rvalue::Use(Operand::Move(destination_local.into())),
|
||||||
|
))),
|
||||||
|
});
|
||||||
|
n += 1;
|
||||||
|
}
|
||||||
|
for local in callee_body.vars_and_temps_iter().rev() {
|
||||||
|
if integrator.always_live_locals.contains(local) {
|
||||||
|
let new_local = integrator.map_local(local);
|
||||||
|
caller_body[block].statements.push(Statement {
|
||||||
|
source_info: callsite.source_info,
|
||||||
|
kind: StatementKind::StorageDead(new_local),
|
||||||
|
});
|
||||||
|
n += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
caller_body[block].statements.rotate_right(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert all of the (mapped) parts of the callee body into the caller.
|
||||||
|
caller_body.local_decls.extend(callee_body.drain_vars_and_temps());
|
||||||
|
caller_body.source_scopes.extend(&mut callee_body.source_scopes.drain(..));
|
||||||
|
caller_body.var_debug_info.append(&mut callee_body.var_debug_info);
|
||||||
|
caller_body.basic_blocks_mut().extend(callee_body.basic_blocks_mut().drain(..));
|
||||||
|
|
||||||
|
caller_body[callsite.block].terminator = Some(Terminator {
|
||||||
|
source_info: callsite.source_info,
|
||||||
|
kind: TerminatorKind::Goto { target: integrator.map_block(START_BLOCK) },
|
||||||
|
});
|
||||||
|
|
||||||
|
// Copy only unevaluated constants from the callee_body into the caller_body.
|
||||||
|
// Although we are only pushing `ConstKind::Unevaluated` consts to
|
||||||
|
// `required_consts`, here we may not only have `ConstKind::Unevaluated`
|
||||||
|
// because we are calling `instantiate_and_normalize_erasing_regions`.
|
||||||
|
caller_body.required_consts.extend(callee_body.required_consts.iter().copied().filter(
|
||||||
|
|&ct| match ct.const_ {
|
||||||
|
Const::Ty(_) => {
|
||||||
|
bug!("should never encounter ty::UnevaluatedConst in `required_consts`")
|
||||||
|
}
|
||||||
|
Const::Val(..) | Const::Unevaluated(..) => true,
|
||||||
|
},
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_call_args(
|
fn make_call_args(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue