Skip to content

Commit

Permalink
Auto merge of rust-lang#129466 - dingxiangfei2009:let-chain-lint-crat…
Browse files Browse the repository at this point in the history
…er-run, r=<try>

[CRATER RUN DO NOT MERGE] Let chain lint crater run

Tracked by rust-lang#124085
Related to rust-lang#107251
cc `@jieyouxu` for review context
cc `@traviscross` for edition tracking

There is one unresolved issue that `cargo fix --edition` does not emit `if-let-rescope` lint. Details in rust-lang/cargo#14447.

Note that this patch is assuming that the feature gate `if_let_rescope` is always on just for this crater run.
  • Loading branch information
bors committed Sep 5, 2024
2 parents eb33b43 + 52e245e commit e496291
Show file tree
Hide file tree
Showing 35 changed files with 1,599 additions and 37 deletions.
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
shallow = true
[submodule "src/tools/cargo"]
path = src/tools/cargo
url = https://github.com/rust-lang/cargo.git
url = https://github.com/dingxiangfei2009/cargo.git
shallow = true
[submodule "src/doc/reference"]
path = src/doc/reference
Expand Down
29 changes: 21 additions & 8 deletions compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1999,19 +1999,32 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
) {
let used_in_call = matches!(
explanation,
BorrowExplanation::UsedLater(LaterUseKind::Call | LaterUseKind::Other, _call_span, _)
BorrowExplanation::UsedLater(
_,
LaterUseKind::Call | LaterUseKind::Other,
_call_span,
_
)
);
if !used_in_call {
debug!("not later used in call");
return;
}
if matches!(
self.body.local_decls[issued_borrow.borrowed_place.local].local_info(),
LocalInfo::IfThenRescopeTemp { .. }
) {
// A better suggestion will be issued by the `if_let_rescope` lint
return;
}

let use_span =
if let BorrowExplanation::UsedLater(LaterUseKind::Other, use_span, _) = explanation {
Some(use_span)
} else {
None
};
let use_span = if let BorrowExplanation::UsedLater(_, LaterUseKind::Other, use_span, _) =
explanation
{
Some(use_span)
} else {
None
};

let outer_call_loc =
if let TwoPhaseActivation::ActivatedAt(loc) = issued_borrow.activation_location {
Expand Down Expand Up @@ -2862,7 +2875,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
// and `move` will not help here.
(
Some(name),
BorrowExplanation::UsedLater(LaterUseKind::ClosureCapture, var_or_use_span, _),
BorrowExplanation::UsedLater(_, LaterUseKind::ClosureCapture, var_or_use_span, _),
) if borrow_spans.for_coroutine() || borrow_spans.for_closure() => self
.report_escaping_closure_capture(
borrow_spans,
Expand Down
95 changes: 86 additions & 9 deletions compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use crate::{MirBorrowckCtxt, WriteKind};

#[derive(Debug)]
pub(crate) enum BorrowExplanation<'tcx> {
UsedLater(LaterUseKind, Span, Option<Span>),
UsedLater(Local, LaterUseKind, Span, Option<Span>),
UsedLaterInLoop(LaterUseKind, Span, Option<Span>),
UsedLaterWhenDropped {
drop_loc: Location,
Expand Down Expand Up @@ -99,17 +99,39 @@ impl<'tcx> BorrowExplanation<'tcx> {
}
}
match *self {
BorrowExplanation::UsedLater(later_use_kind, var_or_use_span, path_span) => {
BorrowExplanation::UsedLater(
dropped_local,
later_use_kind,
var_or_use_span,
path_span,
) => {
let message = match later_use_kind {
LaterUseKind::TraitCapture => "captured here by trait object",
LaterUseKind::ClosureCapture => "captured here by closure",
LaterUseKind::Call => "used by call",
LaterUseKind::FakeLetRead => "stored here",
LaterUseKind::Other => "used here",
};
// We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same
if path_span.map(|path_span| path_span == var_or_use_span).unwrap_or(true) {
if borrow_span.map(|sp| !sp.overlaps(var_or_use_span)).unwrap_or(true) {
let local_decl = &body.local_decls[dropped_local];

if let &LocalInfo::IfThenRescopeTemp { if_then } = local_decl.local_info()
&& let Some((_, hir::Node::Expr(expr))) = tcx.hir().parent_iter(if_then).next()
&& let hir::ExprKind::If(cond, conseq, alt) = expr.kind
&& let hir::ExprKind::Let(&hir::LetExpr {
span: _,
pat,
init,
// FIXME(#101728): enable rewrite when type ascription is stabilized again
ty: None,
recovered: _,
}) = cond.kind
&& pat.span.can_be_used_for_suggestions()
&& let Ok(pat) = tcx.sess.source_map().span_to_snippet(pat.span)
{
suggest_rewrite_if_let(expr, &pat, init, conseq, alt, err);
} else if path_span.map_or(true, |path_span| path_span == var_or_use_span) {
// We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same
if borrow_span.map_or(true, |sp| !sp.overlaps(var_or_use_span)) {
err.span_label(
var_or_use_span,
format!("{borrow_desc}borrow later {message}"),
Expand Down Expand Up @@ -255,6 +277,22 @@ impl<'tcx> BorrowExplanation<'tcx> {
Applicability::MaybeIncorrect,
);
};
} else if let &LocalInfo::IfThenRescopeTemp { if_then } =
local_decl.local_info()
&& let hir::Node::Expr(expr) = tcx.hir_node(if_then)
&& let hir::ExprKind::If(cond, conseq, alt) = expr.kind
&& let hir::ExprKind::Let(&hir::LetExpr {
span: _,
pat,
init,
// FIXME(#101728): enable rewrite when type ascription is stabilized again
ty: None,
recovered: _,
}) = cond.kind
&& pat.span.can_be_used_for_suggestions()
&& let Ok(pat) = tcx.sess.source_map().span_to_snippet(pat.span)
{
suggest_rewrite_if_let(expr, &pat, init, conseq, alt, err);
}
}
}
Expand Down Expand Up @@ -390,6 +428,38 @@ impl<'tcx> BorrowExplanation<'tcx> {
}
}

fn suggest_rewrite_if_let<'tcx>(
expr: &hir::Expr<'tcx>,
pat: &str,
init: &hir::Expr<'tcx>,
conseq: &hir::Expr<'tcx>,
alt: Option<&hir::Expr<'tcx>>,
err: &mut Diag<'_>,
) {
err.span_note(
conseq.span.shrink_to_hi(),
"lifetime for temporaries generated in `if let`s have been shorted in Edition 2024",
);
if expr.span.can_be_used_for_suggestions() && conseq.span.can_be_used_for_suggestions() {
let mut sugg = vec![
(expr.span.shrink_to_lo().between(init.span), "match ".into()),
(conseq.span.shrink_to_lo(), format!(" {{ {pat} => ")),
];
let expr_end = expr.span.shrink_to_hi();
if let Some(alt) = alt {
sugg.push((conseq.span.between(alt.span), format!(" _ => ")));
sugg.push((expr_end, "}".into()));
} else {
sugg.push((expr_end, " _ => {} }".into()));
}
err.multipart_suggestion(
"consider rewriting the `if` into `match` which preserves the extended lifetime",
sugg,
Applicability::MachineApplicable,
);
}
}

impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
fn free_region_constraint_info(
&self,
Expand Down Expand Up @@ -465,14 +535,21 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
.or_else(|| self.borrow_spans(span, location));

if use_in_later_iteration_of_loop {
let later_use = self.later_use_kind(borrow, spans, use_location);
BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1, later_use.2)
let (later_use_kind, var_or_use_span, path_span) =
self.later_use_kind(borrow, spans, use_location);
BorrowExplanation::UsedLaterInLoop(later_use_kind, var_or_use_span, path_span)
} else {
// Check if the location represents a `FakeRead`, and adapt the error
// message to the `FakeReadCause` it is from: in particular,
// the ones inserted in optimized `let var = <expr>` patterns.
let later_use = self.later_use_kind(borrow, spans, location);
BorrowExplanation::UsedLater(later_use.0, later_use.1, later_use.2)
let (later_use_kind, var_or_use_span, path_span) =
self.later_use_kind(borrow, spans, location);
BorrowExplanation::UsedLater(
borrow.borrowed_place.local,
later_use_kind,
var_or_use_span,
path_span,
)
}
}

Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,8 @@ declare_features! (
(unstable, half_open_range_patterns_in_slices, "1.66.0", Some(67264)),
/// Allows `if let` guard in match arms.
(unstable, if_let_guard, "1.47.0", Some(51114)),
/// Rescoping temporaries in `if let` to align with Rust 2024.
(unstable, if_let_rescope, "CURRENT_RUSTC_VERSION", Some(124085)),
/// Allows `impl Trait` to be used inside associated types (RFC 2515).
(unstable, impl_trait_in_assoc_type, "1.70.0", Some(63063)),
/// Allows `impl Trait` as output type in `Fn` traits in return position of functions.
Expand Down
14 changes: 12 additions & 2 deletions compiler/rustc_hir_analysis/src/check/region.rs
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,12 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h

hir::ExprKind::If(cond, then, Some(otherwise)) => {
let expr_cx = visitor.cx;
visitor.enter_scope(Scope { id: then.hir_id.local_id, data: ScopeData::IfThen });
let data = if expr.span.at_least_rust_2024() {
ScopeData::IfThenRescope
} else {
ScopeData::IfThen
};
visitor.enter_scope(Scope { id: then.hir_id.local_id, data });
visitor.cx.var_parent = visitor.cx.parent;
visitor.visit_expr(cond);
visitor.visit_expr(then);
Expand All @@ -482,7 +487,12 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h

hir::ExprKind::If(cond, then, None) => {
let expr_cx = visitor.cx;
visitor.enter_scope(Scope { id: then.hir_id.local_id, data: ScopeData::IfThen });
let data = if expr.span.at_least_rust_2024() {
ScopeData::IfThenRescope
} else {
ScopeData::IfThen
};
visitor.enter_scope(Scope { id: then.hir_id.local_id, data });
visitor.cx.var_parent = visitor.cx.parent;
visitor.visit_expr(cond);
visitor.visit_expr(then);
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_lint/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,13 @@ lint_identifier_uncommon_codepoints = identifier contains {$codepoints_len ->
*[other] {" "}{$identifier_type}
} Unicode general security profile
lint_if_let_rescope = `if let` assigns a shorter lifetime since Edition 2024
.label = this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
.help = the value is now dropped here in Edition 2024
lint_if_let_rescope_suggestion = a `match` with a single arm can preserve the drop order up to Edition 2021
.suggestion = rewrite this `if let` into `match`
lint_ignored_unless_crate_specified = {$level}({$name}) is ignored unless specified at crate level
lint_ill_formed_attribute_input = {$num_suggestions ->
Expand Down
Loading

0 comments on commit e496291

Please sign in to comment.