Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

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

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in 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