Rust: ICE with std::mem::size_of with `repr(packed)` plus associated type

Created on 4 Feb 2019  路  12Comments  路  Source: rust-lang/rust

The compiler panics when there's a std::mem::size_of call for a struct with repr(packed) that contains a matrix type from nalgebra. I'm fairly new to rust and I'm not sure how to isolate what within the nalgebra crate might be causing this.

src/main.rs:

use nalgebra as na;

#[repr(packed)]
struct Foo(na::Vector3<f32>);

fn main() {
    std::mem::size_of::<Foo>();
}

Cargo.toml

[package]
name = "test"
version = "0.1.0"
authors = ["Robert Grindeland <[email protected]>"]
edition = "2018"

[dependencies]
nalgebra = "0.16.13"

Result of RUST_BACKTRACE=1 cargo build --verbose

$ RUST_BACKTRACE=1 cargo build --verbose
       Fresh rand_core v0.4.0
       Fresh libm v0.1.2
       Fresh rawpointer v0.1.0
       Fresh rand_core v0.3.1
       Fresh num-traits v0.2.6
       Fresh winapi v0.3.6
       Fresh typenum v1.10.0
       Fresh matrixmultiply v0.1.15
       Fresh num-complex v0.2.1
       Fresh approx v0.3.1
       Fresh rand v0.5.6
       Fresh generic-array v0.11.1
       Fresh alga v0.7.2
       Fresh nalgebra v0.16.13
   Compiling test v0.1.0 (C:\Users\Rob\Documents\Programming\cpp\compiler-bug)
     Running `rustc --edition=2018 --crate-name test 'src\main.rs' --color always --crate-type bin --emit=dep-info,link -C debuginfo=2 -C metadata=9be42db9345f3907 -C extra-filename=-9be42db9345f3907 --out-dir 'C:\Users\Rob\Documents\Programming\cpp\compiler-bug\target\debug\deps' -C 'incremental=C:\Users\Rob\Documents\Programming\cpp\compiler-bug\target\debug\incremental' -L 'dependency=C:\Users\Rob\Documents\Programming\cpp\compiler-bug\target\debug\deps' --extern 'nalgebra=C:\Users\Rob\Documents\Programming\cpp\compiler-bug\target\debug\deps\libnalgebra-4080678600ea4cae.rlib'`
error: internal compiler error: librustc_typeck\check\wfcheck.rs:261: inference variables in nalgebra::base::matrix::Matrix<f32, nalgebra::base::dimension::U3, nalgebra::base::dimension::U1, nalgebra::base::array_storage::ArrayStorage<_, _, _>>
 --> src\main.rs:4:1
  |
4 | struct Foo(na::Vector3<f32>);
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

thread 'main' panicked at 'Box<Any>', librustc_errors\lib.rs:538:9
stack backtrace:
   0: <std::sync::mpsc::select::Select as core::fmt::Debug>::fmt
   1: std::path::<impl core::convert::From<std::path::PathBuf> for std::ffi::os_str::OsString>::from
   2: std::panicking::take_hook
   3: std::panicking::take_hook
   4: <rustc::ty::sty::Binder<rustc::ty::ProjectionPredicate<'tcx>> as rustc::ty::ToPredicate<'tcx>>::to_predicate
   5: std::panicking::rust_panic_with_hook
   6: rustc_typeck::collect::early_bound_lifetimes_from_generics
   7: rustc_typeck::collect::early_bound_lifetimes_from_generics
   8: <rustc_typeck::outlives::explicit::ExplicitPredicatesMap<'tcx> as core::fmt::Debug>::fmt
   9: <rustc_typeck::outlives::explicit::ExplicitPredicatesMap<'tcx> as core::fmt::Debug>::fmt
  10: <rustc_typeck::outlives::explicit::ExplicitPredicatesMap<'tcx> as core::fmt::Debug>::fmt
  11: <rustc_typeck::outlives::explicit::ExplicitPredicatesMap<'tcx> as core::fmt::Debug>::fmt
  12: <rustc_typeck::outlives::explicit::ExplicitPredicatesMap<'tcx> as core::fmt::Debug>::fmt
  13: <rustc_typeck::outlives::explicit::ExplicitPredicatesMap<'tcx> as core::fmt::Debug>::fmt
  14: <rustc_typeck::outlives::explicit::ExplicitPredicatesMap<'tcx> as core::fmt::Debug>::fmt
  15: <rustc_typeck::outlives::explicit::ExplicitPredicatesMap<'tcx> as core::fmt::Debug>::fmt
  16: <rustc_typeck::check::method::probe::ProbeScope as core::fmt::Debug>::fmt
  17: <rustc_typeck::check::upvar::InferBorrowKind<'a, 'gcx, 'tcx> as rustc::middle::expr_use_visitor::Delegate<'tcx>>::mutate
  18: <rustc::traits::query::outlives_bounds::OutlivesBound<'a> as rustc::ty::context::Lift<'tcx>>::lift_to_tcx
  19: rustc::ty::context::tls::track_diagnostic
  20: rustc::dep_graph::graph::DepGraph::assert_ignored
  21: rustc::ty::adjustment::<impl core::convert::From<rustc::ty::adjustment::AutoBorrowMutability> for rustc::hir::Mutability>::from
  22: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt<'a, 'gcx, 'tcx>>::try_print_query_stack
  23: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt<'a, 'gcx, 'tcx>>::try_print_query_stack
  24: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt<'a, 'gcx, 'tcx>>::try_print_query_stack
  25: <rustc_typeck::outlives::implicit_infer::IgnoreSelfTy as core::fmt::Debug>::fmt
  26: <rustc_typeck::check::regionck::RegionCtxt<'a, 'gcx, 'tcx> as rustc::hir::intravisit::Visitor<'gcx>>::nested_visit_map
  27: rustc_typeck::check_crate
  28: <humantime::date::Error as std::error::Error>::cause
  29: <rustc_driver::pretty::NoAnn<'hir> as rustc_driver::pretty::HirPrinterSupport<'hir>>::sess
  30: <humantime::date::Error as std::error::Error>::cause
  31: rustc_driver::driver::compile_input
  32: rustc_driver::run_compiler
  33: <rustc_driver::profile::trace::Query as core::fmt::Debug>::fmt
  34: rustc_driver::run_compiler
  35: <rustc_driver::profile::trace::Query as core::fmt::Debug>::fmt
  36: _rust_maybe_catch_panic
  37: <unknown>
  38: rustc_driver::main
  39: <unknown>
  40: std::panicking::update_panic_count
  41: _rust_maybe_catch_panic
  42: std::rt::lang_start_internal
  43: <unknown>
  44: <unknown>
  45: BaseThreadInitThunk
  46: RtlUserThreadStart
query stack during panic:
#0 [check_item_well_formed] processing `Foo`
end of query stack
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.31.1 (b6c32da9b 2018-12-18) running on x86_64-pc-windows-msvc

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 `test`.

Caused by:
  process didn't exit successfully: `rustc --edition=2018 --crate-name test 'src\main.rs' --color always --crate-type bin --emit=dep-info,link -C debuginfo=2 -C metadata=9be42db9345f3907 -C extra-filename=-9be42db9345f3907 --out-dir 'C:\Users\Rob\Documents\Programming\cpp\compiler-bug\target\debug\deps' -C 'incremental=C:\Users\Rob\Documents\Programming\cpp\compiler-bug\target\debug\incremental' -L 'dependency=C:\Users\Rob\Documents\Programming\cpp\compiler-bug\target\debug\deps' --extern 'nalgebra=C:\Users\Rob\Documents\Programming\cpp\compiler-bug\target\debug\deps\libnalgebra-4080678600ea4cae.rlib'` (exit code: 101)
A-inference C-bug I-ICE P-high T-compiler

Most helpful comment

Minimized further:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=e1c3725bd288e50631a4cf100538469f

pub struct Matrix<S> {}
pub struct DefaultAllocator;

pub trait Allocator {
    type Buffer;
}

#[repr(packed)]
struct Foo(Matrix<<DefaultAllocator as Allocator>::Buffer>);

All 12 comments

Slightly minimized (this can be reduced _much_ more); the ICE in the following also occurs with std::mem::size_of commented out

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=2d169e6074e39a9cc9057ac3f5562f2c

use std::any::Any;
use std::fmt::Debug;
use std::marker::PhantomData;

#[repr(packed)]
struct Foo(Vector3<f32>);

fn main() {
    // std::mem::size_of::<Foo>();
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct Matrix<N: Scalar, R: Dim, C: Dim, S> {
    pub data: S,
    _phantoms: PhantomData<(N, R, C)>,
}

type MatrixMN<N, R, C> = Matrix<N, R, C, Owned<N, R, C>>;
type VectorN<N, D> = MatrixMN<N, D, U1>;
type Vector3<N> = VectorN<N, U3>;

pub trait Dim: Any + Debug + Copy + PartialEq + Send + Sync {}

#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct U1;
impl Dim for U1 {}

#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct U3;
impl Dim for U3 {}

pub trait Scalar: Copy + PartialEq + Debug + Any {}
impl<T: Copy + PartialEq + Debug + Any> Scalar for T {}

pub unsafe trait Storage<N: Scalar, R: Dim, C: Dim = U1>: Debug + Sized {
    type RStride: Dim;
    type CStride: Dim;
}
pub unsafe trait StorageMut<N: Scalar, R: Dim, C: Dim = U1>: Storage<N, R, C> {}

pub unsafe trait ContiguousStorage<N: Scalar, R: Dim, C: Dim = U1>:
    Storage<N, R, C>
{
}

pub unsafe trait ContiguousStorageMut<N: Scalar, R: Dim, C: Dim = U1>:
    ContiguousStorage<N, R, C> + StorageMut<N, R, C>
{
}

pub trait Allocator<N: Scalar, R: Dim, C: Dim = U1>: Any + Sized {
    type Buffer: ContiguousStorageMut<N, R, C> + Clone;
}

pub struct DefaultAllocator;
pub type Owned<N, R, C = U1> = <DefaultAllocator as Allocator<N, R, C>>::Buffer;

error: internal compiler error: src/librustc_typeck/check/wfcheck.rs:255: inference variables in Matrix<f32, U3, U1, _>
 --> src/main.rs:6:1
  |
6 | struct Foo(Vector3<f32>);
  | ^^^^^^^^^^^^^^^^^^^^^^^^^

thread 'rustc' panicked at 'Box<Any>', src/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 src/libstd/sys/unix/backtrace/tracing/gcc_s.rs:39
   1: std::sys_common::backtrace::_print
             at src/libstd/sys_common/backtrace.rs:70
   2: std::panicking::default_hook::{{closure}}
             at src/libstd/sys_common/backtrace.rs:58
             at src/libstd/panicking.rs:200
   3: std::panicking::default_hook
             at src/libstd/panicking.rs:215
   4: rustc::util::common::panic_hook
   5: std::panicking::rust_panic_with_hook
             at src/libstd/panicking.rs:482
   6: std::panicking::begin_panic
   7: rustc_errors::Handler::span_bug
   8: rustc::util::bug::opt_span_bug_fmt::{{closure}}
   9: rustc::ty::context::tls::with_opt::{{closure}}
  10: rustc::ty::context::tls::with_context_opt
  11: rustc::ty::context::tls::with_opt
  12: rustc::util::bug::opt_span_bug_fmt
  13: rustc::util::bug::span_bug_fmt
  14: rustc_typeck::check::wfcheck::check_type_defn::{{closure}}::{{closure}}::{{closure}}
  15: rustc::ty::context::GlobalCtxt::enter_local
  16: rustc_typeck::check::wfcheck::check_item_well_formed
  17: rustc::ty::query::__query_compute::check_item_well_formed
  18: rustc::ty::query::<impl rustc::ty::query::config::QueryAccessors<'tcx> for rustc::ty::query::queries::check_item_well_formed<'tcx>>::compute
  19: rustc::dep_graph::graph::DepGraph::with_task_impl
  20: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt<'a, 'gcx, 'tcx>>::try_get_with
  21: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt<'a, 'gcx, 'tcx>>::ensure_query
  22: rustc::hir::Crate::visit_all_item_likes
  23: rustc::util::common::time
  24: rustc_typeck::check_crate
  25: <std::thread::local::LocalKey<T>>::with
  26: rustc::ty::context::TyCtxt::create_and_enter
  27: rustc_driver::driver::compile_input
  28: rustc_driver::run_compiler_with_pool
  29: <scoped_tls::ScopedKey<T>>::set
  30: rustc_driver::run_compiler
  31: <scoped_tls::ScopedKey<T>>::set
query stack during panic:
#0 [check_item_well_formed] processing `Foo`
end of query stack
error: aborting due to previous error

note: rustc 1.34.0-nightly (f6fac4225 2019-02-03) running on x86_64-unknown-linux-gnu

note: compiler flags: -C codegen-units=1 -C debuginfo=2 --crate-type bin

rustc 1.34.0-nightly (f6fac4225 2019-02-03)

Minimized further:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=e1c3725bd288e50631a4cf100538469f

pub struct Matrix<S> {}
pub struct DefaultAllocator;

pub trait Allocator {
    type Buffer;
}

#[repr(packed)]
struct Foo(Matrix<<DefaultAllocator as Allocator>::Buffer>);

Even more:

#[repr(packed)]
pub struct Foo(<Vec<u32> as IntoIterator>::Item);

The ICE does not happen without the #[repr(packed)] attribute (also neat: this code would compile without warning when used as a testcase)

Also note, that this "never worked" (I went back to nightly-2018-03-01, and even there it panics).

triage. Marking P-high mostly because 1. it is an ICE and 2. I want to ensure it is at the front of the T-compiler queue for next week's meeting.

(also neat: this code would compile without warning when used as a testcase)

@hellow554 can you clarify what you meant by this parenthetical? Are you saying if I add #[test] somewhere to the file it compiles without any error or warning?

triage: assigning to self.

There's other variations up above, but I thought this one was particularly illuminating:

struct DefaultAllocator;

trait Allocator { type Buffer; }

// impl Allocator for DefaultAllocator { type Buffer = (); }

#[repr(packed)]
struct Foo(<DefaultAllocator as Allocator>::Buffer);

note in particular that, at least in this variation, the concrete type here does not implement the trait in question. So its impossible to actually resolve the associated type when doing the repr(packed) analysis.

(If you add back in the impl commented-out above, then the code compiles. And if you leave it out but remove repr(packed), then the code gets rejected since the concrete type does not implement the trait.)

(also neat: this code would compile without warning when used as a testcase)

@hellow554 can you clarify what you meant by this parenthetical? Are you saying if I add #[test] somewhere to the file it compiles without any error or warning?

when you use it as a regression test in https://github.com/rust-lang/rust/tree/master/src/test

when you use it as a regression test in https://github.com/rust-lang/rust/tree/master/src/test

i find that ... surprising. Will investigate.

Sorry @pnkfelix ! I don't mean that it doesn't crash when used as test, but if this issue will be fixed my code can be used as testcode because it doesn't emit any warnings or errors.

@hellow554 ah, okay yes that makes more sense to me!

Was this page helpful?
0 / 5 - 0 ratings