about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2014-12-09 09:24:44 -0800
committerAlex Crichton <alex@alexcrichton.com>2014-12-09 09:24:44 -0800
commit26c24221e47f76aef8c479ec66c01700df4d6ebb (patch)
tree4dc924bf81a86b91159f04b1bf41ff60127fffa4 /src
parent60f97fc44aa745300ccda73e4f7d3c1827aacda9 (diff)
parente8524198e3931373f5e097dece21e36d21c4a537 (diff)
downloadrust-26c24221e47f76aef8c479ec66c01700df4d6ebb.tar.gz
rust-26c24221e47f76aef8c479ec66c01700df4d6ebb.zip
rollup merge of #19587: huonw/closure-feature-gate
detect UFCS drop and allow UFCS methods to have explicit type parameters.

Work towards #18875.

Since code could previously call the methods & implement the traits
manually, this is a

[breaking-change]

Closes #19586. Closes #19375.
Diffstat (limited to 'src')
-rw-r--r--src/libcore/lib.rs2
-rw-r--r--src/librustc_typeck/check/callee.rs46
-rw-r--r--src/librustc_typeck/check/method/confirm.rs11
-rw-r--r--src/librustc_typeck/check/mod.rs13
-rw-r--r--src/librustc_typeck/coherence/mod.rs25
-rw-r--r--src/librustc_typeck/diagnostics.rs6
-rw-r--r--src/test/compile-fail/explicit-call-to-dtor.rs2
-rw-r--r--src/test/compile-fail/explicit-call-to-supertrait-dtor.rs2
-rw-r--r--src/test/compile-fail/feature-gate-unboxed-closures-manual-impls.rs26
-rw-r--r--src/test/compile-fail/feature-gate-unboxed-closures-method-calls.rs19
-rw-r--r--src/test/compile-fail/feature-gate-unboxed-closures-ufcs-calls.rs19
-rw-r--r--src/test/compile-fail/illegal-ufcs-drop.rs20
-rw-r--r--src/test/run-pass/ufcs-type-params.rs22
13 files changed, 199 insertions, 14 deletions
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index 09d5061a02f..84d84cbd5e1 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -59,7 +59,7 @@
 #![allow(unknown_features, raw_pointer_deriving)]
 #![feature(globs, intrinsics, lang_items, macro_rules, phase)]
 #![feature(simd, unsafe_destructor, slicing_syntax)]
-#![feature(default_type_params)]
+#![feature(default_type_params, unboxed_closures)]
 #![deny(missing_docs)]
 
 mod macros;
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
new file mode 100644
index 00000000000..ee93c896433
--- /dev/null
+++ b/src/librustc_typeck/check/callee.rs
@@ -0,0 +1,46 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use syntax::ast;
+use syntax::codemap::Span;
+use CrateCtxt;
+
+/// Check that it is legal to call methods of the trait corresponding
+/// to `trait_id` (this only cares about the trait, not the specific
+/// method that is called)
+pub fn check_legal_trait_for_method_call(ccx: &CrateCtxt, span: Span, trait_id: ast::DefId) {
+    let tcx = ccx.tcx;
+    let did = Some(trait_id);
+    let li = &tcx.lang_items;
+
+    if did == li.drop_trait() {
+        span_err!(tcx.sess, span, E0040, "explicit use of destructor method");
+    } else if !tcx.sess.features.borrow().unboxed_closures {
+        // the #[feature(unboxed_closures)] feature isn't
+        // activated so we need to enforce the closure
+        // restrictions.
+
+        let method = if did == li.fn_trait() {
+            "call"
+        } else if did == li.fn_mut_trait() {
+            "call_mut"
+        } else if did == li.fn_once_trait() {
+            "call_once"
+        } else {
+            return // not a closure method, everything is OK.
+        };
+
+        span_err!(tcx.sess, span, E0174,
+                  "explicit use of unboxed closure method `{}` is experimental",
+                  method);
+        span_help!(tcx.sess, span,
+                   "add `#![feature(unboxed_closures)]` to the crate attributes to enable");
+    }
+}
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 1fe73f0478d..b6a9e2cbc59 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -10,7 +10,7 @@
 
 use super::probe;
 
-use check::{mod, FnCtxt, NoPreference, PreferMutLvalue};
+use check::{mod, FnCtxt, NoPreference, PreferMutLvalue, callee};
 use middle::subst::{mod, Subst};
 use middle::traits;
 use middle::ty::{mod, Ty};
@@ -90,7 +90,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
         let self_ty = self.adjust_self_ty(unadjusted_self_ty, &pick.adjustment);
 
         // Make sure nobody calls `drop()` explicitly.
-        self.enforce_drop_trait_limitations(&pick);
+        self.enforce_illegal_method_limitations(&pick);
 
         // Create substitutions for the method's type parameters.
         let (rcvr_substs, method_origin) =
@@ -624,14 +624,11 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
         self.fcx.infcx()
     }
 
-    fn enforce_drop_trait_limitations(&self, pick: &probe::Pick) {
+    fn enforce_illegal_method_limitations(&self, pick: &probe::Pick) {
         // Disallow calls to the method `drop` defined in the `Drop` trait.
         match pick.method_ty.container {
             ty::TraitContainer(trait_def_id) => {
-                if Some(trait_def_id) == self.tcx().lang_items.drop_trait() {
-                    span_err!(self.tcx().sess, self.span, E0040,
-                              "explicit call to destructor");
-                }
+                callee::check_legal_trait_for_method_call(self.fcx.ccx, self.span, trait_def_id)
             }
             ty::ImplContainer(..) => {
                 // Since `drop` is a trait method, we expect that any
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index d7916e0a4b6..8288cce3958 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -130,6 +130,7 @@ pub mod demand;
 pub mod method;
 pub mod wf;
 mod closure;
+mod callee;
 
 /// Fields that are part of a `FnCtxt` which are inherited by
 /// closures defined within the function.  For example:
@@ -5095,8 +5096,17 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         }
 
         // Case 3. Reference to a method.
-        def::DefStaticMethod(..) => {
+        def::DefStaticMethod(_, providence) |
+        def::DefMethod(_, _, providence) => {
             assert!(path.segments.len() >= 2);
+
+            match providence {
+                def::FromTrait(trait_did) => {
+                    callee::check_legal_trait_for_method_call(fcx.ccx, span, trait_did)
+                }
+                def::FromImpl(_) => {}
+            }
+
             segment_spaces = Vec::from_elem(path.segments.len() - 2, None);
             segment_spaces.push(Some(subst::TypeSpace));
             segment_spaces.push(Some(subst::FnSpace));
@@ -5108,7 +5118,6 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         def::DefMod(..) |
         def::DefForeignMod(..) |
         def::DefLocal(..) |
-        def::DefMethod(..) |
         def::DefUse(..) |
         def::DefRegion(..) |
         def::DefLabel(..) |
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index 578ed916541..c4e1f6fe8eb 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -212,6 +212,9 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
                    trait_ref.repr(self.crate_context.tcx),
                    token::get_ident(item.ident));
 
+            enforce_trait_manually_implementable(self.crate_context.tcx,
+                                                 item.span,
+                                                 trait_ref.def_id);
             self.add_trait_impl(trait_ref.def_id, impl_did);
         }
 
@@ -542,6 +545,28 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
     }
 }
 
+fn enforce_trait_manually_implementable(tcx: &ty::ctxt, sp: Span, trait_def_id: ast::DefId) {
+    if tcx.sess.features.borrow().unboxed_closures {
+        // the feature gate allows all of them
+        return
+    }
+    let did = Some(trait_def_id);
+    let li = &tcx.lang_items;
+
+    let trait_name = if did == li.fn_trait() {
+        "Fn"
+    } else if did == li.fn_mut_trait() {
+        "FnMut"
+    } else if did == li.fn_once_trait() {
+        "FnOnce"
+    } else {
+        return // everything OK
+    };
+    span_err!(tcx.sess, sp, E0173, "manual implementations of `{}` are experimental", trait_name);
+    span_help!(tcx.sess, sp,
+               "add `#![feature(unboxed_closures)]` to the crate attributes to enable");
+}
+
 fn subst_receiver_types_in_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>,
                                            impl_id: ast::DefId,
                                            impl_poly_type: &ty::Polytype<'tcx>,
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index 36e81f18103..e026fbd05c7 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -53,7 +53,7 @@ register_diagnostics!(
     E0035,
     E0036,
     E0038,
-    E0040,
+    E0040, // explicit use of destructor method
     E0044,
     E0045,
     E0046,
@@ -147,5 +147,7 @@ register_diagnostics!(
     E0168,
     E0169,
     E0171,
-    E0172
+    E0172,
+    E0173, // manual implementations of unboxed closure traits are experimental
+    E0174 // explicit use of unboxed closure methods are experimental
 )
diff --git a/src/test/compile-fail/explicit-call-to-dtor.rs b/src/test/compile-fail/explicit-call-to-dtor.rs
index 3f69cb6e51e..6b334dd6ecd 100644
--- a/src/test/compile-fail/explicit-call-to-dtor.rs
+++ b/src/test/compile-fail/explicit-call-to-dtor.rs
@@ -20,5 +20,5 @@ impl Drop for Foo {
 
 fn main() {
     let x = Foo { x: 3 };
-    x.drop();   //~ ERROR explicit call to destructor
+    x.drop();   //~ ERROR explicit use of destructor method
 }
diff --git a/src/test/compile-fail/explicit-call-to-supertrait-dtor.rs b/src/test/compile-fail/explicit-call-to-supertrait-dtor.rs
index 3d987bf4c58..d0dd0e68da6 100644
--- a/src/test/compile-fail/explicit-call-to-supertrait-dtor.rs
+++ b/src/test/compile-fail/explicit-call-to-supertrait-dtor.rs
@@ -24,7 +24,7 @@ impl Drop for Foo {
 
 impl Bar for Foo {
     fn blah(&self) {
-        self.drop();    //~ ERROR explicit call to destructor
+        self.drop();    //~ ERROR explicit use of destructor method
     }
 }
 
diff --git a/src/test/compile-fail/feature-gate-unboxed-closures-manual-impls.rs b/src/test/compile-fail/feature-gate-unboxed-closures-manual-impls.rs
new file mode 100644
index 00000000000..8999da5b175
--- /dev/null
+++ b/src/test/compile-fail/feature-gate-unboxed-closures-manual-impls.rs
@@ -0,0 +1,26 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(dead_code)]
+
+struct Foo;
+impl Fn<(), ()> for Foo { //~ ERROR manual implementations of `Fn` are experimental
+    extern "rust-call" fn call(&self, args: ()) -> () {}
+}
+struct Bar;
+impl FnMut<(), ()> for Bar { //~ ERROR manual implementations of `FnMut` are experimental
+    extern "rust-call" fn call_mut(&self, args: ()) -> () {}
+}
+struct Baz;
+impl FnOnce<(), ()> for Baz { //~ ERROR manual implementations of `FnOnce` are experimental
+    extern "rust-call" fn call_once(&self, args: ()) -> () {}
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/feature-gate-unboxed-closures-method-calls.rs b/src/test/compile-fail/feature-gate-unboxed-closures-method-calls.rs
new file mode 100644
index 00000000000..5a066c441cf
--- /dev/null
+++ b/src/test/compile-fail/feature-gate-unboxed-closures-method-calls.rs
@@ -0,0 +1,19 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(dead_code)]
+
+fn foo<F: Fn<(), ()>>(mut f: F) {
+    f.call(()); //~ ERROR explicit use of unboxed closure method `call`
+    f.call_mut(()); //~ ERROR explicit use of unboxed closure method `call_mut`
+    f.call_once(()); //~ ERROR explicit use of unboxed closure method `call_once`
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/feature-gate-unboxed-closures-ufcs-calls.rs b/src/test/compile-fail/feature-gate-unboxed-closures-ufcs-calls.rs
new file mode 100644
index 00000000000..8efaf00c9c8
--- /dev/null
+++ b/src/test/compile-fail/feature-gate-unboxed-closures-ufcs-calls.rs
@@ -0,0 +1,19 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(dead_code)]
+
+fn foo<F: Fn<(), ()>>(mut f: F, mut g: F) {
+    Fn::call(&g, ()); //~ ERROR explicit use of unboxed closure method `call`
+    FnMut::call_mut(&mut g, ()); //~ ERROR explicit use of unboxed closure method `call_mut`
+    FnOnce::call_once(g, ()); //~ ERROR explicit use of unboxed closure method `call_once`
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/illegal-ufcs-drop.rs b/src/test/compile-fail/illegal-ufcs-drop.rs
new file mode 100644
index 00000000000..f4c653bd573
--- /dev/null
+++ b/src/test/compile-fail/illegal-ufcs-drop.rs
@@ -0,0 +1,20 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+
+struct Foo;
+
+impl Drop for Foo {
+    fn drop(&mut self) {}
+}
+
+fn main() {
+    Drop::drop(&mut Foo) //~ ERROR explicit use of destructor method
+}
diff --git a/src/test/run-pass/ufcs-type-params.rs b/src/test/run-pass/ufcs-type-params.rs
new file mode 100644
index 00000000000..f4ad78da487
--- /dev/null
+++ b/src/test/run-pass/ufcs-type-params.rs
@@ -0,0 +1,22 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Foo<T> {
+    fn get(&self) -> T;
+}
+
+impl Foo<i32> for i32 {
+    fn get(&self) -> i32 { *self }
+}
+
+fn main() {
+    let x: i32 = 1;
+    Foo::<i32>::get(&x)
+}