diff --git a/src/analyze/local_def.rs b/src/analyze/local_def.rs index 60bffa9..de669cf 100644 --- a/src/analyze/local_def.rs +++ b/src/analyze/local_def.rs @@ -575,6 +575,19 @@ impl<'tcx, 'ctx> Analyzer<'tcx, 'ctx> { .iterate_to_fixpoint() .into_results_cursor(&tmp_body); + let mut zst_locals = BitSet::new_empty(self.body.local_decls.len()); + for (local, local_decl) in self.body.local_decls.iter_enumerated() { + let ty = local_decl.ty; + if self + .tcx + .layout_of(mir_ty::ParamEnv::reveal_all().and(ty)) + .map(|l| l.is_zst()) + .unwrap_or(false) + { + zst_locals.insert(local); + } + } + for (block, data) in mir::traversal::preorder(&tmp_body) { for statement_index in 0..=data.statements.len() { let loc = mir::Location { @@ -590,9 +603,16 @@ impl<'tcx, 'ctx> Analyzer<'tcx, 'ctx> { .map(|p| results.analysis().move_data().move_paths[p].place.local) .collect(); let mut_locals = self.mut_locals(data.visitable(statement_index)); - tracing::info!(?init_locals, ?mut_locals, ?statement_index, ?block, stmt = ?data.statements.get(statement_index)); + tracing::info!( + ?init_locals, + ?mut_locals, + ?zst_locals, + ?statement_index, + ?block, + stmt = ?data.statements.get(statement_index), + ); for mut_local in mut_locals.iter() { - if init_locals.contains(&mut_local) { + if init_locals.contains(&mut_local) || zst_locals.contains(mut_local) { self.body.local_decls[mut_local].mutability = mir::Mutability::Mut; tracing::info!(?mut_local, ?statement_index, ?block, "marking mut"); } diff --git a/src/refine/env.rs b/src/refine/env.rs index 59e5024..77b7556 100644 --- a/src/refine/env.rs +++ b/src/refine/env.rs @@ -887,14 +887,13 @@ where // TODO: consider cloning here again self.locals .iter() - .map(|(local, rty)| (Var::Local(*local), &rty.ty)) + .map(|(local, rty)| (Var::Local(*local), rty.ty.to_sort())) + .filter(|(_, s)| !s.is_singleton()) .chain( - self.temp_vars - .iter_enumerated() - .filter_map(|(idx, b)| b.as_type().map(|rty| (Var::Temp(idx), &rty.ty))), + self.temp_vars.iter_enumerated().filter_map(|(idx, b)| { + b.as_type().map(|rty| (Var::Temp(idx), rty.ty.to_sort())) + }), ) - .map(|(v, ty)| (v, ty.to_sort())) - .filter(|(_, s)| !s.is_singleton()) } fn vars(&self) -> impl Iterator)> + '_ { diff --git a/tests/ui/fail/closure_mut_param.rs b/tests/ui/fail/closure_mut_param.rs new file mode 100644 index 0000000..799c547 --- /dev/null +++ b/tests/ui/fail/closure_mut_param.rs @@ -0,0 +1,10 @@ +//@error-in-other-file: Unsat + +fn next(f: &mut F) where F: Fn() { + f(); +} + +fn main() { + let mut f = || { assert!(false); }; + next(&mut f); +} diff --git a/tests/ui/fail/mut_empty_tuple.rs b/tests/ui/fail/mut_empty_tuple.rs new file mode 100644 index 0000000..2feb50e --- /dev/null +++ b/tests/ui/fail/mut_empty_tuple.rs @@ -0,0 +1,10 @@ +//@error-in-other-file: Unsat + +fn next(_x: &mut ()) { + assert!(false); +} + +fn main() { + let mut s = (); + next(&mut s); +} diff --git a/tests/ui/pass/closure_mut_param.rs b/tests/ui/pass/closure_mut_param.rs new file mode 100644 index 0000000..fdfe826 --- /dev/null +++ b/tests/ui/pass/closure_mut_param.rs @@ -0,0 +1,10 @@ +//@check-pass + +fn next(f: &mut F) where F: Fn() { + f(); +} + +fn main() { + let mut f = || { assert!(true); }; + next(&mut f); +} diff --git a/tests/ui/pass/mut_empty_tuple.rs b/tests/ui/pass/mut_empty_tuple.rs new file mode 100644 index 0000000..36edb4b --- /dev/null +++ b/tests/ui/pass/mut_empty_tuple.rs @@ -0,0 +1,10 @@ +//@check-pass + +fn next(_x: &mut ()) { + assert!(true); +} + +fn main() { + let mut s = (); + next(&mut s); +}