Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/analyze/basic_block/visitor/rust_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ impl<'a, 'tcx, 'ctx> mir::visit::MutVisitor<'tcx> for RustCallVisitor<'a, 'tcx,
let borrowed_closure_local =
self.insert_immut_borrow(arg_closure_place, arg_closure_ty);
args[0].node = mir::Operand::Copy(borrowed_closure_local.into());
// As in case 3, the closure is no longer consumed by the call, so its
// drop obligation, which `moved_locals` stole, must be restored.
if arg_closure_place.projection.is_empty() {
self.analyzer.drop_after_terminator(arg_closure_place.local);
}
tracing::debug!("applied immut-borrow for closure argument");
}
} else if matches!(
Expand Down
18 changes: 14 additions & 4 deletions src/analyze/crate_.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ impl<'tcx, 'ctx> Analyzer<'tcx, 'ctx> {
#[tracing::instrument(skip(self), fields(def_id = %self.tcx.def_path_str(local_def_id)))]
fn refine_fn_def(&mut self, local_def_id: LocalDefId) {
let sig = self.ctx.fn_sig(local_def_id.to_def_id());
let has_constrained_type_param = !self.constrained_type_params(local_def_id).is_empty();

let mut analyzer = self.ctx.local_def_analyzer(local_def_id);

Expand Down Expand Up @@ -147,7 +148,9 @@ impl<'tcx, 'ctx> Analyzer<'tcx, 'ctx> {
};

use mir_ty::TypeVisitableExt as _;
if sig.has_param() {
// A trait-bounded type parameter must stay generic even when the signature does not
// mention it, since the body depends on which impl it is instantiated with.
if sig.has_param() || has_constrained_type_param {
// TODO: needs clear criteria on whether extern_spec'ed target fn is analyzed or not
if target_def_id.as_local().is_none_or(|def_id| {
self.skip_analysis.contains(&def_id) || !self.tcx.is_mir_available(def_id)
Expand Down Expand Up @@ -196,11 +199,13 @@ impl<'tcx, 'ctx> Analyzer<'tcx, 'ctx> {
}
}

fn placeholder_generic_args(&self, local_def_id: LocalDefId) -> mir_ty::GenericArgsRef<'tcx> {
/// Indices of the type parameters bound by a trait other than `Sized`, including bounds
/// inherited from the parent impl or trait.
fn constrained_type_params(&self, local_def_id: LocalDefId) -> HashSet<u32> {
let mut constrained_params = HashSet::new();
let predicates = self.tcx.predicates_of(local_def_id);
let predicates = self.tcx.predicates_of(local_def_id).instantiate_identity(self.tcx);
let sized_trait = self.tcx.lang_items().sized_trait().unwrap();
for (clause, _) in predicates.predicates {
for clause in predicates.predicates {
let mir_ty::ClauseKind::Trait(pred) = clause.kind().skip_binder() else {
continue;
};
Expand All @@ -217,6 +222,11 @@ impl<'tcx, 'ctx> Analyzer<'tcx, 'ctx> {
constrained_params.insert(param_ty.index);
}
}
constrained_params
}

fn placeholder_generic_args(&self, local_def_id: LocalDefId) -> mir_ty::GenericArgsRef<'tcx> {
let constrained_params = self.constrained_type_params(local_def_id);

let mut args: Vec<mir_ty::GenericArg<'tcx>> = Vec::new();

Expand Down
15 changes: 15 additions & 0 deletions tests/ui/fail/closure_fn_once_fn_kind.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//@error-in-other-file: Unsat
//@compile-flags: -C debug-assertions=off

fn call_once<F: FnOnce() -> i64>(f: F) -> i64 {
f()
}

fn main() {
let mut x = 1;
let r = &mut x;
*r = 5;
let c = move || *r;
call_once(c);
assert!(x == 6);
}
30 changes: 30 additions & 0 deletions tests/ui/fail/generic_impl_static_method.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//@error-in-other-file: Unsat
//@compile-flags: -C debug-assertions=off

trait K {
fn k() -> i64;
}

impl K for i32 {
fn k() -> i64 {
0
}
}

impl K for i64 {
fn k() -> i64 {
1
}
}

struct W<T>(T);

impl<T: K> W<T> {
fn kk() -> i64 {
T::k()
}
}

fn main() {
assert!(W::<i64>::kk() == 0);
}
15 changes: 15 additions & 0 deletions tests/ui/pass/closure_fn_once_fn_kind.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//@check-pass
//@compile-flags: -C debug-assertions=off

fn call_once<F: FnOnce() -> i64>(f: F) -> i64 {
f()
}

fn main() {
let mut x = 1;
let r = &mut x;
*r = 5;
let c = move || *r;
call_once(c);
assert!(x == 5);
}
30 changes: 30 additions & 0 deletions tests/ui/pass/generic_impl_static_method.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//@check-pass
//@compile-flags: -C debug-assertions=off

trait K {
fn k() -> i64;
}

impl K for i32 {
fn k() -> i64 {
0
}
}

impl K for i64 {
fn k() -> i64 {
1
}
}

struct W<T>(T);

impl<T: K> W<T> {
fn kk() -> i64 {
T::k()
}
}

fn main() {
assert!(W::<i64>::kk() == 1);
}
Loading