Skip to content

Commit c469850

Browse files
committed
Auto merge of rust-lang#129466 - dingxiangfei2009:let-chain-lint-crater-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.
2 parents 8910346 + 6aa732a commit c469850

35 files changed

+1180
-37
lines changed

.gitmodules

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
shallow = true
55
[submodule "src/tools/cargo"]
66
path = src/tools/cargo
7-
url = https://github.com/rust-lang/cargo.git
7+
url = https://github.com/dingxiangfei2009/cargo.git
88
shallow = true
99
[submodule "src/doc/reference"]
1010
path = src/doc/reference

compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

+21-8
Original file line numberDiff line numberDiff line change
@@ -1997,19 +1997,32 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
19971997
) {
19981998
let used_in_call = matches!(
19991999
explanation,
2000-
BorrowExplanation::UsedLater(LaterUseKind::Call | LaterUseKind::Other, _call_span, _)
2000+
BorrowExplanation::UsedLater(
2001+
_,
2002+
LaterUseKind::Call | LaterUseKind::Other,
2003+
_call_span,
2004+
_
2005+
)
20012006
);
20022007
if !used_in_call {
20032008
debug!("not later used in call");
20042009
return;
20052010
}
2011+
if matches!(
2012+
self.body.local_decls[issued_borrow.borrowed_place.local].local_info(),
2013+
LocalInfo::IfThenRescopeTemp { .. }
2014+
) {
2015+
// A better suggestion will be issued by the `if_let_rescope` lint
2016+
return;
2017+
}
20062018

2007-
let use_span =
2008-
if let BorrowExplanation::UsedLater(LaterUseKind::Other, use_span, _) = explanation {
2009-
Some(use_span)
2010-
} else {
2011-
None
2012-
};
2019+
let use_span = if let BorrowExplanation::UsedLater(_, LaterUseKind::Other, use_span, _) =
2020+
explanation
2021+
{
2022+
Some(use_span)
2023+
} else {
2024+
None
2025+
};
20132026

20142027
let outer_call_loc =
20152028
if let TwoPhaseActivation::ActivatedAt(loc) = issued_borrow.activation_location {
@@ -2860,7 +2873,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
28602873
// and `move` will not help here.
28612874
(
28622875
Some(name),
2863-
BorrowExplanation::UsedLater(LaterUseKind::ClosureCapture, var_or_use_span, _),
2876+
BorrowExplanation::UsedLater(_, LaterUseKind::ClosureCapture, var_or_use_span, _),
28642877
) if borrow_spans.for_coroutine() || borrow_spans.for_closure() => self
28652878
.report_escaping_closure_capture(
28662879
borrow_spans,

compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs

+86-9
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use crate::{MirBorrowckCtxt, WriteKind};
2929

3030
#[derive(Debug)]
3131
pub(crate) enum BorrowExplanation<'tcx> {
32-
UsedLater(LaterUseKind, Span, Option<Span>),
32+
UsedLater(Local, LaterUseKind, Span, Option<Span>),
3333
UsedLaterInLoop(LaterUseKind, Span, Option<Span>),
3434
UsedLaterWhenDropped {
3535
drop_loc: Location,
@@ -98,17 +98,39 @@ impl<'tcx> BorrowExplanation<'tcx> {
9898
}
9999
}
100100
match *self {
101-
BorrowExplanation::UsedLater(later_use_kind, var_or_use_span, path_span) => {
101+
BorrowExplanation::UsedLater(
102+
dropped_local,
103+
later_use_kind,
104+
var_or_use_span,
105+
path_span,
106+
) => {
102107
let message = match later_use_kind {
103108
LaterUseKind::TraitCapture => "captured here by trait object",
104109
LaterUseKind::ClosureCapture => "captured here by closure",
105110
LaterUseKind::Call => "used by call",
106111
LaterUseKind::FakeLetRead => "stored here",
107112
LaterUseKind::Other => "used here",
108113
};
109-
// We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same
110-
if path_span.map(|path_span| path_span == var_or_use_span).unwrap_or(true) {
111-
if borrow_span.map(|sp| !sp.overlaps(var_or_use_span)).unwrap_or(true) {
114+
let local_decl = &body.local_decls[dropped_local];
115+
116+
if let &LocalInfo::IfThenRescopeTemp { if_then } = local_decl.local_info()
117+
&& let Some((_, hir::Node::Expr(expr))) = tcx.hir().parent_iter(if_then).next()
118+
&& let hir::ExprKind::If(cond, conseq, alt) = expr.kind
119+
&& let hir::ExprKind::Let(&hir::LetExpr {
120+
span: _,
121+
pat,
122+
init,
123+
// FIXME(#101728): enable rewrite when type ascription is stabilized again
124+
ty: None,
125+
recovered: _,
126+
}) = cond.kind
127+
&& pat.span.can_be_used_for_suggestions()
128+
&& let Ok(pat) = tcx.sess.source_map().span_to_snippet(pat.span)
129+
{
130+
suggest_rewrite_if_let(expr, &pat, init, conseq, alt, err);
131+
} else if path_span.map_or(true, |path_span| path_span == var_or_use_span) {
132+
// We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same
133+
if borrow_span.map_or(true, |sp| !sp.overlaps(var_or_use_span)) {
112134
err.span_label(
113135
var_or_use_span,
114136
format!("{borrow_desc}borrow later {message}"),
@@ -254,6 +276,22 @@ impl<'tcx> BorrowExplanation<'tcx> {
254276
Applicability::MaybeIncorrect,
255277
);
256278
};
279+
} else if let &LocalInfo::IfThenRescopeTemp { if_then } =
280+
local_decl.local_info()
281+
&& let hir::Node::Expr(expr) = tcx.hir_node(if_then)
282+
&& let hir::ExprKind::If(cond, conseq, alt) = expr.kind
283+
&& let hir::ExprKind::Let(&hir::LetExpr {
284+
span: _,
285+
pat,
286+
init,
287+
// FIXME(#101728): enable rewrite when type ascription is stabilized again
288+
ty: None,
289+
recovered: _,
290+
}) = cond.kind
291+
&& pat.span.can_be_used_for_suggestions()
292+
&& let Ok(pat) = tcx.sess.source_map().span_to_snippet(pat.span)
293+
{
294+
suggest_rewrite_if_let(expr, &pat, init, conseq, alt, err);
257295
}
258296
}
259297
}
@@ -389,6 +427,38 @@ impl<'tcx> BorrowExplanation<'tcx> {
389427
}
390428
}
391429

430+
fn suggest_rewrite_if_let<'tcx>(
431+
expr: &hir::Expr<'tcx>,
432+
pat: &str,
433+
init: &hir::Expr<'tcx>,
434+
conseq: &hir::Expr<'tcx>,
435+
alt: Option<&hir::Expr<'tcx>>,
436+
err: &mut Diag<'_>,
437+
) {
438+
err.span_note(
439+
conseq.span.shrink_to_hi(),
440+
"lifetime for temporaries generated in `if let`s have been shorted in Edition 2024",
441+
);
442+
if expr.span.can_be_used_for_suggestions() && conseq.span.can_be_used_for_suggestions() {
443+
let mut sugg = vec![
444+
(expr.span.shrink_to_lo().between(init.span), "match ".into()),
445+
(conseq.span.shrink_to_lo(), format!(" {{ {pat} => ")),
446+
];
447+
let expr_end = expr.span.shrink_to_hi();
448+
if let Some(alt) = alt {
449+
sugg.push((conseq.span.between(alt.span), format!(" _ => ")));
450+
sugg.push((expr_end, "}".into()));
451+
} else {
452+
sugg.push((expr_end, " _ => {} }".into()));
453+
}
454+
err.multipart_suggestion(
455+
"consider rewriting the `if` into `match` which preserves the extended lifetime",
456+
sugg,
457+
Applicability::MachineApplicable,
458+
);
459+
}
460+
}
461+
392462
impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
393463
fn free_region_constraint_info(
394464
&self,
@@ -464,14 +534,21 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
464534
.or_else(|| self.borrow_spans(span, location));
465535

466536
if use_in_later_iteration_of_loop {
467-
let later_use = self.later_use_kind(borrow, spans, use_location);
468-
BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1, later_use.2)
537+
let (later_use_kind, var_or_use_span, path_span) =
538+
self.later_use_kind(borrow, spans, use_location);
539+
BorrowExplanation::UsedLaterInLoop(later_use_kind, var_or_use_span, path_span)
469540
} else {
470541
// Check if the location represents a `FakeRead`, and adapt the error
471542
// message to the `FakeReadCause` it is from: in particular,
472543
// the ones inserted in optimized `let var = <expr>` patterns.
473-
let later_use = self.later_use_kind(borrow, spans, location);
474-
BorrowExplanation::UsedLater(later_use.0, later_use.1, later_use.2)
544+
let (later_use_kind, var_or_use_span, path_span) =
545+
self.later_use_kind(borrow, spans, location);
546+
BorrowExplanation::UsedLater(
547+
borrow.borrowed_place.local,
548+
later_use_kind,
549+
var_or_use_span,
550+
path_span,
551+
)
475552
}
476553
}
477554

compiler/rustc_feature/src/unstable.rs

+2
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,8 @@ declare_features! (
492492
(unstable, half_open_range_patterns_in_slices, "1.66.0", Some(67264)),
493493
/// Allows `if let` guard in match arms.
494494
(unstable, if_let_guard, "1.47.0", Some(51114)),
495+
/// Rescoping temporaries in `if let` to align with Rust 2024.
496+
(unstable, if_let_rescope, "CURRENT_RUSTC_VERSION", Some(124085)),
495497
/// Allows `impl Trait` to be used inside associated types (RFC 2515).
496498
(unstable, impl_trait_in_assoc_type, "1.70.0", Some(63063)),
497499
/// Allows `impl Trait` as output type in `Fn` traits in return position of functions.

compiler/rustc_hir_analysis/src/check/region.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,12 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
471471

472472
hir::ExprKind::If(cond, then, Some(otherwise)) => {
473473
let expr_cx = visitor.cx;
474-
visitor.enter_scope(Scope { id: then.hir_id.local_id, data: ScopeData::IfThen });
474+
let data = if expr.span.at_least_rust_2024() {
475+
ScopeData::IfThenRescope
476+
} else {
477+
ScopeData::IfThen
478+
};
479+
visitor.enter_scope(Scope { id: then.hir_id.local_id, data });
475480
visitor.cx.var_parent = visitor.cx.parent;
476481
visitor.visit_expr(cond);
477482
visitor.visit_expr(then);
@@ -481,7 +486,12 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
481486

482487
hir::ExprKind::If(cond, then, None) => {
483488
let expr_cx = visitor.cx;
484-
visitor.enter_scope(Scope { id: then.hir_id.local_id, data: ScopeData::IfThen });
489+
let data = if expr.span.at_least_rust_2024() {
490+
ScopeData::IfThenRescope
491+
} else {
492+
ScopeData::IfThen
493+
};
494+
visitor.enter_scope(Scope { id: then.hir_id.local_id, data });
485495
visitor.cx.var_parent = visitor.cx.parent;
486496
visitor.visit_expr(cond);
487497
visitor.visit_expr(then);

compiler/rustc_lint/messages.ftl

+5
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,11 @@ lint_identifier_uncommon_codepoints = identifier contains {$codepoints_len ->
329329
*[other] {" "}{$identifier_type}
330330
} Unicode general security profile
331331
332+
lint_if_let_rescope = `if let` assigns a shorter lifetime since Edition 2024
333+
.label = this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
334+
.help = the value is now dropped here in Edition 2024
335+
.suggestion = rewrite this `if let` into a `match` with a single arm to preserve the drop order up to Edition 2021
336+
332337
lint_ignored_unless_crate_specified = {$level}({$name}) is ignored unless specified at crate level
333338
334339
lint_ill_formed_attribute_input = {$num_suggestions ->

0 commit comments

Comments
 (0)