Skip to content

Commit 94d4dde

Browse files
committed
Add UseCloned trait related code
1 parent e3c69ef commit 94d4dde

File tree

15 files changed

+175
-36
lines changed

15 files changed

+175
-36
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

+41-22
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};
@@ -287,28 +288,46 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
287288
let place = unpack!(block = this.as_place(block, expr));
288289
let ty = place.ty(&this.local_decls, this.tcx).ty;
289290

290-
let success = this.cfg.start_new_block();
291-
let clone_trait = this.tcx.require_lang_item(LangItem::Clone, None);
292-
let clone_fn = this.tcx.associated_item_def_ids(clone_trait)[0];
293-
let func = Operand::function_handle(this.tcx, clone_fn, [ty.into()], expr_span);
294-
let ref_ty = Ty::new_imm_ref(this.tcx, this.tcx.lifetimes.re_erased, ty);
295-
let ref_place = this.temp(ref_ty, span);
296-
this.cfg.push_assign(
297-
block,
298-
source_info,
299-
ref_place,
300-
Rvalue::Ref(this.tcx.lifetimes.re_erased, BorrowKind::Shared, place),
301-
);
302-
this.cfg.terminate(block, source_info, TerminatorKind::Call {
303-
func,
304-
args: [Spanned { node: Operand::Move(ref_place), span: DUMMY_SP }].into(),
305-
destination,
306-
target: Some(success),
307-
unwind: UnwindAction::Unreachable,
308-
call_source: CallSource::Misc,
309-
fn_span: expr_span,
310-
});
311-
success.unit()
291+
if this.tcx.type_is_copy_modulo_regions(this.infcx.typing_env(this.param_env), ty) {
292+
this.cfg.push_assign(
293+
block,
294+
source_info,
295+
destination,
296+
Rvalue::Use(Operand::Copy(place)),
297+
);
298+
block.unit()
299+
} else if this.infcx.type_is_use_cloned_modulo_regions(this.param_env, ty) {
300+
let success = this.cfg.start_new_block();
301+
let clone_trait = this.tcx.require_lang_item(LangItem::Clone, None);
302+
let clone_fn = this.tcx.associated_item_def_ids(clone_trait)[0];
303+
let func = Operand::function_handle(this.tcx, clone_fn, [ty.into()], expr_span);
304+
let ref_ty = Ty::new_imm_ref(this.tcx, this.tcx.lifetimes.re_erased, ty);
305+
let ref_place = this.temp(ref_ty, span);
306+
this.cfg.push_assign(
307+
block,
308+
source_info,
309+
ref_place,
310+
Rvalue::Ref(this.tcx.lifetimes.re_erased, BorrowKind::Shared, place),
311+
);
312+
this.cfg.terminate(block, source_info, TerminatorKind::Call {
313+
func,
314+
args: [Spanned { node: Operand::Move(ref_place), span: DUMMY_SP }].into(),
315+
destination,
316+
target: Some(success),
317+
unwind: UnwindAction::Unreachable,
318+
call_source: CallSource::Misc,
319+
fn_span: expr_span,
320+
});
321+
success.unit()
322+
} else {
323+
this.cfg.push_assign(
324+
block,
325+
source_info,
326+
destination,
327+
Rvalue::Use(Operand::Move(place)),
328+
);
329+
block.unit()
330+
}
312331
}
313332
ExprKind::Use { source } => this.expr_into_dest(destination, block, source),
314333
ExprKind::Borrow { arg, borrow_kind } => {

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2150,6 +2150,7 @@ symbols! {
21502150
unwrap_binder,
21512151
unwrap_or,
21522152
unwrap_unsafe_binder,
2153+
use_cloned,
21532154
use_extern_macros,
21542155
use_nested_groups,
21552156
used,

compiler/rustc_trait_selection/src/infer.rs

+16
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,22 @@ impl<'tcx> InferCtxt<'tcx> {
4747
traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id)
4848
}
4949

50+
fn type_is_use_cloned_modulo_regions(
51+
&self,
52+
param_env: ty::ParamEnv<'tcx>,
53+
ty: Ty<'tcx>,
54+
) -> bool {
55+
let ty = self.resolve_vars_if_possible(ty);
56+
57+
let use_cloned_def_id = self.tcx.require_lang_item(LangItem::UseCloned, None);
58+
59+
// This can get called from typeck (by euv), and `moves_by_default`
60+
// rightly refuses to work with inference variables, but
61+
// moves_by_default has a cache, which we want to use in other
62+
// cases.
63+
traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, use_cloned_def_id)
64+
}
65+
5066
fn type_is_sized_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
5167
let lang_item = self.tcx.require_lang_item(LangItem::Sized, None);
5268
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
@@ -111,6 +111,7 @@
111111
#![feature(deprecated_suggestion)]
112112
#![feature(deref_pure_trait)]
113113
#![feature(dispatch_from_dyn)]
114+
#![feature(ergonomic_clones)]
114115
#![feature(error_generic_member_access)]
115116
#![feature(exact_size_is_empty)]
116117
#![feature(extend_one)]

library/alloc/src/rc.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@
244244
use core::any::Any;
245245
use core::cell::Cell;
246246
#[cfg(not(no_global_oom_handling))]
247-
use core::clone::CloneToUninit;
247+
use core::clone::{CloneToUninit, UseCloned};
248248
use core::cmp::Ordering;
249249
use core::hash::{Hash, Hasher};
250250
use core::intrinsics::abort;
@@ -2312,6 +2312,9 @@ impl<T: ?Sized, A: Allocator + Clone> Clone for Rc<T, A> {
23122312
}
23132313
}
23142314

2315+
#[unstable(feature = "ergonomic_clones", issue = "132290")]
2316+
impl<T: ?Sized, A: Allocator + Clone> UseCloned for Rc<T, A> {}
2317+
23152318
#[cfg(not(no_global_oom_handling))]
23162319
#[stable(feature = "rust1", since = "1.0.0")]
23172320
impl<T: Default> Default for Rc<T> {
@@ -3484,6 +3487,9 @@ impl<T: ?Sized, A: Allocator + Clone> Clone for Weak<T, A> {
34843487
}
34853488
}
34863489

3490+
#[unstable(feature = "ergonomic_clones", issue = "132290")]
3491+
impl<T: ?Sized, A: Allocator + Clone> UseCloned for Weak<T, A> {}
3492+
34873493
#[stable(feature = "rc_weak", since = "1.4.0")]
34883494
impl<T: ?Sized, A: Allocator> fmt::Debug for Weak<T, A> {
34893495
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {

library/alloc/src/sync.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
1111
use core::any::Any;
1212
#[cfg(not(no_global_oom_handling))]
13-
use core::clone::CloneToUninit;
13+
use core::clone::{CloneToUninit, UseCloned};
1414
use core::cmp::Ordering;
1515
use core::hash::{Hash, Hasher};
1616
use core::intrinsics::abort;
@@ -2172,6 +2172,9 @@ impl<T: ?Sized, A: Allocator + Clone> Clone for Arc<T, A> {
21722172
}
21732173
}
21742174

2175+
#[unstable(feature = "ergonomic_clones", issue = "132290")]
2176+
impl<T: ?Sized, A: Allocator + Clone> UseCloned for Arc<T, A> {}
2177+
21752178
#[stable(feature = "rust1", since = "1.0.0")]
21762179
impl<T: ?Sized, A: Allocator> Deref for Arc<T, A> {
21772180
type Target = T;
@@ -3143,6 +3146,9 @@ impl<T: ?Sized, A: Allocator + Clone> Clone for Weak<T, A> {
31433146
}
31443147
}
31453148

3149+
#[unstable(feature = "ergonomic_clones", issue = "132290")]
3150+
impl<T: ?Sized, A: Allocator + Clone> UseCloned for Weak<T, A> {}
3151+
31463152
#[stable(feature = "downgraded_weak", since = "1.10.0")]
31473153
impl<T> Default for Weak<T> {
31483154
/// Constructs a new `Weak<T>`, without allocating memory.

library/core/src/clone.rs

+34
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,24 @@ pub trait Clone: Sized {
176176
}
177177
}
178178

179+
/// Trait for objects whose clone impl is lightweight (e.g. reference-counted)
180+
///
181+
/// Cloning an object implementing this trait should in general:
182+
/// - be O(1) (constant) time regardless of the amount of data managed by the object,
183+
/// - not require a memory allocation,
184+
/// - not require copying more than roughly 64 bytes (a typical cache line size),
185+
/// - not block,
186+
/// - not have any semantic side effects (e.g. allocating a file descriptor), and
187+
/// - not have overhead larger than a couple of atomic operations.
188+
///
189+
/// The `Use` trait does not provide a method; instead, it indicates that
190+
/// `Clone::clone` is lightweight, and allows the use of the `.use` syntax.
191+
#[unstable(feature = "ergonomic_clones", issue = "132290")]
192+
#[cfg_attr(not(bootstrap), lang = "use_cloned")]
193+
#[rustc_diagnostic_item = "UseCloned"]
194+
#[rustc_trivial_field_reads]
195+
pub trait UseCloned: Clone {}
196+
179197
/// Derive macro generating an impl of the trait `Clone`.
180198
#[rustc_builtin_macro]
181199
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
@@ -338,6 +356,22 @@ mod impls {
338356
bool char
339357
}
340358

359+
macro_rules! impl_use_cloned {
360+
($($t:ty)*) => {
361+
$(
362+
#[unstable(feature = "ergonomic_clones", issue = "132290")]
363+
impl crate::clone::UseCloned for $t {}
364+
)*
365+
}
366+
}
367+
368+
impl_use_cloned! {
369+
usize u8 u16 u32 u64 u128
370+
isize i8 i16 i32 i64 i128
371+
f16 f32 f64 f128
372+
bool char
373+
}
374+
341375
#[unstable(feature = "never_type", issue = "35121")]
342376
impl Clone for ! {
343377
#[inline]

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};
@@ -192,6 +193,9 @@ where
192193
}
193194
}
194195

196+
#[unstable(feature = "ergonomic_clones", issue = "132290")]
197+
impl<T> UseCloned for NonZero<T> where T: ZeroablePrimitive {}
198+
195199
#[stable(feature = "nonzero", since = "1.28.0")]
196200
impl<T> Copy for NonZero<T> where T: ZeroablePrimitive {}
197201

library/core/src/option.rs

+4
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,7 @@
556556
557557
#![stable(feature = "rust1", since = "1.0.0")]
558558

559+
use crate::clone::UseCloned;
559560
use crate::iter::{self, FusedIterator, TrustedLen};
560561
use crate::ops::{self, ControlFlow, Deref, DerefMut};
561562
use crate::panicking::{panic, panic_display};
@@ -2050,6 +2051,9 @@ where
20502051
}
20512052
}
20522053

2054+
#[unstable(feature = "ergonomic_clones", issue = "132290")]
2055+
impl<T> UseCloned for Option<T> where T: UseCloned {}
2056+
20532057
#[stable(feature = "rust1", since = "1.0.0")]
20542058
impl<T> Default for Option<T> {
20552059
/// Returns [`None`][Option::None].

library/core/src/result.rs

+9
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,7 @@
513513
514514
#![stable(feature = "rust1", since = "1.0.0")]
515515

516+
use crate::clone::UseCloned;
516517
use crate::iter::{self, FusedIterator, TrustedLen};
517518
use crate::ops::{self, ControlFlow, Deref, DerefMut};
518519
use crate::{convert, fmt, hint};
@@ -1744,6 +1745,14 @@ where
17441745
}
17451746
}
17461747

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

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)