-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Tracking issue for &mut T
in const contexts (const_mut_refs)
#57349
Comments
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
leading_zeroes and this kind of functions are const-ready since 1.34.0 We neeed rust-lang/rust#57349 to constantize further.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
Stabilize `&mut` (and `*mut`) as well as `&Cell` (and `*const Cell`) in const This stabilizes `const_mut_refs` and `const_refs_to_cell`. That allows a bunch of new things in const contexts: - Mentioning `&mut` types - Creating `&mut` and `*mut` values - Creating `&T` and `*const T` values where `T` contains interior mutability - Dereferencing `&mut` and `*mut` values (both for reads and writes) The same rules as at runtime apply: mutating immutable data is UB. This includes mutation through pointers derived from shared references; the following is diagnosed with a hard error: ```rust #[allow(invalid_reference_casting)] const _: () = { let mut val = 15; let ptr = &val as *const i32 as *mut i32; unsafe { *ptr = 16; } }; ``` The main limitation that is enforced is that the final value of a const (or non-`mut` static) may not contain `&mut` values nor interior mutable `&` values. This is necessary because the memory those references point to becomes *read-only* when the constant is done computing, so (interior) mutable references to such memory would be pretty dangerous. We take a multi-layered approach here to ensuring no mutable references escape the initializer expression: - A static analysis rejects (interior) mutable references when the referee looks like it may outlive the current MIR body. - To be extra sure, this static check is complemented by a "safety net" of dynamic checks. ("Dynamic" in the sense of "running during/after const-evaluation, e.g. at runtime of this code" -- in contrast to "static" which works entirely by looking at the MIR without evaluating it.) - After the final value is computed, we do a type-driven traversal of the entire value, and if we find any `&mut` or interior-mutable `&` we error out. - However, the type-driven traversal cannot traverse `union` or raw pointers, so there is a second dynamic check where if the final value of the const contains any pointer that was not derived from a shared reference, we complain. This is currently a future-compat lint, but will become an ICE in rust-lang#128543. On the off-chance that it's actually possible to trigger this lint on stable, I'd prefer if we could make it an ICE before stabilizing const_mut_refs, but it's not a hard blocker. This part of the "safety net" is only active for mutable references since with shared references, it has false positives. Altogether this should prevent people from leaking (interior) mutable references out of the const initializer. While updating the tests I learned that surprisingly, this code gets rejected: ```rust const _: Vec<i32> = { let mut x = Vec::<i32>::new(); //~ ERROR destructor of `Vec<i32>` cannot be evaluated at compile-time let r = &mut x; let y = x; y }; ``` The analysis that rejects destructors in `const` is very conservative when it sees an `&mut` being created to `x`, and then considers `x` to be always live. See [here](rust-lang#65394 (comment)) for a longer explanation. `const_precise_live_drops` will solve this, so I consider this problem to be tracked by rust-lang#73255. Cc `@rust-lang/wg-const-eval` `@rust-lang/lang` Cc rust-lang#57349 Cc rust-lang#80384
Rollup merge of rust-lang#129195 - RalfJung:const-mut-refs, r=fee1-dead Stabilize `&mut` (and `*mut`) as well as `&Cell` (and `*const Cell`) in const This stabilizes `const_mut_refs` and `const_refs_to_cell`. That allows a bunch of new things in const contexts: - Mentioning `&mut` types - Creating `&mut` and `*mut` values - Creating `&T` and `*const T` values where `T` contains interior mutability - Dereferencing `&mut` and `*mut` values (both for reads and writes) The same rules as at runtime apply: mutating immutable data is UB. This includes mutation through pointers derived from shared references; the following is diagnosed with a hard error: ```rust #[allow(invalid_reference_casting)] const _: () = { let mut val = 15; let ptr = &val as *const i32 as *mut i32; unsafe { *ptr = 16; } }; ``` The main limitation that is enforced is that the final value of a const (or non-`mut` static) may not contain `&mut` values nor interior mutable `&` values. This is necessary because the memory those references point to becomes *read-only* when the constant is done computing, so (interior) mutable references to such memory would be pretty dangerous. We take a multi-layered approach here to ensuring no mutable references escape the initializer expression: - A static analysis rejects (interior) mutable references when the referee looks like it may outlive the current MIR body. - To be extra sure, this static check is complemented by a "safety net" of dynamic checks. ("Dynamic" in the sense of "running during/after const-evaluation, e.g. at runtime of this code" -- in contrast to "static" which works entirely by looking at the MIR without evaluating it.) - After the final value is computed, we do a type-driven traversal of the entire value, and if we find any `&mut` or interior-mutable `&` we error out. - However, the type-driven traversal cannot traverse `union` or raw pointers, so there is a second dynamic check where if the final value of the const contains any pointer that was not derived from a shared reference, we complain. This is currently a future-compat lint, but will become an ICE in rust-lang#128543. On the off-chance that it's actually possible to trigger this lint on stable, I'd prefer if we could make it an ICE before stabilizing const_mut_refs, but it's not a hard blocker. This part of the "safety net" is only active for mutable references since with shared references, it has false positives. Altogether this should prevent people from leaking (interior) mutable references out of the const initializer. While updating the tests I learned that surprisingly, this code gets rejected: ```rust const _: Vec<i32> = { let mut x = Vec::<i32>::new(); //~ ERROR destructor of `Vec<i32>` cannot be evaluated at compile-time let r = &mut x; let y = x; y }; ``` The analysis that rejects destructors in `const` is very conservative when it sees an `&mut` being created to `x`, and then considers `x` to be always live. See [here](rust-lang#65394 (comment)) for a longer explanation. `const_precise_live_drops` will solve this, so I consider this problem to be tracked by rust-lang#73255. Cc `@rust-lang/wg-const-eval` `@rust-lang/lang` Cc rust-lang#57349 Cc rust-lang#80384
const fn API currently awaiting checkboxes:
|
There's more:
And things that only very recently even got implemented (updated based on comments below): |
There's also |
This has just been implemented. Let's maybe let it bake on nightly for a bit? |
…dtolnay Mark `char::make_ascii_uppercase` and `char::make_ascii_lowercase` as const. Relevant tracking issue: rust-lang#130698 The `make_ascii_uppercase` and `make_ascii_lowercase` methods in `char` should be marked "const." With the stabilisation of [`const_mut_refs`](rust-lang#57349), this simply requires adding the `const` specifier to the function signatures.
Mark `char::make_ascii_uppercase` and `char::make_ascii_lowercase` as const. Relevant tracking issue: #130698 The `make_ascii_uppercase` and `make_ascii_lowercase` methods in `char` should be marked "const." With the stabilisation of [`const_mut_refs`](rust-lang/rust#57349), this simply requires adding the `const` specifier to the function signatures.
Mark `char::make_ascii_uppercase` and `char::make_ascii_lowercase` as const. Relevant tracking issue: #130698 The `make_ascii_uppercase` and `make_ascii_lowercase` methods in `char` should be marked "const." With the stabilisation of [`const_mut_refs`](rust-lang/rust#57349), this simply requires adding the `const` specifier to the function signatures.
…om_raw_parts_mut, r=workingjubilee Stabilize `const_slice_from_raw_parts_mut` Stabilizes rust-lang#67456, since rust-lang#57349 has been stabilized. Stabilized const API: ```rust // core::ptr pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T]; // core::slice pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T]; // core::ptr::NonNull pub const fn slice_from_raw_parts(data: NonNull<T>, len: usize) -> Self ``` Closes rust-lang#67456. r? libs-api
…om_raw_parts_mut, r=workingjubilee Stabilize `const_slice_from_raw_parts_mut` Stabilizes rust-lang#67456, since rust-lang#57349 has been stabilized. Stabilized const API: ```rust // core::ptr pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T]; // core::slice pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T]; // core::ptr::NonNull pub const fn slice_from_raw_parts(data: NonNull<T>, len: usize) -> Self ``` Closes rust-lang#67456. r? libs-api
…_raw_parts_mut, r=workingjubilee Stabilize `const_slice_from_raw_parts_mut` Stabilizes rust-lang#67456, since rust-lang#57349 has been stabilized. Stabilized const API: ```rust // core::ptr pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T]; // core::slice pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T]; // core::ptr::NonNull pub const fn slice_from_raw_parts(data: NonNull<T>, len: usize) -> Self ``` Closes rust-lang#67456. r? libs-api
…om_raw_parts_mut, r=workingjubilee Stabilize `const_slice_from_raw_parts_mut` Stabilizes rust-lang#67456, since rust-lang#57349 has been stabilized. Stabilized const API: ```rust // core::ptr pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T]; // core::slice pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T]; // core::ptr::NonNull pub const fn slice_from_raw_parts(data: NonNull<T>, len: usize) -> Self ``` Closes rust-lang#67456. r? libs-api
Rollup merge of rust-lang#130403 - eduardosm:stabilize-const_slice_from_raw_parts_mut, r=workingjubilee Stabilize `const_slice_from_raw_parts_mut` Stabilizes rust-lang#67456, since rust-lang#57349 has been stabilized. Stabilized const API: ```rust // core::ptr pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T]; // core::slice pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T]; // core::ptr::NonNull pub const fn slice_from_raw_parts(data: NonNull<T>, len: usize) -> Self ``` Closes rust-lang#67456. r? libs-api
Is there a discussion thread for this? I've searched multiple RFCs, but I can't find a single one mentioning iterators. If I'm not mistaken, this feature is a big step forward to support |
requiring const trait impls means that normal iterators are most likely rather far out. |
Iterators are still blocked on being able to call trait functions in const, which is unfortunately quite tricky. See:
Also, closed issue are not a support forum, so I'll lock this -- too many people get notifications in this one to make it a good place for support questions. |
The
const_mut_refs
feature gate allows the following in const context:&mut
arguments&mut
andaddr_of_mut!
expressions)*
expressions)Remaining work
static mut FOO: &'static mut i32 = &mut 42;
is problematic, because LLVM currently duplicates the inner mutable reference when you dostatic mut BAR: &'static mut i32 = FOO;
. It would probably suffice to give all nested allocations in a static names relative to their original static item. Named allocations are neither deduplicated nor duplicated.const
relies on types more than it should, given thattransmute
is available in consts. Fixed in const-eval interning: get rid of type-driven traversal #119044.&mut
(and*mut
) as well as&Cell
(and*const Cell
) in const #129195Open questions
index out of bounds: the len is 5 but the index is 5
#122399, ICE: hir: index out of bounds: the len is 5 but the index is 5 rustc_codegen_gcc#473The text was updated successfully, but these errors were encountered: