rust icon indicating copy to clipboard operation
rust copied to clipboard

`Vec::push` in consts MVP

Open fee1-dead opened this issue 2 months ago • 15 comments

Example:

const X: &'static [u32] = {
    let mut v = Vec::with_capacity(6);
    let mut x = 1;
    while x < 42 {
        v.push(x);
        x *= 2;
    }
    assert!(v.len() == 6);
    v.const_make_global()
};

assert_eq!([1, 2, 4, 8, 16, 32], X);

Oh this is fun...

  • We split out the implementation of Global such that it calls intrinsics::const_allocate and intrinsics::const_deallocate during compile time. This is achieved using const_eval_select
  • This allows us to impl const Allocator for Global
  • We then constify everything necessary for Vec::with_capacity and Vec::push.
  • Added Vec::const_leak to leak the final value via intrinsics::const_make_global. If we see any pointer in the final value of a const that did not call const_make_global, we error as implemented in rust-lang/rust#143595. (should we name the Vec method const_make_global as well?)

r? @rust-lang/wg-const-eval

To-do for me:

  • [x] Assess the rustdoc impact of additional bounds in the method
  • [ ] Increase test coverage

fee1-dead avatar Oct 19 '25 23:10 fee1-dead

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

Click to see the possible cause of the failure (guessed by this bot)

---- [mir-opt] tests/mir-opt/pre-codegen/drop_boxed_slice.rs stdout ----
25                         }
26                     }
27                     scope 18 (inlined <std::alloc::Global as Allocator>::deallocate) {
-                         let mut _9: *mut u8;
-                         scope 19 (inlined Layout::size) {
-                         }
-                         scope 20 (inlined NonNull::<u8>::as_ptr) {
-                         }
-                         scope 21 (inlined std::alloc::dealloc) {
-                             let mut _10: usize;
---
40                             }
41                         }


thread '[mir-opt] tests/mir-opt/pre-codegen/drop_boxed_slice.rs' panicked at src/tools/compiletest/src/runtest/mir_opt.rs:84:21:
Actual MIR output differs from expected MIR output /checkout/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir
stack backtrace:
   5: __rustc::rust_begin_unwind
             at /rustc/bb624dcb4c8ab987e10c0808d92d76f3b84dd117/library/std/src/panicking.rs:698:5
   6: core::panicking::panic_fmt
             at /rustc/bb624dcb4c8ab987e10c0808d92d76f3b84dd117/library/core/src/panicking.rs:75:14

rust-log-analyzer avatar Oct 20 '25 00:10 rust-log-analyzer

I think it'd make more sense for Box to go first since that is the most primitive type for heap allocations.

That will either require us doing a const_eval_select to do box_new in runtime and something else in compile time, or to constify box_new. I chose Vec because I thought it would be much more useful than Box.

fee1-dead avatar Oct 26 '25 18:10 fee1-dead

The job tidy failed! Check out the build log: (web) (plain enhanced) (plain)

Click to see the possible cause of the failure (guessed by this bot)
[TIMING:end] tool::ToolBuild { build_compiler: Compiler { stage: 0, host: x86_64-unknown-linux-gnu, forced_compiler: false }, target: x86_64-unknown-linux-gnu, tool: "tidy", path: "src/tools/tidy", mode: ToolBootstrap, source_type: InTree, extra_features: [], allow_features: "", cargo_args: [], artifact_kind: Binary } -- 10.487
[TIMING:end] tool::Tidy { compiler: Compiler { stage: 0, host: x86_64-unknown-linux-gnu, forced_compiler: false }, target: x86_64-unknown-linux-gnu } -- 0.000
fmt check
Diff in /checkout/library/alloc/src/vec/mod.rs:855:
     /// values of constants.
     #[unstable(feature = "const_heap", issue = "79597")]
     #[rustc_const_unstable(feature = "const_heap", issue = "79597")]
-    pub const fn const_make_global(mut self) -> &'static [T] where T: Freeze {
+    pub const fn const_make_global(mut self) -> &'static [T]
+    where
+        T: Freeze,
+    {
         unsafe { core::intrinsics::const_make_global(self.as_mut_ptr().cast()) };
         let me = ManuallyDrop::new(self);
         unsafe { slice::from_raw_parts(me.as_ptr(), me.len) }
fmt: checked 6504 files
Bootstrap failed while executing `test src/tools/tidy tidyselftest --extra-checks=py,cpp,js,spellcheck`
Build completed unsuccessfully in 0:00:47
  local time: Sun Oct 26 18:50:03 UTC 2025
  network time: Sun, 26 Oct 2025 18:50:03 GMT

rust-log-analyzer avatar Oct 26 '25 18:10 rust-log-analyzer

The job x86_64-gnu-gcc failed! Check out the build log: (web) (plain enhanced) (plain)

Click to see the possible cause of the failure (guessed by this bot)
test [codegen-units] tests/codegen-units/item-collection/non-generic-closures.rs ... ok
test [codegen-units] tests/codegen-units/item-collection/static-init.rs ... ok
test [codegen-units] tests/codegen-units/item-collection/statics-and-consts.rs ... ok
test [codegen-units] tests/codegen-units/item-collection/overloaded-operators.rs ... ok
FATAL: !(missing.is_empty() && unexpected.is_empty() && wrong_cgus.is_empty())
test [codegen-units] tests/codegen-units/item-collection/opaque-return-impls.rs ... FAILED
test [codegen-units] tests/codegen-units/item-collection/trait-implementations.rs ... ok
test [codegen-units] tests/codegen-units/item-collection/trait-method-default-impl.rs ... ok
test [codegen-units] tests/codegen-units/item-collection/trait-method-as-argument.rs ... ok
test [codegen-units] tests/codegen-units/item-collection/transitive-drop-glue.rs ... ok
---


These items were contained but should not have been:

MONO_ITEM fn std::alloc::Global::alloc_impl_runtime @@ opaque_return_impls.a116a005f37f8ef5-cgu.0[Internal]



thread '[codegen-units] tests/codegen-units/item-collection/opaque-return-impls.rs' panicked at src/tools/compiletest/src/runtest/codegen_units.rs:111:13:
fatal error

For more information how to resolve CI failures of this job, visit this link.

rust-log-analyzer avatar Oct 26 '25 19:10 rust-log-analyzer

@bors try @rust-timer queue This affects core pieces of vec and alloc, let's make sure everything gets optimized well

oli-obk avatar Oct 26 '25 20:10 oli-obk

Awaiting bors try build completion.

@rustbot label: +S-waiting-on-perf

rust-timer avatar Oct 26 '25 20:10 rust-timer

:hourglass: Trying commit aded02cb5b4e87368ad75fa038e088dcf0b701d7 with merge b3f7ade975cf0d5d02740da43e496064c977dfb4…

To cancel the try build, run the command @bors try cancel.

Workflow: https://github.com/rust-lang/rust/actions/runs/18823449504

rust-bors[bot] avatar Oct 26 '25 20:10 rust-bors[bot]

:sunny: Try build successful (CI) Build commit: b3f7ade975cf0d5d02740da43e496064c977dfb4 (b3f7ade975cf0d5d02740da43e496064c977dfb4, parent: f977dfc388ea39c9886b7f8c49abce26e6918df6)

rust-bors[bot] avatar Oct 26 '25 22:10 rust-bors[bot]

Queued b3f7ade975cf0d5d02740da43e496064c977dfb4 with parent f977dfc388ea39c9886b7f8c49abce26e6918df6, future comparison URL. There is currently 1 preceding artifact in the queue. It will probably take at least ~1.1 hours until the benchmark run finishes.

rust-timer avatar Oct 26 '25 22:10 rust-timer

Finished benchmarking commit (b3f7ade975cf0d5d02740da43e496064c977dfb4): comparison URL.

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

Benchmarking this pull request means it may be perf-sensitive – we'll automatically label it not fit for rolling up. You can override this, but we strongly advise not to, due to possible changes in compiler perf.

Next Steps: If you can justify the regressions found in this try perf run, please do so in sufficient writing along with @rustbot label: +perf-regression-triaged. If not, please fix the regressions and do another perf run. If its results are neutral or positive, the label will be automatically removed.

@bors rollup=never @rustbot label: -S-waiting-on-perf +perf-regression

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.3% [0.3%, 0.3%] 1
Regressions ❌
(secondary)
0.2% [0.1%, 0.2%] 3
Improvements ✅
(primary)
-0.6% [-0.6%, -0.6%] 1
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) -0.2% [-0.6%, 0.3%] 2

Max RSS (memory usage)

Results (primary 0.4%, secondary -0.3%)

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

mean range count
Regressions ❌
(primary)
2.7% [1.3%, 4.5%] 5
Regressions ❌
(secondary)
3.7% [3.7%, 3.7%] 1
Improvements ✅
(primary)
-2.0% [-3.3%, -0.4%] 5
Improvements ✅
(secondary)
-2.3% [-3.1%, -1.6%] 2
All ❌✅ (primary) 0.4% [-3.3%, 4.5%] 10

Cycles

Results (primary 3.3%)

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

mean range count
Regressions ❌
(primary)
3.3% [3.3%, 3.3%] 1
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) 3.3% [3.3%, 3.3%] 1

Binary size

Results (primary 0.3%, secondary 0.6%)

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%, 1.5%] 33
Regressions ❌
(secondary)
0.6% [0.0%, 1.0%] 66
Improvements ✅
(primary)
-0.2% [-0.5%, -0.0%] 5
Improvements ✅
(secondary)
-0.1% [-0.1%, -0.1%] 1
All ❌✅ (primary) 0.3% [-0.5%, 1.5%] 38

Bootstrap: 473.751s -> 473.82s (0.01%) Artifact size: 390.43 MiB -> 390.55 MiB (0.03%)

rust-timer avatar Oct 27 '25 00:10 rust-timer

Yeah, rustdoc output is non-ideal. It shows all the where A: Allocator bounds. #148434 could probably make this better?

fee1-dead avatar Nov 03 '25 18:11 fee1-dead

:umbrella: The latest upstream changes (presumably #148573) made this pull request unmergeable. Please resolve the merge conflicts.

bors avatar Nov 06 '25 19:11 bors

The job tidy failed! Check out the build log: (web) (plain enhanced) (plain)

Click to see the possible cause of the failure (guessed by this bot)
fmt check
error: expected identifier, found keyword `impl`
##[error]   --> /checkout/library/alloc/src/raw_vec/mod.rs:168:7
    |
168 | const impl<T, A: [const] Allocator + [const] Destruct> RawVec<T, A> {
    |       ^^^^ expected identifier, found keyword

error: expected identifier, found keyword `impl`
##[error]   --> /checkout/library/alloc/src/vec/mod.rs:850:7
    |
850 | const impl<T, A: [const] Allocator + [const] Destruct> Vec<T, A> {
    |       ^^^^ expected identifier, found keyword

fmt: checked 6563 files
Bootstrap failed while executing `test src/tools/tidy tidyselftest --extra-checks=py,cpp,js,spellcheck`
Build completed unsuccessfully in 0:00:47

rust-log-analyzer avatar Nov 22 '25 02:11 rust-log-analyzer

The job tidy failed! Check out the build log: (web) (plain enhanced) (plain)

Click to see the possible cause of the failure (guessed by this bot)
fmt check
error: expected identifier, found keyword `impl`
##[error]   --> /checkout/library/alloc/src/raw_vec/mod.rs:169:7
    |
169 | const impl<T, A: [const] Allocator + [const] Destruct> RawVec<T, A> {
    |       ^^^^ expected identifier, found keyword

error: expected identifier, found keyword `impl`
##[error]   --> /checkout/library/alloc/src/vec/mod.rs:851:7
    |
851 | const impl<T, A: [const] Allocator + [const] Destruct> Vec<T, A> {
    |       ^^^^ expected identifier, found keyword

fmt: checked 6563 files
Bootstrap failed while executing `test src/tools/tidy tidyselftest --extra-checks=py,cpp,js,spellcheck`
Build completed unsuccessfully in 0:00:49

rust-log-analyzer avatar Nov 22 '25 03:11 rust-log-analyzer

The doc issue is somewhat alleviated by splitting the constified impl into its own block. This seems fine for rustdoc to handle, and it just displays two impl blocks instead of displaying duplicated A: Allocator bounds.

tidy uses the beta rustfmt and not nightly, so we need to wait until the parser changes make their way into rustfmt, or find out someway for rustfmt to skip parsing a file entirely

fee1-dead avatar Nov 22 '25 03:11 fee1-dead

:umbrella: The latest upstream changes (presumably #149979) made this pull request unmergeable. Please resolve the merge conflicts.

bors avatar Dec 14 '25 16:12 bors