From 80cb482318bfa563173892f1b2c13d49bc40f12b Mon Sep 17 00:00:00 2001 From: Paolo_4 Date: Sat, 4 Apr 2026 15:09:46 +0200 Subject: [PATCH 1/4] adds better error message for temporary value does not live long enough --- .../src/diagnostics/conflict_errors.rs | 44 +++++++++++++++++++ .../inline-const/interior-mutable-borrow.rs | 23 ++++++++++ .../interior-mutable-borrow.stderr | 33 ++++++++++++++ 3 files changed, 100 insertions(+) create mode 100644 tests/ui/inline-const/interior-mutable-borrow.rs create mode 100644 tests/ui/inline-const/interior-mutable-borrow.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index da472a08e7e40..2fd43abef84a0 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -3366,6 +3366,50 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } } + // Emit E0492 for `&const { expr }` when `expr` has + // interior mutability, since that's what actually prevents promotion. + if let Some(expr) = self.find_expr(proper_span) + && let hir::ExprKind::ConstBlock(const_block) = expr.kind + { + let borrowed_ty = self.body.local_decls[borrow.borrowed_place.local].ty; + let typing_env = self.infcx.typing_env(self.infcx.param_env); + let tcx = self.infcx.tcx; + if !borrowed_ty.is_freeze(tcx, typing_env) { + let body_expr = tcx.hir_body(const_block.body).value; + let inner_span = if let hir::ExprKind::Block(block, _) = body_expr.kind + && let Some(tail_expr) = block.expr + { + tail_expr.span + } else { + body_expr.span + }; + let mut err = struct_span_code_err!( + self.dcx(), + inner_span, + E0492, + "interior mutable shared borrows of temporaries that have their \ + lifetime extended until the end of the program are not allowed" + ); + err.span_label( + inner_span, + "this borrow of an interior mutable value refers to such a temporary", + ); + err.note( + "temporaries in constants and statics can have their lifetime \ + extended until the end of the program", + ); + err.note( + "to avoid accidentally creating global mutable state, such \ + temporaries must be immutable", + ); + err.help( + "if you really want global mutable state, try replacing the \ + temporary by an interior mutable `static` or a `static mut`", + ); + return err; + } + } + let mut err = self.temporary_value_borrowed_for_too_long(proper_span); err.span_label(proper_span, "creates a temporary value which is freed while still in use"); err.span_label(drop_span, "temporary value is freed at the end of this statement"); diff --git a/tests/ui/inline-const/interior-mutable-borrow.rs b/tests/ui/inline-const/interior-mutable-borrow.rs new file mode 100644 index 0000000000000..27dbe6a6df213 --- /dev/null +++ b/tests/ui/inline-const/interior-mutable-borrow.rs @@ -0,0 +1,23 @@ +// Verify that `&const { expr }` where `expr` has interior mutability +// gets E0492 instead of E0716. + +use std::cell::Cell; +use std::sync::atomic::AtomicUsize; + +struct Mutable(Cell); +impl Mutable { + const fn new(a: u32) -> Self { Self(Cell::new(a)) } +} + +fn main() { + let _: &'static _ = &const { 0u32 }; + + let _: &'static _ = &const { Mutable::new(0u32) }; + //~^ ERROR interior mutable shared borrows of temporaries + + let _: &'static _ = const { &Mutable::new(0u32) }; + //~^ ERROR interior mutable shared borrows of temporaries + + let _: &'static _ = &const { AtomicUsize::new(0) }; + //~^ ERROR interior mutable shared borrows of temporaries +} diff --git a/tests/ui/inline-const/interior-mutable-borrow.stderr b/tests/ui/inline-const/interior-mutable-borrow.stderr new file mode 100644 index 0000000000000..7f5b4078c1361 --- /dev/null +++ b/tests/ui/inline-const/interior-mutable-borrow.stderr @@ -0,0 +1,33 @@ +error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed + --> $DIR/interior-mutable-borrow.rs:18:33 + | +LL | let _: &'static _ = const { &Mutable::new(0u32) }; + | ^^^^^^^^^^^^^^^^^^^ this borrow of an interior mutable value refers to such a temporary + | + = note: temporaries in constants and statics can have their lifetime extended until the end of the program + = note: to avoid accidentally creating global mutable state, such temporaries must be immutable + = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + +error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed + --> $DIR/interior-mutable-borrow.rs:15:34 + | +LL | let _: &'static _ = &const { Mutable::new(0u32) }; + | ^^^^^^^^^^^^^^^^^^ this borrow of an interior mutable value refers to such a temporary + | + = note: temporaries in constants and statics can have their lifetime extended until the end of the program + = note: to avoid accidentally creating global mutable state, such temporaries must be immutable + = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + +error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed + --> $DIR/interior-mutable-borrow.rs:21:34 + | +LL | let _: &'static _ = &const { AtomicUsize::new(0) }; + | ^^^^^^^^^^^^^^^^^^^ this borrow of an interior mutable value refers to such a temporary + | + = note: temporaries in constants and statics can have their lifetime extended until the end of the program + = note: to avoid accidentally creating global mutable state, such temporaries must be immutable + = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0492`. From 77964f9f91ca0305c8b099c06397d62c6bd46ef7 Mon Sep 17 00:00:00 2001 From: Hiryxx Date: Tue, 14 Apr 2026 13:20:53 +0200 Subject: [PATCH 2/4] Fix review comments --- .../src/diagnostics/conflict_errors.rs | 36 ++++----- .../interior-mutable-borrow-issue-154382.rs | 50 +++++++++++++ ...nterior-mutable-borrow-issue-154382.stderr | 73 +++++++++++++++++++ .../inline-const/interior-mutable-borrow.rs | 23 ------ .../interior-mutable-borrow.stderr | 33 --------- 5 files changed, 142 insertions(+), 73 deletions(-) create mode 100644 tests/ui/inline-const/interior-mutable-borrow-issue-154382.rs create mode 100644 tests/ui/inline-const/interior-mutable-borrow-issue-154382.stderr delete mode 100644 tests/ui/inline-const/interior-mutable-borrow.rs delete mode 100644 tests/ui/inline-const/interior-mutable-borrow.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 2fd43abef84a0..dbf4cedc9edc4 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -3352,19 +3352,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { proper_span: Span, explanation: BorrowExplanation<'tcx>, ) -> Diag<'infcx> { - if let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } = - explanation - { - if let Err(diag) = self.try_report_cannot_return_reference_to_local( - borrow, - proper_span, - span, - category, - None, - ) { - return diag; - } - } // Emit E0492 for `&const { expr }` when `expr` has // interior mutability, since that's what actually prevents promotion. @@ -3388,7 +3375,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { inner_span, E0492, "interior mutable shared borrows of temporaries that have their \ - lifetime extended until the end of the program are not allowed" + lifetime extended until the end of the program are not allowed" ); err.span_label( inner_span, @@ -3396,20 +3383,35 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ); err.note( "temporaries in constants and statics can have their lifetime \ - extended until the end of the program", + extended until the end of the program", ); err.note( "to avoid accidentally creating global mutable state, such \ - temporaries must be immutable", + temporaries must be immutable", ); err.help( "if you really want global mutable state, try replacing the \ - temporary by an interior mutable `static` or a `static mut`", + temporary by an interior mutable `static` or a `static mut`", ); return err; } } + if let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } = + explanation + { + if let Err(diag) = self.try_report_cannot_return_reference_to_local( + borrow, + proper_span, + span, + category, + None, + ) { + return diag; + } + } + + let mut err = self.temporary_value_borrowed_for_too_long(proper_span); err.span_label(proper_span, "creates a temporary value which is freed while still in use"); err.span_label(drop_span, "temporary value is freed at the end of this statement"); diff --git a/tests/ui/inline-const/interior-mutable-borrow-issue-154382.rs b/tests/ui/inline-const/interior-mutable-borrow-issue-154382.rs new file mode 100644 index 0000000000000..171280e8df648 --- /dev/null +++ b/tests/ui/inline-const/interior-mutable-borrow-issue-154382.rs @@ -0,0 +1,50 @@ +// Verify that `&const { expr }` where `expr` has interior mutability +// gets E0492 instead of E0716. +// https://github.com/rust-lang/rust/issues/154382 + +use std::cell::Cell; +use std::sync::atomic::AtomicUsize; + +struct Mutable(Cell); +impl Mutable { + const fn new(a: u32) -> Self { Self(Cell::new(a)) } +} + +fn foo() -> &'static Mutable { + &const { Mutable::new(0) } + //~^ ERROR interior mutable shared borrows of temporaries +} + +struct Holder { + val: &'static Mutable, +} + +fn takes_static(_: &'static Mutable) {} + +fn via_closure() { + let _f: fn() -> &'static Mutable = || &const { Mutable::new(0) }; + //~^ ERROR interior mutable shared borrows of temporaries +} + +fn via_struct() { + let _h = Holder { val: &const { Mutable::new(0) } }; + //~^ ERROR interior mutable shared borrows of temporaries +} + +fn via_argument() { + takes_static(&const { Mutable::new(0) }); + //~^ ERROR interior mutable shared borrows of temporaries +} + +fn main() { + let _: &'static _ = &const { 0u32 }; + + let _: &'static _ = &const { Mutable::new(0u32) }; + //~^ ERROR interior mutable shared borrows of temporaries + + let _: &'static _ = const { &Mutable::new(0u32) }; + //~^ ERROR interior mutable shared borrows of temporaries + + let _: &'static _ = &const { AtomicUsize::new(0) }; + //~^ ERROR interior mutable shared borrows of temporaries +} diff --git a/tests/ui/inline-const/interior-mutable-borrow-issue-154382.stderr b/tests/ui/inline-const/interior-mutable-borrow-issue-154382.stderr new file mode 100644 index 0000000000000..36101d244f774 --- /dev/null +++ b/tests/ui/inline-const/interior-mutable-borrow-issue-154382.stderr @@ -0,0 +1,73 @@ +error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed + --> $DIR/interior-mutable-borrow-issue-154382.rs:14:14 + | +LL | &const { Mutable::new(0) } + | ^^^^^^^^^^^^^^^ this borrow of an interior mutable value refers to such a temporary + | + = note: temporaries in constants and statics can have their lifetime extended until the end of the program + = note: to avoid accidentally creating global mutable state, such temporaries must be immutable + = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + +error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed + --> $DIR/interior-mutable-borrow-issue-154382.rs:25:52 + | +LL | let _f: fn() -> &'static Mutable = || &const { Mutable::new(0) }; + | ^^^^^^^^^^^^^^^ this borrow of an interior mutable value refers to such a temporary + | + = note: temporaries in constants and statics can have their lifetime extended until the end of the program + = note: to avoid accidentally creating global mutable state, such temporaries must be immutable + = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + +error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed + --> $DIR/interior-mutable-borrow-issue-154382.rs:30:37 + | +LL | let _h = Holder { val: &const { Mutable::new(0) } }; + | ^^^^^^^^^^^^^^^ this borrow of an interior mutable value refers to such a temporary + | + = note: temporaries in constants and statics can have their lifetime extended until the end of the program + = note: to avoid accidentally creating global mutable state, such temporaries must be immutable + = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + +error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed + --> $DIR/interior-mutable-borrow-issue-154382.rs:35:27 + | +LL | takes_static(&const { Mutable::new(0) }); + | ^^^^^^^^^^^^^^^ this borrow of an interior mutable value refers to such a temporary + | + = note: temporaries in constants and statics can have their lifetime extended until the end of the program + = note: to avoid accidentally creating global mutable state, such temporaries must be immutable + = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + +error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed + --> $DIR/interior-mutable-borrow-issue-154382.rs:45:33 + | +LL | let _: &'static _ = const { &Mutable::new(0u32) }; + | ^^^^^^^^^^^^^^^^^^^ this borrow of an interior mutable value refers to such a temporary + | + = note: temporaries in constants and statics can have their lifetime extended until the end of the program + = note: to avoid accidentally creating global mutable state, such temporaries must be immutable + = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + +error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed + --> $DIR/interior-mutable-borrow-issue-154382.rs:42:34 + | +LL | let _: &'static _ = &const { Mutable::new(0u32) }; + | ^^^^^^^^^^^^^^^^^^ this borrow of an interior mutable value refers to such a temporary + | + = note: temporaries in constants and statics can have their lifetime extended until the end of the program + = note: to avoid accidentally creating global mutable state, such temporaries must be immutable + = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + +error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed + --> $DIR/interior-mutable-borrow-issue-154382.rs:48:34 + | +LL | let _: &'static _ = &const { AtomicUsize::new(0) }; + | ^^^^^^^^^^^^^^^^^^^ this borrow of an interior mutable value refers to such a temporary + | + = note: temporaries in constants and statics can have their lifetime extended until the end of the program + = note: to avoid accidentally creating global mutable state, such temporaries must be immutable + = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0492`. diff --git a/tests/ui/inline-const/interior-mutable-borrow.rs b/tests/ui/inline-const/interior-mutable-borrow.rs deleted file mode 100644 index 27dbe6a6df213..0000000000000 --- a/tests/ui/inline-const/interior-mutable-borrow.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Verify that `&const { expr }` where `expr` has interior mutability -// gets E0492 instead of E0716. - -use std::cell::Cell; -use std::sync::atomic::AtomicUsize; - -struct Mutable(Cell); -impl Mutable { - const fn new(a: u32) -> Self { Self(Cell::new(a)) } -} - -fn main() { - let _: &'static _ = &const { 0u32 }; - - let _: &'static _ = &const { Mutable::new(0u32) }; - //~^ ERROR interior mutable shared borrows of temporaries - - let _: &'static _ = const { &Mutable::new(0u32) }; - //~^ ERROR interior mutable shared borrows of temporaries - - let _: &'static _ = &const { AtomicUsize::new(0) }; - //~^ ERROR interior mutable shared borrows of temporaries -} diff --git a/tests/ui/inline-const/interior-mutable-borrow.stderr b/tests/ui/inline-const/interior-mutable-borrow.stderr deleted file mode 100644 index 7f5b4078c1361..0000000000000 --- a/tests/ui/inline-const/interior-mutable-borrow.stderr +++ /dev/null @@ -1,33 +0,0 @@ -error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed - --> $DIR/interior-mutable-borrow.rs:18:33 - | -LL | let _: &'static _ = const { &Mutable::new(0u32) }; - | ^^^^^^^^^^^^^^^^^^^ this borrow of an interior mutable value refers to such a temporary - | - = note: temporaries in constants and statics can have their lifetime extended until the end of the program - = note: to avoid accidentally creating global mutable state, such temporaries must be immutable - = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` - -error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed - --> $DIR/interior-mutable-borrow.rs:15:34 - | -LL | let _: &'static _ = &const { Mutable::new(0u32) }; - | ^^^^^^^^^^^^^^^^^^ this borrow of an interior mutable value refers to such a temporary - | - = note: temporaries in constants and statics can have their lifetime extended until the end of the program - = note: to avoid accidentally creating global mutable state, such temporaries must be immutable - = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` - -error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed - --> $DIR/interior-mutable-borrow.rs:21:34 - | -LL | let _: &'static _ = &const { AtomicUsize::new(0) }; - | ^^^^^^^^^^^^^^^^^^^ this borrow of an interior mutable value refers to such a temporary - | - = note: temporaries in constants and statics can have their lifetime extended until the end of the program - = note: to avoid accidentally creating global mutable state, such temporaries must be immutable - = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0492`. From 332d5c8f2b3db53653b7f0865e911a983727c9ea Mon Sep 17 00:00:00 2001 From: Hiryxx Date: Tue, 14 Apr 2026 13:27:42 +0200 Subject: [PATCH 3/4] Tidy fix --- compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index dbf4cedc9edc4..0a25e70dbb394 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -3352,7 +3352,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { proper_span: Span, explanation: BorrowExplanation<'tcx>, ) -> Diag<'infcx> { - // Emit E0492 for `&const { expr }` when `expr` has // interior mutability, since that's what actually prevents promotion. if let Some(expr) = self.find_expr(proper_span) @@ -3411,7 +3410,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } } - let mut err = self.temporary_value_borrowed_for_too_long(proper_span); err.span_label(proper_span, "creates a temporary value which is freed while still in use"); err.span_label(drop_span, "temporary value is freed at the end of this statement"); From a91dbb5f4429de2c80d5125c9afcabb9399281a1 Mon Sep 17 00:00:00 2001 From: Hiryxx Date: Fri, 26 Jun 2026 15:01:27 +0200 Subject: [PATCH 4/4] review fixes --- .../src/diagnostics/conflict_errors.rs | 81 +++++++++++-------- compiler/rustc_const_eval/src/errors.rs | 4 + .../interior-mutable-borrow-issue-154382.rs | 14 ++++ ...nterior-mutable-borrow-issue-154382.stderr | 69 +++++++++++++--- 4 files changed, 125 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 0a25e70dbb394..6564729d3621d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -3352,10 +3352,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { proper_span: Span, explanation: BorrowExplanation<'tcx>, ) -> Diag<'infcx> { - // Emit E0492 for `&const { expr }` when `expr` has + // Emit E0492 for a shared `&const { expr }` borrow when `expr` has // interior mutability, since that's what actually prevents promotion. - if let Some(expr) = self.find_expr(proper_span) + let interior_mut_const_span = if let Some(expr) = self.find_expr(proper_span) && let hir::ExprKind::ConstBlock(const_block) = expr.kind + && matches!(borrow.kind(), BorrowKind::Shared) { let borrowed_ty = self.body.local_decls[borrow.borrowed_place.local].ty; let typing_env = self.infcx.typing_env(self.infcx.param_env); @@ -3369,35 +3370,17 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } else { body_expr.span }; - let mut err = struct_span_code_err!( - self.dcx(), - inner_span, - E0492, - "interior mutable shared borrows of temporaries that have their \ - lifetime extended until the end of the program are not allowed" - ); - err.span_label( - inner_span, - "this borrow of an interior mutable value refers to such a temporary", - ); - err.note( - "temporaries in constants and statics can have their lifetime \ - extended until the end of the program", - ); - err.note( - "to avoid accidentally creating global mutable state, such \ - temporaries must be immutable", - ); - err.help( - "if you really want global mutable state, try replacing the \ - temporary by an interior mutable `static` or a `static mut`", - ); - return err; + Some(inner_span) + } else { + None } - } + } else { + None + }; - if let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } = - explanation + if interior_mut_const_span.is_none() + && let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } = + explanation { if let Err(diag) = self.try_report_cannot_return_reference_to_local( borrow, @@ -3410,9 +3393,43 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } } - let mut err = self.temporary_value_borrowed_for_too_long(proper_span); - err.span_label(proper_span, "creates a temporary value which is freed while still in use"); - err.span_label(drop_span, "temporary value is freed at the end of this statement"); + let mut err = if let Some(inner_span) = interior_mut_const_span { + // FIXME(#154810): this message is duplicated from + // `rustc_const_eval::errors::InteriorMutableBorrowEscaping`. Deduplicate once the + // diagnostic struct can be shared across the borrowck/const_eval crate boundary. + let mut err = struct_span_code_err!( + self.dcx(), + inner_span, + E0492, + "interior mutable shared borrows of temporaries that have their \ + lifetime extended until the end of the program are not allowed" + ); + err.span_label( + inner_span, + "this borrow of an interior mutable value refers to such a temporary", + ); + err.note( + "temporaries in constants and statics can have their lifetime \ + extended until the end of the program", + ); + err.note( + "to avoid accidentally creating global mutable state, such \ + temporaries must be immutable", + ); + err.help( + "if you really want global mutable state, try replacing the \ + temporary by an interior mutable `static` or a `static mut`", + ); + err + } else { + let mut err = self.temporary_value_borrowed_for_too_long(proper_span); + err.span_label( + proper_span, + "creates a temporary value which is freed while still in use", + ); + err.span_label(drop_span, "temporary value is freed at the end of this statement"); + err + }; match explanation { BorrowExplanation::UsedLater(..) diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 9faf9a59fc22a..bde84f0430eaf 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -263,6 +263,10 @@ pub(crate) struct UnallowedInlineAsm { pub kind: ConstContext, } +// FIXME(#154810): this message is duplicated in +// `rustc_borrowck::diagnostics::conflict_errors` +// (`report_temporary_value_does_not_live_long_enough`). Keep the two in sync until the +// diagnostic can be shared across the crate boundary. #[derive(Diagnostic)] #[diag("interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed", code = E0492)] #[note( diff --git a/tests/ui/inline-const/interior-mutable-borrow-issue-154382.rs b/tests/ui/inline-const/interior-mutable-borrow-issue-154382.rs index 171280e8df648..639d7d3b3edf8 100644 --- a/tests/ui/inline-const/interior-mutable-borrow-issue-154382.rs +++ b/tests/ui/inline-const/interior-mutable-borrow-issue-154382.rs @@ -36,6 +36,20 @@ fn via_argument() { //~^ ERROR interior mutable shared borrows of temporaries } +// The `let` binding suggestion should still be offered alongside E0492. +fn deferred_assignment() { + let r; + r = &const { Cell::new(0) }; + //~^ ERROR interior mutable shared borrows of temporaries + r.set(1); +} + +// A `&mut` borrow is not a shared borrow, so it keeps the E0716 diagnostic. +fn mut_borrow() { + let _: &'static mut _ = &mut const { Cell::new(0) }; + //~^ ERROR temporary value dropped while borrowed +} + fn main() { let _: &'static _ = &const { 0u32 }; diff --git a/tests/ui/inline-const/interior-mutable-borrow-issue-154382.stderr b/tests/ui/inline-const/interior-mutable-borrow-issue-154382.stderr index 36101d244f774..d33eeb87b4095 100644 --- a/tests/ui/inline-const/interior-mutable-borrow-issue-154382.stderr +++ b/tests/ui/inline-const/interior-mutable-borrow-issue-154382.stderr @@ -2,7 +2,10 @@ error[E0492]: interior mutable shared borrows of temporaries that have their lif --> $DIR/interior-mutable-borrow-issue-154382.rs:14:14 | LL | &const { Mutable::new(0) } - | ^^^^^^^^^^^^^^^ this borrow of an interior mutable value refers to such a temporary + | ---------^^^^^^^^^^^^^^^-- + | | | + | | this borrow of an interior mutable value refers to such a temporary + | returning this value requires that borrow lasts for `'static` | = note: temporaries in constants and statics can have their lifetime extended until the end of the program = note: to avoid accidentally creating global mutable state, such temporaries must be immutable @@ -12,7 +15,11 @@ error[E0492]: interior mutable shared borrows of temporaries that have their lif --> $DIR/interior-mutable-borrow-issue-154382.rs:25:52 | LL | let _f: fn() -> &'static Mutable = || &const { Mutable::new(0) }; - | ^^^^^^^^^^^^^^^ this borrow of an interior mutable value refers to such a temporary + | - ---------^^^^^^^^^^^^^^^-- + | | | | + | | | this borrow of an interior mutable value refers to such a temporary + | | returning this value requires that borrow lasts for `'1` + | return type of closure is &'1 Mutable | = note: temporaries in constants and statics can have their lifetime extended until the end of the program = note: to avoid accidentally creating global mutable state, such temporaries must be immutable @@ -22,7 +29,10 @@ error[E0492]: interior mutable shared borrows of temporaries that have their lif --> $DIR/interior-mutable-borrow-issue-154382.rs:30:37 | LL | let _h = Holder { val: &const { Mutable::new(0) } }; - | ^^^^^^^^^^^^^^^ this borrow of an interior mutable value refers to such a temporary + | ---------^^^^^^^^^^^^^^^-- + | | | + | | this borrow of an interior mutable value refers to such a temporary + | this usage requires that borrow lasts for `'static` | = note: temporaries in constants and statics can have their lifetime extended until the end of the program = note: to avoid accidentally creating global mutable state, such temporaries must be immutable @@ -32,14 +42,46 @@ error[E0492]: interior mutable shared borrows of temporaries that have their lif --> $DIR/interior-mutable-borrow-issue-154382.rs:35:27 | LL | takes_static(&const { Mutable::new(0) }); - | ^^^^^^^^^^^^^^^ this borrow of an interior mutable value refers to such a temporary + | ----------------------^^^^^^^^^^^^^^^--- + | | | + | | this borrow of an interior mutable value refers to such a temporary + | argument requires that borrow lasts for `'static` | = note: temporaries in constants and statics can have their lifetime extended until the end of the program = note: to avoid accidentally creating global mutable state, such temporaries must be immutable = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed - --> $DIR/interior-mutable-borrow-issue-154382.rs:45:33 + --> $DIR/interior-mutable-borrow-issue-154382.rs:42:18 + | +LL | r = &const { Cell::new(0) }; + | ^^^^^^^^^^^^ this borrow of an interior mutable value refers to such a temporary +LL | +LL | r.set(1); + | - borrow later used here + | + = note: temporaries in constants and statics can have their lifetime extended until the end of the program + = note: to avoid accidentally creating global mutable state, such temporaries must be immutable + = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = const { Cell::new(0) }; +LL ~ r = &binding; + | + +error[E0716]: temporary value dropped while borrowed + --> $DIR/interior-mutable-borrow-issue-154382.rs:49:34 + | +LL | let _: &'static mut _ = &mut const { Cell::new(0) }; + | -------------- ^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | +LL | } + | - temporary value is freed at the end of this statement + +error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed + --> $DIR/interior-mutable-borrow-issue-154382.rs:59:33 | LL | let _: &'static _ = const { &Mutable::new(0u32) }; | ^^^^^^^^^^^^^^^^^^^ this borrow of an interior mutable value refers to such a temporary @@ -49,25 +91,30 @@ LL | let _: &'static _ = const { &Mutable::new(0u32) }; = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed - --> $DIR/interior-mutable-borrow-issue-154382.rs:42:34 + --> $DIR/interior-mutable-borrow-issue-154382.rs:56:34 | LL | let _: &'static _ = &const { Mutable::new(0u32) }; - | ^^^^^^^^^^^^^^^^^^ this borrow of an interior mutable value refers to such a temporary + | ---------- ^^^^^^^^^^^^^^^^^^ this borrow of an interior mutable value refers to such a temporary + | | + | type annotation requires that borrow lasts for `'static` | = note: temporaries in constants and statics can have their lifetime extended until the end of the program = note: to avoid accidentally creating global mutable state, such temporaries must be immutable = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed - --> $DIR/interior-mutable-borrow-issue-154382.rs:48:34 + --> $DIR/interior-mutable-borrow-issue-154382.rs:62:34 | LL | let _: &'static _ = &const { AtomicUsize::new(0) }; - | ^^^^^^^^^^^^^^^^^^^ this borrow of an interior mutable value refers to such a temporary + | ---------- ^^^^^^^^^^^^^^^^^^^ this borrow of an interior mutable value refers to such a temporary + | | + | type annotation requires that borrow lasts for `'static` | = note: temporaries in constants and statics can have their lifetime extended until the end of the program = note: to avoid accidentally creating global mutable state, such temporaries must be immutable = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` -error: aborting due to 7 previous errors +error: aborting due to 9 previous errors -For more information about this error, try `rustc --explain E0492`. +Some errors have detailed explanations: E0492, E0716. +For more information about an error, try `rustc --explain E0492`.