Skip to content
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

Closed
4 of 8 tasks
Tracked by #9
ExpHP opened this issue Jan 5, 2019 · 103 comments · Fixed by rust-lang/reference#1590
Closed
4 of 8 tasks
Tracked by #9

Tracking issue for &mut T in const contexts (const_mut_refs) #57349

ExpHP opened this issue Jan 5, 2019 · 103 comments · Fixed by rust-lang/reference#1590
Assignees
Labels
A-const-eval Area: Constant evaluation (MIR interpretation) A-const-fn Area: const fn foo(..) {..}. Pure functions which can be applied at compile time. B-unstable Blocker: Implemented in the nightly compiler and unstable. C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. F-const_mut_refs `#![feature(const_mut_refs)]` T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@ExpHP
Copy link
Contributor

ExpHP commented Jan 5, 2019

The const_mut_refs feature gate allows the following in const context:

  • &mut arguments
  • mutable (re)borrows and raw pointers (&mut and addr_of_mut! expressions)
  • dereferencing mutable references and raw pointers (* expressions)

Remaining work

Open questions

@Centril Centril added T-lang Relevant to the language team, which will review and decide on the PR/issue. C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. needs-rfc This change is large or controversial enough that it should have an RFC accepted before doing it. labels Jan 5, 2019
@Centril Centril changed the title Mutation in const fn Tracking issue for &mut T in const fn Jan 5, 2019
@Centril

This comment was marked as resolved.

@Centril Centril added A-const-fn Area: const fn foo(..) {..}. Pure functions which can be applied at compile time. A-const-eval Area: Constant evaluation (MIR interpretation) labels Jan 5, 2019
@alercah

This comment was marked as resolved.

@eddyb

This comment was marked as resolved.

lu-zero added a commit to rust-av/rav1e that referenced this issue Jul 20, 2019
leading_zeroes and this kind of functions are const-ready since 1.34.0
We neeed rust-lang/rust#57349 to constantize
further.
@elichai

This comment was marked as resolved.

@tema3210

This comment was marked as resolved.

@cramertj

This comment was marked as resolved.

@eddyb

This comment was marked as resolved.

@RalfJung

This comment was marked as resolved.

@eddyb

This comment was marked as resolved.

@oli-obk oli-obk removed the needs-rfc This change is large or controversial enough that it should have an RFC accepted before doing it. label Jul 29, 2020
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Sep 15, 2024
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
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Sep 15, 2024
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
@ehuss ehuss closed this as completed Sep 15, 2024
@workingjubilee
Copy link
Member

workingjubilee commented Sep 19, 2024

@bjoernager
Copy link
Contributor

bjoernager commented Sep 19, 2024

There's also char::encode_utf8: #130512

@RalfJung
Copy link
Member

This has just been implemented. Let's maybe let it bake on nightly for a bit?

@onestacked
Copy link
Contributor

#67456 needs an FCP started for Stabilization PR #130403

bors added a commit to rust-lang-ci/rust that referenced this issue Sep 22, 2024
…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.
github-actions bot pushed a commit to rust-lang/miri that referenced this issue Sep 25, 2024
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.
lnicola pushed a commit to lnicola/rust-analyzer that referenced this issue Sep 25, 2024
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.
workingjubilee added a commit to workingjubilee/rustc that referenced this issue Oct 4, 2024
…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
workingjubilee added a commit to workingjubilee/rustc that referenced this issue Oct 4, 2024
…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
bors added a commit to rust-lang-ci/rust that referenced this issue Oct 4, 2024
…_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
workingjubilee added a commit to workingjubilee/rustc that referenced this issue Oct 5, 2024
…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
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Oct 5, 2024
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
@Rudxain
Copy link
Contributor

Rudxain commented Oct 29, 2024

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 const iteration. We already have const loops, so I can feel core::iter is soon becoming const too!

@Lokathor
Copy link
Contributor

requiring const trait impls means that normal iterators are most likely rather far out.

@RalfJung
Copy link
Member

RalfJung commented Oct 29, 2024

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.

@rust-lang rust-lang locked as off-topic and limited conversation to collaborators Oct 29, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
A-const-eval Area: Constant evaluation (MIR interpretation) A-const-fn Area: const fn foo(..) {..}. Pure functions which can be applied at compile time. B-unstable Blocker: Implemented in the nightly compiler and unstable. C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. F-const_mut_refs `#![feature(const_mut_refs)]` T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.