Skip to content

Commit a580b5c

Browse files
committedJan 8, 2025
Auto merge of #134523 - dingxiangfei2009:issue-130836-attempt-2, r=nikomatsakis
Run borrowck tests on BIDs and emit tail-expr-drop-order lints for violations Fix #132861 r? `@nikomatsakis` cc `@compiler-errors` This patch enlarges the scope where the `tail-expr-drop-order` lint applies, so that all locals involved in tail expressions are inspected. This is necessary to run borrow-checking to capture the cases where it used to compile under Edition 2021 but is not going to pass borrow-checking from Edition 2024 onwards. The way it works is to inspect each BID against the set of borrows that are still live. If the local involved in BID has a borrow index which happens to be live as well at the location of this BID statement, in the future this will be a borrow-checking violation. The lint will fire in this case.
·
1.88.01.86.0
2 parents 6afee11 + c55eefe commit a580b5c

17 files changed

+307
-53
lines changed
 

‎compiler/rustc_borrowck/messages.ftl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,10 @@ borrowck_suggest_create_fresh_reborrow =
213213
borrowck_suggest_iterate_over_slice =
214214
consider iterating over a slice of the `{$ty}`'s content to avoid moving into the `for` loop
215215
216+
borrowck_tail_expr_drop_order = relative drop order changing in Rust 2024
217+
.label = this temporary value will be dropped at the end of the block
218+
.note = consider using a `let` binding to ensure the value will live long enough
219+
216220
borrowck_ty_no_impl_copy =
217221
{$is_partial_move ->
218222
[true] partial move

‎compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
use std::assert_matches::assert_matches;
77

8-
use rustc_errors::{Applicability, Diag};
8+
use rustc_errors::{Applicability, Diag, EmissionGuarantee};
99
use rustc_hir as hir;
1010
use rustc_hir::intravisit::Visitor;
1111
use rustc_infer::infer::NllRegionVariableOrigin;
@@ -61,10 +61,10 @@ impl<'tcx> BorrowExplanation<'tcx> {
6161
pub(crate) fn is_explained(&self) -> bool {
6262
!matches!(self, BorrowExplanation::Unexplained)
6363
}
64-
pub(crate) fn add_explanation_to_diagnostic(
64+
pub(crate) fn add_explanation_to_diagnostic<G: EmissionGuarantee>(
6565
&self,
6666
cx: &MirBorrowckCtxt<'_, '_, 'tcx>,
67-
err: &mut Diag<'_>,
67+
err: &mut Diag<'_, G>,
6868
borrow_desc: &str,
6969
borrow_span: Option<Span>,
7070
multiple_borrow_span: Option<(Span, Span)>,
@@ -346,10 +346,10 @@ impl<'tcx> BorrowExplanation<'tcx> {
346346
}
347347
}
348348

349-
fn add_object_lifetime_default_note(
349+
fn add_object_lifetime_default_note<G: EmissionGuarantee>(
350350
&self,
351351
tcx: TyCtxt<'tcx>,
352-
err: &mut Diag<'_>,
352+
err: &mut Diag<'_, G>,
353353
unsize_ty: Ty<'tcx>,
354354
) {
355355
if let ty::Adt(def, args) = unsize_ty.kind() {
@@ -403,9 +403,9 @@ impl<'tcx> BorrowExplanation<'tcx> {
403403
}
404404
}
405405

406-
fn add_lifetime_bound_suggestion_to_diagnostic(
406+
fn add_lifetime_bound_suggestion_to_diagnostic<G: EmissionGuarantee>(
407407
&self,
408-
err: &mut Diag<'_>,
408+
err: &mut Diag<'_, G>,
409409
category: &ConstraintCategory<'tcx>,
410410
span: Span,
411411
region_name: &RegionName,
@@ -432,14 +432,14 @@ impl<'tcx> BorrowExplanation<'tcx> {
432432
}
433433
}
434434

435-
fn suggest_rewrite_if_let(
435+
fn suggest_rewrite_if_let<G: EmissionGuarantee>(
436436
tcx: TyCtxt<'_>,
437437
expr: &hir::Expr<'_>,
438438
pat: &str,
439439
init: &hir::Expr<'_>,
440440
conseq: &hir::Expr<'_>,
441441
alt: Option<&hir::Expr<'_>>,
442-
err: &mut Diag<'_>,
442+
err: &mut Diag<'_, G>,
443443
) {
444444
let source_map = tcx.sess.source_map();
445445
err.span_note(

‎compiler/rustc_borrowck/src/diagnostics/mod.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::collections::BTreeMap;
44

55
use rustc_abi::{FieldIdx, VariantIdx};
66
use rustc_data_structures::fx::FxIndexMap;
7-
use rustc_errors::{Applicability, Diag, MultiSpan};
7+
use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan};
88
use rustc_hir::def::{CtorKind, Namespace};
99
use rustc_hir::{self as hir, CoroutineKind, LangItem};
1010
use rustc_index::IndexSlice;
@@ -626,9 +626,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
626626

627627
/// Add a note to region errors and borrow explanations when higher-ranked regions in predicates
628628
/// implicitly introduce an "outlives `'static`" constraint.
629-
fn add_placeholder_from_predicate_note(
629+
fn add_placeholder_from_predicate_note<G: EmissionGuarantee>(
630630
&self,
631-
err: &mut Diag<'_>,
631+
err: &mut Diag<'_, G>,
632632
path: &[OutlivesConstraint<'tcx>],
633633
) {
634634
let predicate_span = path.iter().find_map(|constraint| {
@@ -651,9 +651,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
651651

652652
/// Add a label to region errors and borrow explanations when outlives constraints arise from
653653
/// proving a type implements `Sized` or `Copy`.
654-
fn add_sized_or_copy_bound_info(
654+
fn add_sized_or_copy_bound_info<G: EmissionGuarantee>(
655655
&self,
656-
err: &mut Diag<'_>,
656+
err: &mut Diag<'_, G>,
657657
blamed_category: ConstraintCategory<'tcx>,
658658
path: &[OutlivesConstraint<'tcx>],
659659
) {
@@ -1042,6 +1042,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
10421042
kind,
10431043
};
10441044
}
1045+
10451046
normal_ret
10461047
}
10471048

‎compiler/rustc_borrowck/src/diagnostics/region_name.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::fmt::{self, Display};
55
use std::iter;
66

77
use rustc_data_structures::fx::IndexEntry;
8-
use rustc_errors::Diag;
8+
use rustc_errors::{Diag, EmissionGuarantee};
99
use rustc_hir as hir;
1010
use rustc_hir::def::{DefKind, Res};
1111
use rustc_middle::ty::print::RegionHighlightMode;
@@ -108,7 +108,7 @@ impl RegionName {
108108
}
109109
}
110110

111-
pub(crate) fn highlight_region_name(&self, diag: &mut Diag<'_>) {
111+
pub(crate) fn highlight_region_name<G: EmissionGuarantee>(&self, diag: &mut Diag<'_, G>) {
112112
match &self.source {
113113
RegionNameSource::NamedLateParamRegion(span)
114114
| RegionNameSource::NamedEarlyParamRegion(span) => {

‎compiler/rustc_borrowck/src/lib.rs

Lines changed: 82 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,17 @@
1616
#![warn(unreachable_pub)]
1717
// tidy-alphabetical-end
1818

19+
use std::borrow::Cow;
1920
use std::cell::RefCell;
2021
use std::marker::PhantomData;
2122
use std::ops::{ControlFlow, Deref};
2223

2324
use rustc_abi::FieldIdx;
2425
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
2526
use rustc_data_structures::graph::dominators::Dominators;
27+
use rustc_errors::LintDiagnostic;
2628
use rustc_hir as hir;
29+
use rustc_hir::CRATE_HIR_ID;
2730
use rustc_hir::def_id::LocalDefId;
2831
use rustc_index::bit_set::{BitSet, MixedBitSet};
2932
use rustc_index::{IndexSlice, IndexVec};
@@ -43,7 +46,7 @@ use rustc_mir_dataflow::move_paths::{
4346
InitIndex, InitLocation, LookupResult, MoveData, MovePathIndex,
4447
};
4548
use rustc_mir_dataflow::{Analysis, EntryStates, Results, ResultsVisitor, visit_results};
46-
use rustc_session::lint::builtin::UNUSED_MUT;
49+
use rustc_session::lint::builtin::{TAIL_EXPR_DROP_ORDER, UNUSED_MUT};
4750
use rustc_span::{Span, Symbol};
4851
use smallvec::SmallVec;
4952
use tracing::{debug, instrument};
@@ -636,9 +639,11 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<
636639
| StatementKind::Coverage(..)
637640
// These do not actually affect borrowck
638641
| StatementKind::ConstEvalCounter
639-
// This do not affect borrowck
640-
| StatementKind::BackwardIncompatibleDropHint { .. }
641642
| StatementKind::StorageLive(..) => {}
643+
// This does not affect borrowck
644+
StatementKind::BackwardIncompatibleDropHint { place, reason: BackwardIncompatibleDropReason::Edition2024 } => {
645+
self.check_backward_incompatible_drop(location, (**place, span), state);
646+
}
642647
StatementKind::StorageDead(local) => {
643648
self.access_place(
644649
location,
@@ -1007,6 +1012,24 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
10071012
}
10081013
}
10091014

1015+
fn borrows_in_scope<'s>(
1016+
&self,
1017+
location: Location,
1018+
state: &'s BorrowckDomain,
1019+
) -> Cow<'s, BitSet<BorrowIndex>> {
1020+
if let Some(polonius) = &self.polonius_output {
1021+
// Use polonius output if it has been enabled.
1022+
let location = self.location_table.start_index(location);
1023+
let mut polonius_output = BitSet::new_empty(self.borrow_set.len());
1024+
for &idx in polonius.errors_at(location) {
1025+
polonius_output.insert(idx);
1026+
}
1027+
Cow::Owned(polonius_output)
1028+
} else {
1029+
Cow::Borrowed(&state.borrows)
1030+
}
1031+
}
1032+
10101033
#[instrument(level = "debug", skip(self, state))]
10111034
fn check_access_for_conflict(
10121035
&mut self,
@@ -1018,18 +1041,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
10181041
) -> bool {
10191042
let mut error_reported = false;
10201043

1021-
// Use polonius output if it has been enabled.
1022-
let mut polonius_output;
1023-
let borrows_in_scope = if let Some(polonius) = &self.polonius_output {
1024-
let location = self.location_table.start_index(location);
1025-
polonius_output = BitSet::new_empty(self.borrow_set.len());
1026-
for &idx in polonius.errors_at(location) {
1027-
polonius_output.insert(idx);
1028-
}
1029-
&polonius_output
1030-
} else {
1031-
&state.borrows
1032-
};
1044+
let borrows_in_scope = self.borrows_in_scope(location, state);
10331045

10341046
each_borrow_involving_path(
10351047
self,
@@ -1149,6 +1161,61 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
11491161
error_reported
11501162
}
11511163

1164+
/// Through #123739, backward incompatible drops (BIDs) are introduced.
1165+
/// We would like to emit lints whether borrow checking fails at these future drop locations.
1166+
#[instrument(level = "debug", skip(self, state))]
1167+
fn check_backward_incompatible_drop(
1168+
&mut self,
1169+
location: Location,
1170+
(place, place_span): (Place<'tcx>, Span),
1171+
state: &BorrowckDomain,
1172+
) {
1173+
let tcx = self.infcx.tcx;
1174+
// If this type does not need `Drop`, then treat it like a `StorageDead`.
1175+
// This is needed because we track the borrows of refs to thread locals,
1176+
// and we'll ICE because we don't track borrows behind shared references.
1177+
let sd = if place.ty(self.body, tcx).ty.needs_drop(tcx, self.body.typing_env(tcx)) {
1178+
AccessDepth::Drop
1179+
} else {
1180+
AccessDepth::Shallow(None)
1181+
};
1182+
1183+
let borrows_in_scope = self.borrows_in_scope(location, state);
1184+
1185+
// This is a very simplified version of `Self::check_access_for_conflict`.
1186+
// We are here checking on BIDs and specifically still-live borrows of data involving the BIDs.
1187+
each_borrow_involving_path(
1188+
self,
1189+
self.infcx.tcx,
1190+
self.body,
1191+
(sd, place),
1192+
self.borrow_set,
1193+
|borrow_index| borrows_in_scope.contains(borrow_index),
1194+
|this, _borrow_index, borrow| {
1195+
if matches!(borrow.kind, BorrowKind::Fake(_)) {
1196+
return ControlFlow::Continue(());
1197+
}
1198+
let borrowed = this.retrieve_borrow_spans(borrow).var_or_use_path_span();
1199+
let explain = this.explain_why_borrow_contains_point(
1200+
location,
1201+
borrow,
1202+
Some((WriteKind::StorageDeadOrDrop, place)),
1203+
);
1204+
this.infcx.tcx.node_span_lint(
1205+
TAIL_EXPR_DROP_ORDER,
1206+
CRATE_HIR_ID,
1207+
borrowed,
1208+
|diag| {
1209+
session_diagnostics::TailExprDropOrder { borrowed }.decorate_lint(diag);
1210+
explain.add_explanation_to_diagnostic(&this, diag, "", None, None);
1211+
},
1212+
);
1213+
// We may stop at the first case
1214+
ControlFlow::Break(())
1215+
},
1216+
);
1217+
}
1218+
11521219
fn mutate_place(
11531220
&mut self,
11541221
location: Location,

‎compiler/rustc_borrowck/src/session_diagnostics.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,3 +480,10 @@ pub(crate) struct SimdIntrinsicArgConst {
480480
pub arg: usize,
481481
pub intrinsic: String,
482482
}
483+
484+
#[derive(LintDiagnostic)]
485+
#[diag(borrowck_tail_expr_drop_order)]
486+
pub(crate) struct TailExprDropOrder {
487+
#[label]
488+
pub borrowed: Span,
489+
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1131,15 +1131,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
11311131

11321132
/// Schedule emission of a backwards incompatible drop lint hint.
11331133
/// Applicable only to temporary values for now.
1134+
#[instrument(level = "debug", skip(self))]
11341135
pub(crate) fn schedule_backwards_incompatible_drop(
11351136
&mut self,
11361137
span: Span,
11371138
region_scope: region::Scope,
11381139
local: Local,
11391140
) {
1140-
if !self.local_decls[local].ty.has_significant_drop(self.tcx, self.typing_env()) {
1141-
return;
1142-
}
1141+
// Note that we are *not* gating BIDs here on whether they have significant destructor.
1142+
// We need to know all of them so that we can capture potential borrow-checking errors.
11431143
for scope in self.scopes.scopes.iter_mut().rev() {
11441144
// Since we are inserting linting MIR statement, we have to invalidate the caches
11451145
scope.invalidate_cache();

‎compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,14 +351,19 @@ pub(crate) fn run_lint<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body<
351351
{
352352
return;
353353
}
354+
355+
// FIXME(typing_env): This should be able to reveal the opaques local to the
356+
// body using the typeck results.
357+
let typing_env = ty::TypingEnv::non_body_analysis(tcx, def_id);
358+
354359
// ## About BIDs in blocks ##
355360
// Track the set of blocks that contain a backwards-incompatible drop (BID)
356361
// and, for each block, the vector of locations.
357362
//
358363
// We group them per-block because they tend to scheduled in the same drop ladder block.
359364
let mut bid_per_block = IndexMap::default();
360365
let mut bid_places = UnordSet::new();
361-
let typing_env = ty::TypingEnv::post_analysis(tcx, def_id);
366+
362367
let mut ty_dropped_components = UnordMap::default();
363368
for (block, data) in body.basic_blocks.iter_enumerated() {
364369
for (statement_index, stmt) in data.statements.iter().enumerate() {

‎tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-abort.mir

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ fn method_1(_1: Guard) -> () {
7474

7575
bb7: {
7676
backward incompatible drop(_2);
77+
backward incompatible drop(_4);
7778
backward incompatible drop(_5);
7879
goto -> bb21;
7980
}

‎tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-unwind.mir

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ fn method_1(_1: Guard) -> () {
7474

7575
bb7: {
7676
backward incompatible drop(_2);
77+
backward incompatible drop(_4);
7778
backward incompatible drop(_5);
7879
goto -> bb21;
7980
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Edition 2024 lint for change in drop order at tail expression
2+
// This lint is to capture potential borrow-checking errors
3+
// due to implementation of RFC 3606 <https://github.com/rust-lang/rfcs/pull/3606>
4+
//@ edition: 2021
5+
6+
#![deny(tail_expr_drop_order)] //~ NOTE: the lint level is defined here
7+
8+
fn should_lint_with_potential_borrowck_err() {
9+
let _ = { String::new().as_str() }.len();
10+
//~^ ERROR: relative drop order changing
11+
//~| WARN: this changes meaning in Rust 2024
12+
//~| NOTE: this temporary value will be dropped at the end of the block
13+
//~| borrow later used by call
14+
//~| NOTE: for more information, see
15+
}
16+
17+
fn should_lint_with_unsafe_block() {
18+
fn f(_: usize) {}
19+
f(unsafe { String::new().as_str() }.len());
20+
//~^ ERROR: relative drop order changing
21+
//~| WARN: this changes meaning in Rust 2024
22+
//~| NOTE: this temporary value will be dropped at the end of the block
23+
//~| borrow later used by call
24+
//~| NOTE: for more information, see
25+
}
26+
27+
#[rustfmt::skip]
28+
fn should_lint_with_big_block() {
29+
fn f<T>(_: T) {}
30+
f({
31+
&mut || 0
32+
//~^ ERROR: relative drop order changing
33+
//~| WARN: this changes meaning in Rust 2024
34+
//~| NOTE: this temporary value will be dropped at the end of the block
35+
//~| borrow later used here
36+
//~| NOTE: for more information, see
37+
})
38+
}
39+
40+
fn another_temp_that_is_copy_in_arg() {
41+
fn f() {}
42+
fn g(_: &()) {}
43+
g({ &f() });
44+
//~^ ERROR: relative drop order changing
45+
//~| WARN: this changes meaning in Rust 2024
46+
//~| NOTE: this temporary value will be dropped at the end of the block
47+
//~| borrow later used by call
48+
//~| NOTE: for more information, see
49+
}
50+
51+
fn main() {}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
error: relative drop order changing in Rust 2024
2+
--> $DIR/lint-tail-expr-drop-order-borrowck.rs:9:15
3+
|
4+
LL | let _ = { String::new().as_str() }.len();
5+
| ^^^^^^^^^^^^^ --- borrow later used by call
6+
| |
7+
| this temporary value will be dropped at the end of the block
8+
|
9+
= warning: this changes meaning in Rust 2024
10+
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
11+
note: the lint level is defined here
12+
--> $DIR/lint-tail-expr-drop-order-borrowck.rs:6:9
13+
|
14+
LL | #![deny(tail_expr_drop_order)]
15+
| ^^^^^^^^^^^^^^^^^^^^
16+
17+
error: relative drop order changing in Rust 2024
18+
--> $DIR/lint-tail-expr-drop-order-borrowck.rs:19:16
19+
|
20+
LL | f(unsafe { String::new().as_str() }.len());
21+
| ^^^^^^^^^^^^^ --- borrow later used by call
22+
| |
23+
| this temporary value will be dropped at the end of the block
24+
|
25+
= warning: this changes meaning in Rust 2024
26+
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
27+
28+
error: relative drop order changing in Rust 2024
29+
--> $DIR/lint-tail-expr-drop-order-borrowck.rs:31:9
30+
|
31+
LL | &mut || 0
32+
| ^^^^^^^^^
33+
| |
34+
| this temporary value will be dropped at the end of the block
35+
| borrow later used here
36+
|
37+
= warning: this changes meaning in Rust 2024
38+
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
39+
40+
error: relative drop order changing in Rust 2024
41+
--> $DIR/lint-tail-expr-drop-order-borrowck.rs:43:9
42+
|
43+
LL | g({ &f() });
44+
| - ^^^^ this temporary value will be dropped at the end of the block
45+
| |
46+
| borrow later used by call
47+
|
48+
= warning: this changes meaning in Rust 2024
49+
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
50+
51+
error: aborting due to 4 previous errors
52+

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ impl Drop for LoudDropper {
1717
//~| NOTE: `#1` invokes this custom destructor
1818
//~| NOTE: `x` invokes this custom destructor
1919
//~| NOTE: `#1` invokes this custom destructor
20-
//~| NOTE: `future` invokes this custom destructor
2120
//~| NOTE: `_x` invokes this custom destructor
2221
//~| NOTE: `#1` invokes this custom destructor
2322
fn drop(&mut self) {

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

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: relative drop order changing in Rust 2024
2-
--> $DIR/lint-tail-expr-drop-order.rs:41:15
2+
--> $DIR/lint-tail-expr-drop-order.rs:40:15
33
|
44
LL | let x = LoudDropper;
55
| -
@@ -40,7 +40,7 @@ LL | #![deny(tail_expr_drop_order)]
4040
| ^^^^^^^^^^^^^^^^^^^^
4141

4242
error: relative drop order changing in Rust 2024
43-
--> $DIR/lint-tail-expr-drop-order.rs:66:19
43+
--> $DIR/lint-tail-expr-drop-order.rs:65:19
4444
|
4545
LL | let x = LoudDropper;
4646
| -
@@ -76,7 +76,7 @@ LL | | }
7676
= note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
7777

7878
error: relative drop order changing in Rust 2024
79-
--> $DIR/lint-tail-expr-drop-order.rs:93:7
79+
--> $DIR/lint-tail-expr-drop-order.rs:92:7
8080
|
8181
LL | let x = LoudDropper;
8282
| -
@@ -112,7 +112,7 @@ LL | | }
112112
= note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
113113

114114
error: relative drop order changing in Rust 2024
115-
--> $DIR/lint-tail-expr-drop-order.rs:146:5
115+
--> $DIR/lint-tail-expr-drop-order.rs:145:5
116116
|
117117
LL | let future = f();
118118
| ------
@@ -136,19 +136,12 @@ note: `#1` invokes this custom destructor
136136
|
137137
LL | / impl Drop for LoudDropper {
138138
... |
139-
LL | | }
140-
| |_^
141-
note: `future` invokes this custom destructor
142-
--> $DIR/lint-tail-expr-drop-order.rs:10:1
143-
|
144-
LL | / impl Drop for LoudDropper {
145-
... |
146139
LL | | }
147140
| |_^
148141
= note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
149142

150143
error: relative drop order changing in Rust 2024
151-
--> $DIR/lint-tail-expr-drop-order.rs:163:14
144+
--> $DIR/lint-tail-expr-drop-order.rs:162:14
152145
|
153146
LL | let x = T::default();
154147
| -
@@ -170,7 +163,7 @@ LL | }
170163
= note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
171164

172165
error: relative drop order changing in Rust 2024
173-
--> $DIR/lint-tail-expr-drop-order.rs:177:5
166+
--> $DIR/lint-tail-expr-drop-order.rs:176:5
174167
|
175168
LL | let x: Result<LoudDropper, ()> = Ok(LoudDropper);
176169
| -
@@ -206,7 +199,7 @@ LL | | }
206199
= note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
207200

208201
error: relative drop order changing in Rust 2024
209-
--> $DIR/lint-tail-expr-drop-order.rs:221:5
202+
--> $DIR/lint-tail-expr-drop-order.rs:220:5
210203
|
211204
LL | let x = LoudDropper2;
212205
| -
@@ -226,7 +219,7 @@ LL | }
226219
= warning: this changes meaning in Rust 2024
227220
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
228221
note: `#1` invokes this custom destructor
229-
--> $DIR/lint-tail-expr-drop-order.rs:194:5
222+
--> $DIR/lint-tail-expr-drop-order.rs:193:5
230223
|
231224
LL | / impl Drop for LoudDropper3 {
232225
LL | |
@@ -236,7 +229,7 @@ LL | | }
236229
LL | | }
237230
| |_____^
238231
note: `x` invokes this custom destructor
239-
--> $DIR/lint-tail-expr-drop-order.rs:206:5
232+
--> $DIR/lint-tail-expr-drop-order.rs:205:5
240233
|
241234
LL | / impl Drop for LoudDropper2 {
242235
LL | |
@@ -248,7 +241,7 @@ LL | | }
248241
= note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
249242

250243
error: relative drop order changing in Rust 2024
251-
--> $DIR/lint-tail-expr-drop-order.rs:234:13
244+
--> $DIR/lint-tail-expr-drop-order.rs:233:13
252245
|
253246
LL | LoudDropper.get()
254247
| ^^^^^^^^^^^

‎tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.stderr

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,14 @@ error: relative drop order changing in Rust 2024
44
LL | match func().await {
55
| ^^^^^^^-----
66
| | |
7+
| | this value will be stored in a temporary; let us call it `#3`
8+
| | up until Edition 2021 `#3` is dropped last but will be dropped earlier in Edition 2024
79
| | this value will be stored in a temporary; let us call it `#1`
810
| | `#1` will be dropped later as of Edition 2024
911
| this value will be stored in a temporary; let us call it `#2`
1012
| up until Edition 2021 `#2` is dropped last but will be dropped earlier in Edition 2024
13+
| `__awaitee` calls a custom destructor
14+
| `__awaitee` will be dropped later as of Edition 2024
1115
...
1216
LL | Err(e) => {}
1317
| -
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//@ edition: 2021
2+
//@ check-pass
3+
4+
// Make sure we don't cycle error when normalizing types for tail expr drop order lint.
5+
6+
#![deny(tail_expr_drop_order)]
7+
8+
async fn test() -> Result<(), Box<dyn std::error::Error>> {
9+
Box::pin(test()).await?;
10+
Ok(())
11+
}
12+
13+
fn main() {}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//@ check-pass
2+
3+
#![feature(thread_local)]
4+
#![deny(tail_expr_drop_order)]
5+
6+
use std::marker::PhantomData;
7+
use std::ops::{Deref, DerefMut};
8+
9+
pub struct Global;
10+
11+
#[thread_local]
12+
static REENTRANCY_STATE: State<Global> = State { marker: PhantomData, controller: Global };
13+
14+
pub struct Token(PhantomData<*mut ()>);
15+
16+
pub fn with_mut<T>(f: impl FnOnce(&mut Token) -> T) -> T {
17+
f(&mut REENTRANCY_STATE.borrow_mut())
18+
}
19+
20+
pub struct State<T: ?Sized = Global> {
21+
marker: PhantomData<*mut ()>,
22+
controller: T,
23+
}
24+
25+
impl<T: ?Sized> State<T> {
26+
pub fn borrow_mut(&self) -> TokenMut<'_, T> {
27+
todo!()
28+
}
29+
}
30+
31+
pub struct TokenMut<'a, T: ?Sized = Global> {
32+
state: &'a State<T>,
33+
token: Token,
34+
}
35+
36+
impl<T> Deref for TokenMut<'_, T> {
37+
type Target = Token;
38+
39+
fn deref(&self) -> &Self::Target {
40+
todo!()
41+
}
42+
}
43+
44+
impl<T> DerefMut for TokenMut<'_, T> {
45+
fn deref_mut(&mut self) -> &mut Self::Target {
46+
todo!()
47+
}
48+
}
49+
50+
impl<T: ?Sized> Drop for TokenMut<'_, T> {
51+
fn drop(&mut self) {
52+
todo!()
53+
}
54+
}
55+
56+
fn main() {}

0 commit comments

Comments
 (0)
Please sign in to comment.