Skip to content

Miscompilation with recent Nightlies #66851

Closed
@leonardo-m

Description

@leonardo-m

Since few Rustc nightly versions I see a miscompilation problem with the code below.
I am using:

rustc 1.41.0-nightly (e87a205c2 2019-11-27)
binary: rustc
commit-hash: e87a205c2e117d9fb57f6cdeac0a7f6e95c88316
commit-date: 2019-11-27
host: x86_64-pc-windows-gnu
release: 1.41.0-nightly
LLVM version: 9.0

If I compile with:

-C opt-level=1 -Z mir-opt-level=1   ==> OK
-C opt-level=0 -Z mir-opt-level=2   ==> OK
-C opt-level=1 -Z mir-opt-level=2   ==> Runtime error

The code:

#[cfg(debug_assertions)]
use std::convert::TryFrom;

#[cfg(not(debug_assertions))]
macro_rules! to { ($e:expr, $t:ident) => (($e) as $t) }

#[cfg(debug_assertions)]
macro_rules! to { ($e:expr, $t:ident) => ($t::try_from($e).unwrap()) }

fn e103() -> Option<u64> {
    const TARGET: i32 = 7;
    const MAX_COST: i32 = 1 << 12;
    const MAX_COST_U: usize = MAX_COST as _;

    type TSubsets = [i32; 1 << TARGET];
    type TOccupancy = [bool; MAX_COST_U];
    type TMaxMin = [[i32; 2]; 16];

    enum SpecialsRes { Res(u64), Val(i32), Err }

    fn specials(len: i32,
                max_min: &mut TMaxMin,
                mut cost_ceiling: i32,
                vmax: i32,
                ix: i32,
                occupancy: &mut TOccupancy,
                subsets: &mut TSubsets) -> SpecialsRes {
        if ix == len || ix < 0 {
            let mut result = String::new();
            for i in (0 .. ix).rev() {
                result += &subsets[1 << i].to_string();
            }
            return if let Ok(r) = result.parse() {
                SpecialsRes::Res(r)
            } else {
                SpecialsRes::Err
            };
        }

        let mut lo_val: i32 = 0;
        let mut hi_val = vmax;

        for i in 0 .. ix {
            lo_val = lo_val.max(max_min[to!{i, usize} + 1][1] -
                                max_min[to!{i, usize} + 1][0]);
            hi_val = hi_val.min(max_min[to!{i, usize} + 2][0] -
                                max_min[to!{i, usize}][1]);
        }

        let r = len - ix;
        hi_val = hi_val.min(cost_ceiling - lo_val * r - r * (r + 1) / 2);

        let mut v = lo_val + (len - ix);
        while v < hi_val {
            let mut res = true;
            let pl = 1 << ix;
            let mut marked: i32 = 0;

            for i in 0 .. pl {
                let s = subsets[i] + v;
                if occupancy[to!{s, usize}] {
                    res = false;
                    break;
                }
                subsets[pl + i] = s;
                occupancy[to!{s, usize}] = true;
                marked += 1;
            }

            if res {
                let mut new_max_min: TMaxMin = Default::default();
                new_max_min[to!{ix, usize} + 2][0] = std::i32::MAX;

                for i in 1 .. ix + 2 {
                    new_max_min[to!{i, usize}][0] = max_min[to!{i, usize}][0]
                                                    .min(v + max_min[to!{i, usize} - 1][0]);
                    new_max_min[to!{i, usize}][1] = max_min[to!{i, usize}][1]
                                                    .max(v + max_min[to!{i, usize} - 1][1]);
                }

                let res = specials(len,
                                   &mut new_max_min,
                                   cost_ceiling - v,
                                   v,
                                   ix + 1,
                                   occupancy,
                                   subsets);
                match res {
                    SpecialsRes::Res(_) | SpecialsRes::Err => return res,

                    SpecialsRes::Val(val) => {
                        let new_cost_ceiling = v + val;
                        if new_cost_ceiling < cost_ceiling {
                            cost_ceiling = new_cost_ceiling;
                            hi_val = hi_val.min(cost_ceiling - lo_val * r - r * (r + 1) / 2);
                        }
                    }
                }
            }

            for i in 0 .. marked {
                occupancy[to!{subsets[pl + to!{i, usize}], usize}] = false;
            }

            v += 1;
        }

        SpecialsRes::Val(cost_ceiling)
    }

    let mut occupancy: TOccupancy = [false; MAX_COST_U];
    occupancy[0] = true;

    let mut subsets: TSubsets = [0i32; 1 << TARGET as usize];

    let mut max_min: TMaxMin = Default::default();
    max_min[1][0] = std::i32::MAX;

    match specials(TARGET, &mut max_min, MAX_COST,
                   MAX_COST, 0, &mut occupancy, &mut subsets) {
        SpecialsRes::Res(s) => Some(s),
        SpecialsRes::Val(_) | SpecialsRes::Err => None,
    }
}

fn main() {
    assert_eq!(e103(), Some(20_313_839_404_245));
}

Metadata

Metadata

Assignees

Labels

C-bugCategory: This is a bug.E-needs-bisectionCall for participation: This issue needs bisection: https://github.com/rust-lang/cargo-bisect-rustcE-needs-mcveCall for participation: This issue has a repro, but needs a Minimal Complete and Verifiable ExampleI-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.requires-nightlyThis issue requires a nightly compiler in some way.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions