Skip to content

unstable fingerprints error with mockall 0.10 #112430

Closed
@matt-phylum

Description

@matt-phylum

I think this problem is related to asomers/mockall#333. Upgrading to Mockall 0.11.4 is one of the things that prevents it from happening.

I'm not seeing the crash on beta 1.71.0-beta.2, but I can't see a bug for this so I don't know if that's intentional. When I upgraded to 1.70 it seemed like almost every other build I would get a crash. Coworkers downgraded to 1.69 because of it, so to me it seems like a good candidate for backporting if it's not already planned.

Code

[package]
name = "api"
version = "0.1.0"
edition = "2021"

[dependencies]
async-trait = "0.1.56"
mockall = "0.10.2"
paste = "1.0"
use paste::paste;

// This constant allows us to rebuild without changing anything in this file.
#[allow(unused)]
const RANDOM: &str = include_str!("rand.txt");

pub type Callback<T> = Box<dyn for<'a> FnOnce(&'a mut T) + 'static>;

// This trait doesn't seem like it should do anything, but removing it stops the crash.
#[mockall::automock]
pub trait DaoA {}

// Normally, you put these attributes in the opposite order.
// Doing it this way allows the mock callback to return a future for tests that involve synchronization.
#[async_trait::async_trait]
#[mockall::automock]
pub trait DaoB {
    async fn method(&self, param: &usize);
}

// Removing this send constraint stops the crash?
struct Wrapper<M>(Callback<M>)
where
    M: Send;

// Expanding this macro by hand stops the crash?
macro_rules! builder_struct {
    ($($dao_trait:ty),* $(,)?) => {
        paste! {
            pub struct Builder{
                $(
                    [< $dao_trait:snake >]: Wrapper<[<Mock $dao_trait>]>,
                )*
            }

            #[allow(unused)]
            impl Builder {
                $(
                    pub fn [< with_mock_ $dao_trait:snake>] (
                        mut self,
                        config_callback: impl for<'a> FnOnce(&'a mut [<Mock $dao_trait>]) + 'static,
                    ) -> Self {
                        let boxed: Callback<[<Mock $dao_trait>]> = Box::new(config_callback);
                        self.[< $dao_trait:snake >] = Wrapper(boxed);
                        self
                    }
                )*
            }
        }
    }
}

builder_struct!(DaoA, DaoB);

Meta

rustc --version --verbose:

rustc 1.70.0 (90c541806 2023-05-31)
binary: rustc
commit-hash: 90c541806f23a127002de5b4038be731ba1458ca
commit-date: 2023-05-31
host: aarch64-apple-darwin
release: 1.70.0
LLVM version: 16.0.2

Error output

thread 'rustc' panicked at 'Found unstable fingerprints for mir_built(ab11575bca0c211c-f2e0d84c65314716): Steal { value: RwLock(RefCell { value: Some(Body { basic_blocks: BasicBlocks { basic_blocks: [BasicBlockData { statements: [StorageLive(_3), StorageLive(_4), StorageLive(_5), _5 = move _2], terminator: Some(Terminator { source_info: SourceInfo { span: src/lib.rs:43:68: 43:93 (#68), scope: scope[0] }, kind: _4 = Box::<impl for<'a> FnOnce(&'a mut MockDaoB) + 'static>::new(move _5) -> [return: bb1, unwind: bb14] }), is_cleanup: false }, BasicBlockData { statements: [_3 = move _4 as std::boxed::Box<dyn for<'a> std::ops::FnOnce(&'a mut MockDaoB)> (Pointer(Unsize))], terminator: Some(Terminator { source_info: SourceInfo { span: src/lib.rs:43:92: 43:93 (#68), scope: scope[0] }, kind: drop(_4) -> [return: bb2, unwind: bb14] }), is_cleanup: false }, BasicBlockData { statements: [StorageDead(_5), StorageDead(_4), FakeRead(ForLet(None), _3), AscribeUserType(_3, o, UserTypeProjection { base: UserType(2), projs: [] }), StorageLive(_6), StorageLive(_7), StorageLive(_8), _8 = move _3, _7 = move _8 as std::boxed::Box<dyn for<'a> std::ops::FnOnce(&'a mut MockDaoB)> (Pointer(Unsize))], terminator: Some(Terminator { source_info: SourceInfo { span: src/lib.rs:44:67: 44:68 (#68), scope: scope[1] }, kind: drop(_8) -> [return: bb3, unwind: bb12] }), is_cleanup: false }, BasicBlockData { statements: [StorageDead(_8), _6 = Wrapper::<MockDaoB>(move _7)], terminator: Some(Terminator { source_info: SourceInfo { span: src/lib.rs:44:68: 44:69 (#68), scope: scope[1] }, kind: drop(_7) -> [return: bb4, unwind: bb11] }), is_cleanup: false }, BasicBlockData { statements: [StorageDead(_7)], terminator: Some(Terminator { source_info: SourceInfo { span: src/lib.rs:44:25: 44:52 (#127), scope: scope[1] }, kind: drop((_1.1: Wrapper<MockDaoB>)) -> [return: bb5, unwind: bb6] }), is_cleanup: false }, BasicBlockData { statements: [(_1.1: Wrapper<MockDaoB>) = move _6], terminator: Some(Terminator { source_info: SourceInfo { span: src/lib.rs:44:68: 44:69 (#68), scope: scope[1] }, kind: drop(_6) -> [return: bb7, unwind: bb13] }), is_cleanup: false }, BasicBlockData { statements: [(_1.1: Wrapper<MockDaoB>) = move _6], terminator: Some(Terminator { source_info: SourceInfo { span: src/lib.rs:44:25: 44:52 (#127), scope: scope[1] }, kind: goto -> bb11 }), is_cleanup: true }, BasicBlockData { statements: [StorageDead(_6), _0 = move _1], terminator: Some(Terminator { source_info: SourceInfo { span: src/lib.rs:46:21: 46:22 (#68), scope: scope[0] }, kind: drop(_3) -> [return: bb8, unwind: bb15] }), is_cleanup: false }, BasicBlockData { statements: [StorageDead(_3)], terminator: Some(Terminator { source_info: SourceInfo { span: src/lib.rs:46:21: 46:22 (#68), scope: scope[0] }, kind: drop(_2) -> [return: bb9, unwind: bb16] }), is_cleanup: false }, BasicBlockData { statements: [], terminator: Some(Terminator { source_info: SourceInfo { span: src/lib.rs:46:21: 46:22 (#68), scope: scope[0] }, kind: drop(_1) -> [return: bb10, unwind: bb17] }), is_cleanup: false }, BasicBlockData { statements: [], terminator: Some(Terminator { source_info: SourceInfo { span: src/lib.rs:46:22: 46:22 (#68), scope: scope[0] }, kind: return }), is_cleanup: false }, BasicBlockData { statements: [], terminator: Some(Terminator { source_info: SourceInfo { span: src/lib.rs:44:68: 44:69 (#68), scope: scope[1] }, kind: drop(_6) -> [return: bb13, unwind terminate] }), is_cleanup: true }, BasicBlockData { statements: [], terminator: Some(Terminator { source_info: SourceInfo { span: src/lib.rs:44:68: 44:69 (#68), scope: scope[1] }, kind: drop(_7) -> [return: bb13, unwind terminate] }), is_cleanup: true }, BasicBlockData { statements: [], terminator: Some(Terminator { source_info: SourceInfo { span: src/lib.rs:46:21: 46:22 (#68), scope: scope[0] }, kind: drop(_3) -> [return: bb15, unwind terminate] }), is_cleanup: true }, BasicBlockData { statements: [], terminator: Some(Terminator { source_info: SourceInfo { span: src/lib.rs:43:92: 43:93 (#68), scope: scope[0] }, kind: drop(_5) -> [return: bb15, unwind terminate] }), is_cleanup: true }, BasicBlockData { statements: [], terminator: Some(Terminator { source_info: SourceInfo { span: src/lib.rs:46:21: 46:22 (#68), scope: scope[0] }, kind: drop(_2) -> [return: bb16, unwind terminate] }), is_cleanup: true }, BasicBlockData { statements: [], terminator: Some(Terminator { source_info: SourceInfo { span: src/lib.rs:46:21: 46:22 (#68), scope: scope[0] }, kind: drop(_1) -> [return: bb17, unwind terminate] }), is_cleanup: true }, BasicBlockData { statements: [], terminator: Some(Terminator { source_info: SourceInfo { span: src/lib.rs:39:21: 46:22 (#68), scope: scope[0] }, kind: resume }), is_cleanup: true }], cache: Cache { predecessors: OnceCell(Uninit), switch_sources: OnceCell(Uninit), is_cyclic: OnceCell(Uninit), postorder: OnceCell(Uninit) } }, phase: Built, pass_count: 0, source: MirSource { instance: Item(WithOptConstParam { did: DefId(0:258 ~ api[b95e]::{impl#14}::with_mock_dao_b), const_param_did: None }), promoted: None }, source_scopes: [SourceScopeData { span: src/lib.rs:39:21: 46:22 (#68), parent_scope: None, inlined: None, inlined_parent_scope: None, local_data: Set(SourceScopeLocalData { lint_root: HirId(DefId(0:258 ~ api[b95e]::{impl#14}::with_mock_dao_b).0), safety: Safe }) }, SourceScopeData { span: src/lib.rs:43:25: 46:22 (#68), parent_scope: Some(scope[0]), inlined: None, inlined_parent_scope: None, local_data: Set(SourceScopeLocalData { lint_root: HirId(DefId(0:258 ~ api[b95e]::{impl#14}::with_mock_dao_b).0), safety: Safe }) }], generator: None, local_decls: [LocalDecl { mutability: Mut, local_info: Set(Boring), internal: false, ty: Builder, user_ty: None, source_info: SourceInfo { span: src/lib.rs:42:26: 42:30 (#68), scope: scope[0] } }, LocalDecl { mutability: Mut, local_info: Set(User(ImplicitSelf(Mut))), internal: false, ty: Builder, user_ty: None, source_info: SourceInfo { span: src/lib.rs:40:25: 40:33 (#68), scope: scope[0] } }, LocalDecl { mutability: Not, local_info: Set(User(Var(VarBindingForm { binding_mode: BindByValue(Not), opt_ty_info: Some(src/lib.rs:41:42: 41:100 (#68)), opt_match_place: Some((None, src/lib.rs:41:25: 41:40 (#68))), pat_span: src/lib.rs:41:25: 41:40 (#68) }))), internal: false, ty: impl for<'a> FnOnce(&'a mut MockDaoB) + 'static, user_ty: None, source_info: SourceInfo { span: src/lib.rs:41:25: 41:40 (#68), scope: scope[0] } }, LocalDecl { mutability: Not, local_info: Set(User(Var(VarBindingForm { binding_mode: BindByValue(Not), opt_ty_info: None, opt_match_place: Some((None, src/lib.rs:43:68: 43:93 (#68))), pat_span: src/lib.rs:43:29: 43:34 (#68) }))), internal: false, ty: std::boxed::Box<dyn for<'a> std::ops::FnOnce(&'a mut MockDaoB)>, user_ty: Some(UserTypeProjections { contents: [(UserTypeProjection { base: UserType(0), projs: [] }, src/lib.rs:43:36: 43:65 (#68))] }), source_info: SourceInfo { span: src/lib.rs:43:29: 43:34 (#68), scope: scope[0] } }, LocalDecl { mutability: Mut, local_info: Set(Boring), internal: false, ty: std::boxed::Box<impl for<'a> FnOnce(&'a mut MockDaoB) + 'static>, user_ty: None, source_info: SourceInfo { span: src/lib.rs:43:68: 43:93 (#68), scope: scope[0] } }, LocalDecl { mutability: Mut, local_info: Set(Boring), internal: false, ty: impl for<'a> FnOnce(&'a mut MockDaoB) + 'static, user_ty: None, source_info: SourceInfo { span: src/lib.rs:43:77: 43:92 (#68), scope: scope[0] } }, LocalDecl { mutability: Mut, local_info: Set(Boring), internal: false, ty: Wrapper<MockDaoB>, user_ty: None, source_info: SourceInfo { span: src/lib.rs:44:55: 44:69 (#68), scope: scope[0] } }, LocalDecl { mutability: Mut, local_info: Set(AggregateTemp), internal: false, ty: std::boxed::Box<dyn for<'a> std::ops::FnOnce(&'a mut MockDaoB)>, user_ty: None, source_info: SourceInfo { span: src/lib.rs:44:63: 44:68 (#68), scope: scope[0] } }, LocalDecl { mutability: Mut, local_info: Set(Boring), internal: false, ty: std::boxed::Box<dyn for<'a> std::ops::FnOnce(&'a mut MockDaoB)>, user_ty: None, source_info: SourceInfo { span: src/lib.rs:44:63: 44:68 (#68), scope: scope[0] } }], user_type_annotations: [CanonicalUserTypeAnnotation { user_ty: Canonical { value: Ty(std::boxed::Box<(dyn for<'a> std::ops::FnOnce(&'a mut MockDaoB) + 'static)>), max_universe: U0, variables: [] }, span: src/lib.rs:43:36: 43:65 (#68), inferred_ty: std::boxed::Box<dyn for<'a> std::ops::FnOnce(&'a mut MockDaoB)> }, CanonicalUserTypeAnnotation { user_ty: Canonical { value: TypeOf(DefId(5:285 ~ alloc[c023]::boxed::{impl#0}::new), UserSubsts { substs: [^0], user_self_ty: Some(UserSelfTy { impl_def_id: DefId(5:283 ~ alloc[c023]::boxed::{impl#0}), self_ty: std::boxed::Box<^1, ^2> }) }), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: src/lib.rs:43:68: 43:76 (#68), inferred_ty: fn(impl for<'a> FnOnce(&'a mut MockDaoB) + 'static) -> std::boxed::Box<impl for<'a> FnOnce(&'a mut MockDaoB) + 'static> {std::boxed::Box::<impl for<'a> FnOnce(&'a mut MockDaoB) + 'static>::new} }, CanonicalUserTypeAnnotation { user_ty: Canonical { value: Ty(std::boxed::Box<(dyn for<'a> std::ops::FnOnce(&'a mut MockDaoB) + 'static)>), max_universe: U0, variables: [] }, span: src/lib.rs:43:36: 43:65 (#68), inferred_ty: std::boxed::Box<dyn for<'a> std::ops::FnOnce(&'a mut MockDaoB)> }], arg_count: 2, spread_arg: None, var_debug_info: [VarDebugInfo { name: "self", source_info: SourceInfo { span: src/lib.rs:40:25: 40:33 (#68), scope: scope[0] }, value: _1, argument_index: Some(1) }, VarDebugInfo { name: "config_callback", source_info: SourceInfo { span: src/lib.rs:41:25: 41:40 (#68), scope: scope[0] }, value: _2, argument_index: Some(2) }, VarDebugInfo { name: "boxed", source_info: SourceInfo { span: src/lib.rs:43:29: 43:34 (#68), scope: scope[1] }, value: _3, argument_index: None }], span: src/lib.rs:39:21: 46:22 (#68), required_consts: [], is_polymorphic: true, injection_phase: None, tainted_by_errors: None }) }) }', /rustc/90c541806f23a127002de5b4038be731ba1458ca/compiler/rustc_query_system/src/query/plumbing.rs:715:9
Backtrace

stack backtrace:
   0: _rust_begin_unwind
   1: core::panicking::panic_fmt
   2: rustc_query_system::query::plumbing::incremental_verify_ich_failed::<rustc_middle::ty::context::TyCtxt>
   3: <std::thread::local::LocalKey<core::cell::Cell<*const ()>>>::with::<rustc_middle::ty::context::tls::enter_context<rustc_query_system::query::plumbing::execute_job_incr<rustc_query_impl::queries::mir_built, rustc_query_impl::plumbing::QueryCtxt>::{closure#1}, core::option::Option<(rustc_middle::query::erase::Erased<[u8; 8]>, rustc_query_system::dep_graph::graph::DepNodeIndex)>>::{closure#0}, core::option::Option<(rustc_middle::query::erase::Erased<[u8; 8]>, rustc_query_system::dep_graph::graph::DepNodeIndex)>>
   4: rustc_query_system::query::plumbing::try_execute_query::<rustc_query_impl::queries::mir_built, rustc_query_impl::plumbing::QueryCtxt>
   5: <rustc_query_impl::Queries as rustc_middle::ty::query::QueryEngine>::mir_built
   6: rustc_mir_transform::mir_const
   7: <std::thread::local::LocalKey<core::cell::Cell<*const ()>>>::with::<rustc_middle::ty::context::tls::enter_context<rustc_query_system::query::plumbing::execute_job_incr<rustc_query_impl::queries::mir_const, rustc_query_impl::plumbing::QueryCtxt>::{closure#1}, core::option::Option<(rustc_middle::query::erase::Erased<[u8; 8]>, rustc_query_system::dep_graph::graph::DepNodeIndex)>>::{closure#0}, core::option::Option<(rustc_middle::query::erase::Erased<[u8; 8]>, rustc_query_system::dep_graph::graph::DepNodeIndex)>>
   8: rustc_query_system::query::plumbing::try_execute_query::<rustc_query_impl::queries::mir_const, rustc_query_impl::plumbing::QueryCtxt>
   9: <rustc_query_impl::Queries as rustc_middle::ty::query::QueryEngine>::mir_const
  10: rustc_mir_transform::mir_promoted
  11: <std::thread::local::LocalKey<core::cell::Cell<*const ()>>>::with::<rustc_middle::ty::context::tls::enter_context<rustc_query_system::query::plumbing::execute_job_incr<rustc_query_impl::queries::mir_promoted, rustc_query_impl::plumbing::QueryCtxt>::{closure#1}, core::option::Option<(rustc_middle::query::erase::Erased<[u8; 16]>, rustc_query_system::dep_graph::graph::DepNodeIndex)>>::{closure#0}, core::option::Option<(rustc_middle::query::erase::Erased<[u8; 16]>, rustc_query_system::dep_graph::graph::DepNodeIndex)>>
  12: rustc_query_system::query::plumbing::try_execute_query::<rustc_query_impl::queries::mir_promoted, rustc_query_impl::plumbing::QueryCtxt>
  13: <rustc_query_impl::Queries as rustc_middle::ty::query::QueryEngine>::mir_promoted
  14: rustc_borrowck::mir_borrowck
  15: <rustc_borrowck::provide::{closure#0} as core::ops::function::FnOnce<(rustc_middle::ty::context::TyCtxt, rustc_span::def_id::LocalDefId)>>::call_once
  16: <std::thread::local::LocalKey<core::cell::Cell<*const ()>>>::with::<rustc_middle::ty::context::tls::enter_context<rustc_query_system::query::plumbing::execute_job_incr<rustc_query_impl::queries::mir_borrowck, rustc_query_impl::plumbing::QueryCtxt>::{closure#2}, (rustc_middle::query::erase::Erased<[u8; 8]>, rustc_query_system::dep_graph::graph::DepNodeIndex)>::{closure#0}, (rustc_middle::query::erase::Erased<[u8; 8]>, rustc_query_system::dep_graph::graph::DepNodeIndex)>
  17: rustc_query_system::query::plumbing::try_execute_query::<rustc_query_impl::queries::mir_borrowck, rustc_query_impl::plumbing::QueryCtxt>
  18: <rustc_query_impl::Queries as rustc_middle::ty::query::QueryEngine>::mir_borrowck
  19: <core::panic::unwind_safe::AssertUnwindSafe<rustc_data_structures::sync::par_for_each_in<&[rustc_span::def_id::LocalDefId], <rustc_middle::hir::map::Map>::par_body_owners<rustc_interface::passes::analysis::{closure#2}::{closure#0}>::{closure#0}>::{closure#0}::{closure#0}> as core::ops::function::FnOnce<()>>::call_once
  20: rustc_data_structures::sync::par_for_each_in::<&[rustc_span::def_id::LocalDefId], <rustc_middle::hir::map::Map>::par_body_owners<rustc_interface::passes::analysis::{closure#2}::{closure#0}>::{closure#0}>
  21: <rustc_session::session::Session>::time::<(), rustc_interface::passes::analysis::{closure#2}>
  22: rustc_interface::passes::analysis
  23: <std::thread::local::LocalKey<core::cell::Cell<*const ()>>>::with::<rustc_middle::ty::context::tls::enter_context<rustc_query_system::query::plumbing::execute_job_incr<rustc_query_impl::queries::analysis, rustc_query_impl::plumbing::QueryCtxt>::{closure#2}, (rustc_middle::query::erase::Erased<[u8; 1]>, rustc_query_system::dep_graph::graph::DepNodeIndex)>::{closure#0}, (rustc_middle::query::erase::Erased<[u8; 1]>, rustc_query_system::dep_graph::graph::DepNodeIndex)>
  24: rustc_query_system::query::plumbing::try_execute_query::<rustc_query_impl::queries::analysis, rustc_query_impl::plumbing::QueryCtxt>
  25: <rustc_query_impl::Queries as rustc_middle::ty::query::QueryEngine>::analysis
  26: <std::thread::local::LocalKey<core::cell::Cell<*const ()>>>::with::<rustc_middle::ty::context::tls::enter_context<<rustc_middle::ty::context::GlobalCtxt>::enter<rustc_driver_impl::run_compiler::{closure#1}::{closure#2}::{closure#4}, core::result::Result<(), rustc_span::ErrorGuaranteed>>::{closure#0}, core::result::Result<(), rustc_span::ErrorGuaranteed>>::{closure#0}, core::result::Result<(), rustc_span::ErrorGuaranteed>>
  27: <rustc_interface::queries::QueryResult<&rustc_middle::ty::context::GlobalCtxt>>::enter::<core::result::Result<(), rustc_span::ErrorGuaranteed>, rustc_driver_impl::run_compiler::{closure#1}::{closure#2}::{closure#4}>
  28: <rustc_interface::interface::Compiler>::enter::<rustc_driver_impl::run_compiler::{closure#1}::{closure#2}, core::result::Result<core::option::Option<rustc_interface::queries::Linker>, rustc_span::ErrorGuaranteed>>
  29: rustc_span::set_source_map::<core::result::Result<(), rustc_span::ErrorGuaranteed>, rustc_interface::interface::run_compiler<core::result::Result<(), rustc_span::ErrorGuaranteed>, rustc_driver_impl::run_compiler::{closure#1}>::{closure#0}::{closure#0}>

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-incr-compArea: Incremental compilationC-bugCategory: This is a bug.I-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