mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-01 06:51:58 +00:00
Feature-gate explicit unboxed closure method calls & manual impls,
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.
This commit is contained in:
parent
4573da6f4f
commit
e8524198e3
@ -59,7 +59,7 @@
|
||||
#![allow(unknown_features)]
|
||||
#![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;
|
||||
|
46
src/librustc_typeck/check/callee.rs
Normal file
46
src/librustc_typeck/check/callee.rs
Normal file
@ -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");
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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:
|
||||
@ -5088,8 +5089,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));
|
||||
@ -5101,7 +5111,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(..) |
|
||||
|
@ -211,6 +211,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);
|
||||
}
|
||||
|
||||
@ -476,6 +479,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>,
|
||||
|
@ -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
|
||||
)
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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() {}
|
@ -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() {}
|
@ -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() {}
|
20
src/test/compile-fail/illegal-ufcs-drop.rs
Normal file
20
src/test/compile-fail/illegal-ufcs-drop.rs
Normal file
@ -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
|
||||
}
|
22
src/test/run-pass/ufcs-type-params.rs
Normal file
22
src/test/run-pass/ufcs-type-params.rs
Normal file
@ -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)
|
||||
}
|
Loading…
Reference in New Issue
Block a user