Auto merge of #119122 - matthewjasper:if-let-guard-scoping, r=TaKO8Ki
Give temporaries in if let guards correct scopes Temporaries in if-let guards have scopes that escape the match arm, this causes problems because the drops might be for temporaries that are not storage live. This PR changes the scope of temporaries in if-let guards to be limited to the arm: ```rust _ if let Some(s) = std::convert::identity(&Some(String::new())) => {} // Temporary for Some(String::new()) is dropped here ^ ``` We also now deduplicate temporaries between copies of the guard created for or-patterns: ```rust // Only create a single Some(String::new()) temporary variable _ | _ if let Some(s) = std::convert::identity(&Some(String::new())) => {} ``` This changes MIR building to pass around `ExprId`s rather than `Expr`s so that we have a way to index different expressions. cc #51114 Closes #116079
This commit is contained in:
commit
f2348fb29a
17 changed files with 387 additions and 245 deletions
|
@ -179,10 +179,10 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h
|
||||||
fn resolve_arm<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, arm: &'tcx hir::Arm<'tcx>) {
|
fn resolve_arm<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, arm: &'tcx hir::Arm<'tcx>) {
|
||||||
let prev_cx = visitor.cx;
|
let prev_cx = visitor.cx;
|
||||||
|
|
||||||
visitor.enter_scope(Scope { id: arm.hir_id.local_id, data: ScopeData::Node });
|
visitor.terminating_scopes.insert(arm.hir_id.local_id);
|
||||||
visitor.cx.var_parent = visitor.cx.parent;
|
|
||||||
|
|
||||||
visitor.terminating_scopes.insert(arm.body.hir_id.local_id);
|
visitor.enter_node_scope_with_dtor(arm.hir_id.local_id);
|
||||||
|
visitor.cx.var_parent = visitor.cx.parent;
|
||||||
|
|
||||||
if let Some(hir::Guard::If(expr)) = arm.guard {
|
if let Some(hir::Guard::If(expr)) = arm.guard {
|
||||||
visitor.terminating_scopes.insert(expr.hir_id.local_id);
|
visitor.terminating_scopes.insert(expr.hir_id.local_id);
|
||||||
|
|
|
@ -15,7 +15,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
) -> BlockAnd<()> {
|
) -> BlockAnd<()> {
|
||||||
let Block { region_scope, span, ref stmts, expr, targeted_by_break, safety_mode } =
|
let Block { region_scope, span, ref stmts, expr, targeted_by_break, safety_mode } =
|
||||||
self.thir[ast_block];
|
self.thir[ast_block];
|
||||||
let expr = expr.map(|expr| &self.thir[expr]);
|
|
||||||
self.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| {
|
self.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| {
|
||||||
if targeted_by_break {
|
if targeted_by_break {
|
||||||
this.in_breakable_scope(None, destination, span, |this| {
|
this.in_breakable_scope(None, destination, span, |this| {
|
||||||
|
@ -49,7 +48,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
span: Span,
|
span: Span,
|
||||||
stmts: &[StmtId],
|
stmts: &[StmtId],
|
||||||
expr: Option<&Expr<'tcx>>,
|
expr: Option<ExprId>,
|
||||||
safety_mode: BlockSafety,
|
safety_mode: BlockSafety,
|
||||||
region_scope: Scope,
|
region_scope: Scope,
|
||||||
) -> BlockAnd<()> {
|
) -> BlockAnd<()> {
|
||||||
|
@ -90,7 +89,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
let si = (*scope, source_info);
|
let si = (*scope, source_info);
|
||||||
unpack!(
|
unpack!(
|
||||||
block = this.in_scope(si, LintLevel::Inherited, |this| {
|
block = this.in_scope(si, LintLevel::Inherited, |this| {
|
||||||
this.stmt_expr(block, &this.thir[*expr], Some(*scope))
|
this.stmt_expr(block, *expr, Some(*scope))
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -205,8 +204,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
let visibility_scope =
|
let visibility_scope =
|
||||||
Some(this.new_source_scope(remainder_span, LintLevel::Inherited, None));
|
Some(this.new_source_scope(remainder_span, LintLevel::Inherited, None));
|
||||||
|
|
||||||
let init = &this.thir[*initializer];
|
let initializer_span = this.thir[*initializer].span;
|
||||||
let initializer_span = init.span;
|
|
||||||
let scope = (*init_scope, source_info);
|
let scope = (*init_scope, source_info);
|
||||||
let failure = unpack!(
|
let failure = unpack!(
|
||||||
block = this.in_scope(scope, *lint_level, |this| {
|
block = this.in_scope(scope, *lint_level, |this| {
|
||||||
|
@ -232,7 +230,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
this.ast_let_else(
|
this.ast_let_else(
|
||||||
block,
|
block,
|
||||||
init,
|
*initializer,
|
||||||
initializer_span,
|
initializer_span,
|
||||||
*else_block,
|
*else_block,
|
||||||
&last_remainder_scope,
|
&last_remainder_scope,
|
||||||
|
@ -276,9 +274,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
Some(this.new_source_scope(remainder_span, LintLevel::Inherited, None));
|
Some(this.new_source_scope(remainder_span, LintLevel::Inherited, None));
|
||||||
|
|
||||||
// Evaluate the initializer, if present.
|
// Evaluate the initializer, if present.
|
||||||
if let Some(init) = initializer {
|
if let Some(init) = *initializer {
|
||||||
let init = &this.thir[*init];
|
let initializer_span = this.thir[init].span;
|
||||||
let initializer_span = init.span;
|
|
||||||
let scope = (*init_scope, source_info);
|
let scope = (*init_scope, source_info);
|
||||||
|
|
||||||
unpack!(
|
unpack!(
|
||||||
|
@ -334,13 +331,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
// of the block, which is stored into `destination`.
|
// of the block, which is stored into `destination`.
|
||||||
let tcx = this.tcx;
|
let tcx = this.tcx;
|
||||||
let destination_ty = destination.ty(&this.local_decls, tcx).ty;
|
let destination_ty = destination.ty(&this.local_decls, tcx).ty;
|
||||||
if let Some(expr) = expr {
|
if let Some(expr_id) = expr {
|
||||||
|
let expr = &this.thir[expr_id];
|
||||||
let tail_result_is_ignored =
|
let tail_result_is_ignored =
|
||||||
destination_ty.is_unit() || this.block_context.currently_ignores_tail_results();
|
destination_ty.is_unit() || this.block_context.currently_ignores_tail_results();
|
||||||
this.block_context
|
this.block_context
|
||||||
.push(BlockFrame::TailExpr { tail_result_is_ignored, span: expr.span });
|
.push(BlockFrame::TailExpr { tail_result_is_ignored, span: expr.span });
|
||||||
|
|
||||||
unpack!(block = this.expr_into_dest(destination, block, expr));
|
unpack!(block = this.expr_into_dest(destination, block, expr_id));
|
||||||
let popped = this.block_context.pop();
|
let popped = this.block_context.pop();
|
||||||
|
|
||||||
assert!(popped.is_some_and(|bf| bf.is_tail_expr()));
|
assert!(popped.is_some_and(|bf| bf.is_tail_expr()));
|
||||||
|
|
|
@ -17,10 +17,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
pub(crate) fn as_local_operand(
|
pub(crate) fn as_local_operand(
|
||||||
&mut self,
|
&mut self,
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
expr: &Expr<'tcx>,
|
expr_id: ExprId,
|
||||||
) -> BlockAnd<Operand<'tcx>> {
|
) -> BlockAnd<Operand<'tcx>> {
|
||||||
let local_scope = self.local_scope();
|
let local_scope = self.local_scope();
|
||||||
self.as_operand(block, Some(local_scope), expr, LocalInfo::Boring, NeedsTemporary::Maybe)
|
self.as_operand(block, Some(local_scope), expr_id, LocalInfo::Boring, NeedsTemporary::Maybe)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an operand suitable for use until the end of the current scope expression and
|
/// Returns an operand suitable for use until the end of the current scope expression and
|
||||||
|
@ -76,7 +76,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
pub(crate) fn as_local_call_operand(
|
pub(crate) fn as_local_call_operand(
|
||||||
&mut self,
|
&mut self,
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
expr: &Expr<'tcx>,
|
expr: ExprId,
|
||||||
) -> BlockAnd<Operand<'tcx>> {
|
) -> BlockAnd<Operand<'tcx>> {
|
||||||
let local_scope = self.local_scope();
|
let local_scope = self.local_scope();
|
||||||
self.as_call_operand(block, Some(local_scope), expr)
|
self.as_call_operand(block, Some(local_scope), expr)
|
||||||
|
@ -101,17 +101,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
&mut self,
|
&mut self,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
scope: Option<region::Scope>,
|
scope: Option<region::Scope>,
|
||||||
expr: &Expr<'tcx>,
|
expr_id: ExprId,
|
||||||
local_info: LocalInfo<'tcx>,
|
local_info: LocalInfo<'tcx>,
|
||||||
needs_temporary: NeedsTemporary,
|
needs_temporary: NeedsTemporary,
|
||||||
) -> BlockAnd<Operand<'tcx>> {
|
) -> BlockAnd<Operand<'tcx>> {
|
||||||
let this = self;
|
let this = self;
|
||||||
|
|
||||||
|
let expr = &this.thir[expr_id];
|
||||||
if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
|
if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
|
||||||
let source_info = this.source_info(expr.span);
|
let source_info = this.source_info(expr.span);
|
||||||
let region_scope = (region_scope, source_info);
|
let region_scope = (region_scope, source_info);
|
||||||
return this.in_scope(region_scope, lint_level, |this| {
|
return this.in_scope(region_scope, lint_level, |this| {
|
||||||
this.as_operand(block, scope, &this.thir[value], local_info, needs_temporary)
|
this.as_operand(block, scope, value, local_info, needs_temporary)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,7 +127,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
block.and(Operand::Constant(Box::new(constant)))
|
block.and(Operand::Constant(Box::new(constant)))
|
||||||
}
|
}
|
||||||
Category::Constant | Category::Place | Category::Rvalue(..) => {
|
Category::Constant | Category::Place | Category::Rvalue(..) => {
|
||||||
let operand = unpack!(block = this.as_temp(block, scope, expr, Mutability::Mut));
|
let operand = unpack!(block = this.as_temp(block, scope, expr_id, Mutability::Mut));
|
||||||
// Overwrite temp local info if we have something more interesting to record.
|
// Overwrite temp local info if we have something more interesting to record.
|
||||||
if !matches!(local_info, LocalInfo::Boring) {
|
if !matches!(local_info, LocalInfo::Boring) {
|
||||||
let decl_info =
|
let decl_info =
|
||||||
|
@ -144,16 +145,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
&mut self,
|
&mut self,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
scope: Option<region::Scope>,
|
scope: Option<region::Scope>,
|
||||||
expr: &Expr<'tcx>,
|
expr_id: ExprId,
|
||||||
) -> BlockAnd<Operand<'tcx>> {
|
) -> BlockAnd<Operand<'tcx>> {
|
||||||
debug!("as_call_operand(block={:?}, expr={:?})", block, expr);
|
|
||||||
let this = self;
|
let this = self;
|
||||||
|
let expr = &this.thir[expr_id];
|
||||||
|
debug!("as_call_operand(block={:?}, expr={:?})", block, expr);
|
||||||
|
|
||||||
if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
|
if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
|
||||||
let source_info = this.source_info(expr.span);
|
let source_info = this.source_info(expr.span);
|
||||||
let region_scope = (region_scope, source_info);
|
let region_scope = (region_scope, source_info);
|
||||||
return this.in_scope(region_scope, lint_level, |this| {
|
return this.in_scope(region_scope, lint_level, |this| {
|
||||||
this.as_call_operand(block, scope, &this.thir[value])
|
this.as_call_operand(block, scope, value)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,9 +173,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
// type, and that value is coming from the deref of a box.
|
// type, and that value is coming from the deref of a box.
|
||||||
if let ExprKind::Deref { arg } = expr.kind {
|
if let ExprKind::Deref { arg } = expr.kind {
|
||||||
// Generate let tmp0 = arg0
|
// Generate let tmp0 = arg0
|
||||||
let operand = unpack!(
|
let operand = unpack!(block = this.as_temp(block, scope, arg, Mutability::Mut));
|
||||||
block = this.as_temp(block, scope, &this.thir[arg], Mutability::Mut)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Return the operand *tmp0 to be used as the call argument
|
// Return the operand *tmp0 to be used as the call argument
|
||||||
let place = Place {
|
let place = Place {
|
||||||
|
@ -186,6 +186,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.as_operand(block, scope, expr, LocalInfo::Boring, NeedsTemporary::Maybe)
|
this.as_operand(block, scope, expr_id, LocalInfo::Boring, NeedsTemporary::Maybe)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -354,9 +354,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
pub(crate) fn as_place(
|
pub(crate) fn as_place(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
expr: &Expr<'tcx>,
|
expr_id: ExprId,
|
||||||
) -> BlockAnd<Place<'tcx>> {
|
) -> BlockAnd<Place<'tcx>> {
|
||||||
let place_builder = unpack!(block = self.as_place_builder(block, expr));
|
let place_builder = unpack!(block = self.as_place_builder(block, expr_id));
|
||||||
block.and(place_builder.to_place(self))
|
block.and(place_builder.to_place(self))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,9 +365,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
pub(crate) fn as_place_builder(
|
pub(crate) fn as_place_builder(
|
||||||
&mut self,
|
&mut self,
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
expr: &Expr<'tcx>,
|
expr_id: ExprId,
|
||||||
) -> BlockAnd<PlaceBuilder<'tcx>> {
|
) -> BlockAnd<PlaceBuilder<'tcx>> {
|
||||||
self.expr_as_place(block, expr, Mutability::Mut, None)
|
self.expr_as_place(block, expr_id, Mutability::Mut, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compile `expr`, yielding a place that we can move from etc.
|
/// Compile `expr`, yielding a place that we can move from etc.
|
||||||
|
@ -378,9 +378,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
pub(crate) fn as_read_only_place(
|
pub(crate) fn as_read_only_place(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
expr: &Expr<'tcx>,
|
expr_id: ExprId,
|
||||||
) -> BlockAnd<Place<'tcx>> {
|
) -> BlockAnd<Place<'tcx>> {
|
||||||
let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr));
|
let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr_id));
|
||||||
block.and(place_builder.to_place(self))
|
block.and(place_builder.to_place(self))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -393,18 +393,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
fn as_read_only_place_builder(
|
fn as_read_only_place_builder(
|
||||||
&mut self,
|
&mut self,
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
expr: &Expr<'tcx>,
|
expr_id: ExprId,
|
||||||
) -> BlockAnd<PlaceBuilder<'tcx>> {
|
) -> BlockAnd<PlaceBuilder<'tcx>> {
|
||||||
self.expr_as_place(block, expr, Mutability::Not, None)
|
self.expr_as_place(block, expr_id, Mutability::Not, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expr_as_place(
|
fn expr_as_place(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
expr: &Expr<'tcx>,
|
expr_id: ExprId,
|
||||||
mutability: Mutability,
|
mutability: Mutability,
|
||||||
fake_borrow_temps: Option<&mut Vec<Local>>,
|
fake_borrow_temps: Option<&mut Vec<Local>>,
|
||||||
) -> BlockAnd<PlaceBuilder<'tcx>> {
|
) -> BlockAnd<PlaceBuilder<'tcx>> {
|
||||||
|
let expr = &self.thir[expr_id];
|
||||||
debug!("expr_as_place(block={:?}, expr={:?}, mutability={:?})", block, expr, mutability);
|
debug!("expr_as_place(block={:?}, expr={:?}, mutability={:?})", block, expr, mutability);
|
||||||
|
|
||||||
let this = self;
|
let this = self;
|
||||||
|
@ -413,14 +414,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
match expr.kind {
|
match expr.kind {
|
||||||
ExprKind::Scope { region_scope, lint_level, value } => {
|
ExprKind::Scope { region_scope, lint_level, value } => {
|
||||||
this.in_scope((region_scope, source_info), lint_level, |this| {
|
this.in_scope((region_scope, source_info), lint_level, |this| {
|
||||||
this.expr_as_place(block, &this.thir[value], mutability, fake_borrow_temps)
|
this.expr_as_place(block, value, mutability, fake_borrow_temps)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ExprKind::Field { lhs, variant_index, name } => {
|
ExprKind::Field { lhs, variant_index, name } => {
|
||||||
let lhs = &this.thir[lhs];
|
let lhs_expr = &this.thir[lhs];
|
||||||
let mut place_builder =
|
let mut place_builder =
|
||||||
unpack!(block = this.expr_as_place(block, lhs, mutability, fake_borrow_temps,));
|
unpack!(block = this.expr_as_place(block, lhs, mutability, fake_borrow_temps,));
|
||||||
if let ty::Adt(adt_def, _) = lhs.ty.kind() {
|
if let ty::Adt(adt_def, _) = lhs_expr.ty.kind() {
|
||||||
if adt_def.is_enum() {
|
if adt_def.is_enum() {
|
||||||
place_builder = place_builder.downcast(*adt_def, variant_index);
|
place_builder = place_builder.downcast(*adt_def, variant_index);
|
||||||
}
|
}
|
||||||
|
@ -428,16 +429,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
block.and(place_builder.field(name, expr.ty))
|
block.and(place_builder.field(name, expr.ty))
|
||||||
}
|
}
|
||||||
ExprKind::Deref { arg } => {
|
ExprKind::Deref { arg } => {
|
||||||
let place_builder = unpack!(
|
let place_builder =
|
||||||
block =
|
unpack!(block = this.expr_as_place(block, arg, mutability, fake_borrow_temps,));
|
||||||
this.expr_as_place(block, &this.thir[arg], mutability, fake_borrow_temps,)
|
|
||||||
);
|
|
||||||
block.and(place_builder.deref())
|
block.and(place_builder.deref())
|
||||||
}
|
}
|
||||||
ExprKind::Index { lhs, index } => this.lower_index_expression(
|
ExprKind::Index { lhs, index } => this.lower_index_expression(
|
||||||
block,
|
block,
|
||||||
&this.thir[lhs],
|
lhs,
|
||||||
&this.thir[index],
|
index,
|
||||||
mutability,
|
mutability,
|
||||||
fake_borrow_temps,
|
fake_borrow_temps,
|
||||||
expr.temp_lifetime,
|
expr.temp_lifetime,
|
||||||
|
@ -461,12 +460,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
|
|
||||||
ExprKind::PlaceTypeAscription { source, ref user_ty } => {
|
ExprKind::PlaceTypeAscription { source, ref user_ty } => {
|
||||||
let place_builder = unpack!(
|
let place_builder = unpack!(
|
||||||
block = this.expr_as_place(
|
block = this.expr_as_place(block, source, mutability, fake_borrow_temps,)
|
||||||
block,
|
|
||||||
&this.thir[source],
|
|
||||||
mutability,
|
|
||||||
fake_borrow_temps,
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
if let Some(user_ty) = user_ty {
|
if let Some(user_ty) = user_ty {
|
||||||
let annotation_index =
|
let annotation_index =
|
||||||
|
@ -494,9 +488,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
block.and(place_builder)
|
block.and(place_builder)
|
||||||
}
|
}
|
||||||
ExprKind::ValueTypeAscription { source, ref user_ty } => {
|
ExprKind::ValueTypeAscription { source, ref user_ty } => {
|
||||||
let source = &this.thir[source];
|
let source_expr = &this.thir[source];
|
||||||
let temp =
|
let temp = unpack!(
|
||||||
unpack!(block = this.as_temp(block, source.temp_lifetime, source, mutability));
|
block = this.as_temp(block, source_expr.temp_lifetime, source, mutability)
|
||||||
|
);
|
||||||
if let Some(user_ty) = user_ty {
|
if let Some(user_ty) = user_ty {
|
||||||
let annotation_index =
|
let annotation_index =
|
||||||
this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
|
this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
|
||||||
|
@ -562,7 +557,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
// these are not places, so we need to make a temporary.
|
// these are not places, so we need to make a temporary.
|
||||||
debug_assert!(!matches!(Category::of(&expr.kind), Some(Category::Place)));
|
debug_assert!(!matches!(Category::of(&expr.kind), Some(Category::Place)));
|
||||||
let temp =
|
let temp =
|
||||||
unpack!(block = this.as_temp(block, expr.temp_lifetime, expr, mutability));
|
unpack!(block = this.as_temp(block, expr.temp_lifetime, expr_id, mutability));
|
||||||
block.and(PlaceBuilder::from(temp))
|
block.and(PlaceBuilder::from(temp))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -591,8 +586,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
fn lower_index_expression(
|
fn lower_index_expression(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
base: &Expr<'tcx>,
|
base: ExprId,
|
||||||
index: &Expr<'tcx>,
|
index: ExprId,
|
||||||
mutability: Mutability,
|
mutability: Mutability,
|
||||||
fake_borrow_temps: Option<&mut Vec<Local>>,
|
fake_borrow_temps: Option<&mut Vec<Local>>,
|
||||||
temp_lifetime: Option<region::Scope>,
|
temp_lifetime: Option<region::Scope>,
|
||||||
|
@ -609,7 +604,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
// Making this a *fresh* temporary means we do not have to worry about
|
// Making this a *fresh* temporary means we do not have to worry about
|
||||||
// the index changing later: Nothing will ever change this temporary.
|
// the index changing later: Nothing will ever change this temporary.
|
||||||
// The "retagging" transformation (for Stacked Borrows) relies on this.
|
// The "retagging" transformation (for Stacked Borrows) relies on this.
|
||||||
let idx = unpack!(block = self.as_temp(block, temp_lifetime, index, Mutability::Not,));
|
let idx = unpack!(block = self.as_temp(block, temp_lifetime, index, Mutability::Not));
|
||||||
|
|
||||||
block = self.bounds_check(block, &base_place, idx, expr_span, source_info);
|
block = self.bounds_check(block, &base_place, idx, expr_span, source_info);
|
||||||
|
|
||||||
|
|
|
@ -27,10 +27,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
pub(crate) fn as_local_rvalue(
|
pub(crate) fn as_local_rvalue(
|
||||||
&mut self,
|
&mut self,
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
expr: &Expr<'tcx>,
|
expr_id: ExprId,
|
||||||
) -> BlockAnd<Rvalue<'tcx>> {
|
) -> BlockAnd<Rvalue<'tcx>> {
|
||||||
let local_scope = self.local_scope();
|
let local_scope = self.local_scope();
|
||||||
self.as_rvalue(block, Some(local_scope), expr)
|
self.as_rvalue(block, Some(local_scope), expr_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compile `expr`, yielding an rvalue.
|
/// Compile `expr`, yielding an rvalue.
|
||||||
|
@ -38,11 +38,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
&mut self,
|
&mut self,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
scope: Option<region::Scope>,
|
scope: Option<region::Scope>,
|
||||||
expr: &Expr<'tcx>,
|
expr_id: ExprId,
|
||||||
) -> BlockAnd<Rvalue<'tcx>> {
|
) -> BlockAnd<Rvalue<'tcx>> {
|
||||||
|
let this = self;
|
||||||
|
let expr = &this.thir[expr_id];
|
||||||
debug!("expr_as_rvalue(block={:?}, scope={:?}, expr={:?})", block, scope, expr);
|
debug!("expr_as_rvalue(block={:?}, scope={:?}, expr={:?})", block, scope, expr);
|
||||||
|
|
||||||
let this = self;
|
|
||||||
let expr_span = expr.span;
|
let expr_span = expr.span;
|
||||||
let source_info = this.source_info(expr_span);
|
let source_info = this.source_info(expr_span);
|
||||||
|
|
||||||
|
@ -50,9 +51,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
ExprKind::ThreadLocalRef(did) => block.and(Rvalue::ThreadLocalRef(did)),
|
ExprKind::ThreadLocalRef(did) => block.and(Rvalue::ThreadLocalRef(did)),
|
||||||
ExprKind::Scope { region_scope, lint_level, value } => {
|
ExprKind::Scope { region_scope, lint_level, value } => {
|
||||||
let region_scope = (region_scope, source_info);
|
let region_scope = (region_scope, source_info);
|
||||||
this.in_scope(region_scope, lint_level, |this| {
|
this.in_scope(region_scope, lint_level, |this| this.as_rvalue(block, scope, value))
|
||||||
this.as_rvalue(block, scope, &this.thir[value])
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
ExprKind::Repeat { value, count } => {
|
ExprKind::Repeat { value, count } => {
|
||||||
if Some(0) == count.try_eval_target_usize(this.tcx, this.param_env) {
|
if Some(0) == count.try_eval_target_usize(this.tcx, this.param_env) {
|
||||||
|
@ -62,7 +61,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
block = this.as_operand(
|
block = this.as_operand(
|
||||||
block,
|
block,
|
||||||
scope,
|
scope,
|
||||||
&this.thir[value],
|
value,
|
||||||
LocalInfo::Boring,
|
LocalInfo::Boring,
|
||||||
NeedsTemporary::No
|
NeedsTemporary::No
|
||||||
)
|
)
|
||||||
|
@ -75,31 +74,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
block = this.as_operand(
|
block = this.as_operand(
|
||||||
block,
|
block,
|
||||||
scope,
|
scope,
|
||||||
&this.thir[lhs],
|
lhs,
|
||||||
LocalInfo::Boring,
|
LocalInfo::Boring,
|
||||||
NeedsTemporary::Maybe
|
NeedsTemporary::Maybe
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
let rhs = unpack!(
|
let rhs = unpack!(
|
||||||
block = this.as_operand(
|
block =
|
||||||
block,
|
this.as_operand(block, scope, rhs, LocalInfo::Boring, NeedsTemporary::No)
|
||||||
scope,
|
|
||||||
&this.thir[rhs],
|
|
||||||
LocalInfo::Boring,
|
|
||||||
NeedsTemporary::No
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
this.build_binary_op(block, op, expr_span, expr.ty, lhs, rhs)
|
this.build_binary_op(block, op, expr_span, expr.ty, lhs, rhs)
|
||||||
}
|
}
|
||||||
ExprKind::Unary { op, arg } => {
|
ExprKind::Unary { op, arg } => {
|
||||||
let arg = unpack!(
|
let arg = unpack!(
|
||||||
block = this.as_operand(
|
block =
|
||||||
block,
|
this.as_operand(block, scope, arg, LocalInfo::Boring, NeedsTemporary::No)
|
||||||
scope,
|
|
||||||
&this.thir[arg],
|
|
||||||
LocalInfo::Boring,
|
|
||||||
NeedsTemporary::No
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
// Check for -MIN on signed integers
|
// Check for -MIN on signed integers
|
||||||
if this.check_overflow && op == UnOp::Neg && expr.ty.is_signed() {
|
if this.check_overflow && op == UnOp::Neg && expr.ty.is_signed() {
|
||||||
|
@ -126,7 +115,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
block.and(Rvalue::UnaryOp(op, arg))
|
block.and(Rvalue::UnaryOp(op, arg))
|
||||||
}
|
}
|
||||||
ExprKind::Box { value } => {
|
ExprKind::Box { value } => {
|
||||||
let value = &this.thir[value];
|
let value_ty = this.thir[value].ty;
|
||||||
let tcx = this.tcx;
|
let tcx = this.tcx;
|
||||||
|
|
||||||
// `exchange_malloc` is unsafe but box is safe, so need a new scope.
|
// `exchange_malloc` is unsafe but box is safe, so need a new scope.
|
||||||
|
@ -142,7 +131,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
block,
|
block,
|
||||||
synth_info,
|
synth_info,
|
||||||
size,
|
size,
|
||||||
Rvalue::NullaryOp(NullOp::SizeOf, value.ty),
|
Rvalue::NullaryOp(NullOp::SizeOf, value_ty),
|
||||||
);
|
);
|
||||||
|
|
||||||
let align = this.temp(tcx.types.usize, expr_span);
|
let align = this.temp(tcx.types.usize, expr_span);
|
||||||
|
@ -150,7 +139,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
block,
|
block,
|
||||||
synth_info,
|
synth_info,
|
||||||
align,
|
align,
|
||||||
Rvalue::NullaryOp(NullOp::AlignOf, value.ty),
|
Rvalue::NullaryOp(NullOp::AlignOf, value_ty),
|
||||||
);
|
);
|
||||||
|
|
||||||
// malloc some memory of suitable size and align:
|
// malloc some memory of suitable size and align:
|
||||||
|
@ -192,7 +181,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transmute `*mut u8` to the box (thus far, uninitialized):
|
// Transmute `*mut u8` to the box (thus far, uninitialized):
|
||||||
let box_ = Rvalue::ShallowInitBox(Operand::Move(storage), value.ty);
|
let box_ = Rvalue::ShallowInitBox(Operand::Move(storage), value_ty);
|
||||||
this.cfg.push_assign(block, source_info, Place::from(result), box_);
|
this.cfg.push_assign(block, source_info, Place::from(result), box_);
|
||||||
|
|
||||||
// initialize the box contents:
|
// initialize the box contents:
|
||||||
|
@ -200,24 +189,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
block = this.expr_into_dest(
|
block = this.expr_into_dest(
|
||||||
this.tcx.mk_place_deref(Place::from(result)),
|
this.tcx.mk_place_deref(Place::from(result)),
|
||||||
block,
|
block,
|
||||||
value
|
value,
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
block.and(Rvalue::Use(Operand::Move(Place::from(result))))
|
block.and(Rvalue::Use(Operand::Move(Place::from(result))))
|
||||||
}
|
}
|
||||||
ExprKind::Cast { source } => {
|
ExprKind::Cast { source } => {
|
||||||
let source = &this.thir[source];
|
let source_expr = &this.thir[source];
|
||||||
|
|
||||||
// Casting an enum to an integer is equivalent to computing the discriminant and casting the
|
// Casting an enum to an integer is equivalent to computing the discriminant and casting the
|
||||||
// discriminant. Previously every backend had to repeat the logic for this operation. Now we
|
// discriminant. Previously every backend had to repeat the logic for this operation. Now we
|
||||||
// create all the steps directly in MIR with operations all backends need to support anyway.
|
// create all the steps directly in MIR with operations all backends need to support anyway.
|
||||||
let (source, ty) = if let ty::Adt(adt_def, ..) = source.ty.kind()
|
let (source, ty) = if let ty::Adt(adt_def, ..) = source_expr.ty.kind()
|
||||||
&& adt_def.is_enum()
|
&& adt_def.is_enum()
|
||||||
{
|
{
|
||||||
let discr_ty = adt_def.repr().discr_type().to_ty(this.tcx);
|
let discr_ty = adt_def.repr().discr_type().to_ty(this.tcx);
|
||||||
let temp = unpack!(block = this.as_temp(block, scope, source, Mutability::Not));
|
let temp = unpack!(block = this.as_temp(block, scope, source, Mutability::Not));
|
||||||
let layout = this.tcx.layout_of(this.param_env.and(source.ty));
|
let layout = this.tcx.layout_of(this.param_env.and(source_expr.ty));
|
||||||
let discr = this.temp(discr_ty, source.span);
|
let discr = this.temp(discr_ty, source_expr.span);
|
||||||
this.cfg.push_assign(
|
this.cfg.push_assign(
|
||||||
block,
|
block,
|
||||||
source_info,
|
source_info,
|
||||||
|
@ -296,7 +285,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
|
|
||||||
(op, ty)
|
(op, ty)
|
||||||
} else {
|
} else {
|
||||||
let ty = source.ty;
|
let ty = source_expr.ty;
|
||||||
let source = unpack!(
|
let source = unpack!(
|
||||||
block = this.as_operand(
|
block = this.as_operand(
|
||||||
block,
|
block,
|
||||||
|
@ -310,7 +299,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
};
|
};
|
||||||
let from_ty = CastTy::from_ty(ty);
|
let from_ty = CastTy::from_ty(ty);
|
||||||
let cast_ty = CastTy::from_ty(expr.ty);
|
let cast_ty = CastTy::from_ty(expr.ty);
|
||||||
debug!("ExprKind::Cast from_ty={from_ty:?}, cast_ty={:?}/{cast_ty:?}", expr.ty,);
|
debug!("ExprKind::Cast from_ty={from_ty:?}, cast_ty={:?}/{cast_ty:?}", expr.ty);
|
||||||
let cast_kind = mir_cast_kind(ty, expr.ty);
|
let cast_kind = mir_cast_kind(ty, expr.ty);
|
||||||
block.and(Rvalue::Cast(cast_kind, source, expr.ty))
|
block.and(Rvalue::Cast(cast_kind, source, expr.ty))
|
||||||
}
|
}
|
||||||
|
@ -319,7 +308,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
block = this.as_operand(
|
block = this.as_operand(
|
||||||
block,
|
block,
|
||||||
scope,
|
scope,
|
||||||
&this.thir[source],
|
source,
|
||||||
LocalInfo::Boring,
|
LocalInfo::Boring,
|
||||||
NeedsTemporary::No
|
NeedsTemporary::No
|
||||||
)
|
)
|
||||||
|
@ -363,7 +352,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
block = this.as_operand(
|
block = this.as_operand(
|
||||||
block,
|
block,
|
||||||
scope,
|
scope,
|
||||||
&this.thir[f],
|
f,
|
||||||
LocalInfo::Boring,
|
LocalInfo::Boring,
|
||||||
NeedsTemporary::Maybe
|
NeedsTemporary::Maybe
|
||||||
)
|
)
|
||||||
|
@ -384,7 +373,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
block = this.as_operand(
|
block = this.as_operand(
|
||||||
block,
|
block,
|
||||||
scope,
|
scope,
|
||||||
&this.thir[f],
|
f,
|
||||||
LocalInfo::Boring,
|
LocalInfo::Boring,
|
||||||
NeedsTemporary::Maybe
|
NeedsTemporary::Maybe
|
||||||
)
|
)
|
||||||
|
@ -416,8 +405,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
// ```
|
// ```
|
||||||
//
|
//
|
||||||
for (thir_place, cause, hir_id) in fake_reads.into_iter() {
|
for (thir_place, cause, hir_id) in fake_reads.into_iter() {
|
||||||
let place_builder =
|
let place_builder = unpack!(block = this.as_place_builder(block, *thir_place));
|
||||||
unpack!(block = this.as_place_builder(block, &this.thir[*thir_place]));
|
|
||||||
|
|
||||||
if let Some(mir_place) = place_builder.try_to_place(this) {
|
if let Some(mir_place) = place_builder.try_to_place(this) {
|
||||||
this.cfg.push_fake_read(
|
this.cfg.push_fake_read(
|
||||||
|
@ -434,8 +422,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.copied()
|
.copied()
|
||||||
.map(|upvar| {
|
.map(|upvar| {
|
||||||
let upvar = &this.thir[upvar];
|
let upvar_expr = &this.thir[upvar];
|
||||||
match Category::of(&upvar.kind) {
|
match Category::of(&upvar_expr.kind) {
|
||||||
// Use as_place to avoid creating a temporary when
|
// Use as_place to avoid creating a temporary when
|
||||||
// moving a variable into a closure, so that
|
// moving a variable into a closure, so that
|
||||||
// borrowck knows which variables to mark as being
|
// borrowck knows which variables to mark as being
|
||||||
|
@ -453,18 +441,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
// borrow captures when capturing an immutable
|
// borrow captures when capturing an immutable
|
||||||
// variable. This is sound because the mutation
|
// variable. This is sound because the mutation
|
||||||
// that caused the capture will cause an error.
|
// that caused the capture will cause an error.
|
||||||
match upvar.kind {
|
match upvar_expr.kind {
|
||||||
ExprKind::Borrow {
|
ExprKind::Borrow {
|
||||||
borrow_kind:
|
borrow_kind:
|
||||||
BorrowKind::Mut { kind: MutBorrowKind::Default },
|
BorrowKind::Mut { kind: MutBorrowKind::Default },
|
||||||
arg,
|
arg,
|
||||||
} => unpack!(
|
} => unpack!(
|
||||||
block = this.limit_capture_mutability(
|
block = this.limit_capture_mutability(
|
||||||
upvar.span,
|
upvar_expr.span,
|
||||||
upvar.ty,
|
upvar_expr.ty,
|
||||||
scope,
|
scope,
|
||||||
block,
|
block,
|
||||||
&this.thir[arg],
|
arg,
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -498,7 +486,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
block.and(Rvalue::Aggregate(result, operands))
|
block.and(Rvalue::Aggregate(result, operands))
|
||||||
}
|
}
|
||||||
ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => {
|
ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => {
|
||||||
block = unpack!(this.stmt_expr(block, expr, None));
|
block = unpack!(this.stmt_expr(block, expr_id, None));
|
||||||
block.and(Rvalue::Use(Operand::Constant(Box::new(ConstOperand {
|
block.and(Rvalue::Use(Operand::Constant(Box::new(ConstOperand {
|
||||||
span: expr_span,
|
span: expr_span,
|
||||||
user_ty: None,
|
user_ty: None,
|
||||||
|
@ -553,8 +541,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
Some(Category::Rvalue(RvalueFunc::AsRvalue) | Category::Constant)
|
Some(Category::Rvalue(RvalueFunc::AsRvalue) | Category::Constant)
|
||||||
));
|
));
|
||||||
let operand = unpack!(
|
let operand = unpack!(
|
||||||
block =
|
block = this.as_operand(
|
||||||
this.as_operand(block, scope, expr, LocalInfo::Boring, NeedsTemporary::No)
|
block,
|
||||||
|
scope,
|
||||||
|
expr_id,
|
||||||
|
LocalInfo::Boring,
|
||||||
|
NeedsTemporary::No,
|
||||||
|
)
|
||||||
);
|
);
|
||||||
block.and(Rvalue::Use(operand))
|
block.and(Rvalue::Use(operand))
|
||||||
}
|
}
|
||||||
|
@ -719,9 +712,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
outer_source_info: SourceInfo,
|
outer_source_info: SourceInfo,
|
||||||
) -> BlockAnd<Rvalue<'tcx>> {
|
) -> BlockAnd<Rvalue<'tcx>> {
|
||||||
let this = self;
|
let this = self;
|
||||||
let value = &this.thir[value];
|
let value_expr = &this.thir[value];
|
||||||
let elem_ty = value.ty;
|
let elem_ty = value_expr.ty;
|
||||||
if let Some(Category::Constant) = Category::of(&value.kind) {
|
if let Some(Category::Constant) = Category::of(&value_expr.kind) {
|
||||||
// Repeating a const does nothing
|
// Repeating a const does nothing
|
||||||
} else {
|
} else {
|
||||||
// For a non-const, we may need to generate an appropriate `Drop`
|
// For a non-const, we may need to generate an appropriate `Drop`
|
||||||
|
@ -754,7 +747,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
upvar_ty: Ty<'tcx>,
|
upvar_ty: Ty<'tcx>,
|
||||||
temp_lifetime: Option<region::Scope>,
|
temp_lifetime: Option<region::Scope>,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
arg: &Expr<'tcx>,
|
arg: ExprId,
|
||||||
) -> BlockAnd<Operand<'tcx>> {
|
) -> BlockAnd<Operand<'tcx>> {
|
||||||
let this = self;
|
let this = self;
|
||||||
|
|
||||||
|
|
|
@ -14,13 +14,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
&mut self,
|
&mut self,
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
temp_lifetime: Option<region::Scope>,
|
temp_lifetime: Option<region::Scope>,
|
||||||
expr: &Expr<'tcx>,
|
expr_id: ExprId,
|
||||||
mutability: Mutability,
|
mutability: Mutability,
|
||||||
) -> BlockAnd<Local> {
|
) -> BlockAnd<Local> {
|
||||||
// this is the only place in mir building that we need to truly need to worry about
|
// this is the only place in mir building that we need to truly need to worry about
|
||||||
// infinite recursion. Everything else does recurse, too, but it always gets broken up
|
// infinite recursion. Everything else does recurse, too, but it always gets broken up
|
||||||
// at some point by inserting an intermediate temporary
|
// at some point by inserting an intermediate temporary
|
||||||
ensure_sufficient_stack(|| self.as_temp_inner(block, temp_lifetime, expr, mutability))
|
ensure_sufficient_stack(|| self.as_temp_inner(block, temp_lifetime, expr_id, mutability))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip(self), level = "debug")]
|
#[instrument(skip(self), level = "debug")]
|
||||||
|
@ -28,21 +28,26 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
&mut self,
|
&mut self,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
temp_lifetime: Option<region::Scope>,
|
temp_lifetime: Option<region::Scope>,
|
||||||
expr: &Expr<'tcx>,
|
expr_id: ExprId,
|
||||||
mutability: Mutability,
|
mutability: Mutability,
|
||||||
) -> BlockAnd<Local> {
|
) -> BlockAnd<Local> {
|
||||||
let this = self;
|
let this = self;
|
||||||
|
|
||||||
|
let expr = &this.thir[expr_id];
|
||||||
let expr_span = expr.span;
|
let expr_span = expr.span;
|
||||||
let source_info = this.source_info(expr_span);
|
let source_info = this.source_info(expr_span);
|
||||||
if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
|
if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
|
||||||
return this.in_scope((region_scope, source_info), lint_level, |this| {
|
return this.in_scope((region_scope, source_info), lint_level, |this| {
|
||||||
this.as_temp(block, temp_lifetime, &this.thir[value], mutability)
|
this.as_temp(block, temp_lifetime, value, mutability)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let expr_ty = expr.ty;
|
let expr_ty = expr.ty;
|
||||||
let temp = {
|
let deduplicate_temps =
|
||||||
|
this.fixed_temps_scope.is_some() && this.fixed_temps_scope == temp_lifetime;
|
||||||
|
let temp = if deduplicate_temps && let Some(temp_index) = this.fixed_temps.get(&expr_id) {
|
||||||
|
*temp_index
|
||||||
|
} else {
|
||||||
let mut local_decl = LocalDecl::new(expr_ty, expr_span);
|
let mut local_decl = LocalDecl::new(expr_ty, expr_span);
|
||||||
if mutability.is_not() {
|
if mutability.is_not() {
|
||||||
local_decl = local_decl.immutable();
|
local_decl = local_decl.immutable();
|
||||||
|
@ -71,6 +76,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
**local_decl.local_info.as_mut().assert_crate_local() = local_info;
|
**local_decl.local_info.as_mut().assert_crate_local() = local_info;
|
||||||
this.local_decls.push(local_decl)
|
this.local_decls.push(local_decl)
|
||||||
};
|
};
|
||||||
|
if deduplicate_temps {
|
||||||
|
this.fixed_temps.insert(expr_id, temp);
|
||||||
|
}
|
||||||
let temp_place = Place::from(temp);
|
let temp_place = Place::from(temp);
|
||||||
|
|
||||||
match expr.kind {
|
match expr.kind {
|
||||||
|
@ -103,7 +111,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unpack!(block = this.expr_into_dest(temp_place, block, expr));
|
unpack!(block = this.expr_into_dest(temp_place, block, expr_id));
|
||||||
|
|
||||||
if let Some(temp_lifetime) = temp_lifetime {
|
if let Some(temp_lifetime) = temp_lifetime {
|
||||||
this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Value);
|
this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Value);
|
||||||
|
|
|
@ -19,12 +19,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
&mut self,
|
&mut self,
|
||||||
destination: Place<'tcx>,
|
destination: Place<'tcx>,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
expr: &Expr<'tcx>,
|
expr_id: ExprId,
|
||||||
) -> BlockAnd<()> {
|
) -> BlockAnd<()> {
|
||||||
// since we frequently have to reference `self` from within a
|
// since we frequently have to reference `self` from within a
|
||||||
// closure, where `self` would be shadowed, it's easier to
|
// closure, where `self` would be shadowed, it's easier to
|
||||||
// just use the name `this` uniformly
|
// just use the name `this` uniformly
|
||||||
let this = self;
|
let this = self;
|
||||||
|
let expr = &this.thir[expr_id];
|
||||||
let expr_span = expr.span;
|
let expr_span = expr.span;
|
||||||
let source_info = this.source_info(expr_span);
|
let source_info = this.source_info(expr_span);
|
||||||
|
|
||||||
|
@ -40,20 +41,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
let region_scope = (region_scope, source_info);
|
let region_scope = (region_scope, source_info);
|
||||||
ensure_sufficient_stack(|| {
|
ensure_sufficient_stack(|| {
|
||||||
this.in_scope(region_scope, lint_level, |this| {
|
this.in_scope(region_scope, lint_level, |this| {
|
||||||
this.expr_into_dest(destination, block, &this.thir[value])
|
this.expr_into_dest(destination, block, value)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ExprKind::Block { block: ast_block } => {
|
ExprKind::Block { block: ast_block } => {
|
||||||
this.ast_block(destination, block, ast_block, source_info)
|
this.ast_block(destination, block, ast_block, source_info)
|
||||||
}
|
}
|
||||||
ExprKind::Match { scrutinee, ref arms, .. } => {
|
ExprKind::Match { scrutinee, ref arms, .. } => this.match_expr(
|
||||||
this.match_expr(destination, expr_span, block, &this.thir[scrutinee], arms)
|
destination,
|
||||||
}
|
block,
|
||||||
|
scrutinee,
|
||||||
|
arms,
|
||||||
|
expr_span,
|
||||||
|
this.thir[scrutinee].span,
|
||||||
|
),
|
||||||
ExprKind::If { cond, then, else_opt, if_then_scope } => {
|
ExprKind::If { cond, then, else_opt, if_then_scope } => {
|
||||||
let then_blk;
|
let then_blk;
|
||||||
let then_expr = &this.thir[then];
|
let then_span = this.thir[then].span;
|
||||||
let then_source_info = this.source_info(then_expr.span);
|
let then_source_info = this.source_info(then_span);
|
||||||
let condition_scope = this.local_scope();
|
let condition_scope = this.local_scope();
|
||||||
|
|
||||||
let mut else_blk = unpack!(
|
let mut else_blk = unpack!(
|
||||||
|
@ -62,27 +68,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
LintLevel::Inherited,
|
LintLevel::Inherited,
|
||||||
|this| {
|
|this| {
|
||||||
let source_info = if this.is_let(cond) {
|
let source_info = if this.is_let(cond) {
|
||||||
let variable_scope = this.new_source_scope(
|
let variable_scope =
|
||||||
then_expr.span,
|
this.new_source_scope(then_span, LintLevel::Inherited, None);
|
||||||
LintLevel::Inherited,
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
this.source_scope = variable_scope;
|
this.source_scope = variable_scope;
|
||||||
SourceInfo { span: then_expr.span, scope: variable_scope }
|
SourceInfo { span: then_span, scope: variable_scope }
|
||||||
} else {
|
} else {
|
||||||
this.source_info(then_expr.span)
|
this.source_info(then_span)
|
||||||
};
|
};
|
||||||
let (then_block, else_block) =
|
let (then_block, else_block) =
|
||||||
this.in_if_then_scope(condition_scope, then_expr.span, |this| {
|
this.in_if_then_scope(condition_scope, then_span, |this| {
|
||||||
let then_blk = unpack!(this.then_else_break(
|
let then_blk = unpack!(this.then_else_break(
|
||||||
block,
|
block,
|
||||||
&this.thir[cond],
|
cond,
|
||||||
Some(condition_scope),
|
Some(condition_scope),
|
||||||
condition_scope,
|
condition_scope,
|
||||||
source_info
|
source_info
|
||||||
));
|
));
|
||||||
|
|
||||||
this.expr_into_dest(destination, then_blk, then_expr)
|
this.expr_into_dest(destination, then_blk, then)
|
||||||
});
|
});
|
||||||
then_block.and(else_block)
|
then_block.and(else_block)
|
||||||
},
|
},
|
||||||
|
@ -90,7 +93,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
|
|
||||||
else_blk = if let Some(else_opt) = else_opt {
|
else_blk = if let Some(else_opt) = else_opt {
|
||||||
unpack!(this.expr_into_dest(destination, else_blk, &this.thir[else_opt]))
|
unpack!(this.expr_into_dest(destination, else_blk, else_opt))
|
||||||
} else {
|
} else {
|
||||||
// Body of the `if` expression without an `else` clause must return `()`, thus
|
// Body of the `if` expression without an `else` clause must return `()`, thus
|
||||||
// we implicitly generate an `else {}` if it is not specified.
|
// we implicitly generate an `else {}` if it is not specified.
|
||||||
|
@ -107,7 +110,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
ExprKind::Let { expr, ref pat } => {
|
ExprKind::Let { expr, ref pat } => {
|
||||||
let scope = this.local_scope();
|
let scope = this.local_scope();
|
||||||
let (true_block, false_block) = this.in_if_then_scope(scope, expr_span, |this| {
|
let (true_block, false_block) = this.in_if_then_scope(scope, expr_span, |this| {
|
||||||
this.lower_let_expr(block, &this.thir[expr], pat, scope, None, expr_span, true)
|
this.lower_let_expr(block, expr, pat, scope, None, expr_span, true)
|
||||||
});
|
});
|
||||||
|
|
||||||
this.cfg.push_assign_constant(
|
this.cfg.push_assign_constant(
|
||||||
|
@ -138,14 +141,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
join_block.unit()
|
join_block.unit()
|
||||||
}
|
}
|
||||||
ExprKind::NeverToAny { source } => {
|
ExprKind::NeverToAny { source } => {
|
||||||
let source = &this.thir[source];
|
let source_expr = &this.thir[source];
|
||||||
let is_call =
|
let is_call =
|
||||||
matches!(source.kind, ExprKind::Call { .. } | ExprKind::InlineAsm { .. });
|
matches!(source_expr.kind, ExprKind::Call { .. } | ExprKind::InlineAsm { .. });
|
||||||
|
|
||||||
// (#66975) Source could be a const of type `!`, so has to
|
// (#66975) Source could be a const of type `!`, so has to
|
||||||
// exist in the generated MIR.
|
// exist in the generated MIR.
|
||||||
unpack!(
|
unpack!(
|
||||||
block = this.as_temp(block, Some(this.local_scope()), source, Mutability::Mut,)
|
block = this.as_temp(block, Some(this.local_scope()), source, Mutability::Mut)
|
||||||
);
|
);
|
||||||
|
|
||||||
// This is an optimization. If the expression was a call then we already have an
|
// This is an optimization. If the expression was a call then we already have an
|
||||||
|
@ -166,7 +169,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
this.in_if_then_scope(condition_scope, expr.span, |this| {
|
this.in_if_then_scope(condition_scope, expr.span, |this| {
|
||||||
this.then_else_break(
|
this.then_else_break(
|
||||||
block,
|
block,
|
||||||
&this.thir[lhs],
|
lhs,
|
||||||
Some(condition_scope),
|
Some(condition_scope),
|
||||||
condition_scope,
|
condition_scope,
|
||||||
source_info,
|
source_info,
|
||||||
|
@ -192,7 +195,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
const_: Const::from_bool(this.tcx, constant),
|
const_: Const::from_bool(this.tcx, constant),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
let rhs = unpack!(this.expr_into_dest(destination, continuation, &this.thir[rhs]));
|
let rhs = unpack!(this.expr_into_dest(destination, continuation, rhs));
|
||||||
let target = this.cfg.start_new_block();
|
let target = this.cfg.start_new_block();
|
||||||
this.cfg.goto(rhs, source_info, target);
|
this.cfg.goto(rhs, source_info, target);
|
||||||
this.cfg.goto(short_circuit, source_info, target);
|
this.cfg.goto(short_circuit, source_info, target);
|
||||||
|
@ -231,8 +234,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
// introduce a unit temporary as the destination for the loop body.
|
// introduce a unit temporary as the destination for the loop body.
|
||||||
let tmp = this.get_unit_temp();
|
let tmp = this.get_unit_temp();
|
||||||
// Execute the body, branching back to the test.
|
// Execute the body, branching back to the test.
|
||||||
let body_block_end =
|
let body_block_end = unpack!(this.expr_into_dest(tmp, body_block, body));
|
||||||
unpack!(this.expr_into_dest(tmp, body_block, &this.thir[body]));
|
|
||||||
this.cfg.goto(body_block_end, source_info, loop_block);
|
this.cfg.goto(body_block_end, source_info, loop_block);
|
||||||
|
|
||||||
// Loops are only exited by `break` expressions.
|
// Loops are only exited by `break` expressions.
|
||||||
|
@ -240,11 +242,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ExprKind::Call { ty: _, fun, ref args, from_hir_call, fn_span } => {
|
ExprKind::Call { ty: _, fun, ref args, from_hir_call, fn_span } => {
|
||||||
let fun = unpack!(block = this.as_local_operand(block, &this.thir[fun]));
|
let fun = unpack!(block = this.as_local_operand(block, fun));
|
||||||
let args: Vec<_> = args
|
let args: Vec<_> = args
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.copied()
|
.copied()
|
||||||
.map(|arg| unpack!(block = this.as_local_call_operand(block, &this.thir[arg])))
|
.map(|arg| unpack!(block = this.as_local_call_operand(block, arg)))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let success = this.cfg.start_new_block();
|
let success = this.cfg.start_new_block();
|
||||||
|
@ -280,16 +282,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
this.diverge_from(block);
|
this.diverge_from(block);
|
||||||
success.unit()
|
success.unit()
|
||||||
}
|
}
|
||||||
ExprKind::Use { source } => this.expr_into_dest(destination, block, &this.thir[source]),
|
ExprKind::Use { source } => this.expr_into_dest(destination, block, source),
|
||||||
ExprKind::Borrow { arg, borrow_kind } => {
|
ExprKind::Borrow { arg, borrow_kind } => {
|
||||||
let arg = &this.thir[arg];
|
|
||||||
// We don't do this in `as_rvalue` because we use `as_place`
|
// We don't do this in `as_rvalue` because we use `as_place`
|
||||||
// for borrow expressions, so we cannot create an `RValue` that
|
// for borrow expressions, so we cannot create an `RValue` that
|
||||||
// remains valid across user code. `as_rvalue` is usually called
|
// remains valid across user code. `as_rvalue` is usually called
|
||||||
// by this method anyway, so this shouldn't cause too many
|
// by this method anyway, so this shouldn't cause too many
|
||||||
// unnecessary temporaries.
|
// unnecessary temporaries.
|
||||||
let arg_place = match borrow_kind {
|
let arg_place = match borrow_kind {
|
||||||
BorrowKind::Shared => unpack!(block = this.as_read_only_place(block, arg)),
|
BorrowKind::Shared => {
|
||||||
|
unpack!(block = this.as_read_only_place(block, arg))
|
||||||
|
}
|
||||||
_ => unpack!(block = this.as_place(block, arg)),
|
_ => unpack!(block = this.as_place(block, arg)),
|
||||||
};
|
};
|
||||||
let borrow = Rvalue::Ref(this.tcx.lifetimes.re_erased, borrow_kind, arg_place);
|
let borrow = Rvalue::Ref(this.tcx.lifetimes.re_erased, borrow_kind, arg_place);
|
||||||
|
@ -297,7 +300,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
block.unit()
|
block.unit()
|
||||||
}
|
}
|
||||||
ExprKind::AddressOf { mutability, arg } => {
|
ExprKind::AddressOf { mutability, arg } => {
|
||||||
let arg = &this.thir[arg];
|
|
||||||
let place = match mutability {
|
let place = match mutability {
|
||||||
hir::Mutability::Not => this.as_read_only_place(block, arg),
|
hir::Mutability::Not => this.as_read_only_place(block, arg),
|
||||||
hir::Mutability::Mut => this.as_place(block, arg),
|
hir::Mutability::Mut => this.as_place(block, arg),
|
||||||
|
@ -332,7 +334,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
block = this.as_operand(
|
block = this.as_operand(
|
||||||
block,
|
block,
|
||||||
Some(scope),
|
Some(scope),
|
||||||
&this.thir[f.expr],
|
f.expr,
|
||||||
LocalInfo::AggregateTemp,
|
LocalInfo::AggregateTemp,
|
||||||
NeedsTemporary::Maybe,
|
NeedsTemporary::Maybe,
|
||||||
)
|
)
|
||||||
|
@ -344,8 +346,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
let field_names = adt_def.variant(variant_index).fields.indices();
|
let field_names = adt_def.variant(variant_index).fields.indices();
|
||||||
|
|
||||||
let fields = if let Some(FruInfo { base, field_types }) = base {
|
let fields = if let Some(FruInfo { base, field_types }) = base {
|
||||||
let place_builder =
|
let place_builder = unpack!(block = this.as_place_builder(block, *base));
|
||||||
unpack!(block = this.as_place_builder(block, &this.thir[*base]));
|
|
||||||
|
|
||||||
// MIR does not natively support FRU, so for each
|
// MIR does not natively support FRU, so for each
|
||||||
// base-supplied field, generate an operand that
|
// base-supplied field, generate an operand that
|
||||||
|
@ -398,19 +399,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
.map(|op| match *op {
|
.map(|op| match *op {
|
||||||
thir::InlineAsmOperand::In { reg, expr } => mir::InlineAsmOperand::In {
|
thir::InlineAsmOperand::In { reg, expr } => mir::InlineAsmOperand::In {
|
||||||
reg,
|
reg,
|
||||||
value: unpack!(block = this.as_local_operand(block, &this.thir[expr])),
|
value: unpack!(block = this.as_local_operand(block, expr)),
|
||||||
},
|
},
|
||||||
thir::InlineAsmOperand::Out { reg, late, expr } => {
|
thir::InlineAsmOperand::Out { reg, late, expr } => {
|
||||||
mir::InlineAsmOperand::Out {
|
mir::InlineAsmOperand::Out {
|
||||||
reg,
|
reg,
|
||||||
late,
|
late,
|
||||||
place: expr.map(|expr| {
|
place: expr.map(|expr| unpack!(block = this.as_place(block, expr))),
|
||||||
unpack!(block = this.as_place(block, &this.thir[expr]))
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
thir::InlineAsmOperand::InOut { reg, late, expr } => {
|
thir::InlineAsmOperand::InOut { reg, late, expr } => {
|
||||||
let place = unpack!(block = this.as_place(block, &this.thir[expr]));
|
let place = unpack!(block = this.as_place(block, expr));
|
||||||
mir::InlineAsmOperand::InOut {
|
mir::InlineAsmOperand::InOut {
|
||||||
reg,
|
reg,
|
||||||
late,
|
late,
|
||||||
|
@ -423,11 +422,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
mir::InlineAsmOperand::InOut {
|
mir::InlineAsmOperand::InOut {
|
||||||
reg,
|
reg,
|
||||||
late,
|
late,
|
||||||
in_value: unpack!(
|
in_value: unpack!(block = this.as_local_operand(block, in_expr)),
|
||||||
block = this.as_local_operand(block, &this.thir[in_expr])
|
|
||||||
),
|
|
||||||
out_place: out_expr.map(|out_expr| {
|
out_place: out_expr.map(|out_expr| {
|
||||||
unpack!(block = this.as_place(block, &this.thir[out_expr]))
|
unpack!(block = this.as_place(block, out_expr))
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -488,7 +485,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
|
|
||||||
// These cases don't actually need a destination
|
// These cases don't actually need a destination
|
||||||
ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => {
|
ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => {
|
||||||
unpack!(block = this.stmt_expr(block, expr, None));
|
unpack!(block = this.stmt_expr(block, expr_id, None));
|
||||||
this.cfg.push_assign_unit(block, source_info, destination, this.tcx);
|
this.cfg.push_assign_unit(block, source_info, destination, this.tcx);
|
||||||
block.unit()
|
block.unit()
|
||||||
}
|
}
|
||||||
|
@ -497,7 +494,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
| ExprKind::Break { .. }
|
| ExprKind::Break { .. }
|
||||||
| ExprKind::Return { .. }
|
| ExprKind::Return { .. }
|
||||||
| ExprKind::Become { .. } => {
|
| ExprKind::Become { .. } => {
|
||||||
unpack!(block = this.stmt_expr(block, expr, None));
|
unpack!(block = this.stmt_expr(block, expr_id, None));
|
||||||
// No assign, as these have type `!`.
|
// No assign, as these have type `!`.
|
||||||
block.unit()
|
block.unit()
|
||||||
}
|
}
|
||||||
|
@ -509,7 +506,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
| ExprKind::ValueTypeAscription { .. } => {
|
| ExprKind::ValueTypeAscription { .. } => {
|
||||||
debug_assert!(Category::of(&expr.kind) == Some(Category::Place));
|
debug_assert!(Category::of(&expr.kind) == Some(Category::Place));
|
||||||
|
|
||||||
let place = unpack!(block = this.as_place(block, expr));
|
let place = unpack!(block = this.as_place(block, expr_id));
|
||||||
let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
|
let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
|
||||||
this.cfg.push_assign(block, source_info, destination, rvalue);
|
this.cfg.push_assign(block, source_info, destination, rvalue);
|
||||||
block.unit()
|
block.unit()
|
||||||
|
@ -524,7 +521,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
this.local_decls.push(LocalDecl::new(expr.ty, expr.span));
|
this.local_decls.push(LocalDecl::new(expr.ty, expr.span));
|
||||||
}
|
}
|
||||||
|
|
||||||
let place = unpack!(block = this.as_place(block, expr));
|
let place = unpack!(block = this.as_place(block, expr_id));
|
||||||
let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
|
let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
|
||||||
this.cfg.push_assign(block, source_info, destination, rvalue);
|
this.cfg.push_assign(block, source_info, destination, rvalue);
|
||||||
block.unit()
|
block.unit()
|
||||||
|
@ -536,7 +533,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
block = this.as_operand(
|
block = this.as_operand(
|
||||||
block,
|
block,
|
||||||
Some(scope),
|
Some(scope),
|
||||||
&this.thir[value],
|
value,
|
||||||
LocalInfo::Boring,
|
LocalInfo::Boring,
|
||||||
NeedsTemporary::No
|
NeedsTemporary::No
|
||||||
)
|
)
|
||||||
|
@ -582,7 +579,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
_ => true,
|
_ => true,
|
||||||
});
|
});
|
||||||
|
|
||||||
let rvalue = unpack!(block = this.as_local_rvalue(block, expr));
|
let rvalue = unpack!(block = this.as_local_rvalue(block, expr_id));
|
||||||
this.cfg.push_assign(block, source_info, destination, rvalue);
|
this.cfg.push_assign(block, source_info, destination, rvalue);
|
||||||
block.unit()
|
block.unit()
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,10 +11,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
pub(crate) fn stmt_expr(
|
pub(crate) fn stmt_expr(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
expr: &Expr<'tcx>,
|
expr_id: ExprId,
|
||||||
statement_scope: Option<region::Scope>,
|
statement_scope: Option<region::Scope>,
|
||||||
) -> BlockAnd<()> {
|
) -> BlockAnd<()> {
|
||||||
let this = self;
|
let this = self;
|
||||||
|
let expr = &this.thir[expr_id];
|
||||||
let expr_span = expr.span;
|
let expr_span = expr.span;
|
||||||
let source_info = this.source_info(expr.span);
|
let source_info = this.source_info(expr.span);
|
||||||
// Handle a number of expressions that don't need a destination at all. This
|
// Handle a number of expressions that don't need a destination at all. This
|
||||||
|
@ -22,13 +23,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
match expr.kind {
|
match expr.kind {
|
||||||
ExprKind::Scope { region_scope, lint_level, value } => {
|
ExprKind::Scope { region_scope, lint_level, value } => {
|
||||||
this.in_scope((region_scope, source_info), lint_level, |this| {
|
this.in_scope((region_scope, source_info), lint_level, |this| {
|
||||||
this.stmt_expr(block, &this.thir[value], statement_scope)
|
this.stmt_expr(block, value, statement_scope)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ExprKind::Assign { lhs, rhs } => {
|
ExprKind::Assign { lhs, rhs } => {
|
||||||
let lhs = &this.thir[lhs];
|
let lhs_expr = &this.thir[lhs];
|
||||||
let rhs = &this.thir[rhs];
|
|
||||||
let lhs_span = lhs.span;
|
|
||||||
|
|
||||||
// Note: we evaluate assignments right-to-left. This
|
// Note: we evaluate assignments right-to-left. This
|
||||||
// is better for borrowck interaction with overloaded
|
// is better for borrowck interaction with overloaded
|
||||||
|
@ -39,10 +38,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
|
|
||||||
// Generate better code for things that don't need to be
|
// Generate better code for things that don't need to be
|
||||||
// dropped.
|
// dropped.
|
||||||
if lhs.ty.needs_drop(this.tcx, this.param_env) {
|
if lhs_expr.ty.needs_drop(this.tcx, this.param_env) {
|
||||||
let rhs = unpack!(block = this.as_local_rvalue(block, rhs));
|
let rhs = unpack!(block = this.as_local_rvalue(block, rhs));
|
||||||
let lhs = unpack!(block = this.as_place(block, lhs));
|
let lhs = unpack!(block = this.as_place(block, lhs));
|
||||||
unpack!(block = this.build_drop_and_replace(block, lhs_span, lhs, rhs));
|
unpack!(block = this.build_drop_and_replace(block, lhs_expr.span, lhs, rhs));
|
||||||
} else {
|
} else {
|
||||||
let rhs = unpack!(block = this.as_local_rvalue(block, rhs));
|
let rhs = unpack!(block = this.as_local_rvalue(block, rhs));
|
||||||
let lhs = unpack!(block = this.as_place(block, lhs));
|
let lhs = unpack!(block = this.as_place(block, lhs));
|
||||||
|
@ -61,9 +60,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
// only affects weird things like `x += {x += 1; x}`
|
// only affects weird things like `x += {x += 1; x}`
|
||||||
// -- is that equal to `x + (x + 1)` or `2*(x+1)`?
|
// -- is that equal to `x + (x + 1)` or `2*(x+1)`?
|
||||||
|
|
||||||
let lhs = &this.thir[lhs];
|
let lhs_ty = this.thir[lhs].ty;
|
||||||
let rhs = &this.thir[rhs];
|
|
||||||
let lhs_ty = lhs.ty;
|
|
||||||
|
|
||||||
debug!("stmt_expr AssignOp block_context.push(SubExpr) : {:?}", expr);
|
debug!("stmt_expr AssignOp block_context.push(SubExpr) : {:?}", expr);
|
||||||
this.block_context.push(BlockFrame::SubExpr);
|
this.block_context.push(BlockFrame::SubExpr);
|
||||||
|
@ -87,25 +84,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
ExprKind::Continue { label } => {
|
ExprKind::Continue { label } => {
|
||||||
this.break_scope(block, None, BreakableTarget::Continue(label), source_info)
|
this.break_scope(block, None, BreakableTarget::Continue(label), source_info)
|
||||||
}
|
}
|
||||||
ExprKind::Break { label, value } => this.break_scope(
|
ExprKind::Break { label, value } => {
|
||||||
block,
|
this.break_scope(block, value, BreakableTarget::Break(label), source_info)
|
||||||
value.map(|value| &this.thir[value]),
|
}
|
||||||
BreakableTarget::Break(label),
|
ExprKind::Return { value } => {
|
||||||
source_info,
|
this.break_scope(block, value, BreakableTarget::Return, source_info)
|
||||||
),
|
}
|
||||||
ExprKind::Return { value } => this.break_scope(
|
|
||||||
block,
|
|
||||||
value.map(|value| &this.thir[value]),
|
|
||||||
BreakableTarget::Return,
|
|
||||||
source_info,
|
|
||||||
),
|
|
||||||
// FIXME(explicit_tail_calls): properly lower tail calls here
|
// FIXME(explicit_tail_calls): properly lower tail calls here
|
||||||
ExprKind::Become { value } => this.break_scope(
|
ExprKind::Become { value } => {
|
||||||
block,
|
this.break_scope(block, Some(value), BreakableTarget::Return, source_info)
|
||||||
Some(&this.thir[value]),
|
}
|
||||||
BreakableTarget::Return,
|
|
||||||
source_info,
|
|
||||||
),
|
|
||||||
_ => {
|
_ => {
|
||||||
assert!(
|
assert!(
|
||||||
statement_scope.is_some(),
|
statement_scope.is_some(),
|
||||||
|
@ -147,7 +135,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
};
|
};
|
||||||
|
|
||||||
let temp =
|
let temp =
|
||||||
unpack!(block = this.as_temp(block, statement_scope, expr, Mutability::Not));
|
unpack!(block = this.as_temp(block, statement_scope, expr_id, Mutability::Not));
|
||||||
|
|
||||||
if let Some(span) = adjusted_span {
|
if let Some(span) = adjusted_span {
|
||||||
this.local_decls[temp].source_info.span = span;
|
this.local_decls[temp].source_info.span = span;
|
||||||
|
|
|
@ -36,19 +36,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
pub(crate) fn then_else_break(
|
pub(crate) fn then_else_break(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
expr: &Expr<'tcx>,
|
expr_id: ExprId,
|
||||||
temp_scope_override: Option<region::Scope>,
|
temp_scope_override: Option<region::Scope>,
|
||||||
break_scope: region::Scope,
|
break_scope: region::Scope,
|
||||||
variable_source_info: SourceInfo,
|
variable_source_info: SourceInfo,
|
||||||
) -> BlockAnd<()> {
|
) -> BlockAnd<()> {
|
||||||
let this = self;
|
let this = self;
|
||||||
|
let expr = &this.thir[expr_id];
|
||||||
let expr_span = expr.span;
|
let expr_span = expr.span;
|
||||||
|
|
||||||
match expr.kind {
|
match expr.kind {
|
||||||
ExprKind::LogicalOp { op: LogicalOp::And, lhs, rhs } => {
|
ExprKind::LogicalOp { op: LogicalOp::And, lhs, rhs } => {
|
||||||
let lhs_then_block = unpack!(this.then_else_break(
|
let lhs_then_block = unpack!(this.then_else_break(
|
||||||
block,
|
block,
|
||||||
&this.thir[lhs],
|
lhs,
|
||||||
temp_scope_override,
|
temp_scope_override,
|
||||||
break_scope,
|
break_scope,
|
||||||
variable_source_info,
|
variable_source_info,
|
||||||
|
@ -56,7 +57,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
|
|
||||||
let rhs_then_block = unpack!(this.then_else_break(
|
let rhs_then_block = unpack!(this.then_else_break(
|
||||||
lhs_then_block,
|
lhs_then_block,
|
||||||
&this.thir[rhs],
|
rhs,
|
||||||
temp_scope_override,
|
temp_scope_override,
|
||||||
break_scope,
|
break_scope,
|
||||||
variable_source_info,
|
variable_source_info,
|
||||||
|
@ -70,7 +71,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
this.in_if_then_scope(local_scope, expr_span, |this| {
|
this.in_if_then_scope(local_scope, expr_span, |this| {
|
||||||
this.then_else_break(
|
this.then_else_break(
|
||||||
block,
|
block,
|
||||||
&this.thir[lhs],
|
lhs,
|
||||||
temp_scope_override,
|
temp_scope_override,
|
||||||
local_scope,
|
local_scope,
|
||||||
variable_source_info,
|
variable_source_info,
|
||||||
|
@ -78,7 +79,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
});
|
});
|
||||||
let rhs_success_block = unpack!(this.then_else_break(
|
let rhs_success_block = unpack!(this.then_else_break(
|
||||||
failure_block,
|
failure_block,
|
||||||
&this.thir[rhs],
|
rhs,
|
||||||
temp_scope_override,
|
temp_scope_override,
|
||||||
break_scope,
|
break_scope,
|
||||||
variable_source_info,
|
variable_source_info,
|
||||||
|
@ -97,7 +98,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
this.then_else_break(
|
this.then_else_break(
|
||||||
block,
|
block,
|
||||||
&this.thir[arg],
|
arg,
|
||||||
temp_scope_override,
|
temp_scope_override,
|
||||||
local_scope,
|
local_scope,
|
||||||
variable_source_info,
|
variable_source_info,
|
||||||
|
@ -111,7 +112,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
this.in_scope(region_scope, lint_level, |this| {
|
this.in_scope(region_scope, lint_level, |this| {
|
||||||
this.then_else_break(
|
this.then_else_break(
|
||||||
block,
|
block,
|
||||||
&this.thir[value],
|
value,
|
||||||
temp_scope_override,
|
temp_scope_override,
|
||||||
break_scope,
|
break_scope,
|
||||||
variable_source_info,
|
variable_source_info,
|
||||||
|
@ -120,14 +121,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
ExprKind::Use { source } => this.then_else_break(
|
ExprKind::Use { source } => this.then_else_break(
|
||||||
block,
|
block,
|
||||||
&this.thir[source],
|
source,
|
||||||
temp_scope_override,
|
temp_scope_override,
|
||||||
break_scope,
|
break_scope,
|
||||||
variable_source_info,
|
variable_source_info,
|
||||||
),
|
),
|
||||||
ExprKind::Let { expr, ref pat } => this.lower_let_expr(
|
ExprKind::Let { expr, ref pat } => this.lower_let_expr(
|
||||||
block,
|
block,
|
||||||
&this.thir[expr],
|
expr,
|
||||||
pat,
|
pat,
|
||||||
break_scope,
|
break_scope,
|
||||||
Some(variable_source_info.scope),
|
Some(variable_source_info.scope),
|
||||||
|
@ -138,7 +139,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
let temp_scope = temp_scope_override.unwrap_or_else(|| this.local_scope());
|
let temp_scope = temp_scope_override.unwrap_or_else(|| this.local_scope());
|
||||||
let mutability = Mutability::Mut;
|
let mutability = Mutability::Mut;
|
||||||
let place =
|
let place =
|
||||||
unpack!(block = this.as_temp(block, Some(temp_scope), expr, mutability));
|
unpack!(block = this.as_temp(block, Some(temp_scope), expr_id, mutability));
|
||||||
let operand = Operand::Move(Place::from(place));
|
let operand = Operand::Move(Place::from(place));
|
||||||
|
|
||||||
let then_block = this.cfg.start_new_block();
|
let then_block = this.cfg.start_new_block();
|
||||||
|
@ -208,14 +209,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
pub(crate) fn match_expr(
|
pub(crate) fn match_expr(
|
||||||
&mut self,
|
&mut self,
|
||||||
destination: Place<'tcx>,
|
destination: Place<'tcx>,
|
||||||
span: Span,
|
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
scrutinee: &Expr<'tcx>,
|
scrutinee_id: ExprId,
|
||||||
arms: &[ArmId],
|
arms: &[ArmId],
|
||||||
|
span: Span,
|
||||||
|
scrutinee_span: Span,
|
||||||
) -> BlockAnd<()> {
|
) -> BlockAnd<()> {
|
||||||
let scrutinee_span = scrutinee.span;
|
let scrutinee_span = scrutinee_span;
|
||||||
let scrutinee_place =
|
let scrutinee_place =
|
||||||
unpack!(block = self.lower_scrutinee(block, scrutinee, scrutinee_span,));
|
unpack!(block = self.lower_scrutinee(block, scrutinee_id, scrutinee_span));
|
||||||
|
|
||||||
let mut arm_candidates = self.create_match_candidates(&scrutinee_place, arms);
|
let mut arm_candidates = self.create_match_candidates(&scrutinee_place, arms);
|
||||||
|
|
||||||
|
@ -223,7 +225,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
let mut candidates =
|
let mut candidates =
|
||||||
arm_candidates.iter_mut().map(|(_, candidate)| candidate).collect::<Vec<_>>();
|
arm_candidates.iter_mut().map(|(_, candidate)| candidate).collect::<Vec<_>>();
|
||||||
|
|
||||||
let match_start_span = span.shrink_to_lo().to(scrutinee.span);
|
let match_start_span = span.shrink_to_lo().to(scrutinee_span);
|
||||||
|
|
||||||
let fake_borrow_temps = self.lower_match_tree(
|
let fake_borrow_temps = self.lower_match_tree(
|
||||||
block,
|
block,
|
||||||
|
@ -248,10 +250,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
fn lower_scrutinee(
|
fn lower_scrutinee(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
scrutinee: &Expr<'tcx>,
|
scrutinee_id: ExprId,
|
||||||
scrutinee_span: Span,
|
scrutinee_span: Span,
|
||||||
) -> BlockAnd<PlaceBuilder<'tcx>> {
|
) -> BlockAnd<PlaceBuilder<'tcx>> {
|
||||||
let scrutinee_place_builder = unpack!(block = self.as_place_builder(block, scrutinee));
|
let scrutinee_place_builder = unpack!(block = self.as_place_builder(block, scrutinee_id));
|
||||||
if let Some(scrutinee_place) = scrutinee_place_builder.try_to_place(self) {
|
if let Some(scrutinee_place) = scrutinee_place_builder.try_to_place(self) {
|
||||||
let source_info = self.source_info(scrutinee_span);
|
let source_info = self.source_info(scrutinee_span);
|
||||||
self.cfg.push_place_mention(block, source_info, scrutinee_place);
|
self.cfg.push_place_mention(block, source_info, scrutinee_place);
|
||||||
|
@ -394,6 +396,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
let arm_scope = (arm.scope, arm_source_info);
|
let arm_scope = (arm.scope, arm_source_info);
|
||||||
let match_scope = self.local_scope();
|
let match_scope = self.local_scope();
|
||||||
self.in_scope(arm_scope, arm.lint_level, |this| {
|
self.in_scope(arm_scope, arm.lint_level, |this| {
|
||||||
|
let old_dedup_scope =
|
||||||
|
mem::replace(&mut this.fixed_temps_scope, Some(arm.scope));
|
||||||
|
|
||||||
// `try_to_place` may fail if it is unable to resolve the given
|
// `try_to_place` may fail if it is unable to resolve the given
|
||||||
// `PlaceBuilder` inside a closure. In this case, we don't want to include
|
// `PlaceBuilder` inside a closure. In this case, we don't want to include
|
||||||
// a scrutinee place. `scrutinee_place_builder` will fail to be resolved
|
// a scrutinee place. `scrutinee_place_builder` will fail to be resolved
|
||||||
|
@ -425,11 +430,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.fixed_temps_scope = old_dedup_scope;
|
||||||
|
|
||||||
if let Some(source_scope) = scope {
|
if let Some(source_scope) = scope {
|
||||||
this.source_scope = source_scope;
|
this.source_scope = source_scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.expr_into_dest(destination, arm_block, &this.thir[arm.body])
|
this.expr_into_dest(destination, arm_block, arm.body)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -538,14 +545,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
&mut self,
|
&mut self,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
irrefutable_pat: &Pat<'tcx>,
|
irrefutable_pat: &Pat<'tcx>,
|
||||||
initializer: &Expr<'tcx>,
|
initializer_id: ExprId,
|
||||||
) -> BlockAnd<()> {
|
) -> BlockAnd<()> {
|
||||||
match irrefutable_pat.kind {
|
match irrefutable_pat.kind {
|
||||||
// Optimize the case of `let x = ...` to write directly into `x`
|
// Optimize the case of `let x = ...` to write directly into `x`
|
||||||
PatKind::Binding { mode: BindingMode::ByValue, var, subpattern: None, .. } => {
|
PatKind::Binding { mode: BindingMode::ByValue, var, subpattern: None, .. } => {
|
||||||
let place =
|
let place =
|
||||||
self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true);
|
self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true);
|
||||||
unpack!(block = self.expr_into_dest(place, block, initializer));
|
unpack!(block = self.expr_into_dest(place, block, initializer_id));
|
||||||
|
|
||||||
// Inject a fake read, see comments on `FakeReadCause::ForLet`.
|
// Inject a fake read, see comments on `FakeReadCause::ForLet`.
|
||||||
let source_info = self.source_info(irrefutable_pat.span);
|
let source_info = self.source_info(irrefutable_pat.span);
|
||||||
|
@ -576,7 +583,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
} => {
|
} => {
|
||||||
let place =
|
let place =
|
||||||
self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true);
|
self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true);
|
||||||
unpack!(block = self.expr_into_dest(place, block, initializer));
|
unpack!(block = self.expr_into_dest(place, block, initializer_id));
|
||||||
|
|
||||||
// Inject a fake read, see comments on `FakeReadCause::ForLet`.
|
// Inject a fake read, see comments on `FakeReadCause::ForLet`.
|
||||||
let pattern_source_info = self.source_info(irrefutable_pat.span);
|
let pattern_source_info = self.source_info(irrefutable_pat.span);
|
||||||
|
@ -616,8 +623,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
|
let initializer = &self.thir[initializer_id];
|
||||||
let place_builder =
|
let place_builder =
|
||||||
unpack!(block = self.lower_scrutinee(block, initializer, initializer.span));
|
unpack!(block = self.lower_scrutinee(block, initializer_id, initializer.span));
|
||||||
self.place_into_pattern(block, irrefutable_pat, place_builder, true)
|
self.place_into_pattern(block, irrefutable_pat, place_builder, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1831,15 +1839,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
pub(crate) fn lower_let_expr(
|
pub(crate) fn lower_let_expr(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
expr: &Expr<'tcx>,
|
expr_id: ExprId,
|
||||||
pat: &Pat<'tcx>,
|
pat: &Pat<'tcx>,
|
||||||
else_target: region::Scope,
|
else_target: region::Scope,
|
||||||
source_scope: Option<SourceScope>,
|
source_scope: Option<SourceScope>,
|
||||||
span: Span,
|
span: Span,
|
||||||
declare_bindings: bool,
|
declare_bindings: bool,
|
||||||
) -> BlockAnd<()> {
|
) -> BlockAnd<()> {
|
||||||
let expr_span = expr.span;
|
let expr_span = self.thir[expr_id].span;
|
||||||
let expr_place_builder = unpack!(block = self.lower_scrutinee(block, expr, expr_span));
|
let expr_place_builder = unpack!(block = self.lower_scrutinee(block, expr_id, expr_span));
|
||||||
let wildcard = Pat::wildcard_from_ty(pat.ty);
|
let wildcard = Pat::wildcard_from_ty(pat.ty);
|
||||||
let mut guard_candidate = Candidate::new(expr_place_builder.clone(), pat, false, self);
|
let mut guard_candidate = Candidate::new(expr_place_builder.clone(), pat, false, self);
|
||||||
let mut otherwise_candidate =
|
let mut otherwise_candidate =
|
||||||
|
@ -1865,7 +1873,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
self.source_info(pat.span),
|
self.source_info(pat.span),
|
||||||
guard_candidate,
|
guard_candidate,
|
||||||
&fake_borrow_temps,
|
&fake_borrow_temps,
|
||||||
expr.span,
|
expr_span,
|
||||||
None,
|
None,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
@ -2028,8 +2036,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
let (post_guard_block, otherwise_post_guard_block) =
|
let (post_guard_block, otherwise_post_guard_block) =
|
||||||
self.in_if_then_scope(match_scope, guard_span, |this| match *guard {
|
self.in_if_then_scope(match_scope, guard_span, |this| match *guard {
|
||||||
Guard::If(e) => {
|
Guard::If(e) => {
|
||||||
let e = &this.thir[e];
|
guard_span = this.thir[e].span;
|
||||||
guard_span = e.span;
|
|
||||||
this.then_else_break(
|
this.then_else_break(
|
||||||
block,
|
block,
|
||||||
e,
|
e,
|
||||||
|
@ -2038,9 +2045,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
this.source_info(arm.span),
|
this.source_info(arm.span),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Guard::IfLet(ref pat, scrutinee) => {
|
Guard::IfLet(ref pat, s) => {
|
||||||
let s = &this.thir[scrutinee];
|
guard_span = this.thir[s].span;
|
||||||
guard_span = s.span;
|
|
||||||
this.lower_let_expr(block, s, pat, match_scope, None, arm.span, false)
|
this.lower_let_expr(block, s, pat, match_scope, None, arm.span, false)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -2334,7 +2340,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
pub(crate) fn ast_let_else(
|
pub(crate) fn ast_let_else(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
init: &Expr<'tcx>,
|
init_id: ExprId,
|
||||||
initializer_span: Span,
|
initializer_span: Span,
|
||||||
else_block: BlockId,
|
else_block: BlockId,
|
||||||
let_else_scope: ®ion::Scope,
|
let_else_scope: ®ion::Scope,
|
||||||
|
@ -2342,8 +2348,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
) -> BlockAnd<BasicBlock> {
|
) -> BlockAnd<BasicBlock> {
|
||||||
let else_block_span = self.thir[else_block].span;
|
let else_block_span = self.thir[else_block].span;
|
||||||
let (matching, failure) = self.in_if_then_scope(*let_else_scope, else_block_span, |this| {
|
let (matching, failure) = self.in_if_then_scope(*let_else_scope, else_block_span, |this| {
|
||||||
let scrutinee = unpack!(block = this.lower_scrutinee(block, init, initializer_span));
|
let scrutinee = unpack!(block = this.lower_scrutinee(block, init_id, initializer_span));
|
||||||
let pat = Pat { ty: init.ty, span: else_block_span, kind: PatKind::Wild };
|
let pat = Pat { ty: pattern.ty, span: else_block_span, kind: PatKind::Wild };
|
||||||
let mut wildcard = Candidate::new(scrutinee.clone(), &pat, false, this);
|
let mut wildcard = Candidate::new(scrutinee.clone(), &pat, false, this);
|
||||||
let mut candidate = Candidate::new(scrutinee.clone(), pattern, false, this);
|
let mut candidate = Candidate::new(scrutinee.clone(), pattern, false, this);
|
||||||
let fake_borrow_temps = this.lower_match_tree(
|
let fake_borrow_temps = this.lower_match_tree(
|
||||||
|
|
|
@ -18,7 +18,7 @@ use rustc_middle::middle::region;
|
||||||
use rustc_middle::mir::interpret::Scalar;
|
use rustc_middle::mir::interpret::Scalar;
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
use rustc_middle::thir::{
|
use rustc_middle::thir::{
|
||||||
self, BindingMode, Expr, ExprId, LintLevel, LocalVarId, Param, ParamId, PatKind, Thir,
|
self, BindingMode, ExprId, LintLevel, LocalVarId, Param, ParamId, PatKind, Thir,
|
||||||
};
|
};
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
|
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
|
@ -210,6 +210,12 @@ struct Builder<'a, 'tcx> {
|
||||||
/// finish building it.
|
/// finish building it.
|
||||||
guard_context: Vec<GuardFrame>,
|
guard_context: Vec<GuardFrame>,
|
||||||
|
|
||||||
|
/// Temporaries with fixed indexes. Used so that if-let guards on arms
|
||||||
|
/// with an or-pattern are only created once.
|
||||||
|
fixed_temps: FxHashMap<ExprId, Local>,
|
||||||
|
/// Scope of temporaries that should be deduplicated using [Self::fixed_temps].
|
||||||
|
fixed_temps_scope: Option<region::Scope>,
|
||||||
|
|
||||||
/// Maps `HirId`s of variable bindings to the `Local`s created for them.
|
/// Maps `HirId`s of variable bindings to the `Local`s created for them.
|
||||||
/// (A match binding can have two locals; the 2nd is for the arm's guard.)
|
/// (A match binding can have two locals; the 2nd is for the arm's guard.)
|
||||||
var_indices: FxHashMap<LocalVarId, LocalsForNode>,
|
var_indices: FxHashMap<LocalVarId, LocalsForNode>,
|
||||||
|
@ -539,7 +545,7 @@ fn construct_fn<'tcx>(
|
||||||
let return_block =
|
let return_block =
|
||||||
unpack!(builder.in_breakable_scope(None, Place::return_place(), fn_end, |builder| {
|
unpack!(builder.in_breakable_scope(None, Place::return_place(), fn_end, |builder| {
|
||||||
Some(builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| {
|
Some(builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| {
|
||||||
builder.args_and_body(START_BLOCK, arguments, arg_scope, &thir[expr])
|
builder.args_and_body(START_BLOCK, arguments, arg_scope, expr)
|
||||||
}))
|
}))
|
||||||
}));
|
}));
|
||||||
let source_info = builder.source_info(fn_end);
|
let source_info = builder.source_info(fn_end);
|
||||||
|
@ -606,7 +612,7 @@ fn construct_const<'a, 'tcx>(
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut block = START_BLOCK;
|
let mut block = START_BLOCK;
|
||||||
unpack!(block = builder.expr_into_dest(Place::return_place(), block, &thir[expr]));
|
unpack!(block = builder.expr_into_dest(Place::return_place(), block, expr));
|
||||||
|
|
||||||
let source_info = builder.source_info(span);
|
let source_info = builder.source_info(span);
|
||||||
builder.cfg.terminate(block, source_info, TerminatorKind::Return);
|
builder.cfg.terminate(block, source_info, TerminatorKind::Return);
|
||||||
|
@ -752,6 +758,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
source_scopes: IndexVec::new(),
|
source_scopes: IndexVec::new(),
|
||||||
source_scope: OUTERMOST_SOURCE_SCOPE,
|
source_scope: OUTERMOST_SOURCE_SCOPE,
|
||||||
guard_context: vec![],
|
guard_context: vec![],
|
||||||
|
fixed_temps: Default::default(),
|
||||||
|
fixed_temps_scope: None,
|
||||||
in_scope_unsafe: safety,
|
in_scope_unsafe: safety,
|
||||||
local_decls: IndexVec::from_elem_n(LocalDecl::new(return_ty, return_span), 1),
|
local_decls: IndexVec::from_elem_n(LocalDecl::new(return_ty, return_span), 1),
|
||||||
canonical_user_type_annotations: IndexVec::new(),
|
canonical_user_type_annotations: IndexVec::new(),
|
||||||
|
@ -865,8 +873,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
arguments: &IndexSlice<ParamId, Param<'tcx>>,
|
arguments: &IndexSlice<ParamId, Param<'tcx>>,
|
||||||
argument_scope: region::Scope,
|
argument_scope: region::Scope,
|
||||||
expr: &Expr<'tcx>,
|
expr_id: ExprId,
|
||||||
) -> BlockAnd<()> {
|
) -> BlockAnd<()> {
|
||||||
|
let expr_span = self.thir[expr_id].span;
|
||||||
// Allocate locals for the function arguments
|
// Allocate locals for the function arguments
|
||||||
for (argument_index, param) in arguments.iter().enumerate() {
|
for (argument_index, param) in arguments.iter().enumerate() {
|
||||||
let source_info =
|
let source_info =
|
||||||
|
@ -899,7 +908,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
|
|
||||||
// Make sure we drop (parts of) the argument even when not matched on.
|
// Make sure we drop (parts of) the argument even when not matched on.
|
||||||
self.schedule_drop(
|
self.schedule_drop(
|
||||||
param.pat.as_ref().map_or(expr.span, |pat| pat.span),
|
param.pat.as_ref().map_or(expr_span, |pat| pat.span),
|
||||||
argument_scope,
|
argument_scope,
|
||||||
local,
|
local,
|
||||||
DropKind::Value,
|
DropKind::Value,
|
||||||
|
@ -941,8 +950,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
_ => {
|
_ => {
|
||||||
scope = self.declare_bindings(
|
scope = self.declare_bindings(
|
||||||
scope,
|
scope,
|
||||||
expr.span,
|
expr_span,
|
||||||
pat,
|
&pat,
|
||||||
None,
|
None,
|
||||||
Some((Some(&place), span)),
|
Some((Some(&place), span)),
|
||||||
);
|
);
|
||||||
|
@ -958,7 +967,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
self.source_scope = source_scope;
|
self.source_scope = source_scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.expr_into_dest(Place::return_place(), block, expr)
|
self.expr_into_dest(Place::return_place(), block, expr_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_correct_source_scope_for_arg(
|
fn set_correct_source_scope_for_arg(
|
||||||
|
|
|
@ -89,7 +89,7 @@ use rustc_hir::HirId;
|
||||||
use rustc_index::{IndexSlice, IndexVec};
|
use rustc_index::{IndexSlice, IndexVec};
|
||||||
use rustc_middle::middle::region;
|
use rustc_middle::middle::region;
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
use rustc_middle::thir::{Expr, LintLevel};
|
use rustc_middle::thir::{ExprId, LintLevel};
|
||||||
use rustc_session::lint::Level;
|
use rustc_session::lint::Level;
|
||||||
use rustc_span::{Span, DUMMY_SP};
|
use rustc_span::{Span, DUMMY_SP};
|
||||||
|
|
||||||
|
@ -592,7 +592,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
pub(crate) fn break_scope(
|
pub(crate) fn break_scope(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
value: Option<&Expr<'tcx>>,
|
value: Option<ExprId>,
|
||||||
target: BreakableTarget,
|
target: BreakableTarget,
|
||||||
source_info: SourceInfo,
|
source_info: SourceInfo,
|
||||||
) -> BlockAnd<()> {
|
) -> BlockAnd<()> {
|
||||||
|
|
|
@ -343,6 +343,17 @@ fn if_let_guard(a: &Allocator, c: bool, d: i32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn if_let_guard_2(a: &Allocator, num: i32) {
|
||||||
|
let d = a.alloc();
|
||||||
|
match num {
|
||||||
|
#[allow(irrefutable_let_patterns)]
|
||||||
|
1 | 2 if let Ptr(ref _idx, _) = a.alloc() => {
|
||||||
|
a.alloc();
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn panic_after_return(a: &Allocator) -> Ptr<'_> {
|
fn panic_after_return(a: &Allocator) -> Ptr<'_> {
|
||||||
// Panic in the drop of `p` or `q` can leak
|
// Panic in the drop of `p` or `q` can leak
|
||||||
let exceptions = vec![8, 9];
|
let exceptions = vec![8, 9];
|
||||||
|
@ -514,6 +525,9 @@ fn main() {
|
||||||
run_test(|a| if_let_guard(a, false, 0));
|
run_test(|a| if_let_guard(a, false, 0));
|
||||||
run_test(|a| if_let_guard(a, false, 1));
|
run_test(|a| if_let_guard(a, false, 1));
|
||||||
run_test(|a| if_let_guard(a, false, 2));
|
run_test(|a| if_let_guard(a, false, 2));
|
||||||
|
run_test(|a| if_let_guard_2(a, 0));
|
||||||
|
run_test(|a| if_let_guard_2(a, 1));
|
||||||
|
run_test(|a| if_let_guard_2(a, 2));
|
||||||
|
|
||||||
run_test(|a| {
|
run_test(|a| {
|
||||||
panic_after_return(a);
|
panic_after_return(a);
|
||||||
|
|
59
tests/ui/rfcs/rfc-2294-if-let-guard/drop-order.rs
Normal file
59
tests/ui/rfcs/rfc-2294-if-let-guard/drop-order.rs
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
// check drop order of temporaries create in match guards.
|
||||||
|
// For normal guards all temporaries are dropped before the body of the arm.
|
||||||
|
// For let guards temporaries live until the end of the arm.
|
||||||
|
|
||||||
|
// run-pass
|
||||||
|
|
||||||
|
#![feature(if_let_guard)]
|
||||||
|
#![allow(irrefutable_let_patterns)]
|
||||||
|
|
||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
|
static A: Mutex<Vec<i32>> = Mutex::new(Vec::new());
|
||||||
|
|
||||||
|
struct D(i32);
|
||||||
|
|
||||||
|
fn make_d(x: i32) -> D {
|
||||||
|
A.lock().unwrap().push(x);
|
||||||
|
D(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for D {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
A.lock().unwrap().push(!self.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn if_guard(num: i32) {
|
||||||
|
let _d = make_d(1);
|
||||||
|
match num {
|
||||||
|
1 | 2 if make_d(2).0 == 2 => {
|
||||||
|
make_d(3);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn if_let_guard(num: i32) {
|
||||||
|
let _d = make_d(1);
|
||||||
|
match num {
|
||||||
|
1 | 2 if let D(ref _x) = make_d(2) => {
|
||||||
|
make_d(3);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
if_guard(1);
|
||||||
|
if_guard(2);
|
||||||
|
if_let_guard(1);
|
||||||
|
if_let_guard(2);
|
||||||
|
let expected = [
|
||||||
|
1, 2, !2, 3, !3, !1,
|
||||||
|
1, 2, !2, 3, !3, !1,
|
||||||
|
1, 2, 3, !3, !2, !1,
|
||||||
|
1, 2, 3, !3, !2, !1,
|
||||||
|
];
|
||||||
|
assert_eq!(*A.lock().unwrap(), expected);
|
||||||
|
}
|
19
tests/ui/rfcs/rfc-2294-if-let-guard/loop-mutability.rs
Normal file
19
tests/ui/rfcs/rfc-2294-if-let-guard/loop-mutability.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
#![feature(if_let_guard)]
|
||||||
|
|
||||||
|
fn split_last(_: &()) -> Option<(&i32, &i32)> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assign_twice() {
|
||||||
|
loop {
|
||||||
|
match () {
|
||||||
|
#[allow(irrefutable_let_patterns)]
|
||||||
|
() if let _ = split_last(&()) => {}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,32 @@
|
||||||
|
// Check that temporaries in if-let guards are correctly scoped.
|
||||||
|
// Regression test for #116079.
|
||||||
|
|
||||||
|
// build-pass
|
||||||
|
// edition:2018
|
||||||
|
// -Zvalidate-mir
|
||||||
|
|
||||||
|
#![feature(if_let_guard)]
|
||||||
|
|
||||||
|
static mut A: [i32; 5] = [1, 2, 3, 4, 5];
|
||||||
|
|
||||||
|
async fn fun() {
|
||||||
|
unsafe {
|
||||||
|
match A {
|
||||||
|
_ => (),
|
||||||
|
i if let Some(1) = async { Some(1) }.await => (),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn funner() {
|
||||||
|
unsafe {
|
||||||
|
match A {
|
||||||
|
_ => (),
|
||||||
|
_ | _ if let Some(1) = async { Some(1) }.await => (),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
24
tests/ui/rfcs/rfc-2294-if-let-guard/scoping-consistency.rs
Normal file
24
tests/ui/rfcs/rfc-2294-if-let-guard/scoping-consistency.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// Check that temporaries in if-let guards are correctly scoped.
|
||||||
|
|
||||||
|
// build-pass
|
||||||
|
// -Zvalidate-mir
|
||||||
|
|
||||||
|
#![feature(if_let_guard)]
|
||||||
|
|
||||||
|
fn fun() {
|
||||||
|
match 0 {
|
||||||
|
_ => (),
|
||||||
|
_ if let Some(s) = std::convert::identity(&Some(String::new())) => {}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn funner() {
|
||||||
|
match 0 {
|
||||||
|
_ => (),
|
||||||
|
_ | _ if let Some(s) = std::convert::identity(&Some(String::new())) => {}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -124,7 +124,7 @@ body:
|
||||||
body:
|
body:
|
||||||
Expr {
|
Expr {
|
||||||
ty: bool
|
ty: bool
|
||||||
temp_lifetime: Some(Node(13))
|
temp_lifetime: Some(Node(12))
|
||||||
span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0)
|
span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0)
|
||||||
kind:
|
kind:
|
||||||
Scope {
|
Scope {
|
||||||
|
@ -133,7 +133,7 @@ body:
|
||||||
value:
|
value:
|
||||||
Expr {
|
Expr {
|
||||||
ty: bool
|
ty: bool
|
||||||
temp_lifetime: Some(Node(13))
|
temp_lifetime: Some(Node(12))
|
||||||
span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0)
|
span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0)
|
||||||
kind:
|
kind:
|
||||||
Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) }, neg: false)
|
Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) }, neg: false)
|
||||||
|
@ -176,7 +176,7 @@ body:
|
||||||
body:
|
body:
|
||||||
Expr {
|
Expr {
|
||||||
ty: bool
|
ty: bool
|
||||||
temp_lifetime: Some(Node(19))
|
temp_lifetime: Some(Node(18))
|
||||||
span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0)
|
span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0)
|
||||||
kind:
|
kind:
|
||||||
Scope {
|
Scope {
|
||||||
|
@ -185,7 +185,7 @@ body:
|
||||||
value:
|
value:
|
||||||
Expr {
|
Expr {
|
||||||
ty: bool
|
ty: bool
|
||||||
temp_lifetime: Some(Node(19))
|
temp_lifetime: Some(Node(18))
|
||||||
span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0)
|
span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0)
|
||||||
kind:
|
kind:
|
||||||
Literal( lit: Spanned { node: Bool(false), span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) }, neg: false)
|
Literal( lit: Spanned { node: Bool(false), span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) }, neg: false)
|
||||||
|
@ -220,7 +220,7 @@ body:
|
||||||
body:
|
body:
|
||||||
Expr {
|
Expr {
|
||||||
ty: bool
|
ty: bool
|
||||||
temp_lifetime: Some(Node(24))
|
temp_lifetime: Some(Node(23))
|
||||||
span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0)
|
span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0)
|
||||||
kind:
|
kind:
|
||||||
Scope {
|
Scope {
|
||||||
|
@ -229,7 +229,7 @@ body:
|
||||||
value:
|
value:
|
||||||
Expr {
|
Expr {
|
||||||
ty: bool
|
ty: bool
|
||||||
temp_lifetime: Some(Node(24))
|
temp_lifetime: Some(Node(23))
|
||||||
span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0)
|
span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0)
|
||||||
kind:
|
kind:
|
||||||
Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) }, neg: false)
|
Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) }, neg: false)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue