Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 34 additions & 17 deletions compiler/rustc_borrowck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ use rustc_mir_dataflow::move_paths::{
};
use rustc_mir_dataflow::points::DenseLocationMap;
use rustc_mir_dataflow::{Analysis, EntryStates, Results, ResultsVisitor, visit_results};
use rustc_session::lint::builtin::{TAIL_EXPR_DROP_ORDER, UNUSED_MUT};
use rustc_session::lint::builtin::{TAIL_EXPR_DROP_ORDER, UNUSED_MUT, UNWIND_DROP_ORDER};
use rustc_span::{ErrorGuaranteed, Span, Symbol};
use smallvec::SmallVec;
use tracing::{debug, instrument};
Expand Down Expand Up @@ -844,11 +844,8 @@ impl<'a, 'tcx> ResultsVisitor<'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a,
// These do not actually affect borrowck
StatementKind::ConstEvalCounter | StatementKind::StorageLive(..) => {}
// This does not affect borrowck
StatementKind::BackwardIncompatibleDropHint {
place,
reason: BackwardIncompatibleDropReason::Edition2024,
} => {
self.check_backward_incompatible_drop(location, **place, state);
StatementKind::BackwardIncompatibleDropHint { place, reason } => {
self.check_backward_incompatible_drop(location, **place, *reason, state);
}
StatementKind::StorageDead(local) => {
self.access_place(
Expand Down Expand Up @@ -1391,6 +1388,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
&mut self,
location: Location,
place: Place<'tcx>,
reason: BackwardIncompatibleDropReason,
state: &BorrowckDomain,
) {
let tcx = self.infcx.tcx;
Expand Down Expand Up @@ -1424,17 +1422,36 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
borrow,
Some((WriteKind::StorageDeadOrDrop, place)),
);
this.infcx.tcx.emit_node_span_lint(
TAIL_EXPR_DROP_ORDER,
CRATE_HIR_ID,
borrowed,
session_diagnostics::TailExprDropOrder {
borrowed,
callback: |diag| {
explain.add_explanation_to_diagnostic(&this, diag, "", None, None);
},
},
);
match reason {
BackwardIncompatibleDropReason::Edition2024 => {
this.infcx.tcx.emit_node_span_lint(
TAIL_EXPR_DROP_ORDER,
CRATE_HIR_ID,
borrowed,
session_diagnostics::TailExprDropOrder {
borrowed,
callback: |diag| {
explain
.add_explanation_to_diagnostic(&this, diag, "", None, None);
},
},
);
}
BackwardIncompatibleDropReason::UnwindStorageDead => {
this.infcx.tcx.emit_node_span_lint(
UNWIND_DROP_ORDER,
CRATE_HIR_ID,
borrowed,
session_diagnostics::UnwindDropOrder {
borrowed,
callback: |diag| {
explain
.add_explanation_to_diagnostic(&this, diag, "", None, None);
},
},
);
}
}
// We may stop at the first case
ControlFlow::Break(())
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'a, 'tcx> {
// Doesn't have any language semantics
| StatementKind::Coverage(..)
// Does not actually affect borrowck
| StatementKind::StorageLive(..) => {}
| StatementKind::StorageLive(..)
// Future-compatibility drop hints are lint markers, not loan invalidations.
| StatementKind::BackwardIncompatibleDropHint { .. } => {}
Comment thread
sladyn98 marked this conversation as resolved.
StatementKind::StorageDead(local) => {
self.access_place(
location,
Expand All @@ -81,7 +83,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'a, 'tcx> {
}
StatementKind::ConstEvalCounter
| StatementKind::Nop
| StatementKind::BackwardIncompatibleDropHint { .. }
| StatementKind::SetDiscriminant { .. } => {
bug!("Statement not allowed in this MIR phase")
}
Expand Down
16 changes: 16 additions & 0 deletions compiler/rustc_borrowck/src/session_diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -633,3 +633,19 @@ impl<'a, F: FnOnce(&mut Diag<'_, ()>)> Diagnostic<'a, ()> for TailExprDropOrder<
diag
}
}

pub(crate) struct UnwindDropOrder<F: FnOnce(&mut Diag<'_, ()>)> {
pub borrowed: Span,
pub callback: F,
}

impl<'a, F: FnOnce(&mut Diag<'_, ()>)> Diagnostic<'a, ()> for UnwindDropOrder<F> {
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
let Self { borrowed, callback } = self;
let mut diag =
Diag::new(dcx, level, "relative drop order on unwind changing in a future release")
.with_span_label(borrowed, "this value would be considered dead on an unwind path");
callback(&mut diag);
diag
}
}
42 changes: 42 additions & 0 deletions compiler/rustc_lint_defs/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ pub mod hardwired {
UNUSED_UNSAFE,
UNUSED_VARIABLES,
UNUSED_VISIBILITIES,
UNWIND_DROP_ORDER,
USELESS_DEPRECATED,
VARARGS_WITHOUT_PATTERN,
WARNINGS,
Expand Down Expand Up @@ -5233,6 +5234,47 @@ declare_lint! {
};
}

declare_lint! {
/// The `unwind_drop_order` lint detects values whose relative drop order on
/// panic unwind paths will change in a future release.
///
/// ### Example
/// ```rust,no_run
/// #![warn(unwind_drop_order)]
///
/// struct Wrap<T>(T);
///
/// impl<T> Drop for Wrap<T> {
/// fn drop(&mut self) {}
/// }
///
/// fn main() {
/// let x;
/// {
/// let y = 1;
/// x = Wrap(&y);
/// panic!();
/// }
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// During panic unwinding, Rust currently does not mark locals as dead at
/// the same program points as normal control flow. A future release may
/// make unwind paths use the same storage-dead points as normal paths. This
/// lint reports code where that change can affect relative drop order
/// checking.
pub UNWIND_DROP_ORDER,
Allow,

@Amanieu Amanieu Jun 15, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want this to warn by default? It seems like this would be a T-lang decision.

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kept this allow-by-default. It is only surfaced as a future-incompat lint via FutureReleaseSemanticsChange #147875; making it warn/deny by default should be a separate T-lang decision.

"detects future changes to drop order during panic unwinding",
@future_incompatible = FutureIncompatibleInfo {
reason: fcw!(FutureReleaseSemanticsChange #147875),
};
}

declare_lint! {
/// The `rust_2024_guarded_string_incompatible_syntax` lint detects `#` tokens
/// that will be parsed as part of a guarded string literal in Rust 2024.
Expand Down
6 changes: 2 additions & 4 deletions compiler/rustc_middle/src/mir/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -879,10 +879,8 @@ impl Debug for StatementKind<'_> {
Intrinsic(ref intrinsic) => write!(fmt, "{intrinsic}"),
ConstEvalCounter => write!(fmt, "ConstEvalCounter"),
Nop => write!(fmt, "nop"),
BackwardIncompatibleDropHint { ref place, reason: _ } => {
// For now, we don't record the reason because there is only one use case,
// which is to report breaking change in drop order by Edition 2024
write!(fmt, "BackwardIncompatibleDropHint({place:?})")
BackwardIncompatibleDropHint { ref place, reason } => {
write!(fmt, "BackwardIncompatibleDropHint({place:?}, {reason:?})")
}
}
}
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_middle/src/mir/syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -445,8 +445,7 @@ pub enum StatementKind<'tcx> {
/// Marker statement indicating where `place` would be dropped.
/// This is semantically equivalent to `Nop`, so codegen and MIRI should interpret this
/// statement as such.
/// The only use case of this statement is for linting in MIR to detect temporary lifetime
/// changes.
/// The only use case of this statement is for MIR future-compatibility linting.
BackwardIncompatibleDropHint {
/// Place to drop
place: Box<Place<'tcx>>,
Expand Down Expand Up @@ -975,6 +974,7 @@ pub enum TerminatorKind<'tcx> {

#[derive(
Clone,
Copy,
Debug,
TyEncodable,
TyDecodable,
Expand All @@ -986,6 +986,7 @@ pub enum TerminatorKind<'tcx> {
)]
pub enum BackwardIncompatibleDropReason {
Edition2024,
UnwindStorageDead,
}

#[derive(Debug, Clone, TyEncodable, TyDecodable, Hash, StableHash, PartialEq)]
Expand Down
Loading
Loading