Skip to content

Commit 297a6e5

Browse files
committed
Rollup merge of #49299 - SimonSapin:ubiquity, r=nikomatsakis
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. Tracking issue: #44490
2 parents 5454451 + 1efe0b3 commit 297a6e5

24 files changed

+26
-171
lines changed

src/libcore/clone.rs

+5
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@
6363
/// This trait can be used with `#[derive]` if all fields are `Clone`. The `derive`d
6464
/// implementation of [`clone`] calls [`clone`] on each field.
6565
///
66+
/// ## Closures
67+
///
68+
/// Closure types automatically implement `Clone` if they capture no value from the environment
69+
/// or if all such captured values implement `Clone` themselves.
70+
///
6671
/// ## How can I implement `Clone`?
6772
///
6873
/// Types that are [`Copy`] should have a trivial implementation of `Clone`. More formally:

src/libcore/marker.rs

+5
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,11 @@ pub trait Unsize<T: ?Sized> {
166166
/// are allowed to access `x` after the assignment. Under the hood, both a copy and a move
167167
/// can result in bits being copied in memory, although this is sometimes optimized away.
168168
///
169+
/// ## Closures
170+
///
171+
/// Closure types automatically implement `Copy` if they capture no value from the environment
172+
/// or if all such captured values implement `Copy` themselves.
173+
///
169174
/// ## How can I implement `Copy`?
170175
///
171176
/// There are two ways to implement `Copy` on your type. The simplest is to use `derive`:

src/librustc/dep_graph/dep_node.rs

-2
Original file line numberDiff line numberDiff line change
@@ -617,8 +617,6 @@ define_dep_nodes!( <'tcx>
617617
[input] MissingExternCrateItem(CrateNum),
618618
[input] UsedCrateSource(CrateNum),
619619
[input] PostorderCnums,
620-
[] HasCloneClosures(CrateNum),
621-
[] HasCopyClosures(CrateNum),
622620

623621
// This query is not expected to have inputs -- as a result, it's
624622
// not a good candidate for "replay" because it's essentially a

src/librustc/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
#![feature(box_syntax)]
4646
#![feature(conservative_impl_trait)]
4747
#![feature(const_fn)]
48-
#![feature(copy_closures, clone_closures)]
48+
#![cfg_attr(stage0, feature(copy_closures, clone_closures))]
4949
#![feature(core_intrinsics)]
5050
#![feature(drain_filter)]
5151
#![feature(dyn_trait)]

src/librustc/traits/select.rs

+3-8
Original file line numberDiff line numberDiff line change
@@ -2086,14 +2086,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
20862086

20872087
ty::TyClosure(def_id, substs) => {
20882088
let trait_id = obligation.predicate.def_id();
2089-
let copy_closures =
2090-
Some(trait_id) == self.tcx().lang_items().copy_trait() &&
2091-
self.tcx().has_copy_closures(def_id.krate);
2092-
let clone_closures =
2093-
Some(trait_id) == self.tcx().lang_items().clone_trait() &&
2094-
self.tcx().has_clone_closures(def_id.krate);
2095-
2096-
if copy_closures || clone_closures {
2089+
let is_copy_trait = Some(trait_id) == self.tcx().lang_items().copy_trait();
2090+
let is_clone_trait = Some(trait_id) == self.tcx().lang_items().clone_trait();
2091+
if is_copy_trait || is_clone_trait {
20972092
Where(ty::Binder(substs.upvar_tys(def_id, self.tcx()).collect()))
20982093
} else {
20992094
Never

src/librustc/ty/context.rs

-8
Original file line numberDiff line numberDiff line change
@@ -2562,14 +2562,6 @@ pub fn provide(providers: &mut ty::maps::Providers) {
25622562
assert_eq!(cnum, LOCAL_CRATE);
25632563
tcx.output_filenames.clone()
25642564
};
2565-
providers.has_copy_closures = |tcx, cnum| {
2566-
assert_eq!(cnum, LOCAL_CRATE);
2567-
tcx.features().copy_closures
2568-
};
2569-
providers.has_clone_closures = |tcx, cnum| {
2570-
assert_eq!(cnum, LOCAL_CRATE);
2571-
tcx.features().clone_closures
2572-
};
25732565
providers.features_query = |tcx, cnum| {
25742566
assert_eq!(cnum, LOCAL_CRATE);
25752567
Lrc::new(tcx.sess.features_untracked().clone())

src/librustc/ty/maps/config.rs

-12
Original file line numberDiff line numberDiff line change
@@ -610,24 +610,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::output_filenames<'tcx> {
610610
}
611611
}
612612

613-
impl<'tcx> QueryDescription<'tcx> for queries::has_clone_closures<'tcx> {
614-
fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
615-
format!("seeing if the crate has enabled `Clone` closures")
616-
}
617-
}
618-
619613
impl<'tcx> QueryDescription<'tcx> for queries::vtable_methods<'tcx> {
620614
fn describe(tcx: TyCtxt, key: ty::PolyTraitRef<'tcx> ) -> String {
621615
format!("finding all methods for trait {}", tcx.item_path_str(key.def_id()))
622616
}
623617
}
624618

625-
impl<'tcx> QueryDescription<'tcx> for queries::has_copy_closures<'tcx> {
626-
fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
627-
format!("seeing if the crate has enabled `Copy` closures")
628-
}
629-
}
630-
631619
impl<'tcx> QueryDescription<'tcx> for queries::features_query<'tcx> {
632620
fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
633621
format!("looking up enabled feature gates")

src/librustc/ty/maps/mod.rs

-3
Original file line numberDiff line numberDiff line change
@@ -387,9 +387,6 @@ define_maps! { <'tcx>
387387
[] fn output_filenames: output_filenames_node(CrateNum)
388388
-> Arc<OutputFilenames>,
389389

390-
[] fn has_copy_closures: HasCopyClosures(CrateNum) -> bool,
391-
[] fn has_clone_closures: HasCloneClosures(CrateNum) -> bool,
392-
393390
// Erases regions from `ty` to yield a new type.
394391
// Normally you would just use `tcx.erase_regions(&value)`,
395392
// however, which uses this query as a kind of cache.

src/librustc/ty/maps/plumbing.rs

-2
Original file line numberDiff line numberDiff line change
@@ -920,8 +920,6 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
920920
}
921921
DepKind::UsedCrateSource => { force!(used_crate_source, krate!()); }
922922
DepKind::PostorderCnums => { force!(postorder_cnums, LOCAL_CRATE); }
923-
DepKind::HasCloneClosures => { force!(has_clone_closures, krate!()); }
924-
DepKind::HasCopyClosures => { force!(has_copy_closures, krate!()); }
925923

926924
DepKind::Freevars => { force!(freevars, def_id!()); }
927925
DepKind::MaybeUnusedTraitImport => {

src/librustc_metadata/cstore.rs

-10
Original file line numberDiff line numberDiff line change
@@ -226,16 +226,6 @@ impl CrateMetadata {
226226
attr::contains_name(&attrs, "no_builtins")
227227
}
228228

229-
pub fn has_copy_closures(&self, sess: &Session) -> bool {
230-
let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess);
231-
attr::contains_feature_attr(&attrs, "copy_closures")
232-
}
233-
234-
pub fn has_clone_closures(&self, sess: &Session) -> bool {
235-
let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess);
236-
attr::contains_feature_attr(&attrs, "clone_closures")
237-
}
238-
239229
pub fn panic_strategy(&self) -> PanicStrategy {
240230
self.root.panic_strategy.clone()
241231
}

src/librustc_metadata/cstore_impl.rs

-3
Original file line numberDiff line numberDiff line change
@@ -255,9 +255,6 @@ provide! { <'tcx> tcx, def_id, other, cdata,
255255

256256
used_crate_source => { Lrc::new(cdata.source.clone()) }
257257

258-
has_copy_closures => { cdata.has_copy_closures(tcx.sess) }
259-
has_clone_closures => { cdata.has_clone_closures(tcx.sess) }
260-
261258
exported_symbols => {
262259
let cnum = cdata.cnum;
263260
assert!(cnum != LOCAL_CRATE);

src/librustc_typeck/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ This API is completely unstable and subject to change.
7676
#![feature(box_patterns)]
7777
#![feature(box_syntax)]
7878
#![feature(conservative_impl_trait)]
79-
#![feature(copy_closures, clone_closures)]
79+
#![cfg_attr(stage0, feature(copy_closures, clone_closures))]
8080
#![feature(crate_visibility_modifier)]
8181
#![feature(from_ref)]
8282
#![feature(match_default_bindings)]

src/libsyntax/feature_gate.rs

+3-23
Original file line numberDiff line numberDiff line change
@@ -391,10 +391,6 @@ declare_features! (
391391
// Future-proofing enums/structs with #[non_exhaustive] attribute (RFC 2008)
392392
(active, non_exhaustive, "1.22.0", Some(44109), None),
393393

394-
// Copy/Clone closures (RFC 2132)
395-
(active, clone_closures, "1.22.0", Some(44490), None),
396-
(active, copy_closures, "1.22.0", Some(44490), None),
397-
398394
// allow `'_` placeholder lifetimes
399395
(active, underscore_lifetimes, "1.22.0", Some(44524), None),
400396

@@ -567,6 +563,9 @@ declare_features! (
567563
(accepted, dotdoteq_in_patterns, "1.26.0", Some(28237), None),
568564
// Termination trait in main (RFC 1937)
569565
(accepted, termination_trait, "1.26.0", Some(43301), None),
566+
// Copy/Clone closures (RFC 2132)
567+
(accepted, clone_closures, "1.26.0", Some(44490), None),
568+
(accepted, copy_closures, "1.26.0", Some(44490), None),
570569
);
571570

572571
// If you change this, please modify src/doc/unstable-book as well. You must
@@ -1887,8 +1886,6 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
18871886
struct FeatureChecker {
18881887
proc_macro: Option<Span>,
18891888
custom_attribute: Option<Span>,
1890-
copy_closures: Option<Span>,
1891-
clone_closures: Option<Span>,
18921889
}
18931890

18941891
impl FeatureChecker {
@@ -1904,14 +1901,6 @@ impl FeatureChecker {
19041901
if features.custom_attribute {
19051902
self.custom_attribute = self.custom_attribute.or(Some(span));
19061903
}
1907-
1908-
if features.copy_closures {
1909-
self.copy_closures = self.copy_closures.or(Some(span));
1910-
}
1911-
1912-
if features.clone_closures {
1913-
self.clone_closures = self.clone_closures.or(Some(span));
1914-
}
19151904
}
19161905

19171906
fn check(self, handler: &Handler) {
@@ -1923,15 +1912,6 @@ impl FeatureChecker {
19231912

19241913
FatalError.raise();
19251914
}
1926-
1927-
if let (Some(span), None) = (self.copy_closures, self.clone_closures) {
1928-
handler.struct_span_err(span, "`#![feature(copy_closures)]` can only be used with \
1929-
`#![feature(clone_closures)]`")
1930-
.span_note(span, "`#![feature(copy_closures)]` declared here")
1931-
.emit();
1932-
1933-
FatalError.raise();
1934-
}
19351915
}
19361916
}
19371917

src/test/compile-fail/not-clone-closure.rs

-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010

1111
// Check that closures do not implement `Clone` if their environment is not `Clone`.
1212

13-
#![feature(clone_closures)]
14-
1513
struct S(i32);
1614

1715
fn main() {

src/test/compile-fail/not-copy-closure.rs

-3
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@
1010

1111
// Check that closures do not implement `Copy` if their environment is not `Copy`.
1212

13-
#![feature(copy_closures)]
14-
#![feature(clone_closures)]
15-
1613
fn main() {
1714
let mut a = 5;
1815
let hello = || {

src/test/compile-fail/unboxed-closer-non-implicit-copyable.rs

-19
This file was deleted.

src/test/run-pass/clone-closure.rs

-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010

1111
// Check that closures implement `Clone`.
1212

13-
#![feature(clone_closures)]
14-
1513
#[derive(Clone)]
1614
struct S(i32);
1715

src/test/run-pass/copy-closure.rs

-3
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@
1010

1111
// Check that closures implement `Copy`.
1212

13-
#![feature(copy_closures)]
14-
#![feature(clone_closures)]
15-
1613
fn call<T, F: FnOnce() -> T>(f: F) -> T { f() }
1714

1815
fn main() {

src/test/ui/feature-gate-clone-closures.rs

-21
This file was deleted.

src/test/ui/feature-gate-clone-closures.stderr

-11
This file was deleted.

src/test/ui/feature-gate-copy-closures.rs

-19
This file was deleted.

src/test/ui/feature-gate-copy-closures.stderr

-13
This file was deleted.

src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,10 @@ fn test6() {
5858

5959
fn test7() {
6060
fn foo<F>(_: F) where F: FnMut(Box<FnMut(isize)>, isize) {}
61-
let mut f = |g: Box<FnMut(isize)>, b: isize| {};
61+
let s = String::new(); // Capture to make f !Copy
62+
let mut f = move |g: Box<FnMut(isize)>, b: isize| {
63+
let _ = s.len();
64+
};
6265
f(Box::new(|a| {
6366
foo(f);
6467
//~^ ERROR cannot move `f` into closure because it is borrowed

src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,19 @@ LL | f.f.call_mut(())
2828
| ^^^ cannot borrow as mutable
2929

3030
error[E0504]: cannot move `f` into closure because it is borrowed
31-
--> $DIR/borrowck-call-is-borrow-issue-12224.rs:63:13
31+
--> $DIR/borrowck-call-is-borrow-issue-12224.rs:66:13
3232
|
3333
LL | f(Box::new(|a| {
3434
| - borrow of `f` occurs here
3535
LL | foo(f);
3636
| ^ move into closure occurs here
3737

3838
error[E0507]: cannot move out of captured outer variable in an `FnMut` closure
39-
--> $DIR/borrowck-call-is-borrow-issue-12224.rs:63:13
39+
--> $DIR/borrowck-call-is-borrow-issue-12224.rs:66:13
4040
|
41-
LL | let mut f = |g: Box<FnMut(isize)>, b: isize| {};
41+
LL | let mut f = move |g: Box<FnMut(isize)>, b: isize| {
4242
| ----- captured outer variable
43-
LL | f(Box::new(|a| {
43+
...
4444
LL | foo(f);
4545
| ^ cannot move out of captured outer variable in an `FnMut` closure
4646

0 commit comments

Comments
 (0)