From 361fd7e72f2ebc30162afdd881fa77ff6eb3adc3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 17 Feb 2024 09:14:45 +0100 Subject: [PATCH 01/17] intrinsics::simd: add missing functions --- library/core/src/intrinsics/simd.rs | 103 ++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs index ef4c65639eb4d..3d027e1fca04d 100644 --- a/library/core/src/intrinsics/simd.rs +++ b/library/core/src/intrinsics/simd.rs @@ -3,6 +3,24 @@ //! In this module, a "vector" is any `repr(simd)` type. extern "platform-intrinsic" { + /// Insert an element into a vector, returning the updated vector. + /// + /// `T` must be a vector with element type `U`. + /// + /// # Safety + /// + /// `idx` must be in-bounds of the vector. + pub fn simd_insert(x: T, idx: u32, val: U) -> T; + + /// Extract an element from a vector. + /// + /// `T` must be a vector with element type `U`. + /// + /// # Safety + /// + /// `idx` must be in-bounds of the vector. + pub fn simd_extract(x: T, idx: u32) -> U; + /// Add two simd vectors elementwise. /// /// `T` must be a vector of integer or floating point primitive types. @@ -315,6 +333,18 @@ extern "platform-intrinsic" { /// Starting with the value `y`, add the elements of `x` and accumulate. pub fn simd_reduce_add_ordered(x: T, y: U) -> U; + /// Add elements within a vector in arbitrary order, and without regard + /// for signed zeros. + /// + /// `T` must be a vector of integer or floating-point primitive types. + /// + /// `U` must be the element type of `T`. + /// + /// # Safety + /// + /// All input elements must be finite (i.e., not NAN and not +/- INF). + pub fn simd_reduce_add_unordered(x: T) -> U; + /// Multiply elements within a vector from left to right. /// /// `T` must be a vector of integer or floating-point primitive types. @@ -324,6 +354,18 @@ extern "platform-intrinsic" { /// Starting with the value `y`, multiply the elements of `x` and accumulate. pub fn simd_reduce_mul_ordered(x: T, y: U) -> U; + /// Multiply elements within a vector in arbitrary order, and without regard + /// for signed zeros. + /// + /// `T` must be a vector of integer or floating-point primitive types. + /// + /// `U` must be the element type of `T`. + /// + /// # Safety + /// + /// All input elements must be finite (i.e., not NAN and not +/- INF). + pub fn simd_reduce_mul_unordered(x: T) -> U; + /// Check if all mask values are true. /// /// `T` must be a vector of integer primitive types. @@ -349,6 +391,19 @@ extern "platform-intrinsic" { /// For floating-point values, uses IEEE-754 `maxNum`. pub fn simd_reduce_max(x: T) -> U; + /// Return the maximum element of a vector. + /// + /// `T` must be a vector of integer or floating-point primitive types. + /// + /// `U` must be the element type of `T`. + /// + /// For floating-point values, uses IEEE-754 `maxNum`. + /// + /// # Safety + /// + /// All input elements must be finite (i.e., not NAN and not +/- INF). + pub fn simd_reduce_max_nanless(x: T) -> U; + /// Return the minimum element of a vector. /// /// `T` must be a vector of integer or floating-point primitive types. @@ -358,6 +413,19 @@ extern "platform-intrinsic" { /// For floating-point values, uses IEEE-754 `minNum`. pub fn simd_reduce_min(x: T) -> U; + /// Return the minimum element of a vector. + /// + /// `T` must be a vector of integer or floating-point primitive types. + /// + /// `U` must be the element type of `T`. + /// + /// For floating-point values, uses IEEE-754 `minNum`. + /// + /// # Safety + /// + /// All input elements must be finite (i.e., not NAN and not +/- INF). + pub fn simd_reduce_min_nanless(x: T) -> U; + /// Logical "and" all elements together. /// /// `T` must be a vector of integer or floating-point primitive types. @@ -516,4 +584,39 @@ extern "platform-intrinsic" { /// /// `T` must be a vector of floats. pub fn simd_fma(x: T, y: T, z: T) -> T; + + // Computes the sine of each element. + /// + /// `T` must be a vector of floats. + pub fn simd_fsin(a: T) -> T; + + // Computes the cosine of each element. + /// + /// `T` must be a vector of floats. + pub fn simd_fcos(a: T) -> T; + + // Computes the exponential function of each element. + /// + /// `T` must be a vector of floats. + pub fn simd_fexp(a: T) -> T; + + // Computes 2 raised to the power of each element. + /// + /// `T` must be a vector of floats. + pub fn simd_fexp2(a: T) -> T; + + // Computes the base 10 logarithm of each element. + /// + /// `T` must be a vector of floats. + pub fn simd_flog10(a: T) -> T; + + // Computes the base 2 logarithm of each element. + /// + /// `T` must be a vector of floats. + pub fn simd_flog2(a: T) -> T; + + // Computes the natural logarithm of each element. + /// + /// `T` must be a vector of floats. + pub fn simd_flog(a: T) -> T; } From f12d248a6abeef2a1f8dc28f09344c8cba13d663 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sat, 17 Feb 2024 01:45:15 +0100 Subject: [PATCH 02/17] Implement `NonZero` traits generically. --- library/core/src/num/nonzero.rs | 390 ++++++++++-------- tests/ui/did_you_mean/bad-assoc-ty.stderr | 9 +- tests/ui/fmt/ifmt-unimpl.stderr | 2 +- tests/ui/traits/issue-77982.stderr | 1 - tests/ui/try-trait/bad-interconversion.stderr | 1 - 5 files changed, 220 insertions(+), 183 deletions(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index fe2873261751d..8943e2f0e2ab5 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -81,6 +81,217 @@ impl_zeroable_primitive!(isize); #[rustc_diagnostic_item = "NonZero"] pub struct NonZero(T); +macro_rules! impl_nonzero_fmt { + ($Trait:ident) => { + #[stable(feature = "nonzero", since = "1.28.0")] + impl fmt::$Trait for NonZero + where + T: ZeroablePrimitive + fmt::$Trait, + { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.get().fmt(f) + } + } + }; +} + +impl_nonzero_fmt!(Debug); +impl_nonzero_fmt!(Display); +impl_nonzero_fmt!(Binary); +impl_nonzero_fmt!(Octal); +impl_nonzero_fmt!(LowerHex); +impl_nonzero_fmt!(UpperHex); + +#[stable(feature = "nonzero", since = "1.28.0")] +impl Clone for NonZero +where + T: ZeroablePrimitive, +{ + #[inline] + fn clone(&self) -> Self { + // SAFETY: The contained value is non-zero. + unsafe { Self(self.0) } + } +} + +#[stable(feature = "nonzero", since = "1.28.0")] +impl Copy for NonZero where T: ZeroablePrimitive {} + +#[stable(feature = "nonzero", since = "1.28.0")] +impl PartialEq for NonZero +where + T: ZeroablePrimitive + PartialEq, +{ + #[inline] + fn eq(&self, other: &Self) -> bool { + self.get() == other.get() + } + + #[inline] + fn ne(&self, other: &Self) -> bool { + self.get() != other.get() + } +} + +#[unstable(feature = "structural_match", issue = "31434")] +impl StructuralPartialEq for NonZero where T: ZeroablePrimitive + StructuralPartialEq {} + +#[stable(feature = "nonzero", since = "1.28.0")] +impl Eq for NonZero where T: ZeroablePrimitive + Eq {} + +#[stable(feature = "nonzero", since = "1.28.0")] +impl PartialOrd for NonZero +where + T: ZeroablePrimitive + PartialOrd, +{ + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + self.get().partial_cmp(&other.get()) + } + + #[inline] + fn lt(&self, other: &Self) -> bool { + self.get() < other.get() + } + + #[inline] + fn le(&self, other: &Self) -> bool { + self.get() <= other.get() + } + + #[inline] + fn gt(&self, other: &Self) -> bool { + self.get() > other.get() + } + + #[inline] + fn ge(&self, other: &Self) -> bool { + self.get() >= other.get() + } +} + +#[stable(feature = "nonzero", since = "1.28.0")] +impl Ord for NonZero +where + T: ZeroablePrimitive + Ord, +{ + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + self.get().cmp(&other.get()) + } + + #[inline] + fn max(self, other: Self) -> Self { + // SAFETY: The maximum of two non-zero values is still non-zero. + unsafe { Self(self.get().max(other.get())) } + } + + #[inline] + fn min(self, other: Self) -> Self { + // SAFETY: The minimum of two non-zero values is still non-zero. + unsafe { Self(self.get().min(other.get())) } + } + + #[inline] + fn clamp(self, min: Self, max: Self) -> Self { + // SAFETY: A non-zero value clamped between two non-zero values is still non-zero. + unsafe { Self(self.get().clamp(min.get(), max.get())) } + } +} + +#[stable(feature = "nonzero", since = "1.28.0")] +impl Hash for NonZero +where + T: ZeroablePrimitive + Hash, +{ + #[inline] + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.get().hash(state) + } +} + +#[stable(feature = "from_nonzero", since = "1.31.0")] +impl From> for T +where + T: ZeroablePrimitive, +{ + #[inline] + fn from(nonzero: NonZero) -> Self { + // Call `get` method to keep range information. + nonzero.get() + } +} + +#[stable(feature = "nonzero_bitor", since = "1.45.0")] +impl BitOr for NonZero +where + T: ZeroablePrimitive + BitOr, +{ + type Output = Self; + + #[inline] + fn bitor(self, rhs: Self) -> Self::Output { + // SAFETY: Bitwise OR of two non-zero values is still non-zero. + unsafe { Self(self.get() | rhs.get()) } + } +} + +#[stable(feature = "nonzero_bitor", since = "1.45.0")] +impl BitOr for NonZero +where + T: ZeroablePrimitive + BitOr, +{ + type Output = Self; + + #[inline] + fn bitor(self, rhs: T) -> Self::Output { + // SAFETY: Bitwise OR of a non-zero value with anything is still non-zero. + unsafe { Self(self.get() | rhs) } + } +} + +#[stable(feature = "nonzero_bitor", since = "1.45.0")] +impl BitOr> for T +where + T: ZeroablePrimitive + BitOr, +{ + type Output = NonZero; + + #[inline] + fn bitor(self, rhs: NonZero) -> Self::Output { + // SAFETY: Bitwise OR of anything with a non-zero value is still non-zero. + unsafe { NonZero(self | rhs.get()) } + } +} + +#[stable(feature = "nonzero_bitor", since = "1.45.0")] +impl BitOrAssign for NonZero +where + T: ZeroablePrimitive, + Self: BitOr, +{ + #[inline] + fn bitor_assign(&mut self, rhs: Self) { + *self = *self | rhs; + } +} + +#[stable(feature = "nonzero_bitor", since = "1.45.0")] +impl BitOrAssign for NonZero +where + T: ZeroablePrimitive, + Self: BitOr, +{ + #[inline] + fn bitor_assign(&mut self, rhs: T) { + *self = *self | rhs; + } +} + impl NonZero where T: ZeroablePrimitive, @@ -183,20 +394,6 @@ where } } -macro_rules! impl_nonzero_fmt { - ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => { - $( - #[$stability] - impl fmt::$Trait for $Ty { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.get().fmt(f) - } - } - )+ - } -} - macro_rules! nonzero_integer { ( #[$stability:meta] @@ -549,171 +746,6 @@ macro_rules! nonzero_integer { } } - #[$stability] - impl Clone for $Ty { - #[inline] - fn clone(&self) -> Self { - // SAFETY: The contained value is non-zero. - unsafe { Self(self.0) } - } - } - - #[$stability] - impl Copy for $Ty {} - - #[$stability] - impl PartialEq for $Ty { - #[inline] - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } - - #[inline] - fn ne(&self, other: &Self) -> bool { - self.0 != other.0 - } - } - - #[unstable(feature = "structural_match", issue = "31434")] - impl StructuralPartialEq for $Ty {} - - #[$stability] - impl Eq for $Ty {} - - #[$stability] - impl PartialOrd for $Ty { - #[inline] - fn partial_cmp(&self, other: &Self) -> Option { - self.0.partial_cmp(&other.0) - } - - #[inline] - fn lt(&self, other: &Self) -> bool { - self.0 < other.0 - } - - #[inline] - fn le(&self, other: &Self) -> bool { - self.0 <= other.0 - } - - #[inline] - fn gt(&self, other: &Self) -> bool { - self.0 > other.0 - } - - #[inline] - fn ge(&self, other: &Self) -> bool { - self.0 >= other.0 - } - } - - #[$stability] - impl Ord for $Ty { - #[inline] - fn cmp(&self, other: &Self) -> Ordering { - self.0.cmp(&other.0) - } - - #[inline] - fn max(self, other: Self) -> Self { - // SAFETY: The maximum of two non-zero values is still non-zero. - unsafe { Self(self.0.max(other.0)) } - } - - #[inline] - fn min(self, other: Self) -> Self { - // SAFETY: The minimum of two non-zero values is still non-zero. - unsafe { Self(self.0.min(other.0)) } - } - - #[inline] - fn clamp(self, min: Self, max: Self) -> Self { - // SAFETY: A non-zero value clamped between two non-zero values is still non-zero. - unsafe { Self(self.0.clamp(min.0, max.0)) } - } - } - - #[$stability] - impl Hash for $Ty { - #[inline] - fn hash(&self, state: &mut H) - where - H: Hasher, - { - self.0.hash(state) - } - } - - #[stable(feature = "from_nonzero", since = "1.31.0")] - impl From<$Ty> for $Int { - #[doc = concat!("Converts a `", stringify!($Ty), "` into an `", stringify!($Int), "`")] - #[inline] - fn from(nonzero: $Ty) -> Self { - // Call nonzero to keep information range information - // from get method. - nonzero.get() - } - } - - #[stable(feature = "nonzero_bitor", since = "1.45.0")] - impl BitOr for $Ty { - type Output = Self; - - #[inline] - fn bitor(self, rhs: Self) -> Self::Output { - // SAFETY: since `self` and `rhs` are both nonzero, the - // result of the bitwise-or will be nonzero. - unsafe { Self::new_unchecked(self.get() | rhs.get()) } - } - } - - #[stable(feature = "nonzero_bitor", since = "1.45.0")] - impl BitOr<$Int> for $Ty { - type Output = Self; - - #[inline] - fn bitor(self, rhs: $Int) -> Self::Output { - // SAFETY: since `self` is nonzero, the result of the - // bitwise-or will be nonzero regardless of the value of - // `rhs`. - unsafe { Self::new_unchecked(self.get() | rhs) } - } - } - - #[stable(feature = "nonzero_bitor", since = "1.45.0")] - impl BitOr<$Ty> for $Int { - type Output = $Ty; - - #[inline] - fn bitor(self, rhs: $Ty) -> Self::Output { - // SAFETY: since `rhs` is nonzero, the result of the - // bitwise-or will be nonzero regardless of the value of - // `self`. - unsafe { $Ty::new_unchecked(self | rhs.get()) } - } - } - - #[stable(feature = "nonzero_bitor", since = "1.45.0")] - impl BitOrAssign for $Ty { - #[inline] - fn bitor_assign(&mut self, rhs: Self) { - *self = *self | rhs; - } - } - - #[stable(feature = "nonzero_bitor", since = "1.45.0")] - impl BitOrAssign<$Int> for $Ty { - #[inline] - fn bitor_assign(&mut self, rhs: $Int) { - *self = *self | rhs; - } - } - - impl_nonzero_fmt! { - #[$stability] (Debug, Display, Binary, Octal, LowerHex, UpperHex) for $Ty - } - #[stable(feature = "nonzero_parse", since = "1.35.0")] impl FromStr for $Ty { type Err = ParseIntError; diff --git a/tests/ui/did_you_mean/bad-assoc-ty.stderr b/tests/ui/did_you_mean/bad-assoc-ty.stderr index 4a119f673c8ee..dc93762c9b19f 100644 --- a/tests/ui/did_you_mean/bad-assoc-ty.stderr +++ b/tests/ui/did_you_mean/bad-assoc-ty.stderr @@ -191,7 +191,14 @@ error[E0223]: ambiguous associated type --> $DIR/bad-assoc-ty.rs:33:10 | LL | type H = Fn(u8) -> (u8)::Output; - | ^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(dyn Fn(u8) -> u8 + 'static) as IntoFuture>::Output` + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: use fully-qualified syntax + | +LL | type H = <(dyn Fn(u8) -> u8 + 'static) as BitOr>::Output; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | type H = <(dyn Fn(u8) -> u8 + 'static) as IntoFuture>::Output; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error[E0223]: ambiguous associated type --> $DIR/bad-assoc-ty.rs:39:19 diff --git a/tests/ui/fmt/ifmt-unimpl.stderr b/tests/ui/fmt/ifmt-unimpl.stderr index 58531c61bbe80..3c5428e59fb59 100644 --- a/tests/ui/fmt/ifmt-unimpl.stderr +++ b/tests/ui/fmt/ifmt-unimpl.stderr @@ -15,7 +15,7 @@ LL | format!("{:X}", "3"); i128 usize u8 - and 20 others + and 9 others = note: required for `&str` to implement `UpperHex` note: required by a bound in `core::fmt::rt::Argument::<'a>::new_upper_hex` --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL diff --git a/tests/ui/traits/issue-77982.stderr b/tests/ui/traits/issue-77982.stderr index bffad037fba05..5be8d2f4b325e 100644 --- a/tests/ui/traits/issue-77982.stderr +++ b/tests/ui/traits/issue-77982.stderr @@ -46,7 +46,6 @@ LL | let ips: Vec<_> = (0..100_000).map(|_| u32::from(0u32.into())).collect( = note: multiple `impl`s satisfying `u32: From<_>` found in the `core` crate: - impl From for u32; - impl From for u32; - - impl From> for u32; - impl From for u32; - impl From for u32; - impl From for u32; diff --git a/tests/ui/try-trait/bad-interconversion.stderr b/tests/ui/try-trait/bad-interconversion.stderr index 80471c0ab1a40..817acc8fc9904 100644 --- a/tests/ui/try-trait/bad-interconversion.stderr +++ b/tests/ui/try-trait/bad-interconversion.stderr @@ -11,7 +11,6 @@ LL | Ok(Err(123_i32)?) = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = help: the following other types implement trait `From`: > - >> > = note: required for `Result` to implement `FromResidual>` From bb399b15b9d0c944008f1677a31167931931c407 Mon Sep 17 00:00:00 2001 From: joboet Date: Sat, 17 Feb 2024 21:27:11 +0100 Subject: [PATCH 03/17] generate `getelementptr` instead of `inttoptr` for `ptr::invalid` --- library/core/src/ptr/mod.rs | 28 ++++++++++++++++------------ tests/codegen/strict-provenance.rs | 15 +++++++++++++++ 2 files changed, 31 insertions(+), 12 deletions(-) create mode 100644 tests/codegen/strict-provenance.rs diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 2bd14f357d80c..a38c4ddfef6cd 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -537,7 +537,10 @@ pub unsafe fn drop_in_place(to_drop: *mut T) { #[rustc_allow_const_fn_unstable(ptr_metadata)] #[rustc_diagnostic_item = "ptr_null"] pub const fn null() -> *const T { - from_raw_parts(invalid(0), ()) + // Use transmute instead of casting so that Miri knows that the pointer is invalid. + // SAFETY: on all current platforms, usize and pointers have the same layout, + // and the validity invariant of pointers is the same as that of integers + unsafe { mem::transmute(0usize) } } /// Creates a null mutable raw pointer. @@ -563,7 +566,10 @@ pub const fn null() -> *const T { #[rustc_allow_const_fn_unstable(ptr_metadata)] #[rustc_diagnostic_item = "ptr_null_mut"] pub const fn null_mut() -> *mut T { - from_raw_parts_mut(invalid_mut(0), ()) + // Use transmute instead of casting so that Miri knows that the pointer is invalid. + // SAFETY: on all current platforms, usize and pointers have the same layout, + // and the validity invariant of pointers is the same as that of integers + unsafe { mem::transmute(0usize) } } /// Creates an invalid pointer with the given address. @@ -590,11 +596,10 @@ pub const fn null_mut() -> *mut T { #[unstable(feature = "strict_provenance", issue = "95228")] pub const fn invalid(addr: usize) -> *const T { // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. - // We use transmute rather than a cast so tools like Miri can tell that this - // is *not* the same as from_exposed_addr. - // SAFETY: every valid integer is also a valid pointer (as long as you don't dereference that - // pointer). - unsafe { mem::transmute(addr) } + // We offset the null pointer instead of using a cast so that LLVM doesn't + // use inttoptr and so tools like Miri can tell that it is *not* the same + // as from_exposed_addr. + null::().wrapping_byte_add(addr) } /// Creates an invalid mutable pointer with the given address. @@ -621,11 +626,10 @@ pub const fn invalid(addr: usize) -> *const T { #[unstable(feature = "strict_provenance", issue = "95228")] pub const fn invalid_mut(addr: usize) -> *mut T { // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. - // We use transmute rather than a cast so tools like Miri can tell that this - // is *not* the same as from_exposed_addr. - // SAFETY: every valid integer is also a valid pointer (as long as you don't dereference that - // pointer). - unsafe { mem::transmute(addr) } + // We offset the null pointer instead of using a cast so that LLVM doesn't + // use inttoptr and so tools like Miri can tell that it is *not* the same + // as from_exposed_addr. + null_mut::().wrapping_byte_add(addr) } /// Convert an address back to a pointer, picking up a previously 'exposed' provenance. diff --git a/tests/codegen/strict-provenance.rs b/tests/codegen/strict-provenance.rs new file mode 100644 index 0000000000000..b7054206807b3 --- /dev/null +++ b/tests/codegen/strict-provenance.rs @@ -0,0 +1,15 @@ +// compile-flags: -O + +#![crate_type = "lib"] +#![feature(strict_provenance)] + +use std::ptr; + +// CHECK-LABEL: @invalid +#[no_mangle] +fn invalid(addr: usize) -> *const () { + // CHECK: start + // CHECK-NEXT: %0 = getelementptr i8, ptr null, i64 %addr + // CHECK-NEXT: ret ptr %0 + ptr::invalid(addr) +} From 24cffbf703dd70c0718d0c99be37d42eadd39011 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 14 Feb 2024 21:40:45 +0300 Subject: [PATCH 04/17] resolve: Scale back unloading of speculatively loaded crates --- compiler/rustc_metadata/src/creader.rs | 10 ---------- .../rustc_metadata/src/rmeta/decoder/cstore_impl.rs | 10 ++++++++++ compiler/rustc_middle/src/query/mod.rs | 7 +++++++ compiler/rustc_passes/src/lang_items.rs | 2 +- compiler/rustc_resolve/src/late.rs | 5 ----- compiler/rustc_resolve/src/lib.rs | 1 - tests/ui/extern-flag/empty-extern-arg.stderr | 9 ++++++++- 7 files changed, 26 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index c18f0e7b7b938..f6d3dba247090 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -1070,16 +1070,6 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { pub fn maybe_process_path_extern(&mut self, name: Symbol) -> Option { self.maybe_resolve_crate(name, CrateDepKind::Explicit, None).ok() } - - pub fn unload_unused_crates(&mut self) { - for opt_cdata in &mut self.cstore.metas { - if let Some(cdata) = opt_cdata - && !cdata.used() - { - *opt_cdata = None; - } - } - } } fn global_allocator_spans(krate: &ast::Crate) -> Vec { diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 9df28799f4f76..2f507b258fe7e 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -519,6 +519,16 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { tcx.untracked().cstore.freeze(); tcx.arena.alloc_from_iter(CStore::from_tcx(tcx).iter_crate_data().map(|(cnum, _)| cnum)) }, + used_crates: |tcx, ()| { + // The list of loaded crates is now frozen in query cache, + // so make sure cstore is not mutably accessed from here on. + tcx.untracked().cstore.freeze(); + tcx.arena.alloc_from_iter( + CStore::from_tcx(tcx) + .iter_crate_data() + .filter_map(|(cnum, data)| data.used().then_some(cnum)), + ) + }, ..providers.queries }; provide_extern(&mut providers.extern_queries); diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 5be45c33e1124..5ed1ccc49cb09 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1872,6 +1872,13 @@ rustc_queries! { eval_always desc { "fetching all foreign CrateNum instances" } } + // Crates that are loaded non-speculatively (not for diagnostics or doc links). + // FIXME: This is currently only used for collecting lang items, but should be used instead of + // `crates` in most other cases too. + query used_crates(_: ()) -> &'tcx [CrateNum] { + eval_always + desc { "fetching `CrateNum`s for all crates loaded non-speculatively" } + } /// A list of all traits in a crate, used by rustdoc and error reporting. query traits(_: CrateNum) -> &'tcx [DefId] { diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index 9a21397789d6c..d3e3e183845ee 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -250,7 +250,7 @@ fn get_lang_items(tcx: TyCtxt<'_>, (): ()) -> LanguageItems { let mut collector = LanguageItemCollector::new(tcx, resolver); // Collect lang items in other crates. - for &cnum in tcx.crates(()).iter() { + for &cnum in tcx.used_crates(()).iter() { for &(def_id, lang_item) in tcx.defined_lang_items(cnum).iter() { collector.collect_item(lang_item, def_id, None); } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 1cf3fecc28989..6aacb0e17d576 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -23,7 +23,6 @@ use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::{PrimTy, TraitCandidate}; -use rustc_metadata::creader::CStore; use rustc_middle::middle::resolve_bound_vars::Set1; use rustc_middle::{bug, span_bug}; use rustc_session::config::{CrateType, ResolveDocLinks}; @@ -4574,10 +4573,6 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // Encoding foreign def ids in proc macro crate metadata will ICE. return None; } - // Doc paths should be resolved speculatively and should not produce any - // diagnostics, but if they are indeed resolved, then we need to keep the - // corresponding crate alive. - CStore::from_tcx_mut(self.r.tcx).set_used_recursively(def_id.krate); } res }); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 1c625f49e3e9a..a9b6703f3ab68 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1651,7 +1651,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { self.tcx .sess .time("resolve_postprocess", || self.crate_loader(|c| c.postprocess(krate))); - self.crate_loader(|c| c.unload_unused_crates()); }); // Make sure we don't mutate the cstore from here on. diff --git a/tests/ui/extern-flag/empty-extern-arg.stderr b/tests/ui/extern-flag/empty-extern-arg.stderr index 6ad3effe0e26e..2785b12a0aef4 100644 --- a/tests/ui/extern-flag/empty-extern-arg.stderr +++ b/tests/ui/extern-flag/empty-extern-arg.stderr @@ -1,6 +1,13 @@ error: extern location for std does not exist: +error: `#[panic_handler]` function required, but not found + +error: unwinding panics are not supported without std + | + = help: using nightly cargo, use -Zbuild-std with panic="abort" to avoid unwinding + = note: since the core library is usually precompiled with panic="unwind", rebuilding your crate with panic="abort" may not be enough to fix the problem + error: requires `sized` lang_item -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors From f70538c928e6088242bde086dca0dc9fcd7bdf6b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 18 Feb 2024 23:10:34 +0100 Subject: [PATCH 05/17] make simd_reduce_{mul,add}_unordered use only the 'reassoc' flag, not all fast-math flags --- compiler/rustc_codegen_gcc/src/builder.rs | 4 ++-- compiler/rustc_codegen_gcc/src/intrinsic/simd.rs | 4 ++-- compiler/rustc_codegen_llvm/src/builder.rs | 8 ++++---- compiler/rustc_codegen_llvm/src/intrinsic.rs | 4 ++-- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 1 + compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp | 11 ++++++++++- library/core/src/intrinsics/simd.rs | 16 ++++------------ 7 files changed, 25 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 42e61b3ccb5ad..d5da5c845a758 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -1727,7 +1727,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { self.vector_reduce(src, |a, b, context| context.new_binary_op(None, op, a.get_type(), a, b)) } - pub fn vector_reduce_fadd_fast(&mut self, _acc: RValue<'gcc>, _src: RValue<'gcc>) -> RValue<'gcc> { + pub fn vector_reduce_fadd_reassoc(&mut self, _acc: RValue<'gcc>, _src: RValue<'gcc>) -> RValue<'gcc> { unimplemented!(); } @@ -1747,7 +1747,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { unimplemented!(); } - pub fn vector_reduce_fmul_fast(&mut self, _acc: RValue<'gcc>, _src: RValue<'gcc>) -> RValue<'gcc> { + pub fn vector_reduce_fmul_reassoc(&mut self, _acc: RValue<'gcc>, _src: RValue<'gcc>) -> RValue<'gcc> { unimplemented!(); } diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs index 9fa978cd2ef7a..dedd46538589d 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs @@ -989,14 +989,14 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( arith_red!( simd_reduce_add_unordered: BinaryOp::Plus, - vector_reduce_fadd_fast, + vector_reduce_fadd_reassoc, false, add, 0.0 // TODO: Use this argument. ); arith_red!( simd_reduce_mul_unordered: BinaryOp::Mult, - vector_reduce_fmul_fast, + vector_reduce_fmul_reassoc, false, mul, 1.0 diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 7ed27b33dceaa..27dadb7c51106 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1327,17 +1327,17 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { pub fn vector_reduce_fmul(&mut self, acc: &'ll Value, src: &'ll Value) -> &'ll Value { unsafe { llvm::LLVMRustBuildVectorReduceFMul(self.llbuilder, acc, src) } } - pub fn vector_reduce_fadd_fast(&mut self, acc: &'ll Value, src: &'ll Value) -> &'ll Value { + pub fn vector_reduce_fadd_reassoc(&mut self, acc: &'ll Value, src: &'ll Value) -> &'ll Value { unsafe { let instr = llvm::LLVMRustBuildVectorReduceFAdd(self.llbuilder, acc, src); - llvm::LLVMRustSetFastMath(instr); + llvm::LLVMRustSetAllowReassoc(instr); instr } } - pub fn vector_reduce_fmul_fast(&mut self, acc: &'ll Value, src: &'ll Value) -> &'ll Value { + pub fn vector_reduce_fmul_reassoc(&mut self, acc: &'ll Value, src: &'ll Value) -> &'ll Value { unsafe { let instr = llvm::LLVMRustBuildVectorReduceFMul(self.llbuilder, acc, src); - llvm::LLVMRustSetFastMath(instr); + llvm::LLVMRustSetAllowReassoc(instr); instr } } diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 4415c51acf684..b7782410012e2 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1880,14 +1880,14 @@ fn generic_simd_intrinsic<'ll, 'tcx>( arith_red!(simd_reduce_mul_ordered: vector_reduce_mul, vector_reduce_fmul, true, mul, 1.0); arith_red!( simd_reduce_add_unordered: vector_reduce_add, - vector_reduce_fadd_fast, + vector_reduce_fadd_reassoc, false, add, 0.0 ); arith_red!( simd_reduce_mul_unordered: vector_reduce_mul, - vector_reduce_fmul_fast, + vector_reduce_fmul_reassoc, false, mul, 1.0 diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index d0044086c616e..c51a2a8770149 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1618,6 +1618,7 @@ extern "C" { ) -> &'a Value; pub fn LLVMRustSetFastMath(Instr: &Value); + pub fn LLVMRustSetAllowReassoc(Instr: &Value); // Miscellaneous instructions pub fn LLVMRustGetInstrProfIncrementIntrinsic(M: &Module) -> &Value; diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index b45706fd1e5b2..8ae4542076a2d 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -418,7 +418,7 @@ extern "C" LLVMAttributeRef LLVMRustCreateMemoryEffectsAttr(LLVMContextRef C, } } -// Enable a fast-math flag +// Enable all fast-math flags // // https://llvm.org/docs/LangRef.html#fast-math-flags extern "C" void LLVMRustSetFastMath(LLVMValueRef V) { @@ -427,6 +427,15 @@ extern "C" void LLVMRustSetFastMath(LLVMValueRef V) { } } +// Enable the reassoc fast-math flag +// +// https://llvm.org/docs/LangRef.html#fast-math-flags +extern "C" void LLVMRustSetAllowReassoc(LLVMValueRef V) { + if (auto I = dyn_cast(unwrap(V))) { + I->setHasAllowReassoc(true); + } +} + extern "C" LLVMValueRef LLVMRustBuildAtomicLoad(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Source, const char *Name, LLVMAtomicOrdering Order) { diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs index 3d027e1fca04d..0ccdd74fa6269 100644 --- a/library/core/src/intrinsics/simd.rs +++ b/library/core/src/intrinsics/simd.rs @@ -333,16 +333,12 @@ extern "platform-intrinsic" { /// Starting with the value `y`, add the elements of `x` and accumulate. pub fn simd_reduce_add_ordered(x: T, y: U) -> U; - /// Add elements within a vector in arbitrary order, and without regard - /// for signed zeros. + /// Add elements within a vector in arbitrary order. May also be re-associated with + /// unordered additions on the inputs/outputs. /// /// `T` must be a vector of integer or floating-point primitive types. /// /// `U` must be the element type of `T`. - /// - /// # Safety - /// - /// All input elements must be finite (i.e., not NAN and not +/- INF). pub fn simd_reduce_add_unordered(x: T) -> U; /// Multiply elements within a vector from left to right. @@ -354,16 +350,12 @@ extern "platform-intrinsic" { /// Starting with the value `y`, multiply the elements of `x` and accumulate. pub fn simd_reduce_mul_ordered(x: T, y: U) -> U; - /// Multiply elements within a vector in arbitrary order, and without regard - /// for signed zeros. + /// Add elements within a vector in arbitrary order. May also be re-associated with + /// unordered additions on the inputs/outputs. /// /// `T` must be a vector of integer or floating-point primitive types. /// /// `U` must be the element type of `T`. - /// - /// # Safety - /// - /// All input elements must be finite (i.e., not NAN and not +/- INF). pub fn simd_reduce_mul_unordered(x: T) -> U; /// Check if all mask values are true. From 9b193dea994b57df13f5c8d838b61c00cbc5cd8d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 16 Feb 2024 10:35:53 +1100 Subject: [PATCH 06/17] Remove two comments that shouldn't be there. --- compiler/rustc_ast_passes/src/ast_validation.rs | 1 - compiler/rustc_errors/src/lib.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index fa0f532619611..e08e70836e253 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -881,7 +881,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { &item.vis, errors::VisibilityNotPermittedNote::TraitImpl, ); - // njn: use Dummy here if let TyKind::Err(_) = self_ty.kind { this.dcx().emit_err(errors::ObsoleteAuto { span: item.span }); } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 064ea8d75163e..75f61b69f3979 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1276,7 +1276,6 @@ impl DiagCtxtInner { fn emit_stashed_diagnostics(&mut self) { let has_errors = !self.err_guars.is_empty(); for (_, diag) in std::mem::take(&mut self.stashed_diagnostics).into_iter() { - // Decrement the count tracking the stash; emitting will increment it. if diag.is_error() { if diag.is_lint.is_none() { self.stashed_err_count -= 1; From bb4748f54257713338b367f44254bf058840413f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 16 Feb 2024 14:50:07 +1100 Subject: [PATCH 07/17] Remove dead `expect_error_or_delayed_bug` method. --- compiler/rustc_middle/src/ty/context.rs | 5 ----- compiler/rustc_type_ir/src/interner.rs | 3 --- 2 files changed, 8 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index cc734e7157fa4..9d59f779470f6 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -153,11 +153,6 @@ impl<'tcx> Interner for TyCtxt<'tcx> { ) -> Self::Const { Const::new_bound(self, debruijn, var, ty) } - - fn expect_error_or_delayed_bug() { - let has_errors = ty::tls::with(|tcx| tcx.dcx().has_errors_or_lint_errors_or_delayed_bugs()); - assert!(has_errors.is_some()); - } } type InternedSet<'tcx, T> = ShardedHashMap, ()>; diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 7728ee0e842a8..7d2c42a6dbe91 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -95,9 +95,6 @@ pub trait Interner: Sized { fn mk_bound_ty(self, debruijn: DebruijnIndex, var: BoundVar) -> Self::Ty; fn mk_bound_region(self, debruijn: DebruijnIndex, var: BoundVar) -> Self::Region; fn mk_bound_const(self, debruijn: DebruijnIndex, var: BoundVar, ty: Self::Ty) -> Self::Const; - - /// Assert that an error has been delayed or emitted. - fn expect_error_or_delayed_bug(); } /// Common capabilities of placeholder kinds From ebb78c23ee4c81f47e5c851950a3767712a79784 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 16 Feb 2024 15:26:42 +1100 Subject: [PATCH 08/17] Remove `EarlyDiagCtxt::abort_if_errors`. Its one use isn't necessary, because it's not possible for errors to have been emitted at that point. --- compiler/rustc_driver_impl/src/lib.rs | 5 ++--- compiler/rustc_session/src/session.rs | 4 ---- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 60f11b1bdd490..9b2d760282f1c 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -349,11 +349,10 @@ fn run_compiler( }, }; - callbacks.config(&mut config); - - default_early_dcx.abort_if_errors(); drop(default_early_dcx); + callbacks.config(&mut config); + interface::run_compiler(config, |compiler| { let sess = &compiler.sess; let codegen_backend = &*compiler.codegen_backend; diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 9d1133c487f65..422bbadf6a8a0 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1410,10 +1410,6 @@ impl EarlyDiagCtxt { Self { dcx: DiagCtxt::with_emitter(emitter) } } - pub fn abort_if_errors(&self) { - self.dcx.abort_if_errors() - } - /// Swap out the underlying dcx once we acquire the user's preference on error emission /// format. Any errors prior to that will cause an abort and all stashed diagnostics of the /// previous dcx will be emitted. From 6fa6f55b9fcbcd954b820e19a7bb531662cda89d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 19 Feb 2024 09:36:08 +1100 Subject: [PATCH 09/17] Adjust the `has_errors*` methods. Currently `has_errors` excludes lint errors. This commit changes it to include lint errors. The motivation for this is that for most places it doesn't matter whether lint errors are included or not. But there are multiple places where they must be includes, and only one place where they must not be included. So it makes sense for `has_errors` to do the thing that fits the most situations, and the new `has_errors_excluding_lint_errors` method in the one exceptional place. The same change is made for `err_count`. Annoyingly, this requires the introduction of `err_count_excluding_lint_errs` for one place, to preserve existing error printing behaviour. But I still think the change is worthwhile overall. --- compiler/rustc_errors/src/lib.rs | 46 +++++++++++-------- compiler/rustc_incremental/src/persist/fs.rs | 2 +- .../rustc_incremental/src/persist/save.rs | 4 +- compiler/rustc_infer/src/infer/mod.rs | 9 ++-- compiler/rustc_interface/src/passes.rs | 2 +- compiler/rustc_metadata/src/creader.rs | 2 +- .../rustc_query_system/src/dep_graph/graph.rs | 2 +- compiler/rustc_session/src/session.rs | 3 +- src/librustdoc/core.rs | 3 +- src/librustdoc/doctest.rs | 3 +- 10 files changed, 41 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 75f61b69f3979..858d3436c36c1 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -759,13 +759,20 @@ impl DiagCtxt { self.inner.borrow_mut().emit_stashed_diagnostics() } - /// This excludes lint errors, delayed bugs, and stashed errors. + /// This excludes lint errors, delayed bugs and stashed errors. #[inline] - pub fn err_count(&self) -> usize { + pub fn err_count_excluding_lint_errs(&self) -> usize { self.inner.borrow().err_guars.len() } - /// This excludes normal errors, lint errors and delayed bugs. Unless + /// This excludes delayed bugs and stashed errors. + #[inline] + pub fn err_count(&self) -> usize { + let inner = self.inner.borrow(); + inner.err_guars.len() + inner.lint_err_guars.len() + } + + /// This excludes normal errors, lint errors, and delayed bugs. Unless /// absolutely necessary, avoid using this. It's dubious because stashed /// errors can later be cancelled, so the presence of a stashed error at /// some point of time doesn't guarantee anything -- there are no @@ -774,21 +781,21 @@ impl DiagCtxt { self.inner.borrow().stashed_err_count } - /// This excludes lint errors, delayed bugs, and stashed errors. - pub fn has_errors(&self) -> Option { - self.inner.borrow().has_errors() + /// This excludes lint errors, delayed bugs, and stashed errors. Unless + /// absolutely necessary, prefer `has_errors` to this method. + pub fn has_errors_excluding_lint_errors(&self) -> Option { + self.inner.borrow().has_errors_excluding_lint_errors() } - /// This excludes delayed bugs and stashed errors. Unless absolutely - /// necessary, prefer `has_errors` to this method. - pub fn has_errors_or_lint_errors(&self) -> Option { - self.inner.borrow().has_errors_or_lint_errors() + /// This excludes delayed bugs and stashed errors. + pub fn has_errors(&self) -> Option { + self.inner.borrow().has_errors() } /// This excludes stashed errors. Unless absolutely necessary, prefer - /// `has_errors` or `has_errors_or_lint_errors` to this method. - pub fn has_errors_or_lint_errors_or_delayed_bugs(&self) -> Option { - self.inner.borrow().has_errors_or_lint_errors_or_delayed_bugs() + /// `has_errors` to this method. + pub fn has_errors_or_delayed_bugs(&self) -> Option { + self.inner.borrow().has_errors_or_delayed_bugs() } pub fn print_error_count(&self, registry: &Registry) { @@ -1333,7 +1340,7 @@ impl DiagCtxtInner { DelayedBug => { // If we have already emitted at least one error, we don't need // to record the delayed bug, because it'll never be used. - return if let Some(guar) = self.has_errors_or_lint_errors() { + return if let Some(guar) = self.has_errors() { Some(guar) } else { let backtrace = std::backtrace::Backtrace::capture(); @@ -1450,17 +1457,16 @@ impl DiagCtxtInner { .is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() + 1 >= c.get()) } - fn has_errors(&self) -> Option { + fn has_errors_excluding_lint_errors(&self) -> Option { self.err_guars.get(0).copied() } - fn has_errors_or_lint_errors(&self) -> Option { - self.has_errors().or_else(|| self.lint_err_guars.get(0).copied()) + fn has_errors(&self) -> Option { + self.has_errors_excluding_lint_errors().or_else(|| self.lint_err_guars.get(0).copied()) } - fn has_errors_or_lint_errors_or_delayed_bugs(&self) -> Option { - self.has_errors_or_lint_errors() - .or_else(|| self.delayed_bugs.get(0).map(|(_, guar)| guar).copied()) + fn has_errors_or_delayed_bugs(&self) -> Option { + self.has_errors().or_else(|| self.delayed_bugs.get(0).map(|(_, guar)| guar).copied()) } /// Translate `message` eagerly with `args` to `SubdiagnosticMessage::Eager`. diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index 23d29916922ff..dd9c16d006a96 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -312,7 +312,7 @@ pub fn finalize_session_directory(sess: &Session, svh: Option) { let incr_comp_session_dir: PathBuf = sess.incr_comp_session_dir().clone(); - if sess.dcx().has_errors_or_lint_errors_or_delayed_bugs().is_some() { + if sess.dcx().has_errors_or_delayed_bugs().is_some() { // If there have been any errors during compilation, we don't want to // publish this session directory. Rather, we'll just delete it. diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs index ff0c58d09de2d..32759f5284af7 100644 --- a/compiler/rustc_incremental/src/persist/save.rs +++ b/compiler/rustc_incremental/src/persist/save.rs @@ -32,7 +32,7 @@ pub fn save_dep_graph(tcx: TyCtxt<'_>) { return; } // This is going to be deleted in finalize_session_directory, so let's not create it. - if sess.dcx().has_errors_or_lint_errors_or_delayed_bugs().is_some() { + if sess.dcx().has_errors_or_delayed_bugs().is_some() { return; } @@ -87,7 +87,7 @@ pub fn save_work_product_index( return; } // This is going to be deleted in finalize_session_directory, so let's not create it - if sess.dcx().has_errors_or_lint_errors().is_some() { + if sess.dcx().has_errors().is_some() { return; } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 243558b11a863..f131d11c41159 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -713,7 +713,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { reported_trait_errors: Default::default(), reported_signature_mismatch: Default::default(), tainted_by_errors: Cell::new(None), - err_count_on_creation: tcx.dcx().err_count(), + err_count_on_creation: tcx.dcx().err_count_excluding_lint_errs(), stashed_err_count_on_creation: tcx.dcx().stashed_err_count(), universe: Cell::new(ty::UniverseIndex::ROOT), intercrate, @@ -1268,8 +1268,11 @@ impl<'tcx> InferCtxt<'tcx> { pub fn tainted_by_errors(&self) -> Option { if let Some(guar) = self.tainted_by_errors.get() { Some(guar) - } else if self.dcx().err_count() > self.err_count_on_creation { - // Errors reported since this infcx was made. + } else if self.dcx().err_count_excluding_lint_errs() > self.err_count_on_creation { + // Errors reported since this infcx was made. Lint errors are + // excluded to avoid some being swallowed in the presence of + // non-lint errors. (It's arguable whether or not this exclusion is + // important.) let guar = self.dcx().has_errors().unwrap(); self.set_tainted_by_errors(guar); Some(guar) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 60d13f02ad7b5..858db594b4773 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -772,7 +772,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { // lot of annoying errors in the ui tests (basically, // lint warnings and so on -- kindck used to do this abort, but // kindck is gone now). -nmatsakis - if let Some(reported) = sess.dcx().has_errors() { + if let Some(reported) = sess.dcx().has_errors_excluding_lint_errors() { return Err(reported); } else if sess.dcx().stashed_err_count() > 0 { // Without this case we sometimes get delayed bug ICEs and I don't diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index c18f0e7b7b938..66d3853e97628 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -926,7 +926,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { what: &str, needs_dep: &dyn Fn(&CrateMetadata) -> bool, ) { - // don't perform this validation if the session has errors, as one of + // Don't perform this validation if the session has errors, as one of // those errors may indicate a circular dependency which could cause // this to stack overflow. if self.dcx().has_errors().is_some() { diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index b6ac54a9ab59b..7dc1a1f791752 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -817,7 +817,7 @@ impl DepGraphData { None => {} } - if let None = qcx.dep_context().sess().dcx().has_errors_or_lint_errors_or_delayed_bugs() { + if let None = qcx.dep_context().sess().dcx().has_errors_or_delayed_bugs() { panic!("try_mark_previous_green() - Forcing the DepNode should have set its color") } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 422bbadf6a8a0..f8a1d79659d95 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -313,8 +313,7 @@ impl Session { } pub fn compile_status(&self) -> Result<(), ErrorGuaranteed> { - // We must include lint errors here. - if let Some(reported) = self.dcx().has_errors_or_lint_errors() { + if let Some(reported) = self.dcx().has_errors() { self.dcx().emit_stashed_diagnostics(); Err(reported) } else { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index efad5a8d808dd..3f7edd049a713 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -452,8 +452,7 @@ pub(crate) fn run_global_ctxt( tcx.sess.time("check_lint_expectations", || tcx.check_expectations(Some(sym::rustdoc))); - // We must include lint errors here. - if tcx.dcx().has_errors_or_lint_errors().is_some() { + if tcx.dcx().has_errors().is_some() { rustc_errors::FatalError.raise(); } diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index f9d4d1af1140f..09a90b62d97be 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -153,8 +153,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> { collector }); - // We must include lint errors here. - if compiler.sess.dcx().has_errors_or_lint_errors().is_some() { + if compiler.sess.dcx().has_errors().is_some() { FatalError.raise(); } From 9e68d89cc87c5413a6667bf553a80942804d444e Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sun, 18 Feb 2024 22:51:17 +0100 Subject: [PATCH 10/17] Remove the "codegen" profile from bootstrap This profile originally made sense when download-ci-llvm = if-unchanged didn't exist and we had the bad tradeoff of "never modify or always compile". Thankfully, these grim times are over and we have discovered clean water, so the only differentiator between the two profiles is the codegen profile having LLVM assertions. Adding them doesn't cause that much of a slowdown, <10% on UI tests from an unscientific benchmark. It also had LLVM warnings when compiling, which makes sense for every compiler contributor brave enough to compile LLVM. The way I removed is by just issueing a nice error message. Given that everyone with this profile should be a contributor and not someone like a distro who is more upset when things break, this should be fine. If it isn't, we can always fall back to just letting codegen mean compiler. --- src/bootstrap/defaults/config.codegen.toml | 28 --------------------- src/bootstrap/defaults/config.compiler.toml | 5 ++++ src/bootstrap/src/core/build_steps/setup.rs | 23 ++++++----------- src/bootstrap/src/utils/change_tracker.rs | 5 ++++ triagebot.toml | 5 ---- 5 files changed, 17 insertions(+), 49 deletions(-) delete mode 100644 src/bootstrap/defaults/config.codegen.toml diff --git a/src/bootstrap/defaults/config.codegen.toml b/src/bootstrap/defaults/config.codegen.toml deleted file mode 100644 index cf336d7a63639..0000000000000 --- a/src/bootstrap/defaults/config.codegen.toml +++ /dev/null @@ -1,28 +0,0 @@ -# These defaults are meant for contributors to the compiler who modify codegen or LLVM -[build] -# Contributors working on the compiler will probably expect compiler docs to be generated. -compiler-docs = true - -[llvm] -# This enables debug-assertions in LLVM, -# catching logic errors in codegen much earlier in the process. -assertions = true -# enable warnings during the llvm compilation -enable-warnings = true -# build llvm from source -download-ci-llvm = "if-unchanged" - -[rust] -# This enables `RUSTC_LOG=debug`, avoiding confusing situations -# where adding `debug!()` appears to do nothing. -# However, it makes running the compiler slightly slower. -debug-logging = true -# This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower. -incremental = true -# Print backtrace on internal compiler errors during bootstrap -backtrace-on-ice = true -# Make the compiler and standard library faster to build, at the expense of a ~20% runtime slowdown. -lto = "off" -# Forces frame pointers to be used with `-Cforce-frame-pointers`. -# This can be helpful for profiling at a small performance cost. -frame-pointers = true diff --git a/src/bootstrap/defaults/config.compiler.toml b/src/bootstrap/defaults/config.compiler.toml index 5c2d476d98e05..178c6e9056c69 100644 --- a/src/bootstrap/defaults/config.compiler.toml +++ b/src/bootstrap/defaults/config.compiler.toml @@ -19,5 +19,10 @@ lto = "off" frame-pointers = true [llvm] +# This enables debug-assertions in LLVM, +# catching logic errors in codegen much earlier in the process. +assertions = true +# Enable warnings during the LLVM compilation (when LLVM is changed, causing a compilation) +enable-warnings = true # Will download LLVM from CI if available on your platform. download-ci-llvm = "if-unchanged" diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index 5b434eddb7158..f7747e66dd9c5 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -19,7 +19,6 @@ mod tests; #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] pub enum Profile { Compiler, - Codegen, Library, Tools, Dist, @@ -48,7 +47,7 @@ impl Profile { pub fn all() -> impl Iterator { use Profile::*; // N.B. these are ordered by how they are displayed, not alphabetically - [Library, Compiler, Codegen, Tools, Dist, None].iter().copied() + [Library, Compiler, Tools, Dist, None].iter().copied() } pub fn purpose(&self) -> String { @@ -56,7 +55,6 @@ impl Profile { match self { Library => "Contribute to the standard library", Compiler => "Contribute to the compiler itself", - Codegen => "Contribute to the compiler, and also modify LLVM or codegen", Tools => "Contribute to tools which depend on the compiler, but do not modify it directly (e.g. rustdoc, clippy, miri)", Dist => "Install Rust from source", None => "Do not modify `config.toml`" @@ -75,7 +73,6 @@ impl Profile { pub fn as_str(&self) -> &'static str { match self { Profile::Compiler => "compiler", - Profile::Codegen => "codegen", Profile::Library => "library", Profile::Tools => "tools", Profile::Dist => "dist", @@ -91,12 +88,15 @@ impl FromStr for Profile { match s { "lib" | "library" => Ok(Profile::Library), "compiler" => Ok(Profile::Compiler), - "llvm" | "codegen" => Ok(Profile::Codegen), "maintainer" | "dist" | "user" => Ok(Profile::Dist), "tools" | "tool" | "rustdoc" | "clippy" | "miri" | "rustfmt" | "rls" => { Ok(Profile::Tools) } "none" => Ok(Profile::None), + "llvm" | "codegen" => Err(format!( + "the \"llvm\" and \"codegen\" profiles have been removed,\ + use \"compiler\" instead which has the same functionality" + )), _ => Err(format!("unknown profile: '{s}'")), } } @@ -170,22 +170,13 @@ impl Step for Profile { } fn run(self, builder: &Builder<'_>) { - // During ./x.py setup once you select the codegen profile. - // The submodule will be downloaded. It does not work in the - // tarball case since they don't include Git and submodules - // are already included. - if !builder.rust_info().is_from_tarball() { - if self == Profile::Codegen { - builder.update_submodule(&Path::new("src/llvm-project")); - } - } - setup(&builder.build.config, self) + setup(&builder.build.config, self); } } pub fn setup(config: &Config, profile: Profile) { let suggestions: &[&str] = match profile { - Profile::Codegen | Profile::Compiler | Profile::None => &["check", "build", "test"], + Profile::Compiler | Profile::None => &["check", "build", "test"], Profile::Tools => &[ "check", "build", diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 1625047d3e103..fe5b5fe317565 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -124,4 +124,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Info, summary: "A new `rust.frame-pointers` option has been introduced and made the default in the compiler and codegen profiles.", }, + ChangeInfo { + change_id: 121278, + severity: ChangeSeverity::Warning, + summary: "The \"codegen\"/\"llvm\" profile has been removed and replaced with \"compiler\", use it instead for the same behavior.", + }, ]; diff --git a/triagebot.toml b/triagebot.toml index 1a30399e46c03..8c9faf92b7fe9 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -627,11 +627,6 @@ This PR modifies `config.example.toml`. If appropriate, please update `CONFIG_CHANGE_HISTORY` in `src/bootstrap/src/utils/change_tracker.rs`. """ -[mentions."src/bootstrap/defaults/config.compiler.toml"] -message = "This PR changes src/bootstrap/defaults/config.compiler.toml. If appropriate, please also update `config.codegen.toml` so the defaults are in sync." -[mentions."src/bootstrap/defaults/config.codegen.toml"] -message = "This PR changes src/bootstrap/defaults/config.codegen.toml. If appropriate, please also update `config.compiler.toml` so the defaults are in sync." - [mentions."src/bootstrap/src/core/build_steps/llvm.rs"] message = "This PR changes how LLVM is built. Consider updating src/bootstrap/download-ci-llvm-stamp." From 03d03c666c337acdaeb8911deaade55366bf8959 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Fri, 16 Feb 2024 19:43:50 +0100 Subject: [PATCH 11/17] Always inline check in `assert_unsafe_precondition` with cfg(debug_assertions) The current complexities in `assert_unsafe_precondition` are delicately balancing several concerns, among them compile times for the cases where there are no debug assertions. This comes at a large runtime cost when the assertions are enabled, making the debug assertion compiler a lot slower, which is very annoying. To avoid this, we always inline the check when building with debug assertions. Numbers (compiling stage1 library after touching core): - master: 80s - just adding `#[inline(always)]` to the `cfg(bootstrap)` `debug_assertions`: 67s - this: 54s So this seems like a good solution. I think we can still get the same run-time perf improvements for other users too by massaging this code further (see my other PR about adding `#[rustc_no_mir_inline]`) but this is a simpler step that solves the imminent problem of "holy shit my rustc is sooo slow". Funny consequence: This now means compiling the standard library with dbeug assertions makes it faster (than without, when using debug assertions downstream)! --- library/core/src/intrinsics.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index ce1876d5a2f2f..d1ffc39ecbfc2 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2575,6 +2575,7 @@ pub const fn is_val_statically_known(_arg: T) -> bool { /// assertions disabled. This intrinsic is primarily used by [`assert_unsafe_precondition`]. #[rustc_const_unstable(feature = "delayed_debug_assertions", issue = "none")] #[unstable(feature = "core_intrinsics", issue = "none")] +#[inline(always)] #[cfg_attr(not(bootstrap), rustc_intrinsic)] pub(crate) const fn debug_assertions() -> bool { cfg!(debug_assertions) @@ -2659,7 +2660,13 @@ pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) macro_rules! assert_unsafe_precondition { ($message:expr, ($($name:ident:$ty:ty = $arg:expr),*$(,)?) => $e:expr $(,)?) => { { - #[inline(never)] + // When the standard library is compiled with debug assertions, we want the check to inline for better performance. + // This is important when working on the compiler, which is compiled with debug assertions locally. + // When not compiled with debug assertions (so the precompiled std) we outline the check to minimize the compile + // time impact when debug assertions are disabled. + // It is not clear whether that is the best solution, see #120848. + #[cfg_attr(debug_assertions, inline(always))] + #[cfg_attr(not(debug_assertions), inline(never))] #[rustc_nounwind] fn precondition_check($($name:$ty),*) { if !$e { From 226faa9efc9824e7c4ac5a9f79c271cf92ffe006 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 19 Feb 2024 10:00:19 +1100 Subject: [PATCH 12/17] Overhaul the handling of errors at the top-level. Currently `emit_stashed_diagnostic` is called from four(!) different places: `print_error_count`, `DiagCtxtInner::drop`, `abort_if_errors`, and `compile_status`. And `flush_delayed` is called from two different places: `DiagCtxtInner::drop` and `Queries`. This is pretty gross! Each one should really be called from a single place, but there's a bunch of entanglements. This commit cleans up this mess. Specifically, it: - Removes all the existing calls to `emit_stashed_diagnostic`, and adds a single new call in `finish_diagnostics`. - Removes the early `flush_delayed` call in `codegen_and_build_linker`, replacing it with a simple early return if delayed bugs are present. - Changes `DiagCtxtInner::drop` and `DiagCtxtInner::flush_delayed` so they both assert that the stashed diagnostics are empty (i.e. processed beforehand). - Changes `interface::run_compiler` so that any errors emitted during `finish_diagnostics` (i.e. late-emitted stashed diagnostics) are counted and cannot be overlooked. This requires adding `ErrorGuaranteed` return values to several functions. - Removes the `stashed_err_count` call in `analysis`. This is possible now that we don't have to worry about calling `flush_delayed` early from `codegen_and_build_linker` when stashed diagnostics are pending. - Changes the `span_bug` case in `handle_tuple_field_pattern_match` to a `delayed_span_bug`, because it now can be reached due to the removal of the `stashed_err_count` call in `analysis`. - Slightly changes the expected output of three tests. If no errors are emitted but there are delayed bugs, the error count is no longer printed. This is because delayed bugs are now always printed after the error count is printed (or not printed, if the error count is zero). There is a lot going on in this commit. It's hard to break into smaller pieces because the existing code is very tangled. It took me a long time and a lot of effort to understand how the different pieces interact, and I think the new code is a lot simpler and easier to understand. --- compiler/rustc_errors/src/lib.rs | 32 ++++++++++------ compiler/rustc_interface/src/interface.rs | 37 ++++++++++++++++--- compiler/rustc_interface/src/passes.rs | 11 +++--- compiler/rustc_interface/src/queries.rs | 12 +++--- compiler/rustc_passes/src/dead.rs | 5 ++- compiler/rustc_session/src/session.rs | 14 ++++--- .../equality-in-canonical-query.clone.stderr | 2 - .../ui/inference/issue-80409.no-compat.stderr | 2 - ...equality_in_canonical_query.current.stderr | 2 - 9 files changed, 76 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 858d3436c36c1..32fac61305054 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -476,9 +476,10 @@ struct DiagCtxtInner { emitted_diagnostics: FxHashSet, /// Stashed diagnostics emitted in one stage of the compiler that may be - /// stolen by other stages (e.g. to improve them and add more information). - /// The stashed diagnostics count towards the total error count. - /// When `.abort_if_errors()` is called, these are also emitted. + /// stolen and emitted/cancelled by other stages (e.g. to improve them and + /// add more information). All stashed diagnostics must be emitted with + /// `emit_stashed_diagnostics` by the time the `DiagCtxtInner` is dropped, + /// otherwise an assertion failure will occur. stashed_diagnostics: FxIndexMap<(Span, StashKey), Diagnostic>, future_breakage_diagnostics: Vec, @@ -563,7 +564,9 @@ pub struct DiagCtxtFlags { impl Drop for DiagCtxtInner { fn drop(&mut self) { - self.emit_stashed_diagnostics(); + // Any stashed diagnostics should have been handled by + // `emit_stashed_diagnostics` by now. + assert!(self.stashed_diagnostics.is_empty()); if self.err_guars.is_empty() { self.flush_delayed() @@ -755,7 +758,7 @@ impl DiagCtxt { } /// Emit all stashed diagnostics. - pub fn emit_stashed_diagnostics(&self) { + pub fn emit_stashed_diagnostics(&self) -> Option { self.inner.borrow_mut().emit_stashed_diagnostics() } @@ -801,7 +804,9 @@ impl DiagCtxt { pub fn print_error_count(&self, registry: &Registry) { let mut inner = self.inner.borrow_mut(); - inner.emit_stashed_diagnostics(); + // Any stashed diagnostics should have been handled by + // `emit_stashed_diagnostics` by now. + assert!(inner.stashed_diagnostics.is_empty()); if inner.treat_err_as_bug() { return; @@ -877,9 +882,7 @@ impl DiagCtxt { } pub fn abort_if_errors(&self) { - let mut inner = self.inner.borrow_mut(); - inner.emit_stashed_diagnostics(); - if !inner.err_guars.is_empty() { + if self.has_errors().is_some() { FatalError.raise(); } } @@ -1280,7 +1283,8 @@ impl DiagCtxt { // `DiagCtxtInner::foo`. impl DiagCtxtInner { /// Emit all stashed diagnostics. - fn emit_stashed_diagnostics(&mut self) { + fn emit_stashed_diagnostics(&mut self) -> Option { + let mut guar = None; let has_errors = !self.err_guars.is_empty(); for (_, diag) in std::mem::take(&mut self.stashed_diagnostics).into_iter() { if diag.is_error() { @@ -1295,8 +1299,9 @@ impl DiagCtxtInner { continue; } } - self.emit_diagnostic(diag); + guar = guar.or(self.emit_diagnostic(diag)); } + guar } // Return value is only `Some` if the level is `Error` or `DelayedBug`. @@ -1489,6 +1494,11 @@ impl DiagCtxtInner { } fn flush_delayed(&mut self) { + // Stashed diagnostics must be emitted before delayed bugs are flushed. + // Otherwise, we might ICE prematurely when errors would have + // eventually happened. + assert!(self.stashed_diagnostics.is_empty()); + if self.delayed_bugs.is_empty() { return; } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 8a4705e0056e1..cd7957c3bce29 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -423,18 +423,43 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se Compiler { sess, codegen_backend, override_queries: config.override_queries }; rustc_span::set_source_map(compiler.sess.parse_sess.clone_source_map(), move || { - let r = { - let _sess_abort_error = defer(|| { - compiler.sess.finish_diagnostics(&config.registry); + // There are two paths out of `f`. + // - Normal exit. + // - Panic, e.g. triggered by `abort_if_errors`. + // + // We must run `finish_diagnostics` in both cases. + let res = { + // If `f` panics, `finish_diagnostics` will run during + // unwinding because of the `defer`. + let mut guar = None; + let sess_abort_guard = defer(|| { + guar = compiler.sess.finish_diagnostics(&config.registry); }); - f(&compiler) + let res = f(&compiler); + + // If `f` doesn't panic, `finish_diagnostics` will run + // normally when `sess_abort_guard` is dropped. + drop(sess_abort_guard); + + // If `finish_diagnostics` emits errors (e.g. stashed + // errors) we can't return an error directly, because the + // return type of this function is `R`, not `Result`. + // But we need to communicate the errors' existence to the + // caller, otherwise the caller might mistakenly think that + // no errors occurred and return a zero exit code. So we + // abort (panic) instead, similar to if `f` had panicked. + if guar.is_some() { + compiler.sess.dcx().abort_if_errors(); + } + + res }; let prof = compiler.sess.prof.clone(); - prof.generic_activity("drop_compiler").run(move || drop(compiler)); - r + + res }) }, ) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 858db594b4773..d35c2be1fb47d 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -772,12 +772,11 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { // lot of annoying errors in the ui tests (basically, // lint warnings and so on -- kindck used to do this abort, but // kindck is gone now). -nmatsakis - if let Some(reported) = sess.dcx().has_errors_excluding_lint_errors() { - return Err(reported); - } else if sess.dcx().stashed_err_count() > 0 { - // Without this case we sometimes get delayed bug ICEs and I don't - // understand why. -nnethercote - return Err(sess.dcx().delayed_bug("some stashed error is waiting for use")); + // + // But we exclude lint errors from this, because lint errors are typically + // less serious and we're more likely to want to continue (#87337). + if let Some(guar) = sess.dcx().has_errors_excluding_lint_errors() { + return Err(guar); } sess.time("misc_checking_3", || { diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 211bcb9da94db..8170c0a5a1a9f 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -222,12 +222,12 @@ impl<'tcx> Queries<'tcx> { pub fn codegen_and_build_linker(&'tcx self) -> Result { self.global_ctxt()?.enter(|tcx| { - // Don't do code generation if there were any errors - self.compiler.sess.compile_status()?; - - // If we have any delayed bugs, for example because we created TyKind::Error earlier, - // it's likely that codegen will only cause more ICEs, obscuring the original problem - self.compiler.sess.dcx().flush_delayed(); + // Don't do code generation if there were any errors. Likewise if + // there were any delayed bugs, because codegen will likely cause + // more ICEs, obscuring the original problem. + if let Some(guar) = self.compiler.sess.dcx().has_errors_or_delayed_bugs() { + return Err(guar); + } // Hook for UI tests. Self::check_for_rustc_errors_attr(tcx); diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 486396b067726..a3106856a6701 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -237,7 +237,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { ) { let variant = match self.typeck_results().node_type(lhs.hir_id).kind() { ty::Adt(adt, _) => adt.variant_of_res(res), - _ => span_bug!(lhs.span, "non-ADT in tuple struct pattern"), + _ => { + self.tcx.dcx().span_delayed_bug(lhs.span, "non-ADT in tuple struct pattern"); + return; + } }; let dotdot = dotdot.as_opt_usize().unwrap_or(pats.len()); let first_n = pats.iter().enumerate().take(dotdot); diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index f8a1d79659d95..48a18fca27ed2 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -258,7 +258,8 @@ impl Session { } } - fn check_miri_unleashed_features(&self) { + fn check_miri_unleashed_features(&self) -> Option { + let mut guar = None; let unleashed_features = self.miri_unleashed_features.lock(); if !unleashed_features.is_empty() { let mut must_err = false; @@ -279,18 +280,22 @@ impl Session { // If we should err, make sure we did. if must_err && self.dcx().has_errors().is_none() { // We have skipped a feature gate, and not run into other errors... reject. - self.dcx().emit_err(errors::NotCircumventFeature); + guar = Some(self.dcx().emit_err(errors::NotCircumventFeature)); } } + guar } /// Invoked all the way at the end to finish off diagnostics printing. - pub fn finish_diagnostics(&self, registry: &Registry) { - self.check_miri_unleashed_features(); + pub fn finish_diagnostics(&self, registry: &Registry) -> Option { + let mut guar = None; + guar = guar.or(self.check_miri_unleashed_features()); + guar = guar.or(self.dcx().emit_stashed_diagnostics()); self.dcx().print_error_count(registry); if self.opts.json_future_incompat { self.dcx().emit_future_breakage_report(); } + guar } /// Returns true if the crate is a testing one. @@ -314,7 +319,6 @@ impl Session { pub fn compile_status(&self) -> Result<(), ErrorGuaranteed> { if let Some(reported) = self.dcx().has_errors() { - self.dcx().emit_stashed_diagnostics(); Err(reported) } else { Ok(()) diff --git a/tests/ui/impl-trait/equality-in-canonical-query.clone.stderr b/tests/ui/impl-trait/equality-in-canonical-query.clone.stderr index 0e3cd2ff06099..e4c8aec397365 100644 --- a/tests/ui/impl-trait/equality-in-canonical-query.clone.stderr +++ b/tests/ui/impl-trait/equality-in-canonical-query.clone.stderr @@ -21,5 +21,3 @@ LL | same_output(foo, rpit); query stack during panic: end of query stack -error: aborting due to 2 previous errors - diff --git a/tests/ui/inference/issue-80409.no-compat.stderr b/tests/ui/inference/issue-80409.no-compat.stderr index 7bb4786db3a91..205c98c5e9344 100644 --- a/tests/ui/inference/issue-80409.no-compat.stderr +++ b/tests/ui/inference/issue-80409.no-compat.stderr @@ -2,5 +2,3 @@ error: internal compiler error: error performing ParamEnvAnd { param_env: ParamE | = query stack during panic: end of query stack -error: aborting due to 1 previous error - diff --git a/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr b/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr index fd76526644bdd..069292239bc89 100644 --- a/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr +++ b/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr @@ -21,5 +21,3 @@ LL | query(get_rpit); query stack during panic: end of query stack -error: aborting due to 2 previous errors - From add3457e6e81de269224b0eb956134980825437b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 19 Feb 2024 10:13:51 +1100 Subject: [PATCH 13/17] Inline and remove `Session::compile_status`. Because it's now simple enough that it doesn't provide much benefit. --- compiler/rustc_codegen_ssa/src/back/link.rs | 4 +++- compiler/rustc_driver_impl/src/lib.rs | 17 ++++++++++++----- compiler/rustc_interface/src/queries.rs | 4 +++- compiler/rustc_session/src/session.rs | 8 -------- src/tools/miri/src/bin/miri.rs | 2 +- 5 files changed, 19 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 435b517e602b1..7e3f324fe14c2 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -487,7 +487,9 @@ fn collate_raw_dylibs<'a, 'b>( } } } - sess.compile_status()?; + if let Some(guar) = sess.dcx().has_errors() { + return Err(guar); + } Ok(dylib_table .into_iter() .map(|(name, imports)| { diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 9b2d760282f1c..1057235c0a2a8 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -357,18 +357,25 @@ fn run_compiler( let sess = &compiler.sess; let codegen_backend = &*compiler.codegen_backend; + // This is used for early exits unrelated to errors. E.g. when just + // printing some information without compiling, or exiting immediately + // after parsing, etc. + let early_exit = || { + if let Some(guar) = sess.dcx().has_errors() { Err(guar) } else { Ok(()) } + }; + // This implements `-Whelp`. It should be handled very early, like // `--help`/`-Zhelp`/`-Chelp`. This is the earliest it can run, because // it must happen after lints are registered, during session creation. if sess.opts.describe_lints { describe_lints(sess); - return sess.compile_status(); + return early_exit(); } let early_dcx = EarlyDiagCtxt::new(sess.opts.error_format); if print_crate_info(&early_dcx, codegen_backend, sess, has_input) == Compilation::Stop { - return sess.compile_status(); + return early_exit(); } if !has_input { @@ -377,16 +384,16 @@ fn run_compiler( if !sess.opts.unstable_opts.ls.is_empty() { list_metadata(&early_dcx, sess, &*codegen_backend.metadata_loader()); - return sess.compile_status(); + return early_exit(); } if sess.opts.unstable_opts.link_only { process_rlink(sess, compiler); - return sess.compile_status(); + return early_exit(); } let linker = compiler.enter(|queries| { - let early_exit = || sess.compile_status().map(|_| None); + let early_exit = || early_exit().map(|_| None); queries.parse()?; if let Some(ppm) = &sess.opts.pretty { diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 8170c0a5a1a9f..86858bfe41d81 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -261,7 +261,9 @@ impl Linker { let (codegen_results, work_products) = codegen_backend.join_codegen(self.ongoing_codegen, sess, &self.output_filenames); - sess.compile_status()?; + if let Some(guar) = sess.dcx().has_errors() { + return Err(guar); + } sess.time("serialize_work_products", || { rustc_incremental::save_work_product_index(sess, &self.dep_graph, work_products) diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 48a18fca27ed2..02c7a0c6371f9 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -317,14 +317,6 @@ impl Session { err } - pub fn compile_status(&self) -> Result<(), ErrorGuaranteed> { - if let Some(reported) = self.dcx().has_errors() { - Err(reported) - } else { - Ok(()) - } - } - /// Record the fact that we called `trimmed_def_paths`, and do some /// checking about whether its cost was justified. pub fn record_trimmed_def_paths(&self) { diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index db4c4a28debb4..8a7133fea438d 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -68,7 +68,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { queries: &'tcx rustc_interface::Queries<'tcx>, ) -> Compilation { queries.global_ctxt().unwrap().enter(|tcx| { - if tcx.sess.compile_status().is_err() { + if tcx.sess.dcx().has_errors().is_some() { tcx.dcx().fatal("miri cannot be run on programs that fail compilation"); } From 86ba1ab11375112a675179a18099939ca44eeabe Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 19 Feb 2024 10:27:23 +1100 Subject: [PATCH 14/17] Refactor `run_global_ctxt`. It currently is infallible and uses `abort_if_errors` and `FatalError.raise()` to signal errors. It's easy to instead return a `Result<_, ErrorGuaranteed>`, which is the more usual way of doing things. --- src/librustdoc/core.rs | 15 +++++++++------ src/librustdoc/lib.rs | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 3f7edd049a713..c662f054d0524 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -3,7 +3,7 @@ use rustc_data_structures::sync::Lrc; use rustc_data_structures::unord::UnordSet; use rustc_errors::emitter::{DynEmitter, HumanEmitter}; use rustc_errors::json::JsonEmitter; -use rustc_errors::{codes::*, TerminalUrl}; +use rustc_errors::{codes::*, ErrorGuaranteed, TerminalUrl}; use rustc_feature::UnstableFeatures; use rustc_hir::def::Res; use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId}; @@ -306,7 +306,7 @@ pub(crate) fn run_global_ctxt( show_coverage: bool, render_options: RenderOptions, output_format: OutputFormat, -) -> (clean::Crate, RenderOptions, Cache) { +) -> Result<(clean::Crate, RenderOptions, Cache), ErrorGuaranteed> { // Certain queries assume that some checks were run elsewhere // (see https://github.com/rust-lang/rust/pull/73566#issuecomment-656954425), // so type-check everything other than function bodies in this crate before running lints. @@ -331,7 +331,10 @@ pub(crate) fn run_global_ctxt( }); }); - tcx.dcx().abort_if_errors(); + if let Some(guar) = tcx.dcx().has_errors() { + return Err(guar); + } + tcx.sess.time("missing_docs", || rustc_lint::check_crate(tcx)); tcx.sess.time("check_mod_attrs", || { tcx.hir().for_each_module(|module| tcx.ensure().check_mod_attrs(module)) @@ -452,13 +455,13 @@ pub(crate) fn run_global_ctxt( tcx.sess.time("check_lint_expectations", || tcx.check_expectations(Some(sym::rustdoc))); - if tcx.dcx().has_errors().is_some() { - rustc_errors::FatalError.raise(); + if let Some(guar) = tcx.dcx().has_errors() { + return Err(guar); } krate = tcx.sess.time("create_format_cache", || Cache::populate(&mut ctxt, krate)); - (krate, ctxt.render_options, ctxt.cache) + Ok((krate, ctxt.render_options, ctxt.cache)) } /// Due to , diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 18ea49c5baf1b..f88381ad788d6 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -787,7 +787,7 @@ fn main_args( gcx.enter(|tcx| { let (krate, render_opts, mut cache) = sess.time("run_global_ctxt", || { core::run_global_ctxt(tcx, show_coverage, render_options, output_format) - }); + })?; info!("finished with rustc"); if let Some(options) = scrape_examples_options { From 2eb88a7ba768228f631fc70e5414623847166b84 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 19 Feb 2024 10:23:58 +1100 Subject: [PATCH 15/17] Replace unnecessary `abort_if_errors`. Replace `abort_if_errors` calls that are certain to abort -- because we emit an error immediately beforehand -- with `FatalErro.raise()`. --- compiler/rustc_codegen_ssa/src/back/link.rs | 9 +++------ compiler/rustc_codegen_ssa/src/base.rs | 5 +---- compiler/rustc_errors/src/lib.rs | 4 ++++ compiler/rustc_interface/src/passes.rs | 4 +--- compiler/rustc_session/src/output.rs | 3 ++- .../src/traits/error_reporting/type_err_ctxt_ext.rs | 11 ++--------- 6 files changed, 13 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 7e3f324fe14c2..1ad0dec064006 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -3,7 +3,7 @@ use rustc_ast::CRATE_NODE_ID; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::temp_dir::MaybeTempDir; -use rustc_errors::{DiagCtxt, ErrorGuaranteed}; +use rustc_errors::{DiagCtxt, ErrorGuaranteed, FatalError}; use rustc_fs_util::{fix_windows_verbatim_for_gcc, try_canonicalize}; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_metadata::find_native_static_library; @@ -722,10 +722,7 @@ fn link_dwarf_object<'a>( Ok(()) }) { Ok(()) => {} - Err(e) => { - sess.dcx().emit_err(errors::ThorinErrorWrapper(e)); - sess.dcx().abort_if_errors(); - } + Err(e) => sess.dcx().emit_fatal(errors::ThorinErrorWrapper(e)), } } @@ -1001,7 +998,7 @@ fn link_natively<'a>( sess.dcx().emit_note(errors::CheckInstalledVisualStudio); sess.dcx().emit_note(errors::InsufficientVSCodeProduct); } - sess.dcx().abort_if_errors(); + FatalError.raise(); } } diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 760b3f30ee51e..f7afd22a48cab 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -449,10 +449,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let Some(llfn) = cx.declare_c_main(llfty) else { // FIXME: We should be smart and show a better diagnostic here. let span = cx.tcx().def_span(rust_main_def_id); - let dcx = cx.tcx().dcx(); - dcx.emit_err(errors::MultipleMainFunctions { span }); - dcx.abort_if_errors(); - bug!(); + cx.tcx().dcx().emit_fatal(errors::MultipleMainFunctions { span }); }; // `main` should respect same config for frame pointer elimination as rest of code diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 32fac61305054..406435b5ec935 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -881,6 +881,10 @@ impl DiagCtxt { } } + /// This excludes delayed bugs and stashed errors. Used for early aborts + /// after errors occurred -- e.g. because continuing in the face of errors is + /// likely to lead to bad results, such as spurious/uninteresting + /// additional errors -- when returning an error `Result` is difficult. pub fn abort_if_errors(&self) { if self.has_errors().is_some() { FatalError.raise(); diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index d35c2be1fb47d..661401687593d 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -936,9 +936,7 @@ pub fn start_codegen<'tcx>( if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) { if let Err(error) = rustc_mir_transform::dump_mir::emit_mir(tcx) { - let dcx = tcx.dcx(); - dcx.emit_err(errors::CantEmitMIR { error }); - dcx.abort_if_errors(); + tcx.dcx().emit_fatal(errors::CantEmitMIR { error }); } } diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs index db976b3040487..74d26237f2463 100644 --- a/compiler/rustc_session/src/output.rs +++ b/compiler/rustc_session/src/output.rs @@ -6,6 +6,7 @@ use crate::errors::{ }; use crate::Session; use rustc_ast::{self as ast, attr}; +use rustc_errors::FatalError; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; use std::path::Path; @@ -115,7 +116,7 @@ pub fn validate_crate_name(sess: &Session, s: Symbol, sp: Option) { } if err_count > 0 { - sess.dcx().abort_if_errors(); + FatalError.raise(); } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 67bd18d74044f..8759b3e4e4151 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -22,7 +22,7 @@ use crate::traits::{ use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_errors::{ codes::*, pluralize, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, - ErrorGuaranteed, MultiSpan, StashKey, StringPart, + ErrorGuaranteed, FatalError, MultiSpan, StashKey, StringPart, }; use rustc_hir as hir; use rustc_hir::def::{DefKind, Namespace, Res}; @@ -193,14 +193,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let mut err = self.build_overflow_error(predicate, span, suggest_increasing_limit); mutate(&mut err); err.emit(); - - self.dcx().abort_if_errors(); - // FIXME: this should be something like `build_overflow_error_fatal`, which returns - // `DiagnosticBuilder<', !>`. Then we don't even need anything after that `emit()`. - unreachable!( - "did not expect compilation to continue after `abort_if_errors`, \ - since an error was definitely emitted!" - ); + FatalError.raise(); } fn build_overflow_error( From a094903e9cdd06e92cb3f15f8d2fc9dbfc491231 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 19 Feb 2024 13:51:53 +1100 Subject: [PATCH 16/17] Inline and remove `abort_on_err`. It's clumsy and doesn't improve readability. --- compiler/rustc_driver_impl/src/lib.rs | 17 ++++------------- compiler/rustc_driver_impl/src/pretty.rs | 14 ++++++++++---- src/librustdoc/lib.rs | 5 ++--- 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 1057235c0a2a8..692c059beb0c4 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -144,16 +144,6 @@ pub const EXIT_FAILURE: i32 = 1; pub const DEFAULT_BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust/issues/new\ ?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md"; -pub fn abort_on_err(result: Result, sess: &Session) -> T { - match result { - Err(..) => { - sess.dcx().abort_if_errors(); - panic!("error reported but abort_if_errors didn't abort???"); - } - Ok(x) => x, - } -} - pub trait Callbacks { /// Called before creating the compiler instance fn config(&mut self, _config: &mut interface::Config) {} @@ -665,10 +655,11 @@ fn process_rlink(sess: &Session, compiler: &interface::Compiler) { }; } }; - let result = compiler.codegen_backend.link(sess, codegen_results, &outputs); - abort_on_err(result, sess); + if compiler.codegen_backend.link(sess, codegen_results, &outputs).is_err() { + FatalError.raise(); + } } else { - dcx.emit_fatal(RlinkNotAFile {}) + dcx.emit_fatal(RlinkNotAFile {}); } } diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs index e5a7d5501151a..ff5ffd2454a1f 100644 --- a/compiler/rustc_driver_impl/src/pretty.rs +++ b/compiler/rustc_driver_impl/src/pretty.rs @@ -2,6 +2,7 @@ use rustc_ast as ast; use rustc_ast_pretty::pprust as pprust_ast; +use rustc_errors::FatalError; use rustc_hir as hir; use rustc_hir_pretty as pprust_hir; use rustc_middle::bug; @@ -18,7 +19,6 @@ use std::fmt::Write; pub use self::PpMode::*; pub use self::PpSourceMode::*; -use crate::abort_on_err; struct AstNoAnn; @@ -243,7 +243,9 @@ impl<'tcx> PrintExtra<'tcx> { pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) { if ppm.needs_analysis() { - abort_on_err(ex.tcx().analysis(()), sess); + if ex.tcx().analysis(()).is_err() { + FatalError.raise(); + } } let (src, src_name) = get_source(sess); @@ -334,7 +336,9 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) { ThirTree => { let tcx = ex.tcx(); let mut out = String::new(); - abort_on_err(rustc_hir_analysis::check_crate(tcx), tcx.sess); + if rustc_hir_analysis::check_crate(tcx).is_err() { + FatalError.raise(); + } debug!("pretty printing THIR tree"); for did in tcx.hir().body_owners() { let _ = writeln!(out, "{:?}:\n{}\n", did, tcx.thir_tree(did)); @@ -344,7 +348,9 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) { ThirFlat => { let tcx = ex.tcx(); let mut out = String::new(); - abort_on_err(rustc_hir_analysis::check_crate(tcx), tcx.sess); + if rustc_hir_analysis::check_crate(tcx).is_err() { + FatalError.raise(); + } debug!("pretty printing THIR flat"); for did in tcx.hir().body_owners() { let _ = writeln!(out, "{:?}:\n{}\n", did, tcx.thir_flat(did)); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index f88381ad788d6..33837fe5652ce 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -78,8 +78,7 @@ use std::io::{self, IsTerminal}; use std::process; use std::sync::{atomic::AtomicBool, Arc}; -use rustc_driver::abort_on_err; -use rustc_errors::ErrorGuaranteed; +use rustc_errors::{ErrorGuaranteed, FatalError}; use rustc_interface::interface; use rustc_middle::ty::TyCtxt; use rustc_session::config::{make_crate_type_option, ErrorOutputType, RustcOptGroup}; @@ -779,7 +778,7 @@ fn main_args( } compiler.enter(|queries| { - let mut gcx = abort_on_err(queries.global_ctxt(), sess); + let Ok(mut gcx) = queries.global_ctxt() else { FatalError.raise() }; if sess.dcx().has_errors().is_some() { sess.dcx().fatal("Compilation failed, aborting rustdoc"); } From 42c4df01a8b498c56bf762c2307fb4a3c55293fe Mon Sep 17 00:00:00 2001 From: Gurinder Singh Date: Tue, 20 Feb 2024 07:41:48 +0530 Subject: [PATCH 17/17] Rename `ConstPropLint` to `KnownPanicsLint` It is a clearer name because it communicates what the lint does instead of the underlying mechanism it uses (const propagation). --- ...onst_prop_lint.rs => known_panics_lint.rs} | 32 ++++++++++--------- compiler/rustc_mir_transform/src/lib.rs | 4 +-- 2 files changed, 19 insertions(+), 17 deletions(-) rename compiler/rustc_mir_transform/src/{const_prop_lint.rs => known_panics_lint.rs} (97%) diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs similarity index 97% rename from compiler/rustc_mir_transform/src/const_prop_lint.rs rename to compiler/rustc_mir_transform/src/known_panics_lint.rs index 6f2ef8f9a4fdf..a9cd688c31551 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -1,5 +1,8 @@ -//! Propagates constants for early reporting of statically known -//! assertion failures +//! A lint that checks for known panics like +//! overflows, division by zero, +//! out-of-bound access etc. +//! Uses const propagation to determine the +//! values of operands during checks. use std::fmt::Debug; @@ -21,9 +24,9 @@ use crate::dataflow_const_prop::DummyMachine; use crate::errors::{AssertLint, AssertLintKind}; use crate::MirLint; -pub struct ConstPropLint; +pub struct KnownPanicsLint; -impl<'tcx> MirLint<'tcx> for ConstPropLint { +impl<'tcx> MirLint<'tcx> for KnownPanicsLint { fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { if body.tainted_by_errors.is_some() { return; @@ -37,31 +40,28 @@ impl<'tcx> MirLint<'tcx> for ConstPropLint { // Only run const prop on functions, methods, closures and associated constants if !is_fn_like && !is_assoc_const { // skip anon_const/statics/consts because they'll be evaluated by miri anyway - trace!("ConstPropLint skipped for {:?}", def_id); + trace!("KnownPanicsLint skipped for {:?}", def_id); return; } // FIXME(welseywiser) const prop doesn't work on coroutines because of query cycles // computing their layout. if tcx.is_coroutine(def_id.to_def_id()) { - trace!("ConstPropLint skipped for coroutine {:?}", def_id); + trace!("KnownPanicsLint skipped for coroutine {:?}", def_id); return; } - trace!("ConstPropLint starting for {:?}", def_id); + trace!("KnownPanicsLint starting for {:?}", def_id); - // FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold - // constants, instead of just checking for const-folding succeeding. - // That would require a uniform one-def no-mutation analysis - // and RPO (or recursing when needing the value of a local). let mut linter = ConstPropagator::new(body, tcx); linter.visit_body(body); - trace!("ConstPropLint done for {:?}", def_id); + trace!("KnownPanicsLint done for {:?}", def_id); } } -/// Finds optimization opportunities on the MIR. +/// Visits MIR nodes, performs const propagation +/// and runs lint checks as it goes struct ConstPropagator<'mir, 'tcx> { ecx: InterpCx<'mir, 'tcx, DummyMachine>, tcx: TyCtxt<'tcx>, @@ -238,7 +238,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // dedicated error variants should be introduced instead. assert!( !error.kind().formatted_string(), - "const-prop encountered formatting error: {}", + "known panics lint encountered formatting error: {}", format_interp_error(self.ecx.tcx.dcx(), error), ); None @@ -253,7 +253,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { return None; } - // Normalization needed b/c const prop lint runs in + // Normalization needed b/c known panics lint runs in // `mir_drops_elaborated_and_const_checked`, which happens before // optimized MIR. Only after optimizing the MIR can we guarantee // that the `RevealAll` pass has happened and that the body's consts @@ -864,6 +864,8 @@ pub enum ConstPropMode { NoPropagation, } +/// A visitor that determines locals in a MIR body +/// that can be const propagated pub struct CanConstProp { can_const_prop: IndexVec, // False at the beginning. Once set, no more assignments are allowed to that local. diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 74b36eb5ee89e..945c3c662a604 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -59,7 +59,6 @@ mod remove_place_mention; mod add_subtyping_projections; pub mod cleanup_post_borrowck; mod const_debuginfo; -mod const_prop_lint; mod copy_prop; mod coroutine; mod cost_checker; @@ -83,6 +82,7 @@ mod gvn; pub mod inline; mod instsimplify; mod jump_threading; +mod known_panics_lint; mod large_enums; mod lint; mod lower_intrinsics; @@ -533,7 +533,7 @@ fn run_runtime_lowering_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &elaborate_box_derefs::ElaborateBoxDerefs, &coroutine::StateTransform, &add_retag::AddRetag, - &Lint(const_prop_lint::ConstPropLint), + &Lint(known_panics_lint::KnownPanicsLint), ]; pm::run_passes_no_validate(tcx, body, passes, Some(MirPhase::Runtime(RuntimePhase::Initial))); }