Skip to content

ICE "broken MIR ... Field projection specified type ... but actual type is ..." comparing type with type as trait #105044

Description

@teor2345

There seems to be a bug in the way that Rust compiles Iterator::flat_map(), in release mode, with complex iterators.

It also triggers on other "type" vs "type as trait" comparisons in the compiler, for example unsized-vec fails with:

error: internal compiler error: broken MIR in DropGlue(DefId(2:2141 ~ core[0ec9]::ptr::drop_in_place), Some(unsized_vec::UnsizedVec<dyn std::fmt::Debug>)) (after phase change to runtime-optimized) at bb0[0]:
                                Field projection `(*_1).field[0]` specified type `unsized_vec::inner::unaligned::UnalignedVecInner<dyn std::fmt::Debug>`, but actual type is `<dyn std::fmt::Debug as unsized_vec::inner::UnsizedVecImpl>::Impl`
   --> /home/dev/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:490:1
    |
490 | pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: delayed at compiler/rustc_const_eval/src/transform/validate.rs:229:30

error: internal compiler error: broken MIR in DropGlue(DefId(2:2141 ~ core[0ec9]::ptr::drop_in_place), Some(unsized_vec::UnsizedVec<[i32]>)) (after phase change to runtime-optimized) at bb0[0]:
                                Field projection `(*_1).field[0]` specified type `unsized_vec::inner::aligned::AlignedVecInner<[i32]>`, but actual type is `<[i32] as unsized_vec::inner::UnsizedVecImpl>::Impl`
   --> /home/dev/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:490:1

Code

Related crate code:

Details
pub enum Transaction {
    V5 {
        orchard_shielded_data: Option<ShieldedData>,
    },
}

impl Transaction {
    pub fn orchard_shielded_data(&self) -> Option<&ShieldedData> {
        match self {
            // Maybe Orchard shielded data
            Transaction::V5 {
                orchard_shielded_data,
                ..
            } => orchard_shielded_data.as_ref(),
        }
    }

    pub fn orchard_nullifiers(&self) -> impl Iterator<Item = &Nullifier> {
        self.orchard_shielded_data()
            .into_iter()
            .flat_map(ShieldedData::nullifiers)
    }
}

pub struct ShieldedData {
    pub actions: AtLeastOne<AuthorizedAction>,
}

impl ShieldedData {
    pub fn actions(&self) -> impl Iterator<Item = &Action> {
        self.actions.actions()
    }

    pub fn nullifiers(&self) -> impl Iterator<Item = &Nullifier> {
        self.actions().map(|action| &action.nullifier)
    }
}

impl AtLeastOne<AuthorizedAction> {
    pub fn actions(&self) -> impl Iterator<Item = &Action> {
        self.iter()
            .map(|authorized_action| &authorized_action.action)
    }
}

pub struct AuthorizedAction {
    pub action: Action,
}

pub struct Action {
    pub nullifier: (),
}

pub struct AtLeastOne<T> {
    inner: Vec<T>,
}

impl<T> Deref for AtLeastOne<T> {
    type Target = Vec<T>;

    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

impl<T> AsRef<[T]> for AtLeastOne<T> {
    fn as_ref(&self) -> &[T] {
        self.inner.as_ref()
    }
}

impl<T> IntoIterator for AtLeastOne<T> {
    type Item = T;

    type IntoIter = std::vec::IntoIter<T>;

    fn into_iter(self) -> std::vec::IntoIter<T> {
        self.inner.into_iter()
    }
}

Failing code:

impl Transaction {
    pub fn orchard_nullifiers(&self) -> impl Iterator<Item = &Nullifier> {
        self.orchard_shielded_data()
            .into_iter()
            .flat_map(ShieldedData::nullifiers)
    }
}

    let orchard_nullifier_count = block
        .transactions
        .iter()
        .flat_map(|t| t.orchard_nullifiers()) 
        .count();

    for nullifier in prepared.block.orchard_nullifiers() { }

Workaround:

    pub fn orchard_nullifiers(&self) -> impl Iterator<Item = &orchard::Nullifier> {
        let nullifiers: Vec<_> = self
            .transactions
            .iter()
            .flat_map(|transaction| transaction.orchard_nullifiers())
            .collect();

        nullifiers.into_iter()
    }

    let orchard_nullifier_count: usize = block
        .transactions
        .iter()
        .map(|t| t.orchard_nullifiers().into_iter().count())
        .sum();

Meta

Fails from nightly nightly-2022-11-20 onwards, in commit 2f8d804.

rustc --version --verbose:

rustc 1.67.0-nightly (2585bcea0 2022-11-28)
binary: rustc
commit-hash: 2585bcea0bc2a9c42a4be2c1eba5c61137f2b167
commit-date: 2022-11-28
host: x86_64-unknown-linux-gnu
release: 1.67.0-nightly
LLVM version: 15.0.4

I used these commands to bisect the nightly Rust version:

git clone https://github.com/ZcashFoundation/zebra.git
git checkout a763eec9f3
cd zebra-state

cat << EOF > cargo-build-release.sh
#!/usr/bin/env bash
cargo build --release
EOF
chmod +x cargo-build-release.sh

cargo-bisect-rustc --start=2022-11-07 --regress=ice --script=./cargo-build-release.sh

Zebra needs some build dependencies:
https://github.com/ZcashFoundation/zebra#build-instructions

Regression log:
searched nightlies: from nightly-2022-11-07 to nightly-2022-11-29
regressed nightly: nightly-2022-11-20
searched commit range: b833ad5...c5d82ed
regressed commit: 2f8d804

bisected with cargo-bisect-rustc v0.6.4

Host triple: x86_64-unknown-linux-gnu
Reproduce with:

cargo bisect-rustc --regress=ice --script=./cargo-build-release.sh 

Analysis

This might be caused by -C linker-plugin-lto or release builds, but I couldn't find an exact set of flags or a minimal example to reproduce it.

cargo build does not fail, either from the individual crate or workspace directory. But cargo build --release and cargo install --git https://github.com/ZcashFoundation/zebra.git zebrad fail.

I tried commenting out my whole .cargo/config.toml, and it didn't make a difference.

Error output

error: internal compiler error: no errors encountered even though `delay_span_bug` issued                
                                                                                                         
error: internal compiler error: broken MIR in Item(WithOptConstParam { did: DefId(0:1718 ~ zebra_state[4d
f4]::service::finalized_state::zebra_db::metrics::block_precommit_metrics), const_param_did: None }) (aft
er phase change to runtime-optimized) at bb128[5]:                                                       
                                Field projection `_37.field[0]` specified type `std::iter::adapters::flat
ten::FlattenCompat<std::iter::Map<std::slice::Iter<'_, std::sync::Arc<zebra_chain::transaction::Transacti
on>>, [closure@zebra-state/src/service/finalized_state/zebra_db/metrics.rs:39:19: 39:22]>, std::iter::Fla
tMap<std::option::IntoIter<&zebra_chain::orchard::ShieldedData>, std::iter::Map<std::iter::Map<std::slice
::Iter<'_, zebra_chain::orchard::AuthorizedAction>, [closure@zebra_chain::orchard::shielded_data::<impl z
ebra_chain::serialization::AtLeastOne<zebra_chain::orchard::AuthorizedAction>>::actions::{closure#0}]>, [
closure@zebra_chain::orchard::ShieldedData::nullifiers::{closure#0}]>, for<'a> fn(&'a zebra_chain::orchar
d::ShieldedData) -> impl std::iter::Iterator<Item = &'a zebra_chain::orchard::Nullifier> {zebra_chain::or
chard::ShieldedData::nullifiers}>>`, but actual type is `std::iter::adapters::flatten::FlattenCompat<std:
:iter::Map<std::slice::Iter<'_, std::sync::Arc<zebra_chain::transaction::Transaction>>, [closure@zebra-st
ate/src/service/finalized_state/zebra_db/metrics.rs:39:19: 39:22]>, <std::iter::FlatMap<std::option::Into
Iter<&zebra_chain::orchard::ShieldedData>, std::iter::Map<std::iter::Map<std::slice::Iter<'_, zebra_chain
::orchard::AuthorizedAction>, [closure@zebra_chain::orchard::shielded_data::<impl zebra_chain::serializat
ion::AtLeastOne<zebra_chain::orchard::AuthorizedAction>>::actions::{closure#0}]>, [closure@zebra_chain::o
rchard::ShieldedData::nullifiers::{closure#0}]>, for<'a> fn(&'a zebra_chain::orchard::ShieldedData) -> im
pl std::iter::Iterator<Item = &'a zebra_chain::orchard::Nullifier> {zebra_chain::orchard::ShieldedData::n
ullifiers}> as std::iter::IntoIterator>::IntoIter>`                                                      
  --> zebra-state/src/service/finalized_state/zebra_db/metrics.rs:36:35 
   |                                                                                                     
36 |       let orchard_nullifier_count = block
   |  ___________________________________^
37 | |         .transactions
38 | |         .iter()
39 | |         .flat_map(|t| t.orchard_nullifiers()) 
40 | |         .count();
   | |________________^
   |
   = note: delayed at compiler/rustc_const_eval/src/transform/validate.rs:229:30

error: internal compiler error: broken MIR in Item(WithOptConstParam { did: DefId(0:4282 ~ zebra_state[4d
f4]::service::check::nullifier::no_duplicates_in_finalized_chain), const_param_did: None }) (after phase 
change to runtime-optimized) at bb60[6]:
                                Field projection `(*_128).field[0]` specified type `std::iter::adapters::
flatten::FlattenCompat<std::iter::Map<std::slice::Iter<'_, std::sync::Arc<zebra_chain::transaction::Trans
action>>, [closure@zebra_chain::block::Block::orchard_nullifiers::{closure#0}]>, std::iter::FlatMap<std::
option::IntoIter<&zebra_chain::orchard::ShieldedData>, std::iter::Map<std::iter::Map<std::slice::Iter<'_,
 zebra_chain::orchard::AuthorizedAction>, [closure@zebra_chain::orchard::shielded_data::<impl zebra_chain
::serialization::AtLeastOne<zebra_chain::orchard::AuthorizedAction>>::actions::{closure#0}]>, [closure@ze
bra_chain::orchard::ShieldedData::nullifiers::{closure#0}]>, for<'a> fn(&'a zebra_chain::orchard::Shielde
dData) -> impl std::iter::Iterator<Item = &'a zebra_chain::orchard::Nullifier> {zebra_chain::orchard::Shi
eldedData::nullifiers}>>`, but actual type is `std::iter::adapters::flatten::FlattenCompat<std::iter::Map
<std::slice::Iter<'_, std::sync::Arc<zebra_chain::transaction::Transaction>>, [closure@zebra_chain::block
::Block::orchard_nullifiers::{closure#0}]>, <std::iter::FlatMap<std::option::IntoIter<&zebra_chain::orcha
rd::ShieldedData>, std::iter::Map<std::iter::Map<std::slice::Iter<'_, zebra_chain::orchard::AuthorizedAct
ion>, [closure@zebra_chain::orchard::shielded_data::<impl zebra_chain::serialization::AtLeastOne<zebra_ch
ain::orchard::AuthorizedAction>>::actions::{closure#0}]>, [closure@zebra_chain::orchard::ShieldedData::nu
llifiers::{closure#0}]>, for<'a> fn(&'a zebra_chain::orchard::ShieldedData) -> impl std::iter::Iterator<I
tem = &'a zebra_chain::orchard::Nullifier> {zebra_chain::orchard::ShieldedData::nullifiers}> as std::iter
::IntoIterator>::IntoIter>`
  --> zebra-state/src/service/check/nullifier.rs:48:22
   |
48 |     for nullifier in prepared.block.orchard_nullifiers() {
   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: delayed at compiler/rustc_const_eval/src/transform/validate.rs:229:30]

thread 'rustc' panicked at 'Box<dyn Any>', compiler/rustc_errors/src/lib.rs:1609:13
Backtrace

stack backtrace:
   0: std::panicking::begin_panic::<rustc_errors::ExplicitBug>
   1: std::panic::panic_any::<rustc_errors::ExplicitBug>
   2: <rustc_errors::HandlerInner>::flush_delayed::<alloc::vec::Vec<rustc_errors::diagnostic::Diagnostic>
, &str>
   3: <rustc_errors::HandlerInner as core::ops::drop::Drop>::drop
   4: core::ptr::drop_in_place::<rustc_session::parse::ParseSess>
   5: core::ptr::drop_in_place::<rustc_session::session::Session>
   6: core::ptr::drop_in_place::<rustc_interface::interface::Compiler>
   7: rustc_span::with_source_map::<core::result::Result<(), rustc_errors::ErrorGuaranteed>, rustc_interf
ace::interface::run_compiler<core::result::Result<(), rustc_errors::ErrorGuaranteed>, rustc_driver::run_c
ompiler::{closure#1}>::{closure#0}::{closure#0}>
   8: <scoped_tls::ScopedKey<rustc_span::SessionGlobals>>::set::<rustc_interface::interface::run_compiler
<core::result::Result<(), rustc_errors::ErrorGuaranteed>, rustc_driver::run_compiler::{closure#1}>::{clos
ure#0}, core::result::Result<(), rustc_errors::ErrorGuaranteed>>
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

note: compiler flags: --crate-type lib -C opt-level=3 -C panic=abort -C linker-plugin-lto -C debuginfo=1 
-C debug-assertions=on

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

query stack during panic:
end of query stack
error: could not compile `zebra-state`

No activity

Activity on this issue will appear here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: This is a bug.E-needs-mcveCall for participation: This issue has a repro, but needs a Minimal Complete and Verifiable ExampleI-ICEIssue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions