Skip to content

const-eval: allow constants to refer to mutable/external memory, but reject such constants as patterns #140942

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

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

RalfJung
Copy link
Member

@RalfJung RalfJung commented May 12, 2025

This fixes #140653 by accepting code such as this:

static FOO: AtomicU32 = AtomicU32::new(0);
const C: &'static AtomicU32 = &FOO;

This can be written entirely in safe code, so there can't really be anything wrong with it.

We also accept the much more questionable following code, since it looks very similar to the interpreter:

static mut FOO2: u32 = 0;
const C2: &'static u32 = unsafe { &mut FOO2 };

Using this without causing UB is at least very hard (the details are unclear since it is related to how the aliasing model deals with the staging of const-eval vs runtime code).

If a constant like C2 is used as a pattern, we emit an error:

error: constant BAD_PATTERN cannot be used as pattern
  --> $DIR/const_refs_to_static_fail.rs:30:9
   |
LL |         BAD_PATTERN => {},
   |         ^^^^^^^^^^^
   |
   = note: constants that reference mutable or external memory cannot be used as pattern

(If you somehow manage to build a pattern with constant C, you'd get the same error, but that should be impossible: we don't have a type that can be used in patterns and that has interior mutability.)

The same treatment is afforded for shared references to extern static, for the same reason: the const evaluation is entirely fine with it, we just can't build a pattern for it -- and when using interior mutability, this can be totally sound.

We do still not accept anything where there is an &mut in the final value of the const, as that should always require unsafe code and it's hard to imagine a sound use-case that would require this.

@rustbot
Copy link
Collaborator

rustbot commented May 12, 2025

r? @jieyouxu

rustbot has assigned @jieyouxu.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels May 12, 2025
@rustbot
Copy link
Collaborator

rustbot commented May 12, 2025

Some changes occurred to the CTFE machinery

cc @RalfJung, @oli-obk, @lcnr

Some changes occurred to the CTFE / Miri interpreter

cc @rust-lang/miri, @RalfJung, @oli-obk, @lcnr

Some changes occurred to the CTFE / Miri interpreter

cc @rust-lang/miri

@RalfJung RalfJung added T-lang Relevant to the language team S-waiting-on-team Status: Awaiting decision from the relevant subteam (see the T-<team> label). I-lang-nominated Nominated for discussion during a lang team meeting. labels May 12, 2025
@RalfJung
Copy link
Member Author

@rust-lang/lang nominating for FCP following prior discussion in #140653.

@rust-log-analyzer

This comment has been minimized.

@RalfJung RalfJung force-pushed the const-ref-to-mut branch from f619969 to 9767f96 Compare May 12, 2025 12:13
@rust-log-analyzer

This comment has been minimized.

@RalfJung RalfJung force-pushed the const-ref-to-mut branch from 9767f96 to 160cee0 Compare May 12, 2025 12:37
@rustbot
Copy link
Collaborator

rustbot commented May 12, 2025

Some changes occurred in src/tools/clippy

cc @rust-lang/clippy

@RalfJung RalfJung force-pushed the const-ref-to-mut branch from 160cee0 to e316943 Compare May 12, 2025 12:41
@RalfJung RalfJung force-pushed the const-ref-to-mut branch from e316943 to 6722d4d Compare May 12, 2025 13:01
@rust-log-analyzer

This comment has been minimized.

@jieyouxu
Copy link
Member

r? @oli-obk (or someone way more familiar with const-eval)

@rustbot rustbot assigned oli-obk and unassigned jieyouxu May 12, 2025
@RalfJung RalfJung force-pushed the const-ref-to-mut branch 2 times, most recently from 57ea31d to 6e9a7f4 Compare May 12, 2025 16:46
@traviscross traviscross removed the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label May 13, 2025
@traviscross
Copy link
Contributor

traviscross commented May 13, 2025

As discussed in #140653 (comment), this sounds right to me, and I propose that we do it.

@rfcbot fcp merge

@rfcbot
Copy link
Collaborator

rfcbot commented May 13, 2025

Team member @traviscross has proposed to merge this. The next step is review by the rest of the tagged team members:

Concerns:

Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

cc @rust-lang/lang-advisors: FCP proposed for lang, please feel free to register concerns.
See this document for info about what commands tagged team members can give me.

@rfcbot rfcbot added proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. labels May 13, 2025
@RalfJung
Copy link
Member Author

Reference PR: rust-lang/reference#1859

@rfcbot rfcbot added finished-final-comment-period The final comment period is finished for this PR / Issue. to-announce Announce this issue on triage meeting and removed final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. labels Jun 14, 2025
@rfcbot
Copy link
Collaborator

rfcbot commented Jun 14, 2025

The final comment period, with a disposition to merge, as per the review above, is now complete.

As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed.

This will be merged soon.

@RalfJung
Copy link
Member Author

@bors r=oli-obk

@bors
Copy link
Collaborator

bors commented Jun 14, 2025

📌 Commit 6f196f8 has been approved by oli-obk

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. S-waiting-on-team Status: Awaiting decision from the relevant subteam (see the T-<team> label). labels Jun 14, 2025
@RalfJung
Copy link
Member Author

@bors r-
I guess the reference PR has to land first?

@bors bors added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Jun 14, 2025
@traviscross traviscross added the S-waiting-on-documentation Status: Waiting on approved PRs to documentation before merging label Jun 15, 2025
@RalfJung
Copy link
Member Author

RalfJung commented Jun 18, 2025

@oli-obk based on @ehuss's questions in rust-lang/reference#1859, I made the "borrow of non-transient" error more uniform (use a shared error for raw and ref borrows, and use the same wording for mutable and interior mutable borrows), and made them explicitly talk about lifetime extension, since we have to wait for that reference PR anyway. If you prefer, I can also split this into a separate PR.

@rust-log-analyzer

This comment has been minimized.

@rustbot
Copy link
Collaborator

rustbot commented Jun 18, 2025

Some changes occurred to constck

cc @fee1-dead

@rust-log-analyzer

This comment has been minimized.

@@ -1,4 +1,4 @@
error[E0764]: mutable references are not allowed in the final value of constants
error[E0764]: mutable borrows of lifetime-extended temporaries are not allowed in constants
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still somewhat abbreviated... lifetime extension "within" constants is fine, it's just lifetime extension at the top-level scope where we restrict borrows. I couldn't think of a good way to concisely state this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't need to be concise if we add some more info at the label or in a note. That's probably worth it for this case that will otherwise send most ppl to having to ask for help in a forum

@rust-log-analyzer
Copy link
Collaborator

The job aarch64-gnu-llvm-19-1 failed! Check out the build log: (web) (plain)

Click to see the possible cause of the failure (guessed by this bot)
---- [ui] tests/ui/consts/const-mut-refs/mut_ref_in_final.rs stdout ----
Saved the actual stderr to `/checkout/obj/build/aarch64-unknown-linux-gnu/test/ui/consts/const-mut-refs/mut_ref_in_final/mut_ref_in_final.stderr`
diff of stderr:

4 LL | const B: *mut i32 = &mut 4;
5    |                     ^^^^^^
6 
- error[E0764]: mutable references are not allowed in the final value of constants
+ error[E0764]: mutable borrows of lifetime-extended temporaries are not allowed in constants
8   --> $DIR/mut_ref_in_final.rs:21:35
9    |
10 LL | const B3: Option<&mut i32> = Some(&mut 42);


The actual stderr differed from the expected stderr
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args consts/const-mut-refs/mut_ref_in_final.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: env -u RUSTC_LOG_COLOR RUSTC_ICE="0" RUST_BACKTRACE="short" "/checkout/obj/build/aarch64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs" "-Zthreads=1" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "-Z" "ignore-directory-in-diagnostics-source-blocks=/checkout/vendor" "--sysroot" "/checkout/obj/build/aarch64-unknown-linux-gnu/stage2" "--target=aarch64-unknown-linux-gnu" "--check-cfg" "cfg(test,FALSE)" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/aarch64-unknown-linux-gnu/test/ui/consts/const-mut-refs/mut_ref_in_final" "-A" "unused" "-A" "internal_features" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/aarch64-unknown-linux-gnu/native/rust-test-helpers"
stdout: none
--- stderr -------------------------------
error[E0764]: mutable borrows of lifetime-extended temporaries are not allowed in constants
##[error]  --> /checkout/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs:15:21
   |
LL | const B: *mut i32 = &mut 4; //~ ERROR mutable borrows of lifetime-extended temporaries
   |                     ^^^^^^

error[E0764]: mutable borrows of lifetime-extended temporaries are not allowed in constants
##[error]  --> /checkout/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs:21:35
   |
LL | const B3: Option<&mut i32> = Some(&mut 42); //~ ERROR mutable references are not allowed
   |                                   ^^^^^^^

error[E0716]: temporary value dropped while borrowed
##[error]  --> /checkout/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs:24:42
   |
LL | const B4: Option<&mut i32> = helper(&mut 42); //~ ERROR temporary value dropped while borrowed
   |                              ------------^^-
   |                              |           | |
   |                              |           | temporary value is freed at the end of this statement
   |                              |           creates a temporary value which is freed while still in use
   |                              using this value as a constant requires that borrow lasts for `'static`

error[E0080]: constructing invalid value: encountered mutable reference or box pointing to read-only memory
##[error]  --> /checkout/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs:27:1
   |
LL | const IMMUT_MUT_REF: &mut u16 = unsafe { mem::transmute(&13) };
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
   |
   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
   = note: the raw bytes of the constant (size: 8, align: 8) {
               ╾────alloc10<imm>─────╼                         │ ╾──────╼
           }

error[E0080]: constructing invalid value: encountered mutable reference or box pointing to read-only memory
##[error]  --> /checkout/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs:29:1
   |
LL | static IMMUT_MUT_REF_STATIC: &mut u16 = unsafe { mem::transmute(&13) };
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
   |
   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
   = note: the raw bytes of the constant (size: 8, align: 8) {
               ╾────alloc14<imm>─────╼                         │ ╾──────╼
           }

error[E0716]: temporary value dropped while borrowed
##[error]  --> /checkout/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs:52:65
   |
LL | const FOO: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42));
   |                                  -------------------------------^^--
   |                                  |                              |  |
   |                                  |                              |  temporary value is freed at the end of this statement
   |                                  |                              creates a temporary value which is freed while still in use
   |                                  using this value as a constant requires that borrow lasts for `'static`

error[E0716]: temporary value dropped while borrowed
##[error]  --> /checkout/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs:55:67
   |
LL | static FOO2: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42));
   |                                    -------------------------------^^--
   |                                    |                              |  |
   |                                    |                              |  temporary value is freed at the end of this statement
   |                                    |                              creates a temporary value which is freed while still in use
   |                                    using this value as a static requires that borrow lasts for `'static`

error[E0716]: temporary value dropped while borrowed
##[error]  --> /checkout/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs:58:71
   |
LL | static mut FOO3: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42));
   |                                        -------------------------------^^--
   |                                        |                              |  |
   |                                        |                              |  temporary value is freed at the end of this statement
   |                                        |                              creates a temporary value which is freed while still in use
   |                                        using this value as a static requires that borrow lasts for `'static`

error[E0764]: mutable borrows of lifetime-extended temporaries are not allowed in statics
##[error]  --> /checkout/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs:71:53
   |
LL | static RAW_MUT_CAST_S: SyncPtr<i32> = SyncPtr { x : &mut 42 as *mut _ as *const _ };
   |                                                     ^^^^^^^

error[E0764]: mutable borrows of lifetime-extended temporaries are not allowed in statics
##[error]  --> /checkout/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs:73:54
   |
LL | static RAW_MUT_COERCE_S: SyncPtr<i32> = SyncPtr { x: &mut 0 };
   |                                                      ^^^^^^

error[E0764]: mutable borrows of lifetime-extended temporaries are not allowed in constants
##[error]  --> /checkout/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs:75:52
   |
LL | const RAW_MUT_CAST_C: SyncPtr<i32> = SyncPtr { x : &mut 42 as *mut _ as *const _ };
   |                                                    ^^^^^^^

error[E0764]: mutable borrows of lifetime-extended temporaries are not allowed in constants
##[error]  --> /checkout/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs:77:53
   |
LL | const RAW_MUT_COERCE_C: SyncPtr<i32> = SyncPtr { x: &mut 0 };
   |                                                     ^^^^^^

error: aborting due to 12 previous errors

Some errors have detailed explanations: E0080, E0716, E0764.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. S-waiting-on-documentation Status: Waiting on approved PRs to documentation before merging T-lang Relevant to the language team to-announce Announce this issue on triage meeting
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Confusing error when a const contains a shared ref to interior mutable data