Skip to content

internal compiler error: librustc_mir/hair/pattern/_match.rs:959: impossible case reached #51655

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Closed
koutheir opened this issue Jun 20, 2018 · 5 comments
Labels
C-bug Category: This is a bug. I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@koutheir
Copy link
Contributor

I tried this code:

use std::ffi::{OsStr, OsString};
use std::os::unix::ffi::{OsStrExt, OsStringExt};
use std::path::{Path, PathBuf};
use std::{env, fs};

fn main() {
    println!("# {}", normalize_path("etc/././a/.//..//").display());
}

const PATH_DOT_: u8 = '.' as u8;
const PATH_SEPARATOR: u8 = '/' as u8;
const PATH_DOT: &[u8] = &[PATH_DOT_];
const PATH_DOT_DOT: &[u8] = &[PATH_DOT_, PATH_DOT_];

fn normalize_path(path: impl AsRef<Path>) -> PathBuf {
    let (existent_path, existent_len) = try_canonicalize(&path);
    let buffer = if let Some(existent_path) = existent_path {
        existent_path.into_os_string().into_vec()
    } else if path.as_ref().is_absolute() {
        vec![PATH_SEPARATOR]
    } else {
        let cur_dir = env::current_dir().unwrap_or_else(|_e| PathBuf::from("./"));
        cur_dir.into_os_string().into_vec()
    };

    let bytes = &path.as_ref().as_os_str().as_bytes()[existent_len..];
    let buffer = bytes
        .split(is_path_separator)
        .fold(buffer, append_to_existing_path);

    PathBuf::from(OsString::from_vec(buffer))
}

fn is_path_separator(e: &u8) -> bool {
    *e == PATH_SEPARATOR
}

fn try_canonicalize(path: impl AsRef<Path>) -> (Option<PathBuf>, usize) {
    let mut bytes = path.as_ref().as_os_str().as_bytes();
    if bytes.is_empty() {
        return (None, 0);
    }

    loop {
        let sub_path = Path::new(OsStr::from_bytes(bytes));
        if let Ok(r) = fs::canonicalize(sub_path) {
            return (Some(r), bytes.len());
        }

        let mut iter = bytes.rsplitn(2, is_path_separator);
        if let Some(_last) = iter.next() {
            if let Some(prefix) = iter.next() {
                bytes = prefix;
            } else {
                return (None, 0);
            }
        } else {
            return (None, 0);
        }
    }
}

enum ParentPathAction {
    CurrentDirectory,
    TrimRight(usize),
    AppendElement,
}

fn append_to_existing_path(mut path: Vec<u8>, element: &[u8]) -> Vec<u8> {
    match element {
        &[] | PATH_DOT => path,

        PATH_DOT_DOT => {
            let action = {
                let mut iter = path.rsplitn(2, is_path_separator);
                if let Some(parent) = iter.next() {
                    if let Some(prefix) = iter.next() {
                        if prefix.is_empty() {
                            match parent {
                                PATH_DOT | PATH_DOT_DOT => {
                                    // "/../.." => "/"
                                    ParentPathAction::TrimRight(parent.len())
                                }

                                _ => {
                                    // "/parent/.." => "/"
                                    ParentPathAction::TrimRight(parent.len())
                                }
                            }
                        } else {
                            match parent {
                                PATH_DOT | PATH_DOT_DOT => {
                                    // "prefix/../.." => "prefix/../.."
                                    ParentPathAction::AppendElement
                                }

                                _ => {
                                    // "prefix/parent/.." => "prefix"
                                    ParentPathAction::TrimRight(parent.len() + 1)
                                }
                            }
                        }
                    } else {
                        // "parent/.." => "<current_dir>"
                        ParentPathAction::CurrentDirectory
                    }
                } else {
                    // ".." => ".."
                    ParentPathAction::AppendElement
                }
            };

            match action {
                ParentPathAction::CurrentDirectory => {
                    let cur_dir = env::current_dir().unwrap_or_else(|_e| PathBuf::from("."));
                    cur_dir.into_os_string().into_vec()
                }

                ParentPathAction::TrimRight(trim) => {
                    let new_len = path.len() - trim;
                    path.truncate(new_len);
                    path
                }

                ParentPathAction::AppendElement => {
                    let path = PathBuf::from(OsString::from_vec(path));
                    let element = Path::new(OsStr::from_bytes(element));
                    path.join(element).into_os_string().into_vec()
                }
            }
        }

        _ => {
            let path = PathBuf::from(OsString::from_vec(path));
            let element = Path::new(OsStr::from_bytes(element));
            path.join(element).into_os_string().into_vec()
        }
    }
}

I expected to see this happen: compilation error or compilation success.

Instead, this happened: compiler crashed into an impossible case.

Meta

$ rustc --version --verbose
rustc 1.26.2 (594fb253c 2018-06-01)
binary: rustc
commit-hash: 594fb253c2b02b320c728391a425d028e6dc7a09
commit-date: 2018-06-01
host: x86_64-unknown-linux-gnu
release: 1.26.2
LLVM version: 6.0

Backtrace:

librustc_mir/hair/pattern/_match.rs:959: impossible case reached

Error messages:

$ cargo build --verbose
   Compiling paths v0.1.0 (file:///media/data/openjdk/126101-infrastructure/license-analyzer/paths)
     Running `rustc --crate-name paths src/main.rs --crate-type bin --emit=dep-info,link -C debuginfo=2 -C metadata=6e46ca38d9a06af0 -C extra-filename=-6e46ca38d9a06af0 --out-dir /media/data/openjdk/126101-infrastructure/license-analyzer/paths/target/debug/deps -C incremental=/media/data/openjdk/126101-infrastructure/license-analyzer/paths/target/debug/incremental -L dependency=/media/data/openjdk/126101-infrastructure/license-analyzer/paths/target/debug/deps`
error: internal compiler error: librustc_mir/hair/pattern/_match.rs:959: impossible case reached

thread 'rustc' panicked at 'Box<Any>', librustc_errors/lib.rs:543:9
note: Run with `RUST_BACKTRACE=1` for a backtrace.
error: aborting due to previous error


note: the compiler unexpectedly panicked. this is a bug.

note: we would appreciate a bug report: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports

note: rustc 1.26.2 (594fb253c 2018-06-01) running on x86_64-unknown-linux-gnu

note: compiler flags: -C debuginfo=2 -C incremental --crate-type bin

note: some of the compiler flags provided by cargo are hidden

error: Could not compile `paths`.

Caused by:
  process didn't exit successfully: `rustc --crate-name paths src/main.rs --crate-type bin --emit=dep-info,link -C debuginfo=2 -C metadata=6e46ca38d9a06af0 -C extra-filename=-6e46ca38d9a06af0 --out-dir <somewhere>/paths/target/debug/deps -C incremental=<somewhere>/paths/target/debug/incremental -L dependency=<somewhere>/paths/target/debug/deps` (exit code: 101)
@koutheir
Copy link
Contributor Author

koutheir commented Jun 20, 2018

If it may further help, the issue appeared when I wanted to replace instances of &[PATH_DOT] and &[PATH_DOT, PATH_DOT] with two consts defined after PATH_SEPARATOR.

@bjorn3
Copy link
Member

bjorn3 commented Jun 20, 2018

Please run with RUST_BACKTRACE=1 for a backtrace.

@kennytm kennytm added I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. C-bug Category: This is a bug. labels Jun 20, 2018
@kennytm
Copy link
Member

kennytm commented Jun 20, 2018

Reduced test case:

const PATH_DOT: &[u8] = &[b'.'];

fn append_to_existing_path(element: &[u8]) {
    match element {
        &[] => {}
        PATH_DOT => {}
        _ => {}
    }
}

@koutheir
Copy link
Contributor Author

$ RUST_BACKTRACE=1 cargo build --verbose
   Compiling paths v0.1.0 (file:///<somewhere>/paths)
     Running `rustc --crate-name paths src/main.rs --crate-type bin --emit=dep-info,link -C debuginfo=2 -C metadata=6e46ca38d9a06af0 -C extra-filename=-6e46ca38d9a06af0 --out-dir /<somewhere>/paths/target/debug/deps -C incremental=/<somewhere>/paths/target/debug/incremental -L dependency=/<somewhere>/paths/target/debug/deps`
error: internal compiler error: librustc_mir/hair/pattern/_match.rs:959: impossible case reached

thread 'rustc' panicked at 'Box<Any>', librustc_errors/lib.rs:543:9
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
stack backtrace:
   0: std::sys::unix::backtrace::tracing::imp::unwind_backtrace
             at libstd/sys/unix/backtrace/tracing/gcc_s.rs:49
   1: std::sys_common::backtrace::print
             at libstd/sys_common/backtrace.rs:71
             at libstd/sys_common/backtrace.rs:59
   2: std::panicking::default_hook::{{closure}}
             at libstd/panicking.rs:207
   3: std::panicking::default_hook
             at libstd/panicking.rs:223
   4: core::ops::function::Fn::call
   5: std::panicking::rust_panic_with_hook
             at libstd/panicking.rs:403
   6: std::panicking::begin_panic
   7: rustc_errors::Handler::bug
   8: rustc::session::opt_span_bug_fmt::{{closure}}
   9: rustc::ty::context::tls::with_opt::{{closure}}
  10: <std::thread::local::LocalKey<T>>::try_with
  11: <std::thread::local::LocalKey<T>>::with
  12: rustc::ty::context::tls::with
  13: rustc::ty::context::tls::with_opt
  14: rustc::session::opt_span_bug_fmt
  15: rustc::session::bug_fmt
  16: rustc_mir::hair::pattern::_match::specialize
  17: <alloc::vec::Vec<T> as alloc::vec::SpecExtend<T, I>>::from_iter
  18: rustc_mir::hair::pattern::_match::is_useful_specialized
  19: <core::iter::Map<I, F> as core::iter::iterator::Iterator>::try_fold
  20: rustc_mir::hair::pattern::_match::is_useful
  21: rustc_mir::hair::pattern::_match::is_useful_specialized
  22: <core::iter::Map<I, F> as core::iter::iterator::Iterator>::try_fold
  23: rustc_mir::hair::pattern::_match::is_useful
  24: <rustc_mir::hair::pattern::check_match::MatchVisitor<'a, 'tcx> as rustc::hir::intravisit::Visitor<'tcx>>::visit_expr
  25: <rustc_mir::hair::pattern::check_match::MatchVisitor<'a, 'tcx> as rustc::hir::intravisit::Visitor<'tcx>>::visit_expr
  26: rustc::session::Session::track_errors
  27: rustc_mir::hair::pattern::check_match::check_match
  28: rustc::dep_graph::graph::DepGraph::with_task_impl
  29: rustc_errors::Handler::track_diagnostics
  30: rustc::ty::maps::plumbing::<impl rustc::ty::context::TyCtxt<'a, 'gcx, 'tcx>>::cycle_check
  31: rustc::ty::maps::<impl rustc::ty::maps::queries::check_match<'tcx>>::force
  32: rustc::ty::maps::<impl rustc::ty::maps::queries::check_match<'tcx>>::try_get
  33: rustc::ty::maps::TyCtxtAt::check_match
  34: rustc::ty::maps::<impl rustc::ty::context::TyCtxt<'a, 'tcx, 'lcx>>::check_match
  35: rustc::hir::intravisit::Visitor::visit_nested_body
  36: rustc::hir::Crate::visit_all_item_likes
  37: rustc_mir::hair::pattern::check_match::check_crate
  38: <std::thread::local::LocalKey<T>>::with
  39: <std::thread::local::LocalKey<T>>::with
  40: rustc::ty::context::TyCtxt::create_and_enter
  41: rustc_driver::driver::compile_input
  42: rustc_driver::run_compiler_impl
  43: syntax::with_globals
error: aborting due to previous error


note: the compiler unexpectedly panicked. this is a bug.

note: we would appreciate a bug report: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports

note: rustc 1.26.2 (594fb253c 2018-06-01) running on x86_64-unknown-linux-gnu

note: compiler flags: -C debuginfo=2 -C incremental --crate-type bin

note: some of the compiler flags provided by cargo are hidden

error: Could not compile `paths`.

Caused by:
  process didn't exit successfully: `rustc --crate-name paths src/main.rs --crate-type bin --emit=dep-info,link -C debuginfo=2 -C metadata=6e46ca38d9a06af0 -C extra-filename=-6e46ca38d9a06af0 --out-dir /<somewhere>/paths/target/debug/deps -C incremental=/<somewhere>/paths/target/debug/incremental -L dependency=/<somewhere>/paths/target/debug/deps` (exit code: 101)

@varkor
Copy link
Member

varkor commented Jun 20, 2018

I didn't have time to finish looking into it, but in case anyone else does, the issue is on:

if let Some(ptr) = const_val.to_ptr() {

The problem is that const_val here is a ScalarPair rather than a Scalar, so converting to a pointer fails, as it needs to be scalar:
self.to_scalar()?.to_ptr().ok()

bors added a commit that referenced this issue Jun 25, 2018
Fix an ICE when matching over const slices

Fixes #51655. I'm not super familiar with this code, so tell me if this is the wrong approach 😅

r? @oli-obk
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
C-bug Category: This is a bug. I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

4 participants