diff options
| author | Santiago Pastorino <spastorino@gmail.com> | 2024-12-11 18:00:56 -0300 |
|---|---|---|
| committer | Santiago Pastorino <spastorino@gmail.com> | 2025-03-06 17:58:32 -0300 |
| commit | dcdfd551f05073ececfa437be002ce7804b31c91 (patch) | |
| tree | 813604b622c9bb09c15e1724a6cebfd9d340b53d | |
| parent | 57cb498989ac29fbe9938ed2f4a31a3eab6850dc (diff) | |
| download | rust-dcdfd551f05073ececfa437be002ce7804b31c91.tar.gz rust-dcdfd551f05073ececfa437be002ce7804b31c91.zip | |
Add UseCloned trait related code
| -rw-r--r-- | compiler/rustc_hir/src/lang_items.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/builder/expr/into.rs | 72 | ||||
| -rw-r--r-- | compiler/rustc_span/src/symbol.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/infer.rs | 10 | ||||
| -rw-r--r-- | library/alloc/src/lib.rs | 1 | ||||
| -rw-r--r-- | library/alloc/src/rc.rs | 7 | ||||
| -rw-r--r-- | library/alloc/src/sync.rs | 7 | ||||
| -rw-r--r-- | library/core/src/clone.rs | 34 | ||||
| -rw-r--r-- | library/core/src/num/bignum.rs | 2 | ||||
| -rw-r--r-- | library/core/src/num/nonzero.rs | 4 | ||||
| -rw-r--r-- | library/core/src/option.rs | 3 | ||||
| -rw-r--r-- | library/core/src/result.rs | 8 | ||||
| -rw-r--r-- | tests/ui/ergonomic-clones/closure.rs | 30 | ||||
| -rw-r--r-- | tests/ui/ergonomic-clones/dotuse.rs | 9 | ||||
| -rw-r--r-- | tests/ui/feature-gates/feature-gate-ergonomic-clones.rs | 19 | ||||
| -rw-r--r-- | tests/ui/feature-gates/feature-gate-ergonomic-clones.stderr | 32 |
16 files changed, 197 insertions, 43 deletions
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index f5626937ec4..2c73ea6a11a 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -171,6 +171,7 @@ language_item_table! { Copy, sym::copy, copy_trait, Target::Trait, GenericRequirement::Exact(0); Clone, sym::clone, clone_trait, Target::Trait, GenericRequirement::None; CloneFn, sym::clone_fn, clone_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; + UseCloned, sym::use_cloned, use_cloned_trait, Target::Trait, GenericRequirement::None; Sync, sym::sync, sync_trait, Target::Trait, GenericRequirement::Exact(0); DiscriminantKind, sym::discriminant_kind, discriminant_kind_trait, Target::Trait, GenericRequirement::None; /// The associated item of the `DiscriminantKind` trait. diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs index d89f3773e4a..333e69475c5 100644 --- a/compiler/rustc_mir_build/src/builder/expr/into.rs +++ b/compiler/rustc_mir_build/src/builder/expr/into.rs @@ -11,6 +11,7 @@ use rustc_middle::thir::*; use rustc_middle::ty::{CanonicalUserTypeAnnotation, Ty}; use rustc_span::DUMMY_SP; use rustc_span::source_map::Spanned; +use rustc_trait_selection::infer::InferCtxtExt; use tracing::{debug, instrument}; use crate::builder::expr::category::{Category, RvalueFunc}; @@ -295,33 +296,52 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let place = unpack!(block = this.as_place(block, expr)); let ty = place.ty(&this.local_decls, this.tcx).ty; - // Convert `expr.use` to a call like `Clone::clone(&expr)` - let success = this.cfg.start_new_block(); - let clone_trait = this.tcx.require_lang_item(LangItem::Clone, None); - let clone_fn = this.tcx.associated_item_def_ids(clone_trait)[0]; - let func = Operand::function_handle(this.tcx, clone_fn, [ty.into()], expr_span); - let ref_ty = Ty::new_imm_ref(this.tcx, this.tcx.lifetimes.re_erased, ty); - let ref_place = this.temp(ref_ty, span); - this.cfg.push_assign( - block, - source_info, - ref_place, - Rvalue::Ref(this.tcx.lifetimes.re_erased, BorrowKind::Shared, place), - ); - this.cfg.terminate( - block, - source_info, - TerminatorKind::Call { - func, - args: [Spanned { node: Operand::Move(ref_place), span: DUMMY_SP }].into(), + if this.tcx.type_is_copy_modulo_regions(this.infcx.typing_env(this.param_env), ty) { + this.cfg.push_assign( + block, + source_info, destination, - target: Some(success), - unwind: UnwindAction::Unreachable, - call_source: CallSource::Misc, - fn_span: expr_span, - }, - ); - success.unit() + Rvalue::Use(Operand::Copy(place)), + ); + block.unit() + } else if this.infcx.type_is_use_cloned_modulo_regions(this.param_env, ty) { + // Convert `expr.use` to a call like `Clone::clone(&expr)` + let success = this.cfg.start_new_block(); + let clone_trait = this.tcx.require_lang_item(LangItem::Clone, None); + let clone_fn = this.tcx.associated_item_def_ids(clone_trait)[0]; + let func = Operand::function_handle(this.tcx, clone_fn, [ty.into()], expr_span); + let ref_ty = Ty::new_imm_ref(this.tcx, this.tcx.lifetimes.re_erased, ty); + let ref_place = this.temp(ref_ty, span); + this.cfg.push_assign( + block, + source_info, + ref_place, + Rvalue::Ref(this.tcx.lifetimes.re_erased, BorrowKind::Shared, place), + ); + this.cfg.terminate( + block, + source_info, + TerminatorKind::Call { + func, + args: [Spanned { node: Operand::Move(ref_place), span: DUMMY_SP }] + .into(), + destination, + target: Some(success), + unwind: UnwindAction::Unreachable, + call_source: CallSource::Misc, + fn_span: expr_span, + }, + ); + success.unit() + } else { + this.cfg.push_assign( + block, + source_info, + destination, + Rvalue::Use(Operand::Move(place)), + ); + block.unit() + } } ExprKind::Use { source } => this.expr_into_dest(destination, block, source), ExprKind::Borrow { arg, borrow_kind } => { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 3357e085a7d..a8c38d8244d 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2182,6 +2182,7 @@ symbols! { unwrap, unwrap_binder, unwrap_or, + use_cloned, use_extern_macros, use_nested_groups, used, diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index f373706b296..5cf0600ade8 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -53,6 +53,16 @@ impl<'tcx> InferCtxt<'tcx> { traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, clone_def_id) } + fn type_is_use_cloned_modulo_regions( + &self, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + ) -> bool { + let ty = self.resolve_vars_if_possible(ty); + let use_cloned_def_id = self.tcx.require_lang_item(LangItem::UseCloned, None); + traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, use_cloned_def_id) + } + fn type_is_sized_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { let lang_item = self.tcx.require_lang_item(LangItem::Sized, None); traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, lang_item) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index cb93100f56c..aac0eefc519 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -113,6 +113,7 @@ #![feature(deprecated_suggestion)] #![feature(deref_pure_trait)] #![feature(dispatch_from_dyn)] +#![feature(ergonomic_clones)] #![feature(error_generic_member_access)] #![feature(exact_size_is_empty)] #![feature(extend_one)] diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 09206c2f8b2..5847bd8f281 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -245,6 +245,7 @@ use core::any::Any; use core::cell::Cell; #[cfg(not(no_global_oom_handling))] use core::clone::CloneToUninit; +use core::clone::UseCloned; use core::cmp::Ordering; use core::hash::{Hash, Hasher}; use core::intrinsics::abort; @@ -2333,6 +2334,9 @@ impl<T: ?Sized, A: Allocator + Clone> Clone for Rc<T, A> { } } +#[unstable(feature = "ergonomic_clones", issue = "132290")] +impl<T: ?Sized, A: Allocator + Clone> UseCloned for Rc<T, A> {} + #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl<T: Default> Default for Rc<T> { @@ -3496,6 +3500,9 @@ impl<T: ?Sized, A: Allocator + Clone> Clone for Weak<T, A> { } } +#[unstable(feature = "ergonomic_clones", issue = "132290")] +impl<T: ?Sized, A: Allocator + Clone> UseCloned for Weak<T, A> {} + #[stable(feature = "rc_weak", since = "1.4.0")] impl<T: ?Sized, A: Allocator> fmt::Debug for Weak<T, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index dba1449347a..ddd0677ee35 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -11,6 +11,7 @@ use core::any::Any; #[cfg(not(no_global_oom_handling))] use core::clone::CloneToUninit; +use core::clone::UseCloned; use core::cmp::Ordering; use core::hash::{Hash, Hasher}; use core::intrinsics::abort; @@ -2197,6 +2198,9 @@ impl<T: ?Sized, A: Allocator + Clone> Clone for Arc<T, A> { } } +#[unstable(feature = "ergonomic_clones", issue = "132290")] +impl<T: ?Sized, A: Allocator + Clone> UseCloned for Arc<T, A> {} + #[stable(feature = "rust1", since = "1.0.0")] impl<T: ?Sized, A: Allocator> Deref for Arc<T, A> { type Target = T; @@ -3158,6 +3162,9 @@ impl<T: ?Sized, A: Allocator + Clone> Clone for Weak<T, A> { } } +#[unstable(feature = "ergonomic_clones", issue = "132290")] +impl<T: ?Sized, A: Allocator + Clone> UseCloned for Weak<T, A> {} + #[stable(feature = "downgraded_weak", since = "1.10.0")] impl<T> Default for Weak<T> { /// Constructs a new `Weak<T>`, without allocating memory. diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index 00300328b64..249ca6c091f 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -184,6 +184,40 @@ pub macro Clone($item:item) { /* compiler built-in */ } +/// Trait for objects whose [`Clone`] impl is lightweight (e.g. reference-counted) +/// +/// Cloning an object implementing this trait should in general: +/// - be O(1) (constant) time regardless of the amount of data managed by the object, +/// - not require a memory allocation, +/// - not require copying more than roughly 64 bytes (a typical cache line size), +/// - not block the current thread, +/// - not have any semantic side effects (e.g. allocating a file descriptor), and +/// - not have overhead larger than a couple of atomic operations. +/// +/// The `UseCloned` trait does not provide a method; instead, it indicates that +/// `Clone::clone` is lightweight, and allows the use of the `.use` syntax. +#[unstable(feature = "ergonomic_clones", issue = "132290")] +#[cfg_attr(not(bootstrap), lang = "use_cloned")] +pub trait UseCloned: Clone { + // Empty. +} + +macro_rules! impl_use_cloned { + ($($t:ty)*) => { + $( + #[unstable(feature = "ergonomic_clones", issue = "132290")] + impl UseCloned for $t {} + )* + } +} + +impl_use_cloned! { + usize u8 u16 u32 u64 u128 + isize i8 i16 i32 i64 i128 + f16 f32 f64 f128 + bool char +} + // FIXME(aburka): these structs are used solely by #[derive] to // assert that every component of a type implements Clone or Copy. // diff --git a/library/core/src/num/bignum.rs b/library/core/src/num/bignum.rs index 2a47c89e2ae..9de6b349d94 100644 --- a/library/core/src/num/bignum.rs +++ b/library/core/src/num/bignum.rs @@ -405,6 +405,8 @@ macro_rules! define_bignum { } } + impl crate::clone::UseCloned for $name {} + impl crate::fmt::Debug for $name { fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result { let sz = if self.size < 1 { 1 } else { self.size }; diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index a967b72c4fa..5b997d44278 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -1,6 +1,7 @@ //! Definitions of integer that is known not to equal zero. use super::{IntErrorKind, ParseIntError}; +use crate::clone::UseCloned; use crate::cmp::Ordering; use crate::hash::{Hash, Hasher}; use crate::marker::{Freeze, StructuralPartialEq}; @@ -183,6 +184,9 @@ where } } +#[unstable(feature = "ergonomic_clones", issue = "132290")] +impl<T> UseCloned for NonZero<T> where T: ZeroablePrimitive {} + #[stable(feature = "nonzero", since = "1.28.0")] impl<T> Copy for NonZero<T> where T: ZeroablePrimitive {} diff --git a/library/core/src/option.rs b/library/core/src/option.rs index a9f06b92ad5..f668c6f0672 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -2050,6 +2050,9 @@ where } } +#[unstable(feature = "ergonomic_clones", issue = "132290")] +impl<T> crate::clone::UseCloned for Option<T> where T: crate::clone::UseCloned {} + #[stable(feature = "rust1", since = "1.0.0")] impl<T> Default for Option<T> { /// Returns [`None`][Option::None]. diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 92b5cba1531..ee98a47523f 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1744,6 +1744,14 @@ where } } +#[unstable(feature = "ergonomic_clones", issue = "132290")] +impl<T, E> crate::clone::UseCloned for Result<T, E> +where + T: crate::clone::UseCloned, + E: crate::clone::UseCloned, +{ +} + #[stable(feature = "rust1", since = "1.0.0")] impl<T, E> IntoIterator for Result<T, E> { type Item = T; diff --git a/tests/ui/ergonomic-clones/closure.rs b/tests/ui/ergonomic-clones/closure.rs index 340b9ece50e..19ef6f4e13d 100644 --- a/tests/ui/ergonomic-clones/closure.rs +++ b/tests/ui/ergonomic-clones/closure.rs @@ -3,6 +3,9 @@ #![feature(ergonomic_clones)] +use std::clone::UseCloned; +use std::future::Future; + fn ergonomic_clone_closure_no_captures() -> i32 { let cl = use || { 1 @@ -10,7 +13,7 @@ fn ergonomic_clone_closure_no_captures() -> i32 { cl() } -fn ergonomic_clone_closure_with_captures() -> String { +fn ergonomic_clone_closure_move() -> String { let s = String::from("hi"); let cl = use || { @@ -19,14 +22,31 @@ fn ergonomic_clone_closure_with_captures() -> String { cl() } -fn ergonomic_clone_async_closures() -> String { +#[derive(Clone)] +struct Foo; + +impl UseCloned for Foo {} + +fn ergonomic_clone_closure_use_cloned() -> Foo { + let f = Foo; + + let f1 = use || { + f + }; + + let f2 = use || { + f + }; + + f +} + +fn ergonomic_clone_async_closures() -> impl Future<Output = String> { let s = String::from("hi"); async use { s - }; - - s + } } fn main() {} diff --git a/tests/ui/ergonomic-clones/dotuse.rs b/tests/ui/ergonomic-clones/dotuse.rs index 928c27296b1..4bab400fef2 100644 --- a/tests/ui/ergonomic-clones/dotuse.rs +++ b/tests/ui/ergonomic-clones/dotuse.rs @@ -2,11 +2,18 @@ #![feature(ergonomic_clones)] +use std::clone::UseCloned; + fn basic_test(x: i32) -> i32 { x.use.use.abs() } -fn do_not_move_test(x: String) -> String { +#[derive(Clone)] +struct Foo; + +impl UseCloned for Foo {} + +fn do_not_move_test(x: Foo) -> Foo { let s = x.use; x } diff --git a/tests/ui/feature-gates/feature-gate-ergonomic-clones.rs b/tests/ui/feature-gates/feature-gate-ergonomic-clones.rs index 0ffc3925005..8ae78e27d0e 100644 --- a/tests/ui/feature-gates/feature-gate-ergonomic-clones.rs +++ b/tests/ui/feature-gates/feature-gate-ergonomic-clones.rs @@ -1,19 +1,28 @@ +use std::clone::UseCloned; +//~^ ERROR use of unstable library feature `ergonomic_clones` [E0658] + fn ergonomic_clone(x: i32) -> i32 { x.use //~^ ERROR `.use` calls are experimental [E0658] } +#[derive(Clone)] +struct Foo; + +impl UseCloned for Foo {} +//~^ ERROR use of unstable library feature `ergonomic_clones` [E0658] + fn ergonomic_closure_clone() { - let s1 = String::from("hi!"); + let f1 = Foo; - let s2 = use || { + let f2 = use || { //~^ ERROR `.use` calls are experimental [E0658] - s1 + f1 }; - let s3 = use || { + let f3 = use || { //~^ ERROR `.use` calls are experimental [E0658] - s1 + f1 }; } diff --git a/tests/ui/feature-gates/feature-gate-ergonomic-clones.stderr b/tests/ui/feature-gates/feature-gate-ergonomic-clones.stderr index 366151c91a6..68d64715620 100644 --- a/tests/ui/feature-gates/feature-gate-ergonomic-clones.stderr +++ b/tests/ui/feature-gates/feature-gate-ergonomic-clones.stderr @@ -1,5 +1,5 @@ error[E0658]: `.use` calls are experimental - --> $DIR/feature-gate-ergonomic-clones.rs:2:7 + --> $DIR/feature-gate-ergonomic-clones.rs:5:7 | LL | x.use | ^^^ @@ -9,9 +9,9 @@ LL | x.use = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `.use` calls are experimental - --> $DIR/feature-gate-ergonomic-clones.rs:9:14 + --> $DIR/feature-gate-ergonomic-clones.rs:18:14 | -LL | let s2 = use || { +LL | let f2 = use || { | ^^^ | = note: see issue #132290 <https://github.com/rust-lang/rust/issues/132290> for more information @@ -19,15 +19,35 @@ LL | let s2 = use || { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `.use` calls are experimental - --> $DIR/feature-gate-ergonomic-clones.rs:14:14 + --> $DIR/feature-gate-ergonomic-clones.rs:23:14 | -LL | let s3 = use || { +LL | let f3 = use || { | ^^^ | = note: see issue #132290 <https://github.com/rust-lang/rust/issues/132290> for more information = help: add `#![feature(ergonomic_clones)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 3 previous errors +error[E0658]: use of unstable library feature `ergonomic_clones` + --> $DIR/feature-gate-ergonomic-clones.rs:1:5 + | +LL | use std::clone::UseCloned; + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #132290 <https://github.com/rust-lang/rust/issues/132290> for more information + = help: add `#![feature(ergonomic_clones)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature `ergonomic_clones` + --> $DIR/feature-gate-ergonomic-clones.rs:12:6 + | +LL | impl UseCloned for Foo {} + | ^^^^^^^^^ + | + = note: see issue #132290 <https://github.com/rust-lang/rust/issues/132290> for more information + = help: add `#![feature(ergonomic_clones)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0658`. |
