From c55eefe8bc51f302cfc89d375198ca7211d4709b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 6 Jan 2025 03:25:45 +0000 Subject: [PATCH] Try to explain borrow for tail expr temporary drop order change in 2024 --- compiler/rustc_borrowck/messages.ftl | 5 ++- .../src/diagnostics/explain_borrow.rs | 18 ++++----- .../rustc_borrowck/src/diagnostics/mod.rs | 11 +++--- .../src/diagnostics/region_name.rs | 4 +- compiler/rustc_borrowck/src/lib.rs | 19 +++++++--- ...hod_1.ElaborateDrops.after.panic-abort.mir | 1 + ...od_1.ElaborateDrops.after.panic-unwind.mir | 1 + .../lint-tail-expr-drop-order-borrowck.rs | 26 ++++++++++--- .../lint-tail-expr-drop-order-borrowck.stderr | 38 ++++++++++++------- 9 files changed, 81 insertions(+), 42 deletions(-) diff --git a/compiler/rustc_borrowck/messages.ftl b/compiler/rustc_borrowck/messages.ftl index c1d5af59b1b5b..ada20e5c614f8 100644 --- a/compiler/rustc_borrowck/messages.ftl +++ b/compiler/rustc_borrowck/messages.ftl @@ -213,8 +213,9 @@ borrowck_suggest_create_fresh_reborrow = borrowck_suggest_iterate_over_slice = consider iterating over a slice of the `{$ty}`'s content to avoid moving into the `for` loop -borrowck_tail_expr_drop_order = a temporary value will be dropped here before the execution exits the block in Edition 2024, which will raise borrow checking error - .label = consider using a `let` binding to create a longer lived value; or replacing the `{"{"} .. {"}"}` block with curly brackets `( .. )`; or folding the rest of the expression into the surrounding `unsafe {"{"} .. {"}"}` +borrowck_tail_expr_drop_order = relative drop order changing in Rust 2024 + .label = this temporary value will be dropped at the end of the block + .note = consider using a `let` binding to ensure the value will live long enough borrowck_ty_no_impl_copy = {$is_partial_move -> diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 48f28f3f1de95..a52dc447d7685 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -5,7 +5,7 @@ use std::assert_matches::assert_matches; -use rustc_errors::{Applicability, Diag}; +use rustc_errors::{Applicability, Diag, EmissionGuarantee}; use rustc_hir as hir; use rustc_hir::intravisit::Visitor; use rustc_infer::infer::NllRegionVariableOrigin; @@ -61,10 +61,10 @@ impl<'tcx> BorrowExplanation<'tcx> { pub(crate) fn is_explained(&self) -> bool { !matches!(self, BorrowExplanation::Unexplained) } - pub(crate) fn add_explanation_to_diagnostic( + pub(crate) fn add_explanation_to_diagnostic( &self, cx: &MirBorrowckCtxt<'_, '_, 'tcx>, - err: &mut Diag<'_>, + err: &mut Diag<'_, G>, borrow_desc: &str, borrow_span: Option, multiple_borrow_span: Option<(Span, Span)>, @@ -346,10 +346,10 @@ impl<'tcx> BorrowExplanation<'tcx> { } } - fn add_object_lifetime_default_note( + fn add_object_lifetime_default_note( &self, tcx: TyCtxt<'tcx>, - err: &mut Diag<'_>, + err: &mut Diag<'_, G>, unsize_ty: Ty<'tcx>, ) { if let ty::Adt(def, args) = unsize_ty.kind() { @@ -403,9 +403,9 @@ impl<'tcx> BorrowExplanation<'tcx> { } } - fn add_lifetime_bound_suggestion_to_diagnostic( + fn add_lifetime_bound_suggestion_to_diagnostic( &self, - err: &mut Diag<'_>, + err: &mut Diag<'_, G>, category: &ConstraintCategory<'tcx>, span: Span, region_name: &RegionName, @@ -432,14 +432,14 @@ impl<'tcx> BorrowExplanation<'tcx> { } } -fn suggest_rewrite_if_let( +fn suggest_rewrite_if_let( tcx: TyCtxt<'_>, expr: &hir::Expr<'_>, pat: &str, init: &hir::Expr<'_>, conseq: &hir::Expr<'_>, alt: Option<&hir::Expr<'_>>, - err: &mut Diag<'_>, + err: &mut Diag<'_, G>, ) { let source_map = tcx.sess.source_map(); err.span_note( diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 0286ea6cd9dca..d9d9ea75994f1 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -4,7 +4,7 @@ use std::collections::BTreeMap; use rustc_abi::{FieldIdx, VariantIdx}; use rustc_data_structures::fx::FxIndexMap; -use rustc_errors::{Applicability, Diag, MultiSpan}; +use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan}; use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::{self as hir, CoroutineKind, LangItem}; use rustc_index::IndexSlice; @@ -626,9 +626,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { /// Add a note to region errors and borrow explanations when higher-ranked regions in predicates /// implicitly introduce an "outlives `'static`" constraint. - fn add_placeholder_from_predicate_note( + fn add_placeholder_from_predicate_note( &self, - err: &mut Diag<'_>, + err: &mut Diag<'_, G>, path: &[OutlivesConstraint<'tcx>], ) { let predicate_span = path.iter().find_map(|constraint| { @@ -651,9 +651,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { /// Add a label to region errors and borrow explanations when outlives constraints arise from /// proving a type implements `Sized` or `Copy`. - fn add_sized_or_copy_bound_info( + fn add_sized_or_copy_bound_info( &self, - err: &mut Diag<'_>, + err: &mut Diag<'_, G>, blamed_category: ConstraintCategory<'tcx>, path: &[OutlivesConstraint<'tcx>], ) { @@ -1042,6 +1042,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { kind, }; } + normal_ret } diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index bdb880b2bced3..9349b46ec5b0c 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -5,7 +5,7 @@ use std::fmt::{self, Display}; use std::iter; use rustc_data_structures::fx::IndexEntry; -use rustc_errors::Diag; +use rustc_errors::{Diag, EmissionGuarantee}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_middle::ty::print::RegionHighlightMode; @@ -108,7 +108,7 @@ impl RegionName { } } - pub(crate) fn highlight_region_name(&self, diag: &mut Diag<'_>) { + pub(crate) fn highlight_region_name(&self, diag: &mut Diag<'_, G>) { match &self.source { RegionNameSource::NamedLateParamRegion(span) | RegionNameSource::NamedEarlyParamRegion(span) => { diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 8b3870e5cc605..f90f75141026f 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -24,6 +24,7 @@ use std::ops::{ControlFlow, Deref}; use rustc_abi::FieldIdx; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::graph::dominators::Dominators; +use rustc_errors::LintDiagnostic; use rustc_hir as hir; use rustc_hir::CRATE_HIR_ID; use rustc_hir::def_id::LocalDefId; @@ -1192,17 +1193,25 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { |borrow_index| borrows_in_scope.contains(borrow_index), |this, _borrow_index, borrow| { if matches!(borrow.kind, BorrowKind::Fake(_)) { - return Control::Continue; + return ControlFlow::Continue(()); } let borrowed = this.retrieve_borrow_spans(borrow).var_or_use_path_span(); - this.infcx.tcx.emit_node_span_lint( + let explain = this.explain_why_borrow_contains_point( + location, + borrow, + Some((WriteKind::StorageDeadOrDrop, place)), + ); + this.infcx.tcx.node_span_lint( TAIL_EXPR_DROP_ORDER, CRATE_HIR_ID, - place_span, - session_diagnostics::TailExprDropOrder { borrowed }, + borrowed, + |diag| { + session_diagnostics::TailExprDropOrder { borrowed }.decorate_lint(diag); + explain.add_explanation_to_diagnostic(&this, diag, "", None, None); + }, ); // We may stop at the first case - Control::Break + ControlFlow::Break(()) }, ); } diff --git a/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-abort.mir b/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-abort.mir index e9bbe30bd774f..ee6e16d20fd8d 100644 --- a/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-abort.mir +++ b/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-abort.mir @@ -74,6 +74,7 @@ fn method_1(_1: Guard) -> () { bb7: { backward incompatible drop(_2); + backward incompatible drop(_4); backward incompatible drop(_5); goto -> bb21; } diff --git a/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-unwind.mir b/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-unwind.mir index e9bbe30bd774f..ee6e16d20fd8d 100644 --- a/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-unwind.mir +++ b/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-unwind.mir @@ -74,6 +74,7 @@ fn method_1(_1: Guard) -> () { bb7: { backward incompatible drop(_2); + backward incompatible drop(_4); backward incompatible drop(_5); goto -> bb21; } diff --git a/tests/ui/drop/lint-tail-expr-drop-order-borrowck.rs b/tests/ui/drop/lint-tail-expr-drop-order-borrowck.rs index 1bd5655d7fe1d..6f64d83f8a0c3 100644 --- a/tests/ui/drop/lint-tail-expr-drop-order-borrowck.rs +++ b/tests/ui/drop/lint-tail-expr-drop-order-borrowck.rs @@ -7,18 +7,20 @@ fn should_lint_with_potential_borrowck_err() { let _ = { String::new().as_str() }.len(); - //~^ ERROR: a temporary value will be dropped here + //~^ ERROR: relative drop order changing //~| WARN: this changes meaning in Rust 2024 - //~| NOTE: consider using a `let` binding + //~| NOTE: this temporary value will be dropped at the end of the block + //~| borrow later used by call //~| NOTE: for more information, see } fn should_lint_with_unsafe_block() { fn f(_: usize) {} f(unsafe { String::new().as_str() }.len()); - //~^ ERROR: a temporary value will be dropped here + //~^ ERROR: relative drop order changing //~| WARN: this changes meaning in Rust 2024 - //~| NOTE: consider using a `let` binding + //~| NOTE: this temporary value will be dropped at the end of the block + //~| borrow later used by call //~| NOTE: for more information, see } @@ -27,11 +29,23 @@ fn should_lint_with_big_block() { fn f(_: T) {} f({ &mut || 0 - //~^ ERROR: a temporary value will be dropped here + //~^ ERROR: relative drop order changing //~| WARN: this changes meaning in Rust 2024 - //~| NOTE: consider using a `let` binding + //~| NOTE: this temporary value will be dropped at the end of the block + //~| borrow later used here //~| NOTE: for more information, see }) } +fn another_temp_that_is_copy_in_arg() { + fn f() {} + fn g(_: &()) {} + g({ &f() }); + //~^ ERROR: relative drop order changing + //~| WARN: this changes meaning in Rust 2024 + //~| NOTE: this temporary value will be dropped at the end of the block + //~| borrow later used by call + //~| NOTE: for more information, see +} + fn main() {} diff --git a/tests/ui/drop/lint-tail-expr-drop-order-borrowck.stderr b/tests/ui/drop/lint-tail-expr-drop-order-borrowck.stderr index 98ef0547c9075..a55e366dd0be1 100644 --- a/tests/ui/drop/lint-tail-expr-drop-order-borrowck.stderr +++ b/tests/ui/drop/lint-tail-expr-drop-order-borrowck.stderr @@ -1,10 +1,10 @@ -error: a temporary value will be dropped here before the execution exits the block in Edition 2024, which will raise borrow checking error - --> $DIR/lint-tail-expr-drop-order-borrowck.rs:9:36 +error: relative drop order changing in Rust 2024 + --> $DIR/lint-tail-expr-drop-order-borrowck.rs:9:15 | LL | let _ = { String::new().as_str() }.len(); - | ------------- ^ + | ^^^^^^^^^^^^^ --- borrow later used by call | | - | consider using a `let` binding to create a longer lived value; or replacing the `{ .. }` block with curly brackets `( .. )`; or folding the rest of the expression into the surrounding `unsafe { .. }` + | this temporary value will be dropped at the end of the block | = warning: this changes meaning in Rust 2024 = note: for more information, see @@ -14,27 +14,39 @@ note: the lint level is defined here LL | #![deny(tail_expr_drop_order)] | ^^^^^^^^^^^^^^^^^^^^ -error: a temporary value will be dropped here before the execution exits the block in Edition 2024, which will raise borrow checking error - --> $DIR/lint-tail-expr-drop-order-borrowck.rs:18:37 +error: relative drop order changing in Rust 2024 + --> $DIR/lint-tail-expr-drop-order-borrowck.rs:19:16 | LL | f(unsafe { String::new().as_str() }.len()); - | ------------- ^ + | ^^^^^^^^^^^^^ --- borrow later used by call | | - | consider using a `let` binding to create a longer lived value; or replacing the `{ .. }` block with curly brackets `( .. )`; or folding the rest of the expression into the surrounding `unsafe { .. }` + | this temporary value will be dropped at the end of the block | = warning: this changes meaning in Rust 2024 = note: for more information, see -error: a temporary value will be dropped here before the execution exits the block in Edition 2024, which will raise borrow checking error - --> $DIR/lint-tail-expr-drop-order-borrowck.rs:29:17 +error: relative drop order changing in Rust 2024 + --> $DIR/lint-tail-expr-drop-order-borrowck.rs:31:9 | LL | &mut || 0 - | --------^ + | ^^^^^^^^^ | | - | consider using a `let` binding to create a longer lived value; or replacing the `{ .. }` block with curly brackets `( .. )`; or folding the rest of the expression into the surrounding `unsafe { .. }` + | this temporary value will be dropped at the end of the block + | borrow later used here | = warning: this changes meaning in Rust 2024 = note: for more information, see -error: aborting due to 3 previous errors +error: relative drop order changing in Rust 2024 + --> $DIR/lint-tail-expr-drop-order-borrowck.rs:43:9 + | +LL | g({ &f() }); + | - ^^^^ this temporary value will be dropped at the end of the block + | | + | borrow later used by call + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see + +error: aborting due to 4 previous errors