Skip to content

Replace Rvalue::NullaryOp by a variant in mir::Operand.#148766

Merged
bors merged 12 commits into
rust-lang:mainfrom
cjgillot:mir-const-runtime-checks
Dec 22, 2025
Merged

Replace Rvalue::NullaryOp by a variant in mir::Operand.#148766
bors merged 12 commits into
rust-lang:mainfrom
cjgillot:mir-const-runtime-checks

Conversation

@cjgillot

@cjgillot cjgillot commented Nov 9, 2025

Copy link
Copy Markdown
Contributor

Based on #148151

This PR fully removes the MIR Rvalue::NullaryOp. After #148151, it was only useful for runtime checks like ub_checks, contract_checks and overflow_checks.

These are "runtime" checks, boolean constants that may only be true in codegen. It depends on a rustc flag passed to codegen, so we need to represent those flags cross-crate.

This PR replaces those runtime checks by special variants in MIR ConstValue. This allows code that expects constants to manipulate those as such, even if we may not always be able to evaluate them to actual scalars.

@rustbot

rustbot commented Nov 9, 2025

Copy link
Copy Markdown
Collaborator

Some changes occurred to the CTFE machinery

cc @RalfJung, @oli-obk, @lcnr

Some changes occurred to the intrinsics. Make sure the CTFE / Miri interpreter
gets adapted for the changes, if necessary.

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

Some changes occurred in compiler/rustc_codegen_ssa

cc @WaffleLapkin

Some changes occurred in compiler/rustc_codegen_cranelift

cc @bjorn3

Some changes occurred to MIR optimizations

cc @rust-lang/wg-mir-opt

⚠️ #[rustc_intrinsic_const_stable_indirect] controls whether intrinsics can be exposed to stable const
code; adding it needs t-lang approval.

cc @rust-lang/wg-const-eval

Some changes occurred in rustc_ty_utils::consts.rs

cc @BoxyUwU

Some changes occurred in src/tools/clippy

cc @rust-lang/clippy

This PR changes MIR

cc @oli-obk, @RalfJung, @JakobDegen, @vakaras

Some changes occurred to the CTFE / Miri interpreter

cc @rust-lang/miri

This PR changes rustc_public

cc @oli-obk, @celinval, @ouz-a

Some changes occurred in match checking

cc @Nadrieril

Some changes occurred to constck

cc @fee1-dead

This PR changes a file inside tests/crashes. If a crash was fixed, please move into the corresponding ui subdir and add 'Fixes #' to the PR description to autoclose the issue upon merge.

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-clippy Relevant to the Clippy team. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Nov 9, 2025
@rustbot rustbot added the T-libs Relevant to the library team, which will review and decide on the PR/issue. label Nov 9, 2025
@rustbot

rustbot commented Nov 9, 2025

Copy link
Copy Markdown
Collaborator

r? @lcnr

rustbot has assigned @lcnr.
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

@rust-log-analyzer

This comment has been minimized.

@cjgillot cjgillot force-pushed the mir-const-runtime-checks branch from 9560745 to 741855c Compare November 9, 2025 20:34
@rust-log-analyzer

This comment has been minimized.

@cjgillot cjgillot force-pushed the mir-const-runtime-checks branch from 741855c to dcf0916 Compare November 9, 2025 21:54
Comment thread compiler/rustc_middle/src/mir/consts.rs Outdated
Comment on lines +74 to +76
/// Special constants whose value depends on the evaluation context. Their value depends on a
/// flag on the crate being codegenned.
RuntimeChecks(RuntimeChecks),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

For const-eval execution, their value is fixed, right?

@RalfJung

Copy link
Copy Markdown
Member

It seems slightly odd to call these things "constants" when they have a different value inside and outside of const blocks... I am not sure whether this actually breaks anything today, but it seems at least conceptually suboptimal and could lead to issues down the line. For instance, if a constant's body entirely consists just of one of these new constants, then replacing that outer constant by the inner one is not correct (or at least, it can change program behavior) -- so e.g. @saethlin's "trivial const" machinery might need a special case for this.

@bors

bors commented Nov 11, 2025

Copy link
Copy Markdown
Collaborator

☔ The latest upstream changes (presumably #148658) made this pull request unmergeable. Please resolve the merge conflicts.

@cjgillot

Copy link
Copy Markdown
Contributor Author

I agree that's not entirely satisfactory.

Another design would put the variant inside mir::Const, but the conversion RuntimeChecks -> ConstValue would be done in mir::Const::eval, so without access to the interpreter hooks. This makes everything more complex, and I haven't managed to get the correct behavior yet.

@RalfJung

Copy link
Copy Markdown
Member

That would be marginally better ("values" really should be unchanging), though still a footgun e.g. with the trivial const machinery I mentioned.

Making them a new variant of mir::Operand would be the conceptually cleanest option I think. Not sure how well it works in practice though.

@cjgillot cjgillot force-pushed the mir-const-runtime-checks branch from dcf0916 to 76bdfae Compare November 16, 2025 20:29
@rustbot

This comment has been minimized.

@cjgillot cjgillot force-pushed the mir-const-runtime-checks branch from 76bdfae to 68c2a27 Compare November 17, 2025 23:25
@rustbot

This comment has been minimized.

@cjgillot cjgillot changed the title Replace Rvalue::NullaryOp by a variant in mir::ConstValue. Replace Rvalue::NullaryOp by a variant in mir::Operand. Nov 17, 2025
@cjgillot

Copy link
Copy Markdown
Contributor Author

Making them a new variant of mir::Operand would be the conceptually cleanest option I think. Not sure how well it works in practice though.

Latest commit does that. Cleaner than I expected.

@rust-log-analyzer

This comment has been minimized.

@cjgillot cjgillot force-pushed the mir-const-runtime-checks branch from 68c2a27 to 4183df4 Compare November 18, 2025 00:33
@rustbot

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

Comment on lines +127 to +128
// We can't look at `tcx.sess` here as that can differ across crates, which can lead to
// unsound differences in evaluating the same constant at different instantiation sites.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This comment doesn't really make sense in the dummy machine.

Comment thread compiler/rustc_middle/src/mir/pretty.rs Outdated
Constant(ref a) => write!(fmt, "{a:?}"),
Copy(ref place) => write!(fmt, "copy {place:?}"),
Move(ref place) => write!(fmt, "move {place:?}"),
RuntimeChecks(checks) => write!(fmt, "const {checks:?}"),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

"const" is an odd choice, given that we moved it out of the constants

Comment thread compiler/rustc_middle/src/mir/syntax.rs Outdated
Comment thread compiler/rustc_middle/src/mir/statement.rs
@cjgillot cjgillot force-pushed the mir-const-runtime-checks branch from 4183df4 to 06de909 Compare November 19, 2025 01:23
@rustbot

This comment has been minimized.

@bors

bors commented Dec 22, 2025

Copy link
Copy Markdown
Collaborator

📌 Commit c67b99f has been approved by RalfJung,saethlin

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-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Dec 22, 2025
@bors

bors commented Dec 22, 2025

Copy link
Copy Markdown
Collaborator

⌛ Testing commit c67b99f with merge 000ccd6...

@bors

bors commented Dec 22, 2025

Copy link
Copy Markdown
Collaborator

☀️ Test successful - checks-actions
Approved by: RalfJung,saethlin
Pushing 000ccd6 to main...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Dec 22, 2025
@bors bors merged commit 000ccd6 into rust-lang:main Dec 22, 2025
12 checks passed
@rustbot rustbot added this to the 1.94.0 milestone Dec 22, 2025
@github-actions

Copy link
Copy Markdown
Contributor
What is this? This is an experimental post-merge analysis report that shows differences in test outcomes between the merged PR and its parent PR.

Comparing acfd264 (parent) -> 000ccd6 (this PR)

Test differences

Show 38 test diffs

38 doctest diffs were found. These are ignored, as they are noisy.

Test dashboard

Run

cargo run --manifest-path src/ci/citool/Cargo.toml -- \
    test-dashboard 000ccd651d6dfeab13f7703d92a5fd7a9ff7510f --output-dir test-dashboard

And then open test-dashboard/index.html in your browser to see an overview of all executed tests.

Job duration changes

  1. dist-aarch64-apple: 5610.5s -> 7968.1s (+42.0%)
  2. aarch64-apple: 17414.3s -> 13081.0s (-24.9%)
  3. dist-x86_64-apple: 8031.0s -> 9656.7s (+20.2%)
  4. dist-apple-various: 4528.6s -> 3767.5s (-16.8%)
  5. dist-aarch64-linux: 6148.2s -> 7055.4s (+14.8%)
  6. dist-aarch64-llvm-mingw: 6404.3s -> 5791.3s (-9.6%)
  7. dist-x86_64-solaris: 5687.6s -> 5153.8s (-9.4%)
  8. x86_64-gnu-llvm-20-1: 4921.9s -> 4475.4s (-9.1%)
  9. i686-gnu-2: 6181.4s -> 5653.4s (-8.5%)
  10. test-various: 6716.2s -> 7208.5s (+7.3%)
How to interpret the job duration changes?

Job durations can vary a lot, based on the actual runner instance
that executed the job, system noise, invalidated caches, etc. The table above is provided
mostly for t-infra members, for simpler debugging of potential CI slow-downs.

@rust-timer

Copy link
Copy Markdown
Collaborator

Finished benchmarking commit (000ccd6): comparison URL.

Overall result: ❌✅ regressions and improvements - please read the text below

Our benchmarks found a performance regression caused by this PR.
This might be an actual regression, but it can also be just noise.

Next Steps:

  • If the regression was expected or you think it can be justified,
    please write a comment with sufficient written justification, and add
    @rustbot label: +perf-regression-triaged to it, to mark the regression as triaged.
  • If you think that you know of a way to resolve the regression, try to create
    a new PR with a fix for the regression.
  • If you do not understand the regression or you think that it is just noise,
    you can ask the @rust-lang/wg-compiler-performance working group for help (members of this group
    were already notified of this PR).

@rustbot label: +perf-regression
cc @rust-lang/wg-compiler-performance

Instruction count

Our most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.

mean range count
Regressions ❌
(primary)
0.5% [0.1%, 1.4%] 33
Regressions ❌
(secondary)
0.3% [0.1%, 0.6%] 19
Improvements ✅
(primary)
-1.1% [-4.1%, -0.2%] 12
Improvements ✅
(secondary)
-0.7% [-1.8%, -0.0%] 13
All ❌✅ (primary) 0.1% [-4.1%, 1.4%] 45

Max RSS (memory usage)

Results (primary -2.5%, secondary -2.0%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
3.7% [3.7%, 3.7%] 1
Regressions ❌
(secondary)
1.7% [0.9%, 2.6%] 5
Improvements ✅
(primary)
-3.3% [-6.7%, -1.2%] 8
Improvements ✅
(secondary)
-3.6% [-5.6%, -1.0%] 11
All ❌✅ (primary) -2.5% [-6.7%, 3.7%] 9

Cycles

Results (primary -2.9%, secondary 1.2%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
4.0% [1.7%, 6.7%] 6
Improvements ✅
(primary)
-2.9% [-6.4%, -1.2%] 5
Improvements ✅
(secondary)
-2.2% [-2.7%, -1.7%] 5
All ❌✅ (primary) -2.9% [-6.4%, -1.2%] 5

Binary size

Results (primary 0.1%, secondary -0.1%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
0.4% [0.0%, 3.1%] 56
Regressions ❌
(secondary)
0.3% [0.0%, 3.1%] 26
Improvements ✅
(primary)
-0.3% [-1.9%, -0.0%] 31
Improvements ✅
(secondary)
-0.3% [-3.9%, -0.1%] 49
All ❌✅ (primary) 0.1% [-1.9%, 3.1%] 87

Bootstrap: 480.152s -> 481.34s (0.25%)
Artifact size: 390.54 MiB -> 390.37 MiB (-0.04%)

@scottmcm

scottmcm commented Dec 23, 2025

Copy link
Copy Markdown
Member

I think I can recover a bit of the regressions with #150265

bjorn3 pushed a commit to bjorn3/rust that referenced this pull request Dec 23, 2025
…=RalfJung,saethlin

Replace Rvalue::NullaryOp by a variant in mir::Operand.

Based on rust-lang#148151

This PR fully removes the MIR `Rvalue::NullaryOp`. After rust-lang#148151, it was only useful for runtime checks like `ub_checks`, `contract_checks` and `overflow_checks`.

These are "runtime" checks, boolean constants that may only be `true` in codegen. It depends on a rustc flag passed to codegen, so we need to represent those flags cross-crate.

This PR replaces those runtime checks by special variants in MIR `ConstValue`. This allows code that expects constants to manipulate those as such, even if we may not always be able to evaluate them to actual scalars.
@y1lan

y1lan commented Dec 24, 2025

Copy link
Copy Markdown
Contributor

Sorry to bother you, but I have a question regarding when RuntimeChecks operands are introduced into MIR.

I mean, how can I observe them? Would it be necessary by specifying any options like -Z? Or would it always be in all time?

I am currently working on an analysis based on the MIR model, and I would like to understand the precise semantics and introduction point of these operands more clearly.

Thank you for your time.

@bjorn3

bjorn3 commented Dec 24, 2025

Copy link
Copy Markdown
Member

RuntimeChecks are introduced in MIR when the respective option is enabled while compiling the function. And then during codegen it is checked again in case the function is codegened in a different crate. For overflow checks this is -Coverflow-checks and for UB checks it is -Zub-checks. In both cases they default to the value of -Cdebug-assertions when not overridden.

@y1lan

y1lan commented Dec 25, 2025

Copy link
Copy Markdown
Contributor

RuntimeChecks are introduced in MIR when the respective option is enabled while compiling the function. And then during codegen it is checked again in case the function is codegened in a different crate. For overflow checks this is -Coverflow-checks and for UB checks it is -Zub-checks. In both cases they default to the value of -Cdebug-assertions when not overridden.

is it possible to give me a concrete example which can show theses cases ? or where are these relative test cases in ?

@RalfJung

Copy link
Copy Markdown
Member

Please take this to Zulip or some other suitable venue. A merged PR is not a place for discussion, especially not for things that didn't get changed by that PR.

flip1995 pushed a commit to flip1995/rust that referenced this pull request Dec 25, 2025
…=RalfJung,saethlin

Replace Rvalue::NullaryOp by a variant in mir::Operand.

Based on rust-lang#148151

This PR fully removes the MIR `Rvalue::NullaryOp`. After rust-lang#148151, it was only useful for runtime checks like `ub_checks`, `contract_checks` and `overflow_checks`.

These are "runtime" checks, boolean constants that may only be `true` in codegen. It depends on a rustc flag passed to codegen, so we need to represent those flags cross-crate.

This PR replaces those runtime checks by special variants in MIR `ConstValue`. This allows code that expects constants to manipulate those as such, even if we may not always be able to evaluate them to actual scalars.
rust-bors Bot added a commit that referenced this pull request Jan 9, 2026
Stop emitting UbChecks on every Vec→Slice

Spotted this in #148766's test changes.  It doesn't seem like this ubcheck would catch anything useful; let's see if skipping it helps perf.  (After all, this is inside *every* `[]` on a vec, among other things.)
github-actions Bot pushed a commit to rust-lang/compiler-builtins that referenced this pull request Jan 29, 2026
Stop emitting UbChecks on every Vec→Slice

Spotted this in rust-lang/rust#148766's test changes.  It doesn't seem like this ubcheck would catch anything useful; let's see if skipping it helps perf.  (After all, this is inside *every* `[]` on a vec, among other things.)
tautschnig added a commit to tautschnig/kani that referenced this pull request Jul 8, 2026
Adapt kani-compiler to the rustc/rustc_public API changes in this window:

- rust-lang/rust#148766 (mir-const-runtime-checks): `Rvalue::NullaryOp` and
  `NullOp` were removed; `SizeOf`/`AlignOf`/`OffsetOf` become `mir::ConstValue`
  and the `ub_checks`/`contract_checks`/`overflow_checks` flags move to a new
  `Operand::RuntimeChecks(RuntimeChecks)`. Drop the `NullaryOp` match arms and
  handle `Operand::RuntimeChecks` everywhere `Operand` is matched (codegen it to
  `false`, as the old `NullOp::RuntimeChecks` was; treat it as a no-op in the
  points-to / uninit / MIR-internalization visitors).
- rust-lang/rust#150116: `FieldsShape::Arbitrary::memory_index` renamed to
  `in_memory_order` (Kani only uses its length).
- New `ValueAbi::ScalableVector` variant handled in the valid-value analysis.
- rust-lang/rust#6d6068f6c5b (stabilize annotate-snippet): `HumanReadableErrorType`
  became a struct `{ short, unicode }` instead of an enum with a `Default` variant.

Main suites pass on 12-31: expected (458), ui (144), kani (589), 0 failures.

Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
tautschnig added a commit to tautschnig/kani that referenced this pull request Jul 9, 2026
Three follow-ups from the nightly-2025-12-31 bump surfaced by CI:

- clippy `result_large_err` on `ensure_non_empty_span`: the `Err` type is
  rustc's `SpanSnippetError`, which grew and now trips the lint. `#[allow]` it
  (we can't shrink an upstream type).
- LLBC backend (`--features llbc`, not built in the default job): its
  `translate_operand` needs an arm for the new `Operand::RuntimeChecks`
  (rust-lang/rust#148766); left as `todo!()` like the backend's other
  unmodeled cases.
- The stub-cycle error ("Stub configuration for harness `..` has a cycle") also
  embedded a crate-qualified harness name (rust-lang/rust#149401); strip it,
  fixing cargo-kani/stubbing-double-extern-path.

Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
feliperodri pushed a commit to AlexanderPortland/kani that referenced this pull request Jul 11, 2026
Upgrade the toolchain to `nightly-2025-12-31` and adapt Kani to the
corresponding
`rustc`/`rustc_public` changes:

- **Crate-qualified names** (rust-lang/rust#149401): `name()` now
qualifies local
items with the crate name. Add a `strip_local_crate_prefix` helper and
keep
  harness/function/static pretty names, the recursion-tracker
`--nondet-static-exclude`, stubbing diagnostics, and the
autoharness/`list`
output crate-relative; fix the automatic contract-harness lookup
accordingly.
- **MIR runtime checks** (rust-lang/rust#148766):
`Rvalue::NullaryOp`/`NullOp`
  were removed and the `ub`/`contract`/`overflow` checks moved to
`Operand::RuntimeChecks`; update the CPROVER and LLBC codegen and the
related
  analyses.
- **`unsized_fn_params`**: the updated std passes unsized values by
value (e.g.
`impl … for [&str]`). Represent unsized-by-value arguments as fat
pointers so
they codegen instead of triggering an ICE (test under
`tests/kani/UnsizedFnParams`).
- Smaller adaptations: `FieldsShape::…::in_memory_order`
(rust-lang/rust#150116),
the new `ValueAbi::ScalableVector` variant, the `HumanReadableErrorType`
struct
  form, coercion/safety cleanups (rust-lang/rust#148602), a refreshed
`pointer_generator_error` expected file, and a
`clippy::result_large_err` allow.

Resolves: model-checking#4623

By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache 2.0 and MIT licenses.

---------

Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merged-by-bors This PR was explicitly merged by bors. perf-regression Performance regression. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-clippy Relevant to the Clippy team. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.