Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 08ec439

Browse files
committedSep 22, 2024··
reduce false positives of tail-expr-drop-order from consumed values
1 parent 8ed95d1 commit 08ec439

File tree

37 files changed

+801
-373
lines changed

37 files changed

+801
-373
lines changed
 

‎Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4090,6 +4090,7 @@ dependencies = [
40904090
"rustc_hir",
40914091
"rustc_index",
40924092
"rustc_infer",
4093+
"rustc_lint",
40934094
"rustc_macros",
40944095
"rustc_middle",
40954096
"rustc_mir_build",

‎compiler/rustc_borrowck/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -690,7 +690,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
690690
TerminatorKind::SwitchInt { discr, targets: _ } => {
691691
self.consume_operand(loc, (discr, span), state);
692692
}
693-
TerminatorKind::Drop { place, target: _, unwind: _, replace } => {
693+
TerminatorKind::Drop { place, target: _, scope: _, unwind: _, replace } => {
694694
debug!(
695695
"visit_terminator_drop \
696696
loc: {:?} term: {:?} place: {:?} span: {:?}",

‎compiler/rustc_borrowck/src/polonius/loan_invalidations.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'a, 'tcx> {
103103
TerminatorKind::SwitchInt { discr, targets: _ } => {
104104
self.consume_operand(location, discr);
105105
}
106-
TerminatorKind::Drop { place: drop_place, target: _, unwind: _, replace } => {
106+
TerminatorKind::Drop { place: drop_place, target: _, scope: _, unwind: _, replace } => {
107107
let write_kind =
108108
if *replace { WriteKind::Replace } else { WriteKind::StorageDeadOrDrop };
109109
self.access_place(

‎compiler/rustc_codegen_cranelift/src/base.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
549549
| TerminatorKind::CoroutineDrop => {
550550
bug!("shouldn't exist at codegen {:?}", bb_data.terminator());
551551
}
552-
TerminatorKind::Drop { place, target, unwind: _, replace: _ } => {
552+
TerminatorKind::Drop { place, target, unwind: _, scope: _, replace: _ } => {
553553
let drop_place = codegen_place(fx, *place);
554554
crate::abi::codegen_drop(fx, source_info, drop_place, *target);
555555
}

‎compiler/rustc_codegen_ssa/src/mir/block.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1322,7 +1322,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
13221322
MergingSucc::False
13231323
}
13241324

1325-
mir::TerminatorKind::Drop { place, target, unwind, replace: _ } => self
1325+
mir::TerminatorKind::Drop { place, target, unwind, scope: _, replace: _ } => self
13261326
.codegen_drop_terminator(
13271327
helper,
13281328
bx,

‎compiler/rustc_const_eval/src/interpret/step.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
528528
}
529529
}
530530

531-
Drop { place, target, unwind, replace: _ } => {
531+
Drop { place, target, unwind, scope: _, replace: _ } => {
532532
let place = self.eval_place(place)?;
533533
let instance = Instance::resolve_drop_in_place(*self.tcx, place.layout.ty);
534534
if let ty::InstanceKind::DropGlue(_, None) = instance.def {

‎compiler/rustc_hir_typeck/src/expr_use_visitor.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,50 @@ pub trait TypeInformationCtxt<'tcx> {
150150
fn tcx(&self) -> TyCtxt<'tcx>;
151151
}
152152

153+
impl<'tcx> TypeInformationCtxt<'tcx> for (TyCtxt<'tcx>, LocalDefId) {
154+
type TypeckResults<'a> = &'tcx ty::TypeckResults<'tcx>
155+
where
156+
Self: 'a;
157+
158+
type Error = !;
159+
160+
fn typeck_results(&self) -> Self::TypeckResults<'_> {
161+
self.0.typeck(self.1)
162+
}
163+
164+
fn resolve_vars_if_possible<T: TypeFoldable<TyCtxt<'tcx>>>(&self, t: T) -> T {
165+
t
166+
}
167+
168+
fn try_structurally_resolve_type(&self, _span: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
169+
ty
170+
}
171+
172+
fn report_error(&self, span: Span, msg: impl ToString) -> Self::Error {
173+
span_bug!(span, "{}", msg.to_string())
174+
}
175+
176+
fn error_reported_in_ty(&self, _ty: Ty<'tcx>) -> Result<(), Self::Error> {
177+
Ok(())
178+
}
179+
180+
fn tainted_by_errors(&self) -> Result<(), Self::Error> {
181+
Ok(())
182+
}
183+
184+
fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
185+
ty.is_copy_modulo_regions(self.0, self.0.param_env(self.1))
186+
}
187+
188+
fn body_owner_def_id(&self) -> LocalDefId {
189+
self.1
190+
}
191+
192+
fn tcx(&self) -> TyCtxt<'tcx> {
193+
self.0
194+
}
195+
}
196+
153197
impl<'tcx> TypeInformationCtxt<'tcx> for &FnCtxt<'_, 'tcx> {
154198
type TypeckResults<'a> = Ref<'a, ty::TypeckResults<'tcx>>
155199
where

‎compiler/rustc_hir_typeck/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ mod fallback;
3030
mod fn_ctxt;
3131
mod gather_locals;
3232
mod intrinsicck;
33+
mod lint;
3334
mod method;
3435
mod op;
3536
mod pat;
@@ -506,5 +507,6 @@ fn fatally_break_rust(tcx: TyCtxt<'_>, span: Span) -> ! {
506507

507508
pub fn provide(providers: &mut Providers) {
508509
method::provide(providers);
510+
lint::provide(providers);
509511
*providers = Providers { typeck, diagnostic_only_typeck, used_trait_imports, ..*providers };
510512
}

‎compiler/rustc_hir_typeck/src/lint.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
use rustc_hir::def_id::DefId;
2+
use rustc_hir::{HirId, HirIdSet};
3+
use rustc_middle::hir::place::{PlaceBase, PlaceWithHirId};
4+
use rustc_middle::mir::FakeReadCause;
5+
use rustc_middle::query::Providers;
6+
use rustc_middle::ty::{self, TyCtxt};
7+
use tracing::instrument;
8+
9+
use crate::expr_use_visitor::{Delegate, ExprUseVisitor};
10+
11+
#[derive(Default)]
12+
struct ExtractConsumingNodeDelegate {
13+
nodes: HirIdSet,
14+
}
15+
16+
impl<'tcx> Delegate<'tcx> for ExtractConsumingNodeDelegate {
17+
#[instrument(level = "debug", skip(self))]
18+
fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, _: HirId) {
19+
match place_with_id.place.base {
20+
PlaceBase::Rvalue => {
21+
self.nodes.insert(place_with_id.hir_id);
22+
}
23+
PlaceBase::Local(id) => {
24+
self.nodes.insert(id);
25+
}
26+
PlaceBase::Upvar(upvar) => {
27+
self.nodes.insert(upvar.var_path.hir_id);
28+
}
29+
PlaceBase::StaticItem => {}
30+
}
31+
}
32+
33+
fn borrow(
34+
&mut self,
35+
_place_with_id: &PlaceWithHirId<'tcx>,
36+
_diag_expr_id: HirId,
37+
_bk: ty::BorrowKind,
38+
) {
39+
// do nothing
40+
}
41+
42+
fn mutate(&mut self, _assignee_place: &PlaceWithHirId<'tcx>, _diag_expr_id: HirId) {
43+
// do nothing
44+
}
45+
46+
fn fake_read(
47+
&mut self,
48+
_place_with_id: &PlaceWithHirId<'tcx>,
49+
_cause: FakeReadCause,
50+
_diag_expr_id: HirId,
51+
) {
52+
// do nothing
53+
}
54+
}
55+
56+
fn extract_tail_expr_consuming_nodes<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx HirIdSet {
57+
let hir = tcx.hir();
58+
let body = hir.body_owned_by(def_id.expect_local());
59+
let mut delegate = ExtractConsumingNodeDelegate::default();
60+
let euv = ExprUseVisitor::new((tcx, def_id.expect_local()), &mut delegate);
61+
let _ = euv.walk_expr(body.value);
62+
tcx.arena.alloc(delegate.nodes)
63+
}
64+
65+
pub(crate) fn provide(providers: &mut Providers) {
66+
providers.extract_tail_expr_consuming_nodes = extract_tail_expr_consuming_nodes;
67+
}

‎compiler/rustc_lint/messages.ftl

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -789,9 +789,6 @@ lint_suspicious_double_ref_clone =
789789
lint_suspicious_double_ref_deref =
790790
using `.deref()` on a double reference, which returns `{$ty}` instead of dereferencing the inner type
791791
792-
lint_tail_expr_drop_order = these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021
793-
.label = these values have significant drop implementation and will observe changes in drop order under Edition 2024
794-
795792
lint_trailing_semi_macro = trailing semicolon in macro used in expression position
796793
.note1 = macro invocations at the end of a block are treated as expressions
797794
.note2 = to ignore the value produced by the macro, add a semicolon after the invocation of `{$name}`

‎compiler/rustc_lint/src/lib.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@ mod redundant_semicolon;
8282
mod reference_casting;
8383
mod shadowed_into_iter;
8484
mod static_mut_refs;
85-
mod tail_expr_drop_order;
8685
mod traits;
8786
mod types;
8887
mod unit_bindings;
@@ -122,7 +121,6 @@ use rustc_middle::ty::TyCtxt;
122121
use shadowed_into_iter::ShadowedIntoIter;
123122
pub use shadowed_into_iter::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER};
124123
use static_mut_refs::*;
125-
use tail_expr_drop_order::TailExprDropOrder;
126124
use traits::*;
127125
use types::*;
128126
use unit_bindings::*;
@@ -246,7 +244,6 @@ late_lint_methods!(
246244
AsyncFnInTrait: AsyncFnInTrait,
247245
NonLocalDefinitions: NonLocalDefinitions::default(),
248246
ImplTraitOvercaptures: ImplTraitOvercaptures,
249-
TailExprDropOrder: TailExprDropOrder,
250247
IfLetRescope: IfLetRescope::default(),
251248
StaticMutRefs: StaticMutRefs,
252249
]

‎compiler/rustc_lint/src/tail_expr_drop_order.rs

Lines changed: 0 additions & 306 deletions
This file was deleted.

‎compiler/rustc_lint_defs/src/builtin.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ declare_lint_pass! {
9999
SINGLE_USE_LIFETIMES,
100100
SOFT_UNSTABLE,
101101
STABLE_FEATURES,
102+
TAIL_EXPR_DROP_ORDER,
102103
TEST_UNSTABLE_LINT,
103104
TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
104105
TRIVIAL_CASTS,
@@ -4998,3 +4999,81 @@ declare_lint! {
49984999
reference: "issue #124535 <https://github.com/rust-lang/rust/issues/124535>",
49995000
};
50005001
}
5002+
5003+
declare_lint! {
5004+
/// The `tail_expr_drop_order` lint looks for those values generated at the tail expression location, that of type
5005+
/// with a significant `Drop` implementation, such as locks.
5006+
/// In case there are also local variables of type with significant `Drop` implementation as well,
5007+
/// this lint warns you of a potential transposition in the drop order.
5008+
/// Your discretion on the new drop order introduced by Edition 2024 is required.
5009+
///
5010+
/// ### Example
5011+
/// ```rust,edition2024
5012+
/// #![cfg_attr(not(bootstrap), feature(shorter_tail_lifetimes))] // Simplify this in bootstrap bump.
5013+
/// #![warn(tail_expr_drop_order)]
5014+
/// struct Droppy(i32);
5015+
/// impl Droppy {
5016+
/// fn get(&self) -> i32 {
5017+
/// self.0
5018+
/// }
5019+
/// }
5020+
/// impl Drop for Droppy {
5021+
/// fn drop(&mut self) {
5022+
/// // This is a custom destructor and it induces side-effects that is observable
5023+
/// // especially when the drop order at a tail expression changes.
5024+
/// println!("loud drop {}", self.0);
5025+
/// }
5026+
/// }
5027+
/// fn edition_2024() -> i32 {
5028+
/// let another_droppy = Droppy(0);
5029+
/// Droppy(1).get()
5030+
/// }
5031+
/// fn main() {
5032+
/// edition_2024();
5033+
/// }
5034+
/// ```
5035+
///
5036+
/// {{produces}}
5037+
///
5038+
/// ### Explanation
5039+
///
5040+
/// In tail expression of blocks or function bodies,
5041+
/// values of type with significant `Drop` implementation has an ill-specified drop order
5042+
/// before Edition 2024 so that they are dropped only after dropping local variables.
5043+
/// Edition 2024 introduces a new rule with drop orders for them,
5044+
/// so that they are dropped first before dropping local variables.
5045+
///
5046+
/// A significant `Drop::drop` destructor here refers to an explicit, arbitrary
5047+
/// implementation of the `Drop` trait on the type, with exceptions including `Vec`,
5048+
/// `Box`, `Rc`, `BTreeMap` and `HashMap` that are marked by the compiler otherwise
5049+
/// so long that the generic types have no significant destructor recursively.
5050+
/// In other words, a type has a significant drop destructor when it has a `Drop` implementation
5051+
/// or its destructor invokes a significant destructor on a type.
5052+
/// Since we cannot completely reason about the change by just inspecting the existence of
5053+
/// a significant destructor, this lint remains only a suggestion and is set to `allow` by default.
5054+
///
5055+
/// This lint only points out the issue with `Droppy`, which will be dropped before `another_droppy`
5056+
/// does in Edition 2024.
5057+
/// No fix will be proposed by this lint.
5058+
/// However, the most probable fix is to hoist `Droppy` into its own local variable binding.
5059+
/// ```rust
5060+
/// struct Droppy(i32);
5061+
/// impl Droppy {
5062+
/// fn get(&self) -> i32 {
5063+
/// self.0
5064+
/// }
5065+
/// }
5066+
/// fn edition_2024() -> i32 {
5067+
/// let value = Droppy(0);
5068+
/// let another_droppy = Droppy(1);
5069+
/// value.get()
5070+
/// }
5071+
/// ```
5072+
pub TAIL_EXPR_DROP_ORDER,
5073+
Allow,
5074+
"Detect and warn on significant change in drop order in tail expression location",
5075+
@future_incompatible = FutureIncompatibleInfo {
5076+
reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),
5077+
reference: "issue #123739 <https://github.com/rust-lang/rust/issues/123739>",
5078+
};
5079+
}

‎compiler/rustc_middle/src/arena.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ macro_rules! arena_types {
114114
[decode] specialization_graph: rustc_middle::traits::specialization_graph::Graph,
115115
[] crate_inherent_impls: rustc_middle::ty::CrateInherentImpls,
116116
[] hir_owner_nodes: rustc_hir::OwnerNodes<'tcx>,
117+
[] hir_id_set: rustc_hir::HirIdSet,
117118
]);
118119
)
119120
}

‎compiler/rustc_middle/src/mir/syntax.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece, Mutability};
77
use rustc_data_structures::packed::Pu128;
88
use rustc_hir::def_id::DefId;
9-
use rustc_hir::CoroutineKind;
9+
use rustc_hir::{CoroutineKind, ItemLocalId};
1010
use rustc_index::IndexVec;
1111
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
1212
use rustc_span::def_id::LocalDefId;
@@ -704,7 +704,13 @@ pub enum TerminatorKind<'tcx> {
704704
/// The `replace` flag indicates whether this terminator was created as part of an assignment.
705705
/// This should only be used for diagnostic purposes, and does not have any operational
706706
/// meaning.
707-
Drop { place: Place<'tcx>, target: BasicBlock, unwind: UnwindAction, replace: bool },
707+
Drop {
708+
place: Place<'tcx>,
709+
target: BasicBlock,
710+
unwind: UnwindAction,
711+
scope: Option<(DefId, ItemLocalId)>,
712+
replace: bool,
713+
},
708714

709715
/// Roughly speaking, evaluates the `func` operand and the arguments, and starts execution of
710716
/// the referred to function. The operand types must match the argument types of the function.

‎compiler/rustc_middle/src/mir/terminator.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -631,7 +631,7 @@ impl<'tcx> TerminatorKind<'tcx> {
631631
Goto { target } => TerminatorEdges::Single(target),
632632

633633
Assert { target, unwind, expected: _, msg: _, cond: _ }
634-
| Drop { target, unwind, place: _, replace: _ }
634+
| Drop { target, unwind, place: _, scope: _, replace: _ }
635635
| FalseUnwind { real_target: target, unwind } => match unwind {
636636
UnwindAction::Cleanup(unwind) => TerminatorEdges::Double(target, unwind),
637637
UnwindAction::Continue | UnwindAction::Terminate(_) | UnwindAction::Unreachable => {

‎compiler/rustc_middle/src/mir/visit.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,7 @@ macro_rules! make_mir_visitor {
511511
target: _,
512512
unwind: _,
513513
replace: _,
514+
scope: _,
514515
} => {
515516
self.visit_place(
516517
place,

‎compiler/rustc_middle/src/query/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use rustc_hir::def_id::{
2626
CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId, LocalDefIdMap, LocalDefIdSet, LocalModDefId,
2727
};
2828
use rustc_hir::lang_items::{LangItem, LanguageItems};
29-
use rustc_hir::{Crate, ItemLocalId, ItemLocalMap, TraitCandidate};
29+
use rustc_hir::{Crate, HirIdSet, ItemLocalId, ItemLocalMap, TraitCandidate};
3030
use rustc_index::IndexVec;
3131
use rustc_macros::rustc_queries;
3232
use rustc_query_system::ich::StableHashingContext;
@@ -2274,6 +2274,10 @@ rustc_queries! {
22742274
desc { "whether the item should be made inlinable across crates" }
22752275
separate_provide_extern
22762276
}
2277+
2278+
query extract_tail_expr_consuming_nodes(def_id: DefId) -> &'tcx HirIdSet {
2279+
desc { "extract hir nodes that consumes value" }
2280+
}
22772281
}
22782282

22792283
rustc_query_append! { define_callbacks! }

‎compiler/rustc_middle/src/ty/structural_impls.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ TrivialTypeTraversalImpls! {
264264
// interners).
265265
TrivialTypeTraversalAndLiftImpls! {
266266
::rustc_hir::def_id::DefId,
267+
::rustc_hir::hir_id::ItemLocalId,
267268
::rustc_hir::Safety,
268269
::rustc_target::spec::abi::Abi,
269270
crate::ty::ClosureKind,

‎compiler/rustc_mir_build/src/build/custom/parse/instruction.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
7070
target: self.parse_return_to(args[1])?,
7171
unwind: self.parse_unwind_action(args[2])?,
7272
replace: false,
73+
scope: None,
7374
})
7475
},
7576
@call(mir_call, args) => {

‎compiler/rustc_mir_build/src/build/expr/as_rvalue.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
721721
);
722722
if let Operand::Move(to_drop) = value_operand {
723723
let success = this.cfg.start_new_block();
724+
let scope = scope
725+
.and_then(|scope| scope.hir_id(this.region_scope_tree))
726+
.map(|scope| (scope.owner.to_def_id(), scope.local_id));
724727
this.cfg.terminate(
725728
block,
726729
outer_source_info,
@@ -729,6 +732,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
729732
target: success,
730733
unwind: UnwindAction::Continue,
731734
replace: false,
735+
scope,
732736
},
733737
);
734738
this.diverge_from(block);

‎compiler/rustc_mir_build/src/build/scope.rs

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,9 @@ struct DropData {
151151

152152
/// Whether this is a value Drop or a StorageDead.
153153
kind: DropKind,
154+
155+
/// Scope for which the data is obliged to drop
156+
scope: Option<region::Scope>,
154157
}
155158

156159
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -274,8 +277,12 @@ impl DropTree {
274277
// represents the block in the tree that should be jumped to once all
275278
// of the required drops have been performed.
276279
let fake_source_info = SourceInfo::outermost(DUMMY_SP);
277-
let fake_data =
278-
DropData { source_info: fake_source_info, local: Local::MAX, kind: DropKind::Storage };
280+
let fake_data = DropData {
281+
source_info: fake_source_info,
282+
local: Local::MAX,
283+
kind: DropKind::Storage,
284+
scope: None,
285+
};
279286
let drops = IndexVec::from_raw(vec![DropNode { data: fake_data, next: DropIdx::MAX }]);
280287
Self { drops, entry_points: Vec::new(), existing_drops_map: FxHashMap::default() }
281288
}
@@ -311,12 +318,13 @@ impl DropTree {
311318
&mut self,
312319
cfg: &mut CFG<'tcx>,
313320
blocks: &mut IndexVec<DropIdx, Option<BasicBlock>>,
321+
scope_tree: &region::ScopeTree,
314322
) {
315323
debug!("DropTree::build_mir(drops = {:#?})", self);
316324
assert_eq!(blocks.len(), self.drops.len());
317325

318326
self.assign_blocks::<T>(cfg, blocks);
319-
self.link_blocks(cfg, blocks)
327+
self.link_blocks(cfg, blocks, scope_tree)
320328
}
321329

322330
/// Assign blocks for all of the drops in the drop tree that need them.
@@ -390,17 +398,24 @@ impl DropTree {
390398
&self,
391399
cfg: &mut CFG<'tcx>,
392400
blocks: &IndexSlice<DropIdx, Option<BasicBlock>>,
401+
scope_tree: &region::ScopeTree,
393402
) {
394403
for (drop_idx, drop_node) in self.drops.iter_enumerated().rev() {
395404
let Some(block) = blocks[drop_idx] else { continue };
396405
match drop_node.data.kind {
397406
DropKind::Value => {
407+
let scope = drop_node
408+
.data
409+
.scope
410+
.and_then(|scope| scope.hir_id(scope_tree))
411+
.map(|scope| (scope.owner.to_def_id(), scope.local_id));
398412
let terminator = TerminatorKind::Drop {
399413
target: blocks[drop_node.next].unwrap(),
400414
// The caller will handle this if needed.
401415
unwind: UnwindAction::Terminate(UnwindTerminateReason::InCleanup),
402416
place: drop_node.data.local.into(),
403417
replace: false,
418+
scope,
404419
};
405420
cfg.terminate(block, drop_node.data.source_info, terminator);
406421
}
@@ -767,7 +782,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
767782
let local =
768783
place.as_local().unwrap_or_else(|| bug!("projection in tail call args"));
769784

770-
Some(DropData { source_info, local, kind: DropKind::Value })
785+
Some(DropData { source_info, local, kind: DropKind::Value, scope: None })
771786
}
772787
Operand::Constant(_) => None,
773788
})
@@ -806,6 +821,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
806821
unwind_drops.add_entry_point(block, unwind_entry_point);
807822

808823
let next = self.cfg.start_new_block();
824+
let scope = scope
825+
.region_scope
826+
.hir_id(self.region_scope_tree)
827+
.map(|scope| (scope.owner.to_def_id(), scope.local_id));
809828
self.cfg.terminate(
810829
block,
811830
source_info,
@@ -814,6 +833,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
814833
target: next,
815834
unwind: UnwindAction::Continue,
816835
replace: false,
836+
scope,
817837
},
818838
);
819839
block = next;
@@ -849,6 +869,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
849869
unwind_to,
850870
is_coroutine && needs_cleanup,
851871
self.arg_count,
872+
self.region_scope_tree,
852873
)
853874
.into_block()
854875
}
@@ -1097,6 +1118,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
10971118
source_info: SourceInfo { span: scope_end, scope: scope.source_scope },
10981119
local,
10991120
kind: drop_kind,
1121+
scope: Some(region_scope),
11001122
});
11011123

11021124
return;
@@ -1291,6 +1313,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
12911313
target: assign,
12921314
unwind: UnwindAction::Cleanup(assign_unwind),
12931315
replace: true,
1316+
scope: None,
12941317
},
12951318
);
12961319
self.diverge_from(block);
@@ -1351,6 +1374,7 @@ fn build_scope_drops<'tcx>(
13511374
mut unwind_to: DropIdx,
13521375
storage_dead_on_unwind: bool,
13531376
arg_count: usize,
1377+
scope_tree: &region::ScopeTree,
13541378
) -> BlockAnd<()> {
13551379
debug!("build_scope_drops({:?} -> {:?})", block, scope);
13561380

@@ -1397,6 +1421,10 @@ fn build_scope_drops<'tcx>(
13971421
unwind_drops.add_entry_point(block, unwind_to);
13981422

13991423
let next = cfg.start_new_block();
1424+
let scope = drop_data
1425+
.scope
1426+
.and_then(|scope| scope.hir_id(scope_tree))
1427+
.map(|scope| (scope.owner.to_def_id(), scope.local_id));
14001428
cfg.terminate(
14011429
block,
14021430
source_info,
@@ -1405,6 +1433,7 @@ fn build_scope_drops<'tcx>(
14051433
target: next,
14061434
unwind: UnwindAction::Continue,
14071435
replace: false,
1436+
scope,
14081437
},
14091438
);
14101439
block = next;
@@ -1439,7 +1468,7 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> {
14391468
let mut blocks = IndexVec::from_elem(None, &drops.drops);
14401469
blocks[ROOT_NODE] = continue_block;
14411470

1442-
drops.build_mir::<ExitScopes>(&mut self.cfg, &mut blocks);
1471+
drops.build_mir::<ExitScopes>(&mut self.cfg, &mut blocks, self.region_scope_tree);
14431472
let is_coroutine = self.coroutine.is_some();
14441473

14451474
// Link the exit drop tree to unwind drop tree.
@@ -1486,6 +1515,7 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> {
14861515
&mut self.scopes.unwind_drops,
14871516
self.fn_span,
14881517
&mut None,
1518+
self.region_scope_tree,
14891519
);
14901520
}
14911521
}
@@ -1496,7 +1526,7 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> {
14961526
let cfg = &mut self.cfg;
14971527
let fn_span = self.fn_span;
14981528
let mut blocks = IndexVec::from_elem(None, &drops.drops);
1499-
drops.build_mir::<CoroutineDrop>(cfg, &mut blocks);
1529+
drops.build_mir::<CoroutineDrop>(cfg, &mut blocks, self.region_scope_tree);
15001530
if let Some(root_block) = blocks[ROOT_NODE] {
15011531
cfg.terminate(
15021532
root_block,
@@ -1508,7 +1538,7 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> {
15081538
// Build the drop tree for unwinding in the normal control flow paths.
15091539
let resume_block = &mut None;
15101540
let unwind_drops = &mut self.scopes.unwind_drops;
1511-
Self::build_unwind_tree(cfg, unwind_drops, fn_span, resume_block);
1541+
Self::build_unwind_tree(cfg, unwind_drops, fn_span, resume_block, self.region_scope_tree);
15121542

15131543
// Build the drop tree for unwinding when dropping a suspended
15141544
// coroutine.
@@ -1523,18 +1553,19 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> {
15231553
drops.entry_points.push((drop_node.next, blocks[drop_idx].unwrap()));
15241554
}
15251555
}
1526-
Self::build_unwind_tree(cfg, drops, fn_span, resume_block);
1556+
Self::build_unwind_tree(cfg, drops, fn_span, resume_block, self.region_scope_tree);
15271557
}
15281558

15291559
fn build_unwind_tree(
15301560
cfg: &mut CFG<'tcx>,
15311561
drops: &mut DropTree,
15321562
fn_span: Span,
15331563
resume_block: &mut Option<BasicBlock>,
1564+
scope_tree: &region::ScopeTree,
15341565
) {
15351566
let mut blocks = IndexVec::from_elem(None, &drops.drops);
15361567
blocks[ROOT_NODE] = *resume_block;
1537-
drops.build_mir::<Unwind>(cfg, &mut blocks);
1568+
drops.build_mir::<Unwind>(cfg, &mut blocks, scope_tree);
15381569
if let (None, Some(resume)) = (*resume_block, blocks[ROOT_NODE]) {
15391570
cfg.terminate(resume, SourceInfo::outermost(fn_span), TerminatorKind::UnwindResume);
15401571

‎compiler/rustc_mir_dataflow/src/elaborate_drops.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use std::{fmt, iter};
22

3+
use rustc_hir::def_id::DefId;
34
use rustc_hir::lang_items::LangItem;
5+
use rustc_hir::ItemLocalId;
46
use rustc_index::Idx;
57
use rustc_middle::mir::patch::MirPatch;
68
use rustc_middle::mir::*;
@@ -167,6 +169,10 @@ where
167169
path: D::Path,
168170
succ: BasicBlock,
169171
unwind: Unwind,
172+
173+
/// Scope from which the drop is obliged
174+
/// which is the HIR node for the "scope"
175+
scope: Option<(DefId, ItemLocalId)>,
170176
}
171177

172178
/// "Elaborates" a drop of `place`/`path` and patches `bb`'s terminator to execute it.
@@ -185,11 +191,12 @@ pub fn elaborate_drop<'b, 'tcx, D>(
185191
succ: BasicBlock,
186192
unwind: Unwind,
187193
bb: BasicBlock,
194+
scope: Option<(DefId, ItemLocalId)>,
188195
) where
189196
D: DropElaborator<'b, 'tcx>,
190197
'tcx: 'b,
191198
{
192-
DropCtxt { elaborator, source_info, place, path, succ, unwind }.elaborate_drop(bb)
199+
DropCtxt { elaborator, source_info, place, scope, path, succ, unwind }.elaborate_drop(bb)
193200
}
194201

195202
impl<'a, 'b, 'tcx, D> DropCtxt<'a, 'b, 'tcx, D>
@@ -240,6 +247,7 @@ where
240247
target: self.succ,
241248
unwind: self.unwind.into_action(),
242249
replace: false,
250+
scope: self.scope,
243251
},
244252
);
245253
}
@@ -302,6 +310,7 @@ where
302310
place,
303311
succ,
304312
unwind,
313+
scope: self.scope,
305314
}
306315
.elaborated_drop_block()
307316
} else {
@@ -316,6 +325,7 @@ where
316325
// Using `self.path` here to condition the drop on
317326
// our own drop flag.
318327
path: self.path,
328+
scope: self.scope,
319329
}
320330
.complete_drop(succ, unwind)
321331
}
@@ -739,6 +749,7 @@ where
739749
target: loop_block,
740750
unwind: unwind.into_action(),
741751
replace: false,
752+
scope: self.scope,
742753
},
743754
);
744755

@@ -920,6 +931,7 @@ where
920931
target,
921932
unwind: unwind.into_action(),
922933
replace: false,
934+
scope: self.scope,
923935
};
924936
self.new_block(unwind, block)
925937
}

‎compiler/rustc_mir_dataflow/src/impls/initialized.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,8 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
368368
) -> TerminatorEdges<'mir, 'tcx> {
369369
let mut edges = terminator.edges();
370370
if self.skip_unreachable_unwind
371-
&& let mir::TerminatorKind::Drop { target, unwind, place, replace: _ } = terminator.kind
371+
&& let mir::TerminatorKind::Drop { target, unwind, place, scope: _, replace: _ } =
372+
terminator.kind
372373
&& matches!(unwind, mir::UnwindAction::Cleanup(_))
373374
&& self.is_unwind_dead(place, state)
374375
{

‎compiler/rustc_mir_transform/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ rustc_fluent_macro = { path = "../rustc_fluent_macro" }
1717
rustc_hir = { path = "../rustc_hir" }
1818
rustc_index = { path = "../rustc_index" }
1919
rustc_infer = { path = "../rustc_infer" }
20+
rustc_lint = { path = "../rustc_lint" }
2021
rustc_macros = { path = "../rustc_macros" }
2122
rustc_middle = { path = "../rustc_middle" }
2223
rustc_mir_build = { path = "../rustc_mir_build" }

‎compiler/rustc_mir_transform/messages.ftl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ mir_transform_must_not_suspend = {$pre}`{$def_path}`{$post} held across a suspen
2323
.help = consider using a block (`{"{ ... }"}`) to shrink the value's scope, ending before the suspend point
2424
mir_transform_operation_will_panic = this operation will panic at runtime
2525
26+
mir_transform_tail_expr_drop_order = this value of type `{$ty}` has significant drop implementation that will have a different drop order from that of Edition 2021
27+
.label = these local bindings with significant drop implementation may observe changes in drop order under Edition 2024
28+
2629
mir_transform_unaligned_packed_ref = reference to packed field is unaligned
2730
.note = packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
2831
.note_ub = creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)

‎compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ fn add_move_for_packed_drop<'tcx>(
7979
is_cleanup: bool,
8080
) {
8181
debug!("add_move_for_packed_drop({:?} @ {:?})", terminator, loc);
82-
let TerminatorKind::Drop { ref place, target, unwind, replace } = terminator.kind else {
82+
let TerminatorKind::Drop { ref place, target, unwind, scope: _, replace } = terminator.kind
83+
else {
8384
unreachable!();
8485
};
8586

@@ -102,6 +103,7 @@ fn add_move_for_packed_drop<'tcx>(
102103
target: storage_dead_block,
103104
unwind,
104105
replace,
106+
scope: None,
105107
},
106108
);
107109
}

‎compiler/rustc_mir_transform/src/coroutine.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,15 +1086,15 @@ fn elaborate_coroutine_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
10861086
let mut elaborator = DropShimElaborator { body, patch: MirPatch::new(body), tcx, param_env };
10871087

10881088
for (block, block_data) in body.basic_blocks.iter_enumerated() {
1089-
let (target, unwind, source_info) = match block_data.terminator() {
1089+
let (target, unwind, source_info, &scope) = match block_data.terminator() {
10901090
Terminator {
10911091
source_info,
1092-
kind: TerminatorKind::Drop { place, target, unwind, replace: _ },
1092+
kind: TerminatorKind::Drop { place, target, unwind, scope, replace: _ },
10931093
} => {
10941094
if let Some(local) = place.as_local()
10951095
&& local == SELF_ARG
10961096
{
1097-
(target, unwind, source_info)
1097+
(target, unwind, source_info, scope)
10981098
} else {
10991099
continue;
11001100
}
@@ -1119,6 +1119,7 @@ fn elaborate_coroutine_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
11191119
*target,
11201120
unwind,
11211121
block,
1122+
scope,
11221123
);
11231124
}
11241125
elaborator.patch.apply(body);
@@ -1377,6 +1378,7 @@ fn insert_clean_drop(body: &mut Body<'_>) -> BasicBlock {
13771378
target: return_block,
13781379
unwind: UnwindAction::Continue,
13791380
replace: false,
1381+
scope: None,
13801382
};
13811383
let source_info = SourceInfo::outermost(body.span);
13821384

‎compiler/rustc_mir_transform/src/elaborate_drops.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,8 @@ impl<'a, 'tcx> ElaborateDropsCtxt<'a, 'tcx> {
330330
// This function should mirror what `collect_drop_flags` does.
331331
for (bb, data) in self.body.basic_blocks.iter_enumerated() {
332332
let terminator = data.terminator();
333-
let TerminatorKind::Drop { place, target, unwind, replace } = terminator.kind else {
333+
let TerminatorKind::Drop { place, target, unwind, scope, replace } = terminator.kind
334+
else {
334335
continue;
335336
};
336337

@@ -366,7 +367,16 @@ impl<'a, 'tcx> ElaborateDropsCtxt<'a, 'tcx> {
366367
}
367368
};
368369
self.init_data.seek_before(self.body.terminator_loc(bb));
369-
elaborate_drop(self, terminator.source_info, place, path, target, unwind, bb)
370+
elaborate_drop(
371+
self,
372+
terminator.source_info,
373+
place,
374+
path,
375+
target,
376+
unwind,
377+
bb,
378+
scope,
379+
)
370380
}
371381
LookupResult::Parent(None) => {}
372382
LookupResult::Parent(Some(_)) => {

‎compiler/rustc_mir_transform/src/inline.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -535,7 +535,9 @@ impl<'tcx> Inliner<'tcx> {
535535
checker.visit_basic_block_data(bb, blk);
536536

537537
let term = blk.terminator();
538-
if let TerminatorKind::Drop { ref place, target, unwind, replace: _ } = term.kind {
538+
if let TerminatorKind::Drop { ref place, target, unwind, scope: _, replace: _ } =
539+
term.kind
540+
{
539541
work_list.push(target);
540542

541543
// If the place doesn't actually need dropping, treat it like a regular goto.

‎compiler/rustc_mir_transform/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ mod sanity_check;
102102
mod shim;
103103
mod ssa;
104104
// This pass is public to allow external drivers to perform MIR cleanup
105+
mod lint_tail_expr_drop_order;
105106
pub mod simplify;
106107
mod simplify_branches;
107108
mod simplify_comparison_integral;
@@ -355,6 +356,7 @@ fn mir_promoted(
355356
&[&promote_pass, &simplify::SimplifyCfg::PromoteConsts, &coverage::InstrumentCoverage],
356357
Some(MirPhase::Analysis(AnalysisPhase::Initial)),
357358
);
359+
lint_tail_expr_drop_order::run_lint(tcx, def, &body);
358360

359361
let promoted = promote_pass.promoted_fragments.into_inner();
360362
(tcx.alloc_steal_mir(body), tcx.alloc_steal_promoted(promoted))

‎compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs

Lines changed: 401 additions & 0 deletions
Large diffs are not rendered by default.

‎compiler/rustc_mir_transform/src/shim.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>)
288288
return_block,
289289
elaborate_drops::Unwind::To(resume_block),
290290
START_BLOCK,
291+
None,
291292
);
292293
elaborator.patch
293294
};
@@ -616,6 +617,7 @@ impl<'tcx> CloneShimBuilder<'tcx> {
616617
target: unwind,
617618
unwind: UnwindAction::Terminate(UnwindTerminateReason::InCleanup),
618619
replace: false,
620+
scope: None,
619621
},
620622
/* is_cleanup */ true,
621623
);
@@ -878,6 +880,7 @@ fn build_call_shim<'tcx>(
878880
target: BasicBlock::new(2),
879881
unwind: UnwindAction::Continue,
880882
replace: false,
883+
scope: None,
881884
},
882885
false,
883886
);
@@ -894,6 +897,7 @@ fn build_call_shim<'tcx>(
894897
target: BasicBlock::new(4),
895898
unwind: UnwindAction::Terminate(UnwindTerminateReason::InCleanup),
896899
replace: false,
900+
scope: None,
897901
},
898902
/* is_cleanup */ true,
899903
);

‎compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,7 @@ impl<'tcx> AsyncDestructorCtorShimBuilder<'tcx> {
429429
UnwindTerminateReason::InCleanup,
430430
),
431431
replace: false,
432+
scope: None,
432433
}
433434
} else {
434435
TerminatorKind::Goto { target: *top_cleanup_bb }

‎compiler/rustc_smir/src/rustc_smir/convert/mir.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -621,7 +621,7 @@ impl<'tcx> Stable<'tcx> for mir::TerminatorKind<'tcx> {
621621
mir::TerminatorKind::UnwindTerminate(_) => TerminatorKind::Abort,
622622
mir::TerminatorKind::Return => TerminatorKind::Return,
623623
mir::TerminatorKind::Unreachable => TerminatorKind::Unreachable,
624-
mir::TerminatorKind::Drop { place, target, unwind, replace: _ } => {
624+
mir::TerminatorKind::Drop { place, target, unwind, scope: _, replace: _ } => {
625625
TerminatorKind::Drop {
626626
place: place.stable(tables),
627627
target: target.as_usize(),

‎tests/ui/drop/lint-tail-expr-drop-order.rs

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
//@ compile-flags: -Z unstable-options
2-
//@ edition: 2024
3-
41
// Edition 2024 lint for change in drop order at tail expression
52
// This lint is to capture potential change in program semantics
63
// due to implementation of RFC 3606 <https://github.com/rust-lang/rfcs/pull/3606>
@@ -27,14 +24,32 @@ fn should_lint() -> i32 {
2724
let x = LoudDropper;
2825
// Should lint
2926
x.get() + LoudDropper.get()
30-
//~^ ERROR: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021
27+
//~^ ERROR: this value of type `LoudDropper` has significant drop implementation that will have a different drop order from that of Edition 2021
3128
//~| WARN: this changes meaning in Rust 2024
3229
}
3330

3431
fn should_lint_closure() -> impl FnOnce() -> i32 {
3532
let x = LoudDropper;
36-
move || x.get() + LoudDropper.get()
37-
//~^ ERROR: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021
33+
move || {
34+
x.get() + LoudDropper.get()
35+
//~^ ERROR: this value of type `LoudDropper` has significant drop implementation that will have a different drop order from that of Edition 2021
36+
//~| WARN: this changes meaning in Rust 2024
37+
}
38+
}
39+
40+
fn should_lint_in_nested_items() {
41+
fn should_lint_me() -> i32 {
42+
let x = LoudDropper;
43+
// Should lint
44+
x.get() + LoudDropper.get()
45+
//~^ ERROR: this value of type `LoudDropper` has significant drop implementation that will have a different drop order from that of Edition 2021
46+
//~| WARN: this changes meaning in Rust 2024
47+
}
48+
}
49+
50+
fn should_lint_params(x: LoudDropper) -> i32 {
51+
x.get() + LoudDropper.get()
52+
//~^ ERROR: this value of type `LoudDropper` has significant drop implementation that will have a different drop order from that of Edition 2021
3853
//~| WARN: this changes meaning in Rust 2024
3954
}
4055

@@ -44,10 +59,11 @@ fn should_not_lint() -> i32 {
4459
x.get()
4560
}
4661

47-
fn should_not_lint_in_nested_block() -> i32 {
62+
fn should_lint_in_nested_block() -> i32 {
4863
let x = LoudDropper;
49-
// Should not lint because Edition 2021 drops temporaries in blocks earlier already
5064
{ LoudDropper.get() }
65+
//~^ ERROR: this value of type `LoudDropper` has significant drop implementation that will have a different drop order from that of Edition 2021
66+
//~| WARN: this changes meaning in Rust 2024
5167
}
5268

5369
fn should_not_lint_in_match_arm() -> i32 {
@@ -58,14 +74,28 @@ fn should_not_lint_in_match_arm() -> i32 {
5874
}
5975
}
6076

61-
fn should_lint_in_nested_items() {
62-
fn should_lint_me() -> i32 {
63-
let x = LoudDropper;
64-
// Should lint
65-
x.get() + LoudDropper.get()
66-
//~^ ERROR: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021
67-
//~| WARN: this changes meaning in Rust 2024
68-
}
77+
fn should_not_lint_when_consumed() -> (LoudDropper, i32) {
78+
let x = LoudDropper;
79+
// Should not lint
80+
(LoudDropper, x.get())
81+
}
82+
83+
struct MyAdt {
84+
a: LoudDropper,
85+
b: LoudDropper,
86+
}
87+
88+
fn should_not_lint_when_consumed_in_ctor() -> MyAdt {
89+
let a = LoudDropper;
90+
// Should not lint
91+
MyAdt { a, b: LoudDropper }
92+
}
93+
94+
fn should_not_lint_when_moved() -> i32 {
95+
let x = LoudDropper;
96+
drop(x);
97+
// Should not lint
98+
LoudDropper.get()
6999
}
70100

71101
fn main() {}
Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,69 @@
1-
error: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021
2-
--> $DIR/lint-tail-expr-drop-order.rs:29:15
1+
error: this value of type `LoudDropper` has significant drop implementation that will have a different drop order from that of Edition 2021
2+
--> $DIR/lint-tail-expr-drop-order.rs:34:19
33
|
4-
LL | let x = LoudDropper;
5-
| - these values have significant drop implementation and will observe changes in drop order under Edition 2024
6-
LL | // Should lint
7-
LL | x.get() + LoudDropper.get()
8-
| ^^^^^^^^^^^
4+
LL | let x = LoudDropper;
5+
| - these local bindings with significant drop implementation may observe changes in drop order under Edition 2024
6+
LL | / move || {
7+
LL | | x.get() + LoudDropper.get()
8+
| | ^^^^^^^^^^^
9+
LL | |
10+
LL | |
11+
LL | | }
12+
| |_____- these local bindings with significant drop implementation may observe changes in drop order under Edition 2024
913
|
1014
= warning: this changes meaning in Rust 2024
1115
= note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739>
1216
note: the lint level is defined here
13-
--> $DIR/lint-tail-expr-drop-order.rs:8:9
17+
--> $DIR/lint-tail-expr-drop-order.rs:5:9
1418
|
1519
LL | #![deny(tail_expr_drop_order)]
1620
| ^^^^^^^^^^^^^^^^^^^^
1721

18-
error: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021
19-
--> $DIR/lint-tail-expr-drop-order.rs:36:23
22+
error: this value of type `LoudDropper` has significant drop implementation that will have a different drop order from that of Edition 2021
23+
--> $DIR/lint-tail-expr-drop-order.rs:26:15
2024
|
2125
LL | let x = LoudDropper;
22-
| - these values have significant drop implementation and will observe changes in drop order under Edition 2024
23-
LL | move || x.get() + LoudDropper.get()
24-
| ^^^^^^^^^^^
26+
| - these local bindings with significant drop implementation may observe changes in drop order under Edition 2024
27+
LL | // Should lint
28+
LL | x.get() + LoudDropper.get()
29+
| ^^^^^^^^^^^
2530
|
2631
= warning: this changes meaning in Rust 2024
2732
= note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739>
2833

29-
error: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021
30-
--> $DIR/lint-tail-expr-drop-order.rs:65:19
34+
error: this value of type `LoudDropper` has significant drop implementation that will have a different drop order from that of Edition 2021
35+
--> $DIR/lint-tail-expr-drop-order.rs:44:19
3136
|
3237
LL | let x = LoudDropper;
33-
| - these values have significant drop implementation and will observe changes in drop order under Edition 2024
38+
| - these local bindings with significant drop implementation may observe changes in drop order under Edition 2024
3439
LL | // Should lint
3540
LL | x.get() + LoudDropper.get()
3641
| ^^^^^^^^^^^
3742
|
3843
= warning: this changes meaning in Rust 2024
3944
= note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739>
4045

41-
error: aborting due to 3 previous errors
46+
error: this value of type `LoudDropper` has significant drop implementation that will have a different drop order from that of Edition 2021
47+
--> $DIR/lint-tail-expr-drop-order.rs:51:15
48+
|
49+
LL | fn should_lint_params(x: LoudDropper) -> i32 {
50+
| - these local bindings with significant drop implementation may observe changes in drop order under Edition 2024
51+
LL | x.get() + LoudDropper.get()
52+
| ^^^^^^^^^^^
53+
|
54+
= warning: this changes meaning in Rust 2024
55+
= note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739>
56+
57+
error: this value of type `LoudDropper` has significant drop implementation that will have a different drop order from that of Edition 2021
58+
--> $DIR/lint-tail-expr-drop-order.rs:64:7
59+
|
60+
LL | let x = LoudDropper;
61+
| - these local bindings with significant drop implementation may observe changes in drop order under Edition 2024
62+
LL | { LoudDropper.get() }
63+
| ^^^^^^^^^^^
64+
|
65+
= warning: this changes meaning in Rust 2024
66+
= note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739>
67+
68+
error: aborting due to 5 previous errors
4269

0 commit comments

Comments
 (0)
Please sign in to comment.