From ccf1f580812b25eda231d4f2ac2e20c445fe7b62 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 3 Sep 2020 21:34:39 +0200 Subject: [PATCH 01/16] rustdoc: fix min_const_generics with ty::Param --- src/librustdoc/clean/mod.rs | 20 +++++++++---------- src/test/rustdoc/const-generics/type-alias.rs | 6 ++++++ 2 files changed, 16 insertions(+), 10 deletions(-) create mode 100644 src/test/rustdoc/const-generics/type-alias.rs diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 14e0fa7eabb00..fc38c6b14b54b 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1364,16 +1364,16 @@ impl Clean for hir::Ty<'_> { TyKind::Slice(ref ty) => Slice(box ty.clean(cx)), TyKind::Array(ref ty, ref length) => { let def_id = cx.tcx.hir().local_def_id(length.hir_id); - let length = match cx.tcx.const_eval_poly(def_id.to_def_id()) { - Ok(length) => { - print_const(cx, ty::Const::from_value(cx.tcx, length, cx.tcx.types.usize)) - } - Err(_) => cx - .sess() - .source_map() - .span_to_snippet(cx.tcx.def_span(def_id)) - .unwrap_or_else(|_| "_".to_string()), - }; + // NOTE(min_const_generics): We can't use `const_eval_poly` for constants + // as we currently do not supply the parent generics to anonymous constants + // but do allow `ConstKind::Param`. + // + // `const_eval_poly` tries to to first substitute generic parameters which + // results in an ICE while manually constructing the constant and using `eval` + // does nothing for `ConstKind::Param`. + let ct = ty::Const::from_anon_const(cx.tcx, def_id); + let param_env = cx.tcx.param_env(def_id); + let length = print_const(cx, ct.eval(cx.tcx, param_env)); Array(box ty.clean(cx), length) } TyKind::Tup(ref tys) => Tuple(tys.clean(cx)), diff --git a/src/test/rustdoc/const-generics/type-alias.rs b/src/test/rustdoc/const-generics/type-alias.rs new file mode 100644 index 0000000000000..3064d0701e300 --- /dev/null +++ b/src/test/rustdoc/const-generics/type-alias.rs @@ -0,0 +1,6 @@ +// ignore-tidy-linelength +#![feature(min_const_generics)] +#![crate_name = "foo"] + +// @has foo/type.CellIndex.html '//pre[@class="rust typedef"]' 'type CellIndex = [i64; D];' +pub type CellIndex = [i64; D]; From b869aa5f316ae065ce2215e69811e3216c6250cb Mon Sep 17 00:00:00 2001 From: marmeladema Date: Sun, 30 Aug 2020 18:31:34 +0100 Subject: [PATCH 02/16] Add saturating methods for `Duration` --- library/core/src/lib.rs | 1 + library/core/src/time.rs | 97 +++++++++++++++++++++++++ library/core/tests/lib.rs | 2 + library/core/tests/time.rs | 30 ++++++++ src/test/ui/consts/duration-consts-2.rs | 42 +++++++---- 5 files changed, 156 insertions(+), 16 deletions(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 29bbf062f22e4..c3cadcbb01e31 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -100,6 +100,7 @@ #![feature(doc_cfg)] #![feature(doc_spotlight)] #![feature(duration_consts_2)] +#![feature(duration_saturating_ops)] #![feature(extern_types)] #![feature(fundamental)] #![feature(intrinsics)] diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 5741f8a53b522..f39781788d7c0 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -108,6 +108,34 @@ impl Duration { #[unstable(feature = "duration_constants", issue = "57391")] pub const NANOSECOND: Duration = Duration::from_nanos(1); + /// The minimum duration. + /// + /// # Examples + /// + /// ``` + /// #![feature(duration_constants)] + /// use std::time::Duration; + /// + /// assert_eq!(Duration::MIN, Duration::new(0, 0)); + /// ``` + #[unstable(feature = "duration_constants", issue = "57391")] + pub const MIN: Duration = Duration::from_nanos(0); + + /// The maximum duration. + /// + /// It is roughly equal to a duration of 584,942,417,355 years. + /// + /// # Examples + /// + /// ``` + /// #![feature(duration_constants)] + /// use std::time::Duration; + /// + /// assert_eq!(Duration::MAX, Duration::new(u64::MAX, 1_000_000_000 - 1)); + /// ``` + #[unstable(feature = "duration_constants", issue = "57391")] + pub const MAX: Duration = Duration::new(u64::MAX, NANOS_PER_SEC - 1); + /// Creates a new `Duration` from the specified number of whole seconds and /// additional nanoseconds. /// @@ -450,6 +478,29 @@ impl Duration { } } + /// Saturating `Duration` addition. Computes `self + other`, returning [`Duration::MAX`] + /// if overflow occurred. + /// + /// # Examples + /// + /// ``` + /// #![feature(duration_saturating_ops)] + /// #![feature(duration_constants)] + /// use std::time::Duration; + /// + /// assert_eq!(Duration::new(0, 0).saturating_add(Duration::new(0, 1)), Duration::new(0, 1)); + /// assert_eq!(Duration::new(1, 0).saturating_add(Duration::new(u64::MAX, 0)), Duration::MAX); + /// ``` + #[unstable(feature = "duration_saturating_ops", issue = "76416")] + #[inline] + #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + pub const fn saturating_add(self, rhs: Duration) -> Duration { + match self.checked_add(rhs) { + Some(res) => res, + None => Duration::MAX, + } + } + /// Checked `Duration` subtraction. Computes `self - other`, returning [`None`] /// if the result would be negative or if overflow occurred. /// @@ -485,6 +536,29 @@ impl Duration { } } + /// Saturating `Duration` subtraction. Computes `self - other`, returning [`Duration::MIN`] + /// if the result would be negative or if overflow occurred. + /// + /// # Examples + /// + /// ``` + /// #![feature(duration_saturating_ops)] + /// #![feature(duration_constants)] + /// use std::time::Duration; + /// + /// assert_eq!(Duration::new(0, 1).saturating_sub(Duration::new(0, 0)), Duration::new(0, 1)); + /// assert_eq!(Duration::new(0, 0).saturating_sub(Duration::new(0, 1)), Duration::MIN); + /// ``` + #[unstable(feature = "duration_saturating_ops", issue = "76416")] + #[inline] + #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + pub const fn saturating_sub(self, rhs: Duration) -> Duration { + match self.checked_sub(rhs) { + Some(res) => res, + None => Duration::MIN, + } + } + /// Checked `Duration` multiplication. Computes `self * other`, returning /// [`None`] if overflow occurred. /// @@ -515,6 +589,29 @@ impl Duration { None } + /// Saturating `Duration` multiplication. Computes `self * other`, returning + /// [`Duration::MAX`] if overflow occurred. + /// + /// # Examples + /// + /// ``` + /// #![feature(duration_saturating_ops)] + /// #![feature(duration_constants)] + /// use std::time::Duration; + /// + /// assert_eq!(Duration::new(0, 500_000_001).saturating_mul(2), Duration::new(1, 2)); + /// assert_eq!(Duration::new(u64::MAX - 1, 0).saturating_mul(2), Duration::MAX); + /// ``` + #[unstable(feature = "duration_saturating_ops", issue = "76416")] + #[inline] + #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + pub const fn saturating_mul(self, rhs: u32) -> Duration { + match self.checked_mul(rhs) { + Some(res) => res, + None => Duration::MAX, + } + } + /// Checked `Duration` division. Computes `self / other`, returning [`None`] /// if `other == 0`. /// diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 4a651e5aa0ee3..a2e294ace1860 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -10,6 +10,8 @@ #![feature(core_private_diy_float)] #![feature(debug_non_exhaustive)] #![feature(dec2flt)] +#![feature(duration_constants)] +#![feature(duration_saturating_ops)] #![feature(exact_size_is_empty)] #![feature(fixed_size_array)] #![feature(flt2dec)] diff --git a/library/core/tests/time.rs b/library/core/tests/time.rs index 7a6675dc82fa6..4f90eb63b0472 100644 --- a/library/core/tests/time.rs +++ b/library/core/tests/time.rs @@ -89,6 +89,16 @@ fn checked_add() { assert_eq!(Duration::new(1, 0).checked_add(Duration::new(u64::MAX, 0)), None); } +#[test] +fn saturating_add() { + assert_eq!(Duration::new(0, 0).saturating_add(Duration::new(0, 1)), Duration::new(0, 1)); + assert_eq!( + Duration::new(0, 500_000_000).saturating_add(Duration::new(0, 500_000_001)), + Duration::new(1, 1) + ); + assert_eq!(Duration::new(1, 0).saturating_add(Duration::new(u64::MAX, 0)), Duration::MAX); +} + #[test] fn sub() { assert_eq!(Duration::new(0, 1) - Duration::new(0, 0), Duration::new(0, 1)); @@ -107,6 +117,17 @@ fn checked_sub() { assert_eq!(zero.checked_sub(one_sec), None); } +#[test] +fn saturating_sub() { + let zero = Duration::new(0, 0); + let one_nano = Duration::new(0, 1); + let one_sec = Duration::new(1, 0); + assert_eq!(one_nano.saturating_sub(zero), Duration::new(0, 1)); + assert_eq!(one_sec.saturating_sub(one_nano), Duration::new(0, 999_999_999)); + assert_eq!(zero.saturating_sub(one_nano), Duration::MIN); + assert_eq!(zero.saturating_sub(one_sec), Duration::MIN); +} + #[test] #[should_panic] fn sub_bad1() { @@ -136,6 +157,15 @@ fn checked_mul() { assert_eq!(Duration::new(u64::MAX - 1, 0).checked_mul(2), None); } +#[test] +fn saturating_mul() { + assert_eq!(Duration::new(0, 1).saturating_mul(2), Duration::new(0, 2)); + assert_eq!(Duration::new(1, 1).saturating_mul(3), Duration::new(3, 3)); + assert_eq!(Duration::new(0, 500_000_001).saturating_mul(4), Duration::new(2, 4)); + assert_eq!(Duration::new(0, 500_000_001).saturating_mul(4000), Duration::new(2000, 4000)); + assert_eq!(Duration::new(u64::MAX - 1, 0).saturating_mul(2), Duration::MAX); +} + #[test] fn div() { assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0)); diff --git a/src/test/ui/consts/duration-consts-2.rs b/src/test/ui/consts/duration-consts-2.rs index c8b3939933126..bc0969e4f1fba 100644 --- a/src/test/ui/consts/duration-consts-2.rs +++ b/src/test/ui/consts/duration-consts-2.rs @@ -3,6 +3,7 @@ #![feature(const_panic)] #![feature(duration_consts_2)] #![feature(div_duration)] +#![feature(duration_saturating_ops)] use std::time::Duration; @@ -15,29 +16,29 @@ fn duration() { const MAX : Duration = Duration::new(u64::MAX, 1_000_000_000 - 1); - const MAX_ADD_ZERO : Option = MAX.checked_add(ZERO); - assert_eq!(MAX_ADD_ZERO, Some(MAX)); + const MAX_CHECKED_ADD_ZERO : Option = MAX.checked_add(ZERO); + assert_eq!(MAX_CHECKED_ADD_ZERO, Some(MAX)); - const MAX_ADD_ONE : Option = MAX.checked_add(ONE); - assert_eq!(MAX_ADD_ONE, None); + const MAX_CHECKED_ADD_ONE : Option = MAX.checked_add(ONE); + assert_eq!(MAX_CHECKED_ADD_ONE, None); - const ONE_SUB_ONE : Option = ONE.checked_sub(ONE); - assert_eq!(ONE_SUB_ONE, Some(ZERO)); + const ONE_CHECKED_SUB_ONE : Option = ONE.checked_sub(ONE); + assert_eq!(ONE_CHECKED_SUB_ONE, Some(ZERO)); - const ZERO_SUB_ONE : Option = ZERO.checked_sub(ONE); - assert_eq!(ZERO_SUB_ONE, None); + const ZERO_CHECKED_SUB_ONE : Option = ZERO.checked_sub(ONE); + assert_eq!(ZERO_CHECKED_SUB_ONE, None); - const ONE_MUL_ONE : Option = ONE.checked_mul(1); - assert_eq!(ONE_MUL_ONE, Some(ONE)); + const ONE_CHECKED_MUL_ONE : Option = ONE.checked_mul(1); + assert_eq!(ONE_CHECKED_MUL_ONE, Some(ONE)); - const MAX_MUL_TWO : Option = MAX.checked_mul(2); - assert_eq!(MAX_MUL_TWO, None); + const MAX_CHECKED_MUL_TWO : Option = MAX.checked_mul(2); + assert_eq!(MAX_CHECKED_MUL_TWO, None); - const ONE_DIV_ONE : Option = ONE.checked_div(1); - assert_eq!(ONE_DIV_ONE, Some(ONE)); + const ONE_CHECKED_DIV_ONE : Option = ONE.checked_div(1); + assert_eq!(ONE_CHECKED_DIV_ONE, Some(ONE)); - const ONE_DIV_ZERO : Option = ONE.checked_div(0); - assert_eq!(ONE_DIV_ZERO, None); + const ONE_CHECKED_DIV_ZERO : Option = ONE.checked_div(0); + assert_eq!(ONE_CHECKED_DIV_ZERO, None); const MAX_AS_F32 : f32 = MAX.as_secs_f32(); assert_eq!(MAX_AS_F32, 18446744000000000000.0_f32); @@ -50,6 +51,15 @@ fn duration() { const ONE_AS_F64 : f64 = ONE.div_duration_f64(ONE); assert_eq!(ONE_AS_F64, 1.0_f64); + + const MAX_SATURATING_ADD_ONE : Duration = MAX.saturating_add(ONE); + assert_eq!(MAX_SATURATING_ADD_ONE, MAX); + + const ZERO_SATURATING_SUB_ONE : Duration = ZERO.saturating_sub(ONE); + assert_eq!(ZERO_SATURATING_SUB_ONE, ZERO); + + const MAX_SATURATING_MUL_TWO : Duration = MAX.saturating_mul(2); + assert_eq!(MAX_SATURATING_MUL_TWO, MAX); } fn main() { From 75e471ade9ea6095eef6cd4ef35cfc0b8bfc9410 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 8 Sep 2020 19:01:05 +0200 Subject: [PATCH 03/16] Add MaybeUninit::drop. ManuallyDrop's documentation tells the user to use MaybeUninit instead when handling uninitialized data. However, the main functionality of ManuallyDrop (drop) was not available directly on MaybeUninit. Adding it makes it easier to switch from one to the other. --- library/core/src/mem/maybe_uninit.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index b64abf68c5e4a..e826ec0a5e3ee 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -2,6 +2,7 @@ use crate::any::type_name; use crate::fmt; use crate::intrinsics; use crate::mem::ManuallyDrop; +use crate::ptr; /// A wrapper type to construct uninitialized instances of `T`. /// @@ -573,6 +574,28 @@ impl MaybeUninit { } } + /// Drops the contained value in place. + /// + /// If you have ownership of the `MaybeUninit`, it is preferable to use + /// [`assume_init`] instead, which prevents duplicating the content. + /// + /// # Safety + /// + /// Calling this when the content is not yet fully initialized causes undefined + /// behavior: it is up to the caller to guarantee that the `MaybeUninit` really + /// is in an initialized state. + /// + /// This function runs the destructor of the contained value in place. + /// Afterwards, the memory is considered uninitialized again, but remains unmodified. + /// + /// [`assume_init`]: MaybeUninit::assume_init + #[unstable(feature = "maybe_uninit_extra", issue = "63567")] + pub unsafe fn drop(&mut self) { + // SAFETY: the caller must guarantee that `self` is initialized. + // Dropping the value in place is safe if that is the case. + unsafe { ptr::drop_in_place(self.as_mut_ptr()) } + } + /// Gets a shared reference to the contained value. /// /// This can be useful when we want to access a `MaybeUninit` that has been From caef83282bfede657faf38d43967f577841b3be4 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 8 Sep 2020 19:34:23 +0200 Subject: [PATCH 04/16] Fix doc comment on MaybeUninit::drop. --- library/core/src/mem/maybe_uninit.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index e826ec0a5e3ee..001ee0898d45e 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -576,8 +576,7 @@ impl MaybeUninit { /// Drops the contained value in place. /// - /// If you have ownership of the `MaybeUninit`, it is preferable to use - /// [`assume_init`] instead, which prevents duplicating the content. + /// If you have ownership of the `MaybeUninit`, you can use [`assume_init`] instead. /// /// # Safety /// From 656a17b44d2e7ee8096f479ed8a04baab2200cae Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 9 Sep 2020 11:27:09 +0200 Subject: [PATCH 05/16] Rename MaybeUninit::drop to assume_init_drop. --- library/core/src/mem/maybe_uninit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 001ee0898d45e..8d19412e4c414 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -589,7 +589,7 @@ impl MaybeUninit { /// /// [`assume_init`]: MaybeUninit::assume_init #[unstable(feature = "maybe_uninit_extra", issue = "63567")] - pub unsafe fn drop(&mut self) { + pub unsafe fn assume_init_drop(&mut self) { // SAFETY: the caller must guarantee that `self` is initialized. // Dropping the value in place is safe if that is the case. unsafe { ptr::drop_in_place(self.as_mut_ptr()) } From a14efd1d0a2f0fa112e4359b9db1e9857589c796 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 9 Sep 2020 11:27:42 +0200 Subject: [PATCH 06/16] Rename MaybeUninit::read to assume_init_read. --- library/core/src/array/iter.rs | 4 ++-- library/core/src/mem/maybe_uninit.rs | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs index 2e8b6419eea1e..cafb002c01a11 100644 --- a/library/core/src/array/iter.rs +++ b/library/core/src/array/iter.rs @@ -103,7 +103,7 @@ impl Iterator for IntoIter { // dead now (i.e. do not touch). As `idx` was the start of the // alive-zone, the alive zone is now `data[alive]` again, restoring // all invariants. - unsafe { self.data.get_unchecked(idx).read() } + unsafe { self.data.get_unchecked(idx).assume_init_read() } }) } @@ -136,7 +136,7 @@ impl DoubleEndedIterator for IntoIter { // dead now (i.e. do not touch). As `idx` was the end of the // alive-zone, the alive zone is now `data[alive]` again, restoring // all invariants. - unsafe { self.data.get_unchecked(idx).read() } + unsafe { self.data.get_unchecked(idx).assume_init_read() } }) } } diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 8d19412e4c414..38a006ce74ce0 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -520,8 +520,8 @@ impl MaybeUninit { /// this initialization invariant. /// /// Moreover, this leaves a copy of the same data behind in the `MaybeUninit`. When using - /// multiple copies of the data (by calling `read` multiple times, or first - /// calling `read` and then [`assume_init`]), it is your responsibility + /// multiple copies of the data (by calling `assume_init_read` multiple times, or first + /// calling `assume_init_read` and then [`assume_init`]), it is your responsibility /// to ensure that that data may indeed be duplicated. /// /// [inv]: #initialization-invariant @@ -537,16 +537,16 @@ impl MaybeUninit { /// /// let mut x = MaybeUninit::::uninit(); /// x.write(13); - /// let x1 = unsafe { x.read() }; + /// let x1 = unsafe { x.assume_init_read() }; /// // `u32` is `Copy`, so we may read multiple times. - /// let x2 = unsafe { x.read() }; + /// let x2 = unsafe { x.assume_init_read() }; /// assert_eq!(x1, x2); /// /// let mut x = MaybeUninit::>>::uninit(); /// x.write(None); - /// let x1 = unsafe { x.read() }; + /// let x1 = unsafe { x.assume_init_read() }; /// // Duplicating a `None` value is okay, so we may read multiple times. - /// let x2 = unsafe { x.read() }; + /// let x2 = unsafe { x.assume_init_read() }; /// assert_eq!(x1, x2); /// ``` /// @@ -558,14 +558,14 @@ impl MaybeUninit { /// /// let mut x = MaybeUninit::>>::uninit(); /// x.write(Some(vec![0,1,2])); - /// let x1 = unsafe { x.read() }; - /// let x2 = unsafe { x.read() }; + /// let x1 = unsafe { x.assume_init_read() }; + /// let x2 = unsafe { x.assume_init_read() }; /// // We now created two copies of the same vector, leading to a double-free ⚠️ when /// // they both get dropped! /// ``` #[unstable(feature = "maybe_uninit_extra", issue = "63567")] #[inline(always)] - pub unsafe fn read(&self) -> T { + pub unsafe fn assume_init_read(&self) -> T { // SAFETY: the caller must guarantee that `self` is initialized. // Reading from `self.as_ptr()` is safe since `self` should be initialized. unsafe { From a94b2cb034c2521d52e54632b775e181eb7e0bc7 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 9 Sep 2020 18:54:17 +0200 Subject: [PATCH 07/16] Add safety docs about T's invariants in MaybeUninit::assume_init_drop. --- library/core/src/mem/maybe_uninit.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 38a006ce74ce0..0d1d563b5ceec 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -580,17 +580,23 @@ impl MaybeUninit { /// /// # Safety /// - /// Calling this when the content is not yet fully initialized causes undefined - /// behavior: it is up to the caller to guarantee that the `MaybeUninit` really - /// is in an initialized state. - /// - /// This function runs the destructor of the contained value in place. - /// Afterwards, the memory is considered uninitialized again, but remains unmodified. + /// It is up to the caller to guarantee that the `MaybeUninit` really is + /// in an initialized state. Calling this when the content is not yet fully + /// initialized causes undefined behavior. + /// + /// On top of that, all additional invariants of the type `T` must be + /// satisfied, as the `Drop` implementation of `T` (or its members) may + /// rely on this. For example, a `1`-initialized [`Vec`] is considered + /// initialized (under the current implementation; this does not constitute + /// a stable guarantee) because the only requirement the compiler knows + /// about it is that the data pointer must be non-null. Dropping such a + /// `Vec` however will cause undefined behaviour. /// /// [`assume_init`]: MaybeUninit::assume_init #[unstable(feature = "maybe_uninit_extra", issue = "63567")] pub unsafe fn assume_init_drop(&mut self) { - // SAFETY: the caller must guarantee that `self` is initialized. + // SAFETY: the caller must guarantee that `self` is initialized and + // satisfies all invariants of `T`. // Dropping the value in place is safe if that is the case. unsafe { ptr::drop_in_place(self.as_mut_ptr()) } } From 43c7a9b72b284bee6ce8517550cb6ee7903c639e Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 9 Sep 2020 18:56:16 +0200 Subject: [PATCH 08/16] Fix broken doc links in MaybeUninit. --- library/core/src/mem/maybe_uninit.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 0d1d563b5ceec..f68e2b8208982 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -472,6 +472,8 @@ impl MaybeUninit { /// *immediate* undefined behavior, but will cause undefined behavior with most /// safe operations (including dropping it). /// + /// [`Vec`]: ../../std/vec/struct.Vec.html + /// /// # Examples /// /// Correct usage of this method: @@ -593,6 +595,7 @@ impl MaybeUninit { /// `Vec` however will cause undefined behaviour. /// /// [`assume_init`]: MaybeUninit::assume_init + /// [`Vec`]: ../../std/vec/struct.Vec.html #[unstable(feature = "maybe_uninit_extra", issue = "63567")] pub unsafe fn assume_init_drop(&mut self) { // SAFETY: the caller must guarantee that `self` is initialized and From 493c037699603388a00010d96339d84e84e361c6 Mon Sep 17 00:00:00 2001 From: carbotaniuman <41451839+carbotaniuman@users.noreply.github.com> Date: Wed, 9 Sep 2020 12:11:44 -0500 Subject: [PATCH 09/16] Eliminate mut reference UB in Drop impl for Rc This changes `self.ptr.as_mut()` with `get_mut_unchecked` which does not use an intermediate reference. Arc already handled this case properly. --- library/alloc/src/rc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index a9b293856e57b..fe429e6e9464c 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1195,7 +1195,7 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc { self.dec_strong(); if self.strong() == 0 { // destroy the contained object - ptr::drop_in_place(self.ptr.as_mut()); + ptr::drop_in_place(Self::get_mut_unchecked(self)); // remove the implicit "strong weak" pointer now that we've // destroyed the contents. From 8f43fa09893b664e4ceb4cc8c7815fa5ab20c10e Mon Sep 17 00:00:00 2001 From: carbotaniuman <41451839+carbotaniuman@users.noreply.github.com> Date: Wed, 9 Sep 2020 13:39:48 -0500 Subject: [PATCH 10/16] Add WeakInner<'_> and have Weak::inner() return it This avoids overlapping a reference covering the data field, which may be changed due in concurrent conditions. This fully fixed the UB mainfested with `new_cyclic`. --- library/alloc/src/rc.rs | 109 ++++++++++++++++++++++++++-------------- 1 file changed, 70 insertions(+), 39 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index fe429e6e9464c..43cf3fe6fb6ac 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -469,7 +469,7 @@ impl Rc { // the strong count, and then remove the implicit "strong weak" // pointer while also handling drop logic by just crafting a // fake Weak. - this.dec_strong(); + this.inner().dec_strong(); let _weak = Weak { ptr: this.ptr }; forget(this); Ok(val) @@ -735,7 +735,7 @@ impl Rc { /// ``` #[stable(feature = "rc_weak", since = "1.4.0")] pub fn downgrade(this: &Self) -> Weak { - this.inc_weak(); + this.inner().inc_weak(); // Make sure we do not create a dangling Weak debug_assert!(!is_dangling(this.ptr)); Weak { ptr: this.ptr } @@ -756,7 +756,7 @@ impl Rc { #[inline] #[stable(feature = "rc_counts", since = "1.15.0")] pub fn weak_count(this: &Self) -> usize { - this.weak() - 1 + this.inner().weak() - 1 } /// Gets the number of strong (`Rc`) pointers to this allocation. @@ -774,7 +774,7 @@ impl Rc { #[inline] #[stable(feature = "rc_counts", since = "1.15.0")] pub fn strong_count(this: &Self) -> usize { - this.strong() + this.inner().strong() } /// Returns `true` if there are no other `Rc` or [`Weak`] pointers to @@ -844,7 +844,16 @@ impl Rc { #[inline] #[unstable(feature = "get_mut_unchecked", issue = "63292")] pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T { - unsafe { &mut this.ptr.as_mut().value } + // We are careful to *not* create a reference covering the "count" fields, as + // this would alias with reenterant access to the reference counts (e.g. by `Weak`). + unsafe { &mut (*this.ptr.as_ptr()).value } + } + + #[inline] + fn inner(&self) -> &RcBox { + // This unsafety is ok because while this Rc is alive we're guaranteed + // that the inner pointer is valid. + unsafe { self.ptr.as_ref() } } #[inline] @@ -931,10 +940,10 @@ impl Rc { unsafe { let mut swap = Rc::new(ptr::read(&this.ptr.as_ref().value)); mem::swap(this, &mut swap); - swap.dec_strong(); + swap.inner().dec_strong(); // Remove implicit strong-weak ref (no need to craft a fake // Weak here -- we know other Weaks can clean up for us) - swap.dec_weak(); + swap.inner().dec_weak(); forget(swap); } } @@ -1192,16 +1201,16 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc { /// ``` fn drop(&mut self) { unsafe { - self.dec_strong(); - if self.strong() == 0 { + self.inner().dec_strong(); + if self.inner().strong() == 0 { // destroy the contained object ptr::drop_in_place(Self::get_mut_unchecked(self)); // remove the implicit "strong weak" pointer now that we've // destroyed the contents. - self.dec_weak(); + self.inner().dec_weak(); - if self.weak() == 0 { + if self.inner().weak() == 0 { Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); } } @@ -1227,7 +1236,7 @@ impl Clone for Rc { /// ``` #[inline] fn clone(&self) -> Rc { - self.inc_strong(); + self.inner().inc_strong(); Self::from_inner(self.ptr) } } @@ -1851,6 +1860,13 @@ pub(crate) fn is_dangling(ptr: NonNull) -> bool { address == usize::MAX } +/// Helper type to allow accessing the reference counts without +/// making any assertions about the data field. +struct WeakInner<'a> { + weak: &'a Cell, + strong: &'a Cell, +} + impl Weak { /// Attempts to upgrade the `Weak` pointer to an [`Rc`], delaying /// dropping of the inner value if successful. @@ -1910,11 +1926,21 @@ impl Weak { .unwrap_or(0) } - /// Returns `None` when the pointer is dangling and there is no allocated `RcBox` + /// Returns `None` when the pointer is dangling and there is no allocated `RcBox`, /// (i.e., when this `Weak` was created by `Weak::new`). #[inline] - fn inner(&self) -> Option<&RcBox> { - if is_dangling(self.ptr) { None } else { Some(unsafe { self.ptr.as_ref() }) } + fn inner(&self) -> Option> { + if is_dangling(self.ptr) { + None + } else { + // We are careful to *not* create a reference covering the "data" field, as + // the field may be mutated concurrently (for example, if the last `Rc` + // is dropped, the data field will be dropped in-place). + Some(unsafe { + let ptr = self.ptr.as_ptr(); + WeakInner { strong: &(*ptr).strong, weak: &(*ptr).weak } + }) + } } /// Returns `true` if the two `Weak`s point to the same allocation (similar to @@ -1992,14 +2018,14 @@ impl Drop for Weak { /// assert!(other_weak_foo.upgrade().is_none()); /// ``` fn drop(&mut self) { - if let Some(inner) = self.inner() { - inner.dec_weak(); - // the weak count starts at 1, and will only go to zero if all - // the strong pointers have disappeared. - if inner.weak() == 0 { - unsafe { - Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); - } + let inner = if let Some(inner) = self.inner() { inner } else { return }; + + inner.dec_weak(); + // the weak count starts at 1, and will only go to zero if all + // the strong pointers have disappeared. + if inner.weak() == 0 { + unsafe { + Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); } } } @@ -2065,12 +2091,13 @@ impl Default for Weak { // clone these much in Rust thanks to ownership and move-semantics. #[doc(hidden)] -trait RcBoxPtr { - fn inner(&self) -> &RcBox; +trait RcInnerPtr { + fn weak_ref(&self) -> &Cell; + fn strong_ref(&self) -> &Cell; #[inline] fn strong(&self) -> usize { - self.inner().strong.get() + self.strong_ref().get() } #[inline] @@ -2084,17 +2111,17 @@ trait RcBoxPtr { if strong == 0 || strong == usize::MAX { abort(); } - self.inner().strong.set(strong + 1); + self.strong_ref().set(strong + 1); } #[inline] fn dec_strong(&self) { - self.inner().strong.set(self.strong() - 1); + self.strong_ref().set(self.strong() - 1); } #[inline] fn weak(&self) -> usize { - self.inner().weak.get() + self.weak_ref().get() } #[inline] @@ -2108,26 +2135,30 @@ trait RcBoxPtr { if weak == 0 || weak == usize::MAX { abort(); } - self.inner().weak.set(weak + 1); + self.weak_ref().set(weak + 1); } #[inline] fn dec_weak(&self) { - self.inner().weak.set(self.weak() - 1); + self.weak_ref().set(self.weak() - 1); } } -impl RcBoxPtr for Rc { - #[inline(always)] - fn inner(&self) -> &RcBox { - unsafe { self.ptr.as_ref() } +impl RcInnerPtr for RcBox { + fn weak_ref(&self) -> &Cell { + &self.weak + } + fn strong_ref(&self) -> &Cell { + &self.strong } } -impl RcBoxPtr for RcBox { - #[inline(always)] - fn inner(&self) -> &RcBox { - self +impl<'a> RcInnerPtr for WeakInner<'a> { + fn weak_ref(&self) -> &Cell { + self.weak + } + fn strong_ref(&self) -> &Cell { + self.strong } } From bb57c9f91c920a8b1533fb92aa50be342e11f675 Mon Sep 17 00:00:00 2001 From: carbotaniuman <41451839+carbotaniuman@users.noreply.github.com> Date: Wed, 9 Sep 2020 13:44:22 -0500 Subject: [PATCH 11/16] Format --- library/alloc/src/rc.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 43cf3fe6fb6ac..4821c8f567626 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -845,7 +845,7 @@ impl Rc { #[unstable(feature = "get_mut_unchecked", issue = "63292")] pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T { // We are careful to *not* create a reference covering the "count" fields, as - // this would alias with reenterant access to the reference counts (e.g. by `Weak`). + // this would alias with concurrent access to the reference counts (e.g. by `Weak`). unsafe { &mut (*this.ptr.as_ptr()).value } } @@ -2019,7 +2019,7 @@ impl Drop for Weak { /// ``` fn drop(&mut self) { let inner = if let Some(inner) = self.inner() { inner } else { return }; - + inner.dec_weak(); // the weak count starts at 1, and will only go to zero if all // the strong pointers have disappeared. @@ -2144,7 +2144,7 @@ trait RcInnerPtr { } } -impl RcInnerPtr for RcBox { +impl RcInnerPtr for RcBox { fn weak_ref(&self) -> &Cell { &self.weak } From 954361a3d4f8b87a9311b5c976b7e301f6bae1bb Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Fri, 11 Sep 2020 04:05:19 +0200 Subject: [PATCH 12/16] Update `std::os` module documentation. Adds missing descriptions for the modules std::os::linux::fs and std::os::windows::io. Also adds punctuation for consistency with other descriptions. --- library/std/src/os/linux/fs.rs | 2 ++ library/std/src/os/linux/mod.rs | 2 +- library/std/src/os/linux/raw.rs | 2 +- library/std/src/sys/unix/ext/ffi.rs | 2 +- library/std/src/sys/unix/ext/io.rs | 2 +- library/std/src/sys/unix/ext/net.rs | 4 ++-- library/std/src/sys/unix/ext/raw.rs | 2 +- library/std/src/sys/windows/ext/io.rs | 2 ++ library/std/src/sys/windows/ext/raw.rs | 2 +- 9 files changed, 12 insertions(+), 8 deletions(-) diff --git a/library/std/src/os/linux/fs.rs b/library/std/src/os/linux/fs.rs index 14719a9be5e8a..ff23c3d67e3b4 100644 --- a/library/std/src/os/linux/fs.rs +++ b/library/std/src/os/linux/fs.rs @@ -1,3 +1,5 @@ +//! Linux-specific extensions to primitives in the `std::fs` module. + #![stable(feature = "metadata_ext", since = "1.1.0")] use crate::fs::Metadata; diff --git a/library/std/src/os/linux/mod.rs b/library/std/src/os/linux/mod.rs index d35307162cc7e..f179a524336fc 100644 --- a/library/std/src/os/linux/mod.rs +++ b/library/std/src/os/linux/mod.rs @@ -1,4 +1,4 @@ -//! Linux-specific definitions +//! Linux-specific definitions. #![stable(feature = "raw_ext", since = "1.1.0")] diff --git a/library/std/src/os/linux/raw.rs b/library/std/src/os/linux/raw.rs index 1950ffcb21b67..a007fd2b6be04 100644 --- a/library/std/src/os/linux/raw.rs +++ b/library/std/src/os/linux/raw.rs @@ -1,4 +1,4 @@ -//! Linux-specific raw type definitions +//! Linux-specific raw type definitions. #![stable(feature = "raw_ext", since = "1.1.0")] #![rustc_deprecated( diff --git a/library/std/src/sys/unix/ext/ffi.rs b/library/std/src/sys/unix/ext/ffi.rs index 76b34a6b5d84a..123f85deaf9e3 100644 --- a/library/std/src/sys/unix/ext/ffi.rs +++ b/library/std/src/sys/unix/ext/ffi.rs @@ -1,4 +1,4 @@ -//! Unix-specific extension to the primitives in the `std::ffi` module +//! Unix-specific extension to the primitives in the `std::ffi` module. //! //! # Examples //! diff --git a/library/std/src/sys/unix/ext/io.rs b/library/std/src/sys/unix/ext/io.rs index 5077e2e28d18b..ec7a32b675c02 100644 --- a/library/std/src/sys/unix/ext/io.rs +++ b/library/std/src/sys/unix/ext/io.rs @@ -1,4 +1,4 @@ -//! Unix-specific extensions to general I/O primitives +//! Unix-specific extensions to general I/O primitives. #![stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/sys/unix/ext/net.rs b/library/std/src/sys/unix/ext/net.rs index 0e07106f5ce5c..0efd5b9f11043 100644 --- a/library/std/src/sys/unix/ext/net.rs +++ b/library/std/src/sys/unix/ext/net.rs @@ -1,6 +1,6 @@ -#![stable(feature = "unix_socket", since = "1.10.0")] +//! Unix-specific networking functionality. -//! Unix-specific networking functionality +#![stable(feature = "unix_socket", since = "1.10.0")] #[cfg(all(test, not(target_os = "emscripten")))] mod tests; diff --git a/library/std/src/sys/unix/ext/raw.rs b/library/std/src/sys/unix/ext/raw.rs index 40fa53d484f84..3199a0bff0bcc 100644 --- a/library/std/src/sys/unix/ext/raw.rs +++ b/library/std/src/sys/unix/ext/raw.rs @@ -1,4 +1,4 @@ -//! Unix-specific primitives available on all unix platforms +//! Unix-specific primitives available on all unix platforms. #![stable(feature = "raw_ext", since = "1.1.0")] #![rustc_deprecated( diff --git a/library/std/src/sys/windows/ext/io.rs b/library/std/src/sys/windows/ext/io.rs index 4573ee589321d..e75f9a4bfd5e3 100644 --- a/library/std/src/sys/windows/ext/io.rs +++ b/library/std/src/sys/windows/ext/io.rs @@ -1,3 +1,5 @@ +//! Windows-specific extensions to general I/O primitives. + #![stable(feature = "rust1", since = "1.0.0")] use crate::fs; diff --git a/library/std/src/sys/windows/ext/raw.rs b/library/std/src/sys/windows/ext/raw.rs index 7f2a2877828cf..5014e008eb599 100644 --- a/library/std/src/sys/windows/ext/raw.rs +++ b/library/std/src/sys/windows/ext/raw.rs @@ -1,4 +1,4 @@ -//! Windows-specific primitives +//! Windows-specific primitives. #![stable(feature = "raw_ext", since = "1.1.0")] From 9abc6bd28df390279b9f477538a778edf38ffd80 Mon Sep 17 00:00:00 2001 From: Hameer Abbasi Date: Fri, 11 Sep 2020 11:42:32 +0200 Subject: [PATCH 13/16] Add revisions to const generic const_evaluatable_checked tests. --- ...feature-gate-const_evaluatable_checked.full.stderr} | 2 +- .../feature-gate-const_evaluatable_checked.min.stderr | 10 ++++++++++ .../feature-gate-const_evaluatable_checked.rs | 9 ++++++--- .../const_evaluatable_checked/simple.min.stderr | 10 ++++++++++ .../const-generics/const_evaluatable_checked/simple.rs | 8 ++++++-- .../{simple_fail.stderr => simple_fail.full.stderr} | 2 +- .../const_evaluatable_checked/simple_fail.min.stderr | 10 ++++++++++ .../const_evaluatable_checked/simple_fail.rs | 8 ++++++-- 8 files changed, 50 insertions(+), 9 deletions(-) rename src/test/ui/const-generics/const_evaluatable_checked/{feature-gate-const_evaluatable_checked.stderr => feature-gate-const_evaluatable_checked.full.stderr} (82%) create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr rename src/test/ui/const-generics/const_evaluatable_checked/{simple_fail.stderr => simple_fail.full.stderr} (90%) create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr diff --git a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.stderr b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.full.stderr similarity index 82% rename from src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.stderr rename to src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.full.stderr index 6e4a22a38b17c..b2816367ea107 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.full.stderr @@ -1,5 +1,5 @@ error: constant expression depends on a generic parameter - --> $DIR/feature-gate-const_evaluatable_checked.rs:6:30 + --> $DIR/feature-gate-const_evaluatable_checked.rs:9:30 | LL | fn test() -> Arr where Arr: Default { | ^^^^^^ diff --git a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr new file mode 100644 index 0000000000000..269710db164b1 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/feature-gate-const_evaluatable_checked.rs:6:33 + | +LL | type Arr = [u8; N - 1]; + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs index 941bd5e9e5d0a..af3090115f24a 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs +++ b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs @@ -1,10 +1,13 @@ -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] type Arr = [u8; N - 1]; +//[min]~^ ERROR generic parameters must not be used inside of non trivial constant values fn test() -> Arr where Arr: Default { - //~^ ERROR constant expression depends + //[full]~^ ERROR constant expression depends Default::default() } diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr new file mode 100644 index 0000000000000..da8ccdaee4146 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/simple.rs:8:33 + | +LL | type Arr = [u8; N - 1]; + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple.rs b/src/test/ui/const-generics/const_evaluatable_checked/simple.rs index a7ead78b97bae..27dc6b103200d 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/simple.rs +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple.rs @@ -1,8 +1,12 @@ -// run-pass -#![feature(const_generics, const_evaluatable_checked)] +// [full] run-pass +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(min, feature(min_const_generics))] +#![feature(const_evaluatable_checked)] #![allow(incomplete_features)] type Arr = [u8; N - 1]; +//[min]~^ ERROR generic parameters must not be used inside of non trivial constant values fn test() -> Arr where Arr: Default { Default::default() diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr similarity index 90% rename from src/test/ui/const-generics/const_evaluatable_checked/simple_fail.stderr rename to src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr index 1ac5e1d95537a..104cab8667c70 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr @@ -1,5 +1,5 @@ error[E0080]: evaluation of constant value failed - --> $DIR/simple_fail.rs:4:33 + --> $DIR/simple_fail.rs:7:33 | LL | type Arr = [u8; N - 1]; | ^^^^^ attempt to compute `0_usize - 1_usize` which would overflow diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr new file mode 100644 index 0000000000000..042710f13273e --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/simple_fail.rs:7:33 + | +LL | type Arr = [u8; N - 1]; + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs index 1edf1885dd281..b15e0ff183954 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs @@ -1,7 +1,11 @@ -#![feature(const_generics, const_evaluatable_checked)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(min, feature(min_const_generics))] +#![feature(const_evaluatable_checked)] #![allow(incomplete_features)] -type Arr = [u8; N - 1]; //~ ERROR evaluation of constant +type Arr = [u8; N - 1]; //[full]~ ERROR evaluation of constant +//[min]~^ ERROR generic parameters must not be used inside of non trivial constant values fn test() -> Arr where Arr: Sized { todo!() From 5e188f5803bdbfdf3ff000e8b7e266405531c8d7 Mon Sep 17 00:00:00 2001 From: Hameer Abbasi Date: Fri, 11 Sep 2020 11:48:44 +0200 Subject: [PATCH 14/16] Add revisions to const generic type-dependent UI tests. --- .../type-dependent/auxiliary/type_dependent_lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/test/ui/const-generics/type-dependent/auxiliary/type_dependent_lib.rs b/src/test/ui/const-generics/type-dependent/auxiliary/type_dependent_lib.rs index c8db91b62b58c..aa85376bf0d75 100644 --- a/src/test/ui/const-generics/type-dependent/auxiliary/type_dependent_lib.rs +++ b/src/test/ui/const-generics/type-dependent/auxiliary/type_dependent_lib.rs @@ -1,5 +1,6 @@ -#![feature(const_generics)] -#![allow(incomplete_features)] +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] pub struct Struct(()); From b729368d4e6a7e6a85dd4189ca16d49622a1582a Mon Sep 17 00:00:00 2001 From: carbotaniuman <41451839+carbotaniuman@users.noreply.github.com> Date: Fri, 11 Sep 2020 07:25:28 -0500 Subject: [PATCH 15/16] Address review comments --- library/alloc/src/rc.rs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 4821c8f567626..f998e49dcfcde 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -295,6 +295,13 @@ impl, U: ?Sized> CoerceUnsized> for Rc {} impl, U: ?Sized> DispatchFromDyn> for Rc {} impl Rc { + #[inline(always)] + fn inner(&self) -> &RcBox { + // This unsafety is ok because while this Rc is alive we're guaranteed + // that the inner pointer is valid. + unsafe { self.ptr.as_ref() } + } + fn from_inner(ptr: NonNull>) -> Self { Self { ptr, phantom: PhantomData } } @@ -845,17 +852,10 @@ impl Rc { #[unstable(feature = "get_mut_unchecked", issue = "63292")] pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T { // We are careful to *not* create a reference covering the "count" fields, as - // this would alias with concurrent access to the reference counts (e.g. by `Weak`). + // this would conflict with accesses to the reference counts (e.g. by `Weak`). unsafe { &mut (*this.ptr.as_ptr()).value } } - #[inline] - fn inner(&self) -> &RcBox { - // This unsafety is ok because while this Rc is alive we're guaranteed - // that the inner pointer is valid. - unsafe { self.ptr.as_ref() } - } - #[inline] #[stable(feature = "ptr_eq", since = "1.17.0")] /// Returns `true` if the two `Rc`s point to the same allocation @@ -2145,18 +2145,24 @@ trait RcInnerPtr { } impl RcInnerPtr for RcBox { + #[inline(always)] fn weak_ref(&self) -> &Cell { &self.weak } + + #[inline(always)] fn strong_ref(&self) -> &Cell { &self.strong } } impl<'a> RcInnerPtr for WeakInner<'a> { + #[inline(always)] fn weak_ref(&self) -> &Cell { self.weak } + + #[inline(always)] fn strong_ref(&self) -> &Cell { self.strong } From bb9ce7cb01fba4b34bbebf8a44056016cabfa40e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 11 Sep 2020 23:43:37 +0200 Subject: [PATCH 16/16] Add missing examples on binary core traits --- library/core/src/ops/bit.rs | 134 ++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) diff --git a/library/core/src/ops/bit.rs b/library/core/src/ops/bit.rs index bcfff4a223bec..3d71e0b0002c2 100644 --- a/library/core/src/ops/bit.rs +++ b/library/core/src/ops/bit.rs @@ -36,6 +36,15 @@ pub trait Not { type Output; /// Performs the unary `!` operation. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(!true, false); + /// assert_eq!(!false, true); + /// assert_eq!(!1u8, 254); + /// assert_eq!(!0u8, 255); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn not(self) -> Self::Output; @@ -122,6 +131,15 @@ pub trait BitAnd { type Output; /// Performs the `&` operation. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(true & false, false); + /// assert_eq!(true & true, true); + /// assert_eq!(5u8 & 1u8, 1); + /// assert_eq!(5u8 & 2u8, 0); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn bitand(self, rhs: Rhs) -> Self::Output; @@ -208,6 +226,15 @@ pub trait BitOr { type Output; /// Performs the `|` operation. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(true | false, true); + /// assert_eq!(false | false, false); + /// assert_eq!(5u8 | 1u8, 5); + /// assert_eq!(5u8 | 2u8, 7); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn bitor(self, rhs: Rhs) -> Self::Output; @@ -297,6 +324,15 @@ pub trait BitXor { type Output; /// Performs the `^` operation. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(true ^ false, true); + /// assert_eq!(true ^ true, false); + /// assert_eq!(5u8 ^ 1u8, 4); + /// assert_eq!(5u8 ^ 2u8, 7); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn bitxor(self, rhs: Rhs) -> Self::Output; @@ -387,6 +423,13 @@ pub trait Shl { type Output; /// Performs the `<<` operation. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(5u8 << 1, 10); + /// assert_eq!(1u8 << 1, 2); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn shl(self, rhs: Rhs) -> Self::Output; @@ -498,6 +541,13 @@ pub trait Shr { type Output; /// Performs the `>>` operation. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(5u8 >> 1, 2); + /// assert_eq!(2u8 >> 1, 1); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn shr(self, rhs: Rhs) -> Self::Output; @@ -612,6 +662,26 @@ shr_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } )] pub trait BitAndAssign { /// Performs the `&=` operation. + /// + /// # Examples + /// + /// ``` + /// let mut x = true; + /// x &= false; + /// assert_eq!(x, false); + /// + /// let mut x = true; + /// x &= true; + /// assert_eq!(x, true); + /// + /// let mut x: u8 = 5; + /// x &= 1; + /// assert_eq!(x, 1); + /// + /// let mut x: u8 = 5; + /// x &= 2; + /// assert_eq!(x, 0); + /// ``` #[stable(feature = "op_assign_traits", since = "1.8.0")] fn bitand_assign(&mut self, rhs: Rhs); } @@ -663,6 +733,26 @@ bitand_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } )] pub trait BitOrAssign { /// Performs the `|=` operation. + /// + /// # Examples + /// + /// ``` + /// let mut x = true; + /// x |= false; + /// assert_eq!(x, true); + /// + /// let mut x = false; + /// x |= false; + /// assert_eq!(x, false); + /// + /// let mut x: u8 = 5; + /// x |= 1; + /// assert_eq!(x, 5); + /// + /// let mut x: u8 = 5; + /// x |= 2; + /// assert_eq!(x, 7); + /// ``` #[stable(feature = "op_assign_traits", since = "1.8.0")] fn bitor_assign(&mut self, rhs: Rhs); } @@ -714,6 +804,26 @@ bitor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } )] pub trait BitXorAssign { /// Performs the `^=` operation. + /// + /// # Examples + /// + /// ``` + /// let mut x = true; + /// x ^= false; + /// assert_eq!(x, true); + /// + /// let mut x = true; + /// x ^= true; + /// assert_eq!(x, false); + /// + /// let mut x: u8 = 5; + /// x ^= 1; + /// assert_eq!(x, 4); + /// + /// let mut x: u8 = 5; + /// x ^= 2; + /// assert_eq!(x, 7); + /// ``` #[stable(feature = "op_assign_traits", since = "1.8.0")] fn bitxor_assign(&mut self, rhs: Rhs); } @@ -763,6 +873,18 @@ bitxor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } )] pub trait ShlAssign { /// Performs the `<<=` operation. + /// + /// # Examples + /// + /// ``` + /// let mut x: u8 = 5; + /// x <<= 1; + /// assert_eq!(x, 10); + /// + /// let mut x: u8 = 1; + /// x <<= 1; + /// assert_eq!(x, 2); + /// ``` #[stable(feature = "op_assign_traits", since = "1.8.0")] fn shl_assign(&mut self, rhs: Rhs); } @@ -833,6 +955,18 @@ shl_assign_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } )] pub trait ShrAssign { /// Performs the `>>=` operation. + /// + /// # Examples + /// + /// ``` + /// let mut x: u8 = 5; + /// x >>= 1; + /// assert_eq!(x, 2); + /// + /// let mut x: u8 = 2; + /// x >>= 1; + /// assert_eq!(x, 1); + /// ``` #[stable(feature = "op_assign_traits", since = "1.8.0")] fn shr_assign(&mut self, rhs: Rhs); }