Skip to content

Commit e852419

Browse files
committed
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.
1 parent 4573da6 commit e852419

13 files changed

+199
-14
lines changed

src/libcore/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
#![allow(unknown_features)]
6060
#![feature(globs, intrinsics, lang_items, macro_rules, phase)]
6161
#![feature(simd, unsafe_destructor, slicing_syntax)]
62-
#![feature(default_type_params)]
62+
#![feature(default_type_params, unboxed_closures)]
6363
#![deny(missing_docs)]
6464

6565
mod macros;

src/librustc_typeck/check/callee.rs

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use syntax::ast;
12+
use syntax::codemap::Span;
13+
use CrateCtxt;
14+
15+
/// Check that it is legal to call methods of the trait corresponding
16+
/// to `trait_id` (this only cares about the trait, not the specific
17+
/// method that is called)
18+
pub fn check_legal_trait_for_method_call(ccx: &CrateCtxt, span: Span, trait_id: ast::DefId) {
19+
let tcx = ccx.tcx;
20+
let did = Some(trait_id);
21+
let li = &tcx.lang_items;
22+
23+
if did == li.drop_trait() {
24+
span_err!(tcx.sess, span, E0040, "explicit use of destructor method");
25+
} else if !tcx.sess.features.borrow().unboxed_closures {
26+
// the #[feature(unboxed_closures)] feature isn't
27+
// activated so we need to enforce the closure
28+
// restrictions.
29+
30+
let method = if did == li.fn_trait() {
31+
"call"
32+
} else if did == li.fn_mut_trait() {
33+
"call_mut"
34+
} else if did == li.fn_once_trait() {
35+
"call_once"
36+
} else {
37+
return // not a closure method, everything is OK.
38+
};
39+
40+
span_err!(tcx.sess, span, E0174,
41+
"explicit use of unboxed closure method `{}` is experimental",
42+
method);
43+
span_help!(tcx.sess, span,
44+
"add `#![feature(unboxed_closures)]` to the crate attributes to enable");
45+
}
46+
}

src/librustc_typeck/check/method/confirm.rs

+4-7
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
use super::probe;
1212

13-
use check::{mod, FnCtxt, NoPreference, PreferMutLvalue};
13+
use check::{mod, FnCtxt, NoPreference, PreferMutLvalue, callee};
1414
use middle::subst::{mod, Subst};
1515
use middle::traits;
1616
use middle::ty::{mod, Ty};
@@ -90,7 +90,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
9090
let self_ty = self.adjust_self_ty(unadjusted_self_ty, &pick.adjustment);
9191

9292
// Make sure nobody calls `drop()` explicitly.
93-
self.enforce_drop_trait_limitations(&pick);
93+
self.enforce_illegal_method_limitations(&pick);
9494

9595
// Create substitutions for the method's type parameters.
9696
let (rcvr_substs, method_origin) =
@@ -624,14 +624,11 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
624624
self.fcx.infcx()
625625
}
626626

627-
fn enforce_drop_trait_limitations(&self, pick: &probe::Pick) {
627+
fn enforce_illegal_method_limitations(&self, pick: &probe::Pick) {
628628
// Disallow calls to the method `drop` defined in the `Drop` trait.
629629
match pick.method_ty.container {
630630
ty::TraitContainer(trait_def_id) => {
631-
if Some(trait_def_id) == self.tcx().lang_items.drop_trait() {
632-
span_err!(self.tcx().sess, self.span, E0040,
633-
"explicit call to destructor");
634-
}
631+
callee::check_legal_trait_for_method_call(self.fcx.ccx, self.span, trait_def_id)
635632
}
636633
ty::ImplContainer(..) => {
637634
// Since `drop` is a trait method, we expect that any

src/librustc_typeck/check/mod.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ pub mod demand;
130130
pub mod method;
131131
pub mod wf;
132132
mod closure;
133+
mod callee;
133134

134135
/// Fields that are part of a `FnCtxt` which are inherited by
135136
/// closures defined within the function. For example:
@@ -5088,8 +5089,17 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
50885089
}
50895090

50905091
// Case 3. Reference to a method.
5091-
def::DefStaticMethod(..) => {
5092+
def::DefStaticMethod(_, providence) |
5093+
def::DefMethod(_, _, providence) => {
50925094
assert!(path.segments.len() >= 2);
5095+
5096+
match providence {
5097+
def::FromTrait(trait_did) => {
5098+
callee::check_legal_trait_for_method_call(fcx.ccx, span, trait_did)
5099+
}
5100+
def::FromImpl(_) => {}
5101+
}
5102+
50935103
segment_spaces = Vec::from_elem(path.segments.len() - 2, None);
50945104
segment_spaces.push(Some(subst::TypeSpace));
50955105
segment_spaces.push(Some(subst::FnSpace));
@@ -5101,7 +5111,6 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
51015111
def::DefMod(..) |
51025112
def::DefForeignMod(..) |
51035113
def::DefLocal(..) |
5104-
def::DefMethod(..) |
51055114
def::DefUse(..) |
51065115
def::DefRegion(..) |
51075116
def::DefLabel(..) |

src/librustc_typeck/coherence/mod.rs

+25
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,9 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
211211
trait_ref.repr(self.crate_context.tcx),
212212
token::get_ident(item.ident));
213213

214+
enforce_trait_manually_implementable(self.crate_context.tcx,
215+
item.span,
216+
trait_ref.def_id);
214217
self.add_trait_impl(trait_ref.def_id, impl_did);
215218
}
216219

@@ -476,6 +479,28 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
476479
}
477480
}
478481

482+
fn enforce_trait_manually_implementable(tcx: &ty::ctxt, sp: Span, trait_def_id: ast::DefId) {
483+
if tcx.sess.features.borrow().unboxed_closures {
484+
// the feature gate allows all of them
485+
return
486+
}
487+
let did = Some(trait_def_id);
488+
let li = &tcx.lang_items;
489+
490+
let trait_name = if did == li.fn_trait() {
491+
"Fn"
492+
} else if did == li.fn_mut_trait() {
493+
"FnMut"
494+
} else if did == li.fn_once_trait() {
495+
"FnOnce"
496+
} else {
497+
return // everything OK
498+
};
499+
span_err!(tcx.sess, sp, E0173, "manual implementations of `{}` are experimental", trait_name);
500+
span_help!(tcx.sess, sp,
501+
"add `#![feature(unboxed_closures)]` to the crate attributes to enable");
502+
}
503+
479504
fn subst_receiver_types_in_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>,
480505
impl_id: ast::DefId,
481506
impl_poly_type: &ty::Polytype<'tcx>,

src/librustc_typeck/diagnostics.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ register_diagnostics!(
5353
E0035,
5454
E0036,
5555
E0038,
56-
E0040,
56+
E0040, // explicit use of destructor method
5757
E0044,
5858
E0045,
5959
E0046,
@@ -147,5 +147,7 @@ register_diagnostics!(
147147
E0168,
148148
E0169,
149149
E0171,
150-
E0172
150+
E0172,
151+
E0173, // manual implementations of unboxed closure traits are experimental
152+
E0174 // explicit use of unboxed closure methods are experimental
151153
)

src/test/compile-fail/explicit-call-to-dtor.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,5 @@ impl Drop for Foo {
2020

2121
fn main() {
2222
let x = Foo { x: 3 };
23-
x.drop(); //~ ERROR explicit call to destructor
23+
x.drop(); //~ ERROR explicit use of destructor method
2424
}

src/test/compile-fail/explicit-call-to-supertrait-dtor.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ impl Drop for Foo {
2424

2525
impl Bar for Foo {
2626
fn blah(&self) {
27-
self.drop(); //~ ERROR explicit call to destructor
27+
self.drop(); //~ ERROR explicit use of destructor method
2828
}
2929
}
3030

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![allow(dead_code)]
12+
13+
struct Foo;
14+
impl Fn<(), ()> for Foo { //~ ERROR manual implementations of `Fn` are experimental
15+
extern "rust-call" fn call(&self, args: ()) -> () {}
16+
}
17+
struct Bar;
18+
impl FnMut<(), ()> for Bar { //~ ERROR manual implementations of `FnMut` are experimental
19+
extern "rust-call" fn call_mut(&self, args: ()) -> () {}
20+
}
21+
struct Baz;
22+
impl FnOnce<(), ()> for Baz { //~ ERROR manual implementations of `FnOnce` are experimental
23+
extern "rust-call" fn call_once(&self, args: ()) -> () {}
24+
}
25+
26+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![allow(dead_code)]
12+
13+
fn foo<F: Fn<(), ()>>(mut f: F) {
14+
f.call(()); //~ ERROR explicit use of unboxed closure method `call`
15+
f.call_mut(()); //~ ERROR explicit use of unboxed closure method `call_mut`
16+
f.call_once(()); //~ ERROR explicit use of unboxed closure method `call_once`
17+
}
18+
19+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![allow(dead_code)]
12+
13+
fn foo<F: Fn<(), ()>>(mut f: F, mut g: F) {
14+
Fn::call(&g, ()); //~ ERROR explicit use of unboxed closure method `call`
15+
FnMut::call_mut(&mut g, ()); //~ ERROR explicit use of unboxed closure method `call_mut`
16+
FnOnce::call_once(g, ()); //~ ERROR explicit use of unboxed closure method `call_once`
17+
}
18+
19+
fn main() {}
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
12+
struct Foo;
13+
14+
impl Drop for Foo {
15+
fn drop(&mut self) {}
16+
}
17+
18+
fn main() {
19+
Drop::drop(&mut Foo) //~ ERROR explicit use of destructor method
20+
}

src/test/run-pass/ufcs-type-params.rs

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
trait Foo<T> {
12+
fn get(&self) -> T;
13+
}
14+
15+
impl Foo<i32> for i32 {
16+
fn get(&self) -> i32 { *self }
17+
}
18+
19+
fn main() {
20+
let x: i32 = 1;
21+
Foo::<i32>::get(&x)
22+
}

0 commit comments

Comments
 (0)