diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_ast_lowering/src/expr.rs | 45 | ||||
| -rw-r--r-- | compiler/rustc_hir_analysis/src/check/region.rs | 38 | ||||
| -rw-r--r-- | compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_hir_typeck/src/lib.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_hir_typeck/src/pat.rs | 12 | ||||
| -rw-r--r-- | compiler/rustc_span/src/hygiene.rs | 7 |
6 files changed, 34 insertions, 80 deletions
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 8747e624a4a..15e736261d5 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -528,7 +528,7 @@ impl<'hir> LoweringContext<'_, 'hir> { then: &Block, else_opt: Option<&Expr>, ) -> hir::ExprKind<'hir> { - let lowered_cond = self.lower_cond(cond); + let lowered_cond = self.lower_expr(cond); let then_expr = self.lower_block_expr(then); if let Some(rslt) = else_opt { hir::ExprKind::If( @@ -541,44 +541,6 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - // Lowers a condition (i.e. `cond` in `if cond` or `while cond`), wrapping it in a terminating scope - // so that temporaries created in the condition don't live beyond it. - fn lower_cond(&mut self, cond: &Expr) -> &'hir hir::Expr<'hir> { - fn has_let_expr(expr: &Expr) -> bool { - match &expr.kind { - ExprKind::Binary(_, lhs, rhs) => has_let_expr(lhs) || has_let_expr(rhs), - ExprKind::Let(..) => true, - _ => false, - } - } - - // We have to take special care for `let` exprs in the condition, e.g. in - // `if let pat = val` or `if foo && let pat = val`, as we _do_ want `val` to live beyond the - // condition in this case. - // - // In order to maintain the drop behavior for the non `let` parts of the condition, - // we still wrap them in terminating scopes, e.g. `if foo && let pat = val` essentially - // gets transformed into `if { let _t = foo; _t } && let pat = val` - match &cond.kind { - ExprKind::Binary(op @ Spanned { node: ast::BinOpKind::And, .. }, lhs, rhs) - if has_let_expr(cond) => - { - let op = self.lower_binop(*op); - let lhs = self.lower_cond(lhs); - let rhs = self.lower_cond(rhs); - - self.arena.alloc(self.expr(cond.span, hir::ExprKind::Binary(op, lhs, rhs))) - } - ExprKind::Let(..) => self.lower_expr(cond), - _ => { - let cond = self.lower_expr(cond); - let reason = DesugaringKind::CondTemporary; - let span_block = self.mark_span_with_reason(reason, cond.span, None); - self.expr_drop_temps(span_block, cond) - } - } - } - // We desugar: `'label: while $cond $body` into: // // ``` @@ -602,7 +564,7 @@ impl<'hir> LoweringContext<'_, 'hir> { body: &Block, opt_label: Option<Label>, ) -> hir::ExprKind<'hir> { - let lowered_cond = self.with_loop_condition_scope(|t| t.lower_cond(cond)); + let lowered_cond = self.with_loop_condition_scope(|t| t.lower_expr(cond)); let then = self.lower_block_expr(body); let expr_break = self.expr_break(span); let stmt_break = self.stmt_expr(span, expr_break); @@ -2091,7 +2053,8 @@ impl<'hir> LoweringContext<'_, 'hir> { /// In terms of drop order, it has the same effect as wrapping `expr` in /// `{ let _t = $expr; _t }` but should provide better compile-time performance. /// - /// The drop order can be important in e.g. `if expr { .. }`. + /// The drop order can be important, e.g. to drop temporaries from an `async fn` + /// body before its parameters. pub(super) fn expr_drop_temps( &mut self, span: Span, diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 288105dfba7..95f6fba6487 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -167,15 +167,31 @@ fn resolve_block<'tcx>( visitor.cx = prev_cx; } -fn resolve_arm<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, arm: &'tcx hir::Arm<'tcx>) { - fn has_let_expr(expr: &Expr<'_>) -> bool { - match &expr.kind { - hir::ExprKind::Binary(_, lhs, rhs) => has_let_expr(lhs) || has_let_expr(rhs), - hir::ExprKind::Let(..) => true, - _ => false, - } - } +/// Resolve a condition from an `if` expression or match guard so that it is a terminating scope +/// if it doesn't contain `let` expressions. +fn resolve_cond<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, cond: &'tcx hir::Expr<'tcx>) { + let terminate = match cond.kind { + // Temporaries for `let` expressions must live into the success branch. + hir::ExprKind::Let(_) => false, + // Logical operator chains are handled in `resolve_expr`. Since logical operator chains in + // conditions are lowered to control-flow rather than boolean temporaries, there's no + // temporary to drop for logical operators themselves. `resolve_expr` will also recursively + // wrap any operands in terminating scopes, other than `let` expressions (which we shouldn't + // terminate) and other logical operators (which don't need a terminating scope, since their + // operands will be terminated). Any temporaries that would need to be dropped will be + // dropped before we leave this operator's scope; terminating them here would be redundant. + hir::ExprKind::Binary( + source_map::Spanned { node: hir::BinOpKind::And | hir::BinOpKind::Or, .. }, + _, + _, + ) => false, + // Otherwise, conditions should always drop their temporaries. + _ => true, + }; + resolve_expr(visitor, cond, terminate); +} +fn resolve_arm<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, arm: &'tcx hir::Arm<'tcx>) { let prev_cx = visitor.cx; visitor.enter_node_scope_with_dtor(arm.hir_id.local_id, true); @@ -183,7 +199,7 @@ fn resolve_arm<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, arm: &'tcx hir: resolve_pat(visitor, arm.pat); if let Some(guard) = arm.guard { - resolve_expr(visitor, guard, !has_let_expr(guard)); + resolve_cond(visitor, guard); } resolve_expr(visitor, arm.body, false); @@ -340,7 +356,7 @@ fn resolve_expr<'tcx>( }; visitor.enter_scope(Scope { local_id: then.hir_id.local_id, data }); visitor.cx.var_parent = visitor.cx.parent; - visitor.visit_expr(cond); + resolve_cond(visitor, cond); resolve_expr(visitor, then, true); visitor.cx = expr_cx; resolve_expr(visitor, otherwise, true); @@ -355,7 +371,7 @@ fn resolve_expr<'tcx>( }; visitor.enter_scope(Scope { local_id: then.hir_id.local_id, data }); visitor.cx.var_parent = visitor.cx.parent; - visitor.visit_expr(cond); + resolve_cond(visitor, cond); resolve_expr(visitor, then, true); visitor.cx = expr_cx; } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 58751f232d0..af1fc045ac8 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -51,12 +51,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; match span.desugaring_kind() { - // If span arose from a desugaring of `if` or `while`, then it is the condition - // itself, which diverges, that we are about to lint on. This gives suboptimal - // diagnostics. Instead, stop here so that the `if`- or `while`-expression's - // block is linted instead. - Some(DesugaringKind::CondTemporary) => return, - // Don't lint if the result of an async block or async function is `!`. // This does not affect the unreachable lints *within* the body. Some(DesugaringKind::Async) => return, diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index ea8c2c6ce23..9e324286fa1 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -428,11 +428,9 @@ fn report_unexpected_variant_res( } hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Binary(..), hir_id, .. }) => { suggestion.push((expr.span.shrink_to_lo(), "(".to_string())); - if let hir::Node::Expr(drop_temps) = tcx.parent_hir_node(*hir_id) - && let hir::ExprKind::DropTemps(_) = drop_temps.kind - && let hir::Node::Expr(parent) = tcx.parent_hir_node(drop_temps.hir_id) + if let hir::Node::Expr(parent) = tcx.parent_hir_node(*hir_id) && let hir::ExprKind::If(condition, block, None) = parent.kind - && condition.hir_id == drop_temps.hir_id + && condition.hir_id == *hir_id && let hir::ExprKind::Block(block, _) = block.kind && block.stmts.is_empty() && let Some(expr) = block.expr diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 43475521a0f..bf4611e1e34 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -24,7 +24,6 @@ use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; use rustc_session::parse::feature_err; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::edition::Edition; -use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::Spanned; use rustc_span::{BytePos, DUMMY_SP, Ident, Span, kw, sym}; use rustc_trait_selection::infer::InferCtxtExt; @@ -902,16 +901,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // then that's equivalent to there existing a LUB. let cause = self.pattern_cause(ti, span); if let Err(err) = self.demand_suptype_with_origin(&cause, expected, pat_ty) { - err.emit_unless( - ti.span - .filter(|&s| { - // In the case of `if`- and `while`-expressions we've already checked - // that `scrutinee: bool`. We know that the pattern is `true`, - // so an error here would be a duplicate and from the wrong POV. - s.is_desugaring(DesugaringKind::CondTemporary) - }) - .is_some(), - ); + err.emit(); } pat_ty diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 29be3b73ee9..c3080875da8 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -1191,11 +1191,6 @@ impl AstPass { /// The kind of compiler desugaring. #[derive(Clone, Copy, PartialEq, Debug, Encodable, Decodable, HashStable_Generic)] pub enum DesugaringKind { - /// We desugar `if c { i } else { e }` to `match $ExprKind::Use(c) { true => i, _ => e }`. - /// However, we do not want to blame `c` for unreachability but rather say that `i` - /// is unreachable. This desugaring kind allows us to avoid blaming `c`. - /// This also applies to `while` loops. - CondTemporary, QuestionMark, TryBlock, YeetExpr, @@ -1230,7 +1225,6 @@ impl DesugaringKind { /// The description wording should combine well with "desugaring of {}". pub fn descr(self) -> &'static str { match self { - DesugaringKind::CondTemporary => "`if` or `while` condition", DesugaringKind::Async => "`async` block or function", DesugaringKind::Await => "`await` expression", DesugaringKind::QuestionMark => "operator `?`", @@ -1253,7 +1247,6 @@ impl DesugaringKind { /// like `from_desugaring = "QuestionMark"` pub fn matches(&self, value: &str) -> bool { match self { - DesugaringKind::CondTemporary => value == "CondTemporary", DesugaringKind::Async => value == "Async", DesugaringKind::Await => value == "Await", DesugaringKind::QuestionMark => value == "QuestionMark", |
