Skip to content

Rust compiler hangs when compiling code with zip-related benchmarks #116624

Open
@iamanonymouscs

Description

@iamanonymouscs

I tried this code:

Command

rustc -C opt-level=0  /home/interesting/hang_10.rs

Code

#![allow(dead_code)]
#![feature(array_zip, maybe_uninit_array_assume_init, maybe_uninit_uninit_array)]
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use rand::{rngs::OsRng, Rng};
use std::mem::MaybeUninit;
macro_rules! defbenches {
    ($c:ident, $fn:path, $intype:ty, [$($len:literal),+$(,)?]) => {{
        $(defbenches!(@ops $c, $fn, $intype, $len);)+
    }};
    (@ops $c:ident, $fn:path, $intype:ty, $len:literal) => {{
        let a: [$intype; $len] = OsRng.gen();
        let b: [$intype; $len] = OsRng.gen();
        defbenches!(@final $c, $fn, $intype, $len, +, a, b);
        defbenches!(@final $c, $fn, $intype, $len, -, a, b);
        defbenches!(@final $c, $fn, $intype, $len, *, a, b);
        defbenches!(@final $c, $fn, $intype, $len, &, a, b);
        defbenches!(@final $c, $fn, $intype, $len, |, a, b);
        defbenches!(@final $c, $fn, $intype, $len, ^, a, b);
    }};
    (@final $c:ident, $fn:path, $intype:ty, $len:literal, $op:tt, $a:ident, $b:ident) => {{
        $c.bench_function(

            || black_box($fn($a, $b, |a, b| a $op b)),
            || black_box($fn($a, $b, |a, b| b $op a)),
            || black_box($fn($a, $b, |a, b| a $op b)),
            || black_box($fn($a, $b, |a, b| b $op a)),
            || black_box($fn($a, $b, |a, b| a $op b)),
            || black_box($fn($a, $b, |a, b| b $op a)),
            || black_box($fn($a, $b, |a, b| a $op b)),
            || black_box($fn($a, $b, |a, b| b $op a)),
            || black_box($fn($a, $b, |a, b| a $op b)),
            || black_box($fn($a, $b, |a, b| b $op a)),
            || black_box($fn($a, $b, |a, b| a $op b)),
            || black_box($fn($a, $b, |a, b| b $op a)),
            || black_box($fn($a, $b, |a, b| a $op b)),
            || black_box($fn($a, $b, |a, b| b $op a)),
            || black_box($fn($a, $b, |a, b| a $op b)),

            |b| {
                b.iter(|| black_box($fn($a, $b, |a, b| a $op b)));
            },
        );
    }};
}
fn benchmark_primitives(c: &mut Criterion) {
    defbenches!(c, zip_with, u8, [8, 16, 32, 64, 128]);
    defbenches!(c, zip_map_std, u8, [8, 16, 32, 64, 128]);
    defbenches!(c, zip_map_fl, u8, [8, 16, 32, 64, 128]);
    defbenches!(c, zip_with, u16, [8, 16, 32, 64, 128, 256, 512]);
    defbenches!(c, zip_map_std, u16, [8, 16, 32, 64, 128, 256, 512]);
    defbenches!(c, zip_map_fl, u16, [8, 16, 32, 64, 128, 256, 512]);
    defbenches!(c, zip_with, u32, [8, 16, 32, 64, 128, 256, 512]);
    defbenches!(c, zip_map_std, u32, [8, 16, 32, 64, 128, 256, 512]);
    defbenches!(c, zip_map_fl, u32, [8, 16, 32, 64, 128, 256, 512]);
    defbenches!(c, zip_with, u64, [8, 16, 32, 64, 128, 256, 512]);
    defbenches!(c, zip_map_std, u64, [8, 16, 32, 64, 128, 256, 512]);
    defbenches!(c, zip_map_fl, u64, [8, 16, 32, 64, 128, 256, 512]);
}
struct ZipWithGuard<T, U, const N: usize> {
    a: *mut [T; N],
    b: *mut [U; N],
    moved: usize,
}
impl<T, U, const N: usize> Drop for ZipWithGuard<T, U, N> {
    fn drop(&mut self) {
        if needs_drop::<T>() || needs_drop::<U>() {
            for i in self.moved + 1..N {
                unsafe {
                    drop(self.a.cast::<T>().add(i).read());
                    drop(self.b.cast::<U>().add(i).read());
                }
            }
        }
    }
}
pub fn zip_with<T, U, V, F: FnMut(T, U) -> V, const N: usize>(
    a: [T; N],
    b: [U; N],
    mut f: F,
) -> [V; N] {
    let aref = &a as *const _ as *mut [ManuallyDrop<T>; N];
    forget(a);
    let bref = &b as *const _ as *mut [ManuallyDrop<U>; N];
    forget(b);
    let mut guard = ZipWithGuard {
        a: aref,
        b: bref,
        moved: 0,
    };
    let mut out: MaybeUninit<[V; N]> = unsafe { MaybeUninit::uninit().assume_init() };
    let out_ptr = out.as_mut_ptr().cast::<MaybeUninit<V>>();
    while guard.moved < N {
        let i = guard.moved;
        unsafe {
            *out_ptr.add(i) = MaybeUninit::new(f(
                guard.a.cast::<T>().add(i).read(),
                guard.b.cast::<U>().add(i).read(),
            ));
        }
        guard.moved += 1;
    }
    unsafe { out.assume_init() }
}
fn zip_map_fl<T: Copy, U: Copy, V, F: FnMut(T, U) -> V, const N: usize>(
    a: [T; N],
    b: [U; N],
    mut f: F,
) -> [V; N] {
    let mut out: [MaybeUninit<V>; N] = MaybeUninit::uninit_array();
    for i in 0..N {
        out[i] = MaybeUninit::new(f(a[i], b[i]));
    }
    unsafe { MaybeUninit::array_assume_init(out) }
}
fn zip_map_std<T, U, V, F: Fn(T, U) -> V, const N: usize>(a: [T; N], b: [U; N], f: F) -> [V; N] {
    a.zip(b).map(|(a, b)| f(a, b))
}
criterion_group! {
    name = benches;
    config = Criterion::default();
    targets = benchmark_primitives
}
criterion_main! {
    benches
}

I expected to see this happen: The compiler compiles successfully or outputs an error message.

Instead, this happened: The code, as provided below, appears to encounter a hang

Meta

rustc --version --verbose:

rustc 1.73.0 (cc66ad468 2023-10-03)
binary: rustc
commit-hash: cc66ad468955717ab92600c770da8c1601a4ff33
commit-date: 2023-10-03
host: x86_64-unknown-linux-gnu
release: 1.73.0
LLVM version: 17.0.2

The same problem is reproduced on the nightly version(1.75.0-nightly (d627cf0 2023-10-10)) as well. (and -Ztrait-solver=next cannot solve it)
what's more, to get more information,I also tried '-Z time-passes' (using nighly version):

$ rustc  -C opt-level=0 -Ztime-passes -Ztrait-solver=next /home/interesting/hang_10.rs
time:   0.002; rss:   30MB ->   32MB (   +2MB)  parse_crate
time:   0.000; rss:   35MB ->   35MB (   +1MB)  setup_global_ctxt
time:   0.072; rss:   35MB ->   75MB (  +40MB)  expand_crate
time:   0.072; rss:   35MB ->   75MB (  +40MB)  macro_expand_crate
error[E0433]: failed to resolve: maybe a missing crate `rand`?
 --> /home/interesting/hang_10.rs:4:5
  |
4 | use rand::{rngs::OsRng, Rng};
  |     ^^^^ maybe a missing crate `rand`?
  |
  = help: consider adding `extern crate rand` to use the `rand` crate

error[E0432]: unresolved import `criterion`
 --> /home/interesting/hang_10.rs:3:5
  |
3 | use criterion::{black_box, criterion_group, criterion_main, Criterion};
  |     ^^^^^^^^^ maybe a missing crate `criterion`?
  |
  = help: consider adding `extern crate criterion` to use the `criterion` crate

error[E0432]: unresolved import `rand`
 --> /home/interesting/hang_10.rs:4:5
  |
4 | use rand::{rngs::OsRng, Rng};
  |     ^^^^ maybe a missing crate `rand`?
  |
  = help: consider adding `extern crate rand` to use the `rand` crate

time:   0.010; rss:   75MB ->   90MB (  +15MB)  finalize_imports
error: cannot determine resolution for the macro `criterion_group`
   --> /home/interesting/hang_10.rs:118:1
    |
118 | criterion_group! {
    | ^^^^^^^^^^^^^^^
    |
    = note: import resolution is stuck, try simplifying macro imports

error: cannot determine resolution for the macro `criterion_main`
   --> /home/interesting/hang_10.rs:123:1
    |
123 | criterion_main! {
    | ^^^^^^^^^^^^^^
    |
    = note: import resolution is stuck, try simplifying macro imports

time:   0.004; rss:   90MB ->   94MB (   +4MB)  finalize_macro_resolutions
time:   0.038; rss:   94MB ->  103MB (   +9MB)  late_resolve_crate
error[E0425]: cannot find function `needs_drop` in this scope
  --> /home/interesting/hang_10.rs:66:12
   |
66 |         if needs_drop::<T>() || needs_drop::<U>() {
   |            ^^^^^^^^^^ not found in this scope
   |
help: consider importing this function
   |
3  + use std::mem::needs_drop;
   |

error[E0425]: cannot find function `needs_drop` in this scope
  --> /home/interesting/hang_10.rs:66:33
   |
66 |         if needs_drop::<T>() || needs_drop::<U>() {
   |                                 ^^^^^^^^^^ not found in this scope
   |
help: consider importing this function
   |
3  + use std::mem::needs_drop;
   |

error[E0412]: cannot find type `ManuallyDrop` in this scope
  --> /home/interesting/hang_10.rs:81:40
   |
81 |     let aref = &a as *const _ as *mut [ManuallyDrop<T>; N];
   |                                        ^^^^^^^^^^^^ not found in this scope
   |
help: consider importing this struct
   |
3  + use std::mem::ManuallyDrop;
   |

error[E0425]: cannot find function `forget` in this scope
  --> /home/interesting/hang_10.rs:82:5
   |
82 |     forget(a);
   |     ^^^^^^ not found in this scope
   |
help: consider importing this function
   |
3  + use std::mem::forget;
   |

error[E0412]: cannot find type `ManuallyDrop` in this scope
  --> /home/interesting/hang_10.rs:83:40
   |
83 |     let bref = &b as *const _ as *mut [ManuallyDrop<U>; N];
   |                                        ^^^^^^^^^^^^ not found in this scope
   |
help: consider importing this struct
   |
3  + use std::mem::ManuallyDrop;
   |

error[E0425]: cannot find function `forget` in this scope
  --> /home/interesting/hang_10.rs:84:5
   |
84 |     forget(b);
   |     ^^^^^^ not found in this scope
   |
help: consider importing this function
   |
3  + use std::mem::forget;
   |

time:   0.060; rss:   75MB ->  103MB (  +27MB)  resolve_crate
time:   0.008; rss:  124MB ->  124MB (   +0MB)  drop_ast
error[E0601]: `main` function not found in crate `hang_10`
   --> /home/interesting/hang_10.rs:125:2
    |
125 | }
    |  ^ consider adding a `main` function to `/home/interesting/hang_10.rs`

time:   0.080; rss:  103MB ->  124MB (  +21MB)  looking_for_entry_point
error[E0635]: unknown feature `array_zip`
 --> /home/interesting/hang_10.rs:2:12
  |
2 | #![feature(array_zip, maybe_uninit_array_assume_init, maybe_uninit_uninit_array)]
  |            ^^^^^^^^^

time:   0.106; rss:  103MB ->  124MB (  +21MB)  misc_checking_1
time:   0.024; rss:  124MB ->  127MB (   +3MB)  type_collecting
time:   0.002; rss:  127MB ->  130MB (   +3MB)  wf_checking
Backtrace

<backtrace>

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: This is a bug.I-compiletimeIssue: Problems and improvements with respect to compile times.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions