From 6c3ca7e41870e06469838acefa4a63709f1f802f Mon Sep 17 00:00:00 2001 From: mojave2 Date: Thu, 30 Jun 2022 21:10:28 +0800 Subject: [PATCH 01/13] correct the output of a `capacity` method example --- library/alloc/src/string.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 668af60611b86..901bdf11e719f 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -317,11 +317,11 @@ use crate::vec::Vec; /// /// ```text /// 0 -/// 5 -/// 10 -/// 20 -/// 20 -/// 40 +/// 8 +/// 16 +/// 16 +/// 32 +/// 32 /// ``` /// /// At first, we have no memory allocated at all, but as we append to the From f6247ffa5afb29fd86d54db8062ff031daa10555 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Jul 2022 09:38:07 -0400 Subject: [PATCH 02/13] clarify how write_bytes can lead to UB due to invalid values --- library/core/src/intrinsics.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 2895c923adc13..4c8619f313540 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2550,10 +2550,10 @@ pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { /// /// * `dst` must be properly aligned. /// -/// Additionally, the caller must ensure that writing `count * -/// size_of::()` bytes to the given region of memory results in a valid -/// value of `T`. Using a region of memory typed as a `T` that contains an -/// invalid value of `T` is undefined behavior. +/// Additionally, note that changing `*dst` in this way can lead to undefined behavior later if the +/// written bytes are not a valid representation of some `T`. For instance, if `dst: *mut bool`, a +/// `dst.write_bytes(0xFFu8, 1)` followed by `dst.read()` is undefined behavior since the `read` +/// tries to construct a `bool` value from `0xFF` which does not represent any `bool`. /// /// Note that even if the effectively copied size (`count * size_of::()`) is /// `0`, the pointer must be non-null and properly aligned. From 2e0ca9472ba3ec1532bb752f7ea1f477f8c34c90 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Jul 2022 10:48:43 -0400 Subject: [PATCH 03/13] add a concrete example --- library/core/src/intrinsics.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 4c8619f313540..d7ed82e71b6a4 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2550,14 +2550,23 @@ pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { /// /// * `dst` must be properly aligned. /// -/// Additionally, note that changing `*dst` in this way can lead to undefined behavior later if the -/// written bytes are not a valid representation of some `T`. For instance, if `dst: *mut bool`, a -/// `dst.write_bytes(0xFFu8, 1)` followed by `dst.read()` is undefined behavior since the `read` -/// tries to construct a `bool` value from `0xFF` which does not represent any `bool`. -/// /// Note that even if the effectively copied size (`count * size_of::()`) is /// `0`, the pointer must be non-null and properly aligned. /// +/// Additionally, note that changing `*dst` in this way can easily lead to undefined behavior (UB) +/// later if the written bytes are not a valid representation of some `T`. For instance, the +/// follwing is an **incorrect** use of this function: +/// +/// ```rust,no_run +/// unsafe { +/// let mut value: u8 = 0; +/// let ptr: *mut bool = &mut value as *mut u8 as *mut bool; +/// let _bool = ptr.read(); // This is fine, `ptr` points to a valid `bool`. +/// ptr.write_bytes(42u8, 1); // This function itself does not cause UB... +/// let _bool = ptr.read(); // ...but it makes this operation UB! ⚠️ +/// } +/// ``` +/// /// [valid]: crate::ptr#safety /// /// # Examples From eed5df52f63dbf19030fb99045334252fcd5b366 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 11 Jul 2022 09:49:55 -0400 Subject: [PATCH 04/13] typo Co-authored-by: Ben Kimock --- library/core/src/intrinsics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index d7ed82e71b6a4..5f40a59f0b8ee 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2555,7 +2555,7 @@ pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { /// /// Additionally, note that changing `*dst` in this way can easily lead to undefined behavior (UB) /// later if the written bytes are not a valid representation of some `T`. For instance, the -/// follwing is an **incorrect** use of this function: +/// following is an **incorrect** use of this function: /// /// ```rust,no_run /// unsafe { From 1b3870e4271ca7b93de0b17ea6544e749fba3483 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 11 Jul 2022 11:36:08 -0400 Subject: [PATCH 05/13] remove a dubious example --- library/core/src/intrinsics.rs | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 5f40a59f0b8ee..a9330a869200f 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2583,38 +2583,6 @@ pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { /// } /// assert_eq!(vec, [0xfefefefe, 0xfefefefe, 0, 0]); /// ``` -/// -/// Creating an invalid value: -/// -/// ``` -/// use std::ptr; -/// -/// let mut v = Box::new(0i32); -/// -/// unsafe { -/// // Leaks the previously held value by overwriting the `Box` with -/// // a null pointer. -/// ptr::write_bytes(&mut v as *mut Box, 0, 1); -/// } -/// -/// // At this point, using or dropping `v` results in undefined behavior. -/// // drop(v); // ERROR -/// -/// // Even leaking `v` "uses" it, and hence is undefined behavior. -/// // mem::forget(v); // ERROR -/// -/// // In fact, `v` is invalid according to basic type layout invariants, so *any* -/// // operation touching it is undefined behavior. -/// // let v2 = v; // ERROR -/// -/// unsafe { -/// // Let us instead put in a valid value -/// ptr::write(&mut v as *mut Box, Box::new(42i32)); -/// } -/// -/// // Now the box is fine -/// assert_eq!(*v, 42); -/// ``` #[doc(alias = "memset")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] From 9fc5463c18af25b880b1ca476ae05bcba87140e6 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Wed, 29 Dec 2021 14:07:54 +0800 Subject: [PATCH 06/13] Constify a few const `(Partial)Ord` impls --- library/core/src/cmp.rs | 68 +++++++++++++++++++++++++++++------------ library/core/src/lib.rs | 1 + 2 files changed, 50 insertions(+), 19 deletions(-) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 1d3466696ed04..f3034159f040c 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -22,6 +22,8 @@ #![stable(feature = "rust1", since = "1.0.0")] +use crate::marker::Destruct; + use self::Ordering::*; /// Trait for equality comparisons which are [partial equivalence @@ -603,7 +605,8 @@ impl Ordering { pub struct Reverse(#[stable(feature = "reverse_cmp_key", since = "1.19.0")] pub T); #[stable(feature = "reverse_cmp_key", since = "1.19.0")] -impl PartialOrd for Reverse { +#[rustc_const_unstable(feature = "const_cmp", issue = "none")] +impl const PartialOrd for Reverse { #[inline] fn partial_cmp(&self, other: &Reverse) -> Option { other.0.partial_cmp(&self.0) @@ -761,6 +764,7 @@ impl Clone for Reverse { #[doc(alias = ">=")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "Ord"] +#[const_trait] pub trait Ord: Eq + PartialOrd { /// This method returns an [`Ordering`] between `self` and `other`. /// @@ -796,8 +800,12 @@ pub trait Ord: Eq + PartialOrd { fn max(self, other: Self) -> Self where Self: Sized, + Self: ~const Destruct, { - max_by(self, other, Ord::cmp) + match self.cmp(&other) { + Ordering::Less | Ordering::Equal => other, + Ordering::Greater => self, + } } /// Compares and returns the minimum of two values. @@ -816,8 +824,12 @@ pub trait Ord: Eq + PartialOrd { fn min(self, other: Self) -> Self where Self: Sized, + Self: ~const Destruct, { - min_by(self, other, Ord::cmp) + match self.cmp(&other) { + Ordering::Less | Ordering::Equal => self, + Ordering::Greater => other, + } } /// Restrict a value to a certain interval. @@ -841,6 +853,8 @@ pub trait Ord: Eq + PartialOrd { fn clamp(self, min: Self, max: Self) -> Self where Self: Sized, + Self: ~const Destruct, + Self: ~const PartialOrd, { assert!(min <= max); if self < min { @@ -862,7 +876,8 @@ pub macro Ord($item:item) { } #[stable(feature = "rust1", since = "1.0.0")] -impl Ord for Ordering { +#[rustc_const_unstable(feature = "const_cmp", issue = "none")] +impl const Ord for Ordering { #[inline] fn cmp(&self, other: &Ordering) -> Ordering { (*self as i32).cmp(&(*other as i32)) @@ -870,7 +885,8 @@ impl Ord for Ordering { } #[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for Ordering { +#[rustc_const_unstable(feature = "const_cmp", issue = "none")] +impl const PartialOrd for Ordering { #[inline] fn partial_cmp(&self, other: &Ordering) -> Option { (*self as i32).partial_cmp(&(*other as i32)) @@ -1187,8 +1203,9 @@ pub macro PartialOrd($item:item) { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_cmp", issue = "none")] #[cfg_attr(not(test), rustc_diagnostic_item = "cmp_min")] -pub fn min(v1: T, v2: T) -> T { +pub const fn min(v1: T, v2: T) -> T { v1.min(v2) } @@ -1250,8 +1267,9 @@ pub fn min_by_key K, K: Ord>(v1: T, v2: T, mut f: F) -> T { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_cmp", issue = "none")] #[cfg_attr(not(test), rustc_diagnostic_item = "cmp_max")] -pub fn max(v1: T, v2: T) -> T { +pub const fn max(v1: T, v2: T) -> T { v1.max(v2) } @@ -1304,7 +1322,8 @@ mod impls { macro_rules! partial_eq_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - impl PartialEq for $t { + #[rustc_const_unstable(feature = "const_cmp", issue = "none")] + impl const PartialEq for $t { #[inline] fn eq(&self, other: &$t) -> bool { (*self) == (*other) } #[inline] @@ -1314,7 +1333,8 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl PartialEq for () { + #[rustc_const_unstable(feature = "const_cmp", issue = "none")] + impl const PartialEq for () { #[inline] fn eq(&self, _other: &()) -> bool { true @@ -1341,7 +1361,8 @@ mod impls { macro_rules! partial_ord_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - impl PartialOrd for $t { + #[rustc_const_unstable(feature = "const_cmp", issue = "none")] + impl const PartialOrd for $t { #[inline] fn partial_cmp(&self, other: &$t) -> Option { match (*self <= *other, *self >= *other) { @@ -1364,7 +1385,8 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl PartialOrd for () { + #[rustc_const_unstable(feature = "const_cmp", issue = "none")] + impl const PartialOrd for () { #[inline] fn partial_cmp(&self, _: &()) -> Option { Some(Equal) @@ -1372,7 +1394,8 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl PartialOrd for bool { + #[rustc_const_unstable(feature = "const_cmp", issue = "none")] + impl const PartialOrd for bool { #[inline] fn partial_cmp(&self, other: &bool) -> Option { Some(self.cmp(other)) @@ -1384,7 +1407,8 @@ mod impls { macro_rules! ord_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - impl PartialOrd for $t { + #[rustc_const_unstable(feature = "const_cmp", issue = "none")] + impl const PartialOrd for $t { #[inline] fn partial_cmp(&self, other: &$t) -> Option { Some(self.cmp(other)) @@ -1400,7 +1424,8 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl Ord for $t { + #[rustc_const_unstable(feature = "const_cmp", issue = "none")] + impl const Ord for $t { #[inline] fn cmp(&self, other: &$t) -> Ordering { // The order here is important to generate more optimal assembly. @@ -1414,7 +1439,8 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl Ord for () { + #[rustc_const_unstable(feature = "const_cmp", issue = "none")] + impl const Ord for () { #[inline] fn cmp(&self, _other: &()) -> Ordering { Equal @@ -1422,7 +1448,8 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl Ord for bool { + #[rustc_const_unstable(feature = "const_cmp", issue = "none")] + impl const Ord for bool { #[inline] fn cmp(&self, other: &bool) -> Ordering { // Casting to i8's and converting the difference to an Ordering generates @@ -1441,7 +1468,8 @@ mod impls { ord_impl! { char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } #[unstable(feature = "never_type", issue = "35121")] - impl PartialEq for ! { + #[rustc_const_unstable(feature = "const_cmp", issue = "none")] + impl const PartialEq for ! { fn eq(&self, _: &!) -> bool { *self } @@ -1451,14 +1479,16 @@ mod impls { impl Eq for ! {} #[unstable(feature = "never_type", issue = "35121")] - impl PartialOrd for ! { + #[rustc_const_unstable(feature = "const_cmp", issue = "none")] + impl const PartialOrd for ! { fn partial_cmp(&self, _: &!) -> Option { *self } } #[unstable(feature = "never_type", issue = "35121")] - impl Ord for ! { + #[rustc_const_unstable(feature = "const_cmp", issue = "none")] + impl const Ord for ! { fn cmp(&self, _: &!) -> Ordering { *self } diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index f24a7ab61ae89..30f2f0ee05c25 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -105,6 +105,7 @@ #![feature(const_cell_into_inner)] #![feature(const_char_convert)] #![feature(const_clone)] +#![feature(const_cmp)] #![feature(const_discriminant)] #![feature(const_eval_select)] #![feature(const_float_bits_conv)] From a89510e5f9c1610bd5f503d7f556e94b68e6070c Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Wed, 29 Dec 2021 14:18:52 +0800 Subject: [PATCH 07/13] Add issue numbers --- library/core/src/cmp.rs | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index f3034159f040c..e81d15f6c7ced 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -605,7 +605,7 @@ impl Ordering { pub struct Reverse(#[stable(feature = "reverse_cmp_key", since = "1.19.0")] pub T); #[stable(feature = "reverse_cmp_key", since = "1.19.0")] -#[rustc_const_unstable(feature = "const_cmp", issue = "none")] +#[rustc_const_unstable(feature = "const_cmp", issue = "92391")] impl const PartialOrd for Reverse { #[inline] fn partial_cmp(&self, other: &Reverse) -> Option { @@ -876,7 +876,7 @@ pub macro Ord($item:item) { } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_cmp", issue = "none")] +#[rustc_const_unstable(feature = "const_cmp", issue = "92391")] impl const Ord for Ordering { #[inline] fn cmp(&self, other: &Ordering) -> Ordering { @@ -885,7 +885,7 @@ impl const Ord for Ordering { } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_cmp", issue = "none")] +#[rustc_const_unstable(feature = "const_cmp", issue = "92391")] impl const PartialOrd for Ordering { #[inline] fn partial_cmp(&self, other: &Ordering) -> Option { @@ -1203,7 +1203,7 @@ pub macro PartialOrd($item:item) { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_cmp", issue = "none")] +#[rustc_const_unstable(feature = "const_cmp", issue = "92391")] #[cfg_attr(not(test), rustc_diagnostic_item = "cmp_min")] pub const fn min(v1: T, v2: T) -> T { v1.min(v2) @@ -1267,7 +1267,7 @@ pub fn min_by_key K, K: Ord>(v1: T, v2: T, mut f: F) -> T { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_cmp", issue = "none")] +#[rustc_const_unstable(feature = "const_cmp", issue = "92391")] #[cfg_attr(not(test), rustc_diagnostic_item = "cmp_max")] pub const fn max(v1: T, v2: T) -> T { v1.max(v2) @@ -1322,7 +1322,7 @@ mod impls { macro_rules! partial_eq_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cmp", issue = "none")] + #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] impl const PartialEq for $t { #[inline] fn eq(&self, other: &$t) -> bool { (*self) == (*other) } @@ -1333,7 +1333,7 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cmp", issue = "none")] + #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] impl const PartialEq for () { #[inline] fn eq(&self, _other: &()) -> bool { @@ -1361,7 +1361,7 @@ mod impls { macro_rules! partial_ord_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cmp", issue = "none")] + #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] impl const PartialOrd for $t { #[inline] fn partial_cmp(&self, other: &$t) -> Option { @@ -1385,7 +1385,7 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cmp", issue = "none")] + #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] impl const PartialOrd for () { #[inline] fn partial_cmp(&self, _: &()) -> Option { @@ -1394,7 +1394,7 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cmp", issue = "none")] + #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] impl const PartialOrd for bool { #[inline] fn partial_cmp(&self, other: &bool) -> Option { @@ -1407,7 +1407,7 @@ mod impls { macro_rules! ord_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cmp", issue = "none")] + #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] impl const PartialOrd for $t { #[inline] fn partial_cmp(&self, other: &$t) -> Option { @@ -1424,7 +1424,7 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cmp", issue = "none")] + #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] impl const Ord for $t { #[inline] fn cmp(&self, other: &$t) -> Ordering { @@ -1439,7 +1439,7 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cmp", issue = "none")] + #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] impl const Ord for () { #[inline] fn cmp(&self, _other: &()) -> Ordering { @@ -1448,7 +1448,7 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cmp", issue = "none")] + #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] impl const Ord for bool { #[inline] fn cmp(&self, other: &bool) -> Ordering { @@ -1468,7 +1468,7 @@ mod impls { ord_impl! { char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } #[unstable(feature = "never_type", issue = "35121")] - #[rustc_const_unstable(feature = "const_cmp", issue = "none")] + #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] impl const PartialEq for ! { fn eq(&self, _: &!) -> bool { *self @@ -1479,7 +1479,7 @@ mod impls { impl Eq for ! {} #[unstable(feature = "never_type", issue = "35121")] - #[rustc_const_unstable(feature = "const_cmp", issue = "none")] + #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] impl const PartialOrd for ! { fn partial_cmp(&self, _: &!) -> Option { *self @@ -1487,7 +1487,7 @@ mod impls { } #[unstable(feature = "never_type", issue = "35121")] - #[rustc_const_unstable(feature = "const_cmp", issue = "none")] + #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] impl const Ord for ! { fn cmp(&self, _: &!) -> Ordering { *self From 65fca6db1949b2aa30a93b382b899a60bfddb132 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Fri, 14 Jan 2022 16:55:19 +0800 Subject: [PATCH 08/13] add const hack comment --- library/core/src/cmp.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index e81d15f6c7ced..ac286c171f080 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -802,6 +802,9 @@ pub trait Ord: Eq + PartialOrd { Self: Sized, Self: ~const Destruct, { + // HACK(fee1-dead): go back to using `self.max_by(other, Ord::cmp)` + // when trait methods are allowed to be used when a const closure is + // expected. match self.cmp(&other) { Ordering::Less | Ordering::Equal => other, Ordering::Greater => self, @@ -826,6 +829,9 @@ pub trait Ord: Eq + PartialOrd { Self: Sized, Self: ~const Destruct, { + // HACK(fee1-dead): go back to using `self.min_by(other, Ord::cmp)` + // when trait methods are allowed to be used when a const closure is + // expected. match self.cmp(&other) { Ordering::Less | Ordering::Equal => self, Ordering::Greater => other, From f80bf1013d52c50e308746a977ed6a7cdd28c6a5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 Jul 2022 09:21:05 -0400 Subject: [PATCH 09/13] don't ICE on invalid dyn calls --- compiler/rustc_const_eval/src/interpret/terminator.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index 6fef7b3b3cf7c..8af8369f6f921 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -571,8 +571,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Now determine the actual method to call. We can do that in two different ways and // compare them to ensure everything fits. - let ty::VtblEntry::Method(fn_inst) = self.get_vtable_entries(vptr)?[idx] else { - span_bug!(self.cur_span(), "dyn call index points at something that is not a method") + let Some(ty::VtblEntry::Method(fn_inst)) = self.get_vtable_entries(vptr)?.get(idx).copied() else { + throw_ub_format!("`dyn` call trying to call something that is not a method") }; if cfg!(debug_assertions) { let tcx = *self.tcx; From 58034926024af6637dab04493c715acf349088e4 Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Fri, 17 Jun 2022 20:31:59 +0100 Subject: [PATCH 10/13] Implement `fs::get_path` for FreeBSD. Using `F_KINFO` fcntl flag, the kf_structsize field needs to be set beforehand for that effect. --- library/std/src/sys/unix/fs.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 7c8824694408c..ebadc23877d46 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -1126,6 +1126,19 @@ impl fmt::Debug for File { Some(PathBuf::from(OsString::from_vec(buf))) } + #[cfg(target_os = "freebsd")] + fn get_path(fd: c_int) -> Option { + let info = Box::::new_zeroed(); + let mut info = unsafe { info.assume_init() }; + info.kf_structsize = mem::size_of::() as libc::c_int; + let n = unsafe { libc::fcntl(fd, libc::F_KINFO, &mut *info) }; + if n == -1 { + return None; + } + let buf = unsafe { CStr::from_ptr(info.kf_path.as_mut_ptr()).to_bytes().to_vec() }; + Some(PathBuf::from(OsString::from_vec(buf))) + } + #[cfg(target_os = "vxworks")] fn get_path(fd: c_int) -> Option { let mut buf = vec![0; libc::PATH_MAX as usize]; @@ -1142,6 +1155,7 @@ impl fmt::Debug for File { target_os = "linux", target_os = "macos", target_os = "vxworks", + target_os = "freebsd", target_os = "netbsd" )))] fn get_path(_fd: c_int) -> Option { From 5f40a4f7a0aa6552e615fe89a6018e36c93f672e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Mon, 25 Jul 2022 00:00:00 +0000 Subject: [PATCH 11/13] Remove reachable coverage without counters Remove reachable coverage without counters to maintain invariant that either there is no coverage at all or there is a live coverage counter left that provides the function source hash. The motivating example would be a following closure: ```rust let f = |x: bool| { debug_assert!(x); }; ``` Which, with span changes from #93967, with disabled debug assertions, after the final CFG simplifications but before removal of dead blocks, gives rise to MIR: ```rust fn main::{closure#0}(_1: &[closure@a.rs:2:13: 2:22], _2: bool) -> () { debug x => _2; let mut _0: (); bb0: { Coverage::Expression(4294967295) = 1 - 2; return; } ... } ``` --- compiler/rustc_mir_transform/src/simplify.rs | 12 +++++- .../expected_show_coverage.inline-dead.txt | 39 +++++++++++-------- .../run-make-fulldeps/coverage/inline-dead.rs | 9 ++++- 3 files changed, 42 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index d305960b4856d..180f4c7dcd6e8 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -315,7 +315,7 @@ pub fn remove_dead_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { /// with `0` executions. /// /// If there are no live `Counter` `Coverage` statements remaining, we remove -/// dead `Coverage` statements along with the dead blocks. Since at least one +/// `Coverage` statements along with the dead blocks. Since at least one /// counter per function is required by LLVM (and necessary, to add the /// `function_hash` to the counter's call to the LLVM intrinsic /// `instrprof.increment()`). @@ -342,6 +342,16 @@ fn save_unreachable_coverage( } } + for block in &mut basic_blocks.raw[..first_dead_block] { + for statement in &mut block.statements { + let StatementKind::Coverage(_) = &statement.kind else { continue }; + let instance = statement.source_info.scope.inlined_instance(source_scopes); + if !live.contains(&instance) { + statement.make_nop(); + } + } + } + if live.is_empty() { return; } diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inline-dead.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inline-dead.txt index d102d9ecf7d14..effdef80e8eb6 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inline-dead.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inline-dead.txt @@ -1,21 +1,28 @@ 1| |// Regression test for issue #98833. - 2| |// compile-flags: -Zinline-mir + 2| |// compile-flags: -Zinline-mir -Cdebug-assertions=off 3| | 4| 1|fn main() { 5| 1| println!("{}", live::()); - 6| 1|} - 7| | - 8| |#[inline] - 9| 1|fn live() -> u32 { - 10| 1| if B { - 11| 0| dead() - 12| | } else { - 13| 1| 0 - 14| | } - 15| 1|} - 16| | - 17| |#[inline] - 18| 0|fn dead() -> u32 { - 19| 0| 42 - 20| 0|} + 6| 1| + 7| 1| let f = |x: bool| { + 8| | debug_assert!( + 9| | x + 10| | ); + 11| 1| }; + 12| 1| f(false); + 13| 1|} + 14| | + 15| |#[inline] + 16| 1|fn live() -> u32 { + 17| 1| if B { + 18| 0| dead() + 19| | } else { + 20| 1| 0 + 21| | } + 22| 1|} + 23| | + 24| |#[inline] + 25| 0|fn dead() -> u32 { + 26| 0| 42 + 27| 0|} diff --git a/src/test/run-make-fulldeps/coverage/inline-dead.rs b/src/test/run-make-fulldeps/coverage/inline-dead.rs index cd1ae911a5f7e..854fa06296752 100644 --- a/src/test/run-make-fulldeps/coverage/inline-dead.rs +++ b/src/test/run-make-fulldeps/coverage/inline-dead.rs @@ -1,8 +1,15 @@ // Regression test for issue #98833. -// compile-flags: -Zinline-mir +// compile-flags: -Zinline-mir -Cdebug-assertions=off fn main() { println!("{}", live::()); + + let f = |x: bool| { + debug_assert!( + x + ); + }; + f(false); } #[inline] From bf1a5e72f4b3bdb749e6df4f770c44e4f7973963 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Mon, 25 Jul 2022 22:37:14 +0900 Subject: [PATCH 12/13] remove `is_local_span` as it is no longer used --- compiler/rustc_span/src/source_map.rs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index b4a4424e876cd..47159584afe3b 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -586,17 +586,6 @@ impl SourceMap { } } - /// Returns whether or not this span points into a file - /// in the current crate. This may be `false` for spans - /// produced by a macro expansion, or for spans associated - /// with the definition of an item in a foreign crate - pub fn is_local_span(&self, sp: Span) -> bool { - let local_begin = self.lookup_byte_offset(sp.lo()); - let local_end = self.lookup_byte_offset(sp.hi()); - // This might be a weird span that covers multiple files - local_begin.sf.src.is_some() && local_end.sf.src.is_some() - } - pub fn is_span_accessible(&self, sp: Span) -> bool { self.span_to_source(sp, |src, start_index, end_index| { Ok(src.get(start_index..end_index).is_some()) From 051e98b7bf7a2ab095516a9b3912d6120b5b8c91 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Mon, 25 Jul 2022 22:40:00 +0900 Subject: [PATCH 13/13] avoid `&str`/`Symbol` to `String` conversions --- .../rustc_borrowck/src/diagnostics/region_errors.rs | 8 +++----- .../rustc_mir_build/src/thir/pattern/check_match.rs | 2 +- compiler/rustc_resolve/src/diagnostics.rs | 3 +-- compiler/rustc_typeck/src/astconv/errors.rs | 4 ++-- compiler/rustc_typeck/src/astconv/mod.rs | 4 ++-- compiler/rustc_typeck/src/errors.rs | 12 ++++++++++-- 6 files changed, 19 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 07aba50f03b99..1d66153734c78 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -850,13 +850,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { debug!("trait spans found: {:?}", traits); for span in &traits { let mut multi_span: MultiSpan = vec![*span].into(); - multi_span.push_span_label( - *span, - "this has an implicit `'static` lifetime requirement".to_string(), - ); + multi_span + .push_span_label(*span, "this has an implicit `'static` lifetime requirement"); multi_span.push_span_label( ident.span, - "calling this method introduces the `impl`'s 'static` requirement".to_string(), + "calling this method introduces the `impl`'s 'static` requirement", ); err.span_note(multi_span, "the used `impl` has a `'static` requirement"); err.span_suggestion_verbose( diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 5bd1fad0bcb9f..3435f127c72e2 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -951,7 +951,7 @@ fn adt_defined_here<'p, 'tcx>( let mut span: MultiSpan = if spans.is_empty() { def_span.into() } else { spans.clone().into() }; - span.push_span_label(def_span, String::new()); + span.push_span_label(def_span, ""); for pat in spans { span.push_span_label(pat, "not covered"); } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index d74e26fc84498..8a655cbf3845a 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -565,8 +565,7 @@ impl<'a> Resolver<'a> { } else if let Some(sp) = sm.generate_fn_name_span(span) { err.span_label( sp, - "try adding a local generic parameter in this method instead" - .to_string(), + "try adding a local generic parameter in this method instead", ); } else { err.help("try using a local generic parameter instead"); diff --git a/compiler/rustc_typeck/src/astconv/errors.rs b/compiler/rustc_typeck/src/astconv/errors.rs index c873cf27e42c5..99a8101dc96ba 100644 --- a/compiler/rustc_typeck/src/astconv/errors.rs +++ b/compiler/rustc_typeck/src/astconv/errors.rs @@ -8,7 +8,7 @@ use rustc_middle::ty; use rustc_session::parse::feature_err; use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::symbol::{sym, Ident}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{Span, Symbol, DUMMY_SP}; use std::collections::BTreeSet; @@ -17,7 +17,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// the type parameter's name as a placeholder. pub(crate) fn complain_about_missing_type_params( &self, - missing_type_params: Vec, + missing_type_params: Vec, def_id: DefId, span: Span, empty_generic_args: bool, diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 7111812f0b090..eacc9df8da798 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -382,7 +382,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { def_id: DefId, generic_args: &'a GenericArgs<'a>, span: Span, - missing_type_params: Vec, + missing_type_params: Vec, inferred_params: Vec, infer_args: bool, is_object: bool, @@ -514,7 +514,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // defaults. This will lead to an ICE if we are not // careful! if self.default_needs_object_self(param) { - self.missing_type_params.push(param.name.to_string()); + self.missing_type_params.push(param.name); tcx.ty_error().into() } else { // This is a default type parameter. diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs index 4cdec615d8290..0438ac02ea91a 100644 --- a/compiler/rustc_typeck/src/errors.rs +++ b/compiler/rustc_typeck/src/errors.rs @@ -244,7 +244,7 @@ pub struct UnconstrainedOpaqueType { pub struct MissingTypeParams { pub span: Span, pub def_span: Span, - pub missing_type_params: Vec, + pub missing_type_params: Vec, pub empty_generic_args: bool, } @@ -285,7 +285,15 @@ impl<'a> SessionDiagnostic<'a> for MissingTypeParams { err.span_suggestion( self.span, rustc_errors::fluent::typeck::suggestion, - format!("{}<{}>", snippet, self.missing_type_params.join(", ")), + format!( + "{}<{}>", + snippet, + self.missing_type_params + .iter() + .map(|n| n.to_string()) + .collect::>() + .join(", ") + ), Applicability::HasPlaceholders, ); suggested = true;