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 · 100 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 · 100 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
@oli-obk oli-obk removed the S-tracking-impl-incomplete Status: The implementation is incomplete. label Mar 14, 2024
@RalfJung
Copy link
Member

RalfJung commented Mar 14, 2024

We do have a potential blocker still, unfortunately: the new interner is still on probation due to #121610. The mutability check in the interner is currently a lint (#122204). My entire motivation for that interner was to make that check a hard error and I feel uneasy stabilizing const_mut_refs until we can make it a hard error.

@RalfJung
Copy link
Member

The tracking issue lists this was part of this feature

non-initialization assignments could be made (x = y; or *x = y;).

But in fact such assignments are already stable... looks like that feature gate was split up at some point.

@tarcieri
Copy link
Contributor

tarcieri commented Sep 4, 2024

@RalfJung does #128543 resolve #121610, and if so, is it the only blocker for proceeding with a stabilization report for const_mut_refs?

@RalfJung
Copy link
Member

RalfJung commented Sep 4, 2024

Ah, I should have given an update here: with #129508 having landed, I no longer think #121610 is a blocker for stabilization. The stabilization PR for this (and const_refs_to_cell) is up at #129195, which also contains the stabilization report. :)

@clarfonthey
Copy link
Contributor

clarfonthey commented Sep 6, 2024

Is there a central place for all of the library APIs that are blocked by this feature being stabilised (so we can look into stabilising them), or is that something that still needs to be put together?

Since there are a lot of things that are not const-stabilised because they contain mut refs, separately from this feature.

@RalfJung
Copy link
Member

RalfJung commented Sep 6, 2024 via email

@usbalbin
Copy link
Contributor

usbalbin commented Sep 7, 2024

There is this thing https://rust-lang.github.io/const-eval/skill_tree.html

However i am not sure if it is up to date

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
@workingjubilee
Copy link
Member

workingjubilee commented Sep 19, 2024

@RalfJung
Copy link
Member

@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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
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.