Stabilize the copy_closures and clone_closures features
In addition to the `Fn*` family of traits, closures now implement `Copy` (and similarly `Clone`) if all of the captures do.
This commit is contained in:
parent
52f7e8836c
commit
ee67e14034
@ -616,8 +616,6 @@ define_dep_nodes!( <'tcx>
|
||||
[input] MissingExternCrateItem(CrateNum),
|
||||
[input] UsedCrateSource(CrateNum),
|
||||
[input] PostorderCnums,
|
||||
[] HasCloneClosures(CrateNum),
|
||||
[] HasCopyClosures(CrateNum),
|
||||
|
||||
// This query is not expected to have inputs -- as a result, it's
|
||||
// not a good candidate for "replay" because it's essentially a
|
||||
|
@ -45,7 +45,7 @@
|
||||
#![feature(box_syntax)]
|
||||
#![feature(conservative_impl_trait)]
|
||||
#![feature(const_fn)]
|
||||
#![feature(copy_closures, clone_closures)]
|
||||
#![cfg_attr(stage0, feature(copy_closures, clone_closures))]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(drain_filter)]
|
||||
#![feature(dyn_trait)]
|
||||
|
@ -2086,12 +2086,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
|
||||
ty::TyClosure(def_id, substs) => {
|
||||
let trait_id = obligation.predicate.def_id();
|
||||
let copy_closures =
|
||||
Some(trait_id) == self.tcx().lang_items().copy_trait() &&
|
||||
self.tcx().has_copy_closures(def_id.krate);
|
||||
let clone_closures =
|
||||
Some(trait_id) == self.tcx().lang_items().clone_trait() &&
|
||||
self.tcx().has_clone_closures(def_id.krate);
|
||||
let copy_closures = Some(trait_id) == self.tcx().lang_items().copy_trait();
|
||||
let clone_closures = Some(trait_id) == self.tcx().lang_items().clone_trait();
|
||||
|
||||
if copy_closures || clone_closures {
|
||||
Where(ty::Binder(substs.upvar_tys(def_id, self.tcx()).collect()))
|
||||
|
@ -2520,14 +2520,6 @@ pub fn provide(providers: &mut ty::maps::Providers) {
|
||||
assert_eq!(cnum, LOCAL_CRATE);
|
||||
tcx.output_filenames.clone()
|
||||
};
|
||||
providers.has_copy_closures = |tcx, cnum| {
|
||||
assert_eq!(cnum, LOCAL_CRATE);
|
||||
tcx.features().copy_closures
|
||||
};
|
||||
providers.has_clone_closures = |tcx, cnum| {
|
||||
assert_eq!(cnum, LOCAL_CRATE);
|
||||
tcx.features().clone_closures
|
||||
};
|
||||
providers.features_query = |tcx, cnum| {
|
||||
assert_eq!(cnum, LOCAL_CRATE);
|
||||
Lrc::new(tcx.sess.features_untracked().clone())
|
||||
|
@ -604,24 +604,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::output_filenames<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> QueryDescription<'tcx> for queries::has_clone_closures<'tcx> {
|
||||
fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
|
||||
format!("seeing if the crate has enabled `Clone` closures")
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> QueryDescription<'tcx> for queries::vtable_methods<'tcx> {
|
||||
fn describe(tcx: TyCtxt, key: ty::PolyTraitRef<'tcx> ) -> String {
|
||||
format!("finding all methods for trait {}", tcx.item_path_str(key.def_id()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> QueryDescription<'tcx> for queries::has_copy_closures<'tcx> {
|
||||
fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
|
||||
format!("seeing if the crate has enabled `Copy` closures")
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> QueryDescription<'tcx> for queries::features_query<'tcx> {
|
||||
fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
|
||||
format!("looking up enabled feature gates")
|
||||
|
@ -382,9 +382,6 @@ define_maps! { <'tcx>
|
||||
[] fn output_filenames: output_filenames_node(CrateNum)
|
||||
-> Arc<OutputFilenames>,
|
||||
|
||||
[] fn has_copy_closures: HasCopyClosures(CrateNum) -> bool,
|
||||
[] fn has_clone_closures: HasCloneClosures(CrateNum) -> bool,
|
||||
|
||||
// Erases regions from `ty` to yield a new type.
|
||||
// Normally you would just use `tcx.erase_regions(&value)`,
|
||||
// however, which uses this query as a kind of cache.
|
||||
|
@ -917,8 +917,6 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
|
||||
}
|
||||
DepKind::UsedCrateSource => { force!(used_crate_source, krate!()); }
|
||||
DepKind::PostorderCnums => { force!(postorder_cnums, LOCAL_CRATE); }
|
||||
DepKind::HasCloneClosures => { force!(has_clone_closures, krate!()); }
|
||||
DepKind::HasCopyClosures => { force!(has_copy_closures, krate!()); }
|
||||
|
||||
DepKind::Freevars => { force!(freevars, def_id!()); }
|
||||
DepKind::MaybeUnusedTraitImport => {
|
||||
|
@ -228,16 +228,6 @@ impl CrateMetadata {
|
||||
attr::contains_name(&attrs, "no_builtins")
|
||||
}
|
||||
|
||||
pub fn has_copy_closures(&self, sess: &Session) -> bool {
|
||||
let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess);
|
||||
attr::contains_feature_attr(&attrs, "copy_closures")
|
||||
}
|
||||
|
||||
pub fn has_clone_closures(&self, sess: &Session) -> bool {
|
||||
let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess);
|
||||
attr::contains_feature_attr(&attrs, "clone_closures")
|
||||
}
|
||||
|
||||
pub fn panic_strategy(&self) -> PanicStrategy {
|
||||
self.root.panic_strategy.clone()
|
||||
}
|
||||
|
@ -256,9 +256,6 @@ provide! { <'tcx> tcx, def_id, other, cdata,
|
||||
|
||||
used_crate_source => { Lrc::new(cdata.source.clone()) }
|
||||
|
||||
has_copy_closures => { cdata.has_copy_closures(tcx.sess) }
|
||||
has_clone_closures => { cdata.has_clone_closures(tcx.sess) }
|
||||
|
||||
exported_symbols => {
|
||||
let cnum = cdata.cnum;
|
||||
assert!(cnum != LOCAL_CRATE);
|
||||
|
@ -76,7 +76,7 @@ This API is completely unstable and subject to change.
|
||||
#![feature(box_patterns)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(conservative_impl_trait)]
|
||||
#![feature(copy_closures, clone_closures)]
|
||||
#![cfg_attr(stage0, feature(copy_closures, clone_closures))]
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(from_ref)]
|
||||
#![feature(match_default_bindings)]
|
||||
|
@ -391,10 +391,6 @@ declare_features! (
|
||||
// Future-proofing enums/structs with #[non_exhaustive] attribute (RFC 2008)
|
||||
(active, non_exhaustive, "1.22.0", Some(44109), None),
|
||||
|
||||
// Copy/Clone closures (RFC 2132)
|
||||
(active, clone_closures, "1.22.0", Some(44490), None),
|
||||
(active, copy_closures, "1.22.0", Some(44490), None),
|
||||
|
||||
// allow `'_` placeholder lifetimes
|
||||
(active, underscore_lifetimes, "1.22.0", Some(44524), None),
|
||||
|
||||
@ -556,6 +552,9 @@ declare_features! (
|
||||
(accepted, inclusive_range_syntax, "1.26.0", Some(28237), None),
|
||||
// allow `..=` in patterns (RFC 1192)
|
||||
(accepted, dotdoteq_in_patterns, "1.26.0", Some(28237), None),
|
||||
// Copy/Clone closures (RFC 2132)
|
||||
(accepted, clone_closures, "1.26.0", Some(44490), None),
|
||||
(accepted, copy_closures, "1.26.0", Some(44490), None),
|
||||
);
|
||||
|
||||
// If you change this, please modify src/doc/unstable-book as well. You must
|
||||
@ -1867,8 +1866,6 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
|
||||
struct FeatureChecker {
|
||||
proc_macro: Option<Span>,
|
||||
custom_attribute: Option<Span>,
|
||||
copy_closures: Option<Span>,
|
||||
clone_closures: Option<Span>,
|
||||
}
|
||||
|
||||
impl FeatureChecker {
|
||||
@ -1884,14 +1881,6 @@ impl FeatureChecker {
|
||||
if features.custom_attribute {
|
||||
self.custom_attribute = self.custom_attribute.or(Some(span));
|
||||
}
|
||||
|
||||
if features.copy_closures {
|
||||
self.copy_closures = self.copy_closures.or(Some(span));
|
||||
}
|
||||
|
||||
if features.clone_closures {
|
||||
self.clone_closures = self.clone_closures.or(Some(span));
|
||||
}
|
||||
}
|
||||
|
||||
fn check(self, handler: &Handler) {
|
||||
@ -1903,15 +1892,6 @@ impl FeatureChecker {
|
||||
|
||||
FatalError.raise();
|
||||
}
|
||||
|
||||
if let (Some(span), None) = (self.copy_closures, self.clone_closures) {
|
||||
handler.struct_span_err(span, "`#![feature(copy_closures)]` can only be used with \
|
||||
`#![feature(clone_closures)]`")
|
||||
.span_note(span, "`#![feature(copy_closures)]` declared here")
|
||||
.emit();
|
||||
|
||||
FatalError.raise();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,8 +10,6 @@
|
||||
|
||||
// Check that closures do not implement `Clone` if their environment is not `Clone`.
|
||||
|
||||
#![feature(clone_closures)]
|
||||
|
||||
struct S(i32);
|
||||
|
||||
fn main() {
|
||||
|
@ -10,9 +10,6 @@
|
||||
|
||||
// Check that closures do not implement `Copy` if their environment is not `Copy`.
|
||||
|
||||
#![feature(copy_closures)]
|
||||
#![feature(clone_closures)]
|
||||
|
||||
fn main() {
|
||||
let mut a = 5;
|
||||
let hello = || {
|
||||
|
@ -1,19 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#![feature(unboxed_closures)]
|
||||
|
||||
fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
|
||||
|
||||
fn main() {
|
||||
let f = to_fn_once(move|| ());
|
||||
f();
|
||||
f(); //~ ERROR use of moved value
|
||||
}
|
@ -10,8 +10,6 @@
|
||||
|
||||
// Check that closures implement `Clone`.
|
||||
|
||||
#![feature(clone_closures)]
|
||||
|
||||
#[derive(Clone)]
|
||||
struct S(i32);
|
||||
|
||||
|
@ -10,9 +10,6 @@
|
||||
|
||||
// Check that closures implement `Copy`.
|
||||
|
||||
#![feature(copy_closures)]
|
||||
#![feature(clone_closures)]
|
||||
|
||||
fn call<T, F: FnOnce() -> T>(f: F) -> T { f() }
|
||||
|
||||
fn main() {
|
||||
|
@ -1,21 +0,0 @@
|
||||
// Copyright 2017 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.
|
||||
|
||||
#[derive(Clone)]
|
||||
struct S(i32);
|
||||
|
||||
fn main() {
|
||||
let a = S(5);
|
||||
let hello = move || {
|
||||
println!("Hello {}", a.0);
|
||||
};
|
||||
|
||||
let hello = hello.clone(); //~ ERROR no method named `clone` found for type
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
error[E0599]: no method named `clone` found for type `[closure@$DIR/feature-gate-clone-closures.rs:16:17: 18:6 a:_]` in the current scope
|
||||
--> $DIR/feature-gate-clone-closures.rs:20:23
|
||||
|
|
||||
LL | let hello = hello.clone(); //~ ERROR no method named `clone` found for type
|
||||
| ^^^^^
|
||||
|
|
||||
= note: hello is a function, perhaps you wish to call it
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0599`.
|
@ -1,19 +0,0 @@
|
||||
// Copyright 2017 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.
|
||||
|
||||
fn main() {
|
||||
let a = 5;
|
||||
let hello = || {
|
||||
println!("Hello {}", a);
|
||||
};
|
||||
|
||||
let b = hello;
|
||||
let c = hello; //~ ERROR use of moved value: `hello` [E0382]
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
error[E0382]: use of moved value: `hello`
|
||||
--> $DIR/feature-gate-copy-closures.rs:18:9
|
||||
|
|
||||
LL | let b = hello;
|
||||
| - value moved here
|
||||
LL | let c = hello; //~ ERROR use of moved value: `hello` [E0382]
|
||||
| ^ value used here after move
|
||||
|
|
||||
= note: move occurs because `hello` has type `[closure@$DIR/feature-gate-copy-closures.rs:13:17: 15:6 a:&i32]`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0382`.
|
@ -58,7 +58,10 @@ fn test6() {
|
||||
|
||||
fn test7() {
|
||||
fn foo<F>(_: F) where F: FnMut(Box<FnMut(isize)>, isize) {}
|
||||
let mut f = |g: Box<FnMut(isize)>, b: isize| {};
|
||||
let s = String::new(); // Capture to make f !Copy
|
||||
let mut f = move |g: Box<FnMut(isize)>, b: isize| {
|
||||
let _ = s.len();
|
||||
};
|
||||
f(Box::new(|a| {
|
||||
foo(f);
|
||||
//~^ ERROR cannot move `f` into closure because it is borrowed
|
||||
|
@ -28,7 +28,7 @@ LL | f.f.call_mut(())
|
||||
| ^^^ cannot borrow as mutable
|
||||
|
||||
error[E0504]: cannot move `f` into closure because it is borrowed
|
||||
--> $DIR/borrowck-call-is-borrow-issue-12224.rs:63:13
|
||||
--> $DIR/borrowck-call-is-borrow-issue-12224.rs:66:13
|
||||
|
|
||||
LL | f(Box::new(|a| {
|
||||
| - borrow of `f` occurs here
|
||||
@ -36,11 +36,11 @@ LL | foo(f);
|
||||
| ^ move into closure occurs here
|
||||
|
||||
error[E0507]: cannot move out of captured outer variable in an `FnMut` closure
|
||||
--> $DIR/borrowck-call-is-borrow-issue-12224.rs:63:13
|
||||
--> $DIR/borrowck-call-is-borrow-issue-12224.rs:66:13
|
||||
|
|
||||
LL | let mut f = |g: Box<FnMut(isize)>, b: isize| {};
|
||||
LL | let mut f = move |g: Box<FnMut(isize)>, b: isize| {
|
||||
| ----- captured outer variable
|
||||
LL | f(Box::new(|a| {
|
||||
...
|
||||
LL | foo(f);
|
||||
| ^ cannot move out of captured outer variable in an `FnMut` closure
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user