-
-
Notifications
You must be signed in to change notification settings - Fork 14.8k
adds better error message for temporary value does not live long enough #154810
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -3293,6 +3293,50 @@ 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) | ||||
| && 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 \ | ||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think it's a good idea to duplicate the message with rust/compiler/rustc_const_eval/src/errors.rs Line 296 in 1948ee1
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I totally agree. Though the borrow checker does not depend on rust_const_eval, what do you do in these situations? Should I move that under rustc_middle so that both can see that?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @JohnTitor I was trying with that but rustc_middle has some errors definitions that are only used inside that module, so I am not sure it would be a good fit. I could also make the borrowchecker depend on const_evals but it seems an overkill for a single diagnostic structure, what do you think? Do you have a place in mind where you would put that struct without needing an "invasive" change. |
||||
| 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; | ||||
| } | ||||
| } | ||||
|
|
||||
| if let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } = | ||||
| explanation | ||||
| { | ||||
|
|
||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<u32>); | ||
| 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 | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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`. |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
View changes since the review
I guess we could expand the fix for a similar case where promotion failed because the value is not
Freeze, like:The current only addresses the case issue mentioned, I guess it's kinda ad hoc. These cases should have the same diagnostics for consistency.