Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .mailmap
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,7 @@ Philipp Matthias Schäfer <philipp.matthias.schaefer@posteo.de>
phosphorus <steepout@qq.com>
Pierre Krieger <pierre.krieger1708@gmail.com>
pierwill <pierwill@users.noreply.github.com> <19642016+pierwill@users.noreply.github.com>
Pieter-Louis Schoeman <pl.schoeman44@gmail.com> <127837395+P8L1@users.noreply.github.com>
Pietro Albini <pietro@pietroalbini.org> <pietro@pietroalbini.io>
Pietro Albini <pietro@pietroalbini.org> <pietro.albini@ferrous-systems.com>
Pradyumna Rahul <prkinformed@gmail.com>
Expand Down
1 change: 1 addition & 0 deletions library/alloc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@
#![feature(ptr_metadata)]
#![feature(rev_into_inner)]
#![feature(set_ptr_value)]
#![feature(share_trait)]
#![feature(sized_type_properties)]
#![feature(slice_from_ptr_range)]
#![feature(slice_index_methods)]
Expand Down
5 changes: 4 additions & 1 deletion library/alloc/src/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ use core::any::Any;
use core::cell::{Cell, CloneFromCell};
#[cfg(not(no_global_oom_handling))]
use core::clone::TrivialClone;
use core::clone::{CloneToUninit, UseCloned};
use core::clone::{CloneToUninit, Share, UseCloned};
use core::cmp::Ordering;
use core::hash::{Hash, Hasher};
use core::intrinsics::abort;
Expand Down Expand Up @@ -2525,6 +2525,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> {}

#[unstable(feature = "share_trait", issue = "156756")]
impl<T: ?Sized, A: Allocator + Clone> Share for Rc<T, A> {}

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Default> Default for Rc<T> {
Expand Down
5 changes: 4 additions & 1 deletion library/alloc/src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use core::any::Any;
use core::cell::CloneFromCell;
#[cfg(not(no_global_oom_handling))]
use core::clone::TrivialClone;
use core::clone::{CloneToUninit, UseCloned};
use core::clone::{CloneToUninit, Share, UseCloned};
use core::cmp::Ordering;
use core::hash::{Hash, Hasher};
use core::intrinsics::abort;
Expand Down Expand Up @@ -2436,6 +2436,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> {}

#[unstable(feature = "share_trait", issue = "156756")]
impl<T: ?Sized, A: Allocator + Clone> Share for Arc<T, A> {}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized, A: Allocator> Deref for Arc<T, A> {
type Target = T;
Expand Down
89 changes: 88 additions & 1 deletion library/core/src/clone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,90 @@ pub macro Clone($item:item) {
/* compiler built-in */
}

/// A trait for types whose [`Clone`] operation creates another alias to the same
/// logical resource or shared state.
///
/// `Share` marks types where cloning creates another handle, reference, or alias
/// to the same logical resource or shared state, rather than an independent owned
/// value. The distinction is semantic, not cost-based: implementing `Share` does
/// not merely mean that cloning is cheap, constant-time, allocation-free, or
/// convenient.
///
/// Calling [`share`](Share::share) is equivalent to calling [`clone`](Clone::clone)
/// for implementors, but communicates that the resulting value aliases the same
/// underlying resource.
///
/// Shared references, `Rc<T>`, `Arc<T>`, `Sender<T>`, and `SyncSender<T>` are
/// examples of types that can be shared this way. Types such as `Vec<T>`,
/// `String`, and `Box<T>` are not `Share` even though they implement `Clone`,
/// because cloning them creates another owned value rather than another handle
/// to the same logical resource.
///
/// # Examples
///
/// ```
/// #![feature(share_trait)]
///
/// use std::cell::Cell;
/// use std::clone::Share;
/// use std::rc::Rc;
/// use std::sync::{
/// Arc,
/// atomic::{AtomicUsize, Ordering},
/// };
///
/// let value = 1;
/// let reference = &value;
/// assert!(std::ptr::eq(reference, reference.share()));
///
/// let rc = Rc::new(Cell::new(2));
/// let shared_rc = rc.share();
/// assert!(Rc::ptr_eq(&rc, &shared_rc));
/// shared_rc.set(3);
/// assert_eq!(rc.get(), 3);
///
/// let arc = Arc::new(AtomicUsize::new(4));
/// let shared_arc = arc.share();
/// assert!(Arc::ptr_eq(&arc, &shared_arc));
/// shared_arc.store(5, Ordering::Relaxed);
/// assert_eq!(arc.load(Ordering::Relaxed), 5);
/// ```
///
/// ```
/// #![feature(share_trait)]
///
/// use std::clone::Share;
/// use std::sync::mpsc::{channel, sync_channel};
///
/// let (sender, receiver) = channel();
/// let shared_sender = sender.share();
/// sender.send(1).unwrap();
/// shared_sender.send(2).unwrap();
///
/// let mut received = [receiver.recv().unwrap(), receiver.recv().unwrap()];
/// received.sort();
/// assert_eq!(received, [1, 2]);
///
/// let (sync_sender, sync_receiver) = sync_channel(2);
/// let shared_sync_sender = sync_sender.share();
/// sync_sender.send(3).unwrap();
/// shared_sync_sender.send(4).unwrap();
///
/// let mut received = [sync_receiver.recv().unwrap(), sync_receiver.recv().unwrap()];
/// received.sort();
/// assert_eq!(received, [3, 4]);
/// ```
#[unstable(feature = "share_trait", issue = "156756")]
pub trait Share: Clone {
/// Creates another alias to the same underlying resource or shared state.
///
/// This is equivalent to calling [`Clone::clone`].
#[unstable(feature = "share_trait", issue = "156756")]
fn share(&self) -> Self {
Clone::clone(self)
}
}

/// Trait for objects whose [`Clone`] impl is lightweight (e.g. reference-counted)
///
/// Cloning an object implementing this trait should in general:
Expand Down Expand Up @@ -601,7 +685,7 @@ unsafe impl CloneToUninit for crate::bstr::ByteStr {
/// are implemented in `traits::SelectionContext::copy_clone_conditions()`
/// in `rustc_trait_selection`.
mod impls {
use super::TrivialClone;
use super::{Share, TrivialClone};
use crate::marker::PointeeSized;

macro_rules! impl_clone {
Expand Down Expand Up @@ -689,6 +773,9 @@ mod impls {
#[rustc_const_unstable(feature = "const_clone", issue = "142757")]
unsafe impl<T: PointeeSized> const TrivialClone for &T {}

#[unstable(feature = "share_trait", issue = "156756")]
impl<T: PointeeSized> Share for &T {}

/// Shared references can be cloned, but mutable references *cannot*!
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: PointeeSized> !Clone for &mut T {}
Expand Down
1 change: 1 addition & 0 deletions library/core/src/num/f128.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ pub mod consts {
pub const TAU: f128 = 6.28318530717958647692528676655900576839433879875021164194989_f128;

/// The golden ratio (φ)
#[doc(alias = "phi")]
#[unstable(feature = "f128", issue = "116909")]
pub const GOLDEN_RATIO: f128 =
1.61803398874989484820458683436563811772030917980576286213545_f128;
Expand Down
1 change: 1 addition & 0 deletions library/core/src/num/f16.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ pub mod consts {
pub const TAU: f16 = 6.28318530717958647692528676655900577_f16;

/// The golden ratio (φ)
#[doc(alias = "phi")]
#[unstable(feature = "f16", issue = "116909")]
pub const GOLDEN_RATIO: f16 = 1.618033988749894848204586834365638118_f16;

Expand Down
1 change: 1 addition & 0 deletions library/core/src/num/f32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ pub mod consts {
pub const TAU: f32 = 6.28318530717958647692528676655900577_f32;

/// The golden ratio (φ)
#[doc(alias = "phi")]
#[stable(feature = "euler_gamma_golden_ratio", since = "1.94.0")]
pub const GOLDEN_RATIO: f32 = 1.618033988749894848204586834365638118_f32;

Expand Down
1 change: 1 addition & 0 deletions library/core/src/num/f64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ pub mod consts {
pub const TAU: f64 = 6.28318530717958647692528676655900577_f64;

/// The golden ratio (φ)
#[doc(alias = "phi")]
#[stable(feature = "euler_gamma_golden_ratio", since = "1.94.0")]
pub const GOLDEN_RATIO: f64 = 1.618033988749894848204586834365638118_f64;

Expand Down
1 change: 1 addition & 0 deletions library/std/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@
#![feature(random)]
#![feature(raw_os_error_ty)]
#![feature(seek_io_take_position)]
#![feature(share_trait)]
#![feature(slice_internals)]
#![feature(slice_ptr_get)]
#![feature(slice_range)]
Expand Down
8 changes: 8 additions & 0 deletions library/std/src/sync/mpsc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@
// not exposed publicly, but if you are curious about the implementation,
// that's where everything is.

use core::clone::Share;

use crate::sync::mpmc;
use crate::time::{Duration, Instant};
use crate::{error, fmt};
Expand Down Expand Up @@ -645,6 +647,9 @@ impl<T> Clone for Sender<T> {
}
}

#[unstable(feature = "share_trait", issue = "156756")]
impl<T> Share for Sender<T> {}

#[stable(feature = "mpsc_debug", since = "1.8.0")]
impl<T> fmt::Debug for Sender<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Expand Down Expand Up @@ -774,6 +779,9 @@ impl<T> Clone for SyncSender<T> {
}
}

#[unstable(feature = "share_trait", issue = "156756")]
impl<T> Share for SyncSender<T> {}

#[stable(feature = "mpsc_debug", since = "1.8.0")]
impl<T> fmt::Debug for SyncSender<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Expand Down
36 changes: 35 additions & 1 deletion src/librustdoc/clean/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use rustc_index::IndexVec;
use rustc_metadata::rendered_const;
use rustc_middle::span_bug;
use rustc_middle::ty::fast_reject::SimplifiedType;
use rustc_middle::ty::{self, TyCtxt, Visibility};
use rustc_middle::ty::{self, Ty, TyCtxt, Visibility};
use rustc_resolve::rustdoc::{
DocFragment, add_doc_fragment, attrs_to_doc_fragments, inner_docs, span_of_fragments,
};
Expand Down Expand Up @@ -1758,6 +1758,40 @@ impl PrimitiveType {
}
}

pub(crate) fn from_ty(ty: Ty<'_>) -> Option<Self> {
match ty.kind() {
ty::Array(..) => Some(Self::Array),
ty::Bool => Some(Self::Bool),
ty::Char => Some(Self::Char),
ty::FnDef(..) | ty::FnPtr(..) => Some(Self::Fn),
ty::Int(int) => Some(Self::from(*int)),
ty::Uint(uint) => Some(Self::from(*uint)),
ty::Float(float) => Some(Self::from(*float)),
ty::Never => Some(Self::Never),
ty::Pat(..) => Some(Self::Pat),
ty::RawPtr(..) => Some(Self::RawPointer),
ty::Ref(..) => Some(Self::Reference),
ty::Slice(..) => Some(Self::Slice),
ty::Str => Some(Self::Str),
ty::Tuple(elems) if elems.is_empty() => Some(Self::Unit),
ty::Tuple(_) => Some(Self::Tuple),
ty::Adt(..)
| ty::Alias(..)
| ty::Bound(..)
| ty::Closure(..)
| ty::Coroutine(..)
| ty::CoroutineClosure(..)
| ty::CoroutineWitness(..)
| ty::Dynamic(..)
| ty::Error(..)
| ty::Foreign(..)
| ty::Infer(..)
| ty::Param(..)
| ty::Placeholder(..)
| ty::UnsafeBinder(..) => None,
}
}

pub(crate) fn simplified_types() -> &'static SimplifiedTypes {
use PrimitiveType::*;
use ty::{FloatTy, IntTy, UintTy};
Expand Down
35 changes: 20 additions & 15 deletions src/librustdoc/html/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@

use std::cmp::Ordering;
use std::fmt::{self, Display, Write};
use std::iter::{self, once};
use std::slice;
use std::{iter, slice};

use itertools::{Either, Itertools};
use rustc_abi::ExternAbi;
Expand Down Expand Up @@ -434,27 +433,33 @@ fn generate_item_def_id_path(

let tcx = cx.tcx();
let crate_name = tcx.crate_name(def_id.krate);
let mut prim = None;

// No need to try to infer the actual parent item if it's not an associated item from the `impl`
// block.
if def_id != original_def_id && matches!(tcx.def_kind(def_id), DefKind::Impl { .. }) {
let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
def_id = infcx
let ty = tcx.type_of(def_id);
let ty = infcx
.at(&ObligationCause::dummy(), tcx.param_env(def_id))
.query_normalize(ty::Binder::dummy(
tcx.type_of(def_id).instantiate_identity().skip_norm_wip(),
))
.map(|resolved| infcx.resolve_vars_if_possible(resolved.value))
.ok()
.and_then(|normalized| normalized.skip_binder().ty_adt_def())
.map(|adt| adt.did())
.unwrap_or(def_id);
.query_normalize(ty::Binder::dummy(ty.instantiate_identity().skip_norm_wip()))
.map(|resolved| infcx.resolve_vars_if_possible(resolved.value).skip_binder())
.unwrap_or(ty.skip_binder());
if let Some(new_def_id) = ty.ty_adt_def().map(|adt| adt.did()) {
def_id = new_def_id;
} else {
prim = PrimitiveType::from_ty(ty);
}
}

let relative = clean::inline::item_relative_path(tcx, def_id);
let fqp: Vec<Symbol> = once(crate_name).chain(relative).collect();

let shortty = ItemType::from_def_id(def_id, tcx);
let mut fqp = vec![crate_name];
let shortty = if let Some(prim) = prim {
fqp.push(prim.as_sym());
ItemType::Primitive
} else {
fqp.append(&mut clean::inline::item_relative_path(tcx, def_id));
ItemType::from_def_id(def_id, tcx)
};
let module_fqp = to_module_fqp(shortty, &fqp);

let (parts, is_absolute) = url_parts(cx.cache(), def_id, module_fqp, &cx.current)?;
Expand Down
16 changes: 16 additions & 0 deletions tests/rustdoc-html/jump-to-def/prim-method.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Checks that links to primitive types methods work.
// Regression test for <https://github.com/rust-lang/rust/issues/156707>.

// ignore-tidy-linelength
//@ compile-flags: -Zunstable-options --generate-link-to-definition

#![crate_name = "foo"]

//@ has 'src/foo/prim-method.rs.html'

fn scope() {
//@ has - '//a[@href="{{channel}}/core/primitive.usize.html#method.saturating_add"]' 'saturating_add'
let _ = 0usize.saturating_add(1);
//@ has - '//a[@href="{{channel}}/core/primitive.bool.html#method.then_some"]' 'then_some'
let _ = false.then_some(());
}
4 changes: 4 additions & 0 deletions tests/ui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1244,6 +1244,10 @@ In this directory, multiple crates are compiled, but some of them have `inline`

Tests on name shadowing.

## `tests/ui/share-trait`

Tests for the unstable `Share` trait.

## `tests/ui/shell-argfiles/`: `-Z shell-argfiles` command line flag

The `-Zshell-argfiles` compiler flag allows argfiles to be parsed using POSIX "shell-style" quoting. When enabled, the compiler will use shlex to parse the arguments from argfiles specified with `@shell:<path>`.
Expand Down
31 changes: 31 additions & 0 deletions tests/ui/share-trait/share-trait-arc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//@ run-pass

#![feature(share_trait)]

use std::clone::Share;
use std::sync::{Arc, Mutex};

trait Value {
fn get(&self) -> i32;
}

impl Value for Mutex<i32> {
fn get(&self) -> i32 {
*self.lock().unwrap()
}
}

fn main() {
let value = Arc::new(Mutex::new(1));
let shared = value.share();

assert!(Arc::ptr_eq(&value, &shared));
*shared.lock().unwrap() = 2;
assert_eq!(*value.lock().unwrap(), 2);

let dyn_value: Arc<dyn Value + Send + Sync> = Arc::new(Mutex::new(3));
let shared_dyn_value = dyn_value.share();

assert!(Arc::ptr_eq(&dyn_value, &shared_dyn_value));
assert_eq!(shared_dyn_value.get(), 3);
}
Loading
Loading