diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index f597820639c..5c0b35e46b1 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -92,31 +92,39 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Determine if the field can be used as a function in some way let field_ty = field.ty(cx, substs); - if let Ok(fn_once_trait_did) = cx.lang_items.require(FnOnceTraitLangItem) { - let infcx = fcx.infcx(); - infcx.probe(|_| { - let fn_once_substs = Substs::new_trait(vec![infcx.next_ty_var()], - Vec::new(), - field_ty); - let trait_ref = ty::TraitRef::new(fn_once_trait_did, - cx.mk_substs(fn_once_substs)); - let poly_trait_ref = trait_ref.to_poly_trait_ref(); - let obligation = Obligation::misc(span, - fcx.body_id, - poly_trait_ref.to_predicate()); - let mut selcx = SelectionContext::new(infcx); - if selcx.evaluate_obligation(&obligation) { - span_stored_function(); + match field_ty.sty { + // Not all of these (e.g. unsafe fns) implement FnOnce + // so we look for these beforehand + ty::TyClosure(..) | ty::TyBareFn(..) => span_stored_function(), + // If it's not a simple function, look for things which implement FnOnce + _ => { + if let Ok(fn_once_trait_did) = + cx.lang_items.require(FnOnceTraitLangItem) { + let infcx = fcx.infcx(); + infcx.probe(|_| { + let fn_once_substs = Substs::new_trait(vec![ + infcx.next_ty_var()], + Vec::new(), + field_ty); + let trait_ref = ty::TraitRef::new(fn_once_trait_did, + cx.mk_substs(fn_once_substs)); + let poly_trait_ref = trait_ref.to_poly_trait_ref(); + let obligation = Obligation::misc(span, + fcx.body_id, + poly_trait_ref + .to_predicate()); + let mut selcx = SelectionContext::new(infcx); + + if selcx.evaluate_obligation(&obligation) { + span_stored_function(); + } else { + span_did_you_mean(); + } + }); } else { - span_did_you_mean(); + span_did_you_mean() } - }); - } else { - match field_ty.sty { - // fallback to matching a closure or function pointer - ty::TyClosure(..) | ty::TyBareFn(..) => span_stored_function(), - _ => span_did_you_mean(), } } } diff --git a/src/test/compile-fail/issue-2392.rs b/src/test/compile-fail/issue-2392.rs index c5598e8785c..47d50eb9d53 100644 --- a/src/test/compile-fail/issue-2392.rs +++ b/src/test/compile-fail/issue-2392.rs @@ -11,6 +11,16 @@ #![feature(core)] use std::boxed::FnBox; +struct FuncContainer { + f1: fn(data: u8), + f2: extern "C" fn(data: u8), + f3: unsafe fn(data: u8), +} + +struct FuncContainerOuter { + container: Box +} + struct Obj where F: FnOnce() -> u32 { closure: F, not_closure: usize, @@ -66,3 +76,16 @@ fn main() { check_expression().closure();//~ ERROR no method named `closure` found //~^ NOTE use `(check_expression().closure)(...)` if you meant to call the function stored } + +impl FuncContainerOuter { + fn run(&self) { + unsafe { + (*self.container).f1(1); //~ ERROR no method named `f1` found + //~^ NOTE use `(*self.container.f1)(...)` + (*self.container).f2(1); //~ ERROR no method named `f2` found + //~^ NOTE use `(*self.container.f2)(...)` + (*self.container).f3(1); //~ ERROR no method named `f3` found + //~^ NOTE use `(*self.container.f3)(...)` + } + } +}