about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorManish Goregaokar <manishsmail@gmail.com>2015-11-14 10:44:57 +0530
committerManish Goregaokar <manishsmail@gmail.com>2015-11-14 15:34:17 +0530
commit2b3117cabfa85a5d799c14ae56aac02b774c5320 (patch)
treea6a892d6793ec37b17059da9b4fdc27b7d7618e2 /src
parentafd4a5420c3a9f6642da655543aa26df15b2ef9c (diff)
downloadrust-2b3117cabfa85a5d799c14ae56aac02b774c5320.tar.gz
rust-2b3117cabfa85a5d799c14ae56aac02b774c5320.zip
Fix diagnostics for calling indirect extern function pointer field
Fixes #29043
Diffstat (limited to 'src')
-rw-r--r--src/librustc_typeck/check/method/suggest.rs54
-rw-r--r--src/test/compile-fail/issue-2392.rs23
2 files changed, 54 insertions, 23 deletions
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<FuncContainer>
+}
+
 struct Obj<F> 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)(...)`
+        }
+    }
+}