Closed
Description
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}>