diff --git a/compiler/rustc_mir_transform/messages.ftl b/compiler/rustc_mir_transform/messages.ftl index df12673b9f9b0..c1316f616c309 100644 --- a/compiler/rustc_mir_transform/messages.ftl +++ b/compiler/rustc_mir_transform/messages.ftl @@ -27,8 +27,8 @@ mir_transform_operation_will_panic = this operation will panic at runtime mir_transform_tail_expr_drop_order = this value has significant drop implementation that will have a different drop order from that of Edition 2021, whose type `{$ty}` drops `{$ty_drop_components}` while dropping .label = this local binding may observe changes in drop order under Edition 2024, whose type `{$observer_ty}` drops `{$observer_ty_drop_components}` while dropping - .note_ty = these are the types with significant drop implementation - .note_observer_ty = these are the types with significant drop implementation that may be sensitive the the change in the drop order + .note_ty = these are the types and values with significant drop implementation + .note_observer_ty = these are the types and values with significant drop implementation that are from Edition 2024 dropped earlier rather than later mir_transform_unaligned_packed_ref = reference to packed field is unaligned .note = packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index db8915190b5a5..9a0dc2d6b181f 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -359,7 +359,6 @@ fn mir_promoted( &[&promote_pass, &simplify::SimplifyCfg::PromoteConsts, &coverage::InstrumentCoverage], Some(MirPhase::Analysis(AnalysisPhase::Initial)), ); - lint_tail_expr_drop_order::run_lint(tcx, def, &body); let promoted = promote_pass.promoted_fragments.into_inner(); (tcx.alloc_steal_mir(body), tcx.alloc_steal_promoted(promoted)) @@ -416,6 +415,7 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> & } let (body, _) = tcx.mir_promoted(def); + lint_tail_expr_drop_order::run_lint(tcx, def, &body.borrow()); let mut body = body.steal(); if let Some(error_reported) = tainted_by_errors { diff --git a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs index 7ece719c0615f..152134fae1e14 100644 --- a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs +++ b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs @@ -13,6 +13,7 @@ use rustc_mir_dataflow::move_paths::{MoveData, MovePathIndex}; use rustc_mir_dataflow::{Analysis, MaybeReachable}; use rustc_session::lint; use rustc_span::Span; +use smallvec::{SmallVec, smallvec}; use tracing::{debug, instrument}; fn place_has_common_prefix<'tcx>(left: &Place<'tcx>, right: &Place<'tcx>) -> bool { @@ -68,6 +69,41 @@ fn print_ty_without_trimming(ty: Ty<'_>) -> String { ty::print::with_no_trimmed_paths!(format!("{}", ty)) } +#[instrument(level = "debug", skip(tcx, param_env))] +fn extract_component_raw<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, +) -> (SmallVec<[Ty<'tcx>; 4]>, SmallVec<[Span; 4]>) { + // Droppiness does not depend on regions, so let us erase them. + let ty = tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty); + + let Ok(tys) = tcx.list_significant_drop_tys(param_env.and(ty)) else { + return (smallvec![ty], smallvec![]); + }; + debug!(?ty, "components"); + let mut out_tys = smallvec![]; + let mut out_spans = smallvec![]; + for ty in tys { + if let ty::Coroutine(did, args) = ty.kind() + && let Some(witness) = tcx.mir_coroutine_witnesses(did) + { + for field in &witness.field_tys { + let (tys, spans) = extract_component_raw( + tcx, + param_env, + ty::EarlyBinder::bind(field.ty).instantiate(tcx, args), + ); + out_tys.extend(tys); + out_spans.extend([field.source_info.span].into_iter().chain(spans)); + } + } else { + out_tys.push(ty); + } + } + (out_tys, out_spans) +} + #[instrument(level = "debug", skip(tcx, param_env))] fn extract_component_with_significant_dtor<'tcx>( tcx: TyCtxt<'tcx>, @@ -105,20 +141,9 @@ fn extract_component_with_significant_dtor<'tcx>( // I honestly don't know how to extract the span reliably from a param arbitrarily nested ty::Param(_) => None, }; - let Ok(tys) = tcx.list_significant_drop_tys(param_env.and(ty)) else { - return (print_ty_without_trimming(ty), vec![]); - }; - debug!(?ty, "components"); - for ty in tys { - match ty.kind() { - ty::Coroutine(def_id, _) => debug!(?def_id, "coroutine"), - ty::CoroutineWitness(def_id, _) => debug!(?def_id, "coroutine witness"), - ty::Adt(def_id, _) => debug!(?def_id, "adt"), - _ => {} - } - } - let ty_names = tys.iter().map(print_ty_without_trimming).join(", "); - let ty_spans = tys.iter().flat_map(ty_def_span).collect(); + let (tys, spans) = extract_component_raw(tcx, param_env, ty); + let ty_names = tys.iter().copied().map(print_ty_without_trimming).join(", "); + let ty_spans = tys.iter().copied().flat_map(ty_def_span).chain(spans).collect(); (ty_names, ty_spans) } diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index 1a425ec6c849b..171c6bd1e689b 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -195,7 +195,7 @@ where } } - _ if component.is_copy_modulo_regions(tcx, self.param_env) => (), + _ if component.is_copy_modulo_regions(tcx, self.param_env) => {} ty::Closure(_, args) => { for upvar in args.as_closure().upvar_tys() { diff --git a/tests/ui/drop/lint-tail-expr-drop-order.rs b/tests/ui/drop/lint-tail-expr-drop-order.rs index 79313dc088729..389547eb0b266 100644 --- a/tests/ui/drop/lint-tail-expr-drop-order.rs +++ b/tests/ui/drop/lint-tail-expr-drop-order.rs @@ -1,6 +1,8 @@ // Edition 2024 lint for change in drop order at tail expression // This lint is to capture potential change in program semantics // due to implementation of RFC 3606 +//@ edition: 2021 +//@ build-fail #![deny(tail_expr_drop_order)] #![feature(shorter_tail_lifetimes)] @@ -98,4 +100,18 @@ fn should_not_lint_when_moved() -> i32 { LoudDropper.get() } +fn should_lint_into_async_body() -> i32 { + async fn f() { + async fn f() {} + let x = LoudDropper; + f().await; + drop(x); + } + + let future = f(); + LoudDropper.get() + //~^ ERROR: this value has significant drop implementation that will have a different drop order from that of Edition 2021 + //~| WARN: this changes meaning in Rust 2024 +} + fn main() {} diff --git a/tests/ui/drop/lint-tail-expr-drop-order.stderr b/tests/ui/drop/lint-tail-expr-drop-order.stderr index 8147d73ad7bb4..bdd94c61b9a59 100644 --- a/tests/ui/drop/lint-tail-expr-drop-order.stderr +++ b/tests/ui/drop/lint-tail-expr-drop-order.stderr @@ -1,5 +1,5 @@ error: this value has significant drop implementation that will have a different drop order from that of Edition 2021, whose type `LoudDropper` drops `LoudDropper` while dropping - --> $DIR/lint-tail-expr-drop-order.rs:26:15 + --> $DIR/lint-tail-expr-drop-order.rs:28:15 | LL | let x = LoudDropper; | - this local binding may observe changes in drop order under Edition 2024, whose type `LoudDropper` drops `LoudDropper` while dropping @@ -9,14 +9,24 @@ LL | x.get() + LoudDropper.get() | = warning: this changes meaning in Rust 2024 = note: for more information, see issue #123739 +note: these are the types and values with significant drop implementation + --> $DIR/lint-tail-expr-drop-order.rs:10:1 + | +LL | struct LoudDropper; + | ^^^^^^^^^^^^^^^^^^ +note: these are the types and values with significant drop implementation that are from Edition 2024 dropped earlier rather than later + --> $DIR/lint-tail-expr-drop-order.rs:10:1 + | +LL | struct LoudDropper; + | ^^^^^^^^^^^^^^^^^^ note: the lint level is defined here - --> $DIR/lint-tail-expr-drop-order.rs:5:9 + --> $DIR/lint-tail-expr-drop-order.rs:7:9 | LL | #![deny(tail_expr_drop_order)] | ^^^^^^^^^^^^^^^^^^^^ error: this value has significant drop implementation that will have a different drop order from that of Edition 2021, whose type `LoudDropper` drops `LoudDropper` while dropping - --> $DIR/lint-tail-expr-drop-order.rs:44:19 + --> $DIR/lint-tail-expr-drop-order.rs:46:19 | LL | let x = LoudDropper; | - this local binding may observe changes in drop order under Edition 2024, whose type `LoudDropper` drops `LoudDropper` while dropping @@ -26,9 +36,19 @@ LL | x.get() + LoudDropper.get() | = warning: this changes meaning in Rust 2024 = note: for more information, see issue #123739 +note: these are the types and values with significant drop implementation + --> $DIR/lint-tail-expr-drop-order.rs:10:1 + | +LL | struct LoudDropper; + | ^^^^^^^^^^^^^^^^^^ +note: these are the types and values with significant drop implementation that are from Edition 2024 dropped earlier rather than later + --> $DIR/lint-tail-expr-drop-order.rs:10:1 + | +LL | struct LoudDropper; + | ^^^^^^^^^^^^^^^^^^ error: this value has significant drop implementation that will have a different drop order from that of Edition 2021, whose type `LoudDropper` drops `LoudDropper` while dropping - --> $DIR/lint-tail-expr-drop-order.rs:64:7 + --> $DIR/lint-tail-expr-drop-order.rs:66:7 | LL | let x = LoudDropper; | - this local binding may observe changes in drop order under Edition 2024, whose type `LoudDropper` drops `LoudDropper` while dropping @@ -37,6 +57,47 @@ LL | { LoudDropper.get() } | = warning: this changes meaning in Rust 2024 = note: for more information, see issue #123739 +note: these are the types and values with significant drop implementation + --> $DIR/lint-tail-expr-drop-order.rs:10:1 + | +LL | struct LoudDropper; + | ^^^^^^^^^^^^^^^^^^ +note: these are the types and values with significant drop implementation that are from Edition 2024 dropped earlier rather than later + --> $DIR/lint-tail-expr-drop-order.rs:10:1 + | +LL | struct LoudDropper; + | ^^^^^^^^^^^^^^^^^^ + +error: this value has significant drop implementation that will have a different drop order from that of Edition 2021, whose type `LoudDropper` drops `LoudDropper` while dropping + --> $DIR/lint-tail-expr-drop-order.rs:112:5 + | +LL | let future = f(); + | ------ this local binding may observe changes in drop order under Edition 2024, whose type `impl std::future::Future` drops `LoudDropper` while dropping +LL | LoudDropper.get() + | ^^^^^^^^^^^ + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see issue #123739 +note: these are the types and values with significant drop implementation + --> $DIR/lint-tail-expr-drop-order.rs:10:1 + | +LL | struct LoudDropper; + | ^^^^^^^^^^^^^^^^^^ +note: these are the types and values with significant drop implementation that are from Edition 2024 dropped earlier rather than later + --> $DIR/lint-tail-expr-drop-order.rs:10:1 + | +LL | struct LoudDropper; + | ^^^^^^^^^^^^^^^^^^ +note: these are the types and values with significant drop implementation that are from Edition 2024 dropped earlier rather than later + --> $DIR/lint-tail-expr-drop-order.rs:106:13 + | +LL | let x = LoudDropper; + | ^ +note: these are the types and values with significant drop implementation that are from Edition 2024 dropped earlier rather than later + --> $DIR/lint-tail-expr-drop-order.rs:107:9 + | +LL | f().await; + | ^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors