From 6c3ca7e41870e06469838acefa4a63709f1f802f Mon Sep 17 00:00:00 2001 From: mojave2 Date: Thu, 30 Jun 2022 21:10:28 +0800 Subject: [PATCH 01/19] 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/19] 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/19] 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/19] 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/19] 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 c0e4230bf5596d83d61c7a4ca5b06f0490ac4dba Mon Sep 17 00:00:00 2001 From: ouz-a Date: Thu, 12 May 2022 00:27:06 +0300 Subject: [PATCH 06/19] simplify some code that depend on Deref --- compiler/rustc_codegen_ssa/src/mir/place.rs | 11 ++----- compiler/rustc_middle/src/mir/mod.rs | 20 +++++++++++++ compiler/rustc_mir_transform/src/add_retag.rs | 29 ++++++------------- 3 files changed, 32 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 58cee0c8bb0db..38e09f539ded1 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -435,16 +435,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { LocalRef::Place(place) => place, LocalRef::UnsizedPlace(place) => bx.load_operand(place).deref(cx), LocalRef::Operand(..) => { - if let Some(elem) = place_ref - .projection - .iter() - .enumerate() - .find(|elem| matches!(elem.1, mir::ProjectionElem::Deref)) - { - base = elem.0 + 1; + if place_ref.ret_deref().is_some() { + base = 1; let cg_base = self.codegen_consume( bx, - mir::PlaceRef { projection: &place_ref.projection[..elem.0], ..place_ref }, + mir::PlaceRef { projection: &place_ref.projection[..0], ..place_ref }, ); cg_base.deref(bx.cx()) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 702cc48ff7bb3..2a31441ec7b6d 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1461,6 +1461,16 @@ impl<'tcx> Place<'tcx> { self.projection.iter().any(|elem| elem.is_indirect()) } + /// If MirPhase >= Derefered and if projection contains Deref, + /// It's guaranteed to be in the first place + pub fn ret_deref(&self) -> Option> { + if !self.projection.is_empty() && self.projection[0] == PlaceElem::Deref { + return Some(self.projection[0]); + } else { + None + } + } + /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or /// a single deref of a local. #[inline(always)] @@ -1533,6 +1543,16 @@ impl<'tcx> PlaceRef<'tcx> { } } + /// If MirPhase >= Derefered and if projection contains Deref, + /// It's guaranteed to be in the first place + pub fn ret_deref(&self) -> Option> { + if !self.projection.is_empty() && self.projection[0] == PlaceElem::Deref { + return Some(self.projection[0]); + } else { + None + } + } + /// If this place represents a local variable like `_X` with no /// projections, return `Some(_X)`. #[inline] diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs index b91ae083cf594..b0cbcff600c59 100644 --- a/compiler/rustc_mir_transform/src/add_retag.rs +++ b/compiler/rustc_mir_transform/src/add_retag.rs @@ -15,22 +15,13 @@ pub struct AddRetag; /// (Concurrent accesses by other threads are no problem as these are anyway non-atomic /// copies. Data races are UB.) fn is_stable(place: PlaceRef<'_>) -> bool { - place.projection.iter().all(|elem| { - match elem { - // Which place this evaluates to can change with any memory write, - // so cannot assume this to be stable. - ProjectionElem::Deref => false, - // Array indices are interesting, but MIR building generates a *fresh* - // temporary for every array access, so the index cannot be changed as - // a side-effect. - ProjectionElem::Index { .. } | - // The rest is completely boring, they just offset by a constant. - ProjectionElem::Field { .. } | - ProjectionElem::ConstantIndex { .. } | - ProjectionElem::Subslice { .. } | - ProjectionElem::Downcast { .. } => true, - } - }) + if place.ret_deref().is_some() { + // Which place this evaluates to can change with any memory write, + // so cannot assume deref to be stable. + return false; + } else { + return true; + } } /// Determine whether this type may contain a reference (or box), and thus needs retagging. @@ -91,10 +82,8 @@ impl<'tcx> MirPass<'tcx> for AddRetag { }; let place_base_raw = |place: &Place<'tcx>| { // If this is a `Deref`, get the type of what we are deref'ing. - let deref_base = - place.projection.iter().rposition(|p| matches!(p, ProjectionElem::Deref)); - if let Some(deref_base) = deref_base { - let base_proj = &place.projection[..deref_base]; + if place.ret_deref().is_some() { + let base_proj = &place.projection[..0]; let ty = Place::ty_from(place.local, base_proj, &*local_decls, tcx).ty; ty.is_unsafe_ptr() } else { From c3e1e7a947e65f16b35cbd4af9607fc670474542 Mon Sep 17 00:00:00 2001 From: ouz-a Date: Mon, 16 May 2022 16:23:42 +0300 Subject: [PATCH 07/19] simplify more, ret_deref -> has_deref --- compiler/rustc_codegen_ssa/src/mir/place.rs | 3 +-- compiler/rustc_middle/src/mir/mod.rs | 12 ++++++------ compiler/rustc_mir_transform/src/add_retag.rs | 5 ++--- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 38e09f539ded1..268c4d7650305 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -435,13 +435,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { LocalRef::Place(place) => place, LocalRef::UnsizedPlace(place) => bx.load_operand(place).deref(cx), LocalRef::Operand(..) => { - if place_ref.ret_deref().is_some() { + if place_ref.has_deref() { base = 1; let cg_base = self.codegen_consume( bx, mir::PlaceRef { projection: &place_ref.projection[..0], ..place_ref }, ); - cg_base.deref(bx.cx()) } else { bug!("using operand local {:?} as place", place_ref); diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 2a31441ec7b6d..e2084a12cbe6b 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1463,11 +1463,11 @@ impl<'tcx> Place<'tcx> { /// If MirPhase >= Derefered and if projection contains Deref, /// It's guaranteed to be in the first place - pub fn ret_deref(&self) -> Option> { + pub fn has_deref(&self) -> bool { if !self.projection.is_empty() && self.projection[0] == PlaceElem::Deref { - return Some(self.projection[0]); + true } else { - None + false } } @@ -1545,11 +1545,11 @@ impl<'tcx> PlaceRef<'tcx> { /// If MirPhase >= Derefered and if projection contains Deref, /// It's guaranteed to be in the first place - pub fn ret_deref(&self) -> Option> { + pub fn has_deref(&self) -> bool { if !self.projection.is_empty() && self.projection[0] == PlaceElem::Deref { - return Some(self.projection[0]); + true } else { - None + false } } diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs index b0cbcff600c59..c91b3044c4fdf 100644 --- a/compiler/rustc_mir_transform/src/add_retag.rs +++ b/compiler/rustc_mir_transform/src/add_retag.rs @@ -15,7 +15,7 @@ pub struct AddRetag; /// (Concurrent accesses by other threads are no problem as these are anyway non-atomic /// copies. Data races are UB.) fn is_stable(place: PlaceRef<'_>) -> bool { - if place.ret_deref().is_some() { + if place.has_deref() { // Which place this evaluates to can change with any memory write, // so cannot assume deref to be stable. return false; @@ -83,8 +83,7 @@ impl<'tcx> MirPass<'tcx> for AddRetag { let place_base_raw = |place: &Place<'tcx>| { // If this is a `Deref`, get the type of what we are deref'ing. if place.ret_deref().is_some() { - let base_proj = &place.projection[..0]; - let ty = Place::ty_from(place.local, base_proj, &*local_decls, tcx).ty; + let ty = place.ty(local_decls, tcx).ty; ty.is_unsafe_ptr() } else { // Not a deref, and thus not raw. From 447aaceed717a516bb9f4b295d582f5e2594b83b Mon Sep 17 00:00:00 2001 From: ouz-a Date: Mon, 16 May 2022 16:36:33 +0300 Subject: [PATCH 08/19] has_deref: simpler comparison, ty fix --- compiler/rustc_middle/src/mir/mod.rs | 12 ++---------- compiler/rustc_mir_transform/src/add_retag.rs | 14 +++++--------- 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index e2084a12cbe6b..a8408cfe57019 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1464,11 +1464,7 @@ impl<'tcx> Place<'tcx> { /// If MirPhase >= Derefered and if projection contains Deref, /// It's guaranteed to be in the first place pub fn has_deref(&self) -> bool { - if !self.projection.is_empty() && self.projection[0] == PlaceElem::Deref { - true - } else { - false - } + self.projection.first() == Some(&PlaceElem::Deref) } /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or @@ -1546,11 +1542,7 @@ impl<'tcx> PlaceRef<'tcx> { /// If MirPhase >= Derefered and if projection contains Deref, /// It's guaranteed to be in the first place pub fn has_deref(&self) -> bool { - if !self.projection.is_empty() && self.projection[0] == PlaceElem::Deref { - true - } else { - false - } + self.projection.first() == Some(&PlaceElem::Deref) } /// If this place represents a local variable like `_X` with no diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs index c91b3044c4fdf..9c5896c4e4aed 100644 --- a/compiler/rustc_mir_transform/src/add_retag.rs +++ b/compiler/rustc_mir_transform/src/add_retag.rs @@ -15,13 +15,9 @@ pub struct AddRetag; /// (Concurrent accesses by other threads are no problem as these are anyway non-atomic /// copies. Data races are UB.) fn is_stable(place: PlaceRef<'_>) -> bool { - if place.has_deref() { - // Which place this evaluates to can change with any memory write, - // so cannot assume deref to be stable. - return false; - } else { - return true; - } + // Which place this evaluates to can change with any memory write, + // so cannot assume deref to be stable. + !place.has_deref() } /// Determine whether this type may contain a reference (or box), and thus needs retagging. @@ -82,8 +78,8 @@ impl<'tcx> MirPass<'tcx> for AddRetag { }; let place_base_raw = |place: &Place<'tcx>| { // If this is a `Deref`, get the type of what we are deref'ing. - if place.ret_deref().is_some() { - let ty = place.ty(local_decls, tcx).ty; + if place.has_deref() { + let ty = &local_decls[place.local].ty; ty.is_unsafe_ptr() } else { // Not a deref, and thus not raw. From 9f00d836af0a02110a0a47f4d4c7c7182f04574f Mon Sep 17 00:00:00 2001 From: ouz-a Date: Sun, 24 Jul 2022 13:26:20 +0300 Subject: [PATCH 09/19] make sure has_deref is correct --- compiler/rustc_middle/src/mir/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index a8408cfe57019..f7311ebdabfd9 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1464,6 +1464,8 @@ impl<'tcx> Place<'tcx> { /// If MirPhase >= Derefered and if projection contains Deref, /// It's guaranteed to be in the first place pub fn has_deref(&self) -> bool { + // To make sure this is not accidently used in wrong mir phase + debug_assert!(!self.projection[1..].contains(&PlaceElem::Deref)); self.projection.first() == Some(&PlaceElem::Deref) } From 9fc5463c18af25b880b1ca476ae05bcba87140e6 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Wed, 29 Dec 2021 14:07:54 +0800 Subject: [PATCH 10/19] 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 11/19] 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 12/19] 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 13/19] 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 63e74aba813d2e24ffa094d05c2545b5e882229f Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 24 Jul 2022 20:36:22 -0700 Subject: [PATCH 14/19] Expose size_hint() for TokenStream's iterator --- library/proc_macro/src/lib.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 08b45ac11a14c..8e478cd7bc8a2 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -382,6 +382,14 @@ pub mod token_stream { bridge::TokenTree::Literal(tt) => TokenTree::Literal(Literal(tt)), }) } + + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } + + fn count(self) -> usize { + self.0.count() + } } #[stable(feature = "proc_macro_lib2", since = "1.29.0")] From 0c6c69f2e2106c7717275260e5bfc4712c640cc3 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 25 Jul 2022 13:11:07 +0200 Subject: [PATCH 15/19] `Inherited` always has `TypeckResults` available --- compiler/rustc_typeck/src/check/inherited.rs | 9 +++--- compiler/rustc_typeck/src/check/mod.rs | 29 +------------------- 2 files changed, 5 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs index 2f841fc277ded..a499179b95f10 100644 --- a/compiler/rustc_typeck/src/check/inherited.rs +++ b/compiler/rustc_typeck/src/check/inherited.rs @@ -1,5 +1,4 @@ use super::callee::DeferredCallResolution; -use super::MaybeInProgressTables; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; @@ -29,7 +28,7 @@ use std::ops::Deref; pub struct Inherited<'a, 'tcx> { pub(super) infcx: InferCtxt<'a, 'tcx>, - pub(super) typeck_results: super::MaybeInProgressTables<'a, 'tcx>, + pub(super) typeck_results: &'a RefCell>, pub(super) locals: RefCell>>, @@ -110,11 +109,11 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> { let tcx = infcx.tcx; let item_id = tcx.hir().local_def_id_to_hir_id(def_id); let body_id = tcx.hir().maybe_body_owned_by(item_id); + let typeck_results = + infcx.in_progress_typeck_results.expect("building `FnCtxt` without typeck results"); Inherited { - typeck_results: MaybeInProgressTables { - maybe_typeck_results: infcx.in_progress_typeck_results, - }, + typeck_results, infcx, fulfillment_cx: RefCell::new(>::new(tcx)), locals: RefCell::new(Default::default()), diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index b088fc9eddb85..17c2e4868aac7 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -128,8 +128,7 @@ use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits; use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error; use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor; - -use std::cell::{Ref, RefCell, RefMut}; +use std::cell::RefCell; use crate::require_c_abi_if_c_variadic; use crate::util::common::indenter; @@ -900,32 +899,6 @@ enum TupleArgumentsFlag { TupleArguments, } -/// A wrapper for `InferCtxt`'s `in_progress_typeck_results` field. -#[derive(Copy, Clone)] -struct MaybeInProgressTables<'a, 'tcx> { - maybe_typeck_results: Option<&'a RefCell>>, -} - -impl<'a, 'tcx> MaybeInProgressTables<'a, 'tcx> { - fn borrow(self) -> Ref<'a, ty::TypeckResults<'tcx>> { - match self.maybe_typeck_results { - Some(typeck_results) => typeck_results.borrow(), - None => bug!( - "MaybeInProgressTables: inh/fcx.typeck_results.borrow() with no typeck results" - ), - } - } - - fn borrow_mut(self) -> RefMut<'a, ty::TypeckResults<'tcx>> { - match self.maybe_typeck_results { - Some(typeck_results) => typeck_results.borrow_mut(), - None => bug!( - "MaybeInProgressTables: inh/fcx.typeck_results.borrow_mut() with no typeck results" - ), - } - } -} - fn typeck_item_bodies(tcx: TyCtxt<'_>, (): ()) { tcx.hir().par_body_owners(|body_owner_def_id| tcx.ensure().typeck(body_owner_def_id)); } From 202e32a2cadda874a908c148f9e7674f81858612 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 25 Jul 2022 14:19:26 +0200 Subject: [PATCH 16/19] Fix sidebar background-color on mobile --- src/librustdoc/html/static/css/rustdoc.css | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 70b7a47bcd58b..025157713498e 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1855,7 +1855,6 @@ in storage.js plus the media query with (min-width: 701px) the sidebar stays visible for screen readers, which is useful for navigation. */ left: -1000px; margin-left: 0; - background-color: rgba(0,0,0,0); margin: 0; padding: 0; z-index: 11; From 8db7249f26ef4265ae58bb77d8f3559b723134c9 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 25 Jul 2022 14:35:06 +0200 Subject: [PATCH 17/19] Add GUI test to prevent sidebar background regression --- src/test/rustdoc-gui/sidebar-mobile.goml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/test/rustdoc-gui/sidebar-mobile.goml b/src/test/rustdoc-gui/sidebar-mobile.goml index 79f18db8fc7cd..033c65783498f 100644 --- a/src/test/rustdoc-gui/sidebar-mobile.goml +++ b/src/test/rustdoc-gui/sidebar-mobile.goml @@ -40,3 +40,25 @@ assert-position: ("#method\.must_use", {"y": 45}) click: ".sidebar-menu-toggle" scroll-to: ".block.keyword li:nth-child(1)" compare-elements-position-near: (".block.keyword li:nth-child(1)", ".mobile-topbar", {"y": 543}) + +// Now checking the background color of the sidebar. +local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "dark"} +reload: + +// Open the sidebar menu. +click: ".sidebar-menu-toggle" +assert-css: (".sidebar", {"background-color": "rgb(80, 80, 80)"}) + +local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "ayu"} +reload: + +// Open the sidebar menu. +click: ".sidebar-menu-toggle" +assert-css: (".sidebar", {"background-color": "rgb(20, 25, 31)"}) + +local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "light"} +reload: + +// Open the sidebar menu. +click: ".sidebar-menu-toggle" +assert-css: (".sidebar", {"background-color": "rgb(245, 245, 245)"}) From 68b433a089deff105063feaad598a1635615eb1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?A=C3=AFssata?= Date: Tue, 12 Jul 2022 12:17:58 +0000 Subject: [PATCH 18/19] Lighten up const_prop_lint, reusing const_prop --- .../rustc_mir_transform/src/const_prop.rs | 12 +- .../src/const_prop_lint.rs | 229 +----------------- 2 files changed, 19 insertions(+), 222 deletions(-) diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index f6484a9b54d3c..a756f1d8f408c 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -155,18 +155,18 @@ impl<'tcx> MirPass<'tcx> for ConstProp { } } -struct ConstPropMachine<'mir, 'tcx> { +pub struct ConstPropMachine<'mir, 'tcx> { /// The virtual call stack. stack: Vec>, /// `OnlyInsideOwnBlock` locals that were written in the current block get erased at the end. - written_only_inside_own_block_locals: FxHashSet, + pub written_only_inside_own_block_locals: FxHashSet, /// Locals that need to be cleared after every block terminates. - only_propagate_inside_block_locals: BitSet, - can_const_prop: IndexVec, + pub only_propagate_inside_block_locals: BitSet, + pub can_const_prop: IndexVec, } impl ConstPropMachine<'_, '_> { - fn new( + pub fn new( only_propagate_inside_block_locals: BitSet, can_const_prop: IndexVec, ) -> Self { @@ -816,7 +816,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { /// The mode that `ConstProp` is allowed to run in for a given `Local`. #[derive(Clone, Copy, Debug, PartialEq)] -enum ConstPropMode { +pub enum ConstPropMode { /// The `Local` can be propagated into and reads of this `Local` can also be propagated. FullConstProp, /// The `Local` can only be propagated into and from its own block. diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index 97b1433f5d27a..61aee011005b7 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -1,19 +1,23 @@ //! Propagates constants for early reporting of statically known //! assertion failures -use std::cell::Cell; - -use rustc_ast::Mutability; -use rustc_data_structures::fx::FxHashSet; +use crate::const_prop::ConstPropMachine; +use crate::const_prop::ConstPropMode; +use crate::MirLint; +use rustc_const_eval::const_eval::ConstEvalErr; +use rustc_const_eval::interpret::{ + self, InterpCx, InterpResult, LocalState, LocalValue, MemoryKind, OpTy, Scalar, + ScalarMaybeUninit, StackPopCleanup, +}; use rustc_hir::def::DefKind; use rustc_hir::HirId; use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::{ - AssertKind, BasicBlock, BinOp, Body, Constant, ConstantKind, Local, LocalDecl, LocalKind, - Location, Operand, Place, Rvalue, SourceInfo, SourceScope, SourceScopeData, Statement, - StatementKind, Terminator, TerminatorKind, UnOp, RETURN_PLACE, + AssertKind, BinOp, Body, Constant, ConstantKind, Local, LocalDecl, LocalKind, Location, + Operand, Place, Rvalue, SourceInfo, SourceScope, SourceScopeData, Statement, StatementKind, + Terminator, TerminatorKind, UnOp, RETURN_PLACE, }; use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout}; use rustc_middle::ty::subst::{InternalSubsts, Subst}; @@ -22,42 +26,15 @@ use rustc_middle::ty::{ TypeVisitable, }; use rustc_session::lint; -use rustc_span::{def_id::DefId, Span}; +use rustc_span::Span; use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout}; -use rustc_target::spec::abi::Abi as CallAbi; use rustc_trait_selection::traits; - -use crate::MirLint; -use rustc_const_eval::const_eval::ConstEvalErr; -use rustc_const_eval::interpret::{ - self, compile_time_machine, AllocId, ConstAllocation, Frame, ImmTy, InterpCx, InterpResult, - LocalState, LocalValue, MemoryKind, OpTy, PlaceTy, Pointer, Scalar, ScalarMaybeUninit, - StackPopCleanup, StackPopUnwind, -}; +use std::cell::Cell; /// The maximum number of bytes that we'll allocate space for a local or the return value. /// Needed for #66397, because otherwise we eval into large places and that can cause OOM or just /// Severely regress performance. const MAX_ALLOC_LIMIT: u64 = 1024; - -/// Macro for machine-specific `InterpError` without allocation. -/// (These will never be shown to the user, but they help diagnose ICEs.) -macro_rules! throw_machine_stop_str { - ($($tt:tt)*) => {{ - // We make a new local type for it. The type itself does not carry any information, - // but its vtable (for the `MachineStopType` trait) does. - struct Zst; - // Printing this type shows the desired string. - impl std::fmt::Display for Zst { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, $($tt)*) - } - } - impl rustc_middle::mir::interpret::MachineStopType for Zst {} - throw_machine_stop!(Zst) - }}; -} - pub struct ConstProp; impl<'tcx> MirLint<'tcx> for ConstProp { @@ -151,172 +128,6 @@ impl<'tcx> MirLint<'tcx> for ConstProp { } } -struct ConstPropMachine<'mir, 'tcx> { - /// The virtual call stack. - stack: Vec>, - /// `OnlyInsideOwnBlock` locals that were written in the current block get erased at the end. - written_only_inside_own_block_locals: FxHashSet, - /// Locals that need to be cleared after every block terminates. - only_propagate_inside_block_locals: BitSet, - can_const_prop: IndexVec, -} - -impl ConstPropMachine<'_, '_> { - fn new( - only_propagate_inside_block_locals: BitSet, - can_const_prop: IndexVec, - ) -> Self { - Self { - stack: Vec::new(), - written_only_inside_own_block_locals: Default::default(), - only_propagate_inside_block_locals, - can_const_prop, - } - } -} - -impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> { - compile_time_machine!(<'mir, 'tcx>); - const PANIC_ON_ALLOC_FAIL: bool = true; // all allocations are small (see `MAX_ALLOC_LIMIT`) - - type MemoryKind = !; - - fn load_mir( - _ecx: &InterpCx<'mir, 'tcx, Self>, - _instance: ty::InstanceDef<'tcx>, - ) -> InterpResult<'tcx, &'tcx Body<'tcx>> { - throw_machine_stop_str!("calling functions isn't supported in ConstProp") - } - - fn find_mir_or_eval_fn( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _instance: ty::Instance<'tcx>, - _abi: CallAbi, - _args: &[OpTy<'tcx>], - _destination: &PlaceTy<'tcx>, - _target: Option, - _unwind: StackPopUnwind, - ) -> InterpResult<'tcx, Option<(&'mir Body<'tcx>, ty::Instance<'tcx>)>> { - Ok(None) - } - - fn call_intrinsic( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _instance: ty::Instance<'tcx>, - _args: &[OpTy<'tcx>], - _destination: &PlaceTy<'tcx>, - _target: Option, - _unwind: StackPopUnwind, - ) -> InterpResult<'tcx> { - throw_machine_stop_str!("calling intrinsics isn't supported in ConstProp") - } - - fn assert_panic( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _msg: &rustc_middle::mir::AssertMessage<'tcx>, - _unwind: Option, - ) -> InterpResult<'tcx> { - bug!("panics terminators are not evaluated in ConstProp") - } - - fn binary_ptr_op( - _ecx: &InterpCx<'mir, 'tcx, Self>, - _bin_op: BinOp, - _left: &ImmTy<'tcx>, - _right: &ImmTy<'tcx>, - ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { - // We can't do this because aliasing of memory can differ between const eval and llvm - throw_machine_stop_str!("pointer arithmetic or comparisons aren't supported in ConstProp") - } - - fn access_local<'a>( - frame: &'a Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>, - local: Local, - ) -> InterpResult<'tcx, &'a interpret::Operand> { - let l = &frame.locals[local]; - - if matches!( - l.value, - LocalValue::Live(interpret::Operand::Immediate(interpret::Immediate::Uninit)) - ) { - // For us "uninit" means "we don't know its value, might be initiailized or not". - // So stop here. - throw_machine_stop_str!("tried to access a local with unknown value") - } - - l.access() - } - - fn access_local_mut<'a>( - ecx: &'a mut InterpCx<'mir, 'tcx, Self>, - frame: usize, - local: Local, - ) -> InterpResult<'tcx, &'a mut interpret::Operand> { - if ecx.machine.can_const_prop[local] == ConstPropMode::NoPropagation { - throw_machine_stop_str!("tried to write to a local that is marked as not propagatable") - } - if frame == 0 && ecx.machine.only_propagate_inside_block_locals.contains(local) { - trace!( - "mutating local {:?} which is restricted to its block. \ - Will remove it from const-prop after block is finished.", - local - ); - ecx.machine.written_only_inside_own_block_locals.insert(local); - } - ecx.machine.stack[frame].locals[local].access_mut() - } - - fn before_access_global( - _tcx: TyCtxt<'tcx>, - _machine: &Self, - _alloc_id: AllocId, - alloc: ConstAllocation<'tcx, Self::Provenance, Self::AllocExtra>, - _static_def_id: Option, - is_write: bool, - ) -> InterpResult<'tcx> { - if is_write { - throw_machine_stop_str!("can't write to global"); - } - // If the static allocation is mutable, then we can't const prop it as its content - // might be different at runtime. - if alloc.inner().mutability == Mutability::Mut { - throw_machine_stop_str!("can't access mutable globals in ConstProp"); - } - - Ok(()) - } - - #[inline(always)] - fn expose_ptr( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _ptr: Pointer, - ) -> InterpResult<'tcx> { - throw_machine_stop_str!("exposing pointers isn't supported in ConstProp") - } - - #[inline(always)] - fn init_frame_extra( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - frame: Frame<'mir, 'tcx>, - ) -> InterpResult<'tcx, Frame<'mir, 'tcx>> { - Ok(frame) - } - - #[inline(always)] - fn stack<'a>( - ecx: &'a InterpCx<'mir, 'tcx, Self>, - ) -> &'a [Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>] { - &ecx.machine.stack - } - - #[inline(always)] - fn stack_mut<'a>( - ecx: &'a mut InterpCx<'mir, 'tcx, Self>, - ) -> &'a mut Vec> { - &mut ecx.machine.stack - } -} - /// Finds optimization opportunities on the MIR. struct ConstPropagator<'mir, 'tcx> { ecx: InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>, @@ -711,20 +522,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } } -/// The mode that `ConstProp` is allowed to run in for a given `Local`. -#[derive(Clone, Copy, Debug, PartialEq)] -enum ConstPropMode { - /// The `Local` can be propagated into and reads of this `Local` can also be propagated. - FullConstProp, - /// The `Local` can only be propagated into and from its own block. - OnlyInsideOwnBlock, - /// The `Local` can be propagated into but reads cannot be propagated. - OnlyPropagateInto, - /// The `Local` cannot be part of propagation at all. Any statement - /// referencing it either for reading or writing will not get propagated. - NoPropagation, -} - struct CanConstProp { can_const_prop: IndexVec, // False at the beginning. Once set, no more assignments are allowed to that local. From e6518296dcd9e878ac450afdfee4f4bc3fec72f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?A=C3=AFssata?= Date: Mon, 25 Jul 2022 13:54:49 +0000 Subject: [PATCH 19/19] removed CanConstProp + Visitor --- .../rustc_mir_transform/src/const_prop.rs | 4 +- .../src/const_prop_lint.rs | 128 +----------------- 2 files changed, 7 insertions(+), 125 deletions(-) diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index a756f1d8f408c..85ad6b8f2feff 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -828,7 +828,7 @@ pub enum ConstPropMode { NoPropagation, } -struct CanConstProp { +pub struct CanConstProp { can_const_prop: IndexVec, // False at the beginning. Once set, no more assignments are allowed to that local. found_assignment: BitSet, @@ -838,7 +838,7 @@ struct CanConstProp { impl CanConstProp { /// Returns true if `local` can be propagated - fn check<'tcx>( + pub fn check<'tcx>( tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, body: &Body<'tcx>, diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index 61aee011005b7..3ae6a88a140ea 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -1,6 +1,7 @@ //! Propagates constants for early reporting of statically known //! assertion failures +use crate::const_prop::CanConstProp; use crate::const_prop::ConstPropMachine; use crate::const_prop::ConstPropMode; use crate::MirLint; @@ -13,11 +14,11 @@ use rustc_hir::def::DefKind; use rustc_hir::HirId; use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; -use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; +use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::{ - AssertKind, BinOp, Body, Constant, ConstantKind, Local, LocalDecl, LocalKind, Location, - Operand, Place, Rvalue, SourceInfo, SourceScope, SourceScopeData, Statement, StatementKind, - Terminator, TerminatorKind, UnOp, RETURN_PLACE, + AssertKind, BinOp, Body, Constant, ConstantKind, Local, LocalDecl, Location, Operand, Place, + Rvalue, SourceInfo, SourceScope, SourceScopeData, Statement, StatementKind, Terminator, + TerminatorKind, UnOp, RETURN_PLACE, }; use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout}; use rustc_middle::ty::subst::{InternalSubsts, Subst}; @@ -522,125 +523,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } } -struct CanConstProp { - can_const_prop: IndexVec, - // False at the beginning. Once set, no more assignments are allowed to that local. - found_assignment: BitSet, - // Cache of locals' information - local_kinds: IndexVec, -} - -impl CanConstProp { - /// Returns true if `local` can be propagated - fn check<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, - body: &Body<'tcx>, - ) -> IndexVec { - let mut cpv = CanConstProp { - can_const_prop: IndexVec::from_elem(ConstPropMode::FullConstProp, &body.local_decls), - found_assignment: BitSet::new_empty(body.local_decls.len()), - local_kinds: IndexVec::from_fn_n( - |local| body.local_kind(local), - body.local_decls.len(), - ), - }; - for (local, val) in cpv.can_const_prop.iter_enumerated_mut() { - let ty = body.local_decls[local].ty; - match tcx.layout_of(param_env.and(ty)) { - Ok(layout) if layout.size < Size::from_bytes(MAX_ALLOC_LIMIT) => {} - // Either the layout fails to compute, then we can't use this local anyway - // or the local is too large, then we don't want to. - _ => { - *val = ConstPropMode::NoPropagation; - continue; - } - } - // Cannot use args at all - // Cannot use locals because if x < y { y - x } else { x - y } would - // lint for x != y - // FIXME(oli-obk): lint variables until they are used in a condition - // FIXME(oli-obk): lint if return value is constant - if cpv.local_kinds[local] == LocalKind::Arg { - *val = ConstPropMode::OnlyPropagateInto; - trace!( - "local {:?} can't be const propagated because it's a function argument", - local - ); - } else if cpv.local_kinds[local] == LocalKind::Var { - *val = ConstPropMode::OnlyInsideOwnBlock; - trace!( - "local {:?} will only be propagated inside its block, because it's a user variable", - local - ); - } - } - cpv.visit_body(&body); - cpv.can_const_prop - } -} - -impl Visitor<'_> for CanConstProp { - fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) { - use rustc_middle::mir::visit::PlaceContext::*; - match context { - // Projections are fine, because `&mut foo.x` will be caught by - // `MutatingUseContext::Borrow` elsewhere. - MutatingUse(MutatingUseContext::Projection) - // These are just stores, where the storing is not propagatable, but there may be later - // mutations of the same local via `Store` - | MutatingUse(MutatingUseContext::Call) - | MutatingUse(MutatingUseContext::AsmOutput) - | MutatingUse(MutatingUseContext::Deinit) - // Actual store that can possibly even propagate a value - | MutatingUse(MutatingUseContext::SetDiscriminant) - | MutatingUse(MutatingUseContext::Store) => { - if !self.found_assignment.insert(local) { - match &mut self.can_const_prop[local] { - // If the local can only get propagated in its own block, then we don't have - // to worry about multiple assignments, as we'll nuke the const state at the - // end of the block anyway, and inside the block we overwrite previous - // states as applicable. - ConstPropMode::OnlyInsideOwnBlock => {} - ConstPropMode::NoPropagation => {} - ConstPropMode::OnlyPropagateInto => {} - other @ ConstPropMode::FullConstProp => { - trace!( - "local {:?} can't be propagated because of multiple assignments. Previous state: {:?}", - local, other, - ); - *other = ConstPropMode::OnlyInsideOwnBlock; - } - } - } - } - // Reading constants is allowed an arbitrary number of times - NonMutatingUse(NonMutatingUseContext::Copy) - | NonMutatingUse(NonMutatingUseContext::Move) - | NonMutatingUse(NonMutatingUseContext::Inspect) - | NonMutatingUse(NonMutatingUseContext::Projection) - | NonUse(_) => {} - - // These could be propagated with a smarter analysis or just some careful thinking about - // whether they'd be fine right now. - MutatingUse(MutatingUseContext::Yield) - | MutatingUse(MutatingUseContext::Drop) - | MutatingUse(MutatingUseContext::Retag) - // These can't ever be propagated under any scheme, as we can't reason about indirect - // mutation. - | NonMutatingUse(NonMutatingUseContext::SharedBorrow) - | NonMutatingUse(NonMutatingUseContext::ShallowBorrow) - | NonMutatingUse(NonMutatingUseContext::UniqueBorrow) - | NonMutatingUse(NonMutatingUseContext::AddressOf) - | MutatingUse(MutatingUseContext::Borrow) - | MutatingUse(MutatingUseContext::AddressOf) => { - trace!("local {:?} can't be propagaged because it's used: {:?}", local, context); - self.can_const_prop[local] = ConstPropMode::NoPropagation; - } - } - } -} - impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { fn visit_body(&mut self, body: &Body<'tcx>) { for (bb, data) in body.basic_blocks().iter_enumerated() {