Skip to content

Commit dcdfd55

Browse files
committed
Add UseCloned trait related code
1 parent 57cb498 commit dcdfd55

File tree

16 files changed

+197
-43
lines changed

16 files changed

+197
-43
lines changed

compiler/rustc_hir/src/lang_items.rs

+1
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ language_item_table! {
171171
Copy, sym::copy, copy_trait, Target::Trait, GenericRequirement::Exact(0);
172172
Clone, sym::clone, clone_trait, Target::Trait, GenericRequirement::None;
173173
CloneFn, sym::clone_fn, clone_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
174+
UseCloned, sym::use_cloned, use_cloned_trait, Target::Trait, GenericRequirement::None;
174175
Sync, sym::sync, sync_trait, Target::Trait, GenericRequirement::Exact(0);
175176
DiscriminantKind, sym::discriminant_kind, discriminant_kind_trait, Target::Trait, GenericRequirement::None;
176177
/// The associated item of the `DiscriminantKind` trait.

compiler/rustc_mir_build/src/builder/expr/into.rs

+46-26
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use rustc_middle::thir::*;
1111
use rustc_middle::ty::{CanonicalUserTypeAnnotation, Ty};
1212
use rustc_span::DUMMY_SP;
1313
use rustc_span::source_map::Spanned;
14+
use rustc_trait_selection::infer::InferCtxtExt;
1415
use tracing::{debug, instrument};
1516

1617
use crate::builder::expr::category::{Category, RvalueFunc};
@@ -295,33 +296,52 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
295296
let place = unpack!(block = this.as_place(block, expr));
296297
let ty = place.ty(&this.local_decls, this.tcx).ty;
297298

298-
// Convert `expr.use` to a call like `Clone::clone(&expr)`
299-
let success = this.cfg.start_new_block();
300-
let clone_trait = this.tcx.require_lang_item(LangItem::Clone, None);
301-
let clone_fn = this.tcx.associated_item_def_ids(clone_trait)[0];
302-
let func = Operand::function_handle(this.tcx, clone_fn, [ty.into()], expr_span);
303-
let ref_ty = Ty::new_imm_ref(this.tcx, this.tcx.lifetimes.re_erased, ty);
304-
let ref_place = this.temp(ref_ty, span);
305-
this.cfg.push_assign(
306-
block,
307-
source_info,
308-
ref_place,
309-
Rvalue::Ref(this.tcx.lifetimes.re_erased, BorrowKind::Shared, place),
310-
);
311-
this.cfg.terminate(
312-
block,
313-
source_info,
314-
TerminatorKind::Call {
315-
func,
316-
args: [Spanned { node: Operand::Move(ref_place), span: DUMMY_SP }].into(),
299+
if this.tcx.type_is_copy_modulo_regions(this.infcx.typing_env(this.param_env), ty) {
300+
this.cfg.push_assign(
301+
block,
302+
source_info,
317303
destination,
318-
target: Some(success),
319-
unwind: UnwindAction::Unreachable,
320-
call_source: CallSource::Misc,
321-
fn_span: expr_span,
322-
},
323-
);
324-
success.unit()
304+
Rvalue::Use(Operand::Copy(place)),
305+
);
306+
block.unit()
307+
} else if this.infcx.type_is_use_cloned_modulo_regions(this.param_env, ty) {
308+
// Convert `expr.use` to a call like `Clone::clone(&expr)`
309+
let success = this.cfg.start_new_block();
310+
let clone_trait = this.tcx.require_lang_item(LangItem::Clone, None);
311+
let clone_fn = this.tcx.associated_item_def_ids(clone_trait)[0];
312+
let func = Operand::function_handle(this.tcx, clone_fn, [ty.into()], expr_span);
313+
let ref_ty = Ty::new_imm_ref(this.tcx, this.tcx.lifetimes.re_erased, ty);
314+
let ref_place = this.temp(ref_ty, span);
315+
this.cfg.push_assign(
316+
block,
317+
source_info,
318+
ref_place,
319+
Rvalue::Ref(this.tcx.lifetimes.re_erased, BorrowKind::Shared, place),
320+
);
321+
this.cfg.terminate(
322+
block,
323+
source_info,
324+
TerminatorKind::Call {
325+
func,
326+
args: [Spanned { node: Operand::Move(ref_place), span: DUMMY_SP }]
327+
.into(),
328+
destination,
329+
target: Some(success),
330+
unwind: UnwindAction::Unreachable,
331+
call_source: CallSource::Misc,
332+
fn_span: expr_span,
333+
},
334+
);
335+
success.unit()
336+
} else {
337+
this.cfg.push_assign(
338+
block,
339+
source_info,
340+
destination,
341+
Rvalue::Use(Operand::Move(place)),
342+
);
343+
block.unit()
344+
}
325345
}
326346
ExprKind::Use { source } => this.expr_into_dest(destination, block, source),
327347
ExprKind::Borrow { arg, borrow_kind } => {

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2182,6 +2182,7 @@ symbols! {
21822182
unwrap,
21832183
unwrap_binder,
21842184
unwrap_or,
2185+
use_cloned,
21852186
use_extern_macros,
21862187
use_nested_groups,
21872188
used,

compiler/rustc_trait_selection/src/infer.rs

+10
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,16 @@ impl<'tcx> InferCtxt<'tcx> {
5353
traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, clone_def_id)
5454
}
5555

56+
fn type_is_use_cloned_modulo_regions(
57+
&self,
58+
param_env: ty::ParamEnv<'tcx>,
59+
ty: Ty<'tcx>,
60+
) -> bool {
61+
let ty = self.resolve_vars_if_possible(ty);
62+
let use_cloned_def_id = self.tcx.require_lang_item(LangItem::UseCloned, None);
63+
traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, use_cloned_def_id)
64+
}
65+
5666
fn type_is_sized_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
5767
let lang_item = self.tcx.require_lang_item(LangItem::Sized, None);
5868
traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, lang_item)

library/alloc/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@
113113
#![feature(deprecated_suggestion)]
114114
#![feature(deref_pure_trait)]
115115
#![feature(dispatch_from_dyn)]
116+
#![feature(ergonomic_clones)]
116117
#![feature(error_generic_member_access)]
117118
#![feature(exact_size_is_empty)]
118119
#![feature(extend_one)]

library/alloc/src/rc.rs

+7
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ use core::any::Any;
245245
use core::cell::Cell;
246246
#[cfg(not(no_global_oom_handling))]
247247
use core::clone::CloneToUninit;
248+
use core::clone::UseCloned;
248249
use core::cmp::Ordering;
249250
use core::hash::{Hash, Hasher};
250251
use core::intrinsics::abort;
@@ -2333,6 +2334,9 @@ impl<T: ?Sized, A: Allocator + Clone> Clone for Rc<T, A> {
23332334
}
23342335
}
23352336

2337+
#[unstable(feature = "ergonomic_clones", issue = "132290")]
2338+
impl<T: ?Sized, A: Allocator + Clone> UseCloned for Rc<T, A> {}
2339+
23362340
#[cfg(not(no_global_oom_handling))]
23372341
#[stable(feature = "rust1", since = "1.0.0")]
23382342
impl<T: Default> Default for Rc<T> {
@@ -3496,6 +3500,9 @@ impl<T: ?Sized, A: Allocator + Clone> Clone for Weak<T, A> {
34963500
}
34973501
}
34983502

3503+
#[unstable(feature = "ergonomic_clones", issue = "132290")]
3504+
impl<T: ?Sized, A: Allocator + Clone> UseCloned for Weak<T, A> {}
3505+
34993506
#[stable(feature = "rc_weak", since = "1.4.0")]
35003507
impl<T: ?Sized, A: Allocator> fmt::Debug for Weak<T, A> {
35013508
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {

library/alloc/src/sync.rs

+7
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use core::any::Any;
1212
#[cfg(not(no_global_oom_handling))]
1313
use core::clone::CloneToUninit;
14+
use core::clone::UseCloned;
1415
use core::cmp::Ordering;
1516
use core::hash::{Hash, Hasher};
1617
use core::intrinsics::abort;
@@ -2197,6 +2198,9 @@ impl<T: ?Sized, A: Allocator + Clone> Clone for Arc<T, A> {
21972198
}
21982199
}
21992200

2201+
#[unstable(feature = "ergonomic_clones", issue = "132290")]
2202+
impl<T: ?Sized, A: Allocator + Clone> UseCloned for Arc<T, A> {}
2203+
22002204
#[stable(feature = "rust1", since = "1.0.0")]
22012205
impl<T: ?Sized, A: Allocator> Deref for Arc<T, A> {
22022206
type Target = T;
@@ -3158,6 +3162,9 @@ impl<T: ?Sized, A: Allocator + Clone> Clone for Weak<T, A> {
31583162
}
31593163
}
31603164

3165+
#[unstable(feature = "ergonomic_clones", issue = "132290")]
3166+
impl<T: ?Sized, A: Allocator + Clone> UseCloned for Weak<T, A> {}
3167+
31613168
#[stable(feature = "downgraded_weak", since = "1.10.0")]
31623169
impl<T> Default for Weak<T> {
31633170
/// Constructs a new `Weak<T>`, without allocating memory.

library/core/src/clone.rs

+34
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,40 @@ pub macro Clone($item:item) {
184184
/* compiler built-in */
185185
}
186186

187+
/// Trait for objects whose [`Clone`] impl is lightweight (e.g. reference-counted)
188+
///
189+
/// Cloning an object implementing this trait should in general:
190+
/// - be O(1) (constant) time regardless of the amount of data managed by the object,
191+
/// - not require a memory allocation,
192+
/// - not require copying more than roughly 64 bytes (a typical cache line size),
193+
/// - not block the current thread,
194+
/// - not have any semantic side effects (e.g. allocating a file descriptor), and
195+
/// - not have overhead larger than a couple of atomic operations.
196+
///
197+
/// The `UseCloned` trait does not provide a method; instead, it indicates that
198+
/// `Clone::clone` is lightweight, and allows the use of the `.use` syntax.
199+
#[unstable(feature = "ergonomic_clones", issue = "132290")]
200+
#[cfg_attr(not(bootstrap), lang = "use_cloned")]
201+
pub trait UseCloned: Clone {
202+
// Empty.
203+
}
204+
205+
macro_rules! impl_use_cloned {
206+
($($t:ty)*) => {
207+
$(
208+
#[unstable(feature = "ergonomic_clones", issue = "132290")]
209+
impl UseCloned for $t {}
210+
)*
211+
}
212+
}
213+
214+
impl_use_cloned! {
215+
usize u8 u16 u32 u64 u128
216+
isize i8 i16 i32 i64 i128
217+
f16 f32 f64 f128
218+
bool char
219+
}
220+
187221
// FIXME(aburka): these structs are used solely by #[derive] to
188222
// assert that every component of a type implements Clone or Copy.
189223
//

library/core/src/num/bignum.rs

+2
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,8 @@ macro_rules! define_bignum {
405405
}
406406
}
407407

408+
impl crate::clone::UseCloned for $name {}
409+
408410
impl crate::fmt::Debug for $name {
409411
fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result {
410412
let sz = if self.size < 1 { 1 } else { self.size };

library/core/src/num/nonzero.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Definitions of integer that is known not to equal zero.
22
33
use super::{IntErrorKind, ParseIntError};
4+
use crate::clone::UseCloned;
45
use crate::cmp::Ordering;
56
use crate::hash::{Hash, Hasher};
67
use crate::marker::{Freeze, StructuralPartialEq};
@@ -183,6 +184,9 @@ where
183184
}
184185
}
185186

187+
#[unstable(feature = "ergonomic_clones", issue = "132290")]
188+
impl<T> UseCloned for NonZero<T> where T: ZeroablePrimitive {}
189+
186190
#[stable(feature = "nonzero", since = "1.28.0")]
187191
impl<T> Copy for NonZero<T> where T: ZeroablePrimitive {}
188192

library/core/src/option.rs

+3
Original file line numberDiff line numberDiff line change
@@ -2050,6 +2050,9 @@ where
20502050
}
20512051
}
20522052

2053+
#[unstable(feature = "ergonomic_clones", issue = "132290")]
2054+
impl<T> crate::clone::UseCloned for Option<T> where T: crate::clone::UseCloned {}
2055+
20532056
#[stable(feature = "rust1", since = "1.0.0")]
20542057
impl<T> Default for Option<T> {
20552058
/// Returns [`None`][Option::None].

library/core/src/result.rs

+8
Original file line numberDiff line numberDiff line change
@@ -1744,6 +1744,14 @@ where
17441744
}
17451745
}
17461746

1747+
#[unstable(feature = "ergonomic_clones", issue = "132290")]
1748+
impl<T, E> crate::clone::UseCloned for Result<T, E>
1749+
where
1750+
T: crate::clone::UseCloned,
1751+
E: crate::clone::UseCloned,
1752+
{
1753+
}
1754+
17471755
#[stable(feature = "rust1", since = "1.0.0")]
17481756
impl<T, E> IntoIterator for Result<T, E> {
17491757
type Item = T;

tests/ui/ergonomic-clones/closure.rs

+25-5
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,17 @@
33

44
#![feature(ergonomic_clones)]
55

6+
use std::clone::UseCloned;
7+
use std::future::Future;
8+
69
fn ergonomic_clone_closure_no_captures() -> i32 {
710
let cl = use || {
811
1
912
};
1013
cl()
1114
}
1215

13-
fn ergonomic_clone_closure_with_captures() -> String {
16+
fn ergonomic_clone_closure_move() -> String {
1417
let s = String::from("hi");
1518

1619
let cl = use || {
@@ -19,14 +22,31 @@ fn ergonomic_clone_closure_with_captures() -> String {
1922
cl()
2023
}
2124

22-
fn ergonomic_clone_async_closures() -> String {
25+
#[derive(Clone)]
26+
struct Foo;
27+
28+
impl UseCloned for Foo {}
29+
30+
fn ergonomic_clone_closure_use_cloned() -> Foo {
31+
let f = Foo;
32+
33+
let f1 = use || {
34+
f
35+
};
36+
37+
let f2 = use || {
38+
f
39+
};
40+
41+
f
42+
}
43+
44+
fn ergonomic_clone_async_closures() -> impl Future<Output = String> {
2345
let s = String::from("hi");
2446

2547
async use {
2648
s
27-
};
28-
29-
s
49+
}
3050
}
3151

3252
fn main() {}

tests/ui/ergonomic-clones/dotuse.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,18 @@
22

33
#![feature(ergonomic_clones)]
44

5+
use std::clone::UseCloned;
6+
57
fn basic_test(x: i32) -> i32 {
68
x.use.use.abs()
79
}
810

9-
fn do_not_move_test(x: String) -> String {
11+
#[derive(Clone)]
12+
struct Foo;
13+
14+
impl UseCloned for Foo {}
15+
16+
fn do_not_move_test(x: Foo) -> Foo {
1017
let s = x.use;
1118
x
1219
}

tests/ui/feature-gates/feature-gate-ergonomic-clones.rs

+14-5
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,28 @@
1+
use std::clone::UseCloned;
2+
//~^ ERROR use of unstable library feature `ergonomic_clones` [E0658]
3+
14
fn ergonomic_clone(x: i32) -> i32 {
25
x.use
36
//~^ ERROR `.use` calls are experimental [E0658]
47
}
58

9+
#[derive(Clone)]
10+
struct Foo;
11+
12+
impl UseCloned for Foo {}
13+
//~^ ERROR use of unstable library feature `ergonomic_clones` [E0658]
14+
615
fn ergonomic_closure_clone() {
7-
let s1 = String::from("hi!");
16+
let f1 = Foo;
817

9-
let s2 = use || {
18+
let f2 = use || {
1019
//~^ ERROR `.use` calls are experimental [E0658]
11-
s1
20+
f1
1221
};
1322

14-
let s3 = use || {
23+
let f3 = use || {
1524
//~^ ERROR `.use` calls are experimental [E0658]
16-
s1
25+
f1
1726
};
1827
}
1928

0 commit comments

Comments
 (0)