Use correct drop scopes for if expressions

This commit is contained in:
Matthew Jasper 2021-02-25 22:37:22 +00:00 committed by Caio
parent c0490a2dbb
commit 2d9f2eae84
3 changed files with 75 additions and 7 deletions

View file

@ -443,9 +443,20 @@ impl<'hir> LoweringContext<'_, 'hir> {
else_opt: Option<&Expr>,
) -> hir::ExprKind<'hir> {
let cond = self.lower_expr(cond);
let then = self.arena.alloc(self.lower_block_expr(then));
let els = else_opt.map(|els| self.lower_expr(els));
hir::ExprKind::If(cond, then, els)
let wrapped_cond = match cond.kind {
hir::ExprKind::Let(..) => cond,
_ => self.expr_drop_temps(cond.span, cond, AttrVec::new()),
};
let then_expr = self.lower_block_expr(then);
if let Some(rslt) = else_opt {
hir::ExprKind::If(
wrapped_cond,
self.arena.alloc(then_expr),
Some(self.lower_expr(rslt)),
)
} else {
hir::ExprKind::If(wrapped_cond, self.arena.alloc(then_expr), None)
}
}
fn lower_expr_if_let(

View file

@ -35,6 +35,47 @@ use std::convert::TryFrom;
use std::mem;
impl<'a, 'tcx> Builder<'a, 'tcx> {
pub(crate) fn then_else_blocks(
&mut self,
mut block: BasicBlock,
expr: ExprRef<'tcx>,
source_info: SourceInfo,
) -> (BasicBlock, BasicBlock) {
let this = self;
let expr = this.hir.mirror(expr);
let expr_span = expr.span;
match expr.kind {
ExprKind::Scope { region_scope, lint_level, value } => {
let region_scope = (region_scope, source_info);
let then_block;
let else_block = unpack!(
then_block = this.in_scope(region_scope, lint_level, |this| {
let (then_block, else_block) =
this.then_else_blocks(block, value, source_info);
then_block.and(else_block)
})
);
(then_block, else_block)
}
ExprKind::Let { expr, pat } => {
// TODO: Use correct span.
this.lower_let(block, &expr, &pat, expr_span)
}
_ => {
let local_scope = Some(this.local_scope());
let place =
unpack!(block = this.as_temp(block, local_scope, expr, Mutability::Mut));
let operand = Operand::Move(Place::from(place));
let then_block = this.cfg.start_new_block();
let else_block = this.cfg.start_new_block();
let term = TerminatorKind::if_(this.hir.tcx(), operand, then_block, else_block);
this.cfg.terminate(block, source_info, term);
(then_block, else_block)
}
}
}
/// Generates MIR for a `match` expression.
///
/// The MIR that we generate for a match looks like this.

View file

@ -233,14 +233,12 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
terminating(r.hir_id.local_id);
}
hir::ExprKind::If(ref expr, ref then, Some(ref otherwise)) => {
terminating(expr.hir_id.local_id);
hir::ExprKind::If(_, ref then, Some(ref otherwise)) => {
terminating(then.hir_id.local_id);
terminating(otherwise.hir_id.local_id);
}
hir::ExprKind::If(ref expr, ref then, None) => {
terminating(expr.hir_id.local_id);
hir::ExprKind::If(_, ref then, None) => {
terminating(then.hir_id.local_id);
}
@ -392,6 +390,24 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
}
}
hir::ExprKind::If(ref cond, ref then, Some(ref otherwise)) => {
// FIXME(matthewjasper): ideally the scope we use here would only
// contain the condition and then expression. This works, but
// can result in some extra drop flags.
visitor.cx.var_parent = visitor.cx.parent;
visitor.visit_expr(cond);
visitor.cx.var_parent = prev_cx.var_parent;
visitor.visit_expr(then);
visitor.visit_expr(otherwise);
}
hir::ExprKind::If(ref cond, ref then, None) => {
visitor.cx.var_parent = visitor.cx.parent;
visitor.visit_expr(cond);
visitor.cx.var_parent = prev_cx.var_parent;
visitor.visit_expr(then);
}
_ => intravisit::walk_expr(visitor, expr),
}