From 2326f42ce2529330ffbd1b865b90338bd4bf17fd Mon Sep 17 00:00:00 2001 From: Dylan DPC Date: Tue, 25 Oct 2022 18:07:21 +0530 Subject: [PATCH 0001/1197] stabilise array methods --- library/alloc/src/lib.rs | 1 - library/core/src/array/mod.rs | 9 ++------- library/core/tests/lib.rs | 1 - src/librustdoc/lib.rs | 1 - 4 files changed, 2 insertions(+), 10 deletions(-) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index ce36b116f139b..a222871a84650 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -92,7 +92,6 @@ #![feature(allocator_api)] #![feature(array_chunks)] #![feature(array_into_iter_constructors)] -#![feature(array_methods)] #![feature(array_windows)] #![feature(assert_matches)] #![feature(async_iterator)] diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index eae0e1c761866..5fbf15f1a28ba 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -592,8 +592,6 @@ impl [T; N] { /// # Example /// /// ``` - /// #![feature(array_methods)] - /// /// let floats = [3.1, 2.7, -1.0]; /// let float_refs: [&f64; 3] = floats.each_ref(); /// assert_eq!(float_refs, [&3.1, &2.7, &-1.0]); @@ -604,8 +602,6 @@ impl [T; N] { /// array if its elements are not [`Copy`]. /// /// ``` - /// #![feature(array_methods)] - /// /// let strings = ["Ferris".to_string(), "♥".to_string(), "Rust".to_string()]; /// let is_ascii = strings.each_ref().map(|s| s.is_ascii()); /// assert_eq!(is_ascii, [true, false, true]); @@ -613,7 +609,7 @@ impl [T; N] { /// // We can still access the original array: it has not been moved. /// assert_eq!(strings.len(), 3); /// ``` - #[unstable(feature = "array_methods", issue = "76118")] + #[stable(feature = "array_methods", since = "CURRENT_RUSTC_VERSION")] pub fn each_ref(&self) -> [&T; N] { // SAFETY: we know for certain that this iterator will yield exactly `N` // items. @@ -627,7 +623,6 @@ impl [T; N] { /// # Example /// /// ``` - /// #![feature(array_methods)] /// /// let mut floats = [3.1, 2.7, -1.0]; /// let float_refs: [&mut f64; 3] = floats.each_mut(); @@ -635,7 +630,7 @@ impl [T; N] { /// assert_eq!(float_refs, [&mut 0.0, &mut 2.7, &mut -1.0]); /// assert_eq!(floats, [0.0, 2.7, -1.0]); /// ``` - #[unstable(feature = "array_methods", issue = "76118")] + #[stable(feature = "array_methods", since = "CURRENT_RUSTC_VERSION")] pub fn each_mut(&mut self) -> [&mut T; N] { // SAFETY: we know for certain that this iterator will yield exactly `N` // items. diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 3012a78b9c98e..dda8d27605b7e 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -1,6 +1,5 @@ #![feature(alloc_layout_extra)] #![feature(array_chunks)] -#![feature(array_methods)] #![feature(array_windows)] #![feature(bigint_helper_methods)] #![feature(cell_update)] diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 793061a9f7a06..f6b065505530c 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -3,7 +3,6 @@ html_playground_url = "https://play.rust-lang.org/" )] #![feature(rustc_private)] -#![feature(array_methods)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(control_flow_enum)] From cce93f0a04ebaa4a1807f2e7f43d47839926ba94 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 30 Jan 2023 10:35:08 +0000 Subject: [PATCH 0002/1197] Add `str::Lines::remainder` --- library/core/src/str/iter.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index d969475aa484f..fffa421a6462a 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -1137,6 +1137,31 @@ impl<'a> DoubleEndedIterator for Lines<'a> { #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Lines<'_> {} +impl<'a> Lines<'a> { + /// Returns the remaining lines of the split string. + /// + /// # Examples + /// + /// ``` + /// #![feature(str_lines_remainder)] + /// + /// let mut lines = "a\nb\nc\nd".lines(); + /// assert_eq!(lines.remainder(), Some("a\nb\nc\nd")); + /// + /// lines.next(); + /// assert_eq!(lines.remainder(), Some("b\nc\nd")); + /// + /// lines.by_ref().for_each(drop); + /// assert_eq!(lines.remainder(), None); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "str_lines_remainder", issue = "77998")] + pub fn remainder(&self) -> Option<&'a str> { + self.0.iter.remainder() + } +} + /// Created with the method [`lines_any`]. /// /// [`lines_any`]: str::lines_any From 6c87448b57890eabd11103fcb2ab8f5e687a02cc Mon Sep 17 00:00:00 2001 From: The 8472 Date: Wed, 21 Jun 2023 20:49:18 +0200 Subject: [PATCH 0003/1197] optimize Cstr/EscapeAscii display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit old: ascii::bench_ascii_escape_display_mixed 17.97µs/iter +/- 204.00ns ascii::bench_ascii_escape_display_no_escape 545.00ns/iter +/- 6.00ns new: ascii::bench_ascii_escape_display_mixed 4.99µs/iter +/- 56.00ns ascii::bench_ascii_escape_display_no_escape 91.00ns/iter +/- 1.00ns --- library/core/benches/ascii.rs | 28 ++++++++++++++++ library/core/src/ascii.rs | 11 ++++++ library/core/src/iter/adapters/flatten.rs | 8 +++++ library/core/src/iter/adapters/fuse.rs | 4 +++ library/core/src/iter/adapters/map.rs | 4 +++ library/core/src/slice/ascii.rs | 41 ++++++++++++++++++++++- library/core/tests/ascii.rs | 10 ++++++ 7 files changed, 105 insertions(+), 1 deletion(-) diff --git a/library/core/benches/ascii.rs b/library/core/benches/ascii.rs index 64938745a4a16..71ec9fed2fe75 100644 --- a/library/core/benches/ascii.rs +++ b/library/core/benches/ascii.rs @@ -63,6 +63,7 @@ macro_rules! benches { } } +use std::fmt::Write; use test::black_box; use test::Bencher; @@ -351,3 +352,30 @@ static ASCII_CHARACTER_CLASS: [AsciiCharacterClass; 256] = [ N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, ]; + +const ASCII_PATH: &[u8] = b"home/kyubey/rust/build/x86_64-unknown-linux-gnu/stage0/lib:/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-tools/release/deps"; +const RUST_INCANTATION: &[u8] = br#"AR_x86_64_unknown_linux_gnu="ar" CARGO_INCREMENTAL="0" CARGO_PROFILE_RELEASE_DEBUG="1" CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS="false" CARGO_PROFILE_RELEASE_OVERFLOW_CHECKS="false" CARGO_TARGET_DIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-std" CC_x86_64_unknown_linux_gnu="cc" CFG_COMPILER_HOST_TRIPLE="x86_64-unknown-linux-gnu" CFG_RELEASE_CHANNEL="dev" CFLAGS_x86_64_unknown_linux_gnu="-ffunction-sections -fdata-sections -fPIC -m64" CXXFLAGS_x86_64_unknown_linux_gnu="-ffunction-sections -fdata-sections -fPIC -m64" CXX_x86_64_unknown_linux_gnu="c++" LD_LIBRARY_PATH="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-sysroot/lib/rustlib/x86_64-unknown-linux-gnu/lib" LIBC_CHECK_CFG="1" RANLIB_x86_64_unknown_linux_gnu="ar s" REAL_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" RUSTBUILD_NATIVE_DIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/native" RUSTC="/home/kyubey/workspace/rust/build/bootstrap/debug/rustc" RUSTC_BOOTSTRAP="1" RUSTC_BREAK_ON_ICE="1" RUSTC_ERROR_METADATA_DST="/home/kyubey/workspace/rust/build/tmp/extended-error-metadata" RUSTC_FORCE_UNSTABLE="1" RUSTC_HOST_FUSE_LD_LLD="1" RUSTC_INSTALL_BINDIR="bin" RUSTC_LIBDIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/lib" RUSTC_LINT_FLAGS="-Wrust_2018_idioms -Wunused_lifetimes -Wsemicolon_in_expressions_from_macros" RUSTC_REAL="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/bin/rustc" RUSTC_SNAPSHOT="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/bin/rustc" RUSTC_SNAPSHOT_LIBDIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/lib" RUSTC_STAGE="0" RUSTC_SYSROOT="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-sysroot" RUSTC_VERBOSE="0" RUSTDOC="/home/kyubey/workspace/rust/build/bootstrap/debug/rustdoc" RUSTDOCFLAGS="-C target-cpu=native --cfg=bootstrap -Csymbol-mangling-version=legacy -Zunstable-options -Zunstable-options --check-cfg=values(bootstrap) --check-cfg=values(stdarch_intel_sde) --check-cfg=values(no_fp_fmt_parse) --check-cfg=values(no_global_oom_handling) --check-cfg=values(no_rc) --check-cfg=values(no_sync) --check-cfg=values(freebsd12) --check-cfg=values(freebsd13) --check-cfg=values(backtrace_in_libstd) --check-cfg=values(target_env,\"libnx\") --check-cfg=values(target_arch,\"asmjs\",\"spirv\",\"nvptx\",\"xtensa\") -Clink-arg=-fuse-ld=lld -Clink-arg=-Wl,--threads=1 -Wrustdoc::invalid_codeblock_attributes --crate-version 1.72.0-dev -Zcrate-attr=doc(html_root_url=\"https://doc.rust-lang.org/nightly/\") -Zcrate-attr=warn(rust_2018_idioms)" RUSTDOC_FUSE_LD_LLD="1" RUSTDOC_LIBDIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/lib" RUSTDOC_REAL="/path/to/nowhere/rustdoc/not/required" RUSTFLAGS="-C target-cpu=native --cfg=bootstrap -Csymbol-mangling-version=legacy -Zunstable-options -Zunstable-options --check-cfg=values(bootstrap) --check-cfg=values(stdarch_intel_sde) --check-cfg=values(no_fp_fmt_parse) --check-cfg=values(no_global_oom_handling) --check-cfg=values(no_rc) --check-cfg=values(no_sync) --check-cfg=values(freebsd12) --check-cfg=values(freebsd13) --check-cfg=values(backtrace_in_libstd) --check-cfg=values(target_env,\"libnx\") --check-cfg=values(target_arch,\"asmjs\",\"spirv\",\"nvptx\",\"xtensa\") -Zmacro-backtrace -Clink-args=-Wl,-z,origin -Clink-args=-Wl,-rpath,$ORIGIN/../lib -Clink-args=-fuse-ld=lld -Csplit-debuginfo=off -Cprefer-dynamic -Zinline-mir -Clto=off -Zcrate-attr=doc(html_root_url=\"https://doc.rust-lang.org/nightly/\")" RUST_COMPILER_RT_ROOT="/home/kyubey/workspace/rust/src/llvm-project/compiler-rt" RUST_TEST_THREADS="48" WINAPI_NO_BUNDLED_LIBRARIES="1" __CARGO_DEFAULT_LIB_METADATA="bootstrapstd" "/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "bench" "--target" "x86_64-unknown-linux-gnu" "-Zcheck-cfg=names,values,output" "-Zbinary-dep-depinfo" "-j" "48" "--features" " panic-unwind backtrace compiler-builtins-c" "--manifest-path" "/home/kyubey/workspace/rust/library/sysroot/Cargo.toml" "-p" "core" "--" "bench_ascii_escape_display" "--quiet" "-Z" "unstable-options" "--format" "json""#; + +#[bench] +fn bench_ascii_escape_display_no_escape(b: &mut Bencher) { + let mut writer = String::with_capacity(8 * 1024); + + b.iter(move || { + writer.clear(); + let iter = ASCII_PATH.escape_ascii(); + write!(writer, "{}", iter).unwrap(); + writer.len() + }) +} + +#[bench] +fn bench_ascii_escape_display_mixed(b: &mut Bencher) { + let mut writer = String::with_capacity(8 * 1024); + + b.iter(move || { + writer.clear(); + let iter = RUST_INCANTATION.escape_ascii(); + write!(writer, "{}", iter).unwrap(); + writer.len() + }) +} diff --git a/library/core/src/ascii.rs b/library/core/src/ascii.rs index ef8e4d098ed95..02867789b79dd 100644 --- a/library/core/src/ascii.rs +++ b/library/core/src/ascii.rs @@ -96,6 +96,17 @@ pub fn escape_default(c: u8) -> EscapeDefault { EscapeDefault(escape::EscapeIterInner::new(data, range)) } +impl EscapeDefault { + pub(crate) fn empty() -> Self { + let data = [Char::Null; 4]; + EscapeDefault(escape::EscapeIterInner::new(data, 0..0)) + } + + pub(crate) fn as_str(&self) -> &str { + self.0.as_str() + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for EscapeDefault { type Item = u8; diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs index 2568aaf34f3fb..f3992b500adf8 100644 --- a/library/core/src/iter/adapters/flatten.rs +++ b/library/core/src/iter/adapters/flatten.rs @@ -18,6 +18,14 @@ impl U> FlatMap { pub(in crate::iter) fn new(iter: I, f: F) -> FlatMap { FlatMap { inner: FlattenCompat::new(iter.map(f)) } } + + pub(crate) fn into_parts(self) -> (Option, Option, Option) { + ( + self.inner.frontiter, + self.inner.iter.into_inner().map(Map::into_inner), + self.inner.backiter, + ) + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs index b1fa4f92117b1..e38234eae4990 100644 --- a/library/core/src/iter/adapters/fuse.rs +++ b/library/core/src/iter/adapters/fuse.rs @@ -24,6 +24,10 @@ impl Fuse { pub(in crate::iter) fn new(iter: I) -> Fuse { Fuse { iter: Some(iter) } } + + pub(crate) fn into_inner(self) -> Option { + self.iter + } } #[stable(feature = "fused", since = "1.26.0")] diff --git a/library/core/src/iter/adapters/map.rs b/library/core/src/iter/adapters/map.rs index 31d02a4da6ea5..2563f27d16933 100644 --- a/library/core/src/iter/adapters/map.rs +++ b/library/core/src/iter/adapters/map.rs @@ -68,6 +68,10 @@ impl Map { pub(in crate::iter) fn new(iter: I, f: F) -> Map { Map { iter, f } } + + pub(crate) fn into_inner(self) -> I { + self.iter + } } #[stable(feature = "core_impl_debug", since = "1.9.0")] diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index f3311f76a7f06..324bf5c05af20 100644 --- a/library/core/src/slice/ascii.rs +++ b/library/core/src/slice/ascii.rs @@ -5,6 +5,7 @@ use crate::fmt::{self, Write}; use crate::iter; use crate::mem; use crate::ops; +use core::ascii::EscapeDefault; #[cfg(not(test))] impl [u8] { @@ -250,7 +251,45 @@ impl<'a> iter::FusedIterator for EscapeAscii<'a> {} #[stable(feature = "inherent_ascii_escape", since = "1.60.0")] impl<'a> fmt::Display for EscapeAscii<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.clone().try_for_each(|b| f.write_char(b as char)) + // disassemble iterator, including front/back parts of flatmap in case it has been partially consumed + let (front, slice, back) = self.clone().inner.into_parts(); + let front = front.unwrap_or(EscapeDefault::empty()); + let mut bytes = slice.unwrap_or_default().as_slice(); + let back = back.unwrap_or(EscapeDefault::empty()); + + // usually empty, so the formatter won't have to do any work + for byte in front { + f.write_char(byte as char)?; + } + + fn needs_escape(b: u8) -> bool { + b > 0x7E || b < 0x20 || b == b'\\' || b == b'\'' || b == b'"' + } + + while bytes.len() > 0 { + // fast path for the printable, non-escaped subset of ascii + let prefix = bytes.iter().take_while(|&&b| !needs_escape(b)).count(); + // SAFETY: prefix length was derived by counting bytes in the same splice, so it's in-bounds + let (prefix, remainder) = unsafe { bytes.split_at_unchecked(prefix) }; + // SAFETY: prefix is a valid utf8 sequence, as it's a subset of ASCII + let prefix = unsafe { crate::str::from_utf8_unchecked(prefix) }; + + f.write_str(prefix)?; // the fast part + + bytes = remainder; + + if let Some(&b) = bytes.first() { + // guaranteed to be non-empty, better to write it as a str + f.write_str(ascii::escape_default(b).as_str())?; + bytes = &bytes[1..]; + } + } + + // also usually empty + for byte in back { + f.write_char(byte as char)?; + } + Ok(()) } } #[stable(feature = "inherent_ascii_escape", since = "1.60.0")] diff --git a/library/core/tests/ascii.rs b/library/core/tests/ascii.rs index f5f2dd0477885..3d3f8ac10c603 100644 --- a/library/core/tests/ascii.rs +++ b/library/core/tests/ascii.rs @@ -479,3 +479,13 @@ fn ascii_ctype_const() { is_ascii_control => [false, false, false, false, false]; } } + +#[test] +fn test_ascii_display() { + assert_eq!(b"foo'bar".escape_ascii().to_string(), r#"foo\'bar"#); + assert_eq!(b"\0\xff".escape_ascii().to_string(), r#"\x00\xff"#); + let mut it = b"\0fastpath\xffremainder\xff".escape_ascii(); + let _ = it.advance_by(4); + let _ = it.advance_back_by(4); + assert_eq!(it.to_string(), r#"fastpath\xffremainder"#); +} From bab8d29887a0d801fe72f922dafe75a635bc9198 Mon Sep 17 00:00:00 2001 From: Tristan Guichaoua Date: Sat, 8 Jul 2023 19:55:33 +0200 Subject: [PATCH 0004/1197] impl `From<&[T; N]>` for `Cow<[T]>` --- library/alloc/src/vec/cow.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/library/alloc/src/vec/cow.rs b/library/alloc/src/vec/cow.rs index 2c799605b7b67..7d2462ee32e0c 100644 --- a/library/alloc/src/vec/cow.rs +++ b/library/alloc/src/vec/cow.rs @@ -15,6 +15,19 @@ impl<'a, T: Clone> From<&'a [T]> for Cow<'a, [T]> { } } +#[unstable(feature = "cow_from_array_ref", issue = "none")] +impl<'a, T: Clone, const N: usize> From<&'a [T; N]> for Cow<'a, [T]> { + /// Creates a [`Borrowed`] variant of [`Cow`] + /// from a reference to an array. + /// + /// This conversion does not allocate or clone the data. + /// + /// [`Borrowed`]: crate::borrow::Cow::Borrowed + fn from(s: &'a [T; N]) -> Cow<'a, [T]> { + Cow::Borrowed(s as &[_]) + } +} + #[stable(feature = "cow_from_vec", since = "1.8.0")] impl<'a, T: Clone> From> for Cow<'a, [T]> { /// Creates an [`Owned`] variant of [`Cow`] From 6bfad315265cc36d461dedf19f64e445c872da0c Mon Sep 17 00:00:00 2001 From: Tristan Guichaoua Date: Sat, 8 Jul 2023 20:11:47 +0200 Subject: [PATCH 0005/1197] mark as stable --- library/alloc/src/vec/cow.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/vec/cow.rs b/library/alloc/src/vec/cow.rs index 7d2462ee32e0c..b12910f3690b5 100644 --- a/library/alloc/src/vec/cow.rs +++ b/library/alloc/src/vec/cow.rs @@ -15,7 +15,7 @@ impl<'a, T: Clone> From<&'a [T]> for Cow<'a, [T]> { } } -#[unstable(feature = "cow_from_array_ref", issue = "none")] +#[stable(feature = "cow_from_array_ref", since = "CURRENT_RUSTC_VERSION")] impl<'a, T: Clone, const N: usize> From<&'a [T; N]> for Cow<'a, [T]> { /// Creates a [`Borrowed`] variant of [`Cow`] /// from a reference to an array. From fbaa7fc85e1462b9fd8ca6c091327f765a9f4821 Mon Sep 17 00:00:00 2001 From: WiktorPrzetacznik Date: Tue, 18 Jul 2023 17:42:28 +0200 Subject: [PATCH 0006/1197] std::error::Error -> Trait Implementations: lifetimes consistency improvement --- library/alloc/src/boxed.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 8697a77db3bc8..bd341976cd4f8 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -2276,7 +2276,7 @@ impl<'a, E: Error + Send + Sync + 'a> From for Box for Box { +impl<'a> From for Box { /// Converts a [`String`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. /// /// # Examples @@ -2291,7 +2291,7 @@ impl From for Box { /// mem::size_of::>() == mem::size_of_val(&a_boxed_error)) /// ``` #[inline] - fn from(err: String) -> Box { + fn from(err: String) -> Box { struct StringError(String); impl Error for StringError { @@ -2320,7 +2320,7 @@ impl From for Box { #[cfg(not(no_global_oom_handling))] #[stable(feature = "string_box_error", since = "1.6.0")] -impl From for Box { +impl<'a> From for Box { /// Converts a [`String`] into a box of dyn [`Error`]. /// /// # Examples @@ -2333,7 +2333,7 @@ impl From for Box { /// let a_boxed_error = Box::::from(a_string_error); /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) /// ``` - fn from(str_err: String) -> Box { + fn from(str_err: String) -> Box { let err1: Box = From::from(str_err); let err2: Box = err1; err2 @@ -2366,7 +2366,7 @@ impl<'a> From<&str> for Box { #[cfg(not(no_global_oom_handling))] #[stable(feature = "string_box_error", since = "1.6.0")] -impl From<&str> for Box { +impl<'a> From<&str> for Box { /// Converts a [`str`] into a box of dyn [`Error`]. /// /// [`str`]: prim@str @@ -2381,7 +2381,7 @@ impl From<&str> for Box { /// let a_boxed_error = Box::::from(a_str_error); /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) /// ``` - fn from(err: &str) -> Box { + fn from(err: &str) -> Box { From::from(String::from(err)) } } @@ -2410,7 +2410,7 @@ impl<'a, 'b> From> for Box { #[cfg(not(no_global_oom_handling))] #[stable(feature = "cow_box_error", since = "1.22.0")] -impl<'a> From> for Box { +impl<'a, 'b> From> for Box { /// Converts a [`Cow`] into a box of dyn [`Error`]. /// /// # Examples @@ -2424,7 +2424,7 @@ impl<'a> From> for Box { /// let a_boxed_error = Box::::from(a_cow_str_error); /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) /// ``` - fn from(err: Cow<'a, str>) -> Box { + fn from(err: Cow<'b, str>) -> Box { From::from(String::from(err)) } } From 9ced08956902e7aeb6fd52c05fbac935de11c699 Mon Sep 17 00:00:00 2001 From: Taras Tsugrii Date: Sat, 29 Jul 2023 19:42:22 -0700 Subject: [PATCH 0007/1197] [rustc_data_structures] Use partition_point to find binary_search_slice end. --- .../src/binary_search_util/mod.rs | 29 +++++-------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_data_structures/src/binary_search_util/mod.rs b/compiler/rustc_data_structures/src/binary_search_util/mod.rs index bc8a6b9eac0c3..332ad8af33bc6 100644 --- a/compiler/rustc_data_structures/src/binary_search_util/mod.rs +++ b/compiler/rustc_data_structures/src/binary_search_util/mod.rs @@ -14,31 +14,18 @@ where let start = data.partition_point(|x| key_fn(x) < *key); // At this point `start` either points at the first entry with equal or // greater key or is equal to `size` in case all elements have smaller keys + // Invariant: start == size || key_fn(&data[start]) >= *key if start == size || key_fn(&data[start]) != *key { return &[]; }; + // Invariant: start < size && key_fn(&data[start]) == *key - // Now search forward to find the *last* one. - let mut end = start; - let mut previous = start; - let mut step = 1; - loop { - end = end.saturating_add(step).min(size); - if end == size || key_fn(&data[end]) != *key { - break; - } - previous = end; - step *= 2; - } - step = end - previous; - while step > 1 { - let half = step / 2; - let mid = end - half; - if key_fn(&data[mid]) != *key { - end = mid; - } - step -= half; - } + // Find the first entry with key > `key`. Skip `start` entries since + // key_fn(&data[start]) == *key + // Invariant: offset == size || key_fn(&data[offset]) >= *key + let offset = start + 1; + let end = data[offset..].partition_point(|x| key_fn(x) <= *key) + offset; + // Invariant: end == size || key_fn(&data[end]) > *key &data[start..end] } From 3f1ad47b88f973a660dfc99d6f51e77e4e4e4d5e Mon Sep 17 00:00:00 2001 From: Wiktor Przetacznik <85874198+WiktorPrzetacznik@users.noreply.github.com> Date: Tue, 29 Aug 2023 14:09:41 +0200 Subject: [PATCH 0008/1197] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 8a6c559b0b312..59592341d088a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +PR #113833 - https://github.com/rust-lang/rust/pull/113833 + # The Rust Programming Language [![Rust Community](https://img.shields.io/badge/Rust_Community%20-Join_us-brightgreen?style=plastic&logo=rust)](https://www.rust-lang.org/community) From 1da87ee4b31fd1238fe73a42179e5460120d5e2e Mon Sep 17 00:00:00 2001 From: Wiktor Przetacznik Date: Tue, 29 Aug 2023 14:49:09 +0200 Subject: [PATCH 0009/1197] Revert "Update README.md" This reverts commit 3f1ad47b88f973a660dfc99d6f51e77e4e4e4d5e. --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 59592341d088a..8a6c559b0b312 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,3 @@ -PR #113833 - https://github.com/rust-lang/rust/pull/113833 - # The Rust Programming Language [![Rust Community](https://img.shields.io/badge/Rust_Community%20-Join_us-brightgreen?style=plastic&logo=rust)](https://www.rust-lang.org/community) From a20866254c6864e49814d6abd47a37fd01bcff0a Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Thu, 12 Oct 2023 15:35:03 -0700 Subject: [PATCH 0010/1197] References refer to allocated objects --- library/core/src/primitive_docs.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 380a21b376bde..e73d5f990cbac 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1389,6 +1389,18 @@ mod prim_usize {} /// work on references as well as they do on owned values! The implementations described here are /// meant for generic contexts, where the final type `T` is a type parameter or otherwise not /// locally known. +/// +/// # Safety +/// +/// For all types, `T: ?Sized`, and for all `t: &T` or `t: &mut T`, unsafe code may assume that +/// the following properties hold. It is undefined behavior to produce a `t: &T` or `t: &mut T` +/// which violates any of these properties. +/// +/// * `t` is aligned to `align_of_val(t)` +/// * `t` refers to a valid instance of `T` +/// * `t` refers to a single [allocated object] +/// +/// [allocated object]: ptr#allocated-object #[stable(feature = "rust1", since = "1.0.0")] mod prim_ref {} From 4f0192a756f756db6bd1c25a8dbe6e89f0086661 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Thu, 12 Oct 2023 18:55:45 -0700 Subject: [PATCH 0011/1197] Update primitive_docs.rs --- library/core/src/primitive_docs.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index e73d5f990cbac..04ae8c223f2cb 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1397,7 +1397,6 @@ mod prim_usize {} /// which violates any of these properties. /// /// * `t` is aligned to `align_of_val(t)` -/// * `t` refers to a valid instance of `T` /// * `t` refers to a single [allocated object] /// /// [allocated object]: ptr#allocated-object From 39660c4a77d3dda7f5d57a8d91faa946fff5192b Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Fri, 13 Oct 2023 09:47:39 -0700 Subject: [PATCH 0012/1197] Update library/core/src/primitive_docs.rs Co-authored-by: Ralf Jung --- library/core/src/primitive_docs.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 04ae8c223f2cb..cde49aeb687f0 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1397,7 +1397,11 @@ mod prim_usize {} /// which violates any of these properties. /// /// * `t` is aligned to `align_of_val(t)` -/// * `t` refers to a single [allocated object] +/// * `t` is dereferenceable for `size_of_val(t)` many bytes +/// +/// Being "dereferenceable" for N bytes means that the memory range beginning +/// at the address `t` points to and ending N bytes later is all contained within a +/// single [allocated object]. /// /// [allocated object]: ptr#allocated-object #[stable(feature = "rust1", since = "1.0.0")] From 55487e235b106088ced4e5b4710fa8f9674baaf9 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Fri, 13 Oct 2023 09:49:23 -0700 Subject: [PATCH 0013/1197] Update primitive_docs.rs --- library/core/src/primitive_docs.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index cde49aeb687f0..19ff41697d9fc 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1399,9 +1399,8 @@ mod prim_usize {} /// * `t` is aligned to `align_of_val(t)` /// * `t` is dereferenceable for `size_of_val(t)` many bytes /// -/// Being "dereferenceable" for N bytes means that the memory range beginning -/// at the address `t` points to and ending N bytes later is all contained within a -/// single [allocated object]. +/// If `t` points at address `a`, being "dereferenceable" for N bytes means that the memory range +/// `[a, a + N)` is all contained within a single [allocated object]. /// /// [allocated object]: ptr#allocated-object #[stable(feature = "rust1", since = "1.0.0")] From 42b1406d9e0be812b1faeefcdd7c61fd788e1043 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Mon, 30 Oct 2023 21:16:23 -0400 Subject: [PATCH 0014/1197] Make `allow_internal_unstable` work with `stmt_expr_attributes` --- compiler/rustc_expand/src/config.rs | 4 +++- tests/ui/internal/internal-unstable.rs | 10 ++++++++++ tests/ui/internal/internal-unstable.stderr | 8 ++++---- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index bef48765937f5..438796218d449 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -449,7 +449,9 @@ impl<'a> StripUnconfigured<'a> { /// If attributes are not allowed on expressions, emit an error for `attr` #[instrument(level = "trace", skip(self))] pub(crate) fn maybe_emit_expr_attr_err(&self, attr: &Attribute) { - if self.features.is_some_and(|features| !features.stmt_expr_attributes) { + if self.features.is_some_and(|features| !features.stmt_expr_attributes) + && !attr.span.allows_unstable(sym::stmt_expr_attributes) + { let mut err = feature_err( &self.sess.parse_sess, sym::stmt_expr_attributes, diff --git a/tests/ui/internal/internal-unstable.rs b/tests/ui/internal/internal-unstable.rs index 1eb27fbdc3a63..a4445fefef57d 100644 --- a/tests/ui/internal/internal-unstable.rs +++ b/tests/ui/internal/internal-unstable.rs @@ -28,6 +28,14 @@ macro_rules! bar { }} } +#[allow_internal_unstable(stmt_expr_attributes)] +macro_rules! internal_attr { + ($e: expr) => { + #[allow(overflowing_literals)] + $e + } +} + fn main() { // ok, the instability is contained. call_unstable_allow!(); @@ -51,4 +59,6 @@ fn main() { #[allow_internal_unstable] _ => {} } + + assert_eq!(internal_attr!(1e100_f32), f32::INFINITY); } diff --git a/tests/ui/internal/internal-unstable.stderr b/tests/ui/internal/internal-unstable.stderr index b7c47365c2d27..cf741505fa42f 100644 --- a/tests/ui/internal/internal-unstable.stderr +++ b/tests/ui/internal/internal-unstable.stderr @@ -1,5 +1,5 @@ error[E0658]: use of unstable library feature 'function' - --> $DIR/internal-unstable.rs:40:25 + --> $DIR/internal-unstable.rs:48:25 | LL | pass_through_allow!(internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | pass_through_allow!(internal_unstable::unstable()); = help: add `#![feature(function)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'function' - --> $DIR/internal-unstable.rs:42:27 + --> $DIR/internal-unstable.rs:50:27 | LL | pass_through_noallow!(internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | pass_through_noallow!(internal_unstable::unstable()); = help: add `#![feature(function)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'function' - --> $DIR/internal-unstable.rs:46:22 + --> $DIR/internal-unstable.rs:54:22 | LL | println!("{:?}", internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | println!("{:?}", internal_unstable::unstable()); = help: add `#![feature(function)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'function' - --> $DIR/internal-unstable.rs:48:10 + --> $DIR/internal-unstable.rs:56:10 | LL | bar!(internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 1a0309afb62b01002c1ac2466a6af0dc69594596 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Fri, 3 Nov 2023 06:41:23 -0700 Subject: [PATCH 0015/1197] Update primitive_docs.rs --- library/core/src/primitive_docs.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 19ff41697d9fc..939342c4d9760 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1393,8 +1393,9 @@ mod prim_usize {} /// # Safety /// /// For all types, `T: ?Sized`, and for all `t: &T` or `t: &mut T`, unsafe code may assume that -/// the following properties hold. It is undefined behavior to produce a `t: &T` or `t: &mut T` -/// which violates any of these properties. +/// the following properties hold. Rust programmers must assume that, unless explicitly stated +/// otherwise, any Rust code they did not author themselves may rely on these properties, and that +/// violating them may cause that code to exhibit undefined behavior. /// /// * `t` is aligned to `align_of_val(t)` /// * `t` is dereferenceable for `size_of_val(t)` many bytes From 55020c6f2f4aeac24e24d9bf4a623415c83c4608 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 3 Nov 2023 19:59:26 -0500 Subject: [PATCH 0016/1197] Reverse ordering of `split_{first,last}_chunk` to be `(preceding, last)` These methods currently return `(last_chunk, preceding_slice)`, which matches the existing `split_x` methods that remove one item. Change these to instead return `(preceding_slice, last_chunk)` which matches string split methods, should be more intuitive, and will allow for consistency with methods that split more items. --- library/core/src/slice/mod.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 45080eda2ce2f..970b1cb4f1d70 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -456,15 +456,15 @@ impl [T] { /// /// let x = &[0, 1, 2]; /// - /// if let Some((last, elements)) = x.split_last_chunk::<2>() { - /// assert_eq!(last, &[1, 2]); + /// if let Some((elements, last)) = x.split_last_chunk::<2>() { /// assert_eq!(elements, &[0]); + /// assert_eq!(last, &[1, 2]); /// } /// ``` #[unstable(feature = "slice_first_last_chunk", issue = "111774")] #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")] #[inline] - pub const fn split_last_chunk(&self) -> Option<(&[T; N], &[T])> { + pub const fn split_last_chunk(&self) -> Option<(&[T], &[T; N])> { if self.len() < N { None } else { @@ -473,7 +473,7 @@ impl [T] { // SAFETY: We explicitly check for the correct number of elements, // and do not let the references outlive the slice. - Some((unsafe { &*(last.as_ptr() as *const [T; N]) }, init)) + Some((init, unsafe { &*(last.as_ptr() as *const [T; N]) })) } } @@ -486,7 +486,7 @@ impl [T] { /// /// let x = &mut [0, 1, 2]; /// - /// if let Some((last, elements)) = x.split_last_chunk_mut::<2>() { + /// if let Some((elements, last)) = x.split_last_chunk_mut::<2>() { /// last[0] = 3; /// last[1] = 4; /// elements[0] = 5; @@ -498,7 +498,7 @@ impl [T] { #[inline] pub const fn split_last_chunk_mut( &mut self, - ) -> Option<(&mut [T; N], &mut [T])> { + ) -> Option<(&mut [T], &mut [T; N])> { if self.len() < N { None } else { @@ -508,7 +508,7 @@ impl [T] { // SAFETY: We explicitly check for the correct number of elements, // do not let the reference outlive the slice, // and enforce exclusive mutability of the chunk by the split. - Some((unsafe { &mut *(last.as_mut_ptr() as *mut [T; N]) }, init)) + Some((init, unsafe { &mut *(last.as_mut_ptr() as *mut [T; N]) })) } } From 6e8ec852f77f1ee21eaa6bdfffd63d5ae69d9002 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 3 Nov 2023 20:22:53 -0500 Subject: [PATCH 0017/1197] Make documentation of `slice_first_last_chunk` more consistent Clarify that these functions return array references. Also change from doing `as` casting to using the less misuseable `.cast()`. --- library/core/src/slice/mod.rs | 56 ++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 970b1cb4f1d70..7c07a86e2dd01 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -300,7 +300,7 @@ impl [T] { if let [.., last] = self { Some(last) } else { None } } - /// Returns a mutable pointer to the last item in the slice. + /// Returns a mutable reference to the last item in the slice. /// /// # Examples /// @@ -320,7 +320,9 @@ impl [T] { if let [.., last] = self { Some(last) } else { None } } - /// Returns the first `N` elements of the slice, or `None` if it has fewer than `N` elements. + /// Return an array reference to the first `N` items in the slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. /// /// # Examples /// @@ -345,12 +347,13 @@ impl [T] { } else { // SAFETY: We explicitly check for the correct number of elements, // and do not let the reference outlive the slice. - Some(unsafe { &*(self.as_ptr() as *const [T; N]) }) + Some(unsafe { &*(self.as_ptr().cast::<[T; N]>()) }) } } - /// Returns a mutable reference to the first `N` elements of the slice, - /// or `None` if it has fewer than `N` elements. + /// Return a mutable array reference to the first `N` items in the slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. /// /// # Examples /// @@ -375,12 +378,13 @@ impl [T] { // SAFETY: We explicitly check for the correct number of elements, // do not let the reference outlive the slice, // and require exclusive access to the entire slice to mutate the chunk. - Some(unsafe { &mut *(self.as_mut_ptr() as *mut [T; N]) }) + Some(unsafe { &mut *(self.as_mut_ptr().cast::<[T; N]>()) }) } } - /// Returns the first `N` elements of the slice and the remainder, - /// or `None` if it has fewer than `N` elements. + /// Return an array reference to the first `N` items in the slice and the remaining slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. /// /// # Examples /// @@ -406,12 +410,14 @@ impl [T] { // SAFETY: We explicitly check for the correct number of elements, // and do not let the references outlive the slice. - Some((unsafe { &*(first.as_ptr() as *const [T; N]) }, tail)) + Some((unsafe { &*(first.as_ptr().cast::<[T; N]>()) }, tail)) } } - /// Returns a mutable reference to the first `N` elements of the slice and the remainder, - /// or `None` if it has fewer than `N` elements. + /// Return a mutable array reference to the first `N` items in the slice and the remaining + /// slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. /// /// # Examples /// @@ -442,12 +448,13 @@ impl [T] { // SAFETY: We explicitly check for the correct number of elements, // do not let the reference outlive the slice, // and enforce exclusive mutability of the chunk by the split. - Some((unsafe { &mut *(first.as_mut_ptr() as *mut [T; N]) }, tail)) + Some((unsafe { &mut *(first.as_mut_ptr().cast::<[T; N]>()) }, tail)) } } - /// Returns the last `N` elements of the slice and the remainder, - /// or `None` if it has fewer than `N` elements. + /// Return an array reference to the last `N` items in the slice and the remaining slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. /// /// # Examples /// @@ -473,11 +480,14 @@ impl [T] { // SAFETY: We explicitly check for the correct number of elements, // and do not let the references outlive the slice. - Some((init, unsafe { &*(last.as_ptr() as *const [T; N]) })) + Some((init, unsafe { &*(last.as_ptr().cast::<[T; N]>()) })) } } - /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty. + /// Return a mutable array reference to the last `N` items in the slice and the remaining + /// slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. /// /// # Examples /// @@ -508,11 +518,13 @@ impl [T] { // SAFETY: We explicitly check for the correct number of elements, // do not let the reference outlive the slice, // and enforce exclusive mutability of the chunk by the split. - Some((init, unsafe { &mut *(last.as_mut_ptr() as *mut [T; N]) })) + Some((init, unsafe { &mut *(last.as_mut_ptr().cast::<[T; N]>()) })) } } - /// Returns the last element of the slice, or `None` if it is empty. + /// Return an array reference to the last `N` items in the slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. /// /// # Examples /// @@ -541,11 +553,13 @@ impl [T] { // SAFETY: We explicitly check for the correct number of elements, // and do not let the references outlive the slice. - Some(unsafe { &*(last.as_ptr() as *const [T; N]) }) + Some(unsafe { &*(last.as_ptr().cast::<[T; N]>()) }) } } - /// Returns a mutable pointer to the last item in the slice. + /// Return a mutable array reference to the last `N` items in the slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. /// /// # Examples /// @@ -574,7 +588,7 @@ impl [T] { // SAFETY: We explicitly check for the correct number of elements, // do not let the reference outlive the slice, // and require exclusive access to the entire slice to mutate the chunk. - Some(unsafe { &mut *(last.as_mut_ptr() as *mut [T; N]) }) + Some(unsafe { &mut *(last.as_mut_ptr().cast::<[T; N]>()) }) } } From 97bc528877b698df2f61dd743b1a155ca3f5eead Mon Sep 17 00:00:00 2001 From: Taras Tsugrii Date: Sun, 5 Nov 2023 17:35:37 -0600 Subject: [PATCH 0018/1197] Remove invariant comments --- compiler/rustc_data_structures/src/binary_search_util/mod.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/compiler/rustc_data_structures/src/binary_search_util/mod.rs b/compiler/rustc_data_structures/src/binary_search_util/mod.rs index 332ad8af33bc6..1c6e227cec408 100644 --- a/compiler/rustc_data_structures/src/binary_search_util/mod.rs +++ b/compiler/rustc_data_structures/src/binary_search_util/mod.rs @@ -14,18 +14,14 @@ where let start = data.partition_point(|x| key_fn(x) < *key); // At this point `start` either points at the first entry with equal or // greater key or is equal to `size` in case all elements have smaller keys - // Invariant: start == size || key_fn(&data[start]) >= *key if start == size || key_fn(&data[start]) != *key { return &[]; }; - // Invariant: start < size && key_fn(&data[start]) == *key // Find the first entry with key > `key`. Skip `start` entries since // key_fn(&data[start]) == *key - // Invariant: offset == size || key_fn(&data[offset]) >= *key let offset = start + 1; let end = data[offset..].partition_point(|x| key_fn(x) <= *key) + offset; - // Invariant: end == size || key_fn(&data[end]) > *key &data[start..end] } From 8c79f7840d399e3de52c63b1951a46adf6dda515 Mon Sep 17 00:00:00 2001 From: dswij Date: Tue, 7 Nov 2023 17:57:31 +0800 Subject: [PATCH 0019/1197] `read_zero_byte_vec` refactor for better heuristics --- clippy_lints/src/read_zero_byte_vec.rs | 118 +++++++++++++++---------- tests/ui/read_zero_byte_vec.rs | 29 ++++-- tests/ui/read_zero_byte_vec.stderr | 34 ++++--- 3 files changed, 112 insertions(+), 69 deletions(-) diff --git a/clippy_lints/src/read_zero_byte_vec.rs b/clippy_lints/src/read_zero_byte_vec.rs index b27d4cc6e4f8c..f5a8287d2e09f 100644 --- a/clippy_lints/src/read_zero_byte_vec.rs +++ b/clippy_lints/src/read_zero_byte_vec.rs @@ -1,11 +1,13 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::get_enclosing_block; use clippy_utils::higher::{get_vec_init_kind, VecInitKind}; use clippy_utils::source::snippet; -use clippy_utils::visitors::for_each_expr; -use core::ops::ControlFlow; -use hir::{Expr, ExprKind, Local, PatKind, PathSegment, QPath, StmtKind}; + +use hir::{Expr, ExprKind, HirId, Local, PatKind, PathSegment, QPath, StmtKind}; use rustc_errors::Applicability; use rustc_hir as hir; +use rustc_hir::def::Res; +use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -49,57 +51,40 @@ declare_lint_pass!(ReadZeroByteVec => [READ_ZERO_BYTE_VEC]); impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &hir::Block<'tcx>) { - for (idx, stmt) in block.stmts.iter().enumerate() { - if !stmt.span.from_expansion() - // matches `let v = Vec::new();` - && let StmtKind::Local(local) = stmt.kind - && let Local { pat, init: Some(init), .. } = local - && let PatKind::Binding(_, _, ident, _) = pat.kind + for stmt in block.stmts { + if stmt.span.from_expansion() { + return; + } + + if let StmtKind::Local(local) = stmt.kind + && let Local { + pat, init: Some(init), .. + } = local + && let PatKind::Binding(_, id, ident, _) = pat.kind && let Some(vec_init_kind) = get_vec_init_kind(cx, init) { - let visitor = |expr: &Expr<'_>| { - if let ExprKind::MethodCall(path, _, [arg], _) = expr.kind - && let PathSegment { - ident: read_or_read_exact, - .. - } = *path - && matches!(read_or_read_exact.as_str(), "read" | "read_exact") - && let ExprKind::AddrOf(_, hir::Mutability::Mut, inner) = arg.kind - && let ExprKind::Path(QPath::Resolved(None, inner_path)) = inner.kind - && let [inner_seg] = inner_path.segments - && ident.name == inner_seg.ident.name - { - ControlFlow::Break(()) - } else { - ControlFlow::Continue(()) - } + let mut visitor = ReadVecVisitor { + local_id: id, + read_zero_expr: None, + has_resize: false, }; - let (read_found, next_stmt_span) = if let Some(next_stmt) = block.stmts.get(idx + 1) { - // case { .. stmt; stmt; .. } - (for_each_expr(next_stmt, visitor).is_some(), next_stmt.span) - } else if let Some(e) = block.expr { - // case { .. stmt; expr } - (for_each_expr(e, visitor).is_some(), e.span) - } else { + let Some(enclosing_block) = get_enclosing_block(cx, id) else { return; }; + visitor.visit_block(enclosing_block); - if read_found && !next_stmt_span.from_expansion() { + if let Some(expr) = visitor.read_zero_expr { let applicability = Applicability::MaybeIncorrect; match vec_init_kind { VecInitKind::WithConstCapacity(len) => { span_lint_and_sugg( cx, READ_ZERO_BYTE_VEC, - next_stmt_span, + expr.span, "reading zero byte data to `Vec`", "try", - format!( - "{}.resize({len}, 0); {}", - ident.as_str(), - snippet(cx, next_stmt_span, "..") - ), + format!("{}.resize({len}, 0); {}", ident.as_str(), snippet(cx, expr.span, "..")), applicability, ); }, @@ -108,25 +93,20 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { span_lint_and_sugg( cx, READ_ZERO_BYTE_VEC, - next_stmt_span, + expr.span, "reading zero byte data to `Vec`", "try", format!( "{}.resize({}, 0); {}", ident.as_str(), snippet(cx, e.span, ".."), - snippet(cx, next_stmt_span, "..") + snippet(cx, expr.span, "..") ), applicability, ); }, _ => { - span_lint( - cx, - READ_ZERO_BYTE_VEC, - next_stmt_span, - "reading zero byte data to `Vec`", - ); + span_lint(cx, READ_ZERO_BYTE_VEC, expr.span, "reading zero byte data to `Vec`"); }, } } @@ -134,3 +114,47 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { } } } + +struct ReadVecVisitor<'tcx> { + local_id: HirId, + read_zero_expr: Option<&'tcx Expr<'tcx>>, + has_resize: bool, +} + +impl<'tcx> Visitor<'tcx> for ReadVecVisitor<'tcx> { + fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) { + if let ExprKind::MethodCall(path, receiver, args, _) = e.kind { + let PathSegment { ident, .. } = *path; + + match ident.as_str() { + "read" | "read_exact" => { + let [arg] = args else { return }; + if let ExprKind::AddrOf(_, hir::Mutability::Mut, inner) = arg.kind + && let ExprKind::Path(QPath::Resolved(None, inner_path)) = inner.kind + && let [inner_seg] = inner_path.segments + && let Res::Local(res_id) = inner_seg.res + && self.local_id == res_id + { + self.read_zero_expr = Some(e); + return; + } + }, + "resize" => { + // If the Vec is resized, then it's a valid read + if let ExprKind::Path(QPath::Resolved(_, inner_path)) = receiver.kind + && let Res::Local(res_id) = inner_path.res + && self.local_id == res_id + { + self.has_resize = true; + return; + } + }, + _ => {}, + } + } + + if !self.has_resize && self.read_zero_expr.is_none() { + walk_expr(self, e); + } + } +} diff --git a/tests/ui/read_zero_byte_vec.rs b/tests/ui/read_zero_byte_vec.rs index 76b9b98185119..fd5a88a37a66c 100644 --- a/tests/ui/read_zero_byte_vec.rs +++ b/tests/ui/read_zero_byte_vec.rs @@ -55,14 +55,6 @@ fn test() -> io::Result<()> { let mut buf = [0u8; 100]; f.read(&mut buf)?; - // should not lint - let mut empty = vec![]; - let mut data7 = vec![]; - f.read(&mut empty); - - // should not lint - f.read(&mut data7); - // should not lint let mut data8 = Vec::new(); data8.resize(100, 0); @@ -75,6 +67,27 @@ fn test() -> io::Result<()> { Ok(()) } +fn test_nested() -> io::Result<()> { + let cap = 1000; + let mut f = File::open("foo.txt").unwrap(); + + // Issue #9274 + // Should not lint + let mut v = Vec::new(); + { + v.resize(10, 0); + f.read(&mut v)?; + } + + let mut v = Vec::new(); + { + f.read(&mut v)?; + //~^ ERROR: reading zero byte data to `Vec` + } + + Ok(()) +} + async fn test_futures(r: &mut R) { // should lint let mut data = Vec::new(); diff --git a/tests/ui/read_zero_byte_vec.stderr b/tests/ui/read_zero_byte_vec.stderr index 523ecb2948df3..e85aa051c34bc 100644 --- a/tests/ui/read_zero_byte_vec.stderr +++ b/tests/ui/read_zero_byte_vec.stderr @@ -2,7 +2,7 @@ error: reading zero byte data to `Vec` --> $DIR/read_zero_byte_vec.rs:21:5 | LL | f.read_exact(&mut data).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `data.resize(20, 0); f.read_exact(&mut data).unwrap();` + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `data.resize(20, 0); f.read_exact(&mut data)` | = note: `-D clippy::read-zero-byte-vec` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::read_zero_byte_vec)]` @@ -11,19 +11,19 @@ error: reading zero byte data to `Vec` --> $DIR/read_zero_byte_vec.rs:27:5 | LL | f.read_exact(&mut data2)?; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `data2.resize(cap, 0); f.read_exact(&mut data2)?;` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `data2.resize(cap, 0); f.read_exact(&mut data2)` error: reading zero byte data to `Vec` --> $DIR/read_zero_byte_vec.rs:32:5 | LL | f.read_exact(&mut data3)?; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ error: reading zero byte data to `Vec` - --> $DIR/read_zero_byte_vec.rs:37:5 + --> $DIR/read_zero_byte_vec.rs:37:13 | LL | let _ = f.read(&mut data4)?; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ error: reading zero byte data to `Vec` --> $DIR/read_zero_byte_vec.rs:43:9 @@ -38,28 +38,34 @@ LL | f.read(&mut data6) | ^^^^^^^^^^^^^^^^^^ error: reading zero byte data to `Vec` - --> $DIR/read_zero_byte_vec.rs:81:5 + --> $DIR/read_zero_byte_vec.rs:84:9 + | +LL | f.read(&mut v)?; + | ^^^^^^^^^^^^^^ + +error: reading zero byte data to `Vec` + --> $DIR/read_zero_byte_vec.rs:94:5 | LL | r.read(&mut data).await.unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ error: reading zero byte data to `Vec` - --> $DIR/read_zero_byte_vec.rs:86:5 + --> $DIR/read_zero_byte_vec.rs:99:5 | LL | r.read_exact(&mut data2).await.unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ error: reading zero byte data to `Vec` - --> $DIR/read_zero_byte_vec.rs:93:5 + --> $DIR/read_zero_byte_vec.rs:106:5 | LL | r.read(&mut data).await.unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ error: reading zero byte data to `Vec` - --> $DIR/read_zero_byte_vec.rs:98:5 + --> $DIR/read_zero_byte_vec.rs:111:5 | LL | r.read_exact(&mut data2).await.unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 10 previous errors +error: aborting due to 11 previous errors From 0bccdb34a20643ae1bd07ee6f3f0156640a12120 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Tue, 7 Nov 2023 17:46:00 +0100 Subject: [PATCH 0020/1197] Stabilize `slice_group_by` Renamed "group by" to "chunk by" a per #80552. Newly stable items: * `core::slice::ChunkBy` * `core::slice::ChunkByMut` * `[T]::chunk` * `[T]::chunk_by` Closes #80552. --- library/alloc/src/lib.rs | 1 - library/alloc/src/slice.rs | 4 +-- library/alloc/tests/lib.rs | 1 - library/alloc/tests/slice.rs | 16 ++++----- library/core/src/slice/iter.rs | 64 +++++++++++++++++----------------- library/core/src/slice/mod.rs | 32 +++++++---------- library/core/tests/lib.rs | 1 - 7 files changed, 54 insertions(+), 65 deletions(-) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 02ecbe22b3e15..7d04a2964037f 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -149,7 +149,6 @@ #![feature(set_ptr_value)] #![feature(sized_type_properties)] #![feature(slice_from_ptr_range)] -#![feature(slice_group_by)] #![feature(slice_ptr_get)] #![feature(slice_ptr_len)] #![feature(slice_range)] diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index aa3b7b7e1914b..4033f4eb068c6 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -51,14 +51,14 @@ pub use core::slice::{from_mut, from_ref}; pub use core::slice::{from_mut_ptr_range, from_ptr_range}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{from_raw_parts, from_raw_parts_mut}; +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +pub use core::slice::{ChunkBy, ChunkByMut}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{Chunks, Windows}; #[stable(feature = "chunks_exact", since = "1.31.0")] pub use core::slice::{ChunksExact, ChunksExactMut}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{ChunksMut, Split, SplitMut}; -#[unstable(feature = "slice_group_by", issue = "80552")] -pub use core::slice::{GroupBy, GroupByMut}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{Iter, IterMut}; #[stable(feature = "rchunks", since = "1.31.0")] diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 2dcfc6b4abfe9..ca17dab55b027 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -29,7 +29,6 @@ #![feature(iter_advance_by)] #![feature(iter_next_chunk)] #![feature(round_char_boundary)] -#![feature(slice_group_by)] #![feature(slice_partition_dedup)] #![feature(string_remove_matches)] #![feature(const_btree_len)] diff --git a/library/alloc/tests/slice.rs b/library/alloc/tests/slice.rs index 784839a3ffa42..c0f7a11a93e12 100644 --- a/library/alloc/tests/slice.rs +++ b/library/alloc/tests/slice.rs @@ -1614,10 +1614,10 @@ fn subslice_patterns() { } #[test] -fn test_group_by() { +fn test_chunk_by() { let slice = &[1, 1, 1, 3, 3, 2, 2, 2, 1, 0]; - let mut iter = slice.group_by(|a, b| a == b); + let mut iter = slice.chunk_by(|a, b| a == b); assert_eq!(iter.next(), Some(&[1, 1, 1][..])); assert_eq!(iter.next(), Some(&[3, 3][..])); assert_eq!(iter.next(), Some(&[2, 2, 2][..])); @@ -1625,7 +1625,7 @@ fn test_group_by() { assert_eq!(iter.next(), Some(&[0][..])); assert_eq!(iter.next(), None); - let mut iter = slice.group_by(|a, b| a == b); + let mut iter = slice.chunk_by(|a, b| a == b); assert_eq!(iter.next_back(), Some(&[0][..])); assert_eq!(iter.next_back(), Some(&[1][..])); assert_eq!(iter.next_back(), Some(&[2, 2, 2][..])); @@ -1633,7 +1633,7 @@ fn test_group_by() { assert_eq!(iter.next_back(), Some(&[1, 1, 1][..])); assert_eq!(iter.next_back(), None); - let mut iter = slice.group_by(|a, b| a == b); + let mut iter = slice.chunk_by(|a, b| a == b); assert_eq!(iter.next(), Some(&[1, 1, 1][..])); assert_eq!(iter.next_back(), Some(&[0][..])); assert_eq!(iter.next(), Some(&[3, 3][..])); @@ -1643,10 +1643,10 @@ fn test_group_by() { } #[test] -fn test_group_by_mut() { +fn test_chunk_by_mut() { let slice = &mut [1, 1, 1, 3, 3, 2, 2, 2, 1, 0]; - let mut iter = slice.group_by_mut(|a, b| a == b); + let mut iter = slice.chunk_by_mut(|a, b| a == b); assert_eq!(iter.next(), Some(&mut [1, 1, 1][..])); assert_eq!(iter.next(), Some(&mut [3, 3][..])); assert_eq!(iter.next(), Some(&mut [2, 2, 2][..])); @@ -1654,7 +1654,7 @@ fn test_group_by_mut() { assert_eq!(iter.next(), Some(&mut [0][..])); assert_eq!(iter.next(), None); - let mut iter = slice.group_by_mut(|a, b| a == b); + let mut iter = slice.chunk_by_mut(|a, b| a == b); assert_eq!(iter.next_back(), Some(&mut [0][..])); assert_eq!(iter.next_back(), Some(&mut [1][..])); assert_eq!(iter.next_back(), Some(&mut [2, 2, 2][..])); @@ -1662,7 +1662,7 @@ fn test_group_by_mut() { assert_eq!(iter.next_back(), Some(&mut [1, 1, 1][..])); assert_eq!(iter.next_back(), None); - let mut iter = slice.group_by_mut(|a, b| a == b); + let mut iter = slice.chunk_by_mut(|a, b| a == b); assert_eq!(iter.next(), Some(&mut [1, 1, 1][..])); assert_eq!(iter.next_back(), Some(&mut [0][..])); assert_eq!(iter.next(), Some(&mut [3, 3][..])); diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 1c65475b81d70..2d4c7e78aea17 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -3248,26 +3248,26 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for IterMut<'a, T> { /// An iterator over slice in (non-overlapping) chunks separated by a predicate. /// -/// This struct is created by the [`group_by`] method on [slices]. +/// This struct is created by the [`chunk_by`] method on [slices]. /// -/// [`group_by`]: slice::group_by +/// [`chunk_by`]: slice::chunk_by /// [slices]: slice -#[unstable(feature = "slice_group_by", issue = "80552")] +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] #[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct GroupBy<'a, T: 'a, P> { +pub struct ChunkBy<'a, T: 'a, P> { slice: &'a [T], predicate: P, } -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a, P> GroupBy<'a, T, P> { +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a, P> ChunkBy<'a, T, P> { pub(super) fn new(slice: &'a [T], predicate: P) -> Self { - GroupBy { slice, predicate } + ChunkBy { slice, predicate } } } -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a, P> Iterator for GroupBy<'a, T, P> +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a, P> Iterator for ChunkBy<'a, T, P> where P: FnMut(&T, &T) -> bool, { @@ -3300,8 +3300,8 @@ where } } -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a, P> DoubleEndedIterator for GroupBy<'a, T, P> +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a, P> DoubleEndedIterator for ChunkBy<'a, T, P> where P: FnMut(&T, &T) -> bool, { @@ -3322,39 +3322,39 @@ where } } -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a, P> FusedIterator for GroupBy<'a, T, P> where P: FnMut(&T, &T) -> bool {} +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a, P> FusedIterator for ChunkBy<'a, T, P> where P: FnMut(&T, &T) -> bool {} -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for GroupBy<'a, T, P> { +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for ChunkBy<'a, T, P> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("GroupBy").field("slice", &self.slice).finish() + f.debug_struct("ChunkBy").field("slice", &self.slice).finish() } } /// An iterator over slice in (non-overlapping) mutable chunks separated /// by a predicate. /// -/// This struct is created by the [`group_by_mut`] method on [slices]. +/// This struct is created by the [`chunk_by_mut`] method on [slices]. /// -/// [`group_by_mut`]: slice::group_by_mut +/// [`chunk_by_mut`]: slice::chunk_by_mut /// [slices]: slice -#[unstable(feature = "slice_group_by", issue = "80552")] +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] #[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct GroupByMut<'a, T: 'a, P> { +pub struct ChunkByMut<'a, T: 'a, P> { slice: &'a mut [T], predicate: P, } -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a, P> GroupByMut<'a, T, P> { +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a, P> ChunkByMut<'a, T, P> { pub(super) fn new(slice: &'a mut [T], predicate: P) -> Self { - GroupByMut { slice, predicate } + ChunkByMut { slice, predicate } } } -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a, P> Iterator for GroupByMut<'a, T, P> +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a, P> Iterator for ChunkByMut<'a, T, P> where P: FnMut(&T, &T) -> bool, { @@ -3388,8 +3388,8 @@ where } } -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a, P> DoubleEndedIterator for GroupByMut<'a, T, P> +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a, P> DoubleEndedIterator for ChunkByMut<'a, T, P> where P: FnMut(&T, &T) -> bool, { @@ -3411,12 +3411,12 @@ where } } -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a, P> FusedIterator for GroupByMut<'a, T, P> where P: FnMut(&T, &T) -> bool {} +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a, P> FusedIterator for ChunkByMut<'a, T, P> where P: FnMut(&T, &T) -> bool {} -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for GroupByMut<'a, T, P> { +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for ChunkByMut<'a, T, P> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("GroupByMut").field("slice", &self.slice).finish() + f.debug_struct("ChunkByMut").field("slice", &self.slice).finish() } } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 27dda478848c0..fe18c31df1a8d 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -68,8 +68,8 @@ pub use iter::{ArrayChunks, ArrayChunksMut}; #[unstable(feature = "array_windows", issue = "75027")] pub use iter::ArrayWindows; -#[unstable(feature = "slice_group_by", issue = "80552")] -pub use iter::{GroupBy, GroupByMut}; +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +pub use iter::{ChunkBy, ChunkByMut}; #[stable(feature = "split_inclusive", since = "1.51.0")] pub use iter::{SplitInclusive, SplitInclusiveMut}; @@ -1755,11 +1755,9 @@ impl [T] { /// # Examples /// /// ``` - /// #![feature(slice_group_by)] - /// /// let slice = &[1, 1, 1, 3, 3, 2, 2, 2]; /// - /// let mut iter = slice.group_by(|a, b| a == b); + /// let mut iter = slice.chunk_by(|a, b| a == b); /// /// assert_eq!(iter.next(), Some(&[1, 1, 1][..])); /// assert_eq!(iter.next(), Some(&[3, 3][..])); @@ -1770,24 +1768,22 @@ impl [T] { /// This method can be used to extract the sorted subslices: /// /// ``` - /// #![feature(slice_group_by)] - /// /// let slice = &[1, 1, 2, 3, 2, 3, 2, 3, 4]; /// - /// let mut iter = slice.group_by(|a, b| a <= b); + /// let mut iter = slice.chunk_by(|a, b| a <= b); /// /// assert_eq!(iter.next(), Some(&[1, 1, 2, 3][..])); /// assert_eq!(iter.next(), Some(&[2, 3][..])); /// assert_eq!(iter.next(), Some(&[2, 3, 4][..])); /// assert_eq!(iter.next(), None); /// ``` - #[unstable(feature = "slice_group_by", issue = "80552")] + #[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] #[inline] - pub fn group_by(&self, pred: F) -> GroupBy<'_, T, F> + pub fn chunk_by(&self, pred: F) -> ChunkBy<'_, T, F> where F: FnMut(&T, &T) -> bool, { - GroupBy::new(self, pred) + ChunkBy::new(self, pred) } /// Returns an iterator over the slice producing non-overlapping mutable @@ -1800,11 +1796,9 @@ impl [T] { /// # Examples /// /// ``` - /// #![feature(slice_group_by)] - /// /// let slice = &mut [1, 1, 1, 3, 3, 2, 2, 2]; /// - /// let mut iter = slice.group_by_mut(|a, b| a == b); + /// let mut iter = slice.chunk_by_mut(|a, b| a == b); /// /// assert_eq!(iter.next(), Some(&mut [1, 1, 1][..])); /// assert_eq!(iter.next(), Some(&mut [3, 3][..])); @@ -1815,24 +1809,22 @@ impl [T] { /// This method can be used to extract the sorted subslices: /// /// ``` - /// #![feature(slice_group_by)] - /// /// let slice = &mut [1, 1, 2, 3, 2, 3, 2, 3, 4]; /// - /// let mut iter = slice.group_by_mut(|a, b| a <= b); + /// let mut iter = slice.chunk_by_mut(|a, b| a <= b); /// /// assert_eq!(iter.next(), Some(&mut [1, 1, 2, 3][..])); /// assert_eq!(iter.next(), Some(&mut [2, 3][..])); /// assert_eq!(iter.next(), Some(&mut [2, 3, 4][..])); /// assert_eq!(iter.next(), None); /// ``` - #[unstable(feature = "slice_group_by", issue = "80552")] + #[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] #[inline] - pub fn group_by_mut(&mut self, pred: F) -> GroupByMut<'_, T, F> + pub fn chunk_by_mut(&mut self, pred: F) -> ChunkByMut<'_, T, F> where F: FnMut(&T, &T) -> bool, { - GroupByMut::new(self, pred) + ChunkByMut::new(self, pred) } /// Divides one slice into two at an index. diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 89d2b5ef09383..57ad2ad1af9a3 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -101,7 +101,6 @@ #![cfg_attr(target_has_atomic = "128", feature(integer_atomics))] #![cfg_attr(test, feature(cfg_match))] #![feature(int_roundings)] -#![feature(slice_group_by)] #![feature(split_array)] #![feature(strict_provenance)] #![feature(strict_provenance_atomic_ptr)] From d2af7da065286d6169fe28f526fe295cf6083fd8 Mon Sep 17 00:00:00 2001 From: kadiwa Date: Mon, 19 Jun 2023 20:29:01 +0200 Subject: [PATCH 0021/1197] small code improvements in collect_intra_doc_links --- .../passes/collect_intra_doc_links.rs | 103 +++++++----------- 1 file changed, 39 insertions(+), 64 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 1e8ece7e114a3..fa9dcc2e36d5a 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -108,15 +108,13 @@ impl Res { Res::Primitive(_) => return Suggestion::Prefix("prim"), Res::Def(kind, _) => kind, }; - if kind == DefKind::Macro(MacroKind::Bang) { - return Suggestion::Macro; - } else if kind == DefKind::Fn || kind == DefKind::AssocFn { - return Suggestion::Function; - } else if kind == DefKind::Field { - return Suggestion::RemoveDisambiguator; - } let prefix = match kind { + DefKind::Fn | DefKind::AssocFn => return Suggestion::Function, + DefKind::Field => return Suggestion::RemoveDisambiguator, + DefKind::Macro(MacroKind::Bang) => return Suggestion::Macro, + + DefKind::Macro(MacroKind::Derive) => "derive", DefKind::Struct => "struct", DefKind::Enum => "enum", DefKind::Trait => "trait", @@ -126,7 +124,6 @@ impl Res { "const" } DefKind::Static(_) => "static", - DefKind::Macro(MacroKind::Derive) => "derive", // Now handle things that don't have a specific disambiguator _ => match kind .ns() @@ -283,20 +280,15 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { debug!("looking for enum variant {path_str}"); let mut split = path_str.rsplitn(3, "::"); - let variant_field_name = split - .next() - .map(|f| Symbol::intern(f)) - .expect("fold_item should ensure link is non-empty"); - let variant_name = - // we're not sure this is a variant at all, so use the full string - // If there's no second component, the link looks like `[path]`. - // So there's no partial res and we should say the whole link failed to resolve. - split.next().map(|f| Symbol::intern(f)).ok_or_else(no_res)?; - let path = split - .next() - // If there's no third component, we saw `[a::b]` before and it failed to resolve. - // So there's no partial res. - .ok_or_else(no_res)?; + let variant_field_name = Symbol::intern(split.next().unwrap()); + // We're not sure this is a variant at all, so use the full string. + // If there's no second component, the link looks like `[path]`. + // So there's no partial res and we should say the whole link failed to resolve. + let variant_name = Symbol::intern(split.next().ok_or_else(no_res)?); + + // If there's no third component, we saw `[a::b]` before and it failed to resolve. + // So there's no partial res. + let path = split.next().ok_or_else(no_res)?; let ty_res = self.resolve_path(&path, TypeNS, item_id, module_id).ok_or_else(no_res)?; match ty_res { @@ -447,41 +439,29 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } // Try looking for methods and associated items. - let mut split = path_str.rsplitn(2, "::"); - // NB: `split`'s first element is always defined, even if the delimiter was not present. - // NB: `item_str` could be empty when resolving in the root namespace (e.g. `::std`). - let item_str = split.next().unwrap(); - let item_name = Symbol::intern(item_str); - let path_root = split - .next() + // NB: `path_root` could be empty when resolving in the root namespace (e.g. `::std`). + let (path_root, item_str) = path_str.rsplit_once("::").ok_or_else(|| { // If there's no `::`, it's not an associated item. // So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved. - .ok_or_else(|| { - debug!("found no `::`, assuming {item_name} was correctly not in scope"); - UnresolvedPath { - item_id, - module_id, - partial_res: None, - unresolved: item_str.into(), - } - })?; + debug!("found no `::`, assuming {path_str} was correctly not in scope"); + UnresolvedPath { item_id, module_id, partial_res: None, unresolved: path_str.into() } + })?; + let item_name = Symbol::intern(item_str); // FIXME(#83862): this arbitrarily gives precedence to primitives over modules to support // links to primitives when `#[rustc_doc_primitive]` is present. It should give an ambiguity // error instead and special case *only* modules with `#[rustc_doc_primitive]`, not all // primitives. - match resolve_primitive(&path_root, TypeNS) - .or_else(|| self.resolve_path(&path_root, TypeNS, item_id, module_id)) - .and_then(|ty_res| { - let candidates = self - .resolve_associated_item(ty_res, item_name, ns, module_id) + match resolve_primitive(path_root, TypeNS) + .or_else(|| self.resolve_path(path_root, TypeNS, item_id, module_id)) + .map(|ty_res| { + self.resolve_associated_item(ty_res, item_name, ns, module_id) .into_iter() .map(|(res, def_id)| (res, Some(def_id))) - .collect::>(); - if !candidates.is_empty() { Some(candidates) } else { None } + .collect::>() }) { - Some(r) => Ok(r), - None => { + Some(r) if !r.is_empty() => Ok(r), + _ => { if ns == Namespace::ValueNS { self.variant_field(path_str, item_id, module_id) .map(|(res, def_id)| vec![(res, Some(def_id))]) @@ -1262,7 +1242,7 @@ impl LinkCollector<'_, '_> { self.report_rawptr_assoc_feature_gate(diag.dox, &diag.link_range, diag.item); return None; } else { - candidates = vec![candidates[0]]; + candidates = vec![*candidate]; } } @@ -1270,8 +1250,10 @@ impl LinkCollector<'_, '_> { // and after removing duplicated kinds, only one remains, the `ambiguity_error` function // won't emit an error. So at this point, we can just take the first candidate as it was // the first retrieved and use it to generate the link. - if candidates.len() > 1 && !ambiguity_error(self.cx, &diag, &key.path_str, &candidates) { - candidates = vec![candidates[0]]; + if let [candidate, _candidate2, ..] = *candidates + && !ambiguity_error(self.cx, &diag, &key.path_str, &candidates) + { + candidates = vec![candidate]; } if let &[(res, def_id)] = candidates.as_slice() { @@ -1321,12 +1303,11 @@ impl LinkCollector<'_, '_> { let mut err = ResolutionFailure::NotResolved(err); for other_ns in [TypeNS, ValueNS, MacroNS] { if other_ns != expected_ns { - if let Ok(res) = - self.resolve(path_str, other_ns, item_id, module_id) - && !res.is_empty() + if let Ok(&[res, ..]) = + self.resolve(path_str, other_ns, item_id, module_id).as_deref() { err = ResolutionFailure::WrongNamespace { - res: full_res(self.cx.tcx, res[0]), + res: full_res(self.cx.tcx, res), expected_ns, }; break; @@ -1747,7 +1728,6 @@ fn report_diagnostic( lint.note(format!( "the link appears in this line:\n\n{line}\n\ {indicator: Option<(&str, &str)> { - let mut splitter = path.rsplitn(2, "::"); - splitter.next().and_then(|right| splitter.next().map(|left| (left, right))) - } // Check if _any_ parent of the path gets resolved. // If so, report it and say the first which failed; if not, say the first path segment didn't resolve. let mut name = path_str; 'outer: loop { - let Some((start, end)) = split(name) else { + // FIXME(jynelson): this might conflict with my `Self` fix in #76467 + let Some((start, end)) = name.rsplit_once("::") else { // avoid bug that marked [Quux::Z] as missing Z, not Quux if partial_res.is_none() { *unresolved = name.into(); @@ -1830,8 +1805,8 @@ fn resolution_failure( for ns in [TypeNS, ValueNS, MacroNS] { if let Ok(v_res) = collector.resolve(start, ns, item_id, module_id) { debug!("found partial_res={v_res:?}"); - if !v_res.is_empty() { - *partial_res = Some(full_res(tcx, v_res[0])); + if let Some(&res) = v_res.first() { + *partial_res = Some(full_res(tcx, res)); *unresolved = end.into(); break 'outer; } From c5c2fb1761e0962c66793f6753cbe8f0cc2d4c26 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Fri, 17 Nov 2023 12:35:46 +0100 Subject: [PATCH 0022/1197] Improve slice_group_by doc wording --- library/core/src/slice/mod.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index fe18c31df1a8d..2d93ef6fbeb34 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1748,9 +1748,9 @@ impl [T] { /// Returns an iterator over the slice producing non-overlapping runs /// of elements using the predicate to separate them. /// - /// The predicate is called on two elements following themselves, - /// it means the predicate is called on `slice[0]` and `slice[1]` - /// then on `slice[1]` and `slice[2]` and so on. + /// The predicate is called for every pair of consecutive elements, + /// meaning that it is called on `slice[0]` and `slice[1]`, + /// followed by `slice[1]` and `slice[2]`, and so on. /// /// # Examples /// @@ -1789,9 +1789,9 @@ impl [T] { /// Returns an iterator over the slice producing non-overlapping mutable /// runs of elements using the predicate to separate them. /// - /// The predicate is called on two elements following themselves, - /// it means the predicate is called on `slice[0]` and `slice[1]` - /// then on `slice[1]` and `slice[2]` and so on. + /// The predicate is called for every pair of consecutive elements, + /// meaning that it is called on `slice[0]` and `slice[1]`, + /// followed by `slice[1]` and `slice[2]`, and so on. /// /// # Examples /// From 8ee96931776c9d2912b379868ae3f7351d67281c Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 26 Jun 2023 14:26:43 +0100 Subject: [PATCH 0023/1197] Rewrite the BTreeMap cursor API using gaps Tracking issue: #107540 Currently, a `Cursor` points to a single element in the tree, and allows moving to the next or previous element while mutating the tree. However this was found to be confusing and hard to use. This PR completely refactors cursors to instead point to a gap between two elements in the tree. This eliminates the need for a "ghost" element that exists after the last element and before the first one. Additionally, `upper_bound` and `lower_bound` now have a much clearer meaning. The ability to mutate keys is also factored out into a separate `CursorMutKey` type which is unsafe to create. This makes the API easier to use since it avoids duplicated versions of each method with and without key mutation. API summary: ```rust impl BTreeMap { fn lower_bound(&self, bound: Bound<&Q>) -> Cursor<'_, K, V> where K: Borrow + Ord, Q: Ord; fn lower_bound_mut(&mut self, bound: Bound<&Q>) -> CursorMut<'_, K, V> where K: Borrow + Ord, Q: Ord; fn upper_bound(&self, bound: Bound<&Q>) -> Cursor<'_, K, V> where K: Borrow + Ord, Q: Ord; fn upper_bound_mut(&mut self, bound: Bound<&Q>) -> CursorMut<'_, K, V> where K: Borrow + Ord, Q: Ord; } struct Cursor<'a, K: 'a, V: 'a>; impl<'a, K, V> Cursor<'a, K, V> { fn next(&mut self) -> Option<(&'a K, &'a V)>; fn prev(&mut self) -> Option<(&'a K, &'a V)>; fn peek_next(&self) -> Option<(&'a K, &'a V)>; fn peek_prev(&self) -> Option<(&'a K, &'a V)>; } struct CursorMut<'a, K: 'a, V: 'a>; impl<'a, K, V> CursorMut<'a, K, V> { fn next(&mut self) -> Option<(&K, &mut V)>; fn prev(&mut self) -> Option<(&K, &mut V)>; fn peek_next(&mut self) -> Option<(&K, &mut V)>; fn peek_prev(&mut self) -> Option<(&K, &mut V)>; unsafe fn insert_after_unchecked(&mut self, key: K, value: V); unsafe fn insert_before_unchecked(&mut self, key: K, value: V); fn insert_after(&mut self, key: K, value: V); fn insert_before(&mut self, key: K, value: V); fn remove_next(&mut self) -> Option<(K, V)>; fn remove_prev(&mut self) -> Option<(K, V)>; fn as_cursor(&self) -> Cursor<'_, K, V>; unsafe fn with_mutable_key(self) -> CursorMutKey<'a, K, V, A>; } struct CursorMutKey<'a, K: 'a, V: 'a>; impl<'a, K, V> CursorMut<'a, K, V> { fn next(&mut self) -> Option<(&mut K, &mut V)>; fn prev(&mut self) -> Option<(&mut K, &mut V)>; fn peek_next(&mut self) -> Option<(&mut K, &mut V)>; fn peek_prev(&mut self) -> Option<(&mut K, &mut V)>; unsafe fn insert_after_unchecked(&mut self, key: K, value: V); unsafe fn insert_before_unchecked(&mut self, key: K, value: V); fn insert_after(&mut self, key: K, value: V); fn insert_before(&mut self, key: K, value: V); fn remove_next(&mut self) -> Option<(K, V)>; fn remove_prev(&mut self) -> Option<(K, V)>; fn as_cursor(&self) -> Cursor<'_, K, V>; unsafe fn with_mutable_key(self) -> CursorMutKey<'a, K, V, A>; } ``` --- library/alloc/src/collections/btree/map.rs | 749 ++++++++++-------- .../alloc/src/collections/btree/map/tests.rs | 115 ++- library/alloc/src/collections/btree/node.rs | 29 +- 3 files changed, 519 insertions(+), 374 deletions(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 4bdd9639557d4..b36298cde3675 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -2521,14 +2521,10 @@ impl BTreeMap { self.len() == 0 } - /// Returns a [`Cursor`] pointing at the first element that is above the - /// given bound. + /// Returns a [`Cursor`] pointing to the first gap above the given bound. /// - /// If no such element exists then a cursor pointing at the "ghost" - /// non-element is returned. - /// - /// Passing [`Bound::Unbounded`] will return a cursor pointing at the first - /// element of the map. + /// Passing [`Bound::Unbounded`] will return a cursor pointing to the start + /// of the map. /// /// # Examples /// @@ -2542,14 +2538,16 @@ impl BTreeMap { /// a.insert(1, "a"); /// a.insert(2, "b"); /// a.insert(3, "c"); - /// a.insert(4, "c"); + /// a.insert(4, "d"); /// let cursor = a.lower_bound(Bound::Included(&2)); - /// assert_eq!(cursor.key(), Some(&2)); + /// assert_eq!(cursor.peek_prev(), Some((&1, &"a"))); + /// assert_eq!(cursor.peek_next(), Some((&2, &"b"))); /// let cursor = a.lower_bound(Bound::Excluded(&2)); - /// assert_eq!(cursor.key(), Some(&3)); + /// assert_eq!(cursor.peek_prev(), Some((&2, &"b"))); + /// assert_eq!(cursor.peek_next(), Some((&3, &"c"))); /// ``` #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn lower_bound(&self, bound: Bound<&Q>) -> Cursor<'_, K, V> + pub fn lower_bound(&self, bound: Bound<&Q>) -> Cursor<'_, K, V> where K: Borrow + Ord, Q: Ord, @@ -2559,17 +2557,14 @@ impl BTreeMap { Some(root) => root.reborrow(), }; let edge = root_node.lower_bound(SearchBound::from_range(bound)); - Cursor { current: edge.next_kv().ok(), root: self.root.as_ref() } + Cursor { current: Some(edge), root: self.root.as_ref() } } - /// Returns a [`CursorMut`] pointing at the first element that is above the - /// given bound. + /// Returns a [`CursorMut`] pointing to the first gap above the given bound. /// - /// If no such element exists then a cursor pointing at the "ghost" - /// non-element is returned. /// - /// Passing [`Bound::Unbounded`] will return a cursor pointing at the first - /// element of the map. + /// Passing [`Bound::Unbounded`] will return a cursor pointing to the start + /// of the map. /// /// # Examples /// @@ -2583,14 +2578,16 @@ impl BTreeMap { /// a.insert(1, "a"); /// a.insert(2, "b"); /// a.insert(3, "c"); - /// a.insert(4, "c"); - /// let cursor = a.lower_bound_mut(Bound::Included(&2)); - /// assert_eq!(cursor.key(), Some(&2)); - /// let cursor = a.lower_bound_mut(Bound::Excluded(&2)); - /// assert_eq!(cursor.key(), Some(&3)); + /// a.insert(4, "d"); + /// let mut cursor = a.lower_bound_mut(Bound::Included(&2)); + /// assert_eq!(cursor.peek_prev(), Some((&1, &mut "a"))); + /// assert_eq!(cursor.peek_next(), Some((&2, &mut "b"))); + /// let mut cursor = a.lower_bound_mut(Bound::Excluded(&2)); + /// assert_eq!(cursor.peek_prev(), Some((&2, &mut "b"))); + /// assert_eq!(cursor.peek_next(), Some((&3, &mut "c"))); /// ``` #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn lower_bound_mut(&mut self, bound: Bound<&Q>) -> CursorMut<'_, K, V, A> + pub fn lower_bound_mut(&mut self, bound: Bound<&Q>) -> CursorMut<'_, K, V, A> where K: Borrow + Ord, Q: Ord, @@ -2599,31 +2596,31 @@ impl BTreeMap { let root_node = match root.as_mut() { None => { return CursorMut { - current: None, - root: dormant_root, - length: &mut self.length, - alloc: &mut *self.alloc, + inner: CursorMutKey { + current: None, + root: dormant_root, + length: &mut self.length, + alloc: &mut *self.alloc, + }, }; } Some(root) => root.borrow_mut(), }; let edge = root_node.lower_bound(SearchBound::from_range(bound)); CursorMut { - current: edge.next_kv().ok(), - root: dormant_root, - length: &mut self.length, - alloc: &mut *self.alloc, + inner: CursorMutKey { + current: Some(edge), + root: dormant_root, + length: &mut self.length, + alloc: &mut *self.alloc, + }, } } - /// Returns a [`Cursor`] pointing at the last element that is below the - /// given bound. - /// - /// If no such element exists then a cursor pointing at the "ghost" - /// non-element is returned. + /// Returns a [`Cursor`] pointing at the last gap below the given bound. /// - /// Passing [`Bound::Unbounded`] will return a cursor pointing at the last - /// element of the map. + /// Passing [`Bound::Unbounded`] will return a cursor pointing to the end + /// of the map. /// /// # Examples /// @@ -2637,14 +2634,16 @@ impl BTreeMap { /// a.insert(1, "a"); /// a.insert(2, "b"); /// a.insert(3, "c"); - /// a.insert(4, "c"); + /// a.insert(4, "d"); /// let cursor = a.upper_bound(Bound::Included(&3)); - /// assert_eq!(cursor.key(), Some(&3)); + /// assert_eq!(cursor.peek_prev(), Some((&3, &"c"))); + /// assert_eq!(cursor.peek_next(), Some((&4, &"d"))); /// let cursor = a.upper_bound(Bound::Excluded(&3)); - /// assert_eq!(cursor.key(), Some(&2)); + /// assert_eq!(cursor.peek_prev(), Some((&2, &"b"))); + /// assert_eq!(cursor.peek_next(), Some((&3, &"c"))); /// ``` #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn upper_bound(&self, bound: Bound<&Q>) -> Cursor<'_, K, V> + pub fn upper_bound(&self, bound: Bound<&Q>) -> Cursor<'_, K, V> where K: Borrow + Ord, Q: Ord, @@ -2654,17 +2653,13 @@ impl BTreeMap { Some(root) => root.reborrow(), }; let edge = root_node.upper_bound(SearchBound::from_range(bound)); - Cursor { current: edge.next_back_kv().ok(), root: self.root.as_ref() } + Cursor { current: Some(edge), root: self.root.as_ref() } } - /// Returns a [`CursorMut`] pointing at the last element that is below the - /// given bound. - /// - /// If no such element exists then a cursor pointing at the "ghost" - /// non-element is returned. + /// Returns a [`CursorMut`] pointing at the last gap below the given bound. /// - /// Passing [`Bound::Unbounded`] will return a cursor pointing at the last - /// element of the map. + /// Passing [`Bound::Unbounded`] will return a cursor pointing to the end + /// of the map. /// /// # Examples /// @@ -2678,14 +2673,16 @@ impl BTreeMap { /// a.insert(1, "a"); /// a.insert(2, "b"); /// a.insert(3, "c"); - /// a.insert(4, "c"); - /// let cursor = a.upper_bound_mut(Bound::Included(&3)); - /// assert_eq!(cursor.key(), Some(&3)); - /// let cursor = a.upper_bound_mut(Bound::Excluded(&3)); - /// assert_eq!(cursor.key(), Some(&2)); + /// a.insert(4, "d"); + /// let mut cursor = a.upper_bound_mut(Bound::Included(&3)); + /// assert_eq!(cursor.peek_prev(), Some((&3, &mut "c"))); + /// assert_eq!(cursor.peek_next(), Some((&4, &mut "d"))); + /// let mut cursor = a.upper_bound_mut(Bound::Excluded(&3)); + /// assert_eq!(cursor.peek_prev(), Some((&2, &mut "b"))); + /// assert_eq!(cursor.peek_next(), Some((&3, &mut "c"))); /// ``` #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn upper_bound_mut(&mut self, bound: Bound<&Q>) -> CursorMut<'_, K, V, A> + pub fn upper_bound_mut(&mut self, bound: Bound<&Q>) -> CursorMut<'_, K, V, A> where K: Borrow + Ord, Q: Ord, @@ -2694,20 +2691,24 @@ impl BTreeMap { let root_node = match root.as_mut() { None => { return CursorMut { - current: None, - root: dormant_root, - length: &mut self.length, - alloc: &mut *self.alloc, + inner: CursorMutKey { + current: None, + root: dormant_root, + length: &mut self.length, + alloc: &mut *self.alloc, + }, }; } Some(root) => root.borrow_mut(), }; let edge = root_node.upper_bound(SearchBound::from_range(bound)); CursorMut { - current: edge.next_back_kv().ok(), - root: dormant_root, - length: &mut self.length, - alloc: &mut *self.alloc, + inner: CursorMutKey { + current: Some(edge), + root: dormant_root, + length: &mut self.length, + alloc: &mut *self.alloc, + }, } } } @@ -2716,14 +2717,14 @@ impl BTreeMap { /// /// A `Cursor` is like an iterator, except that it can freely seek back-and-forth. /// -/// Cursors always point to an element in the tree, and index in a logically circular way. -/// To accommodate this, there is a "ghost" non-element that yields `None` between the last and -/// first elements of the tree. +/// Cursors always point to a gao between two elements in the map, and can +/// operate on the two immediately adjacent elements. /// /// A `Cursor` is created with the [`BTreeMap::lower_bound`] and [`BTreeMap::upper_bound`] methods. #[unstable(feature = "btree_cursors", issue = "107540")] pub struct Cursor<'a, K: 'a, V: 'a> { - current: Option, K, V, marker::LeafOrInternal>, marker::KV>>, + // If current is None then it means the tree has not been allocated yet. + current: Option, K, V, marker::Leaf>, marker::Edge>>, root: Option<&'a node::Root>, } @@ -2738,22 +2739,21 @@ impl Clone for Cursor<'_, K, V> { #[unstable(feature = "btree_cursors", issue = "107540")] impl Debug for Cursor<'_, K, V> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("Cursor").field(&self.key_value()).finish() + f.write_str("Cursor") } } /// A cursor over a `BTreeMap` with editing operations. /// /// A `Cursor` is like an iterator, except that it can freely seek back-and-forth, and can -/// safely mutate the tree during iteration. This is because the lifetime of its yielded -/// references is tied to its own lifetime, instead of just the underlying tree. This means +/// safely mutate the map during iteration. This is because the lifetime of its yielded +/// references is tied to its own lifetime, instead of just the underlying map. This means /// cursors cannot yield multiple elements at once. /// -/// Cursors always point to an element in the tree, and index in a logically circular way. -/// To accommodate this, there is a "ghost" non-element that yields `None` between the last and -/// first elements of the tree. +/// Cursors always point to a gao between two elements in the map, and can +/// operate on the two immediately adjacent elements. /// -/// A `Cursor` is created with the [`BTreeMap::lower_bound_mut`] and [`BTreeMap::upper_bound_mut`] +/// A `CursorMut` is created with the [`BTreeMap::lower_bound_mut`] and [`BTreeMap::upper_bound_mut`] /// methods. #[unstable(feature = "btree_cursors", issue = "107540")] pub struct CursorMut< @@ -2762,287 +2762,271 @@ pub struct CursorMut< V: 'a, #[unstable(feature = "allocator_api", issue = "32838")] A = Global, > { - current: Option, K, V, marker::LeafOrInternal>, marker::KV>>, + inner: CursorMutKey<'a, K, V, A>, +} + +#[unstable(feature = "btree_cursors", issue = "107540")] +impl Debug for CursorMut<'_, K, V, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("CursorMut") + } +} + +/// A cursor over a `BTreeMap` with editing operations, and which allows +/// mutating the key of elements. +/// +/// A `Cursor` is like an iterator, except that it can freely seek back-and-forth, and can +/// safely mutate the map during iteration. This is because the lifetime of its yielded +/// references is tied to its own lifetime, instead of just the underlying map. This means +/// cursors cannot yield multiple elements at once. +/// +/// Cursors always point to a gao between two elements in the map, and can +/// operate on the two immediately adjacent elements. +/// +/// A `CursorMutKey` is created from a [`CursorMut`] with the +/// [`CursorMut::with_mutable_key`] method. +/// +/// # Safety +/// +/// Since this cursor allows mutating keys, you must ensure that the `BTreeMap` +/// invariants are maintained. Specifically: +/// +/// * The key of the newly inserted element must be unique in the tree. +/// * All keys in the tree must remain in sorted order. +#[unstable(feature = "btree_cursors", issue = "107540")] +pub struct CursorMutKey< + 'a, + K: 'a, + V: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A = Global, +> { + // If current is None then it means the tree has not been allocated yet. + current: Option, K, V, marker::Leaf>, marker::Edge>>, root: DormantMutRef<'a, Option>>, length: &'a mut usize, alloc: &'a mut A, } #[unstable(feature = "btree_cursors", issue = "107540")] -impl Debug for CursorMut<'_, K, V, A> { +impl Debug for CursorMutKey<'_, K, V, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("CursorMut").field(&self.key_value()).finish() + f.write_str("CursorMutKey") } } impl<'a, K, V> Cursor<'a, K, V> { - /// Moves the cursor to the next element of the `BTreeMap`. + /// Advances the cursor to the next gap, returning the key and value of the + /// element that it moved over. /// - /// If the cursor is pointing to the "ghost" non-element then this will move it to - /// the first element of the `BTreeMap`. If it is pointing to the last - /// element of the `BTreeMap` then this will move it to the "ghost" non-element. + /// If the cursor is already at the end of the map then `None` is returned + /// and the cursor is not moved. #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn move_next(&mut self) { - match self.current.take() { - None => { - self.current = self.root.and_then(|root| { - root.reborrow().first_leaf_edge().forget_node_type().right_kv().ok() - }); + pub fn next(&mut self) -> Option<(&'a K, &'a V)> { + let current = self.current.take()?; + match current.next_kv() { + Ok(kv) => { + let result = kv.into_kv(); + self.current = Some(kv.next_leaf_edge()); + Some(result) } - Some(current) => { - self.current = current.next_leaf_edge().next_kv().ok(); + Err(root) => { + self.current = Some(root.last_leaf_edge()); + None } } } - /// Moves the cursor to the previous element of the `BTreeMap`. + /// Advances the cursor to the previous gap, returning the key and value of + /// the element that it moved over. /// - /// If the cursor is pointing to the "ghost" non-element then this will move it to - /// the last element of the `BTreeMap`. If it is pointing to the first - /// element of the `BTreeMap` then this will move it to the "ghost" non-element. + /// If the cursor is already at the start of the map then `None` is returned + /// and the cursor is not moved. #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn move_prev(&mut self) { - match self.current.take() { - None => { - self.current = self.root.and_then(|root| { - root.reborrow().last_leaf_edge().forget_node_type().left_kv().ok() - }); + pub fn prev(&mut self) -> Option<(&'a K, &'a V)> { + let current = self.current.take()?; + match current.next_back_kv() { + Ok(kv) => { + let result = kv.into_kv(); + self.current = Some(kv.next_back_leaf_edge()); + Some(result) } - Some(current) => { - self.current = current.next_back_leaf_edge().next_back_kv().ok(); + Err(root) => { + self.current = Some(root.first_leaf_edge()); + None } } } - /// Returns a reference to the key of the element that the cursor is - /// currently pointing to. - /// - /// This returns `None` if the cursor is currently pointing to the - /// "ghost" non-element. - #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn key(&self) -> Option<&'a K> { - self.current.as_ref().map(|current| current.into_kv().0) - } - - /// Returns a reference to the value of the element that the cursor is - /// currently pointing to. - /// - /// This returns `None` if the cursor is currently pointing to the - /// "ghost" non-element. - #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn value(&self) -> Option<&'a V> { - self.current.as_ref().map(|current| current.into_kv().1) - } - - /// Returns a reference to the key and value of the element that the cursor - /// is currently pointing to. + /// Returns a reference to the the key and value of the next element without + /// moving the cursor. /// - /// This returns `None` if the cursor is currently pointing to the - /// "ghost" non-element. - #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn key_value(&self) -> Option<(&'a K, &'a V)> { - self.current.as_ref().map(|current| current.into_kv()) - } - - /// Returns a reference to the next element. - /// - /// If the cursor is pointing to the "ghost" non-element then this returns - /// the first element of the `BTreeMap`. If it is pointing to the last - /// element of the `BTreeMap` then this returns `None`. + /// If the cursor is at the end of the map then `None` is returned #[unstable(feature = "btree_cursors", issue = "107540")] pub fn peek_next(&self) -> Option<(&'a K, &'a V)> { - let mut next = self.clone(); - next.move_next(); - next.current.as_ref().map(|current| current.into_kv()) + self.clone().next() } - /// Returns a reference to the previous element. + /// Returns a reference to the the key and value of the previous element + /// without moving the cursor. /// - /// If the cursor is pointing to the "ghost" non-element then this returns - /// the last element of the `BTreeMap`. If it is pointing to the first - /// element of the `BTreeMap` then this returns `None`. + /// If the cursor is at the start of the map then `None` is returned. #[unstable(feature = "btree_cursors", issue = "107540")] pub fn peek_prev(&self) -> Option<(&'a K, &'a V)> { - let mut prev = self.clone(); - prev.move_prev(); - prev.current.as_ref().map(|current| current.into_kv()) + self.clone().prev() } } impl<'a, K, V, A> CursorMut<'a, K, V, A> { - /// Moves the cursor to the next element of the `BTreeMap`. + /// Advances the cursor to the next gap, returning the key and value of the + /// element that it moved over. /// - /// If the cursor is pointing to the "ghost" non-element then this will move it to - /// the first element of the `BTreeMap`. If it is pointing to the last - /// element of the `BTreeMap` then this will move it to the "ghost" non-element. + /// If the cursor is already at the end of the map then `None` is returned + /// and the cursor is not moved. #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn move_next(&mut self) { - match self.current.take() { - None => { - // SAFETY: The previous borrow of root has ended. - self.current = unsafe { self.root.reborrow() }.as_mut().and_then(|root| { - root.borrow_mut().first_leaf_edge().forget_node_type().right_kv().ok() - }); - } - Some(current) => { - self.current = current.next_leaf_edge().next_kv().ok(); - } - } + pub fn next(&mut self) -> Option<(&K, &mut V)> { + let (k, v) = self.inner.next()?; + Some((&*k, v)) } - /// Moves the cursor to the previous element of the `BTreeMap`. + /// Advances the cursor to the previous gap, returning the key and value of + /// the element that it moved over. /// - /// If the cursor is pointing to the "ghost" non-element then this will move it to - /// the last element of the `BTreeMap`. If it is pointing to the first - /// element of the `BTreeMap` then this will move it to the "ghost" non-element. + /// If the cursor is already at the start of the map then `None` is returned + /// and the cursor is not moved. #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn move_prev(&mut self) { - match self.current.take() { - None => { - // SAFETY: The previous borrow of root has ended. - self.current = unsafe { self.root.reborrow() }.as_mut().and_then(|root| { - root.borrow_mut().last_leaf_edge().forget_node_type().left_kv().ok() - }); - } - Some(current) => { - self.current = current.next_back_leaf_edge().next_back_kv().ok(); - } - } + pub fn prev(&mut self) -> Option<(&K, &mut V)> { + let (k, v) = self.inner.prev()?; + Some((&*k, v)) } - /// Returns a reference to the key of the element that the cursor is - /// currently pointing to. + /// Returns a reference to the the key and value of the next element without + /// moving the cursor. /// - /// This returns `None` if the cursor is currently pointing to the - /// "ghost" non-element. + /// If the cursor is at the end of the map then `None` is returned #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn key(&self) -> Option<&K> { - self.current.as_ref().map(|current| current.reborrow().into_kv().0) + pub fn peek_next(&mut self) -> Option<(&K, &mut V)> { + let (k, v) = self.inner.peek_next()?; + Some((&*k, v)) } - /// Returns a reference to the value of the element that the cursor is - /// currently pointing to. + /// Returns a reference to the the key and value of the previous element + /// without moving the cursor. /// - /// This returns `None` if the cursor is currently pointing to the - /// "ghost" non-element. + /// If the cursor is at the start of the map then `None` is returned. #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn value(&self) -> Option<&V> { - self.current.as_ref().map(|current| current.reborrow().into_kv().1) + pub fn peek_prev(&mut self) -> Option<(&K, &mut V)> { + let (k, v) = self.inner.peek_prev()?; + Some((&*k, v)) } - /// Returns a reference to the key and value of the element that the cursor - /// is currently pointing to. + /// Returns a read-only cursor pointing to the same location as the + /// `CursorMut`. /// - /// This returns `None` if the cursor is currently pointing to the - /// "ghost" non-element. + /// The lifetime of the returned `Cursor` is bound to that of the + /// `CursorMut`, which means it cannot outlive the `CursorMut` and that the + /// `CursorMut` is frozen for the lifetime of the `Cursor`. #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn key_value(&self) -> Option<(&K, &V)> { - self.current.as_ref().map(|current| current.reborrow().into_kv()) + pub fn as_cursor(&self) -> Cursor<'_, K, V> { + self.inner.as_cursor() } - /// Returns a mutable reference to the value of the element that the cursor - /// is currently pointing to. + /// Converts the cursor into a [`CursorMutKey`], which allows mutating + /// the key of elements in the tree. /// - /// This returns `None` if the cursor is currently pointing to the - /// "ghost" non-element. + /// # Safety + /// + /// Since this cursor allows mutating keys, you must ensure that the `BTreeMap` + /// invariants are maintained. Specifically: + /// + /// * The key of the newly inserted element must be unique in the tree. + /// * All keys in the tree must remain in sorted order. #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn value_mut(&mut self) -> Option<&mut V> { - self.current.as_mut().map(|current| current.kv_mut().1) + pub unsafe fn with_mutable_key(self) -> CursorMutKey<'a, K, V, A> { + self.inner } +} - /// Returns a reference to the key and mutable reference to the value of the - /// element that the cursor is currently pointing to. +impl<'a, K, V, A> CursorMutKey<'a, K, V, A> { + /// Advances the cursor to the next gap, returning the key and value of the + /// element that it moved over. /// - /// This returns `None` if the cursor is currently pointing to the - /// "ghost" non-element. + /// If the cursor is already at the end of the map then `None` is returned + /// and the cursor is not moved. #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn key_value_mut(&mut self) -> Option<(&K, &mut V)> { - self.current.as_mut().map(|current| { - let (k, v) = current.kv_mut(); - (&*k, v) - }) + pub fn next(&mut self) -> Option<(&mut K, &mut V)> { + let current = self.current.take()?; + match current.next_kv() { + Ok(mut kv) => { + // SAFETY: The key/value pointers remain valid even after the + // cursor is moved forward. The lifetimes then prevent any + // further access to the cursor. + let (k, v) = unsafe { kv.reborrow_mut().into_kv_mut() }; + let (k, v) = (k as *mut _, v as *mut _); + self.current = Some(kv.next_leaf_edge()); + Some(unsafe { (&mut *k, &mut *v) }) + } + Err(root) => { + self.current = Some(root.last_leaf_edge()); + None + } + } } - /// Returns a mutable reference to the key of the element that the cursor is - /// currently pointing to. - /// - /// This returns `None` if the cursor is currently pointing to the - /// "ghost" non-element. - /// - /// # Safety - /// - /// This can be used to modify the key, but you must ensure that the - /// `BTreeMap` invariants are maintained. Specifically: + /// Advances the cursor to the previous gap, returning the key and value of + /// the element that it moved over. /// - /// * The key must remain unique within the tree. - /// * The key must remain in sorted order with regards to other elements in - /// the tree. + /// If the cursor is already at the start of the map then `None` is returned + /// and the cursor is not moved. #[unstable(feature = "btree_cursors", issue = "107540")] - pub unsafe fn key_mut_unchecked(&mut self) -> Option<&mut K> { - self.current.as_mut().map(|current| current.kv_mut().0) + pub fn prev(&mut self) -> Option<(&mut K, &mut V)> { + let current = self.current.take()?; + match current.next_back_kv() { + Ok(mut kv) => { + // SAFETY: The key/value pointers remain valid even after the + // cursor is moved forward. The lifetimes then prevent any + // further access to the cursor. + let (k, v) = unsafe { kv.reborrow_mut().into_kv_mut() }; + let (k, v) = (k as *mut _, v as *mut _); + self.current = Some(kv.next_back_leaf_edge()); + Some(unsafe { (&mut *k, &mut *v) }) + } + Err(root) => { + self.current = Some(root.first_leaf_edge()); + None + } + } } - /// Returns a reference to the key and value of the next element. + /// Returns a reference to the the key and value of the next element without + /// moving the cursor. /// - /// If the cursor is pointing to the "ghost" non-element then this returns - /// the first element of the `BTreeMap`. If it is pointing to the last - /// element of the `BTreeMap` then this returns `None`. + /// If the cursor is at the end of the map then `None` is returned #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn peek_next(&mut self) -> Option<(&K, &mut V)> { - let (k, v) = match self.current { - None => { - // SAFETY: The previous borrow of root has ended. - unsafe { self.root.reborrow() } - .as_mut()? - .borrow_mut() - .first_leaf_edge() - .next_kv() - .ok()? - .into_kv_valmut() - } - // SAFETY: We're not using this to mutate the tree. - Some(ref mut current) => { - unsafe { current.reborrow_mut() }.next_leaf_edge().next_kv().ok()?.into_kv_valmut() - } - }; - Some((k, v)) + pub fn peek_next(&mut self) -> Option<(&mut K, &mut V)> { + let current = self.current.as_mut()?; + // SAFETY: We're not using this to mutate the tree. + let kv = unsafe { current.reborrow_mut() }.next_kv().ok()?.into_kv_mut(); + Some(kv) } - /// Returns a reference to the key and value of the previous element. + /// Returns a reference to the the key and value of the previous element + /// without moving the cursor. /// - /// If the cursor is pointing to the "ghost" non-element then this returns - /// the last element of the `BTreeMap`. If it is pointing to the first - /// element of the `BTreeMap` then this returns `None`. + /// If the cursor is at the start of the map then `None` is returned. #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn peek_prev(&mut self) -> Option<(&K, &mut V)> { - let (k, v) = match self.current.as_mut() { - None => { - // SAFETY: The previous borrow of root has ended. - unsafe { self.root.reborrow() } - .as_mut()? - .borrow_mut() - .last_leaf_edge() - .next_back_kv() - .ok()? - .into_kv_valmut() - } - Some(current) => { - // SAFETY: We're not using this to mutate the tree. - unsafe { current.reborrow_mut() } - .next_back_leaf_edge() - .next_back_kv() - .ok()? - .into_kv_valmut() - } - }; - Some((k, v)) + pub fn peek_prev(&mut self) -> Option<(&mut K, &mut V)> { + let current = self.current.as_mut()?; + // SAFETY: We're not using this to mutate the tree. + let kv = unsafe { current.reborrow_mut() }.next_back_kv().ok()?.into_kv_mut(); + Some(kv) } - /// Returns a read-only cursor pointing to the current element. + /// Returns a read-only cursor pointing to the same location as the + /// `CursorMutKey`. /// /// The lifetime of the returned `Cursor` is bound to that of the - /// `CursorMut`, which means it cannot outlive the `CursorMut` and that the - /// `CursorMut` is frozen for the lifetime of the `Cursor`. + /// `CursorMutKey`, which means it cannot outlive the `CursorMutKey` and that the + /// `CursorMutKey` is frozen for the lifetime of the `Cursor`. #[unstable(feature = "btree_cursors", issue = "107540")] pub fn as_cursor(&self) -> Cursor<'_, K, V> { Cursor { @@ -3054,11 +3038,12 @@ impl<'a, K, V, A> CursorMut<'a, K, V, A> { } // Now the tree editing operations -impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> { - /// Inserts a new element into the `BTreeMap` after the current one. +impl<'a, K: Ord, V, A: Allocator + Clone> CursorMutKey<'a, K, V, A> { + /// Inserts a new element into the `BTreeMap` in the gap that the + /// `CursorMutKey` is currently pointing to. /// - /// If the cursor is pointing at the "ghost" non-element then the new element is - /// inserted at the front of the `BTreeMap`. + /// After the insertion the cursor will be pointing at the gap before the + /// newly inserted element. /// /// # Safety /// @@ -3071,20 +3056,19 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> { pub unsafe fn insert_after_unchecked(&mut self, key: K, value: V) { let edge = match self.current.take() { None => { + // Tree is empty, allocate a new root. // SAFETY: We have no other reference to the tree. - match unsafe { self.root.reborrow() } { - root @ None => { - // Tree is empty, allocate a new root. - let mut node = NodeRef::new_leaf(self.alloc.clone()); - node.borrow_mut().push(key, value); - *root = Some(node.forget_type()); - *self.length += 1; - return; - } - Some(root) => root.borrow_mut().first_leaf_edge(), - } + let root = unsafe { self.root.reborrow() }; + debug_assert!(root.is_none()); + let mut node = NodeRef::new_leaf(self.alloc.clone()); + // SAFETY: We don't touch the root while the handle is alive. + let handle = unsafe { node.borrow_mut().push_with_handle(key, value) }; + *root = Some(node.forget_type()); + *self.length += 1; + self.current = Some(handle.left_edge()); + return; } - Some(current) => current.next_leaf_edge(), + Some(current) => current, }; let handle = edge.insert_recursing(key, value, self.alloc.clone(), |ins| { @@ -3094,14 +3078,15 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> { let root = unsafe { self.root.reborrow().as_mut().unwrap() }; root.push_internal_level(self.alloc.clone()).push(ins.kv.0, ins.kv.1, ins.right) }); - self.current = handle.left_edge().next_back_kv().ok(); + self.current = Some(handle.left_edge()); *self.length += 1; } - /// Inserts a new element into the `BTreeMap` before the current one. + /// Inserts a new element into the `BTreeMap` in the gap that the + /// `CursorMutKey` is currently pointing to. /// - /// If the cursor is pointing at the "ghost" non-element then the new element is - /// inserted at the end of the `BTreeMap`. + /// After the insertion the cursor will be pointing at the gap after the + /// newly inserted element. /// /// # Safety /// @@ -3119,15 +3104,17 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> { root @ None => { // Tree is empty, allocate a new root. let mut node = NodeRef::new_leaf(self.alloc.clone()); - node.borrow_mut().push(key, value); + // SAFETY: We don't touch the root while the handle is alive. + let handle = unsafe { node.borrow_mut().push_with_handle(key, value) }; *root = Some(node.forget_type()); *self.length += 1; + self.current = Some(handle.right_edge()); return; } Some(root) => root.borrow_mut().last_leaf_edge(), } } - Some(current) => current.next_back_leaf_edge(), + Some(current) => current, }; let handle = edge.insert_recursing(key, value, self.alloc.clone(), |ins| { @@ -3137,14 +3124,15 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> { let root = unsafe { self.root.reborrow().as_mut().unwrap() }; root.push_internal_level(self.alloc.clone()).push(ins.kv.0, ins.kv.1, ins.right) }); - self.current = handle.right_edge().next_kv().ok(); + self.current = Some(handle.right_edge()); *self.length += 1; } - /// Inserts a new element into the `BTreeMap` after the current one. + /// Inserts a new element into the `BTreeMap` in the gap that the + /// `CursorMutKey` is currently pointing to. /// - /// If the cursor is pointing at the "ghost" non-element then the new element is - /// inserted at the front of the `BTreeMap`. + /// After the insertion the cursor will be pointing at the gap before the + /// newly inserted element. /// /// # Panics /// @@ -3155,9 +3143,9 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> { /// any). #[unstable(feature = "btree_cursors", issue = "107540")] pub fn insert_after(&mut self, key: K, value: V) { - if let Some(current) = self.key() { - if &key <= current { - panic!("key must be ordered above the current element"); + if let Some((prev, _)) = self.peek_prev() { + if &key <= prev { + panic!("key must be ordered above the previous element"); } } if let Some((next, _)) = self.peek_next() { @@ -3170,10 +3158,11 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> { } } - /// Inserts a new element into the `BTreeMap` before the current one. + /// Inserts a new element into the `BTreeMap` in the gap that the + /// `CursorMutKey` is currently pointing to. /// - /// If the cursor is pointing at the "ghost" non-element then the new element is - /// inserted at the end of the `BTreeMap`. + /// After the insertion the cursor will be pointing at the gap after the + /// newly inserted element. /// /// # Panics /// @@ -3184,35 +3173,34 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> { /// any). #[unstable(feature = "btree_cursors", issue = "107540")] pub fn insert_before(&mut self, key: K, value: V) { - if let Some(current) = self.key() { - if &key >= current { - panic!("key must be ordered below the current element"); - } - } if let Some((prev, _)) = self.peek_prev() { if &key <= prev { panic!("key must be ordered above the previous element"); } } + if let Some((next, _)) = self.peek_next() { + if &key >= next { + panic!("key must be ordered below the next element"); + } + } unsafe { self.insert_before_unchecked(key, value); } } - /// Removes the current element from the `BTreeMap`. - /// - /// The element that was removed is returned, and the cursor is - /// moved to point to the next element in the `BTreeMap`. + /// Removes the next element from the `BTreeMap`. /// - /// If the cursor is currently pointing to the "ghost" non-element then no element - /// is removed and `None` is returned. The cursor is not moved in this case. + /// The element that was removed is returned. The cursor position is + /// unchanged (before the removed element). #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn remove_current(&mut self) -> Option<(K, V)> { + pub fn remove_next(&mut self) -> Option<(K, V)> { let current = self.current.take()?; let mut emptied_internal_root = false; - let (kv, pos) = - current.remove_kv_tracking(|| emptied_internal_root = true, self.alloc.clone()); - self.current = pos.next_kv().ok(); + let (kv, pos) = current + .next_kv() + .ok()? + .remove_kv_tracking(|| emptied_internal_root = true, self.alloc.clone()); + self.current = Some(pos); *self.length -= 1; if emptied_internal_root { // SAFETY: This is safe since current does not point within the now @@ -3223,20 +3211,19 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> { Some(kv) } - /// Removes the current element from the `BTreeMap`. - /// - /// The element that was removed is returned, and the cursor is - /// moved to point to the previous element in the `BTreeMap`. + /// Removes the precending element from the `BTreeMap`. /// - /// If the cursor is currently pointing to the "ghost" non-element then no element - /// is removed and `None` is returned. The cursor is not moved in this case. + /// The element that was removed is returned. The cursor position is + /// unchanged (after the removed element). #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn remove_current_and_move_back(&mut self) -> Option<(K, V)> { + pub fn remove_prev(&mut self) -> Option<(K, V)> { let current = self.current.take()?; let mut emptied_internal_root = false; - let (kv, pos) = - current.remove_kv_tracking(|| emptied_internal_root = true, self.alloc.clone()); - self.current = pos.next_back_kv().ok(); + let (kv, pos) = current + .next_back_kv() + .ok()? + .remove_kv_tracking(|| emptied_internal_root = true, self.alloc.clone()); + self.current = Some(pos); *self.length -= 1; if emptied_internal_root { // SAFETY: This is safe since current does not point within the now @@ -3248,5 +3235,97 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> { } } +impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> { + /// Inserts a new element into the `BTreeMap` in the gap that the + /// `CursorMut` is currently pointing to. + /// + /// After the insertion the cursor will be pointing at the gap before the + /// newly inserted element. + /// + /// # Safety + /// + /// You must ensure that the `BTreeMap` invariants are maintained. + /// Specifically: + /// + /// * The key of the newly inserted element must be unique in the tree. + /// * All keys in the tree must remain in sorted order. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub unsafe fn insert_after_unchecked(&mut self, key: K, value: V) { + unsafe { self.inner.insert_after_unchecked(key, value) } + } + + /// Inserts a new element into the `BTreeMap` in the gap that the + /// `CursorMut` is currently pointing to. + /// + /// After the insertion the cursor will be pointing at the gap after the + /// newly inserted element. + /// + /// # Safety + /// + /// You must ensure that the `BTreeMap` invariants are maintained. + /// Specifically: + /// + /// * The key of the newly inserted element must be unique in the tree. + /// * All keys in the tree must remain in sorted order. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub unsafe fn insert_before_unchecked(&mut self, key: K, value: V) { + unsafe { self.inner.insert_before_unchecked(key, value) } + } + + /// Inserts a new element into the `BTreeMap` in the gap that the + /// `CursorMut` is currently pointing to. + /// + /// After the insertion the cursor will be pointing at the gap before the + /// newly inserted element. + /// + /// # Panics + /// + /// This function panics if: + /// - the given key compares less than or equal to the current element (if + /// any). + /// - the given key compares greater than or equal to the next element (if + /// any). + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn insert_after(&mut self, key: K, value: V) { + self.inner.insert_after(key, value) + } + + /// Inserts a new element into the `BTreeMap` in the gap that the + /// `CursorMut` is currently pointing to. + /// + /// After the insertion the cursor will be pointing at the gap after the + /// newly inserted element. + /// + /// # Panics + /// + /// This function panics if: + /// - the given key compares greater than or equal to the current element + /// (if any). + /// - the given key compares less than or equal to the previous element (if + /// any). + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn insert_before(&mut self, key: K, value: V) { + self.inner.insert_before(key, value) + } + + /// Removes the next element from the `BTreeMap`. + /// + /// The element that was removed is returned. The cursor position is + /// unchanged (before the removed element). + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn remove_next(&mut self) -> Option<(K, V)> { + self.inner.remove_next() + } + + /// Removes the precending element from the `BTreeMap`. + /// + /// The element that was removed is returned. The cursor position is + /// unchanged (after the removed element). + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn remove_prev(&mut self) -> Option<(K, V)> { + self.inner.remove_prev() + } +} + #[cfg(test)] mod tests; diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index 8681cfcd61757..eea00cc5d6726 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -2354,48 +2354,95 @@ fn test_cursor() { let map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]); let mut cur = map.lower_bound(Bound::Unbounded); - assert_eq!(cur.key(), Some(&1)); - cur.move_next(); - assert_eq!(cur.key(), Some(&2)); - assert_eq!(cur.peek_next(), Some((&3, &'c'))); - cur.move_prev(); - assert_eq!(cur.key(), Some(&1)); + assert_eq!(cur.peek_next(), Some((&1, &'a'))); assert_eq!(cur.peek_prev(), None); + assert_eq!(cur.prev(), None); + assert_eq!(cur.next(), Some((&1, &'a'))); + + assert_eq!(cur.next(), Some((&2, &'b'))); + + assert_eq!(cur.peek_next(), Some((&3, &'c'))); + assert_eq!(cur.prev(), Some((&2, &'b'))); + assert_eq!(cur.peek_prev(), Some((&1, &'a'))); let mut cur = map.upper_bound(Bound::Excluded(&1)); - assert_eq!(cur.key(), None); - cur.move_next(); - assert_eq!(cur.key(), Some(&1)); - cur.move_prev(); - assert_eq!(cur.key(), None); - assert_eq!(cur.peek_prev(), Some((&3, &'c'))); + assert_eq!(cur.peek_prev(), None); + assert_eq!(cur.next(), Some((&1, &'a'))); + assert_eq!(cur.prev(), Some((&1, &'a'))); } #[test] fn test_cursor_mut() { let mut map = BTreeMap::from([(1, 'a'), (3, 'c'), (5, 'e')]); let mut cur = map.lower_bound_mut(Bound::Excluded(&3)); - assert_eq!(cur.key(), Some(&5)); + assert_eq!(cur.peek_next(), Some((&5, &mut 'e'))); + assert_eq!(cur.peek_prev(), Some((&3, &mut 'c'))); + cur.insert_before(4, 'd'); - assert_eq!(cur.key(), Some(&5)); + assert_eq!(cur.peek_next(), Some((&5, &mut 'e'))); assert_eq!(cur.peek_prev(), Some((&4, &mut 'd'))); - cur.move_next(); - assert_eq!(cur.key(), None); + + assert_eq!(cur.next(), Some((&5, &mut 'e'))); + assert_eq!(cur.peek_next(), None); + assert_eq!(cur.peek_prev(), Some((&5, &mut 'e'))); cur.insert_before(6, 'f'); - assert_eq!(cur.key(), None); - assert_eq!(cur.remove_current(), None); - assert_eq!(cur.key(), None); - cur.insert_after(0, '?'); - assert_eq!(cur.key(), None); - assert_eq!(map, BTreeMap::from([(0, '?'), (1, 'a'), (3, 'c'), (4, 'd'), (5, 'e'), (6, 'f')])); + assert_eq!(cur.peek_next(), None); + assert_eq!(cur.peek_prev(), Some((&6, &mut 'f'))); + assert_eq!(cur.remove_prev(), Some((6, 'f'))); + assert_eq!(cur.remove_prev(), Some((5, 'e'))); + assert_eq!(cur.remove_next(), None); + assert_eq!(map, BTreeMap::from([(1, 'a'), (3, 'c'), (4, 'd')])); let mut cur = map.upper_bound_mut(Bound::Included(&5)); - assert_eq!(cur.key(), Some(&5)); - assert_eq!(cur.remove_current(), Some((5, 'e'))); - assert_eq!(cur.key(), Some(&6)); - assert_eq!(cur.remove_current_and_move_back(), Some((6, 'f'))); - assert_eq!(cur.key(), Some(&4)); - assert_eq!(map, BTreeMap::from([(0, '?'), (1, 'a'), (3, 'c'), (4, 'd')])); + assert_eq!(cur.peek_next(), None); + assert_eq!(cur.prev(), Some((&4, &mut 'd'))); + assert_eq!(cur.peek_next(), Some((&4, &mut 'd'))); + assert_eq!(cur.peek_prev(), Some((&3, &mut 'c'))); + assert_eq!(cur.remove_next(), Some((4, 'd'))); + assert_eq!(map, BTreeMap::from([(1, 'a'), (3, 'c')])); +} + +#[test] +fn test_cursor_mut_key() { + let mut map = BTreeMap::from([(1, 'a'), (3, 'c'), (5, 'e')]); + let mut cur = unsafe { map.lower_bound_mut(Bound::Excluded(&3)).with_mutable_key() }; + assert_eq!(cur.peek_next(), Some((&mut 5, &mut 'e'))); + assert_eq!(cur.peek_prev(), Some((&mut 3, &mut 'c'))); + + cur.insert_before(4, 'd'); + assert_eq!(cur.peek_next(), Some((&mut 5, &mut 'e'))); + assert_eq!(cur.peek_prev(), Some((&mut 4, &mut 'd'))); + + assert_eq!(cur.next(), Some((&mut 5, &mut 'e'))); + assert_eq!(cur.peek_next(), None); + assert_eq!(cur.peek_prev(), Some((&mut 5, &mut 'e'))); + cur.insert_before(6, 'f'); + assert_eq!(cur.peek_next(), None); + assert_eq!(cur.peek_prev(), Some((&mut 6, &mut 'f'))); + assert_eq!(cur.remove_prev(), Some((6, 'f'))); + assert_eq!(cur.remove_prev(), Some((5, 'e'))); + assert_eq!(cur.remove_next(), None); + assert_eq!(map, BTreeMap::from([(1, 'a'), (3, 'c'), (4, 'd')])); + + let mut cur = unsafe { map.upper_bound_mut(Bound::Included(&5)).with_mutable_key() }; + assert_eq!(cur.peek_next(), None); + assert_eq!(cur.prev(), Some((&mut 4, &mut 'd'))); + assert_eq!(cur.peek_next(), Some((&mut 4, &mut 'd'))); + assert_eq!(cur.peek_prev(), Some((&mut 3, &mut 'c'))); + assert_eq!(cur.remove_next(), Some((4, 'd'))); + assert_eq!(map, BTreeMap::from([(1, 'a'), (3, 'c')])); +} + +#[test] +fn test_cursor_empty() { + let mut map = BTreeMap::new(); + let mut cur = map.lower_bound_mut(Bound::Excluded(&3)); + assert_eq!(cur.peek_next(), None); + assert_eq!(cur.peek_prev(), None); + cur.insert_after(0, 0); + assert_eq!(cur.peek_next(), Some((&0, &mut 0))); + assert_eq!(cur.peek_prev(), None); + assert_eq!(map, BTreeMap::from([(0, 0)])); } #[should_panic(expected = "key must be ordered above the previous element")] @@ -2414,7 +2461,7 @@ fn test_cursor_mut_insert_before_2() { cur.insert_before(1, 'd'); } -#[should_panic(expected = "key must be ordered below the current element")] +#[should_panic(expected = "key must be ordered above the previous element")] #[test] fn test_cursor_mut_insert_before_3() { let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]); @@ -2422,7 +2469,7 @@ fn test_cursor_mut_insert_before_3() { cur.insert_before(2, 'd'); } -#[should_panic(expected = "key must be ordered below the current element")] +#[should_panic(expected = "key must be ordered below the next element")] #[test] fn test_cursor_mut_insert_before_4() { let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]); @@ -2430,7 +2477,7 @@ fn test_cursor_mut_insert_before_4() { cur.insert_before(3, 'd'); } -#[should_panic(expected = "key must be ordered above the current element")] +#[should_panic(expected = "key must be ordered above the previous element")] #[test] fn test_cursor_mut_insert_after_1() { let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]); @@ -2438,7 +2485,7 @@ fn test_cursor_mut_insert_after_1() { cur.insert_after(1, 'd'); } -#[should_panic(expected = "key must be ordered above the current element")] +#[should_panic(expected = "key must be ordered above the previous element")] #[test] fn test_cursor_mut_insert_after_2() { let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]); @@ -2467,14 +2514,14 @@ fn cursor_peek_prev_agrees_with_cursor_mut() { let mut map = BTreeMap::from([(1, 1), (2, 2), (3, 3)]); let cursor = map.lower_bound(Bound::Excluded(&3)); - assert!(cursor.key().is_none()); + assert!(cursor.peek_next().is_none()); let prev = cursor.peek_prev(); assert_matches!(prev, Some((&3, _))); // Shadow names so the two parts of this test match. let mut cursor = map.lower_bound_mut(Bound::Excluded(&3)); - assert!(cursor.key().is_none()); + assert!(cursor.peek_next().is_none()); let prev = cursor.peek_prev(); assert_matches!(prev, Some((&3, _))); diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index 3233a575ecf25..78ccb3af66dbb 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -648,17 +648,36 @@ impl NodeRef { impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Leaf> { /// Adds a key-value pair to the end of the node, and returns - /// the mutable reference of the inserted value. - pub fn push(&mut self, key: K, val: V) -> &mut V { + /// a handle to the inserted value. + /// + /// # Safety + /// + /// The returned handle has an unbound lifetime. + pub unsafe fn push_with_handle<'b>( + &mut self, + key: K, + val: V, + ) -> Handle, K, V, marker::Leaf>, marker::KV> { let len = self.len_mut(); let idx = usize::from(*len); assert!(idx < CAPACITY); *len += 1; unsafe { self.key_area_mut(idx).write(key); - self.val_area_mut(idx).write(val) + self.val_area_mut(idx).write(val); + Handle::new_kv( + NodeRef { height: self.height, node: self.node, _marker: PhantomData }, + idx, + ) } } + + /// Adds a key-value pair to the end of the node, and returns + /// the mutable reference of the inserted value. + pub fn push(&mut self, key: K, val: V) -> *mut V { + // SAFETY: The unbound handle is no longer accessible. + unsafe { self.push_with_handle(key, val).into_val_mut() } + } } impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { @@ -1100,10 +1119,10 @@ impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType> unsafe { leaf.vals.get_unchecked_mut(self.idx).assume_init_mut() } } - pub fn into_kv_valmut(self) -> (&'a K, &'a mut V) { + pub fn into_kv_mut(self) -> (&'a mut K, &'a mut V) { debug_assert!(self.idx < self.node.len()); let leaf = self.node.into_leaf_mut(); - let k = unsafe { leaf.keys.get_unchecked(self.idx).assume_init_ref() }; + let k = unsafe { leaf.keys.get_unchecked_mut(self.idx).assume_init_mut() }; let v = unsafe { leaf.vals.get_unchecked_mut(self.idx).assume_init_mut() }; (k, v) } From 166e3485649f1c4a7e6c4766756a1b0db01f95e1 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 23 Nov 2023 12:37:20 +0000 Subject: [PATCH 0024/1197] Update library/alloc/src/collections/btree/map.rs Co-authored-by: Joe ST --- library/alloc/src/collections/btree/map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index b36298cde3675..f0a1561f6508e 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -2717,7 +2717,7 @@ impl BTreeMap { /// /// A `Cursor` is like an iterator, except that it can freely seek back-and-forth. /// -/// Cursors always point to a gao between two elements in the map, and can +/// Cursors always point to a gap between two elements in the map, and can /// operate on the two immediately adjacent elements. /// /// A `Cursor` is created with the [`BTreeMap::lower_bound`] and [`BTreeMap::upper_bound`] methods. From d085f34a2d90a6c32609a1dc8a7ba97d77ce1184 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 23 Nov 2023 16:05:03 +0000 Subject: [PATCH 0025/1197] Add UnorderedKeyError --- library/alloc/src/collections/btree/map.rs | 40 ++++++++++++++----- .../alloc/src/collections/btree/map/tests.rs | 34 ++++++---------- 2 files changed, 43 insertions(+), 31 deletions(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index f0a1561f6508e..b585e2082f137 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -1,6 +1,7 @@ use crate::vec::Vec; use core::borrow::Borrow; use core::cmp::Ordering; +use core::error::Error; use core::fmt::{self, Debug}; use core::hash::{Hash, Hasher}; use core::iter::FusedIterator; @@ -2750,7 +2751,7 @@ impl Debug for Cursor<'_, K, V> { /// references is tied to its own lifetime, instead of just the underlying map. This means /// cursors cannot yield multiple elements at once. /// -/// Cursors always point to a gao between two elements in the map, and can +/// Cursors always point to a gap between two elements in the map, and can /// operate on the two immediately adjacent elements. /// /// A `CursorMut` is created with the [`BTreeMap::lower_bound_mut`] and [`BTreeMap::upper_bound_mut`] @@ -2780,7 +2781,7 @@ impl Debug for CursorMut<'_, K, V, A> { /// references is tied to its own lifetime, instead of just the underlying map. This means /// cursors cannot yield multiple elements at once. /// -/// Cursors always point to a gao between two elements in the map, and can +/// Cursors always point to a gap between two elements in the map, and can /// operate on the two immediately adjacent elements. /// /// A `CursorMutKey` is created from a [`CursorMut`] with the @@ -3142,20 +3143,21 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMutKey<'a, K, V, A> { /// - the given key compares greater than or equal to the next element (if /// any). #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn insert_after(&mut self, key: K, value: V) { + pub fn insert_after(&mut self, key: K, value: V) -> Result<(), UnorderedKeyError> { if let Some((prev, _)) = self.peek_prev() { if &key <= prev { - panic!("key must be ordered above the previous element"); + return Err(UnorderedKeyError {}); } } if let Some((next, _)) = self.peek_next() { if &key >= next { - panic!("key must be ordered below the next element"); + return Err(UnorderedKeyError {}); } } unsafe { self.insert_after_unchecked(key, value); } + Ok(()) } /// Inserts a new element into the `BTreeMap` in the gap that the @@ -3172,20 +3174,21 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMutKey<'a, K, V, A> { /// - the given key compares less than or equal to the previous element (if /// any). #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn insert_before(&mut self, key: K, value: V) { + pub fn insert_before(&mut self, key: K, value: V) -> Result<(), UnorderedKeyError> { if let Some((prev, _)) = self.peek_prev() { if &key <= prev { - panic!("key must be ordered above the previous element"); + return Err(UnorderedKeyError {}); } } if let Some((next, _)) = self.peek_next() { if &key >= next { - panic!("key must be ordered below the next element"); + return Err(UnorderedKeyError {}); } } unsafe { self.insert_before_unchecked(key, value); } + Ok(()) } /// Removes the next element from the `BTreeMap`. @@ -3286,7 +3289,7 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> { /// - the given key compares greater than or equal to the next element (if /// any). #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn insert_after(&mut self, key: K, value: V) { + pub fn insert_after(&mut self, key: K, value: V) -> Result<(), UnorderedKeyError> { self.inner.insert_after(key, value) } @@ -3304,7 +3307,7 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> { /// - the given key compares less than or equal to the previous element (if /// any). #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn insert_before(&mut self, key: K, value: V) { + pub fn insert_before(&mut self, key: K, value: V) -> Result<(), UnorderedKeyError> { self.inner.insert_before(key, value) } @@ -3327,5 +3330,22 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> { } } +/// Error type returned by [`CursorMut::insert_before`] and +/// [`CursorMut::insert_after`] if the key being inserted is not properly +/// ordered with regards to adjacent keys. +#[derive(Clone, PartialEq, Eq, Debug)] +#[unstable(feature = "btree_cursors", issue = "107540")] +pub struct UnorderedKeyError {} + +#[unstable(feature = "btree_cursors", issue = "107540")] +impl fmt::Display for UnorderedKeyError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "key is not properly ordered relative to neighbors") + } +} + +#[unstable(feature = "btree_cursors", issue = "107540")] +impl Error for UnorderedKeyError {} + #[cfg(test)] mod tests; diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index eea00cc5d6726..c1e5df5120478 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -2378,14 +2378,14 @@ fn test_cursor_mut() { assert_eq!(cur.peek_next(), Some((&5, &mut 'e'))); assert_eq!(cur.peek_prev(), Some((&3, &mut 'c'))); - cur.insert_before(4, 'd'); + cur.insert_before(4, 'd').unwrap(); assert_eq!(cur.peek_next(), Some((&5, &mut 'e'))); assert_eq!(cur.peek_prev(), Some((&4, &mut 'd'))); assert_eq!(cur.next(), Some((&5, &mut 'e'))); assert_eq!(cur.peek_next(), None); assert_eq!(cur.peek_prev(), Some((&5, &mut 'e'))); - cur.insert_before(6, 'f'); + cur.insert_before(6, 'f').unwrap(); assert_eq!(cur.peek_next(), None); assert_eq!(cur.peek_prev(), Some((&6, &mut 'f'))); assert_eq!(cur.remove_prev(), Some((6, 'f'))); @@ -2409,14 +2409,14 @@ fn test_cursor_mut_key() { assert_eq!(cur.peek_next(), Some((&mut 5, &mut 'e'))); assert_eq!(cur.peek_prev(), Some((&mut 3, &mut 'c'))); - cur.insert_before(4, 'd'); + cur.insert_before(4, 'd').unwrap(); assert_eq!(cur.peek_next(), Some((&mut 5, &mut 'e'))); assert_eq!(cur.peek_prev(), Some((&mut 4, &mut 'd'))); assert_eq!(cur.next(), Some((&mut 5, &mut 'e'))); assert_eq!(cur.peek_next(), None); assert_eq!(cur.peek_prev(), Some((&mut 5, &mut 'e'))); - cur.insert_before(6, 'f'); + cur.insert_before(6, 'f').unwrap(); assert_eq!(cur.peek_next(), None); assert_eq!(cur.peek_prev(), Some((&mut 6, &mut 'f'))); assert_eq!(cur.remove_prev(), Some((6, 'f'))); @@ -2439,74 +2439,66 @@ fn test_cursor_empty() { let mut cur = map.lower_bound_mut(Bound::Excluded(&3)); assert_eq!(cur.peek_next(), None); assert_eq!(cur.peek_prev(), None); - cur.insert_after(0, 0); + cur.insert_after(0, 0).unwrap(); assert_eq!(cur.peek_next(), Some((&0, &mut 0))); assert_eq!(cur.peek_prev(), None); assert_eq!(map, BTreeMap::from([(0, 0)])); } -#[should_panic(expected = "key must be ordered above the previous element")] #[test] fn test_cursor_mut_insert_before_1() { let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]); let mut cur = map.upper_bound_mut(Bound::Included(&2)); - cur.insert_before(0, 'd'); + cur.insert_before(0, 'd').unwrap_err(); } -#[should_panic(expected = "key must be ordered above the previous element")] #[test] fn test_cursor_mut_insert_before_2() { let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]); let mut cur = map.upper_bound_mut(Bound::Included(&2)); - cur.insert_before(1, 'd'); + cur.insert_before(1, 'd').unwrap_err(); } -#[should_panic(expected = "key must be ordered above the previous element")] #[test] fn test_cursor_mut_insert_before_3() { let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]); let mut cur = map.upper_bound_mut(Bound::Included(&2)); - cur.insert_before(2, 'd'); + cur.insert_before(2, 'd').unwrap_err(); } -#[should_panic(expected = "key must be ordered below the next element")] #[test] fn test_cursor_mut_insert_before_4() { let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]); let mut cur = map.upper_bound_mut(Bound::Included(&2)); - cur.insert_before(3, 'd'); + cur.insert_before(3, 'd').unwrap_err(); } -#[should_panic(expected = "key must be ordered above the previous element")] #[test] fn test_cursor_mut_insert_after_1() { let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]); let mut cur = map.upper_bound_mut(Bound::Included(&2)); - cur.insert_after(1, 'd'); + cur.insert_after(1, 'd').unwrap_err(); } -#[should_panic(expected = "key must be ordered above the previous element")] #[test] fn test_cursor_mut_insert_after_2() { let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]); let mut cur = map.upper_bound_mut(Bound::Included(&2)); - cur.insert_after(2, 'd'); + cur.insert_after(2, 'd').unwrap_err(); } -#[should_panic(expected = "key must be ordered below the next element")] #[test] fn test_cursor_mut_insert_after_3() { let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]); let mut cur = map.upper_bound_mut(Bound::Included(&2)); - cur.insert_after(3, 'd'); + cur.insert_after(3, 'd').unwrap_err(); } -#[should_panic(expected = "key must be ordered below the next element")] #[test] fn test_cursor_mut_insert_after_4() { let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]); let mut cur = map.upper_bound_mut(Bound::Included(&2)); - cur.insert_after(4, 'd'); + cur.insert_after(4, 'd').unwrap_err(); } #[test] From 27f419bc7dfb777f984595ffbc800331f591ce66 Mon Sep 17 00:00:00 2001 From: Ryan Mehri Date: Fri, 22 Sep 2023 16:42:08 -0700 Subject: [PATCH 0026/1197] implement strict_* operations for signed integer types --- library/core/src/lib.rs | 1 + library/core/src/num/int_macros.rs | 508 +++++++++++++++++++++++++ library/core/src/num/mod.rs | 1 + library/core/src/num/overflow_panic.rs | 47 +++ 4 files changed, 557 insertions(+) create mode 100644 library/core/src/num/overflow_panic.rs diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 921a0fb6a9f83..44ba6c58c6707 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -162,6 +162,7 @@ #![feature(const_slice_ptr_len)] #![feature(const_slice_split_at_mut)] #![feature(const_str_from_utf8_unchecked_mut)] +#![feature(const_strict_overflow_ops)] #![feature(const_swap)] #![feature(const_try)] #![feature(const_type_id)] diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index fd01f1b261012..8b3f742bf9197 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -454,6 +454,38 @@ macro_rules! int_impl { if unlikely!(b) {None} else {Some(a)} } + /// Strict integer addition. Computes `self + rhs`, panicking + /// if overflow occurred. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).strict_add(1), ", stringify!($SelfT), "::MAX - 1);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add(3);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn strict_add(self, rhs: Self) -> Self { + let (a, b) = self.overflowing_add(rhs); + if unlikely!(b) {overflow_panic::add()} else {a} + } + /// Unchecked integer addition. Computes `self + rhs`, assuming overflow /// cannot occur. /// @@ -501,6 +533,38 @@ macro_rules! int_impl { if unlikely!(b) {None} else {Some(a)} } + /// Strict addition with an unsigned integer. Computes `self + rhs`, + /// panicking if overflow occurred. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".strict_add_unsigned(2), 3);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add_unsigned(3);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn strict_add_unsigned(self, rhs: $UnsignedT) -> Self { + let (a, b) = self.overflowing_add_unsigned(rhs); + if unlikely!(b) {overflow_panic::add()} else {a} + } + /// Checked integer subtraction. Computes `self - rhs`, returning `None` if /// overflow occurred. /// @@ -522,6 +586,38 @@ macro_rules! int_impl { if unlikely!(b) {None} else {Some(a)} } + /// Strict integer subtraction. Computes `self - rhs`, panicking if + /// overflow occurred. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 2).strict_sub(1), ", stringify!($SelfT), "::MIN + 1);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = (", stringify!($SelfT), "::MIN + 2).strict_sub(3);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn strict_sub(self, rhs: Self) -> Self { + let (a, b) = self.overflowing_sub(rhs); + if unlikely!(b) {overflow_panic::sub()} else {a} + } + /// Unchecked integer subtraction. Computes `self - rhs`, assuming overflow /// cannot occur. /// @@ -569,6 +665,38 @@ macro_rules! int_impl { if unlikely!(b) {None} else {Some(a)} } + /// Strict subtraction with an unsigned integer. Computes `self - rhs`, + /// panicking if overflow occurred. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".strict_sub_unsigned(2), -1);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = (", stringify!($SelfT), "::MIN + 2).strict_sub_unsigned(3);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn strict_sub_unsigned(self, rhs: $UnsignedT) -> Self { + let (a, b) = self.overflowing_sub_unsigned(rhs); + if unlikely!(b) {overflow_panic::sub()} else {a} + } + /// Checked integer multiplication. Computes `self * rhs`, returning `None` if /// overflow occurred. /// @@ -590,6 +718,38 @@ macro_rules! int_impl { if unlikely!(b) {None} else {Some(a)} } + /// Strict integer multiplication. Computes `self * rhs`, panicking if + /// overflow occurred. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.strict_mul(1), ", stringify!($SelfT), "::MAX);")] + /// ``` + /// + /// ``` should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_mul(2);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn strict_mul(self, rhs: Self) -> Self { + let (a, b) = self.overflowing_mul(rhs); + if unlikely!(b) {overflow_panic::mul()} else {a} + } + /// Unchecked integer multiplication. Computes `self * rhs`, assuming overflow /// cannot occur. /// @@ -642,6 +802,49 @@ macro_rules! int_impl { } } + /// Strict integer division. Computes `self / rhs`, panicking + /// if overflow occurred. + /// + /// # Panics + /// + /// This function will panic if `rhs` is zero. + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// + /// The only case where such an overflow can occur is when one divides `MIN / -1` on a signed type (where + /// `MIN` is the negative minimal value for the type); this is equivalent to `-MIN`, a positive value + /// that is too large to represent in the type. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).strict_div(-1), ", stringify!($Max), ");")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_div(-1);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div(0);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn strict_div(self, rhs: Self) -> Self { + let (a, b) = self.overflowing_div(rhs); + if unlikely!(b) {overflow_panic::div()} else {a} + } + /// Checked Euclidean division. Computes `self.div_euclid(rhs)`, /// returning `None` if `rhs == 0` or the division results in overflow. /// @@ -668,6 +871,49 @@ macro_rules! int_impl { } } + /// Strict Euclidean division. Computes `self.div_euclid(rhs)`, panicking + /// if overflow occurred. + /// + /// # Panics + /// + /// This function will panic if `rhs` is zero. + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// + /// The only case where such an overflow can occur is when one divides `MIN / -1` on a signed type (where + /// `MIN` is the negative minimal value for the type); this is equivalent to `-MIN`, a positive value + /// that is too large to represent in the type. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).strict_div_euclid(-1), ", stringify!($Max), ");")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_div_euclid(-1);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div_euclid(0);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn strict_div_euclid(self, rhs: Self) -> Self { + let (a, b) = self.overflowing_div_euclid(rhs); + if unlikely!(b) {overflow_panic::div()} else {a} + } + /// Checked integer remainder. Computes `self % rhs`, returning `None` if /// `rhs == 0` or the division results in overflow. /// @@ -694,6 +940,48 @@ macro_rules! int_impl { } } + /// Strict integer remainder. Computes `self % rhs`, panicking if + /// the division results in overflow. + /// + /// # Panics + /// + /// This function will panic if `rhs` is zero. + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// + /// The only case where such an overflow can occur is `x % y` for `MIN / -1` on a + /// signed type (where `MIN` is the negative minimal value), which is invalid due to implementation artifacts. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".strict_rem(2), 1);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = 5", stringify!($SelfT), ".strict_rem(0);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_rem(-1);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn strict_rem(self, rhs: Self) -> Self { + let (a, b) = self.overflowing_rem(rhs); + if unlikely!(b) {overflow_panic::rem()} else {a} + } + /// Checked Euclidean remainder. Computes `self.rem_euclid(rhs)`, returning `None` /// if `rhs == 0` or the division results in overflow. /// @@ -720,6 +1008,48 @@ macro_rules! int_impl { } } + /// Strict Euclidean remainder. Computes `self.rem_euclid(rhs)`, panicking if + /// the division results in overflow. + /// + /// # Panics + /// + /// This function will panic if `rhs` is zero. + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// + /// The only case where such an overflow can occur is `x % y` for `MIN / -1` on a + /// signed type (where `MIN` is the negative minimal value), which is invalid due to implementation artifacts. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".strict_rem_euclid(2), 1);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = 5", stringify!($SelfT), ".strict_rem_euclid(0);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_rem_euclid(-1);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn strict_rem_euclid(self, rhs: Self) -> Self { + let (a, b) = self.overflowing_rem_euclid(rhs); + if unlikely!(b) {overflow_panic::rem()} else {a} + } + /// Checked negation. Computes `-self`, returning `None` if `self == MIN`. /// /// # Examples @@ -765,6 +1095,37 @@ macro_rules! int_impl { unsafe { intrinsics::unchecked_sub(0, self) } } + /// Strict negation. Computes `-self`, panicking if `self == MIN`. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".strict_neg(), -5);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_neg();")] + /// + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn strict_neg(self) -> Self { + let (a, b) = self.overflowing_neg(); + if unlikely!(b) {overflow_panic::neg()} else {a} + } + /// Checked shift left. Computes `self << rhs`, returning `None` if `rhs` is larger /// than or equal to the number of bits in `self`. /// @@ -786,6 +1147,38 @@ macro_rules! int_impl { if unlikely!(b) {None} else {Some(a)} } + /// Strict shift left. Computes `self << rhs`, panicking if `rhs` is larger + /// than or equal to the number of bits in `self`. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".strict_shl(4), 0x10);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = 0x1", stringify!($SelfT), ".strict_shl(129);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn strict_shl(self, rhs: u32) -> Self { + let (a, b) = self.overflowing_shl(rhs); + if unlikely!(b) {overflow_panic::shl()} else {a} + } + /// Unchecked shift left. Computes `self << rhs`, assuming that /// `rhs` is less than the number of bits in `self`. /// @@ -834,6 +1227,38 @@ macro_rules! int_impl { if unlikely!(b) {None} else {Some(a)} } + /// Strict shift right. Computes `self >> rhs`, panicking `rhs` is + /// larger than or equal to the number of bits in `self`. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".strict_shr(4), 0x1);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = 0x10", stringify!($SelfT), ".strict_shr(128);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn strict_shr(self, rhs: u32) -> Self { + let (a, b) = self.overflowing_shr(rhs); + if unlikely!(b) {overflow_panic::shr()} else {a} + } + /// Unchecked shift right. Computes `self >> rhs`, assuming that /// `rhs` is less than the number of bits in `self`. /// @@ -885,6 +1310,41 @@ macro_rules! int_impl { } } + /// Strict absolute value. Computes `self.abs()`, panicking if + /// `self == MIN`. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!((-5", stringify!($SelfT), ").strict_abs(), 5);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_abs();")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn strict_abs(self) -> Self { + if self.is_negative() { + self.strict_neg() + } else { + self + } + } + /// Checked exponentiation. Computes `self.pow(exp)`, returning `None` if /// overflow occurred. /// @@ -923,6 +1383,54 @@ macro_rules! int_impl { acc.checked_mul(base) } + /// Strict exponentiation. Computes `self.pow(exp)`, panicking if + /// overflow occurred. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(8", stringify!($SelfT), ".strict_pow(2), 64);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_pow(2);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn strict_pow(self, mut exp: u32) -> Self { + if exp == 0 { + return 1; + } + let mut base = self; + let mut acc: Self = 1; + + while exp > 1 { + if (exp & 1) == 1 { + acc = acc.strict_mul(base); + } + exp /= 2; + base = base.strict_mul(base); + } + // since exp!=0, finally the exp must be 1. + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + acc.strict_mul(base) + } + /// Returns the square root of the number, rounded down. /// /// Returns `None` if `self` is negative. diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 2a0b31404f035..96de7673c6f2e 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -44,6 +44,7 @@ mod uint_macros; // import uint_impl! mod error; mod int_log10; mod nonzero; +mod overflow_panic; mod saturating; mod wrapping; diff --git a/library/core/src/num/overflow_panic.rs b/library/core/src/num/overflow_panic.rs new file mode 100644 index 0000000000000..b941fdb212a84 --- /dev/null +++ b/library/core/src/num/overflow_panic.rs @@ -0,0 +1,47 @@ +#[cold] +#[track_caller] +pub const fn add() -> ! { + panic!("attempt to add with overflow") +} + +#[cold] +#[track_caller] +pub const fn sub() -> ! { + panic!("attempt to subtract with overflow") +} + +#[cold] +#[track_caller] +pub const fn mul() -> ! { + panic!("attempt to multiply with overflow") +} + +#[cold] +#[track_caller] +pub const fn div() -> ! { + panic!("attempt to divide with overflow") +} + +#[cold] +#[track_caller] +pub const fn rem() -> ! { + panic!("attempt to calculate the remainder with overflow") +} + +#[cold] +#[track_caller] +pub const fn neg() -> ! { + panic!("attempt to negate with overflow") +} + +#[cold] +#[track_caller] +pub const fn shr() -> ! { + panic!("attempt to shift right with overflow") +} + +#[cold] +#[track_caller] +pub const fn shl() -> ! { + panic!("attempt to shift left with overflow") +} From fb349a2b7a753640e3eb577554641f8c75a6df49 Mon Sep 17 00:00:00 2001 From: Ryan Mehri Date: Fri, 22 Sep 2023 20:34:54 -0700 Subject: [PATCH 0027/1197] implement strict_* operations for unsigned integer types --- library/core/src/num/uint_macros.rs | 394 ++++++++++++++++++++++++++++ 1 file changed, 394 insertions(+) diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 11a53aaf122ec..2d8dbbe1f5089 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -462,6 +462,38 @@ macro_rules! uint_impl { if unlikely!(b) {None} else {Some(a)} } + /// Strict integer addition. Computes `self + rhs`, panicking + /// if overflow occurred. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).strict_add(1), ", stringify!($SelfT), "::MAX - 1);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add(3);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn strict_add(self, rhs: Self) -> Self { + let (a, b) = self.overflowing_add(rhs); + if unlikely!(b) {overflow_panic::add()} else {a} + } + /// Unchecked integer addition. Computes `self + rhs`, assuming overflow /// cannot occur. /// @@ -510,6 +542,43 @@ macro_rules! uint_impl { if unlikely!(b) {None} else {Some(a)} } + /// Strict addition with a signed integer. Computes `self + rhs`, + /// panicking if overflow occurred. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".strict_add_signed(2), 3);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = 1", stringify!($SelfT), ".strict_add_signed(-2);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add_signed(3);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn strict_add_signed(self, rhs: $SignedT) -> Self { + let (a, b) = self.overflowing_add_signed(rhs); + if unlikely!(b) {overflow_panic::add()} else {a} + } + /// Checked integer subtraction. Computes `self - rhs`, returning /// `None` if overflow occurred. /// @@ -531,6 +600,38 @@ macro_rules! uint_impl { if unlikely!(b) {None} else {Some(a)} } + /// Strict integer subtraction. Computes `self - rhs`, panicking if + /// overflow occurred. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".strict_sub(1), 0);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = 0", stringify!($SelfT), ".strict_sub(1);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn strict_sub(self, rhs: Self) -> Self { + let (a, b) = self.overflowing_sub(rhs); + if unlikely!(b) {overflow_panic::sub()} else {a} + } + /// Unchecked integer subtraction. Computes `self - rhs`, assuming overflow /// cannot occur. /// @@ -578,6 +679,38 @@ macro_rules! uint_impl { if unlikely!(b) {None} else {Some(a)} } + /// Strict integer multiplication. Computes `self * rhs`, panicking if + /// overflow occurred. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".strict_mul(1), 5);")] + /// ``` + /// + /// ``` should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_mul(2);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn strict_mul(self, rhs: Self) -> Self { + let (a, b) = self.overflowing_mul(rhs); + if unlikely!(b) {overflow_panic::mul()} else {a} + } + /// Unchecked integer multiplication. Computes `self * rhs`, assuming overflow /// cannot occur. /// @@ -630,6 +763,33 @@ macro_rules! uint_impl { } } + /// Strict integer division. Computes `self / rhs`. + /// Strict division on unsigned types is just normal division. + /// There's no way overflow could ever happen. + /// This function exists, so that all operations + /// are accounted for in the strict operations. + /// + /// # Panics + /// + /// This function will panic if `rhs` is zero. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".strict_div(10), 10);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn strict_div(self, rhs: Self) -> Self { + self / rhs + } + /// Checked Euclidean division. Computes `self.div_euclid(rhs)`, returning `None` /// if `rhs == 0`. /// @@ -654,6 +814,35 @@ macro_rules! uint_impl { } } + /// Strict Euclidean division. Computes `self.div_euclid(rhs)`. + /// Strict division on unsigned types is just normal division. + /// There's no way overflow could ever happen. + /// This function exists, so that all operations + /// are accounted for in the strict operations. + /// Since, for the positive integers, all common + /// definitions of division are equal, this + /// is exactly equal to `self.strict_div(rhs)`. + /// + /// # Panics + /// + /// This function will panic if `rhs` is zero. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".strict_div_euclid(10), 10);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn strict_div_euclid(self, rhs: Self) -> Self { + self / rhs + } /// Checked integer remainder. Computes `self % rhs`, returning `None` /// if `rhs == 0`. @@ -681,6 +870,34 @@ macro_rules! uint_impl { } } + /// Strict integer remainder. Computes `self % rhs`. + /// Strict remainder calculation on unsigned types is + /// just the regular remainder calculation. + /// There's no way overflow could ever happen. + /// This function exists, so that all operations + /// are accounted for in the strict operations. + /// + /// # Panics + /// + /// This function will panic if `rhs` is zero. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".strict_rem(10), 0);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn strict_rem(self, rhs: Self) -> Self { + self % rhs + } + /// Checked Euclidean modulo. Computes `self.rem_euclid(rhs)`, returning `None` /// if `rhs == 0`. /// @@ -705,6 +922,37 @@ macro_rules! uint_impl { } } + /// Strict Euclidean modulo. Computes `self.rem_euclid(rhs)`. + /// Strict modulo calculation on unsigned types is + /// just the regular remainder calculation. + /// There's no way overflow could ever happen. + /// This function exists, so that all operations + /// are accounted for in the strict operations. + /// Since, for the positive integers, all common + /// definitions of division are equal, this + /// is exactly equal to `self.strict_rem(rhs)`. + /// + /// # Panics + /// + /// This function will panic if `rhs` is zero. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".strict_rem_euclid(10), 0);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn strict_rem_euclid(self, rhs: Self) -> Self { + self % rhs + } + /// Returns the logarithm of the number with respect to an arbitrary base, /// rounded down. /// @@ -894,6 +1142,40 @@ macro_rules! uint_impl { if unlikely!(b) {None} else {Some(a)} } + /// Strict negation. Computes `-self`, panicking unless `self == + /// 0`. + /// + /// Note that negating any positive integer will overflow. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".strict_neg(), 0);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = 1", stringify!($SelfT), ".strict_neg();")] + /// + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn strict_neg(self) -> Self { + let (a, b) = self.overflowing_neg(); + if unlikely!(b) {overflow_panic::neg()} else {a} + } + /// Checked shift left. Computes `self << rhs`, returning `None` /// if `rhs` is larger than or equal to the number of bits in `self`. /// @@ -915,6 +1197,38 @@ macro_rules! uint_impl { if unlikely!(b) {None} else {Some(a)} } + /// Strict shift left. Computes `self << rhs`, panicking if `rhs` is larger + /// than or equal to the number of bits in `self`. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".strict_shl(4), 0x10);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = 0x10", stringify!($SelfT), ".strict_shl(129);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn strict_shl(self, rhs: u32) -> Self { + let (a, b) = self.overflowing_shl(rhs); + if unlikely!(b) {overflow_panic::shl()} else {a} + } + /// Unchecked shift left. Computes `self << rhs`, assuming that /// `rhs` is less than the number of bits in `self`. /// @@ -963,6 +1277,38 @@ macro_rules! uint_impl { if unlikely!(b) {None} else {Some(a)} } + /// Strict shift right. Computes `self >> rhs`, panicking `rhs` is + /// larger than or equal to the number of bits in `self`. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".strict_shr(4), 0x1);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = 0x10", stringify!($SelfT), ".strict_shr(129);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn strict_shr(self, rhs: u32) -> Self { + let (a, b) = self.overflowing_shr(rhs); + if unlikely!(b) {overflow_panic::shr()} else {a} + } + /// Unchecked shift right. Computes `self >> rhs`, assuming that /// `rhs` is less than the number of bits in `self`. /// @@ -1029,6 +1375,54 @@ macro_rules! uint_impl { acc.checked_mul(base) } + /// Strict exponentiation. Computes `self.pow(exp)`, panicking if + /// overflow occurred. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".strict_pow(5), 32);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_pow(2);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn strict_pow(self, mut exp: u32) -> Self { + if exp == 0 { + return 1; + } + let mut base = self; + let mut acc: Self = 1; + + while exp > 1 { + if (exp & 1) == 1 { + acc = acc.strict_mul(base); + } + exp /= 2; + base = base.strict_mul(base); + } + // since exp!=0, finally the exp must be 1. + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + acc.strict_mul(base) + } + /// Saturating integer addition. Computes `self + rhs`, saturating at /// the numeric bounds instead of overflowing. /// From 8c7a5b0338f3f168c8b5c8447f132e8983c26105 Mon Sep 17 00:00:00 2001 From: Ryan Mehri Date: Sat, 23 Sep 2023 11:50:02 -0700 Subject: [PATCH 0028/1197] add `#[track_caller]` to improve panic locations --- library/core/src/num/int_macros.rs | 14 ++++++++++++++ library/core/src/num/uint_macros.rs | 12 ++++++++++++ 2 files changed, 26 insertions(+) diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 8b3f742bf9197..b9f794431fb18 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -481,6 +481,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] + #[track_caller] pub const fn strict_add(self, rhs: Self) -> Self { let (a, b) = self.overflowing_add(rhs); if unlikely!(b) {overflow_panic::add()} else {a} @@ -560,6 +561,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] + #[track_caller] pub const fn strict_add_unsigned(self, rhs: $UnsignedT) -> Self { let (a, b) = self.overflowing_add_unsigned(rhs); if unlikely!(b) {overflow_panic::add()} else {a} @@ -613,6 +615,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] + #[track_caller] pub const fn strict_sub(self, rhs: Self) -> Self { let (a, b) = self.overflowing_sub(rhs); if unlikely!(b) {overflow_panic::sub()} else {a} @@ -692,6 +695,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] + #[track_caller] pub const fn strict_sub_unsigned(self, rhs: $UnsignedT) -> Self { let (a, b) = self.overflowing_sub_unsigned(rhs); if unlikely!(b) {overflow_panic::sub()} else {a} @@ -745,6 +749,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] + #[track_caller] pub const fn strict_mul(self, rhs: Self) -> Self { let (a, b) = self.overflowing_mul(rhs); if unlikely!(b) {overflow_panic::mul()} else {a} @@ -840,6 +845,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] + #[track_caller] pub const fn strict_div(self, rhs: Self) -> Self { let (a, b) = self.overflowing_div(rhs); if unlikely!(b) {overflow_panic::div()} else {a} @@ -909,6 +915,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] + #[track_caller] pub const fn strict_div_euclid(self, rhs: Self) -> Self { let (a, b) = self.overflowing_div_euclid(rhs); if unlikely!(b) {overflow_panic::div()} else {a} @@ -977,6 +984,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] + #[track_caller] pub const fn strict_rem(self, rhs: Self) -> Self { let (a, b) = self.overflowing_rem(rhs); if unlikely!(b) {overflow_panic::rem()} else {a} @@ -1045,6 +1053,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] + #[track_caller] pub const fn strict_rem_euclid(self, rhs: Self) -> Self { let (a, b) = self.overflowing_rem_euclid(rhs); if unlikely!(b) {overflow_panic::rem()} else {a} @@ -1121,6 +1130,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] + #[track_caller] pub const fn strict_neg(self) -> Self { let (a, b) = self.overflowing_neg(); if unlikely!(b) {overflow_panic::neg()} else {a} @@ -1174,6 +1184,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] + #[track_caller] pub const fn strict_shl(self, rhs: u32) -> Self { let (a, b) = self.overflowing_shl(rhs); if unlikely!(b) {overflow_panic::shl()} else {a} @@ -1254,6 +1265,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] + #[track_caller] pub const fn strict_shr(self, rhs: u32) -> Self { let (a, b) = self.overflowing_shr(rhs); if unlikely!(b) {overflow_panic::shr()} else {a} @@ -1337,6 +1349,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] + #[track_caller] pub const fn strict_abs(self) -> Self { if self.is_negative() { self.strict_neg() @@ -1410,6 +1423,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] + #[track_caller] pub const fn strict_pow(self, mut exp: u32) -> Self { if exp == 0 { return 1; diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 2d8dbbe1f5089..8d9713856057e 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -489,6 +489,7 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] + #[track_caller] pub const fn strict_add(self, rhs: Self) -> Self { let (a, b) = self.overflowing_add(rhs); if unlikely!(b) {overflow_panic::add()} else {a} @@ -574,6 +575,7 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] + #[track_caller] pub const fn strict_add_signed(self, rhs: $SignedT) -> Self { let (a, b) = self.overflowing_add_signed(rhs); if unlikely!(b) {overflow_panic::add()} else {a} @@ -627,6 +629,7 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] + #[track_caller] pub const fn strict_sub(self, rhs: Self) -> Self { let (a, b) = self.overflowing_sub(rhs); if unlikely!(b) {overflow_panic::sub()} else {a} @@ -706,6 +709,7 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] + #[track_caller] pub const fn strict_mul(self, rhs: Self) -> Self { let (a, b) = self.overflowing_mul(rhs); if unlikely!(b) {overflow_panic::mul()} else {a} @@ -786,6 +790,7 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] + #[track_caller] pub const fn strict_div(self, rhs: Self) -> Self { self / rhs } @@ -840,6 +845,7 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] + #[track_caller] pub const fn strict_div_euclid(self, rhs: Self) -> Self { self / rhs } @@ -894,6 +900,7 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] + #[track_caller] pub const fn strict_rem(self, rhs: Self) -> Self { self % rhs } @@ -949,6 +956,7 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] + #[track_caller] pub const fn strict_rem_euclid(self, rhs: Self) -> Self { self % rhs } @@ -1171,6 +1179,7 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] + #[track_caller] pub const fn strict_neg(self) -> Self { let (a, b) = self.overflowing_neg(); if unlikely!(b) {overflow_panic::neg()} else {a} @@ -1224,6 +1233,7 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] + #[track_caller] pub const fn strict_shl(self, rhs: u32) -> Self { let (a, b) = self.overflowing_shl(rhs); if unlikely!(b) {overflow_panic::shl()} else {a} @@ -1304,6 +1314,7 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] + #[track_caller] pub const fn strict_shr(self, rhs: u32) -> Self { let (a, b) = self.overflowing_shr(rhs); if unlikely!(b) {overflow_panic::shr()} else {a} @@ -1402,6 +1413,7 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] + #[track_caller] pub const fn strict_pow(self, mut exp: u32) -> Self { if exp == 0 { return 1; From 9911d8d9bf4552f0ce05914e2ad239cd3fdc3634 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Mon, 20 Nov 2023 20:01:10 +0000 Subject: [PATCH 0029/1197] freebsd add *stat calls interception support --- src/tools/miri/src/helpers.rs | 15 ++++ .../miri/src/shims/unix/foreign_items.rs | 11 +++ .../src/shims/unix/freebsd/foreign_items.rs | 28 ++++++ src/tools/miri/src/shims/unix/fs.rs | 89 +++++++++++++------ .../src/shims/unix/macos/foreign_items.rs | 15 +--- .../pass-dep/shims/libc-fs-with-isolation.rs | 1 - 6 files changed, 118 insertions(+), 41 deletions(-) diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 21f1d684924a0..3651db982b3a1 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -225,6 +225,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { bug!("No field named {} in type {}", name, base.layout().ty); } + /// Search if Project (which must be a struct or union type) contains the `name` field. + fn projectable_has_field>( + &self, + base: &P, + name: &str, + ) -> bool { + let adt = base.layout().ty.ty_adt_def().unwrap(); + for field in adt.non_enum_variant().fields.iter() { + if field.name.as_str() == name { + return true; + } + } + false + } + /// Write an int of the appropriate size to `dest`. The target type may be signed or unsigned, /// we try to do the right thing anyway. `i128` can fit all integer types except for `u128` so /// this method is fine for almost all integer types. diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 23342c8045e80..35036ce078d37 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -155,6 +155,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } "lseek64" => { let [fd, offset, whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let fd = this.read_scalar(fd)?.to_i32()?; + let offset = this.read_scalar(offset)?.to_i64()?; + let whence = this.read_scalar(whence)?.to_i32()?; + let result = this.lseek64(fd, offset.into(), whence)?; + this.write_scalar(result, dest)?; + } + "lseek" => { + let [fd, offset, whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let fd = this.read_scalar(fd)?.to_i32()?; + let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?; + let whence = this.read_scalar(whence)?.to_i32()?; let result = this.lseek64(fd, offset, whence)?; this.write_scalar(result, dest)?; } diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs index 7c843e106eacf..64094ac307d2a 100644 --- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs @@ -3,6 +3,7 @@ use rustc_target::spec::abi::Abi; use crate::*; use shims::foreign_items::EmulateForeignItemResult; +use shims::unix::fs::EvalContextExt as _; use shims::unix::thread::EvalContextExt as _; pub fn is_dyn_sym(_name: &str) -> bool { @@ -63,6 +64,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.write_scalar(Scalar::from_target_usize(len, this), dest)?; } + // File related shims + // For those, we both intercept `func` and `call@FBSD_1.0` symbols cases + // since freebsd 12 the former form can be expected. + "stat" | "stat@FBSD_1.0" => { + let [path, buf] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let result = this.macos_fbsd_stat(path, buf)?; + this.write_scalar(result, dest)?; + } + "lstat" | "lstat@FBSD_1.0" => { + let [path, buf] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let result = this.macos_fbsd_lstat(path, buf)?; + this.write_scalar(result, dest)?; + } + "fstat" | "fstat@FBSD_1.0" => { + let [fd, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let result = this.macos_fbsd_fstat(fd, buf)?; + this.write_scalar(result, dest)?; + } + "readdir_r" | "readdir_r@FBSD_1.0" => { + let [dirp, entry, result] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let result = this.macos_fbsd_readdir_r(dirp, entry, result)?; + this.write_scalar(result, dest)?; + } + // errno "__error" => { let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index ba40a1b3c321c..b2170c8c87fd3 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -827,24 +827,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { fn lseek64( &mut self, - fd_op: &OpTy<'tcx, Provenance>, - offset_op: &OpTy<'tcx, Provenance>, - whence_op: &OpTy<'tcx, Provenance>, + fd: i32, + offset: i128, + whence: i32, ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); // Isolation check is done via `FileDescriptor` trait. - let fd = this.read_scalar(fd_op)?.to_i32()?; - let offset = this.read_scalar(offset_op)?.to_i64()?; - let whence = this.read_scalar(whence_op)?.to_i32()?; - let seek_from = if whence == this.eval_libc_i32("SEEK_SET") { SeekFrom::Start(u64::try_from(offset).unwrap()) } else if whence == this.eval_libc_i32("SEEK_CUR") { - SeekFrom::Current(offset) + SeekFrom::Current(i64::try_from(offset).unwrap()) } else if whence == this.eval_libc_i32("SEEK_END") { - SeekFrom::End(offset) + SeekFrom::End(i64::try_from(offset).unwrap()) } else { let einval = this.eval_libc("EINVAL"); this.set_last_error(einval)?; @@ -911,13 +907,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.try_unwrap_io_result(result) } - fn macos_stat( + fn macos_fbsd_stat( &mut self, path_op: &OpTy<'tcx, Provenance>, buf_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - this.assert_target_os("macos", "stat"); + + if !matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") { + panic!("`macos_fbsd_stat` should not be called on {}", this.tcx.sess.target.os); + } let path_scalar = this.read_pointer(path_op)?; let path = this.read_path_from_c_str(path_scalar)?.into_owned(); @@ -940,13 +939,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } // `lstat` is used to get symlink metadata. - fn macos_lstat( + fn macos_fbsd_lstat( &mut self, path_op: &OpTy<'tcx, Provenance>, buf_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - this.assert_target_os("macos", "lstat"); + + if !matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") { + panic!("`macos_fbsd_lstat` should not be called on {}", this.tcx.sess.target.os); + } let path_scalar = this.read_pointer(path_op)?; let path = this.read_path_from_c_str(path_scalar)?.into_owned(); @@ -967,14 +969,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?)) } - fn macos_fstat( + fn macos_fbsd_fstat( &mut self, fd_op: &OpTy<'tcx, Provenance>, buf_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - this.assert_target_os("macos", "fstat"); + if !matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") { + panic!("`macos_fbsd_fstat` should not be called on {}", this.tcx.sess.target.os); + } let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -1213,7 +1217,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let this = self.eval_context_mut(); #[cfg_attr(not(unix), allow(unused_variables))] - let mode = if this.tcx.sess.target.os == "macos" { + let mode = if matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") { u32::from(this.read_scalar(mode_op)?.to_u16()?) } else { this.read_scalar(mode_op)?.to_u32()? @@ -1385,7 +1389,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Ok(Scalar::from_maybe_pointer(entry, this)) } - fn macos_readdir_r( + fn macos_fbsd_readdir_r( &mut self, dirp_op: &OpTy<'tcx, Provenance>, entry_op: &OpTy<'tcx, Provenance>, @@ -1393,7 +1397,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - this.assert_target_os("macos", "readdir_r"); + if !matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") { + panic!("`macos_fbsd_readdir_r` should not be called on {}", this.tcx.sess.target.os); + } let dirp = this.read_target_usize(dirp_op)?; @@ -1424,7 +1430,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // } let entry_place = this.deref_pointer_as(entry_op, this.libc_ty_layout("dirent"))?; - let name_place = this.project_field(&entry_place, 5)?; + let name_place = this.project_field_named(&entry_place, "d_name")?; let file_name = dir_entry.file_name(); // not a Path as there are no separators! let (name_fits, file_name_buf_len) = this.write_os_str_to_c_str( @@ -1448,16 +1454,41 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let file_type = this.file_type_to_d_type(dir_entry.file_type())?; - this.write_int_fields_named( - &[ - ("d_ino", ino.into()), - ("d_seekoff", 0), - ("d_reclen", 0), - ("d_namlen", file_name_len.into()), - ("d_type", file_type.into()), - ], - &entry_place, - )?; + // macOS offset field is d_seekoff + if this.projectable_has_field(&entry_place, "d_seekoff") { + this.write_int_fields_named( + &[ + ("d_ino", ino.into()), + ("d_seekoff", 0), + ("d_reclen", 0), + ("d_namlen", file_name_len.into()), + ("d_type", file_type.into()), + ], + &entry_place, + )?; + // freebsd 12 and onwards had added the d_off field + } else if this.projectable_has_field(&entry_place, "d_off") { + this.write_int_fields_named( + &[ + ("d_fileno", ino.into()), + ("d_off", 0), + ("d_reclen", 0), + ("d_type", file_type.into()), + ("d_namlen", file_name_len.into()), + ], + &entry_place, + )?; + } else { + this.write_int_fields_named( + &[ + ("d_fileno", ino.into()), + ("d_reclen", 0), + ("d_type", file_type.into()), + ("d_namlen", file_name_len.into()), + ], + &entry_place, + )?; + } let result_place = this.deref_pointer(result_op)?; this.write_scalar(this.read_scalar(entry_op)?, &result_place)?; diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs index 07e19cadd6e32..ecc07e28a2988 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -40,18 +40,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { "stat" | "stat64" | "stat$INODE64" => { let [path, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let result = this.macos_stat(path, buf)?; + let result = this.macos_fbsd_stat(path, buf)?; this.write_scalar(result, dest)?; } "lstat" | "lstat64" | "lstat$INODE64" => { let [path, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let result = this.macos_lstat(path, buf)?; + let result = this.macos_fbsd_lstat(path, buf)?; this.write_scalar(result, dest)?; } "fstat" | "fstat64" | "fstat$INODE64" => { let [fd, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let result = this.macos_fstat(fd, buf)?; + let result = this.macos_fbsd_fstat(fd, buf)?; this.write_scalar(result, dest)?; } "opendir$INODE64" => { @@ -62,14 +62,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { "readdir_r" | "readdir_r$INODE64" => { let [dirp, entry, result] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let result = this.macos_readdir_r(dirp, entry, result)?; - this.write_scalar(result, dest)?; - } - "lseek" => { - let [fd, offset, whence] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - // macOS is 64bit-only, so this is lseek64 - let result = this.lseek64(fd, offset, whence)?; + let result = this.macos_fbsd_readdir_r(dirp, entry, result)?; this.write_scalar(result, dest)?; } "realpath$DARWIN_EXTSN" => { diff --git a/src/tools/miri/tests/pass-dep/shims/libc-fs-with-isolation.rs b/src/tools/miri/tests/pass-dep/shims/libc-fs-with-isolation.rs index adfece586611d..5185db0b0e29f 100644 --- a/src/tools/miri/tests/pass-dep/shims/libc-fs-with-isolation.rs +++ b/src/tools/miri/tests/pass-dep/shims/libc-fs-with-isolation.rs @@ -1,5 +1,4 @@ //@ignore-target-windows: no libc on Windows -//@ignore-target-freebsd: FIXME needs foreign function `stat@FBSD_1.0` //@compile-flags: -Zmiri-isolation-error=warn-nobacktrace //@normalize-stderr-test: "(stat(x)?)" -> "$$STAT" From a43dc2b67cee8e56cbe73d36ec0a99c6b0f2dd59 Mon Sep 17 00:00:00 2001 From: Dylan DPC Date: Mon, 27 Nov 2023 12:49:09 +0530 Subject: [PATCH 0030/1197] stabilise bound_map --- library/core/src/ops/range.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index b419a738fbe3a..e809273c9ed93 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -710,7 +710,6 @@ impl Bound { /// # Examples /// /// ``` - /// #![feature(bound_map)] /// use std::ops::Bound::*; /// /// let bound_string = Included("Hello, World!"); @@ -719,7 +718,6 @@ impl Bound { /// ``` /// /// ``` - /// #![feature(bound_map)] /// use std::ops::Bound; /// use Bound::*; /// @@ -728,7 +726,7 @@ impl Bound { /// assert_eq!(unbounded_string.map(|s| s.len()), Unbounded); /// ``` #[inline] - #[unstable(feature = "bound_map", issue = "86026")] + #[stable(feature = "bound_map", since = "CURRENT_RUSTC_VERSION")] pub fn map U>(self, f: F) -> Bound { match self { Unbounded => Unbounded, From 6d17169104575315c7801ec7bc55dd3cb932fde8 Mon Sep 17 00:00:00 2001 From: Ryan Mehri Date: Tue, 28 Nov 2023 08:34:55 -0800 Subject: [PATCH 0031/1197] reword panic comments and add spaces to unlikely branches --- library/core/src/num/int_macros.rs | 68 +++++++++++++------------- library/core/src/num/overflow_panic.rs | 4 ++ library/core/src/num/uint_macros.rs | 52 ++++++++++---------- 3 files changed, 64 insertions(+), 60 deletions(-) diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index b9f794431fb18..451a2e14fe950 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -451,7 +451,7 @@ macro_rules! int_impl { #[inline] pub const fn checked_add(self, rhs: Self) -> Option { let (a, b) = self.overflowing_add(rhs); - if unlikely!(b) {None} else {Some(a)} + if unlikely!(b) { None } else { Some(a) } } /// Strict integer addition. Computes `self + rhs`, panicking @@ -461,7 +461,7 @@ macro_rules! int_impl { /// /// ## Overflow behavior /// - /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. /// /// # Examples /// @@ -484,7 +484,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_add(self, rhs: Self) -> Self { let (a, b) = self.overflowing_add(rhs); - if unlikely!(b) {overflow_panic::add()} else {a} + if unlikely!(b) { overflow_panic::add() } else { a } } /// Unchecked integer addition. Computes `self + rhs`, assuming overflow @@ -531,7 +531,7 @@ macro_rules! int_impl { #[inline] pub const fn checked_add_unsigned(self, rhs: $UnsignedT) -> Option { let (a, b) = self.overflowing_add_unsigned(rhs); - if unlikely!(b) {None} else {Some(a)} + if unlikely!(b) { None } else { Some(a) } } /// Strict addition with an unsigned integer. Computes `self + rhs`, @@ -541,7 +541,7 @@ macro_rules! int_impl { /// /// ## Overflow behavior /// - /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. /// /// # Examples /// @@ -564,7 +564,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_add_unsigned(self, rhs: $UnsignedT) -> Self { let (a, b) = self.overflowing_add_unsigned(rhs); - if unlikely!(b) {overflow_panic::add()} else {a} + if unlikely!(b) { overflow_panic::add() } else { a } } /// Checked integer subtraction. Computes `self - rhs`, returning `None` if @@ -585,7 +585,7 @@ macro_rules! int_impl { #[inline] pub const fn checked_sub(self, rhs: Self) -> Option { let (a, b) = self.overflowing_sub(rhs); - if unlikely!(b) {None} else {Some(a)} + if unlikely!(b) { None } else { Some(a) } } /// Strict integer subtraction. Computes `self - rhs`, panicking if @@ -595,7 +595,7 @@ macro_rules! int_impl { /// /// ## Overflow behavior /// - /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. /// /// # Examples /// @@ -618,7 +618,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_sub(self, rhs: Self) -> Self { let (a, b) = self.overflowing_sub(rhs); - if unlikely!(b) {overflow_panic::sub()} else {a} + if unlikely!(b) { overflow_panic::sub() } else { a } } /// Unchecked integer subtraction. Computes `self - rhs`, assuming overflow @@ -665,7 +665,7 @@ macro_rules! int_impl { #[inline] pub const fn checked_sub_unsigned(self, rhs: $UnsignedT) -> Option { let (a, b) = self.overflowing_sub_unsigned(rhs); - if unlikely!(b) {None} else {Some(a)} + if unlikely!(b) { None } else { Some(a) } } /// Strict subtraction with an unsigned integer. Computes `self - rhs`, @@ -675,7 +675,7 @@ macro_rules! int_impl { /// /// ## Overflow behavior /// - /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. /// /// # Examples /// @@ -698,7 +698,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_sub_unsigned(self, rhs: $UnsignedT) -> Self { let (a, b) = self.overflowing_sub_unsigned(rhs); - if unlikely!(b) {overflow_panic::sub()} else {a} + if unlikely!(b) { overflow_panic::sub() } else { a } } /// Checked integer multiplication. Computes `self * rhs`, returning `None` if @@ -719,7 +719,7 @@ macro_rules! int_impl { #[inline] pub const fn checked_mul(self, rhs: Self) -> Option { let (a, b) = self.overflowing_mul(rhs); - if unlikely!(b) {None} else {Some(a)} + if unlikely!(b) { None } else { Some(a) } } /// Strict integer multiplication. Computes `self * rhs`, panicking if @@ -729,7 +729,7 @@ macro_rules! int_impl { /// /// ## Overflow behavior /// - /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. /// /// # Examples /// @@ -752,7 +752,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_mul(self, rhs: Self) -> Self { let (a, b) = self.overflowing_mul(rhs); - if unlikely!(b) {overflow_panic::mul()} else {a} + if unlikely!(b) { overflow_panic::mul() } else { a } } /// Unchecked integer multiplication. Computes `self * rhs`, assuming overflow @@ -816,7 +816,7 @@ macro_rules! int_impl { /// /// ## Overflow behavior /// - /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. /// /// The only case where such an overflow can occur is when one divides `MIN / -1` on a signed type (where /// `MIN` is the negative minimal value for the type); this is equivalent to `-MIN`, a positive value @@ -848,7 +848,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_div(self, rhs: Self) -> Self { let (a, b) = self.overflowing_div(rhs); - if unlikely!(b) {overflow_panic::div()} else {a} + if unlikely!(b) { overflow_panic::div() } else { a } } /// Checked Euclidean division. Computes `self.div_euclid(rhs)`, @@ -886,7 +886,7 @@ macro_rules! int_impl { /// /// ## Overflow behavior /// - /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. /// /// The only case where such an overflow can occur is when one divides `MIN / -1` on a signed type (where /// `MIN` is the negative minimal value for the type); this is equivalent to `-MIN`, a positive value @@ -918,7 +918,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_div_euclid(self, rhs: Self) -> Self { let (a, b) = self.overflowing_div_euclid(rhs); - if unlikely!(b) {overflow_panic::div()} else {a} + if unlikely!(b) { overflow_panic::div() } else { a } } /// Checked integer remainder. Computes `self % rhs`, returning `None` if @@ -956,7 +956,7 @@ macro_rules! int_impl { /// /// ## Overflow behavior /// - /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. /// /// The only case where such an overflow can occur is `x % y` for `MIN / -1` on a /// signed type (where `MIN` is the negative minimal value), which is invalid due to implementation artifacts. @@ -987,7 +987,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_rem(self, rhs: Self) -> Self { let (a, b) = self.overflowing_rem(rhs); - if unlikely!(b) {overflow_panic::rem()} else {a} + if unlikely!(b) { overflow_panic::rem() } else { a } } /// Checked Euclidean remainder. Computes `self.rem_euclid(rhs)`, returning `None` @@ -1025,7 +1025,7 @@ macro_rules! int_impl { /// /// ## Overflow behavior /// - /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. /// /// The only case where such an overflow can occur is `x % y` for `MIN / -1` on a /// signed type (where `MIN` is the negative minimal value), which is invalid due to implementation artifacts. @@ -1056,7 +1056,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_rem_euclid(self, rhs: Self) -> Self { let (a, b) = self.overflowing_rem_euclid(rhs); - if unlikely!(b) {overflow_panic::rem()} else {a} + if unlikely!(b) { overflow_panic::rem() } else { a } } /// Checked negation. Computes `-self`, returning `None` if `self == MIN`. @@ -1076,7 +1076,7 @@ macro_rules! int_impl { #[inline] pub const fn checked_neg(self) -> Option { let (a, b) = self.overflowing_neg(); - if unlikely!(b) {None} else {Some(a)} + if unlikely!(b) { None } else { Some(a) } } /// Unchecked negation. Computes `-self`, assuming overflow cannot occur. @@ -1110,7 +1110,7 @@ macro_rules! int_impl { /// /// ## Overflow behavior /// - /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. /// /// # Examples /// @@ -1133,7 +1133,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_neg(self) -> Self { let (a, b) = self.overflowing_neg(); - if unlikely!(b) {overflow_panic::neg()} else {a} + if unlikely!(b) { overflow_panic::neg() } else { a } } /// Checked shift left. Computes `self << rhs`, returning `None` if `rhs` is larger @@ -1154,7 +1154,7 @@ macro_rules! int_impl { #[inline] pub const fn checked_shl(self, rhs: u32) -> Option { let (a, b) = self.overflowing_shl(rhs); - if unlikely!(b) {None} else {Some(a)} + if unlikely!(b) { None } else { Some(a) } } /// Strict shift left. Computes `self << rhs`, panicking if `rhs` is larger @@ -1164,7 +1164,7 @@ macro_rules! int_impl { /// /// ## Overflow behavior /// - /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. /// /// # Examples /// @@ -1187,7 +1187,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_shl(self, rhs: u32) -> Self { let (a, b) = self.overflowing_shl(rhs); - if unlikely!(b) {overflow_panic::shl()} else {a} + if unlikely!(b) { overflow_panic::shl() } else { a } } /// Unchecked shift left. Computes `self << rhs`, assuming that @@ -1235,7 +1235,7 @@ macro_rules! int_impl { #[inline] pub const fn checked_shr(self, rhs: u32) -> Option { let (a, b) = self.overflowing_shr(rhs); - if unlikely!(b) {None} else {Some(a)} + if unlikely!(b) { None } else { Some(a) } } /// Strict shift right. Computes `self >> rhs`, panicking `rhs` is @@ -1245,7 +1245,7 @@ macro_rules! int_impl { /// /// ## Overflow behavior /// - /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. /// /// # Examples /// @@ -1268,7 +1268,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_shr(self, rhs: u32) -> Self { let (a, b) = self.overflowing_shr(rhs); - if unlikely!(b) {overflow_panic::shr()} else {a} + if unlikely!(b) { overflow_panic::shr() } else { a } } /// Unchecked shift right. Computes `self >> rhs`, assuming that @@ -1329,7 +1329,7 @@ macro_rules! int_impl { /// /// ## Overflow behavior /// - /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. /// /// # Examples /// @@ -1403,7 +1403,7 @@ macro_rules! int_impl { /// /// ## Overflow behavior /// - /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. /// /// # Examples /// diff --git a/library/core/src/num/overflow_panic.rs b/library/core/src/num/overflow_panic.rs index b941fdb212a84..203037ffb43ea 100644 --- a/library/core/src/num/overflow_panic.rs +++ b/library/core/src/num/overflow_panic.rs @@ -1,3 +1,7 @@ +//! Functions for panicking on overflow. +//! +//! In particular, these are used by the `strict_` methods on integers. + #[cold] #[track_caller] pub const fn add() -> ! { diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 8d9713856057e..9915ce385d943 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -459,7 +459,7 @@ macro_rules! uint_impl { #[inline] pub const fn checked_add(self, rhs: Self) -> Option { let (a, b) = self.overflowing_add(rhs); - if unlikely!(b) {None} else {Some(a)} + if unlikely!(b) { None } else { Some(a) } } /// Strict integer addition. Computes `self + rhs`, panicking @@ -469,7 +469,7 @@ macro_rules! uint_impl { /// /// ## Overflow behavior /// - /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. /// /// # Examples /// @@ -492,8 +492,8 @@ macro_rules! uint_impl { #[track_caller] pub const fn strict_add(self, rhs: Self) -> Self { let (a, b) = self.overflowing_add(rhs); - if unlikely!(b) {overflow_panic::add()} else {a} - } + if unlikely!(b) { overflow_panic ::add()} else {a} + } /// Unchecked integer addition. Computes `self + rhs`, assuming overflow /// cannot occur. @@ -540,7 +540,7 @@ macro_rules! uint_impl { #[inline] pub const fn checked_add_signed(self, rhs: $SignedT) -> Option { let (a, b) = self.overflowing_add_signed(rhs); - if unlikely!(b) {None} else {Some(a)} + if unlikely!(b) { None } else { Some(a) } } /// Strict addition with a signed integer. Computes `self + rhs`, @@ -550,7 +550,7 @@ macro_rules! uint_impl { /// /// ## Overflow behavior /// - /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. /// /// # Examples /// @@ -578,8 +578,8 @@ macro_rules! uint_impl { #[track_caller] pub const fn strict_add_signed(self, rhs: $SignedT) -> Self { let (a, b) = self.overflowing_add_signed(rhs); - if unlikely!(b) {overflow_panic::add()} else {a} - } + if unlikely!(b) { overflow_panic ::add()} else {a} + } /// Checked integer subtraction. Computes `self - rhs`, returning /// `None` if overflow occurred. @@ -599,7 +599,7 @@ macro_rules! uint_impl { #[inline] pub const fn checked_sub(self, rhs: Self) -> Option { let (a, b) = self.overflowing_sub(rhs); - if unlikely!(b) {None} else {Some(a)} + if unlikely!(b) { None } else { Some(a) } } /// Strict integer subtraction. Computes `self - rhs`, panicking if @@ -609,7 +609,7 @@ macro_rules! uint_impl { /// /// ## Overflow behavior /// - /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. /// /// # Examples /// @@ -632,8 +632,8 @@ macro_rules! uint_impl { #[track_caller] pub const fn strict_sub(self, rhs: Self) -> Self { let (a, b) = self.overflowing_sub(rhs); - if unlikely!(b) {overflow_panic::sub()} else {a} - } + if unlikely!(b) { overflow_panic ::sub()} else {a} + } /// Unchecked integer subtraction. Computes `self - rhs`, assuming overflow /// cannot occur. @@ -679,7 +679,7 @@ macro_rules! uint_impl { #[inline] pub const fn checked_mul(self, rhs: Self) -> Option { let (a, b) = self.overflowing_mul(rhs); - if unlikely!(b) {None} else {Some(a)} + if unlikely!(b) { None } else { Some(a) } } /// Strict integer multiplication. Computes `self * rhs`, panicking if @@ -689,7 +689,7 @@ macro_rules! uint_impl { /// /// ## Overflow behavior /// - /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. /// /// # Examples /// @@ -712,8 +712,8 @@ macro_rules! uint_impl { #[track_caller] pub const fn strict_mul(self, rhs: Self) -> Self { let (a, b) = self.overflowing_mul(rhs); - if unlikely!(b) {overflow_panic::mul()} else {a} - } + if unlikely!(b) { overflow_panic ::mul()} else {a} + } /// Unchecked integer multiplication. Computes `self * rhs`, assuming overflow /// cannot occur. @@ -1147,7 +1147,7 @@ macro_rules! uint_impl { #[inline] pub const fn checked_neg(self) -> Option { let (a, b) = self.overflowing_neg(); - if unlikely!(b) {None} else {Some(a)} + if unlikely!(b) { None } else { Some(a) } } /// Strict negation. Computes `-self`, panicking unless `self == @@ -1159,7 +1159,7 @@ macro_rules! uint_impl { /// /// ## Overflow behavior /// - /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. /// /// # Examples /// @@ -1182,7 +1182,7 @@ macro_rules! uint_impl { #[track_caller] pub const fn strict_neg(self) -> Self { let (a, b) = self.overflowing_neg(); - if unlikely!(b) {overflow_panic::neg()} else {a} + if unlikely!(b) { overflow_panic::neg() } else { a } } /// Checked shift left. Computes `self << rhs`, returning `None` @@ -1203,7 +1203,7 @@ macro_rules! uint_impl { #[inline] pub const fn checked_shl(self, rhs: u32) -> Option { let (a, b) = self.overflowing_shl(rhs); - if unlikely!(b) {None} else {Some(a)} + if unlikely!(b) { None } else { Some(a) } } /// Strict shift left. Computes `self << rhs`, panicking if `rhs` is larger @@ -1213,7 +1213,7 @@ macro_rules! uint_impl { /// /// ## Overflow behavior /// - /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. /// /// # Examples /// @@ -1236,7 +1236,7 @@ macro_rules! uint_impl { #[track_caller] pub const fn strict_shl(self, rhs: u32) -> Self { let (a, b) = self.overflowing_shl(rhs); - if unlikely!(b) {overflow_panic::shl()} else {a} + if unlikely!(b) { overflow_panic::shl() } else { a } } /// Unchecked shift left. Computes `self << rhs`, assuming that @@ -1284,7 +1284,7 @@ macro_rules! uint_impl { #[inline] pub const fn checked_shr(self, rhs: u32) -> Option { let (a, b) = self.overflowing_shr(rhs); - if unlikely!(b) {None} else {Some(a)} + if unlikely!(b) { None } else { Some(a) } } /// Strict shift right. Computes `self >> rhs`, panicking `rhs` is @@ -1294,7 +1294,7 @@ macro_rules! uint_impl { /// /// ## Overflow behavior /// - /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. /// /// # Examples /// @@ -1317,7 +1317,7 @@ macro_rules! uint_impl { #[track_caller] pub const fn strict_shr(self, rhs: u32) -> Self { let (a, b) = self.overflowing_shr(rhs); - if unlikely!(b) {overflow_panic::shr()} else {a} + if unlikely!(b) { overflow_panic::shr() } else { a } } /// Unchecked shift right. Computes `self >> rhs`, assuming that @@ -1393,7 +1393,7 @@ macro_rules! uint_impl { /// /// ## Overflow behavior /// - /// This function will always panic on overflow, regardless of if overflow checks are enabled. + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. /// /// # Examples /// From bed0c9d97f098b71f4968808ab16d9ba40bce49c Mon Sep 17 00:00:00 2001 From: Peter Jaszkowiak Date: Sat, 12 Aug 2023 14:13:41 -0600 Subject: [PATCH 0032/1197] [style 2024] Combine all last arg delimited exprs --- src/doc/style-guide/src/editions.md | 4 ++ src/doc/style-guide/src/expressions.md | 55 ++++++++++++++++++++++---- 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/src/doc/style-guide/src/editions.md b/src/doc/style-guide/src/editions.md index 5c67a185b8ffa..0d60b01fac3a1 100644 --- a/src/doc/style-guide/src/editions.md +++ b/src/doc/style-guide/src/editions.md @@ -36,6 +36,10 @@ For a full history of changes in the Rust 2024 style edition, see the git history of the style guide. Notable changes in the Rust 2024 style edition include: +- [#114764](https://github.com/rust-lang/rust/pull/114764) As the last member + of a delimited expression, delimited expressions are generally combinable, + regardless of the number of members. Previously only applied with exactly + one member (except for closures with explicit blocks). - Miscellaneous `rustfmt` bugfixes. ## Rust 2015/2018/2021 style edition diff --git a/src/doc/style-guide/src/expressions.md b/src/doc/style-guide/src/expressions.md index 32c604f9f3e10..a88404e87fb17 100644 --- a/src/doc/style-guide/src/expressions.md +++ b/src/doc/style-guide/src/expressions.md @@ -801,11 +801,11 @@ E.g., `&&Some(foo)` matches, `Foo(4, Bar)` does not. ## Combinable expressions -Where a function call has a single argument, and that argument is formatted -across multiple-lines, format the outer call as if it were a single-line call, +When the last argument in a function call is formatted across +multiple-lines, format the outer call as if it were a single-line call, if the result fits. Apply the same combining behaviour to any similar expressions which have multi-line, block-indented lists of sub-expressions -delimited by parentheses (e.g., macros or tuple struct literals). E.g., +delimited by parentheses, brackets, or braces. E.g., ```rust foo(bar( @@ -831,20 +831,61 @@ let arr = [combinable( an_expr, another_expr, )]; + +let x = Thing(an_expr, another_expr, match cond { + A => 1, + B => 2, +}); + +let x = format!("Stuff: {}", [ + an_expr, + another_expr, +]); + +let x = func(an_expr, another_expr, SomeStruct { + field: this_is_long, + another_field: 123, +}); ``` Apply this behavior recursively. -For a function with multiple arguments, if the last argument is a multi-line -closure with an explicit block, there are no other closure arguments, and all -the arguments and the first line of the closure fit on the first line, use the -same combining behavior: +If the last argument is a multi-line closure with an explicit block, +only apply the combining behavior if there are no other closure arguments. ```rust +// Combinable foo(first_arg, x, |param| { action(); foo(param) }) +// Not combinable, because the closure is not the last argument +foo( + first_arg, + |param| { + action(); + foo(param) + }, + whatever, +) +// Not combinable, because the first line of the closure does not fit +foo( + first_arg, + x, + move |very_long_param_causing_line_to_overflow| -> Bar { + action(); + foo(param) + }, +) +// Not combinable, because there is more than one closure argument +foo( + first_arg, + |x| x.bar(), + |param| { + action(); + foo(param) + }, +) ``` ## Ranges From 01337bf1fda37e8fde134454394e27e2ae719a24 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 3 Nov 2023 20:38:30 -0500 Subject: [PATCH 0033/1197] Remove `{,r}split_array_ref{,_mut}` methods from slices The functionality of these methods from `split_array` has been absorbed by the `slice_first_last_chunk` feature. This only affects the methods on slices, not those with the same name that are implemented on array types. Also adjusts testing to reflect this change. --- library/core/src/array/mod.rs | 8 +- library/core/src/slice/mod.rs | 170 +++------------------------------- library/core/tests/lib.rs | 1 + library/core/tests/slice.rs | 52 +++-------- 4 files changed, 31 insertions(+), 200 deletions(-) diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index ebd4a8c05fe30..4f6eef4ef0d53 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -647,7 +647,7 @@ impl [T; N] { )] #[inline] pub fn split_array_ref(&self) -> (&[T; M], &[T]) { - (&self[..]).split_array_ref::() + (&self[..]).split_first_chunk::().unwrap() } /// Divides one mutable array reference into two at an index. @@ -680,7 +680,7 @@ impl [T; N] { )] #[inline] pub fn split_array_mut(&mut self) -> (&mut [T; M], &mut [T]) { - (&mut self[..]).split_array_mut::() + (&mut self[..]).split_first_chunk_mut::().unwrap() } /// Divides one array reference into two at an index from the end. @@ -725,7 +725,7 @@ impl [T; N] { )] #[inline] pub fn rsplit_array_ref(&self) -> (&[T], &[T; M]) { - (&self[..]).rsplit_array_ref::() + (&self[..]).split_last_chunk::().unwrap() } /// Divides one mutable array reference into two at an index from the end. @@ -758,7 +758,7 @@ impl [T; N] { )] #[inline] pub fn rsplit_array_mut(&mut self) -> (&mut [T], &mut [T; M]) { - (&mut self[..]).rsplit_array_mut::() + (&mut self[..]).split_last_chunk_mut::().unwrap() } } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 7c07a86e2dd01..9512d45740fd3 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -367,6 +367,8 @@ impl [T] { /// first[1] = 4; /// } /// assert_eq!(x, &[5, 4, 2]); + /// + /// assert_eq!(None, x.first_chunk_mut::<4>()); /// ``` #[unstable(feature = "slice_first_last_chunk", issue = "111774")] #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")] @@ -397,6 +399,8 @@ impl [T] { /// assert_eq!(first, &[0, 1]); /// assert_eq!(elements, &[2]); /// } + /// + /// assert_eq!(None, x.split_first_chunk::<4>()); /// ``` #[unstable(feature = "slice_first_last_chunk", issue = "111774")] #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")] @@ -432,6 +436,8 @@ impl [T] { /// elements[0] = 5; /// } /// assert_eq!(x, &[3, 4, 5]); + /// + /// assert_eq!(None, x.split_first_chunk_mut::<4>()); /// ``` #[unstable(feature = "slice_first_last_chunk", issue = "111774")] #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")] @@ -467,6 +473,8 @@ impl [T] { /// assert_eq!(elements, &[0]); /// assert_eq!(last, &[1, 2]); /// } + /// + /// assert_eq!(None, x.split_last_chunk::<4>()); /// ``` #[unstable(feature = "slice_first_last_chunk", issue = "111774")] #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")] @@ -502,6 +510,8 @@ impl [T] { /// elements[0] = 5; /// } /// assert_eq!(x, &[5, 3, 4]); + /// + /// assert_eq!(None, x.split_last_chunk_mut::<4>()); /// ``` #[unstable(feature = "slice_first_last_chunk", issue = "111774")] #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")] @@ -573,6 +583,8 @@ impl [T] { /// last[1] = 20; /// } /// assert_eq!(x, &[0, 10, 20]); + /// + /// assert_eq!(None, x.last_chunk_mut::<4>()); /// ``` #[unstable(feature = "slice_first_last_chunk", issue = "111774")] #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")] @@ -2035,164 +2047,6 @@ impl [T] { } } - /// Divides one slice into an array and a remainder slice at an index. - /// - /// The array will contain all indices from `[0, N)` (excluding - /// the index `N` itself) and the slice will contain all - /// indices from `[N, len)` (excluding the index `len` itself). - /// - /// # Panics - /// - /// Panics if `N > len`. - /// - /// # Examples - /// - /// ``` - /// #![feature(split_array)] - /// - /// let v = &[1, 2, 3, 4, 5, 6][..]; - /// - /// { - /// let (left, right) = v.split_array_ref::<0>(); - /// assert_eq!(left, &[]); - /// assert_eq!(right, [1, 2, 3, 4, 5, 6]); - /// } - /// - /// { - /// let (left, right) = v.split_array_ref::<2>(); - /// assert_eq!(left, &[1, 2]); - /// assert_eq!(right, [3, 4, 5, 6]); - /// } - /// - /// { - /// let (left, right) = v.split_array_ref::<6>(); - /// assert_eq!(left, &[1, 2, 3, 4, 5, 6]); - /// assert_eq!(right, []); - /// } - /// ``` - #[unstable(feature = "split_array", reason = "new API", issue = "90091")] - #[inline] - #[track_caller] - #[must_use] - pub fn split_array_ref(&self) -> (&[T; N], &[T]) { - let (a, b) = self.split_at(N); - // SAFETY: a points to [T; N]? Yes it's [T] of length N (checked by split_at) - unsafe { (&*(a.as_ptr() as *const [T; N]), b) } - } - - /// Divides one mutable slice into an array and a remainder slice at an index. - /// - /// The array will contain all indices from `[0, N)` (excluding - /// the index `N` itself) and the slice will contain all - /// indices from `[N, len)` (excluding the index `len` itself). - /// - /// # Panics - /// - /// Panics if `N > len`. - /// - /// # Examples - /// - /// ``` - /// #![feature(split_array)] - /// - /// let mut v = &mut [1, 0, 3, 0, 5, 6][..]; - /// let (left, right) = v.split_array_mut::<2>(); - /// assert_eq!(left, &mut [1, 0]); - /// assert_eq!(right, [3, 0, 5, 6]); - /// left[1] = 2; - /// right[1] = 4; - /// assert_eq!(v, [1, 2, 3, 4, 5, 6]); - /// ``` - #[unstable(feature = "split_array", reason = "new API", issue = "90091")] - #[inline] - #[track_caller] - #[must_use] - pub fn split_array_mut(&mut self) -> (&mut [T; N], &mut [T]) { - let (a, b) = self.split_at_mut(N); - // SAFETY: a points to [T; N]? Yes it's [T] of length N (checked by split_at_mut) - unsafe { (&mut *(a.as_mut_ptr() as *mut [T; N]), b) } - } - - /// Divides one slice into an array and a remainder slice at an index from - /// the end. - /// - /// The slice will contain all indices from `[0, len - N)` (excluding - /// the index `len - N` itself) and the array will contain all - /// indices from `[len - N, len)` (excluding the index `len` itself). - /// - /// # Panics - /// - /// Panics if `N > len`. - /// - /// # Examples - /// - /// ``` - /// #![feature(split_array)] - /// - /// let v = &[1, 2, 3, 4, 5, 6][..]; - /// - /// { - /// let (left, right) = v.rsplit_array_ref::<0>(); - /// assert_eq!(left, [1, 2, 3, 4, 5, 6]); - /// assert_eq!(right, &[]); - /// } - /// - /// { - /// let (left, right) = v.rsplit_array_ref::<2>(); - /// assert_eq!(left, [1, 2, 3, 4]); - /// assert_eq!(right, &[5, 6]); - /// } - /// - /// { - /// let (left, right) = v.rsplit_array_ref::<6>(); - /// assert_eq!(left, []); - /// assert_eq!(right, &[1, 2, 3, 4, 5, 6]); - /// } - /// ``` - #[unstable(feature = "split_array", reason = "new API", issue = "90091")] - #[inline] - #[must_use] - pub fn rsplit_array_ref(&self) -> (&[T], &[T; N]) { - assert!(N <= self.len()); - let (a, b) = self.split_at(self.len() - N); - // SAFETY: b points to [T; N]? Yes it's [T] of length N (checked by split_at) - unsafe { (a, &*(b.as_ptr() as *const [T; N])) } - } - - /// Divides one mutable slice into an array and a remainder slice at an - /// index from the end. - /// - /// The slice will contain all indices from `[0, len - N)` (excluding - /// the index `N` itself) and the array will contain all - /// indices from `[len - N, len)` (excluding the index `len` itself). - /// - /// # Panics - /// - /// Panics if `N > len`. - /// - /// # Examples - /// - /// ``` - /// #![feature(split_array)] - /// - /// let mut v = &mut [1, 0, 3, 0, 5, 6][..]; - /// let (left, right) = v.rsplit_array_mut::<4>(); - /// assert_eq!(left, [1, 0]); - /// assert_eq!(right, &mut [3, 0, 5, 6]); - /// left[1] = 2; - /// right[1] = 4; - /// assert_eq!(v, [1, 2, 3, 4, 5, 6]); - /// ``` - #[unstable(feature = "split_array", reason = "new API", issue = "90091")] - #[inline] - #[must_use] - pub fn rsplit_array_mut(&mut self) -> (&mut [T], &mut [T; N]) { - assert!(N <= self.len()); - let (a, b) = self.split_at_mut(self.len() - N); - // SAFETY: b points to [T; N]? Yes it's [T] of length N (checked by split_at_mut) - unsafe { (a, &mut *(b.as_mut_ptr() as *mut [T; N])) } - } - /// Returns an iterator over subslices separated by elements that match /// `pred`. The matched element is not contained in the subslices. /// diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index df7b34ce73b42..15e58a4e53fb5 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -46,6 +46,7 @@ #![feature(pattern)] #![feature(sort_internals)] #![feature(slice_take)] +#![feature(slice_first_last_chunk)] #![feature(slice_from_ptr_range)] #![feature(slice_split_once)] #![feature(split_as_slice)] diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs index 666452ead3f5a..8bcb7ad1386a2 100644 --- a/library/core/tests/slice.rs +++ b/library/core/tests/slice.rs @@ -2399,37 +2399,45 @@ mod swap_panics { } #[test] -fn slice_split_array_mut() { +fn slice_split_first_chunk_mut() { let v = &mut [1, 2, 3, 4, 5, 6][..]; { - let (left, right) = v.split_array_mut::<0>(); + let (left, right) = v.split_first_chunk_mut::<0>().unwrap(); assert_eq!(left, &mut []); assert_eq!(right, [1, 2, 3, 4, 5, 6]); } { - let (left, right) = v.split_array_mut::<6>(); + let (left, right) = v.split_first_chunk_mut::<6>().unwrap(); assert_eq!(left, &mut [1, 2, 3, 4, 5, 6]); assert_eq!(right, []); } + + { + assert!(v.split_first_chunk_mut::<7>().is_none()); + } } #[test] -fn slice_rsplit_array_mut() { +fn slice_split_last_chunk_mut() { let v = &mut [1, 2, 3, 4, 5, 6][..]; { - let (left, right) = v.rsplit_array_mut::<0>(); + let (left, right) = v.split_last_chunk_mut::<0>().unwrap(); assert_eq!(left, [1, 2, 3, 4, 5, 6]); assert_eq!(right, &mut []); } { - let (left, right) = v.rsplit_array_mut::<6>(); + let (left, right) = v.split_last_chunk_mut::<6>().unwrap(); assert_eq!(left, []); assert_eq!(right, &mut [1, 2, 3, 4, 5, 6]); } + + { + assert!(v.split_last_chunk_mut::<7>().is_none()); + } } #[test] @@ -2444,38 +2452,6 @@ fn split_as_slice() { assert_eq!(split.as_slice(), &[]); } -#[should_panic] -#[test] -fn slice_split_array_ref_out_of_bounds() { - let v = &[1, 2, 3, 4, 5, 6][..]; - - let _ = v.split_array_ref::<7>(); -} - -#[should_panic] -#[test] -fn slice_split_array_mut_out_of_bounds() { - let v = &mut [1, 2, 3, 4, 5, 6][..]; - - let _ = v.split_array_mut::<7>(); -} - -#[should_panic] -#[test] -fn slice_rsplit_array_ref_out_of_bounds() { - let v = &[1, 2, 3, 4, 5, 6][..]; - - let _ = v.rsplit_array_ref::<7>(); -} - -#[should_panic] -#[test] -fn slice_rsplit_array_mut_out_of_bounds() { - let v = &mut [1, 2, 3, 4, 5, 6][..]; - - let _ = v.rsplit_array_mut::<7>(); -} - #[test] fn slice_split_once() { let v = &[1, 2, 3, 2, 4][..]; From 6318cbbe49f916c33bc3f4e5febe6cf0fcb7095a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Thu, 9 Nov 2023 16:21:03 +0100 Subject: [PATCH 0034/1197] `HashMap`/`HashSet`: forward `fold` implementations of iterators --- library/std/src/collections/hash/map.rs | 72 +++++++++++++++++++++++++ library/std/src/collections/hash/set.rs | 58 ++++++++++++++++++++ 2 files changed, 130 insertions(+) diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 39e94902cfe5f..b83c4d89c1e83 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -2232,6 +2232,14 @@ impl<'a, K, V> Iterator for Iter<'a, K, V> { fn size_hint(&self) -> (usize, Option) { self.base.size_hint() } + #[inline] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.base.fold(init, f) + } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Iter<'_, K, V> { @@ -2256,6 +2264,14 @@ impl<'a, K, V> Iterator for IterMut<'a, K, V> { fn size_hint(&self) -> (usize, Option) { self.base.size_hint() } + #[inline] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.base.fold(init, f) + } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IterMut<'_, K, V> { @@ -2290,6 +2306,14 @@ impl Iterator for IntoIter { fn size_hint(&self) -> (usize, Option) { self.base.size_hint() } + #[inline] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.base.fold(init, f) + } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IntoIter { @@ -2320,6 +2344,14 @@ impl<'a, K, V> Iterator for Keys<'a, K, V> { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + #[inline] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (k, _)| f(acc, k)) + } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Keys<'_, K, V> { @@ -2343,6 +2375,14 @@ impl<'a, K, V> Iterator for Values<'a, K, V> { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + #[inline] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (_, v)| f(acc, v)) + } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Values<'_, K, V> { @@ -2366,6 +2406,14 @@ impl<'a, K, V> Iterator for ValuesMut<'a, K, V> { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + #[inline] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (_, v)| f(acc, v)) + } } #[stable(feature = "map_values_mut", since = "1.10.0")] impl ExactSizeIterator for ValuesMut<'_, K, V> { @@ -2396,6 +2444,14 @@ impl Iterator for IntoKeys { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + #[inline] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (k, _)| f(acc, k)) + } } #[stable(feature = "map_into_keys_values", since = "1.54.0")] impl ExactSizeIterator for IntoKeys { @@ -2426,6 +2482,14 @@ impl Iterator for IntoValues { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + #[inline] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (_, v)| f(acc, v)) + } } #[stable(feature = "map_into_keys_values", since = "1.54.0")] impl ExactSizeIterator for IntoValues { @@ -2456,6 +2520,14 @@ impl<'a, K, V> Iterator for Drain<'a, K, V> { fn size_hint(&self) -> (usize, Option) { self.base.size_hint() } + #[inline] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.base.fold(init, f) + } } #[stable(feature = "drain", since = "1.6.0")] impl ExactSizeIterator for Drain<'_, K, V> { diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index 8bc5960829066..ea9239f0c4764 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -1500,6 +1500,14 @@ impl<'a, K> Iterator for Iter<'a, K> { fn size_hint(&self) -> (usize, Option) { self.base.size_hint() } + #[inline] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.base.fold(init, f) + } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Iter<'_, K> { @@ -1530,6 +1538,14 @@ impl Iterator for IntoIter { fn size_hint(&self) -> (usize, Option) { self.base.size_hint() } + #[inline] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.base.fold(init, f) + } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IntoIter { @@ -1560,6 +1576,14 @@ impl<'a, K> Iterator for Drain<'a, K> { fn size_hint(&self) -> (usize, Option) { self.base.size_hint() } + #[inline] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.base.fold(init, f) + } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Drain<'_, K> { @@ -1639,6 +1663,15 @@ where let (_, upper) = self.iter.size_hint(); (0, upper) } + + #[inline] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, |acc, elt| if self.other.contains(elt) { f(acc, elt) } else { acc }) + } } #[stable(feature = "std_debug", since = "1.16.0")] @@ -1691,6 +1724,15 @@ where let (_, upper) = self.iter.size_hint(); (0, upper) } + + #[inline] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, |acc, elt| if self.other.contains(elt) { acc } else { f(acc, elt) }) + } } #[stable(feature = "fused", since = "1.26.0")] @@ -1736,6 +1778,14 @@ where fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + #[inline] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, f) + } } #[stable(feature = "fused", since = "1.26.0")] @@ -1800,6 +1850,14 @@ where fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + #[inline] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, f) + } } #[allow(dead_code)] From 7d369f98301047ca66d761549b53bde33b45ab7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Mon, 27 Nov 2023 10:30:12 +0100 Subject: [PATCH 0035/1197] Specialize `count` too --- library/std/src/collections/hash/map.rs | 32 +++++++++++++++++++++++++ library/std/src/collections/hash/set.rs | 12 ++++++++++ 2 files changed, 44 insertions(+) diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index b83c4d89c1e83..fc27b6a67bfcb 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -2233,6 +2233,10 @@ impl<'a, K, V> Iterator for Iter<'a, K, V> { self.base.size_hint() } #[inline] + fn count(self) -> usize { + self.base.len() + } + #[inline] fn fold(self, init: B, f: F) -> B where Self: Sized, @@ -2265,6 +2269,10 @@ impl<'a, K, V> Iterator for IterMut<'a, K, V> { self.base.size_hint() } #[inline] + fn count(self) -> usize { + self.base.len() + } + #[inline] fn fold(self, init: B, f: F) -> B where Self: Sized, @@ -2307,6 +2315,10 @@ impl Iterator for IntoIter { self.base.size_hint() } #[inline] + fn count(self) -> usize { + self.base.len() + } + #[inline] fn fold(self, init: B, f: F) -> B where Self: Sized, @@ -2345,6 +2357,10 @@ impl<'a, K, V> Iterator for Keys<'a, K, V> { self.inner.size_hint() } #[inline] + fn count(self) -> usize { + self.inner.len() + } + #[inline] fn fold(self, init: B, mut f: F) -> B where Self: Sized, @@ -2376,6 +2392,10 @@ impl<'a, K, V> Iterator for Values<'a, K, V> { self.inner.size_hint() } #[inline] + fn count(self) -> usize { + self.inner.len() + } + #[inline] fn fold(self, init: B, mut f: F) -> B where Self: Sized, @@ -2407,6 +2427,10 @@ impl<'a, K, V> Iterator for ValuesMut<'a, K, V> { self.inner.size_hint() } #[inline] + fn count(self) -> usize { + self.inner.len() + } + #[inline] fn fold(self, init: B, mut f: F) -> B where Self: Sized, @@ -2445,6 +2469,10 @@ impl Iterator for IntoKeys { self.inner.size_hint() } #[inline] + fn count(self) -> usize { + self.inner.len() + } + #[inline] fn fold(self, init: B, mut f: F) -> B where Self: Sized, @@ -2483,6 +2511,10 @@ impl Iterator for IntoValues { self.inner.size_hint() } #[inline] + fn count(self) -> usize { + self.inner.len() + } + #[inline] fn fold(self, init: B, mut f: F) -> B where Self: Sized, diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index ea9239f0c4764..dcb2fa0f771b0 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -1501,6 +1501,10 @@ impl<'a, K> Iterator for Iter<'a, K> { self.base.size_hint() } #[inline] + fn count(self) -> usize { + self.base.len() + } + #[inline] fn fold(self, init: B, f: F) -> B where Self: Sized, @@ -1539,6 +1543,10 @@ impl Iterator for IntoIter { self.base.size_hint() } #[inline] + fn count(self) -> usize { + self.base.len() + } + #[inline] fn fold(self, init: B, f: F) -> B where Self: Sized, @@ -1851,6 +1859,10 @@ where self.iter.size_hint() } #[inline] + fn count(self) -> usize { + self.iter.count() + } + #[inline] fn fold(self, init: B, f: F) -> B where Self: Sized, From 8bc123e321b82359c80ce50dae62e13db39c96cc Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 25 Feb 2022 15:09:37 +0100 Subject: [PATCH 0036/1197] Rework doc blocks headings by not turning them into links anymore and putting an anchor to their left side --- src/librustdoc/html/markdown.rs | 8 ++-- src/librustdoc/html/markdown/tests.rs | 53 +++++++++++++++++----- src/librustdoc/html/static/css/rustdoc.css | 3 ++ 3 files changed, 47 insertions(+), 17 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index abc27bcdf0782..6a48b9367b859 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -558,12 +558,10 @@ impl<'a, 'b, 'ids, I: Iterator>> Iterator let level = std::cmp::min(level as u32 + (self.heading_offset as u32), MAX_HEADER_LEVEL); - self.buf.push_back((Event::Html(format!("").into()), 0..0)); + self.buf.push_back((Event::Html(format!("").into()), 0..0)); - let start_tags = format!( - "\ - ", - ); + let start_tags = + format!("§"); return Some((Event::Html(start_tags.into()), 0..0)); } event diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs index 5eba1d0609f38..fcf777830246c 100644 --- a/src/librustdoc/html/markdown/tests.rs +++ b/src/librustdoc/html/markdown/tests.rs @@ -311,24 +311,29 @@ fn test_header() { assert_eq!(output, expect, "original: {}", input); } - t("# Foo bar", "

Foo bar

"); + t( + "# Foo bar", + "

§Foo bar

", + ); t( "## Foo-bar_baz qux", "

\ - Foo-bar_baz qux

", + §\ + Foo-bar_baz qux\ + ", ); t( "### **Foo** *bar* baz!?!& -_qux_-%", "

\ - Foo \ - bar baz!?!& -qux-%\ + §\ + Foo bar baz!?!& -qux-%\

", ); t( "#### **Foo?** & \\*bar?!* _`baz`_ ❤ #qux", "
\ - Foo? & *bar?!* \ - baz ❤ #qux\ + §\ + Foo? & *bar?!* baz ❤ #qux\
", ); } @@ -351,12 +356,36 @@ fn test_header_ids_multiple_blocks() { assert_eq!(output, expect, "original: {}", input); } - t(&mut map, "# Example", "

Example

"); - t(&mut map, "# Panics", "

Panics

"); - t(&mut map, "# Example", "

Example

"); - t(&mut map, "# Search", "

Search

"); - t(&mut map, "# Example", "

Example

"); - t(&mut map, "# Panics", "

Panics

"); + t( + &mut map, + "# Example", + "

§Example

", + ); + t( + &mut map, + "# Panics", + "

§Panics

", + ); + t( + &mut map, + "# Example", + "

§Example

", + ); + t( + &mut map, + "# Search", + "

§Search

", + ); + t( + &mut map, + "# Example", + "

§Example

", + ); + t( + &mut map, + "# Panics", + "

§Panics

", + ); } #[test] diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index b898eb5d381e3..22fe5d8b0cfc5 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -765,6 +765,9 @@ nav.sub { h2.section-header > .anchor { padding-right: 6px; } +.doc-anchor { + margin-right: 6px; +} .main-heading a:hover, .example-wrap .rust a:hover, From d1dd589a1df3d0e2b392a1bd4034efa43326a4c9 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 25 Feb 2022 15:35:10 +0100 Subject: [PATCH 0037/1197] Allow links in doc blocks headings --- src/librustdoc/html/markdown.rs | 1 - src/librustdoc/html/markdown/tests.rs | 7 +++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 6a48b9367b859..71ad9fc243c32 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -539,7 +539,6 @@ impl<'a, 'b, 'ids, I: Iterator>> Iterator for event in &mut self.inner { match &event.0 { Event::End(Tag::Heading(..)) => break, - Event::Start(Tag::Link(_, _, _)) | Event::End(Tag::Link(..)) => {} Event::Text(text) | Event::Code(text) => { id.extend(text.chars().filter_map(slugify)); self.buf.push_back(event); diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs index fcf777830246c..4dd176b3a692a 100644 --- a/src/librustdoc/html/markdown/tests.rs +++ b/src/librustdoc/html/markdown/tests.rs @@ -336,6 +336,13 @@ fn test_header() { Foo? & *bar?!* baz ❤ #qux\ ", ); + t( + "# Foo [bar](https://hello.yo)", + "

\ + §\ + Foo bar\ +

", + ); } #[test] From 13b2156c68aa8e6565923dfad336461a393b75fa Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 25 Feb 2022 15:57:01 +0100 Subject: [PATCH 0038/1197] Update rustdoc headings tests --- tests/rustdoc-gui/docblock-details.goml | 2 +- .../rustdoc/disambiguate-anchors-header-29449.rs | 15 ++++++++++----- tests/rustdoc/remove-url-from-headings.rs | 11 +++++++---- tests/rustdoc/short-docblock.rs | 6 ++++-- 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/tests/rustdoc-gui/docblock-details.goml b/tests/rustdoc-gui/docblock-details.goml index 8e6d2ba824f73..4b8f5b54fac5d 100644 --- a/tests/rustdoc-gui/docblock-details.goml +++ b/tests/rustdoc-gui/docblock-details.goml @@ -6,7 +6,7 @@ reload: // We first check that the headers in the `.top-doc` doc block still have their // bottom border. -assert-text: (".top-doc .docblock > h3", "Hello") +assert-text: (".top-doc .docblock > h3", "§Hello") assert-css: ( ".top-doc .docblock > h3", {"border-bottom": "1px solid #d2d2d2"}, diff --git a/tests/rustdoc/disambiguate-anchors-header-29449.rs b/tests/rustdoc/disambiguate-anchors-header-29449.rs index 38a4954fc1395..1388af7df4b2e 100644 --- a/tests/rustdoc/disambiguate-anchors-header-29449.rs +++ b/tests/rustdoc/disambiguate-anchors-header-29449.rs @@ -5,18 +5,23 @@ pub struct Foo; impl Foo { - // @has - '//*[@id="examples"]//a' 'Examples' - // @has - '//*[@id="panics"]//a' 'Panics' + // @has - '//*[@id="examples"]' 'Examples' + // @has - '//*[@id="examples"]/a[@href="#examples"]' '§' + // @has - '//*[@id="panics"]' 'Panics' + // @has - '//*[@id="panics"]/a[@href="#panics"]' '§' /// # Examples /// # Panics pub fn bar() {} - // @has - '//*[@id="examples-1"]//a' 'Examples' + // @has - '//*[@id="examples-1"]' 'Examples' + // @has - '//*[@id="examples-1"]/a[@href="#examples-1"]' '§' /// # Examples pub fn bar_1() {} - // @has - '//*[@id="examples-2"]//a' 'Examples' - // @has - '//*[@id="panics-1"]//a' 'Panics' + // @has - '//*[@id="examples-2"]' 'Examples' + // @has - '//*[@id="examples-2"]/a[@href="#examples-2"]' '§' + // @has - '//*[@id="panics-1"]' 'Panics' + // @has - '//*[@id="panics-1"]/a[@href="#panics-1"]' '§' /// # Examples /// # Panics pub fn bar_2() {} diff --git a/tests/rustdoc/remove-url-from-headings.rs b/tests/rustdoc/remove-url-from-headings.rs index 599c429a6e1de..8f4770286192e 100644 --- a/tests/rustdoc/remove-url-from-headings.rs +++ b/tests/rustdoc/remove-url-from-headings.rs @@ -1,9 +1,12 @@ +// It actually checks that the link is kept in the headings as expected now. + #![crate_name = "foo"] // @has foo/fn.foo.html -// @!has - '//a[@href="http://a.a"]' '' -// @has - '//a[@href="#implementing-stuff-somewhere"]' 'Implementing stuff somewhere' -// @has - '//a[@href="#another-one-urg"]' 'Another one urg' +// @has - '//a[@href="http://a.a"]' 'stuff' +// @has - '//*[@id="implementing-stuff-somewhere"]' 'Implementing stuff somewhere' +// @has - '//a[@href="http://b.b"]' 'one' +// @has - '//*[@id="another-one-urg"]' 'Another one urg' /// fooo /// @@ -13,5 +16,5 @@ /// /// # Another [one][two] urg /// -/// [two]: http://a.a +/// [two]: http://b.b pub fn foo() {} diff --git a/tests/rustdoc/short-docblock.rs b/tests/rustdoc/short-docblock.rs index 791d3547c9fec..151a42a9c9ee5 100644 --- a/tests/rustdoc/short-docblock.rs +++ b/tests/rustdoc/short-docblock.rs @@ -2,8 +2,9 @@ // @has foo/index.html '//*[@class="desc docblock-short"]' 'fooo' // @!has foo/index.html '//*[@class="desc docblock-short"]/h1' 'fooo' -// @has foo/fn.foo.html '//h2[@id="fooo"]/a[@href="#fooo"]' 'fooo' +// @has foo/fn.foo.html '//h2[@id="fooo"]' 'fooo' +// @has foo/fn.foo.html '//h2[@id="fooo"]/a[@href="#fooo"]' '§' /// # fooo /// /// foo @@ -11,8 +12,9 @@ pub fn foo() {} // @has foo/index.html '//*[@class="desc docblock-short"]' 'mooood' // @!has foo/index.html '//*[@class="desc docblock-short"]/h2' 'mooood' -// @has foo/foo/index.html '//h3[@id="mooood"]/a[@href="#mooood"]' 'mooood' +// @has foo/foo/index.html '//h3[@id="mooood"]' 'mooood' +// @has foo/foo/index.html '//h3[@id="mooood"]/a[@href="#mooood"]' '§' /// ## mooood /// /// foo mod From a4e5e074ac0dfb478c362af2dc37a9e333d86547 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 14 Nov 2023 15:40:31 +0100 Subject: [PATCH 0039/1197] Make headings anchor hidden by default and show on hover --- src/librustdoc/html/static/css/rustdoc.css | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 22fe5d8b0cfc5..52af572f77093 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -765,14 +765,30 @@ nav.sub { h2.section-header > .anchor { padding-right: 6px; } -.doc-anchor { - margin-right: 6px; +a.doc-anchor { + color: var(--main-color); + display: none; + position: absolute; + left: -17px; + /* We add this padding so that when the cursor moves from the heading's text to the anchor, + the anchor doesn't disappear. */ + padding-right: 5px; + /* And this padding is used to make the anchor larger and easier to click on. */ + padding-left: 3px; +} +*:hover > .doc-anchor { + display: block; +} +/* If the first element of the top doc block is a heading, we don't want to ever display its anchor +because of the `[-]` element which would overlap with it. */ +.top-doc > .docblock > *:first-child > .doc-anchor { + display: none !important; } .main-heading a:hover, .example-wrap .rust a:hover, .all-items a:hover, -.docblock a:not(.test-arrow):not(.scrape-help):not(.tooltip):hover, +.docblock a:not(.test-arrow):not(.scrape-help):not(.tooltip):hover:not(.doc-anchor), .docblock-short a:not(.test-arrow):not(.scrape-help):not(.tooltip):hover, .item-info a { text-decoration: underline; From 42fcba7a6731ec2a0fc6e75383fbd35dd75db41d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 14 Nov 2023 16:40:48 +0100 Subject: [PATCH 0040/1197] Add tests for headings anchor and links in headings --- tests/rustdoc-gui/headers-color.goml | 8 +++---- tests/rustdoc-gui/headings-anchor.goml | 32 ++++++++++++++++++++++++++ tests/rustdoc/links-in-headings.rs | 14 +++++++++++ 3 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 tests/rustdoc-gui/headings-anchor.goml create mode 100644 tests/rustdoc/links-in-headings.rs diff --git a/tests/rustdoc-gui/headers-color.goml b/tests/rustdoc-gui/headers-color.goml index 19185818f407e..80d11c9c849cf 100644 --- a/tests/rustdoc-gui/headers-color.goml +++ b/tests/rustdoc-gui/headers-color.goml @@ -1,4 +1,4 @@ -// This test check for headers text and background colors for the different themes. +// This test check for headings text and background colors for the different themes. define-function: ( "check-colors", @@ -45,7 +45,7 @@ call-function: ( "color": "#c5c5c5", "code_header_color": "#e6e1cf", "focus_background_color": "rgba(255, 236, 164, 0.06)", - "headings_color": "#39afd7", + "headings_color": "#c5c5c5", }, ) call-function: ( @@ -55,7 +55,7 @@ call-function: ( "color": "#ddd", "code_header_color": "#ddd", "focus_background_color": "#494a3d", - "headings_color": "#d2991d", + "headings_color": "#ddd", }, ) call-function: ( @@ -65,6 +65,6 @@ call-function: ( "color": "black", "code_header_color": "black", "focus_background_color": "#fdffd3", - "headings_color": "#3873ad", + "headings_color": "black", }, ) diff --git a/tests/rustdoc-gui/headings-anchor.goml b/tests/rustdoc-gui/headings-anchor.goml new file mode 100644 index 0000000000000..f568caa3b07fe --- /dev/null +++ b/tests/rustdoc-gui/headings-anchor.goml @@ -0,0 +1,32 @@ +// Test to ensure that the headings anchor behave as expected. +go-to: "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html" +show-text: true + +define-function: ( + "check-heading-anchor", + (heading_id), + block { + // The anchor should not be displayed by default. + assert-css: ("#" + |heading_id| + " .doc-anchor", { "display": "none" }) + // We ensure that hovering the heading makes the anchor visible. + move-cursor-to: "#" + |heading_id| + assert-css: ("#" + |heading_id| + ":hover .doc-anchor", { "display": "block" }) + // We then ensure that moving from the heading to the anchor doesn't make the anchor + // disappear. + move-cursor-to: "#" + |heading_id| + " .doc-anchor" + assert-css: ("#" + |heading_id| + " .doc-anchor:hover", { + "display": "block", + // We also ensure that there is no underline decoration. + "text-decoration-line": "none", + }) + } +) + +move-cursor-to: "#top-doc-prose-title" +// If the top documentation block first element is a heading, we should never display its anchor +// to prevent it from overlapping with the `[-]` element. +assert-css: ("#top-doc-prose-title:hover .doc-anchor", { "display": "none" }) + +call-function: ("check-heading-anchor", ("top-doc-prose-sub-heading")) +call-function: ("check-heading-anchor", ("top-doc-prose-sub-sub-heading")) +call-function: ("check-heading-anchor", ("you-know-the-drill")) diff --git a/tests/rustdoc/links-in-headings.rs b/tests/rustdoc/links-in-headings.rs new file mode 100644 index 0000000000000..c5bee1a79750c --- /dev/null +++ b/tests/rustdoc/links-in-headings.rs @@ -0,0 +1,14 @@ +#![crate_name = "foo"] + +//! # Heading with [a link](https://a.com) inside +//! +//! And even with +//! +//! ## [multiple](https://b.com) [links](https://c.com) +//! +//! ! + +// @has 'foo/index.html' +// @has - '//h2/a[@href="https://a.com"]' 'a link' +// @has - '//h3/a[@href="https://b.com"]' 'multiple' +// @has - '//h3/a[@href="https://c.com"]' 'links' From d7c5358a57ec81449f52479f83e2de32f01d696e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 5 Dec 2023 16:10:23 +0100 Subject: [PATCH 0041/1197] Make all headings display the same by creating an anchor right beside them --- src/librustdoc/html/render/print_item.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 131b1d608e683..b9a60a3fbdd1f 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -431,7 +431,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: write!( w, "

\ - {name}\ + {name}§\

{ITEM_TABLE_OPEN}", id = cx.derive_id(my_section.id()), name = my_section.name(), From bf4a20cfca442f211932e181a27baa070e3062cd Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 5 Dec 2023 16:45:21 +0100 Subject: [PATCH 0042/1197] Generate section headings all from one place --- src/librustdoc/html/render/mod.rs | 20 +++- src/librustdoc/html/render/print_item.rs | 112 +++++++++++------------ 2 files changed, 68 insertions(+), 64 deletions(-) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index e076c1b92e6e6..7c9be214d13ed 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1142,17 +1142,31 @@ impl<'a> AssocItemLink<'a> { } } -fn write_impl_section_heading(mut w: impl fmt::Write, title: &str, id: &str) { +pub fn write_section_heading( + w: &mut impl fmt::Write, + title: &str, + id: &str, + extra_class: Option<&str>, + extra: impl fmt::Display, +) { + let (extra_class, whitespace) = match extra_class { + Some(extra) => (extra, " "), + None => ("", ""), + }; write!( w, - "

\ + "

\ {title}\ §\ -

" + {extra}", ) .unwrap(); } +fn write_impl_section_heading(w: &mut impl fmt::Write, title: &str, id: &str) { + write_section_heading(w, title, id, None, "") +} + pub(crate) fn render_all_impls( mut w: impl Write, cx: &mut Context<'_>, diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index b9a60a3fbdd1f..a50e59de0fb28 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -22,8 +22,8 @@ use super::{ item_ty_to_section, notable_traits_button, notable_traits_json, render_all_impls, render_assoc_item, render_assoc_items, render_attributes_in_code, render_attributes_in_pre, render_impl, render_rightside, render_stability_since_raw, - render_stability_since_raw_with_extra, AssocItemLink, AssocItemRender, Context, - ImplRenderingParameters, RenderMode, + render_stability_since_raw_with_extra, write_section_heading, AssocItemLink, AssocItemRender, + Context, ImplRenderingParameters, RenderMode, }; use crate::clean; use crate::config::ModuleSorting; @@ -428,13 +428,12 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: w.write_str(ITEM_TABLE_CLOSE); } last_section = Some(my_section); - write!( + write_section_heading( w, - "

\ - {name}§\ -

{ITEM_TABLE_OPEN}", - id = cx.derive_id(my_section.id()), - name = my_section.name(), + my_section.name(), + &cx.derive_id(my_section.id()), + None, + ITEM_TABLE_OPEN, ); } @@ -824,16 +823,6 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: // Trait documentation write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); - fn write_small_section_header(w: &mut Buffer, id: &str, title: &str, extra_content: &str) { - write!( - w, - "

\ - {1}§\ -

{2}", - id, title, extra_content - ) - } - fn trait_item(w: &mut Buffer, cx: &mut Context<'_>, m: &clean::Item, t: &clean::Item) { let name = m.name.unwrap(); info!("Documenting {name} on {ty_name:?}", ty_name = t.name); @@ -867,10 +856,11 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: } if !required_types.is_empty() { - write_small_section_header( + write_section_heading( w, - "required-associated-types", "Required Associated Types", + "required-associated-types", + None, "
", ); for t in required_types { @@ -879,10 +869,11 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: w.write_str("
"); } if !provided_types.is_empty() { - write_small_section_header( + write_section_heading( w, - "provided-associated-types", "Provided Associated Types", + "provided-associated-types", + None, "
", ); for t in provided_types { @@ -892,10 +883,11 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: } if !required_consts.is_empty() { - write_small_section_header( + write_section_heading( w, - "required-associated-consts", "Required Associated Constants", + "required-associated-consts", + None, "
", ); for t in required_consts { @@ -904,10 +896,11 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: w.write_str("
"); } if !provided_consts.is_empty() { - write_small_section_header( + write_section_heading( w, - "provided-associated-consts", "Provided Associated Constants", + "provided-associated-consts", + None, "
", ); for t in provided_consts { @@ -918,10 +911,11 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: // Output the documentation for each function individually if !required_methods.is_empty() || must_implement_one_of_functions.is_some() { - write_small_section_header( + write_section_heading( w, - "required-methods", "Required Methods", + "required-methods", + None, "
", ); @@ -939,10 +933,11 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: w.write_str("
"); } if !provided_methods.is_empty() { - write_small_section_header( + write_section_heading( w, - "provided-methods", "Provided Methods", + "provided-methods", + None, "
", ); for m in provided_methods { @@ -959,10 +954,11 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: let mut extern_crates = FxHashSet::default(); if !t.is_object_safe(cx.tcx()) { - write_small_section_header( + write_section_heading( w, - "object-safety", "Object Safety", + "object-safety", + None, &format!( "
This trait is not \ \ @@ -1006,7 +1002,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: foreign.sort_by_cached_key(|i| ImplString::new(i, cx)); if !foreign.is_empty() { - write_small_section_header(w, "foreign-impls", "Implementations on Foreign Types", ""); + write_section_heading(w, "Implementations on Foreign Types", "foreign-impls", None, ""); for implementor in foreign { let provided_methods = implementor.inner_impl().provided_trait_methods(tcx); @@ -1031,10 +1027,11 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: } } - write_small_section_header( + write_section_heading( w, - "implementors", "Implementors", + "implementors", + None, "
", ); for implementor in concrete { @@ -1043,10 +1040,11 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: w.write_str("
"); if t.is_auto(tcx) { - write_small_section_header( + write_section_heading( w, - "synthetic-implementors", "Auto implementors", + "synthetic-implementors", + None, "
", ); for implementor in synthetic { @@ -1064,18 +1062,20 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: } else { // even without any implementations to write in, we still want the heading and list, so the // implementors javascript file pulled in below has somewhere to write the impls into - write_small_section_header( + write_section_heading( w, - "implementors", "Implementors", + "implementors", + None, "
", ); if t.is_auto(tcx) { - write_small_section_header( + write_section_heading( w, - "synthetic-implementors", "Auto implementors", + "synthetic-implementors", + None, "
", ); } @@ -1258,11 +1258,7 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); if let Some(inner_type) = &t.inner_type { - write!( - w, - "

\ - Aliased Type§

" - ); + write_section_heading(w, "Aliased Type", "aliased-type", None, ""); match inner_type { clean::TypeAliasInnerType::Enum { variants, is_non_exhaustive } => { @@ -1683,16 +1679,14 @@ fn item_variants( enum_def_id: DefId, ) { let tcx = cx.tcx(); - write!( + write_section_heading( w, - "

\ - Variants{}§\ -

\ - {}\ -
", - document_non_exhaustive_header(it), - document_non_exhaustive(it) + &format!("Variants{}", document_non_exhaustive_header(it)), + "variants", + Some("variants"), + format!("{}
", document_non_exhaustive(it)), ); + let should_show_enum_discriminant = should_show_enum_discriminant(cx, enum_def_id, variants); for (index, variant) in variants.iter_enumerated() { if variant.is_stripped() { @@ -1933,16 +1927,12 @@ fn item_fields( .peekable(); if let None | Some(CtorKind::Fn) = ctor_kind { if fields.peek().is_some() { - write!( - w, - "

\ - {}{}§\ -

\ - {}", + let title = format!( + "{}{}", if ctor_kind.is_none() { "Fields" } else { "Tuple Fields" }, document_non_exhaustive_header(it), - document_non_exhaustive(it) ); + write_section_heading(w, &title, "fields", Some("fields"), document_non_exhaustive(it)); for (index, (field, ty)) in fields.enumerate() { let field_name = field.name.map_or_else(|| index.to_string(), |sym| sym.as_str().to_string()); From 5ec0a21ebeba234d0fcb3d8b5c4d004eeb954998 Mon Sep 17 00:00:00 2001 From: Ludwig Neste Date: Thu, 7 Dec 2023 17:50:37 +0100 Subject: [PATCH 0043/1197] Introduce explanation about fields being used in ordering --- library/core/src/cmp.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index fadf2fcc9fce6..efab04bca2382 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -707,7 +707,8 @@ impl Clone for Reverse { /// [lexicographic](https://en.wikipedia.org/wiki/Lexicographic_order) ordering /// based on the top-to-bottom declaration order of the struct's members. /// -/// When `derive`d on enums, variants are ordered by their discriminants. +/// When `derive`d on enums, variants are ordered primarily by their discriminants. +/// Secondarily, they are ordered by their fields. /// By default, the discriminant is smallest for variants at the top, and /// largest for variants at the bottom. Here's an example: /// @@ -960,7 +961,8 @@ pub macro Ord($item:item) { /// [lexicographic](https://en.wikipedia.org/wiki/Lexicographic_order) ordering /// based on the top-to-bottom declaration order of the struct's members. /// -/// When `derive`d on enums, variants are ordered by their discriminants. +/// When `derive`d on enums, variants are primarily ordered by their discriminants. +/// Secondarily, they are ordered by their fields. /// By default, the discriminant is smallest for variants at the top, and /// largest for variants at the bottom. Here's an example: /// From 17edbe7cad199e04345db5e810970576e8dc6f40 Mon Sep 17 00:00:00 2001 From: David Thomas Date: Sun, 10 Dec 2023 11:36:56 +0000 Subject: [PATCH 0044/1197] Use AtomicU8 instead of AtomicUsize in backtrace.rs --- library/std/src/backtrace.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs index 7fcf2ee358c46..34ac095305025 100644 --- a/library/std/src/backtrace.rs +++ b/library/std/src/backtrace.rs @@ -93,7 +93,7 @@ use crate::env; use crate::ffi::c_void; use crate::fmt; use crate::panic::UnwindSafe; -use crate::sync::atomic::{AtomicUsize, Ordering::Relaxed}; +use crate::sync::atomic::{AtomicU8, Ordering::Relaxed}; use crate::sync::LazyLock; use crate::sys_common::backtrace::{lock, output_filename, set_image_base}; use crate::vec::Vec; @@ -255,7 +255,7 @@ impl Backtrace { // Cache the result of reading the environment variables to make // backtrace captures speedy, because otherwise reading environment // variables every time can be somewhat slow. - static ENABLED: AtomicUsize = AtomicUsize::new(0); + static ENABLED: AtomicU8 = AtomicU8::new(0); match ENABLED.load(Relaxed) { 0 => {} 1 => return false, @@ -268,7 +268,7 @@ impl Backtrace { Err(_) => false, }, }; - ENABLED.store(enabled as usize + 1, Relaxed); + ENABLED.store(enabled as u8 + 1, Relaxed); enabled } From 2d1b2a9906be977d961d96f57dc67c8c9c9024f1 Mon Sep 17 00:00:00 2001 From: Jaro Fietz Date: Sat, 16 Dec 2023 23:32:24 +0100 Subject: [PATCH 0045/1197] Add more weirdness to weird-exprs.rs --- tests/ui/weird-exprs.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/ui/weird-exprs.rs b/tests/ui/weird-exprs.rs index 6d40d6377c5de..ba266c36fc195 100644 --- a/tests/ui/weird-exprs.rs +++ b/tests/ui/weird-exprs.rs @@ -231,6 +231,31 @@ fn infcx() { let _cx: cx::cx::Cx = cx::cx::cx::cx::cx::Cx; } +fn return_already() -> impl std::fmt::Debug { + loop { + return !!!!!!! + break !!!!!!1111 + } +} + +fn cursed_macros() -> impl std::fmt::Debug { + loop { + if! { + match! ( + break! { + return! { + 1337 + } + } + ) + + {} + } + + {} + } +} + pub fn main() { strange(); funny(); @@ -257,4 +282,6 @@ pub fn main() { semisemisemisemisemi(); useful_syntax(); infcx(); + return_already(); + cursed_macros(); } From 605504c5bf5b02026dee02bfe682ff9adf3e22cd Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Sat, 19 Jun 2021 16:41:38 +0200 Subject: [PATCH 0046/1197] Add Ipv6Addr::is_ipv4_mapped This change consists of cherry-picking the content from the original PR[1], which got closed due to inactivity, and applying the following changes: * Resolving merge conflicts (obviously) * Linked to to_ipv4_mapped instead of to_ipv4 in the documentation (seems more appropriate) * Added the must_use and rustc_const_unstable attributes the original didn't have I think it's a reasonably useful method. [1] https://github.com/rust-lang/rust/pull/86490 --- library/core/src/net/ip_addr.rs | 25 +++++++++++++++++++++++++ library/core/tests/net/ip_addr.rs | 12 +++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs index 8bf15c736c34b..65debde100a4b 100644 --- a/library/core/src/net/ip_addr.rs +++ b/library/core/src/net/ip_addr.rs @@ -1777,6 +1777,31 @@ impl Ipv6Addr { (self.segments()[0] & 0xff00) == 0xff00 } + /// Returns [`true`] if the address is an IPv4-mapped address (`::ffff:0:0/96`). + /// + /// IPv4-mapped addresses can be converted to their canonical IPv4 address with + /// [`to_ipv4_mapped`](Ipv6Addr::to_ipv4_mapped). + /// + /// # Examples + /// ``` + /// #![feature(ip)] + /// + /// use std::net::{Ipv4Addr, Ipv6Addr}; + /// + /// let ipv4_mapped = Ipv4Addr::new(192, 0, 2, 255).to_ipv6_mapped(); + /// assert_eq!(ipv4_mapped.is_ipv4_mapped(), true); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x2ff).is_ipv4_mapped(), true); + /// + /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_ipv4_mapped(), false); + /// ``` + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] + #[must_use] + #[inline] + pub const fn is_ipv4_mapped(&self) -> bool { + matches!(self.segments(), [0, 0, 0, 0, 0, 0xffff, _, _]) + } + /// Converts this address to an [`IPv4` address] if it's an [IPv4-mapped] address, /// as defined in [IETF RFC 4291 section 2.5.5.2], otherwise returns [`None`]. /// diff --git a/library/core/tests/net/ip_addr.rs b/library/core/tests/net/ip_addr.rs index 7530fc084874d..12ef678735d44 100644 --- a/library/core/tests/net/ip_addr.rs +++ b/library/core/tests/net/ip_addr.rs @@ -508,6 +508,7 @@ fn ipv6_properties() { | multicast_realm_local | multicast_site_local | multicast_organization_local; + let ipv4_mapped: u32 = 1 << 17; if ($mask & unspecified) == unspecified { assert!(ip!($s).is_unspecified()); @@ -584,6 +585,11 @@ fn ipv6_properties() { assert_eq!(ip!($s).multicast_scope().unwrap(), Ipv6MulticastScope::Global); } + if ($mask & ipv4_mapped) == ipv4_mapped { + assert!(ip!($s).is_ipv4_mapped()); + } else { + assert!(!ip!($s).is_ipv4_mapped()); + } } } @@ -602,6 +608,7 @@ fn ipv6_properties() { let multicast_site_local: u32 = 1 << 13; let multicast_organization_local: u32 = 1 << 14; let multicast_global: u32 = 1 << 15; + let ipv4_mapped: u32 = 1 << 17; check!("::", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unspecified); @@ -614,7 +621,7 @@ fn ipv6_properties() { check!( "::ffff:127.0.0.1", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x7f, 0, 0, 1], - unicast_global + unicast_global | ipv4_mapped ); check!( @@ -982,6 +989,9 @@ fn ipv6_const() { const IS_MULTICAST: bool = IP_ADDRESS.is_multicast(); assert!(!IS_MULTICAST); + const IS_IPV4_MAPPED: bool = IP_ADDRESS.is_ipv4_mapped(); + assert!(!IS_IPV4_MAPPED); + const IP_V4: Option = IP_ADDRESS.to_ipv4(); assert_eq!(IP_V4.unwrap(), Ipv4Addr::new(0, 0, 0, 1)); } From 4369a787300c22110ae5ea8d520870fd8bc975a0 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 19 Dec 2023 16:16:02 +0100 Subject: [PATCH 0047/1197] Add triagebot mentions entry for simd intrinsics --- triagebot.toml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index e4b104cdb8677..8dcfb38e097b5 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -492,6 +492,13 @@ cc = ["@Nadrieril"] message = "Some changes might have occurred in exhaustiveness checking" cc = ["@Nadrieril"] +[mentions."library/core/src/intrinsics/simd.rs"] +message = """ +Some changes occurred to the platform-builtins intrinsics. Make sure all +codegen backends as well as portable-simd get adapted for the changes. +""" +cc = ["@antoyo", "@GuillaumeGomez", "@bjorn3", "@calebzulawski", "@programmerjake"] + [mentions."library/portable-simd"] message = """ Portable SIMD is developed in its own repository. If possible, consider \ From 1c5b2ce67cb8d698350b93143b8de342805145cc Mon Sep 17 00:00:00 2001 From: AngelicosPhosphoros Date: Tue, 19 Dec 2023 22:08:48 +0100 Subject: [PATCH 0048/1197] Docs: Use non-SeqCst in module example of atomics I done this for this reasons: 1. The example now shows that there is more Orderings than just SeqCst. 2. People who would copy from example would now have more suitable orderings for the job. 3. SeqCst is both much harder to reason about and not needed in most situations. IMHO, we should encourage people to think and use memory orderings that is suitable to task instead of blindly defaulting to SeqCst. --- library/core/src/sync/atomic.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 5f1f41e68658c..ad8c70c6a3ca3 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -138,7 +138,7 @@ //! //! In general, *all* atomic accesses on read-only memory are Undefined Behavior. For instance, attempting //! to do a `compare_exchange` that will definitely fail (making it conceptually a read-only -//! operation) can still cause a page fault if the underlying memory page is mapped read-only. Since +//! operation) can still cause a segmentation fault if the underlying memory page is mapped read-only. Since //! atomic `load`s might be implemented using compare-exchange operations, even a `load` can fault //! on read-only memory. //! @@ -181,12 +181,13 @@ //! let spinlock = Arc::new(AtomicUsize::new(1)); //! //! let spinlock_clone = Arc::clone(&spinlock); +//! //! let thread = thread::spawn(move|| { -//! spinlock_clone.store(0, Ordering::SeqCst); +//! spinlock_clone.store(0, Ordering::Release); //! }); //! //! // Wait for the other thread to release the lock -//! while spinlock.load(Ordering::SeqCst) != 0 { +//! while spinlock.load(Ordering::Acquire) != 0 { //! hint::spin_loop(); //! } //! @@ -203,7 +204,11 @@ //! //! static GLOBAL_THREAD_COUNT: AtomicUsize = AtomicUsize::new(0); //! -//! let old_thread_count = GLOBAL_THREAD_COUNT.fetch_add(1, Ordering::SeqCst); +//! // Note that Relaxed ordering doesn't synchronize anything +//! // except the global thread counter itself. +//! let old_thread_count = GLOBAL_THREAD_COUNT.fetch_add(1, Ordering::Relaxed); +//! // Note that this number may not be true at the moment of printing +//! // because some other thread may have changed static value already. //! println!("live threads: {}", old_thread_count + 1); //! ``` From c0a9f722c40b728eef492040332d4616c1393e4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Tue, 5 Dec 2023 08:56:30 +0100 Subject: [PATCH 0049/1197] Undeprecate and use lint `unstable_features` --- compiler/rustc_lexer/src/lib.rs | 5 +-- compiler/rustc_lint/messages.ftl | 2 +- compiler/rustc_lint/src/builtin.rs | 34 +++++++++++++++---- compiler/rustc_parse_format/src/lib.rs | 5 +-- .../feature-gate-feature-gate.stderr | 2 +- 5 files changed, 35 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index 43dfd34a6ff74..f6c9289b529c7 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -20,8 +20,9 @@ //! [`rustc_parse::lexer`]: ../rustc_parse/lexer/index.html #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] -// We want to be able to build this crate with a stable compiler, so no -// `#![feature]` attributes should be added. +// We want to be able to build this crate with a stable compiler, +// so no `#![feature]` attributes should be added. +#![deny(unstable_features)] mod cursor; pub mod unescape; diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 40e6b1b579f5b..54ebe5ba912cc 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -148,7 +148,7 @@ lint_builtin_unsafe_impl = implementation of an `unsafe` trait lint_builtin_unsafe_trait = declaration of an `unsafe` trait -lint_builtin_unstable_features = unstable feature +lint_builtin_unstable_features = use of an unstable feature lint_builtin_unused_doc_comment = unused doc comment .label = rustdoc does not generate documentation for {$kind} diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 045ff38c0568c..324a8896a0769 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1233,10 +1233,30 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes { } declare_lint! { - /// The `unstable_features` is deprecated and should no longer be used. + /// The `unstable_features` lint detects uses of `#![feature]`. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(unstable_features)] + /// #![feature(test)] + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// In larger nightly-based projects which + /// + /// * consist of a multitude of crates where a subset of crates has to compile on + /// stable either unconditionally or depending on a `cfg` flag to for example + /// allow stable users to depend on them, + /// * don't use nightly for experimental features but for, e.g., unstable options only, + /// + /// this lint may come in handy to enforce policies of these kinds. UNSTABLE_FEATURES, Allow, - "enabling unstable features (deprecated. do not use)" + "enabling unstable features" } declare_lint_pass!( @@ -1246,11 +1266,11 @@ declare_lint_pass!( impl<'tcx> LateLintPass<'tcx> for UnstableFeatures { fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) { - if attr.has_name(sym::feature) { - if let Some(items) = attr.meta_item_list() { - for item in items { - cx.emit_spanned_lint(UNSTABLE_FEATURES, item.span(), BuiltinUnstableFeatures); - } + if attr.has_name(sym::feature) + && let Some(items) = attr.meta_item_list() + { + for item in items { + cx.emit_spanned_lint(UNSTABLE_FEATURES, item.span(), BuiltinUnstableFeatures); } } } diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index e886db3da2965..e5998bc3e99cb 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -11,8 +11,9 @@ )] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] -// WARNING: We want to be able to build this crate with a stable compiler, -// so no `#![feature]` attributes should be added! +// We want to be able to build this crate with a stable compiler, +// so no `#![feature]` attributes should be added. +#![deny(unstable_features)] use rustc_lexer::unescape; pub use Alignment::*; diff --git a/tests/ui/feature-gates/feature-gate-feature-gate.stderr b/tests/ui/feature-gates/feature-gate-feature-gate.stderr index 8ff99ddbe2188..6ca6c04e40181 100644 --- a/tests/ui/feature-gates/feature-gate-feature-gate.stderr +++ b/tests/ui/feature-gates/feature-gate-feature-gate.stderr @@ -1,4 +1,4 @@ -error: unstable feature +error: use of an unstable feature --> $DIR/feature-gate-feature-gate.rs:2:12 | LL | #![feature(intrinsics)] From 006ea0356f812f5ee5c7dac944c031ccc6a2dab0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Dec 2023 14:39:14 +0100 Subject: [PATCH 0050/1197] another trophy --- src/tools/miri/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index 3dee742fa0dea..6695f123c7836 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -590,6 +590,7 @@ Definite bugs found: * [Incorrect use of `compare_exchange_weak` in `once_cell`](https://github.com/matklad/once_cell/issues/186) * [Dropping with unaligned pointers in `vec::IntoIter`](https://github.com/rust-lang/rust/pull/106084) * [Deallocating with the wrong layout in new specializations for in-place `Iterator::collect`](https://github.com/rust-lang/rust/pull/118460) +* [Incorrect offset computation for highly-aligned types in `portable-atomic-util`](https://github.com/taiki-e/portable-atomic/pull/138) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): From 0e6f7c6c7c8f64327150c973606c1a87d587a3cc Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 20 Dec 2023 17:41:51 +0000 Subject: [PATCH 0051/1197] Add AsyncFn family of traits --- library/core/src/lib.rs | 1 + library/core/src/ops/async_function.rs | 105 ++++++++++++++++++++++ library/core/src/ops/mod.rs | 4 + tests/ui/async-await/async-fn/simple.rs | 16 ++++ tests/ui/did_you_mean/bad-assoc-ty.stderr | 9 +- 5 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 library/core/src/ops/async_function.rs create mode 100644 tests/ui/async-await/async-fn/simple.rs diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 07720f235989b..1cd0240b87cc6 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -227,6 +227,7 @@ #![feature(fundamental)] #![feature(generic_arg_infer)] #![feature(if_let_guard)] +#![feature(impl_trait_in_assoc_type)] #![feature(inline_const)] #![feature(intra_doc_pointers)] #![feature(intrinsics)] diff --git a/library/core/src/ops/async_function.rs b/library/core/src/ops/async_function.rs new file mode 100644 index 0000000000000..0e05badd06df8 --- /dev/null +++ b/library/core/src/ops/async_function.rs @@ -0,0 +1,105 @@ +use crate::future::Future; +use crate::marker::Tuple; + +/// An async-aware version of the [`Fn`](crate::ops::Fn) trait. +/// +/// All `async fn` and functions returning futures implement this trait. +#[unstable(feature = "async_fn_traits", issue = "none")] +#[rustc_paren_sugar] +#[fundamental] +#[must_use = "async closures are lazy and do nothing unless called"] +pub trait AsyncFn: AsyncFnMut { + /// Future returned by [`AsyncFn::async_call`]. + #[unstable(feature = "async_fn_traits", issue = "none")] + type CallFuture<'a>: Future + where + Self: 'a; + + /// Call the [`AsyncFn`], returning a future which may borrow from the called closure. + #[unstable(feature = "async_fn_traits", issue = "none")] + extern "rust-call" fn async_call(&self, args: Args) -> Self::CallFuture<'_>; +} + +/// An async-aware version of the [`FnMut`](crate::ops::FnMut) trait. +/// +/// All `async fn` and functions returning futures implement this trait. +#[unstable(feature = "async_fn_traits", issue = "none")] +#[rustc_paren_sugar] +#[fundamental] +#[must_use = "async closures are lazy and do nothing unless called"] +pub trait AsyncFnMut: AsyncFnOnce { + /// Future returned by [`AsyncFnMut::async_call_mut`]. + #[unstable(feature = "async_fn_traits", issue = "none")] + type CallMutFuture<'a>: Future + where + Self: 'a; + + /// Call the [`AsyncFnMut`], returning a future which may borrow from the called closure. + #[unstable(feature = "async_fn_traits", issue = "none")] + extern "rust-call" fn async_call_mut(&mut self, args: Args) -> Self::CallMutFuture<'_>; +} + +/// An async-aware version of the [`FnOnce`](crate::ops::FnOnce) trait. +/// +/// All `async fn` and functions returning futures implement this trait. +#[unstable(feature = "async_fn_traits", issue = "none")] +#[rustc_paren_sugar] +#[fundamental] +#[must_use = "async closures are lazy and do nothing unless called"] +pub trait AsyncFnOnce { + /// Future returned by [`AsyncFnOnce::async_call_once`]. + #[unstable(feature = "async_fn_traits", issue = "none")] + type CallOnceFuture: Future; + + /// Output type of the called closure's future. + #[unstable(feature = "async_fn_traits", issue = "none")] + type Output; + + /// Call the [`AsyncFnOnce`], returning a future which may move out of the called closure. + #[unstable(feature = "async_fn_traits", issue = "none")] + extern "rust-call" fn async_call_once(self, args: Args) -> Self::CallOnceFuture; +} + +mod impls { + use super::{AsyncFn, AsyncFnMut, AsyncFnOnce}; + use crate::future::Future; + use crate::marker::Tuple; + + #[unstable(feature = "async_fn_traits", issue = "none")] + impl, A: Tuple> AsyncFn for F + where + >::Output: Future, + { + type CallFuture<'a> = impl Future where Self: 'a; + + extern "rust-call" fn async_call(&self, args: A) -> Self::CallFuture<'_> { + async { self.call(args).await } + } + } + + #[unstable(feature = "async_fn_traits", issue = "none")] + impl, A: Tuple> AsyncFnMut for F + where + >::Output: Future, + { + type CallMutFuture<'a> = impl Future where Self: 'a; + + extern "rust-call" fn async_call_mut(&mut self, args: A) -> Self::CallMutFuture<'_> { + async { self.call_mut(args).await } + } + } + + #[unstable(feature = "async_fn_traits", issue = "none")] + impl, A: Tuple> AsyncFnOnce for F + where + >::Output: Future, + { + type CallOnceFuture = impl Future; + + type Output = <>::Output as Future>::Output; + + extern "rust-call" fn async_call_once(self, args: A) -> Self::CallOnceFuture { + async { self.call_once(args).await } + } + } +} diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index 35654d0b853b7..4289a86f89b06 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs @@ -139,6 +139,7 @@ #![stable(feature = "rust1", since = "1.0.0")] mod arith; +mod async_function; mod bit; mod control_flow; mod coroutine; @@ -173,6 +174,9 @@ pub use self::drop::Drop; #[stable(feature = "rust1", since = "1.0.0")] pub use self::function::{Fn, FnMut, FnOnce}; +#[unstable(feature = "async_fn_traits", issue = "none")] +pub use self::async_function::{AsyncFn, AsyncFnMut, AsyncFnOnce}; + #[stable(feature = "rust1", since = "1.0.0")] pub use self::index::{Index, IndexMut}; diff --git a/tests/ui/async-await/async-fn/simple.rs b/tests/ui/async-await/async-fn/simple.rs new file mode 100644 index 0000000000000..36d1a6d71036b --- /dev/null +++ b/tests/ui/async-await/async-fn/simple.rs @@ -0,0 +1,16 @@ +// edition: 2021 +// check-pass + +#![feature(async_fn_traits)] + +use std::ops::AsyncFn; + +async fn foo() {} + +async fn call_asyncly(f: impl AsyncFn(i32) -> i32) -> i32 { + f.async_call((1i32,)).await +} + +fn main() { + let fut = call_asyncly(|x| async move { x + 1 }); +} diff --git a/tests/ui/did_you_mean/bad-assoc-ty.stderr b/tests/ui/did_you_mean/bad-assoc-ty.stderr index 5c0c7a0b94ffe..356ddf74bb635 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 AsyncFnOnce>::Output; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | type H = <(dyn Fn(u8) -> u8 + 'static) as IntoFuture>::Output; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error[E0223]: ambiguous associated type --> $DIR/bad-assoc-ty.rs:39:19 From fde86e586dfc9826d0db81d1230aba77eb043bc6 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 20 Dec 2023 17:46:34 +0000 Subject: [PATCH 0052/1197] We do not need impl_trait_in_assoc_ty --- library/core/src/lib.rs | 1 - library/core/src/ops/async_function.rs | 12 ++++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 1cd0240b87cc6..07720f235989b 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -227,7 +227,6 @@ #![feature(fundamental)] #![feature(generic_arg_infer)] #![feature(if_let_guard)] -#![feature(impl_trait_in_assoc_type)] #![feature(inline_const)] #![feature(intra_doc_pointers)] #![feature(intrinsics)] diff --git a/library/core/src/ops/async_function.rs b/library/core/src/ops/async_function.rs index 0e05badd06df8..5e5267ed97abf 100644 --- a/library/core/src/ops/async_function.rs +++ b/library/core/src/ops/async_function.rs @@ -70,10 +70,10 @@ mod impls { where >::Output: Future, { - type CallFuture<'a> = impl Future where Self: 'a; + type CallFuture<'a> = >::Output where Self: 'a; extern "rust-call" fn async_call(&self, args: A) -> Self::CallFuture<'_> { - async { self.call(args).await } + self.call(args) } } @@ -82,10 +82,10 @@ mod impls { where >::Output: Future, { - type CallMutFuture<'a> = impl Future where Self: 'a; + type CallMutFuture<'a> = >::Output where Self: 'a; extern "rust-call" fn async_call_mut(&mut self, args: A) -> Self::CallMutFuture<'_> { - async { self.call_mut(args).await } + self.call_mut(args) } } @@ -94,12 +94,12 @@ mod impls { where >::Output: Future, { - type CallOnceFuture = impl Future; + type CallOnceFuture = >::Output; type Output = <>::Output as Future>::Output; extern "rust-call" fn async_call_once(self, args: A) -> Self::CallOnceFuture { - async { self.call_once(args).await } + self.call_once(args) } } } From 17b433351d6c9ef4fb74dae985291b4eb073c807 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 20 Dec 2023 18:03:21 +0000 Subject: [PATCH 0053/1197] select AsyncFn traits during overloaded call op --- compiler/rustc_hir/src/lang_items.rs | 4 ++++ compiler/rustc_hir_typeck/src/callee.rs | 11 +++++++++++ compiler/rustc_span/src/symbol.rs | 6 ++++++ library/core/src/ops/async_function.rs | 3 +++ tests/ui/async-await/async-fn/simple.rs | 2 +- 5 files changed, 25 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 3f3b57ba94f98..783a050742df9 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -208,6 +208,10 @@ language_item_table! { FnMut, sym::fn_mut, fn_mut_trait, Target::Trait, GenericRequirement::Exact(1); FnOnce, sym::fn_once, fn_once_trait, Target::Trait, GenericRequirement::Exact(1); + AsyncFn, sym::async_fn, async_fn_trait, Target::Trait, GenericRequirement::Exact(1); + AsyncFnMut, sym::async_fn_mut, async_fn_mut_trait, Target::Trait, GenericRequirement::Exact(1); + AsyncFnOnce, sym::async_fn_once, async_fn_once_trait, Target::Trait, GenericRequirement::Exact(1); + FnOnceOutput, sym::fn_once_output, fn_once_output, Target::AssocTy, GenericRequirement::None; Iterator, sym::iterator, iterator_trait, Target::Trait, GenericRequirement::Exact(0); diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 2146effd84f06..e464dd45124d8 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -220,6 +220,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (self.tcx.lang_items().fn_trait(), Ident::with_dummy_span(sym::call), true), (self.tcx.lang_items().fn_mut_trait(), Ident::with_dummy_span(sym::call_mut), true), (self.tcx.lang_items().fn_once_trait(), Ident::with_dummy_span(sym::call_once), false), + (self.tcx.lang_items().async_fn_trait(), Ident::with_dummy_span(sym::async_call), true), + ( + self.tcx.lang_items().async_fn_mut_trait(), + Ident::with_dummy_span(sym::async_call_mut), + true, + ), + ( + self.tcx.lang_items().async_fn_once_trait(), + Ident::with_dummy_span(sym::async_call_once), + false, + ), ] { let Some(trait_def_id) = opt_trait_def_id else { continue }; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 95106cc64c129..a123a95352032 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -423,8 +423,14 @@ symbols! { assume, assume_init, async_await, + async_call, + async_call_mut, + async_call_once, async_closure, + async_fn, async_fn_in_trait, + async_fn_mut, + async_fn_once, async_fn_track_caller, async_for_loop, async_iterator, diff --git a/library/core/src/ops/async_function.rs b/library/core/src/ops/async_function.rs index 5e5267ed97abf..965873f163eff 100644 --- a/library/core/src/ops/async_function.rs +++ b/library/core/src/ops/async_function.rs @@ -8,6 +8,7 @@ use crate::marker::Tuple; #[rustc_paren_sugar] #[fundamental] #[must_use = "async closures are lazy and do nothing unless called"] +#[cfg_attr(not(bootstrap), lang = "async_fn")] pub trait AsyncFn: AsyncFnMut { /// Future returned by [`AsyncFn::async_call`]. #[unstable(feature = "async_fn_traits", issue = "none")] @@ -27,6 +28,7 @@ pub trait AsyncFn: AsyncFnMut { #[rustc_paren_sugar] #[fundamental] #[must_use = "async closures are lazy and do nothing unless called"] +#[cfg_attr(not(bootstrap), lang = "async_fn_mut")] pub trait AsyncFnMut: AsyncFnOnce { /// Future returned by [`AsyncFnMut::async_call_mut`]. #[unstable(feature = "async_fn_traits", issue = "none")] @@ -46,6 +48,7 @@ pub trait AsyncFnMut: AsyncFnOnce { #[rustc_paren_sugar] #[fundamental] #[must_use = "async closures are lazy and do nothing unless called"] +#[cfg_attr(not(bootstrap), lang = "async_fn_once")] pub trait AsyncFnOnce { /// Future returned by [`AsyncFnOnce::async_call_once`]. #[unstable(feature = "async_fn_traits", issue = "none")] diff --git a/tests/ui/async-await/async-fn/simple.rs b/tests/ui/async-await/async-fn/simple.rs index 36d1a6d71036b..99a5d56a3093b 100644 --- a/tests/ui/async-await/async-fn/simple.rs +++ b/tests/ui/async-await/async-fn/simple.rs @@ -8,7 +8,7 @@ use std::ops::AsyncFn; async fn foo() {} async fn call_asyncly(f: impl AsyncFn(i32) -> i32) -> i32 { - f.async_call((1i32,)).await + f(1).await } fn main() { From adb6e1b69bfba1e57ba5606797848199733e0f96 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 26 Dec 2023 12:42:40 +0100 Subject: [PATCH 0054/1197] Update triagebot.toml --- triagebot.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/triagebot.toml b/triagebot.toml index 8dcfb38e097b5..6acc698ec1b1c 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -494,8 +494,8 @@ cc = ["@Nadrieril"] [mentions."library/core/src/intrinsics/simd.rs"] message = """ -Some changes occurred to the platform-builtins intrinsics. Make sure all -codegen backends as well as portable-simd get adapted for the changes. +Some changes occurred to the platform-builtins intrinsics. Make sure the +LLVM backend as well as portable-simd gets adapted for the changes. """ cc = ["@antoyo", "@GuillaumeGomez", "@bjorn3", "@calebzulawski", "@programmerjake"] From a63880c4d3a7e7620f25283999eb4a27516f4816 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 20 Nov 2023 21:55:17 +0100 Subject: [PATCH 0055/1197] PartialEq: handle longer transitive chains --- library/core/src/cmp.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index bffd3b2af971a..ba7950a709771 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -61,11 +61,13 @@ use self::Ordering::*; /// The equality relation `==` must satisfy the following conditions /// (for all `a`, `b`, `c` of type `A`, `B`, `C`): /// -/// - **Symmetric**: if `A: PartialEq` and `B: PartialEq`, then **`a == b` +/// - **Symmetry**: if `A: PartialEq` and `B: PartialEq`, then **`a == b` /// implies `b == a`**; and /// -/// - **Transitive**: if `A: PartialEq` and `B: PartialEq` and `A: +/// - **Transitivity**: if `A: PartialEq` and `B: PartialEq` and `A: /// PartialEq`, then **`a == b` and `b == c` implies `a == c`**. +/// This must also work for longer chains, such as when `A: PartialEq`, `B: PartialEq`, +/// `C: PartialEq`, and `A: PartialEq` all exist. /// /// Note that the `B: PartialEq` (symmetric) and `A: PartialEq` /// (transitive) impls are not forced to exist, but these requirements apply From 3e389ef6d50c2cae6b561a04adb9224e666eb964 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 20 Nov 2023 21:45:51 +0100 Subject: [PATCH 0056/1197] PartialOrd: transitivity and duality are required only if the corresponding impls exist --- library/core/src/cmp.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index ba7950a709771..e95410ba648b5 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -921,14 +921,18 @@ pub macro Ord($item:item) { /// easy to accidentally make them disagree by deriving some of the traits and manually /// implementing others. /// -/// The comparison must satisfy, for all `a`, `b` and `c`: +/// The comparison relations must satisfy the following conditions +/// (for all `a`, `b`, `c` of type `A`, `B`, `C`): /// -/// - transitivity: `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`. -/// - duality: `a < b` if and only if `b > a`. +/// - **Transitivity**: if `A: PartialOrd` and `B: PartialOrd` and `A: +/// PartialOrd`, then `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`. +/// This must also work for longer chains, such as when `A: PartialOrd`, `B: PartialOrd`, +/// `C: PartialOrd`, and `A: PartialOrd` all exist. +/// - **Duality**: if `A: PartialOrd` and `B: PartialOrd`, then `a < b` if and only if `b > a`. /// -/// Note that these requirements mean that the trait itself must be implemented symmetrically and -/// transitively: if `T: PartialOrd` and `U: PartialOrd` then `U: PartialOrd` and `T: -/// PartialOrd`. +/// Note that the `B: PartialOrd` (dual) and `A: PartialOrd` +/// (transitive) impls are not forced to exist, but these requirements apply +/// whenever they do exist. /// /// Violating these requirements is a logic error. The behavior resulting from a logic error is not /// specified, but users of the trait must ensure that such logic errors do *not* result in From baaf6d706ac3cb8b306ebede165706b7a0038415 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 26 Dec 2023 19:52:20 +0100 Subject: [PATCH 0057/1197] explain what crates should do when adding comparison with foreign types --- library/core/src/cmp.rs | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index e95410ba648b5..9c18d5573e627 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -78,6 +78,25 @@ use self::Ordering::*; /// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of these /// methods. /// +/// ## Cross-crate considerations +/// +/// Upholding the requirements stated above can become tricky when one crate implements `PartialEq` +/// for a type of another crate (i.e., to allow comparing one of its own types with a type from the +/// standard library). The recommendation is to never implement this trait for a foreign type. In +/// other words, such a crate should do `impl PartialEq for LocalType`, but it should +/// *not* do `impl PartialEq for ForeignType`. +/// +/// This avoids the problem of transitive chains that criss-cross crate boundaries: for all local +/// types `T`, you may assue that no other crate will add `impl`s that allow comparing `T == U`. In +/// other words, if other crates add `impl`s that allow building longer transitive chains `U1 == ... +/// == T == V1 == ...`, then all the types that appear to the right of `T` must be types that the +/// crate defining `T` already knows about. This rules out transitive chains where downstream crates +/// can add new `impl`s that "stitch together" comparisons of foreign types in ways that violate +/// transitivity. +/// +/// Not having such foreign `impl`s also avoids forward compatibility issues where one crate adding +/// more `PartialEq` implementations can cause build failures in downstream crates. +/// /// ## Derivable /// /// This trait can be used with `#[derive]`. When `derive`d on structs, two @@ -939,6 +958,25 @@ pub macro Ord($item:item) { /// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of these /// methods. /// +/// ## Cross-crate considerations +/// +/// Upholding the requirements stated above can become tricky when one crate implements `PartialOrd` +/// for a type of another crate (i.e., to allow comparing one of its own types with a type from the +/// standard library). The recommendation is to never implement this trait for a foreign type. In +/// other words, such a crate should do `impl PartialOrd for LocalType`, but it should +/// *not* do `impl PartialOrd for ForeignType`. +/// +/// This avoids the problem of transitive chains that criss-cross crate boundaries: for all local +/// types `T`, you may assue that no other crate will add `impl`s that allow comparing `T < U`. In +/// other words, if other crates add `impl`s that allow building longer transitive chains `U1 < ... +/// < T < V1 < ...`, then all the types that appear to the right of `T` must be types that the crate +/// defining `T` already knows about. This rules out transitive chains where downstream crates can +/// add new `impl`s that "stitch together" comparisons of foreign types in ways that violate +/// transitivity. +/// +/// Not having such foreign `impl`s also avoids forward compatibility issues where one crate adding +/// more `PartialOrd` implementations can cause build failures in downstream crates. +/// /// ## Corollaries /// /// The following corollaries follow from the above requirements: From 42afefa09b30bff7699275ee5ccb33b79c54d90c Mon Sep 17 00:00:00 2001 From: Sky Date: Sun, 31 Dec 2023 00:02:08 -0500 Subject: [PATCH 0058/1197] Initial implementation of `str::from_raw_parts[_mut]` --- library/core/src/str/converts.rs | 40 +++++++++++++++++++++++++++++++- library/core/src/str/mod.rs | 3 +++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs index 0f23cf7ae239f..ba282f09d2067 100644 --- a/library/core/src/str/converts.rs +++ b/library/core/src/str/converts.rs @@ -1,6 +1,6 @@ //! Ways to create a `str` from bytes slice. -use crate::mem; +use crate::{mem, ptr}; use super::validations::run_utf8_validation; use super::Utf8Error; @@ -205,3 +205,41 @@ pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { // comes from a reference which is guaranteed to be valid for writes. unsafe { &mut *(v as *mut [u8] as *mut str) } } + +/// Creates an `&str` from a pointer and a length. +/// +/// The pointed-to bytes must be valid UTF-8. +/// If this might not be the case, use `str::from_utf8(slice::from_raw_parts(ptr, len))`, +/// which will return an `Err` if the data isn't valid UTF-8. +/// +/// This function is the `str` equivalent of [`slice::from_raw_parts`](crate::slice::from_raw_parts). +/// See that function's documentation for safety concerns and examples. +/// +/// The mutable version of this function is [`from_raw_parts_mut`]. +#[inline] +#[must_use] +#[unstable(feature = "str_from_raw_parts", issue = "119206")] +#[rustc_const_unstable(feature = "str_from_raw_parts", issue = "119206")] +pub const unsafe fn from_raw_parts<'a>(ptr: *const u8, len: usize) -> &'a str { + // SAFETY: the caller must uphold the safety contract for `from_raw_parts`. + unsafe { &*ptr::from_raw_parts(ptr.cast(), len) } +} + +/// Creates an `&mut str` from a pointer and a length. +/// +/// The pointed-to bytes must be valid UTF-8. +/// If this might not be the case, use `str::from_utf8_mut(slice::from_raw_parts_mut(ptr, len))`, +/// which will return an `Err` if the data isn't valid UTF-8. +/// +/// This function is the `str` equivalent of [`slice::from_raw_parts_mut`](crate::slice::from_raw_parts_mut). +/// See that function's documentation for safety concerns and examples. +/// +/// The immutable version of this function is [`from_raw_parts`]. +#[inline] +#[must_use] +#[unstable(feature = "str_from_raw_parts", issue = "119206")] +#[rustc_const_unstable(feature = "const_str_from_raw_parts_mut", issue = "119206")] +pub const unsafe fn from_raw_parts_mut<'a>(ptr: *mut u8, len: usize) -> &'a str { + // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`. + unsafe { &mut *ptr::from_raw_parts_mut(ptr.cast(), len) } +} diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index a22c46edce254..2981d1206dd59 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -33,6 +33,9 @@ pub use converts::{from_utf8, from_utf8_unchecked}; #[stable(feature = "str_mut_extras", since = "1.20.0")] pub use converts::{from_utf8_mut, from_utf8_unchecked_mut}; +#[unstable(feature = "str_from_raw_parts", issue = "119206")] +pub use converts::{from_raw_parts, from_raw_parts_mut}; + #[stable(feature = "rust1", since = "1.0.0")] pub use error::{ParseBoolError, Utf8Error}; From 0cfbc47b9a32735659f8347872c571bdfeba8424 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 31 Dec 2023 13:29:53 +0000 Subject: [PATCH 0059/1197] Merge commit '6d355f6844323db03bfd608899613e363e701951' into sync_cg_clif-2023-12-31 --- .github/workflows/main.yml | 16 ++++++---------- .github/workflows/rustc.yml | 5 +++++ rust-toolchain | 2 +- scripts/setup_rust_fork.sh | 15 +++++++-------- src/driver/jit.rs | 2 +- src/global_asm.rs | 2 ++ 6 files changed, 22 insertions(+), 20 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 05dc28d074530..9bbb18fc37fca 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -175,14 +175,10 @@ jobs: path: build/cg_clif key: ${{ runner.os }}-x86_64-unknown-linux-gnu-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} - - name: Cache cargo bin dir - uses: actions/cache@v3 - with: - path: ~/.cargo/bin - key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-bin-dir-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} - - name: Install hyperfine - run: cargo install hyperfine || true + run: | + sudo apt update + sudo apt install -y hyperfine - name: Prepare dependencies run: ./y.sh prepare @@ -257,14 +253,14 @@ jobs: - name: Upload prebuilt cg_clif if: matrix.os == 'windows-latest' || matrix.env.TARGET_TRIPLE != 'x86_64-pc-windows-gnu' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: cg_clif-${{ matrix.env.TARGET_TRIPLE }} path: cg_clif.tar.xz - name: Upload prebuilt cg_clif (cross compile) if: matrix.os != 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: cg_clif-${{ runner.os }}-cross-x86_64-mingw path: cg_clif.tar.xz @@ -283,7 +279,7 @@ jobs: - uses: actions/checkout@v3 - name: Download all built artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: path: artifacts/ diff --git a/.github/workflows/rustc.yml b/.github/workflows/rustc.yml index cb5dd51fee310..8085dc58263cc 100644 --- a/.github/workflows/rustc.yml +++ b/.github/workflows/rustc.yml @@ -43,6 +43,11 @@ jobs: path: build/cg_clif key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} + - name: Install ripgrep + run: | + sudo apt update + sudo apt install -y ripgrep + - name: Prepare dependencies run: ./y.sh prepare diff --git a/rust-toolchain b/rust-toolchain index e1e1760c5977f..a086c0293601f 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-12-24" +channel = "nightly-2023-12-31" components = ["rust-src", "rustc-dev", "llvm-tools"] diff --git a/scripts/setup_rust_fork.sh b/scripts/setup_rust_fork.sh index 731828caae2c4..684a5d0729355 100644 --- a/scripts/setup_rust_fork.sh +++ b/scripts/setup_rust_fork.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -e -# CG_CLIF_FORCE_GNU_AS will force usage of as instead of the LLVM backend of rustc as we +# CG_CLIF_FORCE_GNU_AS will force usage of as instead of the LLVM backend of rustc as # the LLVM backend isn't compiled in here. export CG_CLIF_FORCE_GNU_AS=1 @@ -11,20 +11,19 @@ export CG_CLIF_FORCE_GNU_AS=1 CG_CLIF_STDLIB_REMAP_PATH_PREFIX=/rustc/FAKE_PREFIX ./y.sh build echo "[SETUP] Rust fork" -git clone https://github.com/rust-lang/rust.git --filter=tree:0 || true +git clone --quiet https://github.com/rust-lang/rust.git --filter=tree:0 || true pushd rust git fetch -git checkout -- . -git checkout "$(rustc -V | cut -d' ' -f3 | tr -d '(')" +git checkout --no-progress -- . +git checkout --no-progress "$(rustc -V | cut -d' ' -f3 | tr -d '(')" + +git submodule update --quiet --init src/tools/cargo library/backtrace library/stdarch git -c user.name=Dummy -c user.email=dummy@example.com -c commit.gpgSign=false \ am ../patches/*-stdlib-*.patch cat > config.toml < {} Linkage::Static => { let name = crate_info.crate_name[&cnum]; - let mut err = sess.struct_err(format!("Can't load static lib {}", name)); + let mut err = sess.dcx().struct_err(format!("Can't load static lib {}", name)); err.note("rustc_codegen_cranelift can only load dylibs in JIT mode."); err.emit(); } diff --git a/src/global_asm.rs b/src/global_asm.rs index af99239d81593..da07b66c762ee 100644 --- a/src/global_asm.rs +++ b/src/global_asm.rs @@ -154,6 +154,8 @@ pub(crate) fn compile_global_asm( } } else { let mut child = Command::new(std::env::current_exe().unwrap()) + // Avoid a warning about the jobserver fd not being passed + .env_remove("CARGO_MAKEFLAGS") .arg("--target") .arg(&config.target) .arg("--crate-type") From 7ac4515dde285decf97985107f154bf9e08b4a7e Mon Sep 17 00:00:00 2001 From: Brian Romanowski Date: Sun, 31 Dec 2023 15:09:32 -0600 Subject: [PATCH 0060/1197] Clarify ambiguity in select_nth_unstable docs --- library/core/src/slice/mod.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index b14d9712794bc..7882ddcdc3064 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -3047,7 +3047,7 @@ impl [T] { sort::quicksort(self, |a, b| f(a).lt(&f(b))); } - /// Reorder the slice such that the element at `index` is at its final sorted position. + /// Reorder the slice such that the element at `index` after the reordering is at its final sorted position. /// /// This reordering has the additional property that any value at position `i < index` will be /// less than or equal to any value at a position `j > index`. Additionally, this reordering is @@ -3075,7 +3075,7 @@ impl [T] { /// # Examples /// /// ``` - /// let mut v = [-5i32, 4, 1, -3, 2]; + /// let mut v = [-5i32, 4, 2, -3, 1]; /// /// // Find the median /// v.select_nth_unstable(2); @@ -3096,8 +3096,8 @@ impl [T] { select::partition_at_index(self, index, T::lt) } - /// Reorder the slice with a comparator function such that the element at `index` is at its - /// final sorted position. + /// Reorder the slice with a comparator function such that the element at `index` after the reordering is at + /// its final sorted position. /// /// This reordering has the additional property that any value at position `i < index` will be /// less than or equal to any value at a position `j > index` using the comparator function. @@ -3126,7 +3126,7 @@ impl [T] { /// # Examples /// /// ``` - /// let mut v = [-5i32, 4, 1, -3, 2]; + /// let mut v = [-5i32, 4, 2, -3, 1]; /// /// // Find the median as if the slice were sorted in descending order. /// v.select_nth_unstable_by(2, |a, b| b.cmp(a)); @@ -3151,8 +3151,8 @@ impl [T] { select::partition_at_index(self, index, |a: &T, b: &T| compare(a, b) == Less) } - /// Reorder the slice with a key extraction function such that the element at `index` is at its - /// final sorted position. + /// Reorder the slice with a key extraction function such that the element at `index` after the reordering is + /// at its final sorted position. /// /// This reordering has the additional property that any value at position `i < index` will be /// less than or equal to any value at a position `j > index` using the key extraction function. From 543d56938e23865eb70b49f153c71a2057668c79 Mon Sep 17 00:00:00 2001 From: Aneesh Kadiyala <143342960+ARandomDev99@users.noreply.github.com> Date: Tue, 2 Jan 2024 11:30:20 +0530 Subject: [PATCH 0061/1197] Make `HirEqInterExpr::eq_block` take comments into account This commit: - now makes `HirEqInterExpr::eq_block` take comments into account. Identical code with varying comments will no longer be considered equal. - makes necessary adjustments to UI tests. --- clippy_utils/src/hir_utils.rs | 6 +- .../ui/branches_sharing_code/shared_at_top.rs | 8 +-- .../shared_at_top.stderr | 6 +- .../branches_sharing_code/valid_if_blocks.rs | 12 ++-- .../valid_if_blocks.stderr | 18 ++--- tests/ui/if_same_then_else.rs | 28 +++----- tests/ui/if_same_then_else.stderr | 69 +++++++------------ tests/ui/if_same_then_else2.rs | 18 ++--- tests/ui/if_same_then_else2.stderr | 37 ++++------ tests/ui/match_same_arms2.rs | 4 +- tests/ui/match_same_arms2.stderr | 5 +- 11 files changed, 73 insertions(+), 138 deletions(-) diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index e610ed930505b..ea8d3631b0d27 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -134,7 +134,7 @@ impl HirEqInterExpr<'_, '_, '_> { /// Checks whether two blocks are the same. #[expect(clippy::similar_names)] fn eq_block(&mut self, left: &Block<'_>, right: &Block<'_>) -> bool { - use TokenKind::{BlockComment, LineComment, Semi, Whitespace}; + use TokenKind::{Semi, Whitespace}; if left.stmts.len() != right.stmts.len() { return false; } @@ -177,7 +177,7 @@ impl HirEqInterExpr<'_, '_, '_> { return false; } if !eq_span_tokens(self.inner.cx, lstart..lstmt_span.lo, rstart..rstmt_span.lo, |t| { - !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. } | Semi) + !matches!(t, Whitespace | Semi) }) { return false; } @@ -212,7 +212,7 @@ impl HirEqInterExpr<'_, '_, '_> { return false; } eq_span_tokens(self.inner.cx, lstart..lend, rstart..rend, |t| { - !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. } | Semi) + !matches!(t, Whitespace | Semi) }) } diff --git a/tests/ui/branches_sharing_code/shared_at_top.rs b/tests/ui/branches_sharing_code/shared_at_top.rs index 44f8b2eabce3b..9af81f6f7cdda 100644 --- a/tests/ui/branches_sharing_code/shared_at_top.rs +++ b/tests/ui/branches_sharing_code/shared_at_top.rs @@ -9,17 +9,16 @@ fn simple_examples() { // Simple if true { - //~^ ERROR: all if blocks contain the same code at the start println!("Hello World!"); println!("I'm branch nr: 1"); } else { println!("Hello World!"); println!("I'm branch nr: 2"); } + //~^^^^^^^ ERROR: all if blocks contain the same code at the start // Else if if x == 0 { - //~^ ERROR: all if blocks contain the same code at the start let y = 9; println!("The value y was set to: `{}`", y); let _z = y; @@ -38,6 +37,7 @@ fn simple_examples() { println!("Ha, Pascal allows you to start the array where you want") } + //~^^^^^^^^^^^^^^^^^^^ ERROR: all if blocks contain the same code at the start // Return a value let _ = if x == 7 { @@ -60,7 +60,6 @@ fn simple_but_suggestion_is_invalid() { // Can't be automatically moved because used_value_name is getting used again let used_value_name = 19; if x == 10 { - //~^ ERROR: all if blocks contain the same code at the start let used_value_name = "Different type"; println!("Str: {}", used_value_name); let _ = 1; @@ -69,6 +68,7 @@ fn simple_but_suggestion_is_invalid() { println!("Str: {}", used_value_name); let _ = 2; } + //~^^^^^^^^^ ERROR: all if blocks contain the same code at the start let _ = used_value_name; // This can be automatically moved as `can_be_overridden` is not used again @@ -101,11 +101,11 @@ fn check_if_same_than_else_mask() { } if x == 2019 { - //~^ ERROR: this `if` has identical blocks println!("This should trigger `IS_SAME_THAN_ELSE` as usual"); } else { println!("This should trigger `IS_SAME_THAN_ELSE` as usual"); } + //~^^^^^ ERROR: this `if` has identical blocks } #[allow(clippy::vec_init_then_push)] diff --git a/tests/ui/branches_sharing_code/shared_at_top.stderr b/tests/ui/branches_sharing_code/shared_at_top.stderr index 9d4d42fb689e4..317d1577226ca 100644 --- a/tests/ui/branches_sharing_code/shared_at_top.stderr +++ b/tests/ui/branches_sharing_code/shared_at_top.stderr @@ -2,7 +2,6 @@ error: all if blocks contain the same code at the start --> $DIR/shared_at_top.rs:11:5 | LL | / if true { -LL | | LL | | println!("Hello World!"); | |_________________________________^ | @@ -21,7 +20,6 @@ error: all if blocks contain the same code at the start --> $DIR/shared_at_top.rs:21:5 | LL | / if x == 0 { -LL | | LL | | let y = 9; LL | | println!("The value y was set to: `{}`", y); LL | | let _z = y; @@ -54,7 +52,6 @@ error: all if blocks contain the same code at the start --> $DIR/shared_at_top.rs:62:5 | LL | / if x == 10 { -LL | | LL | | let used_value_name = "Different type"; LL | | println!("Str: {}", used_value_name); | |_____________________________________________^ @@ -105,13 +102,12 @@ error: this `if` has identical blocks | LL | if x == 2019 { | __________________^ -LL | | LL | | println!("This should trigger `IS_SAME_THAN_ELSE` as usual"); LL | | } else { | |_____^ | note: same as this - --> $DIR/shared_at_top.rs:106:12 + --> $DIR/shared_at_top.rs:105:12 | LL | } else { | ____________^ diff --git a/tests/ui/branches_sharing_code/valid_if_blocks.rs b/tests/ui/branches_sharing_code/valid_if_blocks.rs index 2aeacb89c0cb6..b63819d7c3932 100644 --- a/tests/ui/branches_sharing_code/valid_if_blocks.rs +++ b/tests/ui/branches_sharing_code/valid_if_blocks.rs @@ -107,9 +107,9 @@ fn valid_examples() { // Let's test empty blocks if false { - //~^ ERROR: this `if` has identical blocks } else { } + //~^^^ ERROR: this `if` has identical blocks } /// This makes sure that the `if_same_then_else` masks the `shared_code_in_if_blocks` lint @@ -119,7 +119,6 @@ fn trigger_other_lint() { // Same block if x == 0 { - //~^ ERROR: this `if` has identical blocks let u = 19; println!("How are u today?"); let _ = "This is a string"; @@ -128,6 +127,7 @@ fn trigger_other_lint() { println!("How are u today?"); let _ = "This is a string"; } + //~^^^^^^^^^ ERROR: this `if` has identical blocks // Only same expression let _ = if x == 6 { 7 } else { 7 }; @@ -138,28 +138,24 @@ fn trigger_other_lint() { println!("Well I'm the most important block"); "I'm a pretty string" } else if x == 68 { - //~^ ERROR: this `if` has identical blocks println!("I'm a doppelgänger"); - // Don't listen to my clone below if y == 90 { "=^.^=" } else { ":D" } } else { - // Don't listen to my clone above println!("I'm a doppelgänger"); if y == 90 { "=^.^=" } else { ":D" } }; + //~^^^^^^^^^ ERROR: this `if` has identical blocks if x == 0 { println!("I'm single"); } else if x == 68 { - //~^ ERROR: this `if` has identical blocks println!("I'm a doppelgänger"); - // Don't listen to my clone below } else { - // Don't listen to my clone above println!("I'm a doppelgänger"); } + //~^^^^^ ERROR: this `if` has identical blocks } fn main() {} diff --git a/tests/ui/branches_sharing_code/valid_if_blocks.stderr b/tests/ui/branches_sharing_code/valid_if_blocks.stderr index fcbf12235aa16..0daf2ff6967cd 100644 --- a/tests/ui/branches_sharing_code/valid_if_blocks.stderr +++ b/tests/ui/branches_sharing_code/valid_if_blocks.stderr @@ -3,12 +3,11 @@ error: this `if` has identical blocks | LL | if false { | ______________^ -LL | | LL | | } else { | |_____^ | note: same as this - --> $DIR/valid_if_blocks.rs:111:12 + --> $DIR/valid_if_blocks.rs:110:12 | LL | } else { | ____________^ @@ -25,7 +24,6 @@ error: this `if` has identical blocks | LL | if x == 0 { | _______________^ -LL | | LL | | let u = 19; LL | | println!("How are u today?"); LL | | let _ = "This is a string"; @@ -33,7 +31,7 @@ LL | | } else { | |_____^ | note: same as this - --> $DIR/valid_if_blocks.rs:126:12 + --> $DIR/valid_if_blocks.rs:125:12 | LL | } else { | ____________^ @@ -60,20 +58,17 @@ error: this `if` has identical blocks | LL | } else if x == 68 { | _______________________^ -LL | | LL | | println!("I'm a doppelgänger"); -LL | | // Don't listen to my clone below LL | | LL | | if y == 90 { "=^.^=" } else { ":D" } LL | | } else { | |_____^ | note: same as this - --> $DIR/valid_if_blocks.rs:146:12 + --> $DIR/valid_if_blocks.rs:144:12 | LL | } else { | ____________^ -LL | | // Don't listen to my clone above LL | | println!("I'm a doppelgänger"); LL | | LL | | if y == 90 { "=^.^=" } else { ":D" } @@ -81,22 +76,19 @@ LL | | }; | |_____^ error: this `if` has identical blocks - --> $DIR/valid_if_blocks.rs:155:23 + --> $DIR/valid_if_blocks.rs:153:23 | LL | } else if x == 68 { | _______________________^ -LL | | LL | | println!("I'm a doppelgänger"); -LL | | // Don't listen to my clone below LL | | } else { | |_____^ | note: same as this - --> $DIR/valid_if_blocks.rs:159:12 + --> $DIR/valid_if_blocks.rs:155:12 | LL | } else { | ____________^ -LL | | // Don't listen to my clone above LL | | println!("I'm a doppelgänger"); LL | | } | |_____^ diff --git a/tests/ui/if_same_then_else.rs b/tests/ui/if_same_then_else.rs index e84b20e9fef07..d53e1383d845c 100644 --- a/tests/ui/if_same_then_else.rs +++ b/tests/ui/if_same_then_else.rs @@ -21,7 +21,6 @@ fn foo() -> bool { fn if_same_then_else() { if true { - //~^ ERROR: this `if` has identical blocks Foo { bar: 42 }; 0..10; ..; @@ -38,6 +37,7 @@ fn if_same_then_else() { 0..=10; foo(); } + //~^^^^^^^^^^^^^^^^^ ERROR: this `if` has identical blocks if true { Foo { bar: 42 }; @@ -64,19 +64,11 @@ fn if_same_then_else() { foo(); } - let _ = if true { - //~^ ERROR: this `if` has identical blocks - 0.0 - } else { - 0.0 - }; + let _ = if true { 0.0 } else { 0.0 }; + //~^ ERROR: this `if` has identical blocks - let _ = if true { - //~^ ERROR: this `if` has identical blocks - -0.0 - } else { - -0.0 - }; + let _ = if true { -0.0 } else { -0.0 }; + //~^ ERROR: this `if` has identical blocks let _ = if true { 0.0 } else { -0.0 }; @@ -87,15 +79,10 @@ fn if_same_then_else() { foo(); } - let _ = if true { - //~^ ERROR: this `if` has identical blocks - 42 - } else { - 42 - }; + let _ = if true { 42 } else { 42 }; + //~^ ERROR: this `if` has identical blocks if true { - //~^ ERROR: this `if` has identical blocks let bar = if true { 42 } else { 43 }; while foo() { @@ -110,6 +97,7 @@ fn if_same_then_else() { } bar + 1; } + //~^^^^^^^^^^^^^^^ ERROR: this `if` has identical blocks if true { let _ = match 42 { diff --git a/tests/ui/if_same_then_else.stderr b/tests/ui/if_same_then_else.stderr index fb33e94e6c3de..281f30f88b46d 100644 --- a/tests/ui/if_same_then_else.stderr +++ b/tests/ui/if_same_then_else.stderr @@ -3,16 +3,16 @@ error: this `if` has identical blocks | LL | if true { | _____________^ -LL | | LL | | Foo { bar: 42 }; LL | | 0..10; +LL | | ..; ... | LL | | foo(); LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else.rs:32:12 + --> $DIR/if_same_then_else.rs:31:12 | LL | } else { | ____________^ @@ -29,75 +29,54 @@ LL | | } error: this `if` has identical blocks --> $DIR/if_same_then_else.rs:67:21 | -LL | let _ = if true { - | _____________________^ -LL | | -LL | | 0.0 -LL | | } else { - | |_____^ +LL | let _ = if true { 0.0 } else { 0.0 }; + | ^^^^^^^ | note: same as this - --> $DIR/if_same_then_else.rs:70:12 + --> $DIR/if_same_then_else.rs:67:34 | -LL | } else { - | ____________^ -LL | | 0.0 -LL | | }; - | |_____^ +LL | let _ = if true { 0.0 } else { 0.0 }; + | ^^^^^^^ error: this `if` has identical blocks - --> $DIR/if_same_then_else.rs:74:21 + --> $DIR/if_same_then_else.rs:70:21 | -LL | let _ = if true { - | _____________________^ -LL | | -LL | | -0.0 -LL | | } else { - | |_____^ +LL | let _ = if true { -0.0 } else { -0.0 }; + | ^^^^^^^^ | note: same as this - --> $DIR/if_same_then_else.rs:77:12 + --> $DIR/if_same_then_else.rs:70:35 | -LL | } else { - | ____________^ -LL | | -0.0 -LL | | }; - | |_____^ +LL | let _ = if true { -0.0 } else { -0.0 }; + | ^^^^^^^^ error: this `if` has identical blocks - --> $DIR/if_same_then_else.rs:90:21 + --> $DIR/if_same_then_else.rs:82:21 | -LL | let _ = if true { - | _____________________^ -LL | | -LL | | 42 -LL | | } else { - | |_____^ +LL | let _ = if true { 42 } else { 42 }; + | ^^^^^^ | note: same as this - --> $DIR/if_same_then_else.rs:93:12 + --> $DIR/if_same_then_else.rs:82:33 | -LL | } else { - | ____________^ -LL | | 42 -LL | | }; - | |_____^ +LL | let _ = if true { 42 } else { 42 }; + | ^^^^^^ error: this `if` has identical blocks - --> $DIR/if_same_then_else.rs:97:13 + --> $DIR/if_same_then_else.rs:85:13 | LL | if true { | _____________^ -LL | | LL | | let bar = if true { 42 } else { 43 }; LL | | +LL | | while foo() { ... | LL | | bar + 1; LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else.rs:105:12 + --> $DIR/if_same_then_else.rs:92:12 | LL | } else { | ____________^ @@ -110,7 +89,7 @@ LL | | } | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else.rs:250:14 + --> $DIR/if_same_then_else.rs:238:14 | LL | if x { | ______________^ @@ -119,7 +98,7 @@ LL | | } else { | |_________^ | note: same as this - --> $DIR/if_same_then_else.rs:252:16 + --> $DIR/if_same_then_else.rs:240:16 | LL | } else { | ________________^ diff --git a/tests/ui/if_same_then_else2.rs b/tests/ui/if_same_then_else2.rs index 0b171f21d0cc4..e23c77b082744 100644 --- a/tests/ui/if_same_then_else2.rs +++ b/tests/ui/if_same_then_else2.rs @@ -13,7 +13,6 @@ fn if_same_then_else2() -> Result<&'static str, ()> { if true { - //~^ ERROR: this `if` has identical blocks for _ in &[42] { let foo: &Option<_> = &Some::(42); if foo.is_some() { @@ -32,20 +31,21 @@ fn if_same_then_else2() -> Result<&'static str, ()> { } } } + //~^^^^^^^^^^^^^^^^^^^ ERROR: this `if` has identical blocks if true { - //~^ ERROR: this `if` has identical blocks if let Some(a) = Some(42) {} } else { if let Some(a) = Some(42) {} } + //~^^^^^ ERROR: this `if` has identical blocks if true { - //~^ ERROR: this `if` has identical blocks if let (1, .., 3) = (1, 2, 3) {} } else { if let (1, .., 3) = (1, 2, 3) {} } + //~^^^^^ ERROR: this `if` has identical blocks if true { if let (1, .., 3) = (1, 2, 3) {} @@ -90,19 +90,15 @@ fn if_same_then_else2() -> Result<&'static str, ()> { } // Same NaNs - let _ = if true { - //~^ ERROR: this `if` has identical blocks - f32::NAN - } else { - f32::NAN - }; + let _ = if true { f32::NAN } else { f32::NAN }; + //~^ ERROR: this `if` has identical blocks if true { - //~^ ERROR: this `if` has identical blocks Ok("foo")?; } else { Ok("foo")?; } + //~^^^^^ ERROR: this `if` has identical blocks if true { let foo = ""; @@ -122,13 +118,13 @@ fn if_same_then_else2() -> Result<&'static str, ()> { let foo = "bar"; return Ok(&foo[0..]); } else if true { - //~^ ERROR: this `if` has identical blocks let foo = ""; return Ok(&foo[0..]); } else { let foo = ""; return Ok(&foo[0..]); } + //~^^^^^^^ ERROR: this `if` has identical blocks // False positive `if_same_then_else`: `let (x, y)` vs. `let (y, x)`; see issue #3559. if true { diff --git a/tests/ui/if_same_then_else2.stderr b/tests/ui/if_same_then_else2.stderr index fe68ef2711b59..4e7a7c87dc54b 100644 --- a/tests/ui/if_same_then_else2.stderr +++ b/tests/ui/if_same_then_else2.stderr @@ -3,16 +3,16 @@ error: this `if` has identical blocks | LL | if true { | _____________^ -LL | | LL | | for _ in &[42] { LL | | let foo: &Option<_> = &Some::(42); +LL | | if foo.is_some() { ... | LL | | } LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:25:12 + --> $DIR/if_same_then_else2.rs:24:12 | LL | } else { | ____________^ @@ -31,13 +31,12 @@ error: this `if` has identical blocks | LL | if true { | _____________^ -LL | | LL | | if let Some(a) = Some(42) {} LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:39:12 + --> $DIR/if_same_then_else2.rs:38:12 | LL | } else { | ____________^ @@ -50,13 +49,12 @@ error: this `if` has identical blocks | LL | if true { | _____________^ -LL | | LL | | if let (1, .., 3) = (1, 2, 3) {} LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:46:12 + --> $DIR/if_same_then_else2.rs:45:12 | LL | } else { | ____________^ @@ -67,34 +65,26 @@ LL | | } error: this `if` has identical blocks --> $DIR/if_same_then_else2.rs:93:21 | -LL | let _ = if true { - | _____________________^ -LL | | -LL | | f32::NAN -LL | | } else { - | |_____^ +LL | let _ = if true { f32::NAN } else { f32::NAN }; + | ^^^^^^^^^^^^ | note: same as this - --> $DIR/if_same_then_else2.rs:96:12 + --> $DIR/if_same_then_else2.rs:93:39 | -LL | } else { - | ____________^ -LL | | f32::NAN -LL | | }; - | |_____^ +LL | let _ = if true { f32::NAN } else { f32::NAN }; + | ^^^^^^^^^^^^ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:100:13 + --> $DIR/if_same_then_else2.rs:96:13 | LL | if true { | _____________^ -LL | | LL | | Ok("foo")?; LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:103:12 + --> $DIR/if_same_then_else2.rs:98:12 | LL | } else { | ____________^ @@ -103,18 +93,17 @@ LL | | } | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:124:20 + --> $DIR/if_same_then_else2.rs:120:20 | LL | } else if true { | ____________________^ -LL | | LL | | let foo = ""; LL | | return Ok(&foo[0..]); LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:128:12 + --> $DIR/if_same_then_else2.rs:123:12 | LL | } else { | ____________^ diff --git a/tests/ui/match_same_arms2.rs b/tests/ui/match_same_arms2.rs index 525a355f40355..3428ff4590602 100644 --- a/tests/ui/match_same_arms2.rs +++ b/tests/ui/match_same_arms2.rs @@ -13,7 +13,6 @@ fn foo() -> bool { fn match_same_arms() { let _ = match 42 { 42 => { - //~^ ERROR: this match arm has an identical body to the `_` wildcard arm foo(); let mut a = 42 + [23].len() as i32; if true { @@ -32,6 +31,7 @@ fn match_same_arms() { a }, }; + //~^^^^^^^^^^^^^^^^^^^ ERROR: this match arm has an identical body to the `_` wildcard arm let _ = match 42 { 42 => foo(), @@ -146,13 +146,13 @@ fn match_same_arms() { empty!(0); }, 1 => { - //~^ ERROR: this match arm has an identical body to another arm empty!(0); }, x => { empty!(x); }, } + //~^^^^^^^ ERROR: this match arm has an identical body to another arm match_expr_like_matches_macro_priority(); } diff --git a/tests/ui/match_same_arms2.stderr b/tests/ui/match_same_arms2.stderr index 40b20c7e16d28..512ca7413a795 100644 --- a/tests/ui/match_same_arms2.stderr +++ b/tests/ui/match_same_arms2.stderr @@ -2,9 +2,9 @@ error: this match arm has an identical body to the `_` wildcard arm --> $DIR/match_same_arms2.rs:15:9 | LL | / 42 => { -LL | | LL | | foo(); LL | | let mut a = 42 + [23].len() as i32; +LL | | if true { ... | LL | | a LL | | }, @@ -12,7 +12,7 @@ LL | | }, | = help: or try changing either arm body note: `_` wildcard arm here - --> $DIR/match_same_arms2.rs:25:9 + --> $DIR/match_same_arms2.rs:24:9 | LL | / _ => { LL | | foo(); @@ -122,7 +122,6 @@ LL | 1 => { | ^ help: try merging the arm patterns: `1 | 0` | _________| | | -LL | | LL | | empty!(0); LL | | }, | |_________^ From c427754b52415a1fb11c83aa278b5fec21146b27 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 2 Jan 2024 20:39:31 +0000 Subject: [PATCH 0062/1197] Add platform support matrix Fixes rust-lang/rustc_codegen_cranelift#1441 --- Readme.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Readme.md b/Readme.md index ca6ecdf1d0e88..1c48097da2aae 100644 --- a/Readme.md +++ b/Readme.md @@ -62,6 +62,27 @@ $ ./test.sh For more docs on how to build and test see [build_system/usage.txt](build_system/usage.txt) or the help message of `./y.sh`. +## Platform support + +|OS \ architecture|x86\_64|AArch64|Riscv64|s390x (System-Z)| +|---|---|---|---|---| +|Linux|✅|✅|✅[^no-rustup]|✅[^no-rustup]| +|FreeBSD|✅[^no-rustup]|❓|❓|❓| +|AIX|❌[^xcoff]|N/A|N/A|❌[^xcoff]| +|Other unixes|❓|❓|❓|❓| +|macOS|✅|❌[^apple-silicon]|N/A|N/A| +|Windows|✅[^no-rustup]|❌|N/A|N/A| + +✅: Fully supported and tested +❓: Maybe supported, not tested +❌: Not supported at all + +Not all targets are available as rustup component for nightly. See notes in the platform support matrix. + +[^xcoff]: XCOFF object file format is not supported. +[^apple-silicon]: Tracked in [#1248](https://github.com/rust-lang/rustc_codegen_cranelift/issues/1248). +[^no-rustup]: Not available as rustup component for nightly. You can build it yourself. + ## Usage rustc_codegen_cranelift can be used as a near-drop-in replacement for `cargo build` or `cargo run` for existing projects. From 45d8c121ba02c825379b655d8dd74e1843e98d62 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 2 Jan 2024 21:17:00 +0000 Subject: [PATCH 0063/1197] Return architecturally mandated target features to rustc In the future the actual target features that Cranelift enables should be returned here, but for now this works. Fixes rust-lang/rustc_codegen_cranelift#1438 --- src/lib.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b482f0dd2f0ab..f327577eb4d32 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,7 +42,7 @@ use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_session::config::OutputFilenames; use rustc_session::Session; -use rustc_span::Symbol; +use rustc_span::{sym, Symbol}; pub use crate::config::*; use crate::prelude::*; @@ -190,8 +190,17 @@ impl CodegenBackend for CraneliftCodegenBackend { } } - fn target_features(&self, _sess: &Session, _allow_unstable: bool) -> Vec { - vec![] // FIXME necessary for #[cfg(target_feature] + fn target_features(&self, sess: &Session, _allow_unstable: bool) -> Vec { + // FIXME return the actually used target features. this is necessary for #[cfg(target_feature)] + if sess.target.arch == "x86_64" && sess.target.os != "none" { + // x86_64 mandates SSE2 support + vec![Symbol::intern("fxsr"), sym::sse, Symbol::intern("sse2")] + } else if sess.target.arch == "aarch64" && sess.target.os != "none" { + // AArch64 mandates Neon support + vec![sym::neon] + } else { + vec![] + } } fn print_version(&self) { From 3b8794edf4b930c3de435cdc436f00e7b9e72cf8 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 3 Jan 2024 11:08:32 +0000 Subject: [PATCH 0064/1197] Fix xmm operands in inline assembly --- src/inline_asm.rs | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/src/inline_asm.rs b/src/inline_asm.rs index 6b9cec39d7020..1d0d7ee75de2f 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -506,10 +506,34 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { if self.options.contains(InlineAsmOptions::ATT_SYNTAX) { generated_asm.push('%'); } - self.registers[*operand_idx] - .unwrap() - .emit(&mut generated_asm, self.arch, *modifier) - .unwrap(); + + let reg = self.registers[*operand_idx].unwrap(); + match self.arch { + InlineAsmArch::X86_64 => match reg { + InlineAsmReg::X86(reg) + if reg as u32 >= X86InlineAsmReg::xmm0 as u32 + && reg as u32 <= X86InlineAsmReg::xmm15 as u32 => + { + // rustc emits x0 rather than xmm0 + let class = match *modifier { + None | Some('x') => "xmm", + Some('y') => "ymm", + Some('z') => "zmm", + _ => unreachable!(), + }; + write!( + generated_asm, + "{class}{}", + reg as u32 - X86InlineAsmReg::xmm0 as u32 + ) + .unwrap(); + } + _ => reg + .emit(&mut generated_asm, InlineAsmArch::X86_64, *modifier) + .unwrap(), + }, + _ => reg.emit(&mut generated_asm, self.arch, *modifier).unwrap(), + } } CInlineAsmOperand::Const { ref value } => { generated_asm.push_str(value); From c8f5d35508e062bd2d95e6c03429bfec831db6d3 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Tue, 2 Jan 2024 22:18:00 +0100 Subject: [PATCH 0065/1197] Restructure x86 signed pack instructions This reduces the amount of duplicated code and the chance for bugs. I validated the new code for correctness against LLVM using the following script. It found many bugs in the implementation until I was finally able to get it correct and passing. ```rust //! Test for x86 pack instructions. Prints deterministic results, use it to compare backends. use std::arch::x86_64::{self, __m128i, __m256i}; use rand::{rngs::SmallRng, Rng, SeedableRng}; fn main() { let rng = &mut SmallRng::seed_from_u64(123); for _ in 0..100_000 { unsafe { sse_test(rng); avx_test(rng); } } } unsafe fn sse_test(rng: &mut SmallRng) { print_sse_8(x86_64::_mm_packus_epi16(sse16(rng), sse16(rng))); print_sse_8(x86_64::_mm_packs_epi16(sse16(rng), sse16(rng))); print_sse_16(x86_64::_mm_packus_epi32(sse32(rng), sse32(rng))); print_sse_16(x86_64::_mm_packs_epi32(sse32(rng), sse32(rng))); } unsafe fn avx_test(rng: &mut SmallRng) { print_avx_8(x86_64::_mm256_packs_epi16(avx16(rng), avx16(rng))); print_avx_8(x86_64::_mm256_packs_epi16(avx16(rng), avx16(rng))); print_avx_16(x86_64::_mm256_packus_epi32(avx32(rng), avx32(rng))); print_avx_16(x86_64::_mm256_packs_epi32(avx32(rng), avx32(rng))); } fn print_sse_8(t: __m128i) { let ints = unsafe { std::mem::transmute::<_, [i8; 16]>(t) }; println!("{ints:?}"); } fn print_sse_16(t: __m128i) { let ints = unsafe { std::mem::transmute::<_, [i16; 8]>(t) }; println!("{ints:?}"); } fn print_avx_8(t: __m256i) { let ints = unsafe { std::mem::transmute::<_, [i8; 32]>(t) }; println!("{ints:?}"); } fn print_avx_16(t: __m256i) { let ints = unsafe { std::mem::transmute::<_, [i16; 16]>(t) }; println!("{ints:?}"); } fn sse16(rand: &mut SmallRng) -> __m128i { unsafe { std::mem::transmute([(); 8].map(|()| i16(rand))) } } fn sse32(rand: &mut SmallRng) -> __m128i { unsafe { std::mem::transmute([(); 4].map(|()| i32(rand))) } } fn avx16(rand: &mut SmallRng) -> __m256i { unsafe { std::mem::transmute([(); 16].map(|()| i16(rand))) } } fn avx32(rand: &mut SmallRng) -> __m256i { unsafe { std::mem::transmute([(); 8].map(|()| i32(rand))) } } fn i16(rand: &mut SmallRng) -> i16 { if rand.gen() { rand.gen::() } else { rand.gen::() as i16 } } fn i32(rand: &mut SmallRng) -> i32 { if rand.gen() { rand.gen::() } else { rand.gen::() as i32 } } ``` --- src/intrinsics/llvm_x86.rs | 328 +++++++++++++++---------------------- 1 file changed, 132 insertions(+), 196 deletions(-) diff --git a/src/intrinsics/llvm_x86.rs b/src/intrinsics/llvm_x86.rs index 81114cbf40d83..445622fc539bc 100644 --- a/src/intrinsics/llvm_x86.rs +++ b/src/intrinsics/llvm_x86.rs @@ -610,230 +610,56 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_packus_epi16&ig_expand=4903 intrinsic_args!(fx, args => (a, b); intrinsic); - assert_eq!(a.layout(), b.layout()); - let layout = a.layout(); - - let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx); - let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); - assert_eq!(lane_ty, fx.tcx.types.i16); - assert_eq!(ret_lane_ty, fx.tcx.types.u8); - assert_eq!(lane_count * 2, ret_lane_count); - - let zero = fx.bcx.ins().iconst(types::I16, 0); - let max_u8 = fx.bcx.ins().iconst(types::I16, 255); - let ret_lane_layout = fx.layout_of(fx.tcx.types.u8); - - for idx in 0..lane_count { - let lane = a.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, zero); - let sat = fx.bcx.ins().umin(sat, max_u8); - let res = fx.bcx.ins().ireduce(types::I8, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, idx).write_cvalue(fx, res_lane); - } + pack_instruction(fx, a, b, ret, PackSize::U8, PackWidth::Sse); + } - for idx in 0..lane_count { - let lane = b.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, zero); - let sat = fx.bcx.ins().umin(sat, max_u8); - let res = fx.bcx.ins().ireduce(types::I8, sat); + "llvm.x86.sse2.packsswb.128" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_packs_epi16&ig_expand=4848 + intrinsic_args!(fx, args => (a, b); intrinsic); - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, lane_count + idx).write_cvalue(fx, res_lane); - } + pack_instruction(fx, a, b, ret, PackSize::S8, PackWidth::Sse); } "llvm.x86.avx2.packuswb" => { // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_packus_epi16&ig_expand=4906 intrinsic_args!(fx, args => (a, b); intrinsic); - assert_eq!(a.layout(), b.layout()); - let layout = a.layout(); - - let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx); - let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); - assert_eq!(lane_ty, fx.tcx.types.i16); - assert_eq!(ret_lane_ty, fx.tcx.types.u8); - assert_eq!(lane_count * 2, ret_lane_count); - - let zero = fx.bcx.ins().iconst(types::I16, 0); - let max_u8 = fx.bcx.ins().iconst(types::I16, 255); - let ret_lane_layout = fx.layout_of(fx.tcx.types.u8); - - for idx in 0..lane_count / 2 { - let lane = a.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, zero); - let sat = fx.bcx.ins().umin(sat, max_u8); - let res = fx.bcx.ins().ireduce(types::I8, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, idx).write_cvalue(fx, res_lane); - } - - for idx in 0..lane_count / 2 { - let lane = b.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, zero); - let sat = fx.bcx.ins().umin(sat, max_u8); - let res = fx.bcx.ins().ireduce(types::I8, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, lane_count / 2 + idx).write_cvalue(fx, res_lane); - } - - for idx in 0..lane_count / 2 { - let lane = a.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, zero); - let sat = fx.bcx.ins().umin(sat, max_u8); - let res = fx.bcx.ins().ireduce(types::I8, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, lane_count / 2 * 2 + idx).write_cvalue(fx, res_lane); - } - - for idx in 0..lane_count / 2 { - let lane = b.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, zero); - let sat = fx.bcx.ins().umin(sat, max_u8); - let res = fx.bcx.ins().ireduce(types::I8, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, lane_count / 2 * 3 + idx).write_cvalue(fx, res_lane); - } + pack_instruction(fx, a, b, ret, PackSize::U8, PackWidth::Avx); } - "llvm.x86.sse2.packssdw.128" => { - // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_packs_epi32&ig_expand=4889 + "llvm.x86.avx2.packsswb" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_packs_epi16&ig_expand=4851 intrinsic_args!(fx, args => (a, b); intrinsic); - assert_eq!(a.layout(), b.layout()); - let layout = a.layout(); - - let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx); - let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); - assert_eq!(lane_ty, fx.tcx.types.i32); - assert_eq!(ret_lane_ty, fx.tcx.types.i16); - assert_eq!(lane_count * 2, ret_lane_count); - - let min_i16 = fx.bcx.ins().iconst(types::I32, i32::from(i16::MIN) as u32 as i64); - let max_i16 = fx.bcx.ins().iconst(types::I32, i32::from(i16::MAX) as u32 as i64); - let ret_lane_layout = fx.layout_of(fx.tcx.types.i16); - - for idx in 0..lane_count { - let lane = a.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, min_i16); - let sat = fx.bcx.ins().smin(sat, max_i16); - let res = fx.bcx.ins().ireduce(types::I16, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, idx).write_cvalue(fx, res_lane); - } - - for idx in 0..lane_count { - let lane = b.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, min_i16); - let sat = fx.bcx.ins().smin(sat, max_i16); - let res = fx.bcx.ins().ireduce(types::I16, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, lane_count + idx).write_cvalue(fx, res_lane); - } + pack_instruction(fx, a, b, ret, PackSize::S8, PackWidth::Avx); } "llvm.x86.sse41.packusdw" => { // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_packus_epi32&ig_expand=4912 intrinsic_args!(fx, args => (a, b); intrinsic); - assert_eq!(a.layout(), b.layout()); - let layout = a.layout(); - - let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx); - let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); - assert_eq!(lane_ty, fx.tcx.types.i32); - assert_eq!(ret_lane_ty, fx.tcx.types.u16); - assert_eq!(lane_count * 2, ret_lane_count); - - let min_u16 = fx.bcx.ins().iconst(types::I32, i64::from(u16::MIN)); - let max_u16 = fx.bcx.ins().iconst(types::I32, i64::from(u16::MAX)); - let ret_lane_layout = fx.layout_of(fx.tcx.types.u16); + pack_instruction(fx, a, b, ret, PackSize::U16, PackWidth::Sse); + } - for idx in 0..lane_count { - let lane = a.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, min_u16); - let sat = fx.bcx.ins().smin(sat, max_u16); - let res = fx.bcx.ins().ireduce(types::I16, sat); + "llvm.x86.sse2.packssdw.128" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_packs_epi32&ig_expand=4889 + intrinsic_args!(fx, args => (a, b); intrinsic); - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, idx).write_cvalue(fx, res_lane); - } + pack_instruction(fx, a, b, ret, PackSize::S16, PackWidth::Sse); + } - for idx in 0..lane_count { - let lane = b.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, min_u16); - let sat = fx.bcx.ins().smin(sat, max_u16); - let res = fx.bcx.ins().ireduce(types::I16, sat); + "llvm.x86.avx2.packusdw" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_packus_epi32&ig_expand=4883 + intrinsic_args!(fx, args => (a, b); intrinsic); - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, lane_count + idx).write_cvalue(fx, res_lane); - } + pack_instruction(fx, a, b, ret, PackSize::U16, PackWidth::Avx); } "llvm.x86.avx2.packssdw" => { // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_packs_epi32&ig_expand=4892 intrinsic_args!(fx, args => (a, b); intrinsic); - assert_eq!(a.layout(), b.layout()); - let layout = a.layout(); - - let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx); - let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); - assert_eq!(lane_ty, fx.tcx.types.i32); - assert_eq!(ret_lane_ty, fx.tcx.types.i16); - assert_eq!(lane_count * 2, ret_lane_count); - - let min_i16 = fx.bcx.ins().iconst(types::I32, i32::from(i16::MIN) as u32 as i64); - let max_i16 = fx.bcx.ins().iconst(types::I32, i32::from(i16::MAX) as u32 as i64); - let ret_lane_layout = fx.layout_of(fx.tcx.types.i16); - - for idx in 0..lane_count / 2 { - let lane = a.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, min_i16); - let sat = fx.bcx.ins().smin(sat, max_i16); - let res = fx.bcx.ins().ireduce(types::I16, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, idx).write_cvalue(fx, res_lane); - } - - for idx in 0..lane_count / 2 { - let lane = b.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, min_i16); - let sat = fx.bcx.ins().smin(sat, max_i16); - let res = fx.bcx.ins().ireduce(types::I16, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, lane_count / 2 + idx).write_cvalue(fx, res_lane); - } - - for idx in 0..lane_count / 2 { - let lane = a.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, min_i16); - let sat = fx.bcx.ins().smin(sat, max_i16); - let res = fx.bcx.ins().ireduce(types::I16, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, lane_count / 2 * 2 + idx).write_cvalue(fx, res_lane); - } - - for idx in 0..lane_count / 2 { - let lane = b.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, min_i16); - let sat = fx.bcx.ins().smin(sat, max_i16); - let res = fx.bcx.ins().ireduce(types::I16, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, lane_count / 2 * 3 + idx).write_cvalue(fx, res_lane); - } + pack_instruction(fx, a, b, ret, PackSize::S16, PackWidth::Avx); } "llvm.x86.fma.vfmaddsub.ps" @@ -1407,3 +1233,113 @@ fn llvm_add_sub<'tcx>( (cb_out, c) } + +enum PackSize { + U8, + U16, + S8, + S16, +} + +impl PackSize { + fn ret_clif_type(&self) -> Type { + match self { + Self::U8 | Self::S8 => types::I8, + Self::U16 | Self::S16 => types::I16, + } + } + fn src_clif_type(&self) -> Type { + match self { + Self::U8 | Self::S8 => types::I16, + Self::U16 | Self::S16 => types::I32, + } + } + fn src_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + match self { + Self::U8 | Self::S8 => tcx.types.i16, + Self::U16 | Self::S16 => tcx.types.i32, + } + } + fn ret_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + match self { + Self::U8 => tcx.types.u8, + Self::S8 => tcx.types.i8, + Self::U16 => tcx.types.u16, + Self::S16 => tcx.types.i16, + } + } + fn max(&self) -> i64 { + match self { + Self::U8 => u8::MAX as u64 as i64, + Self::S8 => i8::MAX as u8 as u64 as i64, + Self::U16 => u16::MAX as u64 as i64, + Self::S16 => i16::MAX as u64 as u64 as i64, + } + } + fn min(&self) -> i64 { + match self { + Self::U8 | Self::U16 => 0, + Self::S8 => i16::from(i8::MIN) as u16 as i64, + Self::S16 => i32::from(i16::MIN) as u32 as i64, + } + } +} + +enum PackWidth { + Sse = 1, + Avx = 2, +} +impl PackWidth { + fn divisor(&self) -> u64 { + match self { + Self::Sse => 1, + Self::Avx => 2, + } + } +} + +fn pack_instruction<'tcx>( + fx: &mut FunctionCx<'_, '_, 'tcx>, + a: CValue<'tcx>, + b: CValue<'tcx>, + ret: CPlace<'tcx>, + ret_size: PackSize, + width: PackWidth, +) { + assert_eq!(a.layout(), b.layout()); + let layout = a.layout(); + + let (src_lane_count, src_lane_ty) = layout.ty.simd_size_and_type(fx.tcx); + let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); + assert_eq!(src_lane_ty, ret_size.src_ty(fx.tcx)); + assert_eq!(ret_lane_ty, ret_size.ret_ty(fx.tcx)); + assert_eq!(src_lane_count * 2, ret_lane_count); + + let min = fx.bcx.ins().iconst(ret_size.src_clif_type(), ret_size.min()); + let max = fx.bcx.ins().iconst(ret_size.src_clif_type(), ret_size.max()); + let ret_lane_layout = fx.layout_of(ret_size.ret_ty(fx.tcx)); + + let mut round = |source: CValue<'tcx>, source_offset: u64, dest_offset: u64| { + let step_amount = src_lane_count / width.divisor(); + let dest_offset = step_amount * dest_offset; + for idx in 0..step_amount { + let lane = source.value_lane(fx, step_amount * source_offset + idx).load_scalar(fx); + let sat = fx.bcx.ins().smax(lane, min); + let sat = match ret_size { + PackSize::U8 | PackSize::U16 => fx.bcx.ins().umin(sat, max), + PackSize::S8 | PackSize::S16 => fx.bcx.ins().smin(sat, max), + }; + let res = fx.bcx.ins().ireduce(ret_size.ret_clif_type(), sat); + let res_lane = CValue::by_val(res, ret_lane_layout); + ret.place_lane(fx, dest_offset + idx).write_cvalue(fx, res_lane); + } + }; + + round(a, 0, 0); + round(b, 0, 1); + + if let PackWidth::Avx = width { + round(a, 1, 2); + round(b, 1, 3); + } +} From 22019dbac879ae899c1ab13ad48503af28c3802b Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Wed, 3 Jan 2024 20:28:08 +0100 Subject: [PATCH 0066/1197] Mention correctness test --- src/intrinsics/llvm_x86.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/intrinsics/llvm_x86.rs b/src/intrinsics/llvm_x86.rs index 445622fc539bc..24a5df1630de8 100644 --- a/src/intrinsics/llvm_x86.rs +++ b/src/intrinsics/llvm_x86.rs @@ -1298,6 +1298,8 @@ impl PackWidth { } } +/// Implement an x86 pack instruction with the intrinsic `_mm{,256}pack{us,s}_epi{16,32}`. +/// Validated for correctness against LLVM, see commit `c8f5d35508e062bd2d95e6c03429bfec831db6d3`. fn pack_instruction<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, a: CValue<'tcx>, From 6fea128f8c859a3f63e6ca684083419ca00d58d3 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Wed, 3 Jan 2024 21:23:55 +0100 Subject: [PATCH 0067/1197] Use `rust-analyzer.rustc.source` to get r-a working with rustc --- .vscode/settings.json | 3 ++- Readme.md | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 834a1362caf32..491646ce59bb3 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,8 +1,9 @@ { "editor.formatOnSave": true, - // source for rustc_* is not included in the rust-src component; disable the errors about this + // in case rustc.source is disabled for performance reasons; disable the errors about this "rust-analyzer.diagnostics.disabled": ["unresolved-extern-crate", "unresolved-macro-call"], + "rust-analyzer.rustc.source": "discover", "rust-analyzer.imports.granularity.enforce": true, "rust-analyzer.imports.granularity.group": "module", "rust-analyzer.imports.prefix": "crate", diff --git a/Readme.md b/Readme.md index 1c48097da2aae..4f45526196397 100644 --- a/Readme.md +++ b/Readme.md @@ -121,6 +121,8 @@ You need to do this steps to successfully compile and use the cranelift backend * (Optional) run tests: `rustup run stage2 ./y.sh test` 8. Now you can use your cg_clif build to compile other Rust programs, e.g. you can open any Rust crate and run commands like `$RustCheckoutDir/compiler/rustc_codegen_cranelift/dist/cargo-clif build --release`. +You can also set `rust-analyzer.rustc.source` to your rust workspace to get rust-analyzer to understand your changes. + ## Configuration See the documentation on the `BackendConfig` struct in [config.rs](src/config.rs) for all From 4b7e0a0b56aa2446e670dfd6558380a1039a86aa Mon Sep 17 00:00:00 2001 From: Arlo Siemsen Date: Thu, 4 Jan 2024 11:40:56 -0600 Subject: [PATCH 0068/1197] Handle vendored sources when remapping paths --- src/bootstrap/src/core/builder.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 4e20babc55a68..3770d0687b242 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -1799,15 +1799,20 @@ impl<'a> Builder<'a> { } if self.config.rust_remap_debuginfo { - // FIXME: handle vendored sources - let registry_src = t!(home::cargo_home()).join("registry").join("src"); let mut env_var = OsString::new(); - for entry in t!(std::fs::read_dir(registry_src)) { - if !env_var.is_empty() { - env_var.push("\t"); - } - env_var.push(t!(entry).path()); + if self.config.vendor { + let vendor = self.build.src.join("vendor"); + env_var.push(vendor); env_var.push("=/rust/deps"); + } else { + let registry_src = t!(home::cargo_home()).join("registry").join("src"); + for entry in t!(std::fs::read_dir(registry_src)) { + if !env_var.is_empty() { + env_var.push("\t"); + } + env_var.push(t!(entry).path()); + env_var.push("=/rust/deps"); + } } cargo.env("RUSTC_CARGO_REGISTRY_SRC_TO_REMAP", env_var); } From c824399d74feee7f00e4b8d75f9dd85c633193f9 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Thu, 4 Jan 2024 13:08:38 -0800 Subject: [PATCH 0069/1197] Fix broken markdown in csky-unknown-linux-gnuabiv2.md --- .../rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md b/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md index a54abcb606ea7..e72bfb8bae767 100644 --- a/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md +++ b/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md @@ -50,6 +50,7 @@ cc = "${TOOLCHAIN_PATH}/bin/csky-linux-gnuabiv2-gcc" [target.csky-unknown-linux-gnuabiv2hf] # ADJUST THIS PATH TO POINT AT YOUR TOOLCHAIN cc = "${TOOLCHAIN_PATH}/bin/csky-linux-gnuabiv2-gcc" +``` ### Build From 16e117cf964064f8f70ab2e55f24ed37e1e9a4ee Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Fri, 5 Jan 2024 02:52:37 +0000 Subject: [PATCH 0070/1197] Remove outdated references to `librustc_middle`. --- compiler/rustc_const_eval/src/const_eval/error.rs | 4 +--- compiler/rustc_data_structures/src/lib.rs | 2 +- compiler/rustc_error_codes/src/error_codes/E0264.md | 2 +- compiler/rustc_errors/src/lib.rs | 3 ++- compiler/rustc_lint/src/builtin.rs | 2 +- compiler/rustc_middle/src/arena.rs | 2 +- compiler/rustc_middle/src/tests.rs | 4 ++-- 7 files changed, 9 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index ef39d13d78ab4..c5f6aff24d34a 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -50,9 +50,7 @@ impl MachineStopType for ConstEvalErrKind { } } -// The errors become `MachineStop` with plain strings when being raised. -// `ConstEvalErr` (in `librustc_middle/mir/interpret/error.rs`) knows to -// handle these. +/// The errors become [`InterpError::MachineStop`] when being raised. impl<'tcx> Into> for ConstEvalErrKind { fn into(self) -> InterpErrorInfo<'tcx> { err_machine_stop!(self).into() diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 93b4032c31089..f7d1352f38701 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -147,7 +147,7 @@ pub fn make_display(f: impl Fn(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl Printer { f } } -// See comments in src/librustc_middle/lib.rs +// See comments in compiler/rustc_middle/src/tests.rs #[doc(hidden)] pub fn __noop_fix_for_27438() {} diff --git a/compiler/rustc_error_codes/src/error_codes/E0264.md b/compiler/rustc_error_codes/src/error_codes/E0264.md index d790607622992..33ddf3405acca 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0264.md +++ b/compiler/rustc_error_codes/src/error_codes/E0264.md @@ -13,7 +13,7 @@ extern "C" { ``` A list of available external lang items is available in -`src/librustc_middle/middle/weak_lang_items.rs`. Example: +`compiler/rustc_hir/src/weak_lang_items.rs`. Example: ``` #![feature(lang_items)] diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 6707e17e90f4a..7a85f3be74e0b 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -639,7 +639,8 @@ impl DiagCtxt { } // This is here to not allow mutation of flags; - // as of this writing it's only used in tests in librustc_middle. + // as of this writing it's used in Session::consider_optimizing and + // in tests in rustc_interface. pub fn can_emit_warnings(&self) -> bool { self.inner.borrow_mut().flags.can_emit_warnings } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 8d2f2aaca5574..9e10c036b4531 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -72,7 +72,7 @@ use crate::nonstandard_style::{method_context, MethodLateContext}; use std::fmt::Write; -// hardwired lints from librustc_middle +// hardwired lints from rustc_lint_defs pub use rustc_session::lint::builtin::*; declare_lint! { diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 52fd494a10db0..f3172cb2bc804 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -94,7 +94,7 @@ macro_rules! arena_types { // Note that this deliberately duplicates items in the `rustc_hir::arena`, // since we need to allocate this type on both the `rustc_hir` arena - // (during lowering) and the `librustc_middle` arena (for decoding MIR) + // (during lowering) and the `rustc_middle` arena (for decoding MIR) [decode] asm_template: rustc_ast::InlineAsmTemplatePiece, [decode] used_trait_imports: rustc_data_structures::unord::UnordSet, [decode] is_late_bound_map: rustc_data_structures::fx::FxIndexSet, diff --git a/compiler/rustc_middle/src/tests.rs b/compiler/rustc_middle/src/tests.rs index 757e0bd3bfbf9..49960cc0bb2a2 100644 --- a/compiler/rustc_middle/src/tests.rs +++ b/compiler/rustc_middle/src/tests.rs @@ -1,7 +1,7 @@ use super::*; -// FIXME(#27438): right now the unit tests of librustc_middle don't refer to any actual -// functions generated in librustc_data_structures (all +// FIXME(#27438): right now the unit tests of rustc_middle don't refer to any actual +// functions generated in rustc_data_structures (all // references are through generic functions), but statics are // referenced from time to time. Due to this bug we won't // actually correctly link in the statics unless we also From 74987d04fc3f8b85be2cdbdddc3ea3e1e09a6ae1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Fri, 5 Jan 2024 22:40:25 +0100 Subject: [PATCH 0071/1197] fix a couple of clippy warnings --- src/driver/aot.rs | 2 +- src/inline_asm.rs | 4 ++-- src/intrinsics/simd.rs | 4 ++-- src/lib.rs | 7 ++----- src/unsize.rs | 7 +++---- src/vtable.rs | 2 +- 6 files changed, 11 insertions(+), 15 deletions(-) diff --git a/src/driver/aot.rs b/src/driver/aot.rs index e77b0cd0721b2..6cfbb52e92180 100644 --- a/src/driver/aot.rs +++ b/src/driver/aot.rs @@ -467,7 +467,7 @@ pub(crate) fn run_aot( let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx); let metadata_cgu_name = cgu_name_builder - .build_cgu_name(LOCAL_CRATE, &["crate"], Some("metadata")) + .build_cgu_name(LOCAL_CRATE, ["crate"], Some("metadata")) .as_str() .to_string(); diff --git a/src/inline_asm.rs b/src/inline_asm.rs index 1d0d7ee75de2f..7793b1b70924b 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -52,7 +52,7 @@ pub(crate) fn codegen_inline_asm_terminator<'tcx>( } let operands = operands - .into_iter() + .iter() .map(|operand| match *operand { InlineAsmOperand::In { reg, ref value } => CInlineAsmOperand::In { reg, @@ -763,7 +763,7 @@ fn call_inline_asm<'tcx>( }, ) .unwrap(); - let inline_asm_func = fx.module.declare_func_in_func(inline_asm_func, &mut fx.bcx.func); + let inline_asm_func = fx.module.declare_func_in_func(inline_asm_func, fx.bcx.func); if fx.clif_comments.enabled() { fx.add_comment(inline_asm_func, asm_name); } diff --git a/src/intrinsics/simd.rs b/src/intrinsics/simd.rs index 78ea7c2dbfc39..59dfba31a0a4e 100644 --- a/src/intrinsics/simd.rs +++ b/src/intrinsics/simd.rs @@ -293,7 +293,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( } ret.write_cvalue(fx, base); - let ret_lane = ret.place_lane(fx, idx.try_into().unwrap()); + let ret_lane = ret.place_lane(fx, idx.into()); ret_lane.write_cvalue(fx, val); } @@ -340,7 +340,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( ); } - let ret_lane = v.value_lane(fx, idx.try_into().unwrap()); + let ret_lane = v.value_lane(fx, idx.into()); ret.write_cvalue(fx, ret_lane); } diff --git a/src/lib.rs b/src/lib.rs index f327577eb4d32..635ff0ba7097e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -314,16 +314,13 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Arc { - let builder = cranelift_native::builder_with_options(true).unwrap(); - builder - } + Some("native") => cranelift_native::builder_with_options(true).unwrap(), Some(value) => { let mut builder = cranelift_codegen::isa::lookup(target_triple.clone()).unwrap_or_else(|err| { sess.dcx().fatal(format!("can't compile for {}: {}", target_triple, err)); }); - if let Err(_) = builder.enable(value) { + if builder.enable(value).is_err() { sess.dcx() .fatal("the specified target cpu isn't currently supported by Cranelift."); } diff --git a/src/unsize.rs b/src/unsize.rs index f777e11371f13..acfa461a6f30b 100644 --- a/src/unsize.rs +++ b/src/unsize.rs @@ -28,10 +28,9 @@ pub(crate) fn unsized_info<'tcx>( .bcx .ins() .iconst(fx.pointer_type, len.eval_target_usize(fx.tcx, ParamEnv::reveal_all()) as i64), - ( - &ty::Dynamic(ref data_a, _, src_dyn_kind), - &ty::Dynamic(ref data_b, _, target_dyn_kind), - ) if src_dyn_kind == target_dyn_kind => { + (&ty::Dynamic(data_a, _, src_dyn_kind), &ty::Dynamic(data_b, _, target_dyn_kind)) + if src_dyn_kind == target_dyn_kind => + { let old_info = old_info.expect("unsized_info: missing old info for trait upcasting coercion"); if data_a.principal_def_id() == data_b.principal_def_id() { diff --git a/src/vtable.rs b/src/vtable.rs index 41ea0b122de73..d2254d4c15e6f 100644 --- a/src/vtable.rs +++ b/src/vtable.rs @@ -95,7 +95,7 @@ pub(crate) fn get_vtable<'tcx>( let alloc_id = fx.tcx.vtable_allocation((ty, trait_ref)); let data_id = data_id_for_alloc_id(&mut fx.constants_cx, &mut *fx.module, alloc_id, Mutability::Not); - let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); + let local_data_id = fx.module.declare_data_in_func(data_id, fx.bcx.func); if fx.clif_comments.enabled() { fx.add_comment(local_data_id, format!("vtable: {:?}", alloc_id)); } From 853504df238835208d8a565cbb532918d84492c6 Mon Sep 17 00:00:00 2001 From: Ethan Brierley Date: Fri, 5 Jan 2024 22:34:43 +0000 Subject: [PATCH 0072/1197] Remove feature not required by `Ipv6Addr::to_cononical` doctest The feature does not seem to be required by this doctest. --- library/core/src/net/ip_addr.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs index 1ef876a3163c9..762d1caad4b38 100644 --- a/library/core/src/net/ip_addr.rs +++ b/library/core/src/net/ip_addr.rs @@ -1860,7 +1860,6 @@ impl Ipv6Addr { /// # Examples /// /// ``` - /// #![feature(ip)] /// use std::net::Ipv6Addr; /// /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).is_loopback(), false); From 245afd7896007da982df46dbc98f1c7e4b007eae Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sun, 26 Nov 2023 17:06:13 -0500 Subject: [PATCH 0073/1197] Sometimes return the same AllocId for a ConstAllocation --- .../src/interpret/eval_context.rs | 16 +++--- .../rustc_const_eval/src/interpret/machine.rs | 20 +++++++ src/tools/miri/src/machine.rs | 52 ++++++++++++++++++- src/tools/miri/tests/pass/const-addrs.rs | 38 ++++++++++++++ 4 files changed, 117 insertions(+), 9 deletions(-) create mode 100644 src/tools/miri/tests/pass/const-addrs.rs diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index bbebf329d2659..ecab6fa387ded 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -1138,13 +1138,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { span: Option, layout: Option>, ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { - let const_val = val.eval(*self.tcx, self.param_env, span).map_err(|err| { - // FIXME: somehow this is reachable even when POST_MONO_CHECKS is on. - // Are we not always populating `required_consts`? - err.emit_note(*self.tcx); - err - })?; - self.const_val_to_op(const_val, val.ty(), layout) + M::eval_mir_constant(self, *val, span, layout, |ecx, val, span, layout| { + let const_val = val.eval(*ecx.tcx, ecx.param_env, span).map_err(|err| { + // FIXME: somehow this is reachable even when POST_MONO_CHECKS is on. + // Are we not always populating `required_consts`? + err.emit_note(*ecx.tcx); + err + })?; + ecx.const_val_to_op(const_val, val.ty(), layout) + }) } #[must_use] diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 5e69965512b94..d32a29ede4982 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -13,6 +13,7 @@ use rustc_middle::query::TyCtxtAt; use rustc_middle::ty; use rustc_middle::ty::layout::TyAndLayout; use rustc_span::def_id::DefId; +use rustc_span::Span; use rustc_target::abi::{Align, Size}; use rustc_target::spec::abi::Abi as CallAbi; @@ -510,6 +511,25 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized { ) -> InterpResult<'tcx> { Ok(()) } + + #[inline(always)] + fn eval_mir_constant( + ecx: &InterpCx<'mir, 'tcx, Self>, + val: mir::Const<'tcx>, + span: Option, + layout: Option>, + eval: F, + ) -> InterpResult<'tcx, OpTy<'tcx, Self::Provenance>> + where + F: Fn( + &InterpCx<'mir, 'tcx, Self>, + mir::Const<'tcx>, + Option, + Option>, + ) -> InterpResult<'tcx, OpTy<'tcx, Self::Provenance>>, + { + eval(ecx, val, span, layout) + } } /// A lot of the flexibility above is just needed for `Miri`, but all "compile-time" machines diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 4a878f4a36e6c..4cd48b2e5a3a4 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -3,6 +3,7 @@ use std::borrow::Cow; use std::cell::{Cell, RefCell}; +use std::collections::hash_map::Entry; use std::fmt; use std::path::Path; use std::process; @@ -10,6 +11,7 @@ use std::process; use either::Either; use rand::rngs::StdRng; use rand::SeedableRng; +use rand::Rng; use rustc_ast::ast::Mutability; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -45,6 +47,11 @@ pub const SIGRTMIN: i32 = 34; /// `SIGRTMAX` - `SIGRTMIN` >= 8 (which is the value of `_POSIX_RTSIG_MAX`) pub const SIGRTMAX: i32 = 42; +/// Each const has multiple addresses, but only this many. Since const allocations are never +/// deallocated, choosing a new [`AllocId`] and thus base address for each evaluation would +/// produce unbounded memory usage. +const ADDRS_PER_CONST: usize = 16; + /// Extra data stored with each stack frame pub struct FrameExtra<'tcx> { /// Extra data for the Borrow Tracker. @@ -65,12 +72,18 @@ pub struct FrameExtra<'tcx> { /// optimization. /// This is used by `MiriMachine::current_span` and `MiriMachine::caller_span` pub is_user_relevant: bool, + + /// We have a cache for the mapping from [`mir::Const`] to resulting [`AllocId`]. + /// However, we don't want all frames to always get the same result, so we insert + /// an additional bit of "salt" into the cache key. This salt is fixed per-frame + /// so that within a call, a const will have a stable address. + salt: usize, } impl<'tcx> std::fmt::Debug for FrameExtra<'tcx> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { // Omitting `timing`, it does not support `Debug`. - let FrameExtra { borrow_tracker, catch_unwind, timing: _, is_user_relevant: _ } = self; + let FrameExtra { borrow_tracker, catch_unwind, timing: _, is_user_relevant: _, salt: _ } = self; f.debug_struct("FrameData") .field("borrow_tracker", borrow_tracker) .field("catch_unwind", catch_unwind) @@ -80,7 +93,7 @@ impl<'tcx> std::fmt::Debug for FrameExtra<'tcx> { impl VisitProvenance for FrameExtra<'_> { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { - let FrameExtra { catch_unwind, borrow_tracker, timing: _, is_user_relevant: _ } = self; + let FrameExtra { catch_unwind, borrow_tracker, timing: _, is_user_relevant: _, salt: _ } = self; catch_unwind.visit_provenance(visit); borrow_tracker.visit_provenance(visit); @@ -552,6 +565,11 @@ pub struct MiriMachine<'mir, 'tcx> { /// The spans we will use to report where an allocation was created and deallocated in /// diagnostics. pub(crate) allocation_spans: RefCell)>>, + + /// Maps MIR consts to their evaluated result. We combine the const with a "salt" (`usize`) + /// that is fixed per stack frame; this lets us have sometimes different results for the + /// same const while ensuring consistent results within a single call. + const_cache: RefCell, usize), OpTy<'tcx, Provenance>>>, } impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { @@ -677,6 +695,7 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { stack_size, collect_leak_backtraces: config.collect_leak_backtraces, allocation_spans: RefCell::new(FxHashMap::default()), + const_cache: RefCell::new(FxHashMap::default()), } } @@ -857,6 +876,7 @@ impl VisitProvenance for MiriMachine<'_, '_> { stack_size: _, collect_leak_backtraces: _, allocation_spans: _, + const_cache: _, } = self; threads.visit_provenance(visit); @@ -1400,6 +1420,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { catch_unwind: None, timing, is_user_relevant: ecx.machine.is_user_relevant(&frame), + salt: ecx.machine.rng.borrow_mut().gen::() % ADDRS_PER_CONST, }; Ok(frame.with_extra(extra)) @@ -1505,4 +1526,31 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { ecx.machine.allocation_spans.borrow_mut().insert(alloc_id, (span, None)); Ok(()) } + + fn eval_mir_constant( + ecx: &InterpCx<'mir, 'tcx, Self>, + val: mir::Const<'tcx>, + span: Option, + layout: Option>, + eval: F, + ) -> InterpResult<'tcx, OpTy<'tcx, Self::Provenance>> + where + F: Fn( + &InterpCx<'mir, 'tcx, Self>, + mir::Const<'tcx>, + Option, + Option>, + ) -> InterpResult<'tcx, OpTy<'tcx, Self::Provenance>>, + { + let frame = ecx.active_thread_stack().last().unwrap(); + let mut cache = ecx.machine.const_cache.borrow_mut(); + match cache.entry((val, frame.extra.salt)) { + Entry::Vacant(ve) => { + let op = eval(ecx, val, span, layout)?; + ve.insert(op.clone()); + Ok(op) + } + Entry::Occupied(oe) => Ok(oe.get().clone()), + } + } } diff --git a/src/tools/miri/tests/pass/const-addrs.rs b/src/tools/miri/tests/pass/const-addrs.rs new file mode 100644 index 0000000000000..6c14f0b679ce8 --- /dev/null +++ b/src/tools/miri/tests/pass/const-addrs.rs @@ -0,0 +1,38 @@ +// The const fn interpreter creates a new AllocId every time it evaluates any const. +// If we do that in Miri, repeatedly evaluating a const causes unbounded memory use +// we need to keep track of the base address for that AllocId, and the allocation is never +// deallocated. +// In Miri we explicitly store previously-assigned AllocIds for each const and ensure +// that we only hand out a finite number of AllocIds per const. +// MIR inlining will put every evaluation of the const we're repeatedly evaluting into the same +// stack frame, breaking this test. +//@compile-flags: -Zinline-mir=no +#![feature(strict_provenance)] + +const EVALS: usize = 256; + +use std::collections::HashSet; +fn main() { + let mut addrs = HashSet::new(); + for _ in 0..EVALS { + addrs.insert(const_addr()); + } + // Check that the const allocation has multiple base addresses + assert!(addrs.len() > 1); + // But also that we get a limited number of unique base addresses + assert!(addrs.len() < EVALS); + + // Check that within a call we always produce the same address + let mut prev = 0; + for iter in 0..EVALS { + let addr = "test".as_bytes().as_ptr().addr(); + if iter > 0 { + assert_eq!(prev, addr); + } + prev = addr; + } +} + +fn const_addr() -> usize { + "test".as_bytes().as_ptr().addr() +} From 837c0305c6e61c1591b0c59935bb71df11b3638e Mon Sep 17 00:00:00 2001 From: Obei Sideg Date: Fri, 22 Dec 2023 15:12:01 +0300 Subject: [PATCH 0074/1197] Update test for `E0796` and `static_mut_ref` lint --- example/mini_core_hello_world.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/example/mini_core_hello_world.rs b/example/mini_core_hello_world.rs index a1cdf31c68a00..2a7b1107ffcaa 100644 --- a/example/mini_core_hello_world.rs +++ b/example/mini_core_hello_world.rs @@ -111,6 +111,9 @@ fn start( } static mut NUM: u8 = 6 * 7; + +// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint +#[allow(static_mut_ref)] static NUM_REF: &'static u8 = unsafe { &NUM }; unsafe fn zeroed() -> T { From 4e973b0b63ab0177369e60d402ff54198ee357f3 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Mon, 8 Jan 2024 00:36:31 +0900 Subject: [PATCH 0075/1197] rc,sync: Do not create references to uninitialized values --- library/alloc/src/rc.rs | 27 ++++++++++++++++----------- library/alloc/src/sync.rs | 18 +++++++++--------- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 263b1449de156..fa652aa0517ac 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1885,10 +1885,10 @@ impl Rc { // Initialize the RcBox let inner = mem_to_rcbox(ptr.as_non_null_ptr().as_ptr()); unsafe { - debug_assert_eq!(Layout::for_value(&*inner), layout); + debug_assert_eq!(Layout::for_value_raw(inner), layout); - ptr::write(&mut (*inner).strong, Cell::new(1)); - ptr::write(&mut (*inner).weak, Cell::new(1)); + ptr::addr_of_mut!((*inner).strong).write(Cell::new(1)); + ptr::addr_of_mut!((*inner).weak).write(Cell::new(1)); } Ok(inner) @@ -1902,7 +1902,7 @@ impl Rc { // Allocate for the `RcBox` using the given value. unsafe { Rc::::allocate_for_layout( - Layout::for_value(&*ptr), + Layout::for_value_raw(ptr), |layout| alloc.allocate(layout), |mem| mem.with_metadata_of(ptr as *const RcBox), ) @@ -1918,7 +1918,7 @@ impl Rc { // Copy value as bytes ptr::copy_nonoverlapping( &*src as *const T as *const u8, - &mut (*ptr).value as *mut _ as *mut u8, + ptr::addr_of_mut!((*ptr).value) as *mut u8, value_size, ); @@ -1952,7 +1952,11 @@ impl Rc<[T]> { unsafe fn copy_from_slice(v: &[T]) -> Rc<[T]> { unsafe { let ptr = Self::allocate_for_slice(v.len()); - ptr::copy_nonoverlapping(v.as_ptr(), &mut (*ptr).value as *mut [T] as *mut T, v.len()); + ptr::copy_nonoverlapping( + v.as_ptr(), + ptr::addr_of_mut!((*ptr).value) as *mut T, + v.len(), + ); Self::from_ptr(ptr) } } @@ -1987,10 +1991,10 @@ impl Rc<[T]> { let ptr = Self::allocate_for_slice(len); let mem = ptr as *mut _ as *mut u8; - let layout = Layout::for_value(&*ptr); + let layout = Layout::for_value_raw(ptr); // Pointer to first element - let elems = &mut (*ptr).value as *mut [T] as *mut T; + let elems = ptr::addr_of_mut!((*ptr).value) as *mut T; let mut guard = Guard { mem: NonNull::new_unchecked(mem), elems, layout, n_elems: 0 }; @@ -2096,7 +2100,8 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Rc { self.inner().dec_weak(); if self.inner().weak() == 0 { - self.alloc.deallocate(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); + self.alloc + .deallocate(self.ptr.cast(), Layout::for_value_raw(self.ptr.as_ptr())); } } } @@ -2524,7 +2529,7 @@ impl From> for Rc<[T], A> { let (vec_ptr, len, cap, alloc) = v.into_raw_parts_with_alloc(); let rc_ptr = Self::allocate_for_slice_in(len, &alloc); - ptr::copy_nonoverlapping(vec_ptr, &mut (*rc_ptr).value as *mut [T] as *mut T, len); + ptr::copy_nonoverlapping(vec_ptr, ptr::addr_of_mut!((*rc_ptr).value) as *mut T, len); // Create a `Vec` with length 0, to deallocate the buffer // without dropping its contents or the allocator @@ -3514,7 +3519,7 @@ unsafe impl<#[may_dangle] T> Drop for UniqueRc { self.ptr.as_ref().dec_weak(); if self.ptr.as_ref().weak() == 0 { - Global.deallocate(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); + Global.deallocate(self.ptr.cast(), Layout::for_value_raw(self.ptr.as_ptr())); } } } diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 5273b3cb2dafa..70e1f63dd7385 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1828,11 +1828,11 @@ impl Arc { mem_to_arcinner: impl FnOnce(*mut u8) -> *mut ArcInner, ) -> *mut ArcInner { let inner = mem_to_arcinner(ptr.as_non_null_ptr().as_ptr()); - debug_assert_eq!(unsafe { Layout::for_value(&*inner) }, layout); + debug_assert_eq!(unsafe { Layout::for_value_raw(inner) }, layout); unsafe { - ptr::write(&mut (*inner).strong, atomic::AtomicUsize::new(1)); - ptr::write(&mut (*inner).weak, atomic::AtomicUsize::new(1)); + ptr::addr_of_mut!((*inner).strong).write(atomic::AtomicUsize::new(1)); + ptr::addr_of_mut!((*inner).weak).write(atomic::AtomicUsize::new(1)); } inner @@ -1847,7 +1847,7 @@ impl Arc { // Allocate for the `ArcInner` using the given value. unsafe { Arc::allocate_for_layout( - Layout::for_value(&*ptr), + Layout::for_value_raw(ptr), |layout| alloc.allocate(layout), |mem| mem.with_metadata_of(ptr as *const ArcInner), ) @@ -1863,7 +1863,7 @@ impl Arc { // Copy value as bytes ptr::copy_nonoverlapping( &*src as *const T as *const u8, - &mut (*ptr).data as *mut _ as *mut u8, + ptr::addr_of_mut!((*ptr).data) as *mut u8, value_size, ); @@ -1898,7 +1898,7 @@ impl Arc<[T]> { unsafe { let ptr = Self::allocate_for_slice(v.len()); - ptr::copy_nonoverlapping(v.as_ptr(), &mut (*ptr).data as *mut [T] as *mut T, v.len()); + ptr::copy_nonoverlapping(v.as_ptr(), ptr::addr_of_mut!((*ptr).data) as *mut T, v.len()); Self::from_ptr(ptr) } @@ -1934,10 +1934,10 @@ impl Arc<[T]> { let ptr = Self::allocate_for_slice(len); let mem = ptr as *mut _ as *mut u8; - let layout = Layout::for_value(&*ptr); + let layout = Layout::for_value_raw(ptr); // Pointer to first element - let elems = &mut (*ptr).data as *mut [T] as *mut T; + let elems = ptr::addr_of_mut!((*ptr).data) as *mut T; let mut guard = Guard { mem: NonNull::new_unchecked(mem), elems, layout, n_elems: 0 }; @@ -3380,7 +3380,7 @@ impl From> for Arc<[T], A> { let (vec_ptr, len, cap, alloc) = v.into_raw_parts_with_alloc(); let rc_ptr = Self::allocate_for_slice_in(len, &alloc); - ptr::copy_nonoverlapping(vec_ptr, &mut (*rc_ptr).data as *mut [T] as *mut T, len); + ptr::copy_nonoverlapping(vec_ptr, ptr::addr_of_mut!((*rc_ptr).data) as *mut T, len); // Create a `Vec` with length 0, to deallocate the buffer // without dropping its contents or the allocator From c4b10545250387876297777c2769b4195835b689 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 3 Dec 2023 13:09:51 +0000 Subject: [PATCH 0076/1197] Move PointIndex to mir_dataflow. --- compiler/rustc_borrowck/src/nll.rs | 5 +- .../rustc_borrowck/src/region_infer/mod.rs | 6 +- .../rustc_borrowck/src/region_infer/values.rs | 104 ++---------------- .../src/type_check/liveness/local_use_map.rs | 8 +- .../src/type_check/liveness/mod.rs | 5 +- .../src/type_check/liveness/trace.rs | 9 +- compiler/rustc_borrowck/src/type_check/mod.rs | 9 +- compiler/rustc_mir_dataflow/src/lib.rs | 1 + compiler/rustc_mir_dataflow/src/points.rs | 94 ++++++++++++++++ 9 files changed, 127 insertions(+), 114 deletions(-) create mode 100644 compiler/rustc_mir_dataflow/src/points.rs diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 5b764495922ba..cc8208e9dc306 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -12,6 +12,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, OpaqueHiddenType, TyCtxt}; use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::MoveData; +use rustc_mir_dataflow::points::DenseLocationMap; use rustc_mir_dataflow::ResultsCursor; use rustc_span::symbol::sym; use std::env; @@ -27,7 +28,7 @@ use crate::{ facts::{AllFacts, AllFactsExt, RustcFacts}, location::LocationTable, polonius, - region_infer::{values::RegionValueElements, RegionInferenceContext}, + region_infer::RegionInferenceContext, renumber, type_check::{self, MirTypeckRegionConstraints, MirTypeckResults}, universal_regions::UniversalRegions, @@ -98,7 +99,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>( let universal_regions = Rc::new(universal_regions); - let elements = &Rc::new(RegionValueElements::new(body)); + let elements = &Rc::new(DenseLocationMap::new(body)); // Run the MIR type-checker. let MirTypeckResults { constraints, universal_region_relations, opaque_type_values } = diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 948221e940734..cbf01feae06a0 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -19,6 +19,7 @@ use rustc_middle::mir::{ use rustc_middle::traits::ObligationCause; use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; +use rustc_mir_dataflow::points::DenseLocationMap; use rustc_span::Span; use crate::constraints::graph::{self, NormalConstraintGraph, RegionGraph}; @@ -30,8 +31,7 @@ use crate::{ nll::PoloniusOutput, region_infer::reverse_sccs::ReverseSccGraph, region_infer::values::{ - LivenessValues, PlaceholderIndices, RegionElement, RegionValueElements, RegionValues, - ToElementIndex, + LivenessValues, PlaceholderIndices, RegionElement, RegionValues, ToElementIndex, }, type_check::{free_region_relations::UniversalRegionRelations, Locations}, universal_regions::UniversalRegions, @@ -330,7 +330,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { universe_causes: FxIndexMap>, type_tests: Vec>, liveness_constraints: LivenessValues, - elements: &Rc, + elements: &Rc, ) -> Self { debug!("universal_regions: {:#?}", universal_regions); debug!("outlives constraints: {:#?}", outlives_constraints); diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index dc3ee849d004a..01f7bfcadb6f5 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -5,97 +5,13 @@ use rustc_index::bit_set::SparseBitMatrix; use rustc_index::interval::IntervalSet; use rustc_index::interval::SparseIntervalMatrix; use rustc_index::Idx; -use rustc_index::IndexVec; -use rustc_middle::mir::{BasicBlock, Body, Location}; +use rustc_middle::mir::{BasicBlock, Location}; use rustc_middle::ty::{self, RegionVid}; +use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex}; use std::fmt::Debug; use std::rc::Rc; -use crate::dataflow::BorrowIndex; - -/// Maps between a `Location` and a `PointIndex` (and vice versa). -pub(crate) struct RegionValueElements { - /// For each basic block, how many points are contained within? - statements_before_block: IndexVec, - - /// Map backward from each point to the basic block that it - /// belongs to. - basic_blocks: IndexVec, - - num_points: usize, -} - -impl RegionValueElements { - pub(crate) fn new(body: &Body<'_>) -> Self { - let mut num_points = 0; - let statements_before_block: IndexVec = body - .basic_blocks - .iter() - .map(|block_data| { - let v = num_points; - num_points += block_data.statements.len() + 1; - v - }) - .collect(); - debug!("RegionValueElements: statements_before_block={:#?}", statements_before_block); - debug!("RegionValueElements: num_points={:#?}", num_points); - - let mut basic_blocks = IndexVec::with_capacity(num_points); - for (bb, bb_data) in body.basic_blocks.iter_enumerated() { - basic_blocks.extend((0..=bb_data.statements.len()).map(|_| bb)); - } - - Self { statements_before_block, basic_blocks, num_points } - } - - /// Total number of point indices - pub(crate) fn num_points(&self) -> usize { - self.num_points - } - - /// Converts a `Location` into a `PointIndex`. O(1). - pub(crate) fn point_from_location(&self, location: Location) -> PointIndex { - let Location { block, statement_index } = location; - let start_index = self.statements_before_block[block]; - PointIndex::new(start_index + statement_index) - } - - /// Converts a `Location` into a `PointIndex`. O(1). - pub(crate) fn entry_point(&self, block: BasicBlock) -> PointIndex { - let start_index = self.statements_before_block[block]; - PointIndex::new(start_index) - } - - /// Return the PointIndex for the block start of this index. - pub(crate) fn to_block_start(&self, index: PointIndex) -> PointIndex { - PointIndex::new(self.statements_before_block[self.basic_blocks[index]]) - } - - /// Converts a `PointIndex` back to a location. O(1). - pub(crate) fn to_location(&self, index: PointIndex) -> Location { - assert!(index.index() < self.num_points); - let block = self.basic_blocks[index]; - let start_index = self.statements_before_block[block]; - let statement_index = index.index() - start_index; - Location { block, statement_index } - } - - /// Sometimes we get point-indices back from bitsets that may be - /// out of range (because they round up to the nearest 2^N number - /// of bits). Use this function to filter such points out if you - /// like. - pub(crate) fn point_in_range(&self, index: PointIndex) -> bool { - index.index() < self.num_points - } -} - -rustc_index::newtype_index! { - /// A single integer representing a `Location` in the MIR control-flow - /// graph. Constructed efficiently from `RegionValueElements`. - #[orderable] - #[debug_format = "PointIndex({})"] - pub struct PointIndex {} -} +use crate::BorrowIndex; rustc_index::newtype_index! { /// A single integer representing a `ty::Placeholder`. @@ -123,7 +39,7 @@ pub(crate) enum RegionElement { /// an interval matrix storing liveness ranges for each region-vid. pub(crate) struct LivenessValues { /// The map from locations to points. - elements: Rc, + elements: Rc, /// For each region: the points where it is live. points: SparseIntervalMatrix, @@ -155,9 +71,9 @@ impl LiveLoans { impl LivenessValues { /// Create an empty map of regions to locations where they're live. - pub(crate) fn new(elements: Rc) -> Self { + pub(crate) fn new(elements: Rc) -> Self { LivenessValues { - points: SparseIntervalMatrix::new(elements.num_points), + points: SparseIntervalMatrix::new(elements.num_points()), elements, loans: None, } @@ -298,7 +214,7 @@ impl PlaceholderIndices { /// it would also contain various points from within the function. #[derive(Clone)] pub(crate) struct RegionValues { - elements: Rc, + elements: Rc, placeholder_indices: Rc, points: SparseIntervalMatrix, free_regions: SparseBitMatrix, @@ -313,14 +229,14 @@ impl RegionValues { /// Each of the regions in num_region_variables will be initialized with an /// empty set of points and no causal information. pub(crate) fn new( - elements: &Rc, + elements: &Rc, num_universal_regions: usize, placeholder_indices: &Rc, ) -> Self { let num_placeholders = placeholder_indices.len(); Self { elements: elements.clone(), - points: SparseIntervalMatrix::new(elements.num_points), + points: SparseIntervalMatrix::new(elements.num_points()), placeholder_indices: placeholder_indices.clone(), free_regions: SparseBitMatrix::new(num_universal_regions), placeholders: SparseBitMatrix::new(num_placeholders), @@ -486,7 +402,7 @@ impl ToElementIndex for ty::PlaceholderRegion { /// For debugging purposes, returns a pretty-printed string of the given points. pub(crate) fn pretty_print_points( - elements: &RegionValueElements, + elements: &DenseLocationMap, points: impl IntoIterator, ) -> String { pretty_print_region_elements( diff --git a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs index 7433c94a0bcd1..da5456692ab13 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs @@ -2,9 +2,9 @@ use rustc_data_structures::vec_linked_list as vll; use rustc_index::IndexVec; use rustc_middle::mir::visit::{PlaceContext, Visitor}; use rustc_middle::mir::{Body, Local, Location}; +use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex}; use crate::def_use::{self, DefUse}; -use crate::region_infer::values::{PointIndex, RegionValueElements}; /// A map that cross references each local with the locations where it /// is defined (assigned), used, or dropped. Used during liveness @@ -60,7 +60,7 @@ impl vll::LinkElem for Appearance { impl LocalUseMap { pub(crate) fn build( live_locals: &[Local], - elements: &RegionValueElements, + elements: &DenseLocationMap, body: &Body<'_>, ) -> Self { let nones = IndexVec::from_elem(None, &body.local_decls); @@ -103,7 +103,7 @@ impl LocalUseMap { struct LocalUseMapBuild<'me> { local_use_map: &'me mut LocalUseMap, - elements: &'me RegionValueElements, + elements: &'me DenseLocationMap, // Vector used in `visit_local` to signal which `Local`s do we need // def/use/drop information on, constructed from `live_locals` (that @@ -144,7 +144,7 @@ impl LocalUseMapBuild<'_> { } fn insert( - elements: &RegionValueElements, + elements: &DenseLocationMap, first_appearance: &mut Option, appearances: &mut IndexVec, location: Location, diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs index e137bc1be0aeb..51ae7d14e4386 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs @@ -6,6 +6,7 @@ use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{GenericArgsRef, Region, RegionVid, Ty, TyCtxt}; use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::MoveData; +use rustc_mir_dataflow::points::DenseLocationMap; use rustc_mir_dataflow::ResultsCursor; use std::rc::Rc; @@ -13,7 +14,7 @@ use crate::{ constraints::OutlivesConstraintSet, facts::{AllFacts, AllFactsExt}, location::LocationTable, - region_infer::values::{LivenessValues, RegionValueElements}, + region_infer::values::LivenessValues, universal_regions::UniversalRegions, }; @@ -34,7 +35,7 @@ mod trace; pub(super) fn generate<'mir, 'tcx>( typeck: &mut TypeChecker<'_, 'tcx>, body: &Body<'tcx>, - elements: &Rc, + elements: &Rc, flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, move_data: &MoveData<'tcx>, location_table: &LocationTable, diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index c718d57bec399..eec128b5f1d58 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -7,6 +7,7 @@ use rustc_infer::infer::outlives::for_liveness; use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location}; use rustc_middle::traits::query::DropckOutlivesResult; use rustc_middle::ty::{Ty, TyCtxt, TypeVisitable, TypeVisitableExt}; +use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex}; use rustc_span::DUMMY_SP; use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives; use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; @@ -17,7 +18,7 @@ use rustc_mir_dataflow::move_paths::{HasMoveData, MoveData, MovePathIndex}; use rustc_mir_dataflow::ResultsCursor; use crate::{ - region_infer::values::{self, LiveLoans, PointIndex, RegionValueElements}, + region_infer::values::{self, LiveLoans}, type_check::liveness::local_use_map::LocalUseMap, type_check::liveness::polonius, type_check::NormalizeLocation, @@ -41,7 +42,7 @@ use crate::{ pub(super) fn trace<'mir, 'tcx>( typeck: &mut TypeChecker<'_, 'tcx>, body: &Body<'tcx>, - elements: &Rc, + elements: &Rc, flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, move_data: &MoveData<'tcx>, relevant_live_locals: Vec, @@ -105,7 +106,7 @@ struct LivenessContext<'me, 'typeck, 'flow, 'tcx> { typeck: &'me mut TypeChecker<'typeck, 'tcx>, /// Defines the `PointIndex` mapping - elements: &'me RegionValueElements, + elements: &'me DenseLocationMap, /// MIR we are analyzing. body: &'me Body<'tcx>, @@ -570,7 +571,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { } fn make_all_regions_live( - elements: &RegionValueElements, + elements: &DenseLocationMap, typeck: &mut TypeChecker<'_, 'tcx>, value: impl TypeVisitable>, live_at: &IntervalSet, diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 9c0f53ddb86fa..ea5593c09a972 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -35,6 +35,7 @@ use rustc_middle::ty::{ OpaqueHiddenType, OpaqueTypeKey, RegionVid, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, }; use rustc_middle::ty::{GenericArgsRef, UserArgs}; +use rustc_mir_dataflow::points::DenseLocationMap; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::symbol::sym; use rustc_span::{Span, DUMMY_SP}; @@ -58,9 +59,7 @@ use crate::{ location::LocationTable, member_constraints::MemberConstraintSet, path_utils, - region_infer::values::{ - LivenessValues, PlaceholderIndex, PlaceholderIndices, RegionValueElements, - }, + region_infer::values::{LivenessValues, PlaceholderIndex, PlaceholderIndices}, region_infer::TypeTest, type_check::free_region_relations::{CreateResult, UniversalRegionRelations}, universal_regions::{DefiningTy, UniversalRegions}, @@ -133,7 +132,7 @@ pub(crate) fn type_check<'mir, 'tcx>( all_facts: &mut Option, flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, move_data: &MoveData<'tcx>, - elements: &Rc, + elements: &Rc, upvars: &[&ty::CapturedPlace<'tcx>], use_polonius: bool, ) -> MirTypeckResults<'tcx> { @@ -545,7 +544,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { let all_facts = &mut None; let mut constraints = Default::default(); let mut liveness_constraints = - LivenessValues::new(Rc::new(RegionValueElements::new(promoted_body))); + LivenessValues::new(Rc::new(DenseLocationMap::new(promoted_body))); // Don't try to add borrow_region facts for the promoted MIR let mut swap_constraints = |this: &mut Self| { diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index f0b21fd418472..b805f8ca23eb4 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -34,6 +34,7 @@ mod errors; mod framework; pub mod impls; pub mod move_paths; +pub mod points; pub mod rustc_peek; pub mod storage; pub mod un_derefer; diff --git a/compiler/rustc_mir_dataflow/src/points.rs b/compiler/rustc_mir_dataflow/src/points.rs new file mode 100644 index 0000000000000..538e27ca1afb4 --- /dev/null +++ b/compiler/rustc_mir_dataflow/src/points.rs @@ -0,0 +1,94 @@ +use rustc_index::Idx; +use rustc_index::IndexVec; +use rustc_middle::mir::{BasicBlock, Body, Location}; + +/// Maps between a `Location` and a `PointIndex` (and vice versa). +pub struct DenseLocationMap { + /// For each basic block, how many points are contained within? + statements_before_block: IndexVec, + + /// Map backward from each point to the basic block that it + /// belongs to. + basic_blocks: IndexVec, + + num_points: usize, +} + +impl DenseLocationMap { + #[inline] + pub fn new(body: &Body<'_>) -> Self { + let mut num_points = 0; + let statements_before_block: IndexVec = body + .basic_blocks + .iter() + .map(|block_data| { + let v = num_points; + num_points += block_data.statements.len() + 1; + v + }) + .collect(); + debug!("DenseLocationMap: statements_before_block={:#?}", statements_before_block); + debug!("DenseLocationMap: num_points={:#?}", num_points); + + let mut basic_blocks = IndexVec::with_capacity(num_points); + for (bb, bb_data) in body.basic_blocks.iter_enumerated() { + basic_blocks.extend((0..=bb_data.statements.len()).map(|_| bb)); + } + + Self { statements_before_block, basic_blocks, num_points } + } + + /// Total number of point indices + #[inline] + pub fn num_points(&self) -> usize { + self.num_points + } + + /// Converts a `Location` into a `PointIndex`. O(1). + #[inline] + pub fn point_from_location(&self, location: Location) -> PointIndex { + let Location { block, statement_index } = location; + let start_index = self.statements_before_block[block]; + PointIndex::new(start_index + statement_index) + } + + /// Converts a `Location` into a `PointIndex`. O(1). + #[inline] + pub fn entry_point(&self, block: BasicBlock) -> PointIndex { + let start_index = self.statements_before_block[block]; + PointIndex::new(start_index) + } + + /// Return the PointIndex for the block start of this index. + #[inline] + pub fn to_block_start(&self, index: PointIndex) -> PointIndex { + PointIndex::new(self.statements_before_block[self.basic_blocks[index]]) + } + + /// Converts a `PointIndex` back to a location. O(1). + #[inline] + pub fn to_location(&self, index: PointIndex) -> Location { + assert!(index.index() < self.num_points); + let block = self.basic_blocks[index]; + let start_index = self.statements_before_block[block]; + let statement_index = index.index() - start_index; + Location { block, statement_index } + } + + /// Sometimes we get point-indices back from bitsets that may be + /// out of range (because they round up to the nearest 2^N number + /// of bits). Use this function to filter such points out if you + /// like. + #[inline] + pub fn point_in_range(&self, index: PointIndex) -> bool { + index.index() < self.num_points + } +} + +rustc_index::newtype_index! { + /// A single integer representing a `Location` in the MIR control-flow + /// graph. Constructed efficiently from `DenseLocationMap`. + #[orderable] + #[debug_format = "PointIndex({})"] + pub struct PointIndex {} +} From da235ce92db7270ad66ed7cd3e7bc8260c0c9b60 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 3 Dec 2023 13:32:02 +0000 Subject: [PATCH 0077/1197] Do not recompute liveness for DestinationPropagation. --- compiler/rustc_mir_dataflow/src/points.rs | 66 ++++++++++++++- compiler/rustc_mir_transform/src/dest_prop.rs | 81 +++++++++---------- 2 files changed, 102 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/points.rs b/compiler/rustc_mir_dataflow/src/points.rs index 538e27ca1afb4..161560516da2a 100644 --- a/compiler/rustc_mir_dataflow/src/points.rs +++ b/compiler/rustc_mir_dataflow/src/points.rs @@ -1,6 +1,9 @@ +use crate::framework::{visit_results, ResultsVisitable, ResultsVisitor}; +use rustc_index::bit_set::ChunkedBitSet; +use rustc_index::interval::SparseIntervalMatrix; use rustc_index::Idx; use rustc_index::IndexVec; -use rustc_middle::mir::{BasicBlock, Body, Location}; +use rustc_middle::mir::{self, BasicBlock, Body, Location}; /// Maps between a `Location` and a `PointIndex` (and vice versa). pub struct DenseLocationMap { @@ -92,3 +95,64 @@ rustc_index::newtype_index! { #[debug_format = "PointIndex({})"] pub struct PointIndex {} } + +/// Add points depending on the result of the given dataflow analysis. +pub fn save_as_intervals<'tcx, N, R>( + elements: &DenseLocationMap, + body: &mir::Body<'tcx>, + mut results: R, +) -> SparseIntervalMatrix +where + N: Idx, + R: ResultsVisitable<'tcx, FlowState = ChunkedBitSet>, +{ + let values = SparseIntervalMatrix::new(elements.num_points()); + let mut visitor = Visitor { elements, values }; + visit_results( + body, + body.basic_blocks.reverse_postorder().iter().copied(), + &mut results, + &mut visitor, + ); + visitor.values +} + +struct Visitor<'a, N: Idx> { + elements: &'a DenseLocationMap, + values: SparseIntervalMatrix, +} + +impl<'mir, 'tcx, R, N> ResultsVisitor<'mir, 'tcx, R> for Visitor<'_, N> +where + N: Idx, +{ + type FlowState = ChunkedBitSet; + + fn visit_statement_after_primary_effect( + &mut self, + _results: &mut R, + state: &Self::FlowState, + _statement: &'mir mir::Statement<'tcx>, + location: Location, + ) { + let point = self.elements.point_from_location(location); + // Use internal iterator manually as it is much more efficient. + state.iter().fold((), |(), node| { + self.values.insert(node, point); + }); + } + + fn visit_terminator_after_primary_effect( + &mut self, + _results: &mut R, + state: &Self::FlowState, + _terminator: &'mir mir::Terminator<'tcx>, + location: Location, + ) { + let point = self.elements.point_from_location(location); + // Use internal iterator manually as it is much more efficient. + state.iter().fold((), |(), node| { + self.values.insert(node, point); + }); + } +} diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index 49b0edc0db884..49bb114609c46 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -134,6 +134,7 @@ use crate::MirPass; use rustc_data_structures::fx::{FxIndexMap, IndexEntry, IndexOccupiedEntry}; use rustc_index::bit_set::BitSet; +use rustc_index::interval::SparseIntervalMatrix; use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; use rustc_middle::mir::HasLocalDecls; use rustc_middle::mir::{dump_mir, PassWhere}; @@ -143,7 +144,8 @@ use rustc_middle::mir::{ }; use rustc_middle::ty::TyCtxt; use rustc_mir_dataflow::impls::MaybeLiveLocals; -use rustc_mir_dataflow::{Analysis, ResultsCursor}; +use rustc_mir_dataflow::points::{save_as_intervals, DenseLocationMap, PointIndex}; +use rustc_mir_dataflow::Analysis; pub struct DestinationPropagation; @@ -167,6 +169,13 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation { let borrowed = rustc_mir_dataflow::impls::borrowed_locals(body); + let live = MaybeLiveLocals + .into_engine(tcx, body) + .pass_name("MaybeLiveLocals-DestinationPropagation") + .iterate_to_fixpoint(); + let points = DenseLocationMap::new(body); + let mut live = save_as_intervals(&points, body, live); + // In order to avoid having to collect data for every single pair of locals in the body, we // do not allow doing more than one merge for places that are derived from the same local at // once. To avoid missed opportunities, we instead iterate to a fixed point - we'll refer to @@ -190,22 +199,19 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation { &mut allocations.candidates_reverse, ); trace!(?candidates); - let mut live = MaybeLiveLocals - .into_engine(tcx, body) - .iterate_to_fixpoint() - .into_results_cursor(body); - dest_prop_mir_dump(tcx, body, &mut live, round_count); + dest_prop_mir_dump(tcx, body, &points, &live, round_count); FilterInformation::filter_liveness( &mut candidates, - &mut live, + &points, + &live, &mut allocations.write_info, body, ); - // Because we do not update liveness information, it is unsound to use a local for more - // than one merge operation within a single round of optimizations. We store here which - // ones we have already used. + // Because we only filter once per round, it is unsound to use a local for more than + // one merge operation within a single round of optimizations. We store here which ones + // we have already used. let mut merged_locals: BitSet = BitSet::new_empty(body.local_decls.len()); // This is the set of merges we will apply this round. It is a subset of the candidates. @@ -224,9 +230,15 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation { }) { break; } + + // Replace `src` by `dest` everywhere. merges.insert(*src, *dest); merged_locals.insert(*src); merged_locals.insert(*dest); + + // Update liveness information based on the merge we just performed. + // Every location where `src` was live, `dest` will be live. + live.union_rows(*src, *dest); } trace!(merging = ?merges); @@ -349,7 +361,8 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Merger<'a, 'tcx> { struct FilterInformation<'a, 'body, 'alloc, 'tcx> { body: &'body Body<'tcx>, - live: &'a mut ResultsCursor<'body, 'tcx, MaybeLiveLocals>, + points: &'a DenseLocationMap, + live: &'a SparseIntervalMatrix, candidates: &'a mut Candidates<'alloc>, write_info: &'alloc mut WriteInfo, at: Location, @@ -452,12 +465,14 @@ impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> { /// locals as also being read from. fn filter_liveness<'b>( candidates: &mut Candidates<'alloc>, - live: &mut ResultsCursor<'b, 'tcx, MaybeLiveLocals>, + points: &DenseLocationMap, + live: &SparseIntervalMatrix, write_info_alloc: &'alloc mut WriteInfo, body: &'b Body<'tcx>, ) { let mut this = FilterInformation { body, + points, live, candidates, // We don't actually store anything at this scope, we just keep things here to be able @@ -472,13 +487,11 @@ impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> { fn internal_filter_liveness(&mut self) { for (block, data) in traversal::preorder(self.body) { self.at = Location { block, statement_index: data.statements.len() }; - self.live.seek_after_primary_effect(self.at); self.write_info.for_terminator(&data.terminator().kind); self.apply_conflicts(); for (i, statement) in data.statements.iter().enumerate().rev() { self.at = Location { block, statement_index: i }; - self.live.seek_after_primary_effect(self.at); self.write_info.for_statement(&statement.kind, self.body); self.apply_conflicts(); } @@ -497,6 +510,7 @@ impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> { None } }); + let at = self.points.point_from_location(self.at); self.candidates.filter_candidates_by( *p, |q| { @@ -508,7 +522,7 @@ impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> { // calls or inline asm. Because of this, we also mark locals as // conflicting when both of them are written to in the same // statement. - if self.live.contains(q) || writes.contains(&q) { + if self.live.contains(q, at) || writes.contains(&q) { CandidateFilter::Remove } else { CandidateFilter::Keep @@ -801,38 +815,17 @@ fn is_local_required(local: Local, body: &Body<'_>) -> bool { fn dest_prop_mir_dump<'body, 'tcx>( tcx: TyCtxt<'tcx>, body: &'body Body<'tcx>, - live: &mut ResultsCursor<'body, 'tcx, MaybeLiveLocals>, + points: &DenseLocationMap, + live: &SparseIntervalMatrix, round: usize, ) { - let mut reachable = None; + let locals_live_at = |location| { + let location = points.point_from_location(location); + live.rows().filter(|&r| live.contains(r, location)).collect::>() + }; dump_mir(tcx, false, "DestinationPropagation-dataflow", &round, body, |pass_where, w| { - let reachable = reachable.get_or_insert_with(|| traversal::reachable_as_bitset(body)); - - match pass_where { - PassWhere::BeforeLocation(loc) if reachable.contains(loc.block) => { - live.seek_after_primary_effect(loc); - writeln!(w, " // live: {:?}", live.get())?; - } - PassWhere::AfterTerminator(bb) if reachable.contains(bb) => { - let loc = body.terminator_loc(bb); - live.seek_before_primary_effect(loc); - writeln!(w, " // live: {:?}", live.get())?; - } - - PassWhere::BeforeBlock(bb) if reachable.contains(bb) => { - live.seek_to_block_start(bb); - writeln!(w, " // live: {:?}", live.get())?; - } - - PassWhere::BeforeCFG | PassWhere::AfterCFG | PassWhere::AfterLocation(_) => {} - - PassWhere::BeforeLocation(_) | PassWhere::AfterTerminator(_) => { - writeln!(w, " // live: ")?; - } - - PassWhere::BeforeBlock(_) => { - writeln!(w, " // live: ")?; - } + if let PassWhere::BeforeLocation(loc) = pass_where { + writeln!(w, " // live: {:?}", locals_live_at(loc))?; } Ok(()) From 3082028be3707e2e4c88af2cf4d9d8ccc352a230 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 3 Dec 2023 13:33:56 +0000 Subject: [PATCH 0078/1197] Fix comment. --- compiler/rustc_mir_dataflow/src/points.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/points.rs b/compiler/rustc_mir_dataflow/src/points.rs index 161560516da2a..c111ab2b8819a 100644 --- a/compiler/rustc_mir_dataflow/src/points.rs +++ b/compiler/rustc_mir_dataflow/src/points.rs @@ -30,8 +30,6 @@ impl DenseLocationMap { v }) .collect(); - debug!("DenseLocationMap: statements_before_block={:#?}", statements_before_block); - debug!("DenseLocationMap: num_points={:#?}", num_points); let mut basic_blocks = IndexVec::with_capacity(num_points); for (bb, bb_data) in body.basic_blocks.iter_enumerated() { @@ -55,7 +53,7 @@ impl DenseLocationMap { PointIndex::new(start_index + statement_index) } - /// Converts a `Location` into a `PointIndex`. O(1). + /// Returns the `PointIndex` for the first statement in the given `BasicBlock`. O(1). #[inline] pub fn entry_point(&self, block: BasicBlock) -> PointIndex { let start_index = self.statements_before_block[block]; From 1d6723a77a642850e60559c7d9c64b4b5233c9be Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 7 Jan 2024 20:09:26 +0000 Subject: [PATCH 0079/1197] Use for_each instead of fold. --- compiler/rustc_mir_dataflow/src/points.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/points.rs b/compiler/rustc_mir_dataflow/src/points.rs index c111ab2b8819a..ff17ce1fe079a 100644 --- a/compiler/rustc_mir_dataflow/src/points.rs +++ b/compiler/rustc_mir_dataflow/src/points.rs @@ -135,7 +135,7 @@ where ) { let point = self.elements.point_from_location(location); // Use internal iterator manually as it is much more efficient. - state.iter().fold((), |(), node| { + state.iter().for_each(|node| { self.values.insert(node, point); }); } @@ -149,7 +149,7 @@ where ) { let point = self.elements.point_from_location(location); // Use internal iterator manually as it is much more efficient. - state.iter().fold((), |(), node| { + state.iter().for_each(|node| { self.values.insert(node, point); }); } From e6570dccccd85f5bfc8497bbd4db615f1d2fdbd2 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 3 Jan 2024 17:03:10 +1100 Subject: [PATCH 0080/1197] Use chaining for `DiagnosticBuilder` construction and `emit`. To avoid the use of a mutable local variable, and because it reads more nicely. --- src/driver/jit.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/driver/jit.rs b/src/driver/jit.rs index a8d8fb189e2e0..50d9f287e74c9 100644 --- a/src/driver/jit.rs +++ b/src/driver/jit.rs @@ -321,9 +321,10 @@ fn dep_symbol_lookup_fn( Linkage::NotLinked | Linkage::IncludedFromDylib => {} Linkage::Static => { let name = crate_info.crate_name[&cnum]; - let mut err = sess.dcx().struct_err(format!("Can't load static lib {}", name)); - err.note("rustc_codegen_cranelift can only load dylibs in JIT mode."); - err.emit(); + sess.dcx() + .struct_err(format!("Can't load static lib {}", name)) + .note("rustc_codegen_cranelift can only load dylibs in JIT mode.") + .emit(); } Linkage::Dynamic => { dylib_paths.push(src.dylib.as_ref().unwrap().0.clone()); From 1eaeaaf08b7135fd8d41339b90fdb6d189c89d69 Mon Sep 17 00:00:00 2001 From: sfzhu93 Date: Sun, 7 Jan 2024 21:16:22 -0800 Subject: [PATCH 0081/1197] Add FileCheck for array_index.rs, boolean_identities.rs and cast.rs --- tests/mir-opt/dataflow-const-prop/array_index.rs | 12 +++++++++++- .../dataflow-const-prop/boolean_identities.rs | 5 ++++- tests/mir-opt/dataflow-const-prop/cast.rs | 8 +++++++- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/tests/mir-opt/dataflow-const-prop/array_index.rs b/tests/mir-opt/dataflow-const-prop/array_index.rs index 3d420f930076d..42c99df969e37 100644 --- a/tests/mir-opt/dataflow-const-prop/array_index.rs +++ b/tests/mir-opt/dataflow-const-prop/array_index.rs @@ -1,9 +1,19 @@ -// skip-filecheck // EMIT_MIR_FOR_EACH_PANIC_STRATEGY // unit-test: DataflowConstProp // EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR array_index.main.DataflowConstProp.diff + +// CHECK-LABEL: fn main() -> () { fn main() { + // CHECK: let mut [[array_lit:_.*]]: [u32; 4]; + // CHECK: debug x => [[x:_.*]]; + let x: u32 = [0, 1, 2, 3][2]; + // CHECK: bb{{[0-9]+}}: { + // CHECK: [[array_lit]] = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; + // CHECK: [[index:_.*]] = const 2_usize; + // CHECK: bb{{[0-9]+}}: { + // CHECK-NOT: [[x]] = [[array_lit]][[[index]]]; + // CHECK: [[x]] = [[array_lit]][2 of 3]; } diff --git a/tests/mir-opt/dataflow-const-prop/boolean_identities.rs b/tests/mir-opt/dataflow-const-prop/boolean_identities.rs index 2605c7019e6f4..93e9b8d52fc2e 100644 --- a/tests/mir-opt/dataflow-const-prop/boolean_identities.rs +++ b/tests/mir-opt/dataflow-const-prop/boolean_identities.rs @@ -1,11 +1,14 @@ -// skip-filecheck // unit-test: DataflowConstProp // EMIT_MIR boolean_identities.test.DataflowConstProp.diff + +// CHECK-LABEL: fn test( pub fn test(x: bool, y: bool) -> bool { (y | true) & (x & false) + // CHECK: _0 = const false; } +// CHECK-LABEL: fn main( fn main() { test(true, false); } diff --git a/tests/mir-opt/dataflow-const-prop/cast.rs b/tests/mir-opt/dataflow-const-prop/cast.rs index c87872609dcf7..298ff49803936 100644 --- a/tests/mir-opt/dataflow-const-prop/cast.rs +++ b/tests/mir-opt/dataflow-const-prop/cast.rs @@ -1,8 +1,14 @@ -// skip-filecheck // unit-test: DataflowConstProp // EMIT_MIR cast.main.DataflowConstProp.diff + +// CHECK-LABEL: fn main( fn main() { + // CHECK: debug a => [[a:_.*]]; + // CHECK: debug b => [[b:_.*]]; + + // CHECK: [[a]] = const 257_i32; let a = 257; + // CHECK: [[b]] = const 2_u8; let b = a as u8 + 1; } From e05c779ee30fc7d2bdbb41ae95dd7e5b7d404621 Mon Sep 17 00:00:00 2001 From: sfzhu93 Date: Sun, 7 Jan 2024 21:16:55 -0800 Subject: [PATCH 0082/1197] Add FileCheck for checked.rs and default_boxed_slice.rs. --- tests/mir-opt/dataflow-const-prop/checked.rs | 17 ++++++++++++++++- .../dataflow-const-prop/default_boxed_slice.rs | 13 ++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/tests/mir-opt/dataflow-const-prop/checked.rs b/tests/mir-opt/dataflow-const-prop/checked.rs index f7fac8890a057..7350e5fb3d83a 100644 --- a/tests/mir-opt/dataflow-const-prop/checked.rs +++ b/tests/mir-opt/dataflow-const-prop/checked.rs @@ -1,15 +1,30 @@ -// skip-filecheck // unit-test: DataflowConstProp // compile-flags: -Coverflow-checks=on // EMIT_MIR_FOR_EACH_PANIC_STRATEGY // EMIT_MIR checked.main.DataflowConstProp.diff #[allow(arithmetic_overflow)] + +// CHECK-LABEL: fn main( fn main() { + // CHECK: debug a => [[a:_.*]]; + // CHECK: debug b => [[b:_.*]]; + // CHECK: debug c => [[c:_.*]]; + // CHECK: debug d => [[d:_.*]]; + // CHECK: debug e => [[e:_.*]]; + + // CHECK: [[a]] = const 1_i32; let a = 1; + + // CHECK: [[b]] = const 2_i32; let b = 2; + + // CHECK: [[c]] = const 3_i32; let c = a + b; + // CHECK: [[d]] = const _; let d = i32::MAX; + + // CHECK: [[e]] = const i32::MIN; let e = d + 1; } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs index 8006bd510e150..5917403450356 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs @@ -1,4 +1,3 @@ -// skip-filecheck // unit-test: DataflowConstProp // compile-flags: -Zmir-enable-passes=+GVN,+Inline // ignore-debug assertions change the output MIR @@ -11,8 +10,20 @@ struct A { // EMIT_MIR default_boxed_slice.main.GVN.diff // EMIT_MIR default_boxed_slice.main.DataflowConstProp.diff + +// CHECK-LABEL: fn main( fn main() { // ConstProp will create a constant of type `Box<[bool]>`. // Verify that `DataflowConstProp` does not ICE trying to dereference it directly. + + // CHECK: debug a => [[a:_.*]]; + // CHECK: scope {{[0-9]+}} (inlined as Default>::default) { + // CHECK: scope {{[0-9]+}} (inlined Unique::<[bool; 0]>::dangling) { + // CHECK: scope {{[0-9]+}} (inlined NonNull::<[bool; 0]>::dangling) { + // We may check other inlined functions as well... + + // CHECK: bb{{[0-9]+}}: { + // CHECK: [[box_obj:_.*]] = Box::<[bool]>(_3, const std::alloc::Global); + // CHECK: [[a]] = A { foo: move [[box_obj]] }; let a: A = A { foo: Box::default() }; } From 33e5d851a923ab46544d2cda70f80a59e4c1398c Mon Sep 17 00:00:00 2001 From: sfzhu93 Date: Sun, 7 Jan 2024 22:03:42 -0800 Subject: [PATCH 0083/1197] Add FileCheck for enum.rs --- ...enum.constant.DataflowConstProp.64bit.diff | 4 +- ...enum.multiple.DataflowConstProp.32bit.diff | 2 +- ...enum.multiple.DataflowConstProp.64bit.diff | 2 +- tests/mir-opt/dataflow-const-prop/enum.rs | 72 ++++++++++++++++--- .../enum.simple.DataflowConstProp.32bit.diff | 4 +- .../enum.simple.DataflowConstProp.64bit.diff | 4 +- .../enum.statics.DataflowConstProp.32bit.diff | 16 ++--- .../enum.statics.DataflowConstProp.64bit.diff | 16 ++--- 8 files changed, 86 insertions(+), 34 deletions(-) diff --git a/tests/mir-opt/dataflow-const-prop/enum.constant.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/enum.constant.DataflowConstProp.64bit.diff index 07ac5b72e244c..f50a763ef9a05 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.constant.DataflowConstProp.64bit.diff +++ b/tests/mir-opt/dataflow-const-prop/enum.constant.DataflowConstProp.64bit.diff @@ -14,10 +14,10 @@ debug x => _2; } scope 3 { - debug x => _4; + debug x1 => _4; } scope 4 { - debug x => _5; + debug x2 => _5; } } diff --git a/tests/mir-opt/dataflow-const-prop/enum.multiple.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/enum.multiple.DataflowConstProp.32bit.diff index 775325c4d0626..6bf702b856815 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.multiple.DataflowConstProp.32bit.diff +++ b/tests/mir-opt/dataflow-const-prop/enum.multiple.DataflowConstProp.32bit.diff @@ -14,7 +14,7 @@ let _6: u8; let _8: u8; scope 2 { - debug x => _6; + debug x2 => _6; let _9: u8; scope 4 { debug y => _9; diff --git a/tests/mir-opt/dataflow-const-prop/enum.multiple.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/enum.multiple.DataflowConstProp.64bit.diff index 775325c4d0626..6bf702b856815 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.multiple.DataflowConstProp.64bit.diff +++ b/tests/mir-opt/dataflow-const-prop/enum.multiple.DataflowConstProp.64bit.diff @@ -14,7 +14,7 @@ let _6: u8; let _8: u8; scope 2 { - debug x => _6; + debug x2 => _6; let _9: u8; scope 4 { debug y => _9; diff --git a/tests/mir-opt/dataflow-const-prop/enum.rs b/tests/mir-opt/dataflow-const-prop/enum.rs index e35c0e6e85bed..f33e424034440 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.rs +++ b/tests/mir-opt/dataflow-const-prop/enum.rs @@ -1,4 +1,3 @@ -// skip-filecheck // unit-test: DataflowConstProp // EMIT_MIR_FOR_EACH_BIT_WIDTH @@ -13,27 +12,66 @@ enum E { } // EMIT_MIR enum.simple.DataflowConstProp.diff + +// CHECK-LABEL: fn simple( fn simple() { + // CHECK: debug e => [[e:_.*]]; + // CHECK: debug x => [[x:_.*]]; + // CHECK: [[e]] = const E::V1(0_i32); let e = E::V1(0); - let x = match e { E::V1(x) => x, E::V2(x) => x }; + + // CHECK: switchInt(const 0_isize) -> [0: bb[[target_bb:[0-9]+]], 1: bb1, otherwise: bb2]; + // CHECK: bb[[target_bb]]: { + // CHECK: [[x]] = const 0_i32; + let x = match e { E::V1(x1) => x1, E::V2(x2) => x2 }; } // EMIT_MIR enum.constant.DataflowConstProp.diff + +// CHECK-LABEL: fn constant( fn constant() { + // CHECK: debug e => [[e:_.*]]; + // CHECK: debug x => [[x:_.*]]; const C: E = E::V1(0); + + // CHECK: [[e]] = const _; let e = C; - let x = match e { E::V1(x) => x, E::V2(x) => x }; + // CHECK: switchInt(const 0_isize) -> [0: bb[[target_bb:[0-9]+]], 1: bb1, otherwise: bb2]; + // CHECK: bb[[target_bb]]: { + // CHECK: [[x]] = const 0_i32; + let x = match e { E::V1(x1) => x1, E::V2(x2) => x2 }; } // EMIT_MIR enum.statics.DataflowConstProp.diff + +// CHECK-LABEL: fn statics( fn statics() { + // CHECK: debug e1 => [[e1:_.*]]; + // CHECK: debug x1 => [[x1:_.*]]; + // CHECK: debug e2 => [[e2:_.*]]; + // CHECK: debug x2 => [[x2:_.*]]; + static C: E = E::V1(0); - let e = C; - let x = match e { E::V1(x) => x, E::V2(x) => x }; + + // CHECK: [[e1]] = const E::V1(0_i32); + let e1 = C; + // CHECK: switchInt(const 0_isize) -> [0: bb[[target_bb1:[0-9]+]], 1: bb1, otherwise: bb2]; + // CHECK: bb[[target_bb]]: { + // CHECK: [[x1]] = const 0_i32; + let x1 = match e1 { E::V1(x11) => x11, E::V2(x12) => x12 }; static RC: &E = &E::V2(4); - let e = RC; - let x = match e { E::V1(x) => x, E::V2(x) => x }; + + // CHECK: [[t:_.*]] = const {alloc2: &&E}; + // CHECK: [[e2]] = (*[[t]]); + let e2 = RC; + // CHECK: switchInt(move _{{[0-9]+}}) -> [0: bb{{[0-9]+}}, 1: bb{{[0-9]+}}, otherwise: bb{{[0-9]+}}]; + // FIXME: add checks for x2. Currently, their MIRs are not symmetric in the two + // switch branches. + // One is `_9 = &(*_12) and another is `_9 = _11`. It is different from what we can + // get by printing MIR directly. It is better to check if there are any bugs in the + // MIR passes around this stage. + let x2 = match e2 { E::V1(x21) => x21, E::V2(x22) => x22 }; } #[rustc_layout_scalar_valid_range_start(1)] @@ -41,6 +79,8 @@ fn statics() { struct NonZeroUsize(usize); // EMIT_MIR enum.mutate_discriminant.DataflowConstProp.diff + +// CHECK-LABEL: fn mutate_discriminant( #[custom_mir(dialect = "runtime", phase = "post-cleanup")] fn mutate_discriminant() -> u8 { mir!( @@ -50,7 +90,11 @@ fn mutate_discriminant() -> u8 { // This assignment overwrites the niche in which the discriminant is stored. place!(Field(Field(Variant(x, 1), 0), 0)) = 0_usize; // So we cannot know the value of this discriminant. + + // CHECK: [[a:_.*]] = discriminant(_{{[0-9]*}}); let a = Discriminant(x); + + // CHECK: switchInt([[a]]) -> [0: bb{{[0-9]+}}, otherwise: bb{{[0-9]+}}]; match a { 0 => bb1, _ => bad, @@ -68,18 +112,26 @@ fn mutate_discriminant() -> u8 { } // EMIT_MIR enum.multiple.DataflowConstProp.diff +// CHECK-LABEL: fn multiple( fn multiple(x: bool, i: u8) { + // CHECK: debug x => [[x:_.*]]; + // CHECK: debug e => [[e:_.*]]; + // CHECK: debug x2 => [[x2:_.*]]; let e = if x { + // CHECK: [[e]] = Option::::Some(move _{{[0-9]+}}); Some(i) } else { + // CHECK: [[e]] = Option::::None; None }; // The dataflow state must have: // discriminant(e) => Top // (e as Some).0 => Top - let x = match e { Some(i) => i, None => 0 }; - // Therefore, `x` should be `Top` here, and no replacement shall happen. - let y = x; + // CHECK: [[x2]] = const 0_u8; + // CHECK: [[x2]] = _{{[0-9]+}} + let x2 = match e { Some(i) => i, None => 0 }; + // Therefore, `x2` should be `Top` here, and no replacement shall happen. + let y = x2; } fn main() { diff --git a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff index 798b0c041b4ec..b31f98460e45b 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff +++ b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff @@ -14,10 +14,10 @@ debug x => _2; } scope 3 { - debug x => _4; + debug x1 => _4; } scope 4 { - debug x => _5; + debug x2 => _5; } } diff --git a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff index 798b0c041b4ec..b31f98460e45b 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff +++ b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff @@ -14,10 +14,10 @@ debug x => _2; } scope 3 { - debug x => _4; + debug x1 => _4; } scope 4 { - debug x => _5; + debug x2 => _5; } } diff --git a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff index 053981abea3ec..44e8d39cca333 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff +++ b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff @@ -9,34 +9,34 @@ let mut _8: &&E; let mut _10: isize; scope 1 { - debug e => _1; + debug e1 => _1; let _3: i32; let _5: i32; let _6: i32; scope 2 { - debug x => _3; + debug x1 => _3; let _7: &E; scope 5 { - debug e => _7; + debug e2 => _7; let _9: &i32; let _11: &i32; let _12: &i32; scope 6 { - debug x => _9; + debug x2 => _9; } scope 7 { - debug x => _11; + debug x21 => _11; } scope 8 { - debug x => _12; + debug x22 => _12; } } } scope 3 { - debug x => _5; + debug x11 => _5; } scope 4 { - debug x => _6; + debug x12 => _6; } } diff --git a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff index d862bd93ff577..ac4ca086d0fed 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff +++ b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff @@ -9,34 +9,34 @@ let mut _8: &&E; let mut _10: isize; scope 1 { - debug e => _1; + debug e1 => _1; let _3: i32; let _5: i32; let _6: i32; scope 2 { - debug x => _3; + debug x1 => _3; let _7: &E; scope 5 { - debug e => _7; + debug e2 => _7; let _9: &i32; let _11: &i32; let _12: &i32; scope 6 { - debug x => _9; + debug x2 => _9; } scope 7 { - debug x => _11; + debug x21 => _11; } scope 8 { - debug x => _12; + debug x22 => _12; } } } scope 3 { - debug x => _5; + debug x11 => _5; } scope 4 { - debug x => _6; + debug x12 => _6; } } From 2b3cd46832d99218576b5d01c910a64a4330b542 Mon Sep 17 00:00:00 2001 From: Andrew Zhogin Date: Wed, 29 Nov 2023 12:49:48 +0700 Subject: [PATCH 0084/1197] Improved support of collapse_debuginfo attribute for macros. --- src/debuginfo/line_info.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/debuginfo/line_info.rs b/src/debuginfo/line_info.rs index 6230ca15d6e10..d1b21d0a0b6c5 100644 --- a/src/debuginfo/line_info.rs +++ b/src/debuginfo/line_info.rs @@ -68,15 +68,7 @@ impl DebugContext { // In order to have a good line stepping behavior in debugger, we overwrite debug // locations of macro expansions with that of the outermost expansion site (when the macro is // annotated with `#[collapse_debuginfo]` or when `-Zdebug-macros` is provided). - let span = if tcx.should_collapse_debuginfo(span) { - span - } else { - // Walk up the macro expansion chain until we reach a non-expanded span. - // We also stop at the function body level because no line stepping can occur - // at the level above that. - rustc_span::hygiene::walk_chain(span, function_span.ctxt()) - }; - + let span = tcx.collapsed_debuginfo(span, function_span); match tcx.sess.source_map().lookup_line(span.lo()) { Ok(SourceFileAndLine { sf: file, line }) => { let line_pos = file.lines()[line]; From 47443364e812ccdd3fb36f5f87503d075454244e Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Mon, 8 Jan 2024 09:46:34 -0500 Subject: [PATCH 0085/1197] Run the tier 2 sysroots job on a schedule, not push --- src/tools/miri/.github/workflows/sysroots.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/miri/.github/workflows/sysroots.yml b/src/tools/miri/.github/workflows/sysroots.yml index 509521e7478b0..96d7d4d111851 100644 --- a/src/tools/miri/.github/workflows/sysroots.yml +++ b/src/tools/miri/.github/workflows/sysroots.yml @@ -1,8 +1,8 @@ name: Tier 2 sysroots -on: push -# schedule: -# - cron: '44 4 * * *' # At 4:44 UTC every day. +on: + schedule: + - cron: '44 4 * * *' # At 4:44 UTC every day. defaults: run: From 8b52275ee34c829a29bbb677fffd7da48d242616 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 8 Jan 2024 09:27:52 -0700 Subject: [PATCH 0086/1197] rustdoc: hide modals when resizing the sidebar Follow-up for https://github.com/rust-lang/rust/pull/119477#discussion_r1439085011 --- src/librustdoc/html/static/js/main.js | 1 + .../sidebar-resize-close-popover.goml | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 tests/rustdoc-gui/sidebar-resize-close-popover.goml diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 88901191cda25..b46701b55ea7a 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -1721,6 +1721,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm } currentPointerId = e.pointerId; } + window.hideAllModals(false); e.preventDefault(); window.addEventListener("pointermove", resize, false); window.addEventListener("pointercancel", stopResize, false); diff --git a/tests/rustdoc-gui/sidebar-resize-close-popover.goml b/tests/rustdoc-gui/sidebar-resize-close-popover.goml new file mode 100644 index 0000000000000..2a8fbac855e97 --- /dev/null +++ b/tests/rustdoc-gui/sidebar-resize-close-popover.goml @@ -0,0 +1,20 @@ +// Checks sidebar resizing close the Settings popover +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" +assert-property: (".sidebar", {"clientWidth": "200"}) +show-text: true +click: "#settings-menu" +wait-for: "#settings" +assert-css: ("#settings", {"display": "block"}) +// normal resizing +drag-and-drop: ((205, 100), (185, 100)) +assert-property: (".sidebar", {"clientWidth": "182"}) +assert-css: ("#settings", {"display": "none"}) + +// Now same thing, but for source code +go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html" +click: "#settings-menu" +wait-for: "#settings" +assert-css: ("#settings", {"display": "block"}) +assert-property: (".sidebar", {"clientWidth": "49"}) +drag-and-drop: ((52, 100), (185, 100)) +assert-css: ("#settings", {"display": "none"}) From 6dd0772707eb50a8129eb0a748cd9ef3de6a754a Mon Sep 17 00:00:00 2001 From: sjwang05 <63834813+sjwang05@users.noreply.github.com> Date: Fri, 22 Dec 2023 21:56:58 -0800 Subject: [PATCH 0087/1197] Emit suggestion when trying to write exclusive ranges as `..<` --- .../rustc_parse/src/parser/diagnostics.rs | 25 ++++++++-- compiler/rustc_parse/src/parser/expr.rs | 10 +++- tests/ui/parser/range-exclusive-dotdotlt.rs | 43 +++++++++++++++++ .../ui/parser/range-exclusive-dotdotlt.stderr | 46 +++++++++++++++++++ 4 files changed, 117 insertions(+), 7 deletions(-) create mode 100644 tests/ui/parser/range-exclusive-dotdotlt.rs create mode 100644 tests/ui/parser/range-exclusive-dotdotlt.stderr diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index a9cf26d991c71..dc7a4d5aa3831 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -23,7 +23,7 @@ use crate::parser; use crate::parser::attr::InnerAttrPolicy; use rustc_ast as ast; use rustc_ast::ptr::P; -use rustc_ast::token::{self, Delimiter, Lit, LitKind, TokenKind}; +use rustc_ast::token::{self, Delimiter, Lit, LitKind, Token, TokenKind}; use rustc_ast::tokenstream::AttrTokenTree; use rustc_ast::util::parser::AssocOp; use rustc_ast::{ @@ -448,12 +448,11 @@ impl<'a> Parser<'a> { }) } - let mut expected = edible + self.expected_tokens.extend(edible.iter().chain(inedible).cloned().map(TokenType::Token)); + let mut expected = self + .expected_tokens .iter() - .chain(inedible) .cloned() - .map(TokenType::Token) - .chain(self.expected_tokens.iter().cloned()) .filter(|token| { // Filter out suggestions that suggest the same token which was found and deemed incorrect. fn is_ident_eq_keyword(found: &TokenKind, expected: &TokenType) -> bool { @@ -2927,6 +2926,22 @@ impl<'a> Parser<'a> { Ok(()) } + /// Check for exclusive ranges written as `..<` + pub(crate) fn maybe_err_dotdotlt_syntax(&self, maybe_lt: Token, mut err: PErr<'a>) -> PErr<'a> { + if maybe_lt == token::Lt + && (self.expected_tokens.contains(&TokenType::Token(token::Gt)) + || matches!(self.token.kind, token::Literal(..))) + { + err.span_suggestion( + maybe_lt.span, + "remove the `<` to write an exclusive range", + "", + Applicability::MachineApplicable, + ); + } + err + } + pub fn is_diff_marker(&mut self, long_kind: &TokenKind, short_kind: &TokenKind) -> bool { (0..3).all(|i| self.look_ahead(i, |tok| tok == long_kind)) && self.look_ahead(3, |tok| tok == short_kind) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index db777266b59d2..7f4d26b370f1a 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -483,7 +483,11 @@ impl<'a> Parser<'a> { cur_op_span: Span, ) -> PResult<'a, P> { let rhs = if self.is_at_start_of_range_notation_rhs() { - Some(self.parse_expr_assoc_with(prec + 1, LhsExpr::NotYetParsed)?) + let maybe_lt = self.token.clone(); + Some( + self.parse_expr_assoc_with(prec + 1, LhsExpr::NotYetParsed) + .map_err(|err| self.maybe_err_dotdotlt_syntax(maybe_lt, err))?, + ) } else { None }; @@ -532,11 +536,13 @@ impl<'a> Parser<'a> { let attrs = self.parse_or_use_outer_attributes(attrs)?; self.collect_tokens_for_expr(attrs, |this, attrs| { let lo = this.token.span; + let maybe_lt = this.look_ahead(1, |t| t.clone()); this.bump(); let (span, opt_end) = if this.is_at_start_of_range_notation_rhs() { // RHS must be parsed with more associativity than the dots. this.parse_expr_assoc_with(op.unwrap().precedence() + 1, LhsExpr::NotYetParsed) - .map(|x| (lo.to(x.span), Some(x)))? + .map(|x| (lo.to(x.span), Some(x))) + .map_err(|err| this.maybe_err_dotdotlt_syntax(maybe_lt, err))? } else { (lo, None) }; diff --git a/tests/ui/parser/range-exclusive-dotdotlt.rs b/tests/ui/parser/range-exclusive-dotdotlt.rs new file mode 100644 index 0000000000000..5752566026f02 --- /dev/null +++ b/tests/ui/parser/range-exclusive-dotdotlt.rs @@ -0,0 +1,43 @@ +fn foo() { + let _ = 0..<10; + //~^ ERROR: expected type, found `10` + //~| HELP: remove the `<` to write an exclusive range +} + +fn bar() { + let _ = 0..`, or `as`, found `;` + //~| HELP: remove the `<` to write an exclusive range +} + +fn baz() { + let _ = ; + //~^ ERROR: expected `::`, found `;` +} + +fn qux() { + let _ = [1, 2, 3][..<1]; + //~^ ERROR: expected type, found `1` + //~| HELP: remove the `<` to write an exclusive range +} + +fn quux() { + let _ = [1, 2, 3][..`, or `as`, found `]` + //~| HELP: remove the `<` to write an exclusive range +} + +fn foobar() { + let _ = [1, 2, 3][..]; + //~^ ERROR: expected `::`, found `]` +} + +fn ok1() { + let _ = [1, 2, 3][..::default()]; +} + +fn ok2() { + let _ = 0..::default(); +} + +fn main() {} diff --git a/tests/ui/parser/range-exclusive-dotdotlt.stderr b/tests/ui/parser/range-exclusive-dotdotlt.stderr new file mode 100644 index 0000000000000..af25e1df343de --- /dev/null +++ b/tests/ui/parser/range-exclusive-dotdotlt.stderr @@ -0,0 +1,46 @@ +error: expected type, found `10` + --> $DIR/range-exclusive-dotdotlt.rs:2:17 + | +LL | let _ = 0..<10; + | -^^ expected type + | | + | help: remove the `<` to write an exclusive range + +error: expected one of `!`, `(`, `+`, `::`, `<`, `>`, or `as`, found `;` + --> $DIR/range-exclusive-dotdotlt.rs:8:20 + | +LL | let _ = 0.. $DIR/range-exclusive-dotdotlt.rs:14:18 + | +LL | let _ = ; + | ^ expected `::` + +error: expected type, found `1` + --> $DIR/range-exclusive-dotdotlt.rs:19:26 + | +LL | let _ = [1, 2, 3][..<1]; + | -^ expected type + | | + | help: remove the `<` to write an exclusive range + +error: expected one of `!`, `(`, `+`, `::`, `<`, `>`, or `as`, found `]` + --> $DIR/range-exclusive-dotdotlt.rs:25:29 + | +LL | let _ = [1, 2, 3][.. $DIR/range-exclusive-dotdotlt.rs:31:30 + | +LL | let _ = [1, 2, 3][..]; + | ^ expected `::` + +error: aborting due to 6 previous errors + From 24aefa0e5d134526c8e29c5603dcb4d42637968a Mon Sep 17 00:00:00 2001 From: sfzhu93 Date: Mon, 8 Jan 2024 16:58:58 -0800 Subject: [PATCH 0088/1197] Add FileCheck for if.rs, inherit_overflow.rs, issue_81605.rs --- tests/mir-opt/dataflow-const-prop/if.rs | 18 +++++++++++++++++- .../dataflow-const-prop/inherit_overflow.rs | 5 ++++- .../mir-opt/dataflow-const-prop/issue_81605.rs | 5 ++++- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/tests/mir-opt/dataflow-const-prop/if.rs b/tests/mir-opt/dataflow-const-prop/if.rs index 72aabbccf56c8..28e0ee9c622f5 100644 --- a/tests/mir-opt/dataflow-const-prop/if.rs +++ b/tests/mir-opt/dataflow-const-prop/if.rs @@ -1,12 +1,28 @@ -// skip-filecheck // unit-test: DataflowConstProp // EMIT_MIR if.main.DataflowConstProp.diff +// CHECK-LABEL: fn main( fn main() { + // CHECK: debug b => [[b:_.*]]; + // CHECK: debug c => [[c:_.*]]; + // CHECK: debug d => [[d:_.*]]; + // CHECK: debug e => [[e:_.*]]; + let a = 1; + + // CHECK: switchInt(const true) -> [0: {{bb[0-9]+}}, otherwise: [[bb_first_true:bb[0-9]+]]]; + // CHECK: [[bb_first_true]]: { + // CHECK: [[b]] = const 2_i32; let b = if a == 1 { 2 } else { 3 }; + + // CHECK: [[c]] = const 3_i32; let c = b + 1; + // CHECK: switchInt(const true) -> [0: {{bb[0-9]+}}, otherwise: [[bb_second_true:bb[0-9]+]]]; + // CHECK: [[bb_second_true]]: { + // CHECK: [[d]] = const 1_i32; let d = if a == 1 { a } else { a + 1 }; + + // CHECK: [[e]] = const 2_i32; let e = d + 1; } diff --git a/tests/mir-opt/dataflow-const-prop/inherit_overflow.rs b/tests/mir-opt/dataflow-const-prop/inherit_overflow.rs index 664cbcb2c259f..0a2774c782009 100644 --- a/tests/mir-opt/dataflow-const-prop/inherit_overflow.rs +++ b/tests/mir-opt/dataflow-const-prop/inherit_overflow.rs @@ -1,11 +1,14 @@ -// skip-filecheck // EMIT_MIR_FOR_EACH_PANIC_STRATEGY // unit-test: DataflowConstProp // compile-flags: -Zmir-enable-passes=+Inline // EMIT_MIR inherit_overflow.main.DataflowConstProp.diff +// CHECK-LABEL: fn main( fn main() { // After inlining, this will contain a `CheckedBinaryOp`. // Propagating the overflow is ok as codegen will just skip emitting the panic. + + // CHECK: {{_.*}} = const (0_u8, true); + // CHECK-LABEL: assert(!const true, let _ = ::add(255, 1); } diff --git a/tests/mir-opt/dataflow-const-prop/issue_81605.rs b/tests/mir-opt/dataflow-const-prop/issue_81605.rs index 7c5eceb8a2b68..e8a00c72eb66b 100644 --- a/tests/mir-opt/dataflow-const-prop/issue_81605.rs +++ b/tests/mir-opt/dataflow-const-prop/issue_81605.rs @@ -1,9 +1,12 @@ -// skip-filecheck // unit-test: DataflowConstProp // EMIT_MIR issue_81605.f.DataflowConstProp.diff + +// CHECK-LABEL: fn f fn f() -> usize { + // CHECK: switchInt(const true) -> [0: {{bb[0-9]+}}, otherwise: {{bb[0-9]+}}]; 1 + if true { 1 } else { 2 } + // CHECK: _0 = const 2_usize; } fn main() { From 1b08e25c9db5dbe000397b96db1c0ad45d5a9bb1 Mon Sep 17 00:00:00 2001 From: vuittont60 <81072379+vuittont60@users.noreply.github.com> Date: Mon, 8 Jan 2024 14:08:19 +0800 Subject: [PATCH 0089/1197] fix typo --- tests/rustdoc-ui/error-in-impl-trait/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/rustdoc-ui/error-in-impl-trait/README.md b/tests/rustdoc-ui/error-in-impl-trait/README.md index d969ab10ef5ea..0b42ff1771e20 100644 --- a/tests/rustdoc-ui/error-in-impl-trait/README.md +++ b/tests/rustdoc-ui/error-in-impl-trait/README.md @@ -1,5 +1,5 @@ Each of these needs to be in a separate file, -because the `span_delayed_bug` ICE in rustdoc won't be triggerred +because the `span_delayed_bug` ICE in rustdoc won't be triggered if even a single other error was emitted. However, conceptually they are all testing basically the same thing. From 9452d7ed1acd62c44dbec775d42f41b508c572bf Mon Sep 17 00:00:00 2001 From: sfzhu93 Date: Mon, 8 Jan 2024 20:18:59 -0800 Subject: [PATCH 0090/1197] Add FileCheck to 3 tests: large_array_index, mult_by_zero, and offset_of --- .../dataflow-const-prop/large_array_index.rs | 10 ++++++- .../dataflow-const-prop/mult_by_zero.rs | 3 +- .../mir-opt/dataflow-const-prop/offset_of.rs | 29 ++++++++++++++++++- 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/tests/mir-opt/dataflow-const-prop/large_array_index.rs b/tests/mir-opt/dataflow-const-prop/large_array_index.rs index d611a54ba71a2..6b8a0248d19bc 100644 --- a/tests/mir-opt/dataflow-const-prop/large_array_index.rs +++ b/tests/mir-opt/dataflow-const-prop/large_array_index.rs @@ -1,10 +1,18 @@ -// skip-filecheck // unit-test: DataflowConstProp // EMIT_MIR_FOR_EACH_PANIC_STRATEGY // EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR large_array_index.main.DataflowConstProp.diff + +// CHECK-LABEL: fn main fn main() { // check that we don't propagate this, because it's too large + + // CHECK: debug x => [[x:_.*]]; + // CHECK: [[array_lit:_.*]] = [const 0_u8; 5000]; + // CHECK: {{_.*}} = const 5000_usize; + // CHECK: {{_.*}} = const true; + // CHECK-LABEL: assert(const true + // CHECK: [[x]] = [[array_lit]][2 of 3]; let x: u8 = [0_u8; 5000][2]; } diff --git a/tests/mir-opt/dataflow-const-prop/mult_by_zero.rs b/tests/mir-opt/dataflow-const-prop/mult_by_zero.rs index 16a45c8e9fb59..c7e05579e4005 100644 --- a/tests/mir-opt/dataflow-const-prop/mult_by_zero.rs +++ b/tests/mir-opt/dataflow-const-prop/mult_by_zero.rs @@ -1,9 +1,10 @@ -// skip-filecheck // unit-test: DataflowConstProp // EMIT_MIR mult_by_zero.test.DataflowConstProp.diff +// CHECK-LABEL: fn test fn test(x : i32) -> i32 { x * 0 + // CHECK: _0 = const 0_i32; } fn main() { diff --git a/tests/mir-opt/dataflow-const-prop/offset_of.rs b/tests/mir-opt/dataflow-const-prop/offset_of.rs index e71b3f59ecab3..a2032ea996edd 100644 --- a/tests/mir-opt/dataflow-const-prop/offset_of.rs +++ b/tests/mir-opt/dataflow-const-prop/offset_of.rs @@ -1,4 +1,3 @@ -// skip-filecheck // unit-test: DataflowConstProp // EMIT_MIR_FOR_EACH_PANIC_STRATEGY @@ -29,18 +28,46 @@ struct Delta { } // EMIT_MIR offset_of.concrete.DataflowConstProp.diff + +// CHECK-LABEL: fn concrete fn concrete() { + // CHECK: debug x => [[x:_.*]]; + // CHECK: debug y => [[y:_.*]]; + // CHECK: debug z0 => [[z0:_.*]]; + // CHECK: debug z1 => [[z1:_.*]]; + + // CHECK: [[x]] = must_use::(const 4_usize) -> [return: {{bb[0-9]+}}, unwind continue]; let x = offset_of!(Alpha, x); + + // CHECK: [[y]] = must_use::(const 0_usize) -> [return: {{bb[0-9]+}}, unwind continue]; let y = offset_of!(Alpha, y); + + // CHECK: [[z0]] = must_use::(const 2_usize) -> [return: {{bb[0-9]+}}, unwind continue]; let z0 = offset_of!(Alpha, z.0); + + // CHECK: [[z1]] = must_use::(const 3_usize) -> [return: {{bb[0-9]+}}, unwind continue]; let z1 = offset_of!(Alpha, z.1); } // EMIT_MIR offset_of.generic.DataflowConstProp.diff + +// CHECK-LABEL: generic fn generic() { + // CHECK: debug gx => [[gx:_.*]]; + // CHECK: debug gy => [[gy:_.*]]; + // CHECK: debug dx => [[dx:_.*]]; + // CHECK: debug dy => [[dy:_.*]]; + + // CHECK: [[gx]] = must_use::(move {{_[0-9]+}}) -> [return: {{bb[0-9]+}}, unwind continue]; let gx = offset_of!(Gamma, x); + + // CHECK: [[gy]] = must_use::(move {{_[0-9]+}}) -> [return: {{bb[0-9]+}}, unwind continue]; let gy = offset_of!(Gamma, y); + + // CHECK: [[dx]] = must_use::(const 0_usize) -> [return: {{bb[0-9]+}}, unwind continue]; let dx = offset_of!(Delta, x); + + // CHECK: [[dy]] = must_use::(const 2_usize) -> [return: {{bb[0-9]+}}, unwind continue]; let dy = offset_of!(Delta, y); } From e9152e2b6c95aad0f3c89af8b0f98a0cbf4f45c7 Mon Sep 17 00:00:00 2001 From: sfzhu93 Date: Mon, 8 Jan 2024 20:19:59 -0800 Subject: [PATCH 0091/1197] Add FileCheck to 3 tests: ref_without_sb, repeat, repr_transparent --- tests/mir-opt/dataflow-const-prop/ref_without_sb.rs | 11 ++++++++++- tests/mir-opt/dataflow-const-prop/repeat.rs | 10 +++++++++- tests/mir-opt/dataflow-const-prop/repr_transparent.rs | 9 ++++++++- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/tests/mir-opt/dataflow-const-prop/ref_without_sb.rs b/tests/mir-opt/dataflow-const-prop/ref_without_sb.rs index 2851c0590ad5f..fb66cda38ddbd 100644 --- a/tests/mir-opt/dataflow-const-prop/ref_without_sb.rs +++ b/tests/mir-opt/dataflow-const-prop/ref_without_sb.rs @@ -1,4 +1,3 @@ -// skip-filecheck // EMIT_MIR_FOR_EACH_PANIC_STRATEGY // unit-test: DataflowConstProp @@ -9,11 +8,21 @@ fn escape(x: &T) {} fn some_function() {} // EMIT_MIR ref_without_sb.main.DataflowConstProp.diff +// CHECK-LABEL: fn main fn main() { + // CHECK: debug a => [[a:_.*]]; + // CHECK: debug b => [[b:_.*]]; + let mut a = 0; + + // CHECK: {{_[0-9]+}} = escape::(move {{_[0-9]+}}) -> [return: {{bb[0-9]+}}, unwind continue]; escape(&a); a = 1; + + // CHECK: {{_[0-9]+}} = some_function() -> [return: {{bb[0-9]+}}, unwind continue]; some_function(); // This should currently not be propagated. + + // CHECK: [[b]] = [[a]]; let b = a; } diff --git a/tests/mir-opt/dataflow-const-prop/repeat.rs b/tests/mir-opt/dataflow-const-prop/repeat.rs index b824481948116..5d1c1a3edb695 100644 --- a/tests/mir-opt/dataflow-const-prop/repeat.rs +++ b/tests/mir-opt/dataflow-const-prop/repeat.rs @@ -1,9 +1,17 @@ -// skip-filecheck // unit-test: DataflowConstProp // EMIT_MIR_FOR_EACH_PANIC_STRATEGY // EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR repeat.main.DataflowConstProp.diff +// CHECK-LABEL: fn main fn main() { + // CHECK: debug x => [[x:_.*]]; + + // CHECK: {{_[0-9]+}} = const 8_usize; + // CHECK: {{_[0-9]+}} = const true; + // CHECK-LABEL: assert(const true + + // CHECK: {{_[0-9]+}} = {{_[0-9]+}}[2 of 3]; + // CHECK: [[x]] = Add(move {{_[0-9]+}}, const 0_u32); let x: u32 = [42; 8][2] + 0; } diff --git a/tests/mir-opt/dataflow-const-prop/repr_transparent.rs b/tests/mir-opt/dataflow-const-prop/repr_transparent.rs index 8cbed6fbb624d..d007301e568b1 100644 --- a/tests/mir-opt/dataflow-const-prop/repr_transparent.rs +++ b/tests/mir-opt/dataflow-const-prop/repr_transparent.rs @@ -1,4 +1,3 @@ -// skip-filecheck // unit-test: DataflowConstProp // The struct has scalar ABI, but is not a scalar type. @@ -7,7 +6,15 @@ struct I32(i32); // EMIT_MIR repr_transparent.main.DataflowConstProp.diff + +// CHECK-LABEL: fn main fn main() { + // CHECK: debug x => [[x:_.*]]; + // CHECK: debug y => [[y:_.*]]; + + // CHECK: [[x]] = const I32(0_i32); let x = I32(0); + + // CHECK: [[y]] = const I32(0_i32); let y = I32(x.0 + x.0); } From 3ab1d5d4506924b6d020c8edf539d2be6b7bb9e9 Mon Sep 17 00:00:00 2001 From: sfzhu93 Date: Mon, 8 Jan 2024 20:20:27 -0800 Subject: [PATCH 0092/1197] Add FileCheck to 3 tests: self_assign_add, self_assign, and sibling_ptr --- tests/mir-opt/dataflow-const-prop/self_assign.rs | 15 ++++++++++++++- .../dataflow-const-prop/self_assign_add.rs | 8 +++++++- tests/mir-opt/dataflow-const-prop/sibling_ptr.rs | 7 ++++++- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/tests/mir-opt/dataflow-const-prop/self_assign.rs b/tests/mir-opt/dataflow-const-prop/self_assign.rs index c5866c4a9fd98..7d58b972d655b 100644 --- a/tests/mir-opt/dataflow-const-prop/self_assign.rs +++ b/tests/mir-opt/dataflow-const-prop/self_assign.rs @@ -1,13 +1,26 @@ -// skip-filecheck // unit-test: DataflowConstProp // EMIT_MIR self_assign.main.DataflowConstProp.diff + +// CHECK-LABEL: fn main fn main() { + // CHECK: debug a => [[a:_.*]]; + // CHECK: debug b => [[b:_.*]]; + let mut a = 0; + + // CHECK: [[a]] = Add(move {{_[0-9]+}}, const 1_i32); a = a + 1; + + // CHECK: [[a]] = move {{_[0-9]+}}; a = a; + // CHECK: [[b]] = &[[a]]; let mut b = &a; + + // CHECK: [[b]] = move {{_[0-9]+}}; b = b; + + // CHECK: [[a]] = move {{_[0-9]+}}; a = *b; } diff --git a/tests/mir-opt/dataflow-const-prop/self_assign_add.rs b/tests/mir-opt/dataflow-const-prop/self_assign_add.rs index cfe1458e44be7..09be3865d60b3 100644 --- a/tests/mir-opt/dataflow-const-prop/self_assign_add.rs +++ b/tests/mir-opt/dataflow-const-prop/self_assign_add.rs @@ -1,9 +1,15 @@ -// skip-filecheck // unit-test: DataflowConstProp // EMIT_MIR self_assign_add.main.DataflowConstProp.diff + +// CHECK-LABEL: fn main fn main() { + // CHECK: debug a => [[a:_.*]]; let mut a = 0; + + // CHECK: [[a]] = const 1_i32; a += 1; + + // CHECK: [[a]] = const 2_i32; a += 1; } diff --git a/tests/mir-opt/dataflow-const-prop/sibling_ptr.rs b/tests/mir-opt/dataflow-const-prop/sibling_ptr.rs index 68aff528695d5..6e39e39839410 100644 --- a/tests/mir-opt/dataflow-const-prop/sibling_ptr.rs +++ b/tests/mir-opt/dataflow-const-prop/sibling_ptr.rs @@ -1,4 +1,3 @@ -// skip-filecheck // EMIT_MIR_FOR_EACH_PANIC_STRATEGY // This attempts to modify `x.1` via a pointer derived from `addr_of_mut!(x.0)`. // According to Miri, that is UB. However, T-opsem has not finalized that @@ -10,11 +9,17 @@ // unit-test: DataflowConstProp // EMIT_MIR sibling_ptr.main.DataflowConstProp.diff + +// CHECK-LABEL: fn main fn main() { + // CHECK: debug x1 => [[x1:_[0-9]+]]; + let mut x: (u8, u8) = (0, 0); unsafe { let p = std::ptr::addr_of_mut!(x.0); *p.add(1) = 1; } + + // CHECK: [[x1]] = ({{_[0-9]+}}.1: u8); let x1 = x.1; // should not be propagated } From d765e3ae1faf4786b56da542c9dc5fbfc18162d8 Mon Sep 17 00:00:00 2001 From: sfzhu93 Date: Mon, 8 Jan 2024 20:20:53 -0800 Subject: [PATCH 0093/1197] Add FileCheck to slice_len.rs --- tests/mir-opt/dataflow-const-prop/slice_len.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.rs b/tests/mir-opt/dataflow-const-prop/slice_len.rs index 86266ef5d4e60..cd63980949638 100644 --- a/tests/mir-opt/dataflow-const-prop/slice_len.rs +++ b/tests/mir-opt/dataflow-const-prop/slice_len.rs @@ -1,13 +1,23 @@ -// skip-filecheck // EMIT_MIR_FOR_EACH_PANIC_STRATEGY // unit-test: DataflowConstProp // compile-flags: -Zmir-enable-passes=+InstSimplify // EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR slice_len.main.DataflowConstProp.diff + +// CHECK-LABEL: fn main fn main() { + // CHECK: debug local => [[local:_[0-9]+]]; + // CHECK: debug constant => [[constant:_[0-9]+]]; + + // CHECK: {{_[0-9]+}} = const 3_usize; + // CHECK: {{_[0-9]+}} = const true; + + // CHECK: [[local]] = (*{{_[0-9]+}})[1 of 2]; let local = (&[1u32, 2, 3] as &[u32])[1]; const SLICE: &[u32] = &[1, 2, 3]; + + // CHECK: [[constant]] = (*{{_[0-9]+}})[1 of 2]; let constant = SLICE[1]; } From 732f6a1303c4e3f9a354221e76e065571b2f1e37 Mon Sep 17 00:00:00 2001 From: sfzhu93 Date: Mon, 8 Jan 2024 20:21:06 -0800 Subject: [PATCH 0094/1197] Add FileCheck to struct.rs --- .../struct.main.DataflowConstProp.32bit.diff | 24 ++++---- .../struct.main.DataflowConstProp.64bit.diff | 24 ++++---- tests/mir-opt/dataflow-const-prop/struct.rs | 55 ++++++++++++++++--- 3 files changed, 72 insertions(+), 31 deletions(-) diff --git a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff index 0f461f515fdd0..c486281d6f8d7 100644 --- a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff +++ b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff @@ -37,16 +37,16 @@ let _8: std::option::Option; let _9: &[f32]; scope 4 { - debug a => _7; - debug b => _8; - debug c => _9; + debug a1 => _7; + debug b1 => _8; + debug c1 => _9; let _11: f32; let _12: std::option::Option; let _13: &[f32]; scope 5 { - debug a => _11; - debug b => _12; - debug c => _13; + debug a2 => _11; + debug b2 => _12; + debug c2 => _13; let _15: SmallStruct; scope 6 { debug ss => _15; @@ -54,16 +54,16 @@ let _20: std::option::Option; let _21: &[f32]; scope 7 { - debug a => _19; - debug b => _20; - debug c => _21; + debug a3 => _19; + debug b3 => _20; + debug c3 => _21; let _23: f32; let _24: std::option::Option; let _25: &[f32]; scope 8 { - debug a => _23; - debug b => _24; - debug c => _25; + debug a4 => _23; + debug b4 => _24; + debug c4 => _25; let _27: BigStruct; scope 9 { debug bs => _27; diff --git a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff index 3c40ec8bfb450..7ea53d157334d 100644 --- a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff +++ b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff @@ -37,16 +37,16 @@ let _8: std::option::Option; let _9: &[f32]; scope 4 { - debug a => _7; - debug b => _8; - debug c => _9; + debug a1 => _7; + debug b1 => _8; + debug c1 => _9; let _11: f32; let _12: std::option::Option; let _13: &[f32]; scope 5 { - debug a => _11; - debug b => _12; - debug c => _13; + debug a2 => _11; + debug b2 => _12; + debug c2 => _13; let _15: SmallStruct; scope 6 { debug ss => _15; @@ -54,16 +54,16 @@ let _20: std::option::Option; let _21: &[f32]; scope 7 { - debug a => _19; - debug b => _20; - debug c => _21; + debug a3 => _19; + debug b3 => _20; + debug c3 => _21; let _23: f32; let _24: std::option::Option; let _25: &[f32]; scope 8 { - debug a => _23; - debug b => _24; - debug c => _25; + debug a4 => _23; + debug b4 => _24; + debug c4 => _25; let _27: BigStruct; scope 9 { debug bs => _27; diff --git a/tests/mir-opt/dataflow-const-prop/struct.rs b/tests/mir-opt/dataflow-const-prop/struct.rs index 043981a295484..4eec15a7f1630 100644 --- a/tests/mir-opt/dataflow-const-prop/struct.rs +++ b/tests/mir-opt/dataflow-const-prop/struct.rs @@ -1,4 +1,3 @@ -// skip-filecheck // unit-test: DataflowConstProp // EMIT_MIR_FOR_EACH_BIT_WIDTH @@ -12,27 +11,69 @@ struct SmallStruct(f32, Option, &'static [f32]); struct BigStruct(f32, Option, &'static [f32]); // EMIT_MIR struct.main.DataflowConstProp.diff + +// CHECK-LABEL: fn main fn main() { + // CHECK: debug s => [[s:_[0-9]+]]; + // CHECK: debug a => [[a:_[0-9]+]]; + // CHECK: debug b => [[b:_[0-9]+]]; + // CHECK: debug a1 => [[a1:_[0-9]+]]; + // CHECK: debug b1 => [[b1:_[0-9]+]]; + // CHECK: debug c1 => [[c1:_[0-9]+]]; + // CHECK: debug a2 => [[a2:_[0-9]+]]; + // CHECK: debug b2 => [[b2:_[0-9]+]]; + // CHECK: debug c2 => [[c2:_[0-9]+]]; + // CHECK: debug ss => [[ss:_[0-9]+]]; + // CHECK: debug a3 => [[a3:_[0-9]+]]; + // CHECK: debug b3 => [[b3:_[0-9]+]]; + // CHECK: debug c3 => [[c3:_[0-9]+]]; + // CHECK: debug a4 => [[a4:_[0-9]+]]; + // CHECK: debug b4 => [[b4:_[0-9]+]]; + // CHECK: debug c4 => [[c4:_[0-9]+]]; + // CHECK: debug bs => [[bs:_[0-9]+]]; + + // CHECK: [[s]] = const S(1_i32); let mut s = S(1); + + // CHECK: [[a]] = const 3_i32; let a = s.0 + 2; s.0 = 3; + + // CHECK: [[b]] = const 6_i32; let b = a + s.0; const SMALL_VAL: SmallStruct = SmallStruct(4., Some(S(1)), &[]); - let SmallStruct(a, b, c) = SMALL_VAL; + + // CHECK: [[a1]] = const 4f32; + // CHECK: [[b1]] = const Option::::Some(S(1_i32)); + // CHECK: [[c1]] = ({{_[0-9]+}}.2: &[f32]); + let SmallStruct(a1, b1, c1) = SMALL_VAL; static SMALL_STAT: &SmallStruct = &SmallStruct(9., None, &[13.]); - let SmallStruct(a, b, c) = *SMALL_STAT; - let ss = SmallStruct(a, b, c); + // CHECK: [[a2]] = const 9f32; + // CHECK: [[b2]] = ((*{{_[0-9]+}}).1: std::option::Option); + // CHECK: [[c2]] = ((*{{_[0-9]+}}).2: &[f32]); + let SmallStruct(a2, b2, c2) = *SMALL_STAT; + + // CHECK: [[ss]] = SmallStruct(const 9f32, move {{_[0-9]+}}, move {{_[0-9]+}}); + let ss = SmallStruct(a2, b2, c2); const BIG_VAL: BigStruct = BigStruct(25., None, &[]); - let BigStruct(a, b, c) = BIG_VAL; + + // CHECK: [[a3]] = const 25f32; + // CHECK: [[b3]] = ({{_[0-9]+}}.1: std::option::Option); + // CHECK: [[c3]] = ({{_[0-9]+}}.2: &[f32]); + let BigStruct(a3, b3, c3) = BIG_VAL; static BIG_STAT: &BigStruct = &BigStruct(82., Some(S(35)), &[45., 72.]); - let BigStruct(a, b, c) = *BIG_STAT; + // CHECK: [[a4]] = const 82f32; + // CHECK: [[b4]] = const Option::::Some(S(35_i32)); + // CHECK: [[c4]] = ((*{{_[0-9]+}}).2: &[f32]); + let BigStruct(a4, b4, c4) = *BIG_STAT; // We arbitrarily limit the size of synthetized values to 4 pointers. // `BigStruct` can be read, but we will keep a MIR aggregate for this. - let bs = BigStruct(a, b, c); + // CHECK: [[bs]] = BigStruct(const 82f32, const Option::::Some(S(35_i32)), move {{_[0-9]+}}); + let bs = BigStruct(a4, b4, c4); } From 1adda9a170085823f43672e60c19be29a4deb18f Mon Sep 17 00:00:00 2001 From: sfzhu93 Date: Mon, 8 Jan 2024 20:21:23 -0800 Subject: [PATCH 0095/1197] Add FileCheck to terminator.rs and tuple.rs --- tests/mir-opt/dataflow-const-prop/terminator.rs | 4 +++- tests/mir-opt/dataflow-const-prop/tuple.rs | 16 +++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/tests/mir-opt/dataflow-const-prop/terminator.rs b/tests/mir-opt/dataflow-const-prop/terminator.rs index 92a42f22c218f..985eddad26440 100644 --- a/tests/mir-opt/dataflow-const-prop/terminator.rs +++ b/tests/mir-opt/dataflow-const-prop/terminator.rs @@ -1,12 +1,14 @@ -// skip-filecheck // EMIT_MIR_FOR_EACH_PANIC_STRATEGY // unit-test: DataflowConstProp fn foo(n: i32) {} // EMIT_MIR terminator.main.DataflowConstProp.diff + +// CHECK-LABEL: fn main fn main() { let a = 1; // Checks that we propagate into terminators. + // CHECK: {{_[0-9]+}} = foo(const 2_i32) -> [return: {{bb[0-9]+}}, unwind continue]; foo(a + 1); } diff --git a/tests/mir-opt/dataflow-const-prop/tuple.rs b/tests/mir-opt/dataflow-const-prop/tuple.rs index bb706eafe8885..bd5adeda8b3dc 100644 --- a/tests/mir-opt/dataflow-const-prop/tuple.rs +++ b/tests/mir-opt/dataflow-const-prop/tuple.rs @@ -1,13 +1,27 @@ -// skip-filecheck // unit-test: DataflowConstProp // EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR tuple.main.DataflowConstProp.diff + +// CHECK-LABEL: fn main fn main() { + // CHECK: debug a => [[a:_[0-9]+]]; + // CHECK: debug b => [[b:_[0-9]+]]; + // CHECK: debug c => [[c:_[0-9]+]]; + // CHECK: debug d => [[d:_[0-9]+]]; + + // CHECK: [[a]] = const (1_i32, 2_i32); let mut a = (1, 2); + + // CHECK: [[b]] = const 6_i32; let b = a.0 + a.1 + 3; + + // CHECK: [[a]] = const (2_i32, 3_i32); a = (2, 3); + + // CHECK: [[c]] = const 11_i32; let c = a.0 + a.1 + b; + // CHECK: [[d]] = (const 6_i32, const (2_i32, 3_i32), const 11_i32); let d = (b, a, c); } From 7135168d0874ee5e0485bb31d89ab69966a48337 Mon Sep 17 00:00:00 2001 From: sfzhu93 Date: Sun, 7 Jan 2024 22:03:42 -0800 Subject: [PATCH 0096/1197] Add FileCheck for enum.rs --- .../enum.constant.DataflowConstProp.32bit.diff | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/mir-opt/dataflow-const-prop/enum.constant.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/enum.constant.DataflowConstProp.32bit.diff index 07ac5b72e244c..f50a763ef9a05 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.constant.DataflowConstProp.32bit.diff +++ b/tests/mir-opt/dataflow-const-prop/enum.constant.DataflowConstProp.32bit.diff @@ -14,10 +14,10 @@ debug x => _2; } scope 3 { - debug x => _4; + debug x1 => _4; } scope 4 { - debug x => _5; + debug x2 => _5; } } From c2d071c11c008b08d841d30bae40f8acfdac0c6e Mon Sep 17 00:00:00 2001 From: Eugene Date: Tue, 9 Jan 2024 06:50:17 -0800 Subject: [PATCH 0097/1197] Documentation edits for arc_with_non_send_sync Arc's documentation uses the term "thread", aligning to that terminology. Fix typo in "Rc". --- clippy_lints/src/arc_with_non_send_sync.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/arc_with_non_send_sync.rs b/clippy_lints/src/arc_with_non_send_sync.rs index 657d52d0e9e17..58738d5287883 100644 --- a/clippy_lints/src/arc_with_non_send_sync.rs +++ b/clippy_lints/src/arc_with_non_send_sync.rs @@ -14,8 +14,8 @@ declare_clippy_lint! { /// This lint warns when you use `Arc` with a type that does not implement `Send` or `Sync`. /// /// ### Why is this bad? - /// `Arc` is an Atomic `RC` and guarantees that updates to the reference counter are - /// Atomic. This is useful in multiprocessing scenarios. To send an `Arc` across processes + /// `Arc` is an Atomic `Rc` and guarantees that updates to the reference counter are + /// Atomic. This is useful in multithreading scenarios. To send an `Arc` across threads /// and make use of the atomic ref counter, `T` must be [both `Send` and `Sync`](https://doc.rust-lang.org/std/sync/struct.Arc.html#impl-Send-for-Arc%3CT%3E), /// either `T` should be made `Send + Sync` or an `Rc` should be used instead of an `Arc` /// From 1ceb2ea414fc7f7251e20f0a6dafea69b4e397f9 Mon Sep 17 00:00:00 2001 From: Rebecca Turner Date: Tue, 19 Sep 2023 12:44:30 -0700 Subject: [PATCH 0098/1197] Show which roots are being scanned in progress messages See: #12613 --- crates/load-cargo/src/lib.rs | 2 +- crates/rust-analyzer/src/main_loop.rs | 17 ++++++++++++++-- crates/vfs-notify/src/lib.rs | 28 +++++++++++++++++++++++++-- crates/vfs/src/loader.rs | 14 ++++++++++++-- 4 files changed, 54 insertions(+), 7 deletions(-) diff --git a/crates/load-cargo/src/lib.rs b/crates/load-cargo/src/lib.rs index e6ddfd580c30e..8f02f20ad1b94 100644 --- a/crates/load-cargo/src/lib.rs +++ b/crates/load-cargo/src/lib.rs @@ -317,7 +317,7 @@ fn load_crate_graph( // wait until Vfs has loaded all roots for task in receiver { match task { - vfs::loader::Message::Progress { n_done, n_total, config_version: _ } => { + vfs::loader::Message::Progress { n_done, n_total, .. } => { if n_done == n_total { break; } diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index ca7893faf5dd7..714476c482caf 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -586,7 +586,7 @@ impl GlobalState { } } } - vfs::loader::Message::Progress { n_total, n_done, config_version } => { + vfs::loader::Message::Progress { n_total, n_done, file, config_version } => { always!(config_version <= self.vfs_config_version); self.vfs_progress_config_version = config_version; @@ -601,10 +601,23 @@ impl GlobalState { assert_eq!(n_done, n_total); Progress::End }; + + let mut message = format!("{n_done}/{n_total}"); + if let Some(file) = file { + message += &format!( + ": {}", + match file.strip_prefix(&self.config.root_path()) { + Some(relative_path) => relative_path.as_ref(), + None => file.as_ref(), + } + .display() + ); + } + self.report_progress( "Roots Scanned", state, - Some(format!("{n_done}/{n_total}")), + Some(message), Some(Progress::fraction(n_done, n_total)), None, ); diff --git a/crates/vfs-notify/src/lib.rs b/crates/vfs-notify/src/lib.rs index 19b34ffe6b9d7..a6e4da5615b74 100644 --- a/crates/vfs-notify/src/lib.rs +++ b/crates/vfs-notify/src/lib.rs @@ -103,21 +103,39 @@ impl NotifyActor { let config_version = config.version; let n_total = config.load.len(); - self.send(loader::Message::Progress { n_total, n_done: 0, config_version }); + self.send(loader::Message::Progress { + n_total, + n_done: 0, + config_version, + file: None, + }); self.watched_entries.clear(); for (i, entry) in config.load.into_iter().enumerate() { + self.send(loader::Message::Progress { + n_total, + n_done: i, + config_version, + file: None, + }); let watch = config.watch.contains(&i); if watch { self.watched_entries.push(entry.clone()); } - let files = self.load_entry(entry, watch); + let files = + self.load_entry(entry, watch, |file| loader::Message::Progress { + n_total, + n_done: i, + file: Some(file), + config_version, + }); self.send(loader::Message::Loaded { files }); self.send(loader::Message::Progress { n_total, n_done: i + 1, config_version, + file: None, }); } } @@ -170,6 +188,7 @@ impl NotifyActor { &mut self, entry: loader::Entry, watch: bool, + make_message: impl Fn(AbsPathBuf) -> loader::Message, ) -> Vec<(AbsPathBuf, Option>)> { match entry { loader::Entry::Files(files) => files @@ -186,6 +205,7 @@ impl NotifyActor { let mut res = Vec::new(); for root in &dirs.include { + self.send(make_message(root.clone())); let walkdir = WalkDir::new(root).follow_links(true).into_iter().filter_entry(|entry| { if !entry.file_type().is_dir() { @@ -197,9 +217,13 @@ impl NotifyActor { }); let files = walkdir.filter_map(|it| it.ok()).filter_map(|entry| { + let depth = entry.depth(); let is_dir = entry.file_type().is_dir(); let is_file = entry.file_type().is_file(); let abs_path = AbsPathBuf::assert(entry.into_path()); + if depth < 2 && is_dir { + self.send(make_message(abs_path.clone())); + } if is_dir && watch { self.watch(abs_path.clone()); } diff --git a/crates/vfs/src/loader.rs b/crates/vfs/src/loader.rs index 89a544c81d8c9..5c507c3dbef3a 100644 --- a/crates/vfs/src/loader.rs +++ b/crates/vfs/src/loader.rs @@ -48,7 +48,16 @@ pub enum Message { /// Indicate a gradual progress. /// /// This is supposed to be the number of loaded files. - Progress { n_total: usize, n_done: usize, config_version: u32 }, + Progress { + /// The total files to be loaded. + n_total: usize, + /// The files that have been loaded successfully. + n_done: usize, + /// The file being loaded, if any. + file: Option, + /// The [`Config`] version. + config_version: u32, + }, /// The handle loaded the following files' content. Loaded { files: Vec<(AbsPathBuf, Option>)> }, /// The handle loaded the following files' content. @@ -204,10 +213,11 @@ impl fmt::Debug for Message { Message::Changed { files } => { f.debug_struct("Changed").field("n_files", &files.len()).finish() } - Message::Progress { n_total, n_done, config_version } => f + Message::Progress { n_total, n_done, file, config_version } => f .debug_struct("Progress") .field("n_total", n_total) .field("n_done", n_done) + .field("file", file) .field("config_version", config_version) .finish(), } From 0dc13d7acb0118d6c14a9209d921e5278e829458 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 9 Jan 2024 14:16:09 +0100 Subject: [PATCH 0099/1197] Implement _mm_prefetch as nop --- src/intrinsics/llvm.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/intrinsics/llvm.rs b/src/intrinsics/llvm.rs index a38a728c926d8..9c686eba5e030 100644 --- a/src/intrinsics/llvm.rs +++ b/src/intrinsics/llvm.rs @@ -35,6 +35,10 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( } match intrinsic { + "llvm.prefetch" => { + // Nothing to do. This is merely a perf hint. + } + _ if intrinsic.starts_with("llvm.ctlz.v") => { intrinsic_args!(fx, args => (a); intrinsic); From b152de29c59fc0d34ab26b0be445a45e9ffe2dfb Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 5 Jan 2024 13:23:05 +1100 Subject: [PATCH 0100/1197] coverage: Discard code regions that might cause fatal errors in `llvm-cov` --- .../rustc_mir_transform/src/coverage/mod.rs | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index dcd7014f4fc90..4b91f042f007a 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -330,7 +330,7 @@ fn make_code_region( start_line = source_map.doctest_offset_line(&file.name, start_line); end_line = source_map.doctest_offset_line(&file.name, end_line); - Some(CodeRegion { + check_code_region(CodeRegion { file_name, start_line: start_line as u32, start_col: start_col as u32, @@ -339,6 +339,41 @@ fn make_code_region( }) } +/// If `llvm-cov` sees a code region that is improperly ordered (end < start), +/// it will immediately exit with a fatal error. To prevent that from happening, +/// discard regions that are improperly ordered, or might be interpreted in a +/// way that makes them improperly ordered. +fn check_code_region(code_region: CodeRegion) -> Option { + let CodeRegion { file_name: _, start_line, start_col, end_line, end_col } = code_region; + + // Line/column coordinates are supposed to be 1-based. If we ever emit + // coordinates of 0, `llvm-cov` might misinterpret them. + let all_nonzero = [start_line, start_col, end_line, end_col].into_iter().all(|x| x != 0); + // Coverage mappings use the high bit of `end_col` to indicate that a + // region is actually a "gap" region, so make sure it's unset. + let end_col_has_high_bit_unset = (end_col & (1 << 31)) == 0; + // If a region is improperly ordered (end < start), `llvm-cov` will exit + // with a fatal error, which is inconvenient for users and hard to debug. + let is_ordered = (start_line, start_col) <= (end_line, end_col); + + if all_nonzero && end_col_has_high_bit_unset && is_ordered { + Some(code_region) + } else { + debug!( + ?code_region, + ?all_nonzero, + ?end_col_has_high_bit_unset, + ?is_ordered, + "Skipping code region that would be misinterpreted or rejected by LLVM" + ); + if cfg!(debug_assertions) { + // If this happens in a debug build, ICE to make it easier to notice. + bug!("Improper code region: {code_region:?}"); + } + None + } +} + fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { // Only instrument functions, methods, and closures (not constants since they are evaluated // at compile time by Miri). From 7a75766c41893b39352171dd313557f79f2b9f9d Mon Sep 17 00:00:00 2001 From: The Miri Conjob Bot Date: Wed, 10 Jan 2024 05:03:16 +0000 Subject: [PATCH 0101/1197] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 548e12ffdeafb..bdf2416a20e61 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -5bcd86d89b2b7b6a490f7e075dd4eb346deb5f98 +94807670a6a3834cc9b71b0b803d49d307c9ba5d From 500d6f64791d4f9576c8588ef2cdeab4a3139a02 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 3 Nov 2023 21:56:06 -0400 Subject: [PATCH 0102/1197] Stabilize `slice_first_last_chunk` This stabilizes all methods under `slice_first_last_chunk`. Additionally, it const stabilizes the non-mut functions and moves the `_mut` functions under `const_slice_first_last_chunk`. These are blocked on `const_mut_refs`. As part of this change, `slice_split_at_unchecked` was marked const-stable for internal use (but not fully stable). --- compiler/rustc_serialize/src/lib.rs | 1 - library/core/src/slice/mod.rs | 54 +++++++++++------------------ library/core/tests/lib.rs | 1 - 3 files changed, 20 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs index cfa54072eb91b..c149b659a4f7f 100644 --- a/compiler/rustc_serialize/src/lib.rs +++ b/compiler/rustc_serialize/src/lib.rs @@ -16,7 +16,6 @@ #![feature(min_specialization)] #![feature(never_type)] #![feature(ptr_sub_ptr)] -#![feature(slice_first_last_chunk)] #![cfg_attr(test, feature(test))] #![allow(rustc::internal)] #![deny(rustc::untranslatable_diagnostic)] diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 9512d45740fd3..a425beb1c9ae6 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -327,8 +327,6 @@ impl [T] { /// # Examples /// /// ``` - /// #![feature(slice_first_last_chunk)] - /// /// let u = [10, 40, 30]; /// assert_eq!(Some(&[10, 40]), u.first_chunk::<2>()); /// @@ -338,9 +336,9 @@ impl [T] { /// let w: &[i32] = &[]; /// assert_eq!(Some(&[]), w.first_chunk::<0>()); /// ``` - #[unstable(feature = "slice_first_last_chunk", issue = "111774")] - #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")] #[inline] + #[stable(feature = "slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] pub const fn first_chunk(&self) -> Option<&[T; N]> { if self.len() < N { None @@ -358,8 +356,6 @@ impl [T] { /// # Examples /// /// ``` - /// #![feature(slice_first_last_chunk)] - /// /// let x = &mut [0, 1, 2]; /// /// if let Some(first) = x.first_chunk_mut::<2>() { @@ -370,9 +366,9 @@ impl [T] { /// /// assert_eq!(None, x.first_chunk_mut::<4>()); /// ``` - #[unstable(feature = "slice_first_last_chunk", issue = "111774")] - #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")] #[inline] + #[stable(feature = "slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_unstable(feature = "const_slice_first_last_chunk", issue = "111774")] pub const fn first_chunk_mut(&mut self) -> Option<&mut [T; N]> { if self.len() < N { None @@ -391,8 +387,6 @@ impl [T] { /// # Examples /// /// ``` - /// #![feature(slice_first_last_chunk)] - /// /// let x = &[0, 1, 2]; /// /// if let Some((first, elements)) = x.split_first_chunk::<2>() { @@ -402,9 +396,9 @@ impl [T] { /// /// assert_eq!(None, x.split_first_chunk::<4>()); /// ``` - #[unstable(feature = "slice_first_last_chunk", issue = "111774")] - #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")] #[inline] + #[stable(feature = "slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] pub const fn split_first_chunk(&self) -> Option<(&[T; N], &[T])> { if self.len() < N { None @@ -426,8 +420,6 @@ impl [T] { /// # Examples /// /// ``` - /// #![feature(slice_first_last_chunk)] - /// /// let x = &mut [0, 1, 2]; /// /// if let Some((first, elements)) = x.split_first_chunk_mut::<2>() { @@ -439,9 +431,9 @@ impl [T] { /// /// assert_eq!(None, x.split_first_chunk_mut::<4>()); /// ``` - #[unstable(feature = "slice_first_last_chunk", issue = "111774")] - #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")] #[inline] + #[stable(feature = "slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_unstable(feature = "const_slice_first_last_chunk", issue = "111774")] pub const fn split_first_chunk_mut( &mut self, ) -> Option<(&mut [T; N], &mut [T])> { @@ -465,8 +457,6 @@ impl [T] { /// # Examples /// /// ``` - /// #![feature(slice_first_last_chunk)] - /// /// let x = &[0, 1, 2]; /// /// if let Some((elements, last)) = x.split_last_chunk::<2>() { @@ -476,9 +466,9 @@ impl [T] { /// /// assert_eq!(None, x.split_last_chunk::<4>()); /// ``` - #[unstable(feature = "slice_first_last_chunk", issue = "111774")] - #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")] #[inline] + #[stable(feature = "slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] pub const fn split_last_chunk(&self) -> Option<(&[T], &[T; N])> { if self.len() < N { None @@ -500,8 +490,6 @@ impl [T] { /// # Examples /// /// ``` - /// #![feature(slice_first_last_chunk)] - /// /// let x = &mut [0, 1, 2]; /// /// if let Some((elements, last)) = x.split_last_chunk_mut::<2>() { @@ -513,9 +501,9 @@ impl [T] { /// /// assert_eq!(None, x.split_last_chunk_mut::<4>()); /// ``` - #[unstable(feature = "slice_first_last_chunk", issue = "111774")] - #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")] #[inline] + #[stable(feature = "slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_unstable(feature = "const_slice_first_last_chunk", issue = "111774")] pub const fn split_last_chunk_mut( &mut self, ) -> Option<(&mut [T], &mut [T; N])> { @@ -539,8 +527,6 @@ impl [T] { /// # Examples /// /// ``` - /// #![feature(slice_first_last_chunk)] - /// /// let u = [10, 40, 30]; /// assert_eq!(Some(&[40, 30]), u.last_chunk::<2>()); /// @@ -550,9 +536,9 @@ impl [T] { /// let w: &[i32] = &[]; /// assert_eq!(Some(&[]), w.last_chunk::<0>()); /// ``` - #[unstable(feature = "slice_first_last_chunk", issue = "111774")] - #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")] #[inline] + #[stable(feature = "slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_unstable(feature = "const_slice_first_last_chunk", issue = "111774")] pub const fn last_chunk(&self) -> Option<&[T; N]> { if self.len() < N { None @@ -574,8 +560,6 @@ impl [T] { /// # Examples /// /// ``` - /// #![feature(slice_first_last_chunk)] - /// /// let x = &mut [0, 1, 2]; /// /// if let Some(last) = x.last_chunk_mut::<2>() { @@ -586,9 +570,9 @@ impl [T] { /// /// assert_eq!(None, x.last_chunk_mut::<4>()); /// ``` - #[unstable(feature = "slice_first_last_chunk", issue = "111774")] - #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")] #[inline] + #[stable(feature = "slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_unstable(feature = "const_slice_first_last_chunk", issue = "111774")] pub const fn last_chunk_mut(&mut self) -> Option<&mut [T; N]> { if self.len() < N { None @@ -1885,7 +1869,6 @@ impl [T] { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_slice_split_at_not_mut", since = "1.71.0")] - #[rustc_allow_const_fn_unstable(slice_split_at_unchecked)] #[inline] #[track_caller] #[must_use] @@ -1972,7 +1955,10 @@ impl [T] { /// } /// ``` #[unstable(feature = "slice_split_at_unchecked", reason = "new API", issue = "76014")] - #[rustc_const_unstable(feature = "slice_split_at_unchecked", issue = "76014")] + #[rustc_const_stable( + feature = "const_slice_split_at_unchecked", + since = "CURRENT_RUSTC_VERSION" + )] #[inline] #[must_use] pub const unsafe fn split_at_unchecked(&self, mid: usize) -> (&[T], &[T]) { diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 15e58a4e53fb5..df7b34ce73b42 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -46,7 +46,6 @@ #![feature(pattern)] #![feature(sort_internals)] #![feature(slice_take)] -#![feature(slice_first_last_chunk)] #![feature(slice_from_ptr_range)] #![feature(slice_split_once)] #![feature(split_as_slice)] From bfe04e08c04e2c332eb759d9ae8c5d53144b72b8 Mon Sep 17 00:00:00 2001 From: zachs18 <8355914+zachs18@users.noreply.github.com> Date: Tue, 9 Jan 2024 16:46:45 -0600 Subject: [PATCH 0103/1197] Fix deallocation with wrong allocator in (A)Rc::from_box_in --- library/alloc/src/rc.rs | 2 +- library/alloc/src/sync.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 263b1449de156..f986df058467b 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1924,7 +1924,7 @@ impl Rc { // Free the allocation without dropping its contents let (bptr, alloc) = Box::into_raw_with_allocator(src); - let src = Box::from_raw(bptr as *mut mem::ManuallyDrop); + let src = Box::from_raw_in(bptr as *mut mem::ManuallyDrop, alloc.by_ref()); drop(src); Self::from_ptr_in(ptr, alloc) diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 5273b3cb2dafa..dc82c9c411110 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1869,7 +1869,7 @@ impl Arc { // Free the allocation without dropping its contents let (bptr, alloc) = Box::into_raw_with_allocator(src); - let src = Box::from_raw(bptr as *mut mem::ManuallyDrop); + let src = Box::from_raw_in(bptr as *mut mem::ManuallyDrop, alloc.by_ref()); drop(src); Self::from_ptr_in(ptr, alloc) From 281ceb2bd2b2dd5f6ac201f585a2de2d21a41250 Mon Sep 17 00:00:00 2001 From: ardi Date: Wed, 10 Jan 2024 10:26:18 +0100 Subject: [PATCH 0104/1197] Document the struct and a few methods --- compiler/rustc_index/src/vec.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 66c5cc774b224..3148b054790fc 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -12,10 +12,26 @@ use std::vec; use crate::{Idx, IndexSlice}; /// An owned contiguous collection of `T`s, indexed by `I` rather than by `usize`. +/// Its purpose is to avoid mixing indexes. /// /// While it's possible to use `u32` or `usize` directly for `I`, /// you almost certainly want to use a [`newtype_index!`]-generated type instead. /// +/// This allows to index the IndexVec with the new index type: +/// +/// ``` +/// use crate as rustc_index; +/// use rustc_index::{IndexVec, newtype_index}; +/// +/// newtype_index! { +/// pub struct MyIdx {} +/// } +/// +/// let my_index_vec: IndexVec = IndexVec::from_raw(vec![0,1,2,3]); +/// let idx: MyIdx = MyIdx::from_u32(2); +/// assert_eq!(my_index_vec[idx], 2); +/// ``` +/// /// [`newtype_index!`]: ../macro.newtype_index.html #[derive(Clone, PartialEq, Eq, Hash)] #[repr(transparent)] @@ -25,11 +41,13 @@ pub struct IndexVec { } impl IndexVec { + /// Constructs a new, empty `IndexVec`. #[inline] pub const fn new() -> Self { IndexVec::from_raw(Vec::new()) } + /// Constructs a new `IndexVec` from a `Vec` #[inline] pub const fn from_raw(raw: Vec) -> Self { IndexVec { raw, _marker: PhantomData } @@ -59,6 +77,7 @@ impl IndexVec { IndexVec::from_raw(vec![elem; universe.len()]) } + /// Creates a new `IndexVec` with n copies of `elem` #[inline] pub fn from_elem_n(elem: T, n: usize) -> Self where From 075f2e0345a00fcb3352ac9ece8a87817b73d305 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emil=20Gardstr=C3=B6m?= Date: Wed, 10 Jan 2024 10:20:26 +0100 Subject: [PATCH 0105/1197] Add `#[track_caller]` to the "From implies Into" impl --- library/core/src/convert/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index 8c01b0973d65a..45f6e375e8942 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -753,6 +753,7 @@ where /// That is, this conversion is whatever the implementation of /// [From]<T> for U chooses to do. #[inline] + #[track_caller] fn into(self) -> U { U::from(self) } From 1bf3aee3811b92d5833154fd35b98159a233b938 Mon Sep 17 00:00:00 2001 From: ardi Date: Wed, 10 Jan 2024 11:17:46 +0100 Subject: [PATCH 0106/1197] Oh well --- compiler/rustc_index/src/vec.rs | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 3148b054790fc..3c66e6dde1c2e 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -17,27 +17,15 @@ use crate::{Idx, IndexSlice}; /// While it's possible to use `u32` or `usize` directly for `I`, /// you almost certainly want to use a [`newtype_index!`]-generated type instead. /// -/// This allows to index the IndexVec with the new index type: +/// This allows to index the IndexVec with the new index type /// -/// ``` -/// use crate as rustc_index; -/// use rustc_index::{IndexVec, newtype_index}; -/// -/// newtype_index! { -/// pub struct MyIdx {} -/// } -/// -/// let my_index_vec: IndexVec = IndexVec::from_raw(vec![0,1,2,3]); -/// let idx: MyIdx = MyIdx::from_u32(2); -/// assert_eq!(my_index_vec[idx], 2); -/// ``` /// /// [`newtype_index!`]: ../macro.newtype_index.html #[derive(Clone, PartialEq, Eq, Hash)] #[repr(transparent)] pub struct IndexVec { pub raw: Vec, - _marker: PhantomData, + _marker: PhantomData, } impl IndexVec { @@ -77,7 +65,7 @@ impl IndexVec { IndexVec::from_raw(vec![elem; universe.len()]) } - /// Creates a new `IndexVec` with n copies of `elem` + /// Creates a new IndexVec #[inline] pub fn from_elem_n(elem: T, n: usize) -> Self where From fcaeb4542173b364835aef7dd2526303191b2d2c Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 10 Jan 2024 17:12:01 +0200 Subject: [PATCH 0107/1197] deps: deduplicate the version of libloading used The changelog can be found here: https://docs.rs/libloading/latest/libloading/changelog/r0_8_0/index.html --- Cargo.lock | 16 +++------------- compiler/rustc_codegen_cranelift/Cargo.toml | 2 +- compiler/rustc_interface/Cargo.toml | 2 +- compiler/rustc_metadata/Cargo.toml | 2 +- 4 files changed, 6 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 75c7de4f405aa..dc44041141b05 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2177,16 +2177,6 @@ dependencies = [ "cc", ] -[[package]] -name = "libloading" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" -dependencies = [ - "cfg-if", - "winapi", -] - [[package]] name = "libloading" version = "0.8.1" @@ -2469,7 +2459,7 @@ dependencies = [ "lazy_static", "libc", "libffi", - "libloading 0.8.1", + "libloading", "log", "measureme", "rand", @@ -3993,7 +3983,7 @@ dependencies = [ name = "rustc_interface" version = "0.0.0" dependencies = [ - "libloading 0.7.4", + "libloading", "rustc-rayon", "rustc-rayon-core", "rustc_ast", @@ -4123,7 +4113,7 @@ name = "rustc_metadata" version = "0.0.0" dependencies = [ "bitflags 2.4.1", - "libloading 0.7.4", + "libloading", "odht", "rustc_ast", "rustc_attr", diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml index fdac789423c9c..c57e964168f4d 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.toml +++ b/compiler/rustc_codegen_cranelift/Cargo.toml @@ -19,7 +19,7 @@ gimli = { version = "0.28", default-features = false, features = ["write"]} object = { version = "0.32", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } indexmap = "2.0.0" -libloading = { version = "0.7.3", optional = true } +libloading = { version = "0.8.0", optional = true } smallvec = "1.8.1" [patch.crates-io] diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml index 319e81758094d..a238eacda44ba 100644 --- a/compiler/rustc_interface/Cargo.toml +++ b/compiler/rustc_interface/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start -libloading = "0.7.1" +libloading = "0.8.0" rustc-rayon = { version = "0.5.0", optional = true } rustc-rayon-core = { version = "0.5.0", optional = true } rustc_ast = { path = "../rustc_ast" } diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml index 08cc8173eb049..79d3482472a81 100644 --- a/compiler/rustc_metadata/Cargo.toml +++ b/compiler/rustc_metadata/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start bitflags = "2.4.1" -libloading = "0.7.1" +libloading = "0.8.0" odht = { version = "0.3.1", features = ["nightly"] } rustc_ast = { path = "../rustc_ast" } rustc_attr = { path = "../rustc_attr" } From c8875309b8865b0fc119da4ba795dae129532bc1 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 10 Jan 2024 17:12:01 +0200 Subject: [PATCH 0108/1197] deps: deduplicate the version of libloading used The changelog can be found here: https://docs.rs/libloading/latest/libloading/changelog/r0_8_0/index.html --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index fdac789423c9c..c57e964168f4d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ gimli = { version = "0.28", default-features = false, features = ["write"]} object = { version = "0.32", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } indexmap = "2.0.0" -libloading = { version = "0.7.3", optional = true } +libloading = { version = "0.8.0", optional = true } smallvec = "1.8.1" [patch.crates-io] From 1dc3ab02cdba905aa1cce73d938c8e825107a8e8 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 10 Jan 2024 17:13:03 +0200 Subject: [PATCH 0109/1197] Format sources into the error message when loading codegen backends cc https://github.com/rust-lang/rustc_codegen_cranelift/issues/1447 --- compiler/rustc_codegen_cranelift/Cargo.lock | 6 +++--- compiler/rustc_interface/src/lib.rs | 3 ++- compiler/rustc_interface/src/util.rs | 12 +++++++++--- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock index 74e7afee7bcb2..6d6a1200f5028 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/Cargo.lock @@ -246,12 +246,12 @@ checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" [[package]] name = "libloading" -version = "0.7.4" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" dependencies = [ "cfg-if", - "winapi", + "windows-sys", ] [[package]] diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index cfa46447845a2..764306ce6ec6a 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -1,9 +1,10 @@ #![feature(box_patterns)] #![feature(decl_macro)] +#![feature(error_iter)] #![feature(internal_output_capture)] -#![feature(thread_spawn_unchecked)] #![feature(lazy_cell)] #![feature(let_chains)] +#![feature(thread_spawn_unchecked)] #![feature(try_blocks)] #![recursion_limit = "256"] #![deny(rustc::untranslatable_diagnostic)] diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 92a6445ed0916..a09bb3c5fd0df 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -162,15 +162,21 @@ pub(crate) fn run_in_thread_pool_with_globals R + Send, R: Send>( } fn load_backend_from_dylib(early_dcx: &EarlyDiagCtxt, path: &Path) -> MakeBackendFn { + fn format_err(e: &(dyn std::error::Error + 'static)) -> String { + e.sources().map(|e| format!(": {e}")).collect() + } let lib = unsafe { Library::new(path) }.unwrap_or_else(|err| { - let err = format!("couldn't load codegen backend {path:?}: {err}"); + let err = format!("couldn't load codegen backend {path:?}{}", format_err(&err)); early_dcx.early_fatal(err); }); let backend_sym = unsafe { lib.get::(b"__rustc_codegen_backend") } .unwrap_or_else(|e| { - let err = format!("couldn't load codegen backend: {e}"); - early_dcx.early_fatal(err); + let e = format!( + "`__rustc_codegen_backend` symbol lookup in the codegen backend failed{}", + format_err(&e) + ); + early_dcx.early_fatal(e); }); // Intentionally leak the dynamic library. We can't ever unload it From be1b86fef43a7cf6c57a2848be02e0dca4738ef1 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 10 Jan 2024 17:13:03 +0200 Subject: [PATCH 0110/1197] Format sources into the error message when loading codegen backends cc https://github.com/rust-lang/rustc_codegen_cranelift/issues/1447 --- Cargo.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 74e7afee7bcb2..6d6a1200f5028 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -246,12 +246,12 @@ checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" [[package]] name = "libloading" -version = "0.7.4" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" dependencies = [ "cfg-if", - "winapi", + "windows-sys", ] [[package]] From 08fc5e8acd1bc41fbf5b8a4b5c96a42c16bab158 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 10 Jan 2024 16:03:05 +0000 Subject: [PATCH 0111/1197] Define hidden types in confirmation --- .../src/traits/project.rs | 2 +- .../nested_inference_failure.rs | 26 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 tests/ui/type-alias-impl-trait/nested_inference_failure.rs diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index dd4e69efe379e..abbc2066eac16 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -2466,7 +2466,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>( debug!(?cache_projection, ?obligation_projection); match infcx.at(cause, param_env).eq( - DefineOpaqueTypes::No, + DefineOpaqueTypes::Yes, cache_projection, obligation_projection, ) { diff --git a/tests/ui/type-alias-impl-trait/nested_inference_failure.rs b/tests/ui/type-alias-impl-trait/nested_inference_failure.rs new file mode 100644 index 0000000000000..16b78f18aa347 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/nested_inference_failure.rs @@ -0,0 +1,26 @@ +// check-pass + +//! This test checks that we can successfully infer +//! the hidden type of `FooImpl` to be `Foo` +//! and `ImplT` to be `i32`. This test used to fail, because +//! we were unable to make the connection that the closure +//! argument is the same as the first argument of `Foo`. + +#![feature(type_alias_impl_trait)] + +use std::fmt::Debug; +use std::marker::PhantomData; + +struct Foo { + f: F, + _phantom: PhantomData, +} + +type ImplT = impl Debug; +type FooImpl = Foo; + +fn bar() -> FooImpl { + Foo:: { f: |_| (), _phantom: PhantomData } +} + +fn main() {} From 0ae00444dc075c814dd061aa1cfdc5c461c1f608 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 10 Jan 2024 16:05:24 +0000 Subject: [PATCH 0112/1197] Make sure the new solver agrees --- tests/ui/type-alias-impl-trait/nested_inference_failure.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/ui/type-alias-impl-trait/nested_inference_failure.rs b/tests/ui/type-alias-impl-trait/nested_inference_failure.rs index 16b78f18aa347..d2091ca96ea01 100644 --- a/tests/ui/type-alias-impl-trait/nested_inference_failure.rs +++ b/tests/ui/type-alias-impl-trait/nested_inference_failure.rs @@ -1,4 +1,6 @@ // check-pass +// revisions: new old +//[new] compile-flags: -Znext-solver //! This test checks that we can successfully infer //! the hidden type of `FooImpl` to be `Foo` From ee8510e4e13e723639e904cdc218e6f3013f0bb4 Mon Sep 17 00:00:00 2001 From: ardi Date: Wed, 10 Jan 2024 18:28:42 +0100 Subject: [PATCH 0113/1197] Fix some mistakes + new doc --- compiler/rustc_index/src/vec.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 3c66e6dde1c2e..73265eb89961c 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -17,15 +17,13 @@ use crate::{Idx, IndexSlice}; /// While it's possible to use `u32` or `usize` directly for `I`, /// you almost certainly want to use a [`newtype_index!`]-generated type instead. /// -/// This allows to index the IndexVec with the new index type -/// -/// +/// This allows to index the IndexVec with the new index type. /// [`newtype_index!`]: ../macro.newtype_index.html #[derive(Clone, PartialEq, Eq, Hash)] #[repr(transparent)] pub struct IndexVec { pub raw: Vec, - _marker: PhantomData, + _marker: PhantomData, } impl IndexVec { @@ -35,7 +33,7 @@ impl IndexVec { IndexVec::from_raw(Vec::new()) } - /// Constructs a new `IndexVec` from a `Vec` + /// Constructs a new `IndexVec` from a `Vec`. #[inline] pub const fn from_raw(raw: Vec) -> Self { IndexVec { raw, _marker: PhantomData } @@ -65,7 +63,7 @@ impl IndexVec { IndexVec::from_raw(vec![elem; universe.len()]) } - /// Creates a new IndexVec + /// Creates a new IndexVec with n copies of the `elem`. #[inline] pub fn from_elem_n(elem: T, n: usize) -> Self where @@ -92,6 +90,7 @@ impl IndexVec { IndexSlice::from_raw_mut(&mut self.raw) } + /// Pushes an element to the array returning the index where it was pushed to. #[inline] pub fn push(&mut self, d: T) -> I { let idx = self.next_index(); From a2a7caacf7e8e1ec78ac23e01aa281312ec780c2 Mon Sep 17 00:00:00 2001 From: The8472 Date: Thu, 20 May 2021 00:29:20 +0200 Subject: [PATCH 0114/1197] implement TrustedLen for StepBy --- library/core/src/iter/adapters/step_by.rs | 16 +++++++++------- library/core/tests/iter/adapters/step_by.rs | 7 +++++-- library/core/tests/iter/range.rs | 10 ++++++++++ 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/library/core/src/iter/adapters/step_by.rs b/library/core/src/iter/adapters/step_by.rs index 9e83584e3f3db..54ed4c952fb8b 100644 --- a/library/core/src/iter/adapters/step_by.rs +++ b/library/core/src/iter/adapters/step_by.rs @@ -1,7 +1,7 @@ use crate::convert::TryFrom; use crate::{ intrinsics, - iter::{from_fn, TrustedLen}, + iter::{from_fn, TrustedLen, TrustedRandomAccess}, ops::{Range, Try}, }; @@ -124,6 +124,14 @@ where #[stable(feature = "iterator_step_by", since = "1.28.0")] impl ExactSizeIterator for StepBy where I: ExactSizeIterator {} +// SAFETY: This adapter is shortening. TrustedLen requires the upper bound to be calculated correctly. +// These requirements can only be satisfied when the upper bound of the inner iterator's upper +// bound is never `None`. I: TrustedRandomAccess happens to provide this guarantee while +// I: TrustedLen would not. +// This also covers the Range specializations since the ranges also implement TRA +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for StepBy where I: Iterator + TrustedRandomAccess {} + trait SpecRangeSetup { fn setup(inner: T, step: usize) -> T; } @@ -480,12 +488,6 @@ macro_rules! spec_int_ranges { acc } } - - /// Safety: This macro is only applied to ranges over types <= usize - /// which means the inner length is guaranteed to fit into a usize and so - /// the outer length calculation won't encounter clamped values - #[unstable(feature = "trusted_len", issue = "37572")] - unsafe impl TrustedLen for StepBy> {} )*) } diff --git a/library/core/tests/iter/adapters/step_by.rs b/library/core/tests/iter/adapters/step_by.rs index 4c5b1dd9a6bd1..67360e38131ab 100644 --- a/library/core/tests/iter/adapters/step_by.rs +++ b/library/core/tests/iter/adapters/step_by.rs @@ -220,7 +220,8 @@ fn test_iterator_step_by_size_hint() { assert_eq!(it.len(), 3); // Cannot be TrustedLen as a step greater than one makes an iterator - // with (usize::MAX, None) no longer meet the safety requirements + // with (usize::MAX, None) no longer meet the safety requirements. + // Exception: The inner iterator is known to have a len() <= usize::MAX trait TrustedLenCheck { fn test(self) -> bool; } @@ -235,7 +236,9 @@ fn test_iterator_step_by_size_hint() { } } assert!(TrustedLenCheck::test(a.iter())); - assert!(!TrustedLenCheck::test(a.iter().step_by(1))); + assert!(TrustedLenCheck::test(a.iter().step_by(1))); + assert!(TrustedLenCheck::test(a.iter().chain(a.iter()))); + assert!(!TrustedLenCheck::test(a.iter().chain(a.iter()).step_by(1))); } #[test] diff --git a/library/core/tests/iter/range.rs b/library/core/tests/iter/range.rs index 5b87d6c1fa0e3..a6b9f1cb7c889 100644 --- a/library/core/tests/iter/range.rs +++ b/library/core/tests/iter/range.rs @@ -474,6 +474,16 @@ fn test_range_inclusive_size_hint() { assert_eq!((imin..=imax + 1).size_hint(), (usize::MAX, None)); } +#[test] +fn test_range_trusted_random_access() { + let mut range = 0..10; + unsafe { + assert_eq!(range.next(), Some(0)); + assert_eq!(range.__iterator_get_unchecked(0), 1); + assert_eq!(range.__iterator_get_unchecked(1), 2); + } +} + #[test] fn test_double_ended_range() { assert_eq!((11..14).rev().collect::>(), [13, 12, 11]); From 451a3b17757960560b887b612e94d05666493ace Mon Sep 17 00:00:00 2001 From: The8472 Date: Thu, 20 May 2021 00:29:53 +0200 Subject: [PATCH 0115/1197] implement TrustedRandomAccess and TrustedLen for Skip --- library/core/src/iter/adapters/skip.rs | 52 +++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/library/core/src/iter/adapters/skip.rs b/library/core/src/iter/adapters/skip.rs index e6c946e7f880d..f5188dd458df9 100644 --- a/library/core/src/iter/adapters/skip.rs +++ b/library/core/src/iter/adapters/skip.rs @@ -1,6 +1,10 @@ use crate::intrinsics::unlikely; +use crate::iter::adapters::zip::try_get_unchecked; use crate::iter::TrustedFused; -use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable}; +use crate::iter::{ + adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen, TrustedRandomAccess, + TrustedRandomAccessNoCoerce, +}; use crate::num::NonZeroUsize; use crate::ops::{ControlFlow, Try}; @@ -152,6 +156,32 @@ where NonZeroUsize::new(n).map_or(Ok(()), Err) } + + #[doc(hidden)] + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item + where + Self: TrustedRandomAccessNoCoerce, + { + // SAFETY: the caller must uphold the contract for + // `Iterator::__iterator_get_unchecked`. + // + // Dropping the skipped prefix when index 0 is passed is safe + // since + // * the caller passing index 0 means that the inner iterator has more items than `self.n` + // * TRA contract requires that get_unchecked will only be called once + // (unless elements are copyable) + // * it does not conflict with in-place iteration since index 0 must be accessed + // before something is written into the storage used by the prefix + unsafe { + if Self::MAY_HAVE_SIDE_EFFECT && idx == 0 { + for skipped_idx in 0..self.n { + drop(try_get_unchecked(&mut self.iter, skipped_idx)); + } + } + + try_get_unchecked(&mut self.iter, idx + self.n) + } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -237,3 +267,23 @@ unsafe impl InPlaceIterable for Skip { const EXPAND_BY: Option = I::EXPAND_BY; const MERGE_BY: Option = I::MERGE_BY; } + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccess for Skip where I: TrustedRandomAccess {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccessNoCoerce for Skip +where + I: TrustedRandomAccessNoCoerce, +{ + const MAY_HAVE_SIDE_EFFECT: bool = I::MAY_HAVE_SIDE_EFFECT; +} + +// SAFETY: This adapter is shortening. TrustedLen requires the upper bound to be calculated correctly. +// These requirements can only be satisfied when the upper bound of the inner iterator's upper +// bound is never `None`. I: TrustedRandomAccess happens to provide this guarantee while +// I: TrustedLen would not. +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Skip where I: Iterator + TrustedRandomAccess {} From 3aa73135cf9656c3371492810a077409b7a37598 Mon Sep 17 00:00:00 2001 From: The8472 Date: Sat, 12 Jun 2021 10:39:00 +0200 Subject: [PATCH 0116/1197] bench trustedrandomaccess specialization in zip --- library/core/benches/iter.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/library/core/benches/iter.rs b/library/core/benches/iter.rs index 05fec0c4b9d26..c1cec5e6d3c8c 100644 --- a/library/core/benches/iter.rs +++ b/library/core/benches/iter.rs @@ -391,6 +391,19 @@ fn bench_skip_then_zip(b: &mut Bencher) { }); } +#[bench] +fn bench_skip_trusted_random_access(b: &mut Bencher) { + let v: Vec = black_box(vec![42; 10000]); + let mut sink = [0; 10000]; + + b.iter(|| { + for (val, idx) in v.iter().skip(8).zip(0..10000) { + sink[idx] += val; + } + sink + }); +} + #[bench] fn bench_filter_count(b: &mut Bencher) { b.iter(|| (0i64..1000000).map(black_box).filter(|x| x % 3 == 0).count()) From 37d26c719d35659a809624902324e828031e94df Mon Sep 17 00:00:00 2001 From: The8472 Date: Thu, 20 May 2021 00:40:55 +0200 Subject: [PATCH 0117/1197] Implement in-place iteratation markers for iter::{Copied, Cloned} --- library/alloc/tests/vec.rs | 8 ++++++-- library/core/src/iter/adapters/cloned.rs | 25 ++++++++++++++++++++++-- library/core/src/iter/adapters/copied.rs | 24 +++++++++++++++++++++-- 3 files changed, 51 insertions(+), 6 deletions(-) diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index 9ec6f6ae1acd5..6fd021fc9fdf7 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -1166,10 +1166,14 @@ fn test_from_iter_partially_drained_in_place_specialization() { #[test] fn test_from_iter_specialization_with_iterator_adapters() { fn assert_in_place_trait(_: &T) {} - let src: Vec = vec![0usize; 256]; + let owned: Vec = vec![0usize; 256]; + let refd: Vec<&usize> = owned.iter().collect(); + let src: Vec<&&usize> = refd.iter().collect(); let srcptr = src.as_ptr(); let iter = src .into_iter() + .copied() + .cloned() .enumerate() .map(|i| i.0 + i.1) .zip(std::iter::repeat(1usize)) @@ -1180,7 +1184,7 @@ fn test_from_iter_specialization_with_iterator_adapters() { assert_in_place_trait(&iter); let sink = iter.collect::, _>>().unwrap(); let sinkptr = sink.as_ptr(); - assert_eq!(srcptr, sinkptr as *const usize); + assert_eq!(srcptr as *const usize, sinkptr as *const usize); } #[test] diff --git a/library/core/src/iter/adapters/cloned.rs b/library/core/src/iter/adapters/cloned.rs index d3cceb8d4ad54..3de91267cf5d9 100644 --- a/library/core/src/iter/adapters/cloned.rs +++ b/library/core/src/iter/adapters/cloned.rs @@ -1,8 +1,9 @@ use crate::iter::adapters::{ - zip::try_get_unchecked, TrustedRandomAccess, TrustedRandomAccessNoCoerce, + zip::try_get_unchecked, SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce, }; -use crate::iter::{FusedIterator, TrustedLen, UncheckedIterator}; +use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen, UncheckedIterator}; use crate::ops::Try; +use core::num::NonZeroUsize; /// An iterator that clones the elements of an underlying iterator. /// @@ -167,3 +168,23 @@ impl Default for Cloned { Self::new(Default::default()) } } + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Cloned +where + I: SourceIter, +{ + type Source = I::Source; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut I::Source { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.it) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Cloned { + const EXPAND_BY: Option = I::EXPAND_BY; + const MERGE_BY: Option = I::MERGE_BY; +} diff --git a/library/core/src/iter/adapters/copied.rs b/library/core/src/iter/adapters/copied.rs index 7a2c9d839b7e4..52a5add1132a4 100644 --- a/library/core/src/iter/adapters/copied.rs +++ b/library/core/src/iter/adapters/copied.rs @@ -1,7 +1,7 @@ use crate::iter::adapters::{ - zip::try_get_unchecked, TrustedRandomAccess, TrustedRandomAccessNoCoerce, + zip::try_get_unchecked, SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce, }; -use crate::iter::{FusedIterator, TrustedLen}; +use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen}; use crate::mem::MaybeUninit; use crate::mem::SizedTypeProperties; use crate::num::NonZeroUsize; @@ -255,3 +255,23 @@ impl Default for Copied { Self::new(Default::default()) } } + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Copied +where + I: SourceIter, +{ + type Source = I::Source; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut I::Source { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.it) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Copied { + const EXPAND_BY: Option = I::EXPAND_BY; + const MERGE_BY: Option = I::MERGE_BY; +} From b0dc5439197cfe17d398e3da5951d47e0add8ec9 Mon Sep 17 00:00:00 2001 From: The Miri Conjob Bot Date: Thu, 11 Jan 2024 04:53:55 +0000 Subject: [PATCH 0118/1197] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index bdf2416a20e61..61aa9c128220d 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -94807670a6a3834cc9b71b0b803d49d307c9ba5d +65b323b168daa6c723a8a5b4ddf939f3b12e0329 From 7c389acd277eada4d2e0856707361cce24c9b23f Mon Sep 17 00:00:00 2001 From: cocodery Date: Thu, 11 Jan 2024 14:52:03 +0800 Subject: [PATCH 0119/1197] Fix error warning span for issue12045 --- clippy_lints/src/no_effect.rs | 2 +- tests/ui/no_effect.stderr | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index 6bbe427ea2988..2a2c2b331ba79 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -155,7 +155,7 @@ fn check_no_effect(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool { cx, NO_EFFECT_UNDERSCORE_BINDING, init.hir_id, - stmt.span, + ident.span, "binding to `_` prefixed variable with no side-effect", ); return true; diff --git a/tests/ui/no_effect.stderr b/tests/ui/no_effect.stderr index f5ba234b4cbf6..8140ba1feee9c 100644 --- a/tests/ui/no_effect.stderr +++ b/tests/ui/no_effect.stderr @@ -152,31 +152,31 @@ LL | FooString { s: s }; | ^^^^^^^^^^^^^^^^^^^ error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:175:5 + --> $DIR/no_effect.rs:175:9 | LL | let _unused = 1; - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^ | = note: `-D clippy::no-effect-underscore-binding` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::no_effect_underscore_binding)]` error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:178:5 + --> $DIR/no_effect.rs:178:9 | LL | let _penguin = || println!("Some helpful closure"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^ error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:180:5 + --> $DIR/no_effect.rs:180:9 | LL | let _duck = Struct { field: 0 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^ error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:182:5 + --> $DIR/no_effect.rs:182:9 | LL | let _cat = [2, 4, 6, 8][2]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^ error: aborting due to 29 previous errors From fb83ef649587413c4e3a8ec9e364b828ec250a56 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 11 Jan 2024 14:22:44 +1100 Subject: [PATCH 0120/1197] Stop using `DiagnosticBuilder::buffer` in the parser. One consequence is that errors returned by `maybe_new_parser_from_source_str` now must be consumed, so a bunch of places that previously ignored those errors now cancel them. (Most of them explicitly dropped the errors before. I guess that was to indicate "we are explicitly ignoring these", though I'm not 100% sure.) --- clippy_lints/src/doc/needless_doctest_main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/doc/needless_doctest_main.rs b/clippy_lints/src/doc/needless_doctest_main.rs index a744b69ecb478..8b018220c1715 100644 --- a/clippy_lints/src/doc/needless_doctest_main.rs +++ b/clippy_lints/src/doc/needless_doctest_main.rs @@ -53,7 +53,7 @@ pub fn check( let mut parser = match maybe_new_parser_from_source_str(&sess, filename, code) { Ok(p) => p, Err(errs) => { - drop(errs); + errs.into_iter().for_each(|err| err.cancel()); return (false, test_attr_spans); }, }; From 0aedd6e86fd11c146b1bf8f0c38415ca7e66f240 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 6 Jan 2024 18:34:25 +0000 Subject: [PATCH 0121/1197] Sandwich MIR optimizations between DSE. --- .../src/dead_store_elimination.rs | 12 ++- compiler/rustc_mir_transform/src/lib.rs | 9 +- ...n.DataflowConstProp.32bit.panic-abort.diff | 15 ++-- ....DataflowConstProp.32bit.panic-unwind.diff | 15 ++-- ...n.DataflowConstProp.64bit.panic-abort.diff | 15 ++-- ....DataflowConstProp.64bit.panic-unwind.diff | 15 ++-- ...oxed_slice.main.GVN.32bit.panic-abort.diff | 15 ++-- ...xed_slice.main.GVN.32bit.panic-unwind.diff | 15 ++-- ...oxed_slice.main.GVN.64bit.panic-abort.diff | 15 ++-- ...xed_slice.main.GVN.64bit.panic-unwind.diff | 15 ++-- ...adStoreElimination-final.panic-abort.diff} | 4 +- ...dStoreElimination-final.panic-unwind.diff} | 4 +- ...adStoreElimination-final.panic-abort.diff} | 4 +- ...dStoreElimination-final.panic-unwind.diff} | 4 +- .../dead-store-elimination/call_arg_copy.rs | 12 ++- ...e.cycle.DeadStoreElimination-initial.diff} | 4 +- tests/mir-opt/dead-store-elimination/cycle.rs | 9 +- ...on.main.DeadStoreElimination-initial.diff} | 4 +- .../dead-store-elimination/place_mention.rs | 15 ++-- ..._to_int.DeadStoreElimination-initial.diff} | 4 +- ....retags.DeadStoreElimination-initial.diff} | 4 +- .../provenance_soundness.rs | 18 ++-- ...in.DestinationPropagation.panic-abort.diff | 10 ++- ...n.DestinationPropagation.panic-unwind.diff | 10 ++- ...to_exponential_common.GVN.panic-abort.diff | 34 +++++++- ...o_exponential_common.GVN.panic-unwind.diff | 34 +++++++- ...ine_coroutine.main.Inline.panic-abort.diff | 2 +- ...ne_coroutine.main.Inline.panic-unwind.diff | 2 +- ...inline_diverging.h.Inline.panic-abort.diff | 2 +- ...nline_diverging.h.Inline.panic-unwind.diff | 2 +- ...unchecked.PreCodegen.after.panic-abort.mir | 2 +- ...nchecked.PreCodegen.after.panic-unwind.mir | 2 +- .../issue_101973.inner.GVN.panic-abort.diff | 14 +++- .../issue_101973.inner.GVN.panic-unwind.diff | 14 +++- ...ng.identity.JumpThreading.panic-abort.diff | 4 +- ...g.identity.JumpThreading.panic-unwind.diff | 4 +- ...d_constant.main.GVN.32bit.panic-abort.diff | 16 +++- ..._constant.main.GVN.32bit.panic-unwind.diff | 16 +++- ...d_constant.main.GVN.64bit.panic-abort.diff | 16 +++- ..._constant.main.GVN.64bit.panic-unwind.diff | 16 +++- .../loops.filter_mapped.PreCodegen.after.mir | 2 +- .../loops.int_range.PreCodegen.after.mir | 2 +- .../loops.mapped.PreCodegen.after.mir | 2 +- ...m_replace.mem_replace.PreCodegen.after.mir | 19 +++-- ...o_variable.main.GVN.32bit.panic-abort.diff | 8 +- ..._variable.main.GVN.32bit.panic-unwind.diff | 8 +- ...o_variable.main.GVN.64bit.panic-abort.diff | 8 +- ..._variable.main.GVN.64bit.panic-unwind.diff | 8 +- ...ward_loop.PreCodegen.after.panic-abort.mir | 2 +- ...ard_loop.PreCodegen.after.panic-unwind.mir | 2 +- ...sive_loop.PreCodegen.after.panic-abort.mir | 2 +- ...ive_loop.PreCodegen.after.panic-unwind.mir | 2 +- ...mut_usize.PreCodegen.after.panic-abort.mir | 13 +-- ...ut_usize.PreCodegen.after.panic-unwind.mir | 13 +-- ...mut_range.PreCodegen.after.panic-abort.mir | 17 ++-- ...ut_range.PreCodegen.after.panic-unwind.mir | 17 ++-- ...ated_loop.PreCodegen.after.panic-abort.mir | 19 +++-- ...ted_loop.PreCodegen.after.panic-unwind.mir | 19 +++-- ...ward_loop.PreCodegen.after.panic-abort.mir | 17 ++-- ...ard_loop.PreCodegen.after.panic-unwind.mir | 17 ++-- ...ange_loop.PreCodegen.after.panic-abort.mir | 2 +- ...nge_loop.PreCodegen.after.panic-unwind.mir | 2 +- ...erse_loop.PreCodegen.after.panic-abort.mir | 19 +++-- ...rse_loop.PreCodegen.after.panic-unwind.mir | 19 +++-- .../try_identity.new.PreCodegen.after.mir | 8 +- .../try_identity.old.PreCodegen.after.mir | 4 +- ...t_switch.identity.SeparateConstSwitch.diff | 82 ++++++++++--------- ...witch.too_complex.SeparateConstSwitch.diff | 41 +++++----- .../simplify_match.main.GVN.panic-abort.diff | 10 ++- .../simplify_match.main.GVN.panic-unwind.diff | 10 ++- 70 files changed, 539 insertions(+), 282 deletions(-) rename tests/mir-opt/dead-store-elimination/{call_arg_copy.move_packed.DeadStoreElimination.panic-abort.diff => call_arg_copy.move_packed.DeadStoreElimination-final.panic-abort.diff} (64%) rename tests/mir-opt/dead-store-elimination/{call_arg_copy.move_packed.DeadStoreElimination.panic-unwind.diff => call_arg_copy.move_packed.DeadStoreElimination-final.panic-unwind.diff} (64%) rename tests/mir-opt/dead-store-elimination/{call_arg_copy.move_simple.DeadStoreElimination.panic-abort.diff => call_arg_copy.move_simple.DeadStoreElimination-final.panic-abort.diff} (78%) rename tests/mir-opt/dead-store-elimination/{call_arg_copy.move_simple.DeadStoreElimination.panic-unwind.diff => call_arg_copy.move_simple.DeadStoreElimination-final.panic-unwind.diff} (78%) rename tests/mir-opt/dead-store-elimination/{cycle.cycle.DeadStoreElimination.diff => cycle.cycle.DeadStoreElimination-initial.diff} (81%) rename tests/mir-opt/dead-store-elimination/{place_mention.main.DeadStoreElimination.diff => place_mention.main.DeadStoreElimination-initial.diff} (73%) rename tests/mir-opt/dead-store-elimination/{provenance_soundness.pointer_to_int.DeadStoreElimination.diff => provenance_soundness.pointer_to_int.DeadStoreElimination-initial.diff} (84%) rename tests/mir-opt/dead-store-elimination/{provenance_soundness.retags.DeadStoreElimination.diff => provenance_soundness.retags.DeadStoreElimination-initial.diff} (61%) diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs index 3d74ef7e3278e..9dd5aa4c8bd8e 100644 --- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs +++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs @@ -127,9 +127,19 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { crate::simplify::simplify_locals(body, tcx) } -pub struct DeadStoreElimination; +pub enum DeadStoreElimination { + Initial, + Final, +} impl<'tcx> MirPass<'tcx> for DeadStoreElimination { + fn name(&self) -> &'static str { + match self { + DeadStoreElimination::Initial => "DeadStoreElimination-initial", + DeadStoreElimination::Final => "DeadStoreElimination-final", + } + } + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { sess.mir_opt_level() >= 2 } diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index ce9043ec28702..4e8afcd7d2fcc 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -595,24 +595,25 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &multiple_return_terminators::MultipleReturnTerminators, &instsimplify::InstSimplify, &simplify::SimplifyLocals::BeforeConstProp, - ©_prop::CopyProp, + &dead_store_elimination::DeadStoreElimination::Initial, + &gvn::GVN, + &simplify::SimplifyLocals::AfterGVN, // Perform `SeparateConstSwitch` after SSA-based analyses, as cloning blocks may // destroy the SSA property. It should still happen before const-propagation, so the // latter pass will leverage the created opportunities. &separate_const_switch::SeparateConstSwitch, - &gvn::GVN, - &simplify::SimplifyLocals::AfterGVN, &dataflow_const_prop::DataflowConstProp, &const_debuginfo::ConstDebugInfo, &o1(simplify_branches::SimplifyConstCondition::AfterConstProp), &jump_threading::JumpThreading, &early_otherwise_branch::EarlyOtherwiseBranch, &simplify_comparison_integral::SimplifyComparisonIntegral, - &dead_store_elimination::DeadStoreElimination, &dest_prop::DestinationPropagation, &o1(simplify_branches::SimplifyConstCondition::Final), &o1(remove_noop_landing_pads::RemoveNoopLandingPads), &o1(simplify::SimplifyCfg::Final), + ©_prop::CopyProp, + &dead_store_elimination::DeadStoreElimination::Final, &nrvo::RenameReturnPlace, &simplify::SimplifyLocals::Final, &multiple_return_terminators::MultipleReturnTerminators, diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff index 6925fdb1e704f..ffbd97bb5452f 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff @@ -25,20 +25,21 @@ scope 11 (inlined NonNull::<[bool; 0]>::new_unchecked) { debug ptr => _6; let mut _8: *const [bool; 0]; + let mut _9: *mut [bool; 0]; scope 12 { scope 13 (inlined NonNull::::new_unchecked::runtime::<[bool; 0]>) { - debug ptr => _6; + debug ptr => _9; scope 14 (inlined std::ptr::mut_ptr::::is_null) { - debug self => _6; - let mut _9: *mut u8; + debug self => _9; + let mut _10: *mut u8; scope 15 { scope 16 (inlined std::ptr::mut_ptr::::is_null::runtime_impl) { - debug ptr => _9; + debug ptr => _10; scope 17 (inlined std::ptr::mut_ptr::::addr) { - debug self => _9; + debug self => _10; scope 18 { scope 19 (inlined std::ptr::mut_ptr::::cast::<()>) { - debug self => _9; + debug self => _10; } } } @@ -74,8 +75,10 @@ StorageDead(_7); StorageLive(_8); StorageLive(_9); + StorageLive(_10); _8 = const {0x1 as *mut [bool; 0]} as *const [bool; 0] (PointerCoercion(MutToConstPointer)); _5 = NonNull::<[bool; 0]> { pointer: _8 }; + StorageDead(_10); StorageDead(_9); StorageDead(_8); StorageDead(_6); diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff index 82ad842505c5a..7b6dcf1972b2e 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff @@ -25,20 +25,21 @@ scope 11 (inlined NonNull::<[bool; 0]>::new_unchecked) { debug ptr => _6; let mut _8: *const [bool; 0]; + let mut _9: *mut [bool; 0]; scope 12 { scope 13 (inlined NonNull::::new_unchecked::runtime::<[bool; 0]>) { - debug ptr => _6; + debug ptr => _9; scope 14 (inlined std::ptr::mut_ptr::::is_null) { - debug self => _6; - let mut _9: *mut u8; + debug self => _9; + let mut _10: *mut u8; scope 15 { scope 16 (inlined std::ptr::mut_ptr::::is_null::runtime_impl) { - debug ptr => _9; + debug ptr => _10; scope 17 (inlined std::ptr::mut_ptr::::addr) { - debug self => _9; + debug self => _10; scope 18 { scope 19 (inlined std::ptr::mut_ptr::::cast::<()>) { - debug self => _9; + debug self => _10; } } } @@ -74,8 +75,10 @@ StorageDead(_7); StorageLive(_8); StorageLive(_9); + StorageLive(_10); _8 = const {0x1 as *mut [bool; 0]} as *const [bool; 0] (PointerCoercion(MutToConstPointer)); _5 = NonNull::<[bool; 0]> { pointer: _8 }; + StorageDead(_10); StorageDead(_9); StorageDead(_8); StorageDead(_6); diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff index 6925fdb1e704f..ffbd97bb5452f 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff @@ -25,20 +25,21 @@ scope 11 (inlined NonNull::<[bool; 0]>::new_unchecked) { debug ptr => _6; let mut _8: *const [bool; 0]; + let mut _9: *mut [bool; 0]; scope 12 { scope 13 (inlined NonNull::::new_unchecked::runtime::<[bool; 0]>) { - debug ptr => _6; + debug ptr => _9; scope 14 (inlined std::ptr::mut_ptr::::is_null) { - debug self => _6; - let mut _9: *mut u8; + debug self => _9; + let mut _10: *mut u8; scope 15 { scope 16 (inlined std::ptr::mut_ptr::::is_null::runtime_impl) { - debug ptr => _9; + debug ptr => _10; scope 17 (inlined std::ptr::mut_ptr::::addr) { - debug self => _9; + debug self => _10; scope 18 { scope 19 (inlined std::ptr::mut_ptr::::cast::<()>) { - debug self => _9; + debug self => _10; } } } @@ -74,8 +75,10 @@ StorageDead(_7); StorageLive(_8); StorageLive(_9); + StorageLive(_10); _8 = const {0x1 as *mut [bool; 0]} as *const [bool; 0] (PointerCoercion(MutToConstPointer)); _5 = NonNull::<[bool; 0]> { pointer: _8 }; + StorageDead(_10); StorageDead(_9); StorageDead(_8); StorageDead(_6); diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff index 82ad842505c5a..7b6dcf1972b2e 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff @@ -25,20 +25,21 @@ scope 11 (inlined NonNull::<[bool; 0]>::new_unchecked) { debug ptr => _6; let mut _8: *const [bool; 0]; + let mut _9: *mut [bool; 0]; scope 12 { scope 13 (inlined NonNull::::new_unchecked::runtime::<[bool; 0]>) { - debug ptr => _6; + debug ptr => _9; scope 14 (inlined std::ptr::mut_ptr::::is_null) { - debug self => _6; - let mut _9: *mut u8; + debug self => _9; + let mut _10: *mut u8; scope 15 { scope 16 (inlined std::ptr::mut_ptr::::is_null::runtime_impl) { - debug ptr => _9; + debug ptr => _10; scope 17 (inlined std::ptr::mut_ptr::::addr) { - debug self => _9; + debug self => _10; scope 18 { scope 19 (inlined std::ptr::mut_ptr::::cast::<()>) { - debug self => _9; + debug self => _10; } } } @@ -74,8 +75,10 @@ StorageDead(_7); StorageLive(_8); StorageLive(_9); + StorageLive(_10); _8 = const {0x1 as *mut [bool; 0]} as *const [bool; 0] (PointerCoercion(MutToConstPointer)); _5 = NonNull::<[bool; 0]> { pointer: _8 }; + StorageDead(_10); StorageDead(_9); StorageDead(_8); StorageDead(_6); diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff index 13545aa464aa5..df68ce496fd8c 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff @@ -25,20 +25,21 @@ scope 11 (inlined NonNull::<[bool; 0]>::new_unchecked) { debug ptr => _6; let mut _8: *const [bool; 0]; + let mut _9: *mut [bool; 0]; scope 12 { scope 13 (inlined NonNull::::new_unchecked::runtime::<[bool; 0]>) { - debug ptr => _6; + debug ptr => _9; scope 14 (inlined std::ptr::mut_ptr::::is_null) { - debug self => _6; - let mut _9: *mut u8; + debug self => _9; + let mut _10: *mut u8; scope 15 { scope 16 (inlined std::ptr::mut_ptr::::is_null::runtime_impl) { - debug ptr => _9; + debug ptr => _10; scope 17 (inlined std::ptr::mut_ptr::::addr) { - debug self => _9; + debug self => _10; scope 18 { scope 19 (inlined std::ptr::mut_ptr::::cast::<()>) { - debug self => _9; + debug self => _10; } } } @@ -76,9 +77,11 @@ StorageDead(_7); StorageLive(_8); StorageLive(_9); + StorageLive(_10); - _8 = _6 as *const [bool; 0] (PointerCoercion(MutToConstPointer)); + _8 = const {0x1 as *mut [bool; 0]} as *const [bool; 0] (PointerCoercion(MutToConstPointer)); _5 = NonNull::<[bool; 0]> { pointer: _8 }; + StorageDead(_10); StorageDead(_9); StorageDead(_8); StorageDead(_6); diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff index bf32691538148..e16ea22091ee2 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff @@ -25,20 +25,21 @@ scope 11 (inlined NonNull::<[bool; 0]>::new_unchecked) { debug ptr => _6; let mut _8: *const [bool; 0]; + let mut _9: *mut [bool; 0]; scope 12 { scope 13 (inlined NonNull::::new_unchecked::runtime::<[bool; 0]>) { - debug ptr => _6; + debug ptr => _9; scope 14 (inlined std::ptr::mut_ptr::::is_null) { - debug self => _6; - let mut _9: *mut u8; + debug self => _9; + let mut _10: *mut u8; scope 15 { scope 16 (inlined std::ptr::mut_ptr::::is_null::runtime_impl) { - debug ptr => _9; + debug ptr => _10; scope 17 (inlined std::ptr::mut_ptr::::addr) { - debug self => _9; + debug self => _10; scope 18 { scope 19 (inlined std::ptr::mut_ptr::::cast::<()>) { - debug self => _9; + debug self => _10; } } } @@ -76,9 +77,11 @@ StorageDead(_7); StorageLive(_8); StorageLive(_9); + StorageLive(_10); - _8 = _6 as *const [bool; 0] (PointerCoercion(MutToConstPointer)); + _8 = const {0x1 as *mut [bool; 0]} as *const [bool; 0] (PointerCoercion(MutToConstPointer)); _5 = NonNull::<[bool; 0]> { pointer: _8 }; + StorageDead(_10); StorageDead(_9); StorageDead(_8); StorageDead(_6); diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff index 13545aa464aa5..df68ce496fd8c 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff @@ -25,20 +25,21 @@ scope 11 (inlined NonNull::<[bool; 0]>::new_unchecked) { debug ptr => _6; let mut _8: *const [bool; 0]; + let mut _9: *mut [bool; 0]; scope 12 { scope 13 (inlined NonNull::::new_unchecked::runtime::<[bool; 0]>) { - debug ptr => _6; + debug ptr => _9; scope 14 (inlined std::ptr::mut_ptr::::is_null) { - debug self => _6; - let mut _9: *mut u8; + debug self => _9; + let mut _10: *mut u8; scope 15 { scope 16 (inlined std::ptr::mut_ptr::::is_null::runtime_impl) { - debug ptr => _9; + debug ptr => _10; scope 17 (inlined std::ptr::mut_ptr::::addr) { - debug self => _9; + debug self => _10; scope 18 { scope 19 (inlined std::ptr::mut_ptr::::cast::<()>) { - debug self => _9; + debug self => _10; } } } @@ -76,9 +77,11 @@ StorageDead(_7); StorageLive(_8); StorageLive(_9); + StorageLive(_10); - _8 = _6 as *const [bool; 0] (PointerCoercion(MutToConstPointer)); + _8 = const {0x1 as *mut [bool; 0]} as *const [bool; 0] (PointerCoercion(MutToConstPointer)); _5 = NonNull::<[bool; 0]> { pointer: _8 }; + StorageDead(_10); StorageDead(_9); StorageDead(_8); StorageDead(_6); diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff index bf32691538148..e16ea22091ee2 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff @@ -25,20 +25,21 @@ scope 11 (inlined NonNull::<[bool; 0]>::new_unchecked) { debug ptr => _6; let mut _8: *const [bool; 0]; + let mut _9: *mut [bool; 0]; scope 12 { scope 13 (inlined NonNull::::new_unchecked::runtime::<[bool; 0]>) { - debug ptr => _6; + debug ptr => _9; scope 14 (inlined std::ptr::mut_ptr::::is_null) { - debug self => _6; - let mut _9: *mut u8; + debug self => _9; + let mut _10: *mut u8; scope 15 { scope 16 (inlined std::ptr::mut_ptr::::is_null::runtime_impl) { - debug ptr => _9; + debug ptr => _10; scope 17 (inlined std::ptr::mut_ptr::::addr) { - debug self => _9; + debug self => _10; scope 18 { scope 19 (inlined std::ptr::mut_ptr::::cast::<()>) { - debug self => _9; + debug self => _10; } } } @@ -76,9 +77,11 @@ StorageDead(_7); StorageLive(_8); StorageLive(_9); + StorageLive(_10); - _8 = _6 as *const [bool; 0] (PointerCoercion(MutToConstPointer)); + _8 = const {0x1 as *mut [bool; 0]} as *const [bool; 0] (PointerCoercion(MutToConstPointer)); _5 = NonNull::<[bool; 0]> { pointer: _8 }; + StorageDead(_10); StorageDead(_9); StorageDead(_8); StorageDead(_6); diff --git a/tests/mir-opt/dead-store-elimination/call_arg_copy.move_packed.DeadStoreElimination.panic-abort.diff b/tests/mir-opt/dead-store-elimination/call_arg_copy.move_packed.DeadStoreElimination-final.panic-abort.diff similarity index 64% rename from tests/mir-opt/dead-store-elimination/call_arg_copy.move_packed.DeadStoreElimination.panic-abort.diff rename to tests/mir-opt/dead-store-elimination/call_arg_copy.move_packed.DeadStoreElimination-final.panic-abort.diff index dc0f9073416fd..07fb8301b9a94 100644 --- a/tests/mir-opt/dead-store-elimination/call_arg_copy.move_packed.DeadStoreElimination.panic-abort.diff +++ b/tests/mir-opt/dead-store-elimination/call_arg_copy.move_packed.DeadStoreElimination-final.panic-abort.diff @@ -1,5 +1,5 @@ -- // MIR for `move_packed` before DeadStoreElimination -+ // MIR for `move_packed` after DeadStoreElimination +- // MIR for `move_packed` before DeadStoreElimination-final ++ // MIR for `move_packed` after DeadStoreElimination-final fn move_packed(_1: Packed) -> () { let mut _0: (); diff --git a/tests/mir-opt/dead-store-elimination/call_arg_copy.move_packed.DeadStoreElimination.panic-unwind.diff b/tests/mir-opt/dead-store-elimination/call_arg_copy.move_packed.DeadStoreElimination-final.panic-unwind.diff similarity index 64% rename from tests/mir-opt/dead-store-elimination/call_arg_copy.move_packed.DeadStoreElimination.panic-unwind.diff rename to tests/mir-opt/dead-store-elimination/call_arg_copy.move_packed.DeadStoreElimination-final.panic-unwind.diff index 86ef026ec5c88..cac3badfa6732 100644 --- a/tests/mir-opt/dead-store-elimination/call_arg_copy.move_packed.DeadStoreElimination.panic-unwind.diff +++ b/tests/mir-opt/dead-store-elimination/call_arg_copy.move_packed.DeadStoreElimination-final.panic-unwind.diff @@ -1,5 +1,5 @@ -- // MIR for `move_packed` before DeadStoreElimination -+ // MIR for `move_packed` after DeadStoreElimination +- // MIR for `move_packed` before DeadStoreElimination-final ++ // MIR for `move_packed` after DeadStoreElimination-final fn move_packed(_1: Packed) -> () { let mut _0: (); diff --git a/tests/mir-opt/dead-store-elimination/call_arg_copy.move_simple.DeadStoreElimination.panic-abort.diff b/tests/mir-opt/dead-store-elimination/call_arg_copy.move_simple.DeadStoreElimination-final.panic-abort.diff similarity index 78% rename from tests/mir-opt/dead-store-elimination/call_arg_copy.move_simple.DeadStoreElimination.panic-abort.diff rename to tests/mir-opt/dead-store-elimination/call_arg_copy.move_simple.DeadStoreElimination-final.panic-abort.diff index 8f799b33f45d9..268924b7c5dcc 100644 --- a/tests/mir-opt/dead-store-elimination/call_arg_copy.move_simple.DeadStoreElimination.panic-abort.diff +++ b/tests/mir-opt/dead-store-elimination/call_arg_copy.move_simple.DeadStoreElimination-final.panic-abort.diff @@ -1,5 +1,5 @@ -- // MIR for `move_simple` before DeadStoreElimination -+ // MIR for `move_simple` after DeadStoreElimination +- // MIR for `move_simple` before DeadStoreElimination-final ++ // MIR for `move_simple` after DeadStoreElimination-final fn move_simple(_1: i32) -> () { debug x => _1; diff --git a/tests/mir-opt/dead-store-elimination/call_arg_copy.move_simple.DeadStoreElimination.panic-unwind.diff b/tests/mir-opt/dead-store-elimination/call_arg_copy.move_simple.DeadStoreElimination-final.panic-unwind.diff similarity index 78% rename from tests/mir-opt/dead-store-elimination/call_arg_copy.move_simple.DeadStoreElimination.panic-unwind.diff rename to tests/mir-opt/dead-store-elimination/call_arg_copy.move_simple.DeadStoreElimination-final.panic-unwind.diff index 0551d663b50f2..bd754f9ebd428 100644 --- a/tests/mir-opt/dead-store-elimination/call_arg_copy.move_simple.DeadStoreElimination.panic-unwind.diff +++ b/tests/mir-opt/dead-store-elimination/call_arg_copy.move_simple.DeadStoreElimination-final.panic-unwind.diff @@ -1,5 +1,5 @@ -- // MIR for `move_simple` before DeadStoreElimination -+ // MIR for `move_simple` after DeadStoreElimination +- // MIR for `move_simple` before DeadStoreElimination-final ++ // MIR for `move_simple` after DeadStoreElimination-final fn move_simple(_1: i32) -> () { debug x => _1; diff --git a/tests/mir-opt/dead-store-elimination/call_arg_copy.rs b/tests/mir-opt/dead-store-elimination/call_arg_copy.rs index 490a4aa502c38..37b3313f7d041 100644 --- a/tests/mir-opt/dead-store-elimination/call_arg_copy.rs +++ b/tests/mir-opt/dead-store-elimination/call_arg_copy.rs @@ -1,6 +1,5 @@ -// skip-filecheck // EMIT_MIR_FOR_EACH_PANIC_STRATEGY -// unit-test: DeadStoreElimination +// unit-test: DeadStoreElimination-final // compile-flags: -Zmir-enable-passes=+CopyProp #![feature(core_intrinsics)] @@ -12,8 +11,10 @@ use std::intrinsics::mir::*; #[inline(never)] fn use_both(_: i32, _: i32) {} -// EMIT_MIR call_arg_copy.move_simple.DeadStoreElimination.diff +// EMIT_MIR call_arg_copy.move_simple.DeadStoreElimination-final.diff fn move_simple(x: i32) { + // CHECK-LABEL: fn move_simple( + // CHECK: = use_both(_1, move _1) use_both(x, x); } @@ -23,11 +24,14 @@ struct Packed { y: i32, } -// EMIT_MIR call_arg_copy.move_packed.DeadStoreElimination.diff +// EMIT_MIR call_arg_copy.move_packed.DeadStoreElimination-final.diff #[custom_mir(dialect = "analysis")] fn move_packed(packed: Packed) { + // CHECK-LABEL: fn move_packed( + // CHECK: = use_both(const 0_i32, (_1.1: i32)) mir!( { + // We have a packed struct, verify that the copy is not turned into a move. Call(RET = use_both(0, packed.y), ReturnTo(ret), UnwindContinue()) } ret = { diff --git a/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.diff b/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination-initial.diff similarity index 81% rename from tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.diff rename to tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination-initial.diff index cf73358dc52eb..f13588c3aa485 100644 --- a/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.diff +++ b/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination-initial.diff @@ -1,5 +1,5 @@ -- // MIR for `cycle` before DeadStoreElimination -+ // MIR for `cycle` after DeadStoreElimination +- // MIR for `cycle` before DeadStoreElimination-initial ++ // MIR for `cycle` after DeadStoreElimination-initial fn cycle(_1: i32, _2: i32, _3: i32) -> () { let mut _0: (); diff --git a/tests/mir-opt/dead-store-elimination/cycle.rs b/tests/mir-opt/dead-store-elimination/cycle.rs index 13e5411275da8..e8f566b4aa7be 100644 --- a/tests/mir-opt/dead-store-elimination/cycle.rs +++ b/tests/mir-opt/dead-store-elimination/cycle.rs @@ -1,9 +1,8 @@ -// skip-filecheck // This example is interesting because the non-transitive version of `MaybeLiveLocals` would // report that *all* of these stores are live. // // needs-unwind -// unit-test: DeadStoreElimination +// unit-test: DeadStoreElimination-initial #![feature(core_intrinsics, custom_mir)] use std::intrinsics::mir::*; @@ -13,9 +12,13 @@ fn cond() -> bool { false } -// EMIT_MIR cycle.cycle.DeadStoreElimination.diff +// EMIT_MIR cycle.cycle.DeadStoreElimination-initial.diff #[custom_mir(dialect = "runtime", phase = "post-cleanup")] fn cycle(mut x: i32, mut y: i32, mut z: i32) { + // CHECK-LABEL: fn cycle( + // CHECK-NOT: {{_.*}} = {{_.*}}; + // CHECK-NOT: {{_.*}} = move {{_.*}}; + // We use custom MIR to avoid generating debuginfo, that would force to preserve writes. mir!( let condition: bool; diff --git a/tests/mir-opt/dead-store-elimination/place_mention.main.DeadStoreElimination.diff b/tests/mir-opt/dead-store-elimination/place_mention.main.DeadStoreElimination-initial.diff similarity index 73% rename from tests/mir-opt/dead-store-elimination/place_mention.main.DeadStoreElimination.diff rename to tests/mir-opt/dead-store-elimination/place_mention.main.DeadStoreElimination-initial.diff index 2130518771a58..5a55028587124 100644 --- a/tests/mir-opt/dead-store-elimination/place_mention.main.DeadStoreElimination.diff +++ b/tests/mir-opt/dead-store-elimination/place_mention.main.DeadStoreElimination-initial.diff @@ -1,5 +1,5 @@ -- // MIR for `main` before DeadStoreElimination -+ // MIR for `main` after DeadStoreElimination +- // MIR for `main` before DeadStoreElimination-initial ++ // MIR for `main` after DeadStoreElimination-initial fn main() -> () { let mut _0: (); diff --git a/tests/mir-opt/dead-store-elimination/place_mention.rs b/tests/mir-opt/dead-store-elimination/place_mention.rs index 4813cf7ee2bd6..ae75e622ff7f9 100644 --- a/tests/mir-opt/dead-store-elimination/place_mention.rs +++ b/tests/mir-opt/dead-store-elimination/place_mention.rs @@ -1,10 +1,15 @@ -// skip-filecheck -// unit-test: DeadStoreElimination +// Verify that we account for the `PlaceMention` statement as a use of the tuple, +// and don't remove it as a dead store. +// +// unit-test: DeadStoreElimination-initial // compile-flags: -Zmir-keep-place-mention -// EMIT_MIR place_mention.main.DeadStoreElimination.diff +// EMIT_MIR place_mention.main.DeadStoreElimination-initial.diff fn main() { - // Verify that we account for the `PlaceMention` statement as a use of the tuple, - // and don't remove it as a dead store. + // CHECK-LABEL: fn main( + // CHECK-NOT: PlaceMention( + // CHECK: [[tmp:_.*]] = + // CHECK-NEXT: PlaceMention([[tmp:_.*]]); + let (_, _) = ("Hello", "World"); } diff --git a/tests/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination.diff b/tests/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination-initial.diff similarity index 84% rename from tests/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination.diff rename to tests/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination-initial.diff index 31f727e5fb350..9b0dc6b6af670 100644 --- a/tests/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination.diff +++ b/tests/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination-initial.diff @@ -1,5 +1,5 @@ -- // MIR for `pointer_to_int` before DeadStoreElimination -+ // MIR for `pointer_to_int` after DeadStoreElimination +- // MIR for `pointer_to_int` before DeadStoreElimination-initial ++ // MIR for `pointer_to_int` after DeadStoreElimination-initial fn pointer_to_int(_1: *mut i32) -> () { debug p => _1; diff --git a/tests/mir-opt/dead-store-elimination/provenance_soundness.retags.DeadStoreElimination.diff b/tests/mir-opt/dead-store-elimination/provenance_soundness.retags.DeadStoreElimination-initial.diff similarity index 61% rename from tests/mir-opt/dead-store-elimination/provenance_soundness.retags.DeadStoreElimination.diff rename to tests/mir-opt/dead-store-elimination/provenance_soundness.retags.DeadStoreElimination-initial.diff index e1ebc39aacc4a..ab74d2411bb10 100644 --- a/tests/mir-opt/dead-store-elimination/provenance_soundness.retags.DeadStoreElimination.diff +++ b/tests/mir-opt/dead-store-elimination/provenance_soundness.retags.DeadStoreElimination-initial.diff @@ -1,5 +1,5 @@ -- // MIR for `retags` before DeadStoreElimination -+ // MIR for `retags` after DeadStoreElimination +- // MIR for `retags` before DeadStoreElimination-initial ++ // MIR for `retags` after DeadStoreElimination-initial fn retags(_1: &mut i32) -> () { debug _r => _1; diff --git a/tests/mir-opt/dead-store-elimination/provenance_soundness.rs b/tests/mir-opt/dead-store-elimination/provenance_soundness.rs index 24ffbe980ebc6..916c393b9de07 100644 --- a/tests/mir-opt/dead-store-elimination/provenance_soundness.rs +++ b/tests/mir-opt/dead-store-elimination/provenance_soundness.rs @@ -1,17 +1,21 @@ -// skip-filecheck -// unit-test: DeadStoreElimination -// compile-flags: -Zmir-emit-retag - // Test that we don't remove pointer to int casts or retags +// unit-test: DeadStoreElimination-initial +// compile-flags: -Zmir-emit-retag -// EMIT_MIR provenance_soundness.pointer_to_int.DeadStoreElimination.diff +// EMIT_MIR provenance_soundness.pointer_to_int.DeadStoreElimination-initial.diff fn pointer_to_int(p: *mut i32) { + // CHECK-LABEL: fn pointer_to_int( + // CHECK: {{_.*}} = {{.*}} as usize (PointerExposeAddress); + // CHECK: {{_.*}} = {{.*}} as isize (PointerExposeAddress); let _x = p as usize; let _y = p as isize; } -// EMIT_MIR provenance_soundness.retags.DeadStoreElimination.diff -fn retags(_r: &mut i32) {} +// EMIT_MIR provenance_soundness.retags.DeadStoreElimination-initial.diff +fn retags(_r: &mut i32) { + // CHECK-LABEL: fn retags( + // CHECK: Retag([fn entry] _1); +} fn main() { pointer_to_int(&mut 5 as *mut _); diff --git a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff index 993e0f1d1a67d..0af3faf28f076 100644 --- a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff +++ b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff @@ -5,12 +5,13 @@ let mut _0: (); let _1: main::Un; let mut _2: u32; + let mut _3: u32; scope 1 { debug un => _1; scope 2 { } scope 4 (inlined std::mem::drop::) { - debug _x => _2; + debug _x => _3; } } scope 3 (inlined val) { @@ -18,10 +19,13 @@ bb0: { StorageLive(_1); - _1 = Un { us: const 1_u32 }; StorageLive(_2); - _2 = (_1.0: u32); + _2 = const 1_u32; + _1 = Un { us: const 1_u32 }; StorageDead(_2); + StorageLive(_3); + _3 = (_1.0: u32); + StorageDead(_3); StorageDead(_1); return; } diff --git a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff index 993e0f1d1a67d..0af3faf28f076 100644 --- a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff +++ b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff @@ -5,12 +5,13 @@ let mut _0: (); let _1: main::Un; let mut _2: u32; + let mut _3: u32; scope 1 { debug un => _1; scope 2 { } scope 4 (inlined std::mem::drop::) { - debug _x => _2; + debug _x => _3; } } scope 3 (inlined val) { @@ -18,10 +19,13 @@ bb0: { StorageLive(_1); - _1 = Un { us: const 1_u32 }; StorageLive(_2); - _2 = (_1.0: u32); + _2 = const 1_u32; + _1 = Un { us: const 1_u32 }; StorageDead(_2); + StorageLive(_3); + _3 = (_1.0: u32); + StorageDead(_3); StorageDead(_1); return; } diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-abort.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-abort.diff index 0ba1bac0a0308..080478ea88419 100644 --- a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-abort.diff +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-abort.diff @@ -73,31 +73,59 @@ } bb4: { +- StorageLive(_8); ++ nop; _8 = ((_6 as Some).0: usize); + StorageLive(_9); + _9 = _1; + StorageLive(_10); + _10 = _2; StorageLive(_11); _11 = _5; StorageLive(_12); StorageLive(_13); - _13 = _8 as u32 (IntToInt); + StorageLive(_14); + _14 = _8; +- _13 = move _14 as u32 (IntToInt); ++ _13 = _8 as u32 (IntToInt); + StorageDead(_14); _12 = Add(move _13, const 1_u32); StorageDead(_13); - _0 = float_to_exponential_common_exact::(_1, _2, move _11, move _12, _3) -> [return: bb5, unwind unreachable]; + StorageLive(_15); + _15 = _3; +- _0 = float_to_exponential_common_exact::(move _9, move _10, move _11, move _12, move _15) -> [return: bb5, unwind unreachable]; ++ _0 = float_to_exponential_common_exact::(_1, _2, move _11, move _12, _3) -> [return: bb5, unwind unreachable]; } bb5: { + StorageDead(_15); StorageDead(_12); StorageDead(_11); + StorageDead(_10); + StorageDead(_9); +- StorageDead(_8); ++ nop; goto -> bb8; } bb6: { + StorageLive(_16); + _16 = _1; + StorageLive(_17); + _17 = _2; StorageLive(_18); _18 = _5; - _0 = float_to_exponential_common_shortest::(_1, _2, move _18, _3) -> [return: bb7, unwind unreachable]; + StorageLive(_19); + _19 = _3; +- _0 = float_to_exponential_common_shortest::(move _16, move _17, move _18, move _19) -> [return: bb7, unwind unreachable]; ++ _0 = float_to_exponential_common_shortest::(_1, _2, move _18, _3) -> [return: bb7, unwind unreachable]; } bb7: { + StorageDead(_19); StorageDead(_18); + StorageDead(_17); + StorageDead(_16); goto -> bb8; } diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-unwind.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-unwind.diff index 27ea43ef12b77..ff8933fca8b2c 100644 --- a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-unwind.diff +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-unwind.diff @@ -73,31 +73,59 @@ } bb4: { +- StorageLive(_8); ++ nop; _8 = ((_6 as Some).0: usize); + StorageLive(_9); + _9 = _1; + StorageLive(_10); + _10 = _2; StorageLive(_11); _11 = _5; StorageLive(_12); StorageLive(_13); - _13 = _8 as u32 (IntToInt); + StorageLive(_14); + _14 = _8; +- _13 = move _14 as u32 (IntToInt); ++ _13 = _8 as u32 (IntToInt); + StorageDead(_14); _12 = Add(move _13, const 1_u32); StorageDead(_13); - _0 = float_to_exponential_common_exact::(_1, _2, move _11, move _12, _3) -> [return: bb5, unwind continue]; + StorageLive(_15); + _15 = _3; +- _0 = float_to_exponential_common_exact::(move _9, move _10, move _11, move _12, move _15) -> [return: bb5, unwind continue]; ++ _0 = float_to_exponential_common_exact::(_1, _2, move _11, move _12, _3) -> [return: bb5, unwind continue]; } bb5: { + StorageDead(_15); StorageDead(_12); StorageDead(_11); + StorageDead(_10); + StorageDead(_9); +- StorageDead(_8); ++ nop; goto -> bb8; } bb6: { + StorageLive(_16); + _16 = _1; + StorageLive(_17); + _17 = _2; StorageLive(_18); _18 = _5; - _0 = float_to_exponential_common_shortest::(_1, _2, move _18, _3) -> [return: bb7, unwind continue]; + StorageLive(_19); + _19 = _3; +- _0 = float_to_exponential_common_shortest::(move _16, move _17, move _18, move _19) -> [return: bb7, unwind continue]; ++ _0 = float_to_exponential_common_shortest::(_1, _2, move _18, _3) -> [return: bb7, unwind continue]; } bb7: { + StorageDead(_19); StorageDead(_18); + StorageDead(_17); + StorageDead(_16); goto -> bb8; } diff --git a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff index 68c612314f6d0..8e53427e7e060 100644 --- a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff @@ -36,7 +36,7 @@ - _4 = g() -> [return: bb1, unwind unreachable]; + _4 = {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8 (#0)}; + _3 = &mut _4; -+ _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}> { pointer: move _3 }; ++ _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}> { pointer: _3 }; + StorageDead(_3); + StorageLive(_5); + _5 = const false; diff --git a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff index 1bf14e8c3b330..b06db41af9d40 100644 --- a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff @@ -36,7 +36,7 @@ - _4 = g() -> [return: bb1, unwind continue]; + _4 = {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8 (#0)}; + _3 = &mut _4; -+ _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}> { pointer: move _3 }; ++ _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}> { pointer: _3 }; + StorageDead(_3); + StorageLive(_5); + _5 = const false; diff --git a/tests/mir-opt/inline/inline_diverging.h.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_diverging.h.Inline.panic-abort.diff index da45ebcb4d85c..2bbb830fc7790 100644 --- a/tests/mir-opt/inline/inline_diverging.h.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/inline_diverging.h.Inline.panic-abort.diff @@ -40,7 +40,7 @@ + + bb2: { + StorageDead(_5); -+ _1 = (move _4, move _6); ++ _1 = (_4, _6); + drop(_2) -> [return: bb3, unwind unreachable]; + } + diff --git a/tests/mir-opt/inline/inline_diverging.h.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_diverging.h.Inline.panic-unwind.diff index d65c65e5fd032..bc4f2d24df0b5 100644 --- a/tests/mir-opt/inline/inline_diverging.h.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/inline_diverging.h.Inline.panic-unwind.diff @@ -43,7 +43,7 @@ + StorageDead(_5); + StorageLive(_7); + _7 = move _4; -+ _1 = (move _7, move _6); ++ _1 = (move _7, _6); + StorageDead(_7); + StorageDead(_4); + drop(_2) -> [return: bb3, unwind continue]; diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-abort.mir b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-abort.mir index aeb93bd334fe6..d6a608476df9c 100644 --- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-abort.mir @@ -31,7 +31,7 @@ fn unwrap_unchecked(_1: Option) -> T { _2 = discriminant(_1); _3 = Eq(_2, const 1_isize); assume(move _3); - _0 = move ((_1 as Some).0: T); + _0 = ((_1 as Some).0: T); StorageDead(_3); StorageDead(_2); StorageDead(_4); diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-unwind.mir index aeb93bd334fe6..d6a608476df9c 100644 --- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-unwind.mir @@ -31,7 +31,7 @@ fn unwrap_unchecked(_1: Option) -> T { _2 = discriminant(_1); _3 = Eq(_2, const 1_isize); assume(move _3); - _0 = move ((_1 as Some).0: T); + _0 = ((_1 as Some).0: T); StorageDead(_3); StorageDead(_2); StorageDead(_4); diff --git a/tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff b/tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff index d2db8f61916a9..b04728a9b0f58 100644 --- a/tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff +++ b/tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff @@ -17,7 +17,7 @@ let mut _12: u32; let mut _13: bool; scope 1 (inlined imm8) { - debug x => _1; + debug x => _5; let mut _14: u32; let mut _15: u32; scope 2 { @@ -33,17 +33,23 @@ StorageLive(_2); StorageLive(_3); StorageLive(_4); + StorageLive(_5); + _5 = _1; _4 = const 0_u32; StorageLive(_15); StorageLive(_14); - _14 = Shr(_1, const 0_i32); +- _14 = Shr(_5, const 0_i32); ++ _14 = Shr(_1, const 0_i32); _15 = BitAnd(move _14, const 255_u32); StorageDead(_14); _4 = BitOr(const 0_u32, move _15); StorageDead(_15); + StorageDead(_5); StorageLive(_6); StorageLive(_7); StorageLive(_8); + StorageLive(_9); + _9 = _1; - _10 = const 8_i32 as u32 (IntToInt); - _11 = Lt(move _10, const 32_u32); - assert(move _11, "attempt to shift right by `{}`, which would overflow", const 8_i32) -> [success: bb1, unwind unreachable]; @@ -53,7 +59,9 @@ } bb1: { - _8 = Shr(_1, const 8_i32); +- _8 = Shr(move _9, const 8_i32); ++ _8 = Shr(_1, const 8_i32); + StorageDead(_9); _7 = BitAnd(move _8, const 15_u32); StorageDead(_8); - _12 = const 1_i32 as u32 (IntToInt); diff --git a/tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff b/tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff index 514183b3bc05e..fcf99ac6918de 100644 --- a/tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff +++ b/tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff @@ -17,7 +17,7 @@ let mut _12: u32; let mut _13: bool; scope 1 (inlined imm8) { - debug x => _1; + debug x => _5; let mut _14: u32; let mut _15: u32; scope 2 { @@ -33,17 +33,23 @@ StorageLive(_2); StorageLive(_3); StorageLive(_4); + StorageLive(_5); + _5 = _1; _4 = const 0_u32; StorageLive(_15); StorageLive(_14); - _14 = Shr(_1, const 0_i32); +- _14 = Shr(_5, const 0_i32); ++ _14 = Shr(_1, const 0_i32); _15 = BitAnd(move _14, const 255_u32); StorageDead(_14); _4 = BitOr(const 0_u32, move _15); StorageDead(_15); + StorageDead(_5); StorageLive(_6); StorageLive(_7); StorageLive(_8); + StorageLive(_9); + _9 = _1; - _10 = const 8_i32 as u32 (IntToInt); - _11 = Lt(move _10, const 32_u32); - assert(move _11, "attempt to shift right by `{}`, which would overflow", const 8_i32) -> [success: bb1, unwind continue]; @@ -53,7 +59,9 @@ } bb1: { - _8 = Shr(_1, const 8_i32); +- _8 = Shr(move _9, const 8_i32); ++ _8 = Shr(_1, const 8_i32); + StorageDead(_9); _7 = BitAnd(move _8, const 15_u32); StorageDead(_8); - _12 = const 1_i32 as u32 (IntToInt); diff --git a/tests/mir-opt/jump_threading.identity.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.identity.JumpThreading.panic-abort.diff index f04ca72dd6d97..9cc4385f60b87 100644 --- a/tests/mir-opt/jump_threading.identity.JumpThreading.panic-abort.diff +++ b/tests/mir-opt/jump_threading.identity.JumpThreading.panic-abort.diff @@ -110,7 +110,7 @@ bb6: { _12 = move ((_4 as Err).0: i32); StorageLive(_13); - _13 = Result::::Err(move _12); + _13 = Result::::Err(_12); _3 = ControlFlow::, i32>::Break(move _13); StorageDead(_13); - goto -> bb5; @@ -119,7 +119,7 @@ bb7: { _11 = move ((_4 as Ok).0: i32); - _3 = ControlFlow::, i32>::Continue(move _11); + _3 = ControlFlow::, i32>::Continue(_11); goto -> bb5; + } + diff --git a/tests/mir-opt/jump_threading.identity.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.identity.JumpThreading.panic-unwind.diff index f04ca72dd6d97..9cc4385f60b87 100644 --- a/tests/mir-opt/jump_threading.identity.JumpThreading.panic-unwind.diff +++ b/tests/mir-opt/jump_threading.identity.JumpThreading.panic-unwind.diff @@ -110,7 +110,7 @@ bb6: { _12 = move ((_4 as Err).0: i32); StorageLive(_13); - _13 = Result::::Err(move _12); + _13 = Result::::Err(_12); _3 = ControlFlow::, i32>::Break(move _13); StorageDead(_13); - goto -> bb5; @@ -119,7 +119,7 @@ bb7: { _11 = move ((_4 as Ok).0: i32); - _3 = ControlFlow::, i32>::Continue(move _11); + _3 = ControlFlow::, i32>::Continue(_11); goto -> bb5; + } + diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff index 47e0d402347d3..3cb4409688169 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff @@ -19,7 +19,7 @@ } scope 5 (inlined ::allocate) { debug self => _9; - debug layout => _1; + debug layout => _8; } scope 6 (inlined #[track_caller] Result::, std::alloc::AllocError>::unwrap) { debug self => _6; @@ -51,6 +51,8 @@ } bb0: { +- StorageLive(_1); ++ nop; StorageLive(_2); - _2 = Option::::None; + _2 = const Option::::None; @@ -74,12 +76,20 @@ StorageLive(_4); StorageLive(_5); StorageLive(_6); + StorageLive(_7); _9 = const _; -- _6 = std::alloc::Global::alloc_impl(_9, _1, const false) -> [return: bb3, unwind unreachable]; +- _7 = _9; ++ _7 = const {ALLOC1: &std::alloc::Global}; + StorageLive(_8); +- _8 = _1; +- _6 = std::alloc::Global::alloc_impl(move _7, move _8, const false) -> [return: bb3, unwind unreachable]; ++ _8 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum32) }}; + _6 = std::alloc::Global::alloc_impl(const {ALLOC1: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum32) }}, const false) -> [return: bb3, unwind unreachable]; } bb3: { + StorageDead(_8); + StorageDead(_7); StorageLive(_12); StorageLive(_15); _12 = discriminant(_6); @@ -109,6 +119,8 @@ _3 = move _4 as *mut u8 (PtrToPtr); StorageDead(_4); StorageDead(_3); +- StorageDead(_1); ++ nop; return; } diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff index dee57ce6c27bb..06d5e615b1440 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff @@ -19,7 +19,7 @@ } scope 5 (inlined ::allocate) { debug self => _9; - debug layout => _1; + debug layout => _8; } scope 6 (inlined NonNull::<[u8]>::as_ptr) { debug self => _5; @@ -36,6 +36,8 @@ } bb0: { +- StorageLive(_1); ++ nop; StorageLive(_2); - _2 = Option::::None; + _2 = const Option::::None; @@ -56,6 +58,8 @@ _3 = move _4 as *mut u8 (PtrToPtr); StorageDead(_4); StorageDead(_3); +- StorageDead(_1); ++ nop; return; } @@ -72,12 +76,20 @@ StorageLive(_4); StorageLive(_5); StorageLive(_6); + StorageLive(_7); _9 = const _; -- _6 = std::alloc::Global::alloc_impl(_9, _1, const false) -> [return: bb4, unwind continue]; +- _7 = _9; ++ _7 = const {ALLOC1: &std::alloc::Global}; + StorageLive(_8); +- _8 = _1; +- _6 = std::alloc::Global::alloc_impl(move _7, move _8, const false) -> [return: bb4, unwind continue]; ++ _8 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum32) }}; + _6 = std::alloc::Global::alloc_impl(const {ALLOC1: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum32) }}, const false) -> [return: bb4, unwind continue]; } bb4: { + StorageDead(_8); + StorageDead(_7); _5 = Result::, std::alloc::AllocError>::unwrap(move _6) -> [return: bb1, unwind continue]; } diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff index a255b15920cba..eb54cc7da8553 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff @@ -19,7 +19,7 @@ } scope 5 (inlined ::allocate) { debug self => _9; - debug layout => _1; + debug layout => _8; } scope 6 (inlined #[track_caller] Result::, std::alloc::AllocError>::unwrap) { debug self => _6; @@ -51,6 +51,8 @@ } bb0: { +- StorageLive(_1); ++ nop; StorageLive(_2); - _2 = Option::::None; + _2 = const Option::::None; @@ -74,12 +76,20 @@ StorageLive(_4); StorageLive(_5); StorageLive(_6); + StorageLive(_7); _9 = const _; -- _6 = std::alloc::Global::alloc_impl(_9, _1, const false) -> [return: bb3, unwind unreachable]; +- _7 = _9; ++ _7 = const {ALLOC1: &std::alloc::Global}; + StorageLive(_8); +- _8 = _1; +- _6 = std::alloc::Global::alloc_impl(move _7, move _8, const false) -> [return: bb3, unwind unreachable]; ++ _8 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}; + _6 = std::alloc::Global::alloc_impl(const {ALLOC1: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}, const false) -> [return: bb3, unwind unreachable]; } bb3: { + StorageDead(_8); + StorageDead(_7); StorageLive(_12); StorageLive(_15); _12 = discriminant(_6); @@ -109,6 +119,8 @@ _3 = move _4 as *mut u8 (PtrToPtr); StorageDead(_4); StorageDead(_3); +- StorageDead(_1); ++ nop; return; } diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff index 192ffea259157..4200ce3087f3e 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff @@ -19,7 +19,7 @@ } scope 5 (inlined ::allocate) { debug self => _9; - debug layout => _1; + debug layout => _8; } scope 6 (inlined NonNull::<[u8]>::as_ptr) { debug self => _5; @@ -36,6 +36,8 @@ } bb0: { +- StorageLive(_1); ++ nop; StorageLive(_2); - _2 = Option::::None; + _2 = const Option::::None; @@ -56,6 +58,8 @@ _3 = move _4 as *mut u8 (PtrToPtr); StorageDead(_4); StorageDead(_3); +- StorageDead(_1); ++ nop; return; } @@ -72,12 +76,20 @@ StorageLive(_4); StorageLive(_5); StorageLive(_6); + StorageLive(_7); _9 = const _; -- _6 = std::alloc::Global::alloc_impl(_9, _1, const false) -> [return: bb4, unwind continue]; +- _7 = _9; ++ _7 = const {ALLOC1: &std::alloc::Global}; + StorageLive(_8); +- _8 = _1; +- _6 = std::alloc::Global::alloc_impl(move _7, move _8, const false) -> [return: bb4, unwind continue]; ++ _8 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}; + _6 = std::alloc::Global::alloc_impl(const {ALLOC1: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}, const false) -> [return: bb4, unwind continue]; } bb4: { + StorageDead(_8); + StorageDead(_7); _5 = Result::, std::alloc::AllocError>::unwrap(move _6) -> [return: bb1, unwind continue]; } diff --git a/tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir index 8dbb688999a02..8d182069adc99 100644 --- a/tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir @@ -32,7 +32,7 @@ fn filter_mapped(_1: impl Iterator, _2: impl Fn(T) -> Option) -> () bb1: { StorageLive(_4); - _4 = move _3; + _4 = _3; goto -> bb2; } diff --git a/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir index 42c7eb3c6aad0..e27e417ed4ae6 100644 --- a/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir @@ -46,7 +46,7 @@ fn int_range(_1: usize, _2: usize) -> () { bb0: { _3 = std::ops::Range:: { start: _1, end: _2 }; StorageLive(_4); - _4 = move _3; + _4 = _3; goto -> bb1; } diff --git a/tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir index 30bdc13109089..b800a1be22bae 100644 --- a/tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir @@ -27,7 +27,7 @@ fn mapped(_1: impl Iterator, _2: impl Fn(T) -> U) -> () { bb1: { StorageLive(_4); - _4 = move _3; + _4 = _3; goto -> bb2; } diff --git a/tests/mir-opt/pre-codegen/mem_replace.mem_replace.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/mem_replace.mem_replace.PreCodegen.after.mir index 713d6cc558acc..f0cb4ca31fecc 100644 --- a/tests/mir-opt/pre-codegen/mem_replace.mem_replace.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/mem_replace.mem_replace.PreCodegen.after.mir @@ -19,22 +19,23 @@ fn mem_replace(_1: &mut u32, _2: u32) -> u32 { } scope 4 (inlined std::ptr::read::) { debug src => _1; + let mut _3: *const u32; scope 5 { scope 6 (inlined std::ptr::read::runtime::) { - debug src => _1; + debug src => _3; scope 7 (inlined intrinsics::is_aligned_and_not_null::) { - debug ptr => _1; + debug ptr => _3; scope 8 (inlined std::ptr::const_ptr::::is_null) { - debug self => _1; - let mut _3: *const u8; + debug self => _3; + let mut _4: *const u8; scope 9 { scope 10 (inlined std::ptr::const_ptr::::is_null::runtime_impl) { - debug ptr => _3; + debug ptr => _4; scope 11 (inlined std::ptr::const_ptr::::addr) { - debug self => _3; + debug self => _4; scope 12 { scope 13 (inlined std::ptr::const_ptr::::cast::<()>) { - debug self => _3; + debug self => _4; } } } @@ -42,7 +43,7 @@ fn mem_replace(_1: &mut u32, _2: u32) -> u32 { } } scope 14 (inlined std::ptr::const_ptr::::is_aligned) { - debug self => _1; + debug self => _3; scope 15 (inlined align_of::) { } } @@ -55,7 +56,9 @@ fn mem_replace(_1: &mut u32, _2: u32) -> u32 { bb0: { StorageLive(_3); + StorageLive(_4); _0 = (*_1); + StorageDead(_4); StorageDead(_3); (*_1) = _2; return; diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff index 4e34233a9798d..0e7e1f971ec34 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff @@ -17,7 +17,7 @@ debug y => _3; let _8: u32; scope 3 { - debug z => _9; + debug z => _8; } } } @@ -50,7 +50,13 @@ + _3 = const 3_i32; StorageDead(_5); StorageDead(_4); + StorageLive(_8); + StorageLive(_9); _9 = const 42_u32; +- _8 = _9; ++ _8 = const 42_u32; + StorageDead(_9); + StorageDead(_8); StorageDead(_3); StorageDead(_1); return; diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff index 275f17e52aeca..9071a3339c080 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff @@ -17,7 +17,7 @@ debug y => _3; let _8: u32; scope 3 { - debug z => _9; + debug z => _8; } } } @@ -50,7 +50,13 @@ + _3 = const 3_i32; StorageDead(_5); StorageDead(_4); + StorageLive(_8); + StorageLive(_9); _9 = const 42_u32; +- _8 = _9; ++ _8 = const 42_u32; + StorageDead(_9); + StorageDead(_8); StorageDead(_3); StorageDead(_1); return; diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff index 4e34233a9798d..0e7e1f971ec34 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff @@ -17,7 +17,7 @@ debug y => _3; let _8: u32; scope 3 { - debug z => _9; + debug z => _8; } } } @@ -50,7 +50,13 @@ + _3 = const 3_i32; StorageDead(_5); StorageDead(_4); + StorageLive(_8); + StorageLive(_9); _9 = const 42_u32; +- _8 = _9; ++ _8 = const 42_u32; + StorageDead(_9); + StorageDead(_8); StorageDead(_3); StorageDead(_1); return; diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff index 275f17e52aeca..9071a3339c080 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff @@ -17,7 +17,7 @@ debug y => _3; let _8: u32; scope 3 { - debug z => _9; + debug z => _8; } } } @@ -50,7 +50,13 @@ + _3 = const 3_i32; StorageDead(_5); StorageDead(_4); + StorageLive(_8); + StorageLive(_9); _9 = const 42_u32; +- _8 = _9; ++ _8 = const 42_u32; + StorageDead(_9); + StorageDead(_8); StorageDead(_3); StorageDead(_1); return; diff --git a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir index e5940bd82019e..99805da56694c 100644 --- a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir @@ -49,7 +49,7 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () { bb0: { _4 = std::ops::Range:: { start: _1, end: _2 }; StorageLive(_5); - _5 = move _4; + _5 = _4; goto -> bb1; } diff --git a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir index 87e7485cb3604..f40f130717569 100644 --- a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir @@ -49,7 +49,7 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () { bb0: { _4 = std::ops::Range:: { start: _1, end: _2 }; StorageLive(_5); - _5 = move _4; + _5 = _4; goto -> bb1; } diff --git a/tests/mir-opt/pre-codegen/range_iter.inclusive_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/range_iter.inclusive_loop.PreCodegen.after.panic-abort.mir index 1b23e421368b6..0836600cb6e6d 100644 --- a/tests/mir-opt/pre-codegen/range_iter.inclusive_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/range_iter.inclusive_loop.PreCodegen.after.panic-abort.mir @@ -34,7 +34,7 @@ fn inclusive_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () { bb0: { _4 = RangeInclusive:: { start: _1, end: _2, exhausted: const false }; StorageLive(_5); - _5 = move _4; + _5 = _4; goto -> bb1; } diff --git a/tests/mir-opt/pre-codegen/range_iter.inclusive_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/range_iter.inclusive_loop.PreCodegen.after.panic-unwind.mir index a677e8b439fa0..8c1794de5244c 100644 --- a/tests/mir-opt/pre-codegen/range_iter.inclusive_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/range_iter.inclusive_loop.PreCodegen.after.panic-unwind.mir @@ -34,7 +34,7 @@ fn inclusive_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () { bb0: { _4 = RangeInclusive:: { start: _1, end: _2, exhausted: const false }; StorageLive(_5); - _5 = move _4; + _5 = _4; goto -> bb1; } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir index a12411a041378..cdbd8d89f28c3 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir @@ -20,7 +20,8 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> { debug self => _2; debug slice => _5; let mut _6: *mut u32; - let mut _9: &[&str]; + let mut _9: *mut [u32]; + let mut _10: &[&str]; scope 5 { scope 10 (inlined std::ptr::mut_ptr::::as_mut_ptr) { debug self => _5; @@ -33,16 +34,16 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> { } } scope 6 (inlined std::ptr::mut_ptr::::len) { - debug self => _5; - let mut _10: *const [u32]; + debug self => _9; + let mut _11: *const [u32]; scope 7 (inlined std::ptr::metadata::<[u32]>) { - debug ptr => _10; + debug ptr => _11; scope 8 { } } } scope 9 (inlined Arguments::<'_>::new_const) { - debug pieces => _9; + debug pieces => _10; } } } @@ -70,10 +71,12 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> { _5 = &raw mut (*_1); StorageLive(_9); StorageLive(_10); + StorageLive(_11); StorageLive(_6); _6 = _5 as *mut u32 (PtrToPtr); _7 = Offset(_6, _2); StorageDead(_6); + StorageDead(_11); StorageDead(_10); StorageDead(_9); StorageDead(_5); diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir index a12411a041378..cdbd8d89f28c3 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir @@ -20,7 +20,8 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> { debug self => _2; debug slice => _5; let mut _6: *mut u32; - let mut _9: &[&str]; + let mut _9: *mut [u32]; + let mut _10: &[&str]; scope 5 { scope 10 (inlined std::ptr::mut_ptr::::as_mut_ptr) { debug self => _5; @@ -33,16 +34,16 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> { } } scope 6 (inlined std::ptr::mut_ptr::::len) { - debug self => _5; - let mut _10: *const [u32]; + debug self => _9; + let mut _11: *const [u32]; scope 7 (inlined std::ptr::metadata::<[u32]>) { - debug ptr => _10; + debug ptr => _11; scope 8 { } } } scope 9 (inlined Arguments::<'_>::new_const) { - debug pieces => _9; + debug pieces => _10; } } } @@ -70,10 +71,12 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> { _5 = &raw mut (*_1); StorageLive(_9); StorageLive(_10); + StorageLive(_11); StorageLive(_6); _6 = _5 as *mut u32 (PtrToPtr); _7 = Offset(_6, _2); StorageDead(_6); + StorageDead(_11); StorageDead(_10); StorageDead(_9); StorageDead(_5); diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir index 0d95f81c37c54..36329f8fc6845 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir @@ -19,7 +19,8 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> debug slice => _5; let mut _7: *mut u32; let mut _8: *mut u32; - let mut _14: &[&str]; + let mut _14: *mut [u32]; + let mut _15: &[&str]; scope 4 { let _6: usize; scope 5 { @@ -53,16 +54,16 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> } } scope 6 (inlined std::ptr::mut_ptr::::len) { - debug self => _5; - let mut _15: *const [u32]; + debug self => _14; + let mut _16: *const [u32]; scope 7 (inlined std::ptr::metadata::<[u32]>) { - debug ptr => _15; + debug ptr => _16; scope 8 { } } } scope 9 (inlined Arguments::<'_>::new_const) { - debug pieces => _14; + debug pieces => _15; } } } @@ -74,8 +75,9 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> StorageLive(_5); _5 = &raw mut (*_1); StorageLive(_14); - StorageLive(_6); StorageLive(_15); + StorageLive(_6); + StorageLive(_16); _6 = SubUnchecked(_4, _3); StorageLive(_8); StorageLive(_7); @@ -96,8 +98,9 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> StorageDead(_12); StorageDead(_9); StorageDead(_8); - StorageDead(_15); + StorageDead(_16); StorageDead(_6); + StorageDead(_15); StorageDead(_14); StorageDead(_5); _0 = &mut (*_13); diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir index 0d95f81c37c54..36329f8fc6845 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir @@ -19,7 +19,8 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> debug slice => _5; let mut _7: *mut u32; let mut _8: *mut u32; - let mut _14: &[&str]; + let mut _14: *mut [u32]; + let mut _15: &[&str]; scope 4 { let _6: usize; scope 5 { @@ -53,16 +54,16 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> } } scope 6 (inlined std::ptr::mut_ptr::::len) { - debug self => _5; - let mut _15: *const [u32]; + debug self => _14; + let mut _16: *const [u32]; scope 7 (inlined std::ptr::metadata::<[u32]>) { - debug ptr => _15; + debug ptr => _16; scope 8 { } } } scope 9 (inlined Arguments::<'_>::new_const) { - debug pieces => _14; + debug pieces => _15; } } } @@ -74,8 +75,9 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> StorageLive(_5); _5 = &raw mut (*_1); StorageLive(_14); - StorageLive(_6); StorageLive(_15); + StorageLive(_6); + StorageLive(_16); _6 = SubUnchecked(_4, _3); StorageLive(_8); StorageLive(_7); @@ -96,8 +98,9 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> StorageDead(_12); StorageDead(_9); StorageDead(_8); - StorageDead(_15); + StorageDead(_16); StorageDead(_6); + StorageDead(_15); StorageDead(_14); StorageDead(_5); _0 = &mut (*_13); diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir index c58b630a0c365..26b2663fa3580 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir @@ -42,20 +42,21 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { scope 13 (inlined NonNull::::new_unchecked) { debug ptr => _9; let mut _10: *const T; + let mut _24: *mut T; scope 14 { scope 15 (inlined NonNull::::new_unchecked::runtime::) { - debug ptr => _9; + debug ptr => _24; scope 16 (inlined std::ptr::mut_ptr::::is_null) { - debug self => _9; - let mut _24: *mut u8; + debug self => _24; + let mut _25: *mut u8; scope 17 { scope 18 (inlined std::ptr::mut_ptr::::is_null::runtime_impl) { - debug ptr => _24; + debug ptr => _25; scope 19 (inlined std::ptr::mut_ptr::::addr) { - debug self => _24; + debug self => _25; scope 20 { scope 21 (inlined std::ptr::mut_ptr::::cast::<()>) { - debug self => _24; + debug self => _25; } } } @@ -131,8 +132,10 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { _9 = _4 as *mut T (PtrToPtr); StorageLive(_10); StorageLive(_24); + StorageLive(_25); _10 = _9 as *const T (PointerCoercion(MutToConstPointer)); _11 = NonNull:: { pointer: _10 }; + StorageDead(_25); StorageDead(_24); StorageDead(_10); StorageDead(_9); @@ -143,10 +146,10 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { StorageDead(_11); StorageDead(_7); StorageDead(_4); - _14 = Enumerate::> { iter: move _13, count: const 0_usize }; + _14 = Enumerate::> { iter: _13, count: const 0_usize }; StorageDead(_13); StorageLive(_15); - _15 = move _14; + _15 = _14; goto -> bb4; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir index 1a805f0fd8dc8..a055612bd5feb 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir @@ -42,20 +42,21 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { scope 13 (inlined NonNull::::new_unchecked) { debug ptr => _9; let mut _10: *const T; + let mut _24: *mut T; scope 14 { scope 15 (inlined NonNull::::new_unchecked::runtime::) { - debug ptr => _9; + debug ptr => _24; scope 16 (inlined std::ptr::mut_ptr::::is_null) { - debug self => _9; - let mut _24: *mut u8; + debug self => _24; + let mut _25: *mut u8; scope 17 { scope 18 (inlined std::ptr::mut_ptr::::is_null::runtime_impl) { - debug ptr => _24; + debug ptr => _25; scope 19 (inlined std::ptr::mut_ptr::::addr) { - debug self => _24; + debug self => _25; scope 20 { scope 21 (inlined std::ptr::mut_ptr::::cast::<()>) { - debug self => _24; + debug self => _25; } } } @@ -131,8 +132,10 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { _9 = _4 as *mut T (PtrToPtr); StorageLive(_10); StorageLive(_24); + StorageLive(_25); _10 = _9 as *const T (PointerCoercion(MutToConstPointer)); _11 = NonNull:: { pointer: _10 }; + StorageDead(_25); StorageDead(_24); StorageDead(_10); StorageDead(_9); @@ -143,10 +146,10 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { StorageDead(_11); StorageDead(_7); StorageDead(_4); - _14 = Enumerate::> { iter: move _13, count: const 0_usize }; + _14 = Enumerate::> { iter: _13, count: const 0_usize }; StorageDead(_13); StorageLive(_15); - _15 = move _14; + _15 = _14; goto -> bb4; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir index 09075eed6a9cd..471491108e0b6 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir @@ -39,20 +39,21 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 13 (inlined NonNull::::new_unchecked) { debug ptr => _9; let mut _10: *const T; + let mut _22: *mut T; scope 14 { scope 15 (inlined NonNull::::new_unchecked::runtime::) { - debug ptr => _9; + debug ptr => _22; scope 16 (inlined std::ptr::mut_ptr::::is_null) { - debug self => _9; - let mut _22: *mut u8; + debug self => _22; + let mut _23: *mut u8; scope 17 { scope 18 (inlined std::ptr::mut_ptr::::is_null::runtime_impl) { - debug ptr => _22; + debug ptr => _23; scope 19 (inlined std::ptr::mut_ptr::::addr) { - debug self => _22; + debug self => _23; scope 20 { scope 21 (inlined std::ptr::mut_ptr::::cast::<()>) { - debug self => _22; + debug self => _23; } } } @@ -121,8 +122,10 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { _9 = _4 as *mut T (PtrToPtr); StorageLive(_10); StorageLive(_22); + StorageLive(_23); _10 = _9 as *const T (PointerCoercion(MutToConstPointer)); _11 = NonNull:: { pointer: _10 }; + StorageDead(_23); StorageDead(_22); StorageDead(_10); StorageDead(_9); @@ -134,7 +137,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { StorageDead(_7); StorageDead(_4); StorageLive(_14); - _14 = move _13; + _14 = _13; goto -> bb4; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir index 47b84746468a0..bbf38aba91f08 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir @@ -39,20 +39,21 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 13 (inlined NonNull::::new_unchecked) { debug ptr => _9; let mut _10: *const T; + let mut _22: *mut T; scope 14 { scope 15 (inlined NonNull::::new_unchecked::runtime::) { - debug ptr => _9; + debug ptr => _22; scope 16 (inlined std::ptr::mut_ptr::::is_null) { - debug self => _9; - let mut _22: *mut u8; + debug self => _22; + let mut _23: *mut u8; scope 17 { scope 18 (inlined std::ptr::mut_ptr::::is_null::runtime_impl) { - debug ptr => _22; + debug ptr => _23; scope 19 (inlined std::ptr::mut_ptr::::addr) { - debug self => _22; + debug self => _23; scope 20 { scope 21 (inlined std::ptr::mut_ptr::::cast::<()>) { - debug self => _22; + debug self => _23; } } } @@ -121,8 +122,10 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { _9 = _4 as *mut T (PtrToPtr); StorageLive(_10); StorageLive(_22); + StorageLive(_23); _10 = _9 as *const T (PointerCoercion(MutToConstPointer)); _11 = NonNull:: { pointer: _10 }; + StorageDead(_23); StorageDead(_22); StorageDead(_10); StorageDead(_9); @@ -134,7 +137,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { StorageDead(_7); StorageDead(_4); StorageLive(_14); - _14 = move _13; + _14 = _13; goto -> bb4; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir index 6a99f15774ff4..83915d3c44931 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir @@ -58,7 +58,7 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { _4 = std::ops::Range:: { start: const 0_usize, end: move _3 }; StorageDead(_3); StorageLive(_5); - _5 = move _4; + _5 = _4; goto -> bb1; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir index 4f028fa0a6468..0a005a460e84d 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir @@ -58,7 +58,7 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { _4 = std::ops::Range:: { start: const 0_usize, end: move _3 }; StorageDead(_3); StorageLive(_5); - _5 = move _4; + _5 = _4; goto -> bb1; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir index 5ed7ca5e2b86f..f9c8ab4db60b7 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir @@ -44,20 +44,21 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 13 (inlined NonNull::::new_unchecked) { debug ptr => _9; let mut _10: *const T; + let mut _24: *mut T; scope 14 { scope 15 (inlined NonNull::::new_unchecked::runtime::) { - debug ptr => _9; + debug ptr => _24; scope 16 (inlined std::ptr::mut_ptr::::is_null) { - debug self => _9; - let mut _24: *mut u8; + debug self => _24; + let mut _25: *mut u8; scope 17 { scope 18 (inlined std::ptr::mut_ptr::::is_null::runtime_impl) { - debug ptr => _24; + debug ptr => _25; scope 19 (inlined std::ptr::mut_ptr::::addr) { - debug self => _24; + debug self => _25; scope 20 { scope 21 (inlined std::ptr::mut_ptr::::cast::<()>) { - debug self => _24; + debug self => _25; } } } @@ -133,8 +134,10 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { _9 = _4 as *mut T (PtrToPtr); StorageLive(_10); StorageLive(_24); + StorageLive(_25); _10 = _9 as *const T (PointerCoercion(MutToConstPointer)); _11 = NonNull:: { pointer: _10 }; + StorageDead(_25); StorageDead(_24); StorageDead(_10); StorageDead(_9); @@ -145,10 +148,10 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { StorageDead(_11); StorageDead(_7); StorageDead(_4); - _14 = Rev::> { iter: move _13 }; + _14 = Rev::> { iter: _13 }; StorageDead(_13); StorageLive(_15); - _15 = move _14; + _15 = _14; goto -> bb4; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir index bbb979d23b36a..65f423ac326be 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir @@ -44,20 +44,21 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 13 (inlined NonNull::::new_unchecked) { debug ptr => _9; let mut _10: *const T; + let mut _24: *mut T; scope 14 { scope 15 (inlined NonNull::::new_unchecked::runtime::) { - debug ptr => _9; + debug ptr => _24; scope 16 (inlined std::ptr::mut_ptr::::is_null) { - debug self => _9; - let mut _24: *mut u8; + debug self => _24; + let mut _25: *mut u8; scope 17 { scope 18 (inlined std::ptr::mut_ptr::::is_null::runtime_impl) { - debug ptr => _24; + debug ptr => _25; scope 19 (inlined std::ptr::mut_ptr::::addr) { - debug self => _24; + debug self => _25; scope 20 { scope 21 (inlined std::ptr::mut_ptr::::cast::<()>) { - debug self => _24; + debug self => _25; } } } @@ -133,8 +134,10 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { _9 = _4 as *mut T (PtrToPtr); StorageLive(_10); StorageLive(_24); + StorageLive(_25); _10 = _9 as *const T (PointerCoercion(MutToConstPointer)); _11 = NonNull:: { pointer: _10 }; + StorageDead(_25); StorageDead(_24); StorageDead(_10); StorageDead(_9); @@ -145,10 +148,10 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { StorageDead(_11); StorageDead(_7); StorageDead(_4); - _14 = Rev::> { iter: move _13 }; + _14 = Rev::> { iter: _13 }; StorageDead(_13); StorageLive(_15); - _15 = move _14; + _15 = _14; goto -> bb4; } diff --git a/tests/mir-opt/pre-codegen/try_identity.new.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/try_identity.new.PreCodegen.after.mir index 0bf4a2670020d..c1d4d4871d02c 100644 --- a/tests/mir-opt/pre-codegen/try_identity.new.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/try_identity.new.PreCodegen.after.mir @@ -31,13 +31,13 @@ fn new(_1: Result) -> Result { bb1: { _3 = move ((_1 as Ok).0: T); - _4 = ControlFlow::::Continue(move _3); + _4 = ControlFlow::::Continue(_3); goto -> bb3; } bb2: { _5 = move ((_1 as Err).0: E); - _4 = ControlFlow::::Break(move _5); + _4 = ControlFlow::::Break(_5); goto -> bb3; } @@ -48,14 +48,14 @@ fn new(_1: Result) -> Result { bb4: { _7 = move ((_4 as Continue).0: T); - _0 = Result::::Ok(move _7); + _0 = Result::::Ok(_7); StorageDead(_4); goto -> bb6; } bb5: { _8 = move ((_4 as Break).0: E); - _0 = Result::::Err(move _8); + _0 = Result::::Err(_8); StorageDead(_4); goto -> bb6; } diff --git a/tests/mir-opt/pre-codegen/try_identity.old.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/try_identity.old.PreCodegen.after.mir index 7ccb8b0430de1..d6883ac9fda08 100644 --- a/tests/mir-opt/pre-codegen/try_identity.old.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/try_identity.old.PreCodegen.after.mir @@ -20,13 +20,13 @@ fn old(_1: Result) -> Result { bb1: { _3 = move ((_1 as Ok).0: T); - _0 = Result::::Ok(move _3); + _0 = Result::::Ok(_3); goto -> bb3; } bb2: { _4 = move ((_1 as Err).0: E); - _0 = Result::::Err(move _4); + _0 = Result::::Err(_4); goto -> bb3; } diff --git a/tests/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff b/tests/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff index a12db0a730c57..e7280f148377c 100644 --- a/tests/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff +++ b/tests/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff @@ -4,92 +4,96 @@ fn identity(_1: Result) -> Result { debug x => _1; let mut _0: std::result::Result; - let mut _2: i32; - let mut _3: std::ops::ControlFlow, i32>; - let mut _4: std::result::Result; - let mut _5: isize; - let _6: std::result::Result; - let mut _7: std::result::Result; - let _8: i32; + let mut _2: std::ops::ControlFlow, i32>; + let mut _3: std::result::Result; + let mut _4: isize; + let _5: std::result::Result; + let mut _6: std::result::Result; + let _7: i32; scope 1 { - debug residual => _6; + debug residual => _5; scope 2 { scope 8 (inlined #[track_caller] as FromResidual>>::from_residual) { debug residual => _6; - let _13: i32; - let mut _14: i32; + let _12: i32; scope 9 { - debug e => _13; + debug e => _12; scope 10 (inlined >::from) { - debug t => _13; + debug t => _12; } } } } } scope 3 { - debug val => _8; + debug val => _7; scope 4 { } } scope 5 (inlined as Try>::branch) { - debug self => _1; - let mut _9: isize; + debug self => _3; + let mut _8: isize; + let _9: i32; let _10: i32; - let _11: i32; - let mut _12: std::result::Result; + let mut _11: std::result::Result; scope 6 { - debug v => _10; + debug v => _9; } scope 7 { - debug e => _11; + debug e => _10; } } bb0: { + StorageLive(_2); StorageLive(_3); + _3 = _1; + StorageLive(_8); StorageLive(_9); StorageLive(_10); - StorageLive(_11); - _9 = discriminant(_1); - switchInt(move _9) -> [0: bb5, 1: bb4, otherwise: bb6]; + _8 = discriminant(_1); + switchInt(move _8) -> [0: bb5, 1: bb4, otherwise: bb6]; } bb1: { - _8 = ((_3 as Continue).0: i32); - _0 = Result::::Ok(_8); - StorageDead(_3); + _7 = ((_2 as Continue).0: i32); + _0 = Result::::Ok(_7); + StorageDead(_2); return; } bb2: { - _6 = ((_3 as Break).0: std::result::Result); - _13 = ((_6 as Err).0: i32); - _0 = Result::::Err(move _13); - StorageDead(_3); + _5 = ((_2 as Break).0: std::result::Result); + StorageLive(_6); + _6 = _5; + _12 = move ((_5 as Err).0: i32); + _0 = Result::::Err(_12); + StorageDead(_6); + StorageDead(_2); return; } bb3: { - StorageDead(_11); StorageDead(_10); StorageDead(_9); - _5 = discriminant(_3); - switchInt(move _5) -> [0: bb1, 1: bb2, otherwise: bb6]; + StorageDead(_8); + StorageDead(_3); + _4 = discriminant(_2); + switchInt(move _4) -> [0: bb1, 1: bb2, otherwise: bb6]; } bb4: { - _11 = ((_1 as Err).0: i32); - StorageLive(_12); - _12 = Result::::Err(move _11); - _3 = ControlFlow::, i32>::Break(move _12); - StorageDead(_12); + _10 = move ((_1 as Err).0: i32); + StorageLive(_11); + _11 = Result::::Err(_10); + _2 = ControlFlow::, i32>::Break(move _11); + StorageDead(_11); goto -> bb3; } bb5: { - _10 = ((_1 as Ok).0: i32); - _3 = ControlFlow::, i32>::Continue(move _10); + _9 = move ((_1 as Ok).0: i32); + _2 = ControlFlow::, i32>::Continue(_9); goto -> bb3; } diff --git a/tests/mir-opt/separate_const_switch.too_complex.SeparateConstSwitch.diff b/tests/mir-opt/separate_const_switch.too_complex.SeparateConstSwitch.diff index 80f40b86919eb..294bfa661cfa4 100644 --- a/tests/mir-opt/separate_const_switch.too_complex.SeparateConstSwitch.diff +++ b/tests/mir-opt/separate_const_switch.too_complex.SeparateConstSwitch.diff @@ -7,24 +7,21 @@ let mut _2: std::ops::ControlFlow; let mut _3: isize; let _4: i32; - let mut _5: i32; - let _6: usize; - let mut _7: usize; - let mut _8: isize; - let _9: i32; - let mut _10: i32; - let _11: usize; + let _5: usize; + let mut _6: isize; + let _7: i32; + let _8: usize; scope 1 { debug v => _4; } scope 2 { - debug r => _6; + debug r => _5; } scope 3 { - debug v => _9; + debug v => _7; } scope 4 { - debug r => _11; + debug r => _8; } bb0: { @@ -34,8 +31,8 @@ } bb1: { - _6 = ((_1 as Err).0: usize); - _2 = ControlFlow::::Break(_6); + _5 = ((_1 as Err).0: usize); + _2 = ControlFlow::::Break(_5); goto -> bb3; } @@ -46,21 +43,21 @@ } bb3: { - _8 = discriminant(_2); - switchInt(move _8) -> [0: bb5, 1: bb4, otherwise: bb7]; + _6 = discriminant(_2); + switchInt(move _6) -> [0: bb5, 1: bb4, otherwise: bb7]; } bb4: { - StorageLive(_11); - _11 = ((_2 as Break).0: usize); - _0 = Option::::None; - StorageDead(_11); + StorageLive(_8); + _8 = ((_2 as Break).0: usize); + _0 = const Option::::None; + StorageDead(_8); goto -> bb6; } bb5: { - _9 = ((_2 as Continue).0: i32); - _0 = Option::::Some(_9); + _7 = ((_2 as Continue).0: i32); + _0 = Option::::Some(_7); goto -> bb6; } @@ -74,3 +71,7 @@ } } + ALLOC0 (size: 8, align: 4) { + 00 00 00 00 __ __ __ __ │ ....░░░░ + } + diff --git a/tests/mir-opt/simplify_match.main.GVN.panic-abort.diff b/tests/mir-opt/simplify_match.main.GVN.panic-abort.diff index d7ade041e4ccb..33b36f660cb3a 100644 --- a/tests/mir-opt/simplify_match.main.GVN.panic-abort.diff +++ b/tests/mir-opt/simplify_match.main.GVN.panic-abort.diff @@ -10,8 +10,15 @@ } bb0: { + StorageLive(_1); +- StorageLive(_2); ++ nop; _2 = const false; -- switchInt(_2) -> [0: bb2, otherwise: bb1]; +- _1 = _2; +- StorageDead(_2); +- switchInt(_1) -> [0: bb2, otherwise: bb1]; ++ _1 = const false; ++ nop; + switchInt(const false) -> [0: bb2, otherwise: bb1]; } @@ -20,6 +27,7 @@ } bb2: { + StorageDead(_1); return; } } diff --git a/tests/mir-opt/simplify_match.main.GVN.panic-unwind.diff b/tests/mir-opt/simplify_match.main.GVN.panic-unwind.diff index 931c5c43c4c6d..e5c3adff62369 100644 --- a/tests/mir-opt/simplify_match.main.GVN.panic-unwind.diff +++ b/tests/mir-opt/simplify_match.main.GVN.panic-unwind.diff @@ -10,8 +10,15 @@ } bb0: { + StorageLive(_1); +- StorageLive(_2); ++ nop; _2 = const false; -- switchInt(_2) -> [0: bb2, otherwise: bb1]; +- _1 = _2; +- StorageDead(_2); +- switchInt(_1) -> [0: bb2, otherwise: bb1]; ++ _1 = const false; ++ nop; + switchInt(const false) -> [0: bb2, otherwise: bb1]; } @@ -20,6 +27,7 @@ } bb2: { + StorageDead(_1); return; } } From 974b727874b18a161c17fd0eaa4ca883d05bf19a Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 6 Jan 2024 20:01:52 +0000 Subject: [PATCH 0122/1197] Bless ui-fulldeps. --- tests/ui-fulldeps/stable-mir/check_allocation.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui-fulldeps/stable-mir/check_allocation.rs b/tests/ui-fulldeps/stable-mir/check_allocation.rs index 7ce3597206b62..93def93127c88 100644 --- a/tests/ui-fulldeps/stable-mir/check_allocation.rs +++ b/tests/ui-fulldeps/stable-mir/check_allocation.rs @@ -111,7 +111,7 @@ fn check_other_consts(item: CrateItem) { // Instance body will force constant evaluation. let body = Instance::try_from(item).unwrap().body().unwrap(); let assigns = collect_consts(&body); - assert_eq!(assigns.len(), 9); + assert_eq!(assigns.len(), 8); for (name, alloc) in assigns { match name.as_str() { "_max_u128" => { From bc35ee41fa6751a85a528656953b581fb02ddd25 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 7 Jan 2024 12:22:33 +0000 Subject: [PATCH 0123/1197] Do not run simplify_locals inside DSE. The full pass is run short after. --- compiler/rustc_mir_transform/src/dead_store_elimination.rs | 2 -- ....move_simple.DeadStoreElimination-final.panic-abort.diff | 4 ++-- ...move_simple.DeadStoreElimination-final.panic-unwind.diff | 4 ++-- .../cycle.cycle.DeadStoreElimination-initial.diff | 6 +++++- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs index 9dd5aa4c8bd8e..c27718d7bdacf 100644 --- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs +++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs @@ -123,8 +123,6 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let Operand::Copy(place) = *arg else { bug!() }; *arg = Operand::Move(place); } - - crate::simplify::simplify_locals(body, tcx) } pub enum DeadStoreElimination { diff --git a/tests/mir-opt/dead-store-elimination/call_arg_copy.move_simple.DeadStoreElimination-final.panic-abort.diff b/tests/mir-opt/dead-store-elimination/call_arg_copy.move_simple.DeadStoreElimination-final.panic-abort.diff index 268924b7c5dcc..f9bc9405d6a4b 100644 --- a/tests/mir-opt/dead-store-elimination/call_arg_copy.move_simple.DeadStoreElimination-final.panic-abort.diff +++ b/tests/mir-opt/dead-store-elimination/call_arg_copy.move_simple.DeadStoreElimination-final.panic-abort.diff @@ -5,8 +5,8 @@ debug x => _1; let mut _0: (); let _2: (); -- let mut _3: i32; -- let mut _4: i32; + let mut _3: i32; + let mut _4: i32; bb0: { StorageLive(_2); diff --git a/tests/mir-opt/dead-store-elimination/call_arg_copy.move_simple.DeadStoreElimination-final.panic-unwind.diff b/tests/mir-opt/dead-store-elimination/call_arg_copy.move_simple.DeadStoreElimination-final.panic-unwind.diff index bd754f9ebd428..efe165422d943 100644 --- a/tests/mir-opt/dead-store-elimination/call_arg_copy.move_simple.DeadStoreElimination-final.panic-unwind.diff +++ b/tests/mir-opt/dead-store-elimination/call_arg_copy.move_simple.DeadStoreElimination-final.panic-unwind.diff @@ -5,8 +5,8 @@ debug x => _1; let mut _0: (); let _2: (); -- let mut _3: i32; -- let mut _4: i32; + let mut _3: i32; + let mut _4: i32; bb0: { StorageLive(_2); diff --git a/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination-initial.diff b/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination-initial.diff index f13588c3aa485..2766b6ce6a9fa 100644 --- a/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination-initial.diff +++ b/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination-initial.diff @@ -4,7 +4,7 @@ fn cycle(_1: i32, _2: i32, _3: i32) -> () { let mut _0: (); let mut _4: bool; -- let mut _5: i32; + let mut _5: i32; bb0: { _4 = cond() -> [return: bb1, unwind continue]; @@ -19,6 +19,10 @@ - _3 = _2; - _2 = _1; - _1 = _5; ++ nop; ++ nop; ++ nop; ++ nop; _4 = cond() -> [return: bb1, unwind continue]; } From e6dd522761ded0e73ff2dfeed2ef598fcb508819 Mon Sep 17 00:00:00 2001 From: Young-Flash Date: Thu, 11 Jan 2024 19:50:35 +0800 Subject: [PATCH 0124/1197] fix: add err recovery for use_tree_list parsing --- crates/parser/src/grammar/items/use_item.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/crates/parser/src/grammar/items/use_item.rs b/crates/parser/src/grammar/items/use_item.rs index 69880b7946b69..e34bf9668c1fa 100644 --- a/crates/parser/src/grammar/items/use_item.rs +++ b/crates/parser/src/grammar/items/use_item.rs @@ -11,7 +11,7 @@ pub(super) fn use_(p: &mut Parser<'_>, m: Marker) { // test use_tree // use outer::tree::{inner::tree}; -fn use_tree(p: &mut Parser<'_>, top_level: bool) { +fn use_tree(p: &mut Parser<'_>, top_level: bool) -> bool { let m = p.start(); match p.current() { // test use_tree_star @@ -70,24 +70,25 @@ fn use_tree(p: &mut Parser<'_>, top_level: bool) { // main balanced `{}` p.err_and_bump(msg); } - return; + return false; } } m.complete(p, USE_TREE); + true } +pub(super) const USE_TREE_LIST_RECOVERY_SET: TokenSet = + TokenSet::new(&[T![;], T![,], T![.], T![ident]]); + // test use_tree_list // use {a, b, c}; pub(crate) fn use_tree_list(p: &mut Parser<'_>) { assert!(p.at(T!['{'])); let m = p.start(); - p.bump(T!['{']); - while !p.at(EOF) && !p.at(T!['}']) { - use_tree(p, false); - if !p.at(T!['}']) { - p.expect(T![,]); - } - } - p.expect(T!['}']); + + delimited(p, T!['{'], T!['}'], T![,], USE_TREE_LIST_RECOVERY_SET, |p: &mut Parser<'_>| { + use_tree(p, false) || p.at_ts(USE_TREE_LIST_RECOVERY_SET) + }); + m.complete(p, USE_TREE_LIST); } From afe05fe1d869c1ca759a6604cd486d5acee87f80 Mon Sep 17 00:00:00 2001 From: Young-Flash Date: Thu, 11 Jan 2024 19:51:45 +0800 Subject: [PATCH 0125/1197] fix broken test --- .../parser/err/0036_partial_use.rast | 41 ++++++++----------- 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/crates/parser/test_data/parser/err/0036_partial_use.rast b/crates/parser/test_data/parser/err/0036_partial_use.rast index 13e76e68307e6..ad4bc89e83aa5 100644 --- a/crates/parser/test_data/parser/err/0036_partial_use.rast +++ b/crates/parser/test_data/parser/err/0036_partial_use.rast @@ -22,30 +22,23 @@ SOURCE_FILE IDENT "Error" ERROR SEMICOLON ";" - WHITESPACE "\n" - ERROR - USE_KW "use" - WHITESPACE " " - USE_TREE - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "std" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "io" - ERROR - SEMICOLON ";" + WHITESPACE "\n" + USE + USE_KW "use" + WHITESPACE " " + USE_TREE + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "std" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "io" + SEMICOLON ";" WHITESPACE "\n" error 22: expected COMMA error 22: expected one of `*`, `::`, `{`, `self`, `super` or an identifier -error 23: expected COMMA -error 24: expected one of `*`, `::`, `{`, `self`, `super` or an identifier -error 27: expected COMMA -error 35: expected COMMA -error 35: expected one of `*`, `::`, `{`, `self`, `super` or an identifier -error 36: expected COMMA -error 36: expected R_CURLY -error 36: expected SEMICOLON +error 23: expected R_CURLY +error 23: expected SEMICOLON From 45eea5711525ad19f8b6669f4e1317964efa4d8a Mon Sep 17 00:00:00 2001 From: Young-Flash Date: Thu, 11 Jan 2024 19:52:23 +0800 Subject: [PATCH 0126/1197] add in-comment test case for use_tree_list_err_recovery --- crates/parser/src/grammar/items/use_item.rs | 5 ++ .../err/0026_use_tree_list_err_recovery.rast | 50 +++++++++++++++++++ .../err/0026_use_tree_list_err_recovery.rs | 4 ++ 3 files changed, 59 insertions(+) create mode 100644 crates/parser/test_data/parser/inline/err/0026_use_tree_list_err_recovery.rast create mode 100644 crates/parser/test_data/parser/inline/err/0026_use_tree_list_err_recovery.rs diff --git a/crates/parser/src/grammar/items/use_item.rs b/crates/parser/src/grammar/items/use_item.rs index e34bf9668c1fa..b397454173569 100644 --- a/crates/parser/src/grammar/items/use_item.rs +++ b/crates/parser/src/grammar/items/use_item.rs @@ -86,6 +86,11 @@ pub(crate) fn use_tree_list(p: &mut Parser<'_>) { assert!(p.at(T!['{'])); let m = p.start(); + // test_err use_tree_list_err_recovery + // use {a; + // use b; + // struct T; + // fn test() {} delimited(p, T!['{'], T!['}'], T![,], USE_TREE_LIST_RECOVERY_SET, |p: &mut Parser<'_>| { use_tree(p, false) || p.at_ts(USE_TREE_LIST_RECOVERY_SET) }); diff --git a/crates/parser/test_data/parser/inline/err/0026_use_tree_list_err_recovery.rast b/crates/parser/test_data/parser/inline/err/0026_use_tree_list_err_recovery.rast new file mode 100644 index 0000000000000..7732bdf72f40b --- /dev/null +++ b/crates/parser/test_data/parser/inline/err/0026_use_tree_list_err_recovery.rast @@ -0,0 +1,50 @@ +SOURCE_FILE + USE + USE_KW "use" + WHITESPACE " " + USE_TREE + USE_TREE_LIST + L_CURLY "{" + USE_TREE + PATH + PATH_SEGMENT + NAME_REF + IDENT "a" + ERROR + SEMICOLON ";" + WHITESPACE "\n" + USE + USE_KW "use" + WHITESPACE " " + USE_TREE + PATH + PATH_SEGMENT + NAME_REF + IDENT "b" + SEMICOLON ";" + WHITESPACE "\n" + STRUCT + STRUCT_KW "struct" + WHITESPACE " " + NAME + IDENT "T" + SEMICOLON ";" + WHITESPACE "\n" + FN + FN_KW "fn" + WHITESPACE " " + NAME + IDENT "test" + PARAM_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + R_CURLY "}" + WHITESPACE "\n" +error 6: expected COMMA +error 6: expected one of `*`, `::`, `{`, `self`, `super` or an identifier +error 7: expected R_CURLY +error 7: expected SEMICOLON diff --git a/crates/parser/test_data/parser/inline/err/0026_use_tree_list_err_recovery.rs b/crates/parser/test_data/parser/inline/err/0026_use_tree_list_err_recovery.rs new file mode 100644 index 0000000000000..f16959c25f276 --- /dev/null +++ b/crates/parser/test_data/parser/inline/err/0026_use_tree_list_err_recovery.rs @@ -0,0 +1,4 @@ +use {a; +use b; +struct T; +fn test() {} From adce3fd99ba2ad3f3b03136473c29256513213fb Mon Sep 17 00:00:00 2001 From: Nathan Reller Date: Thu, 11 Jan 2024 15:26:16 +0000 Subject: [PATCH 0127/1197] Enable Static Builds for FreeBSD Enable crt-static for FreeBSD to enable statically compiled binaries. --- compiler/rustc_target/src/spec/base/freebsd.rs | 1 + library/unwind/src/lib.rs | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/spec/base/freebsd.rs b/compiler/rustc_target/src/spec/base/freebsd.rs index 8c141aaaec34a..80b3da8a752d2 100644 --- a/compiler/rustc_target/src/spec/base/freebsd.rs +++ b/compiler/rustc_target/src/spec/base/freebsd.rs @@ -6,6 +6,7 @@ pub fn opts() -> TargetOptions { dynamic_linking: true, families: cvs!["unix"], has_rpath: true, + crt_static_respected: true, position_independent_executables: true, relro_level: RelroLevel::Full, abi_return_struct_as_int: true, diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index eeee98f754e09..f5988a4df1364 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -121,10 +121,16 @@ extern "C" {} #[link(name = "unwind", kind = "static", modifiers = "-bundle")] extern "C" {} -#[cfg(any(target_os = "freebsd", target_os = "netbsd"))] +#[cfg(target_os = "netbsd")] #[link(name = "gcc_s")] extern "C" {} +#[cfg(target_os = "freebsd")] +#[link(name = "gcc", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))] +#[link(name = "gcc_eh", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))] +#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))] +extern "C" {} + #[cfg(all(target_os = "openbsd", target_arch = "sparc64"))] #[link(name = "gcc")] extern "C" {} From aa220c7ee7a51ab39bccd03ee90fa1c9365a589a Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 11 Jan 2024 17:27:03 +0100 Subject: [PATCH 0128/1197] Merge commit '26ac6aab023393c94edf42f38f6ad31196009643' --- .github/workflows/clippy.yml | 2 +- .github/workflows/clippy_bors.yml | 10 +- .github/workflows/clippy_dev.yml | 2 +- .github/workflows/deploy.yml | 4 +- .github/workflows/remark.yml | 2 +- CHANGELOG.md | 7 + COPYRIGHT | 2 +- LICENSE-APACHE | 2 +- LICENSE-MIT | 2 +- README.md | 4 +- book/src/README.md | 2 +- book/src/SUMMARY.md | 1 + .../continuous_integration/github_actions.md | 2 +- book/src/continuous_integration/gitlab.md | 16 + book/src/development/macro_expansions.md | 2 +- book/src/development/type_checking.md | 4 +- book/src/lint_configuration.md | 10 + clippy_config/src/conf.rs | 7 +- clippy_config/src/metadata.rs | 3 + clippy_config/src/msrvs.rs | 2 +- clippy_config/src/types.rs | 6 + clippy_dev/src/new_lint.rs | 2 +- clippy_lints/src/casts/cast_sign_loss.rs | 141 ++++-- clippy_lints/src/declared_lints.rs | 8 +- clippy_lints/src/default_numeric_fallback.rs | 41 +- ...ith_brackets.rs => empty_with_brackets.rs} | 56 ++- clippy_lints/src/if_then_some_else_none.rs | 7 +- clippy_lints/src/instant_subtraction.rs | 5 +- clippy_lints/src/item_name_repetitions.rs | 5 + clippy_lints/src/iter_without_into_iter.rs | 9 +- clippy_lints/src/lib.rs | 17 +- clippy_lints/src/lines_filter_map_ok.rs | 3 +- clippy_lints/src/methods/filter_map.rs | 3 +- clippy_lints/src/methods/iter_filter.rs | 206 +++++++-- .../src/methods/manual_is_variant_and.rs | 59 +++ clippy_lints/src/methods/map_clone.rs | 142 ++++-- clippy_lints/src/methods/mod.rs | 115 ++++- .../src/methods/option_as_ref_cloned.rs | 24 + .../src/methods/option_map_unwrap_or.rs | 2 +- .../src/methods/path_ends_with_ext.rs | 2 +- clippy_lints/src/methods/redundant_as_str.rs | 6 +- clippy_lints/src/methods/str_split.rs | 38 ++ .../src/methods/unnecessary_to_owned.rs | 24 +- clippy_lints/src/methods/useless_asref.rs | 123 +++++- clippy_lints/src/methods/utils.rs | 1 + .../src/missing_asserts_for_indexing.rs | 2 +- .../src/missing_enforced_import_rename.rs | 14 +- clippy_lints/src/mutex_atomic.rs | 26 +- clippy_lints/src/no_effect.rs | 2 +- .../src/non_octal_unix_permissions.rs | 12 +- clippy_lints/src/operators/identity_op.rs | 208 +++++---- clippy_lints/src/pub_underscore_fields.rs | 83 ++++ clippy_lints/src/question_mark.rs | 7 +- clippy_lints/src/serde_api.rs | 2 +- ...ead_local_initializer_can_be_made_const.rs | 102 +++++ clippy_lints/src/transmute/eager_transmute.rs | 53 ++- .../src/transmute/transmute_undefined_repr.rs | 4 +- clippy_lints/src/unconditional_recursion.rs | 413 +++++++++++++++--- .../src/undocumented_unsafe_blocks.rs | 10 +- clippy_lints/src/unit_types/let_unit_value.rs | 21 +- clippy_lints/src/vec.rs | 17 +- clippy_lints/src/wildcard_imports.rs | 2 +- clippy_utils/src/eager_or_lazy.rs | 13 +- clippy_utils/src/hir_utils.rs | 2 +- clippy_utils/src/macros.rs | 2 +- clippy_utils/src/ty/type_certainty/mod.rs | 6 +- rust-toolchain | 2 +- rustc_tools_util/README.md | 2 +- .../all_pub_fields/clippy.toml | 1 + .../exported/clippy.toml | 1 + ...ub_underscore_fields.all_pub_fields.stderr | 60 +++ .../pub_underscore_fields.exported.stderr | 12 + .../pub_underscore_fields.rs | 66 +++ .../toml_unknown_key/conf_unknown_key.stderr | 2 + tests/ui/as_conversions.rs | 2 +- tests/ui/cast.rs | 49 +++ tests/ui/cast.stderr | 74 +++- tests/ui/crashes/ice-8821.fixed | 10 - tests/ui/crashes/ice-8821.rs | 2 - tests/ui/crashes/ice-8821.stderr | 11 - tests/ui/default_numeric_fallback_f64.fixed | 4 +- tests/ui/default_numeric_fallback_f64.rs | 2 - tests/ui/default_numeric_fallback_f64.stderr | 26 +- tests/ui/default_numeric_fallback_i32.fixed | 36 +- tests/ui/default_numeric_fallback_i32.rs | 34 +- tests/ui/default_numeric_fallback_i32.stderr | 44 +- tests/ui/eager_transmute.fixed | 35 +- tests/ui/eager_transmute.rs | 35 +- tests/ui/eager_transmute.stderr | 117 ++++- .../empty_enum_variants_with_brackets.fixed | 27 ++ tests/ui/empty_enum_variants_with_brackets.rs | 27 ++ .../empty_enum_variants_with_brackets.stderr | 36 ++ tests/ui/identity_op.fixed | 94 +++- tests/ui/identity_op.rs | 94 +++- tests/ui/identity_op.stderr | 154 +++++-- tests/ui/if_then_some_else_none.rs | 5 + tests/ui/into_iter_without_iter.rs | 39 ++ tests/ui/into_iter_without_iter.stderr | 38 +- tests/ui/iter_filter_is_ok.fixed | 193 +++++++- tests/ui/iter_filter_is_ok.rs | 193 +++++++- tests/ui/iter_filter_is_ok.stderr | 74 +++- tests/ui/iter_filter_is_some.fixed | 231 +++++++++- tests/ui/iter_filter_is_some.rs | 231 +++++++++- tests/ui/iter_filter_is_some.stderr | 62 ++- tests/ui/iter_without_into_iter.rs | 31 ++ tests/ui/iter_without_into_iter.stderr | 40 +- tests/ui/let_unit.fixed | 50 +-- tests/ui/let_unit.rs | 48 +- tests/ui/let_unit.stderr | 56 +-- tests/ui/manual_is_variant_and.fixed | 51 +++ tests/ui/manual_is_variant_and.rs | 57 +++ tests/ui/manual_is_variant_and.stderr | 82 ++++ tests/ui/map_clone.fixed | 24 + tests/ui/map_clone.rs | 24 + tests/ui/map_clone.stderr | 44 +- tests/ui/must_use_candidates.fixed | 6 +- tests/ui/must_use_candidates.rs | 6 +- tests/ui/must_use_candidates.stderr | 10 +- tests/ui/mutex_atomic.rs | 19 +- tests/ui/mutex_atomic.stderr | 30 +- tests/ui/non_octal_unix_permissions.fixed | 4 + tests/ui/non_octal_unix_permissions.rs | 4 + tests/ui/non_octal_unix_permissions.stderr | 2 +- tests/ui/option_as_ref_cloned.fixed | 21 + tests/ui/option_as_ref_cloned.rs | 21 + tests/ui/option_as_ref_cloned.stderr | 37 ++ tests/ui/redundant_as_str.fixed | 2 +- tests/ui/redundant_as_str.rs | 2 +- tests/ui/regex.rs | 2 +- tests/ui/single_char_pattern.fixed | 2 + tests/ui/single_char_pattern.rs | 2 + tests/ui/single_char_pattern.stderr | 26 +- tests/ui/str_split.fixed | 145 ++++++ tests/ui/str_split.rs | 145 ++++++ tests/ui/str_split.stderr | 65 +++ tests/ui/struct_fields.rs | 24 +- tests/ui/struct_fields.stderr | 28 +- ..._local_initializer_can_be_made_const.fixed | 30 ++ ...ead_local_initializer_can_be_made_const.rs | 30 ++ ...local_initializer_can_be_made_const.stderr | 29 ++ tests/ui/unconditional_recursion.rs | 108 ++++- tests/ui/unconditional_recursion.stderr | 95 +++- tests/ui/unnecessary_lazy_eval.fixed | 13 + tests/ui/unnecessary_lazy_eval.rs | 13 + tests/ui/unnecessary_lazy_eval.stderr | 126 +++--- tests/ui/unnecessary_safety_comment.rs | 21 + tests/ui/unnecessary_to_owned_on_split.fixed | 18 +- tests/ui/unnecessary_to_owned_on_split.rs | 18 +- tests/ui/unnecessary_to_owned_on_split.stderr | 24 +- tests/ui/useless_asref.fixed | 14 +- tests/ui/useless_asref.rs | 14 +- tests/ui/useless_asref.stderr | 42 +- tests/ui/useless_conversion.fixed | 4 +- tests/ui/useless_conversion.rs | 4 +- tests/ui/vec.fixed | 7 + tests/ui/vec.rs | 7 + triagebot.toml | 1 - 157 files changed, 5166 insertions(+), 819 deletions(-) create mode 100644 book/src/continuous_integration/gitlab.md rename clippy_lints/src/{empty_structs_with_brackets.rs => empty_with_brackets.rs} (62%) create mode 100644 clippy_lints/src/methods/manual_is_variant_and.rs create mode 100644 clippy_lints/src/methods/option_as_ref_cloned.rs create mode 100644 clippy_lints/src/methods/str_split.rs create mode 100644 clippy_lints/src/pub_underscore_fields.rs create mode 100644 clippy_lints/src/thread_local_initializer_can_be_made_const.rs create mode 100644 tests/ui-toml/pub_underscore_fields/all_pub_fields/clippy.toml create mode 100644 tests/ui-toml/pub_underscore_fields/exported/clippy.toml create mode 100644 tests/ui-toml/pub_underscore_fields/pub_underscore_fields.all_pub_fields.stderr create mode 100644 tests/ui-toml/pub_underscore_fields/pub_underscore_fields.exported.stderr create mode 100644 tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs delete mode 100644 tests/ui/crashes/ice-8821.fixed delete mode 100644 tests/ui/crashes/ice-8821.stderr create mode 100644 tests/ui/empty_enum_variants_with_brackets.fixed create mode 100644 tests/ui/empty_enum_variants_with_brackets.rs create mode 100644 tests/ui/empty_enum_variants_with_brackets.stderr create mode 100644 tests/ui/manual_is_variant_and.fixed create mode 100644 tests/ui/manual_is_variant_and.rs create mode 100644 tests/ui/manual_is_variant_and.stderr create mode 100644 tests/ui/option_as_ref_cloned.fixed create mode 100644 tests/ui/option_as_ref_cloned.rs create mode 100644 tests/ui/option_as_ref_cloned.stderr create mode 100644 tests/ui/str_split.fixed create mode 100644 tests/ui/str_split.rs create mode 100644 tests/ui/str_split.stderr create mode 100644 tests/ui/thread_local_initializer_can_be_made_const.fixed create mode 100644 tests/ui/thread_local_initializer_can_be_made_const.rs create mode 100644 tests/ui/thread_local_initializer_can_be_made_const.stderr diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml index 99d80bec0255f..5ba960db66dde 100644 --- a/.github/workflows/clippy.yml +++ b/.github/workflows/clippy.yml @@ -38,7 +38,7 @@ jobs: github_token: "${{ secrets.github_token }}" - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install toolchain run: rustup show active-toolchain diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml index 73c2555074286..012797e5ca72a 100644 --- a/.github/workflows/clippy_bors.yml +++ b/.github/workflows/clippy_bors.yml @@ -26,7 +26,7 @@ jobs: github_token: "${{ secrets.github_token }}" - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.ref }} @@ -72,7 +72,7 @@ jobs: github_token: "${{ secrets.github_token }}" - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install i686 dependencies if: matrix.host == 'i686-unknown-linux-gnu' @@ -151,7 +151,7 @@ jobs: github_token: "${{ secrets.github_token }}" - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install toolchain run: rustup show active-toolchain @@ -175,7 +175,7 @@ jobs: github_token: "${{ secrets.github_token }}" - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install toolchain run: rustup show active-toolchain @@ -231,7 +231,7 @@ jobs: github_token: "${{ secrets.github_token }}" - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install toolchain run: rustup show active-toolchain diff --git a/.github/workflows/clippy_dev.yml b/.github/workflows/clippy_dev.yml index 0f0e3f2db925c..37f18a4c08740 100644 --- a/.github/workflows/clippy_dev.yml +++ b/.github/workflows/clippy_dev.yml @@ -24,7 +24,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Run - name: Build diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 999ee7acfe761..94f494b65c47c 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -21,10 +21,10 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ env.TARGET_BRANCH }} path: 'out' diff --git a/.github/workflows/remark.yml b/.github/workflows/remark.yml index 30bd476332f75..05e1b3b9202b4 100644 --- a/.github/workflows/remark.yml +++ b/.github/workflows/remark.yml @@ -16,7 +16,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v3 diff --git a/CHANGELOG.md b/CHANGELOG.md index f82421a687b82..4d32bbec914a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5105,6 +5105,7 @@ Released 2018-09-13 [`else_if_without_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#else_if_without_else [`empty_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_drop [`empty_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_enum +[`empty_enum_variants_with_brackets`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_enum_variants_with_brackets [`empty_line_after_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_line_after_doc_comments [`empty_line_after_outer_attr`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_line_after_outer_attr [`empty_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_loop @@ -5294,6 +5295,7 @@ Released 2018-09-13 [`manual_is_ascii_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check [`manual_is_finite`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_finite [`manual_is_infinite`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_infinite +[`manual_is_variant_and`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_variant_and [`manual_let_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else [`manual_main_separator_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_main_separator_str [`manual_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_map @@ -5440,6 +5442,7 @@ Released 2018-09-13 [`only_used_in_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#only_used_in_recursion [`op_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#op_ref [`option_and_then_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_and_then_some +[`option_as_ref_cloned`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_cloned [`option_as_ref_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref [`option_env_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_env_unwrap [`option_expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_expect_used @@ -5483,6 +5486,7 @@ Released 2018-09-13 [`ptr_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_eq [`ptr_offset_with_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_offset_with_cast [`pub_enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_enum_variant_names +[`pub_underscore_fields`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_underscore_fields [`pub_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_use [`pub_with_shorthand`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_with_shorthand [`pub_without_shorthand`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_without_shorthand @@ -5580,6 +5584,7 @@ Released 2018-09-13 [`stable_sort_primitive`]: https://rust-lang.github.io/rust-clippy/master/index.html#stable_sort_primitive [`std_instead_of_alloc`]: https://rust-lang.github.io/rust-clippy/master/index.html#std_instead_of_alloc [`std_instead_of_core`]: https://rust-lang.github.io/rust-clippy/master/index.html#std_instead_of_core +[`str_split_at_newline`]: https://rust-lang.github.io/rust-clippy/master/index.html#str_split_at_newline [`str_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#str_to_string [`string_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add [`string_add_assign`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add_assign @@ -5612,6 +5617,7 @@ Released 2018-09-13 [`temporary_cstring_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_cstring_as_ptr [`test_attr_in_doctest`]: https://rust-lang.github.io/rust-clippy/master/index.html#test_attr_in_doctest [`tests_outside_test_module`]: https://rust-lang.github.io/rust-clippy/master/index.html#tests_outside_test_module +[`thread_local_initializer_can_be_made_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#thread_local_initializer_can_be_made_const [`to_digit_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some [`to_string_in_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_display [`to_string_in_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_format_args @@ -5810,4 +5816,5 @@ Released 2018-09-13 [`allowed-dotfiles`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-dotfiles [`enforce-iter-loop-reborrow`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enforce-iter-loop-reborrow [`check-private-items`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-private-items +[`pub-underscore-fields-behavior`]: https://doc.rust-lang.org/clippy/lint_configuration.html#pub-underscore-fields-behavior diff --git a/COPYRIGHT b/COPYRIGHT index 82703b18fd7d2..219693d63d973 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -1,6 +1,6 @@ // REUSE-IgnoreStart -Copyright 2014-2022 The Rust Project Developers +Copyright 2014-2024 The Rust Project Developers Licensed under the Apache License, Version 2.0 or the MIT license diff --git a/LICENSE-APACHE b/LICENSE-APACHE index 0d62c37278e58..506582c31d6d5 100644 --- a/LICENSE-APACHE +++ b/LICENSE-APACHE @@ -186,7 +186,7 @@ APPENDIX: How to apply the Apache License to your work. same "printed page" as the copyright notice for easier identification within third-party archives. -Copyright 2014-2022 The Rust Project Developers +Copyright 2014-2024 The Rust Project Developers Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/LICENSE-MIT b/LICENSE-MIT index b724b24aa8309..6d8ee9afb6163 100644 --- a/LICENSE-MIT +++ b/LICENSE-MIT @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2014-2022 The Rust Project Developers +Copyright (c) 2014-2024 The Rust Project Developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated diff --git a/README.md b/README.md index 5d490645d8979..fa18447090c19 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are over 650 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are over 700 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html). You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the lint level by category. @@ -278,7 +278,7 @@ If you want to contribute to Clippy, you can find more information in [CONTRIBUT -Copyright 2014-2023 The Rust Project Developers +Copyright 2014-2024 The Rust Project Developers Licensed under the Apache License, Version 2.0 or the MIT license diff --git a/book/src/README.md b/book/src/README.md index 486ea3df70420..e7972b0db19ce 100644 --- a/book/src/README.md +++ b/book/src/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are over 650 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are over 700 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html). You can choose how diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index b02457307d743..a048fbbd8acf9 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -9,6 +9,7 @@ - [Clippy's Lints](lints.md) - [Continuous Integration](continuous_integration/README.md) - [GitHub Actions](continuous_integration/github_actions.md) + - [GitLab CI](continuous_integration/gitlab.md) - [Travis CI](continuous_integration/travis.md) - [Development](development/README.md) - [Basics](development/basics.md) diff --git a/book/src/continuous_integration/github_actions.md b/book/src/continuous_integration/github_actions.md index 339287a7dd95f..b588c8f0f02c4 100644 --- a/book/src/continuous_integration/github_actions.md +++ b/book/src/continuous_integration/github_actions.md @@ -15,7 +15,7 @@ jobs: clippy_check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Run Clippy run: cargo clippy --all-targets --all-features ``` diff --git a/book/src/continuous_integration/gitlab.md b/book/src/continuous_integration/gitlab.md new file mode 100644 index 0000000000000..bb3ef246c2faa --- /dev/null +++ b/book/src/continuous_integration/gitlab.md @@ -0,0 +1,16 @@ +# GitLab CI + +You can add Clippy to GitLab CI by using the latest stable [rust docker image](https://hub.docker.com/_/rust), +as it is shown in the `.gitlab-ci.yml` CI configuration file below, + +```yml +# Make sure CI fails on all warnings, including Clippy lints +variables: + RUSTFLAGS: "-Dwarnings" + +clippy_check: + image: rust:latest + script: + - rustup component add clippy + - cargo clippy --all-targets --all-features +``` diff --git a/book/src/development/macro_expansions.md b/book/src/development/macro_expansions.md index c5eb000272d39..aecca9ef72e98 100644 --- a/book/src/development/macro_expansions.md +++ b/book/src/development/macro_expansions.md @@ -102,7 +102,7 @@ let x: Option = Some(42); m!(x, x.unwrap()); ``` -If the `m!(x, x.unwrapp());` line is expanded, we would get two expanded +If the `m!(x, x.unwrap());` line is expanded, we would get two expanded expressions: - `x.is_some()` (from the `$a.is_some()` line in the `m` macro) diff --git a/book/src/development/type_checking.md b/book/src/development/type_checking.md index a8c9660da4c85..dc29ab5d08dad 100644 --- a/book/src/development/type_checking.md +++ b/book/src/development/type_checking.md @@ -133,7 +133,7 @@ in this chapter: - [Type checking](https://rustc-dev-guide.rust-lang.org/type-checking.html) - [Ty module](https://rustc-dev-guide.rust-lang.org/ty.html) -[Adt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/sty/enum.TyKind.html#variant.Adt +[Adt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/ty_kind/enum.TyKind.html#variant.Adt [AdtDef]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/adt/struct.AdtDef.html [expr_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html#method.expr_ty [node_type]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html#method.node_type @@ -144,7 +144,7 @@ in this chapter: [LateLintPass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.LateLintPass.html [pat_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/typeck_results/struct.TypeckResults.html#method.pat_ty [Ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html -[TyKind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/sty/enum.TyKind.html +[TyKind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/ty_kind/enum.TyKind.html [TypeckResults]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html [middle_ty]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_middle/ty/struct.Ty.html [hir_ty]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_hir/struct.Ty.html diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 7c9a8eb1bfba1..3b62ae0524ab0 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -805,3 +805,13 @@ for _ in &mut *rmvec {} * [`missing_errors_doc`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc) +## `pub-underscore-fields-behavior` + + +**Default Value:** `"PublicallyExported"` + +--- +**Affected lints:** +* [`pub_underscore_fields`](https://rust-lang.github.io/rust-clippy/master/index.html#pub_underscore_fields) + + diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index a4f368397cede..5477d9b83a72c 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -1,5 +1,5 @@ use crate::msrvs::Msrv; -use crate::types::{DisallowedPath, MacroMatcher, MatchLintBehaviour, Rename}; +use crate::types::{DisallowedPath, MacroMatcher, MatchLintBehaviour, PubUnderscoreFieldsBehaviour, Rename}; use crate::ClippyConfiguration; use rustc_data_structures::fx::FxHashSet; use rustc_session::Session; @@ -547,6 +547,11 @@ define_Conf! { /// /// Whether to also run the listed lints on private items. (check_private_items: bool = false), + /// Lint: PUB_UNDERSCORE_FIELDS + /// + /// Lint "public" fields in a struct that are prefixed with an underscore based on their + /// exported visibility, or whether they are marked as "pub". + (pub_underscore_fields_behavior: PubUnderscoreFieldsBehaviour = PubUnderscoreFieldsBehaviour::PublicallyExported), } /// Search for the configuration file. diff --git a/clippy_config/src/metadata.rs b/clippy_config/src/metadata.rs index 2451fbc91e898..3ba2796e18d3c 100644 --- a/clippy_config/src/metadata.rs +++ b/clippy_config/src/metadata.rs @@ -96,6 +96,9 @@ fn parse_config_field_doc(doc_comment: &str) -> Option<(Vec, String)> { doc_comment.make_ascii_lowercase(); let lints: Vec = doc_comment .split_off(DOC_START.len()) + .lines() + .next() + .unwrap() .split(", ") .map(str::to_string) .collect(); diff --git a/clippy_config/src/msrvs.rs b/clippy_config/src/msrvs.rs index dae9f09ec00a0..72d5b9aff28df 100644 --- a/clippy_config/src/msrvs.rs +++ b/clippy_config/src/msrvs.rs @@ -17,7 +17,7 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { 1,71,0 { TUPLE_ARRAY_CONVERSIONS, BUILD_HASHER_HASH_ONE } - 1,70,0 { OPTION_IS_SOME_AND, BINARY_HEAP_RETAIN } + 1,70,0 { OPTION_RESULT_IS_VARIANT_AND, BINARY_HEAP_RETAIN } 1,68,0 { PATH_MAIN_SEPARATOR_STR } 1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS } 1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE } diff --git a/clippy_config/src/types.rs b/clippy_config/src/types.rs index df48cc3f5e391..baee09629ac44 100644 --- a/clippy_config/src/types.rs +++ b/clippy_config/src/types.rs @@ -126,3 +126,9 @@ unimplemented_serialize! { Rename, MacroMatcher, } + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)] +pub enum PubUnderscoreFieldsBehaviour { + PublicallyExported, + AllPubFields, +} diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 31a42734c1310..5d9cde06cd86b 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -67,7 +67,7 @@ pub fn create( if pass == "early" { println!( "\n\ - NOTE: Use a late pass unless you need something specific from\ + NOTE: Use a late pass unless you need something specific from\n\ an early pass, as they lack many features and utilities" ); } diff --git a/clippy_lints/src/casts/cast_sign_loss.rs b/clippy_lints/src/casts/cast_sign_loss.rs index bd12ee406284b..1df5a25f674d7 100644 --- a/clippy_lints/src/casts/cast_sign_loss.rs +++ b/clippy_lints/src/casts/cast_sign_loss.rs @@ -1,12 +1,14 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint; -use clippy_utils::{method_chain_args, sext}; -use rustc_hir::{Expr, ExprKind}; +use clippy_utils::{clip, method_chain_args, sext}; +use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, Ty, UintTy}; use super::CAST_SIGN_LOSS; +const METHODS_RET_POSITIVE: &[&str] = &["abs", "checked_abs", "rem_euclid", "checked_rem_euclid"]; + pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { if should_lint(cx, cast_op, cast_from, cast_to) { span_lint( @@ -25,33 +27,28 @@ fn should_lint(cx: &LateContext<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast return false; } - // Don't lint for positive constants. - let const_val = constant(cx, cx.typeck_results(), cast_op); - if let Some(Constant::Int(n)) = const_val - && let ty::Int(ity) = *cast_from.kind() - && sext(cx.tcx, n, ity) >= 0 - { + // Don't lint if `cast_op` is known to be positive. + if let Sign::ZeroOrPositive = expr_sign(cx, cast_op, cast_from) { return false; } - // Don't lint for the result of methods that always return non-negative values. - if let ExprKind::MethodCall(path, ..) = cast_op.kind { - let mut method_name = path.ident.name.as_str(); - let allowed_methods = ["abs", "checked_abs", "rem_euclid", "checked_rem_euclid"]; - - if method_name == "unwrap" - && let Some(arglist) = method_chain_args(cast_op, &["unwrap"]) - && let ExprKind::MethodCall(inner_path, ..) = &arglist[0].0.kind - { - method_name = inner_path.ident.name.as_str(); - } - - if allowed_methods.iter().any(|&name| method_name == name) { - return false; - } + let (mut uncertain_count, mut negative_count) = (0, 0); + // Peel off possible binary expressions, e.g. x * x * y => [x, x, y] + let Some(exprs) = exprs_with_selected_binop_peeled(cast_op) else { + // Assume cast sign lose if we cannot determine the sign of `cast_op` + return true; + }; + for expr in exprs { + let ty = cx.typeck_results().expr_ty(expr); + match expr_sign(cx, expr, ty) { + Sign::Negative => negative_count += 1, + Sign::Uncertain => uncertain_count += 1, + Sign::ZeroOrPositive => (), + }; } - true + // Lint if there are odd number of uncertain or negative results + uncertain_count % 2 == 1 || negative_count % 2 == 1 }, (false, true) => !cast_to.is_signed(), @@ -59,3 +56,97 @@ fn should_lint(cx: &LateContext<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast (_, _) => false, } } + +fn get_const_int_eval(cx: &LateContext<'_>, expr: &Expr<'_>, ty: Ty<'_>) -> Option { + if let Constant::Int(n) = constant(cx, cx.typeck_results(), expr)? + && let ty::Int(ity) = *ty.kind() + { + return Some(sext(cx.tcx, n, ity)); + } + None +} + +enum Sign { + ZeroOrPositive, + Negative, + Uncertain, +} + +fn expr_sign(cx: &LateContext<'_>, expr: &Expr<'_>, ty: Ty<'_>) -> Sign { + // Try evaluate this expr first to see if it's positive + if let Some(val) = get_const_int_eval(cx, expr, ty) { + return if val >= 0 { Sign::ZeroOrPositive } else { Sign::Negative }; + } + // Calling on methods that always return non-negative values. + if let ExprKind::MethodCall(path, caller, args, ..) = expr.kind { + let mut method_name = path.ident.name.as_str(); + + if method_name == "unwrap" + && let Some(arglist) = method_chain_args(expr, &["unwrap"]) + && let ExprKind::MethodCall(inner_path, ..) = &arglist[0].0.kind + { + method_name = inner_path.ident.name.as_str(); + } + + if method_name == "pow" + && let [arg] = args + { + return pow_call_result_sign(cx, caller, arg); + } else if METHODS_RET_POSITIVE.iter().any(|&name| method_name == name) { + return Sign::ZeroOrPositive; + } + } + + Sign::Uncertain +} + +/// Return the sign of the `pow` call's result. +/// +/// If the caller is a positive number, the result is always positive, +/// If the `power_of` is a even number, the result is always positive as well, +/// Otherwise a [`Sign::Uncertain`] will be returned. +fn pow_call_result_sign(cx: &LateContext<'_>, caller: &Expr<'_>, power_of: &Expr<'_>) -> Sign { + let caller_ty = cx.typeck_results().expr_ty(caller); + if let Some(caller_val) = get_const_int_eval(cx, caller, caller_ty) + && caller_val >= 0 + { + return Sign::ZeroOrPositive; + } + + if let Some(Constant::Int(n)) = constant(cx, cx.typeck_results(), power_of) + && clip(cx.tcx, n, UintTy::U32) % 2 == 0 + { + return Sign::ZeroOrPositive; + } + + Sign::Uncertain +} + +/// Peels binary operators such as [`BinOpKind::Mul`], [`BinOpKind::Div`] or [`BinOpKind::Rem`], +/// which the result could always be positive under certain condition. +/// +/// Other operators such as `+`/`-` causing the result's sign hard to determine, which we will +/// return `None` +fn exprs_with_selected_binop_peeled<'a>(expr: &'a Expr<'_>) -> Option>> { + #[inline] + fn collect_operands<'a>(expr: &'a Expr<'a>, operands: &mut Vec<&'a Expr<'a>>) -> Option<()> { + match expr.kind { + ExprKind::Binary(op, lhs, rhs) => { + if matches!(op.node, BinOpKind::Mul | BinOpKind::Div | BinOpKind::Rem) { + collect_operands(lhs, operands); + operands.push(rhs); + } else { + // Things are complicated when there are other binary ops exist, + // abort checking by returning `None` for now. + return None; + } + }, + _ => operands.push(expr), + } + Some(()) + } + + let mut res = vec![]; + collect_operands(expr, &mut res)?; + Some(res) +} diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index eae9dfac064e8..20230106d5366 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -150,7 +150,8 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::else_if_without_else::ELSE_IF_WITHOUT_ELSE_INFO, crate::empty_drop::EMPTY_DROP_INFO, crate::empty_enum::EMPTY_ENUM_INFO, - crate::empty_structs_with_brackets::EMPTY_STRUCTS_WITH_BRACKETS_INFO, + crate::empty_with_brackets::EMPTY_ENUM_VARIANTS_WITH_BRACKETS_INFO, + crate::empty_with_brackets::EMPTY_STRUCTS_WITH_BRACKETS_INFO, crate::endian_bytes::BIG_ENDIAN_BYTES_INFO, crate::endian_bytes::HOST_ENDIAN_BYTES_INFO, crate::endian_bytes::LITTLE_ENDIAN_BYTES_INFO, @@ -385,6 +386,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::JOIN_ABSOLUTE_PATHS_INFO, crate::methods::MANUAL_FILTER_MAP_INFO, crate::methods::MANUAL_FIND_MAP_INFO, + crate::methods::MANUAL_IS_VARIANT_AND_INFO, crate::methods::MANUAL_NEXT_BACK_INFO, crate::methods::MANUAL_OK_OR_INFO, crate::methods::MANUAL_SATURATING_ARITHMETIC_INFO, @@ -408,6 +410,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::NO_EFFECT_REPLACE_INFO, crate::methods::OBFUSCATED_IF_ELSE_INFO, crate::methods::OK_EXPECT_INFO, + crate::methods::OPTION_AS_REF_CLONED_INFO, crate::methods::OPTION_AS_REF_DEREF_INFO, crate::methods::OPTION_FILTER_MAP_INFO, crate::methods::OPTION_MAP_OR_ERR_OK_INFO, @@ -433,6 +436,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::STABLE_SORT_PRIMITIVE_INFO, crate::methods::STRING_EXTEND_CHARS_INFO, crate::methods::STRING_LIT_CHARS_ANY_INFO, + crate::methods::STR_SPLIT_AT_NEWLINE_INFO, crate::methods::SUSPICIOUS_COMMAND_ARG_SPACE_INFO, crate::methods::SUSPICIOUS_MAP_INFO, crate::methods::SUSPICIOUS_SPLITN_INFO, @@ -576,6 +580,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::ptr::MUT_FROM_REF_INFO, crate::ptr::PTR_ARG_INFO, crate::ptr_offset_with_cast::PTR_OFFSET_WITH_CAST_INFO, + crate::pub_underscore_fields::PUB_UNDERSCORE_FIELDS_INFO, crate::pub_use::PUB_USE_INFO, crate::question_mark::QUESTION_MARK_INFO, crate::question_mark_used::QUESTION_MARK_USED_INFO, @@ -648,6 +653,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::tabs_in_doc_comments::TABS_IN_DOC_COMMENTS_INFO, crate::temporary_assignment::TEMPORARY_ASSIGNMENT_INFO, crate::tests_outside_test_module::TESTS_OUTSIDE_TEST_MODULE_INFO, + crate::thread_local_initializer_can_be_made_const::THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST_INFO, crate::to_digit_is_some::TO_DIGIT_IS_SOME_INFO, crate::trailing_empty_array::TRAILING_EMPTY_ARRAY_INFO, crate::trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS_INFO, diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index 64a924a776a65..712bc075650fa 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -4,7 +4,7 @@ use clippy_utils::{get_parent_node, numeric_literal}; use rustc_ast::ast::{LitFloatType, LitIntType, LitKind}; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, walk_stmt, Visitor}; -use rustc_hir::{Body, Expr, ExprKind, HirId, ItemKind, Lit, Node, Stmt, StmtKind}; +use rustc_hir::{Block, Body, Expr, ExprKind, FnRetTy, HirId, ItemKind, Lit, Node, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, FloatTy, IntTy, PolyFnSig, Ty}; @@ -122,13 +122,42 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { match &expr.kind { + ExprKind::Block( + Block { + stmts, expr: Some(_), .. + }, + _, + ) => { + if let Some(parent) = self.cx.tcx.hir().find_parent(expr.hir_id) + && let Some(fn_sig) = parent.fn_sig() + && let FnRetTy::Return(_ty) = fn_sig.decl.output + { + // We cannot check the exact type since it's a `hir::Ty`` which does not implement `is_numeric` + self.ty_bounds.push(ExplicitTyBound(true)); + for stmt in *stmts { + self.visit_stmt(stmt); + } + self.ty_bounds.pop(); + // Ignore return expr since we know its type was inferred from return ty + return; + } + }, + + // Ignore return expr since we know its type was inferred from return ty + ExprKind::Ret(_) => return, + ExprKind::Call(func, args) => { if let Some(fn_sig) = fn_sig_opt(self.cx, func.hir_id) { for (expr, bound) in iter::zip(*args, fn_sig.skip_binder().inputs()) { - // Push found arg type, then visit arg. - self.ty_bounds.push((*bound).into()); - self.visit_expr(expr); - self.ty_bounds.pop(); + // If is from macro, try to use last bound type (typically pushed when visiting stmt), + // otherwise push found arg type, then visit arg, + if expr.span.from_expansion() { + self.visit_expr(expr); + } else { + self.ty_bounds.push((*bound).into()); + self.visit_expr(expr); + self.ty_bounds.pop(); + } } return; } @@ -137,7 +166,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { ExprKind::MethodCall(_, receiver, args, _) => { if let Some(def_id) = self.cx.typeck_results().type_dependent_def_id(expr.hir_id) { let fn_sig = self.cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder(); - for (expr, bound) in iter::zip(std::iter::once(*receiver).chain(args.iter()), fn_sig.inputs()) { + for (expr, bound) in iter::zip(iter::once(*receiver).chain(args.iter()), fn_sig.inputs()) { self.ty_bounds.push((*bound).into()); self.visit_expr(expr); self.ty_bounds.pop(); diff --git a/clippy_lints/src/empty_structs_with_brackets.rs b/clippy_lints/src/empty_with_brackets.rs similarity index 62% rename from clippy_lints/src/empty_structs_with_brackets.rs rename to clippy_lints/src/empty_with_brackets.rs index 3cf67b3ecbfa4..969df6d85b5a0 100644 --- a/clippy_lints/src/empty_structs_with_brackets.rs +++ b/clippy_lints/src/empty_with_brackets.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_opt; -use rustc_ast::ast::{Item, ItemKind, VariantData}; +use rustc_ast::ast::{Item, ItemKind, Variant, VariantData}; use rustc_errors::Applicability; use rustc_lexer::TokenKind; use rustc_lint::{EarlyContext, EarlyLintPass}; @@ -27,9 +27,38 @@ declare_clippy_lint! { restriction, "finds struct declarations with empty brackets" } -declare_lint_pass!(EmptyStructsWithBrackets => [EMPTY_STRUCTS_WITH_BRACKETS]); -impl EarlyLintPass for EmptyStructsWithBrackets { +declare_clippy_lint! { + /// ### What it does + /// Finds enum variants without fields that are declared with empty brackets. + /// + /// ### Why is this bad? + /// Empty brackets while defining enum variants are redundant and can be omitted. + /// + /// ### Example + /// ```no_run + /// enum MyEnum { + /// HasData(u8), + /// HasNoData(), // redundant parentheses + /// } + /// ``` + /// + /// Use instead: + /// ```no_run + /// enum MyEnum { + /// HasData(u8), + /// HasNoData, + /// } + /// ``` + #[clippy::version = "1.77.0"] + pub EMPTY_ENUM_VARIANTS_WITH_BRACKETS, + restriction, + "finds enum variants with empty brackets" +} + +declare_lint_pass!(EmptyWithBrackets => [EMPTY_STRUCTS_WITH_BRACKETS, EMPTY_ENUM_VARIANTS_WITH_BRACKETS]); + +impl EarlyLintPass for EmptyWithBrackets { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { let span_after_ident = item.span.with_lo(item.ident.span.hi()); @@ -53,6 +82,27 @@ impl EarlyLintPass for EmptyStructsWithBrackets { ); } } + + fn check_variant(&mut self, cx: &EarlyContext<'_>, variant: &Variant) { + let span_after_ident = variant.span.with_lo(variant.ident.span.hi()); + + if has_brackets(&variant.data) && has_no_fields(cx, &variant.data, span_after_ident) { + span_lint_and_then( + cx, + EMPTY_ENUM_VARIANTS_WITH_BRACKETS, + span_after_ident, + "enum variant has empty brackets", + |diagnostic| { + diagnostic.span_suggestion_hidden( + span_after_ident, + "remove the brackets", + "", + Applicability::MaybeIncorrect, + ); + }, + ); + } + } } fn has_no_ident_token(braces_span_str: &str) -> bool { diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index cd6c46a71a8e1..8f48941c4a91e 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::source::snippet_with_context; use clippy_utils::sugg::Sugg; -use clippy_utils::{contains_return, higher, is_else_clause, is_res_lang_ctor, path_res, peel_blocks}; +use clippy_utils::{contains_return, higher, in_constant, is_else_clause, is_res_lang_ctor, path_res, peel_blocks}; use rustc_errors::Applicability; use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::{Expr, ExprKind}; @@ -74,6 +74,11 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { return; } + // `bool::then()` and `bool::then_some()` are not const + if in_constant(cx, expr.hir_id) { + return; + } + let ctxt = expr.span.ctxt(); if let Some(higher::If { diff --git a/clippy_lints/src/instant_subtraction.rs b/clippy_lints/src/instant_subtraction.rs index 655f4b82aa4f1..17b6256f982b2 100644 --- a/clippy_lints/src/instant_subtraction.rs +++ b/clippy_lints/src/instant_subtraction.rs @@ -40,7 +40,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Lints subtraction between an [`Instant`] and a [`Duration`]. + /// Lints subtraction between an `Instant` and a `Duration`. /// /// ### Why is this bad? /// Unchecked subtraction could cause underflow on certain platforms, leading to @@ -57,9 +57,6 @@ declare_clippy_lint! { /// # use std::time::{Instant, Duration}; /// let time_passed = Instant::now().checked_sub(Duration::from_secs(5)); /// ``` - /// - /// [`Duration`]: std::time::Duration - /// [`Instant::now()`]: std::time::Instant::now; #[clippy::version = "1.67.0"] pub UNCHECKED_DURATION_SUBTRACTION, pedantic, diff --git a/clippy_lints/src/item_name_repetitions.rs b/clippy_lints/src/item_name_repetitions.rs index a9f1612ff05ed..276c1abb60cd5 100644 --- a/clippy_lints/src/item_name_repetitions.rs +++ b/clippy_lints/src/item_name_repetitions.rs @@ -1,6 +1,7 @@ //! lint on enum variants that are prefixed or suffixed by the same characters use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_hir}; +use clippy_utils::is_bool; use clippy_utils::macros::span_is_local; use clippy_utils::source::is_present_in_source; use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start, to_camel_case, to_snake_case}; @@ -231,6 +232,10 @@ fn check_fields(cx: &LateContext<'_>, threshold: u64, item: &Item<'_>, fields: & (false, _) => ("pre", prefix), (true, false) => ("post", postfix), }; + if fields.iter().all(|field| is_bool(field.ty)) { + // If all fields are booleans, we don't want to emit this lint. + return; + } span_lint_and_help( cx, STRUCT_FIELD_NAMES, diff --git a/clippy_lints/src/iter_without_into_iter.rs b/clippy_lints/src/iter_without_into_iter.rs index c9dc48668f29d..903d3a2ab8960 100644 --- a/clippy_lints/src/iter_without_into_iter.rs +++ b/clippy_lints/src/iter_without_into_iter.rs @@ -5,7 +5,8 @@ use clippy_utils::ty::{implements_trait, make_normalized_projection}; use rustc_ast::Mutability; use rustc_errors::Applicability; use rustc_hir::{FnRetTy, ImplItemKind, ImplicitSelfKind, ItemKind, TyKind}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; use rustc_session::declare_lint_pass; use rustc_span::{sym, Symbol}; @@ -152,7 +153,8 @@ fn adt_has_inherent_method(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol impl LateLintPass<'_> for IterWithoutIntoIter { fn check_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::Item<'_>) { - if let ItemKind::Impl(imp) = item.kind + if !in_external_macro(cx.sess(), item.span) + && let ItemKind::Impl(imp) = item.kind && let TyKind::Ref(_, self_ty_without_ref) = &imp.self_ty.kind && let Some(trait_ref) = imp.of_trait && trait_ref @@ -219,7 +221,8 @@ impl {self_ty_without_ref} {{ _ => return, }; - if let ImplItemKind::Fn(sig, _) = item.kind + if !in_external_macro(cx.sess(), item.span) + && let ImplItemKind::Fn(sig, _) = item.kind && let FnRetTy::Return(ret) = sig.decl.output && is_nameable_in_impl_trait(ret) && cx.tcx.generics_of(item_did).params.is_empty() diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 755a4ff525d2e..efdd392594977 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -115,7 +115,7 @@ mod duplicate_mod; mod else_if_without_else; mod empty_drop; mod empty_enum; -mod empty_structs_with_brackets; +mod empty_with_brackets; mod endian_bytes; mod entry; mod enum_clike; @@ -272,6 +272,7 @@ mod permissions_set_readonly_false; mod precedence; mod ptr; mod ptr_offset_with_cast; +mod pub_underscore_fields; mod pub_use; mod question_mark; mod question_mark_used; @@ -322,6 +323,7 @@ mod swap_ptr_to_ref; mod tabs_in_doc_comments; mod temporary_assignment; mod tests_outside_test_module; +mod thread_local_initializer_can_be_made_const; mod to_digit_is_some; mod trailing_empty_array; mod trait_bounds; @@ -571,6 +573,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { verbose_bit_mask_threshold, warn_on_all_wildcard_imports, check_private_items, + pub_underscore_fields_behavior, blacklisted_names: _, cyclomatic_complexity_threshold: _, @@ -947,7 +950,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { }) }); store.register_early_pass(|| Box::new(crate_in_macro_def::CrateInMacroDef)); - store.register_early_pass(|| Box::new(empty_structs_with_brackets::EmptyStructsWithBrackets)); + store.register_early_pass(|| Box::new(empty_with_brackets::EmptyWithBrackets)); store.register_late_pass(|_| Box::new(unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings)); store.register_early_pass(|| Box::new(pub_use::PubUse)); store.register_late_pass(|_| Box::new(format_push_string::FormatPushString)); @@ -1080,7 +1083,15 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(repeat_vec_with_capacity::RepeatVecWithCapacity)); store.register_late_pass(|_| Box::new(uninhabited_references::UninhabitedReferences)); store.register_late_pass(|_| Box::new(ineffective_open_options::IneffectiveOpenOptions)); - store.register_late_pass(|_| Box::new(unconditional_recursion::UnconditionalRecursion)); + store.register_late_pass(|_| Box::::default()); + store.register_late_pass(move |_| { + Box::new(pub_underscore_fields::PubUnderscoreFields { + behavior: pub_underscore_fields_behavior, + }) + }); + store.register_late_pass(move |_| { + Box::new(thread_local_initializer_can_be_made_const::ThreadLocalInitializerCanBeMadeConst::new(msrv())) + }); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/lines_filter_map_ok.rs b/clippy_lints/src/lines_filter_map_ok.rs index 8a0955147bb54..29957e423b0b9 100644 --- a/clippy_lints/src/lines_filter_map_ok.rs +++ b/clippy_lints/src/lines_filter_map_ok.rs @@ -96,8 +96,7 @@ fn should_lint(cx: &LateContext<'_>, args: &[Expr<'_>], method_str: &str) -> boo ExprKind::Path(qpath) => cx .qpath_res(qpath, fm_arg.hir_id) .opt_def_id() - .map(|did| match_def_path(cx, did, &paths::CORE_RESULT_OK_METHOD)) - .unwrap_or_default(), + .is_some_and(|did| match_def_path(cx, did, &paths::CORE_RESULT_OK_METHOD)), // Detect `|x| x.ok()` ExprKind::Closure(Closure { body, .. }) => { if let Body { diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index 7cfd3d346b638..e489899c19e34 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -26,13 +26,14 @@ fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) -> hir::ExprKind::Closure(&hir::Closure { body, .. }) => { let body = cx.tcx.hir().body(body); let closure_expr = peel_blocks(body.value); - let arg_id = body.params[0].pat.hir_id; match closure_expr.kind { hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, receiver, ..) => { if ident.name == method_name && let hir::ExprKind::Path(path) = &receiver.kind && let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id) + && !body.params.is_empty() { + let arg_id = body.params[0].pat.hir_id; return arg_id == *local; } false diff --git a/clippy_lints/src/methods/iter_filter.rs b/clippy_lints/src/methods/iter_filter.rs index ade8e3155fae3..9f84321ced4ae 100644 --- a/clippy_lints/src/methods/iter_filter.rs +++ b/clippy_lints/src/methods/iter_filter.rs @@ -1,87 +1,197 @@ +use clippy_utils::ty::get_iterator_item_ty; +use hir::ExprKind; use rustc_lint::{LateContext, LintContext}; use super::{ITER_FILTER_IS_OK, ITER_FILTER_IS_SOME}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{indent_of, reindent_multiline}; -use clippy_utils::{is_trait_method, peel_blocks, span_contains_comment}; +use clippy_utils::{get_parent_expr, is_trait_method, peel_blocks, span_contains_comment}; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::def::Res; use rustc_hir::QPath; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; use std::borrow::Cow; -fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) -> bool { - match &expr.kind { - hir::ExprKind::Path(QPath::TypeRelative(_, mname)) => mname.ident.name == method_name, - hir::ExprKind::Path(QPath::Resolved(_, segments)) => { - segments.segments.last().unwrap().ident.name == method_name +/// +/// Returns true if the expression is a method call to `method_name` +/// e.g. `a.method_name()` or `Option::method_name`. +/// +/// The type-checker verifies for us that the method accepts the right kind of items +/// (e.g. `Option::is_some` accepts `Option<_>`), so we don't need to check that. +/// +/// How to capture each case: +/// +/// `.filter(|a| { std::option::Option::is_some(a) })` +/// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ <- this is a closure, getting unwrapped and +/// recursively checked. +/// `std::option::Option::is_some(a)` +/// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ <- this is a call. It unwraps to a path with +/// `QPath::TypeRelative`. Since this is a type relative path, we need to check the method name, the +/// type, and that the parameter of the closure is passed in the call. This part is the dual of +/// `receiver.method_name()` below. +/// +/// `filter(std::option::Option::is_some);` +/// ^^^^^^^^^^^^^^^^^^^^^^^^^^^ <- this is a type relative path, like above, we check the +/// type and the method name. +/// +/// `filter(|a| a.is_some());` +/// ^^^^^^^^^^^^^^^ <- this is a method call inside a closure, +/// we check that the parameter of the closure is the receiver of the method call and don't allow +/// any other parameters. +fn is_method( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + type_symbol: Symbol, + method_name: Symbol, + params: &[&hir::Pat<'_>], +) -> bool { + fn pat_is_recv(ident: Ident, param: &hir::Pat<'_>) -> bool { + match param.kind { + hir::PatKind::Binding(_, _, other, _) => ident == other, + hir::PatKind::Ref(pat, _) => pat_is_recv(ident, pat), + _ => false, + } + } + match expr.kind { + hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, recv, ..) => { + // compare the identifier of the receiver to the parameter + // we are in a filter => closure has a single parameter and a single, non-block + // expression, this means that the parameter shadows all outside variables with + // the same name => avoid FPs. If the parameter is not the receiver, then this hits + // outside variables => avoid FP + if ident.name == method_name + && let ExprKind::Path(QPath::Resolved(None, path)) = recv.kind + && let &[seg] = path.segments + && params.iter().any(|p| pat_is_recv(seg.ident, p)) + { + return true; + } + false + }, + // This is used to check for complete paths via `|a| std::option::Option::is_some(a)` + // this then unwraps to a path with `QPath::TypeRelative` + // we pass the params as they've been passed to the current call through the closure + hir::ExprKind::Call(expr, [param]) => { + // this will hit the `QPath::TypeRelative` case and check that the method name is correct + if is_method(cx, expr, type_symbol, method_name, params) + // we then check that this is indeed passing the parameter of the closure + && let ExprKind::Path(QPath::Resolved(None, path)) = param.kind + && let &[seg] = path.segments + && params.iter().any(|p| pat_is_recv(seg.ident, p)) + { + return true; + } + false + }, + hir::ExprKind::Path(QPath::TypeRelative(ty, mname)) => { + let ty = cx.typeck_results().node_type(ty.hir_id); + if let Some(did) = cx.tcx.get_diagnostic_item(type_symbol) + && ty.ty_adt_def() == cx.tcx.type_of(did).skip_binder().ty_adt_def() + { + return mname.ident.name == method_name; + } + false }, - hir::ExprKind::MethodCall(segment, _, _, _) => segment.ident.name == method_name, hir::ExprKind::Closure(&hir::Closure { body, .. }) => { let body = cx.tcx.hir().body(body); let closure_expr = peel_blocks(body.value); - let arg_id = body.params[0].pat.hir_id; - match closure_expr.kind { - hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, receiver, ..) => { - if ident.name == method_name - && let hir::ExprKind::Path(path) = &receiver.kind - && let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id) - { - return arg_id == *local; - } - false - }, - _ => false, - } + let params = body.params.iter().map(|param| param.pat).collect::>(); + is_method(cx, closure_expr, type_symbol, method_name, params.as_slice()) }, _ => false, } } fn parent_is_map(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { - if let hir::Node::Expr(parent_expr) = cx.tcx.hir().get_parent(expr.hir_id) { - is_method(cx, parent_expr, rustc_span::sym::map) - } else { - false + if let Some(expr) = get_parent_expr(cx, expr) + && is_trait_method(cx, expr, sym::Iterator) + && let hir::ExprKind::MethodCall(path, _, _, _) = expr.kind + && path.ident.name == rustc_span::sym::map + { + return true; } + false } -#[allow(clippy::too_many_arguments)] -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_arg: &hir::Expr<'_>, filter_span: Span) { - let is_iterator = is_trait_method(cx, expr, sym::Iterator); - let parent_is_not_map = !parent_is_map(cx, expr); +enum FilterType { + IsSome, + IsOk, +} - if is_iterator - && parent_is_not_map - && is_method(cx, filter_arg, sym!(is_some)) - && !span_contains_comment(cx.sess().source_map(), filter_span.with_hi(expr.span.hi())) +/// Returns the `FilterType` of the expression if it is a filter over an Iter() { LL | extern "C" { LL | static baz: *const A; | ^ use of generic parameter from outer item + | + = note: a `static` is a separate item from the item that contains it error: aborting due to 1 previous error diff --git a/tests/ui/resolve/issue-65035-static-with-parent-generics.stderr b/tests/ui/resolve/issue-65035-static-with-parent-generics.stderr index f1fe1a6002c93..98ffb4567f164 100644 --- a/tests/ui/resolve/issue-65035-static-with-parent-generics.stderr +++ b/tests/ui/resolve/issue-65035-static-with-parent-generics.stderr @@ -6,6 +6,8 @@ LL | fn f() { LL | extern "C" { LL | static a: *const T; | ^ use of generic parameter from outer item + | + = note: a `static` is a separate item from the item that contains it error[E0401]: can't use generic parameters from outer item --> $DIR/issue-65035-static-with-parent-generics.rs:9:22 @@ -14,6 +16,8 @@ LL | fn g() { | - type parameter from outer item LL | static a: *const T = Default::default(); | ^ use of generic parameter from outer item + | + = note: a `static` is a separate item from the item that contains it error[E0401]: can't use generic parameters from outer item --> $DIR/issue-65035-static-with-parent-generics.rs:15:24 @@ -23,6 +27,8 @@ LL | fn h() { LL | extern "C" { LL | static a: [u8; N]; | ^ use of generic parameter from outer item + | + = note: a `static` is a separate item from the item that contains it error[E0401]: can't use generic parameters from outer item --> $DIR/issue-65035-static-with-parent-generics.rs:21:20 @@ -31,6 +37,8 @@ LL | fn i() { | - const parameter from outer item LL | static a: [u8; N] = [0; N]; | ^ use of generic parameter from outer item + | + = note: a `static` is a separate item from the item that contains it error[E0401]: can't use generic parameters from outer item --> $DIR/issue-65035-static-with-parent-generics.rs:21:29 @@ -39,6 +47,8 @@ LL | fn i() { | - const parameter from outer item LL | static a: [u8; N] = [0; N]; | ^ use of generic parameter from outer item + | + = note: a `static` is a separate item from the item that contains it error: aborting due to 5 previous errors From 2cfc81766c37eb0f6696d50f9207876293fa7732 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Sat, 13 Jan 2024 19:24:52 +0000 Subject: [PATCH 0194/1197] Special case 'generic param from outer item' message for `Self` --- compiler/rustc_resolve/messages.ftl | 10 ++++++++-- compiler/rustc_resolve/src/diagnostics.rs | 2 ++ compiler/rustc_resolve/src/errors.rs | 1 + tests/ui/error-codes/E0401.stderr | 4 ++-- tests/ui/resolve/issue-12796.rs | 2 +- tests/ui/resolve/issue-12796.stderr | 4 ++-- tests/ui/resolve/use-self-in-inner-fn.rs | 4 ++-- tests/ui/resolve/use-self-in-inner-fn.stderr | 4 ++-- 8 files changed, 20 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 1947107235b2c..69675b57e31a1 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -114,8 +114,14 @@ resolve_forward_declared_generic_param = .label = defaulted generic parameters cannot be forward declared resolve_generic_params_from_outer_item = - can't use generic parameters from outer item - .label = use of generic parameter from outer item + can't use {$is_self -> + [true] `Self` + *[false] generic parameters + } from outer item + .label = use of {$is_self -> + [true] `Self` + *[false] generic parameter + } from outer item .refer_to_type_directly = refer to the type directly here instead .suggestion = try introducing a local generic parameter here diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 46da5b9d2e46d..da31382112a0b 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -568,12 +568,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { DefKind::Const => Some(errs::GenericParamsFromOuterItemStaticOrConst::Const), _ => None, }; + let is_self = matches!(outer_res, Res::SelfTyParam { .. } | Res::SelfTyAlias { .. }); let mut err = errs::GenericParamsFromOuterItem { span, label: None, refer_to_type_directly: None, sugg: None, static_or_const, + is_self, }; let sm = self.tcx.sess.source_map(); diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index bd00cab66b0aa..da89df84c8ae5 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -46,6 +46,7 @@ pub(crate) struct GenericParamsFromOuterItem { pub(crate) sugg: Option, #[subdiagnostic] pub(crate) static_or_const: Option, + pub(crate) is_self: bool, } #[derive(Subdiagnostic)] diff --git a/tests/ui/error-codes/E0401.stderr b/tests/ui/error-codes/E0401.stderr index d27fade487fe2..754867061c7f8 100644 --- a/tests/ui/error-codes/E0401.stderr +++ b/tests/ui/error-codes/E0401.stderr @@ -20,7 +20,7 @@ LL | fn baz $DIR/E0401.rs:24:25 | LL | impl Iterator for A { @@ -29,7 +29,7 @@ LL | impl Iterator for A { LL | fn helper(sel: &Self) -> u8 { | ^^^^ | | - | use of generic parameter from outer item + | use of `Self` from outer item | refer to the type directly here instead error[E0283]: type annotations needed diff --git a/tests/ui/resolve/issue-12796.rs b/tests/ui/resolve/issue-12796.rs index de3e73437f080..e5dcf9643453b 100644 --- a/tests/ui/resolve/issue-12796.rs +++ b/tests/ui/resolve/issue-12796.rs @@ -1,7 +1,7 @@ trait Trait { fn outer(&self) { fn inner(_: &Self) { - //~^ ERROR can't use generic parameters from outer item + //~^ ERROR can't use `Self` from outer item } } } diff --git a/tests/ui/resolve/issue-12796.stderr b/tests/ui/resolve/issue-12796.stderr index 6809fd50f7475..2305971303a71 100644 --- a/tests/ui/resolve/issue-12796.stderr +++ b/tests/ui/resolve/issue-12796.stderr @@ -1,10 +1,10 @@ -error[E0401]: can't use generic parameters from outer item +error[E0401]: can't use `Self` from outer item --> $DIR/issue-12796.rs:3:22 | LL | fn inner(_: &Self) { | ^^^^ | | - | use of generic parameter from outer item + | use of `Self` from outer item | can't use `Self` here error: aborting due to 1 previous error diff --git a/tests/ui/resolve/use-self-in-inner-fn.rs b/tests/ui/resolve/use-self-in-inner-fn.rs index f4dfa4c40ab24..62f9dc5664ffe 100644 --- a/tests/ui/resolve/use-self-in-inner-fn.rs +++ b/tests/ui/resolve/use-self-in-inner-fn.rs @@ -4,8 +4,8 @@ impl A { //~^ NOTE `Self` type implicitly declared here, by this `impl` fn banana(&mut self) { fn peach(this: &Self) { - //~^ ERROR can't use generic parameters from outer item - //~| NOTE use of generic parameter from outer item + //~^ ERROR can't use `Self` from outer item + //~| NOTE use of `Self` from outer item //~| NOTE refer to the type directly here instead } } diff --git a/tests/ui/resolve/use-self-in-inner-fn.stderr b/tests/ui/resolve/use-self-in-inner-fn.stderr index 165e100bf2f5c..9c388df8bc20c 100644 --- a/tests/ui/resolve/use-self-in-inner-fn.stderr +++ b/tests/ui/resolve/use-self-in-inner-fn.stderr @@ -1,4 +1,4 @@ -error[E0401]: can't use generic parameters from outer item +error[E0401]: can't use `Self` from outer item --> $DIR/use-self-in-inner-fn.rs:6:25 | LL | impl A { @@ -7,7 +7,7 @@ LL | impl A { LL | fn peach(this: &Self) { | ^^^^ | | - | use of generic parameter from outer item + | use of `Self` from outer item | refer to the type directly here instead error: aborting due to 1 previous error From 1bcaf29e0b3574597341c70a25bf263c77658ba0 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 14 Jan 2024 14:13:04 +0100 Subject: [PATCH 0195/1197] Correctly suggest `std` or `core` path depending if this is a `no_std` crate --- .../src/default_instead_of_iter_empty.rs | 16 +++++++++++----- clippy_lints/src/mem_replace.rs | 19 ++++++++++++++----- .../iter_on_single_or_empty_collections.rs | 10 +++------- .../src/methods/unnecessary_sort_by.rs | 4 ++-- clippy_lints/src/operators/ptr_eq.rs | 8 ++++---- .../src/transmute/transmute_int_to_char.rs | 7 +++++-- .../src/transmute/transmute_ref_to_ref.rs | 8 +++++--- 7 files changed, 44 insertions(+), 28 deletions(-) diff --git a/clippy_lints/src/default_instead_of_iter_empty.rs b/clippy_lints/src/default_instead_of_iter_empty.rs index 2472e2ee76f93..7287b3fcec9b7 100644 --- a/clippy_lints/src/default_instead_of_iter_empty.rs +++ b/clippy_lints/src/default_instead_of_iter_empty.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::last_path_segment; use clippy_utils::source::snippet_with_context; +use clippy_utils::{is_no_std_crate, last_path_segment}; use rustc_errors::Applicability; use rustc_hir::{def, Expr, ExprKind, GenericArg, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -42,12 +42,17 @@ impl<'tcx> LateLintPass<'tcx> for DefaultIterEmpty { && ty.span.ctxt() == ctxt { let mut applicability = Applicability::MachineApplicable; - let sugg = make_sugg(cx, ty_path, ctxt, &mut applicability); + let path = if is_no_std_crate(cx) { + "core::iter::empty" + } else { + "std::iter::empty" + }; + let sugg = make_sugg(cx, ty_path, ctxt, &mut applicability, path); span_lint_and_sugg( cx, DEFAULT_INSTEAD_OF_ITER_EMPTY, expr.span, - "`std::iter::empty()` is the more idiomatic way", + &format!("`{path}()` is the more idiomatic way"), "try", sugg, applicability, @@ -61,6 +66,7 @@ fn make_sugg( ty_path: &rustc_hir::QPath<'_>, ctxt: SyntaxContext, applicability: &mut Applicability, + path: &str, ) -> String { if let Some(last) = last_path_segment(ty_path).args && let Some(iter_ty) = last.args.iter().find_map(|arg| match arg { @@ -69,10 +75,10 @@ fn make_sugg( }) { format!( - "std::iter::empty::<{}>()", + "{path}::<{}>()", snippet_with_context(cx, iter_ty.span, ctxt, "..", applicability).0 ) } else { - "std::iter::empty()".to_owned() + format!("{path}()") } } diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index c22f76484d03d..919a959073a7f 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lin use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_non_aggregate_primitive_type; -use clippy_utils::{is_default_equivalent, is_res_lang_ctor, path_res, peel_ref_operators}; +use clippy_utils::{is_default_equivalent, is_no_std_crate, is_res_lang_ctor, path_res, peel_ref_operators}; use rustc_errors::Applicability; use rustc_hir::LangItem::OptionNone; use rustc_hir::{Expr, ExprKind}; @@ -123,6 +123,10 @@ fn check_replace_option_with_none(cx: &LateContext<'_>, dest: &Expr<'_>, expr_sp ); } +fn get_top_crate(cx: &LateContext<'_>) -> &'static str { + if is_no_std_crate(cx) { "core" } else { "std" } +} + fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) { if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(src.hir_id) // check if replacement is mem::MaybeUninit::uninit().assume_init() @@ -136,7 +140,8 @@ fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<' "replacing with `mem::MaybeUninit::uninit().assume_init()`", "consider using", format!( - "std::ptr::read({})", + "{}::ptr::read({})", + get_top_crate(cx), snippet_with_applicability(cx, dest.span, "", &mut applicability) ), applicability, @@ -157,7 +162,8 @@ fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<' "replacing with `mem::uninitialized()`", "consider using", format!( - "std::ptr::read({})", + "{}::ptr::read({})", + get_top_crate(cx), snippet_with_applicability(cx, dest.span, "", &mut applicability) ), applicability, @@ -184,14 +190,17 @@ fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr< return; } if is_default_equivalent(cx, src) && !in_external_macro(cx.tcx.sess, expr_span) { + let top_crate = get_top_crate(cx); span_lint_and_then( cx, MEM_REPLACE_WITH_DEFAULT, expr_span, - "replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`", + &format!( + "replacing a value of type `T` with `T::default()` is better expressed using `{top_crate}::mem::take`" + ), |diag| { if !expr_span.from_expansion() { - let suggestion = format!("std::mem::take({})", snippet(cx, dest.span, "")); + let suggestion = format!("{top_crate}::mem::take({})", snippet(cx, dest.span, "")); diag.span_suggestion( expr_span, diff --git a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs index 70abe4891d985..e1ed272231a38 100644 --- a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs +++ b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs @@ -58,10 +58,10 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: &str, re return; } + let top_crate = if is_no_std_crate(cx) { "core" } else { "std" }; if let Some(i) = item { let sugg = format!( - "{}::iter::once({}{})", - if is_no_std_crate(cx) { "core" } else { "std" }, + "{top_crate}::iter::once({}{})", iter_type.ref_prefix(), snippet(cx, i.span, "...") ); @@ -81,11 +81,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: &str, re expr.span, &format!("`{method_name}` call on an empty collection"), "try", - if is_no_std_crate(cx) { - "core::iter::empty()".to_string() - } else { - "std::iter::empty()".to_string() - }, + format!("{top_crate}::iter::empty()"), Applicability::MaybeIncorrect, ); } diff --git a/clippy_lints/src/methods/unnecessary_sort_by.rs b/clippy_lints/src/methods/unnecessary_sort_by.rs index 4949ccd770e28..a92fe9e55a469 100644 --- a/clippy_lints/src/methods/unnecessary_sort_by.rs +++ b/clippy_lints/src/methods/unnecessary_sort_by.rs @@ -204,7 +204,7 @@ pub(super) fn check<'tcx>( cx, UNNECESSARY_SORT_BY, expr.span, - "use Vec::sort_by_key here instead", + "consider using `sort_by_key`", "try", format!( "{}.sort{}_by_key(|{}| {})", @@ -227,7 +227,7 @@ pub(super) fn check<'tcx>( cx, UNNECESSARY_SORT_BY, expr.span, - "use Vec::sort here instead", + "consider using `sort`", "try", format!( "{}.sort{}()", diff --git a/clippy_lints/src/operators/ptr_eq.rs b/clippy_lints/src/operators/ptr_eq.rs index 9db2e24630aac..31b51193fb159 100644 --- a/clippy_lints/src/operators/ptr_eq.rs +++ b/clippy_lints/src/operators/ptr_eq.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_no_std_crate; use clippy_utils::source::snippet_opt; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; @@ -6,8 +7,6 @@ use rustc_lint::LateContext; use super::PTR_EQ; -static LINT_MSG: &str = "use `std::ptr::eq` when comparing raw pointers"; - pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, @@ -26,13 +25,14 @@ pub(super) fn check<'tcx>( && let Some(left_snip) = snippet_opt(cx, left_var.span) && let Some(right_snip) = snippet_opt(cx, right_var.span) { + let top_crate = if is_no_std_crate(cx) { "core" } else { "std" }; span_lint_and_sugg( cx, PTR_EQ, expr.span, - LINT_MSG, + &format!("use `{top_crate}::ptr::eq` when comparing raw pointers"), "try", - format!("std::ptr::eq({left_snip}, {right_snip})"), + format!("{top_crate}::ptr::eq({left_snip}, {right_snip})"), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/transmute/transmute_int_to_char.rs b/clippy_lints/src/transmute/transmute_int_to_char.rs index 7d31c375f8cf2..71e8a26a566d3 100644 --- a/clippy_lints/src/transmute/transmute_int_to_char.rs +++ b/clippy_lints/src/transmute/transmute_int_to_char.rs @@ -1,6 +1,6 @@ use super::TRANSMUTE_INT_TO_CHAR; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::sugg; +use clippy_utils::{is_no_std_crate, sugg}; use rustc_ast as ast; use rustc_errors::Applicability; use rustc_hir::Expr; @@ -34,7 +34,10 @@ pub(super) fn check<'tcx>( diag.span_suggestion( e.span, "consider using", - format!("std::char::from_u32({arg}).unwrap()"), + format!( + "{}::char::from_u32({arg}).unwrap()", + if is_no_std_crate(cx) { "core" } else { "std" } + ), Applicability::Unspecified, ); }, diff --git a/clippy_lints/src/transmute/transmute_ref_to_ref.rs b/clippy_lints/src/transmute/transmute_ref_to_ref.rs index 98e9ea2d7751f..c923b4b6dd4a9 100644 --- a/clippy_lints/src/transmute/transmute_ref_to_ref.rs +++ b/clippy_lints/src/transmute/transmute_ref_to_ref.rs @@ -1,7 +1,7 @@ use super::{TRANSMUTE_BYTES_TO_STR, TRANSMUTE_PTR_TO_PTR}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet; -use clippy_utils::sugg; +use clippy_utils::{is_no_std_crate, sugg}; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability}; use rustc_lint::LateContext; @@ -29,6 +29,8 @@ pub(super) fn check<'tcx>( let snippet = snippet(cx, arg.span, ".."); + let top_crate = if is_no_std_crate(cx) { "core" } else { "std" }; + span_lint_and_sugg( cx, TRANSMUTE_BYTES_TO_STR, @@ -36,9 +38,9 @@ pub(super) fn check<'tcx>( &format!("transmute from a `{from_ty}` to a `{to_ty}`"), "consider using", if const_context { - format!("std::str::from_utf8_unchecked{postfix}({snippet})") + format!("{top_crate}::str::from_utf8_unchecked{postfix}({snippet})") } else { - format!("std::str::from_utf8{postfix}({snippet}).unwrap()") + format!("{top_crate}::str::from_utf8{postfix}({snippet}).unwrap()") }, Applicability::MaybeIncorrect, ); From 40a45a463f3093df0d2bc1a9bd6457fcf4f26b83 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 14 Jan 2024 14:13:26 +0100 Subject: [PATCH 0196/1197] Update and add ui tests for core/std suggestions --- ...default_instead_of_iter_empty_no_std.fixed | 28 +++++++ .../default_instead_of_iter_empty_no_std.rs | 28 +++++++ ...efault_instead_of_iter_empty_no_std.stderr | 17 ++++ tests/ui/mem_replace_no_std.fixed | 82 +++++++++++++++++++ tests/ui/mem_replace_no_std.rs | 82 +++++++++++++++++++ tests/ui/mem_replace_no_std.stderr | 50 +++++++++++ tests/ui/ptr_eq_no_std.fixed | 49 +++++++++++ tests/ui/ptr_eq_no_std.rs | 49 +++++++++++ tests/ui/ptr_eq_no_std.stderr | 17 ++++ tests/ui/transmute.rs | 13 --- tests/ui/transmute.stderr | 61 ++++++-------- tests/ui/transmute_int_to_char.fixed | 15 ++++ tests/ui/transmute_int_to_char.rs | 15 ++++ tests/ui/transmute_int_to_char.stderr | 17 ++++ tests/ui/transmute_int_to_char_no_std.fixed | 27 ++++++ tests/ui/transmute_int_to_char_no_std.rs | 27 ++++++ tests/ui/transmute_int_to_char_no_std.stderr | 17 ++++ tests/ui/transmute_ref_to_ref.rs | 2 +- tests/ui/transmute_ref_to_ref.stderr | 4 +- tests/ui/transmute_ref_to_ref_no_std.rs | 30 +++++++ tests/ui/transmute_ref_to_ref_no_std.stderr | 26 ++++++ tests/ui/unnecessary_sort_by.stderr | 24 +++--- 22 files changed, 614 insertions(+), 66 deletions(-) create mode 100644 tests/ui/default_instead_of_iter_empty_no_std.fixed create mode 100644 tests/ui/default_instead_of_iter_empty_no_std.rs create mode 100644 tests/ui/default_instead_of_iter_empty_no_std.stderr create mode 100644 tests/ui/mem_replace_no_std.fixed create mode 100644 tests/ui/mem_replace_no_std.rs create mode 100644 tests/ui/mem_replace_no_std.stderr create mode 100644 tests/ui/ptr_eq_no_std.fixed create mode 100644 tests/ui/ptr_eq_no_std.rs create mode 100644 tests/ui/ptr_eq_no_std.stderr create mode 100644 tests/ui/transmute_int_to_char.fixed create mode 100644 tests/ui/transmute_int_to_char.rs create mode 100644 tests/ui/transmute_int_to_char.stderr create mode 100644 tests/ui/transmute_int_to_char_no_std.fixed create mode 100644 tests/ui/transmute_int_to_char_no_std.rs create mode 100644 tests/ui/transmute_int_to_char_no_std.stderr create mode 100644 tests/ui/transmute_ref_to_ref_no_std.rs create mode 100644 tests/ui/transmute_ref_to_ref_no_std.stderr diff --git a/tests/ui/default_instead_of_iter_empty_no_std.fixed b/tests/ui/default_instead_of_iter_empty_no_std.fixed new file mode 100644 index 0000000000000..7300bd9bd2abd --- /dev/null +++ b/tests/ui/default_instead_of_iter_empty_no_std.fixed @@ -0,0 +1,28 @@ +#![warn(clippy::default_instead_of_iter_empty)] +#![allow(dead_code)] +#![feature(lang_items)] +#![no_std] + +use core::panic::PanicInfo; + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + loop {} +} + +#[derive(Default)] +struct Iter { + iter: core::iter::Empty, +} + +fn main() { + // Do lint. + let _ = core::iter::empty::(); + let _foo: core::iter::Empty = core::iter::empty(); + + // Do not lint. + let _ = Iter::default(); +} diff --git a/tests/ui/default_instead_of_iter_empty_no_std.rs b/tests/ui/default_instead_of_iter_empty_no_std.rs new file mode 100644 index 0000000000000..0bc5c7169d129 --- /dev/null +++ b/tests/ui/default_instead_of_iter_empty_no_std.rs @@ -0,0 +1,28 @@ +#![warn(clippy::default_instead_of_iter_empty)] +#![allow(dead_code)] +#![feature(lang_items)] +#![no_std] + +use core::panic::PanicInfo; + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + loop {} +} + +#[derive(Default)] +struct Iter { + iter: core::iter::Empty, +} + +fn main() { + // Do lint. + let _ = core::iter::Empty::::default(); + let _foo: core::iter::Empty = core::iter::Empty::default(); + + // Do not lint. + let _ = Iter::default(); +} diff --git a/tests/ui/default_instead_of_iter_empty_no_std.stderr b/tests/ui/default_instead_of_iter_empty_no_std.stderr new file mode 100644 index 0000000000000..747a31ecbf366 --- /dev/null +++ b/tests/ui/default_instead_of_iter_empty_no_std.stderr @@ -0,0 +1,17 @@ +error: `core::iter::empty()` is the more idiomatic way + --> $DIR/default_instead_of_iter_empty_no_std.rs:23:13 + | +LL | let _ = core::iter::Empty::::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::iter::empty::()` + | + = note: `-D clippy::default-instead-of-iter-empty` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::default_instead_of_iter_empty)]` + +error: `core::iter::empty()` is the more idiomatic way + --> $DIR/default_instead_of_iter_empty_no_std.rs:24:42 + | +LL | let _foo: core::iter::Empty = core::iter::Empty::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::iter::empty()` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/mem_replace_no_std.fixed b/tests/ui/mem_replace_no_std.fixed new file mode 100644 index 0000000000000..c970f2ba2814b --- /dev/null +++ b/tests/ui/mem_replace_no_std.fixed @@ -0,0 +1,82 @@ +#![allow(unused)] +#![warn( + clippy::all, + clippy::style, + clippy::mem_replace_option_with_none, + clippy::mem_replace_with_default +)] +#![feature(lang_items)] +#![no_std] + +use core::mem; +use core::panic::PanicInfo; + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + loop {} +} + +fn replace_option_with_none() { + let mut an_option = Some(1); + let _ = an_option.take(); + let an_option = &mut Some(1); + let _ = an_option.take(); +} + +fn replace_with_default() { + let mut refstr = "hello"; + let _ = core::mem::take(&mut refstr); + + let mut slice: &[i32] = &[1, 2, 3]; + let _ = core::mem::take(&mut slice); +} + +// lint is disabled for primitives because in this case `take` +// has no clear benefit over `replace` and sometimes is harder to read +fn dont_lint_primitive() { + let mut pbool = true; + let _ = mem::replace(&mut pbool, false); + + let mut pint = 5; + let _ = mem::replace(&mut pint, 0); +} + +fn main() { + replace_option_with_none(); + replace_with_default(); + dont_lint_primitive(); +} + +fn issue9824() { + struct Foo<'a>(Option<&'a str>); + impl<'a> core::ops::Deref for Foo<'a> { + type Target = Option<&'a str>; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl<'a> core::ops::DerefMut for Foo<'a> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + + struct Bar { + opt: Option, + val: u8, + } + + let mut f = Foo(Some("foo")); + let mut b = Bar { opt: Some(1), val: 12 }; + + // replace option with none + let _ = f.0.take(); + let _ = (*f).take(); + let _ = b.opt.take(); + // replace with default + let _ = mem::replace(&mut b.val, u8::default()); +} diff --git a/tests/ui/mem_replace_no_std.rs b/tests/ui/mem_replace_no_std.rs new file mode 100644 index 0000000000000..673d5c7b4f45a --- /dev/null +++ b/tests/ui/mem_replace_no_std.rs @@ -0,0 +1,82 @@ +#![allow(unused)] +#![warn( + clippy::all, + clippy::style, + clippy::mem_replace_option_with_none, + clippy::mem_replace_with_default +)] +#![feature(lang_items)] +#![no_std] + +use core::mem; +use core::panic::PanicInfo; + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + loop {} +} + +fn replace_option_with_none() { + let mut an_option = Some(1); + let _ = mem::replace(&mut an_option, None); + let an_option = &mut Some(1); + let _ = mem::replace(an_option, None); +} + +fn replace_with_default() { + let mut refstr = "hello"; + let _ = mem::replace(&mut refstr, ""); + + let mut slice: &[i32] = &[1, 2, 3]; + let _ = mem::replace(&mut slice, &[]); +} + +// lint is disabled for primitives because in this case `take` +// has no clear benefit over `replace` and sometimes is harder to read +fn dont_lint_primitive() { + let mut pbool = true; + let _ = mem::replace(&mut pbool, false); + + let mut pint = 5; + let _ = mem::replace(&mut pint, 0); +} + +fn main() { + replace_option_with_none(); + replace_with_default(); + dont_lint_primitive(); +} + +fn issue9824() { + struct Foo<'a>(Option<&'a str>); + impl<'a> core::ops::Deref for Foo<'a> { + type Target = Option<&'a str>; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl<'a> core::ops::DerefMut for Foo<'a> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + + struct Bar { + opt: Option, + val: u8, + } + + let mut f = Foo(Some("foo")); + let mut b = Bar { opt: Some(1), val: 12 }; + + // replace option with none + let _ = mem::replace(&mut f.0, None); + let _ = mem::replace(&mut *f, None); + let _ = mem::replace(&mut b.opt, None); + // replace with default + let _ = mem::replace(&mut b.val, u8::default()); +} diff --git a/tests/ui/mem_replace_no_std.stderr b/tests/ui/mem_replace_no_std.stderr new file mode 100644 index 0000000000000..744fb5a15876e --- /dev/null +++ b/tests/ui/mem_replace_no_std.stderr @@ -0,0 +1,50 @@ +error: replacing an `Option` with `None` + --> $DIR/mem_replace_no_std.rs:24:13 + | +LL | let _ = mem::replace(&mut an_option, None); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()` + | + = note: `-D clippy::mem-replace-option-with-none` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::mem_replace_option_with_none)]` + +error: replacing an `Option` with `None` + --> $DIR/mem_replace_no_std.rs:26:13 + | +LL | let _ = mem::replace(an_option, None); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()` + +error: replacing a value of type `T` with `T::default()` is better expressed using `core::mem::take` + --> $DIR/mem_replace_no_std.rs:31:13 + | +LL | let _ = mem::replace(&mut refstr, ""); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `core::mem::take(&mut refstr)` + | + = note: `-D clippy::mem-replace-with-default` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::mem_replace_with_default)]` + +error: replacing a value of type `T` with `T::default()` is better expressed using `core::mem::take` + --> $DIR/mem_replace_no_std.rs:34:13 + | +LL | let _ = mem::replace(&mut slice, &[]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `core::mem::take(&mut slice)` + +error: replacing an `Option` with `None` + --> $DIR/mem_replace_no_std.rs:77:13 + | +LL | let _ = mem::replace(&mut f.0, None); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `f.0.take()` + +error: replacing an `Option` with `None` + --> $DIR/mem_replace_no_std.rs:78:13 + | +LL | let _ = mem::replace(&mut *f, None); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `(*f).take()` + +error: replacing an `Option` with `None` + --> $DIR/mem_replace_no_std.rs:79:13 + | +LL | let _ = mem::replace(&mut b.opt, None); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `b.opt.take()` + +error: aborting due to 7 previous errors + diff --git a/tests/ui/ptr_eq_no_std.fixed b/tests/ui/ptr_eq_no_std.fixed new file mode 100644 index 0000000000000..97c8c394c03d4 --- /dev/null +++ b/tests/ui/ptr_eq_no_std.fixed @@ -0,0 +1,49 @@ +#![warn(clippy::ptr_eq)] +#![no_std] +#![feature(lang_items)] + +use core::panic::PanicInfo; + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + loop {} +} + +macro_rules! mac { + ($a:expr, $b:expr) => { + $a as *const _ as usize == $b as *const _ as usize + }; +} + +macro_rules! another_mac { + ($a:expr, $b:expr) => { + $a as *const _ == $b as *const _ + }; +} + +fn main() { + let a = &[1, 2, 3]; + let b = &[1, 2, 3]; + + let _ = core::ptr::eq(a, b); + let _ = core::ptr::eq(a, b); + let _ = a.as_ptr() == b as *const _; + let _ = a.as_ptr() == b.as_ptr(); + + // Do not lint + + let _ = mac!(a, b); + let _ = another_mac!(a, b); + + let a = &mut [1, 2, 3]; + let b = &mut [1, 2, 3]; + + let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _; + let _ = a.as_mut_ptr() == b.as_mut_ptr(); + + let _ = a == b; + let _ = core::ptr::eq(a, b); +} diff --git a/tests/ui/ptr_eq_no_std.rs b/tests/ui/ptr_eq_no_std.rs new file mode 100644 index 0000000000000..a7ba9b4d81746 --- /dev/null +++ b/tests/ui/ptr_eq_no_std.rs @@ -0,0 +1,49 @@ +#![warn(clippy::ptr_eq)] +#![no_std] +#![feature(lang_items)] + +use core::panic::PanicInfo; + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + loop {} +} + +macro_rules! mac { + ($a:expr, $b:expr) => { + $a as *const _ as usize == $b as *const _ as usize + }; +} + +macro_rules! another_mac { + ($a:expr, $b:expr) => { + $a as *const _ == $b as *const _ + }; +} + +fn main() { + let a = &[1, 2, 3]; + let b = &[1, 2, 3]; + + let _ = a as *const _ as usize == b as *const _ as usize; + let _ = a as *const _ == b as *const _; + let _ = a.as_ptr() == b as *const _; + let _ = a.as_ptr() == b.as_ptr(); + + // Do not lint + + let _ = mac!(a, b); + let _ = another_mac!(a, b); + + let a = &mut [1, 2, 3]; + let b = &mut [1, 2, 3]; + + let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _; + let _ = a.as_mut_ptr() == b.as_mut_ptr(); + + let _ = a == b; + let _ = core::ptr::eq(a, b); +} diff --git a/tests/ui/ptr_eq_no_std.stderr b/tests/ui/ptr_eq_no_std.stderr new file mode 100644 index 0000000000000..3e289f5be613e --- /dev/null +++ b/tests/ui/ptr_eq_no_std.stderr @@ -0,0 +1,17 @@ +error: use `core::ptr::eq` when comparing raw pointers + --> $DIR/ptr_eq_no_std.rs:31:13 + | +LL | let _ = a as *const _ as usize == b as *const _ as usize; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a, b)` + | + = note: `-D clippy::ptr-eq` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::ptr_eq)]` + +error: use `core::ptr::eq` when comparing raw pointers + --> $DIR/ptr_eq_no_std.rs:32:13 + | +LL | let _ = a as *const _ == b as *const _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a, b)` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/transmute.rs b/tests/ui/transmute.rs index 32f6027e99111..1796ccaf28e1a 100644 --- a/tests/ui/transmute.rs +++ b/tests/ui/transmute.rs @@ -102,19 +102,6 @@ fn crosspointer() { } } -#[warn(clippy::transmute_int_to_char)] -fn int_to_char() { - let _: char = unsafe { std::mem::transmute(0_u32) }; - //~^ ERROR: transmute from a `u32` to a `char` - //~| NOTE: `-D clippy::transmute-int-to-char` implied by `-D warnings` - let _: char = unsafe { std::mem::transmute(0_i32) }; - //~^ ERROR: transmute from a `i32` to a `char` - - // These shouldn't warn - const _: char = unsafe { std::mem::transmute(0_u32) }; - const _: char = unsafe { std::mem::transmute(0_i32) }; -} - #[warn(clippy::transmute_int_to_bool)] fn int_to_bool() { let _: bool = unsafe { std::mem::transmute(0_u8) }; diff --git a/tests/ui/transmute.stderr b/tests/ui/transmute.stderr index cdc733b54a9b2..df32d478cbf40 100644 --- a/tests/ui/transmute.stderr +++ b/tests/ui/transmute.stderr @@ -88,23 +88,8 @@ error: transmute from a type (`Usize`) to a pointer to that type (`*mut Usize`) LL | let _: *mut Usize = core::intrinsics::transmute(my_int()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: transmute from a `u32` to a `char` - --> $DIR/transmute.rs:107:28 - | -LL | let _: char = unsafe { std::mem::transmute(0_u32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_u32).unwrap()` - | - = note: `-D clippy::transmute-int-to-char` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_char)]` - -error: transmute from a `i32` to a `char` - --> $DIR/transmute.rs:110:28 - | -LL | let _: char = unsafe { std::mem::transmute(0_i32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_i32 as u32).unwrap()` - error: transmute from a `u8` to a `bool` - --> $DIR/transmute.rs:120:28 + --> $DIR/transmute.rs:107:28 | LL | let _: bool = unsafe { std::mem::transmute(0_u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `0_u8 != 0` @@ -113,7 +98,7 @@ LL | let _: bool = unsafe { std::mem::transmute(0_u8) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_bool)]` error: transmute from a `u32` to a `f32` - --> $DIR/transmute.rs:128:31 + --> $DIR/transmute.rs:115:31 | LL | let _: f32 = unsafe { std::mem::transmute(0_u32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)` @@ -122,25 +107,25 @@ LL | let _: f32 = unsafe { std::mem::transmute(0_u32) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_float)]` error: transmute from a `i32` to a `f32` - --> $DIR/transmute.rs:131:31 + --> $DIR/transmute.rs:118:31 | LL | let _: f32 = unsafe { std::mem::transmute(0_i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_i32 as u32)` error: transmute from a `u64` to a `f64` - --> $DIR/transmute.rs:133:31 + --> $DIR/transmute.rs:120:31 | LL | let _: f64 = unsafe { std::mem::transmute(0_u64) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_u64)` error: transmute from a `i64` to a `f64` - --> $DIR/transmute.rs:135:31 + --> $DIR/transmute.rs:122:31 | LL | let _: f64 = unsafe { std::mem::transmute(0_i64) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)` error: transmute from a `u8` to a `[u8; 1]` - --> $DIR/transmute.rs:156:30 + --> $DIR/transmute.rs:143:30 | LL | let _: [u8; 1] = std::mem::transmute(0u8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()` @@ -149,85 +134,85 @@ LL | let _: [u8; 1] = std::mem::transmute(0u8); = help: to override `-D warnings` add `#[allow(clippy::transmute_num_to_bytes)]` error: transmute from a `u32` to a `[u8; 4]` - --> $DIR/transmute.rs:159:30 + --> $DIR/transmute.rs:146:30 | LL | let _: [u8; 4] = std::mem::transmute(0u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()` error: transmute from a `u128` to a `[u8; 16]` - --> $DIR/transmute.rs:161:31 + --> $DIR/transmute.rs:148:31 | LL | let _: [u8; 16] = std::mem::transmute(0u128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()` error: transmute from a `i8` to a `[u8; 1]` - --> $DIR/transmute.rs:163:30 + --> $DIR/transmute.rs:150:30 | LL | let _: [u8; 1] = std::mem::transmute(0i8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()` error: transmute from a `i32` to a `[u8; 4]` - --> $DIR/transmute.rs:165:30 + --> $DIR/transmute.rs:152:30 | LL | let _: [u8; 4] = std::mem::transmute(0i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()` error: transmute from a `i128` to a `[u8; 16]` - --> $DIR/transmute.rs:167:31 + --> $DIR/transmute.rs:154:31 | LL | let _: [u8; 16] = std::mem::transmute(0i128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()` error: transmute from a `f32` to a `[u8; 4]` - --> $DIR/transmute.rs:169:30 + --> $DIR/transmute.rs:156:30 | LL | let _: [u8; 4] = std::mem::transmute(0.0f32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()` error: transmute from a `f64` to a `[u8; 8]` - --> $DIR/transmute.rs:171:30 + --> $DIR/transmute.rs:158:30 | LL | let _: [u8; 8] = std::mem::transmute(0.0f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()` error: transmute from a `u8` to a `[u8; 1]` - --> $DIR/transmute.rs:177:30 + --> $DIR/transmute.rs:164:30 | LL | let _: [u8; 1] = std::mem::transmute(0u8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()` error: transmute from a `u32` to a `[u8; 4]` - --> $DIR/transmute.rs:179:30 + --> $DIR/transmute.rs:166:30 | LL | let _: [u8; 4] = std::mem::transmute(0u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()` error: transmute from a `u128` to a `[u8; 16]` - --> $DIR/transmute.rs:181:31 + --> $DIR/transmute.rs:168:31 | LL | let _: [u8; 16] = std::mem::transmute(0u128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()` error: transmute from a `i8` to a `[u8; 1]` - --> $DIR/transmute.rs:183:30 + --> $DIR/transmute.rs:170:30 | LL | let _: [u8; 1] = std::mem::transmute(0i8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()` error: transmute from a `i32` to a `[u8; 4]` - --> $DIR/transmute.rs:185:30 + --> $DIR/transmute.rs:172:30 | LL | let _: [u8; 4] = std::mem::transmute(0i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()` error: transmute from a `i128` to a `[u8; 16]` - --> $DIR/transmute.rs:187:31 + --> $DIR/transmute.rs:174:31 | LL | let _: [u8; 16] = std::mem::transmute(0i128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()` error: transmute from a `&[u8]` to a `&str` - --> $DIR/transmute.rs:198:28 + --> $DIR/transmute.rs:185:28 | LL | let _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(B).unwrap()` @@ -236,16 +221,16 @@ LL | let _: &str = unsafe { std::mem::transmute(B) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_bytes_to_str)]` error: transmute from a `&mut [u8]` to a `&mut str` - --> $DIR/transmute.rs:201:32 + --> $DIR/transmute.rs:188:32 | LL | let _: &mut str = unsafe { std::mem::transmute(mb) }; | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()` error: transmute from a `&[u8]` to a `&str` - --> $DIR/transmute.rs:203:30 + --> $DIR/transmute.rs:190:30 | LL | const _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_unchecked(B)` -error: aborting due to 38 previous errors +error: aborting due to 36 previous errors diff --git a/tests/ui/transmute_int_to_char.fixed b/tests/ui/transmute_int_to_char.fixed new file mode 100644 index 0000000000000..1708011817541 --- /dev/null +++ b/tests/ui/transmute_int_to_char.fixed @@ -0,0 +1,15 @@ +#![warn(clippy::transmute_int_to_char)] + +fn int_to_char() { + let _: char = unsafe { std::char::from_u32(0_u32).unwrap() }; + //~^ ERROR: transmute from a `u32` to a `char` + //~| NOTE: `-D clippy::transmute-int-to-char` implied by `-D warnings` + let _: char = unsafe { std::char::from_u32(0_i32 as u32).unwrap() }; + //~^ ERROR: transmute from a `i32` to a `char` + + // These shouldn't warn + const _: char = unsafe { std::mem::transmute(0_u32) }; + const _: char = unsafe { std::mem::transmute(0_i32) }; +} + +fn main() {} diff --git a/tests/ui/transmute_int_to_char.rs b/tests/ui/transmute_int_to_char.rs new file mode 100644 index 0000000000000..5846a97e88abf --- /dev/null +++ b/tests/ui/transmute_int_to_char.rs @@ -0,0 +1,15 @@ +#![warn(clippy::transmute_int_to_char)] + +fn int_to_char() { + let _: char = unsafe { std::mem::transmute(0_u32) }; + //~^ ERROR: transmute from a `u32` to a `char` + //~| NOTE: `-D clippy::transmute-int-to-char` implied by `-D warnings` + let _: char = unsafe { std::mem::transmute(0_i32) }; + //~^ ERROR: transmute from a `i32` to a `char` + + // These shouldn't warn + const _: char = unsafe { std::mem::transmute(0_u32) }; + const _: char = unsafe { std::mem::transmute(0_i32) }; +} + +fn main() {} diff --git a/tests/ui/transmute_int_to_char.stderr b/tests/ui/transmute_int_to_char.stderr new file mode 100644 index 0000000000000..2297f5b4f8bf2 --- /dev/null +++ b/tests/ui/transmute_int_to_char.stderr @@ -0,0 +1,17 @@ +error: transmute from a `u32` to a `char` + --> $DIR/transmute_int_to_char.rs:4:28 + | +LL | let _: char = unsafe { std::mem::transmute(0_u32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_u32).unwrap()` + | + = note: `-D clippy::transmute-int-to-char` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_char)]` + +error: transmute from a `i32` to a `char` + --> $DIR/transmute_int_to_char.rs:7:28 + | +LL | let _: char = unsafe { std::mem::transmute(0_i32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_i32 as u32).unwrap()` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/transmute_int_to_char_no_std.fixed b/tests/ui/transmute_int_to_char_no_std.fixed new file mode 100644 index 0000000000000..9ae4e11fb56e7 --- /dev/null +++ b/tests/ui/transmute_int_to_char_no_std.fixed @@ -0,0 +1,27 @@ +#![no_std] +#![feature(lang_items)] +#![warn(clippy::transmute_int_to_char)] + +use core::panic::PanicInfo; + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + loop {} +} + +fn int_to_char() { + let _: char = unsafe { core::char::from_u32(0_u32).unwrap() }; + //~^ ERROR: transmute from a `u32` to a `char` + //~| NOTE: `-D clippy::transmute-int-to-char` implied by `-D warnings` + let _: char = unsafe { core::char::from_u32(0_i32 as u32).unwrap() }; + //~^ ERROR: transmute from a `i32` to a `char` + + // These shouldn't warn + const _: char = unsafe { core::mem::transmute(0_u32) }; + const _: char = unsafe { core::mem::transmute(0_i32) }; +} + +fn main() {} diff --git a/tests/ui/transmute_int_to_char_no_std.rs b/tests/ui/transmute_int_to_char_no_std.rs new file mode 100644 index 0000000000000..9a2afd5bd2fd6 --- /dev/null +++ b/tests/ui/transmute_int_to_char_no_std.rs @@ -0,0 +1,27 @@ +#![no_std] +#![feature(lang_items)] +#![warn(clippy::transmute_int_to_char)] + +use core::panic::PanicInfo; + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + loop {} +} + +fn int_to_char() { + let _: char = unsafe { core::mem::transmute(0_u32) }; + //~^ ERROR: transmute from a `u32` to a `char` + //~| NOTE: `-D clippy::transmute-int-to-char` implied by `-D warnings` + let _: char = unsafe { core::mem::transmute(0_i32) }; + //~^ ERROR: transmute from a `i32` to a `char` + + // These shouldn't warn + const _: char = unsafe { core::mem::transmute(0_u32) }; + const _: char = unsafe { core::mem::transmute(0_i32) }; +} + +fn main() {} diff --git a/tests/ui/transmute_int_to_char_no_std.stderr b/tests/ui/transmute_int_to_char_no_std.stderr new file mode 100644 index 0000000000000..aace6968696da --- /dev/null +++ b/tests/ui/transmute_int_to_char_no_std.stderr @@ -0,0 +1,17 @@ +error: transmute from a `u32` to a `char` + --> $DIR/transmute_int_to_char_no_std.rs:16:28 + | +LL | let _: char = unsafe { core::mem::transmute(0_u32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `core::char::from_u32(0_u32).unwrap()` + | + = note: `-D clippy::transmute-int-to-char` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_char)]` + +error: transmute from a `i32` to a `char` + --> $DIR/transmute_int_to_char_no_std.rs:19:28 + | +LL | let _: char = unsafe { core::mem::transmute(0_i32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `core::char::from_u32(0_i32 as u32).unwrap()` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/transmute_ref_to_ref.rs b/tests/ui/transmute_ref_to_ref.rs index e7f35c5743684..bdc7b9f647877 100644 --- a/tests/ui/transmute_ref_to_ref.rs +++ b/tests/ui/transmute_ref_to_ref.rs @@ -12,7 +12,7 @@ fn main() { let b: &[u8] = unsafe { std::mem::transmute(a) }; //~^ ERROR: transmute from a reference to a reference let bytes = &[1u8, 2u8, 3u8, 4u8] as &[u8]; - let alt_slice: &[u32] = unsafe { core::mem::transmute(bytes) }; + let alt_slice: &[u32] = unsafe { std::mem::transmute(bytes) }; //~^ ERROR: transmute from a reference to a reference } } diff --git a/tests/ui/transmute_ref_to_ref.stderr b/tests/ui/transmute_ref_to_ref.stderr index cc6b156b18885..4238bc637ad04 100644 --- a/tests/ui/transmute_ref_to_ref.stderr +++ b/tests/ui/transmute_ref_to_ref.stderr @@ -19,8 +19,8 @@ LL | let b: &[u8] = unsafe { std::mem::transmute(a) }; error: transmute from a reference to a reference --> $DIR/transmute_ref_to_ref.rs:15:42 | -LL | let alt_slice: &[u32] = unsafe { core::mem::transmute(bytes) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(bytes as *const [u8] as *const [u32])` +LL | let alt_slice: &[u32] = unsafe { std::mem::transmute(bytes) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(bytes as *const [u8] as *const [u32])` error: aborting due to 3 previous errors diff --git a/tests/ui/transmute_ref_to_ref_no_std.rs b/tests/ui/transmute_ref_to_ref_no_std.rs new file mode 100644 index 0000000000000..b67386f858852 --- /dev/null +++ b/tests/ui/transmute_ref_to_ref_no_std.rs @@ -0,0 +1,30 @@ +//@no-rustfix + +#![deny(clippy::transmute_ptr_to_ptr)] +#![allow(dead_code)] +#![feature(lang_items)] +#![no_std] + +use core::panic::PanicInfo; + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + loop {} +} + +fn main() { + unsafe { + let single_u64: &[u64] = &[0xDEAD_BEEF_DEAD_BEEF]; + let bools: &[bool] = unsafe { core::mem::transmute(single_u64) }; + //~^ ERROR: transmute from a reference to a reference + let a: &[u32] = &[0x12345678, 0x90ABCDEF, 0xFEDCBA09, 0x87654321]; + let b: &[u8] = unsafe { core::mem::transmute(a) }; + //~^ ERROR: transmute from a reference to a reference + let bytes = &[1u8, 2u8, 3u8, 4u8] as &[u8]; + let alt_slice: &[u32] = unsafe { core::mem::transmute(bytes) }; + //~^ ERROR: transmute from a reference to a reference + } +} diff --git a/tests/ui/transmute_ref_to_ref_no_std.stderr b/tests/ui/transmute_ref_to_ref_no_std.stderr new file mode 100644 index 0000000000000..ca7966ffa9e88 --- /dev/null +++ b/tests/ui/transmute_ref_to_ref_no_std.stderr @@ -0,0 +1,26 @@ +error: transmute from a reference to a reference + --> $DIR/transmute_ref_to_ref_no_std.rs:21:39 + | +LL | let bools: &[bool] = unsafe { core::mem::transmute(single_u64) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(single_u64 as *const [u64] as *const [bool])` + | +note: the lint level is defined here + --> $DIR/transmute_ref_to_ref_no_std.rs:3:9 + | +LL | #![deny(clippy::transmute_ptr_to_ptr)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: transmute from a reference to a reference + --> $DIR/transmute_ref_to_ref_no_std.rs:24:33 + | +LL | let b: &[u8] = unsafe { core::mem::transmute(a) }; + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a as *const [u32] as *const [u8])` + +error: transmute from a reference to a reference + --> $DIR/transmute_ref_to_ref_no_std.rs:27:42 + | +LL | let alt_slice: &[u32] = unsafe { core::mem::transmute(bytes) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(bytes as *const [u8] as *const [u32])` + +error: aborting due to 3 previous errors + diff --git a/tests/ui/unnecessary_sort_by.stderr b/tests/ui/unnecessary_sort_by.stderr index 9d54c8d50e31f..f4409113a45fa 100644 --- a/tests/ui/unnecessary_sort_by.stderr +++ b/tests/ui/unnecessary_sort_by.stderr @@ -1,4 +1,4 @@ -error: use Vec::sort here instead +error: consider using `sort` --> $DIR/unnecessary_sort_by.rs:12:5 | LL | vec.sort_by(|a, b| a.cmp(b)); @@ -7,67 +7,67 @@ LL | vec.sort_by(|a, b| a.cmp(b)); = note: `-D clippy::unnecessary-sort-by` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unnecessary_sort_by)]` -error: use Vec::sort here instead +error: consider using `sort` --> $DIR/unnecessary_sort_by.rs:13:5 | LL | vec.sort_unstable_by(|a, b| a.cmp(b)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable()` -error: use Vec::sort_by_key here instead +error: consider using `sort_by_key` --> $DIR/unnecessary_sort_by.rs:14:5 | LL | vec.sort_by(|a, b| (a + 5).abs().cmp(&(b + 5).abs())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|a| (a + 5).abs())` -error: use Vec::sort_by_key here instead +error: consider using `sort_by_key` --> $DIR/unnecessary_sort_by.rs:15:5 | LL | vec.sort_unstable_by(|a, b| id(-a).cmp(&id(-b))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|a| id(-a))` -error: use Vec::sort_by_key here instead +error: consider using `sort_by_key` --> $DIR/unnecessary_sort_by.rs:18:5 | LL | vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|b| std::cmp::Reverse((b + 5).abs()))` -error: use Vec::sort_by_key here instead +error: consider using `sort_by_key` --> $DIR/unnecessary_sort_by.rs:19:5 | LL | vec.sort_unstable_by(|a, b| id(-b).cmp(&id(-a))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|b| std::cmp::Reverse(id(-b)))` -error: use Vec::sort_by_key here instead +error: consider using `sort_by_key` --> $DIR/unnecessary_sort_by.rs:29:5 | LL | vec.sort_by(|a, b| (***a).abs().cmp(&(***b).abs())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|a| (***a).abs())` -error: use Vec::sort_by_key here instead +error: consider using `sort_by_key` --> $DIR/unnecessary_sort_by.rs:30:5 | LL | vec.sort_unstable_by(|a, b| (***a).abs().cmp(&(***b).abs())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|a| (***a).abs())` -error: use Vec::sort_by_key here instead +error: consider using `sort_by_key` --> $DIR/unnecessary_sort_by.rs:89:9 | LL | args.sort_by(|a, b| a.name().cmp(&b.name())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_by_key(|a| a.name())` -error: use Vec::sort_by_key here instead +error: consider using `sort_by_key` --> $DIR/unnecessary_sort_by.rs:90:9 | LL | args.sort_unstable_by(|a, b| a.name().cmp(&b.name())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_unstable_by_key(|a| a.name())` -error: use Vec::sort_by_key here instead +error: consider using `sort_by_key` --> $DIR/unnecessary_sort_by.rs:92:9 | LL | args.sort_by(|a, b| b.name().cmp(&a.name())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_by_key(|b| std::cmp::Reverse(b.name()))` -error: use Vec::sort_by_key here instead +error: consider using `sort_by_key` --> $DIR/unnecessary_sort_by.rs:93:9 | LL | args.sort_unstable_by(|a, b| b.name().cmp(&a.name())); From 5d06fbb46d2434c50d3c50695e4a0f0bb187fdb5 Mon Sep 17 00:00:00 2001 From: Kristof Mattei <864376+Kristof-Mattei@users.noreply.github.com> Date: Sun, 14 Jan 2024 09:25:31 -0700 Subject: [PATCH 0197/1197] fix: don't allocate new string when not needed --- clippy_lints/src/cargo/multiple_crate_versions.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/cargo/multiple_crate_versions.rs b/clippy_lints/src/cargo/multiple_crate_versions.rs index a28934266cbc1..8e86c0017e1d5 100644 --- a/clippy_lints/src/cargo/multiple_crate_versions.rs +++ b/clippy_lints/src/cargo/multiple_crate_versions.rs @@ -16,7 +16,12 @@ pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata) { if let Some(resolve) = &metadata.resolve && let Some(local_id) = packages.iter().find_map(|p| { - if p.name.replace('-', "_") == local_name.as_str() { + if p.name + .chars() + .into_iter() + .map(|c| if c == '-' { '_' } else { c }) + .eq(local_name.as_str().chars()) + { Some(&p.id) } else { None From b1c52d502d6c0441c944225287281c70282c1c9b Mon Sep 17 00:00:00 2001 From: Kristof Mattei <864376+Kristof-Mattei@users.noreply.github.com> Date: Sun, 14 Jan 2024 09:32:36 -0700 Subject: [PATCH 0198/1197] chore: add comments to explain reasoning --- clippy_lints/src/cargo/multiple_crate_versions.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/clippy_lints/src/cargo/multiple_crate_versions.rs b/clippy_lints/src/cargo/multiple_crate_versions.rs index 8e86c0017e1d5..c487ffb1c8224 100644 --- a/clippy_lints/src/cargo/multiple_crate_versions.rs +++ b/clippy_lints/src/cargo/multiple_crate_versions.rs @@ -16,6 +16,9 @@ pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata) { if let Some(resolve) = &metadata.resolve && let Some(local_id) = packages.iter().find_map(|p| { + // p.name contains the original crate names with dashes intact + // local_name contains the crate name as a namespace, with the dashes converted to underscores + // the code below temporarily rectifies this discrepancy if p.name .chars() .into_iter() From ea585ef321b6ba63635984772fe576e6a4e461fc Mon Sep 17 00:00:00 2001 From: Kristof Mattei <864376+Kristof-Mattei@users.noreply.github.com> Date: Sun, 14 Jan 2024 09:40:14 -0700 Subject: [PATCH 0199/1197] chore: remove unneeded into_iter --- clippy_lints/src/cargo/multiple_crate_versions.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/clippy_lints/src/cargo/multiple_crate_versions.rs b/clippy_lints/src/cargo/multiple_crate_versions.rs index c487ffb1c8224..6b4af6753c3e8 100644 --- a/clippy_lints/src/cargo/multiple_crate_versions.rs +++ b/clippy_lints/src/cargo/multiple_crate_versions.rs @@ -21,7 +21,6 @@ pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata) { // the code below temporarily rectifies this discrepancy if p.name .chars() - .into_iter() .map(|c| if c == '-' { '_' } else { c }) .eq(local_name.as_str().chars()) { From d4b43d5a516009c67b8abcca3a399d554f4ba8aa Mon Sep 17 00:00:00 2001 From: davidsemakula Date: Sun, 14 Jan 2024 19:49:50 +0300 Subject: [PATCH 0200/1197] improve ordered use tree merging implementation --- crates/ide-db/src/imports/merge_imports.rs | 117 +++++++++------------ 1 file changed, 50 insertions(+), 67 deletions(-) diff --git a/crates/ide-db/src/imports/merge_imports.rs b/crates/ide-db/src/imports/merge_imports.rs index 4e56ef5b4d2bd..52c94678ade77 100644 --- a/crates/ide-db/src/imports/merge_imports.rs +++ b/crates/ide-db/src/imports/merge_imports.rs @@ -1,14 +1,14 @@ //! Handle syntactic aspects of merging UseTrees. use std::cmp::Ordering; -use std::iter::{empty, successors}; +use std::iter::empty; use itertools::{EitherOrBoth, Itertools}; -use parser::{SyntaxKind, T}; -use rustc_hash::{FxHashMap, FxHashSet}; +use parser::T; use syntax::{ + algo, ast::{self, make, AstNode, HasAttrs, HasName, HasVisibility, PathSegmentKind}, ted::{self, Position}, - SyntaxElement, TokenText, + Direction, TokenText, }; use crate::syntax_helpers::node_ext::vis_eq; @@ -101,22 +101,6 @@ fn recursive_merge(lhs: &ast::UseTree, rhs: &ast::UseTree, merge: MergeBehavior) // same as a `filter` op). .map(|tree| merge.is_tree_allowed(&tree).then_some(tree)) .collect::>()?; - // Preserves some positional formatting info before sorting. - let positional_formatting_map: FxHashMap<_, _> = use_trees - .iter() - .enumerate() - .filter_map(|(idx, tree)| { - formatting_whitespace(&SyntaxElement::from(tree.syntax().clone())) - .map(|trivia| (idx, trivia)) - }) - .collect(); - let closing_formatting_trivia = if use_trees.len() > 0 { - lhs.use_tree_list() - .and_then(|list| list.r_curly_token()) - .and_then(|token| formatting_whitespace(&SyntaxElement::from(token))) - } else { - None - }; // Sorts the use trees similar to rustfmt's algorithm for ordering imports // (see `use_tree_cmp` doc). use_trees.sort_unstable_by(|a, b| use_tree_cmp(a, b)); @@ -184,60 +168,59 @@ fn recursive_merge(lhs: &ast::UseTree, rhs: &ast::UseTree, merge: MergeBehavior) // Creates a new use tree list with the item. None => lhs.get_or_create_use_tree_list().add_use_tree(rhs_t), // Recreates the use tree list with sorted items (see `use_tree_cmp` doc). - // Also attempts to preserve formatting (but only in terms of index-based - // "positions" of new lines and indents). - Some(old_list) => { - ted::remove(old_list.syntax()); + Some(use_tree_list) => { + if use_tree_list.l_curly_token().is_none() { + ted::insert_raw( + Position::first_child_of(use_tree_list.syntax()), + make::token(T!['{']), + ); + } + if use_tree_list.r_curly_token().is_none() { + ted::insert_raw( + Position::last_child_of(use_tree_list.syntax()), + make::token(T!['}']), + ); + } - let new_list = make::use_tree_list(empty()).clone_for_update(); let mut elements = Vec::new(); for (idx, tree) in use_trees.iter().enumerate() { if idx > 0 { elements.push(make::token(T![,]).into()); - } - match positional_formatting_map.get(&idx) { - None if idx > 0 => { - elements.push(make::tokens::single_space().into()) - } - Some(prev_trivia) => { - elements.extend(prev_trivia.clone().into_iter()) - } - _ => (), + elements.push(make::tokens::single_space().into()); } elements.push(tree.syntax().clone().into()); } - if let Some(ref trivia) = closing_formatting_trivia { - elements.extend(trivia.clone().into_iter()) - } - let trees_pos = match new_list.l_curly_token() { - Some(l_curly) => Position::after(l_curly), - None => Position::last_child_of(new_list.syntax()), - }; - ted::insert_all_raw(trees_pos, elements); - - let list_pos = Position::last_child_of(lhs.syntax()); - ted::insert_raw(list_pos, new_list.syntax()); + let start = use_tree_list + .l_curly_token() + .and_then(|l_curly| { + algo::non_trivia_sibling(l_curly.into(), Direction::Next) + }) + .filter(|it| it.kind() != T!['}']); + let end = use_tree_list + .r_curly_token() + .and_then(|r_curly| { + algo::non_trivia_sibling(r_curly.into(), Direction::Prev) + }) + .filter(|it| it.kind() != T!['{']); + if let Some((start, end)) = start.zip(end) { + // Attempt to insert elements while preserving preceding and trailing trivia. + ted::replace_all(start..=end, elements); + } else { + let new_use_tree_list = make::use_tree_list(empty()).clone_for_update(); + let trees_pos = match new_use_tree_list.l_curly_token() { + Some(l_curly) => Position::after(l_curly), + None => Position::last_child_of(new_use_tree_list.syntax()), + }; + ted::insert_all_raw(trees_pos, elements); + ted::replace(use_tree_list.syntax(), new_use_tree_list.syntax()); + } } } } } } - return Some(()); - - // Returns all trivia preceding a syntax element if it may be relevant to formatting - // (i.e. includes at least one new line character). - fn formatting_whitespace(elem: &SyntaxElement) -> Option> { - let succ = - |item: &SyntaxElement| item.prev_sibling_or_token().filter(|it| it.kind().is_trivia()); - let first = succ(elem); - let trivia_set: FxHashSet<_> = successors(first, succ).collect(); - let contains_formatting_whitespace = trivia_set.iter().any(|it| { - it.kind() == SyntaxKind::WHITESPACE - && it.as_token().is_some_and(|token| token.text().contains('\n')) - }); - contains_formatting_whitespace.then_some(trivia_set) - } + Some(()) } /// Traverses both paths until they differ, returning the common prefix of both. @@ -383,13 +366,13 @@ fn path_segment_cmp(a: &ast::PathSegment, b: &ast::PathSegment) -> Ordering { } } -// Orders for use trees with equal paths (see `use_tree_cmp` for details about use tree ordering). -// -// If the `strict` parameter is set to true and both trees have tree lists, the tree lists are -// ordered by calling `use_tree_cmp` on their "sub-tree" pairs until either the tie is broken -// or tree list equality is confirmed, otherwise (i.e. if either `strict` is false or at least -// one of the trees does *not* have tree list), this potentially recursive step is skipped, -// and only the presence of a glob pattern or an alias is used to determine the ordering. +/// Orders for use trees with equal paths (see `use_tree_cmp` for details about use tree ordering). +/// +/// If the `strict` parameter is set to true and both trees have tree lists, the tree lists are +/// ordered by calling `use_tree_cmp` on their "sub-tree" pairs until either the tie is broken +/// or tree list equality is confirmed, otherwise (i.e. if either `strict` is false or at least +/// one of the trees does *not* have tree list), this potentially recursive step is skipped, +/// and only the presence of a glob pattern or an alias is used to determine the ordering. fn use_tree_cmp_by_tree_list_glob_or_alias( a: &ast::UseTree, b: &ast::UseTree, From 02d21f21cf7505c388c3140159b0da21cbff87fc Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 14 Jan 2024 10:54:20 -0800 Subject: [PATCH 0201/1197] Add a stable #visual-studio anchor to the Manual --- docs/user/manual.adoc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc index fa8413c19ae07..069a62ddbfe96 100644 --- a/docs/user/manual.adoc +++ b/docs/user/manual.adoc @@ -512,7 +512,8 @@ https://docs.helix-editor.com/[Helix] supports LSP by default. However, it won't install `rust-analyzer` automatically. You can follow instructions for installing <>. -=== Visual Studio 2022 +[#visual-studio] +=== [[visual-studio-2022]]Visual Studio 2022 There are multiple rust-analyzer extensions for Visual Studio 2022 on Windows: From 6f98a6cc8015cb094dc0c6acb330eb71ef75cb64 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 14 Jan 2024 18:29:01 +0000 Subject: [PATCH 0202/1197] Simplify closure_env_ty and closure_env_param --- .../rustc_borrowck/src/universal_regions.rs | 6 +- compiler/rustc_middle/src/ty/util.rs | 14 ++--- compiler/rustc_mir_build/src/thir/cx/mod.rs | 56 +++++++------------ compiler/rustc_ty_utils/src/abi.rs | 6 +- 4 files changed, 34 insertions(+), 48 deletions(-) diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index addb41ff5fc8f..ae8a135f09059 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -668,7 +668,11 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { kind: ty::BrEnv, }; let env_region = ty::Region::new_bound(tcx, ty::INNERMOST, br); - let closure_ty = tcx.closure_env_ty(def_id, args, env_region).unwrap(); + let closure_ty = tcx.closure_env_ty( + Ty::new_closure(tcx, def_id, args), + args.as_closure().kind(), + env_region, + ); // The "inputs" of the closure in the // signature appear as a tuple. The MIR side diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 7285cdb830e39..3a50ec2251a09 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -604,19 +604,15 @@ impl<'tcx> TyCtxt<'tcx> { /// wrapped in a binder. pub fn closure_env_ty( self, - closure_def_id: DefId, - closure_args: GenericArgsRef<'tcx>, + closure_ty: Ty<'tcx>, + closure_kind: ty::ClosureKind, env_region: ty::Region<'tcx>, - ) -> Option> { - let closure_ty = Ty::new_closure(self, closure_def_id, closure_args); - let closure_kind_ty = closure_args.as_closure().kind_ty(); - let closure_kind = closure_kind_ty.to_opt_closure_kind()?; - let env_ty = match closure_kind { + ) -> Ty<'tcx> { + match closure_kind { ty::ClosureKind::Fn => Ty::new_imm_ref(self, env_region, closure_ty), ty::ClosureKind::FnMut => Ty::new_mut_ref(self, env_region, closure_ty), ty::ClosureKind::FnOnce => closure_ty, - }; - Some(env_ty) + } } /// Returns `true` if the node pointed to by `def_id` is a `static` item. diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index fa3dd2afa85db..5d0bb3954ccc6 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -117,50 +117,32 @@ impl<'tcx> Cx<'tcx> { pat_from_hir(self.tcx, self.param_env, self.typeck_results(), p) } - fn closure_env_param(&self, owner_def: LocalDefId, owner_id: HirId) -> Option> { - match self.tcx.def_kind(owner_def) { - DefKind::Closure if self.tcx.is_coroutine(owner_def.to_def_id()) => { - let coroutine_ty = self.typeck_results.node_type(owner_id); - let coroutine_param = Param { - ty: coroutine_ty, - pat: None, - ty_span: None, - self_kind: None, - hir_id: None, - }; - Some(coroutine_param) + fn closure_env_param(&self, owner_def: LocalDefId, expr_id: HirId) -> Option> { + if self.tcx.def_kind(owner_def) != DefKind::Closure { + return None; + } + + let closure_ty = self.typeck_results.node_type(expr_id); + Some(match *closure_ty.kind() { + ty::Coroutine(..) => { + Param { ty: closure_ty, pat: None, ty_span: None, self_kind: None, hir_id: None } } - DefKind::Closure => { - let closure_ty = self.typeck_results.node_type(owner_id); - - let ty::Closure(closure_def_id, closure_args) = *closure_ty.kind() else { - bug!("closure expr does not have closure type: {:?}", closure_ty); - }; - - let bound_vars = - self.tcx.mk_bound_variable_kinds(&[ty::BoundVariableKind::Region(ty::BrEnv)]); - let br = ty::BoundRegion { - var: ty::BoundVar::from_usize(bound_vars.len() - 1), - kind: ty::BrEnv, - }; - let env_region = ty::Region::new_bound(self.tcx, ty::INNERMOST, br); - let closure_env_ty = - self.tcx.closure_env_ty(closure_def_id, closure_args, env_region).unwrap(); - let liberated_closure_env_ty = self.tcx.instantiate_bound_regions_with_erased( - ty::Binder::bind_with_vars(closure_env_ty, bound_vars), + ty::Closure(_, closure_args) => { + let closure_env_ty = self.tcx.closure_env_ty( + closure_ty, + closure_args.as_closure().kind(), + self.tcx.lifetimes.re_erased, ); - let env_param = Param { - ty: liberated_closure_env_ty, + Param { + ty: closure_env_ty, pat: None, ty_span: None, self_kind: None, hir_id: None, - }; - - Some(env_param) + } } - _ => None, - } + _ => bug!("unexpected closure type: {closure_ty}"), + }) } fn explicit_params<'a>( diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 2772831e731ec..11f7972ceee1f 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -83,7 +83,11 @@ fn fn_sig_for_fn_abi<'tcx>( kind: ty::BoundRegionKind::BrEnv, }; let env_region = ty::Region::new_bound(tcx, ty::INNERMOST, br); - let env_ty = tcx.closure_env_ty(def_id, args, env_region).unwrap(); + let env_ty = tcx.closure_env_ty( + Ty::new_closure(tcx, def_id, args), + args.as_closure().kind(), + env_region, + ); let sig = sig.skip_binder(); ty::Binder::bind_with_vars( From 56df3bb70d808d535e46f1c017bafeccbbf1cb6d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 5 Dec 2023 18:47:10 -0800 Subject: [PATCH 0203/1197] Move nonzero_integers macro call to bottom of module This way all the other macros defined in this module, such as nonzero_leading_trailing_zeros, are available to call within the expansion of nonzero_integers. (Macros defined by macro_rules cannot be called from the same module above the location of the macro_rules.) In this commit the ability to call things like nonzero_leading_trailing_zeros is not immediately used, but later commits in this stack will be consolidating the entire API of NonZeroT to be generated through nonzero_integers, and will need to make use of some of the other macros to do that. --- library/core/src/num/nonzero.rs | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 2df38ab5848af..1de9226f47f2c 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -190,21 +190,6 @@ macro_rules! nonzero_integers { } } -nonzero_integers! { - #[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] NonZeroU8(u8); - #[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] NonZeroU16(u16); - #[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] NonZeroU32(u32); - #[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] NonZeroU64(u64); - #[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] NonZeroU128(u128); - #[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] NonZeroUsize(usize); - #[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI8(i8); - #[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI16(i16); - #[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI32(i32); - #[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI64(i64); - #[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI128(i128); - #[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroIsize(isize); -} - macro_rules! from_str_radix_nzint_impl { ($($t:ty)*) => {$( #[stable(feature = "nonzero_parse", since = "1.35.0")] @@ -1396,3 +1381,18 @@ nonzero_bits! { NonZeroUsize(usize); NonZeroIsize(isize); } + +nonzero_integers! { + #[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] NonZeroU8(u8); + #[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] NonZeroU16(u16); + #[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] NonZeroU32(u32); + #[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] NonZeroU64(u64); + #[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] NonZeroU128(u128); + #[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] NonZeroUsize(usize); + #[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI8(i8); + #[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI16(i16); + #[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI32(i32); + #[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI64(i64); + #[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI128(i128); + #[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroIsize(isize); +} From 54cb822563dc7ffd4838c23d04f7c1ad6c3e90cd Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 5 Dec 2023 18:21:50 -0800 Subject: [PATCH 0204/1197] Define only a single NonZero type per macro call Later in this stack, as the nonzero_integers macro is going to be responsible for producing a larger fraction of the API for the NonZero integer types, it will need to receive a number of additional arguments beyond the ones currently seen here. Additional arguments, especially named arguments across multiple lines, will turn out clearer if everything in one macro call is for the same NonZero type. This commit adopts a similar arrangement to what we do for generating the API of the integer primitives (`impl u8` etc), which also generate a single type's API per top-level macro call, rather than generating all 12 impl blocks for the 12 types from one macro call. --- library/core/src/num/nonzero.rs | 45 ++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 1de9226f47f2c..6b113d57f25fe 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -22,9 +22,10 @@ macro_rules! impl_nonzero_fmt { } } -macro_rules! nonzero_integers { - ( $( #[$stability: meta] #[$const_new_unchecked_stability: meta] $Ty: ident($Int: ty); )+ ) => { - $( +macro_rules! nonzero_integer { + ( + #[$stability:meta] #[$const_new_unchecked_stability:meta] $Ty:ident($Int:ty); + ) => { /// An integer that is known not to equal zero. /// /// This enables some memory layout optimization. @@ -186,8 +187,7 @@ macro_rules! nonzero_integers { impl_nonzero_fmt! { #[$stability] (Debug, Display, Binary, Octal, LowerHex, UpperHex) for $Ty } - )+ - } + }; } macro_rules! from_str_radix_nzint_impl { @@ -1382,17 +1382,50 @@ nonzero_bits! { NonZeroIsize(isize); } -nonzero_integers! { +nonzero_integer! { #[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] NonZeroU8(u8); +} + +nonzero_integer! { #[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] NonZeroU16(u16); +} + +nonzero_integer! { #[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] NonZeroU32(u32); +} + +nonzero_integer! { #[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] NonZeroU64(u64); +} + +nonzero_integer! { #[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] NonZeroU128(u128); +} + +nonzero_integer! { #[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] NonZeroUsize(usize); +} + +nonzero_integer! { #[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI8(i8); +} + +nonzero_integer! { #[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI16(i16); +} + +nonzero_integer! { #[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI32(i32); +} + +nonzero_integer! { #[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI64(i64); +} + +nonzero_integer! { #[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI128(i128); +} + +nonzero_integer! { #[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroIsize(isize); } From 9196d2a552c28144252730bcf8a8e58878f625d4 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 5 Dec 2023 18:44:02 -0800 Subject: [PATCH 0205/1197] Unindent nonzero_integer macro body --- library/core/src/num/nonzero.rs | 278 ++++++++++++++++---------------- 1 file changed, 139 insertions(+), 139 deletions(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 6b113d57f25fe..f7098bcf6e9c9 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -26,167 +26,167 @@ macro_rules! nonzero_integer { ( #[$stability:meta] #[$const_new_unchecked_stability:meta] $Ty:ident($Int:ty); ) => { - /// An integer that is known not to equal zero. + /// An integer that is known not to equal zero. + /// + /// This enables some memory layout optimization. + #[doc = concat!("For example, `Option<", stringify!($Ty), ">` is the same size as `", stringify!($Int), "`:")] + /// + /// ```rust + /// use std::mem::size_of; + #[doc = concat!("assert_eq!(size_of::>(), size_of::<", stringify!($Int), ">());")] + /// ``` + /// + /// # Layout + /// + #[doc = concat!("`", stringify!($Ty), "` is guaranteed to have the same layout and bit validity as `", stringify!($Int), "`")] + /// with the exception that `0` is not a valid instance. + #[doc = concat!("`Option<", stringify!($Ty), ">` is guaranteed to be compatible with `", stringify!($Int), "`,")] + /// including in FFI. + /// + /// Thanks to the [null pointer optimization], + #[doc = concat!("`", stringify!($Ty), "` and `Option<", stringify!($Ty), ">`")] + /// are guaranteed to have the same size and alignment: + /// + /// ``` + /// # use std::mem::{size_of, align_of}; + #[doc = concat!("use std::num::", stringify!($Ty), ";")] + /// + #[doc = concat!("assert_eq!(size_of::<", stringify!($Ty), ">(), size_of::>());")] + #[doc = concat!("assert_eq!(align_of::<", stringify!($Ty), ">(), align_of::>());")] + /// ``` + /// + /// [null pointer optimization]: crate::option#representation + #[$stability] + #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] + #[repr(transparent)] + #[rustc_layout_scalar_valid_range_start(1)] + #[rustc_nonnull_optimization_guaranteed] + #[rustc_diagnostic_item = stringify!($Ty)] + pub struct $Ty($Int); + + impl $Ty { + /// Creates a non-zero without checking whether the value is non-zero. + /// This results in undefined behaviour if the value is zero. /// - /// This enables some memory layout optimization. - #[doc = concat!("For example, `Option<", stringify!($Ty), ">` is the same size as `", stringify!($Int), "`:")] + /// # Safety /// - /// ```rust - /// use std::mem::size_of; - #[doc = concat!("assert_eq!(size_of::>(), size_of::<", stringify!($Int), ">());")] - /// ``` - /// - /// # Layout - /// - #[doc = concat!("`", stringify!($Ty), "` is guaranteed to have the same layout and bit validity as `", stringify!($Int), "`")] - /// with the exception that `0` is not a valid instance. - #[doc = concat!("`Option<", stringify!($Ty), ">` is guaranteed to be compatible with `", stringify!($Int), "`,")] - /// including in FFI. - /// - /// Thanks to the [null pointer optimization], - #[doc = concat!("`", stringify!($Ty), "` and `Option<", stringify!($Ty), ">`")] - /// are guaranteed to have the same size and alignment: - /// - /// ``` - /// # use std::mem::{size_of, align_of}; - #[doc = concat!("use std::num::", stringify!($Ty), ";")] - /// - #[doc = concat!("assert_eq!(size_of::<", stringify!($Ty), ">(), size_of::>());")] - #[doc = concat!("assert_eq!(align_of::<", stringify!($Ty), ">(), align_of::>());")] - /// ``` - /// - /// [null pointer optimization]: crate::option#representation + /// The value must not be zero. #[$stability] - #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] - #[repr(transparent)] - #[rustc_layout_scalar_valid_range_start(1)] - #[rustc_nonnull_optimization_guaranteed] - #[rustc_diagnostic_item = stringify!($Ty)] - pub struct $Ty($Int); - - impl $Ty { - /// Creates a non-zero without checking whether the value is non-zero. - /// This results in undefined behaviour if the value is zero. - /// - /// # Safety - /// - /// The value must not be zero. - #[$stability] - #[$const_new_unchecked_stability] - #[must_use] - #[inline] - pub const unsafe fn new_unchecked(n: $Int) -> Self { - crate::panic::debug_assert_nounwind!( - n != 0, - concat!(stringify!($Ty), "::new_unchecked requires a non-zero argument") - ); - // SAFETY: this is guaranteed to be safe by the caller. - unsafe { - Self(n) - } - } - - /// Creates a non-zero if the given value is not zero. - #[$stability] - #[rustc_const_stable(feature = "const_nonzero_int_methods", since = "1.47.0")] - #[must_use] - #[inline] - pub const fn new(n: $Int) -> Option { - if n != 0 { - // SAFETY: we just checked that there's no `0` - Some(unsafe { Self(n) }) - } else { - None - } + #[$const_new_unchecked_stability] + #[must_use] + #[inline] + pub const unsafe fn new_unchecked(n: $Int) -> Self { + crate::panic::debug_assert_nounwind!( + n != 0, + concat!(stringify!($Ty), "::new_unchecked requires a non-zero argument") + ); + // SAFETY: this is guaranteed to be safe by the caller. + unsafe { + Self(n) } + } - /// Returns the value as a primitive type. - #[$stability] - #[inline] - #[rustc_const_stable(feature = "const_nonzero_get", since = "1.34.0")] - pub const fn get(self) -> $Int { - // FIXME: Remove this after LLVM supports `!range` metadata for function - // arguments https://github.com/llvm/llvm-project/issues/76628 - // - // Rustc can set range metadata only if it loads `self` from - // memory somewhere. If the value of `self` was from by-value argument - // of some not-inlined function, LLVM don't have range metadata - // to understand that the value cannot be zero. - - // SAFETY: It is an invariant of this type. - unsafe { - intrinsics::assume(self.0 != 0); - } - self.0 + /// Creates a non-zero if the given value is not zero. + #[$stability] + #[rustc_const_stable(feature = "const_nonzero_int_methods", since = "1.47.0")] + #[must_use] + #[inline] + pub const fn new(n: $Int) -> Option { + if n != 0 { + // SAFETY: we just checked that there's no `0` + Some(unsafe { Self(n) }) + } else { + None } - } - #[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() + /// Returns the value as a primitive type. + #[$stability] + #[inline] + #[rustc_const_stable(feature = "const_nonzero_get", since = "1.34.0")] + pub const fn get(self) -> $Int { + // FIXME: Remove this after LLVM supports `!range` metadata for function + // arguments https://github.com/llvm/llvm-project/issues/76628 + // + // Rustc can set range metadata only if it loads `self` from + // memory somewhere. If the value of `self` was from by-value argument + // of some not-inlined function, LLVM don't have range metadata + // to understand that the value cannot be zero. + + // SAFETY: It is an invariant of this type. + unsafe { + intrinsics::assume(self.0 != 0); } + self.0 } - #[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 { $Ty::new_unchecked(self.get() | rhs.get()) } - } + } + + #[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<$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 { $Ty::new_unchecked(self.get() | rhs) } - } + #[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 { $Ty::new_unchecked(self.get() | rhs.get()) } } + } - #[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 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 { $Ty::new_unchecked(self.get() | rhs) } } + } - #[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 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<$Int> for $Ty { - #[inline] - fn bitor_assign(&mut self, rhs: $Int) { - *self = *self | rhs; - } + #[stable(feature = "nonzero_bitor", since = "1.45.0")] + impl BitOrAssign for $Ty { + #[inline] + fn bitor_assign(&mut self, rhs: Self) { + *self = *self | rhs; } + } - impl_nonzero_fmt! { - #[$stability] (Debug, Display, Binary, Octal, LowerHex, UpperHex) for $Ty + #[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 + } }; } From a6152cdd9a6c287411212209a18904ca5d68d484 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 5 Dec 2023 18:24:16 -0800 Subject: [PATCH 0206/1197] Format nonzero_integer macro calls same way we do the primitive int impls The `key = $value` style will be beneficial as we introduce some more macro arguments here in later commits. --- library/core/src/num/nonzero.rs | 79 ++++++++++++++++++++++++--------- 1 file changed, 59 insertions(+), 20 deletions(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index f7098bcf6e9c9..f6ccefa261415 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -24,7 +24,10 @@ macro_rules! impl_nonzero_fmt { macro_rules! nonzero_integer { ( - #[$stability:meta] #[$const_new_unchecked_stability:meta] $Ty:ident($Int:ty); + Self = $Ty:ident, + Primitive = $signedness:ident $Int:ident, + feature = $feature:literal, + original_stabilization = $since:literal, ) => { /// An integer that is known not to equal zero. /// @@ -56,7 +59,7 @@ macro_rules! nonzero_integer { /// ``` /// /// [null pointer optimization]: crate::option#representation - #[$stability] + #[stable(feature = $feature, since = $since)] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] #[repr(transparent)] #[rustc_layout_scalar_valid_range_start(1)] @@ -71,8 +74,8 @@ macro_rules! nonzero_integer { /// # Safety /// /// The value must not be zero. - #[$stability] - #[$const_new_unchecked_stability] + #[stable(feature = $feature, since = $since)] + #[rustc_const_stable(feature = $feature, since = $since)] #[must_use] #[inline] pub const unsafe fn new_unchecked(n: $Int) -> Self { @@ -87,7 +90,7 @@ macro_rules! nonzero_integer { } /// Creates a non-zero if the given value is not zero. - #[$stability] + #[stable(feature = $feature, since = $since)] #[rustc_const_stable(feature = "const_nonzero_int_methods", since = "1.47.0")] #[must_use] #[inline] @@ -101,7 +104,7 @@ macro_rules! nonzero_integer { } /// Returns the value as a primitive type. - #[$stability] + #[stable(feature = $feature, since = $since)] #[inline] #[rustc_const_stable(feature = "const_nonzero_get", since = "1.34.0")] pub const fn get(self) -> $Int { @@ -119,7 +122,6 @@ macro_rules! nonzero_integer { } self.0 } - } #[stable(feature = "from_nonzero", since = "1.31.0")] @@ -185,7 +187,8 @@ macro_rules! nonzero_integer { } impl_nonzero_fmt! { - #[$stability] (Debug, Display, Binary, Octal, LowerHex, UpperHex) for $Ty + #[stable(feature = $feature, since = $since)] + (Debug, Display, Binary, Octal, LowerHex, UpperHex) for $Ty } }; } @@ -1383,49 +1386,85 @@ nonzero_bits! { } nonzero_integer! { - #[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] NonZeroU8(u8); + Self = NonZeroU8, + Primitive = unsigned u8, + feature = "nonzero", + original_stabilization = "1.28.0", } nonzero_integer! { - #[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] NonZeroU16(u16); + Self = NonZeroU16, + Primitive = unsigned u16, + feature = "nonzero", + original_stabilization = "1.28.0", } nonzero_integer! { - #[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] NonZeroU32(u32); + Self = NonZeroU32, + Primitive = unsigned u32, + feature = "nonzero", + original_stabilization = "1.28.0", } nonzero_integer! { - #[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] NonZeroU64(u64); + Self = NonZeroU64, + Primitive = unsigned u64, + feature = "nonzero", + original_stabilization = "1.28.0", } nonzero_integer! { - #[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] NonZeroU128(u128); + Self = NonZeroU128, + Primitive = unsigned u128, + feature = "nonzero", + original_stabilization = "1.28.0", } nonzero_integer! { - #[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] NonZeroUsize(usize); + Self = NonZeroUsize, + Primitive = unsigned usize, + feature = "nonzero", + original_stabilization = "1.28.0", } nonzero_integer! { - #[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI8(i8); + Self = NonZeroI8, + Primitive = signed i8, + feature = "signed_nonzero", + original_stabilization = "1.34.0", } nonzero_integer! { - #[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI16(i16); + Self = NonZeroI16, + Primitive = signed i16, + feature = "signed_nonzero", + original_stabilization = "1.34.0", } nonzero_integer! { - #[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI32(i32); + Self = NonZeroI32, + Primitive = signed i32, + feature = "signed_nonzero", + original_stabilization = "1.34.0", } nonzero_integer! { - #[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI64(i64); + Self = NonZeroI64, + Primitive = signed i64, + feature = "signed_nonzero", + original_stabilization = "1.34.0", } nonzero_integer! { - #[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI128(i128); + Self = NonZeroI128, + Primitive = signed i128, + feature = "signed_nonzero", + original_stabilization = "1.34.0", } nonzero_integer! { - #[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroIsize(isize); + Self = NonZeroIsize, + Primitive = signed isize, + feature = "signed_nonzero", + original_stabilization = "1.34.0", } From 3de0af1a4da54885dd312e5e6f39641f5da06410 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 5 Dec 2023 18:28:52 -0800 Subject: [PATCH 0207/1197] Move 'impl FromStr for NonZero' into nonzero_integer macro --- library/core/src/num/nonzero.rs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index f6ccefa261415..0f5d421235e1a 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -190,13 +190,9 @@ macro_rules! nonzero_integer { #[stable(feature = $feature, since = $since)] (Debug, Display, Binary, Octal, LowerHex, UpperHex) for $Ty } - }; -} -macro_rules! from_str_radix_nzint_impl { - ($($t:ty)*) => {$( #[stable(feature = "nonzero_parse", since = "1.35.0")] - impl FromStr for $t { + impl FromStr for $Ty { type Err = ParseIntError; fn from_str(src: &str) -> Result { Self::new(from_str_radix(src, 10)?) @@ -205,12 +201,9 @@ macro_rules! from_str_radix_nzint_impl { }) } } - )*} + }; } -from_str_radix_nzint_impl! { NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroU128 NonZeroUsize -NonZeroI8 NonZeroI16 NonZeroI32 NonZeroI64 NonZeroI128 NonZeroIsize } - macro_rules! nonzero_leading_trailing_zeros { ( $( $Ty: ident($Uint: ty) , $LeadingTestExpr:expr ;)+ ) => { $( From 81e1a7c6b5bb5bea9fbbd0f5db0c118dbea867fb Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 5 Dec 2023 18:41:24 -0800 Subject: [PATCH 0208/1197] Move impl Div and Rem into nonzero_integer macro --- library/core/src/num/nonzero.rs | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 0f5d421235e1a..79cca27647999 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -201,6 +201,8 @@ macro_rules! nonzero_integer { }) } } + + nonzero_integer_impl_div_rem!($Ty $signedness $Int); }; } @@ -275,9 +277,12 @@ nonzero_leading_trailing_zeros! { NonZeroIsize(usize), -1isize; } -macro_rules! nonzero_integers_div { - ( $( $Ty: ident($Int: ty); )+ ) => { - $( +macro_rules! nonzero_integer_impl_div_rem { + ($Ty:ident signed $Int:ty) => { + // nothing for signed ints + }; + + ($Ty:ident unsigned $Int:ty) => { #[stable(feature = "nonzero_div", since = "1.51.0")] impl Div<$Ty> for $Int { type Output = $Int; @@ -302,17 +307,7 @@ macro_rules! nonzero_integers_div { unsafe { crate::intrinsics::unchecked_rem(self, other.get()) } } } - )+ - } -} - -nonzero_integers_div! { - NonZeroU8(u8); - NonZeroU16(u16); - NonZeroU32(u32); - NonZeroU64(u64); - NonZeroU128(u128); - NonZeroUsize(usize); + }; } // A bunch of methods for unsigned nonzero types only. From a78d9a6de1848358b3835d3ac8ce6b20a24c061f Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 5 Dec 2023 21:07:42 -0800 Subject: [PATCH 0209/1197] Unindent nonzero_integer_impl_div_rem macro body --- library/core/src/num/nonzero.rs | 42 ++++++++++++++++----------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 79cca27647999..75429d9059a69 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -283,30 +283,30 @@ macro_rules! nonzero_integer_impl_div_rem { }; ($Ty:ident unsigned $Int:ty) => { - #[stable(feature = "nonzero_div", since = "1.51.0")] - impl Div<$Ty> for $Int { - type Output = $Int; - /// This operation rounds towards zero, - /// truncating any fractional part of the exact result, and cannot panic. - #[inline] - fn div(self, other: $Ty) -> $Int { - // SAFETY: div by zero is checked because `other` is a nonzero, - // and MIN/-1 is checked because `self` is an unsigned int. - unsafe { crate::intrinsics::unchecked_div(self, other.get()) } - } + #[stable(feature = "nonzero_div", since = "1.51.0")] + impl Div<$Ty> for $Int { + type Output = $Int; + /// This operation rounds towards zero, + /// truncating any fractional part of the exact result, and cannot panic. + #[inline] + fn div(self, other: $Ty) -> $Int { + // SAFETY: div by zero is checked because `other` is a nonzero, + // and MIN/-1 is checked because `self` is an unsigned int. + unsafe { crate::intrinsics::unchecked_div(self, other.get()) } } + } - #[stable(feature = "nonzero_div", since = "1.51.0")] - impl Rem<$Ty> for $Int { - type Output = $Int; - /// This operation satisfies `n % d == n - (n / d) * d`, and cannot panic. - #[inline] - fn rem(self, other: $Ty) -> $Int { - // SAFETY: rem by zero is checked because `other` is a nonzero, - // and MIN/-1 is checked because `self` is an unsigned int. - unsafe { crate::intrinsics::unchecked_rem(self, other.get()) } - } + #[stable(feature = "nonzero_div", since = "1.51.0")] + impl Rem<$Ty> for $Int { + type Output = $Int; + /// This operation satisfies `n % d == n - (n / d) * d`, and cannot panic. + #[inline] + fn rem(self, other: $Ty) -> $Int { + // SAFETY: rem by zero is checked because `other` is a nonzero, + // and MIN/-1 is checked because `self` is an unsigned int. + unsafe { crate::intrinsics::unchecked_rem(self, other.get()) } } + } }; } From f846ed53e41a18fbb900e794467351fda5ffbb80 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 5 Dec 2023 21:37:28 -0800 Subject: [PATCH 0210/1197] Move leading_zeros and trailing_zeros methods into nonzero_integer macro --- library/core/src/num/nonzero.rs | 146 ++++++++++++++++---------------- 1 file changed, 75 insertions(+), 71 deletions(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 75429d9059a69..9c396710fd488 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -26,8 +26,12 @@ macro_rules! nonzero_integer { ( Self = $Ty:ident, Primitive = $signedness:ident $Int:ident, + UnsignedPrimitive = $UnsignedPrimitive:ty, feature = $feature:literal, original_stabilization = $since:literal, + + // Used in doc comments. + leading_zeros_test = $leading_zeros_test:expr, ) => { /// An integer that is known not to equal zero. /// @@ -122,6 +126,53 @@ macro_rules! nonzero_integer { } self.0 } + + /// Returns the number of leading zeros in the binary representation of `self`. + /// + /// On many architectures, this function can perform better than `leading_zeros()` on the underlying integer type, as special handling of zero can be avoided. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + #[doc = concat!("let n = std::num::", stringify!($Ty), "::new(", stringify!($leading_zeros_test), ").unwrap();")] + /// + /// assert_eq!(n.leading_zeros(), 0); + /// ``` + #[stable(feature = "nonzero_leading_trailing_zeros", since = "1.53.0")] + #[rustc_const_stable(feature = "nonzero_leading_trailing_zeros", since = "1.53.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn leading_zeros(self) -> u32 { + // SAFETY: since `self` cannot be zero, it is safe to call `ctlz_nonzero`. + unsafe { intrinsics::ctlz_nonzero(self.get() as $UnsignedPrimitive) as u32 } + } + + /// Returns the number of trailing zeros in the binary representation + /// of `self`. + /// + /// On many architectures, this function can perform better than `trailing_zeros()` on the underlying integer type, as special handling of zero can be avoided. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + #[doc = concat!("let n = std::num::", stringify!($Ty), "::new(0b0101000).unwrap();")] + /// + /// assert_eq!(n.trailing_zeros(), 3); + /// ``` + #[stable(feature = "nonzero_leading_trailing_zeros", since = "1.53.0")] + #[rustc_const_stable(feature = "nonzero_leading_trailing_zeros", since = "1.53.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn trailing_zeros(self) -> u32 { + // SAFETY: since `self` cannot be zero, it is safe to call `cttz_nonzero`. + unsafe { intrinsics::cttz_nonzero(self.get() as $UnsignedPrimitive) as u32 } + } } #[stable(feature = "from_nonzero", since = "1.31.0")] @@ -206,77 +257,6 @@ macro_rules! nonzero_integer { }; } -macro_rules! nonzero_leading_trailing_zeros { - ( $( $Ty: ident($Uint: ty) , $LeadingTestExpr:expr ;)+ ) => { - $( - impl $Ty { - /// Returns the number of leading zeros in the binary representation of `self`. - /// - /// On many architectures, this function can perform better than `leading_zeros()` on the underlying integer type, as special handling of zero can be avoided. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - #[doc = concat!("let n = std::num::", stringify!($Ty), "::new(", stringify!($LeadingTestExpr), ").unwrap();")] - /// - /// assert_eq!(n.leading_zeros(), 0); - /// ``` - #[stable(feature = "nonzero_leading_trailing_zeros", since = "1.53.0")] - #[rustc_const_stable(feature = "nonzero_leading_trailing_zeros", since = "1.53.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn leading_zeros(self) -> u32 { - // SAFETY: since `self` cannot be zero, it is safe to call `ctlz_nonzero`. - unsafe { intrinsics::ctlz_nonzero(self.get() as $Uint) as u32 } - } - - /// Returns the number of trailing zeros in the binary representation - /// of `self`. - /// - /// On many architectures, this function can perform better than `trailing_zeros()` on the underlying integer type, as special handling of zero can be avoided. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - #[doc = concat!("let n = std::num::", stringify!($Ty), "::new(0b0101000).unwrap();")] - /// - /// assert_eq!(n.trailing_zeros(), 3); - /// ``` - #[stable(feature = "nonzero_leading_trailing_zeros", since = "1.53.0")] - #[rustc_const_stable(feature = "nonzero_leading_trailing_zeros", since = "1.53.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn trailing_zeros(self) -> u32 { - // SAFETY: since `self` cannot be zero, it is safe to call `cttz_nonzero`. - unsafe { intrinsics::cttz_nonzero(self.get() as $Uint) as u32 } - } - - } - )+ - } -} - -nonzero_leading_trailing_zeros! { - NonZeroU8(u8), u8::MAX; - NonZeroU16(u16), u16::MAX; - NonZeroU32(u32), u32::MAX; - NonZeroU64(u64), u64::MAX; - NonZeroU128(u128), u128::MAX; - NonZeroUsize(usize), usize::MAX; - NonZeroI8(u8), -1i8; - NonZeroI16(u16), -1i16; - NonZeroI32(u32), -1i32; - NonZeroI64(u64), -1i64; - NonZeroI128(u128), -1i128; - NonZeroIsize(usize), -1isize; -} - macro_rules! nonzero_integer_impl_div_rem { ($Ty:ident signed $Int:ty) => { // nothing for signed ints @@ -1376,83 +1356,107 @@ nonzero_bits! { nonzero_integer! { Self = NonZeroU8, Primitive = unsigned u8, + UnsignedPrimitive = u8, feature = "nonzero", original_stabilization = "1.28.0", + leading_zeros_test = u8::MAX, } nonzero_integer! { Self = NonZeroU16, Primitive = unsigned u16, + UnsignedPrimitive = u16, feature = "nonzero", original_stabilization = "1.28.0", + leading_zeros_test = u16::MAX, } nonzero_integer! { Self = NonZeroU32, Primitive = unsigned u32, + UnsignedPrimitive = u32, feature = "nonzero", original_stabilization = "1.28.0", + leading_zeros_test = u32::MAX, } nonzero_integer! { Self = NonZeroU64, Primitive = unsigned u64, + UnsignedPrimitive = u64, feature = "nonzero", original_stabilization = "1.28.0", + leading_zeros_test = u64::MAX, } nonzero_integer! { Self = NonZeroU128, Primitive = unsigned u128, + UnsignedPrimitive = u128, feature = "nonzero", original_stabilization = "1.28.0", + leading_zeros_test = u128::MAX, } nonzero_integer! { Self = NonZeroUsize, Primitive = unsigned usize, + UnsignedPrimitive = usize, feature = "nonzero", original_stabilization = "1.28.0", + leading_zeros_test = usize::MAX, } nonzero_integer! { Self = NonZeroI8, Primitive = signed i8, + UnsignedPrimitive = u8, feature = "signed_nonzero", original_stabilization = "1.34.0", + leading_zeros_test = -1i8, } nonzero_integer! { Self = NonZeroI16, Primitive = signed i16, + UnsignedPrimitive = u16, feature = "signed_nonzero", original_stabilization = "1.34.0", + leading_zeros_test = -1i16, } nonzero_integer! { Self = NonZeroI32, Primitive = signed i32, + UnsignedPrimitive = u32, feature = "signed_nonzero", original_stabilization = "1.34.0", + leading_zeros_test = -1i32, } nonzero_integer! { Self = NonZeroI64, Primitive = signed i64, + UnsignedPrimitive = u64, feature = "signed_nonzero", original_stabilization = "1.34.0", + leading_zeros_test = -1i64, } nonzero_integer! { Self = NonZeroI128, Primitive = signed i128, + UnsignedPrimitive = u128, feature = "signed_nonzero", original_stabilization = "1.34.0", + leading_zeros_test = -1i128, } nonzero_integer! { Self = NonZeroIsize, Primitive = signed isize, + UnsignedPrimitive = usize, feature = "signed_nonzero", original_stabilization = "1.34.0", + leading_zeros_test = -1isize, } From 23483664a24434e0bd5dab1576dffe4d8ada712c Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 13 Jan 2024 17:53:14 -0800 Subject: [PATCH 0211/1197] Split out `option::unwrap_failed` like we have `result::unwrap_failed` ...and like `option::expect_failed` --- library/core/src/option.rs | 12 ++++++++++-- tests/codegen/debuginfo-inline-callsite-location.rs | 4 ++-- ...352.num_to_digit.PreCodegen.after.panic-abort.mir | 2 +- ...52.num_to_digit.PreCodegen.after.panic-unwind.mir | 2 +- ..._invalid_constant.main.GVN.32bit.panic-abort.diff | 2 +- ...invalid_constant.main.GVN.32bit.panic-unwind.diff | 2 +- ..._invalid_constant.main.GVN.64bit.panic-abort.diff | 2 +- ...invalid_constant.main.GVN.64bit.panic-unwind.diff | 2 +- 8 files changed, 18 insertions(+), 10 deletions(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index ff4353492498c..975aff90d35f0 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -921,14 +921,14 @@ impl Option { /// let x: Option<&str> = None; /// assert_eq!(x.unwrap(), "air"); // fails /// ``` - #[inline] + #[inline(always)] #[track_caller] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_option", issue = "67441")] pub const fn unwrap(self) -> T { match self { Some(val) => val, - None => panic("called `Option::unwrap()` on a `None` value"), + None => unwrap_failed(), } } @@ -1970,6 +1970,14 @@ impl Option> { } } +#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] +#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cold] +#[track_caller] +const fn unwrap_failed() -> ! { + panic("called `Option::unwrap()` on a `None` value") +} + // This is a separate function to reduce the code size of .expect() itself. #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] #[cfg_attr(feature = "panic_immediate_abort", inline)] diff --git a/tests/codegen/debuginfo-inline-callsite-location.rs b/tests/codegen/debuginfo-inline-callsite-location.rs index b1475ee793160..d529f9ccead56 100644 --- a/tests/codegen/debuginfo-inline-callsite-location.rs +++ b/tests/codegen/debuginfo-inline-callsite-location.rs @@ -4,9 +4,9 @@ // can correctly merge the debug info if it merges the inlined code (e.g., for merging of tail // calls to panic. -// CHECK: tail call void @_ZN4core9panicking5panic17h{{([0-9a-z]{16})}}E +// CHECK: tail call void @_ZN4core6option13unwrap_failed17h{{([0-9a-z]{16})}}E // CHECK-SAME: !dbg ![[#first_dbg:]] -// CHECK: tail call void @_ZN4core9panicking5panic17h{{([0-9a-z]{16})}}E +// CHECK: tail call void @_ZN4core6option13unwrap_failed17h{{([0-9a-z]{16})}}E // CHECK-SAME: !dbg ![[#second_dbg:]] // CHECK-DAG: ![[#func_dbg:]] = distinct !DISubprogram(name: "unwrap" diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-abort.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-abort.mir index 5d25c6557002c..f7be8b75db7b8 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-abort.mir @@ -51,7 +51,7 @@ fn num_to_digit(_1: char) -> u32 { } bb4: { - _7 = core::panicking::panic(const "called `Option::unwrap()` on a `None` value") -> unwind unreachable; + _7 = option::unwrap_failed() -> unwind unreachable; } bb5: { diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-unwind.mir index 4677c0108e3bb..e76fe992ac7d3 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-unwind.mir @@ -51,7 +51,7 @@ fn num_to_digit(_1: char) -> u32 { } bb4: { - _7 = core::panicking::panic(const "called `Option::unwrap()` on a `None` value") -> unwind continue; + _7 = option::unwrap_failed() -> unwind continue; } bb5: { diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff index 47e0d402347d3..cf93897d591f4 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff @@ -62,7 +62,7 @@ } bb1: { - _11 = core::panicking::panic(const "called `Option::unwrap()` on a `None` value") -> unwind unreachable; + _11 = option::unwrap_failed() -> unwind unreachable; } bb2: { diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff index dee57ce6c27bb..ca33619aa1fb1 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff @@ -60,7 +60,7 @@ } bb2: { - _11 = core::panicking::panic(const "called `Option::unwrap()` on a `None` value") -> unwind continue; + _11 = option::unwrap_failed() -> unwind continue; } bb3: { diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff index a255b15920cba..9c026280ea9c3 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff @@ -62,7 +62,7 @@ } bb1: { - _11 = core::panicking::panic(const "called `Option::unwrap()` on a `None` value") -> unwind unreachable; + _11 = option::unwrap_failed() -> unwind unreachable; } bb2: { diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff index 192ffea259157..7eec7ffb01f32 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff @@ -60,7 +60,7 @@ } bb2: { - _11 = core::panicking::panic(const "called `Option::unwrap()` on a `None` value") -> unwind continue; + _11 = option::unwrap_failed() -> unwind continue; } bb3: { From 757ed2566701feba8fc67cae3d21a7423254efba Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 5 Dec 2023 21:50:14 -0800 Subject: [PATCH 0212/1197] Move Neg impl into the macro that generates Div and Rem --- library/core/src/num/nonzero.rs | 40 ++++++++++++++++----------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 9c396710fd488..b1dd766de315c 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -253,15 +253,12 @@ macro_rules! nonzero_integer { } } - nonzero_integer_impl_div_rem!($Ty $signedness $Int); + nonzero_integer_signedness_dependent_impls!($Ty $signedness $Int); }; } -macro_rules! nonzero_integer_impl_div_rem { - ($Ty:ident signed $Int:ty) => { - // nothing for signed ints - }; - +macro_rules! nonzero_integer_signedness_dependent_impls { + // Impls for unsigned nonzero types only. ($Ty:ident unsigned $Int:ty) => { #[stable(feature = "nonzero_div", since = "1.51.0")] impl Div<$Ty> for $Int { @@ -288,6 +285,23 @@ macro_rules! nonzero_integer_impl_div_rem { } } }; + + // Impls for signed nonzero types only. + ($Ty:ident signed $Int:ty) => { + #[stable(feature = "signed_nonzero_neg", since = "1.71.0")] + impl Neg for $Ty { + type Output = $Ty; + + #[inline] + fn neg(self) -> $Ty { + // SAFETY: negation of nonzero cannot yield zero values. + unsafe { $Ty::new_unchecked(self.get().neg()) } + } + } + + forward_ref_unop! { impl Neg, neg for $Ty, + #[stable(feature = "signed_nonzero_neg", since = "1.71.0")] } + }; } // A bunch of methods for unsigned nonzero types only. @@ -921,20 +935,6 @@ macro_rules! nonzero_signed_operations { unsafe { $Ty::new_unchecked(result) } } } - - #[stable(feature = "signed_nonzero_neg", since = "1.71.0")] - impl Neg for $Ty { - type Output = $Ty; - - #[inline] - fn neg(self) -> $Ty { - // SAFETY: negation of nonzero cannot yield zero values. - unsafe { $Ty::new_unchecked(self.get().neg()) } - } - } - - forward_ref_unop! { impl Neg, neg for $Ty, - #[stable(feature = "signed_nonzero_neg", since = "1.71.0")] } )+ } } From 4291b3ff62e4aad3dae4c573bde5f203d3baec79 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 5 Dec 2023 22:03:55 -0800 Subject: [PATCH 0213/1197] Move signedness dependent methods into the omnibus impl block --- library/core/src/num/nonzero.rs | 65 +++++++++++++++------------------ 1 file changed, 30 insertions(+), 35 deletions(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index b1dd766de315c..1b8920f94774f 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -26,6 +26,7 @@ macro_rules! nonzero_integer { ( Self = $Ty:ident, Primitive = $signedness:ident $Int:ident, + $(UnsignedNonZero = $UnsignedNonZero:ident,)? UnsignedPrimitive = $UnsignedPrimitive:ty, feature = $feature:literal, original_stabilization = $since:literal, @@ -173,6 +174,13 @@ macro_rules! nonzero_integer { // SAFETY: since `self` cannot be zero, it is safe to call `cttz_nonzero`. unsafe { intrinsics::cttz_nonzero(self.get() as $UnsignedPrimitive) as u32 } } + + nonzero_integer_signedness_dependent_methods! { + Self = $Ty, + Primitive = $signedness $Int, + $(UnsignedNonZero = $UnsignedNonZero,)? + UnsignedPrimitive = $UnsignedPrimitive, + } } #[stable(feature = "from_nonzero", since = "1.31.0")] @@ -304,11 +312,13 @@ macro_rules! nonzero_integer_signedness_dependent_impls { }; } -// A bunch of methods for unsigned nonzero types only. -macro_rules! nonzero_unsigned_operations { - ( $( $Ty: ident($Int: ident); )+ ) => { - $( - impl $Ty { +macro_rules! nonzero_integer_signedness_dependent_methods { + // Methods for unsigned nonzero types only. + ( + Self = $Ty:ident, + Primitive = unsigned $Int:ident, + UnsignedPrimitive = $Uint:ty, + ) => { /// Adds an unsigned integer to a non-zero value. /// Checks for overflow and returns [`None`] on overflow. /// As a consequence, the result cannot wrap to zero. @@ -538,25 +548,15 @@ macro_rules! nonzero_unsigned_operations { // never being 0. unsafe { $Ty::new_unchecked(self.get().midpoint(rhs.get())) } } - } - )+ - } -} - -nonzero_unsigned_operations! { - NonZeroU8(u8); - NonZeroU16(u16); - NonZeroU32(u32); - NonZeroU64(u64); - NonZeroU128(u128); - NonZeroUsize(usize); -} + }; -// A bunch of methods for signed nonzero types only. -macro_rules! nonzero_signed_operations { - ( $( $Ty: ident($Int: ty) -> $Uty: ident($Uint: ty); )+ ) => { - $( - impl $Ty { + // Methods for signed nonzero types only. + ( + Self = $Ty:ident, + Primitive = signed $Int:ident, + UnsignedNonZero = $Uty:ident, + UnsignedPrimitive = $Uint:ty, + ) => { /// Computes the absolute value of self. #[doc = concat!("See [`", stringify!($Int), "::abs`]")] /// for documentation on overflow behaviour. @@ -934,18 +934,7 @@ macro_rules! nonzero_signed_operations { // SAFETY: negation of nonzero cannot yield zero values. unsafe { $Ty::new_unchecked(result) } } - } - )+ - } -} - -nonzero_signed_operations! { - NonZeroI8(i8) -> NonZeroU8(u8); - NonZeroI16(i16) -> NonZeroU16(u16); - NonZeroI32(i32) -> NonZeroU32(u32); - NonZeroI64(i64) -> NonZeroU64(u64); - NonZeroI128(i128) -> NonZeroU128(u128); - NonZeroIsize(isize) -> NonZeroUsize(usize); + }; } // A bunch of methods for both signed and unsigned nonzero types. @@ -1410,6 +1399,7 @@ nonzero_integer! { nonzero_integer! { Self = NonZeroI8, Primitive = signed i8, + UnsignedNonZero = NonZeroU8, UnsignedPrimitive = u8, feature = "signed_nonzero", original_stabilization = "1.34.0", @@ -1419,6 +1409,7 @@ nonzero_integer! { nonzero_integer! { Self = NonZeroI16, Primitive = signed i16, + UnsignedNonZero = NonZeroU16, UnsignedPrimitive = u16, feature = "signed_nonzero", original_stabilization = "1.34.0", @@ -1428,6 +1419,7 @@ nonzero_integer! { nonzero_integer! { Self = NonZeroI32, Primitive = signed i32, + UnsignedNonZero = NonZeroU32, UnsignedPrimitive = u32, feature = "signed_nonzero", original_stabilization = "1.34.0", @@ -1437,6 +1429,7 @@ nonzero_integer! { nonzero_integer! { Self = NonZeroI64, Primitive = signed i64, + UnsignedNonZero = NonZeroU64, UnsignedPrimitive = u64, feature = "signed_nonzero", original_stabilization = "1.34.0", @@ -1446,6 +1439,7 @@ nonzero_integer! { nonzero_integer! { Self = NonZeroI128, Primitive = signed i128, + UnsignedNonZero = NonZeroU128, UnsignedPrimitive = u128, feature = "signed_nonzero", original_stabilization = "1.34.0", @@ -1455,6 +1449,7 @@ nonzero_integer! { nonzero_integer! { Self = NonZeroIsize, Primitive = signed isize, + UnsignedNonZero = NonZeroUsize, UnsignedPrimitive = usize, feature = "signed_nonzero", original_stabilization = "1.34.0", From b21b9cc901c3f021c7b7475c406662cd9c0d76e1 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 5 Dec 2023 22:06:40 -0800 Subject: [PATCH 0214/1197] Unindent nonzero_integer_signedness_dependent_methods macro body --- library/core/src/num/nonzero.rs | 1178 +++++++++++++++---------------- 1 file changed, 589 insertions(+), 589 deletions(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 1b8920f94774f..8550a7b4c7b68 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -319,235 +319,235 @@ macro_rules! nonzero_integer_signedness_dependent_methods { Primitive = unsigned $Int:ident, UnsignedPrimitive = $Uint:ty, ) => { - /// Adds an unsigned integer to a non-zero value. - /// Checks for overflow and returns [`None`] on overflow. - /// As a consequence, the result cannot wrap to zero. - /// - /// - /// # Examples - /// - /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// # fn main() { test().unwrap(); } - /// # fn test() -> Option<()> { - #[doc = concat!("let one = ", stringify!($Ty), "::new(1)?;")] - #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] - #[doc = concat!("let max = ", stringify!($Ty), "::new(", - stringify!($Int), "::MAX)?;")] - /// - /// assert_eq!(Some(two), one.checked_add(1)); - /// assert_eq!(None, max.checked_add(1)); - /// # Some(()) - /// # } - /// ``` - #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] - #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_add(self, other: $Int) -> Option<$Ty> { - if let Some(result) = self.get().checked_add(other) { - // SAFETY: - // - `checked_add` returns `None` on overflow - // - `self` is non-zero - // - the only way to get zero from an addition without overflow is for both - // sides to be zero - // - // So the result cannot be zero. - Some(unsafe { $Ty::new_unchecked(result) }) - } else { - None - } - } + /// Adds an unsigned integer to a non-zero value. + /// Checks for overflow and returns [`None`] on overflow. + /// As a consequence, the result cannot wrap to zero. + /// + /// + /// # Examples + /// + /// ``` + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let one = ", stringify!($Ty), "::new(1)?;")] + #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] + #[doc = concat!("let max = ", stringify!($Ty), "::new(", + stringify!($Int), "::MAX)?;")] + /// + /// assert_eq!(Some(two), one.checked_add(1)); + /// assert_eq!(None, max.checked_add(1)); + /// # Some(()) + /// # } + /// ``` + #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] + #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_add(self, other: $Int) -> Option<$Ty> { + if let Some(result) = self.get().checked_add(other) { + // SAFETY: + // - `checked_add` returns `None` on overflow + // - `self` is non-zero + // - the only way to get zero from an addition without overflow is for both + // sides to be zero + // + // So the result cannot be zero. + Some(unsafe { $Ty::new_unchecked(result) }) + } else { + None + } + } - /// Adds an unsigned integer to a non-zero value. - #[doc = concat!("Return [`", stringify!($Ty), "::MAX`] on overflow.")] - /// - /// # Examples - /// - /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// # fn main() { test().unwrap(); } - /// # fn test() -> Option<()> { - #[doc = concat!("let one = ", stringify!($Ty), "::new(1)?;")] - #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] - #[doc = concat!("let max = ", stringify!($Ty), "::new(", - stringify!($Int), "::MAX)?;")] - /// - /// assert_eq!(two, one.saturating_add(1)); - /// assert_eq!(max, max.saturating_add(1)); - /// # Some(()) - /// # } - /// ``` - #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] - #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn saturating_add(self, other: $Int) -> $Ty { - // SAFETY: - // - `saturating_add` returns `u*::MAX` on overflow, which is non-zero - // - `self` is non-zero - // - the only way to get zero from an addition without overflow is for both - // sides to be zero - // - // So the result cannot be zero. - unsafe { $Ty::new_unchecked(self.get().saturating_add(other)) } - } + /// Adds an unsigned integer to a non-zero value. + #[doc = concat!("Return [`", stringify!($Ty), "::MAX`] on overflow.")] + /// + /// # Examples + /// + /// ``` + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let one = ", stringify!($Ty), "::new(1)?;")] + #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] + #[doc = concat!("let max = ", stringify!($Ty), "::new(", + stringify!($Int), "::MAX)?;")] + /// + /// assert_eq!(two, one.saturating_add(1)); + /// assert_eq!(max, max.saturating_add(1)); + /// # Some(()) + /// # } + /// ``` + #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] + #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn saturating_add(self, other: $Int) -> $Ty { + // SAFETY: + // - `saturating_add` returns `u*::MAX` on overflow, which is non-zero + // - `self` is non-zero + // - the only way to get zero from an addition without overflow is for both + // sides to be zero + // + // So the result cannot be zero. + unsafe { $Ty::new_unchecked(self.get().saturating_add(other)) } + } - /// Adds an unsigned integer to a non-zero value, - /// assuming overflow cannot occur. - /// Overflow is unchecked, and it is undefined behaviour to overflow - /// *even if the result would wrap to a non-zero value*. - /// The behaviour is undefined as soon as - #[doc = concat!("`self + rhs > ", stringify!($Int), "::MAX`.")] - /// - /// # Examples - /// - /// ``` - /// #![feature(nonzero_ops)] - /// - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// # fn main() { test().unwrap(); } - /// # fn test() -> Option<()> { - #[doc = concat!("let one = ", stringify!($Ty), "::new(1)?;")] - #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] - /// - /// assert_eq!(two, unsafe { one.unchecked_add(1) }); - /// # Some(()) - /// # } - /// ``` - #[unstable(feature = "nonzero_ops", issue = "84186")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const unsafe fn unchecked_add(self, other: $Int) -> $Ty { - // SAFETY: The caller ensures there is no overflow. - unsafe { $Ty::new_unchecked(self.get().unchecked_add(other)) } - } + /// Adds an unsigned integer to a non-zero value, + /// assuming overflow cannot occur. + /// Overflow is unchecked, and it is undefined behaviour to overflow + /// *even if the result would wrap to a non-zero value*. + /// The behaviour is undefined as soon as + #[doc = concat!("`self + rhs > ", stringify!($Int), "::MAX`.")] + /// + /// # Examples + /// + /// ``` + /// #![feature(nonzero_ops)] + /// + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let one = ", stringify!($Ty), "::new(1)?;")] + #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] + /// + /// assert_eq!(two, unsafe { one.unchecked_add(1) }); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_ops", issue = "84186")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const unsafe fn unchecked_add(self, other: $Int) -> $Ty { + // SAFETY: The caller ensures there is no overflow. + unsafe { $Ty::new_unchecked(self.get().unchecked_add(other)) } + } - /// Returns the smallest power of two greater than or equal to n. - /// Checks for overflow and returns [`None`] - /// if the next power of two is greater than the type’s maximum value. - /// As a consequence, the result cannot wrap to zero. - /// - /// # Examples - /// - /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// # fn main() { test().unwrap(); } - /// # fn test() -> Option<()> { - #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] - #[doc = concat!("let three = ", stringify!($Ty), "::new(3)?;")] - #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")] - #[doc = concat!("let max = ", stringify!($Ty), "::new(", - stringify!($Int), "::MAX)?;")] - /// - /// assert_eq!(Some(two), two.checked_next_power_of_two() ); - /// assert_eq!(Some(four), three.checked_next_power_of_two() ); - /// assert_eq!(None, max.checked_next_power_of_two() ); - /// # Some(()) - /// # } - /// ``` - #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] - #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_next_power_of_two(self) -> Option<$Ty> { - if let Some(nz) = self.get().checked_next_power_of_two() { - // SAFETY: The next power of two is positive - // and overflow is checked. - Some(unsafe { $Ty::new_unchecked(nz) }) - } else { - None - } - } + /// Returns the smallest power of two greater than or equal to n. + /// Checks for overflow and returns [`None`] + /// if the next power of two is greater than the type’s maximum value. + /// As a consequence, the result cannot wrap to zero. + /// + /// # Examples + /// + /// ``` + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] + #[doc = concat!("let three = ", stringify!($Ty), "::new(3)?;")] + #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")] + #[doc = concat!("let max = ", stringify!($Ty), "::new(", + stringify!($Int), "::MAX)?;")] + /// + /// assert_eq!(Some(two), two.checked_next_power_of_two() ); + /// assert_eq!(Some(four), three.checked_next_power_of_two() ); + /// assert_eq!(None, max.checked_next_power_of_two() ); + /// # Some(()) + /// # } + /// ``` + #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] + #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_next_power_of_two(self) -> Option<$Ty> { + if let Some(nz) = self.get().checked_next_power_of_two() { + // SAFETY: The next power of two is positive + // and overflow is checked. + Some(unsafe { $Ty::new_unchecked(nz) }) + } else { + None + } + } - /// Returns the base 2 logarithm of the number, rounded down. - /// - /// This is the same operation as - #[doc = concat!("[`", stringify!($Int), "::ilog2`],")] - /// except that it has no failure cases to worry about - /// since this value can never be zero. - /// - /// # Examples - /// - /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(7).unwrap().ilog2(), 2);")] - #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(8).unwrap().ilog2(), 3);")] - #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(9).unwrap().ilog2(), 3);")] - /// ``` - #[stable(feature = "int_log", since = "1.67.0")] - #[rustc_const_stable(feature = "int_log", since = "1.67.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn ilog2(self) -> u32 { - Self::BITS - 1 - self.leading_zeros() - } + /// Returns the base 2 logarithm of the number, rounded down. + /// + /// This is the same operation as + #[doc = concat!("[`", stringify!($Int), "::ilog2`],")] + /// except that it has no failure cases to worry about + /// since this value can never be zero. + /// + /// # Examples + /// + /// ``` + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(7).unwrap().ilog2(), 2);")] + #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(8).unwrap().ilog2(), 3);")] + #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(9).unwrap().ilog2(), 3);")] + /// ``` + #[stable(feature = "int_log", since = "1.67.0")] + #[rustc_const_stable(feature = "int_log", since = "1.67.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn ilog2(self) -> u32 { + Self::BITS - 1 - self.leading_zeros() + } - /// Returns the base 10 logarithm of the number, rounded down. - /// - /// This is the same operation as - #[doc = concat!("[`", stringify!($Int), "::ilog10`],")] - /// except that it has no failure cases to worry about - /// since this value can never be zero. - /// - /// # Examples - /// - /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(99).unwrap().ilog10(), 1);")] - #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(100).unwrap().ilog10(), 2);")] - #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(101).unwrap().ilog10(), 2);")] - /// ``` - #[stable(feature = "int_log", since = "1.67.0")] - #[rustc_const_stable(feature = "int_log", since = "1.67.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn ilog10(self) -> u32 { - super::int_log10::$Int(self.get()) - } + /// Returns the base 10 logarithm of the number, rounded down. + /// + /// This is the same operation as + #[doc = concat!("[`", stringify!($Int), "::ilog10`],")] + /// except that it has no failure cases to worry about + /// since this value can never be zero. + /// + /// # Examples + /// + /// ``` + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(99).unwrap().ilog10(), 1);")] + #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(100).unwrap().ilog10(), 2);")] + #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(101).unwrap().ilog10(), 2);")] + /// ``` + #[stable(feature = "int_log", since = "1.67.0")] + #[rustc_const_stable(feature = "int_log", since = "1.67.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn ilog10(self) -> u32 { + super::int_log10::$Int(self.get()) + } - /// Calculates the middle point of `self` and `rhs`. - /// - /// `midpoint(a, b)` is `(a + b) >> 1` as if it were performed in a - /// sufficiently-large signed integral type. This implies that the result is - /// always rounded towards negative infinity and that no overflow will ever occur. - /// - /// # Examples - /// - /// ``` - /// #![feature(num_midpoint)] - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// - /// # fn main() { test().unwrap(); } - /// # fn test() -> Option<()> { - #[doc = concat!("let one = ", stringify!($Ty), "::new(1)?;")] - #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] - #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")] - /// - /// assert_eq!(one.midpoint(four), two); - /// assert_eq!(four.midpoint(one), two); - /// # Some(()) - /// # } - /// ``` - #[unstable(feature = "num_midpoint", issue = "110840")] - #[rustc_const_unstable(feature = "const_num_midpoint", issue = "110840")] - #[rustc_allow_const_fn_unstable(const_num_midpoint)] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn midpoint(self, rhs: Self) -> Self { - // SAFETY: The only way to get `0` with midpoint is to have two opposite or - // near opposite numbers: (-5, 5), (0, 1), (0, 0) which is impossible because - // of the unsignedness of this number and also because $Ty is guaranteed to - // never being 0. - unsafe { $Ty::new_unchecked(self.get().midpoint(rhs.get())) } - } + /// Calculates the middle point of `self` and `rhs`. + /// + /// `midpoint(a, b)` is `(a + b) >> 1` as if it were performed in a + /// sufficiently-large signed integral type. This implies that the result is + /// always rounded towards negative infinity and that no overflow will ever occur. + /// + /// # Examples + /// + /// ``` + /// #![feature(num_midpoint)] + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let one = ", stringify!($Ty), "::new(1)?;")] + #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] + #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")] + /// + /// assert_eq!(one.midpoint(four), two); + /// assert_eq!(four.midpoint(one), two); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "num_midpoint", issue = "110840")] + #[rustc_const_unstable(feature = "const_num_midpoint", issue = "110840")] + #[rustc_allow_const_fn_unstable(const_num_midpoint)] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn midpoint(self, rhs: Self) -> Self { + // SAFETY: The only way to get `0` with midpoint is to have two opposite or + // near opposite numbers: (-5, 5), (0, 1), (0, 0) which is impossible because + // of the unsignedness of this number and also because $Ty is guaranteed to + // never being 0. + unsafe { $Ty::new_unchecked(self.get().midpoint(rhs.get())) } + } }; // Methods for signed nonzero types only. @@ -557,383 +557,383 @@ macro_rules! nonzero_integer_signedness_dependent_methods { UnsignedNonZero = $Uty:ident, UnsignedPrimitive = $Uint:ty, ) => { - /// Computes the absolute value of self. - #[doc = concat!("See [`", stringify!($Int), "::abs`]")] - /// for documentation on overflow behaviour. - /// - /// # Example - /// - /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// # fn main() { test().unwrap(); } - /// # fn test() -> Option<()> { - #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")] - #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")] - /// - /// assert_eq!(pos, pos.abs()); - /// assert_eq!(pos, neg.abs()); - /// # Some(()) - /// # } - /// ``` - #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] - #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn abs(self) -> $Ty { - // SAFETY: This cannot overflow to zero. - unsafe { $Ty::new_unchecked(self.get().abs()) } - } + /// Computes the absolute value of self. + #[doc = concat!("See [`", stringify!($Int), "::abs`]")] + /// for documentation on overflow behaviour. + /// + /// # Example + /// + /// ``` + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")] + #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")] + /// + /// assert_eq!(pos, pos.abs()); + /// assert_eq!(pos, neg.abs()); + /// # Some(()) + /// # } + /// ``` + #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] + #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn abs(self) -> $Ty { + // SAFETY: This cannot overflow to zero. + unsafe { $Ty::new_unchecked(self.get().abs()) } + } - /// Checked absolute value. - /// Checks for overflow and returns [`None`] if - #[doc = concat!("`self == ", stringify!($Ty), "::MIN`.")] - /// The result cannot be zero. - /// - /// # Example - /// - /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// # fn main() { test().unwrap(); } - /// # fn test() -> Option<()> { - #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")] - #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")] - #[doc = concat!("let min = ", stringify!($Ty), "::new(", - stringify!($Int), "::MIN)?;")] - /// - /// assert_eq!(Some(pos), neg.checked_abs()); - /// assert_eq!(None, min.checked_abs()); - /// # Some(()) - /// # } - /// ``` - #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] - #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_abs(self) -> Option<$Ty> { - if let Some(nz) = self.get().checked_abs() { - // SAFETY: absolute value of nonzero cannot yield zero values. - Some(unsafe { $Ty::new_unchecked(nz) }) - } else { - None - } - } + /// Checked absolute value. + /// Checks for overflow and returns [`None`] if + #[doc = concat!("`self == ", stringify!($Ty), "::MIN`.")] + /// The result cannot be zero. + /// + /// # Example + /// + /// ``` + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")] + #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")] + #[doc = concat!("let min = ", stringify!($Ty), "::new(", + stringify!($Int), "::MIN)?;")] + /// + /// assert_eq!(Some(pos), neg.checked_abs()); + /// assert_eq!(None, min.checked_abs()); + /// # Some(()) + /// # } + /// ``` + #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] + #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_abs(self) -> Option<$Ty> { + if let Some(nz) = self.get().checked_abs() { + // SAFETY: absolute value of nonzero cannot yield zero values. + Some(unsafe { $Ty::new_unchecked(nz) }) + } else { + None + } + } - /// Computes the absolute value of self, - /// with overflow information, see - #[doc = concat!("[`", stringify!($Int), "::overflowing_abs`].")] - /// - /// # Example - /// - /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// # fn main() { test().unwrap(); } - /// # fn test() -> Option<()> { - #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")] - #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")] - #[doc = concat!("let min = ", stringify!($Ty), "::new(", - stringify!($Int), "::MIN)?;")] - /// - /// assert_eq!((pos, false), pos.overflowing_abs()); - /// assert_eq!((pos, false), neg.overflowing_abs()); - /// assert_eq!((min, true), min.overflowing_abs()); - /// # Some(()) - /// # } - /// ``` - #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] - #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn overflowing_abs(self) -> ($Ty, bool) { - let (nz, flag) = self.get().overflowing_abs(); - ( - // SAFETY: absolute value of nonzero cannot yield zero values. - unsafe { $Ty::new_unchecked(nz) }, - flag, - ) - } + /// Computes the absolute value of self, + /// with overflow information, see + #[doc = concat!("[`", stringify!($Int), "::overflowing_abs`].")] + /// + /// # Example + /// + /// ``` + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")] + #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")] + #[doc = concat!("let min = ", stringify!($Ty), "::new(", + stringify!($Int), "::MIN)?;")] + /// + /// assert_eq!((pos, false), pos.overflowing_abs()); + /// assert_eq!((pos, false), neg.overflowing_abs()); + /// assert_eq!((min, true), min.overflowing_abs()); + /// # Some(()) + /// # } + /// ``` + #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] + #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_abs(self) -> ($Ty, bool) { + let (nz, flag) = self.get().overflowing_abs(); + ( + // SAFETY: absolute value of nonzero cannot yield zero values. + unsafe { $Ty::new_unchecked(nz) }, + flag, + ) + } - /// Saturating absolute value, see - #[doc = concat!("[`", stringify!($Int), "::saturating_abs`].")] - /// - /// # Example - /// - /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// # fn main() { test().unwrap(); } - /// # fn test() -> Option<()> { - #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")] - #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")] - #[doc = concat!("let min = ", stringify!($Ty), "::new(", - stringify!($Int), "::MIN)?;")] - #[doc = concat!("let min_plus = ", stringify!($Ty), "::new(", - stringify!($Int), "::MIN + 1)?;")] - #[doc = concat!("let max = ", stringify!($Ty), "::new(", - stringify!($Int), "::MAX)?;")] - /// - /// assert_eq!(pos, pos.saturating_abs()); - /// assert_eq!(pos, neg.saturating_abs()); - /// assert_eq!(max, min.saturating_abs()); - /// assert_eq!(max, min_plus.saturating_abs()); - /// # Some(()) - /// # } - /// ``` - #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] - #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn saturating_abs(self) -> $Ty { - // SAFETY: absolute value of nonzero cannot yield zero values. - unsafe { $Ty::new_unchecked(self.get().saturating_abs()) } - } + /// Saturating absolute value, see + #[doc = concat!("[`", stringify!($Int), "::saturating_abs`].")] + /// + /// # Example + /// + /// ``` + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")] + #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")] + #[doc = concat!("let min = ", stringify!($Ty), "::new(", + stringify!($Int), "::MIN)?;")] + #[doc = concat!("let min_plus = ", stringify!($Ty), "::new(", + stringify!($Int), "::MIN + 1)?;")] + #[doc = concat!("let max = ", stringify!($Ty), "::new(", + stringify!($Int), "::MAX)?;")] + /// + /// assert_eq!(pos, pos.saturating_abs()); + /// assert_eq!(pos, neg.saturating_abs()); + /// assert_eq!(max, min.saturating_abs()); + /// assert_eq!(max, min_plus.saturating_abs()); + /// # Some(()) + /// # } + /// ``` + #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] + #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn saturating_abs(self) -> $Ty { + // SAFETY: absolute value of nonzero cannot yield zero values. + unsafe { $Ty::new_unchecked(self.get().saturating_abs()) } + } - /// Wrapping absolute value, see - #[doc = concat!("[`", stringify!($Int), "::wrapping_abs`].")] - /// - /// # Example - /// - /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// # fn main() { test().unwrap(); } - /// # fn test() -> Option<()> { - #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")] - #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")] - #[doc = concat!("let min = ", stringify!($Ty), "::new(", - stringify!($Int), "::MIN)?;")] - #[doc = concat!("# let max = ", stringify!($Ty), "::new(", - stringify!($Int), "::MAX)?;")] - /// - /// assert_eq!(pos, pos.wrapping_abs()); - /// assert_eq!(pos, neg.wrapping_abs()); - /// assert_eq!(min, min.wrapping_abs()); - /// assert_eq!(max, (-max).wrapping_abs()); - /// # Some(()) - /// # } - /// ``` - #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] - #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_abs(self) -> $Ty { - // SAFETY: absolute value of nonzero cannot yield zero values. - unsafe { $Ty::new_unchecked(self.get().wrapping_abs()) } - } + /// Wrapping absolute value, see + #[doc = concat!("[`", stringify!($Int), "::wrapping_abs`].")] + /// + /// # Example + /// + /// ``` + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")] + #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")] + #[doc = concat!("let min = ", stringify!($Ty), "::new(", + stringify!($Int), "::MIN)?;")] + #[doc = concat!("# let max = ", stringify!($Ty), "::new(", + stringify!($Int), "::MAX)?;")] + /// + /// assert_eq!(pos, pos.wrapping_abs()); + /// assert_eq!(pos, neg.wrapping_abs()); + /// assert_eq!(min, min.wrapping_abs()); + /// assert_eq!(max, (-max).wrapping_abs()); + /// # Some(()) + /// # } + /// ``` + #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] + #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_abs(self) -> $Ty { + // SAFETY: absolute value of nonzero cannot yield zero values. + unsafe { $Ty::new_unchecked(self.get().wrapping_abs()) } + } - /// Computes the absolute value of self - /// without any wrapping or panicking. - /// - /// # Example - /// - /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - #[doc = concat!("# use std::num::", stringify!($Uty), ";")] - /// - /// # fn main() { test().unwrap(); } - /// # fn test() -> Option<()> { - #[doc = concat!("let u_pos = ", stringify!($Uty), "::new(1)?;")] - #[doc = concat!("let i_pos = ", stringify!($Ty), "::new(1)?;")] - #[doc = concat!("let i_neg = ", stringify!($Ty), "::new(-1)?;")] - #[doc = concat!("let i_min = ", stringify!($Ty), "::new(", - stringify!($Int), "::MIN)?;")] - #[doc = concat!("let u_max = ", stringify!($Uty), "::new(", - stringify!($Uint), "::MAX / 2 + 1)?;")] - /// - /// assert_eq!(u_pos, i_pos.unsigned_abs()); - /// assert_eq!(u_pos, i_neg.unsigned_abs()); - /// assert_eq!(u_max, i_min.unsigned_abs()); - /// # Some(()) - /// # } - /// ``` - #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] - #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn unsigned_abs(self) -> $Uty { - // SAFETY: absolute value of nonzero cannot yield zero values. - unsafe { $Uty::new_unchecked(self.get().unsigned_abs()) } - } + /// Computes the absolute value of self + /// without any wrapping or panicking. + /// + /// # Example + /// + /// ``` + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + #[doc = concat!("# use std::num::", stringify!($Uty), ";")] + /// + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let u_pos = ", stringify!($Uty), "::new(1)?;")] + #[doc = concat!("let i_pos = ", stringify!($Ty), "::new(1)?;")] + #[doc = concat!("let i_neg = ", stringify!($Ty), "::new(-1)?;")] + #[doc = concat!("let i_min = ", stringify!($Ty), "::new(", + stringify!($Int), "::MIN)?;")] + #[doc = concat!("let u_max = ", stringify!($Uty), "::new(", + stringify!($Uint), "::MAX / 2 + 1)?;")] + /// + /// assert_eq!(u_pos, i_pos.unsigned_abs()); + /// assert_eq!(u_pos, i_neg.unsigned_abs()); + /// assert_eq!(u_max, i_min.unsigned_abs()); + /// # Some(()) + /// # } + /// ``` + #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] + #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn unsigned_abs(self) -> $Uty { + // SAFETY: absolute value of nonzero cannot yield zero values. + unsafe { $Uty::new_unchecked(self.get().unsigned_abs()) } + } - /// Returns `true` if `self` is positive and `false` if the - /// number is negative. - /// - /// # Example - /// - /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// # fn main() { test().unwrap(); } - /// # fn test() -> Option<()> { - #[doc = concat!("let pos_five = ", stringify!($Ty), "::new(5)?;")] - #[doc = concat!("let neg_five = ", stringify!($Ty), "::new(-5)?;")] - /// - /// assert!(pos_five.is_positive()); - /// assert!(!neg_five.is_positive()); - /// # Some(()) - /// # } - /// ``` - #[must_use] - #[inline] - #[stable(feature = "nonzero_negation_ops", since = "1.71.0")] - #[rustc_const_stable(feature = "nonzero_negation_ops", since = "1.71.0")] - pub const fn is_positive(self) -> bool { - self.get().is_positive() - } + /// Returns `true` if `self` is positive and `false` if the + /// number is negative. + /// + /// # Example + /// + /// ``` + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let pos_five = ", stringify!($Ty), "::new(5)?;")] + #[doc = concat!("let neg_five = ", stringify!($Ty), "::new(-5)?;")] + /// + /// assert!(pos_five.is_positive()); + /// assert!(!neg_five.is_positive()); + /// # Some(()) + /// # } + /// ``` + #[must_use] + #[inline] + #[stable(feature = "nonzero_negation_ops", since = "1.71.0")] + #[rustc_const_stable(feature = "nonzero_negation_ops", since = "1.71.0")] + pub const fn is_positive(self) -> bool { + self.get().is_positive() + } - /// Returns `true` if `self` is negative and `false` if the - /// number is positive. - /// - /// # Example - /// - /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// # fn main() { test().unwrap(); } - /// # fn test() -> Option<()> { - #[doc = concat!("let pos_five = ", stringify!($Ty), "::new(5)?;")] - #[doc = concat!("let neg_five = ", stringify!($Ty), "::new(-5)?;")] - /// - /// assert!(neg_five.is_negative()); - /// assert!(!pos_five.is_negative()); - /// # Some(()) - /// # } - /// ``` - #[must_use] - #[inline] - #[stable(feature = "nonzero_negation_ops", since = "1.71.0")] - #[rustc_const_stable(feature = "nonzero_negation_ops", since = "1.71.0")] - pub const fn is_negative(self) -> bool { - self.get().is_negative() - } + /// Returns `true` if `self` is negative and `false` if the + /// number is positive. + /// + /// # Example + /// + /// ``` + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let pos_five = ", stringify!($Ty), "::new(5)?;")] + #[doc = concat!("let neg_five = ", stringify!($Ty), "::new(-5)?;")] + /// + /// assert!(neg_five.is_negative()); + /// assert!(!pos_five.is_negative()); + /// # Some(()) + /// # } + /// ``` + #[must_use] + #[inline] + #[stable(feature = "nonzero_negation_ops", since = "1.71.0")] + #[rustc_const_stable(feature = "nonzero_negation_ops", since = "1.71.0")] + pub const fn is_negative(self) -> bool { + self.get().is_negative() + } - /// Checked negation. Computes `-self`, - #[doc = concat!("returning `None` if `self == ", stringify!($Ty), "::MIN`.")] - /// - /// # Example - /// - /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// # fn main() { test().unwrap(); } - /// # fn test() -> Option<()> { - #[doc = concat!("let pos_five = ", stringify!($Ty), "::new(5)?;")] - #[doc = concat!("let neg_five = ", stringify!($Ty), "::new(-5)?;")] - #[doc = concat!("let min = ", stringify!($Ty), "::new(", - stringify!($Int), "::MIN)?;")] - /// - /// assert_eq!(pos_five.checked_neg(), Some(neg_five)); - /// assert_eq!(min.checked_neg(), None); - /// # Some(()) - /// # } - /// ``` - #[inline] - #[stable(feature = "nonzero_negation_ops", since = "1.71.0")] - #[rustc_const_stable(feature = "nonzero_negation_ops", since = "1.71.0")] - pub const fn checked_neg(self) -> Option<$Ty> { - if let Some(result) = self.get().checked_neg() { - // SAFETY: negation of nonzero cannot yield zero values. - return Some(unsafe { $Ty::new_unchecked(result) }); - } - None - } + /// Checked negation. Computes `-self`, + #[doc = concat!("returning `None` if `self == ", stringify!($Ty), "::MIN`.")] + /// + /// # Example + /// + /// ``` + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let pos_five = ", stringify!($Ty), "::new(5)?;")] + #[doc = concat!("let neg_five = ", stringify!($Ty), "::new(-5)?;")] + #[doc = concat!("let min = ", stringify!($Ty), "::new(", + stringify!($Int), "::MIN)?;")] + /// + /// assert_eq!(pos_five.checked_neg(), Some(neg_five)); + /// assert_eq!(min.checked_neg(), None); + /// # Some(()) + /// # } + /// ``` + #[inline] + #[stable(feature = "nonzero_negation_ops", since = "1.71.0")] + #[rustc_const_stable(feature = "nonzero_negation_ops", since = "1.71.0")] + pub const fn checked_neg(self) -> Option<$Ty> { + if let Some(result) = self.get().checked_neg() { + // SAFETY: negation of nonzero cannot yield zero values. + return Some(unsafe { $Ty::new_unchecked(result) }); + } + None + } - /// Negates self, overflowing if this is equal to the minimum value. - /// - #[doc = concat!("See [`", stringify!($Int), "::overflowing_neg`]")] - /// for documentation on overflow behaviour. - /// - /// # Example - /// - /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// # fn main() { test().unwrap(); } - /// # fn test() -> Option<()> { - #[doc = concat!("let pos_five = ", stringify!($Ty), "::new(5)?;")] - #[doc = concat!("let neg_five = ", stringify!($Ty), "::new(-5)?;")] - #[doc = concat!("let min = ", stringify!($Ty), "::new(", - stringify!($Int), "::MIN)?;")] - /// - /// assert_eq!(pos_five.overflowing_neg(), (neg_five, false)); - /// assert_eq!(min.overflowing_neg(), (min, true)); - /// # Some(()) - /// # } - /// ``` - #[inline] - #[stable(feature = "nonzero_negation_ops", since = "1.71.0")] - #[rustc_const_stable(feature = "nonzero_negation_ops", since = "1.71.0")] - pub const fn overflowing_neg(self) -> ($Ty, bool) { - let (result, overflow) = self.get().overflowing_neg(); - // SAFETY: negation of nonzero cannot yield zero values. - ((unsafe { $Ty::new_unchecked(result) }), overflow) - } + /// Negates self, overflowing if this is equal to the minimum value. + /// + #[doc = concat!("See [`", stringify!($Int), "::overflowing_neg`]")] + /// for documentation on overflow behaviour. + /// + /// # Example + /// + /// ``` + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let pos_five = ", stringify!($Ty), "::new(5)?;")] + #[doc = concat!("let neg_five = ", stringify!($Ty), "::new(-5)?;")] + #[doc = concat!("let min = ", stringify!($Ty), "::new(", + stringify!($Int), "::MIN)?;")] + /// + /// assert_eq!(pos_five.overflowing_neg(), (neg_five, false)); + /// assert_eq!(min.overflowing_neg(), (min, true)); + /// # Some(()) + /// # } + /// ``` + #[inline] + #[stable(feature = "nonzero_negation_ops", since = "1.71.0")] + #[rustc_const_stable(feature = "nonzero_negation_ops", since = "1.71.0")] + pub const fn overflowing_neg(self) -> ($Ty, bool) { + let (result, overflow) = self.get().overflowing_neg(); + // SAFETY: negation of nonzero cannot yield zero values. + ((unsafe { $Ty::new_unchecked(result) }), overflow) + } - /// Saturating negation. Computes `-self`, - #[doc = concat!("returning [`", stringify!($Ty), "::MAX`]")] - #[doc = concat!("if `self == ", stringify!($Ty), "::MIN`")] - /// instead of overflowing. - /// - /// # Example - /// - /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// # fn main() { test().unwrap(); } - /// # fn test() -> Option<()> { - #[doc = concat!("let pos_five = ", stringify!($Ty), "::new(5)?;")] - #[doc = concat!("let neg_five = ", stringify!($Ty), "::new(-5)?;")] - #[doc = concat!("let min = ", stringify!($Ty), "::new(", - stringify!($Int), "::MIN)?;")] - #[doc = concat!("let min_plus_one = ", stringify!($Ty), "::new(", - stringify!($Int), "::MIN + 1)?;")] - #[doc = concat!("let max = ", stringify!($Ty), "::new(", - stringify!($Int), "::MAX)?;")] - /// - /// assert_eq!(pos_five.saturating_neg(), neg_five); - /// assert_eq!(min.saturating_neg(), max); - /// assert_eq!(max.saturating_neg(), min_plus_one); - /// # Some(()) - /// # } - /// ``` - #[inline] - #[stable(feature = "nonzero_negation_ops", since = "1.71.0")] - #[rustc_const_stable(feature = "nonzero_negation_ops", since = "1.71.0")] - pub const fn saturating_neg(self) -> $Ty { - if let Some(result) = self.checked_neg() { - return result; - } - $Ty::MAX - } + /// Saturating negation. Computes `-self`, + #[doc = concat!("returning [`", stringify!($Ty), "::MAX`]")] + #[doc = concat!("if `self == ", stringify!($Ty), "::MIN`")] + /// instead of overflowing. + /// + /// # Example + /// + /// ``` + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let pos_five = ", stringify!($Ty), "::new(5)?;")] + #[doc = concat!("let neg_five = ", stringify!($Ty), "::new(-5)?;")] + #[doc = concat!("let min = ", stringify!($Ty), "::new(", + stringify!($Int), "::MIN)?;")] + #[doc = concat!("let min_plus_one = ", stringify!($Ty), "::new(", + stringify!($Int), "::MIN + 1)?;")] + #[doc = concat!("let max = ", stringify!($Ty), "::new(", + stringify!($Int), "::MAX)?;")] + /// + /// assert_eq!(pos_five.saturating_neg(), neg_five); + /// assert_eq!(min.saturating_neg(), max); + /// assert_eq!(max.saturating_neg(), min_plus_one); + /// # Some(()) + /// # } + /// ``` + #[inline] + #[stable(feature = "nonzero_negation_ops", since = "1.71.0")] + #[rustc_const_stable(feature = "nonzero_negation_ops", since = "1.71.0")] + pub const fn saturating_neg(self) -> $Ty { + if let Some(result) = self.checked_neg() { + return result; + } + $Ty::MAX + } - /// Wrapping (modular) negation. Computes `-self`, wrapping around at the boundary - /// of the type. - /// - #[doc = concat!("See [`", stringify!($Int), "::wrapping_neg`]")] - /// for documentation on overflow behaviour. - /// - /// # Example - /// - /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// # fn main() { test().unwrap(); } - /// # fn test() -> Option<()> { - #[doc = concat!("let pos_five = ", stringify!($Ty), "::new(5)?;")] - #[doc = concat!("let neg_five = ", stringify!($Ty), "::new(-5)?;")] - #[doc = concat!("let min = ", stringify!($Ty), "::new(", - stringify!($Int), "::MIN)?;")] - /// - /// assert_eq!(pos_five.wrapping_neg(), neg_five); - /// assert_eq!(min.wrapping_neg(), min); - /// # Some(()) - /// # } - /// ``` - #[inline] - #[stable(feature = "nonzero_negation_ops", since = "1.71.0")] - #[rustc_const_stable(feature = "nonzero_negation_ops", since = "1.71.0")] - pub const fn wrapping_neg(self) -> $Ty { - let result = self.get().wrapping_neg(); - // SAFETY: negation of nonzero cannot yield zero values. - unsafe { $Ty::new_unchecked(result) } - } + /// Wrapping (modular) negation. Computes `-self`, wrapping around at the boundary + /// of the type. + /// + #[doc = concat!("See [`", stringify!($Int), "::wrapping_neg`]")] + /// for documentation on overflow behaviour. + /// + /// # Example + /// + /// ``` + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let pos_five = ", stringify!($Ty), "::new(5)?;")] + #[doc = concat!("let neg_five = ", stringify!($Ty), "::new(-5)?;")] + #[doc = concat!("let min = ", stringify!($Ty), "::new(", + stringify!($Int), "::MIN)?;")] + /// + /// assert_eq!(pos_five.wrapping_neg(), neg_five); + /// assert_eq!(min.wrapping_neg(), min); + /// # Some(()) + /// # } + /// ``` + #[inline] + #[stable(feature = "nonzero_negation_ops", since = "1.71.0")] + #[rustc_const_stable(feature = "nonzero_negation_ops", since = "1.71.0")] + pub const fn wrapping_neg(self) -> $Ty { + let result = self.get().wrapping_neg(); + // SAFETY: negation of nonzero cannot yield zero values. + unsafe { $Ty::new_unchecked(result) } + } }; } From c6d776ef4ba4f133b5f370f144b99cd3f39388fa Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 5 Dec 2023 22:38:38 -0800 Subject: [PATCH 0215/1197] Work around rustfmt doc attribute indentation bug --- library/core/src/num/nonzero.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 8550a7b4c7b68..6b28f8100e78a 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -312,6 +312,7 @@ macro_rules! nonzero_integer_signedness_dependent_impls { }; } +#[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/5974 macro_rules! nonzero_integer_signedness_dependent_methods { // Methods for unsigned nonzero types only. ( From 63256af236f4620701d7d8771f874c4ef57e6ff2 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 5 Dec 2023 22:46:18 -0800 Subject: [PATCH 0216/1197] Move nonzero_unsigned_signed_operations methods into the omnibus impl block --- library/core/src/num/nonzero.rs | 426 +++++++++++++++----------------- 1 file changed, 201 insertions(+), 225 deletions(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 6b28f8100e78a..c9693a22e8761 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -181,6 +181,207 @@ macro_rules! nonzero_integer { $(UnsignedNonZero = $UnsignedNonZero,)? UnsignedPrimitive = $UnsignedPrimitive, } + + /// Multiplies two non-zero integers together. + /// Checks for overflow and returns [`None`] on overflow. + /// As a consequence, the result cannot wrap to zero. + /// + /// # Examples + /// + /// ``` + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] + #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")] + #[doc = concat!("let max = ", stringify!($Ty), "::new(", + stringify!($Int), "::MAX)?;")] + /// + /// assert_eq!(Some(four), two.checked_mul(two)); + /// assert_eq!(None, max.checked_mul(two)); + /// # Some(()) + /// # } + /// ``` + #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] + #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_mul(self, other: $Ty) -> Option<$Ty> { + if let Some(result) = self.get().checked_mul(other.get()) { + // SAFETY: + // - `checked_mul` returns `None` on overflow + // - `self` and `other` are non-zero + // - the only way to get zero from a multiplication without overflow is for one + // of the sides to be zero + // + // So the result cannot be zero. + Some(unsafe { $Ty::new_unchecked(result) }) + } else { + None + } + } + + /// Multiplies two non-zero integers together. + #[doc = concat!("Return [`", stringify!($Ty), "::MAX`] on overflow.")] + /// + /// # Examples + /// + /// ``` + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] + #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")] + #[doc = concat!("let max = ", stringify!($Ty), "::new(", + stringify!($Int), "::MAX)?;")] + /// + /// assert_eq!(four, two.saturating_mul(two)); + /// assert_eq!(max, four.saturating_mul(max)); + /// # Some(()) + /// # } + /// ``` + #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] + #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn saturating_mul(self, other: $Ty) -> $Ty { + // SAFETY: + // - `saturating_mul` returns `u*::MAX`/`i*::MAX`/`i*::MIN` on overflow/underflow, + // all of which are non-zero + // - `self` and `other` are non-zero + // - the only way to get zero from a multiplication without overflow is for one + // of the sides to be zero + // + // So the result cannot be zero. + unsafe { $Ty::new_unchecked(self.get().saturating_mul(other.get())) } + } + + /// Multiplies two non-zero integers together, + /// assuming overflow cannot occur. + /// Overflow is unchecked, and it is undefined behaviour to overflow + /// *even if the result would wrap to a non-zero value*. + /// The behaviour is undefined as soon as + #[doc = sign_dependent_expr!{ + $signedness ? + if signed { + concat!("`self * rhs > ", stringify!($Int), "::MAX`, ", + "or `self * rhs < ", stringify!($Int), "::MIN`.") + } + if unsigned { + concat!("`self * rhs > ", stringify!($Int), "::MAX`.") + } + }] + /// + /// # Examples + /// + /// ``` + /// #![feature(nonzero_ops)] + /// + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] + #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")] + /// + /// assert_eq!(four, unsafe { two.unchecked_mul(two) }); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_ops", issue = "84186")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const unsafe fn unchecked_mul(self, other: $Ty) -> $Ty { + // SAFETY: The caller ensures there is no overflow. + unsafe { $Ty::new_unchecked(self.get().unchecked_mul(other.get())) } + } + + /// Raises non-zero value to an integer power. + /// Checks for overflow and returns [`None`] on overflow. + /// As a consequence, the result cannot wrap to zero. + /// + /// # Examples + /// + /// ``` + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let three = ", stringify!($Ty), "::new(3)?;")] + #[doc = concat!("let twenty_seven = ", stringify!($Ty), "::new(27)?;")] + #[doc = concat!("let half_max = ", stringify!($Ty), "::new(", + stringify!($Int), "::MAX / 2)?;")] + /// + /// assert_eq!(Some(twenty_seven), three.checked_pow(3)); + /// assert_eq!(None, half_max.checked_pow(3)); + /// # Some(()) + /// # } + /// ``` + #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] + #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_pow(self, other: u32) -> Option<$Ty> { + if let Some(result) = self.get().checked_pow(other) { + // SAFETY: + // - `checked_pow` returns `None` on overflow/underflow + // - `self` is non-zero + // - the only way to get zero from an exponentiation without overflow is + // for base to be zero + // + // So the result cannot be zero. + Some(unsafe { $Ty::new_unchecked(result) }) + } else { + None + } + } + + /// Raise non-zero value to an integer power. + #[doc = sign_dependent_expr!{ + $signedness ? + if signed { + concat!("Return [`", stringify!($Ty), "::MIN`] ", + "or [`", stringify!($Ty), "::MAX`] on overflow.") + } + if unsigned { + concat!("Return [`", stringify!($Ty), "::MAX`] on overflow.") + } + }] + /// + /// # Examples + /// + /// ``` + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let three = ", stringify!($Ty), "::new(3)?;")] + #[doc = concat!("let twenty_seven = ", stringify!($Ty), "::new(27)?;")] + #[doc = concat!("let max = ", stringify!($Ty), "::new(", + stringify!($Int), "::MAX)?;")] + /// + /// assert_eq!(twenty_seven, three.saturating_pow(3)); + /// assert_eq!(max, max.saturating_pow(3)); + /// # Some(()) + /// # } + /// ``` + #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] + #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn saturating_pow(self, other: u32) -> $Ty { + // SAFETY: + // - `saturating_pow` returns `u*::MAX`/`i*::MAX`/`i*::MIN` on overflow/underflow, + // all of which are non-zero + // - `self` is non-zero + // - the only way to get zero from an exponentiation without overflow is + // for base to be zero + // + // So the result cannot be zero. + unsafe { $Ty::new_unchecked(self.get().saturating_pow(other)) } + } } #[stable(feature = "from_nonzero", since = "1.31.0")] @@ -938,216 +1139,6 @@ macro_rules! nonzero_integer_signedness_dependent_methods { }; } -// A bunch of methods for both signed and unsigned nonzero types. -macro_rules! nonzero_unsigned_signed_operations { - ( $( $signedness:ident $Ty: ident($Int: ty); )+ ) => { - $( - impl $Ty { - /// Multiplies two non-zero integers together. - /// Checks for overflow and returns [`None`] on overflow. - /// As a consequence, the result cannot wrap to zero. - /// - /// # Examples - /// - /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// # fn main() { test().unwrap(); } - /// # fn test() -> Option<()> { - #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] - #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")] - #[doc = concat!("let max = ", stringify!($Ty), "::new(", - stringify!($Int), "::MAX)?;")] - /// - /// assert_eq!(Some(four), two.checked_mul(two)); - /// assert_eq!(None, max.checked_mul(two)); - /// # Some(()) - /// # } - /// ``` - #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] - #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_mul(self, other: $Ty) -> Option<$Ty> { - if let Some(result) = self.get().checked_mul(other.get()) { - // SAFETY: - // - `checked_mul` returns `None` on overflow - // - `self` and `other` are non-zero - // - the only way to get zero from a multiplication without overflow is for one - // of the sides to be zero - // - // So the result cannot be zero. - Some(unsafe { $Ty::new_unchecked(result) }) - } else { - None - } - } - - /// Multiplies two non-zero integers together. - #[doc = concat!("Return [`", stringify!($Ty), "::MAX`] on overflow.")] - /// - /// # Examples - /// - /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// # fn main() { test().unwrap(); } - /// # fn test() -> Option<()> { - #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] - #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")] - #[doc = concat!("let max = ", stringify!($Ty), "::new(", - stringify!($Int), "::MAX)?;")] - /// - /// assert_eq!(four, two.saturating_mul(two)); - /// assert_eq!(max, four.saturating_mul(max)); - /// # Some(()) - /// # } - /// ``` - #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] - #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn saturating_mul(self, other: $Ty) -> $Ty { - // SAFETY: - // - `saturating_mul` returns `u*::MAX`/`i*::MAX`/`i*::MIN` on overflow/underflow, - // all of which are non-zero - // - `self` and `other` are non-zero - // - the only way to get zero from a multiplication without overflow is for one - // of the sides to be zero - // - // So the result cannot be zero. - unsafe { $Ty::new_unchecked(self.get().saturating_mul(other.get())) } - } - - /// Multiplies two non-zero integers together, - /// assuming overflow cannot occur. - /// Overflow is unchecked, and it is undefined behaviour to overflow - /// *even if the result would wrap to a non-zero value*. - /// The behaviour is undefined as soon as - #[doc = sign_dependent_expr!{ - $signedness ? - if signed { - concat!("`self * rhs > ", stringify!($Int), "::MAX`, ", - "or `self * rhs < ", stringify!($Int), "::MIN`.") - } - if unsigned { - concat!("`self * rhs > ", stringify!($Int), "::MAX`.") - } - }] - /// - /// # Examples - /// - /// ``` - /// #![feature(nonzero_ops)] - /// - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// # fn main() { test().unwrap(); } - /// # fn test() -> Option<()> { - #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] - #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")] - /// - /// assert_eq!(four, unsafe { two.unchecked_mul(two) }); - /// # Some(()) - /// # } - /// ``` - #[unstable(feature = "nonzero_ops", issue = "84186")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const unsafe fn unchecked_mul(self, other: $Ty) -> $Ty { - // SAFETY: The caller ensures there is no overflow. - unsafe { $Ty::new_unchecked(self.get().unchecked_mul(other.get())) } - } - - /// Raises non-zero value to an integer power. - /// Checks for overflow and returns [`None`] on overflow. - /// As a consequence, the result cannot wrap to zero. - /// - /// # Examples - /// - /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// # fn main() { test().unwrap(); } - /// # fn test() -> Option<()> { - #[doc = concat!("let three = ", stringify!($Ty), "::new(3)?;")] - #[doc = concat!("let twenty_seven = ", stringify!($Ty), "::new(27)?;")] - #[doc = concat!("let half_max = ", stringify!($Ty), "::new(", - stringify!($Int), "::MAX / 2)?;")] - /// - /// assert_eq!(Some(twenty_seven), three.checked_pow(3)); - /// assert_eq!(None, half_max.checked_pow(3)); - /// # Some(()) - /// # } - /// ``` - #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] - #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_pow(self, other: u32) -> Option<$Ty> { - if let Some(result) = self.get().checked_pow(other) { - // SAFETY: - // - `checked_pow` returns `None` on overflow/underflow - // - `self` is non-zero - // - the only way to get zero from an exponentiation without overflow is - // for base to be zero - // - // So the result cannot be zero. - Some(unsafe { $Ty::new_unchecked(result) }) - } else { - None - } - } - - /// Raise non-zero value to an integer power. - #[doc = sign_dependent_expr!{ - $signedness ? - if signed { - concat!("Return [`", stringify!($Ty), "::MIN`] ", - "or [`", stringify!($Ty), "::MAX`] on overflow.") - } - if unsigned { - concat!("Return [`", stringify!($Ty), "::MAX`] on overflow.") - } - }] - /// - /// # Examples - /// - /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// # fn main() { test().unwrap(); } - /// # fn test() -> Option<()> { - #[doc = concat!("let three = ", stringify!($Ty), "::new(3)?;")] - #[doc = concat!("let twenty_seven = ", stringify!($Ty), "::new(27)?;")] - #[doc = concat!("let max = ", stringify!($Ty), "::new(", - stringify!($Int), "::MAX)?;")] - /// - /// assert_eq!(twenty_seven, three.saturating_pow(3)); - /// assert_eq!(max, max.saturating_pow(3)); - /// # Some(()) - /// # } - /// ``` - #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] - #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn saturating_pow(self, other: u32) -> $Ty { - // SAFETY: - // - `saturating_pow` returns `u*::MAX`/`i*::MAX`/`i*::MIN` on overflow/underflow, - // all of which are non-zero - // - `self` is non-zero - // - the only way to get zero from an exponentiation without overflow is - // for base to be zero - // - // So the result cannot be zero. - unsafe { $Ty::new_unchecked(self.get().saturating_pow(other)) } - } - } - )+ - } -} - // Use this when the generated code should differ between signed and unsigned types. macro_rules! sign_dependent_expr { (signed ? if signed { $signed_case:expr } if unsigned { $unsigned_case:expr } ) => { @@ -1158,21 +1149,6 @@ macro_rules! sign_dependent_expr { }; } -nonzero_unsigned_signed_operations! { - unsigned NonZeroU8(u8); - unsigned NonZeroU16(u16); - unsigned NonZeroU32(u32); - unsigned NonZeroU64(u64); - unsigned NonZeroU128(u128); - unsigned NonZeroUsize(usize); - signed NonZeroI8(i8); - signed NonZeroI16(i16); - signed NonZeroI32(i32); - signed NonZeroI64(i64); - signed NonZeroI128(i128); - signed NonZeroIsize(isize); -} - macro_rules! nonzero_unsigned_is_power_of_two { ( $( $Ty: ident )+ ) => { $( From 441913626d33919b743e167c5c9e951487291fdd Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 5 Dec 2023 22:47:53 -0800 Subject: [PATCH 0217/1197] Move is_power_of_two into unsigned part of signedness_dependent_methods --- library/core/src/num/nonzero.rs | 68 ++++++++++++++------------------- 1 file changed, 28 insertions(+), 40 deletions(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index c9693a22e8761..0c34012ab5c61 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -750,6 +750,34 @@ macro_rules! nonzero_integer_signedness_dependent_methods { // never being 0. unsafe { $Ty::new_unchecked(self.get().midpoint(rhs.get())) } } + + /// Returns `true` if and only if `self == (1 << k)` for some `k`. + /// + /// On many architectures, this function can perform better than `is_power_of_two()` + /// on the underlying integer type, as special handling of zero can be avoided. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + #[doc = concat!("let eight = std::num::", stringify!($Ty), "::new(8).unwrap();")] + /// assert!(eight.is_power_of_two()); + #[doc = concat!("let ten = std::num::", stringify!($Ty), "::new(10).unwrap();")] + /// assert!(!ten.is_power_of_two()); + /// ``` + #[must_use] + #[stable(feature = "nonzero_is_power_of_two", since = "1.59.0")] + #[rustc_const_stable(feature = "nonzero_is_power_of_two", since = "1.59.0")] + #[inline] + pub const fn is_power_of_two(self) -> bool { + // LLVM 11 normalizes `unchecked_sub(x, 1) & x == 0` to the implementation seen here. + // On the basic x86-64 target, this saves 3 instructions for the zero check. + // On x86_64 with BMI1, being nonzero lets it codegen to `BLSR`, which saves an instruction + // compared to the `POPCNT` implementation on the underlying integer type. + + intrinsics::ctpop(self.get()) < 2 + } }; // Methods for signed nonzero types only. @@ -1149,46 +1177,6 @@ macro_rules! sign_dependent_expr { }; } -macro_rules! nonzero_unsigned_is_power_of_two { - ( $( $Ty: ident )+ ) => { - $( - impl $Ty { - - /// Returns `true` if and only if `self == (1 << k)` for some `k`. - /// - /// On many architectures, this function can perform better than `is_power_of_two()` - /// on the underlying integer type, as special handling of zero can be avoided. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - #[doc = concat!("let eight = std::num::", stringify!($Ty), "::new(8).unwrap();")] - /// assert!(eight.is_power_of_two()); - #[doc = concat!("let ten = std::num::", stringify!($Ty), "::new(10).unwrap();")] - /// assert!(!ten.is_power_of_two()); - /// ``` - #[must_use] - #[stable(feature = "nonzero_is_power_of_two", since = "1.59.0")] - #[rustc_const_stable(feature = "nonzero_is_power_of_two", since = "1.59.0")] - #[inline] - pub const fn is_power_of_two(self) -> bool { - // LLVM 11 normalizes `unchecked_sub(x, 1) & x == 0` to the implementation seen here. - // On the basic x86-64 target, this saves 3 instructions for the zero check. - // On x86_64 with BMI1, being nonzero lets it codegen to `BLSR`, which saves an instruction - // compared to the `POPCNT` implementation on the underlying integer type. - - intrinsics::ctpop(self.get()) < 2 - } - - } - )+ - } -} - -nonzero_unsigned_is_power_of_two! { NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroU128 NonZeroUsize } - macro_rules! nonzero_min_max_unsigned { ( $( $Ty: ident($Int: ident); )+ ) => { $( From 7f7c5af097678da556cd57936a8d8b6c02858502 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 5 Dec 2023 22:49:44 -0800 Subject: [PATCH 0218/1197] Move unsigned MIN and MAX into signedness_dependent_methods --- library/core/src/num/nonzero.rs | 69 +++++++++++++-------------------- 1 file changed, 26 insertions(+), 43 deletions(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 0c34012ab5c61..0ab89aa0d6c24 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -515,12 +515,37 @@ macro_rules! nonzero_integer_signedness_dependent_impls { #[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/5974 macro_rules! nonzero_integer_signedness_dependent_methods { - // Methods for unsigned nonzero types only. + // Associated items for unsigned nonzero types only. ( Self = $Ty:ident, Primitive = unsigned $Int:ident, UnsignedPrimitive = $Uint:ty, ) => { + /// The smallest value that can be represented by this non-zero + /// integer type, 1. + /// + /// # Examples + /// + /// ``` + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + #[doc = concat!("assert_eq!(", stringify!($Ty), "::MIN.get(), 1", stringify!($Int), ");")] + /// ``` + #[stable(feature = "nonzero_min_max", since = "1.70.0")] + pub const MIN: Self = Self::new(1).unwrap(); + + /// The largest value that can be represented by this non-zero + /// integer type, + #[doc = concat!("equal to [`", stringify!($Int), "::MAX`].")] + /// + /// # Examples + /// + /// ``` + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + #[doc = concat!("assert_eq!(", stringify!($Ty), "::MAX.get(), ", stringify!($Int), "::MAX);")] + /// ``` + #[stable(feature = "nonzero_min_max", since = "1.70.0")] + pub const MAX: Self = Self::new(<$Int>::MAX).unwrap(); + /// Adds an unsigned integer to a non-zero value. /// Checks for overflow and returns [`None`] on overflow. /// As a consequence, the result cannot wrap to zero. @@ -1177,39 +1202,6 @@ macro_rules! sign_dependent_expr { }; } -macro_rules! nonzero_min_max_unsigned { - ( $( $Ty: ident($Int: ident); )+ ) => { - $( - impl $Ty { - /// The smallest value that can be represented by this non-zero - /// integer type, 1. - /// - /// # Examples - /// - /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - #[doc = concat!("assert_eq!(", stringify!($Ty), "::MIN.get(), 1", stringify!($Int), ");")] - /// ``` - #[stable(feature = "nonzero_min_max", since = "1.70.0")] - pub const MIN: Self = Self::new(1).unwrap(); - - /// The largest value that can be represented by this non-zero - /// integer type, - #[doc = concat!("equal to [`", stringify!($Int), "::MAX`].")] - /// - /// # Examples - /// - /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - #[doc = concat!("assert_eq!(", stringify!($Ty), "::MAX.get(), ", stringify!($Int), "::MAX);")] - /// ``` - #[stable(feature = "nonzero_min_max", since = "1.70.0")] - pub const MAX: Self = Self::new(<$Int>::MAX).unwrap(); - } - )+ - } -} - macro_rules! nonzero_min_max_signed { ( $( $Ty: ident($Int: ident); )+ ) => { $( @@ -1252,15 +1244,6 @@ macro_rules! nonzero_min_max_signed { } } -nonzero_min_max_unsigned! { - NonZeroU8(u8); - NonZeroU16(u16); - NonZeroU32(u32); - NonZeroU64(u64); - NonZeroU128(u128); - NonZeroUsize(usize); -} - nonzero_min_max_signed! { NonZeroI8(i8); NonZeroI16(i16); From 66cda3b75fb35655076b1fa555bf4f95fdd9b54e Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 5 Dec 2023 22:50:31 -0800 Subject: [PATCH 0219/1197] Move signed MIN and MAX into signedness_dependent_methods --- library/core/src/num/nonzero.rs | 87 +++++++++++++-------------------- 1 file changed, 35 insertions(+), 52 deletions(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 0ab89aa0d6c24..9c48a5b0dbddd 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -805,13 +805,47 @@ macro_rules! nonzero_integer_signedness_dependent_methods { } }; - // Methods for signed nonzero types only. + // Associated items for signed nonzero types only. ( Self = $Ty:ident, Primitive = signed $Int:ident, UnsignedNonZero = $Uty:ident, UnsignedPrimitive = $Uint:ty, ) => { + /// The smallest value that can be represented by this non-zero + /// integer type, + #[doc = concat!("equal to [`", stringify!($Int), "::MIN`].")] + /// + /// Note: While most integer types are defined for every whole + /// number between `MIN` and `MAX`, signed non-zero integers are + /// a special case. They have a "gap" at 0. + /// + /// # Examples + /// + /// ``` + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + #[doc = concat!("assert_eq!(", stringify!($Ty), "::MIN.get(), ", stringify!($Int), "::MIN);")] + /// ``` + #[stable(feature = "nonzero_min_max", since = "1.70.0")] + pub const MIN: Self = Self::new(<$Int>::MIN).unwrap(); + + /// The largest value that can be represented by this non-zero + /// integer type, + #[doc = concat!("equal to [`", stringify!($Int), "::MAX`].")] + /// + /// Note: While most integer types are defined for every whole + /// number between `MIN` and `MAX`, signed non-zero integers are + /// a special case. They have a "gap" at 0. + /// + /// # Examples + /// + /// ``` + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + #[doc = concat!("assert_eq!(", stringify!($Ty), "::MAX.get(), ", stringify!($Int), "::MAX);")] + /// ``` + #[stable(feature = "nonzero_min_max", since = "1.70.0")] + pub const MAX: Self = Self::new(<$Int>::MAX).unwrap(); + /// Computes the absolute value of self. #[doc = concat!("See [`", stringify!($Int), "::abs`]")] /// for documentation on overflow behaviour. @@ -1202,57 +1236,6 @@ macro_rules! sign_dependent_expr { }; } -macro_rules! nonzero_min_max_signed { - ( $( $Ty: ident($Int: ident); )+ ) => { - $( - impl $Ty { - /// The smallest value that can be represented by this non-zero - /// integer type, - #[doc = concat!("equal to [`", stringify!($Int), "::MIN`].")] - /// - /// Note: While most integer types are defined for every whole - /// number between `MIN` and `MAX`, signed non-zero integers are - /// a special case. They have a "gap" at 0. - /// - /// # Examples - /// - /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - #[doc = concat!("assert_eq!(", stringify!($Ty), "::MIN.get(), ", stringify!($Int), "::MIN);")] - /// ``` - #[stable(feature = "nonzero_min_max", since = "1.70.0")] - pub const MIN: Self = Self::new(<$Int>::MIN).unwrap(); - - /// The largest value that can be represented by this non-zero - /// integer type, - #[doc = concat!("equal to [`", stringify!($Int), "::MAX`].")] - /// - /// Note: While most integer types are defined for every whole - /// number between `MIN` and `MAX`, signed non-zero integers are - /// a special case. They have a "gap" at 0. - /// - /// # Examples - /// - /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - #[doc = concat!("assert_eq!(", stringify!($Ty), "::MAX.get(), ", stringify!($Int), "::MAX);")] - /// ``` - #[stable(feature = "nonzero_min_max", since = "1.70.0")] - pub const MAX: Self = Self::new(<$Int>::MAX).unwrap(); - } - )+ - } -} - -nonzero_min_max_signed! { - NonZeroI8(i8); - NonZeroI16(i16); - NonZeroI32(i32); - NonZeroI64(i64); - NonZeroI128(i128); - NonZeroIsize(isize); -} - macro_rules! nonzero_bits { ( $( $Ty: ident($Int: ty); )+ ) => { $( From c53713274cc6c04cad7b903c597ff54e4cdc8d27 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 5 Dec 2023 22:52:20 -0800 Subject: [PATCH 0220/1197] Move BITS into omnibus impl block --- library/core/src/num/nonzero.rs | 51 +++++++++------------------------ 1 file changed, 14 insertions(+), 37 deletions(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 9c48a5b0dbddd..0b42b628675ad 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -128,6 +128,20 @@ macro_rules! nonzero_integer { self.0 } + /// The size of this non-zero integer type in bits. + /// + #[doc = concat!("This value is equal to [`", stringify!($Int), "::BITS`].")] + /// + /// # Examples + /// + /// ``` + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// + #[doc = concat!("assert_eq!(", stringify!($Ty), "::BITS, ", stringify!($Int), "::BITS);")] + /// ``` + #[stable(feature = "nonzero_bits", since = "1.67.0")] + pub const BITS: u32 = <$Int>::BITS; + /// Returns the number of leading zeros in the binary representation of `self`. /// /// On many architectures, this function can perform better than `leading_zeros()` on the underlying integer type, as special handling of zero can be avoided. @@ -1236,43 +1250,6 @@ macro_rules! sign_dependent_expr { }; } -macro_rules! nonzero_bits { - ( $( $Ty: ident($Int: ty); )+ ) => { - $( - impl $Ty { - /// The size of this non-zero integer type in bits. - /// - #[doc = concat!("This value is equal to [`", stringify!($Int), "::BITS`].")] - /// - /// # Examples - /// - /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// - #[doc = concat!("assert_eq!(", stringify!($Ty), "::BITS, ", stringify!($Int), "::BITS);")] - /// ``` - #[stable(feature = "nonzero_bits", since = "1.67.0")] - pub const BITS: u32 = <$Int>::BITS; - } - )+ - } -} - -nonzero_bits! { - NonZeroU8(u8); - NonZeroI8(i8); - NonZeroU16(u16); - NonZeroI16(i16); - NonZeroU32(u32); - NonZeroI32(i32); - NonZeroU64(u64); - NonZeroI64(i64); - NonZeroU128(u128); - NonZeroI128(i128); - NonZeroUsize(usize); - NonZeroIsize(isize); -} - nonzero_integer! { Self = NonZeroU8, Primitive = unsigned u8, From cdee1feb49989f13e5091c591fbba90ef9278add Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 6 Dec 2023 00:41:18 -0800 Subject: [PATCH 0221/1197] Unbreak tidy's feature parser tidy error: /git/rust/library/core/src/num/nonzero.rs:67: malformed stability attribute: missing `feature` key tidy error: /git/rust/library/core/src/num/nonzero.rs:82: malformed stability attribute: missing `feature` key tidy error: /git/rust/library/core/src/num/nonzero.rs:98: malformed stability attribute: missing the `since` key tidy error: /git/rust/library/core/src/num/nonzero.rs:112: malformed stability attribute: missing `feature` key tidy error: /git/rust/library/core/src/num/nonzero.rs:450: malformed stability attribute: missing `feature` key some tidy checks failed --- library/core/src/num/nonzero.rs | 83 ++++++++++++--------------------- 1 file changed, 31 insertions(+), 52 deletions(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 0b42b628675ad..174fa200737c0 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -24,12 +24,12 @@ macro_rules! impl_nonzero_fmt { macro_rules! nonzero_integer { ( + #[$stability:meta] + #[$const_new_unchecked_stability:meta] Self = $Ty:ident, Primitive = $signedness:ident $Int:ident, $(UnsignedNonZero = $UnsignedNonZero:ident,)? UnsignedPrimitive = $UnsignedPrimitive:ty, - feature = $feature:literal, - original_stabilization = $since:literal, // Used in doc comments. leading_zeros_test = $leading_zeros_test:expr, @@ -64,7 +64,7 @@ macro_rules! nonzero_integer { /// ``` /// /// [null pointer optimization]: crate::option#representation - #[stable(feature = $feature, since = $since)] + #[$stability] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] #[repr(transparent)] #[rustc_layout_scalar_valid_range_start(1)] @@ -79,8 +79,8 @@ macro_rules! nonzero_integer { /// # Safety /// /// The value must not be zero. - #[stable(feature = $feature, since = $since)] - #[rustc_const_stable(feature = $feature, since = $since)] + #[$stability] + #[$const_new_unchecked_stability] #[must_use] #[inline] pub const unsafe fn new_unchecked(n: $Int) -> Self { @@ -95,7 +95,7 @@ macro_rules! nonzero_integer { } /// Creates a non-zero if the given value is not zero. - #[stable(feature = $feature, since = $since)] + #[$stability] #[rustc_const_stable(feature = "const_nonzero_int_methods", since = "1.47.0")] #[must_use] #[inline] @@ -109,7 +109,7 @@ macro_rules! nonzero_integer { } /// Returns the value as a primitive type. - #[stable(feature = $feature, since = $since)] + #[$stability] #[inline] #[rustc_const_stable(feature = "const_nonzero_get", since = "1.34.0")] pub const fn get(self) -> $Int { @@ -151,7 +151,7 @@ macro_rules! nonzero_integer { /// Basic usage: /// /// ``` - #[doc = concat!("let n = std::num::", stringify!($Ty), "::new(", stringify!($leading_zeros_test), ").unwrap();")] + #[doc = concat!("let n = std::num::", stringify!($Ty), "::new(", $leading_zeros_test, ").unwrap();")] /// /// assert_eq!(n.leading_zeros(), 0); /// ``` @@ -461,8 +461,7 @@ macro_rules! nonzero_integer { } impl_nonzero_fmt! { - #[stable(feature = $feature, since = $since)] - (Debug, Display, Binary, Octal, LowerHex, UpperHex) for $Ty + #[$stability] (Debug, Display, Binary, Octal, LowerHex, UpperHex) for $Ty } #[stable(feature = "nonzero_parse", since = "1.35.0")] @@ -478,6 +477,28 @@ macro_rules! nonzero_integer { nonzero_integer_signedness_dependent_impls!($Ty $signedness $Int); }; + + (Self = $Ty:ident, Primitive = unsigned $Int:ident $(,)?) => { + nonzero_integer! { + #[stable(feature = "nonzero", since = "1.28.0")] + #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] + Self = $Ty, + Primitive = unsigned $Int, + UnsignedPrimitive = $Int, + leading_zeros_test = concat!(stringify!($Int), "::MAX"), + } + }; + + (Self = $Ty:ident, Primitive = signed $Int:ident, $($rest:tt)*) => { + nonzero_integer! { + #[stable(feature = "signed_nonzero", since = "1.34.0")] + #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] + Self = $Ty, + Primitive = signed $Int, + $($rest)* + leading_zeros_test = concat!("-1", stringify!($Int)), + } + }; } macro_rules! nonzero_integer_signedness_dependent_impls { @@ -1253,55 +1274,31 @@ macro_rules! sign_dependent_expr { nonzero_integer! { Self = NonZeroU8, Primitive = unsigned u8, - UnsignedPrimitive = u8, - feature = "nonzero", - original_stabilization = "1.28.0", - leading_zeros_test = u8::MAX, } nonzero_integer! { Self = NonZeroU16, Primitive = unsigned u16, - UnsignedPrimitive = u16, - feature = "nonzero", - original_stabilization = "1.28.0", - leading_zeros_test = u16::MAX, } nonzero_integer! { Self = NonZeroU32, Primitive = unsigned u32, - UnsignedPrimitive = u32, - feature = "nonzero", - original_stabilization = "1.28.0", - leading_zeros_test = u32::MAX, } nonzero_integer! { Self = NonZeroU64, Primitive = unsigned u64, - UnsignedPrimitive = u64, - feature = "nonzero", - original_stabilization = "1.28.0", - leading_zeros_test = u64::MAX, } nonzero_integer! { Self = NonZeroU128, Primitive = unsigned u128, - UnsignedPrimitive = u128, - feature = "nonzero", - original_stabilization = "1.28.0", - leading_zeros_test = u128::MAX, } nonzero_integer! { Self = NonZeroUsize, Primitive = unsigned usize, - UnsignedPrimitive = usize, - feature = "nonzero", - original_stabilization = "1.28.0", - leading_zeros_test = usize::MAX, } nonzero_integer! { @@ -1309,9 +1306,6 @@ nonzero_integer! { Primitive = signed i8, UnsignedNonZero = NonZeroU8, UnsignedPrimitive = u8, - feature = "signed_nonzero", - original_stabilization = "1.34.0", - leading_zeros_test = -1i8, } nonzero_integer! { @@ -1319,9 +1313,6 @@ nonzero_integer! { Primitive = signed i16, UnsignedNonZero = NonZeroU16, UnsignedPrimitive = u16, - feature = "signed_nonzero", - original_stabilization = "1.34.0", - leading_zeros_test = -1i16, } nonzero_integer! { @@ -1329,9 +1320,6 @@ nonzero_integer! { Primitive = signed i32, UnsignedNonZero = NonZeroU32, UnsignedPrimitive = u32, - feature = "signed_nonzero", - original_stabilization = "1.34.0", - leading_zeros_test = -1i32, } nonzero_integer! { @@ -1339,9 +1327,6 @@ nonzero_integer! { Primitive = signed i64, UnsignedNonZero = NonZeroU64, UnsignedPrimitive = u64, - feature = "signed_nonzero", - original_stabilization = "1.34.0", - leading_zeros_test = -1i64, } nonzero_integer! { @@ -1349,9 +1334,6 @@ nonzero_integer! { Primitive = signed i128, UnsignedNonZero = NonZeroU128, UnsignedPrimitive = u128, - feature = "signed_nonzero", - original_stabilization = "1.34.0", - leading_zeros_test = -1i128, } nonzero_integer! { @@ -1359,7 +1341,4 @@ nonzero_integer! { Primitive = signed isize, UnsignedNonZero = NonZeroUsize, UnsignedPrimitive = usize, - feature = "signed_nonzero", - original_stabilization = "1.34.0", - leading_zeros_test = -1isize, } From e8ec99811b80372012d3ece0e0f31f5722785eec Mon Sep 17 00:00:00 2001 From: Kristof Mattei <864376+Kristof-Mattei@users.noreply.github.com> Date: Sun, 14 Jan 2024 14:00:13 -0700 Subject: [PATCH 0222/1197] fix: crates are limited to ASCII values --- clippy_lints/src/cargo/multiple_crate_versions.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/cargo/multiple_crate_versions.rs b/clippy_lints/src/cargo/multiple_crate_versions.rs index 6b4af6753c3e8..57b7b7497fe24 100644 --- a/clippy_lints/src/cargo/multiple_crate_versions.rs +++ b/clippy_lints/src/cargo/multiple_crate_versions.rs @@ -20,9 +20,10 @@ pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata) { // local_name contains the crate name as a namespace, with the dashes converted to underscores // the code below temporarily rectifies this discrepancy if p.name - .chars() - .map(|c| if c == '-' { '_' } else { c }) - .eq(local_name.as_str().chars()) + .as_bytes() + .iter() + .map(|b| if b == &b'-' { &b'_' } else { b }) + .eq(local_name.as_str().as_bytes()) { Some(&p.id) } else { From 5747eceef859c6e1ac74c04723ac9e2b5e039e1f Mon Sep 17 00:00:00 2001 From: sfzhu93 Date: Sun, 14 Jan 2024 22:35:00 -0800 Subject: [PATCH 0223/1197] add FIXME for default_boxed_slice.rs --- tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs index b15809f2510ff..bfa52b694d0ec 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs @@ -4,6 +4,8 @@ // EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR_FOR_EACH_PANIC_STRATEGY +// This test is to check ICE in issue [#115789](https://github.com/rust-lang/rust/issues/115789). + struct A { foo: Box<[bool]>, } @@ -14,13 +16,14 @@ struct A { // CHECK-LABEL: fn main( fn main() { // ConstProp will create a constant of type `Box<[bool]>`. + // FIXME: it is not yet a constant. + // Verify that `DataflowConstProp` does not ICE trying to dereference it directly. // CHECK: debug a => [[a:_.*]]; // We may check other inlined functions as well... - // CHECK: [[box_obj:_.*]] = Box::<[bool]>(_3, const std::alloc::Global); - // CHECK: [[a]] = A { foo: move [[box_obj]] }; - // FIXME: we do not have `const Box::<[bool]>` after constprop right now. + // CHECK-LABEL: _.* = Box::<[bool]>( + // FIXME: should be `_.* = const Box::<[bool]>` let a: A = A { foo: Box::default() }; } From 89cf17777bd3e1ebb15cc6e85cbcbd955bf12252 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sat, 13 Jan 2024 20:04:47 +0000 Subject: [PATCH 0224/1197] std::net: bind update for using backlog as `-1` too. Albeit not documented, macOs also support negative value for the backlog argument. ref: https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/bsd/kern/uipc_socket.c#L1061 --- library/std/src/os/unix/net/listener.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs index 8bf1e2dca6f7b..ecc0bbce5437a 100644 --- a/library/std/src/os/unix/net/listener.rs +++ b/library/std/src/os/unix/net/listener.rs @@ -80,7 +80,12 @@ impl UnixListener { target_os = "horizon" ))] const backlog: libc::c_int = 128; - #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"))] + #[cfg(any( + target_os = "linux", + target_os = "freebsd", + target_os = "openbsd", + target_os = "macos" + ))] const backlog: libc::c_int = -1; #[cfg(not(any( target_os = "windows", @@ -88,6 +93,7 @@ impl UnixListener { target_os = "linux", target_os = "freebsd", target_os = "openbsd", + target_os = "macos", target_os = "espidf", target_os = "horizon" )))] From 33d8e47e98bf45fdc105d1fadb37dd03789ba1b3 Mon Sep 17 00:00:00 2001 From: Adam Reichold Date: Sun, 10 Dec 2023 07:34:48 +0100 Subject: [PATCH 0225/1197] Try to improve wording and fix dead link in description of arc_with_non_send_sync lint. --- clippy_lints/src/arc_with_non_send_sync.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/arc_with_non_send_sync.rs b/clippy_lints/src/arc_with_non_send_sync.rs index 58738d5287883..1102c7fb236b5 100644 --- a/clippy_lints/src/arc_with_non_send_sync.rs +++ b/clippy_lints/src/arc_with_non_send_sync.rs @@ -14,10 +14,10 @@ declare_clippy_lint! { /// This lint warns when you use `Arc` with a type that does not implement `Send` or `Sync`. /// /// ### Why is this bad? - /// `Arc` is an Atomic `Rc` and guarantees that updates to the reference counter are - /// Atomic. This is useful in multithreading scenarios. To send an `Arc` across threads - /// and make use of the atomic ref counter, `T` must be [both `Send` and `Sync`](https://doc.rust-lang.org/std/sync/struct.Arc.html#impl-Send-for-Arc%3CT%3E), - /// either `T` should be made `Send + Sync` or an `Rc` should be used instead of an `Arc` + /// `Arc` is a thread-safe `Rc` and guarantees that updates to the reference counter + /// use atomic operations. To send an `Arc` across thread boundaries and + /// share ownership between multiple threads, `T` must be [both `Send` and `Sync`](https://doc.rust-lang.org/std/sync/struct.Arc.html#thread-safety), + /// so either `T` should be made `Send + Sync` or an `Rc` should be used instead of an `Arc` /// /// ### Example /// ```no_run From c7eb52dd7b2a8222d4a09934bacc1b2b07deafb0 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 13 Jan 2024 17:22:39 +0100 Subject: [PATCH 0226/1197] internal: Add unstable config for loading the sysroot sources via `cargo metadata` --- crates/base-db/src/input.rs | 42 ++- crates/project-model/src/cargo_workspace.rs | 2 + crates/project-model/src/sysroot.rs | 275 ++++++++++----- crates/project-model/src/tests.rs | 63 +++- crates/project-model/src/workspace.rs | 317 ++++++++++-------- ...rust_project_hello_world_project_model.txt | 2 +- crates/rust-analyzer/src/cli/rustc_tests.rs | 9 +- crates/rust-analyzer/src/config.rs | 9 + crates/rust-analyzer/src/reload.rs | 2 +- docs/user/generated_config.adoc | 10 + editors/code/package.json | 5 + 11 files changed, 497 insertions(+), 239 deletions(-) diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs index e45a81238ac9b..8c43f97b91f54 100644 --- a/crates/base-db/src/input.rs +++ b/crates/base-db/src/input.rs @@ -9,7 +9,7 @@ use std::{fmt, mem, ops, str::FromStr}; use cfg::CfgOptions; -use la_arena::{Arena, Idx}; +use la_arena::{Arena, Idx, RawIdx}; use rustc_hash::{FxHashMap, FxHashSet}; use semver::Version; use syntax::SmolStr; @@ -157,6 +157,10 @@ impl CrateOrigin { pub fn is_lib(&self) -> bool { matches!(self, CrateOrigin::Library { .. }) } + + pub fn is_lang(&self) -> bool { + matches!(self, CrateOrigin::Lang { .. }) + } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -174,7 +178,7 @@ impl From<&str> for LangCrateOrigin { match s { "alloc" => LangCrateOrigin::Alloc, "core" => LangCrateOrigin::Core, - "proc-macro" => LangCrateOrigin::ProcMacro, + "proc-macro" | "proc_macro" => LangCrateOrigin::ProcMacro, "std" => LangCrateOrigin::Std, "test" => LangCrateOrigin::Test, _ => LangCrateOrigin::Other, @@ -522,7 +526,7 @@ impl CrateGraph { self.arena.iter().map(|(idx, _)| idx) } - // FIXME: used for `handle_hack_cargo_workspace`, should be removed later + // FIXME: used for fixing up the toolchain sysroot, should be removed and done differently #[doc(hidden)] pub fn iter_mut(&mut self) -> impl Iterator + '_ { self.arena.iter_mut() @@ -619,7 +623,12 @@ impl CrateGraph { /// This will deduplicate the crates of the graph where possible. /// Note that for deduplication to fully work, `self`'s crate dependencies must be sorted by crate id. /// If the crate dependencies were sorted, the resulting graph from this `extend` call will also have the crate dependencies sorted. - pub fn extend(&mut self, mut other: CrateGraph, proc_macros: &mut ProcMacroPaths) { + pub fn extend( + &mut self, + mut other: CrateGraph, + proc_macros: &mut ProcMacroPaths, + on_finished: impl FnOnce(&FxHashMap), + ) { let topo = other.crates_in_topological_order(); let mut id_map: FxHashMap = FxHashMap::default(); for topo in topo { @@ -670,6 +679,8 @@ impl CrateGraph { *proc_macros = mem::take(proc_macros).into_iter().map(|(id, macros)| (id_map[&id], macros)).collect(); + + on_finished(&id_map); } fn find_path( @@ -721,6 +732,29 @@ impl CrateGraph { fn hacky_find_crate<'a>(&'a self, display_name: &'a str) -> impl Iterator + 'a { self.iter().filter(move |it| self[*it].display_name.as_deref() == Some(display_name)) } + + /// Removes all crates from this crate graph except for the ones in `to_keep` and fixes up the dependencies. + /// Returns a mapping from old crate ids to new crate ids. + pub fn remove_crates_except(&mut self, to_keep: &[CrateId]) -> Vec> { + let mut id_map = vec![None; self.arena.len()]; + self.arena = std::mem::take(&mut self.arena) + .into_iter() + .filter_map(|(id, data)| if to_keep.contains(&id) { Some((id, data)) } else { None }) + .enumerate() + .map(|(new_id, (id, data))| { + id_map[id.into_raw().into_u32() as usize] = + Some(CrateId::from_raw(RawIdx::from_u32(new_id as u32))); + data + }) + .collect(); + for (_, data) in self.arena.iter_mut() { + data.dependencies.iter_mut().for_each(|dep| { + dep.crate_id = + id_map[dep.crate_id.into_raw().into_u32() as usize].expect("crate was filtered") + }); + } + id_map + } } impl ops::Index for CrateGraph { diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs index bc1fcd08e20ce..dba9edab3c93c 100644 --- a/crates/project-model/src/cargo_workspace.rs +++ b/crates/project-model/src/cargo_workspace.rs @@ -82,6 +82,8 @@ pub struct CargoConfig { pub target: Option, /// Sysroot loading behavior pub sysroot: Option, + /// Whether to invoke `cargo metadata` on the sysroot crate. + pub sysroot_query_metadata: bool, pub sysroot_src: Option, /// rustc private crate source pub rustc_source: Option, diff --git a/crates/project-model/src/sysroot.rs b/crates/project-model/src/sysroot.rs index d52e448d74700..fb5e8c365a34a 100644 --- a/crates/project-model/src/sysroot.rs +++ b/crates/project-model/src/sysroot.rs @@ -8,6 +8,7 @@ use std::{env, fs, iter, ops, path::PathBuf, process::Command}; use anyhow::{format_err, Context, Result}; use base_db::CrateName; +use itertools::Itertools; use la_arena::{Arena, Idx}; use paths::{AbsPath, AbsPathBuf}; use rustc_hash::FxHashMap; @@ -18,42 +19,29 @@ use crate::{utf8_stdout, CargoConfig, CargoWorkspace, ManifestPath}; pub struct Sysroot { root: AbsPathBuf, src_root: AbsPathBuf, - crates: Arena, - /// Stores the result of `cargo metadata` of the `RA_UNSTABLE_SYSROOT_HACK` workspace. - pub hack_cargo_workspace: Option, + mode: SysrootMode, } -pub(crate) type SysrootCrate = Idx; +#[derive(Debug, Clone, Eq, PartialEq)] +pub(crate) enum SysrootMode { + Workspace(CargoWorkspace), + Stitched(Stitched), +} #[derive(Debug, Clone, Eq, PartialEq)] -pub struct SysrootCrateData { - pub name: String, - pub root: ManifestPath, - pub deps: Vec, +pub(crate) struct Stitched { + crates: Arena, } -impl ops::Index for Sysroot { +impl ops::Index for Stitched { type Output = SysrootCrateData; fn index(&self, index: SysrootCrate) -> &SysrootCrateData { &self.crates[index] } } -impl Sysroot { - /// Returns sysroot "root" directory, where `bin/`, `etc/`, `lib/`, `libexec/` - /// subfolder live, like: - /// `$HOME/.rustup/toolchains/nightly-2022-07-23-x86_64-unknown-linux-gnu` - pub fn root(&self) -> &AbsPath { - &self.root - } - - /// Returns the sysroot "source" directory, where stdlib sources are located, like: - /// `$HOME/.rustup/toolchains/nightly-2022-07-23-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library` - pub fn src_root(&self) -> &AbsPath { - &self.src_root - } - - pub fn public_deps(&self) -> impl Iterator + '_ { +impl Stitched { + pub(crate) fn public_deps(&self) -> impl Iterator + '_ { // core is added as a dependency before std in order to // mimic rustcs dependency order ["core", "alloc", "std"] @@ -65,20 +53,56 @@ impl Sysroot { }) } - pub fn proc_macro(&self) -> Option { + pub(crate) fn proc_macro(&self) -> Option { self.by_name("proc_macro") } - pub fn crates(&self) -> impl Iterator + ExactSizeIterator + '_ { + pub(crate) fn crates(&self) -> impl Iterator + ExactSizeIterator + '_ { self.crates.iter().map(|(id, _data)| id) } + fn by_name(&self, name: &str) -> Option { + let (id, _data) = self.crates.iter().find(|(_id, data)| data.name == name)?; + Some(id) + } +} + +pub(crate) type SysrootCrate = Idx; + +#[derive(Debug, Clone, Eq, PartialEq)] +pub(crate) struct SysrootCrateData { + pub(crate) name: String, + pub(crate) root: ManifestPath, + pub(crate) deps: Vec, +} + +impl Sysroot { + /// Returns sysroot "root" directory, where `bin/`, `etc/`, `lib/`, `libexec/` + /// subfolder live, like: + /// `$HOME/.rustup/toolchains/nightly-2022-07-23-x86_64-unknown-linux-gnu` + pub fn root(&self) -> &AbsPath { + &self.root + } + + /// Returns the sysroot "source" directory, where stdlib sources are located, like: + /// `$HOME/.rustup/toolchains/nightly-2022-07-23-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library` + pub fn src_root(&self) -> &AbsPath { + &self.src_root + } + pub fn is_empty(&self) -> bool { - self.crates.is_empty() + match &self.mode { + SysrootMode::Workspace(ws) => ws.packages().next().is_none(), + SysrootMode::Stitched(stitched) => stitched.crates.is_empty(), + } } pub fn loading_warning(&self) -> Option { - if self.by_name("core").is_none() { + let has_core = match &self.mode { + SysrootMode::Workspace(ws) => ws.packages().any(|p| ws[p].name == "core"), + SysrootMode::Stitched(stitched) => stitched.by_name("core").is_some(), + }; + if !has_core { let var_note = if env::var_os("RUST_SRC_PATH").is_some() { " (`RUST_SRC_PATH` might be incorrect, try unsetting it)" } else { @@ -92,27 +116,43 @@ impl Sysroot { None } } + + pub fn num_packages(&self) -> usize { + match &self.mode { + SysrootMode::Workspace(ws) => ws.packages().count(), + SysrootMode::Stitched(c) => c.crates().count(), + } + } + + pub(crate) fn mode(&self) -> &SysrootMode { + &self.mode + } } // FIXME: Expose a builder api as loading the sysroot got way too modular and complicated. impl Sysroot { /// Attempts to discover the toolchain's sysroot from the given `dir`. - pub fn discover(dir: &AbsPath, extra_env: &FxHashMap) -> Result { + pub fn discover( + dir: &AbsPath, + extra_env: &FxHashMap, + metadata: bool, + ) -> Result { tracing::debug!("discovering sysroot for {dir}"); let sysroot_dir = discover_sysroot_dir(dir, extra_env)?; let sysroot_src_dir = discover_sysroot_src_dir_or_add_component(&sysroot_dir, dir, extra_env)?; - Ok(Sysroot::load(sysroot_dir, sysroot_src_dir)) + Ok(Sysroot::load(sysroot_dir, sysroot_src_dir, metadata)) } pub fn discover_with_src_override( current_dir: &AbsPath, extra_env: &FxHashMap, src: AbsPathBuf, + metadata: bool, ) -> Result { tracing::debug!("discovering sysroot for {current_dir}"); let sysroot_dir = discover_sysroot_dir(current_dir, extra_env)?; - Ok(Sysroot::load(sysroot_dir, src)) + Ok(Sysroot::load(sysroot_dir, src, metadata)) } pub fn discover_rustc_src(&self) -> Option { @@ -131,49 +171,132 @@ impl Sysroot { } } - pub fn with_sysroot_dir(sysroot_dir: AbsPathBuf) -> Result { + pub fn with_sysroot_dir(sysroot_dir: AbsPathBuf, metadata: bool) -> Result { let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir).ok_or_else(|| { format_err!("can't load standard library from sysroot path {sysroot_dir}") })?; - Ok(Sysroot::load(sysroot_dir, sysroot_src_dir)) + Ok(Sysroot::load(sysroot_dir, sysroot_src_dir, metadata)) } - pub fn load(sysroot_dir: AbsPathBuf, mut sysroot_src_dir: AbsPathBuf) -> Sysroot { - // FIXME: Remove this `hack_cargo_workspace` field completely once we support sysroot dependencies - let hack_cargo_workspace = if let Ok(path) = std::env::var("RA_UNSTABLE_SYSROOT_HACK") { - let cargo_toml = ManifestPath::try_from( - AbsPathBuf::try_from(&*format!("{path}/Cargo.toml")).unwrap(), - ) - .unwrap(); - sysroot_src_dir = AbsPathBuf::try_from(&*path).unwrap().join("library"); - CargoWorkspace::fetch_metadata( - &cargo_toml, - &AbsPathBuf::try_from("/").unwrap(), - &CargoConfig::default(), - &|_| (), - ) - .map(CargoWorkspace::new) - .ok() - } else { - None - }; - let mut sysroot = Sysroot { - root: sysroot_dir, - src_root: sysroot_src_dir, - crates: Arena::default(), - hack_cargo_workspace, - }; + pub fn load(sysroot_dir: AbsPathBuf, sysroot_src_dir: AbsPathBuf, metadata: bool) -> Sysroot { + if metadata { + let sysroot: Option<_> = (|| { + let sysroot_cargo_toml = ManifestPath::try_from( + AbsPathBuf::try_from(&*format!("{sysroot_src_dir}/sysroot/Cargo.toml")).ok()?, + ) + .ok()?; + let current_dir = + AbsPathBuf::try_from(&*format!("{sysroot_src_dir}/sysroot")).ok()?; + let res = CargoWorkspace::fetch_metadata( + &sysroot_cargo_toml, + ¤t_dir, + &CargoConfig::default(), + &|_| (), + ) + .map_err(|e| { + tracing::error!( + "failed to load sysroot `{sysroot_src_dir}/sysroot/Cargo.toml`: {}", + e + ); + e + }); + if let Err(e) = + std::fs::remove_file(&format!("{sysroot_src_dir}/sysroot/Cargo.lock")) + { + tracing::error!( + "failed to remove sysroot `{sysroot_src_dir}/sysroot/Cargo.lock`: {}", + e + ) + } + let mut res = res.ok()?; + + // Patch out `rustc-std-workspace-*` crates to point to the real crates. + // This is done prior to `CrateGraph` construction to avoid having duplicate `std` targets. + + let mut fake_core = None; + let mut fake_alloc = None; + let mut fake_std = None; + let mut real_core = None; + let mut real_alloc = None; + let mut real_std = None; + res.packages.iter().enumerate().for_each(|(idx, package)| { + match package.name.strip_prefix("rustc-std-workspace-") { + Some("core") => fake_core = Some((idx, package.id.clone())), + Some("alloc") => fake_alloc = Some((idx, package.id.clone())), + Some("std") => fake_std = Some((idx, package.id.clone())), + Some(_) => { + tracing::warn!("unknown rustc-std-workspace-* crate: {}", package.name) + } + None => match &*package.name { + "core" => real_core = Some(package.id.clone()), + "alloc" => real_alloc = Some(package.id.clone()), + "std" => real_std = Some(package.id.clone()), + _ => (), + }, + } + }); + + let patches = + [fake_core.zip(real_core), fake_alloc.zip(real_alloc), fake_std.zip(real_std)] + .into_iter() + .flatten(); + + let resolve = res.resolve.as_mut().expect("metadata executed with deps"); + let mut remove_nodes = vec![]; + for (idx, node) in resolve.nodes.iter_mut().enumerate() { + // Replace them in the dependency list + node.deps.iter_mut().for_each(|dep| { + if let Some((_, real)) = + patches.clone().find(|((_, fake_id), _)| *fake_id == dep.pkg) + { + dep.pkg = real; + } + }); + if patches.clone().any(|((_, fake), _)| fake == node.id) { + remove_nodes.push(idx); + } + } + // Remove the fake ones from the resolve data + remove_nodes.into_iter().rev().for_each(|r| { + resolve.nodes.remove(r); + }); + // Remove the fake ones from the packages + patches.map(|((r, _), _)| r).sorted().rev().for_each(|r| { + res.packages.remove(r); + }); + + res.workspace_members = res + .packages + .iter() + .filter_map(|package| { + RELEVANT_SYSROOT_CRATES + .contains(&&*package.name) + .then(|| package.id.clone()) + }) + .collect(); + let cargo_workspace = CargoWorkspace::new(res); + Some(Sysroot { + root: sysroot_dir.clone(), + src_root: sysroot_src_dir.clone(), + mode: SysrootMode::Workspace(cargo_workspace), + }) + })(); + if let Some(sysroot) = sysroot { + return sysroot; + } + } + let mut stitched = Stitched { crates: Arena::default() }; for path in SYSROOT_CRATES.trim().lines() { let name = path.split('/').last().unwrap(); let root = [format!("{path}/src/lib.rs"), format!("lib{path}/lib.rs")] .into_iter() - .map(|it| sysroot.src_root.join(it)) + .map(|it| sysroot_src_dir.join(it)) .filter_map(|it| ManifestPath::try_from(it).ok()) .find(|it| fs::metadata(it).is_ok()); if let Some(root) = root { - sysroot.crates.alloc(SysrootCrateData { + stitched.crates.alloc(SysrootCrateData { name: name.into(), root, deps: Vec::new(), @@ -181,36 +304,34 @@ impl Sysroot { } } - if let Some(std) = sysroot.by_name("std") { + if let Some(std) = stitched.by_name("std") { for dep in STD_DEPS.trim().lines() { - if let Some(dep) = sysroot.by_name(dep) { - sysroot.crates[std].deps.push(dep) + if let Some(dep) = stitched.by_name(dep) { + stitched.crates[std].deps.push(dep) } } } - if let Some(alloc) = sysroot.by_name("alloc") { + if let Some(alloc) = stitched.by_name("alloc") { for dep in ALLOC_DEPS.trim().lines() { - if let Some(dep) = sysroot.by_name(dep) { - sysroot.crates[alloc].deps.push(dep) + if let Some(dep) = stitched.by_name(dep) { + stitched.crates[alloc].deps.push(dep) } } } - if let Some(proc_macro) = sysroot.by_name("proc_macro") { + if let Some(proc_macro) = stitched.by_name("proc_macro") { for dep in PROC_MACRO_DEPS.trim().lines() { - if let Some(dep) = sysroot.by_name(dep) { - sysroot.crates[proc_macro].deps.push(dep) + if let Some(dep) = stitched.by_name(dep) { + stitched.crates[proc_macro].deps.push(dep) } } } - - sysroot - } - - fn by_name(&self, name: &str) -> Option { - let (id, _data) = self.crates.iter().find(|(_id, data)| data.name == name)?; - Some(id) + Sysroot { + root: sysroot_dir, + src_root: sysroot_src_dir, + mode: SysrootMode::Stitched(stitched), + } } } @@ -318,3 +439,5 @@ test"; const PROC_MACRO_DEPS: &str = " std core"; + +const RELEVANT_SYSROOT_CRATES: &[&str] = &["core", "alloc", "std", "test", "proc_macro"]; diff --git a/crates/project-model/src/tests.rs b/crates/project-model/src/tests.rs index 4887b29815ae2..9e6b00d93803e 100644 --- a/crates/project-model/src/tests.rs +++ b/crates/project-model/src/tests.rs @@ -38,7 +38,7 @@ fn load_cargo_with_overrides( to_crate_graph(project_workspace) } -fn load_cargo_with_sysroot( +fn load_cargo_with_fake_sysroot( file_map: &mut FxHashMap, file: &str, ) -> (CrateGraph, ProcMacroPaths) { @@ -125,7 +125,7 @@ fn get_fake_sysroot() -> Sysroot { // fake sysroot, so we give them both the same path: let sysroot_dir = AbsPathBuf::assert(sysroot_path); let sysroot_src_dir = sysroot_dir.clone(); - Sysroot::load(sysroot_dir, sysroot_src_dir) + Sysroot::load(sysroot_dir, sysroot_src_dir, false) } fn rooted_project_json(data: ProjectJsonData) -> ProjectJson { @@ -225,12 +225,12 @@ fn rust_project_is_proc_macro_has_proc_macro_dep() { #[test] fn crate_graph_dedup_identical() { let (mut crate_graph, proc_macros) = - load_cargo_with_sysroot(&mut Default::default(), "regex-metadata.json"); + load_cargo_with_fake_sysroot(&mut Default::default(), "regex-metadata.json"); crate_graph.sort_deps(); let (d_crate_graph, mut d_proc_macros) = (crate_graph.clone(), proc_macros.clone()); - crate_graph.extend(d_crate_graph.clone(), &mut d_proc_macros); + crate_graph.extend(d_crate_graph.clone(), &mut d_proc_macros, |_| ()); assert!(crate_graph.iter().eq(d_crate_graph.iter())); assert_eq!(proc_macros, d_proc_macros); } @@ -239,14 +239,14 @@ fn crate_graph_dedup_identical() { fn crate_graph_dedup() { let path_map = &mut Default::default(); let (mut crate_graph, _proc_macros) = - load_cargo_with_sysroot(path_map, "ripgrep-metadata.json"); + load_cargo_with_fake_sysroot(path_map, "ripgrep-metadata.json"); assert_eq!(crate_graph.iter().count(), 81); crate_graph.sort_deps(); let (regex_crate_graph, mut regex_proc_macros) = - load_cargo_with_sysroot(path_map, "regex-metadata.json"); + load_cargo_with_fake_sysroot(path_map, "regex-metadata.json"); assert_eq!(regex_crate_graph.iter().count(), 60); - crate_graph.extend(regex_crate_graph, &mut regex_proc_macros); + crate_graph.extend(regex_crate_graph, &mut regex_proc_macros, |_| ()); assert_eq!(crate_graph.iter().count(), 118); } @@ -254,12 +254,12 @@ fn crate_graph_dedup() { fn test_deduplicate_origin_dev() { let path_map = &mut Default::default(); let (mut crate_graph, _proc_macros) = - load_cargo_with_sysroot(path_map, "deduplication_crate_graph_A.json"); + load_cargo_with_fake_sysroot(path_map, "deduplication_crate_graph_A.json"); crate_graph.sort_deps(); let (crate_graph_1, mut _proc_macros_2) = - load_cargo_with_sysroot(path_map, "deduplication_crate_graph_B.json"); + load_cargo_with_fake_sysroot(path_map, "deduplication_crate_graph_B.json"); - crate_graph.extend(crate_graph_1, &mut _proc_macros_2); + crate_graph.extend(crate_graph_1, &mut _proc_macros_2, |_| ()); let mut crates_named_p2 = vec![]; for id in crate_graph.iter() { @@ -280,12 +280,12 @@ fn test_deduplicate_origin_dev() { fn test_deduplicate_origin_dev_rev() { let path_map = &mut Default::default(); let (mut crate_graph, _proc_macros) = - load_cargo_with_sysroot(path_map, "deduplication_crate_graph_B.json"); + load_cargo_with_fake_sysroot(path_map, "deduplication_crate_graph_B.json"); crate_graph.sort_deps(); let (crate_graph_1, mut _proc_macros_2) = - load_cargo_with_sysroot(path_map, "deduplication_crate_graph_A.json"); + load_cargo_with_fake_sysroot(path_map, "deduplication_crate_graph_A.json"); - crate_graph.extend(crate_graph_1, &mut _proc_macros_2); + crate_graph.extend(crate_graph_1, &mut _proc_macros_2, |_| ()); let mut crates_named_p2 = vec![]; for id in crate_graph.iter() { @@ -301,3 +301,40 @@ fn test_deduplicate_origin_dev_rev() { let p2 = crates_named_p2[0]; assert!(p2.origin.is_local()); } + +#[test] +fn smoke_test_real_sysroot_cargo() { + if std::env::var("SYSROOT_CARGO_METADATA").is_err() { + return; + } + let file_map = &mut FxHashMap::::default(); + let meta = get_test_json_file("hello-world-metadata.json"); + + let cargo_workspace = CargoWorkspace::new(meta); + let sysroot = Ok(Sysroot::discover( + AbsPath::assert(Path::new(env!("CARGO_MANIFEST_DIR"))), + &Default::default(), + true, + ) + .unwrap()); + + let project_workspace = ProjectWorkspace::Cargo { + cargo: cargo_workspace, + build_scripts: WorkspaceBuildScripts::default(), + sysroot, + rustc: Err(None), + rustc_cfg: Vec::new(), + cfg_overrides: Default::default(), + toolchain: None, + target_layout: Err("target_data_layout not loaded".into()), + }; + project_workspace.to_crate_graph( + &mut { + |path| { + let len = file_map.len(); + Some(*file_map.entry(path.to_path_buf()).or_insert(FileId::from_raw(len as u32))) + } + }, + &Default::default(), + ); +} diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index c04eddc56fb7f..679f219dcc4f0 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -9,7 +9,7 @@ use base_db::{ CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, DependencyKind, Edition, Env, FileId, LangCrateOrigin, ProcMacroPaths, TargetLayoutLoadResult, }; -use cfg::{CfgDiff, CfgOptions}; +use cfg::{CfgAtom, CfgDiff, CfgOptions}; use paths::{AbsPath, AbsPathBuf}; use rustc_hash::{FxHashMap, FxHashSet}; use semver::Version; @@ -22,7 +22,7 @@ use crate::{ cfg_flag::CfgFlag, project_json::Crate, rustc_cfg::{self, RustcCfgConfig}, - sysroot::SysrootCrate, + sysroot::{SysrootCrate, SysrootMode}, target_data_layout, utf8_stdout, CargoConfig, CargoWorkspace, InvocationStrategy, ManifestPath, Package, ProjectJson, ProjectManifest, Sysroot, TargetData, TargetKind, WorkspaceBuildScripts, }; @@ -130,7 +130,7 @@ impl fmt::Debug for ProjectWorkspace { let mut debug_struct = f.debug_struct("Json"); debug_struct.field("n_crates", &project.n_crates()); if let Ok(sysroot) = sysroot { - debug_struct.field("n_sysroot_crates", &sysroot.crates().len()); + debug_struct.field("n_sysroot_crates", &sysroot.num_packages()); } debug_struct.field("toolchain", &toolchain); debug_struct.field("n_rustc_cfg", &rustc_cfg.len()); @@ -208,23 +208,23 @@ impl ProjectWorkspace { let sysroot = match (&config.sysroot, &config.sysroot_src) { (Some(RustLibSource::Path(path)), None) => { - Sysroot::with_sysroot_dir(path.clone()).map_err(|e| { + Sysroot::with_sysroot_dir(path.clone(), config.sysroot_query_metadata).map_err(|e| { Some(format!("Failed to find sysroot at {path}:{e}")) }) } (Some(RustLibSource::Discover), None) => { - Sysroot::discover(cargo_toml.parent(), &config.extra_env).map_err(|e| { + Sysroot::discover(cargo_toml.parent(), &config.extra_env, config.sysroot_query_metadata).map_err(|e| { Some(format!("Failed to find sysroot for Cargo.toml file {cargo_toml}. Is rust-src installed? {e}")) }) } (Some(RustLibSource::Path(sysroot)), Some(sysroot_src)) => { - Ok(Sysroot::load(sysroot.clone(), sysroot_src.clone())) + Ok(Sysroot::load(sysroot.clone(), sysroot_src.clone(), config.sysroot_query_metadata)) } (Some(RustLibSource::Discover), Some(sysroot_src)) => { Sysroot::discover_with_src_override( cargo_toml.parent(), &config.extra_env, - sysroot_src.clone(), + sysroot_src.clone(), config.sysroot_query_metadata, ).map_err(|e| { Some(format!("Failed to find sysroot for Cargo.toml file {cargo_toml}. Is rust-src installed? {e}")) }) @@ -317,12 +317,12 @@ impl ProjectWorkspace { toolchain: Option, ) -> ProjectWorkspace { let sysroot = match (project_json.sysroot.clone(), project_json.sysroot_src.clone()) { - (Some(sysroot), Some(sysroot_src)) => Ok(Sysroot::load(sysroot, sysroot_src)), + (Some(sysroot), Some(sysroot_src)) => Ok(Sysroot::load(sysroot, sysroot_src, false)), (Some(sysroot), None) => { // assume sysroot is structured like rustup's and guess `sysroot_src` let sysroot_src = sysroot.join("lib").join("rustlib").join("src").join("rust").join("library"); - Ok(Sysroot::load(sysroot, sysroot_src)) + Ok(Sysroot::load(sysroot, sysroot_src, false)) } (None, Some(sysroot_src)) => { // assume sysroot is structured like rustup's and guess `sysroot` @@ -330,7 +330,7 @@ impl ProjectWorkspace { for _ in 0..5 { sysroot.pop(); } - Ok(Sysroot::load(sysroot, sysroot_src)) + Ok(Sysroot::load(sysroot, sysroot_src, false)) } (None, None) => Err(None), }; @@ -354,16 +354,22 @@ impl ProjectWorkspace { config: &CargoConfig, ) -> anyhow::Result { let sysroot = match &config.sysroot { - Some(RustLibSource::Path(path)) => Sysroot::with_sysroot_dir(path.clone()) - .map_err(|e| Some(format!("Failed to find sysroot at {path}:{e}"))), + Some(RustLibSource::Path(path)) => { + Sysroot::with_sysroot_dir(path.clone(), config.sysroot_query_metadata) + .map_err(|e| Some(format!("Failed to find sysroot at {path}:{e}"))) + } Some(RustLibSource::Discover) => { let dir = &detached_files .first() .and_then(|it| it.parent()) .ok_or_else(|| format_err!("No detached files to load"))?; - Sysroot::discover(dir, &config.extra_env).map_err(|e| { - Some(format!("Failed to find sysroot for {dir}. Is rust-src installed? {e}")) - }) + Sysroot::discover(dir, &config.extra_env, config.sysroot_query_metadata).map_err( + |e| { + Some(format!( + "Failed to find sysroot for {dir}. Is rust-src installed? {e}" + )) + }, + ) } None => Err(None), }; @@ -494,13 +500,43 @@ impl ProjectWorkspace { /// The return type contains the path and whether or not /// the root is a member of the current workspace pub fn to_roots(&self) -> Vec { - let mk_sysroot = |sysroot: Result<&Sysroot, _>, project_root: Option<&AbsPath>| { - sysroot.map(|sysroot| PackageRoot { - // mark the sysroot as mutable if it is located inside of the project - is_local: project_root - .map_or(false, |project_root| sysroot.src_root().starts_with(project_root)), - include: vec![sysroot.src_root().to_path_buf()], - exclude: Vec::new(), + let mk_sysroot = |sysroot: Result<_, _>, project_root: Option<&AbsPath>| { + let project_root = project_root.map(ToOwned::to_owned); + sysroot.into_iter().flat_map(move |sysroot: &Sysroot| { + let mut r = match sysroot.mode() { + SysrootMode::Workspace(ws) => ws + .packages() + .filter_map(|pkg| { + if ws[pkg].is_local { + // the local ones are included in the main `PackageRoot`` below + return None; + } + let pkg_root = ws[pkg].manifest.parent().to_path_buf(); + + let include = vec![pkg_root.clone()]; + + let exclude = vec![ + pkg_root.join(".git"), + pkg_root.join("target"), + pkg_root.join("tests"), + pkg_root.join("examples"), + pkg_root.join("benches"), + ]; + Some(PackageRoot { is_local: false, include, exclude }) + }) + .collect(), + SysrootMode::Stitched(_) => vec![], + }; + + r.push(PackageRoot { + // mark the sysroot as mutable if it is located inside of the project + is_local: project_root + .as_ref() + .map_or(false, |project_root| sysroot.src_root().starts_with(project_root)), + include: vec![sysroot.src_root().to_path_buf()], + exclude: Vec::new(), + }); + r }) }; match self { @@ -588,16 +624,16 @@ impl ProjectWorkspace { pub fn n_packages(&self) -> usize { match self { ProjectWorkspace::Json { project, sysroot, .. } => { - let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.crates().len()); + let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.num_packages()); sysroot_package_len + project.n_crates() } ProjectWorkspace::Cargo { cargo, sysroot, rustc, .. } => { let rustc_package_len = rustc.as_ref().map_or(0, |(it, _)| it.packages().len()); - let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.crates().len()); + let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.num_packages()); cargo.packages().len() + sysroot_package_len + rustc_package_len } ProjectWorkspace::DetachedFiles { sysroot, files, .. } => { - let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.crates().len()); + let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.num_packages()); sysroot_package_len + files.len() } } @@ -638,7 +674,6 @@ impl ProjectWorkspace { sysroot.as_ref().ok(), rustc_cfg.clone(), cfg_overrides, - None, build_scripts, match target_layout.as_ref() { Ok(it) => Ok(Arc::from(it.as_str())), @@ -849,8 +884,6 @@ fn cargo_to_crate_graph( sysroot: Option<&Sysroot>, rustc_cfg: Vec, override_cfg: &CfgOverrides, - // Don't compute cfg and use this if present, only used for the sysroot experiment hack - forced_cfg: Option, build_scripts: &WorkspaceBuildScripts, target_layout: TargetLayoutLoadResult, toolchain: Option<&Version>, @@ -883,7 +916,7 @@ fn cargo_to_crate_graph( for pkg in cargo.packages() { has_private |= cargo[pkg].metadata.rustc_private; - let cfg_options = forced_cfg.clone().unwrap_or_else(|| { + let cfg_options = { let mut cfg_options = cfg_options.clone(); // Add test cfg for local crates @@ -908,7 +941,7 @@ fn cargo_to_crate_graph( cfg_options.apply_diff(diff.clone()); }; cfg_options - }); + }; let mut lib_tgt = None; for &tgt in cargo[pkg].targets.iter() { @@ -1349,124 +1382,126 @@ fn sysroot_to_crate_graph( toolchain: Option<&Version>, ) -> (SysrootPublicDeps, Option) { let _p = profile::span("sysroot_to_crate_graph"); - let cfg_options = create_cfg_options(rustc_cfg.clone()); - let sysroot_crates: FxHashMap = match &sysroot.hack_cargo_workspace { - Some(cargo) => handle_hack_cargo_workspace( - load, - cargo, - rustc_cfg, - cfg_options, - target_layout, - toolchain, - crate_graph, - sysroot, - ), - None => sysroot - .crates() - .filter_map(|krate| { - let file_id = load(&sysroot[krate].root)?; - - let env = Env::default(); - let display_name = - CrateDisplayName::from_canonical_name(sysroot[krate].name.clone()); - let crate_id = crate_graph.add_crate_root( - file_id, - Edition::CURRENT, - Some(display_name), - None, - cfg_options.clone(), - None, - env, - false, - CrateOrigin::Lang(LangCrateOrigin::from(&*sysroot[krate].name)), - target_layout.clone(), - toolchain.cloned(), - ); - Some((krate, crate_id)) - }) - .collect(), - }; - for from in sysroot.crates() { - for &to in sysroot[from].deps.iter() { - let name = CrateName::new(&sysroot[to].name).unwrap(); - if let (Some(&from), Some(&to)) = (sysroot_crates.get(&from), sysroot_crates.get(&to)) { - add_dep(crate_graph, from, name, to, DependencyKind::Normal); + match sysroot.mode() { + SysrootMode::Workspace(cargo) => { + let (mut cg, mut pm) = cargo_to_crate_graph( + load, + None, + cargo, + None, + rustc_cfg, + &CfgOverrides::default(), + &WorkspaceBuildScripts::default(), + target_layout, + toolchain, + ); + + let mut pub_deps = vec![]; + let mut libproc_macro = None; + let diff = CfgDiff::new(vec![], vec![CfgAtom::Flag("test".into())]).unwrap(); + for (cid, c) in cg.iter_mut() { + // uninject `test` flag so `core` keeps working. + c.cfg_options.apply_diff(diff.clone()); + // patch the origin + if c.origin.is_local() { + let lang_crate = LangCrateOrigin::from( + c.display_name.as_ref().map_or("", |it| it.canonical_name()), + ); + c.origin = CrateOrigin::Lang(lang_crate); + match lang_crate { + LangCrateOrigin::Test + | LangCrateOrigin::Alloc + | LangCrateOrigin::Core + | LangCrateOrigin::Std => pub_deps.push(( + CrateName::normalize_dashes(&lang_crate.to_string()), + cid, + !matches!(lang_crate, LangCrateOrigin::Test), + )), + LangCrateOrigin::ProcMacro => libproc_macro = Some(cid), + LangCrateOrigin::Other => (), + } + } + } + + let mut marker_set = vec![]; + for &(_, cid, _) in pub_deps.iter() { + marker_set.extend(cg.transitive_deps(cid)); } + if let Some(cid) = libproc_macro { + marker_set.extend(cg.transitive_deps(cid)); + } + + marker_set.sort(); + marker_set.dedup(); + + // Remove all crates except the ones we are interested in to keep the sysroot graph small. + let removed_mapping = cg.remove_crates_except(&marker_set); + + crate_graph.extend(cg, &mut pm, |mapping| { + // Map the id through the removal mapping first, then through the crate graph extension mapping. + pub_deps.iter_mut().for_each(|(_, cid, _)| { + *cid = mapping[&removed_mapping[cid.into_raw().into_u32() as usize].unwrap()] + }); + if let Some(libproc_macro) = &mut libproc_macro { + *libproc_macro = mapping + [&removed_mapping[libproc_macro.into_raw().into_u32() as usize].unwrap()]; + } + }); + + (SysrootPublicDeps { deps: pub_deps }, libproc_macro) } - } + SysrootMode::Stitched(stitched) => { + let cfg_options = create_cfg_options(rustc_cfg.clone()); + let sysroot_crates: FxHashMap = stitched + .crates() + .filter_map(|krate| { + let file_id = load(&stitched[krate].root)?; - let public_deps = SysrootPublicDeps { - deps: sysroot - .public_deps() - .filter_map(|(name, idx, prelude)| Some((name, *sysroot_crates.get(&idx)?, prelude))) - .collect::>(), - }; + let env = Env::default(); + let display_name = + CrateDisplayName::from_canonical_name(stitched[krate].name.clone()); + let crate_id = crate_graph.add_crate_root( + file_id, + Edition::CURRENT, + Some(display_name), + None, + cfg_options.clone(), + None, + env, + false, + CrateOrigin::Lang(LangCrateOrigin::from(&*stitched[krate].name)), + target_layout.clone(), + toolchain.cloned(), + ); + Some((krate, crate_id)) + }) + .collect(); + + for from in stitched.crates() { + for &to in stitched[from].deps.iter() { + let name = CrateName::new(&stitched[to].name).unwrap(); + if let (Some(&from), Some(&to)) = + (sysroot_crates.get(&from), sysroot_crates.get(&to)) + { + add_dep(crate_graph, from, name, to, DependencyKind::Normal); + } + } + } - let libproc_macro = sysroot.proc_macro().and_then(|it| sysroot_crates.get(&it).copied()); - (public_deps, libproc_macro) -} + let public_deps = SysrootPublicDeps { + deps: stitched + .public_deps() + .filter_map(|(name, idx, prelude)| { + Some((name, *sysroot_crates.get(&idx)?, prelude)) + }) + .collect::>(), + }; -fn handle_hack_cargo_workspace( - load: &mut dyn FnMut(&AbsPath) -> Option, - cargo: &CargoWorkspace, - rustc_cfg: Vec, - cfg_options: CfgOptions, - target_layout: Result, Arc>, - toolchain: Option<&Version>, - crate_graph: &mut CrateGraph, - sysroot: &Sysroot, -) -> FxHashMap { - let (cg, mut pm) = cargo_to_crate_graph( - load, - None, - cargo, - None, - rustc_cfg, - &CfgOverrides::default(), - Some(cfg_options), - &WorkspaceBuildScripts::default(), - target_layout, - toolchain, - ); - crate_graph.extend(cg, &mut pm); - for crate_name in ["std", "alloc", "core"] { - let original = crate_graph - .iter() - .find(|x| { - crate_graph[*x] - .display_name - .as_ref() - .map(|x| x.canonical_name() == crate_name) - .unwrap_or(false) - }) - .unwrap(); - let fake_crate_name = format!("rustc-std-workspace-{}", crate_name); - let fake = crate_graph - .iter() - .find(|x| { - crate_graph[*x] - .display_name - .as_ref() - .map(|x| x.canonical_name() == fake_crate_name) - .unwrap_or(false) - }) - .unwrap(); - crate_graph.remove_and_replace(fake, original).unwrap(); - } - for (_, c) in crate_graph.iter_mut() { - if c.origin.is_local() { - // LangCrateOrigin::Other is good enough for a hack. - c.origin = CrateOrigin::Lang(LangCrateOrigin::Other); + let libproc_macro = + stitched.proc_macro().and_then(|it| sysroot_crates.get(&it).copied()); + (public_deps, libproc_macro) } } - sysroot - .crates() - .filter_map(|krate| { - let file_id = load(&sysroot[krate].root)?; - let crate_id = crate_graph.crate_id_for_crate_root(file_id)?; - Some((krate, crate_id)) - }) - .collect() } fn add_dep( diff --git a/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt b/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt index e35f0fc7327e2..0df99534c5bd9 100644 --- a/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt +++ b/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt @@ -182,7 +182,7 @@ }, ], origin: Lang( - Other, + ProcMacro, ), is_proc_macro: false, target_layout: Err( diff --git a/crates/rust-analyzer/src/cli/rustc_tests.rs b/crates/rust-analyzer/src/cli/rustc_tests.rs index b8f6138161e5c..87bb3cbd3410d 100644 --- a/crates/rust-analyzer/src/cli/rustc_tests.rs +++ b/crates/rust-analyzer/src/cli/rustc_tests.rs @@ -61,9 +61,12 @@ impl Tester { cargo_config.sysroot = Some(RustLibSource::Discover); let workspace = ProjectWorkspace::DetachedFiles { files: vec![tmp_file.clone()], - sysroot: Ok( - Sysroot::discover(tmp_file.parent().unwrap(), &cargo_config.extra_env).unwrap() - ), + sysroot: Ok(Sysroot::discover( + tmp_file.parent().unwrap(), + &cargo_config.extra_env, + false, + ) + .unwrap()), rustc_cfg: vec![], }; let load_cargo_config = LoadCargoConfig { diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index fe009f82a71fd..3ec5d86966154 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -135,6 +135,13 @@ config_data! { /// /// This option does not take effect until rust-analyzer is restarted. cargo_sysroot: Option = "\"discover\"", + /// Whether to run cargo metadata on the sysroot library allowing rust-analyzer to analyze + /// third-party dependencies of the standard libraries. + /// + /// This will cause `cargo` to create a lockfile in your sysroot directory. rust-analyzer + /// will attempt to clean up afterwards, but nevertheless requires the location to be + /// writable to. + cargo_sysrootQueryMetadata: bool = "false", /// Relative path to the sysroot library sources. If left unset, this will default to /// `{cargo.sysroot}/lib/rustlib/src/rust/library`. /// @@ -1233,6 +1240,7 @@ impl Config { }); let sysroot_src = self.data.cargo_sysrootSrc.as_ref().map(|sysroot| self.root_path.join(sysroot)); + let sysroot_query_metadata = self.data.cargo_sysrootQueryMetadata; CargoConfig { features: match &self.data.cargo_features { @@ -1244,6 +1252,7 @@ impl Config { }, target: self.data.cargo_target.clone(), sysroot, + sysroot_query_metadata, sysroot_src, rustc_source, cfg_overrides: project_model::CfgOverrides { diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 8e3fa7fa4dace..24af5fb49c042 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -516,7 +516,7 @@ impl GlobalState { for ws in &**self.workspaces { let (other, mut crate_proc_macros) = ws.to_crate_graph(&mut load, &self.config.extra_env()); - crate_graph.extend(other, &mut crate_proc_macros); + crate_graph.extend(other, &mut crate_proc_macros, |_| {}); proc_macros.push(crate_proc_macros); } (crate_graph, proc_macros, crate_graph_file_dependencies) diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index ecc90abff1353..1a2791954e629 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc @@ -121,6 +121,16 @@ Unsetting this disables sysroot loading. This option does not take effect until rust-analyzer is restarted. -- +[[rust-analyzer.cargo.sysrootQueryMetadata]]rust-analyzer.cargo.sysrootQueryMetadata (default: `false`):: ++ +-- +Whether to run cargo metadata on the sysroot library allowing rust-analyzer to analyze +third-party dependencies of the standard libraries. + +This will cause `cargo` to create a lockfile in your sysroot directory. rust-analyzer +will attempt to clean up afterwards, but nevertheless requires the location to be +writable to. +-- [[rust-analyzer.cargo.sysrootSrc]]rust-analyzer.cargo.sysrootSrc (default: `null`):: + -- diff --git a/editors/code/package.json b/editors/code/package.json index 8307f6833e6fb..e7ceee165cdcb 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -648,6 +648,11 @@ "string" ] }, + "rust-analyzer.cargo.sysrootQueryMetadata": { + "markdownDescription": "Whether to run cargo metadata on the sysroot library allowing rust-analyzer to analyze\nthird-party dependencies of the standard libraries.\n\nThis will cause `cargo` to create a lockfile in your sysroot directory. rust-analyzer\nwill attempt to clean up afterwards, but nevertheless requires the location to be\nwritable to.", + "default": false, + "type": "boolean" + }, "rust-analyzer.cargo.sysrootSrc": { "markdownDescription": "Relative path to the sysroot library sources. If left unset, this will default to\n`{cargo.sysroot}/lib/rustlib/src/rust/library`.\n\nThis option does not take effect until rust-analyzer is restarted.", "default": null, From d80d2fcae0fb66901d88980d74520992fd5882ff Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 15 Jan 2024 10:24:14 +0100 Subject: [PATCH 0227/1197] Eagerly lower enum variants in CrateDefMap construction --- crates/hir-def/src/attr.rs | 82 +------- crates/hir-def/src/body.rs | 7 +- crates/hir-def/src/body/pretty.rs | 14 +- crates/hir-def/src/child_by_source.rs | 22 ++- crates/hir-def/src/data/adt.rs | 185 +++++------------- crates/hir-def/src/db.rs | 35 ++-- crates/hir-def/src/find_path.rs | 12 +- crates/hir-def/src/item_scope.rs | 7 +- crates/hir-def/src/item_tree.rs | 54 +++-- crates/hir-def/src/item_tree/lower.rs | 10 +- crates/hir-def/src/item_tree/pretty.rs | 2 +- crates/hir-def/src/lang_item.rs | 8 +- crates/hir-def/src/lib.rs | 35 ++-- crates/hir-def/src/nameres/collector.rs | 100 ++++++---- crates/hir-def/src/nameres/path_resolution.rs | 66 +++++-- crates/hir-def/src/pretty.rs | 8 +- crates/hir-def/src/resolver.rs | 8 +- crates/hir-def/src/src.rs | 17 +- crates/hir-def/src/trace.rs | 6 +- crates/hir-def/src/visibility.rs | 4 +- crates/hir-expand/src/db.rs | 3 + crates/hir-ty/src/consteval.rs | 21 +- crates/hir-ty/src/db.rs | 2 +- crates/hir-ty/src/diagnostics/decl_check.rs | 8 +- crates/hir-ty/src/diagnostics/match_check.rs | 3 +- .../match_check/deconstruct_pat.rs | 2 +- crates/hir-ty/src/display.rs | 16 +- crates/hir-ty/src/infer.rs | 58 +++--- crates/hir-ty/src/infer/closure.rs | 2 +- crates/hir-ty/src/infer/path.rs | 5 +- crates/hir-ty/src/inhabitedness.rs | 17 +- crates/hir-ty/src/layout.rs | 8 +- crates/hir-ty/src/layout/adt.rs | 17 +- crates/hir-ty/src/lower.rs | 27 +-- crates/hir-ty/src/mir/eval.rs | 84 ++++---- crates/hir-ty/src/mir/lower.rs | 15 +- .../hir-ty/src/mir/lower/pattern_matching.rs | 24 +-- crates/hir-ty/src/mir/pretty.rs | 15 +- crates/hir-ty/src/tests.rs | 22 +-- crates/hir-ty/src/tls.rs | 5 +- crates/hir-ty/src/utils.rs | 26 +-- crates/hir/src/attrs.rs | 2 +- crates/hir/src/db.rs | 6 +- crates/hir/src/from_id.rs | 4 +- crates/hir/src/has_source.rs | 2 +- crates/hir/src/lib.rs | 54 ++--- crates/hir/src/symbols.rs | 4 +- crates/ide-db/src/apply_change.rs | 5 +- crates/ide-db/src/lib.rs | 5 +- 49 files changed, 552 insertions(+), 592 deletions(-) diff --git a/crates/hir-def/src/attr.rs b/crates/hir-def/src/attr.rs index 30452e34aac36..be69d6f1351ac 100644 --- a/crates/hir-def/src/attr.rs +++ b/crates/hir-def/src/attr.rs @@ -28,8 +28,8 @@ use crate::{ lang_item::LangItem, nameres::{ModuleOrigin, ModuleSource}, src::{HasChildSource, HasSource}, - AdtId, AssocItemLoc, AttrDefId, EnumId, GenericParamId, ItemLoc, LocalEnumVariantId, - LocalFieldId, Lookup, MacroId, VariantId, + AdtId, AssocItemLoc, AttrDefId, GenericParamId, ItemLoc, LocalFieldId, Lookup, MacroId, + VariantId, }; #[derive(Default, Debug, Clone, PartialEq, Eq)] @@ -70,33 +70,6 @@ impl ops::Deref for AttrsWithOwner { impl Attrs { pub const EMPTY: Self = Self(RawAttrs::EMPTY); - pub(crate) fn variants_attrs_query( - db: &dyn DefDatabase, - e: EnumId, - ) -> Arc> { - let _p = profile::span("variants_attrs_query"); - // FIXME: There should be some proper form of mapping between item tree enum variant ids and hir enum variant ids - let mut res = ArenaMap::default(); - - let loc = e.lookup(db); - let krate = loc.container.krate; - let item_tree = loc.id.item_tree(db); - let enum_ = &item_tree[loc.id.value]; - let crate_graph = db.crate_graph(); - let cfg_options = &crate_graph[krate].cfg_options; - - let mut idx = 0; - for variant in enum_.variants.clone() { - let attrs = item_tree.attrs(db, krate, variant.into()); - if attrs.is_cfg_enabled(cfg_options) { - res.insert(Idx::from_raw(RawIdx::from(idx)), attrs); - idx += 1; - } - } - - Arc::new(res) - } - pub(crate) fn fields_attrs_query( db: &dyn DefDatabase, v: VariantId, @@ -108,29 +81,11 @@ impl Attrs { let crate_graph = db.crate_graph(); let (fields, item_tree, krate) = match v { VariantId::EnumVariantId(it) => { - let e = it.parent; - let loc = e.lookup(db); + let loc = it.lookup(db); let krate = loc.container.krate; let item_tree = loc.id.item_tree(db); - let enum_ = &item_tree[loc.id.value]; - - let cfg_options = &crate_graph[krate].cfg_options; - - let Some(variant) = enum_ - .variants - .clone() - .filter(|variant| { - let attrs = item_tree.attrs(db, krate, (*variant).into()); - attrs.is_cfg_enabled(cfg_options) - }) - .zip(0u32..) - .find(|(_variant, idx)| it.local_id == Idx::from_raw(RawIdx::from(*idx))) - .map(|(variant, _idx)| variant) - else { - return Arc::new(res); - }; - - (item_tree[variant].fields.clone(), item_tree, krate) + let variant = &item_tree[loc.id.value]; + (variant.fields.clone(), item_tree, krate) } VariantId::StructId(it) => { let loc = it.lookup(db); @@ -401,10 +356,12 @@ impl AttrsWithOwner { AttrDefId::FieldId(it) => { return db.fields_attrs(it.parent)[it.local_id].clone(); } + // FIXME: DRY this up AttrDefId::EnumVariantId(it) => { - return db.variants_attrs(it.parent)[it.local_id].clone(); + let id = it.lookup(db).id; + let tree = id.item_tree(db); + tree.raw_attrs(id.value.into()).clone() } - // FIXME: DRY this up AttrDefId::AdtId(it) => match it { AdtId::StructId(it) => attrs_from_item_tree_loc(db, it), AdtId::EnumId(it) => attrs_from_item_tree_loc(db, it), @@ -503,12 +460,7 @@ impl AttrsWithOwner { AdtId::EnumId(id) => any_has_attrs(db, id), }, AttrDefId::FunctionId(id) => any_has_attrs(db, id), - AttrDefId::EnumVariantId(id) => { - let map = db.variants_attrs_source_map(id.parent); - let file_id = id.parent.lookup(db).id.file_id(); - let root = db.parse_or_expand(file_id); - InFile::new(file_id, ast::AnyHasAttrs::new(map[id.local_id].to_node(&root))) - } + AttrDefId::EnumVariantId(id) => any_has_attrs(db, id), AttrDefId::StaticId(id) => any_has_attrs(db, id), AttrDefId::ConstId(id) => any_has_attrs(db, id), AttrDefId::TraitId(id) => any_has_attrs(db, id), @@ -676,20 +628,6 @@ fn attrs_from_item_tree_assoc<'db, N: ItemTreeNode>( attrs_from_item_tree(db, id) } -pub(crate) fn variants_attrs_source_map( - db: &dyn DefDatabase, - def: EnumId, -) -> Arc>> { - let mut res = ArenaMap::default(); - let child_source = def.child_source(db); - - for (idx, variant) in child_source.value.iter() { - res.insert(idx, AstPtr::new(variant)); - } - - Arc::new(res) -} - pub(crate) fn fields_attrs_source_map( db: &dyn DefDatabase, def: VariantId, diff --git a/crates/hir-def/src/body.rs b/crates/hir-def/src/body.rs index db28c6731ece1..a9c71f649a7b5 100644 --- a/crates/hir-def/src/body.rs +++ b/crates/hir-def/src/body.rs @@ -26,7 +26,7 @@ use crate::{ }, nameres::DefMap, path::{ModPath, Path}, - src::{HasChildSource, HasSource}, + src::HasSource, BlockId, DefWithBodyId, HasModule, Lookup, }; @@ -160,8 +160,9 @@ impl Body { src.map(|it| it.body()) } DefWithBodyId::VariantId(v) => { - let src = v.parent.child_source(db); - src.map(|it| it[v.local_id].expr()) + let s = v.lookup(db); + let src = s.source(db); + src.map(|it| it.expr()) } DefWithBodyId::InTypeConstId(c) => c.lookup(db).id.map(|_| c.source(db).expr()), } diff --git a/crates/hir-def/src/body/pretty.rs b/crates/hir-def/src/body/pretty.rs index 02b19ade44ba9..601878e8e79ca 100644 --- a/crates/hir-def/src/body/pretty.rs +++ b/crates/hir-def/src/body/pretty.rs @@ -3,7 +3,6 @@ use std::fmt::{self, Write}; use itertools::Itertools; -use syntax::ast::HasName; use crate::{ hir::{ @@ -42,12 +41,13 @@ pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBo } DefWithBodyId::InTypeConstId(_) => format!("In type const = "), DefWithBodyId::VariantId(it) => { - let src = it.parent.child_source(db); - let variant = &src.value[it.local_id]; - match &variant.name() { - Some(name) => name.to_string(), - None => "_".to_string(), - } + let loc = it.lookup(db); + let enum_loc = loc.parent.lookup(db); + format!( + "enum {}::{}", + enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db.upcast()), + loc.id.item_tree(db)[loc.id.value].name.display(db.upcast()), + ) } }; diff --git a/crates/hir-def/src/child_by_source.rs b/crates/hir-def/src/child_by_source.rs index 32c53cb950313..e8a771141effb 100644 --- a/crates/hir-def/src/child_by_source.rs +++ b/crates/hir-def/src/child_by_source.rs @@ -13,8 +13,8 @@ use crate::{ item_scope::ItemScope, nameres::DefMap, src::{HasChildSource, HasSource}, - AdtId, AssocItemId, DefWithBodyId, EnumId, EnumVariantId, ExternCrateId, FieldId, ImplId, - Lookup, MacroId, ModuleDefId, ModuleId, TraitId, UseId, VariantId, + AdtId, AssocItemId, DefWithBodyId, EnumId, ExternCrateId, FieldId, ImplId, Lookup, MacroId, + ModuleDefId, ModuleId, TraitId, UseId, VariantId, }; pub trait ChildBySource { @@ -205,12 +205,18 @@ impl ChildBySource for VariantId { impl ChildBySource for EnumId { fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, _: HirFileId) { - let arena_map = self.child_source(db); - let arena_map = arena_map.as_ref(); - for (local_id, source) in arena_map.value.iter() { - let id = EnumVariantId { parent: *self, local_id }; - res[keys::VARIANT].insert(source.clone(), id) - } + let loc = &self.lookup(db); + + let tree = loc.id.item_tree(db); + let ast_id_map = db.ast_id_map(loc.id.file_id()); + let root = db.parse_or_expand(loc.id.file_id()); + + db.enum_data(*self).variants.iter().for_each(|&(variant, _)| { + res[keys::VARIANT].insert( + ast_id_map.get(tree[variant.lookup(db).id.value].ast_id).to_node(&root), + variant, + ); + }); } } diff --git a/crates/hir-def/src/data/adt.rs b/crates/hir-def/src/data/adt.rs index 8772c34f02f1a..93a64dc6ec6fb 100644 --- a/crates/hir-def/src/data/adt.rs +++ b/crates/hir-def/src/data/adt.rs @@ -28,8 +28,7 @@ use crate::{ tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree}, type_ref::TypeRef, visibility::RawVisibility, - EnumId, EnumLoc, LocalEnumVariantId, LocalFieldId, LocalModuleId, Lookup, ModuleId, StructId, - UnionId, VariantId, + EnumId, EnumVariantId, LocalFieldId, LocalModuleId, Lookup, StructId, UnionId, VariantId, }; /// Note that we use `StructData` for unions as well! @@ -43,7 +42,7 @@ pub struct StructData { } bitflags! { -#[derive(Debug, Clone, PartialEq, Eq)] + #[derive(Debug, Clone, PartialEq, Eq)] pub struct StructFlags: u8 { const NO_FLAGS = 0; /// Indicates whether the struct is `PhantomData`. @@ -65,7 +64,7 @@ bitflags! { #[derive(Debug, Clone, PartialEq, Eq)] pub struct EnumData { pub name: Name, - pub variants: Arena, + pub variants: Box<[(EnumVariantId, Name)]>, pub repr: Option, pub visibility: RawVisibility, pub rustc_has_incoherent_inherent_impls: bool, @@ -75,7 +74,6 @@ pub struct EnumData { pub struct EnumVariantData { pub name: Name, pub variant_data: Arc, - pub tree_id: la_arena::Idx, } #[derive(Debug, Clone, PartialEq, Eq)] @@ -287,17 +285,9 @@ impl StructData { impl EnumData { pub(crate) fn enum_data_query(db: &dyn DefDatabase, e: EnumId) -> Arc { - db.enum_data_with_diagnostics(e).0 - } - - pub(crate) fn enum_data_with_diagnostics_query( - db: &dyn DefDatabase, - e: EnumId, - ) -> (Arc, Arc<[DefDiagnostic]>) { let loc = e.lookup(db); let krate = loc.container.krate; let item_tree = loc.id.item_tree(db); - let cfg_options = db.crate_graph()[krate].cfg_options.clone(); let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into()); let rustc_has_incoherent_inherent_impls = item_tree .attrs(db, loc.container.krate, ModItem::from(loc.id.value).into()) @@ -305,53 +295,21 @@ impl EnumData { .exists(); let enum_ = &item_tree[loc.id.value]; - let mut variants = Arena::new(); - let mut diagnostics = Vec::new(); - for tree_id in enum_.variants.clone() { - let attrs = item_tree.attrs(db, krate, tree_id.into()); - let var = &item_tree[tree_id]; - if attrs.is_cfg_enabled(&cfg_options) { - let (var_data, field_diagnostics) = lower_fields( - db, - krate, - loc.id.file_id(), - loc.container.local_id, - &item_tree, - &cfg_options, - &var.fields, - Some(enum_.visibility), - ); - diagnostics.extend(field_diagnostics); - - variants.alloc(EnumVariantData { - name: var.name.clone(), - variant_data: Arc::new(var_data), - tree_id, - }); - } else { - diagnostics.push(DefDiagnostic::unconfigured_code( - loc.container.local_id, - InFile::new(loc.id.file_id(), var.ast_id.erase()), - attrs.cfg().unwrap(), - cfg_options.clone(), - )) - } - } - ( - Arc::new(EnumData { - name: enum_.name.clone(), - variants, - repr, - visibility: item_tree[enum_.visibility].clone(), - rustc_has_incoherent_inherent_impls, - }), - diagnostics.into(), - ) + Arc::new(EnumData { + name: enum_.name.clone(), + variants: loc.container.def_map(db)[loc.container.local_id].scope.enums[&e] + .iter() + .map(|&id| (id, item_tree[id.lookup(db).id.value].name.clone())) + .collect(), + repr, + visibility: item_tree[enum_.visibility].clone(), + rustc_has_incoherent_inherent_impls, + }) } - pub fn variant(&self, name: &Name) -> Option { - let (id, _) = self.variants.iter().find(|(_id, data)| &data.name == name)?; + pub fn variant(&self, name: &Name) -> Option { + let &(id, _) = self.variants.iter().find(|(_id, n)| n == name)?; Some(id) } @@ -363,82 +321,46 @@ impl EnumData { } } -impl HasChildSource for EnumId { - type Value = ast::Variant; - fn child_source( - &self, +impl EnumVariantData { + pub(crate) fn enum_variant_data_query( db: &dyn DefDatabase, - ) -> InFile> { - let loc = &self.lookup(db); - let src = loc.source(db); - let mut trace = Trace::new_for_map(); - lower_enum(db, &mut trace, &src, loc); - src.with_value(trace.into_map()) + e: EnumVariantId, + ) -> Arc { + db.enum_variant_data_with_diagnostics(e).0 } -} -fn lower_enum( - db: &dyn DefDatabase, - trace: &mut Trace, - ast: &InFile, - loc: &EnumLoc, -) { - let item_tree = loc.id.item_tree(db); - let krate = loc.container.krate; - - let item_tree_variants = item_tree[loc.id.value].variants.clone(); - - let cfg_options = &db.crate_graph()[krate].cfg_options; - let variants = ast - .value - .variant_list() - .into_iter() - .flat_map(|it| it.variants()) - .zip(item_tree_variants) - .filter(|&(_, item_tree_id)| { - item_tree.attrs(db, krate, item_tree_id.into()).is_cfg_enabled(cfg_options) - }); - for (var, item_tree_id) in variants { - trace.alloc( - || var.clone(), - || EnumVariantData { - name: var.name().map_or_else(Name::missing, |it| it.as_name()), - variant_data: Arc::new(VariantData::new( - db, - ast.with_value(var.kind()), - loc.container, - &item_tree, - item_tree_id, - )), - tree_id: item_tree_id, - }, + pub(crate) fn enum_variant_data_with_diagnostics_query( + db: &dyn DefDatabase, + e: EnumVariantId, + ) -> (Arc, Arc<[DefDiagnostic]>) { + let loc = e.lookup(db); + let krate = loc.container.krate; + let item_tree = loc.id.item_tree(db); + let cfg_options = db.crate_graph()[krate].cfg_options.clone(); + let variant = &item_tree[loc.id.value]; + + let (var_data, field_diagnostics) = lower_fields( + db, + krate, + loc.id.file_id(), + loc.container.local_id, + &item_tree, + &cfg_options, + &variant.fields, + Some(item_tree[loc.parent.lookup(db).id.value].visibility), ); + + ( + Arc::new(EnumVariantData { + name: variant.name.clone(), + variant_data: Arc::new(var_data), + }), + field_diagnostics.into(), + ) } } impl VariantData { - fn new( - db: &dyn DefDatabase, - flavor: InFile, - module_id: ModuleId, - item_tree: &ItemTree, - variant: la_arena::Idx, - ) -> Self { - let mut trace = Trace::new_for_arena(); - match lower_struct( - db, - &mut trace, - &flavor, - module_id.krate, - item_tree, - &item_tree[variant].fields, - ) { - StructKind::Tuple => VariantData::Tuple(trace.into_arena()), - StructKind::Record => VariantData::Record(trace.into_arena()), - StructKind::Unit => VariantData::Unit, - } - } - pub fn fields(&self) -> &Arena { const EMPTY: &Arena = &Arena::new(); match &self { @@ -468,14 +390,13 @@ impl HasChildSource for VariantId { let item_tree; let (src, fields, container) = match *self { VariantId::EnumVariantId(it) => { - // I don't really like the fact that we call into parent source - // here, this might add to more queries then necessary. - let lookup = it.parent.lookup(db); + let lookup = it.lookup(db); item_tree = lookup.id.item_tree(db); - let src = it.parent.child_source(db); - let tree_id = db.enum_data(it.parent).variants[it.local_id].tree_id; - let fields = &item_tree[tree_id].fields; - (src.map(|map| map[it.local_id].kind()), fields, lookup.container) + ( + lookup.source(db).map(|it| it.kind()), + &item_tree[lookup.id.value].fields, + lookup.container, + ) } VariantId::StructId(it) => { let lookup = it.lookup(db); diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs index 70c0d5193d4bf..4201b1dd17435 100644 --- a/crates/hir-def/src/db.rs +++ b/crates/hir-def/src/db.rs @@ -11,7 +11,7 @@ use crate::{ attr::{Attrs, AttrsWithOwner}, body::{scope::ExprScopes, Body, BodySourceMap}, data::{ - adt::{EnumData, StructData}, + adt::{EnumData, EnumVariantData, StructData}, ConstData, ExternCrateDeclData, FunctionData, ImplData, Macro2Data, MacroRulesData, ProcMacroData, StaticData, TraitAliasData, TraitData, TypeAliasData, }, @@ -22,12 +22,12 @@ use crate::{ nameres::{diagnostics::DefDiagnostic, DefMap}, visibility::{self, Visibility}, AttrDefId, BlockId, BlockLoc, ConstBlockId, ConstBlockLoc, ConstId, ConstLoc, DefWithBodyId, - EnumId, EnumLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId, - FunctionLoc, GenericDefId, ImplId, ImplLoc, InTypeConstId, InTypeConstLoc, LocalEnumVariantId, - LocalFieldId, Macro2Id, Macro2Loc, MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, - ProcMacroId, ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc, TraitAliasId, - TraitAliasLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc, - VariantId, + EnumId, EnumLoc, EnumVariantId, EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, + ExternCrateLoc, FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, InTypeConstId, + InTypeConstLoc, LocalFieldId, Macro2Id, Macro2Loc, MacroId, MacroRulesId, MacroRulesLoc, + MacroRulesLocFlags, ProcMacroId, ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc, + TraitAliasId, TraitAliasLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, + UseId, UseLoc, VariantId, }; #[salsa::query_group(InternDatabaseStorage)] @@ -46,6 +46,8 @@ pub trait InternDatabase: SourceDatabase { #[salsa::interned] fn intern_enum(&self, loc: EnumLoc) -> EnumId; #[salsa::interned] + fn intern_enum_variant(&self, loc: EnumVariantLoc) -> EnumVariantId; + #[salsa::interned] fn intern_const(&self, loc: ConstLoc) -> ConstId; #[salsa::interned] fn intern_static(&self, loc: StaticLoc) -> StaticId; @@ -131,8 +133,14 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast Arc; - #[salsa::invoke(EnumData::enum_data_with_diagnostics_query)] - fn enum_data_with_diagnostics(&self, e: EnumId) -> (Arc, Arc<[DefDiagnostic]>); + #[salsa::invoke(EnumVariantData::enum_variant_data_query)] + fn enum_variant_data(&self, id: EnumVariantId) -> Arc; + + #[salsa::invoke(EnumVariantData::enum_variant_data_with_diagnostics_query)] + fn enum_variant_data_with_diagnostics( + &self, + id: EnumVariantId, + ) -> (Arc, Arc<[DefDiagnostic]>); #[salsa::invoke(ImplData::impl_data_query)] fn impl_data(&self, e: ImplId) -> Arc; @@ -189,18 +197,9 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast Arc>; - #[salsa::invoke(Attrs::fields_attrs_query)] fn fields_attrs(&self, def: VariantId) -> Arc>; - #[salsa::invoke(crate::attr::variants_attrs_source_map)] - fn variants_attrs_source_map( - &self, - def: EnumId, - ) -> Arc>>; - #[salsa::invoke(crate::attr::fields_attrs_source_map)] fn fields_attrs_source_map( &self, diff --git a/crates/hir-def/src/find_path.rs b/crates/hir-def/src/find_path.rs index 67e43f15cd3f3..3ff51b9845cef 100644 --- a/crates/hir-def/src/find_path.rs +++ b/crates/hir-def/src/find_path.rs @@ -2,7 +2,10 @@ use std::{cmp::Ordering, iter}; -use hir_expand::name::{known, AsName, Name}; +use hir_expand::{ + name::{known, AsName, Name}, + Lookup, +}; use rustc_hash::FxHashSet; use crate::{ @@ -139,9 +142,10 @@ fn find_path_inner(ctx: FindPathCtx<'_>, item: ItemInNs, from: ModuleId) -> Opti if let Some(ModuleDefId::EnumVariantId(variant)) = item.as_module_def_id() { // - if the item is an enum variant, refer to it via the enum - if let Some(mut path) = find_path_inner(ctx, ItemInNs::Types(variant.parent.into()), from) { - let data = ctx.db.enum_data(variant.parent); - path.push_segment(data.variants[variant.local_id].name.clone()); + if let Some(mut path) = + find_path_inner(ctx, ItemInNs::Types(variant.lookup(ctx.db).parent.into()), from) + { + path.push_segment(ctx.db.enum_variant_data(variant).name.clone()); return Some(path); } // If this doesn't work, it seems we have no way of referring to the diff --git a/crates/hir-def/src/item_scope.rs b/crates/hir-def/src/item_scope.rs index 168ee4acffbef..436bc0c98c2ad 100644 --- a/crates/hir-def/src/item_scope.rs +++ b/crates/hir-def/src/item_scope.rs @@ -18,8 +18,8 @@ use crate::{ db::DefDatabase, per_ns::PerNs, visibility::{Visibility, VisibilityExplicity}, - AdtId, BuiltinType, ConstId, ExternCrateId, HasModule, ImplId, LocalModuleId, Lookup, MacroId, - ModuleDefId, ModuleId, TraitId, UseId, + AdtId, BuiltinType, ConstId, EnumId, EnumVariantId, ExternCrateId, HasModule, ImplId, + LocalModuleId, Lookup, MacroId, ModuleDefId, ModuleId, TraitId, UseId, }; #[derive(Debug, Default)] @@ -79,6 +79,7 @@ pub struct ItemScope { /// declared. declarations: Vec, + pub enums: FxHashMap>, impls: Vec, unnamed_consts: Vec, /// Traits imported via `use Trait as _;`. @@ -718,6 +719,7 @@ impl ItemScope { use_imports_types, use_imports_macros, macro_invocations, + enums, } = self; types.shrink_to_fit(); values.shrink_to_fit(); @@ -736,6 +738,7 @@ impl ItemScope { extern_crate_decls.shrink_to_fit(); use_decls.shrink_to_fit(); macro_invocations.shrink_to_fit(); + enums.shrink_to_fit(); } } diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index 82ea5ffeba17c..0f81bef500643 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -41,7 +41,7 @@ mod tests; use std::{ fmt::{self, Debug}, hash::{Hash, Hasher}, - ops::Index, + ops::{Index, Range}, }; use ast::{AstNode, HasName, StructKind}; @@ -308,7 +308,7 @@ pub enum AttrOwner { /// Inner attributes of the source file. TopLevel, - Variant(Idx), + Variant(FileItemTreeId), Field(Idx), Param(Idx), TypeOrConstParamData(Idx), @@ -329,7 +329,7 @@ macro_rules! from_attrs { from_attrs!( ModItem(ModItem), - Variant(Idx), + Variant(FileItemTreeId), Field(Idx), Param(Idx), TypeOrConstParamData(Idx), @@ -352,35 +352,44 @@ pub trait ItemTreeNode: Clone { fn id_to_mod_item(id: FileItemTreeId) -> ModItem; } -pub struct FileItemTreeId(Idx); +pub struct FileItemTreeId(Idx); -impl FileItemTreeId { +impl FileItemTreeId { + pub fn range_iter(range: Range) -> impl Iterator { + (range.start.index().into_raw().into_u32()..range.end.index().into_raw().into_u32()) + .map(RawIdx::from_u32) + .map(Idx::from_raw) + .map(Self) + } +} + +impl FileItemTreeId { pub fn index(&self) -> Idx { self.0 } } -impl Clone for FileItemTreeId { +impl Clone for FileItemTreeId { fn clone(&self) -> Self { Self(self.0) } } -impl Copy for FileItemTreeId {} +impl Copy for FileItemTreeId {} -impl PartialEq for FileItemTreeId { +impl PartialEq for FileItemTreeId { fn eq(&self, other: &FileItemTreeId) -> bool { self.0 == other.0 } } -impl Eq for FileItemTreeId {} +impl Eq for FileItemTreeId {} -impl Hash for FileItemTreeId { +impl Hash for FileItemTreeId { fn hash(&self, state: &mut H) { self.0.hash(state) } } -impl fmt::Debug for FileItemTreeId { +impl fmt::Debug for FileItemTreeId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } @@ -415,12 +424,12 @@ impl TreeId { } #[derive(Debug)] -pub struct ItemTreeId { +pub struct ItemTreeId { tree: TreeId, pub value: FileItemTreeId, } -impl ItemTreeId { +impl ItemTreeId { pub fn new(tree: TreeId, idx: FileItemTreeId) -> Self { Self { tree, value: idx } } @@ -438,22 +447,22 @@ impl ItemTreeId { } } -impl Copy for ItemTreeId {} -impl Clone for ItemTreeId { +impl Copy for ItemTreeId {} +impl Clone for ItemTreeId { fn clone(&self) -> Self { *self } } -impl PartialEq for ItemTreeId { +impl PartialEq for ItemTreeId { fn eq(&self, other: &Self) -> bool { self.tree == other.tree && self.value == other.value } } -impl Eq for ItemTreeId {} +impl Eq for ItemTreeId {} -impl Hash for ItemTreeId { +impl Hash for ItemTreeId { fn hash(&self, state: &mut H) { self.tree.hash(state); self.value.hash(state); @@ -568,6 +577,13 @@ impl Index> for ItemTree { } } +impl Index> for ItemTree { + type Output = Variant; + fn index(&self, id: FileItemTreeId) -> &Variant { + &self[id.index()] + } +} + #[derive(Debug, Clone, Eq, PartialEq)] pub struct Use { pub visibility: RawVisibilityId, @@ -678,7 +694,7 @@ pub struct Enum { pub name: Name, pub visibility: RawVisibilityId, pub generic_params: Interned, - pub variants: IdxRange, + pub variants: Range>, pub ast_id: FileAstId, } diff --git a/crates/hir-def/src/item_tree/lower.rs b/crates/hir-def/src/item_tree/lower.rs index 6343b43a016b2..8d19b5000cf4d 100644 --- a/crates/hir-def/src/item_tree/lower.rs +++ b/crates/hir-def/src/item_tree/lower.rs @@ -253,25 +253,27 @@ impl<'a> Ctx<'a> { let generic_params = self.lower_generic_params(HasImplicitSelf::No, enum_); let variants = match &enum_.variant_list() { Some(variant_list) => self.lower_variants(variant_list), - None => IdxRange::new(self.next_variant_idx()..self.next_variant_idx()), + None => { + FileItemTreeId(self.next_variant_idx())..FileItemTreeId(self.next_variant_idx()) + } }; let res = Enum { name, visibility, generic_params, variants, ast_id }; Some(id(self.data().enums.alloc(res))) } - fn lower_variants(&mut self, variants: &ast::VariantList) -> IdxRange { + fn lower_variants(&mut self, variants: &ast::VariantList) -> Range> { let start = self.next_variant_idx(); for variant in variants.variants() { if let Some(data) = self.lower_variant(&variant) { let idx = self.data().variants.alloc(data); self.add_attrs( - idx.into(), + FileItemTreeId(idx).into(), RawAttrs::new(self.db.upcast(), &variant, self.span_map()), ); } } let end = self.next_variant_idx(); - IdxRange::new(start..end) + FileItemTreeId(start)..FileItemTreeId(end) } fn lower_variant(&mut self, variant: &ast::Variant) -> Option { diff --git a/crates/hir-def/src/item_tree/pretty.rs b/crates/hir-def/src/item_tree/pretty.rs index 8693b9a98c9d9..d8a0cb569839e 100644 --- a/crates/hir-def/src/item_tree/pretty.rs +++ b/crates/hir-def/src/item_tree/pretty.rs @@ -318,7 +318,7 @@ impl Printer<'_> { self.print_generic_params(generic_params); self.print_where_clause_and_opening_brace(generic_params); self.indented(|this| { - for variant in variants.clone() { + for variant in FileItemTreeId::range_iter(variants.clone()) { let Variant { name, fields, ast_id: _ } = &this.tree[variant]; this.print_attrs_of(variant, "\n"); w!(this, "{}", name.display(self.db.upcast())); diff --git a/crates/hir-def/src/lang_item.rs b/crates/hir-def/src/lang_item.rs index 66e0d2cc346bc..fc2edce93da71 100644 --- a/crates/hir-def/src/lang_item.rs +++ b/crates/hir-def/src/lang_item.rs @@ -125,12 +125,8 @@ impl LangItems { } ModuleDefId::AdtId(AdtId::EnumId(e)) => { lang_items.collect_lang_item(db, e, LangItemTarget::EnumId); - db.enum_data(e).variants.iter().for_each(|(local_id, _)| { - lang_items.collect_lang_item( - db, - EnumVariantId { parent: e, local_id }, - LangItemTarget::EnumVariant, - ); + module_data.scope.enums[&e].iter().for_each(|&id| { + lang_items.collect_lang_item(db, id, LangItemTarget::EnumVariant); }); } ModuleDefId::AdtId(AdtId::StructId(s)) => { diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index aa84ccaee6eee..1712eaede0920 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -100,7 +100,7 @@ use crate::{ db::DefDatabase, item_tree::{ Const, Enum, ExternCrate, Function, Impl, ItemTreeId, ItemTreeNode, Macro2, MacroRules, - Static, Struct, Trait, TraitAlias, TypeAlias, Union, Use, + Static, Struct, Trait, TraitAlias, TypeAlias, Union, Use, Variant, }, }; @@ -299,12 +299,15 @@ impl_intern!(EnumId, EnumLoc, intern_enum, lookup_intern_enum); // FIXME: rename to `VariantId`, only enums can ave variants #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct EnumVariantId { +pub struct EnumVariantId(salsa::InternId); + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct EnumVariantLoc { + pub container: ModuleId, + pub id: ItemTreeId, pub parent: EnumId, - pub local_id: LocalEnumVariantId, } - -pub type LocalEnumVariantId = Idx; +impl_intern!(EnumVariantId, EnumVariantLoc, intern_enum_variant, lookup_intern_enum_variant); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct FieldId { @@ -953,23 +956,21 @@ impl VariantId { match self { VariantId::StructId(it) => db.struct_data(it).variant_data.clone(), VariantId::UnionId(it) => db.union_data(it).variant_data.clone(), - VariantId::EnumVariantId(it) => { - db.enum_data(it.parent).variants[it.local_id].variant_data.clone() - } + VariantId::EnumVariantId(it) => db.enum_variant_data(it).variant_data.clone(), } } pub fn file_id(self, db: &dyn DefDatabase) -> HirFileId { match self { - VariantId::EnumVariantId(it) => it.parent.lookup(db).id.file_id(), + VariantId::EnumVariantId(it) => it.lookup(db).id.file_id(), VariantId::StructId(it) => it.lookup(db).id.file_id(), VariantId::UnionId(it) => it.lookup(db).id.file_id(), } } - pub fn adt_id(self) -> AdtId { + pub fn adt_id(self, db: &dyn DefDatabase) -> AdtId { match self { - VariantId::EnumVariantId(it) => it.parent.into(), + VariantId::EnumVariantId(it) => it.lookup(db).parent.into(), VariantId::StructId(it) => it.into(), VariantId::UnionId(it) => it.into(), } @@ -1016,7 +1017,7 @@ impl HasModule for ExternCrateId { impl HasModule for VariantId { fn module(&self, db: &dyn DefDatabase) -> ModuleId { match self { - VariantId::EnumVariantId(it) => it.parent.lookup(db).container, + VariantId::EnumVariantId(it) => it.lookup(db).container, VariantId::StructId(it) => it.lookup(db).container, VariantId::UnionId(it) => it.lookup(db).container, } @@ -1045,7 +1046,7 @@ impl HasModule for TypeOwnerId { TypeOwnerId::TraitAliasId(it) => it.lookup(db).container, TypeOwnerId::TypeAliasId(it) => it.lookup(db).module(db), TypeOwnerId::ImplId(it) => it.lookup(db).container, - TypeOwnerId::EnumVariantId(it) => it.parent.lookup(db).container, + TypeOwnerId::EnumVariantId(it) => it.lookup(db).container, } } } @@ -1056,7 +1057,7 @@ impl HasModule for DefWithBodyId { DefWithBodyId::FunctionId(it) => it.lookup(db).module(db), DefWithBodyId::StaticId(it) => it.lookup(db).module(db), DefWithBodyId::ConstId(it) => it.lookup(db).module(db), - DefWithBodyId::VariantId(it) => it.parent.lookup(db).container, + DefWithBodyId::VariantId(it) => it.lookup(db).container, DefWithBodyId::InTypeConstId(it) => it.lookup(db).owner.module(db), } } @@ -1071,7 +1072,7 @@ impl HasModule for GenericDefId { GenericDefId::TraitAliasId(it) => it.lookup(db).container, GenericDefId::TypeAliasId(it) => it.lookup(db).module(db), GenericDefId::ImplId(it) => it.lookup(db).container, - GenericDefId::EnumVariantId(it) => it.parent.lookup(db).container, + GenericDefId::EnumVariantId(it) => it.lookup(db).container, GenericDefId::ConstId(it) => it.lookup(db).module(db), } } @@ -1098,7 +1099,7 @@ impl ModuleDefId { ModuleDefId::ModuleId(id) => *id, ModuleDefId::FunctionId(id) => id.lookup(db).module(db), ModuleDefId::AdtId(id) => id.module(db), - ModuleDefId::EnumVariantId(id) => id.parent.lookup(db).container, + ModuleDefId::EnumVariantId(id) => id.lookup(db).container, ModuleDefId::ConstId(id) => id.lookup(db).container.module(db), ModuleDefId::StaticId(id) => id.lookup(db).module(db), ModuleDefId::TraitId(id) => id.lookup(db).container, @@ -1117,7 +1118,7 @@ impl AttrDefId { AttrDefId::FieldId(it) => it.parent.module(db).krate, AttrDefId::AdtId(it) => it.module(db).krate, AttrDefId::FunctionId(it) => it.lookup(db).module(db).krate, - AttrDefId::EnumVariantId(it) => it.parent.lookup(db).container.krate, + AttrDefId::EnumVariantId(it) => it.lookup(db).container.krate, AttrDefId::StaticId(it) => it.lookup(db).module(db).krate, AttrDefId::ConstId(it) => it.lookup(db).module(db).krate, AttrDefId::TraitId(it) => it.lookup(db).container.krate, diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index a18ac4b28c4ea..fc15a77e8c349 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -23,7 +23,7 @@ use itertools::{izip, Itertools}; use la_arena::Idx; use limit::Limit; use rustc_hash::{FxHashMap, FxHashSet}; -use span::{Span, SyntaxContextId}; +use span::{ErasedFileAstId, Span, SyntaxContextId}; use stdx::always; use syntax::{ast, SmolStr}; use triomphe::Arc; @@ -51,7 +51,7 @@ use crate::{ per_ns::PerNs, tt, visibility::{RawVisibility, Visibility}, - AdtId, AstId, AstIdWithPath, ConstLoc, CrateRootModuleId, EnumLoc, EnumVariantId, + AdtId, AstId, AstIdWithPath, ConstLoc, CrateRootModuleId, EnumLoc, EnumVariantLoc, ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId, FunctionLoc, ImplLoc, Intern, ItemContainerId, LocalModuleId, Lookup, Macro2Id, Macro2Loc, MacroExpander, MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ModuleDefId, ModuleId, ProcMacroId, @@ -980,24 +980,35 @@ impl DefCollector<'_> { cov_mark::hit!(glob_enum); // glob import from enum => just import all the variants - // XXX: urgh, so this works by accident! Here, we look at - // the enum data, and, in theory, this might require us to - // look back at the crate_def_map, creating a cycle. For - // example, `enum E { crate::some_macro!(); }`. Luckily, the - // only kind of macro that is allowed inside enum is a - // `cfg_macro`, and we don't need to run name resolution for - // it, but this is sheer luck! - let enum_data = self.db.enum_data(e); - let resolutions = enum_data - .variants - .iter() - .map(|(local_id, variant_data)| { - let name = variant_data.name.clone(); - let variant = EnumVariantId { parent: e, local_id }; - let res = PerNs::both(variant.into(), variant.into(), vis, None); - (Some(name), res) - }) - .collect::>(); + // We need to check if the def map the enum is from is us, then we can't + // call the def-map query since we are currently constructing it! + let loc = e.lookup(self.db); + let tree = loc.id.item_tree(self.db); + let current_def_map = self.def_map.krate == loc.container.krate + && self.def_map.block_id() == loc.container.block; + let resolutions = if current_def_map { + self.def_map.modules[loc.container.local_id].scope.enums[&e] + .iter() + .map(|&variant| { + let name = tree[variant.lookup(self.db).id.value].name.clone(); + let res = + PerNs::both(variant.into(), variant.into(), vis, None); + (Some(name), res) + }) + .collect::>() + } else { + loc.container.def_map(self.db).modules[loc.container.local_id] + .scope + .enums[&e] + .iter() + .map(|&variant| { + let name = tree[variant.lookup(self.db).id.value].name.clone(); + let res = + PerNs::both(variant.into(), variant.into(), vis, None); + (Some(name), res) + }) + .collect::>() + }; self.update(module_id, &resolutions, vis, Some(ImportType::Glob(id))); } Some(d) => { @@ -1577,7 +1588,7 @@ impl ModCollector<'_, '_> { let attrs = self.item_tree.attrs(db, krate, item.into()); if let Some(cfg) = attrs.cfg() { if !self.is_cfg_enabled(&cfg) { - self.emit_unconfigured_diagnostic(item, &cfg); + self.emit_unconfigured_diagnostic(item.ast_id(self.item_tree).erase(), &cfg); return; } } @@ -1708,17 +1719,40 @@ impl ModCollector<'_, '_> { } ModItem::Enum(id) => { let it = &self.item_tree[id]; + let enum_ = + EnumLoc { container: module, id: ItemTreeId::new(self.tree_id, id) } + .intern(db); let vis = resolve_vis(def_map, &self.item_tree[it.visibility]); - update_def( - self.def_collector, - EnumLoc { container: module, id: ItemTreeId::new(self.tree_id, id) } - .intern(db) - .into(), - &it.name, - vis, - false, - ); + update_def(self.def_collector, enum_.into(), &it.name, vis, false); + + let variants = FileItemTreeId::range_iter(it.variants.clone()) + .filter_map(|variant| { + let attrs = self.item_tree.attrs(db, krate, variant.into()); + if let Some(cfg) = attrs.cfg() { + if !self.is_cfg_enabled(&cfg) { + self.emit_unconfigured_diagnostic( + self.item_tree[variant.index()].ast_id.erase(), + &cfg, + ); + return None; + } + } + + Some( + EnumVariantLoc { + container: module, + id: ItemTreeId::new(self.tree_id, variant), + parent: enum_, + } + .intern(db), + ) + }) + .collect(); + self.def_collector.def_map.modules[module_id] + .scope + .enums + .insert(enum_, variants); } ModItem::Const(id) => { let it = &self.item_tree[id]; @@ -2360,10 +2394,8 @@ impl ModCollector<'_, '_> { self.def_collector.cfg_options.check(cfg) != Some(false) } - fn emit_unconfigured_diagnostic(&mut self, item: ModItem, cfg: &CfgExpr) { - let ast_id = item.ast_id(self.item_tree); - - let ast_id = InFile::new(self.file_id(), ast_id.erase()); + fn emit_unconfigured_diagnostic(&mut self, ast_id: ErasedFileAstId, cfg: &CfgExpr) { + let ast_id = InFile::new(self.file_id(), ast_id); self.def_collector.def_map.diagnostics.push(DefDiagnostic::unconfigured_code( self.module_id, ast_id, diff --git a/crates/hir-def/src/nameres/path_resolution.rs b/crates/hir-def/src/nameres/path_resolution.rs index 389dabdbc8678..372d148021841 100644 --- a/crates/hir-def/src/nameres/path_resolution.rs +++ b/crates/hir-def/src/nameres/path_resolution.rs @@ -11,18 +11,18 @@ //! `ReachedFixedPoint` signals about this. use base_db::Edition; -use hir_expand::name::Name; +use hir_expand::{name::Name, Lookup}; use triomphe::Arc; use crate::{ - data::adt::VariantData, db::DefDatabase, item_scope::{ImportOrExternCrate, BUILTIN_SCOPE}, + item_tree::Fields, nameres::{sub_namespace_match, BlockInfo, BuiltinShadowMode, DefMap, MacroSubNs}, path::{ModPath, PathKind}, per_ns::PerNs, visibility::{RawVisibility, Visibility}, - AdtId, CrateId, EnumVariantId, LocalModuleId, ModuleDefId, + AdtId, CrateId, LocalModuleId, ModuleDefId, }; #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -355,29 +355,55 @@ impl DefMap { ModuleDefId::AdtId(AdtId::EnumId(e)) => { // enum variant cov_mark::hit!(can_import_enum_variant); - let enum_data = db.enum_data(e); - match enum_data.variant(segment) { - Some(local_id) => { - let variant = EnumVariantId { parent: e, local_id }; - match &*enum_data.variants[local_id].variant_data { - VariantData::Record(_) => { - PerNs::types(variant.into(), Visibility::Public, None) - } - VariantData::Tuple(_) | VariantData::Unit => PerNs::both( - variant.into(), - variant.into(), - Visibility::Public, - None, - ), - } - } + + let loc = e.lookup(db); + let tree = loc.id.item_tree(db); + let current_def_map = + self.krate == loc.container.krate && self.block_id() == loc.container.block; + let res = if current_def_map { + self.modules[loc.container.local_id].scope.enums[&e].iter().find_map( + |&variant| { + let variant_data = &tree[variant.lookup(db).id.value]; + (variant_data.name == *segment).then(|| match variant_data.fields { + Fields::Record(_) => { + PerNs::types(variant.into(), Visibility::Public, None) + } + Fields::Tuple(_) | Fields::Unit => PerNs::both( + variant.into(), + variant.into(), + Visibility::Public, + None, + ), + }) + }, + ) + } else { + loc.container.def_map(db).modules[loc.container.local_id].scope.enums[&e] + .iter() + .find_map(|&variant| { + let variant_data = &tree[variant.lookup(db).id.value]; + (variant_data.name == *segment).then(|| match variant_data.fields { + Fields::Record(_) => { + PerNs::types(variant.into(), Visibility::Public, None) + } + Fields::Tuple(_) | Fields::Unit => PerNs::both( + variant.into(), + variant.into(), + Visibility::Public, + None, + ), + }) + }) + }; + match res { + Some(res) => res, None => { return ResolvePathResult::with( PerNs::types(e.into(), vis, imp), ReachedFixedPoint::Yes, Some(i), Some(self.krate), - ); + ) } } } diff --git a/crates/hir-def/src/pretty.rs b/crates/hir-def/src/pretty.rs index f4f5541e3733d..8e0df46970180 100644 --- a/crates/hir-def/src/pretty.rs +++ b/crates/hir-def/src/pretty.rs @@ -39,11 +39,9 @@ pub(crate) fn print_path(db: &dyn DefDatabase, path: &Path, buf: &mut dyn Write) LangItemTarget::Trait(it) => { write!(buf, "{}", db.trait_data(it).name.display(db.upcast()))? } - LangItemTarget::EnumVariant(it) => write!( - buf, - "{}", - db.enum_data(it.parent).variants[it.local_id].name.display(db.upcast()) - )?, + LangItemTarget::EnumVariant(it) => { + write!(buf, "{}", db.enum_variant_data(it).name.display(db.upcast()))? + } } if let Some(s) = s { diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs index 1d850f721c1f8..bb530259ac585 100644 --- a/crates/hir-def/src/resolver.rs +++ b/crates/hir-def/src/resolver.rs @@ -1111,7 +1111,7 @@ impl HasResolver for DefWithBodyId { DefWithBodyId::ConstId(c) => c.resolver(db), DefWithBodyId::FunctionId(f) => f.resolver(db), DefWithBodyId::StaticId(s) => s.resolver(db), - DefWithBodyId::VariantId(v) => v.parent.resolver(db), + DefWithBodyId::VariantId(v) => v.resolver(db), DefWithBodyId::InTypeConstId(c) => c.lookup(db).owner.resolver(db), } } @@ -1137,7 +1137,7 @@ impl HasResolver for GenericDefId { GenericDefId::TraitAliasId(inner) => inner.resolver(db), GenericDefId::TypeAliasId(inner) => inner.resolver(db), GenericDefId::ImplId(inner) => inner.resolver(db), - GenericDefId::EnumVariantId(inner) => inner.parent.resolver(db), + GenericDefId::EnumVariantId(inner) => inner.resolver(db), GenericDefId::ConstId(inner) => inner.resolver(db), } } @@ -1145,14 +1145,14 @@ impl HasResolver for GenericDefId { impl HasResolver for EnumVariantId { fn resolver(self, db: &dyn DefDatabase) -> Resolver { - self.parent.resolver(db) + self.lookup(db).parent.resolver(db) } } impl HasResolver for VariantId { fn resolver(self, db: &dyn DefDatabase) -> Resolver { match self { - VariantId::EnumVariantId(it) => it.parent.resolver(db), + VariantId::EnumVariantId(it) => it.resolver(db), VariantId::StructId(it) => it.resolver(db), VariantId::UnionId(it) => it.resolver(db), } diff --git a/crates/hir-def/src/src.rs b/crates/hir-def/src/src.rs index 3770103cda53e..4698e967eb7d9 100644 --- a/crates/hir-def/src/src.rs +++ b/crates/hir-def/src/src.rs @@ -5,8 +5,8 @@ use la_arena::ArenaMap; use syntax::ast; use crate::{ - db::DefDatabase, item_tree::ItemTreeNode, AssocItemLoc, ItemLoc, Lookup, Macro2Loc, - MacroRulesLoc, ProcMacroLoc, UseId, + db::DefDatabase, item_tree::ItemTreeNode, AssocItemLoc, EnumVariantLoc, ItemLoc, Lookup, + Macro2Loc, MacroRulesLoc, ProcMacroLoc, UseId, }; pub trait HasSource { @@ -40,6 +40,19 @@ impl HasSource for ItemLoc { } } +impl HasSource for EnumVariantLoc { + type Value = ast::Variant; + + fn source(&self, db: &dyn DefDatabase) -> InFile { + let tree = self.id.item_tree(db); + let ast_id_map = db.ast_id_map(self.id.file_id()); + let root = db.parse_or_expand(self.id.file_id()); + let node = &tree[self.id.value]; + + InFile::new(self.id.file_id(), ast_id_map.get(node.ast_id).to_node(&root)) + } +} + impl HasSource for Macro2Loc { type Value = ast::MacroDef; diff --git a/crates/hir-def/src/trace.rs b/crates/hir-def/src/trace.rs index 6e6ceb8e47495..01654f04ccf40 100644 --- a/crates/hir-def/src/trace.rs +++ b/crates/hir-def/src/trace.rs @@ -18,10 +18,7 @@ pub(crate) struct Trace { } impl Trace { - pub(crate) fn new_for_arena() -> Trace { - Trace { arena: Some(Arena::default()), map: None, len: 0 } - } - + #[allow(dead_code)] pub(crate) fn new_for_map() -> Trace { Trace { arena: None, map: Some(ArenaMap::default()), len: 0 } } @@ -41,6 +38,7 @@ impl Trace { id } + #[allow(dead_code)] pub(crate) fn into_arena(mut self) -> Arena { self.arena.take().unwrap() } diff --git a/crates/hir-def/src/visibility.rs b/crates/hir-def/src/visibility.rs index cd8023f5d7d7d..c73ffa334c3de 100644 --- a/crates/hir-def/src/visibility.rs +++ b/crates/hir-def/src/visibility.rs @@ -225,9 +225,7 @@ pub(crate) fn field_visibilities_query( let var_data = match variant_id { VariantId::StructId(it) => db.struct_data(it).variant_data.clone(), VariantId::UnionId(it) => db.union_data(it).variant_data.clone(), - VariantId::EnumVariantId(it) => { - db.enum_data(it.parent).variants[it.local_id].variant_data.clone() - } + VariantId::EnumVariantId(it) => db.enum_variant_data(it).variant_data.clone(), }; let resolver = variant_id.module(db).resolver(db); let mut res = ArenaMap::default(); diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs index ed04582cb0abe..035664c644607 100644 --- a/crates/hir-expand/src/db.rs +++ b/crates/hir-expand/src/db.rs @@ -218,6 +218,9 @@ pub fn real_span_map(db: &dyn ExpandDatabase, file_id: FileId) -> Arc { - let prev_variant = EnumVariantId { local_id, parent: variant_id.parent }; - 1 + db.const_eval_discriminant(prev_variant)? + Some(prev_idx) => { + 1 + db.const_eval_discriminant( + db.enum_data(loc.parent).variants[prev_idx as usize].0, + )? } _ => 0, }; diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs index ad790fa094d82..481992aa0b312 100644 --- a/crates/hir-ty/src/db.rs +++ b/crates/hir-ty/src/db.rs @@ -292,7 +292,7 @@ fn infer_wait(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc .display(db.upcast()) .to_string(), DefWithBodyId::VariantId(it) => { - db.enum_data(it.parent).variants[it.local_id].name.display(db.upcast()).to_string() + db.enum_variant_data(it).name.display(db.upcast()).to_string() } DefWithBodyId::InTypeConstId(it) => format!("in type const {it:?}"), }); diff --git a/crates/hir-ty/src/diagnostics/decl_check.rs b/crates/hir-ty/src/diagnostics/decl_check.rs index 51a044d8ef562..7ea1b9e4213e3 100644 --- a/crates/hir-ty/src/diagnostics/decl_check.rs +++ b/crates/hir-ty/src/diagnostics/decl_check.rs @@ -582,11 +582,11 @@ impl<'a> DeclValidator<'a> { // Check the field names. let enum_fields_replacements = data .variants - .values() - .filter_map(|variant| { + .iter() + .filter_map(|(_, name)| { Some(Replacement { - current_name: variant.name.clone(), - suggested_text: to_camel_case(&variant.name.to_smol_str())?, + current_name: name.clone(), + suggested_text: to_camel_case(&name.to_smol_str())?, expected_case: CaseType::UpperCamelCase, }) }) diff --git a/crates/hir-ty/src/diagnostics/match_check.rs b/crates/hir-ty/src/diagnostics/match_check.rs index 2e04bbfee83b7..e4d4536fc9321 100644 --- a/crates/hir-ty/src/diagnostics/match_check.rs +++ b/crates/hir-ty/src/diagnostics/match_check.rs @@ -318,8 +318,7 @@ impl HirDisplay for Pat { if let Some(variant) = variant { match variant { VariantId::EnumVariantId(v) => { - let data = f.db.enum_data(v.parent); - write!(f, "{}", data.variants[v.local_id].name.display(f.db.upcast()))?; + write!(f, "{}", f.db.enum_variant_data(v).name.display(f.db.upcast()))?; } VariantId::StructId(s) => { write!(f, "{}", f.db.struct_data(s).name.display(f.db.upcast()))? diff --git a/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs b/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs index a0f6b9368ee01..f066f8b798d6c 100644 --- a/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs +++ b/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs @@ -594,7 +594,7 @@ impl SplitWildcard { let mut ctors: SmallVec<[_; 1]> = enum_data .variants .iter() - .map(|(local_id, _)| EnumVariantId { parent: *enum_id, local_id }) + .map(|&(variant, _)| variant) .filter(|&variant| { // If `exhaustive_patterns` is enabled, we exclude variants known to be // uninhabited. diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs index d63a64a70de2a..18f2cdaae5f11 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ty/src/display.rs @@ -20,8 +20,7 @@ use hir_def::{ path::{Path, PathKind}, type_ref::{TraitBoundModifier, TypeBound, TypeRef}, visibility::Visibility, - EnumVariantId, HasModule, ItemContainerId, LocalFieldId, Lookup, ModuleDefId, ModuleId, - TraitId, + HasModule, ItemContainerId, LocalFieldId, Lookup, ModuleDefId, ModuleId, TraitId, }; use hir_expand::name::Name; use intern::{Internable, Interned}; @@ -613,10 +612,9 @@ fn render_const_scalar( else { return f.write_str(""); }; - let data = &f.db.enum_data(e).variants[var_id]; + let data = f.db.enum_variant_data(var_id); write!(f, "{}", data.name.display(f.db.upcast()))?; - let field_types = - f.db.field_types(EnumVariantId { parent: e, local_id: var_id }.into()); + let field_types = f.db.field_types(var_id.into()); render_variant_after_name( &data.variant_data, f, @@ -892,11 +890,9 @@ impl HirDisplay for Ty { CallableDefId::StructId(s) => { write!(f, "{}", db.struct_data(s).name.display(f.db.upcast()))? } - CallableDefId::EnumVariantId(e) => write!( - f, - "{}", - db.enum_data(e.parent).variants[e.local_id].name.display(f.db.upcast()) - )?, + CallableDefId::EnumVariantId(e) => { + write!(f, "{}", db.enum_variant_data(e).name.display(f.db.upcast()))? + } }; f.end_location_link(); if parameters.len(Interner) > 0 { diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index a78e3e7dc2515..9dd8e4da22f67 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -40,8 +40,8 @@ use hir_def::{ path::{ModPath, Path}, resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs}, type_ref::TypeRef, - AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, ItemContainerId, Lookup, - TraitId, TupleFieldId, TupleId, TypeAliasId, VariantId, + AdtId, AssocItemId, DefWithBodyId, FieldId, FunctionId, ItemContainerId, Lookup, TraitId, + TupleFieldId, TupleId, TypeAliasId, VariantId, }; use hir_expand::name::{name, Name}; use indexmap::IndexSet; @@ -87,28 +87,30 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc ctx.collect_const(&db.const_data(c)), DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_data(s)), DefWithBodyId::VariantId(v) => { - ctx.return_ty = TyBuilder::builtin(match db.enum_data(v.parent).variant_body_type() { - hir_def::layout::IntegerType::Pointer(signed) => match signed { - true => BuiltinType::Int(BuiltinInt::Isize), - false => BuiltinType::Uint(BuiltinUint::Usize), + ctx.return_ty = TyBuilder::builtin( + match db.enum_data(v.lookup(db.upcast()).parent.into()).variant_body_type() { + hir_def::layout::IntegerType::Pointer(signed) => match signed { + true => BuiltinType::Int(BuiltinInt::Isize), + false => BuiltinType::Uint(BuiltinUint::Usize), + }, + hir_def::layout::IntegerType::Fixed(size, signed) => match signed { + true => BuiltinType::Int(match size { + Integer::I8 => BuiltinInt::I8, + Integer::I16 => BuiltinInt::I16, + Integer::I32 => BuiltinInt::I32, + Integer::I64 => BuiltinInt::I64, + Integer::I128 => BuiltinInt::I128, + }), + false => BuiltinType::Uint(match size { + Integer::I8 => BuiltinUint::U8, + Integer::I16 => BuiltinUint::U16, + Integer::I32 => BuiltinUint::U32, + Integer::I64 => BuiltinUint::U64, + Integer::I128 => BuiltinUint::U128, + }), + }, }, - hir_def::layout::IntegerType::Fixed(size, signed) => match signed { - true => BuiltinType::Int(match size { - Integer::I8 => BuiltinInt::I8, - Integer::I16 => BuiltinInt::I16, - Integer::I32 => BuiltinInt::I32, - Integer::I64 => BuiltinInt::I64, - Integer::I128 => BuiltinInt::I128, - }), - false => BuiltinType::Uint(match size { - Integer::I8 => BuiltinUint::U8, - Integer::I16 => BuiltinUint::U16, - Integer::I32 => BuiltinUint::U32, - Integer::I64 => BuiltinUint::U64, - Integer::I128 => BuiltinUint::U128, - }), - }, - }); + ); } DefWithBodyId::InTypeConstId(c) => { // FIXME(const-generic-body): We should not get the return type in this way. @@ -1062,7 +1064,7 @@ impl<'a> InferenceContext<'a> { Some(ResolveValueResult::ValueNs(value, _)) => match value { ValueNs::EnumVariantId(var) => { let substs = ctx.substs_from_path(path, var.into(), true); - let ty = self.db.ty(var.parent.into()); + let ty = self.db.ty(var.lookup(self.db.upcast()).parent.into()); let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); return (ty, Some(var.into())); } @@ -1105,7 +1107,7 @@ impl<'a> InferenceContext<'a> { } TypeNs::EnumVariantId(var) => { let substs = ctx.substs_from_path(path, var.into(), true); - let ty = self.db.ty(var.parent.into()); + let ty = self.db.ty(var.lookup(self.db.upcast()).parent.into()); let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); forbid_unresolved_segments((ty, Some(var.into())), unresolved) } @@ -1131,8 +1133,7 @@ impl<'a> InferenceContext<'a> { if let Some((AdtId::EnumId(id), _)) = ty.as_adt() { let enum_data = self.db.enum_data(id); let name = current_segment.first().unwrap().name; - if let Some(local_id) = enum_data.variant(name) { - let variant = EnumVariantId { parent: id, local_id }; + if let Some(variant) = enum_data.variant(name) { return if remaining_segments.len() == 1 { (ty, Some(variant.into())) } else { @@ -1247,8 +1248,7 @@ impl<'a> InferenceContext<'a> { // this could be an enum variant or associated type if let Some((AdtId::EnumId(enum_id), _)) = ty.as_adt() { let enum_data = self.db.enum_data(enum_id); - if let Some(local_id) = enum_data.variant(segment) { - let variant = EnumVariantId { parent: enum_id, local_id }; + if let Some(variant) = enum_data.variant(segment) { return (ty, Some(variant.into())); } } diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs index 118b9c0149f6f..14b0efabffa3e 100644 --- a/crates/hir-ty/src/infer/closure.rs +++ b/crates/hir-ty/src/infer/closure.rs @@ -666,7 +666,7 @@ impl InferenceContext<'_> { | Pat::Or(_) => (), Pat::TupleStruct { .. } | Pat::Record { .. } => { if let Some(variant) = self.result.variant_resolution_for_pat(p) { - let adt = variant.adt_id(); + let adt = variant.adt_id(self.db.upcast()); let is_multivariant = match adt { hir_def::AdtId::EnumId(e) => self.db.enum_data(e).variants.len() != 1, _ => false, diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs index e61a070265a4b..a09bb15147f65 100644 --- a/crates/hir-ty/src/infer/path.rs +++ b/crates/hir-ty/src/infer/path.rs @@ -4,7 +4,7 @@ use chalk_ir::cast::Cast; use hir_def::{ path::{Path, PathSegment}, resolver::{ResolveValueResult, TypeNs, ValueNs}, - AdtId, AssocItemId, EnumVariantId, GenericDefId, ItemContainerId, Lookup, + AdtId, AssocItemId, GenericDefId, ItemContainerId, Lookup, }; use hir_expand::name::Name; use stdx::never; @@ -395,8 +395,7 @@ impl InferenceContext<'_> { _ => return None, }; let enum_data = self.db.enum_data(enum_id); - let local_id = enum_data.variant(name)?; - let variant = EnumVariantId { parent: enum_id, local_id }; + let variant = enum_data.variant(name)?; self.write_variant_resolution(id, variant.into()); Some((ValueNs::EnumVariantId(variant), subst.clone())) } diff --git a/crates/hir-ty/src/inhabitedness.rs b/crates/hir-ty/src/inhabitedness.rs index e5038543b68e6..dda5ddd0bae85 100644 --- a/crates/hir-ty/src/inhabitedness.rs +++ b/crates/hir-ty/src/inhabitedness.rs @@ -30,17 +30,15 @@ pub(crate) fn is_enum_variant_uninhabited_from( target_mod: ModuleId, db: &dyn HirDatabase, ) -> bool { - let enum_data = db.enum_data(variant.parent); - let vars_attrs = db.variants_attrs(variant.parent); - let is_local = variant.parent.lookup(db.upcast()).container.krate() == target_mod.krate(); + let is_local = variant.lookup(db.upcast()).container.krate() == target_mod.krate(); let mut uninhabited_from = UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default() }; let inhabitedness = uninhabited_from.visit_variant( variant.into(), - &enum_data.variants[variant.local_id].variant_data, + &db.enum_variant_data(variant).variant_data, subst, - &vars_attrs[variant.local_id], + &db.attrs(variant.into()), is_local, ); inhabitedness == BREAK_VISIBLY_UNINHABITED @@ -117,15 +115,14 @@ impl UninhabitedFrom<'_> { self.visit_variant(s.into(), &struct_data.variant_data, subst, &attrs, is_local) } AdtId::EnumId(e) => { - let vars_attrs = self.db.variants_attrs(e); let enum_data = self.db.enum_data(e); - for (local_id, enum_var) in enum_data.variants.iter() { + for &(variant, _) in enum_data.variants.iter() { let variant_inhabitedness = self.visit_variant( - EnumVariantId { parent: e, local_id }.into(), - &enum_var.variant_data, + variant.into(), + &self.db.enum_variant_data(variant).variant_data, subst, - &vars_attrs[local_id], + &self.db.attrs(variant.into()), is_local, ); match variant_inhabitedness { diff --git a/crates/hir-ty/src/layout.rs b/crates/hir-ty/src/layout.rs index b7bfaf2931b6b..539276f42ee0b 100644 --- a/crates/hir-ty/src/layout.rs +++ b/crates/hir-ty/src/layout.rs @@ -9,7 +9,7 @@ use hir_def::{ Abi, FieldsShape, Integer, LayoutCalculator, LayoutS, Primitive, ReprOptions, Scalar, Size, StructKind, TargetDataLayout, WrappingRange, }, - LocalEnumVariantId, LocalFieldId, StructId, + LocalFieldId, StructId, }; use la_arena::{Idx, RawIdx}; use rustc_abi::AddressSpace; @@ -32,15 +32,15 @@ mod adt; mod target; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct RustcEnumVariantIdx(pub LocalEnumVariantId); +pub struct RustcEnumVariantIdx(pub usize); impl rustc_index::Idx for RustcEnumVariantIdx { fn new(idx: usize) -> Self { - RustcEnumVariantIdx(Idx::from_raw(RawIdx::from(idx as u32))) + RustcEnumVariantIdx(idx) } fn index(self) -> usize { - u32::from(self.0.into_raw()) as usize + self.0 } } diff --git a/crates/hir-ty/src/layout/adt.rs b/crates/hir-ty/src/layout/adt.rs index 8a7715ce8729f..9fcc251356f6f 100644 --- a/crates/hir-ty/src/layout/adt.rs +++ b/crates/hir-ty/src/layout/adt.rs @@ -6,9 +6,8 @@ use base_db::salsa::Cycle; use hir_def::{ data::adt::VariantData, layout::{Integer, LayoutCalculator, ReprOptions, TargetDataLayout}, - AdtId, EnumVariantId, LocalEnumVariantId, VariantId, + AdtId, VariantId, }; -use la_arena::RawIdx; use rustc_index::IndexVec; use smallvec::SmallVec; use triomphe::Arc; @@ -22,8 +21,8 @@ use crate::{ use super::LayoutCx; -pub(crate) const fn struct_variant_idx() -> RustcEnumVariantIdx { - RustcEnumVariantIdx(LocalEnumVariantId::from_raw(RawIdx::from_u32(0))) +pub(crate) fn struct_variant_idx() -> RustcEnumVariantIdx { + RustcEnumVariantIdx(0) } pub fn layout_of_adt_query( @@ -62,12 +61,7 @@ pub fn layout_of_adt_query( let r = data .variants .iter() - .map(|(idx, v)| { - handle_variant( - EnumVariantId { parent: e, local_id: idx }.into(), - &v.variant_data, - ) - }) + .map(|&(v, _)| handle_variant(v.into(), &db.enum_variant_data(v).variant_data)) .collect::, _>>()?; (r, data.repr.unwrap_or_default()) } @@ -89,8 +83,7 @@ pub fn layout_of_adt_query( |min, max| repr_discr(&dl, &repr, min, max).unwrap_or((Integer::I8, false)), variants.iter_enumerated().filter_map(|(id, _)| { let AdtId::EnumId(e) = def else { return None }; - let d = - db.const_eval_discriminant(EnumVariantId { parent: e, local_id: id.0 }).ok()?; + let d = db.const_eval_discriminant(db.enum_data(e).variants[id.0].0).ok()?; Some((id, d)) }), // FIXME: The current code for niche-filling relies on variant indices diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index e371e42761560..e160f05b01383 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -762,7 +762,7 @@ impl<'a> TyLoweringContext<'a> { Some(segment) if segment.args_and_bindings.is_some() => Some(segment), _ => last, }; - (segment, Some(var.parent.into())) + (segment, Some(var.lookup(self.db.upcast()).parent.into())) } }; if let Some(segment) = segment { @@ -1375,11 +1375,13 @@ pub(crate) fn field_types_query( let (resolver, def): (_, GenericDefId) = match variant_id { VariantId::StructId(it) => (it.resolver(db.upcast()), it.into()), VariantId::UnionId(it) => (it.resolver(db.upcast()), it.into()), - VariantId::EnumVariantId(it) => (it.parent.resolver(db.upcast()), it.parent.into()), + VariantId::EnumVariantId(it) => { + (it.resolver(db.upcast()), it.lookup(db.upcast()).parent.into()) + } }; let generics = generics(db.upcast(), def); let mut res = ArenaMap::default(); - let ctx = TyLoweringContext::new(db, &resolver, GenericDefId::from(variant_id.adt_id()).into()) + let ctx = TyLoweringContext::new(db, &resolver, def.into()) .with_type_param_mode(ParamLoweringMode::Variable); for (field_id, field_data) in var_data.fields().iter() { res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(&field_data.type_ref))); @@ -1740,25 +1742,24 @@ fn type_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> Binders PolyFnSig { - let enum_data = db.enum_data(def.parent); - let var_data = &enum_data.variants[def.local_id]; + let var_data = db.enum_variant_data(def); let fields = var_data.variant_data.fields(); - let resolver = def.parent.resolver(db.upcast()); + let resolver = def.resolver(db.upcast()); let ctx = TyLoweringContext::new(db, &resolver, DefWithBodyId::VariantId(def).into()) .with_type_param_mode(ParamLoweringMode::Variable); let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::>(); - let (ret, binders) = type_for_adt(db, def.parent.into()).into_value_and_skipped_binders(); + let (ret, binders) = + type_for_adt(db, def.lookup(db.upcast()).parent.into()).into_value_and_skipped_binders(); Binders::new(binders, CallableSig::from_params_and_return(params, ret, false, Safety::Safe)) } /// Build the type of a tuple enum variant constructor. fn type_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) -> Binders { - let enum_data = db.enum_data(def.parent); - let var_data = &enum_data.variants[def.local_id].variant_data; - if let StructKind::Unit = var_data.kind() { - return type_for_adt(db, def.parent.into()); + let e = def.lookup(db.upcast()).parent; + if let StructKind::Unit = db.enum_variant_data(def).variant_data.kind() { + return type_for_adt(db, e.into()); } - let generics = generics(db.upcast(), def.parent.into()); + let generics = generics(db.upcast(), e.into()); let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST); make_binders( db, @@ -1812,7 +1813,7 @@ impl CallableDefId { match self { CallableDefId::FunctionId(f) => f.lookup(db).module(db), CallableDefId::StructId(s) => s.lookup(db).container, - CallableDefId::EnumVariantId(e) => e.parent.lookup(db).container, + CallableDefId::EnumVariantId(e) => e.lookup(db).container, } .krate() } diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index 16075d9073438..431d09c5650f4 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -751,9 +751,19 @@ impl Evaluator<'_> { Variants::Single { .. } => &layout, Variants::Multiple { variants, .. } => { &variants[match f.parent { - hir_def::VariantId::EnumVariantId(it) => { - RustcEnumVariantIdx(it.local_id) - } + hir_def::VariantId::EnumVariantId(it) => RustcEnumVariantIdx({ + let lookup = it.lookup(self.db.upcast()); + let rustc_enum_variant_idx = + lookup.id.value.index().into_raw().into_u32() + - lookup.id.item_tree(self.db.upcast()) + [lookup.parent.lookup(self.db.upcast()).id.value] + .variants + .start + .index() + .into_raw() + .into_u32(); + rustc_enum_variant_idx as usize + }), _ => { return Err(MirEvalError::TypeError( "Multivariant layout only happens for enums", @@ -1412,22 +1422,12 @@ impl Evaluator<'_> { fn compute_discriminant(&self, ty: Ty, bytes: &[u8]) -> Result { let layout = self.layout(&ty)?; - let enum_id = 'b: { - match ty.kind(Interner) { - TyKind::Adt(e, _) => match e.0 { - AdtId::EnumId(e) => break 'b e, - _ => (), - }, - _ => (), - } + let &TyKind::Adt(chalk_ir::AdtId(AdtId::EnumId(e)), _) = ty.kind(Interner) else { return Ok(0); }; match &layout.variants { Variants::Single { index } => { - let r = self.const_eval_discriminant(EnumVariantId { - parent: enum_id, - local_id: index.0, - })?; + let r = self.const_eval_discriminant(self.db.enum_data(e).variants[index.0].0)?; Ok(r) } Variants::Multiple { tag, tag_encoding, variants, .. } => { @@ -1446,17 +1446,15 @@ impl Evaluator<'_> { let candidate_tag = i128::from_le_bytes(pad16(tag, false)) .wrapping_sub(*niche_start as i128) as usize; - let variant = variants + let idx = variants .iter_enumerated() .map(|(it, _)| it) .filter(|it| it != untagged_variant) .nth(candidate_tag) .unwrap_or(*untagged_variant) .0; - let result = self.const_eval_discriminant(EnumVariantId { - parent: enum_id, - local_id: variant, - })?; + let result = + self.const_eval_discriminant(self.db.enum_data(e).variants[idx].0)?; Ok(result) } } @@ -1579,14 +1577,16 @@ impl Evaluator<'_> { subst: Substitution, locals: &Locals, ) -> Result<(usize, Arc, Option<(usize, usize, i128)>)> { - let adt = it.adt_id(); + let adt = it.adt_id(self.db.upcast()); if let DefWithBodyId::VariantId(f) = locals.body.owner { if let VariantId::EnumVariantId(it) = it { - if AdtId::from(f.parent) == adt { - // Computing the exact size of enums require resolving the enum discriminants. In order to prevent loops (and - // infinite sized type errors) we use a dummy layout - let i = self.const_eval_discriminant(it)?; - return Ok((16, self.layout(&TyBuilder::unit())?, Some((0, 16, i)))); + if let AdtId::EnumId(e) = adt { + if f.lookup(self.db.upcast()).parent == e { + // Computing the exact size of enums require resolving the enum discriminants. In order to prevent loops (and + // infinite sized type errors) we use a dummy layout + let i = self.const_eval_discriminant(it)?; + return Ok((16, self.layout(&TyBuilder::unit())?, Some((0, 16, i)))); + } } } } @@ -1602,8 +1602,17 @@ impl Evaluator<'_> { VariantId::EnumVariantId(it) => it, _ => not_supported!("multi variant layout for non-enums"), }; - let rustc_enum_variant_idx = RustcEnumVariantIdx(enum_variant_id.local_id); let mut discriminant = self.const_eval_discriminant(enum_variant_id)?; + let lookup = enum_variant_id.lookup(self.db.upcast()); + let rustc_enum_variant_idx = lookup.id.value.index().into_raw().into_u32() + - lookup.id.item_tree(self.db.upcast()) + [lookup.parent.lookup(self.db.upcast()).id.value] + .variants + .start + .index() + .into_raw() + .into_u32(); + let rustc_enum_variant_idx = RustcEnumVariantIdx(rustc_enum_variant_idx as usize); let variant_layout = variants[rustc_enum_variant_idx].clone(); let have_tag = match tag_encoding { TagEncoding::Direct => true, @@ -1847,8 +1856,8 @@ impl Evaluator<'_> { .then(|| (layout.size.bytes_usize(), layout.align.abi.bytes() as usize))); } if let DefWithBodyId::VariantId(f) = locals.body.owner { - if let Some((adt, _)) = ty.as_adt() { - if AdtId::from(f.parent) == adt { + if let Some((AdtId::EnumId(e), _)) = ty.as_adt() { + if f.lookup(self.db.upcast()).parent == e { // Computing the exact size of enums require resolving the enum discriminants. In order to prevent loops (and // infinite sized type errors) we use a dummy size return Ok(Some((16, 16))); @@ -2019,10 +2028,8 @@ impl Evaluator<'_> { bytes, e, ) { - let data = &this.db.enum_data(e).variants[v].variant_data; - let field_types = this - .db - .field_types(EnumVariantId { parent: e, local_id: v }.into()); + let data = &this.db.enum_variant_data(v).variant_data; + let field_types = this.db.field_types(v.into()); for (f, _) in data.fields().iter() { let offset = l.fields.offset(u32::from(f.into_raw()) as usize).bytes_usize(); @@ -2093,14 +2100,13 @@ impl Evaluator<'_> { } AdtId::UnionId(_) => (), AdtId::EnumId(e) => { - if let Some((variant, layout)) = detect_variant_from_bytes( + if let Some((ev, layout)) = detect_variant_from_bytes( &layout, self.db, self.trait_env.clone(), self.read_memory(addr, layout.size.bytes_usize())?, e, ) { - let ev = EnumVariantId { parent: e, local_id: variant }; for (i, (_, ty)) in self.db.field_types(ev.into()).iter().enumerate() { let offset = layout.fields.offset(i).bytes_usize(); let ty = ty.clone().substitute(Interner, subst); @@ -2540,11 +2546,13 @@ impl Evaluator<'_> { match r { Ok(r) => Ok(r), Err(e) => { - let data = self.db.enum_data(variant.parent); + let db = self.db.upcast(); + let loc = variant.lookup(db); + let enum_loc = loc.parent.lookup(db); let name = format!( "{}::{}", - data.name.display(self.db.upcast()), - data.variants[variant.local_id].name.display(self.db.upcast()) + enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db.upcast()), + loc.id.item_tree(db)[loc.id.value].name.display(db.upcast()), ); Err(MirEvalError::ConstEvalError(name, Box::new(e))) } diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index c02c5ef8767f9..69d8046524b43 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -456,9 +456,8 @@ impl<'ctx> MirLowerCtx<'ctx> { Ok(Some(current)) } ValueNs::EnumVariantId(variant_id) => { - let variant_data = - &self.db.enum_data(variant_id.parent).variants[variant_id.local_id]; - if variant_data.variant_data.kind() == StructKind::Unit { + let variant_data = &self.db.enum_variant_data(variant_id).variant_data; + if variant_data.kind() == StructKind::Unit { let ty = self.infer.type_of_expr[expr_id].clone(); current = self.lower_enum_variant( variant_id, @@ -1874,11 +1873,13 @@ impl<'ctx> MirLowerCtx<'ctx> { match r { Ok(r) => Ok(r), Err(e) => { - let data = self.db.enum_data(variant.parent); + let db = self.db.upcast(); + let loc = variant.lookup(db); + let enum_loc = loc.parent.lookup(db); let name = format!( "{}::{}", - data.name.display(self.db.upcast()), - data.variants[variant.local_id].name.display(self.db.upcast()) + enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db.upcast()), + loc.id.item_tree(db)[loc.id.value].name.display(db.upcast()), ); Err(MirLowerError::ConstEvalError(name.into(), Box::new(e))) } @@ -2104,7 +2105,7 @@ pub fn mir_body_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Result { - db.enum_data(it.parent).variants[it.local_id].name.display(db.upcast()).to_string() + db.enum_variant_data(it).name.display(db.upcast()).to_string() } DefWithBodyId::InTypeConstId(it) => format!("in type const {it:?}"), }); diff --git a/crates/hir-ty/src/mir/lower/pattern_matching.rs b/crates/hir-ty/src/mir/lower/pattern_matching.rs index 98c2e7c63bc17..bbb513b24cb9d 100644 --- a/crates/hir-ty/src/mir/lower/pattern_matching.rs +++ b/crates/hir-ty/src/mir/lower/pattern_matching.rs @@ -524,22 +524,9 @@ impl MirLowerCtx<'_> { ); current = next; } - let enum_data = self.db.enum_data(v.parent); self.pattern_matching_variant_fields( shape, - &enum_data.variants[v.local_id].variant_data, - variant, - current, - current_else, - &cond_place, - mode, - )? - } - VariantId::StructId(s) => { - let struct_data = self.db.struct_data(s); - self.pattern_matching_variant_fields( - shape, - &struct_data.variant_data, + &self.db.enum_variant_data(v).variant_data, variant, current, current_else, @@ -547,6 +534,15 @@ impl MirLowerCtx<'_> { mode, )? } + VariantId::StructId(s) => self.pattern_matching_variant_fields( + shape, + &self.db.struct_data(s).variant_data, + variant, + current, + current_else, + &cond_place, + mode, + )?, VariantId::UnionId(_) => { return Err(MirLowerError::TypeError("pattern matching on union")) } diff --git a/crates/hir-ty/src/mir/pretty.rs b/crates/hir-ty/src/mir/pretty.rs index 366c2f662b54b..65fb58848255b 100644 --- a/crates/hir-ty/src/mir/pretty.rs +++ b/crates/hir-ty/src/mir/pretty.rs @@ -7,7 +7,7 @@ use std::{ use either::Either; use hir_def::{body::Body, hir::BindingId}; -use hir_expand::name::Name; +use hir_expand::{name::Name, Lookup}; use la_arena::ArenaMap; use crate::{ @@ -58,8 +58,14 @@ impl MirBody { ); } hir_def::DefWithBodyId::VariantId(id) => { - let data = db.enum_data(id.parent); - w!(this, "enum {} = ", data.name.display(db.upcast())); + let loc = id.lookup(db.upcast()); + let enum_loc = loc.parent.lookup(db.upcast()); + w!( + this, + "enum {}::{} = ", + enum_loc.id.item_tree(db.upcast())[enum_loc.id.value].name.display(db.upcast()), + loc.id.item_tree(db.upcast())[loc.id.value].name.display(db.upcast()), + ) } hir_def::DefWithBodyId::InTypeConstId(id) => { w!(this, "in type const {id:?} = "); @@ -306,8 +312,7 @@ impl<'a> MirPrettyCtx<'a> { hir_def::VariantId::EnumVariantId(e) => { w!(this, "("); f(this, local, head); - let variant_name = - &this.db.enum_data(e.parent).variants[e.local_id].name; + let variant_name = &this.db.enum_variant_data(e).name; w!( this, " as {}).{}", diff --git a/crates/hir-ty/src/tests.rs b/crates/hir-ty/src/tests.rs index c8cc61cc21b48..671fd9ec3a451 100644 --- a/crates/hir-ty/src/tests.rs +++ b/crates/hir-ty/src/tests.rs @@ -16,7 +16,7 @@ use base_db::{FileRange, SourceDatabaseExt}; use expect_test::Expect; use hir_def::{ body::{Body, BodySourceMap, SyntheticSyntax}, - db::{DefDatabase, InternDatabase}, + db::DefDatabase, hir::{ExprId, Pat, PatId}, item_scope::ItemScope, nameres::DefMap, @@ -145,7 +145,7 @@ fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_sour loc.source(&db).value.syntax().text_range().start() } DefWithBodyId::VariantId(it) => { - let loc = db.lookup_intern_enum(it.parent); + let loc = it.lookup(&db); loc.source(&db).value.syntax().text_range().start() } DefWithBodyId::InTypeConstId(it) => it.source(&db).syntax().text_range().start(), @@ -383,7 +383,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { loc.source(&db).value.syntax().text_range().start() } DefWithBodyId::VariantId(it) => { - let loc = db.lookup_intern_enum(it.parent); + let loc = it.lookup(&db); loc.source(&db).value.syntax().text_range().start() } DefWithBodyId::InTypeConstId(it) => it.source(&db).syntax().text_range().start(), @@ -453,16 +453,12 @@ fn visit_module( visit_body(db, &body, cb); } ModuleDefId::AdtId(hir_def::AdtId::EnumId(it)) => { - db.enum_data(it) - .variants - .iter() - .map(|(id, _)| hir_def::EnumVariantId { parent: it, local_id: id }) - .for_each(|it| { - let def = it.into(); - cb(def); - let body = db.body(def); - visit_body(db, &body, cb); - }); + db.enum_data(it).variants.iter().for_each(|&(it, _)| { + let def = it.into(); + cb(def); + let body = db.body(def); + visit_body(db, &body, cb); + }); } ModuleDefId::TraitId(it) => { let trait_data = db.trait_data(it); diff --git a/crates/hir-ty/src/tls.rs b/crates/hir-ty/src/tls.rs index 83814ed0ec1f1..db5fa3205778d 100644 --- a/crates/hir-ty/src/tls.rs +++ b/crates/hir-ty/src/tls.rs @@ -107,10 +107,7 @@ impl DebugContext<'_> { let name = match def { CallableDefId::FunctionId(ff) => self.0.function_data(ff).name.clone(), CallableDefId::StructId(s) => self.0.struct_data(s).name.clone(), - CallableDefId::EnumVariantId(e) => { - let enum_data = self.0.enum_data(e.parent); - enum_data.variants[e.local_id].name.clone() - } + CallableDefId::EnumVariantId(e) => self.0.enum_variant_data(e).name.clone(), }; match def { CallableDefId::FunctionId(_) => write!(fmt, "{{fn {}}}", name.display(self.0.upcast())), diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs index 75b8b9afa7085..e80eab87009ab 100644 --- a/crates/hir-ty/src/utils.rs +++ b/crates/hir-ty/src/utils.rs @@ -19,9 +19,8 @@ use hir_def::{ lang_item::LangItem, resolver::{HasResolver, TypeNs}, type_ref::{TraitBoundModifier, TypeRef}, - ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId, ItemContainerId, - LocalEnumVariantId, Lookup, OpaqueInternableThing, TraitId, TypeAliasId, TypeOrConstParamId, - TypeParamId, + ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId, ItemContainerId, Lookup, + OpaqueInternableThing, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, }; use hir_expand::name::Name; use intern::Interned; @@ -355,7 +354,7 @@ fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option it.lookup(db).container, GenericDefId::TypeAliasId(it) => it.lookup(db).container, GenericDefId::ConstId(it) => it.lookup(db).container, - GenericDefId::EnumVariantId(it) => return Some(it.parent.into()), + GenericDefId::EnumVariantId(it) => return Some(it.lookup(db).parent.into()), GenericDefId::AdtId(_) | GenericDefId::TraitId(_) | GenericDefId::ImplId(_) @@ -435,10 +434,12 @@ pub(crate) fn detect_variant_from_bytes<'a>( trait_env: Arc, b: &[u8], e: EnumId, -) -> Option<(LocalEnumVariantId, &'a Layout)> { +) -> Option<(EnumVariantId, &'a Layout)> { let krate = trait_env.krate; let (var_id, var_layout) = match &layout.variants { - hir_def::layout::Variants::Single { index } => (index.0, &*layout), + hir_def::layout::Variants::Single { index } => { + (db.enum_data(e).variants[index.0].0, &*layout) + } hir_def::layout::Variants::Multiple { tag, tag_encoding, variants, .. } => { let target_data_layout = db.target_data_layout(krate)?; let size = tag.size(&*target_data_layout).bytes_usize(); @@ -446,11 +447,12 @@ pub(crate) fn detect_variant_from_bytes<'a>( let tag = i128::from_le_bytes(pad16(&b[offset..offset + size], false)); match tag_encoding { TagEncoding::Direct => { - let x = variants.iter_enumerated().find(|x| { - db.const_eval_discriminant(EnumVariantId { parent: e, local_id: x.0 .0 }) - == Ok(tag) - })?; - (x.0 .0, x.1) + let (var_idx, layout) = + variants.iter_enumerated().find_map(|(var_idx, v)| { + let def = db.enum_data(e).variants[var_idx.0].0; + (db.const_eval_discriminant(def) == Ok(tag)).then_some((def, v)) + })?; + (var_idx, layout) } TagEncoding::Niche { untagged_variant, niche_start, .. } => { let candidate_tag = tag.wrapping_sub(*niche_start as i128) as usize; @@ -460,7 +462,7 @@ pub(crate) fn detect_variant_from_bytes<'a>( .filter(|x| x != untagged_variant) .nth(candidate_tag) .unwrap_or(*untagged_variant); - (variant.0, &variants[variant]) + (db.enum_data(e).variants[variant.0].0, &variants[variant]) } } } diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs index 5a21f41dca84a..7b9f895bc73eb 100644 --- a/crates/hir/src/attrs.rs +++ b/crates/hir/src/attrs.rs @@ -115,7 +115,7 @@ fn resolve_doc_path_on_( AttrDefId::FieldId(it) => it.parent.resolver(db.upcast()), AttrDefId::AdtId(it) => it.resolver(db.upcast()), AttrDefId::FunctionId(it) => it.resolver(db.upcast()), - AttrDefId::EnumVariantId(it) => it.parent.resolver(db.upcast()), + AttrDefId::EnumVariantId(it) => it.resolver(db.upcast()), AttrDefId::StaticId(it) => it.resolver(db.upcast()), AttrDefId::ConstId(it) => it.resolver(db.upcast()), AttrDefId::TraitId(it) => it.resolver(db.upcast()), diff --git a/crates/hir/src/db.rs b/crates/hir/src/db.rs index 403a6c88ab0f5..a2492840cb75c 100644 --- a/crates/hir/src/db.rs +++ b/crates/hir/src/db.rs @@ -6,8 +6,8 @@ pub use hir_def::db::{ AttrsQuery, BlockDefMapQuery, BlockItemTreeQueryQuery, BodyQuery, BodyWithSourceMapQuery, ConstDataQuery, ConstVisibilityQuery, CrateDefMapQueryQuery, CrateLangItemsQuery, - CrateSupportsNoStdQuery, DefDatabase, DefDatabaseStorage, EnumDataQuery, - EnumDataWithDiagnosticsQuery, ExprScopesQuery, ExternCrateDeclDataQuery, + CrateSupportsNoStdQuery, DefDatabase, DefDatabaseStorage, EnumDataQuery, EnumVariantDataQuery, + EnumVariantDataWithDiagnosticsQuery, ExprScopesQuery, ExternCrateDeclDataQuery, FieldVisibilitiesQuery, FieldsAttrsQuery, FieldsAttrsSourceMapQuery, FileItemTreeQuery, FunctionDataQuery, FunctionVisibilityQuery, GenericParamsQuery, ImplDataQuery, ImplDataWithDiagnosticsQuery, ImportMapQuery, InternAnonymousConstQuery, InternBlockQuery, @@ -19,7 +19,7 @@ pub use hir_def::db::{ MacroRulesDataQuery, ProcMacroDataQuery, StaticDataQuery, StructDataQuery, StructDataWithDiagnosticsQuery, TraitAliasDataQuery, TraitDataQuery, TraitDataWithDiagnosticsQuery, TypeAliasDataQuery, UnionDataQuery, - UnionDataWithDiagnosticsQuery, VariantsAttrsQuery, VariantsAttrsSourceMapQuery, + UnionDataWithDiagnosticsQuery, }; pub use hir_expand::db::{ AstIdMapQuery, DeclMacroExpanderQuery, ExpandDatabase, ExpandDatabaseStorage, diff --git a/crates/hir/src/from_id.rs b/crates/hir/src/from_id.rs index fc4bbffdb8361..887227bf4d071 100644 --- a/crates/hir/src/from_id.rs +++ b/crates/hir/src/from_id.rs @@ -93,13 +93,13 @@ impl From for GenericParamId { impl From for Variant { fn from(id: EnumVariantId) -> Self { - Variant { parent: id.parent.into(), id: id.local_id } + Variant { id } } } impl From for EnumVariantId { fn from(def: Variant) -> Self { - EnumVariantId { parent: def.parent.id, local_id: def.id } + def.id } } diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs index 31cf8ba336434..d10884517f92d 100644 --- a/crates/hir/src/has_source.rs +++ b/crates/hir/src/has_source.rs @@ -116,7 +116,7 @@ impl HasSource for Enum { impl HasSource for Variant { type Ast = ast::Variant; fn source(self, db: &dyn HirDatabase) -> Option> { - Some(self.parent.id.child_source(db.upcast()).map(|map| map[self.id].clone())) + Some(self.id.lookup(db.upcast()).source(db.upcast())) } } impl HasSource for Function { diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 3180a2b713a89..246fc231b47f5 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -54,9 +54,9 @@ use hir_def::{ src::HasSource as _, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId, ExternCrateId, FunctionId, GenericDefId, GenericParamId, HasModule, - ImplId, InTypeConstId, ItemContainerId, LifetimeParamId, LocalEnumVariantId, LocalFieldId, - Lookup, MacroExpander, MacroId, ModuleId, StaticId, StructId, TraitAliasId, TraitId, TupleId, - TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, + ImplId, InTypeConstId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup, MacroExpander, + MacroId, ModuleId, StaticId, StructId, TraitAliasId, TraitId, TupleId, TypeAliasId, + TypeOrConstParamId, TypeParamId, UnionId, }; use hir_expand::{attrs::collect_attrs, name::name, proc_macro::ProcMacroKind, MacroCallKind}; use hir_ty::{ @@ -375,9 +375,7 @@ impl ModuleDef { ModuleDef::Module(it) => it.id.into(), ModuleDef::Const(it) => it.id.into(), ModuleDef::Static(it) => it.id.into(), - ModuleDef::Variant(it) => { - EnumVariantId { parent: it.parent.into(), local_id: it.id }.into() - } + ModuleDef::Variant(it) => it.id.into(), ModuleDef::BuiltinType(_) | ModuleDef::Macro(_) => return Vec::new(), }; @@ -586,10 +584,9 @@ impl Module { Adt::Enum(e) => { for v in e.variants(db) { acc.extend(ModuleDef::Variant(v).diagnostics(db)); - } - - for diag in db.enum_data_with_diagnostics(e.id).1.iter() { - emit_def_diagnostic(db, acc, diag); + for diag in db.enum_variant_data_with_diagnostics(v.id).1.iter() { + emit_def_diagnostic(db, acc, diag); + } } } } @@ -1084,7 +1081,7 @@ impl Field { let generic_def_id: GenericDefId = match self.parent { VariantDef::Struct(it) => it.id.into(), VariantDef::Union(it) => it.id.into(), - VariantDef::Variant(it) => it.parent.id.into(), + VariantDef::Variant(it) => it.id.into(), }; let substs = TyBuilder::placeholder_subst(db, generic_def_id); let ty = db.field_types(var_id)[self.id].clone().substitute(Interner, &substs); @@ -1224,7 +1221,7 @@ impl Enum { } pub fn variants(self, db: &dyn HirDatabase) -> Vec { - db.enum_data(self.id).variants.iter().map(|(id, _)| Variant { parent: self, id }).collect() + db.enum_data(self.id).variants.iter().map(|&(id, _)| Variant { id }).collect() } pub fn repr(self, db: &dyn HirDatabase) -> Option { @@ -1292,25 +1289,24 @@ impl From<&Variant> for DefWithBodyId { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Variant { - pub(crate) parent: Enum, - pub(crate) id: LocalEnumVariantId, + pub(crate) id: EnumVariantId, } impl Variant { pub fn module(self, db: &dyn HirDatabase) -> Module { - self.parent.module(db) + Module { id: self.id.lookup(db.upcast()).container } } - pub fn parent_enum(self, _db: &dyn HirDatabase) -> Enum { - self.parent + pub fn parent_enum(self, db: &dyn HirDatabase) -> Enum { + self.id.lookup(db.upcast()).parent.into() } pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type { - Type::from_value_def(db, EnumVariantId { parent: self.parent.id, local_id: self.id }) + Type::from_value_def(db, self.id) } pub fn name(self, db: &dyn HirDatabase) -> Name { - db.enum_data(self.parent.id).variants[self.id].name.clone() + db.enum_variant_data(self.id).name.clone() } pub fn fields(self, db: &dyn HirDatabase) -> Vec { @@ -1326,7 +1322,7 @@ impl Variant { } pub(crate) fn variant_data(self, db: &dyn HirDatabase) -> Arc { - db.enum_data(self.parent.id).variants[self.id].variant_data.clone() + db.enum_variant_data(self.id).variant_data.clone() } pub fn value(self, db: &dyn HirDatabase) -> Option { @@ -1342,7 +1338,21 @@ impl Variant { let parent_layout = parent_enum.layout(db)?; Ok(match &parent_layout.0.variants { layout::Variants::Multiple { variants, .. } => Layout( - Arc::new(variants[RustcEnumVariantIdx(self.id)].clone()), + { + let lookup = self.id.lookup(db.upcast()); + let rustc_enum_variant_idx = lookup.id.value.index().into_raw().into_u32() + - lookup.id.item_tree(db.upcast()) + [lookup.parent.lookup(db.upcast()).id.value] + .variants + .start + .index() + .into_raw() + .into_u32(); + let rustc_enum_variant_idx = + RustcEnumVariantIdx(rustc_enum_variant_idx as usize); + + Arc::new(variants[rustc_enum_variant_idx].clone()) + }, db.target_data_layout(parent_enum.krate(db).into()).unwrap(), ), _ => parent_layout, @@ -1547,7 +1557,7 @@ impl DefWithBody { DefWithBody::Function(it) => it.ret_type(db), DefWithBody::Static(it) => it.ty(db), DefWithBody::Const(it) => it.ty(db), - DefWithBody::Variant(it) => it.parent.variant_body_ty(db), + DefWithBody::Variant(it) => it.parent_enum(db).variant_body_ty(db), DefWithBody::InTypeConst(it) => Type::new_with_resolver_inner( db, &DefWithBodyId::from(it.id).resolver(db.upcast()), diff --git a/crates/hir/src/symbols.rs b/crates/hir/src/symbols.rs index e1101dd8236e6..28ac5940e6922 100644 --- a/crates/hir/src/symbols.rs +++ b/crates/hir/src/symbols.rs @@ -262,9 +262,7 @@ impl<'a> SymbolCollector<'a> { DefWithBodyId::FunctionId(id) => Some(self.db.function_data(id).name.to_smol_str()), DefWithBodyId::StaticId(id) => Some(self.db.static_data(id).name.to_smol_str()), DefWithBodyId::ConstId(id) => Some(self.db.const_data(id).name.as_ref()?.to_smol_str()), - DefWithBodyId::VariantId(id) => { - Some(self.db.enum_data(id.parent).variants[id.local_id].name.to_smol_str()) - } + DefWithBodyId::VariantId(id) => Some(self.db.enum_variant_data(id).name.to_smol_str()), DefWithBodyId::InTypeConstId(_) => Some("in type const".into()), } } diff --git a/crates/ide-db/src/apply_change.rs b/crates/ide-db/src/apply_change.rs index 259d141404d3f..9871fb5c54090 100644 --- a/crates/ide-db/src/apply_change.rs +++ b/crates/ide-db/src/apply_change.rs @@ -141,7 +141,8 @@ impl RootDatabase { hir::db::UnionDataQuery hir::db::UnionDataWithDiagnosticsQuery hir::db::EnumDataQuery - hir::db::EnumDataWithDiagnosticsQuery + hir::db::EnumVariantDataWithDiagnosticsQuery + hir::db::EnumVariantDataQuery hir::db::ImplDataQuery hir::db::ImplDataWithDiagnosticsQuery hir::db::TraitDataQuery @@ -158,9 +159,7 @@ impl RootDatabase { hir::db::BodyQuery hir::db::ExprScopesQuery hir::db::GenericParamsQuery - hir::db::VariantsAttrsQuery hir::db::FieldsAttrsQuery - hir::db::VariantsAttrsSourceMapQuery hir::db::FieldsAttrsSourceMapQuery hir::db::AttrsQuery hir::db::CrateLangItemsQuery diff --git a/crates/ide-db/src/lib.rs b/crates/ide-db/src/lib.rs index eae23e9548240..05abc9d815183 100644 --- a/crates/ide-db/src/lib.rs +++ b/crates/ide-db/src/lib.rs @@ -222,7 +222,8 @@ impl RootDatabase { hir_db::UnionDataQuery hir_db::UnionDataWithDiagnosticsQuery hir_db::EnumDataQuery - hir_db::EnumDataWithDiagnosticsQuery + hir_db::EnumDataQuery + hir_db::EnumVariantDataWithDiagnosticsQuery hir_db::ImplDataQuery hir_db::ImplDataWithDiagnosticsQuery hir_db::TraitDataQuery @@ -239,9 +240,7 @@ impl RootDatabase { hir_db::BodyQuery hir_db::ExprScopesQuery hir_db::GenericParamsQuery - hir_db::VariantsAttrsQuery hir_db::FieldsAttrsQuery - hir_db::VariantsAttrsSourceMapQuery hir_db::FieldsAttrsSourceMapQuery hir_db::AttrsQuery hir_db::CrateLangItemsQuery From 6bbd106c70370ca6a78de0676f103810f9eea22a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Mon, 15 Jan 2024 11:40:09 +0200 Subject: [PATCH 0228/1197] Merge commit '9d8889cdfcc3aa0302353fc988ed21ff9bc9925c' into sync-from-ra --- Cargo.lock | 44 ++-- Cargo.toml | 8 +- crates/base-db/src/lib.rs | 18 +- crates/hir-def/Cargo.toml | 7 +- crates/hir-def/src/attr.rs | 9 +- crates/hir-def/src/body/lower.rs | 5 +- crates/hir-def/src/child_by_source.rs | 2 +- crates/hir-def/src/data/adt.rs | 2 +- crates/hir-def/src/db.rs | 7 +- crates/hir-def/src/find_path.rs | 204 ++++++++------- crates/hir-def/src/generics.rs | 241 +++++++++-------- crates/hir-def/src/hir/format_args.rs | 2 +- crates/hir-def/src/hir/type_ref.rs | 3 +- crates/hir-def/src/item_scope.rs | 91 ++++--- crates/hir-def/src/item_tree.rs | 37 ++- crates/hir-def/src/item_tree/lower.rs | 12 +- crates/hir-def/src/item_tree/pretty.rs | 4 +- crates/hir-def/src/lang_item.rs | 17 +- crates/hir-def/src/lib.rs | 17 +- .../builtin_derive_macro.rs | 83 +++--- .../macro_expansion_tests/builtin_fn_macro.rs | 2 +- crates/hir-def/src/nameres.rs | 7 +- crates/hir-def/src/nameres/path_resolution.rs | 8 +- crates/hir-def/src/nameres/tests/macros.rs | 48 ++++ crates/hir-def/src/resolver.rs | 2 +- crates/hir-def/src/test_db.rs | 3 +- crates/hir-def/src/visibility.rs | 52 ++-- crates/hir-expand/src/builtin_derive_macro.rs | 114 ++------ crates/hir-expand/src/builtin_fn_macro.rs | 24 +- crates/hir-expand/src/lib.rs | 4 + crates/hir-expand/src/quote.rs | 4 + crates/hir-ty/Cargo.toml | 6 +- crates/hir-ty/src/chalk_db.rs | 8 +- crates/hir-ty/src/db.rs | 36 +-- crates/hir-ty/src/display.rs | 2 +- crates/hir-ty/src/layout.rs | 11 +- crates/hir-ty/src/layout/adt.rs | 2 +- crates/hir-ty/src/layout/tests.rs | 4 +- crates/hir-ty/src/lib.rs | 15 +- crates/hir-ty/src/lower.rs | 2 +- crates/hir-ty/src/method_resolution.rs | 125 ++++----- crates/hir-ty/src/test_db.rs | 3 +- crates/hir-ty/src/tests/macros.rs | 30 ++- crates/hir/src/attrs.rs | 2 +- crates/hir/src/db.rs | 4 +- crates/hir/src/lib.rs | 2 +- crates/hir/src/symbols.rs | 3 +- .../ide-assists/src/handlers/auto_import.rs | 35 +++ .../src/handlers/extract_function.rs | 52 +++- .../src/handlers/generate_constant.rs | 16 ++ .../src/handlers/generate_delegate_methods.rs | 45 ++-- .../src/handlers/merge_nested_if.rs | 246 ++++++++++++++++++ crates/ide-assists/src/lib.rs | 2 + crates/ide-assists/src/tests/generated.rs | 17 ++ crates/ide-completion/src/context.rs | 5 + crates/ide-completion/src/item.rs | 6 + crates/ide-completion/src/render.rs | 81 ++++++ crates/ide-completion/src/render/function.rs | 14 +- crates/ide-db/src/apply_change.rs | 144 +++++----- crates/ide-db/src/imports/import_assets.rs | 5 +- crates/ide-db/src/lib.rs | 13 +- crates/ide-db/src/path_transform.rs | 21 +- crates/ide-db/src/search.rs | 2 +- .../src/handlers/unresolved_assoc_item.rs | 1 + crates/ide/src/expand_macro.rs | 8 +- crates/ide/src/lib.rs | 2 +- crates/load-cargo/src/lib.rs | 7 +- crates/parser/Cargo.toml | 7 +- crates/parser/src/grammar/expressions.rs | 10 +- crates/parser/src/lexed_str.rs | 2 - crates/parser/src/lib.rs | 5 + .../ok/0208_closure_range_method_call.rast | 49 ++++ .../ok/0208_closure_range_method_call.rs | 4 + crates/proc-macro-api/src/lib.rs | 10 +- crates/proc-macro-api/src/process.rs | 66 ++++- crates/proc-macro-srv-cli/src/main.rs | 3 +- crates/proc-macro-srv/Cargo.toml | 2 +- .../proc-macro-srv/proc-macro-test/Cargo.toml | 3 - .../proc-macro-srv/proc-macro-test/build.rs | 28 +- .../proc-macro-test/imp/Cargo.toml | 3 - .../proc-macro-test/imp/src/lib.rs | 3 - crates/proc-macro-srv/src/lib.rs | 4 +- crates/project-model/src/workspace.rs | 2 +- crates/rust-analyzer/Cargo.toml | 4 +- crates/rust-analyzer/src/global_state.rs | 85 +++--- .../src/handlers/notification.rs | 27 +- crates/rust-analyzer/src/handlers/request.rs | 1 - crates/rust-analyzer/src/lsp/utils.rs | 35 ++- crates/rust-analyzer/src/main_loop.rs | 9 +- crates/rust-analyzer/src/mem_docs.rs | 5 +- crates/rust-analyzer/src/reload.rs | 7 +- crates/rustc-dependencies/Cargo.toml | 23 -- crates/rustc-dependencies/src/lib.rs | 48 ---- crates/syntax/Cargo.toml | 6 +- crates/syntax/src/ast/node_ext.rs | 20 +- crates/syntax/src/ast/token_ext.rs | 2 - crates/syntax/src/lib.rs | 5 + crates/syntax/src/validation.rs | 2 +- crates/test-utils/src/minicore.rs | 10 + crates/vfs-notify/src/lib.rs | 2 +- crates/vfs/src/lib.rs | 110 ++++---- crates/vfs/src/loader.rs | 5 + docs/dev/syntax.md | 3 +- editors/code/package-lock.json | 6 +- 104 files changed, 1650 insertions(+), 1024 deletions(-) create mode 100644 crates/ide-assists/src/handlers/merge_nested_if.rs create mode 100644 crates/parser/test_data/parser/inline/ok/0208_closure_range_method_call.rast create mode 100644 crates/parser/test_data/parser/inline/ok/0208_closure_range_method_call.rs delete mode 100644 crates/rustc-dependencies/Cargo.toml delete mode 100644 crates/rustc-dependencies/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 6670e92f51bc1..15d06222eb42d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -513,7 +513,8 @@ dependencies = [ "mbe", "once_cell", "profile", - "rustc-dependencies", + "ra-ap-rustc_abi", + "ra-ap-rustc_parse_format", "rustc-hash", "smallvec", "span", @@ -579,7 +580,8 @@ dependencies = [ "oorandom", "profile", "project-model", - "rustc-dependencies", + "ra-ap-rustc_abi", + "ra-ap-rustc_index", "rustc-hash", "scoped-tls", "smallvec", @@ -1196,7 +1198,7 @@ dependencies = [ "drop_bomb", "expect-test", "limit", - "rustc-dependencies", + "ra-ap-rustc_lexer", "sourcegen", "stdx", ] @@ -1540,7 +1542,6 @@ dependencies = [ "profile", "project-model", "rayon", - "rustc-dependencies", "rustc-hash", "scip", "serde", @@ -1567,9 +1568,9 @@ dependencies = [ [[package]] name = "rust-analyzer-salsa" -version = "0.17.0-pre.4" +version = "0.17.0-pre.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16c42b8737c320578b441a82daf7cdf8d897468de64e8a774fa54b53a50b6cc0" +checksum = "ca9d387a9801f4fb9b366789ad1bfc08448cafc49cf148d907cfcd88ab665d7f" dependencies = [ "indexmap", "lock_api", @@ -1579,13 +1580,14 @@ dependencies = [ "rust-analyzer-salsa-macros", "rustc-hash", "smallvec", + "triomphe", ] [[package]] name = "rust-analyzer-salsa-macros" -version = "0.17.0-pre.4" +version = "0.17.0-pre.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db72b0883f3592ade2be15a10583c75e0b269ec26e1190800fda2e2ce5ae6634" +checksum = "a2035f385d7fae31e9b086f40b272ee1d79c484472f31c9a10348a406e841eaf" dependencies = [ "heck", "proc-macro2", @@ -1599,16 +1601,6 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" -[[package]] -name = "rustc-dependencies" -version = "0.0.0" -dependencies = [ - "ra-ap-rustc_abi", - "ra-ap-rustc_index", - "ra-ap-rustc_lexer", - "ra-ap-rustc_parse_format", -] - [[package]] name = "rustc-hash" version = "1.1.0" @@ -1751,6 +1743,12 @@ dependencies = [ "vfs", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "static_assertions" version = "1.1.0" @@ -1808,9 +1806,9 @@ dependencies = [ "proc-macro2", "profile", "quote", + "ra-ap-rustc_lexer", "rayon", "rowan", - "rustc-dependencies", "rustc-hash", "smol_str", "sourcegen", @@ -2028,9 +2026,13 @@ dependencies = [ [[package]] name = "triomphe" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c5a71827ac326072b6405552093e2ad2accd25a32fd78d4edc82d98c7f2409" +checksum = "859eb650cfee7434994602c3a68b25d77ad9e68c8a6cd491616ef86661382eb3" +dependencies = [ + "serde", + "stable_deref_trait", +] [[package]] name = "tt" diff --git a/Cargo.toml b/Cargo.toml index 4ee8064b5e347..35bef151196f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -78,7 +78,11 @@ toolchain = { path = "./crates/toolchain", version = "0.0.0" } tt = { path = "./crates/tt", version = "0.0.0" } vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" } vfs = { path = "./crates/vfs", version = "0.0.0" } -rustc-dependencies = { path = "./crates/rustc-dependencies", version = "0.0.0" } + +ra-ap-rustc_lexer = { version = "0.21.0", default-features = false } +ra-ap-rustc_parse_format = { version = "0.21.0", default-features = false } +ra-ap-rustc_index = { version = "0.21.0", default-features = false } +ra-ap-rustc_abi = { version = "0.21.0", default-features = false } # local crates that aren't published to crates.io. These should not have versions. sourcegen = { path = "./crates/sourcegen" } @@ -108,7 +112,7 @@ itertools = "0.12.0" libc = "0.2.150" nohash-hasher = "0.2.0" rayon = "1.8.0" -rust-analyzer-salsa = "0.17.0-pre.4" +rust-analyzer-salsa = "0.17.0-pre.5" rustc-hash = "1.1.0" semver = "1.0.14" serde = { version = "1.0.192", features = ["derive"] } diff --git a/crates/base-db/src/lib.rs b/crates/base-db/src/lib.rs index a0a55df5f99af..92d2b9c3f57c9 100644 --- a/crates/base-db/src/lib.rs +++ b/crates/base-db/src/lib.rs @@ -7,7 +7,6 @@ mod change; use std::panic; -use rustc_hash::FxHashSet; use syntax::{ast, Parse, SourceFile}; use triomphe::Arc; @@ -44,12 +43,13 @@ pub trait Upcast { } pub const DEFAULT_PARSE_LRU_CAP: usize = 128; +pub const DEFAULT_BORROWCK_LRU_CAP: usize = 256; pub trait FileLoader { /// Text of the file. fn file_text(&self, file_id: FileId) -> Arc; fn resolve_path(&self, path: AnchoredPath<'_>) -> Option; - fn relevant_crates(&self, file_id: FileId) -> Arc>; + fn relevant_crates(&self, file_id: FileId) -> Arc<[CrateId]>; } /// Database which stores all significant input facts: source code and project @@ -84,19 +84,21 @@ pub trait SourceDatabaseExt: SourceDatabase { #[salsa::input] fn source_root(&self, id: SourceRootId) -> Arc; - fn source_root_crates(&self, id: SourceRootId) -> Arc>; + fn source_root_crates(&self, id: SourceRootId) -> Arc<[CrateId]>; } -fn source_root_crates(db: &dyn SourceDatabaseExt, id: SourceRootId) -> Arc> { +fn source_root_crates(db: &dyn SourceDatabaseExt, id: SourceRootId) -> Arc<[CrateId]> { let graph = db.crate_graph(); - let res = graph + let mut crates = graph .iter() .filter(|&krate| { let root_file = graph[krate].root_file_id; db.file_source_root(root_file) == id }) - .collect(); - Arc::new(res) + .collect::>(); + crates.sort(); + crates.dedup(); + crates.into_iter().collect() } /// Silly workaround for cyclic deps between the traits @@ -113,7 +115,7 @@ impl FileLoader for FileLoaderDelegate<&'_ T> { source_root.resolve_path(path) } - fn relevant_crates(&self, file_id: FileId) -> Arc> { + fn relevant_crates(&self, file_id: FileId) -> Arc<[CrateId]> { let _p = profile::span("relevant_crates"); let source_root = self.0.file_source_root(file_id); self.0.source_root_crates(source_root) diff --git a/crates/hir-def/Cargo.toml b/crates/hir-def/Cargo.toml index 5933d30040fad..523ff6fc404e8 100644 --- a/crates/hir-def/Cargo.toml +++ b/crates/hir-def/Cargo.toml @@ -29,7 +29,8 @@ smallvec.workspace = true hashbrown.workspace = true triomphe.workspace = true -rustc-dependencies.workspace = true +ra-ap-rustc_parse_format.workspace = true +ra-ap-rustc_abi.workspace = true # local deps stdx.workspace = true @@ -53,7 +54,7 @@ test-utils.workspace = true test-fixture.workspace = true [features] -in-rust-tree = ["rustc-dependencies/in-rust-tree"] +in-rust-tree = [] [lints] -workspace = true \ No newline at end of file +workspace = true diff --git a/crates/hir-def/src/attr.rs b/crates/hir-def/src/attr.rs index 26f76afb1f09f..30452e34aac36 100644 --- a/crates/hir-def/src/attr.rs +++ b/crates/hir-def/src/attr.rs @@ -207,6 +207,13 @@ impl Attrs { }) } + pub fn has_doc_notable_trait(&self) -> bool { + self.by_key("doc").tt_values().any(|tt| { + tt.delimiter.kind == DelimiterKind::Parenthesis && + matches!(&*tt.token_trees, [tt::TokenTree::Leaf(tt::Leaf::Ident(ident))] if ident.text == "notable_trait") + }) + } + pub fn doc_exprs(&self) -> impl Iterator + '_ { self.by_key("doc").tt_values().map(DocExpr::parse) } @@ -355,7 +362,7 @@ fn parse_comma_sep(subtree: &tt::Subtree) -> Vec { } impl AttrsWithOwner { - pub(crate) fn attrs_with_owner(db: &dyn DefDatabase, owner: AttrDefId) -> Self { + pub fn attrs_with_owner(db: &dyn DefDatabase, owner: AttrDefId) -> Self { Self { attrs: db.attrs(owner), owner } } diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs index c728570d9866a..fc0a4eb43dc2a 100644 --- a/crates/hir-def/src/body/lower.rs +++ b/crates/hir-def/src/body/lower.rs @@ -965,11 +965,10 @@ impl ExprCollector<'_> { let res = match self.def_map.modules[module] .scope - .macro_invocations - .get(&InFile::new(outer_file, self.ast_id_map.ast_id_for_ptr(syntax_ptr))) + .macro_invoc(InFile::new(outer_file, self.ast_id_map.ast_id_for_ptr(syntax_ptr))) { // fast path, macro call is in a block module - Some(&call) => Ok(self.expander.enter_expand_id(self.db, call)), + Some(call) => Ok(self.expander.enter_expand_id(self.db, call)), None => self.expander.enter_expand(self.db, mcall, |path| { self.def_map .resolve_path( diff --git a/crates/hir-def/src/child_by_source.rs b/crates/hir-def/src/child_by_source.rs index c82d2347de5c6..32c53cb950313 100644 --- a/crates/hir-def/src/child_by_source.rs +++ b/crates/hir-def/src/child_by_source.rs @@ -92,7 +92,7 @@ impl ChildBySource for ItemScope { self.impls().for_each(|imp| add_impl(db, res, file_id, imp)); self.extern_crate_decls().for_each(|ext| add_extern_crate(db, res, file_id, ext)); self.use_decls().for_each(|ext| add_use(db, res, file_id, ext)); - self.unnamed_consts().for_each(|konst| { + self.unnamed_consts(db).for_each(|konst| { let loc = konst.lookup(db); if loc.id.file_id() == file_id { res[keys::CONST].insert(loc.source(db).value, konst); diff --git a/crates/hir-def/src/data/adt.rs b/crates/hir-def/src/data/adt.rs index a95b78614e822..8772c34f02f1a 100644 --- a/crates/hir-def/src/data/adt.rs +++ b/crates/hir-def/src/data/adt.rs @@ -11,7 +11,7 @@ use hir_expand::{ }; use intern::Interned; use la_arena::{Arena, ArenaMap}; -use rustc_dependencies::abi::{Align, Integer, IntegerType, ReprFlags, ReprOptions}; +use rustc_abi::{Align, Integer, IntegerType, ReprFlags, ReprOptions}; use syntax::ast::{self, HasName, HasVisibility}; use triomphe::Arc; diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs index d5831022f28f7..70c0d5193d4bf 100644 --- a/crates/hir-def/src/db.rs +++ b/crates/hir-def/src/db.rs @@ -210,13 +210,10 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast Attrs; + #[salsa::transparent] #[salsa::invoke(lang_item::lang_attr_query)] fn lang_attr(&self, def: AttrDefId) -> Option; - #[salsa::transparent] - #[salsa::invoke(AttrsWithOwner::attrs_with_owner)] - fn attrs_with_owner(&self, def: AttrDefId) -> AttrsWithOwner; - // endregion:attrs #[salsa::invoke(LangItems::lang_item_query)] @@ -240,7 +237,7 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast Arc; + fn crate_lang_items(&self, krate: CrateId) -> Option>; fn crate_supports_no_std(&self, crate_id: CrateId) -> bool; } diff --git a/crates/hir-def/src/find_path.rs b/crates/hir-def/src/find_path.rs index 4737b48703db3..67e43f15cd3f3 100644 --- a/crates/hir-def/src/find_path.rs +++ b/crates/hir-def/src/find_path.rs @@ -10,7 +10,7 @@ use crate::{ item_scope::ItemInNs, nameres::DefMap, path::{ModPath, PathKind}, - visibility::Visibility, + visibility::{Visibility, VisibilityExplicity}, CrateRootModuleId, ModuleDefId, ModuleId, }; @@ -24,7 +24,7 @@ pub fn find_path( prefer_prelude: bool, ) -> Option { let _p = profile::span("find_path"); - find_path_inner(db, item, from, None, prefer_no_std, prefer_prelude) + find_path_inner(FindPathCtx { db, prefixed: None, prefer_no_std, prefer_prelude }, item, from) } pub fn find_path_prefixed( @@ -36,7 +36,11 @@ pub fn find_path_prefixed( prefer_prelude: bool, ) -> Option { let _p = profile::span("find_path_prefixed"); - find_path_inner(db, item, from, Some(prefix_kind), prefer_no_std, prefer_prelude) + find_path_inner( + FindPathCtx { db, prefixed: Some(prefix_kind), prefer_no_std, prefer_prelude }, + item, + from, + ) } #[derive(Copy, Clone, Debug)] @@ -83,64 +87,60 @@ impl PrefixKind { } } -/// Attempts to find a path to refer to the given `item` visible from the `from` ModuleId -fn find_path_inner( - db: &dyn DefDatabase, - item: ItemInNs, - from: ModuleId, +#[derive(Copy, Clone)] +struct FindPathCtx<'db> { + db: &'db dyn DefDatabase, prefixed: Option, prefer_no_std: bool, prefer_prelude: bool, -) -> Option { +} + +/// Attempts to find a path to refer to the given `item` visible from the `from` ModuleId +fn find_path_inner(ctx: FindPathCtx<'_>, item: ItemInNs, from: ModuleId) -> Option { // - if the item is a builtin, it's in scope if let ItemInNs::Types(ModuleDefId::BuiltinType(builtin)) = item { return Some(ModPath::from_segments(PathKind::Plain, Some(builtin.as_name()))); } - let def_map = from.def_map(db); + let def_map = from.def_map(ctx.db); let crate_root = def_map.crate_root(); // - if the item is a module, jump straight to module search if let ItemInNs::Types(ModuleDefId::ModuleId(module_id)) = item { let mut visited_modules = FxHashSet::default(); return find_path_for_module( - db, + FindPathCtx { + prefer_no_std: ctx.prefer_no_std || ctx.db.crate_supports_no_std(crate_root.krate), + ..ctx + }, &def_map, &mut visited_modules, crate_root, from, module_id, MAX_PATH_LEN, - prefixed, - prefer_no_std || db.crate_supports_no_std(crate_root.krate), - prefer_prelude, ) .map(|(item, _)| item); } // - if the item is already in scope, return the name under which it is - let scope_name = find_in_scope(db, &def_map, from, item); - if prefixed.is_none() { + let scope_name = find_in_scope(ctx.db, &def_map, from, item); + if ctx.prefixed.is_none() { if let Some(scope_name) = scope_name { return Some(ModPath::from_segments(PathKind::Plain, Some(scope_name))); } } // - if the item is in the prelude, return the name from there - if let value @ Some(_) = find_in_prelude(db, &crate_root.def_map(db), &def_map, item, from) { + if let value @ Some(_) = + find_in_prelude(ctx.db, &crate_root.def_map(ctx.db), &def_map, item, from) + { return value; } if let Some(ModuleDefId::EnumVariantId(variant)) = item.as_module_def_id() { // - if the item is an enum variant, refer to it via the enum - if let Some(mut path) = find_path_inner( - db, - ItemInNs::Types(variant.parent.into()), - from, - prefixed, - prefer_no_std, - prefer_prelude, - ) { - let data = db.enum_data(variant.parent); + if let Some(mut path) = find_path_inner(ctx, ItemInNs::Types(variant.parent.into()), from) { + let data = ctx.db.enum_data(variant.parent); path.push_segment(data.variants[variant.local_id].name.clone()); return Some(path); } @@ -152,32 +152,29 @@ fn find_path_inner( let mut visited_modules = FxHashSet::default(); calculate_best_path( - db, + FindPathCtx { + prefer_no_std: ctx.prefer_no_std || ctx.db.crate_supports_no_std(crate_root.krate), + ..ctx + }, &def_map, &mut visited_modules, crate_root, MAX_PATH_LEN, item, from, - prefixed, - prefer_no_std || db.crate_supports_no_std(crate_root.krate), - prefer_prelude, scope_name, ) .map(|(item, _)| item) } fn find_path_for_module( - db: &dyn DefDatabase, + ctx: FindPathCtx<'_>, def_map: &DefMap, visited_modules: &mut FxHashSet, crate_root: CrateRootModuleId, from: ModuleId, module_id: ModuleId, max_len: usize, - prefixed: Option, - prefer_no_std: bool, - prefer_prelude: bool, ) -> Option<(ModPath, Stability)> { if max_len == 0 { return None; @@ -185,8 +182,8 @@ fn find_path_for_module( // Base cases: // - if the item is already in scope, return the name under which it is - let scope_name = find_in_scope(db, def_map, from, ItemInNs::Types(module_id.into())); - if prefixed.is_none() { + let scope_name = find_in_scope(ctx.db, def_map, from, ItemInNs::Types(module_id.into())); + if ctx.prefixed.is_none() { if let Some(scope_name) = scope_name { return Some((ModPath::from_segments(PathKind::Plain, Some(scope_name)), Stable)); } @@ -198,20 +195,20 @@ fn find_path_for_module( } // - if relative paths are fine, check if we are searching for a parent - if prefixed.filter(PrefixKind::is_absolute).is_none() { + if ctx.prefixed.filter(PrefixKind::is_absolute).is_none() { if let modpath @ Some(_) = find_self_super(def_map, module_id, from) { return modpath.zip(Some(Stable)); } } // - if the item is the crate root of a dependency crate, return the name from the extern prelude - let root_def_map = crate_root.def_map(db); + let root_def_map = crate_root.def_map(ctx.db); for (name, (def_id, _extern_crate)) in root_def_map.extern_prelude() { if module_id == def_id { let name = scope_name.unwrap_or_else(|| name.clone()); let name_already_occupied_in_type_ns = def_map - .with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| { + .with_ancestor_maps(ctx.db, from.local_id, &mut |def_map, local_id| { def_map[local_id] .scope .type_(&name) @@ -229,21 +226,18 @@ fn find_path_for_module( } if let value @ Some(_) = - find_in_prelude(db, &root_def_map, &def_map, ItemInNs::Types(module_id.into()), from) + find_in_prelude(ctx.db, &root_def_map, &def_map, ItemInNs::Types(module_id.into()), from) { return value.zip(Some(Stable)); } calculate_best_path( - db, + ctx, def_map, visited_modules, crate_root, max_len, ItemInNs::Types(module_id.into()), from, - prefixed, - prefer_no_std, - prefer_prelude, scope_name, ) } @@ -256,7 +250,7 @@ fn find_in_scope( item: ItemInNs, ) -> Option { def_map.with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| { - def_map[local_id].scope.name_of(item).map(|(name, _)| name.clone()) + def_map[local_id].scope.name_of(item).map(|(name, _, _)| name.clone()) }) } @@ -273,7 +267,7 @@ fn find_in_prelude( // Preludes in block DefMaps are ignored, only the crate DefMap is searched let prelude_def_map = prelude_module.def_map(db); let prelude_scope = &prelude_def_map[prelude_module.local_id].scope; - let (name, vis) = prelude_scope.name_of(item)?; + let (name, vis, _declared) = prelude_scope.name_of(item)?; if !vis.is_visible_from(db, from) { return None; } @@ -315,16 +309,13 @@ fn find_self_super(def_map: &DefMap, item: ModuleId, from: ModuleId) -> Option, def_map: &DefMap, visited_modules: &mut FxHashSet, crate_root: CrateRootModuleId, max_len: usize, item: ItemInNs, from: ModuleId, - mut prefixed: Option, - prefer_no_std: bool, - prefer_prelude: bool, scope_name: Option, ) -> Option<(ModPath, Stability)> { if max_len <= 1 { @@ -341,32 +332,29 @@ fn calculate_best_path( }; // Recursive case: // - otherwise, look for modules containing (reexporting) it and import it from one of those - if item.krate(db) == Some(from.krate) { + if item.krate(ctx.db) == Some(from.krate) { let mut best_path_len = max_len; // Item was defined in the same crate that wants to import it. It cannot be found in any // dependency in this case. - for (module_id, name) in find_local_import_locations(db, item, from) { + for (module_id, name) in find_local_import_locations(ctx.db, item, from) { if !visited_modules.insert(module_id) { cov_mark::hit!(recursive_imports); continue; } if let Some(mut path) = find_path_for_module( - db, + ctx, def_map, visited_modules, crate_root, from, module_id, best_path_len - 1, - prefixed, - prefer_no_std, - prefer_prelude, ) { path.0.push_segment(name); let new_path = match best_path.take() { Some(best_path) => { - select_best_path(best_path, path, prefer_no_std, prefer_prelude) + select_best_path(best_path, path, ctx.prefer_no_std, ctx.prefer_prelude) } None => path, }; @@ -379,8 +367,8 @@ fn calculate_best_path( // too (unless we can't name it at all). It could *also* be (re)exported by the same crate // that wants to import it here, but we always prefer to use the external path here. - for dep in &db.crate_graph()[from.krate].dependencies { - let import_map = db.import_map(dep.crate_id); + for dep in &ctx.db.crate_graph()[from.krate].dependencies { + let import_map = ctx.db.import_map(dep.crate_id); let Some(import_info_for) = import_map.import_info_for(item) else { continue }; for info in import_info_for { if info.is_doc_hidden { @@ -391,16 +379,13 @@ fn calculate_best_path( // Determine best path for containing module and append last segment from `info`. // FIXME: we should guide this to look up the path locally, or from the same crate again? let Some((mut path, path_stability)) = find_path_for_module( - db, + ctx, def_map, visited_modules, crate_root, from, info.container, max_len - 1, - prefixed, - prefer_no_std, - prefer_prelude, ) else { continue; }; @@ -413,17 +398,21 @@ fn calculate_best_path( ); let new_path_with_stab = match best_path.take() { - Some(best_path) => { - select_best_path(best_path, path_with_stab, prefer_no_std, prefer_prelude) - } + Some(best_path) => select_best_path( + best_path, + path_with_stab, + ctx.prefer_no_std, + ctx.prefer_prelude, + ), None => path_with_stab, }; update_best_path(&mut best_path, new_path_with_stab); } } } - if let Some(module) = item.module(db) { - if module.containing_block().is_some() && prefixed.is_some() { + let mut prefixed = ctx.prefixed; + if let Some(module) = item.module(ctx.db) { + if module.containing_block().is_some() && ctx.prefixed.is_some() { cov_mark::hit!(prefixed_in_block_expression); prefixed = Some(PrefixKind::Plain); } @@ -548,34 +537,35 @@ fn find_local_import_locations( &ext_def_map[module.local_id] }; - if let Some((name, vis)) = data.scope.name_of(item) { + if let Some((name, vis, declared)) = data.scope.name_of(item) { if vis.is_visible_from(db, from) { - let is_private = match vis { - Visibility::Module(private_to) => private_to.local_id == module.local_id, - Visibility::Public => false, - }; - let is_original_def = match item.as_module_def_id() { - Some(module_def_id) => data.scope.declarations().any(|it| it == module_def_id), - None => false, + let is_pub_or_explicit = match vis { + Visibility::Module(_, VisibilityExplicity::Explicit) => { + cov_mark::hit!(explicit_private_imports); + true + } + Visibility::Module(_, VisibilityExplicity::Implicit) => { + cov_mark::hit!(discount_private_imports); + false + } + Visibility::Public => true, }; - // Ignore private imports. these could be used if we are + // Ignore private imports unless they are explicit. these could be used if we are // in a submodule of this module, but that's usually not // what the user wants; and if this module can import // the item and we're a submodule of it, so can we. // Also this keeps the cached data smaller. - if !is_private || is_original_def { + if is_pub_or_explicit || declared { locations.push((module, name.clone())); } } } // Descend into all modules visible from `from`. - for (ty, vis) in data.scope.types() { - if let ModuleDefId::ModuleId(module) = ty { - if vis.is_visible_from(db, from) { - worklist.push(module); - } + for (module, vis) in data.scope.modules_in_scope() { + if vis.is_visible_from(db, from) { + worklist.push(module); } } } @@ -625,16 +615,14 @@ mod tests { .expect("path does not resolve to a type"); let found_path = find_path_inner( - &db, + FindPathCtx { prefer_no_std: false, db: &db, prefixed: prefix_kind, prefer_prelude }, ItemInNs::Types(resolved), module, - prefix_kind, - false, - prefer_prelude, ); assert_eq!(found_path, Some(mod_path), "on kind: {prefix_kind:?}"); } + #[track_caller] fn check_found_path( ra_fixture: &str, unprefixed: &str, @@ -1004,6 +992,7 @@ pub use crate::foo::bar::S; #[test] fn discount_private_imports() { + cov_mark::check!(discount_private_imports); check_found_path( r#" //- /main.rs @@ -1021,6 +1010,47 @@ $0 ); } + #[test] + fn explicit_private_imports_crate() { + cov_mark::check!(explicit_private_imports); + check_found_path( + r#" +//- /main.rs +mod foo; +pub mod bar { pub struct S; } +pub(crate) use bar::S; +//- /foo.rs +$0 + "#, + "crate::S", + "crate::S", + "crate::S", + "crate::S", + ); + } + + #[test] + fn explicit_private_imports() { + cov_mark::check!(explicit_private_imports); + check_found_path( + r#" +//- /main.rs +pub mod bar { + mod foo; + pub mod baz { pub struct S; } + pub(self) use baz::S; +} + +//- /bar/foo.rs +$0 + "#, + "super::S", + "super::S", + "crate::bar::S", + "super::S", + ); + } + #[test] fn import_cycle() { check_found_path( diff --git a/crates/hir-def/src/generics.rs b/crates/hir-def/src/generics.rs index f5324f052e592..6cb9b8448d14f 100644 --- a/crates/hir-def/src/generics.rs +++ b/crates/hir-def/src/generics.rs @@ -107,11 +107,11 @@ impl TypeOrConstParamData { impl_from!(TypeParamData, ConstParamData for TypeOrConstParamData); /// Data about the generic parameters of a function, struct, impl, etc. -#[derive(Clone, PartialEq, Eq, Debug, Default, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct GenericParams { pub type_or_consts: Arena, pub lifetimes: Arena, - pub where_predicates: Vec, + pub where_predicates: Box<[WherePredicate]>, } /// A single predicate from a where clause, i.e. `where Type: Trait`. Combined @@ -142,109 +142,14 @@ pub enum WherePredicateTypeTarget { TypeOrConstParam(LocalTypeOrConstParamId), } -impl GenericParams { - /// Iterator of type_or_consts field - pub fn iter( - &self, - ) -> impl DoubleEndedIterator, &TypeOrConstParamData)> { - self.type_or_consts.iter() - } - - pub(crate) fn generic_params_query( - db: &dyn DefDatabase, - def: GenericDefId, - ) -> Interned { - let _p = profile::span("generic_params_query"); - - let krate = def.module(db).krate; - let cfg_options = db.crate_graph(); - let cfg_options = &cfg_options[krate].cfg_options; - - // Returns the generic parameters that are enabled under the current `#[cfg]` options - let enabled_params = |params: &Interned, item_tree: &ItemTree| { - let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options); - - // In the common case, no parameters will by disabled by `#[cfg]` attributes. - // Therefore, make a first pass to check if all parameters are enabled and, if so, - // clone the `Interned` instead of recreating an identical copy. - let all_type_or_consts_enabled = - params.type_or_consts.iter().all(|(idx, _)| enabled(idx.into())); - let all_lifetimes_enabled = params.lifetimes.iter().all(|(idx, _)| enabled(idx.into())); - - if all_type_or_consts_enabled && all_lifetimes_enabled { - params.clone() - } else { - Interned::new(GenericParams { - type_or_consts: all_type_or_consts_enabled - .then(|| params.type_or_consts.clone()) - .unwrap_or_else(|| { - params - .type_or_consts - .iter() - .filter_map(|(idx, param)| { - enabled(idx.into()).then(|| param.clone()) - }) - .collect() - }), - lifetimes: all_lifetimes_enabled - .then(|| params.lifetimes.clone()) - .unwrap_or_else(|| { - params - .lifetimes - .iter() - .filter_map(|(idx, param)| { - enabled(idx.into()).then(|| param.clone()) - }) - .collect() - }), - where_predicates: params.where_predicates.clone(), - }) - } - }; - macro_rules! id_to_generics { - ($id:ident) => {{ - let id = $id.lookup(db).id; - let tree = id.item_tree(db); - let item = &tree[id.value]; - enabled_params(&item.generic_params, &tree) - }}; - } - - match def { - GenericDefId::FunctionId(id) => { - let loc = id.lookup(db); - let tree = loc.id.item_tree(db); - let item = &tree[loc.id.value]; - - let enabled_params = enabled_params(&item.explicit_generic_params, &tree); - let mut generic_params = GenericParams::clone(&enabled_params); - - let module = loc.container.module(db); - let func_data = db.function_data(id); - - // Don't create an `Expander` if not needed since this - // could cause a reparse after the `ItemTree` has been created due to the spanmap. - let mut expander = - Lazy::new(|| (module.def_map(db), Expander::new(db, loc.id.file_id(), module))); - for param in func_data.params.iter() { - generic_params.fill_implicit_impl_trait_args(db, &mut expander, param); - } - - Interned::new(generic_params) - } - GenericDefId::AdtId(AdtId::StructId(id)) => id_to_generics!(id), - GenericDefId::AdtId(AdtId::EnumId(id)) => id_to_generics!(id), - GenericDefId::AdtId(AdtId::UnionId(id)) => id_to_generics!(id), - GenericDefId::TraitId(id) => id_to_generics!(id), - GenericDefId::TraitAliasId(id) => id_to_generics!(id), - GenericDefId::TypeAliasId(id) => id_to_generics!(id), - GenericDefId::ImplId(id) => id_to_generics!(id), - GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => { - Interned::new(GenericParams::default()) - } - } - } +#[derive(Clone, Default)] +pub(crate) struct GenericParamsCollector { + pub(crate) type_or_consts: Arena, + lifetimes: Arena, + where_predicates: Vec, +} +impl GenericParamsCollector { pub(crate) fn fill( &mut self, lower_ctx: &LowerCtx<'_>, @@ -444,11 +349,131 @@ impl GenericParams { }); } - pub(crate) fn shrink_to_fit(&mut self) { - let Self { lifetimes, type_or_consts: types, where_predicates } = self; + pub(crate) fn finish(self) -> GenericParams { + let Self { mut lifetimes, mut type_or_consts, where_predicates } = self; lifetimes.shrink_to_fit(); - types.shrink_to_fit(); - where_predicates.shrink_to_fit(); + type_or_consts.shrink_to_fit(); + GenericParams { + type_or_consts, + lifetimes, + where_predicates: where_predicates.into_boxed_slice(), + } + } +} + +impl GenericParams { + /// Iterator of type_or_consts field + pub fn iter( + &self, + ) -> impl DoubleEndedIterator, &TypeOrConstParamData)> { + self.type_or_consts.iter() + } + + pub(crate) fn generic_params_query( + db: &dyn DefDatabase, + def: GenericDefId, + ) -> Interned { + let _p = profile::span("generic_params_query"); + + let krate = def.module(db).krate; + let cfg_options = db.crate_graph(); + let cfg_options = &cfg_options[krate].cfg_options; + + // Returns the generic parameters that are enabled under the current `#[cfg]` options + let enabled_params = |params: &Interned, item_tree: &ItemTree| { + let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options); + + // In the common case, no parameters will by disabled by `#[cfg]` attributes. + // Therefore, make a first pass to check if all parameters are enabled and, if so, + // clone the `Interned` instead of recreating an identical copy. + let all_type_or_consts_enabled = + params.type_or_consts.iter().all(|(idx, _)| enabled(idx.into())); + let all_lifetimes_enabled = params.lifetimes.iter().all(|(idx, _)| enabled(idx.into())); + + if all_type_or_consts_enabled && all_lifetimes_enabled { + params.clone() + } else { + Interned::new(GenericParams { + type_or_consts: all_type_or_consts_enabled + .then(|| params.type_or_consts.clone()) + .unwrap_or_else(|| { + params + .type_or_consts + .iter() + .filter_map(|(idx, param)| { + enabled(idx.into()).then(|| param.clone()) + }) + .collect() + }), + lifetimes: all_lifetimes_enabled + .then(|| params.lifetimes.clone()) + .unwrap_or_else(|| { + params + .lifetimes + .iter() + .filter_map(|(idx, param)| { + enabled(idx.into()).then(|| param.clone()) + }) + .collect() + }), + where_predicates: params.where_predicates.clone(), + }) + } + }; + macro_rules! id_to_generics { + ($id:ident) => {{ + let id = $id.lookup(db).id; + let tree = id.item_tree(db); + let item = &tree[id.value]; + enabled_params(&item.generic_params, &tree) + }}; + } + + match def { + GenericDefId::FunctionId(id) => { + let loc = id.lookup(db); + let tree = loc.id.item_tree(db); + let item = &tree[loc.id.value]; + + let enabled_params = enabled_params(&item.explicit_generic_params, &tree); + + let module = loc.container.module(db); + let func_data = db.function_data(id); + if func_data.params.is_empty() { + enabled_params + } else { + let mut generic_params = GenericParamsCollector { + type_or_consts: enabled_params.type_or_consts.clone(), + lifetimes: enabled_params.lifetimes.clone(), + where_predicates: enabled_params.where_predicates.clone().into(), + }; + + // Don't create an `Expander` if not needed since this + // could cause a reparse after the `ItemTree` has been created due to the spanmap. + let mut expander = Lazy::new(|| { + (module.def_map(db), Expander::new(db, loc.id.file_id(), module)) + }); + for param in func_data.params.iter() { + generic_params.fill_implicit_impl_trait_args(db, &mut expander, param); + } + Interned::new(generic_params.finish()) + } + } + GenericDefId::AdtId(AdtId::StructId(id)) => id_to_generics!(id), + GenericDefId::AdtId(AdtId::EnumId(id)) => id_to_generics!(id), + GenericDefId::AdtId(AdtId::UnionId(id)) => id_to_generics!(id), + GenericDefId::TraitId(id) => id_to_generics!(id), + GenericDefId::TraitAliasId(id) => id_to_generics!(id), + GenericDefId::TypeAliasId(id) => id_to_generics!(id), + GenericDefId::ImplId(id) => id_to_generics!(id), + GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => { + Interned::new(GenericParams { + type_or_consts: Default::default(), + lifetimes: Default::default(), + where_predicates: Default::default(), + }) + } + } } pub fn find_type_by_name(&self, name: &Name, parent: GenericDefId) -> Option { diff --git a/crates/hir-def/src/hir/format_args.rs b/crates/hir-def/src/hir/format_args.rs index 7fc33abc7c9a1..c0d1738b5048e 100644 --- a/crates/hir-def/src/hir/format_args.rs +++ b/crates/hir-def/src/hir/format_args.rs @@ -2,7 +2,7 @@ use std::mem; use hir_expand::name::Name; -use rustc_dependencies::parse_format as parse; +use rustc_parse_format as parse; use stdx::TupleExt; use syntax::{ ast::{self, IsString}, diff --git a/crates/hir-def/src/hir/type_ref.rs b/crates/hir-def/src/hir/type_ref.rs index 75adf21abdcb2..935a8ebad165b 100644 --- a/crates/hir-def/src/hir/type_ref.rs +++ b/crates/hir-def/src/hir/type_ref.rs @@ -116,8 +116,7 @@ pub enum TypeRef { Path(Path), RawPtr(Box, Mutability), Reference(Box, Option, Mutability), - // FIXME: for full const generics, the latter element (length) here is going to have to be an - // expression that is further lowered later in hir_ty. + // FIXME: This should be Array(Box, Ast), Array(Box, ConstRef), Slice(Box), /// A fn pointer. Last element of the vector is the return type. diff --git a/crates/hir-def/src/item_scope.rs b/crates/hir-def/src/item_scope.rs index 4902f24e2e3ab..168ee4acffbef 100644 --- a/crates/hir-def/src/item_scope.rs +++ b/crates/hir-def/src/item_scope.rs @@ -15,9 +15,11 @@ use stdx::format_to; use syntax::ast; use crate::{ - db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ConstId, - ExternCrateId, HasModule, ImplId, LocalModuleId, Lookup, MacroId, ModuleDefId, ModuleId, - TraitId, UseId, + db::DefDatabase, + per_ns::PerNs, + visibility::{Visibility, VisibilityExplicity}, + AdtId, BuiltinType, ConstId, ExternCrateId, HasModule, ImplId, LocalModuleId, Lookup, MacroId, + ModuleDefId, ModuleId, TraitId, UseId, }; #[derive(Debug, Default)] @@ -105,7 +107,7 @@ pub struct ItemScope { /// The attribute macro invocations in this scope. attr_macros: FxHashMap, MacroCallId>, /// The macro invocations in this scope. - pub macro_invocations: FxHashMap, MacroCallId>, + macro_invocations: FxHashMap, MacroCallId>, /// The derive macro invocations in this scope, keyed by the owner item over the actual derive attributes /// paired with the derive macro invocations for the specific attribute. derive_macros: FxHashMap, SmallVec<[DeriveMacroInvocation; 1]>>, @@ -145,8 +147,8 @@ impl ItemScope { .chain(self.values.keys()) .chain(self.macros.keys()) .chain(self.unresolved.iter()) - .unique() .sorted() + .dedup() .map(move |name| (name, self.get(name))) } @@ -157,8 +159,8 @@ impl ItemScope { .filter_map(ImportOrExternCrate::into_import) .chain(self.use_imports_values.keys().copied()) .chain(self.use_imports_macros.keys().copied()) - .unique() .sorted() + .dedup() } pub fn fully_resolve_import(&self, db: &dyn DefDatabase, mut import: ImportId) -> PerNs { @@ -234,20 +236,37 @@ impl ItemScope { self.impls.iter().copied() } - pub fn values( - &self, - ) -> impl Iterator + ExactSizeIterator + '_ { - self.values.values().copied().map(|(a, b, _)| (a, b)) + pub(crate) fn modules_in_scope(&self) -> impl Iterator + '_ { + self.types.values().copied().filter_map(|(def, vis, _)| match def { + ModuleDefId::ModuleId(module) => Some((module, vis)), + _ => None, + }) } - pub(crate) fn types( - &self, - ) -> impl Iterator + ExactSizeIterator + '_ { - self.types.values().copied().map(|(def, vis, _)| (def, vis)) - } + pub fn unnamed_consts<'a>( + &'a self, + db: &'a dyn DefDatabase, + ) -> impl Iterator + 'a { + // FIXME: Also treat consts named `_DERIVE_*` as unnamed, since synstructure generates those. + // Should be removed once synstructure stops doing that. + let synstructure_hack_consts = self.values.values().filter_map(|(item, _, _)| match item { + &ModuleDefId::ConstId(id) => { + let loc = id.lookup(db); + let item_tree = loc.id.item_tree(db); + if item_tree[loc.id.value] + .name + .as_ref() + .map_or(false, |n| n.to_smol_str().starts_with("_DERIVE_")) + { + Some(id) + } else { + None + } + } + _ => None, + }); - pub fn unnamed_consts(&self) -> impl Iterator + '_ { - self.unnamed_consts.iter().copied() + self.unnamed_consts.iter().copied().chain(synstructure_hack_consts) } /// Iterate over all module scoped macros @@ -274,21 +293,18 @@ impl ItemScope { } /// XXX: this is O(N) rather than O(1), try to not introduce new usages. - pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> { + pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility, /*declared*/ bool)> { match item { - ItemInNs::Macros(def) => self - .macros - .iter() - .find_map(|(name, &(other_def, vis, _))| (other_def == def).then_some((name, vis))), - ItemInNs::Types(def) => self - .types - .iter() - .find_map(|(name, &(other_def, vis, _))| (other_def == def).then_some((name, vis))), - - ItemInNs::Values(def) => self - .values - .iter() - .find_map(|(name, &(other_def, vis, _))| (other_def == def).then_some((name, vis))), + ItemInNs::Macros(def) => self.macros.iter().find_map(|(name, &(other_def, vis, i))| { + (other_def == def).then_some((name, vis, i.is_none())) + }), + ItemInNs::Types(def) => self.types.iter().find_map(|(name, &(other_def, vis, i))| { + (other_def == def).then_some((name, vis, i.is_none())) + }), + + ItemInNs::Values(def) => self.values.iter().find_map(|(name, &(other_def, vis, i))| { + (other_def == def).then_some((name, vis, i.is_none())) + }), } } @@ -316,6 +332,10 @@ impl ItemScope { }), ) } + + pub(crate) fn macro_invoc(&self, call: AstId) -> Option { + self.macro_invocations.get(&call).copied() + } } impl ItemScope { @@ -624,18 +644,17 @@ impl ItemScope { pub(crate) fn censor_non_proc_macros(&mut self, this_module: ModuleId) { self.types .values_mut() - .map(|(def, vis, _)| (def, vis)) - .chain(self.values.values_mut().map(|(def, vis, _)| (def, vis))) - .map(|(_, v)| v) + .map(|(_, vis, _)| vis) + .chain(self.values.values_mut().map(|(_, vis, _)| vis)) .chain(self.unnamed_trait_imports.values_mut().map(|(vis, _)| vis)) - .for_each(|vis| *vis = Visibility::Module(this_module)); + .for_each(|vis| *vis = Visibility::Module(this_module, VisibilityExplicity::Implicit)); for (mac, vis, import) in self.macros.values_mut() { if matches!(mac, MacroId::ProcMacroId(_) if import.is_none()) { continue; } - *vis = Visibility::Module(this_module); + *vis = Visibility::Module(this_module, VisibilityExplicity::Implicit); } } diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index 20e4e44339e9a..82ea5ffeba17c 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -69,7 +69,7 @@ use crate::{ generics::{GenericParams, LifetimeParamData, TypeOrConstParamData}, path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind}, type_ref::{Mutability, TraitRef, TypeBound, TypeRef}, - visibility::RawVisibility, + visibility::{RawVisibility, VisibilityExplicity}, BlockId, Lookup, }; @@ -78,8 +78,9 @@ pub struct RawVisibilityId(u32); impl RawVisibilityId { pub const PUB: Self = RawVisibilityId(u32::max_value()); - pub const PRIV: Self = RawVisibilityId(u32::max_value() - 1); - pub const PUB_CRATE: Self = RawVisibilityId(u32::max_value() - 2); + pub const PRIV_IMPLICIT: Self = RawVisibilityId(u32::max_value() - 1); + pub const PRIV_EXPLICIT: Self = RawVisibilityId(u32::max_value() - 2); + pub const PUB_CRATE: Self = RawVisibilityId(u32::max_value() - 3); } impl fmt::Debug for RawVisibilityId { @@ -87,7 +88,7 @@ impl fmt::Debug for RawVisibilityId { let mut f = f.debug_tuple("RawVisibilityId"); match *self { Self::PUB => f.field(&"pub"), - Self::PRIV => f.field(&"pub(self)"), + Self::PRIV_IMPLICIT | Self::PRIV_EXPLICIT => f.field(&"pub(self)"), Self::PUB_CRATE => f.field(&"pub(crate)"), _ => f.field(&self.0), }; @@ -249,19 +250,30 @@ impl ItemVisibilities { fn alloc(&mut self, vis: RawVisibility) -> RawVisibilityId { match &vis { RawVisibility::Public => RawVisibilityId::PUB, - RawVisibility::Module(path) if path.segments().is_empty() => match &path.kind { - PathKind::Super(0) => RawVisibilityId::PRIV, - PathKind::Crate => RawVisibilityId::PUB_CRATE, - _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()), - }, + RawVisibility::Module(path, explicitiy) if path.segments().is_empty() => { + match (&path.kind, explicitiy) { + (PathKind::Super(0), VisibilityExplicity::Explicit) => { + RawVisibilityId::PRIV_EXPLICIT + } + (PathKind::Super(0), VisibilityExplicity::Implicit) => { + RawVisibilityId::PRIV_IMPLICIT + } + (PathKind::Crate, _) => RawVisibilityId::PUB_CRATE, + _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()), + } + } _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()), } } } static VIS_PUB: RawVisibility = RawVisibility::Public; -static VIS_PRIV: RawVisibility = RawVisibility::Module(ModPath::from_kind(PathKind::Super(0))); -static VIS_PUB_CRATE: RawVisibility = RawVisibility::Module(ModPath::from_kind(PathKind::Crate)); +static VIS_PRIV_IMPLICIT: RawVisibility = + RawVisibility::Module(ModPath::from_kind(PathKind::Super(0)), VisibilityExplicity::Implicit); +static VIS_PRIV_EXPLICIT: RawVisibility = + RawVisibility::Module(ModPath::from_kind(PathKind::Super(0)), VisibilityExplicity::Explicit); +static VIS_PUB_CRATE: RawVisibility = + RawVisibility::Module(ModPath::from_kind(PathKind::Crate), VisibilityExplicity::Explicit); #[derive(Default, Debug, Eq, PartialEq)] struct ItemTreeData { @@ -540,7 +552,8 @@ impl Index for ItemTree { type Output = RawVisibility; fn index(&self, index: RawVisibilityId) -> &Self::Output { match index { - RawVisibilityId::PRIV => &VIS_PRIV, + RawVisibilityId::PRIV_IMPLICIT => &VIS_PRIV_IMPLICIT, + RawVisibilityId::PRIV_EXPLICIT => &VIS_PRIV_EXPLICIT, RawVisibilityId::PUB => &VIS_PUB, RawVisibilityId::PUB_CRATE => &VIS_PUB_CRATE, _ => &self.data().vis.arena[Idx::from_raw(index.0.into())], diff --git a/crates/hir-def/src/item_tree/lower.rs b/crates/hir-def/src/item_tree/lower.rs index 8e2fafe81b50f..6343b43a016b2 100644 --- a/crates/hir-def/src/item_tree/lower.rs +++ b/crates/hir-def/src/item_tree/lower.rs @@ -6,7 +6,7 @@ use hir_expand::{ast_id_map::AstIdMap, span_map::SpanMapRef, HirFileId}; use syntax::ast::{self, HasModuleItem, HasTypeBounds}; use crate::{ - generics::{GenericParams, TypeParamData, TypeParamProvenance}, + generics::{GenericParams, GenericParamsCollector, TypeParamData, TypeParamProvenance}, type_ref::{LifetimeRef, TraitBoundModifier, TraitRef}, LocalLifetimeParamId, LocalTypeOrConstParamId, }; @@ -386,17 +386,16 @@ impl<'a> Ctx<'a> { flags |= FnFlags::HAS_UNSAFE_KW; } - let mut res = Function { + let res = Function { name, visibility, - explicit_generic_params: Interned::new(GenericParams::default()), + explicit_generic_params: self.lower_generic_params(HasImplicitSelf::No, func), abi, params, ret_type: Interned::new(ret_type), ast_id, flags, }; - res.explicit_generic_params = self.lower_generic_params(HasImplicitSelf::No, func); Some(id(self.data().functions.alloc(res))) } @@ -604,7 +603,7 @@ impl<'a> Ctx<'a> { has_implicit_self: HasImplicitSelf, node: &dyn ast::HasGenericParams, ) -> Interned { - let mut generics = GenericParams::default(); + let mut generics = GenericParamsCollector::default(); if let HasImplicitSelf::Yes(bounds) = has_implicit_self { // Traits and trait aliases get the Self type as an implicit first type parameter. @@ -642,8 +641,7 @@ impl<'a> Ctx<'a> { }; generics.fill(&self.body_ctx, node, add_param_attrs); - generics.shrink_to_fit(); - Interned::new(generics) + Interned::new(generics.finish()) } fn lower_type_bounds(&mut self, node: &dyn ast::HasTypeBounds) -> Box<[Interned]> { diff --git a/crates/hir-def/src/item_tree/pretty.rs b/crates/hir-def/src/item_tree/pretty.rs index 6d92fce07272f..8693b9a98c9d9 100644 --- a/crates/hir-def/src/item_tree/pretty.rs +++ b/crates/hir-def/src/item_tree/pretty.rs @@ -104,7 +104,9 @@ impl Printer<'_> { fn print_visibility(&mut self, vis: RawVisibilityId) { match &self.tree[vis] { - RawVisibility::Module(path) => w!(self, "pub({}) ", path.display(self.db.upcast())), + RawVisibility::Module(path, _expl) => { + w!(self, "pub({}) ", path.display(self.db.upcast())) + } RawVisibility::Public => w!(self, "pub "), }; } diff --git a/crates/hir-def/src/lang_item.rs b/crates/hir-def/src/lang_item.rs index 1ae6bd4c91949..66e0d2cc346bc 100644 --- a/crates/hir-def/src/lang_item.rs +++ b/crates/hir-def/src/lang_item.rs @@ -87,7 +87,10 @@ impl LangItems { } /// Salsa query. This will look for lang items in a specific crate. - pub(crate) fn crate_lang_items_query(db: &dyn DefDatabase, krate: CrateId) -> Arc { + pub(crate) fn crate_lang_items_query( + db: &dyn DefDatabase, + krate: CrateId, + ) -> Option> { let _p = profile::span("crate_lang_items_query"); let mut lang_items = LangItems::default(); @@ -150,7 +153,11 @@ impl LangItems { } } - Arc::new(lang_items) + if lang_items.items.is_empty() { + None + } else { + Some(Arc::new(lang_items)) + } } /// Salsa query. Look for a lang item, starting from the specified crate and recursively @@ -161,9 +168,9 @@ impl LangItems { item: LangItem, ) -> Option { let _p = profile::span("lang_item_query"); - let lang_items = db.crate_lang_items(start_crate); - let start_crate_target = lang_items.items.get(&item); - if let Some(&target) = start_crate_target { + if let Some(target) = + db.crate_lang_items(start_crate).and_then(|it| it.items.get(&item).copied()) + { return Some(target); } db.crate_graph()[start_crate] diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index 250d7b677b5dd..aa84ccaee6eee 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -10,10 +10,17 @@ #![warn(rust_2018_idioms, unused_lifetimes)] #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] -#[allow(unused)] -macro_rules! eprintln { - ($($tt:tt)*) => { stdx::eprintln!($($tt)*) }; -} +#[cfg(feature = "in-rust-tree")] +extern crate rustc_parse_format; + +#[cfg(not(feature = "in-rust-tree"))] +extern crate ra_ap_rustc_parse_format as rustc_parse_format; + +#[cfg(feature = "in-rust-tree")] +extern crate rustc_abi; + +#[cfg(not(feature = "in-rust-tree"))] +extern crate ra_ap_rustc_abi as rustc_abi; pub mod db; @@ -49,7 +56,7 @@ pub mod visibility; pub mod find_path; pub mod import_map; -pub use rustc_dependencies::abi as layout; +pub use rustc_abi as layout; use triomphe::Arc; #[cfg(test)] diff --git a/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs b/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs index abd84c6a46de5..553c0b795336d 100644 --- a/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs +++ b/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs @@ -16,13 +16,12 @@ struct Foo; #[derive(Copy)] struct Foo; -impl < > core::marker::Copy for Foo< > where {}"#]], +impl < > $crate::marker::Copy for Foo< > where {}"#]], ); } #[test] fn test_copy_expand_in_core() { - cov_mark::check!(test_copy_expand_in_core); check( r#" //- /lib.rs crate:core @@ -41,7 +40,7 @@ macro Copy {} #[derive(Copy)] struct Foo; -impl < > crate ::marker::Copy for Foo< > where {}"#]], +impl < > $crate::marker::Copy for Foo< > where {}"#]], ); } @@ -57,7 +56,7 @@ struct Foo; #[derive(Copy)] struct Foo; -impl core::marker::Copy for Foo where {}"#]], +impl $crate::marker::Copy for Foo where {}"#]], ); } @@ -74,7 +73,7 @@ struct Foo; #[derive(Copy)] struct Foo; -impl core::marker::Copy for Foo where {}"#]], +impl $crate::marker::Copy for Foo where {}"#]], ); } @@ -98,7 +97,7 @@ enum Command { Jump, } -impl core::clone::Clone for Command where { +impl $crate::clone::Clone for Command where { fn clone(&self ) -> Self { match self { Command::Move { @@ -158,7 +157,7 @@ where generic: Vec, } -impl core::clone::Clone for Foo where T: Trait, T::InFieldShorthand: core::clone::Clone, T::InGenericArg: core::clone::Clone, { +impl $crate::clone::Clone for Foo where T: Trait, T::InFieldShorthand: $crate::clone::Clone, T::InGenericArg: $crate::clone::Clone, { fn clone(&self ) -> Self { match self { Foo { @@ -186,7 +185,7 @@ struct Foo(u32); #[derive(Clone)] struct Foo(u32); -impl core::clone::Clone for Foo where { +impl $crate::clone::Clone for Foo where { fn clone(&self ) -> Self { match self { Foo(f0, )=>Foo(f0.clone(), ), @@ -226,14 +225,14 @@ enum Bar { Bar, } -impl < > core::default::Default for Foo< > where { +impl < > $crate::default::Default for Foo< > where { fn default() -> Self { Foo { - field1: core::default::Default::default(), field2: core::default::Default::default(), + field1: $crate::default::Default::default(), field2: $crate::default::Default::default(), } } } -impl < > core::default::Default for Bar< > where { +impl < > $crate::default::Default for Bar< > where { fn default() -> Self { Bar::Bar } @@ -261,7 +260,7 @@ enum Command { Jump, } -impl < > core::cmp::PartialEq for Command< > where { +impl < > $crate::cmp::PartialEq for Command< > where { fn eq(&self , other: &Self ) -> bool { match (self , other) { (Command::Move { @@ -274,7 +273,7 @@ impl < > core::cmp::PartialEq for Command< > where { } } } -impl < > core::cmp::Eq for Command< > where {}"#]], +impl < > $crate::cmp::Eq for Command< > where {}"#]], ); } @@ -299,7 +298,7 @@ enum Command { Jump, } -impl < > core::cmp::PartialEq for Command< > where { +impl < > $crate::cmp::PartialEq for Command< > where { fn eq(&self , other: &Self ) -> bool { match (self , other) { (Command::Move { @@ -312,7 +311,7 @@ impl < > core::cmp::PartialEq for Command< > where { } } } -impl < > core::cmp::Eq for Command< > where {}"#]], +impl < > $crate::cmp::Eq for Command< > where {}"#]], ); } @@ -336,10 +335,10 @@ enum Command { Jump, } -impl < > core::cmp::PartialOrd for Command< > where { - fn partial_cmp(&self , other: &Self ) -> core::option::Option::Option { - match core::intrinsics::discriminant_value(self ).partial_cmp(&core::intrinsics::discriminant_value(other)) { - core::option::Option::Some(core::cmp::Ordering::Equal)=> { +impl < > $crate::cmp::PartialOrd for Command< > where { + fn partial_cmp(&self , other: &Self ) -> $crate::option::Option::Option<$crate::cmp::Ordering> { + match $crate::intrinsics::discriminant_value(self ).partial_cmp(&$crate::intrinsics::discriminant_value(other)) { + $crate::option::Option::Some($crate::cmp::Ordering::Equal)=> { match (self , other) { (Command::Move { x: x_self, y: y_self, @@ -348,10 +347,10 @@ impl < > core::cmp::PartialOrd for Command< > where { x: x_other, y: y_other, } )=>match x_self.partial_cmp(&x_other) { - core::option::Option::Some(core::cmp::Ordering::Equal)=> { + $crate::option::Option::Some($crate::cmp::Ordering::Equal)=> { match y_self.partial_cmp(&y_other) { - core::option::Option::Some(core::cmp::Ordering::Equal)=> { - core::option::Option::Some(core::cmp::Ordering::Equal) + $crate::option::Option::Some($crate::cmp::Ordering::Equal)=> { + $crate::option::Option::Some($crate::cmp::Ordering::Equal) } c=>return c, } @@ -359,22 +358,22 @@ impl < > core::cmp::PartialOrd for Command< > where { c=>return c, } , (Command::Do(f0_self, ), Command::Do(f0_other, ))=>match f0_self.partial_cmp(&f0_other) { - core::option::Option::Some(core::cmp::Ordering::Equal)=> { - core::option::Option::Some(core::cmp::Ordering::Equal) + $crate::option::Option::Some($crate::cmp::Ordering::Equal)=> { + $crate::option::Option::Some($crate::cmp::Ordering::Equal) } c=>return c, } - , (Command::Jump, Command::Jump)=>core::option::Option::Some(core::cmp::Ordering::Equal), _unused=>core::option::Option::Some(core::cmp::Ordering::Equal) + , (Command::Jump, Command::Jump)=>$crate::option::Option::Some($crate::cmp::Ordering::Equal), _unused=>$crate::option::Option::Some($crate::cmp::Ordering::Equal) } } c=>return c, } } } -impl < > core::cmp::Ord for Command< > where { - fn cmp(&self , other: &Self ) -> core::cmp::Ordering { - match core::intrinsics::discriminant_value(self ).cmp(&core::intrinsics::discriminant_value(other)) { - core::cmp::Ordering::Equal=> { +impl < > $crate::cmp::Ord for Command< > where { + fn cmp(&self , other: &Self ) -> $crate::cmp::Ordering { + match $crate::intrinsics::discriminant_value(self ).cmp(&$crate::intrinsics::discriminant_value(other)) { + $crate::cmp::Ordering::Equal=> { match (self , other) { (Command::Move { x: x_self, y: y_self, @@ -383,10 +382,10 @@ impl < > core::cmp::Ord for Command< > where { x: x_other, y: y_other, } )=>match x_self.cmp(&x_other) { - core::cmp::Ordering::Equal=> { + $crate::cmp::Ordering::Equal=> { match y_self.cmp(&y_other) { - core::cmp::Ordering::Equal=> { - core::cmp::Ordering::Equal + $crate::cmp::Ordering::Equal=> { + $crate::cmp::Ordering::Equal } c=>return c, } @@ -394,12 +393,12 @@ impl < > core::cmp::Ord for Command< > where { c=>return c, } , (Command::Do(f0_self, ), Command::Do(f0_other, ))=>match f0_self.cmp(&f0_other) { - core::cmp::Ordering::Equal=> { - core::cmp::Ordering::Equal + $crate::cmp::Ordering::Equal=> { + $crate::cmp::Ordering::Equal } c=>return c, } - , (Command::Jump, Command::Jump)=>core::cmp::Ordering::Equal, _unused=>core::cmp::Ordering::Equal + , (Command::Jump, Command::Jump)=>$crate::cmp::Ordering::Equal, _unused=>$crate::cmp::Ordering::Equal } } c=>return c, @@ -433,8 +432,8 @@ struct Foo { z: (i32, u64), } -impl < > core::hash::Hash for Foo< > where { - fn hash(&self , ra_expand_state: &mut H) { +impl < > $crate::hash::Hash for Foo< > where { + fn hash(&self , ra_expand_state: &mut H) { match self { Foo { x: x, y: y, z: z, @@ -471,9 +470,9 @@ enum Command { Jump, } -impl < > core::hash::Hash for Command< > where { - fn hash(&self , ra_expand_state: &mut H) { - core::mem::discriminant(self ).hash(ra_expand_state); +impl < > $crate::hash::Hash for Command< > where { + fn hash(&self , ra_expand_state: &mut H) { + $crate::mem::discriminant(self ).hash(ra_expand_state); match self { Command::Move { x: x, y: y, @@ -517,8 +516,8 @@ enum Command { Jump, } -impl < > core::fmt::Debug for Command< > where { - fn fmt(&self , f: &mut core::fmt::Formatter) -> core::fmt::Result { +impl < > $crate::fmt::Debug for Command< > where { + fn fmt(&self , f: &mut $crate::fmt::Formatter) -> $crate::fmt::Result { match self { Command::Move { x: x, y: y, diff --git a/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs index d4798f4507d12..4690ca5d363cd 100644 --- a/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs +++ b/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs @@ -136,7 +136,7 @@ fn main() { option_env!("TEST_ENV_VAR"); } #[rustc_builtin_macro] macro_rules! option_env {() => {}} -fn main() { ::core::option::Option::None:: < &str>; } +fn main() { $crate::option::Option::None:: < &str>; } "#]], ); } diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs index 52a981fd19ebc..53644f58efc44 100644 --- a/crates/hir-def/src/nameres.rs +++ b/crates/hir-def/src/nameres.rs @@ -79,7 +79,7 @@ use crate::{ nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode}, path::ModPath, per_ns::PerNs, - visibility::Visibility, + visibility::{Visibility, VisibilityExplicity}, AstId, BlockId, BlockLoc, CrateRootModuleId, ExternCrateId, FunctionId, LocalModuleId, Lookup, MacroExpander, MacroId, ModuleId, ProcMacroId, UseId, }; @@ -332,7 +332,10 @@ impl DefMap { // NB: we use `None` as block here, which would be wrong for implicit // modules declared by blocks with items. At the moment, we don't use // this visibility for anything outside IDE, so that's probably OK. - let visibility = Visibility::Module(ModuleId { krate, local_id, block: None }); + let visibility = Visibility::Module( + ModuleId { krate, local_id, block: None }, + VisibilityExplicity::Implicit, + ); let module_data = ModuleData::new( ModuleOrigin::BlockExpr { block: block.ast_id, id: block_id }, visibility, diff --git a/crates/hir-def/src/nameres/path_resolution.rs b/crates/hir-def/src/nameres/path_resolution.rs index be3438e427dba..389dabdbc8678 100644 --- a/crates/hir-def/src/nameres/path_resolution.rs +++ b/crates/hir-def/src/nameres/path_resolution.rs @@ -87,7 +87,7 @@ impl DefMap { within_impl: bool, ) -> Option { let mut vis = match visibility { - RawVisibility::Module(path) => { + RawVisibility::Module(path, explicity) => { let (result, remaining) = self.resolve_path(db, original_module, path, BuiltinShadowMode::Module, None); if remaining.is_some() { @@ -95,7 +95,7 @@ impl DefMap { } let types = result.take_types()?; match types { - ModuleDefId::ModuleId(m) => Visibility::Module(m), + ModuleDefId::ModuleId(m) => Visibility::Module(m, *explicity), // error: visibility needs to refer to module _ => { return None; @@ -108,11 +108,11 @@ impl DefMap { // In block expressions, `self` normally refers to the containing non-block module, and // `super` to its parent (etc.). However, visibilities must only refer to a module in the // DefMap they're written in, so we restrict them when that happens. - if let Visibility::Module(m) = vis { + if let Visibility::Module(m, mv) = vis { // ...unless we're resolving visibility for an associated item in an impl. if self.block_id() != m.block && !within_impl { cov_mark::hit!(adjust_vis_in_block_def_map); - vis = Visibility::Module(self.module_id(Self::ROOT)); + vis = Visibility::Module(self.module_id(Self::ROOT), mv); tracing::debug!("visibility {:?} points outside DefMap, adjusting to {:?}", m, vis); } } diff --git a/crates/hir-def/src/nameres/tests/macros.rs b/crates/hir-def/src/nameres/tests/macros.rs index 48fe43450a710..0f6e64016f18a 100644 --- a/crates/hir-def/src/nameres/tests/macros.rs +++ b/crates/hir-def/src/nameres/tests/macros.rs @@ -1264,6 +1264,54 @@ struct A; ); } +#[test] +fn nested_include() { + check( + r#" +//- minicore: include +//- /lib.rs +include!("out_dir/includes.rs"); + +//- /out_dir/includes.rs +pub mod company_name { + pub mod network { + pub mod v1 { + include!("company_name.network.v1.rs"); + } + } +} +//- /out_dir/company_name.network.v1.rs +pub struct IpAddress { + pub ip_type: &'static str, +} +/// Nested message and enum types in `IpAddress`. +pub mod ip_address { + pub enum IpType { + IpV4(u32), + } +} + +"#, + expect![[r#" + crate + company_name: t + + crate::company_name + network: t + + crate::company_name::network + v1: t + + crate::company_name::network::v1 + IpAddress: t + ip_address: t + + crate::company_name::network::v1::ip_address + IpType: t + "#]], + ); +} + #[test] fn macro_use_imports_all_macro_types() { let db = TestDB::with_files( diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs index 301391516d64e..1d850f721c1f8 100644 --- a/crates/hir-def/src/resolver.rs +++ b/crates/hir-def/src/resolver.rs @@ -242,7 +242,7 @@ impl Resolver { let within_impl = self.scopes().find(|scope| matches!(scope, Scope::ImplDefScope(_))).is_some(); match visibility { - RawVisibility::Module(_) => { + RawVisibility::Module(_, _) => { let (item_map, module) = self.item_scope(); item_map.resolve_visibility(db, module, visibility, within_impl) } diff --git a/crates/hir-def/src/test_db.rs b/crates/hir-def/src/test_db.rs index f4a6b61f7af5e..c992c3c920486 100644 --- a/crates/hir-def/src/test_db.rs +++ b/crates/hir-def/src/test_db.rs @@ -8,7 +8,6 @@ use base_db::{ Upcast, }; use hir_expand::{db::ExpandDatabase, InFile}; -use rustc_hash::FxHashSet; use syntax::{algo, ast, AstNode}; use triomphe::Arc; @@ -76,7 +75,7 @@ impl FileLoader for TestDB { fn resolve_path(&self, path: AnchoredPath<'_>) -> Option { FileLoaderDelegate(self).resolve_path(path) } - fn relevant_crates(&self, file_id: FileId) -> Arc> { + fn relevant_crates(&self, file_id: FileId) -> Arc<[CrateId]> { FileLoaderDelegate(self).relevant_crates(file_id) } } diff --git a/crates/hir-def/src/visibility.rs b/crates/hir-def/src/visibility.rs index 49688c5ee9c27..cd8023f5d7d7d 100644 --- a/crates/hir-def/src/visibility.rs +++ b/crates/hir-def/src/visibility.rs @@ -20,14 +20,14 @@ use crate::{ pub enum RawVisibility { /// `pub(in module)`, `pub(crate)` or `pub(super)`. Also private, which is /// equivalent to `pub(self)`. - Module(ModPath), + Module(ModPath, VisibilityExplicity), /// `pub`. Public, } impl RawVisibility { pub(crate) const fn private() -> RawVisibility { - RawVisibility::Module(ModPath::from_kind(PathKind::Super(0))) + RawVisibility::Module(ModPath::from_kind(PathKind::Super(0)), VisibilityExplicity::Implicit) } pub(crate) fn from_ast( @@ -41,18 +41,9 @@ impl RawVisibility { db: &dyn DefDatabase, node: Option, span_map: SpanMapRef<'_>, - ) -> RawVisibility { - Self::from_ast_with_span_map_and_default(db, node, RawVisibility::private(), span_map) - } - - pub(crate) fn from_ast_with_span_map_and_default( - db: &dyn DefDatabase, - node: Option, - default: RawVisibility, - span_map: SpanMapRef<'_>, ) -> RawVisibility { let node = match node { - None => return default, + None => return RawVisibility::private(), Some(node) => node, }; match node.kind() { @@ -62,19 +53,19 @@ impl RawVisibility { None => return RawVisibility::private(), Some(path) => path, }; - RawVisibility::Module(path) + RawVisibility::Module(path, VisibilityExplicity::Explicit) } ast::VisibilityKind::PubCrate => { let path = ModPath::from_kind(PathKind::Crate); - RawVisibility::Module(path) + RawVisibility::Module(path, VisibilityExplicity::Explicit) } ast::VisibilityKind::PubSuper => { let path = ModPath::from_kind(PathKind::Super(1)); - RawVisibility::Module(path) + RawVisibility::Module(path, VisibilityExplicity::Explicit) } ast::VisibilityKind::PubSelf => { let path = ModPath::from_kind(PathKind::Super(0)); - RawVisibility::Module(path) + RawVisibility::Module(path, VisibilityExplicity::Explicit) } ast::VisibilityKind::Pub => RawVisibility::Public, } @@ -94,7 +85,7 @@ impl RawVisibility { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum Visibility { /// Visibility is restricted to a certain module. - Module(ModuleId), + Module(ModuleId, VisibilityExplicity), /// Visibility is unrestricted. Public, } @@ -102,7 +93,7 @@ pub enum Visibility { impl Visibility { pub fn is_visible_from(self, db: &dyn DefDatabase, from_module: ModuleId) -> bool { let to_module = match self { - Visibility::Module(m) => m, + Visibility::Module(m, _) => m, Visibility::Public => return true, }; // if they're not in the same crate, it can't be visible @@ -124,7 +115,7 @@ impl Visibility { mut from_module: LocalModuleId, ) -> bool { let mut to_module = match self { - Visibility::Module(m) => m, + Visibility::Module(m, _) => m, Visibility::Public => return true, }; @@ -181,9 +172,9 @@ impl Visibility { /// visible in unrelated modules). pub(crate) fn max(self, other: Visibility, def_map: &DefMap) -> Option { match (self, other) { - (Visibility::Module(_) | Visibility::Public, Visibility::Public) - | (Visibility::Public, Visibility::Module(_)) => Some(Visibility::Public), - (Visibility::Module(mod_a), Visibility::Module(mod_b)) => { + (Visibility::Module(_, _) | Visibility::Public, Visibility::Public) + | (Visibility::Public, Visibility::Module(_, _)) => Some(Visibility::Public), + (Visibility::Module(mod_a, vis_a), Visibility::Module(mod_b, vis_b)) => { if mod_a.krate != mod_b.krate { return None; } @@ -199,12 +190,12 @@ impl Visibility { if a_ancestors.any(|m| m == mod_b.local_id) { // B is above A - return Some(Visibility::Module(mod_b)); + return Some(Visibility::Module(mod_b, vis_b)); } if b_ancestors.any(|m| m == mod_a.local_id) { // A is above B - return Some(Visibility::Module(mod_a)); + return Some(Visibility::Module(mod_a, vis_a)); } None @@ -213,6 +204,19 @@ impl Visibility { } } +/// Whether the item was imported through `pub(crate) use` or just `use`. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum VisibilityExplicity { + Explicit, + Implicit, +} + +impl VisibilityExplicity { + pub fn is_explicit(&self) -> bool { + matches!(self, Self::Explicit) + } +} + /// Resolve visibility of all specific fields of a struct or union variant. pub(crate) fn field_visibilities_query( db: &dyn DefDatabase, diff --git a/crates/hir-expand/src/builtin_derive_macro.rs b/crates/hir-expand/src/builtin_derive_macro.rs index 8f240ef07320a..46bbb7f92c079 100644 --- a/crates/hir-expand/src/builtin_derive_macro.rs +++ b/crates/hir-expand/src/builtin_derive_macro.rs @@ -1,6 +1,5 @@ //! Builtin derives. -use base_db::{CrateOrigin, LangCrateOrigin}; use itertools::izip; use rustc_hash::FxHashSet; use span::{MacroCallId, Span}; @@ -10,6 +9,7 @@ use tracing::debug; use crate::{ hygiene::span_with_def_site_ctxt, name::{AsName, Name}, + quote::dollar_crate, span_map::SpanMapRef, tt, }; @@ -38,7 +38,7 @@ macro_rules! register_builtin { let span = db.lookup_intern_macro_call(id).call_site; let span = span_with_def_site_ctxt(db, span, id); - expander(db, id, span, tt, token_map) + expander(span, tt, token_map) } fn find_by_name(name: &name::Name) -> Option { @@ -398,41 +398,13 @@ fn expand_simple_derive( ExpandResult::ok(expanded) } -fn find_builtin_crate(db: &dyn ExpandDatabase, id: MacroCallId, span: Span) -> tt::TokenTree { - // FIXME: make hygiene works for builtin derive macro - // such that $crate can be used here. - let cg = db.crate_graph(); - let krate = db.lookup_intern_macro_call(id).krate; - - let tt = if matches!(cg[krate].origin, CrateOrigin::Lang(LangCrateOrigin::Core)) { - cov_mark::hit!(test_copy_expand_in_core); - quote! {span => crate } - } else { - quote! {span => core } - }; - - tt.token_trees[0].clone() -} - -fn copy_expand( - db: &dyn ExpandDatabase, - id: MacroCallId, - span: Span, - tt: &ast::Adt, - tm: SpanMapRef<'_>, -) -> ExpandResult { - let krate = find_builtin_crate(db, id, span); +fn copy_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult { + let krate = dollar_crate(span); expand_simple_derive(span, tt, tm, quote! {span => #krate::marker::Copy }, |_| quote! {span =>}) } -fn clone_expand( - db: &dyn ExpandDatabase, - id: MacroCallId, - span: Span, - tt: &ast::Adt, - tm: SpanMapRef<'_>, -) -> ExpandResult { - let krate = find_builtin_crate(db, id, span); +fn clone_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult { + let krate = dollar_crate(span); expand_simple_derive(span, tt, tm, quote! {span => #krate::clone::Clone }, |adt| { if matches!(adt.shape, AdtShape::Union) { let star = tt::Punct { char: '*', spacing: ::tt::Spacing::Alone, span }; @@ -482,14 +454,8 @@ fn and_and(span: Span) -> tt::Subtree { quote! {span => #and& } } -fn default_expand( - db: &dyn ExpandDatabase, - id: MacroCallId, - span: Span, - tt: &ast::Adt, - tm: SpanMapRef<'_>, -) -> ExpandResult { - let krate = &find_builtin_crate(db, id, span); +fn default_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult { + let krate = &dollar_crate(span); expand_simple_derive(span, tt, tm, quote! {span => #krate::default::Default }, |adt| { let body = match &adt.shape { AdtShape::Struct(fields) => { @@ -527,14 +493,8 @@ fn default_expand( }) } -fn debug_expand( - db: &dyn ExpandDatabase, - id: MacroCallId, - span: Span, - tt: &ast::Adt, - tm: SpanMapRef<'_>, -) -> ExpandResult { - let krate = &find_builtin_crate(db, id, span); +fn debug_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult { + let krate = &dollar_crate(span); expand_simple_derive(span, tt, tm, quote! {span => #krate::fmt::Debug }, |adt| { let for_variant = |name: String, v: &VariantShape| match v { VariantShape::Struct(fields) => { @@ -605,14 +565,8 @@ fn debug_expand( }) } -fn hash_expand( - db: &dyn ExpandDatabase, - id: MacroCallId, - span: Span, - tt: &ast::Adt, - tm: SpanMapRef<'_>, -) -> ExpandResult { - let krate = &find_builtin_crate(db, id, span); +fn hash_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult { + let krate = &dollar_crate(span); expand_simple_derive(span, tt, tm, quote! {span => #krate::hash::Hash }, |adt| { if matches!(adt.shape, AdtShape::Union) { // FIXME: Return expand error here @@ -658,25 +612,13 @@ fn hash_expand( }) } -fn eq_expand( - db: &dyn ExpandDatabase, - id: MacroCallId, - span: Span, - tt: &ast::Adt, - tm: SpanMapRef<'_>, -) -> ExpandResult { - let krate = find_builtin_crate(db, id, span); +fn eq_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult { + let krate = dollar_crate(span); expand_simple_derive(span, tt, tm, quote! {span => #krate::cmp::Eq }, |_| quote! {span =>}) } -fn partial_eq_expand( - db: &dyn ExpandDatabase, - id: MacroCallId, - span: Span, - tt: &ast::Adt, - tm: SpanMapRef<'_>, -) -> ExpandResult { - let krate = find_builtin_crate(db, id, span); +fn partial_eq_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult { + let krate = dollar_crate(span); expand_simple_derive(span, tt, tm, quote! {span => #krate::cmp::PartialEq }, |adt| { if matches!(adt.shape, AdtShape::Union) { // FIXME: Return expand error here @@ -747,17 +689,11 @@ fn self_and_other_patterns( (self_patterns, other_patterns) } -fn ord_expand( - db: &dyn ExpandDatabase, - id: MacroCallId, - span: Span, - tt: &ast::Adt, - tm: SpanMapRef<'_>, -) -> ExpandResult { - let krate = &find_builtin_crate(db, id, span); +fn ord_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult { + let krate = &dollar_crate(span); expand_simple_derive(span, tt, tm, quote! {span => #krate::cmp::Ord }, |adt| { fn compare( - krate: &tt::TokenTree, + krate: &tt::Ident, left: tt::Subtree, right: tt::Subtree, rest: tt::Subtree, @@ -811,17 +747,11 @@ fn ord_expand( }) } -fn partial_ord_expand( - db: &dyn ExpandDatabase, - id: MacroCallId, - span: Span, - tt: &ast::Adt, - tm: SpanMapRef<'_>, -) -> ExpandResult { - let krate = &find_builtin_crate(db, id, span); +fn partial_ord_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult { + let krate = &dollar_crate(span); expand_simple_derive(span, tt, tm, quote! {span => #krate::cmp::PartialOrd }, |adt| { fn compare( - krate: &tt::TokenTree, + krate: &tt::Ident, left: tt::Subtree, right: tt::Subtree, rest: tt::Subtree, diff --git a/crates/hir-expand/src/builtin_fn_macro.rs b/crates/hir-expand/src/builtin_fn_macro.rs index f99a891762332..c892f462d2c72 100644 --- a/crates/hir-expand/src/builtin_fn_macro.rs +++ b/crates/hir-expand/src/builtin_fn_macro.rs @@ -6,18 +6,16 @@ use either::Either; use itertools::Itertools; use mbe::{parse_exprs_with_sep, parse_to_token_tree}; use span::{Span, SpanAnchor, SyntaxContextId, ROOT_ERASED_FILE_AST_ID}; -use syntax::{ - ast::{self, AstToken}, - SmolStr, -}; +use syntax::ast::{self, AstToken}; use crate::{ db::ExpandDatabase, hygiene::{span_with_call_site_ctxt, span_with_def_site_ctxt}, name::{self, known}, quote, + quote::dollar_crate, tt::{self, DelimSpan}, - ExpandError, ExpandResult, HirFileIdExt, MacroCallId, + ExpandError, ExpandResult, HirFileIdExt, MacroCallId, MacroFileIdExt, }; macro_rules! register_builtin { @@ -205,7 +203,7 @@ fn assert_expand( ) -> ExpandResult { let call_site_span = span_with_call_site_ctxt(db, span, id); let args = parse_exprs_with_sep(tt, ',', call_site_span); - let dollar_crate = tt::Ident { text: SmolStr::new_inline("$crate"), span }; + let dollar_crate = dollar_crate(span); let expanded = match &*args { [cond, panic_args @ ..] => { let comma = tt::Subtree { @@ -300,7 +298,7 @@ fn asm_expand( [tt::TokenTree::Leaf(tt::Leaf::Literal(lit))] | [tt::TokenTree::Leaf(tt::Leaf::Literal(lit)), tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: ',', span: _, spacing: _ }))] => { - let dollar_krate = tt::Ident { text: SmolStr::new_inline("$crate"), span }; + let dollar_krate = dollar_crate(span); literals.push(quote!(span=>#dollar_krate::format_args!(#lit);)); } _ => break, @@ -345,7 +343,7 @@ fn panic_expand( tt: &tt::Subtree, span: Span, ) -> ExpandResult { - let dollar_crate = tt::Ident { text: SmolStr::new_inline("$crate"), span }; + let dollar_crate = dollar_crate(span); let call_site_span = span_with_call_site_ctxt(db, span, id); let mac = @@ -371,7 +369,7 @@ fn unreachable_expand( tt: &tt::Subtree, span: Span, ) -> ExpandResult { - let dollar_crate = tt::Ident { text: SmolStr::new_inline("$crate"), span }; + let dollar_crate = dollar_crate(span); let call_site_span = span_with_call_site_ctxt(db, span, id); let mac = if use_panic_2021(db, call_site_span) { @@ -611,7 +609,7 @@ fn relative_file( path_str: &str, allow_recursion: bool, ) -> Result { - let call_site = call_id.as_file().original_file(db); + let call_site = call_id.as_macro_file().parent(db).original_file_respecting_includes(db); let path = AnchoredPath { anchor: call_site, path: path_str }; let res = db .resolve_path(path) @@ -763,10 +761,10 @@ fn option_env_expand( return ExpandResult::new(tt::Subtree::empty(DelimSpan { open: span, close: span }), e) } }; - // FIXME: Use `DOLLAR_CRATE` when that works in eager macros. + let dollar_crate = dollar_crate(span); let expanded = match get_env_inner(db, arg_id, &key) { - None => quote! {span => ::core::option::Option::None::<&str> }, - Some(s) => quote! {span => ::core::option::Option::Some(#s) }, + None => quote! {span => #dollar_crate::option::Option::None::<&str> }, + Some(s) => quote! {span => #dollar_crate::option::Option::Some(#s) }, }; ExpandResult::ok(expanded) diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs index 6a122e0859cc5..ae7d17e49a904 100644 --- a/crates/hir-expand/src/lib.rs +++ b/crates/hir-expand/src/lib.rs @@ -318,6 +318,7 @@ pub trait MacroFileIdExt { fn expansion_level(self, db: &dyn ExpandDatabase) -> u32; /// If this is a macro call, returns the syntax node of the call. fn call_node(self, db: &dyn ExpandDatabase) -> InFile; + fn parent(self, db: &dyn ExpandDatabase) -> HirFileId; fn expansion_info(self, db: &dyn ExpandDatabase) -> ExpansionInfo; @@ -353,6 +354,9 @@ impl MacroFileIdExt for MacroFileId { }; } } + fn parent(self, db: &dyn ExpandDatabase) -> HirFileId { + self.macro_call_id.lookup(db).kind.file_id() + } /// Return expansion information if it is a macro-expansion file fn expansion_info(self, db: &dyn ExpandDatabase) -> ExpansionInfo { diff --git a/crates/hir-expand/src/quote.rs b/crates/hir-expand/src/quote.rs index 9bdd75f9d2240..a3b84afd2ae4c 100644 --- a/crates/hir-expand/src/quote.rs +++ b/crates/hir-expand/src/quote.rs @@ -4,6 +4,10 @@ use span::Span; use crate::name::Name; +pub(crate) fn dollar_crate(span: Span) -> tt::Ident { + tt::Ident { text: syntax::SmolStr::new_inline("$crate"), span } +} + // A helper macro quote macro // FIXME: // 1. Not all puncts are handled diff --git a/crates/hir-ty/Cargo.toml b/crates/hir-ty/Cargo.toml index c7807bcf9aa1b..803c18677da53 100644 --- a/crates/hir-ty/Cargo.toml +++ b/crates/hir-ty/Cargo.toml @@ -34,7 +34,9 @@ nohash-hasher.workspace = true typed-arena = "2.0.1" indexmap.workspace = true -rustc-dependencies.workspace = true +ra-ap-rustc_abi.workspace = true +ra-ap-rustc_index.workspace = true + # local deps stdx.workspace = true @@ -58,7 +60,7 @@ test-utils.workspace = true test-fixture.workspace = true [features] -in-rust-tree = ["rustc-dependencies/in-rust-tree"] +in-rust-tree = [] [lints] workspace = true diff --git a/crates/hir-ty/src/chalk_db.rs b/crates/hir-ty/src/chalk_db.rs index f4fbace19e35c..e81d4ced5543e 100644 --- a/crates/hir-ty/src/chalk_db.rs +++ b/crates/hir-ty/src/chalk_db.rs @@ -167,7 +167,7 @@ impl chalk_solve::RustIrDatabase for ChalkContext<'_> { } }); }) - .map(|block_id| self.db.trait_impls_in_block(block_id)); + .filter_map(|block_id| self.db.trait_impls_in_block(block_id)); let id_to_chalk = |id: hir_def::ImplId| id.to_chalk(self.db); let mut result = vec![]; @@ -183,7 +183,8 @@ impl chalk_solve::RustIrDatabase for ChalkContext<'_> { def_blocks .into_iter() .flatten() - .for_each(|it| f(&self.db.trait_impls_in_block(it))); + .filter_map(|it| self.db.trait_impls_in_block(it)) + .for_each(|it| f(&it)); } fps => { let mut f = @@ -198,7 +199,8 @@ impl chalk_solve::RustIrDatabase for ChalkContext<'_> { def_blocks .into_iter() .flatten() - .for_each(|it| f(&self.db.trait_impls_in_block(it))); + .filter_map(|it| self.db.trait_impls_in_block(it)) + .for_each(|it| f(&it)); } } diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs index 410bcbf0356f0..ad790fa094d82 100644 --- a/crates/hir-ty/src/db.rs +++ b/crates/hir-ty/src/db.rs @@ -34,6 +34,8 @@ pub trait HirDatabase: DefDatabase + Upcast { #[salsa::invoke(crate::infer::infer_query)] fn infer_query(&self, def: DefWithBodyId) -> Arc; + // region:mir + #[salsa::invoke(crate::mir::mir_body_query)] #[salsa::cycle(crate::mir::mir_body_recover)] fn mir_body(&self, def: DefWithBodyId) -> Result, MirLowerError>; @@ -61,20 +63,6 @@ pub trait HirDatabase: DefDatabase + Upcast { #[salsa::invoke(crate::mir::borrowck_query)] fn borrowck(&self, def: DefWithBodyId) -> Result, MirLowerError>; - #[salsa::invoke(crate::lower::ty_query)] - #[salsa::cycle(crate::lower::ty_recover)] - fn ty(&self, def: TyDefId) -> Binders; - - #[salsa::invoke(crate::lower::value_ty_query)] - fn value_ty(&self, def: ValueTyDefId) -> Binders; - - #[salsa::invoke(crate::lower::impl_self_ty_query)] - #[salsa::cycle(crate::lower::impl_self_ty_recover)] - fn impl_self_ty(&self, def: ImplId) -> Binders; - - #[salsa::invoke(crate::lower::const_param_ty_query)] - fn const_param_ty(&self, def: ConstParamId) -> Ty; - #[salsa::invoke(crate::consteval::const_eval_query)] #[salsa::cycle(crate::consteval::const_eval_recover)] fn const_eval( @@ -92,6 +80,22 @@ pub trait HirDatabase: DefDatabase + Upcast { #[salsa::cycle(crate::consteval::const_eval_discriminant_recover)] fn const_eval_discriminant(&self, def: EnumVariantId) -> Result; + // endregion:mir + + #[salsa::invoke(crate::lower::ty_query)] + #[salsa::cycle(crate::lower::ty_recover)] + fn ty(&self, def: TyDefId) -> Binders; + + #[salsa::invoke(crate::lower::value_ty_query)] + fn value_ty(&self, def: ValueTyDefId) -> Binders; + + #[salsa::invoke(crate::lower::impl_self_ty_query)] + #[salsa::cycle(crate::lower::impl_self_ty_recover)] + fn impl_self_ty(&self, def: ImplId) -> Binders; + + #[salsa::invoke(crate::lower::const_param_ty_query)] + fn const_param_ty(&self, def: ConstParamId) -> Ty; + #[salsa::invoke(crate::lower::impl_trait_query)] fn impl_trait(&self, def: ImplId) -> Option>; @@ -158,7 +162,7 @@ pub trait HirDatabase: DefDatabase + Upcast { fn inherent_impls_in_crate(&self, krate: CrateId) -> Arc; #[salsa::invoke(InherentImpls::inherent_impls_in_block_query)] - fn inherent_impls_in_block(&self, block: BlockId) -> Arc; + fn inherent_impls_in_block(&self, block: BlockId) -> Option>; /// Collects all crates in the dependency graph that have impls for the /// given fingerprint. This is only used for primitive types and types @@ -175,7 +179,7 @@ pub trait HirDatabase: DefDatabase + Upcast { fn trait_impls_in_crate(&self, krate: CrateId) -> Arc; #[salsa::invoke(TraitImpls::trait_impls_in_block_query)] - fn trait_impls_in_block(&self, block: BlockId) -> Arc; + fn trait_impls_in_block(&self, block: BlockId) -> Option>; #[salsa::invoke(TraitImpls::trait_impls_in_deps_query)] fn trait_impls_in_deps(&self, krate: CrateId) -> Arc<[Arc]>; diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs index 23d951542214b..d63a64a70de2a 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ty/src/display.rs @@ -1629,7 +1629,7 @@ pub fn write_visibility( ) -> Result<(), HirDisplayError> { match vis { Visibility::Public => write!(f, "pub "), - Visibility::Module(vis_id) => { + Visibility::Module(vis_id, _) => { let def_map = module_id.def_map(f.db.upcast()); let root_module_id = def_map.module_id(DefMap::ROOT); if vis_id == module_id { diff --git a/crates/hir-ty/src/layout.rs b/crates/hir-ty/src/layout.rs index 68619bb8b18c4..b7bfaf2931b6b 100644 --- a/crates/hir-ty/src/layout.rs +++ b/crates/hir-ty/src/layout.rs @@ -12,10 +12,9 @@ use hir_def::{ LocalEnumVariantId, LocalFieldId, StructId, }; use la_arena::{Idx, RawIdx}; -use rustc_dependencies::{ - abi::AddressSpace, - index::{IndexSlice, IndexVec}, -}; +use rustc_abi::AddressSpace; +use rustc_index::{IndexSlice, IndexVec}; + use stdx::never; use triomphe::Arc; @@ -35,7 +34,7 @@ mod target; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct RustcEnumVariantIdx(pub LocalEnumVariantId); -impl rustc_dependencies::index::Idx for RustcEnumVariantIdx { +impl rustc_index::Idx for RustcEnumVariantIdx { fn new(idx: usize) -> Self { RustcEnumVariantIdx(Idx::from_raw(RawIdx::from(idx as u32))) } @@ -54,7 +53,7 @@ impl RustcFieldIdx { } } -impl rustc_dependencies::index::Idx for RustcFieldIdx { +impl rustc_index::Idx for RustcFieldIdx { fn new(idx: usize) -> Self { RustcFieldIdx(Idx::from_raw(RawIdx::from(idx as u32))) } diff --git a/crates/hir-ty/src/layout/adt.rs b/crates/hir-ty/src/layout/adt.rs index 39788a9502993..8a7715ce8729f 100644 --- a/crates/hir-ty/src/layout/adt.rs +++ b/crates/hir-ty/src/layout/adt.rs @@ -9,7 +9,7 @@ use hir_def::{ AdtId, EnumVariantId, LocalEnumVariantId, VariantId, }; use la_arena::RawIdx; -use rustc_dependencies::index::IndexVec; +use rustc_index::IndexVec; use smallvec::SmallVec; use triomphe::Arc; diff --git a/crates/hir-ty/src/layout/tests.rs b/crates/hir-ty/src/layout/tests.rs index ef0be7ab2dafe..57214193cfbcb 100644 --- a/crates/hir-ty/src/layout/tests.rs +++ b/crates/hir-ty/src/layout/tests.rs @@ -118,7 +118,7 @@ fn check_fail(ra_fixture: &str, e: LayoutError) { macro_rules! size_and_align { (minicore: $($x:tt),*;$($t:tt)*) => { { - #[allow(dead_code)] + #![allow(dead_code)] $($t)* check_size_and_align( stringify!($($t)*), @@ -130,7 +130,7 @@ macro_rules! size_and_align { }; ($($t:tt)*) => { { - #[allow(dead_code)] + #![allow(dead_code)] $($t)* check_size_and_align( stringify!($($t)*), diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs index 793b52b49faa1..e72864a12eec5 100644 --- a/crates/hir-ty/src/lib.rs +++ b/crates/hir-ty/src/lib.rs @@ -3,10 +3,17 @@ #![warn(rust_2018_idioms, unused_lifetimes)] #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] -#[allow(unused)] -macro_rules! eprintln { - ($($tt:tt)*) => { stdx::eprintln!($($tt)*) }; -} +#[cfg(feature = "in-rust-tree")] +extern crate rustc_index; + +#[cfg(not(feature = "in-rust-tree"))] +extern crate ra_ap_rustc_index as rustc_index; + +#[cfg(feature = "in-rust-tree")] +extern crate rustc_abi; + +#[cfg(not(feature = "in-rust-tree"))] +extern crate ra_ap_rustc_abi as rustc_abi; mod builder; mod chalk_db; diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index 97c4a741ff2a9..e371e42761560 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -1601,7 +1601,7 @@ fn implicitly_sized_clauses<'a>( pub(crate) fn generic_defaults_query( db: &dyn HirDatabase, def: GenericDefId, -) -> Arc<[Binders>]> { +) -> Arc<[Binders]> { let resolver = def.resolver(db.upcast()); let ctx = TyLoweringContext::new(db, &resolver, def.into()) .with_type_param_mode(ParamLoweringMode::Variable); diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index 33619edfee93e..03ed8d36a1dd6 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -8,10 +8,9 @@ use base_db::{CrateId, Edition}; use chalk_ir::{cast::Cast, Mutability, TyKind, UniverseIndex, WhereClause}; use hir_def::{ data::{adt::StructFlags, ImplData}, - item_scope::ItemScope, nameres::DefMap, AssocItemId, BlockId, ConstId, FunctionId, HasModule, ImplId, ItemContainerId, Lookup, - ModuleDefId, ModuleId, TraitId, + ModuleId, TraitId, }; use hir_expand::name::Name; use rustc_hash::{FxHashMap, FxHashSet}; @@ -132,34 +131,40 @@ pub(crate) const ALL_FLOAT_FPS: [TyFingerprint; 2] = [ TyFingerprint::Scalar(Scalar::Float(FloatTy::F64)), ]; +type TraitFpMap = FxHashMap, Box<[ImplId]>>>; +type TraitFpMapCollector = FxHashMap, Vec>>; + /// Trait impls defined or available in some crate. #[derive(Debug, Eq, PartialEq)] pub struct TraitImpls { // If the `Option` is `None`, the impl may apply to any self type. - map: FxHashMap, Vec>>, + map: TraitFpMap, } impl TraitImpls { pub(crate) fn trait_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc { let _p = profile::span("trait_impls_in_crate_query").detail(|| format!("{krate:?}")); - let mut impls = Self { map: FxHashMap::default() }; + let mut impls = FxHashMap::default(); - let crate_def_map = db.crate_def_map(krate); - impls.collect_def_map(db, &crate_def_map); - impls.shrink_to_fit(); + Self::collect_def_map(db, &mut impls, &db.crate_def_map(krate)); - Arc::new(impls) + Arc::new(Self::finish(impls)) } - pub(crate) fn trait_impls_in_block_query(db: &dyn HirDatabase, block: BlockId) -> Arc { + pub(crate) fn trait_impls_in_block_query( + db: &dyn HirDatabase, + block: BlockId, + ) -> Option> { let _p = profile::span("trait_impls_in_block_query"); - let mut impls = Self { map: FxHashMap::default() }; + let mut impls = FxHashMap::default(); - let block_def_map = db.block_def_map(block); - impls.collect_def_map(db, &block_def_map); - impls.shrink_to_fit(); + Self::collect_def_map(db, &mut impls, &db.block_def_map(block)); - Arc::new(impls) + if impls.is_empty() { + None + } else { + Some(Arc::new(Self::finish(impls))) + } } pub(crate) fn trait_impls_in_deps_query( @@ -174,15 +179,16 @@ impl TraitImpls { ) } - fn shrink_to_fit(&mut self) { - self.map.shrink_to_fit(); - self.map.values_mut().for_each(|map| { - map.shrink_to_fit(); - map.values_mut().for_each(Vec::shrink_to_fit); - }); + fn finish(map: TraitFpMapCollector) -> TraitImpls { + TraitImpls { + map: map + .into_iter() + .map(|(k, v)| (k, v.into_iter().map(|(k, v)| (k, v.into_boxed_slice())).collect())) + .collect(), + } } - fn collect_def_map(&mut self, db: &dyn HirDatabase, def_map: &DefMap) { + fn collect_def_map(db: &dyn HirDatabase, map: &mut TraitFpMapCollector, def_map: &DefMap) { for (_module_id, module_data) in def_map.modules() { for impl_id in module_data.scope.impls() { // Reservation impls should be ignored during trait resolution, so we never need @@ -200,20 +206,15 @@ impl TraitImpls { }; let self_ty = db.impl_self_ty(impl_id); let self_ty_fp = TyFingerprint::for_trait_impl(self_ty.skip_binders()); - self.map - .entry(target_trait) - .or_default() - .entry(self_ty_fp) - .or_default() - .push(impl_id); + map.entry(target_trait).or_default().entry(self_ty_fp).or_default().push(impl_id); } // To better support custom derives, collect impls in all unnamed const items. // const _: () = { ... }; - for konst in collect_unnamed_consts(db, &module_data.scope) { + for konst in module_data.scope.unnamed_consts(db.upcast()) { let body = db.body(konst.into()); for (_, block_def_map) in body.blocks(db.upcast()) { - self.collect_def_map(db, &block_def_map); + Self::collect_def_map(db, map, &block_def_map); } } } @@ -281,7 +282,10 @@ impl InherentImpls { Arc::new(impls) } - pub(crate) fn inherent_impls_in_block_query(db: &dyn HirDatabase, block: BlockId) -> Arc { + pub(crate) fn inherent_impls_in_block_query( + db: &dyn HirDatabase, + block: BlockId, + ) -> Option> { let _p = profile::span("inherent_impls_in_block_query"); let mut impls = Self { map: FxHashMap::default(), invalid_impls: Vec::default() }; @@ -289,7 +293,11 @@ impl InherentImpls { impls.collect_def_map(db, &block_def_map); impls.shrink_to_fit(); - Arc::new(impls) + if impls.map.is_empty() && impls.invalid_impls.is_empty() { + None + } else { + Some(Arc::new(impls)) + } } fn shrink_to_fit(&mut self) { @@ -321,7 +329,7 @@ impl InherentImpls { // To better support custom derives, collect impls in all unnamed const items. // const _: () = { ... }; - for konst in collect_unnamed_consts(db, &module_data.scope) { + for konst in module_data.scope.unnamed_consts(db.upcast()) { let body = db.body(konst.into()); for (_, block_def_map) in body.blocks(db.upcast()) { self.collect_def_map(db, &block_def_map); @@ -367,34 +375,6 @@ pub(crate) fn incoherent_inherent_impl_crates( res } -fn collect_unnamed_consts<'a>( - db: &'a dyn HirDatabase, - scope: &'a ItemScope, -) -> impl Iterator + 'a { - let unnamed_consts = scope.unnamed_consts(); - - // FIXME: Also treat consts named `_DERIVE_*` as unnamed, since synstructure generates those. - // Should be removed once synstructure stops doing that. - let synstructure_hack_consts = scope.values().filter_map(|(item, _)| match item { - ModuleDefId::ConstId(id) => { - let loc = id.lookup(db.upcast()); - let item_tree = loc.id.item_tree(db.upcast()); - if item_tree[loc.id.value] - .name - .as_ref() - .map_or(false, |n| n.to_smol_str().starts_with("_DERIVE_")) - { - Some(id) - } else { - None - } - } - _ => None, - }); - - unnamed_consts.chain(synstructure_hack_consts) -} - pub fn def_crates( db: &dyn HirDatabase, ty: &Ty, @@ -737,7 +717,7 @@ fn lookup_impl_assoc_item_for_trait_ref( let impls = db.trait_impls_in_deps(env.krate); let self_impls = match self_ty.kind(Interner) { TyKind::Adt(id, _) => { - id.0.module(db.upcast()).containing_block().map(|it| db.trait_impls_in_block(it)) + id.0.module(db.upcast()).containing_block().and_then(|it| db.trait_impls_in_block(it)) } _ => None, }; @@ -1254,17 +1234,18 @@ fn iterate_inherent_methods( }; while let Some(block_id) = block { - let impls = db.inherent_impls_in_block(block_id); - impls_for_self_ty( - &impls, - self_ty, - table, - name, - receiver_ty, - receiver_adjustments.clone(), - module, - callback, - )?; + if let Some(impls) = db.inherent_impls_in_block(block_id) { + impls_for_self_ty( + &impls, + self_ty, + table, + name, + receiver_ty, + receiver_adjustments.clone(), + module, + callback, + )?; + } block = db.block_def_map(block_id).parent().and_then(|module| module.containing_block()); } diff --git a/crates/hir-ty/src/test_db.rs b/crates/hir-ty/src/test_db.rs index 6f4aef22d2f78..d0a1fb1d57691 100644 --- a/crates/hir-ty/src/test_db.rs +++ b/crates/hir-ty/src/test_db.rs @@ -9,7 +9,6 @@ use base_db::{ use hir_def::{db::DefDatabase, ModuleId}; use hir_expand::db::ExpandDatabase; use nohash_hasher::IntMap; -use rustc_hash::FxHashSet; use syntax::TextRange; use test_utils::extract_annotations; use triomphe::Arc; @@ -81,7 +80,7 @@ impl FileLoader for TestDB { fn resolve_path(&self, path: AnchoredPath<'_>) -> Option { FileLoaderDelegate(self).resolve_path(path) } - fn relevant_crates(&self, file_id: FileId) -> Arc> { + fn relevant_crates(&self, file_id: FileId) -> Arc<[CrateId]> { FileLoaderDelegate(self).relevant_crates(file_id) } } diff --git a/crates/hir-ty/src/tests/macros.rs b/crates/hir-ty/src/tests/macros.rs index d16e0eb0137bf..622b4f56d4ffa 100644 --- a/crates/hir-ty/src/tests/macros.rs +++ b/crates/hir-ty/src/tests/macros.rs @@ -987,15 +987,12 @@ fn infer_builtin_macros_env() { fn infer_builtin_macros_option_env() { check_types( r#" - //- minicore: option - //- /main.rs env:foo=bar - #[rustc_builtin_macro] - macro_rules! option_env {() => {}} - - fn main() { - let x = option_env!("foo"); - //^ Option<&str> - } +//- minicore: env +//- /main.rs env:foo=bar +fn main() { + let x = option_env!("foo"); + //^ Option<&str> +} "#, ); } @@ -1014,6 +1011,21 @@ fn test() { ); } +#[test] +fn infer_builtin_derive_resolves_with_core_module() { + check_types( + r#" +//- minicore: derive, clone +mod core {} +#[derive(Clone)] +struct S; +fn test() { + S.clone(); +} //^^^^^^^^^ S +"#, + ); +} + #[test] fn infer_derive_clone_with_params() { check_types( diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs index 60ddc4aa86fee..5a21f41dca84a 100644 --- a/crates/hir/src/attrs.rs +++ b/crates/hir/src/attrs.rs @@ -35,7 +35,7 @@ macro_rules! impl_has_attrs { impl HasAttrs for $def { fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner { let def = AttrDefId::$def_id(self.into()); - db.attrs_with_owner(def) + AttrsWithOwner::attrs_with_owner(db.upcast(), def) } fn attr_id(self) -> AttrDefId { AttrDefId::$def_id(self.into()) diff --git a/crates/hir/src/db.rs b/crates/hir/src/db.rs index 7204868464b30..403a6c88ab0f5 100644 --- a/crates/hir/src/db.rs +++ b/crates/hir/src/db.rs @@ -15,8 +15,8 @@ pub use hir_def::db::{ InternExternBlockQuery, InternExternCrateQuery, InternFunctionQuery, InternImplQuery, InternInTypeConstQuery, InternMacro2Query, InternMacroRulesQuery, InternProcMacroQuery, InternStaticQuery, InternStructQuery, InternTraitAliasQuery, InternTraitQuery, - InternTypeAliasQuery, InternUnionQuery, InternUseQuery, LangAttrQuery, LangItemQuery, - Macro2DataQuery, MacroRulesDataQuery, ProcMacroDataQuery, StaticDataQuery, StructDataQuery, + InternTypeAliasQuery, InternUnionQuery, InternUseQuery, LangItemQuery, Macro2DataQuery, + MacroRulesDataQuery, ProcMacroDataQuery, StaticDataQuery, StructDataQuery, StructDataWithDiagnosticsQuery, TraitAliasDataQuery, TraitDataQuery, TraitDataWithDiagnosticsQuery, TypeAliasDataQuery, UnionDataQuery, UnionDataWithDiagnosticsQuery, VariantsAttrsQuery, VariantsAttrsSourceMapQuery, diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 0266915c39b68..3180a2b713a89 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -754,7 +754,7 @@ impl Module { scope .declarations() .map(ModuleDef::from) - .chain(scope.unnamed_consts().map(|id| ModuleDef::Const(Const::from(id)))) + .chain(scope.unnamed_consts(db.upcast()).map(|id| ModuleDef::Const(Const::from(id)))) .collect() } diff --git a/crates/hir/src/symbols.rs b/crates/hir/src/symbols.rs index 841ddfb9c4373..e1101dd8236e6 100644 --- a/crates/hir/src/symbols.rs +++ b/crates/hir/src/symbols.rs @@ -165,6 +165,7 @@ impl<'a> SymbolCollector<'a> { // Record renamed imports. // FIXME: In case it imports multiple items under different namespaces we just pick one arbitrarily // for now. + // FIXME: This parses! for id in scope.imports() { let source = id.import.child_source(self.db.upcast()); let Some(use_tree_src) = source.value.get(id.idx) else { continue }; @@ -195,7 +196,7 @@ impl<'a> SymbolCollector<'a> { }); } - for const_id in scope.unnamed_consts() { + for const_id in scope.unnamed_consts(self.db.upcast()) { self.collect_from_body(const_id); } diff --git a/crates/ide-assists/src/handlers/auto_import.rs b/crates/ide-assists/src/handlers/auto_import.rs index 7b71d9b869685..a64591c9ca090 100644 --- a/crates/ide-assists/src/handlers/auto_import.rs +++ b/crates/ide-assists/src/handlers/auto_import.rs @@ -1551,4 +1551,39 @@ use foo::Foo$0; ", ); } + + #[test] + fn considers_pub_crate() { + check_assist( + auto_import, + r#" +mod foo { + pub struct Foo; +} + +pub(crate) use self::foo::*; + +mod bar { + fn main() { + Foo$0; + } +} +"#, + r#" +mod foo { + pub struct Foo; +} + +pub(crate) use self::foo::*; + +mod bar { + use crate::Foo; + + fn main() { + Foo; + } +} +"#, + ); + } } diff --git a/crates/ide-assists/src/handlers/extract_function.rs b/crates/ide-assists/src/handlers/extract_function.rs index 347a3e9ba0747..1eb28626f75d1 100644 --- a/crates/ide-assists/src/handlers/extract_function.rs +++ b/crates/ide-assists/src/handlers/extract_function.rs @@ -25,7 +25,7 @@ use syntax::{ edit::{AstNodeEdit, IndentLevel}, AstNode, HasGenericParams, }, - match_ast, ted, SyntaxElement, + match_ast, ted, AstToken, SyntaxElement, SyntaxKind::{self, COMMENT}, SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset, WalkEvent, T, }; @@ -1733,8 +1733,23 @@ fn make_body( ast::Expr::BlockExpr(block) => { // If the extracted expression is itself a block, there is no need to wrap it inside another block. let block = block.dedent(old_indent); - // Recreate the block for formatting consistency with other extracted functions. - make::block_expr(block.statements(), block.tail_expr()) + let elements = block.stmt_list().map_or_else( + || Either::Left(iter::empty()), + |stmt_list| { + let elements = stmt_list.syntax().children_with_tokens().filter_map( + |node_or_token| match &node_or_token { + syntax::NodeOrToken::Node(node) => { + ast::Stmt::cast(node.clone()).map(|_| node_or_token) + } + syntax::NodeOrToken::Token(token) => { + ast::Comment::cast(token.clone()).map(|_| node_or_token) + } + }, + ); + Either::Right(elements) + }, + ); + make::hacky_block_expr(elements, block.tail_expr()) } _ => { let expr = expr.dedent(old_indent).indent(IndentLevel(1)); @@ -5961,6 +5976,37 @@ fn $0fun_name() -> ControlFlow<()> { ); } + #[test] + fn comments_in_block_expr() { + check_assist( + extract_function, + r#" +fn f() { + let c = $0{ + // comment 1 + let a = 2 + 3; + // comment 2 + let b = 5; + a + b + }$0; +} +"#, + r#" +fn f() { + let c = fun_name(); +} + +fn $0fun_name() -> i32 { + // comment 1 + let a = 2 + 3; + // comment 2 + let b = 5; + a + b +} +"#, + ); + } + #[test] fn in_left_curly_is_not_applicable() { cov_mark::check!(extract_function_in_braces_is_not_applicable); diff --git a/crates/ide-assists/src/handlers/generate_constant.rs b/crates/ide-assists/src/handlers/generate_constant.rs index a4e8e7388f624..8b8c6ceee99e2 100644 --- a/crates/ide-assists/src/handlers/generate_constant.rs +++ b/crates/ide-assists/src/handlers/generate_constant.rs @@ -50,6 +50,10 @@ pub(crate) fn generate_constant(acc: &mut Assists, ctx: &AssistContext<'_>) -> O ty.original().display_source_code(ctx.db(), constant_module.into(), false).ok()?; let target = statement.syntax().parent()?.text_range(); let path = constant_token.syntax().ancestors().find_map(ast::Path::cast)?; + if path.parent_path().is_some() { + cov_mark::hit!(not_last_path_segment); + return None; + } let name_refs = path.segments().map(|s| s.name_ref()); let mut outer_exists = false; @@ -250,6 +254,18 @@ fn bar() -> i32 { } fn bar() -> i32 { foo::goo::A_CONSTANT +}"#, + ); + } + + #[test] + fn test_wont_apply_when_not_last_path_segment() { + cov_mark::check!(not_last_path_segment); + check_assist_not_applicable( + generate_constant, + r#"mod foo {} +fn bar() -> i32 { + foo::A_CON$0STANT::invalid_segment }"#, ); } diff --git a/crates/ide-assists/src/handlers/generate_delegate_methods.rs b/crates/ide-assists/src/handlers/generate_delegate_methods.rs index dc02aaf9af68c..1f5c24f8ea446 100644 --- a/crates/ide-assists/src/handlers/generate_delegate_methods.rs +++ b/crates/ide-assists/src/handlers/generate_delegate_methods.rs @@ -107,31 +107,48 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' |edit| { // Create the function let method_source = match ctx.sema.source(method) { - Some(source) => source.value, + Some(source) => { + let v = source.value.clone_for_update(); + let source_scope = ctx.sema.scope(v.syntax()); + let target_scope = ctx.sema.scope(strukt.syntax()); + if let (Some(s), Some(t)) = (source_scope, target_scope) { + PathTransform::generic_transformation(&t, &s).apply(v.syntax()); + } + v + } None => return, }; + let vis = method_source.visibility(); + let is_async = method_source.async_token().is_some(); + let is_const = method_source.const_token().is_some(); + let is_unsafe = method_source.unsafe_token().is_some(); + let fn_name = make::name(&name); + + let type_params = method_source.generic_param_list(); + let where_clause = method_source.where_clause(); let params = method_source.param_list().unwrap_or_else(|| make::param_list(None, [])); - let type_params = method_source.generic_param_list(); - let arg_list = match method_source.param_list() { - Some(list) => convert_param_list_to_arg_list(list), - None => make::arg_list([]), - }; + + // compute the `body` + let arg_list = method_source + .param_list() + .map(|list| convert_param_list_to_arg_list(list)) + .unwrap_or_else(|| make::arg_list([])); + let tail_expr = make::expr_method_call(field, make::name_ref(&name), arg_list); - let ret_type = method_source.ret_type(); - let is_async = method_source.async_token().is_some(); - let is_const = method_source.const_token().is_some(); - let is_unsafe = method_source.unsafe_token().is_some(); let tail_expr_finished = if is_async { make::expr_await(tail_expr) } else { tail_expr }; let body = make::block_expr([], Some(tail_expr_finished)); + + let ret_type = method_source.ret_type(); + let f = make::fn_( vis, fn_name, type_params, - method_source.where_clause(), + where_clause, params, body, ret_type, @@ -184,12 +201,6 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' let assoc_items = impl_def.get_or_create_assoc_item_list(); assoc_items.add_item(f.clone().into()); - if let Some((target, source)) = - ctx.sema.scope(strukt.syntax()).zip(ctx.sema.scope(method_source.syntax())) - { - PathTransform::generic_transformation(&target, &source).apply(f.syntax()); - } - if let Some(cap) = ctx.config.snippet_cap { edit.add_tabstop_before(cap, f) } diff --git a/crates/ide-assists/src/handlers/merge_nested_if.rs b/crates/ide-assists/src/handlers/merge_nested_if.rs new file mode 100644 index 0000000000000..2f3136f027b0d --- /dev/null +++ b/crates/ide-assists/src/handlers/merge_nested_if.rs @@ -0,0 +1,246 @@ +use ide_db::syntax_helpers::node_ext::is_pattern_cond; +use syntax::{ + ast::{self, AstNode, BinaryOp}, + T, +}; + +use crate::{ + assist_context::{AssistContext, Assists}, + AssistId, AssistKind, +}; +// Assist: merge_nested_if +// +// This transforms if expressions of the form `if x { if y {A} }` into `if x && y {A}` +// This assist can only be applied with the cursor on `if`. +// +// ``` +// fn main() { +// i$0f x == 3 { if y == 4 { 1 } } +// } +// ``` +// -> +// ``` +// fn main() { +// if x == 3 && y == 4 { 1 } +// } +// ``` +pub(crate) fn merge_nested_if(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + let if_keyword = ctx.find_token_syntax_at_offset(T![if])?; + let expr = ast::IfExpr::cast(if_keyword.parent()?)?; + let if_range = if_keyword.text_range(); + let cursor_in_range = if_range.contains_range(ctx.selection_trimmed()); + if !cursor_in_range { + return None; + } + + //should not apply to if with else branch. + if expr.else_branch().is_some() { + return None; + } + + let cond = expr.condition()?; + //should not apply for if-let + if is_pattern_cond(cond.clone()) { + return None; + } + + let cond_range = cond.syntax().text_range(); + + //check if the then branch is a nested if + let then_branch = expr.then_branch()?; + let stmt = then_branch.stmt_list()?; + if stmt.statements().count() != 0 { + return None; + } + + let nested_if_to_merge = then_branch.tail_expr().and_then(|e| match e { + ast::Expr::IfExpr(e) => Some(e), + _ => None, + })?; + // should not apply to nested if with else branch. + if nested_if_to_merge.else_branch().is_some() { + return None; + } + let nested_if_cond = nested_if_to_merge.condition()?; + if is_pattern_cond(nested_if_cond.clone()) { + return None; + } + + let nested_if_then_branch = nested_if_to_merge.then_branch()?; + let then_branch_range = then_branch.syntax().text_range(); + + acc.add( + AssistId("merge_nested_if", AssistKind::RefactorRewrite), + "Merge nested if", + if_range, + |edit| { + let cond_text = if has_logic_op_or(&cond) { + format!("({})", cond.syntax().text()) + } else { + cond.syntax().text().to_string() + }; + + let nested_if_cond_text = if has_logic_op_or(&nested_if_cond) { + format!("({})", nested_if_cond.syntax().text()) + } else { + nested_if_cond.syntax().text().to_string() + }; + + let replace_cond = format!("{} && {}", cond_text, nested_if_cond_text); + + edit.replace(cond_range, replace_cond); + edit.replace(then_branch_range, nested_if_then_branch.syntax().text()); + }, + ) +} + +/// Returns whether the given if condition has logical operators. +fn has_logic_op_or(expr: &ast::Expr) -> bool { + match expr { + ast::Expr::BinExpr(bin_expr) => { + if let Some(kind) = bin_expr.op_kind() { + matches!(kind, BinaryOp::LogicOp(ast::LogicOp::Or)) + } else { + false + } + } + _ => false, + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::tests::{check_assist, check_assist_not_applicable}; + + #[test] + fn merge_nested_if_test1() { + check_assist( + merge_nested_if, + "fn f() { i$0f x == 3 { if y == 4 { 1 } } }", + "fn f() { if x == 3 && y == 4 { 1 } }", + ) + } + + #[test] + fn merge_nested_if_test2() { + check_assist( + merge_nested_if, + "fn f() { i$0f x == 3 || y == 1 { if z == 4 { 1 } } }", + "fn f() { if (x == 3 || y == 1) && z == 4 { 1 } }", + ) + } + + #[test] + fn merge_nested_if_test3() { + check_assist( + merge_nested_if, + "fn f() { i$0f x == 3 && y == 1 { if z == 4 { 1 } } }", + "fn f() { if x == 3 && y == 1 && z == 4 { 1 } }", + ) + } + + #[test] + fn merge_nested_if_test4() { + check_assist( + merge_nested_if, + "fn f() { i$0f x == 3 && y == 1 { if z == 4 && q == 3 { 1 } } }", + "fn f() { if x == 3 && y == 1 && z == 4 && q == 3 { 1 } }", + ) + } + + #[test] + fn merge_nested_if_test5() { + check_assist( + merge_nested_if, + "fn f() { i$0f x == 3 && y == 1 { if z == 4 || q == 3 { 1 } } }", + "fn f() { if x == 3 && y == 1 && (z == 4 || q == 3) { 1 } }", + ) + } + + #[test] + fn merge_nested_if_test6() { + check_assist( + merge_nested_if, + "fn f() { i$0f x == 3 || y == 1 { if z == 4 || q == 3 { 1 } } }", + "fn f() { if (x == 3 || y == 1) && (z == 4 || q == 3) { 1 } }", + ) + } + + #[test] + fn merge_nested_if_test7() { + check_assist( + merge_nested_if, + "fn f() { i$0f x == 3 || y == 1 { if z == 4 && q == 3 { 1 } } }", + "fn f() { if (x == 3 || y == 1) && z == 4 && q == 3 { 1 } }", + ) + } + + #[test] + fn merge_nested_if_do_not_apply_to_if_with_else_branch() { + check_assist_not_applicable( + merge_nested_if, + "fn f() { i$0f x == 3 { if y == 4 { 1 } } else { 2 } }", + ) + } + + #[test] + fn merge_nested_if_do_not_apply_to_nested_if_with_else_branch() { + check_assist_not_applicable( + merge_nested_if, + "fn f() { i$0f x == 3 { if y == 4 { 1 } else { 2 } } }", + ) + } + + #[test] + fn merge_nested_if_do_not_apply_to_if_let() { + check_assist_not_applicable( + merge_nested_if, + "fn f() { i$0f let Some(x) = y { if x == 4 { 1 } } }", + ) + } + + #[test] + fn merge_nested_if_do_not_apply_to_nested_if_let() { + check_assist_not_applicable( + merge_nested_if, + "fn f() { i$0f y == 0 { if let Some(x) = y { 1 } } }", + ) + } + + #[test] + fn merge_nested_if_do_not_apply_to_if_with_else_branch_and_nested_if() { + check_assist_not_applicable( + merge_nested_if, + "fn f() { i$0f x == 3 { if y == 4 { 1 } } else { if z == 5 { 2 } } }", + ) + } + + #[test] + fn merge_nested_if_do_not_apply_with_cursor_not_on_if() { + check_assist_not_applicable(merge_nested_if, "fn f() { if $0x==0 { if y == 3 { 1 } } }") + } + + #[test] + fn merge_nested_if_do_not_apply_with_mulpiple_if() { + check_assist_not_applicable( + merge_nested_if, + "fn f() { i$0f x == 0 { if y == 3 { 1 } else if y == 4 { 2 } } }", + ) + } + #[test] + fn merge_nested_if_do_not_apply_with_not_only_has_nested_if() { + check_assist_not_applicable( + merge_nested_if, + "fn f() { i$0f x == 0 { if y == 3 { foo(); } foo(); } }", + ) + } + + #[test] + fn merge_nested_if_do_not_apply_with_multiply_nested_if() { + check_assist_not_applicable( + merge_nested_if, + "fn f() { i$0f x == 0 { if y == 3 { foo(); } if z == 3 { 2 } } }", + ) + } +} diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs index 1e4d1c94f5bee..1eb4903ab2033 100644 --- a/crates/ide-assists/src/lib.rs +++ b/crates/ide-assists/src/lib.rs @@ -217,6 +217,7 @@ mod handlers { mod unqualify_method_call; mod wrap_return_type_in_result; mod into_to_qualified_from; + mod merge_nested_if; pub(crate) fn all() -> &'static [Handler] { &[ @@ -291,6 +292,7 @@ mod handlers { invert_if::invert_if, merge_imports::merge_imports, merge_match_arms::merge_match_arms, + merge_nested_if::merge_nested_if, move_bounds::move_bounds_to_where_clause, move_const_to_impl::move_const_to_impl, move_guard::move_arm_cond_to_match_guard, diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index 0c2331796f9ea..0ce89ae0a9a5e 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -2051,6 +2051,23 @@ fn handle(action: Action) { ) } +#[test] +fn doctest_merge_nested_if() { + check_doc_test( + "merge_nested_if", + r#####" +fn main() { + i$0f x == 3 { if y == 4 { 1 } } +} +"#####, + r#####" +fn main() { + if x == 3 && y == 4 { 1 } +} +"#####, + ) +} + #[test] fn doctest_move_arm_cond_to_match_guard() { check_doc_test( diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs index 108b040de6bad..92aa1da89c411 100644 --- a/crates/ide-completion/src/context.rs +++ b/crates/ide-completion/src/context.rs @@ -529,6 +529,11 @@ impl CompletionContext<'_> { } } + /// Whether the given trait has `#[doc(notable_trait)]` + pub(crate) fn is_doc_notable_trait(&self, trait_: hir::Trait) -> bool { + trait_.attrs(self.db).has_doc_notable_trait() + } + /// Returns the traits in scope, with the [`Drop`] trait removed. pub(crate) fn traits_in_scope(&self) -> hir::VisibleTraits { let mut traits_in_scope = self.scope.visible_traits(); diff --git a/crates/ide-completion/src/item.rs b/crates/ide-completion/src/item.rs index de41a5bd70c4d..affd9b729646d 100644 --- a/crates/ide-completion/src/item.rs +++ b/crates/ide-completion/src/item.rs @@ -152,6 +152,8 @@ pub struct CompletionRelevance { pub is_local: bool, /// This is set when trait items are completed in an impl of that trait. pub is_item_from_trait: bool, + /// This is set for when trait items are from traits with `#[doc(notable_trait)]` + pub is_item_from_notable_trait: bool, /// This is set when an import is suggested whose name is already imported. pub is_name_already_imported: bool, /// This is set for completions that will insert a `use` item. @@ -228,6 +230,7 @@ impl CompletionRelevance { is_private_editable, postfix_match, is_definite, + is_item_from_notable_trait, } = self; // lower rank private things @@ -266,6 +269,9 @@ impl CompletionRelevance { if is_item_from_trait { score += 1; } + if is_item_from_notable_trait { + score += 1; + } if is_definite { score += 10; } diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs index 581d557e831ad..8c0e6694761ed 100644 --- a/crates/ide-completion/src/render.rs +++ b/crates/ide-completion/src/render.rs @@ -1170,6 +1170,7 @@ fn main() { let _: m::Spam = S$0 } ), is_local: false, is_item_from_trait: false, + is_item_from_notable_trait: false, is_name_already_imported: false, requires_import: false, is_op_method: false, @@ -1196,6 +1197,7 @@ fn main() { let _: m::Spam = S$0 } ), is_local: false, is_item_from_trait: false, + is_item_from_notable_trait: false, is_name_already_imported: false, requires_import: false, is_op_method: false, @@ -1274,6 +1276,7 @@ fn foo() { A { the$0 } } ), is_local: false, is_item_from_trait: false, + is_item_from_notable_trait: false, is_name_already_imported: false, requires_import: false, is_op_method: false, @@ -2089,6 +2092,7 @@ fn foo() { ), is_local: false, is_item_from_trait: false, + is_item_from_notable_trait: false, is_name_already_imported: false, requires_import: false, is_op_method: false, @@ -2439,4 +2443,81 @@ impl S { "#, ) } + + #[test] + fn notable_traits_method_relevance() { + check_kinds( + r#" +#[doc(notable_trait)] +trait Write { + fn write(&self); + fn flush(&self); +} + +struct Writer; + +impl Write for Writer { + fn write(&self) {} + fn flush(&self) {} +} + +fn main() { + Writer.$0 +} +"#, + &[ + CompletionItemKind::Method, + CompletionItemKind::SymbolKind(SymbolKind::Field), + CompletionItemKind::SymbolKind(SymbolKind::Function), + ], + expect![[r#" + [ + CompletionItem { + label: "flush()", + source_range: 193..193, + delete: 193..193, + insert: "flush()$0", + kind: Method, + lookup: "flush", + detail: "fn(&self)", + relevance: CompletionRelevance { + exact_name_match: false, + type_match: None, + is_local: false, + is_item_from_trait: false, + is_item_from_notable_trait: true, + is_name_already_imported: false, + requires_import: false, + is_op_method: false, + is_private_editable: false, + postfix_match: None, + is_definite: false, + }, + }, + CompletionItem { + label: "write()", + source_range: 193..193, + delete: 193..193, + insert: "write()$0", + kind: Method, + lookup: "write", + detail: "fn(&self)", + relevance: CompletionRelevance { + exact_name_match: false, + type_match: None, + is_local: false, + is_item_from_trait: false, + is_item_from_notable_trait: true, + is_name_already_imported: false, + requires_import: false, + is_op_method: false, + is_private_editable: false, + postfix_match: None, + is_definite: false, + }, + }, + ] + "#]], + ); + } } diff --git a/crates/ide-completion/src/render/function.rs b/crates/ide-completion/src/render/function.rs index b306bede653be..6ad84eba33bea 100644 --- a/crates/ide-completion/src/render/function.rs +++ b/crates/ide-completion/src/render/function.rs @@ -74,10 +74,13 @@ fn render( ); let ret_type = func.ret_type(db); - let is_op_method = func - .as_assoc_item(ctx.db()) - .and_then(|trait_| trait_.containing_trait_or_trait_impl(ctx.db())) - .map_or(false, |trait_| completion.is_ops_trait(trait_)); + let assoc_item = func.as_assoc_item(db); + + let trait_ = assoc_item.and_then(|trait_| trait_.containing_trait_or_trait_impl(db)); + let is_op_method = trait_.map_or(false, |trait_| completion.is_ops_trait(trait_)); + + let is_item_from_notable_trait = + trait_.map_or(false, |trait_| completion.is_doc_notable_trait(trait_)); let (has_dot_receiver, has_call_parens, cap) = match func_kind { FuncKind::Function(&PathCompletionCtx { @@ -105,6 +108,7 @@ fn render( }, exact_name_match: compute_exact_name_match(completion, &call), is_op_method, + is_item_from_notable_trait, ..ctx.completion_relevance() }); @@ -141,7 +145,7 @@ fn render( item.add_import(import_to_add); } None => { - if let Some(actm) = func.as_assoc_item(db) { + if let Some(actm) = assoc_item { if let Some(trt) = actm.containing_trait_or_trait_impl(db) { item.trait_name(trt.name(db).to_smol_str()); } diff --git a/crates/ide-db/src/apply_change.rs b/crates/ide-db/src/apply_change.rs index db6cd128e83d3..259d141404d3f 100644 --- a/crates/ide-db/src/apply_change.rs +++ b/crates/ide-db/src/apply_change.rs @@ -84,26 +84,53 @@ impl RootDatabase { )*} } purge_each_query![ - // SourceDatabase - base_db::ParseQuery - base_db::CrateGraphQuery - - // SourceDatabaseExt - base_db::FileTextQuery - base_db::FileSourceRootQuery - base_db::SourceRootQuery - base_db::SourceRootCratesQuery - - // ExpandDatabase - hir::db::AstIdMapQuery - hir::db::DeclMacroExpanderQuery - hir::db::ExpandProcMacroQuery - hir::db::InternMacroCallQuery - hir::db::InternSyntaxContextQuery - hir::db::MacroArgQuery - hir::db::ParseMacroExpansionQuery - hir::db::RealSpanMapQuery - hir::db::ProcMacrosQuery + // SymbolsDatabase + crate::symbol_index::ModuleSymbolsQuery + crate::symbol_index::LibrarySymbolsQuery + crate::symbol_index::LocalRootsQuery + crate::symbol_index::LibraryRootsQuery + // HirDatabase + hir::db::InferQueryQuery + hir::db::MirBodyQuery + hir::db::BorrowckQuery + hir::db::TyQuery + hir::db::ValueTyQuery + hir::db::ImplSelfTyQuery + hir::db::ConstParamTyQuery + hir::db::ConstEvalQuery + hir::db::ConstEvalDiscriminantQuery + hir::db::ImplTraitQuery + hir::db::FieldTypesQuery + hir::db::LayoutOfAdtQuery + hir::db::TargetDataLayoutQuery + hir::db::CallableItemSignatureQuery + hir::db::ReturnTypeImplTraitsQuery + hir::db::GenericPredicatesForParamQuery + hir::db::GenericPredicatesQuery + hir::db::TraitEnvironmentQuery + hir::db::GenericDefaultsQuery + hir::db::InherentImplsInCrateQuery + hir::db::InherentImplsInBlockQuery + hir::db::IncoherentInherentImplCratesQuery + hir::db::TraitImplsInCrateQuery + hir::db::TraitImplsInBlockQuery + hir::db::TraitImplsInDepsQuery + hir::db::InternCallableDefQuery + hir::db::InternLifetimeParamIdQuery + hir::db::InternImplTraitIdQuery + hir::db::InternTypeOrConstParamIdQuery + hir::db::InternClosureQuery + hir::db::InternGeneratorQuery + hir::db::AssociatedTyDataQuery + hir::db::TraitDatumQuery + hir::db::StructDatumQuery + hir::db::ImplDatumQuery + hir::db::FnDefDatumQuery + hir::db::FnDefVarianceQuery + hir::db::AdtVarianceQuery + hir::db::AssociatedTyValueQuery + hir::db::TraitSolveQueryQuery + hir::db::ProgramClausesForChalkEnvQuery // DefDatabase hir::db::FileItemTreeQuery @@ -145,64 +172,11 @@ impl RootDatabase { hir::db::CrateSupportsNoStdQuery hir::db::BlockItemTreeQueryQuery hir::db::ExternCrateDeclDataQuery - hir::db::LangAttrQuery hir::db::InternAnonymousConstQuery hir::db::InternExternCrateQuery hir::db::InternInTypeConstQuery hir::db::InternUseQuery - // HirDatabase - hir::db::InferQueryQuery - hir::db::MirBodyQuery - hir::db::BorrowckQuery - hir::db::TyQuery - hir::db::ValueTyQuery - hir::db::ImplSelfTyQuery - hir::db::ConstParamTyQuery - hir::db::ConstEvalQuery - hir::db::ConstEvalDiscriminantQuery - hir::db::ImplTraitQuery - hir::db::FieldTypesQuery - hir::db::LayoutOfAdtQuery - hir::db::TargetDataLayoutQuery - hir::db::CallableItemSignatureQuery - hir::db::ReturnTypeImplTraitsQuery - hir::db::GenericPredicatesForParamQuery - hir::db::GenericPredicatesQuery - hir::db::TraitEnvironmentQuery - hir::db::GenericDefaultsQuery - hir::db::InherentImplsInCrateQuery - hir::db::InherentImplsInBlockQuery - hir::db::IncoherentInherentImplCratesQuery - hir::db::TraitImplsInCrateQuery - hir::db::TraitImplsInBlockQuery - hir::db::TraitImplsInDepsQuery - hir::db::InternCallableDefQuery - hir::db::InternLifetimeParamIdQuery - hir::db::InternImplTraitIdQuery - hir::db::InternTypeOrConstParamIdQuery - hir::db::InternClosureQuery - hir::db::InternGeneratorQuery - hir::db::AssociatedTyDataQuery - hir::db::TraitDatumQuery - hir::db::StructDatumQuery - hir::db::ImplDatumQuery - hir::db::FnDefDatumQuery - hir::db::FnDefVarianceQuery - hir::db::AdtVarianceQuery - hir::db::AssociatedTyValueQuery - hir::db::TraitSolveQueryQuery - hir::db::ProgramClausesForChalkEnvQuery - - // SymbolsDatabase - crate::symbol_index::ModuleSymbolsQuery - crate::symbol_index::LibrarySymbolsQuery - crate::symbol_index::LocalRootsQuery - crate::symbol_index::LibraryRootsQuery - - // LineIndexDatabase - crate::LineIndexQuery - // InternDatabase hir::db::InternFunctionQuery hir::db::InternStructQuery @@ -219,6 +193,30 @@ impl RootDatabase { hir::db::InternMacro2Query hir::db::InternProcMacroQuery hir::db::InternMacroRulesQuery + + // ExpandDatabase + hir::db::AstIdMapQuery + hir::db::DeclMacroExpanderQuery + hir::db::ExpandProcMacroQuery + hir::db::InternMacroCallQuery + hir::db::InternSyntaxContextQuery + hir::db::MacroArgQuery + hir::db::ParseMacroExpansionQuery + hir::db::RealSpanMapQuery + hir::db::ProcMacrosQuery + + // LineIndexDatabase + crate::LineIndexQuery + + // SourceDatabase + base_db::ParseQuery + base_db::CrateGraphQuery + + // SourceDatabaseExt + base_db::FileTextQuery + base_db::FileSourceRootQuery + base_db::SourceRootQuery + base_db::SourceRootCratesQuery ]; acc.sort_by_key(|it| std::cmp::Reverse(it.1)); diff --git a/crates/ide-db/src/imports/import_assets.rs b/crates/ide-db/src/imports/import_assets.rs index 652968d808fac..b834f517d491d 100644 --- a/crates/ide-db/src/imports/import_assets.rs +++ b/crates/ide-db/src/imports/import_assets.rs @@ -681,11 +681,10 @@ fn path_import_candidate( Some(qualifier) => match sema.resolve_path(&qualifier) { None => { if qualifier.first_qualifier().map_or(true, |it| sema.resolve_path(&it).is_none()) { - let mut qualifier = qualifier - .segments_of_this_path_only_rev() + let qualifier = qualifier + .segments() .map(|seg| seg.name_ref().map(|name| SmolStr::new(name.text()))) .collect::>>()?; - qualifier.reverse(); ImportCandidate::Path(PathImportCandidate { qualifier: Some(qualifier), name }) } else { return None; diff --git a/crates/ide-db/src/lib.rs b/crates/ide-db/src/lib.rs index 128971994f64b..eae23e9548240 100644 --- a/crates/ide-db/src/lib.rs +++ b/crates/ide-db/src/lib.rs @@ -124,7 +124,7 @@ impl FileLoader for RootDatabase { fn resolve_path(&self, path: AnchoredPath<'_>) -> Option { FileLoaderDelegate(self).resolve_path(path) } - fn relevant_crates(&self, file_id: FileId) -> Arc> { + fn relevant_crates(&self, file_id: FileId) -> Arc<[CrateId]> { FileLoaderDelegate(self).relevant_crates(file_id) } } @@ -145,7 +145,7 @@ impl RootDatabase { db.set_local_roots_with_durability(Default::default(), Durability::HIGH); db.set_library_roots_with_durability(Default::default(), Durability::HIGH); db.set_expand_proc_attr_macros_with_durability(false, Durability::HIGH); - db.update_parse_query_lru_capacity(lru_capacity); + db.update_base_query_lru_capacities(lru_capacity); db.setup_syntax_context_root(); db } @@ -154,11 +154,12 @@ impl RootDatabase { self.set_expand_proc_attr_macros_with_durability(true, Durability::HIGH); } - pub fn update_parse_query_lru_capacity(&mut self, lru_capacity: Option) { + pub fn update_base_query_lru_capacities(&mut self, lru_capacity: Option) { let lru_capacity = lru_capacity.unwrap_or(base_db::DEFAULT_PARSE_LRU_CAP); base_db::ParseQuery.in_db_mut(self).set_lru_capacity(lru_capacity); // macro expansions are usually rather small, so we can afford to keep more of them alive hir::db::ParseMacroExpansionQuery.in_db_mut(self).set_lru_capacity(4 * lru_capacity); + hir::db::BorrowckQuery.in_db_mut(self).set_lru_capacity(base_db::DEFAULT_BORROWCK_LRU_CAP); } pub fn update_lru_capacities(&mut self, lru_capacities: &FxHashMap, usize>) { @@ -176,6 +177,12 @@ impl RootDatabase { .copied() .unwrap_or(4 * base_db::DEFAULT_PARSE_LRU_CAP), ); + hir_db::BorrowckQuery.in_db_mut(self).set_lru_capacity( + lru_capacities + .get(stringify!(BorrowckQuery)) + .copied() + .unwrap_or(base_db::DEFAULT_BORROWCK_LRU_CAP), + ); macro_rules! update_lru_capacity_per_query { ($( $module:ident :: $query:ident )*) => {$( diff --git a/crates/ide-db/src/path_transform.rs b/crates/ide-db/src/path_transform.rs index edfeddc1bc9c8..47bcaae259b41 100644 --- a/crates/ide-db/src/path_transform.rs +++ b/crates/ide-db/src/path_transform.rs @@ -3,6 +3,7 @@ use crate::helpers::mod_path_to_ast; use either::Either; use hir::{AsAssocItem, HirDisplay, ModuleDef, SemanticsScope}; +use itertools::Itertools; use rustc_hash::FxHashMap; use syntax::{ ast::{self, make, AstNode}, @@ -227,11 +228,15 @@ struct Ctx<'a> { same_self_type: bool, } -fn postorder(item: &SyntaxNode) -> impl Iterator { - item.preorder().filter_map(|event| match event { - syntax::WalkEvent::Enter(_) => None, - syntax::WalkEvent::Leave(node) => Some(node), - }) +fn preorder_rev(item: &SyntaxNode) -> impl Iterator { + let x = item + .preorder() + .filter_map(|event| match event { + syntax::WalkEvent::Enter(node) => Some(node), + syntax::WalkEvent::Leave(_) => None, + }) + .collect_vec(); + x.into_iter().rev() } impl Ctx<'_> { @@ -239,12 +244,12 @@ impl Ctx<'_> { // `transform_path` may update a node's parent and that would break the // tree traversal. Thus all paths in the tree are collected into a vec // so that such operation is safe. - let paths = postorder(item).filter_map(ast::Path::cast).collect::>(); + let paths = preorder_rev(item).filter_map(ast::Path::cast).collect::>(); for path in paths { self.transform_path(path); } - postorder(item).filter_map(ast::Lifetime::cast).for_each(|lifetime| { + preorder_rev(item).filter_map(ast::Lifetime::cast).for_each(|lifetime| { if let Some(subst) = self.lifetime_substs.get(&lifetime.syntax().text().to_string()) { ted::replace(lifetime.syntax(), subst.clone_subtree().clone_for_update().syntax()); } @@ -263,7 +268,7 @@ impl Ctx<'_> { // `transform_path` may update a node's parent and that would break the // tree traversal. Thus all paths in the tree are collected into a vec // so that such operation is safe. - let paths = postorder(value).filter_map(ast::Path::cast).collect::>(); + let paths = preorder_rev(value).filter_map(ast::Path::cast).collect::>(); for path in paths { self.transform_path(path); } diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs index a40dd2692cfd1..e2b20ef92fc43 100644 --- a/crates/ide-db/src/search.rs +++ b/crates/ide-db/src/search.rs @@ -356,7 +356,7 @@ impl Definition { if let Some(Visibility::Public) = vis { return SearchScope::reverse_dependencies(db, module.krate()); } - if let Some(Visibility::Module(module)) = vis { + if let Some(Visibility::Module(module, _)) = vis { return SearchScope::module_and_children(db, module.into()); } diff --git a/crates/ide-diagnostics/src/handlers/unresolved_assoc_item.rs b/crates/ide-diagnostics/src/handlers/unresolved_assoc_item.rs index f1c95993c843e..551021c55a98e 100644 --- a/crates/ide-diagnostics/src/handlers/unresolved_assoc_item.rs +++ b/crates/ide-diagnostics/src/handlers/unresolved_assoc_item.rs @@ -13,6 +13,7 @@ pub(crate) fn unresolved_assoc_item( "no such associated item", d.expr_or_pat.clone().map(Into::into), ) + .experimental() } #[cfg(test)] diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs index 024053effe423..17c701ad03591 100644 --- a/crates/ide/src/expand_macro.rs +++ b/crates/ide/src/expand_macro.rs @@ -481,7 +481,7 @@ struct Foo {} "#, expect![[r#" Clone - impl < >core::clone::Clone for Foo< >where { + impl < >$crate::clone::Clone for Foo< >where { fn clone(&self) -> Self { match self { Foo{} @@ -507,7 +507,7 @@ struct Foo {} "#, expect![[r#" Copy - impl < >core::marker::Copy for Foo< >where{}"#]], + impl < >$crate::marker::Copy for Foo< >where{}"#]], ); } @@ -522,7 +522,7 @@ struct Foo {} "#, expect![[r#" Copy - impl < >core::marker::Copy for Foo< >where{}"#]], + impl < >$crate::marker::Copy for Foo< >where{}"#]], ); check( r#" @@ -533,7 +533,7 @@ struct Foo {} "#, expect![[r#" Clone - impl < >core::clone::Clone for Foo< >where { + impl < >$crate::clone::Clone for Foo< >where { fn clone(&self) -> Self { match self { Foo{} diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index c98e9fba120ad..60a9367adceec 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -171,7 +171,7 @@ impl AnalysisHost { } pub fn update_lru_capacity(&mut self, lru_capacity: Option) { - self.db.update_parse_query_lru_capacity(lru_capacity); + self.db.update_base_query_lru_capacities(lru_capacity); } pub fn update_lru_capacities(&mut self, lru_capacities: &FxHashMap, usize>) { diff --git a/crates/load-cargo/src/lib.rs b/crates/load-cargo/src/lib.rs index 556ed73a04c2c..e6ddfd580c30e 100644 --- a/crates/load-cargo/src/lib.rs +++ b/crates/load-cargo/src/lib.rs @@ -322,7 +322,7 @@ fn load_crate_graph( break; } } - vfs::loader::Message::Loaded { files } => { + vfs::loader::Message::Loaded { files } | vfs::loader::Message::Changed { files } => { for (path, contents) in files { vfs.set_file_contents(path.into(), contents); } @@ -331,9 +331,8 @@ fn load_crate_graph( } let changes = vfs.take_changes(); for file in changes { - if file.exists() { - let contents = vfs.file_contents(file.file_id); - if let Ok(text) = std::str::from_utf8(contents) { + if let vfs::Change::Create(v) | vfs::Change::Modify(v) = file.change { + if let Ok(text) = std::str::from_utf8(&v) { analysis_change.change_file(file.file_id, Some(text.into())) } } diff --git a/crates/parser/Cargo.toml b/crates/parser/Cargo.toml index 0c63484634be9..e74b340126c0a 100644 --- a/crates/parser/Cargo.toml +++ b/crates/parser/Cargo.toml @@ -13,8 +13,7 @@ doctest = false [dependencies] drop_bomb = "0.1.5" -rustc-dependencies.workspace = true - +ra-ap-rustc_lexer.workspace = true limit.workspace = true [dev-dependencies] @@ -24,7 +23,7 @@ stdx.workspace = true sourcegen.workspace = true [features] -in-rust-tree = ["rustc-dependencies/in-rust-tree"] +in-rust-tree = [] [lints] -workspace = true \ No newline at end of file +workspace = true diff --git a/crates/parser/src/grammar/expressions.rs b/crates/parser/src/grammar/expressions.rs index e346ece2f94b6..c8626111145de 100644 --- a/crates/parser/src/grammar/expressions.rs +++ b/crates/parser/src/grammar/expressions.rs @@ -371,7 +371,15 @@ fn lhs(p: &mut Parser<'_>, r: Restrictions) -> Option<(CompletedMarker, BlockLik if p.at(op) { m = p.start(); p.bump(op); - if p.at_ts(EXPR_FIRST) && !(r.forbid_structs && p.at(T!['{'])) { + + // test closure_range_method_call + // fn foo() { + // || .. .method(); + // || .. .field; + // } + let has_access_after = p.at(T![.]) && p.nth_at(1, SyntaxKind::IDENT); + let struct_forbidden = r.forbid_structs && p.at(T!['{']); + if p.at_ts(EXPR_FIRST) && !has_access_after && !struct_forbidden { expr_bp(p, None, r, 2); } let cm = m.complete(p, RANGE_EXPR); diff --git a/crates/parser/src/lexed_str.rs b/crates/parser/src/lexed_str.rs index b9e7566fdf9bc..f47ec49df1d9f 100644 --- a/crates/parser/src/lexed_str.rs +++ b/crates/parser/src/lexed_str.rs @@ -8,8 +8,6 @@ //! Note that these tokens, unlike the tokens we feed into the parser, do //! include info about comments and whitespace. -use rustc_dependencies::lexer as rustc_lexer; - use std::ops; use rustc_lexer::unescape::{EscapeError, Mode}; diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index d9b3f46f2001c..ed0aec3cab32a 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -21,6 +21,11 @@ #![allow(rustdoc::private_intra_doc_links)] #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] +#[cfg(not(feature = "in-rust-tree"))] +extern crate ra_ap_rustc_lexer as rustc_lexer; +#[cfg(feature = "in-rust-tree")] +extern crate rustc_lexer; + mod lexed_str; mod token_set; mod syntax_kind; diff --git a/crates/parser/test_data/parser/inline/ok/0208_closure_range_method_call.rast b/crates/parser/test_data/parser/inline/ok/0208_closure_range_method_call.rast new file mode 100644 index 0000000000000..542711339d19c --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/0208_closure_range_method_call.rast @@ -0,0 +1,49 @@ +SOURCE_FILE + FN + FN_KW "fn" + WHITESPACE " " + NAME + IDENT "foo" + PARAM_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + EXPR_STMT + METHOD_CALL_EXPR + CLOSURE_EXPR + PARAM_LIST + PIPE "|" + PIPE "|" + WHITESPACE " " + RANGE_EXPR + DOT2 ".." + WHITESPACE " " + DOT "." + NAME_REF + IDENT "method" + ARG_LIST + L_PAREN "(" + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n " + EXPR_STMT + FIELD_EXPR + CLOSURE_EXPR + PARAM_LIST + PIPE "|" + PIPE "|" + WHITESPACE " " + RANGE_EXPR + DOT2 ".." + WHITESPACE " " + DOT "." + NAME_REF + IDENT "field" + SEMICOLON ";" + WHITESPACE "\n" + R_CURLY "}" + WHITESPACE "\n" diff --git a/crates/parser/test_data/parser/inline/ok/0208_closure_range_method_call.rs b/crates/parser/test_data/parser/inline/ok/0208_closure_range_method_call.rs new file mode 100644 index 0000000000000..a81d3c37133a6 --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/0208_closure_range_method_call.rs @@ -0,0 +1,4 @@ +fn foo() { + || .. .method(); + || .. .field; +} diff --git a/crates/proc-macro-api/src/lib.rs b/crates/proc-macro-api/src/lib.rs index a87becd63e288..208051113a7d2 100644 --- a/crates/proc-macro-api/src/lib.rs +++ b/crates/proc-macro-api/src/lib.rs @@ -14,8 +14,10 @@ mod version; use indexmap::IndexSet; use paths::AbsPathBuf; use span::Span; -use std::{fmt, io, sync::Mutex}; -use triomphe::Arc; +use std::{ + fmt, io, + sync::{Arc, Mutex}, +}; use serde::{Deserialize, Serialize}; @@ -81,9 +83,11 @@ impl PartialEq for ProcMacro { } } +#[derive(Clone, Debug)] pub struct ServerError { pub message: String, - pub io: Option, + // io::Error isn't Clone for some reason + pub io: Option>, } impl fmt::Display for ServerError { diff --git a/crates/proc-macro-api/src/process.rs b/crates/proc-macro-api/src/process.rs index 3494164c0675c..5ce601bce6929 100644 --- a/crates/proc-macro-api/src/process.rs +++ b/crates/proc-macro-api/src/process.rs @@ -1,8 +1,9 @@ //! Handle process life-time and message passing for proc-macro client use std::{ - io::{self, BufRead, BufReader, Write}, + io::{self, BufRead, BufReader, Read, Write}, process::{Child, ChildStdin, ChildStdout, Command, Stdio}, + sync::Arc, }; use paths::{AbsPath, AbsPathBuf}; @@ -15,9 +16,11 @@ use crate::{ #[derive(Debug)] pub(crate) struct ProcMacroProcessSrv { - _process: Process, + process: Process, stdin: ChildStdin, stdout: BufReader, + /// Populated when the server exits. + server_exited: Option, version: u32, mode: SpanMode, } @@ -29,9 +32,10 @@ impl ProcMacroProcessSrv { let (stdin, stdout) = process.stdio().expect("couldn't access child stdio"); io::Result::Ok(ProcMacroProcessSrv { - _process: process, + process, stdin, stdout, + server_exited: None, version: 0, mode: SpanMode::Id, }) @@ -105,8 +109,35 @@ impl ProcMacroProcessSrv { } pub(crate) fn send_task(&mut self, req: Request) -> Result { + if let Some(server_error) = &self.server_exited { + return Err(server_error.clone()); + } + let mut buf = String::new(); - send_request(&mut self.stdin, &mut self.stdout, req, &mut buf) + send_request(&mut self.stdin, &mut self.stdout, req, &mut buf).map_err(|e| { + if e.io.as_ref().map(|it| it.kind()) == Some(io::ErrorKind::BrokenPipe) { + match self.process.child.try_wait() { + Ok(None) => e, + Ok(Some(status)) => { + let mut msg = String::new(); + if !status.success() { + if let Some(stderr) = self.process.child.stderr.as_mut() { + _ = stderr.read_to_string(&mut msg); + } + } + let server_error = ServerError { + message: format!("server exited with {status}: {msg}"), + io: None, + }; + self.server_exited = Some(server_error.clone()); + server_error + } + Err(_) => e, + } + } else { + e + } + }) } } @@ -131,12 +162,19 @@ impl Process { } fn mk_child(path: &AbsPath, null_stderr: bool) -> io::Result { - Command::new(path.as_os_str()) - .env("RUST_ANALYZER_INTERNALS_DO_NOT_USE", "this is unstable") + let mut cmd = Command::new(path.as_os_str()); + cmd.env("RUST_ANALYZER_INTERNALS_DO_NOT_USE", "this is unstable") .stdin(Stdio::piped()) .stdout(Stdio::piped()) - .stderr(if null_stderr { Stdio::null() } else { Stdio::inherit() }) - .spawn() + .stderr(if null_stderr { Stdio::null() } else { Stdio::inherit() }); + if cfg!(windows) { + let mut path_var = std::ffi::OsString::new(); + path_var.push(path.parent().unwrap().parent().unwrap().as_os_str()); + path_var.push("\\bin;"); + path_var.push(std::env::var_os("PATH").unwrap_or_default()); + cmd.env("PATH", path_var); + } + cmd.spawn() } fn send_request( @@ -145,9 +183,13 @@ fn send_request( req: Request, buf: &mut String, ) -> Result { - req.write(&mut writer) - .map_err(|err| ServerError { message: "failed to write request".into(), io: Some(err) })?; - let res = Response::read(&mut reader, buf) - .map_err(|err| ServerError { message: "failed to read response".into(), io: Some(err) })?; + req.write(&mut writer).map_err(|err| ServerError { + message: "failed to write request".into(), + io: Some(Arc::new(err)), + })?; + let res = Response::read(&mut reader, buf).map_err(|err| ServerError { + message: "failed to read response".into(), + io: Some(Arc::new(err)), + })?; res.ok_or_else(|| ServerError { message: "server exited".into(), io: None }) } diff --git a/crates/proc-macro-srv-cli/src/main.rs b/crates/proc-macro-srv-cli/src/main.rs index 87f7555b02ce4..af9a03826ffc0 100644 --- a/crates/proc-macro-srv-cli/src/main.rs +++ b/crates/proc-macro-srv-cli/src/main.rs @@ -24,7 +24,8 @@ fn main() -> std::io::Result<()> { #[cfg(not(any(feature = "sysroot-abi", rust_analyzer)))] fn run() -> io::Result<()> { - panic!("proc-macro-srv-cli requires the `sysroot-abi` feature to be enabled"); + eprintln!("proc-macro-srv-cli requires the `sysroot-abi` feature to be enabled"); + std::process::exit(70); } #[cfg(any(feature = "sysroot-abi", rust_analyzer))] diff --git a/crates/proc-macro-srv/Cargo.toml b/crates/proc-macro-srv/Cargo.toml index 9c4375559c11b..ba17ea6f7b439 100644 --- a/crates/proc-macro-srv/Cargo.toml +++ b/crates/proc-macro-srv/Cargo.toml @@ -37,7 +37,7 @@ expect-test = "1.4.0" proc-macro-test.path = "./proc-macro-test" [features] -sysroot-abi = ["proc-macro-test/sysroot-abi"] +sysroot-abi = [] in-rust-tree = ["mbe/in-rust-tree", "sysroot-abi"] [lints] diff --git a/crates/proc-macro-srv/proc-macro-test/Cargo.toml b/crates/proc-macro-srv/proc-macro-test/Cargo.toml index 90545bb5130c7..7977afb1cbd23 100644 --- a/crates/proc-macro-srv/proc-macro-test/Cargo.toml +++ b/crates/proc-macro-srv/proc-macro-test/Cargo.toml @@ -14,6 +14,3 @@ cargo_metadata = "0.18.1" # local deps toolchain.workspace = true - -[features] -sysroot-abi = [] diff --git a/crates/proc-macro-srv/proc-macro-test/build.rs b/crates/proc-macro-srv/proc-macro-test/build.rs index 7299147686df7..6cf2b5643e579 100644 --- a/crates/proc-macro-srv/proc-macro-test/build.rs +++ b/crates/proc-macro-srv/proc-macro-test/build.rs @@ -17,11 +17,24 @@ use cargo_metadata::Message; fn main() { println!("cargo:rerun-if-changed=imp"); - println!("cargo:rerun-if-env-changed=PROC_MACRO_TEST_TOOLCHAIN"); + + let has_features = env::var_os("RUSTC_BOOTSTRAP").is_some() + || String::from_utf8( + Command::new(toolchain::cargo()).arg("--version").output().unwrap().stdout, + ) + .unwrap() + .contains("nightly"); let out_dir = env::var_os("OUT_DIR").unwrap(); let out_dir = Path::new(&out_dir); + if !has_features { + println!("proc-macro-test testing only works on nightly toolchains"); + let info_path = out_dir.join("proc_macro_test_location.txt"); + fs::File::create(info_path).unwrap(); + return; + } + let name = "proc-macro-test-impl"; let version = "0.0.0"; @@ -53,15 +66,7 @@ fn main() { let target_dir = out_dir.join("target"); - let mut cmd = if let Ok(toolchain) = std::env::var("PROC_MACRO_TEST_TOOLCHAIN") { - // leverage rustup to find user-specific toolchain - let mut cmd = Command::new("cargo"); - cmd.arg(format!("+{toolchain}")); - cmd - } else { - Command::new(toolchain::cargo()) - }; - + let mut cmd = Command::new(toolchain::cargo()); cmd.current_dir(&staging_dir) .args(["build", "-p", "proc-macro-test-impl", "--message-format", "json"]) // Explicit override the target directory to avoid using the same one which the parent @@ -70,9 +75,6 @@ fn main() { // instance to use the same target directory. .arg("--target-dir") .arg(&target_dir); - if cfg!(feature = "sysroot-abi") { - cmd.args(["--features", "sysroot-abi"]); - } if let Ok(target) = std::env::var("TARGET") { cmd.args(["--target", &target]); diff --git a/crates/proc-macro-srv/proc-macro-test/imp/Cargo.toml b/crates/proc-macro-srv/proc-macro-test/imp/Cargo.toml index dc94fcd61a4f7..fa189752b76f3 100644 --- a/crates/proc-macro-srv/proc-macro-test/imp/Cargo.toml +++ b/crates/proc-macro-srv/proc-macro-test/imp/Cargo.toml @@ -13,7 +13,4 @@ proc-macro = true # this crate should not have any dependencies, since it uses its own workspace, # and its own `Cargo.lock` -[features] -sysroot-abi = [] - [workspace] diff --git a/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs b/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs index b8aad4acefcf0..d9018b1b87d34 100644 --- a/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs +++ b/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs @@ -1,8 +1,5 @@ //! Exports a few trivial procedural macros for testing. -#![allow(unexpected_cfgs)] -#![cfg(feature = "sysroot-abi")] -#![cfg(any(feature = "sysroot-abi", rust_analyzer))] #![warn(rust_2018_idioms, unused_lifetimes)] #![feature(proc_macro_span, proc_macro_def_site)] diff --git a/crates/proc-macro-srv/src/lib.rs b/crates/proc-macro-srv/src/lib.rs index f1575a5b0bd83..67b9f57a1636c 100644 --- a/crates/proc-macro-srv/src/lib.rs +++ b/crates/proc-macro-srv/src/lib.rs @@ -11,11 +11,13 @@ //! rustc rather than `unstable`. (Although in general ABI compatibility is still an issue)… #![cfg(any(feature = "sysroot-abi", rust_analyzer))] -#![feature(proc_macro_internals, proc_macro_diagnostic, proc_macro_span, rustc_private)] +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] +#![feature(proc_macro_internals, proc_macro_diagnostic, proc_macro_span)] #![warn(rust_2018_idioms, unused_lifetimes)] #![allow(unreachable_pub, internal_features)] extern crate proc_macro; +#[cfg(feature = "in-rust-tree")] extern crate rustc_driver as _; mod dylib; diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index 00cc7c30ee3e0..c04eddc56fb7f 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -1398,7 +1398,7 @@ fn sysroot_to_crate_graph( let public_deps = SysrootPublicDeps { deps: sysroot .public_deps() - .map(|(name, idx, prelude)| (name, sysroot_crates[&idx], prelude)) + .filter_map(|(name, idx, prelude)| Some((name, *sysroot_crates.get(&idx)?, prelude))) .collect::>(), }; diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index ad24d6d28cd7a..76414160716c8 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml @@ -49,7 +49,6 @@ flycheck.workspace = true hir-def.workspace = true hir-ty.workspace = true hir.workspace = true -rustc-dependencies.workspace = true ide-db.workspace = true # This should only be used in CLI ide-ssr.workspace = true @@ -89,11 +88,10 @@ in-rust-tree = [ "ide/in-rust-tree", "syntax/in-rust-tree", "parser/in-rust-tree", - "rustc-dependencies/in-rust-tree", "hir/in-rust-tree", "hir-def/in-rust-tree", "hir-ty/in-rust-tree", ] [lints] -workspace = true \ No newline at end of file +workspace = true diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index f57a27305f03c..c4a29e0cbb03b 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -3,7 +3,7 @@ //! //! Each tick provides an immutable snapshot of the state as `WorldSnapshot`. -use std::time::Instant; +use std::{collections::hash_map::Entry, time::Instant}; use crossbeam_channel::{unbounded, Receiver, Sender}; use flycheck::FlycheckHandle; @@ -21,7 +21,7 @@ use proc_macro_api::ProcMacroServer; use project_model::{CargoWorkspace, ProjectWorkspace, Target, WorkspaceBuildScripts}; use rustc_hash::{FxHashMap, FxHashSet}; use triomphe::Arc; -use vfs::{AnchoredPathBuf, Vfs}; +use vfs::{AnchoredPathBuf, ChangedFile, Vfs}; use crate::{ config::{Config, ConfigError}, @@ -217,8 +217,8 @@ impl GlobalState { pub(crate) fn process_changes(&mut self) -> bool { let _p = profile::span("GlobalState::process_changes"); - let mut file_changes = FxHashMap::default(); - let (change, changed_files, workspace_structure_change) = { + let mut file_changes = FxHashMap::<_, (bool, ChangedFile)>::default(); + let (change, modified_rust_files, workspace_structure_change) = { let mut change = Change::new(); let mut guard = self.vfs.write(); let changed_files = guard.0.take_changes(); @@ -233,64 +233,63 @@ impl GlobalState { // id that is followed by a delete we actually skip observing the file text from the // earlier event, to avoid problems later on. for changed_file in changed_files { - use vfs::ChangeKind::*; - - file_changes - .entry(changed_file.file_id) - .and_modify(|(change, just_created)| { - // None -> Delete => keep - // Create -> Delete => collapse - // - match (change, just_created, changed_file.change_kind) { + use vfs::Change::*; + match file_changes.entry(changed_file.file_id) { + Entry::Occupied(mut o) => { + let (just_created, change) = o.get_mut(); + match (&mut change.change, just_created, changed_file.change) { // latter `Delete` wins (change, _, Delete) => *change = Delete, // merge `Create` with `Create` or `Modify` - (Create, _, Create | Modify) => {} + (Create(prev), _, Create(new) | Modify(new)) => *prev = new, // collapse identical `Modify`es - (Modify, _, Modify) => {} + (Modify(prev), _, Modify(new)) => *prev = new, // equivalent to `Modify` - (change @ Delete, just_created, Create) => { - *change = Modify; + (change @ Delete, just_created, Create(new)) => { + *change = Modify(new); *just_created = true; } // shouldn't occur, but collapse into `Create` - (change @ Delete, just_created, Modify) => { - *change = Create; + (change @ Delete, just_created, Modify(new)) => { + *change = Create(new); *just_created = true; } - // shouldn't occur, but collapse into `Modify` - (Modify, _, Create) => {} + // shouldn't occur, but keep the Create + (prev @ Modify(_), _, new @ Create(_)) => *prev = new, } - }) - .or_insert(( - changed_file.change_kind, - matches!(changed_file.change_kind, Create), - )); + } + Entry::Vacant(v) => { + _ = v.insert((matches!(&changed_file.change, Create(_)), changed_file)) + } + } } let changed_files: Vec<_> = file_changes .into_iter() - .filter(|(_, (change_kind, just_created))| { - !matches!((change_kind, just_created), (vfs::ChangeKind::Delete, true)) + .filter(|(_, (just_created, change))| { + !(*just_created && matches!(change.change, vfs::Change::Delete)) }) - .map(|(file_id, (change_kind, _))| vfs::ChangedFile { file_id, change_kind }) + .map(|(file_id, (_, change))| vfs::ChangedFile { file_id, ..change }) .collect(); let mut workspace_structure_change = None; // A file was added or deleted let mut has_structure_changes = false; let mut bytes = vec![]; - for file in &changed_files { + let mut modified_rust_files = vec![]; + for file in changed_files { let vfs_path = &vfs.file_path(file.file_id); if let Some(path) = vfs_path.as_path() { let path = path.to_path_buf(); - if reload::should_refresh_for_change(&path, file.change_kind) { + if reload::should_refresh_for_change(&path, file.kind()) { workspace_structure_change = Some((path.clone(), false)); } if file.is_created_or_deleted() { has_structure_changes = true; workspace_structure_change = Some((path, self.crate_graph_file_dependencies.contains(vfs_path))); + } else if path.extension() == Some("rs".as_ref()) { + modified_rust_files.push(file.file_id); } } @@ -299,10 +298,8 @@ impl GlobalState { self.diagnostics.clear_native_for(file.file_id); } - let text = if file.exists() { - let bytes = vfs.file_contents(file.file_id).to_vec(); - - String::from_utf8(bytes).ok().and_then(|text| { + let text = if let vfs::Change::Create(v) | vfs::Change::Modify(v) = file.change { + String::from_utf8(v).ok().and_then(|text| { // FIXME: Consider doing normalization in the `vfs` instead? That allows // getting rid of some locking let (text, line_endings) = LineEndings::normalize(text); @@ -327,11 +324,10 @@ impl GlobalState { let roots = self.source_root_config.partition(vfs); change.set_roots(roots); } - (change, changed_files, workspace_structure_change) + (change, modified_rust_files, workspace_structure_change) }; self.analysis_host.apply_change(change); - { let raw_database = self.analysis_host.raw_database(); // FIXME: ideally we should only trigger a workspace fetch for non-library changes @@ -343,13 +339,12 @@ impl GlobalState { force_crate_graph_reload, ); } - self.proc_macro_changed = - changed_files.iter().filter(|file| !file.is_created_or_deleted()).any(|file| { - let crates = raw_database.relevant_crates(file.file_id); - let crate_graph = raw_database.crate_graph(); + self.proc_macro_changed = modified_rust_files.into_iter().any(|file_id| { + let crates = raw_database.relevant_crates(file_id); + let crate_graph = raw_database.crate_graph(); - crates.iter().any(|&krate| crate_graph[krate].is_proc_macro) - }); + crates.iter().any(|&krate| crate_graph[krate].is_proc_macro) + }); } true @@ -494,10 +489,6 @@ impl GlobalStateSnapshot { }) } - pub(crate) fn vfs_memory_usage(&self) -> usize { - self.vfs_read().memory_usage() - } - pub(crate) fn file_exists(&self, file_id: FileId) -> bool { self.vfs.read().0.exists(file_id) } diff --git a/crates/rust-analyzer/src/handlers/notification.rs b/crates/rust-analyzer/src/handlers/notification.rs index 7e6219991b665..ce69d612255a5 100644 --- a/crates/rust-analyzer/src/handlers/notification.rs +++ b/crates/rust-analyzer/src/handlers/notification.rs @@ -59,7 +59,13 @@ pub(crate) fn handle_did_open_text_document( if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) { let already_exists = state .mem_docs - .insert(path.clone(), DocumentData::new(params.text_document.version)) + .insert( + path.clone(), + DocumentData::new( + params.text_document.version, + params.text_document.text.clone().into_bytes(), + ), + ) .is_err(); if already_exists { tracing::error!("duplicate DidOpenTextDocument: {}", path); @@ -76,11 +82,12 @@ pub(crate) fn handle_did_change_text_document( let _p = profile::span("handle_did_change_text_document"); if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) { - match state.mem_docs.get_mut(&path) { + let data = match state.mem_docs.get_mut(&path) { Some(doc) => { // The version passed in DidChangeTextDocument is the version after all edits are applied // so we should apply it before the vfs is notified. doc.version = params.text_document.version; + &mut doc.data } None => { tracing::error!("unexpected DidChangeTextDocument: {}", path); @@ -88,16 +95,16 @@ pub(crate) fn handle_did_change_text_document( } }; - let text = apply_document_changes( + let new_contents = apply_document_changes( state.config.position_encoding(), - || { - let vfs = &state.vfs.read().0; - let file_id = vfs.file_id(&path).unwrap(); - std::str::from_utf8(vfs.file_contents(file_id)).unwrap().into() - }, + std::str::from_utf8(data).unwrap(), params.content_changes, - ); - state.vfs.write().0.set_file_contents(path, Some(text.into_bytes())); + ) + .into_bytes(); + if *data != new_contents { + *data = new_contents.clone(); + state.vfs.write().0.set_file_contents(path, Some(new_contents)); + } } Ok(()) } diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs index 13544558c50c9..22c7e9b0503c5 100644 --- a/crates/rust-analyzer/src/handlers/request.rs +++ b/crates/rust-analyzer/src/handlers/request.rs @@ -103,7 +103,6 @@ pub(crate) fn handle_analyzer_status( .collect::>() ); } - format_to!(buf, "\nVfs memory usage: {}\n", profile::Bytes::new(snap.vfs_memory_usage() as _)); buf.push_str("\nAnalysis:\n"); buf.push_str( &snap diff --git a/crates/rust-analyzer/src/lsp/utils.rs b/crates/rust-analyzer/src/lsp/utils.rs index a4417e4d4a143..fa5ea5b57db00 100644 --- a/crates/rust-analyzer/src/lsp/utils.rs +++ b/crates/rust-analyzer/src/lsp/utils.rs @@ -168,7 +168,7 @@ impl GlobalState { pub(crate) fn apply_document_changes( encoding: PositionEncoding, - file_contents: impl FnOnce() -> String, + file_contents: &str, mut content_changes: Vec, ) -> String { // If at least one of the changes is a full document change, use the last @@ -179,7 +179,7 @@ pub(crate) fn apply_document_changes( let text = mem::take(&mut content_changes[idx].text); (text, &content_changes[idx + 1..]) } - None => (file_contents(), &content_changes[..]), + None => (file_contents.to_owned(), &content_changes[..]), }; if content_changes.is_empty() { return text; @@ -276,11 +276,11 @@ mod tests { } let encoding = PositionEncoding::Wide(WideEncoding::Utf16); - let text = apply_document_changes(encoding, || String::new(), vec![]); + let text = apply_document_changes(encoding, "", vec![]); assert_eq!(text, ""); let text = apply_document_changes( encoding, - || text, + &text, vec![TextDocumentContentChangeEvent { range: None, range_length: None, @@ -288,49 +288,46 @@ mod tests { }], ); assert_eq!(text, "the"); - let text = apply_document_changes(encoding, || text, c![0, 3; 0, 3 => " quick"]); + let text = apply_document_changes(encoding, &text, c![0, 3; 0, 3 => " quick"]); assert_eq!(text, "the quick"); let text = - apply_document_changes(encoding, || text, c![0, 0; 0, 4 => "", 0, 5; 0, 5 => " foxes"]); + apply_document_changes(encoding, &text, c![0, 0; 0, 4 => "", 0, 5; 0, 5 => " foxes"]); assert_eq!(text, "quick foxes"); - let text = apply_document_changes(encoding, || text, c![0, 11; 0, 11 => "\ndream"]); + let text = apply_document_changes(encoding, &text, c![0, 11; 0, 11 => "\ndream"]); assert_eq!(text, "quick foxes\ndream"); - let text = apply_document_changes(encoding, || text, c![1, 0; 1, 0 => "have "]); + let text = apply_document_changes(encoding, &text, c![1, 0; 1, 0 => "have "]); assert_eq!(text, "quick foxes\nhave dream"); let text = apply_document_changes( encoding, - || text, + &text, c![0, 0; 0, 0 => "the ", 1, 4; 1, 4 => " quiet", 1, 16; 1, 16 => "s\n"], ); assert_eq!(text, "the quick foxes\nhave quiet dreams\n"); - let text = apply_document_changes( - encoding, - || text, - c![0, 15; 0, 15 => "\n", 2, 17; 2, 17 => "\n"], - ); + let text = + apply_document_changes(encoding, &text, c![0, 15; 0, 15 => "\n", 2, 17; 2, 17 => "\n"]); assert_eq!(text, "the quick foxes\n\nhave quiet dreams\n\n"); let text = apply_document_changes( encoding, - || text, + &text, c![1, 0; 1, 0 => "DREAM", 2, 0; 2, 0 => "they ", 3, 0; 3, 0 => "DON'T THEY?"], ); assert_eq!(text, "the quick foxes\nDREAM\nthey have quiet dreams\nDON'T THEY?\n"); let text = - apply_document_changes(encoding, || text, c![0, 10; 1, 5 => "", 2, 0; 2, 12 => ""]); + apply_document_changes(encoding, &text, c![0, 10; 1, 5 => "", 2, 0; 2, 12 => ""]); assert_eq!(text, "the quick \nthey have quiet dreams\n"); let text = String::from("❤️"); - let text = apply_document_changes(encoding, || text, c![0, 0; 0, 0 => "a"]); + let text = apply_document_changes(encoding, &text, c![0, 0; 0, 0 => "a"]); assert_eq!(text, "a❤️"); let text = String::from("a\nb"); let text = - apply_document_changes(encoding, || text, c![0, 1; 1, 0 => "\nțc", 0, 1; 1, 1 => "d"]); + apply_document_changes(encoding, &text, c![0, 1; 1, 0 => "\nțc", 0, 1; 1, 1 => "d"]); assert_eq!(text, "adcb"); let text = String::from("a\nb"); let text = - apply_document_changes(encoding, || text, c![0, 1; 1, 0 => "ț\nc", 0, 2; 0, 2 => "c"]); + apply_document_changes(encoding, &text, c![0, 1; 1, 0 => "ț\nc", 0, 2; 0, 2 => "c"]); assert_eq!(text, "ațc\ncb"); } diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index cdf41c955d26f..ca7893faf5dd7 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -571,13 +571,18 @@ impl GlobalState { } fn handle_vfs_msg(&mut self, message: vfs::loader::Message) { + let is_changed = matches!(message, vfs::loader::Message::Changed { .. }); match message { - vfs::loader::Message::Loaded { files } => { + vfs::loader::Message::Changed { files } | vfs::loader::Message::Loaded { files } => { let vfs = &mut self.vfs.write().0; for (path, contents) in files { let path = VfsPath::from(path); + // if the file is in mem docs, it's managed by the client via notifications + // so only set it if its not in there if !self.mem_docs.contains(&path) { - vfs.set_file_contents(path, contents); + if is_changed || vfs.file_id(&path).is_none() { + vfs.set_file_contents(path, contents); + } } } } diff --git a/crates/rust-analyzer/src/mem_docs.rs b/crates/rust-analyzer/src/mem_docs.rs index 45a1dab9772fa..6a93a0ebb4cec 100644 --- a/crates/rust-analyzer/src/mem_docs.rs +++ b/crates/rust-analyzer/src/mem_docs.rs @@ -62,10 +62,11 @@ impl MemDocs { #[derive(Debug, Clone)] pub(crate) struct DocumentData { pub(crate) version: i32, + pub(crate) data: Vec, } impl DocumentData { - pub(crate) fn new(version: i32) -> Self { - DocumentData { version } + pub(crate) fn new(version: i32, data: Vec) -> Self { + DocumentData { version, data } } } diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 91dc6c2e4b411..8e3fa7fa4dace 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -503,10 +503,9 @@ impl GlobalState { match vfs.file_id(&vfs_path) { Some(file_id) => Some(file_id), None => { - if !self.mem_docs.contains(&vfs_path) { - let contents = loader.handle.load_sync(path); - vfs.set_file_contents(vfs_path.clone(), contents); - } + // FIXME: Consider not loading this here? + let contents = loader.handle.load_sync(path); + vfs.set_file_contents(vfs_path.clone(), contents); vfs.file_id(&vfs_path) } } diff --git a/crates/rustc-dependencies/Cargo.toml b/crates/rustc-dependencies/Cargo.toml deleted file mode 100644 index 0bf04301df169..0000000000000 --- a/crates/rustc-dependencies/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -name = "rustc-dependencies" -version = "0.0.0" -description = "TBD" - -rust-version.workspace = true -edition.workspace = true -license.workspace = true -authors.workspace = true - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -ra-ap-rustc_lexer = { version = "0.21.0" } -ra-ap-rustc_parse_format = { version = "0.21.0", default-features = false } -ra-ap-rustc_index = { version = "0.21.0", default-features = false } -ra-ap-rustc_abi = { version = "0.21.0", default-features = false } - -[features] -in-rust-tree = [] - -[lints] -workspace = true \ No newline at end of file diff --git a/crates/rustc-dependencies/src/lib.rs b/crates/rustc-dependencies/src/lib.rs deleted file mode 100644 index 13fcbc4919370..0000000000000 --- a/crates/rustc-dependencies/src/lib.rs +++ /dev/null @@ -1,48 +0,0 @@ -//! A wrapper around rustc internal crates, which enables switching between compiler provided -//! ones and stable ones published in crates.io - -#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] - -#[cfg(feature = "in-rust-tree")] -extern crate rustc_lexer; - -pub mod lexer { - #[cfg(not(feature = "in-rust-tree"))] - pub use ::ra_ap_rustc_lexer::*; - - #[cfg(feature = "in-rust-tree")] - pub use ::rustc_lexer::*; -} - -#[cfg(feature = "in-rust-tree")] -extern crate rustc_parse_format; - -pub mod parse_format { - #[cfg(not(feature = "in-rust-tree"))] - pub use ::ra_ap_rustc_parse_format::*; - - #[cfg(feature = "in-rust-tree")] - pub use ::rustc_parse_format::*; -} - -#[cfg(feature = "in-rust-tree")] -extern crate rustc_abi; - -pub mod abi { - #[cfg(not(feature = "in-rust-tree"))] - pub use ::ra_ap_rustc_abi::*; - - #[cfg(feature = "in-rust-tree")] - pub use ::rustc_abi::*; -} - -#[cfg(feature = "in-rust-tree")] -extern crate rustc_index; - -pub mod index { - #[cfg(not(feature = "in-rust-tree"))] - pub use ::ra_ap_rustc_index::*; - - #[cfg(feature = "in-rust-tree")] - pub use ::rustc_index::*; -} diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml index 40a93fec2cec2..9f78614bba66b 100644 --- a/crates/syntax/Cargo.toml +++ b/crates/syntax/Cargo.toml @@ -23,7 +23,7 @@ indexmap.workspace = true smol_str.workspace = true triomphe.workspace = true -rustc-dependencies.workspace = true +ra-ap-rustc_lexer.workspace = true parser.workspace = true profile.workspace = true @@ -41,7 +41,7 @@ test-utils.workspace = true sourcegen.workspace = true [features] -in-rust-tree = ["rustc-dependencies/in-rust-tree"] +in-rust-tree = [] [lints] -workspace = true \ No newline at end of file +workspace = true diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs index 8618018c0b6a5..1c6157de55958 100644 --- a/crates/syntax/src/ast/node_ext.rs +++ b/crates/syntax/src/ast/node_ext.rs @@ -285,14 +285,16 @@ impl ast::Path { self.first_qualifier_or_self().segment() } - // FIXME: Check usages of Self::segments, they might be wrong because of the logic of the bloew function - pub fn segments_of_this_path_only_rev(&self) -> impl Iterator + Clone { - self.qualifiers_and_self().filter_map(|it| it.segment()) - } - pub fn segments(&self) -> impl Iterator + Clone { - successors(self.first_segment(), |p| { - p.parent_path().parent_path().and_then(|p| p.segment()) + let path_range = self.syntax().text_range(); + successors(self.first_segment(), move |p| { + p.parent_path().parent_path().and_then(|p| { + if path_range.contains_range(p.syntax().text_range()) { + p.segment() + } else { + None + } + }) }) } @@ -300,10 +302,6 @@ impl ast::Path { successors(self.qualifier(), |p| p.qualifier()) } - pub fn qualifiers_and_self(&self) -> impl Iterator + Clone { - successors(Some(self.clone()), |p| p.qualifier()) - } - pub fn top_path(&self) -> ast::Path { let mut this = self.clone(); while let Some(path) = this.parent_path() { diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs index d5d565a015a0d..ede392fc62a2c 100644 --- a/crates/syntax/src/ast/token_ext.rs +++ b/crates/syntax/src/ast/token_ext.rs @@ -2,8 +2,6 @@ use std::borrow::Cow; -use rustc_dependencies::lexer as rustc_lexer; - use rustc_lexer::unescape::{ unescape_byte, unescape_c_string, unescape_char, unescape_literal, CStrUnit, Mode, }; diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs index d600698040dc7..1b41596a5f27b 100644 --- a/crates/syntax/src/lib.rs +++ b/crates/syntax/src/lib.rs @@ -22,6 +22,11 @@ #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] #![warn(rust_2018_idioms, unused_lifetimes)] +#[cfg(not(feature = "in-rust-tree"))] +extern crate ra_ap_rustc_lexer as rustc_lexer; +#[cfg(feature = "in-rust-tree")] +extern crate rustc_lexer; + #[allow(unused)] macro_rules! eprintln { ($($tt:tt)*) => { stdx::eprintln!($($tt)*) }; diff --git a/crates/syntax/src/validation.rs b/crates/syntax/src/validation.rs index eabbda2c3983c..6c6916c585f1f 100644 --- a/crates/syntax/src/validation.rs +++ b/crates/syntax/src/validation.rs @@ -5,7 +5,7 @@ mod block; use rowan::Direction; -use rustc_dependencies::lexer::unescape::{self, unescape_literal, Mode}; +use rustc_lexer::unescape::{self, unescape_literal, Mode}; use crate::{ algo, diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index 1f3136404c615..140bb08042785 100644 --- a/crates/test-utils/src/minicore.rs +++ b/crates/test-utils/src/minicore.rs @@ -25,6 +25,7 @@ //! derive: //! discriminant: //! drop: +//! env: option //! eq: sized //! error: fmt //! fmt: result, transmute, coerce_unsized @@ -1450,6 +1451,15 @@ mod macros { #[macro_export] macro_rules! concat {} // endregion:concat + + // region:env + #[rustc_builtin_macro] + #[macro_export] + macro_rules! env {} + #[rustc_builtin_macro] + #[macro_export] + macro_rules! option_env {} + // endregion:env } // region:non_zero diff --git a/crates/vfs-notify/src/lib.rs b/crates/vfs-notify/src/lib.rs index 0306504371465..19b34ffe6b9d7 100644 --- a/crates/vfs-notify/src/lib.rs +++ b/crates/vfs-notify/src/lib.rs @@ -160,7 +160,7 @@ impl NotifyActor { Some((path, contents)) }) .collect(); - self.send(loader::Message::Loaded { files }); + self.send(loader::Message::Changed { files }); } } } diff --git a/crates/vfs/src/lib.rs b/crates/vfs/src/lib.rs index ef5b10ee9db2f..34a85818eb84b 100644 --- a/crates/vfs/src/lib.rs +++ b/crates/vfs/src/lib.rs @@ -1,8 +1,8 @@ //! # Virtual File System //! -//! VFS stores all files read by rust-analyzer. Reading file contents from VFS -//! always returns the same contents, unless VFS was explicitly modified with -//! [`set_file_contents`]. All changes to VFS are logged, and can be retrieved via +//! VFS records all file changes pushed to it via [`set_file_contents`]. +//! As such it only ever stores changes, not the actual content of a file at any given moment. +//! All file changes are logged, and can be retrieved via //! [`take_changes`] method. The pack of changes is then pushed to `salsa` and //! triggers incremental recomputation. //! @@ -84,40 +84,65 @@ impl FileId { /// safe because `FileId` is a newtype of `u32` impl nohash_hasher::IsEnabled for FileId {} -/// Storage for all files read by rust-analyzer. +/// Storage for all file changes and the file id to path mapping. /// /// For more information see the [crate-level](crate) documentation. #[derive(Default)] pub struct Vfs { interner: PathInterner, - data: Vec>>, + data: Vec, changes: Vec, } +#[derive(Copy, PartialEq, PartialOrd, Clone)] +pub enum FileState { + Exists, + Deleted, +} + /// Changed file in the [`Vfs`]. #[derive(Debug)] pub struct ChangedFile { /// Id of the changed file pub file_id: FileId, /// Kind of change - pub change_kind: ChangeKind, + pub change: Change, } impl ChangedFile { /// Returns `true` if the change is not [`Delete`](ChangeKind::Delete). pub fn exists(&self) -> bool { - self.change_kind != ChangeKind::Delete + !matches!(self.change, Change::Delete) } /// Returns `true` if the change is [`Create`](ChangeKind::Create) or - /// [`Delete`](ChangeKind::Delete). + /// [`Delete`](Change::Delete). pub fn is_created_or_deleted(&self) -> bool { - matches!(self.change_kind, ChangeKind::Create | ChangeKind::Delete) + matches!(self.change, Change::Create(_) | Change::Delete) } + + pub fn kind(&self) -> ChangeKind { + match self.change { + Change::Create(_) => ChangeKind::Create, + Change::Modify(_) => ChangeKind::Modify, + Change::Delete => ChangeKind::Delete, + } + } +} + +/// Kind of [file change](ChangedFile). +#[derive(Eq, PartialEq, Debug)] +pub enum Change { + /// The file was (re-)created + Create(Vec), + /// The file was modified + Modify(Vec), + /// The file was deleted + Delete, } /// Kind of [file change](ChangedFile). -#[derive(Eq, PartialEq, Copy, Clone, Debug)] +#[derive(Eq, PartialEq, Debug)] pub enum ChangeKind { /// The file was (re-)created Create, @@ -130,7 +155,7 @@ pub enum ChangeKind { impl Vfs { /// Id of the given path if it exists in the `Vfs` and is not deleted. pub fn file_id(&self, path: &VfsPath) -> Option { - self.interner.get(path).filter(|&it| self.get(it).is_some()) + self.interner.get(path).filter(|&it| matches!(self.get(it), FileState::Exists)) } /// File path corresponding to the given `file_id`. @@ -142,28 +167,13 @@ impl Vfs { self.interner.lookup(file_id).clone() } - /// File content corresponding to the given `file_id`. - /// - /// # Panics - /// - /// Panics if the id is not present in the `Vfs`, or if the corresponding file is - /// deleted. - pub fn file_contents(&self, file_id: FileId) -> &[u8] { - self.get(file_id).as_deref().unwrap() - } - - /// Returns the overall memory usage for the stored files. - pub fn memory_usage(&self) -> usize { - self.data.iter().flatten().map(|d| d.capacity()).sum() - } - /// Returns an iterator over the stored ids and their corresponding paths. /// /// This will skip deleted files. pub fn iter(&self) -> impl Iterator + '_ { (0..self.data.len()) .map(|it| FileId(it as u32)) - .filter(move |&file_id| self.get(file_id).is_some()) + .filter(move |&file_id| matches!(self.get(file_id), FileState::Exists)) .map(move |file_id| { let path = self.interner.lookup(file_id); (file_id, path) @@ -176,28 +186,21 @@ impl Vfs { /// /// If the path does not currently exists in the `Vfs`, allocates a new /// [`FileId`] for it. - pub fn set_file_contents(&mut self, path: VfsPath, mut contents: Option>) -> bool { + pub fn set_file_contents(&mut self, path: VfsPath, contents: Option>) -> bool { let file_id = self.alloc_file_id(path); - let change_kind = match (self.get(file_id), &contents) { - (None, None) => return false, - (Some(old), Some(new)) if old == new => return false, - (None, Some(_)) => ChangeKind::Create, - (Some(_), None) => ChangeKind::Delete, - (Some(_), Some(_)) => ChangeKind::Modify, + let change_kind = match (self.get(file_id), contents) { + (FileState::Deleted, None) => return false, + (FileState::Deleted, Some(v)) => Change::Create(v), + (FileState::Exists, None) => Change::Delete, + (FileState::Exists, Some(v)) => Change::Modify(v), }; - if let Some(contents) = &mut contents { - contents.shrink_to_fit(); - } - *self.get_mut(file_id) = contents; - self.changes.push(ChangedFile { file_id, change_kind }); + let changed_file = ChangedFile { file_id, change: change_kind }; + self.data[file_id.0 as usize] = + if changed_file.exists() { FileState::Exists } else { FileState::Deleted }; + self.changes.push(changed_file); true } - /// Returns `true` if the `Vfs` contains [changes](ChangedFile). - pub fn has_changes(&self) -> bool { - !self.changes.is_empty() - } - /// Drain and returns all the changes in the `Vfs`. pub fn take_changes(&mut self) -> Vec { mem::take(&mut self.changes) @@ -205,7 +208,7 @@ impl Vfs { /// Provides a panic-less way to verify file_id validity. pub fn exists(&self, file_id: FileId) -> bool { - self.get(file_id).is_some() + matches!(self.get(file_id), FileState::Exists) } /// Returns the id associated with `path` @@ -219,26 +222,17 @@ impl Vfs { let file_id = self.interner.intern(path); let idx = file_id.0 as usize; let len = self.data.len().max(idx + 1); - self.data.resize_with(len, || None); + self.data.resize(len, FileState::Deleted); file_id } - /// Returns the content associated with the given `file_id`. - /// - /// # Panics - /// - /// Panics if no file is associated to that id. - fn get(&self, file_id: FileId) -> &Option> { - &self.data[file_id.0 as usize] - } - - /// Mutably returns the content associated with the given `file_id`. + /// Returns the status of the file associated with the given `file_id`. /// /// # Panics /// /// Panics if no file is associated to that id. - fn get_mut(&mut self, file_id: FileId) -> &mut Option> { - &mut self.data[file_id.0 as usize] + fn get(&self, file_id: FileId) -> FileState { + self.data[file_id.0 as usize] } } diff --git a/crates/vfs/src/loader.rs b/crates/vfs/src/loader.rs index e2d74782ae526..89a544c81d8c9 100644 --- a/crates/vfs/src/loader.rs +++ b/crates/vfs/src/loader.rs @@ -51,6 +51,8 @@ pub enum Message { Progress { n_total: usize, n_done: usize, config_version: u32 }, /// The handle loaded the following files' content. Loaded { files: Vec<(AbsPathBuf, Option>)> }, + /// The handle loaded the following files' content. + Changed { files: Vec<(AbsPathBuf, Option>)> }, } /// Type that will receive [`Messages`](Message) from a [`Handle`]. @@ -199,6 +201,9 @@ impl fmt::Debug for Message { Message::Loaded { files } => { f.debug_struct("Loaded").field("n_files", &files.len()).finish() } + Message::Changed { files } => { + f.debug_struct("Changed").field("n_files", &files.len()).finish() + } Message::Progress { n_total, n_done, config_version } => f .debug_struct("Progress") .field("n_total", n_total) diff --git a/docs/dev/syntax.md b/docs/dev/syntax.md index 97e376787c828..fd6f220f4fa90 100644 --- a/docs/dev/syntax.md +++ b/docs/dev/syntax.md @@ -41,7 +41,6 @@ Syntax trees are a semi-transient data structure. In general, frontend does not keep syntax trees for all files in memory. Instead, it *lowers* syntax trees to more compact and rigid representation, which is not full-fidelity, but which can be mapped back to a syntax tree if so desired. - ### GreenNode GreenNode is a purely-functional tree with arbitrary arity. Conceptually, it is equivalent to the following run of the mill struct: @@ -500,7 +499,7 @@ Specifically, `TreeSink` constructs the tree in lockstep with draining the origi In the process, it records which tokens of the tree correspond to which tokens of the input, by using text ranges to identify syntax tokens. The end result is that parsing an expanded code yields a syntax tree and a mapping of text-ranges of the tree to original tokens. -To deal with precedence in cases like `$expr * 1`, we use special invisible parenthesis, which are explicitly handled by the parser +To deal with precedence in cases like `$expr * 1`, we use special invisible parenthesis, which are explicitly handled by the parser. ### Whitespace & Comments diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json index 8b9d5d4a74619..291cef926f82e 100644 --- a/editors/code/package-lock.json +++ b/editors/code/package-lock.json @@ -2290,9 +2290,9 @@ "dev": true }, "node_modules/follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "version": "1.15.4", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz", + "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==", "dev": true, "funding": [ { From 2d72ec71ec454fed5812a749683a3114ee4c0af5 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 15 Jan 2024 10:58:05 +0100 Subject: [PATCH 0229/1197] Deduplicate --- crates/hir-def/src/body/pretty.rs | 30 +++++------ crates/hir-def/src/child_by_source.rs | 7 ++- crates/hir-def/src/data/adt.rs | 10 ++-- crates/hir-def/src/db.rs | 2 +- crates/hir-def/src/dyn_map/keys.rs | 2 +- crates/hir-def/src/item_scope.rs | 7 +-- crates/hir-def/src/item_tree.rs | 7 +++ crates/hir-def/src/lang_item.rs | 2 +- crates/hir-def/src/nameres.rs | 8 ++- crates/hir-def/src/nameres/collector.rs | 40 +++++--------- crates/hir-def/src/nameres/path_resolution.rs | 53 +++++++------------ crates/hir/src/lib.rs | 7 ++- crates/hir/src/semantics/source_to_def.rs | 2 +- 13 files changed, 82 insertions(+), 95 deletions(-) diff --git a/crates/hir-def/src/body/pretty.rs b/crates/hir-def/src/body/pretty.rs index 601878e8e79ca..a389a283b593f 100644 --- a/crates/hir-def/src/body/pretty.rs +++ b/crates/hir-def/src/body/pretty.rs @@ -18,27 +18,21 @@ use super::*; pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBodyId) -> String { let header = match owner { DefWithBodyId::FunctionId(it) => { - let item_tree_id = it.lookup(db).id; - format!( - "fn {}", - item_tree_id.item_tree(db)[item_tree_id.value].name.display(db.upcast()) - ) + it.lookup(db).id.resolved(db, |it| format!("fn {} = ", it.name.display(db.upcast()))) } - DefWithBodyId::StaticId(it) => { - let item_tree_id = it.lookup(db).id; + DefWithBodyId::StaticId(it) => it + .lookup(db) + .id + .resolved(db, |it| format!("static {} = ", it.name.display(db.upcast()))), + DefWithBodyId::ConstId(it) => it.lookup(db).id.resolved(db, |it| { format!( - "static {} = ", - item_tree_id.item_tree(db)[item_tree_id.value].name.display(db.upcast()) + "const {} = ", + match &it.name { + Some(name) => name.display(db.upcast()).to_string(), + None => "_".to_string(), + } ) - } - DefWithBodyId::ConstId(it) => { - let item_tree_id = it.lookup(db).id; - let name = match &item_tree_id.item_tree(db)[item_tree_id.value].name { - Some(name) => name.display(db.upcast()).to_string(), - None => "_".to_string(), - }; - format!("const {name} = ") - } + }), DefWithBodyId::InTypeConstId(_) => format!("In type const = "), DefWithBodyId::VariantId(it) => { let loc = it.lookup(db); diff --git a/crates/hir-def/src/child_by_source.rs b/crates/hir-def/src/child_by_source.rs index e8a771141effb..b3bb3355f1234 100644 --- a/crates/hir-def/src/child_by_source.rs +++ b/crates/hir-def/src/child_by_source.rs @@ -204,15 +204,18 @@ impl ChildBySource for VariantId { } impl ChildBySource for EnumId { - fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, _: HirFileId) { + fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) { let loc = &self.lookup(db); + if file_id != loc.id.file_id() { + return; + } let tree = loc.id.item_tree(db); let ast_id_map = db.ast_id_map(loc.id.file_id()); let root = db.parse_or_expand(loc.id.file_id()); db.enum_data(*self).variants.iter().for_each(|&(variant, _)| { - res[keys::VARIANT].insert( + res[keys::ENUM_VARIANT].insert( ast_id_map.get(tree[variant.lookup(db).id.value].ast_id).to_node(&root), variant, ); diff --git a/crates/hir-def/src/data/adt.rs b/crates/hir-def/src/data/adt.rs index 93a64dc6ec6fb..942fafe329efa 100644 --- a/crates/hir-def/src/data/adt.rs +++ b/crates/hir-def/src/data/adt.rs @@ -298,7 +298,7 @@ impl EnumData { Arc::new(EnumData { name: enum_.name.clone(), - variants: loc.container.def_map(db)[loc.container.local_id].scope.enums[&e] + variants: loc.container.def_map(db).enum_definitions[&e] .iter() .map(|&id| (id, item_tree[id.lookup(db).id.value].name.clone())) .collect(), @@ -332,7 +332,7 @@ impl EnumVariantData { pub(crate) fn enum_variant_data_with_diagnostics_query( db: &dyn DefDatabase, e: EnumVariantId, - ) -> (Arc, Arc<[DefDiagnostic]>) { + ) -> (Arc, Option>>) { let loc = e.lookup(db); let krate = loc.container.krate; let item_tree = loc.id.item_tree(db); @@ -355,7 +355,11 @@ impl EnumVariantData { name: variant.name.clone(), variant_data: Arc::new(var_data), }), - field_diagnostics.into(), + if field_diagnostics.is_empty() { + None + } else { + Some(Arc::new(field_diagnostics.into_boxed_slice())) + }, ) } } diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs index 4201b1dd17435..2b1d0bca283be 100644 --- a/crates/hir-def/src/db.rs +++ b/crates/hir-def/src/db.rs @@ -140,7 +140,7 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast (Arc, Arc<[DefDiagnostic]>); + ) -> (Arc, Option>>); #[salsa::invoke(ImplData::impl_data_query)] fn impl_data(&self, e: ImplId) -> Arc; diff --git a/crates/hir-def/src/dyn_map/keys.rs b/crates/hir-def/src/dyn_map/keys.rs index d0f2bfab43223..60832f59eb9c5 100644 --- a/crates/hir-def/src/dyn_map/keys.rs +++ b/crates/hir-def/src/dyn_map/keys.rs @@ -28,7 +28,7 @@ pub const ENUM: Key = Key::new(); pub const EXTERN_CRATE: Key = Key::new(); pub const USE: Key = Key::new(); -pub const VARIANT: Key = Key::new(); +pub const ENUM_VARIANT: Key = Key::new(); pub const TUPLE_FIELD: Key = Key::new(); pub const RECORD_FIELD: Key = Key::new(); pub const TYPE_PARAM: Key = Key::new(); diff --git a/crates/hir-def/src/item_scope.rs b/crates/hir-def/src/item_scope.rs index 436bc0c98c2ad..168ee4acffbef 100644 --- a/crates/hir-def/src/item_scope.rs +++ b/crates/hir-def/src/item_scope.rs @@ -18,8 +18,8 @@ use crate::{ db::DefDatabase, per_ns::PerNs, visibility::{Visibility, VisibilityExplicity}, - AdtId, BuiltinType, ConstId, EnumId, EnumVariantId, ExternCrateId, HasModule, ImplId, - LocalModuleId, Lookup, MacroId, ModuleDefId, ModuleId, TraitId, UseId, + AdtId, BuiltinType, ConstId, ExternCrateId, HasModule, ImplId, LocalModuleId, Lookup, MacroId, + ModuleDefId, ModuleId, TraitId, UseId, }; #[derive(Debug, Default)] @@ -79,7 +79,6 @@ pub struct ItemScope { /// declared. declarations: Vec, - pub enums: FxHashMap>, impls: Vec, unnamed_consts: Vec, /// Traits imported via `use Trait as _;`. @@ -719,7 +718,6 @@ impl ItemScope { use_imports_types, use_imports_macros, macro_invocations, - enums, } = self; types.shrink_to_fit(); values.shrink_to_fit(); @@ -738,7 +736,6 @@ impl ItemScope { extern_crate_decls.shrink_to_fit(); use_decls.shrink_to_fit(); macro_invocations.shrink_to_fit(); - enums.shrink_to_fit(); } } diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index 0f81bef500643..173aa817b0d53 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -445,6 +445,13 @@ impl ItemTreeId { pub fn item_tree(self, db: &dyn DefDatabase) -> Arc { self.tree.item_tree(db) } + + pub fn resolved(self, db: &dyn DefDatabase, cb: impl FnOnce(&N) -> R) -> R + where + ItemTree: Index, Output = N>, + { + cb(&self.tree.item_tree(db)[self.value]) + } } impl Copy for ItemTreeId {} diff --git a/crates/hir-def/src/lang_item.rs b/crates/hir-def/src/lang_item.rs index fc2edce93da71..bd2d804e4b380 100644 --- a/crates/hir-def/src/lang_item.rs +++ b/crates/hir-def/src/lang_item.rs @@ -125,7 +125,7 @@ impl LangItems { } ModuleDefId::AdtId(AdtId::EnumId(e)) => { lang_items.collect_lang_item(db, e, LangItemTarget::EnumId); - module_data.scope.enums[&e].iter().for_each(|&id| { + crate_def_map.enum_definitions[&e].iter().for_each(|&id| { lang_items.collect_lang_item(db, id, LangItemTarget::EnumVariant); }); } diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs index 53644f58efc44..7eb2f3adddbf9 100644 --- a/crates/hir-def/src/nameres.rs +++ b/crates/hir-def/src/nameres.rs @@ -80,8 +80,8 @@ use crate::{ path::ModPath, per_ns::PerNs, visibility::{Visibility, VisibilityExplicity}, - AstId, BlockId, BlockLoc, CrateRootModuleId, ExternCrateId, FunctionId, LocalModuleId, Lookup, - MacroExpander, MacroId, ModuleId, ProcMacroId, UseId, + AstId, BlockId, BlockLoc, CrateRootModuleId, EnumId, EnumVariantId, ExternCrateId, FunctionId, + LocalModuleId, Lookup, MacroExpander, MacroId, ModuleId, ProcMacroId, UseId, }; /// Contains the results of (early) name resolution. @@ -113,6 +113,7 @@ pub struct DefMap { /// this contains all kinds of macro, not just `macro_rules!` macro. /// ExternCrateId being None implies it being imported from the general prelude import. macro_use_prelude: FxHashMap)>, + pub(crate) enum_definitions: FxHashMap>, /// Tracks which custom derives are in scope for an item, to allow resolution of derive helper /// attributes. @@ -370,6 +371,7 @@ impl DefMap { macro_use_prelude: FxHashMap::default(), derive_helpers_in_scope: FxHashMap::default(), diagnostics: Vec::new(), + enum_definitions: FxHashMap::default(), data: Arc::new(DefMapCrateData { extern_prelude: FxHashMap::default(), exported_derives: FxHashMap::default(), @@ -612,12 +614,14 @@ impl DefMap { krate: _, prelude: _, data: _, + enum_definitions, } = self; macro_use_prelude.shrink_to_fit(); diagnostics.shrink_to_fit(); modules.shrink_to_fit(); derive_helpers_in_scope.shrink_to_fit(); + enum_definitions.shrink_to_fit(); for (_, module) in modules.iter_mut() { module.children.shrink_to_fit(); module.scope.shrink_to_fit(); diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index fc15a77e8c349..760f811ede6a0 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -980,35 +980,26 @@ impl DefCollector<'_> { cov_mark::hit!(glob_enum); // glob import from enum => just import all the variants - // We need to check if the def map the enum is from is us, then we can't + // We need to check if the def map the enum is from is us, if it is we can't // call the def-map query since we are currently constructing it! let loc = e.lookup(self.db); let tree = loc.id.item_tree(self.db); let current_def_map = self.def_map.krate == loc.container.krate && self.def_map.block_id() == loc.container.block; + let def_map; let resolutions = if current_def_map { - self.def_map.modules[loc.container.local_id].scope.enums[&e] - .iter() - .map(|&variant| { - let name = tree[variant.lookup(self.db).id.value].name.clone(); - let res = - PerNs::both(variant.into(), variant.into(), vis, None); - (Some(name), res) - }) - .collect::>() + &self.def_map.enum_definitions[&e] } else { - loc.container.def_map(self.db).modules[loc.container.local_id] - .scope - .enums[&e] - .iter() - .map(|&variant| { - let name = tree[variant.lookup(self.db).id.value].name.clone(); - let res = - PerNs::both(variant.into(), variant.into(), vis, None); - (Some(name), res) - }) - .collect::>() - }; + def_map = loc.container.def_map(self.db); + &def_map.enum_definitions[&e] + } + .iter() + .map(|&variant| { + let name = tree[variant.lookup(self.db).id.value].name.clone(); + let res = PerNs::both(variant.into(), variant.into(), vis, None); + (Some(name), res) + }) + .collect::>(); self.update(module_id, &resolutions, vis, Some(ImportType::Glob(id))); } Some(d) => { @@ -1749,10 +1740,7 @@ impl ModCollector<'_, '_> { ) }) .collect(); - self.def_collector.def_map.modules[module_id] - .scope - .enums - .insert(enum_, variants); + self.def_collector.def_map.enum_definitions.insert(enum_, variants); } ModItem::Const(id) => { let it = &self.item_tree[id]; diff --git a/crates/hir-def/src/nameres/path_resolution.rs b/crates/hir-def/src/nameres/path_resolution.rs index 372d148021841..7300a0628f572 100644 --- a/crates/hir-def/src/nameres/path_resolution.rs +++ b/crates/hir-def/src/nameres/path_resolution.rs @@ -360,41 +360,28 @@ impl DefMap { let tree = loc.id.item_tree(db); let current_def_map = self.krate == loc.container.krate && self.block_id() == loc.container.block; + let def_map; let res = if current_def_map { - self.modules[loc.container.local_id].scope.enums[&e].iter().find_map( - |&variant| { - let variant_data = &tree[variant.lookup(db).id.value]; - (variant_data.name == *segment).then(|| match variant_data.fields { - Fields::Record(_) => { - PerNs::types(variant.into(), Visibility::Public, None) - } - Fields::Tuple(_) | Fields::Unit => PerNs::both( - variant.into(), - variant.into(), - Visibility::Public, - None, - ), - }) - }, - ) + &self.enum_definitions[&e] } else { - loc.container.def_map(db).modules[loc.container.local_id].scope.enums[&e] - .iter() - .find_map(|&variant| { - let variant_data = &tree[variant.lookup(db).id.value]; - (variant_data.name == *segment).then(|| match variant_data.fields { - Fields::Record(_) => { - PerNs::types(variant.into(), Visibility::Public, None) - } - Fields::Tuple(_) | Fields::Unit => PerNs::both( - variant.into(), - variant.into(), - Visibility::Public, - None, - ), - }) - }) - }; + def_map = loc.container.def_map(db); + &def_map.enum_definitions[&e] + } + .iter() + .find_map(|&variant| { + let variant_data = &tree[variant.lookup(db).id.value]; + (variant_data.name == *segment).then(|| match variant_data.fields { + Fields::Record(_) => { + PerNs::types(variant.into(), Visibility::Public, None) + } + Fields::Tuple(_) | Fields::Unit => PerNs::both( + variant.into(), + variant.into(), + Visibility::Public, + None, + ), + }) + }); match res { Some(res) => res, None => { diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 246fc231b47f5..5e133bf5c758d 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -584,8 +584,11 @@ impl Module { Adt::Enum(e) => { for v in e.variants(db) { acc.extend(ModuleDef::Variant(v).diagnostics(db)); - for diag in db.enum_variant_data_with_diagnostics(v.id).1.iter() { - emit_def_diagnostic(db, acc, diag); + if let Some(diags) = &db.enum_variant_data_with_diagnostics(v.id).1 + { + for diag in &***diags { + emit_def_diagnostic(db, acc, diag); + } } } } diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs index df8c1e904fe89..cb04f98911ebd 100644 --- a/crates/hir/src/semantics/source_to_def.rs +++ b/crates/hir/src/semantics/source_to_def.rs @@ -201,7 +201,7 @@ impl SourceToDefCtx<'_, '_> { &mut self, src: InFile, ) -> Option { - self.to_def(src, keys::VARIANT) + self.to_def(src, keys::ENUM_VARIANT) } pub(super) fn extern_crate_to_def( &mut self, From 1669344b2a4168afdebc10fba34b9a0c63a29e72 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 15 Jan 2024 11:07:26 +0100 Subject: [PATCH 0230/1197] Thinner DefDiagnostics --- crates/hir-def/src/data.rs | 10 +++++----- crates/hir-def/src/data/adt.rs | 20 ++++++++------------ crates/hir-def/src/db.rs | 13 ++++++------- crates/hir-def/src/nameres/diagnostics.rs | 17 +++++++++++++++++ crates/hir-ty/src/mir/lower.rs | 1 + crates/hir/src/lib.rs | 7 ++----- 6 files changed, 39 insertions(+), 29 deletions(-) diff --git a/crates/hir-def/src/data.rs b/crates/hir-def/src/data.rs index 9c183c9332ba8..a42d6bb33789a 100644 --- a/crates/hir-def/src/data.rs +++ b/crates/hir-def/src/data.rs @@ -19,7 +19,7 @@ use crate::{ macro_call_as_call_id, nameres::{ attr_resolution::ResolvedAttr, - diagnostics::DefDiagnostic, + diagnostics::{DefDiagnostic, DefDiagnostics}, proc_macro::{parse_macro_name_and_helper_attrs, ProcMacroKind}, DefMap, MacroSubNs, }, @@ -240,7 +240,7 @@ impl TraitData { pub(crate) fn trait_data_with_diagnostics_query( db: &dyn DefDatabase, tr: TraitId, - ) -> (Arc, Arc<[DefDiagnostic]>) { + ) -> (Arc, DefDiagnostics) { let tr_loc @ ItemLoc { container: module_id, id: tree_id } = tr.lookup(db); let item_tree = tree_id.item_tree(db); let tr_def = &item_tree[tree_id.value]; @@ -274,7 +274,7 @@ impl TraitData { rustc_has_incoherent_inherent_impls, fundamental, }), - diagnostics.into(), + DefDiagnostics::new(diagnostics), ) } @@ -340,7 +340,7 @@ impl ImplData { pub(crate) fn impl_data_with_diagnostics_query( db: &dyn DefDatabase, id: ImplId, - ) -> (Arc, Arc<[DefDiagnostic]>) { + ) -> (Arc, DefDiagnostics) { let _p = profile::span("impl_data_with_diagnostics_query"); let ItemLoc { container: module_id, id: tree_id } = id.lookup(db); @@ -367,7 +367,7 @@ impl ImplData { is_unsafe, attribute_calls, }), - diagnostics.into(), + DefDiagnostics::new(diagnostics), ) } diff --git a/crates/hir-def/src/data/adt.rs b/crates/hir-def/src/data/adt.rs index 942fafe329efa..6e302aea653de 100644 --- a/crates/hir-def/src/data/adt.rs +++ b/crates/hir-def/src/data/adt.rs @@ -21,7 +21,7 @@ use crate::{ item_tree::{AttrOwner, Field, FieldAstId, Fields, ItemTree, ModItem, RawVisibilityId}, lang_item::LangItem, lower::LowerCtx, - nameres::diagnostics::DefDiagnostic, + nameres::diagnostics::{DefDiagnostic, DefDiagnostics}, src::HasChildSource, src::HasSource, trace::Trace, @@ -187,7 +187,7 @@ impl StructData { pub(crate) fn struct_data_with_diagnostics_query( db: &dyn DefDatabase, id: StructId, - ) -> (Arc, Arc<[DefDiagnostic]>) { + ) -> (Arc, DefDiagnostics) { let loc = id.lookup(db); let krate = loc.container.krate; let item_tree = loc.id.item_tree(db); @@ -232,7 +232,7 @@ impl StructData { visibility: item_tree[strukt.visibility].clone(), flags, }), - diagnostics.into(), + DefDiagnostics::new(diagnostics), ) } @@ -243,7 +243,7 @@ impl StructData { pub(crate) fn union_data_with_diagnostics_query( db: &dyn DefDatabase, id: UnionId, - ) -> (Arc, Arc<[DefDiagnostic]>) { + ) -> (Arc, DefDiagnostics) { let loc = id.lookup(db); let krate = loc.container.krate; let item_tree = loc.id.item_tree(db); @@ -278,7 +278,7 @@ impl StructData { visibility: item_tree[union.visibility].clone(), flags, }), - diagnostics.into(), + DefDiagnostics::new(diagnostics), ) } } @@ -332,14 +332,14 @@ impl EnumVariantData { pub(crate) fn enum_variant_data_with_diagnostics_query( db: &dyn DefDatabase, e: EnumVariantId, - ) -> (Arc, Option>>) { + ) -> (Arc, DefDiagnostics) { let loc = e.lookup(db); let krate = loc.container.krate; let item_tree = loc.id.item_tree(db); let cfg_options = db.crate_graph()[krate].cfg_options.clone(); let variant = &item_tree[loc.id.value]; - let (var_data, field_diagnostics) = lower_fields( + let (var_data, diagnostics) = lower_fields( db, krate, loc.id.file_id(), @@ -355,11 +355,7 @@ impl EnumVariantData { name: variant.name.clone(), variant_data: Arc::new(var_data), }), - if field_diagnostics.is_empty() { - None - } else { - Some(Arc::new(field_diagnostics.into_boxed_slice())) - }, + DefDiagnostics::new(diagnostics), ) } } diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs index 2b1d0bca283be..186a8cf2d9ff5 100644 --- a/crates/hir-def/src/db.rs +++ b/crates/hir-def/src/db.rs @@ -19,7 +19,7 @@ use crate::{ import_map::ImportMap, item_tree::{AttrOwner, ItemTree}, lang_item::{self, LangItem, LangItemTarget, LangItems}, - nameres::{diagnostics::DefDiagnostic, DefMap}, + nameres::{diagnostics::DefDiagnostics, DefMap}, visibility::{self, Visibility}, AttrDefId, BlockId, BlockLoc, ConstBlockId, ConstBlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, EnumVariantId, EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, @@ -121,14 +121,13 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast Arc; #[salsa::invoke(StructData::struct_data_with_diagnostics_query)] - fn struct_data_with_diagnostics(&self, id: StructId) - -> (Arc, Arc<[DefDiagnostic]>); + fn struct_data_with_diagnostics(&self, id: StructId) -> (Arc, DefDiagnostics); #[salsa::invoke(StructData::union_data_query)] fn union_data(&self, id: UnionId) -> Arc; #[salsa::invoke(StructData::union_data_with_diagnostics_query)] - fn union_data_with_diagnostics(&self, id: UnionId) -> (Arc, Arc<[DefDiagnostic]>); + fn union_data_with_diagnostics(&self, id: UnionId) -> (Arc, DefDiagnostics); #[salsa::invoke(EnumData::enum_data_query)] fn enum_data(&self, e: EnumId) -> Arc; @@ -140,19 +139,19 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast (Arc, Option>>); + ) -> (Arc, DefDiagnostics); #[salsa::invoke(ImplData::impl_data_query)] fn impl_data(&self, e: ImplId) -> Arc; #[salsa::invoke(ImplData::impl_data_with_diagnostics_query)] - fn impl_data_with_diagnostics(&self, e: ImplId) -> (Arc, Arc<[DefDiagnostic]>); + fn impl_data_with_diagnostics(&self, e: ImplId) -> (Arc, DefDiagnostics); #[salsa::invoke(TraitData::trait_data_query)] fn trait_data(&self, e: TraitId) -> Arc; #[salsa::invoke(TraitData::trait_data_with_diagnostics_query)] - fn trait_data_with_diagnostics(&self, tr: TraitId) -> (Arc, Arc<[DefDiagnostic]>); + fn trait_data_with_diagnostics(&self, tr: TraitId) -> (Arc, DefDiagnostics); #[salsa::invoke(TraitAliasData::trait_alias_query)] fn trait_alias_data(&self, e: TraitAliasId) -> Arc; diff --git a/crates/hir-def/src/nameres/diagnostics.rs b/crates/hir-def/src/nameres/diagnostics.rs index 9cffb3c9f37fe..0a3f7bf7ec3d6 100644 --- a/crates/hir-def/src/nameres/diagnostics.rs +++ b/crates/hir-def/src/nameres/diagnostics.rs @@ -40,6 +40,23 @@ pub enum DefDiagnosticKind { MacroDefError { ast: AstId, message: String }, } +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct DefDiagnostics(Option>>); + +impl DefDiagnostics { + pub fn new(diagnostics: Vec) -> Self { + Self(if diagnostics.is_empty() { + None + } else { + Some(triomphe::Arc::new(diagnostics.into_boxed_slice())) + }) + } + + pub fn iter(&self) -> impl Iterator { + self.0.as_ref().into_iter().flat_map(|it| &***it) + } +} + #[derive(Debug, PartialEq, Eq)] pub struct DefDiagnostic { pub in_module: LocalModuleId, diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index 69d8046524b43..749ca43fba7fc 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -69,6 +69,7 @@ struct MirLowerCtx<'a> { drop_scopes: Vec, } +// FIXME: Make this smaller, its stored in database queries #[derive(Debug, Clone, PartialEq, Eq)] pub enum MirLowerError { ConstEvalError(Box, Box), diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 5e133bf5c758d..246fc231b47f5 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -584,11 +584,8 @@ impl Module { Adt::Enum(e) => { for v in e.variants(db) { acc.extend(ModuleDef::Variant(v).diagnostics(db)); - if let Some(diags) = &db.enum_variant_data_with_diagnostics(v.id).1 - { - for diag in &***diags { - emit_def_diagnostic(db, acc, diag); - } + for diag in db.enum_variant_data_with_diagnostics(v.id).1.iter() { + emit_def_diagnostic(db, acc, diag); } } } From 180e9b2bbfa39c2c00cfa944d9823cae4867d651 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 15 Jan 2024 12:03:31 +0100 Subject: [PATCH 0231/1197] Cleanup --- crates/hir-def/src/attr.rs | 13 ++- crates/hir-def/src/body/pretty.rs | 2 +- crates/hir-def/src/data/adt.rs | 13 +-- crates/hir-def/src/item_tree.rs | 6 +- crates/hir-def/src/item_tree/lower.rs | 2 +- crates/hir-def/src/lib.rs | 63 ++++++---- crates/hir-def/src/nameres/collector.rs | 109 +++++++++++------- crates/hir-def/src/nameres/path_resolution.rs | 2 +- crates/hir-def/src/src.rs | 6 +- crates/hir-def/src/trace.rs | 4 + crates/hir-def/src/visibility.rs | 6 +- crates/hir-ty/src/consteval.rs | 10 +- crates/hir-ty/src/inhabitedness.rs | 4 +- crates/hir-ty/src/lower.rs | 53 +++++---- crates/hir-ty/src/mir/eval.rs | 26 +---- crates/hir/src/lib.rs | 18 +-- crates/syntax/src/ast/node_ext.rs | 6 + 17 files changed, 175 insertions(+), 168 deletions(-) diff --git a/crates/hir-def/src/attr.rs b/crates/hir-def/src/attr.rs index be69d6f1351ac..8fbfcc81d2800 100644 --- a/crates/hir-def/src/attr.rs +++ b/crates/hir-def/src/attr.rs @@ -24,7 +24,7 @@ use triomphe::Arc; use crate::{ db::DefDatabase, - item_tree::{AttrOwner, Fields, ItemTreeId, ItemTreeNode}, + item_tree::{AttrOwner, Fields, ItemTreeId, ItemTreeModItemNode}, lang_item::LangItem, nameres::{ModuleOrigin, ModuleSource}, src::{HasChildSource, HasSource}, @@ -82,7 +82,7 @@ impl Attrs { let (fields, item_tree, krate) = match v { VariantId::EnumVariantId(it) => { let loc = it.lookup(db); - let krate = loc.container.krate; + let krate = loc.parent.lookup(db).container.krate; let item_tree = loc.id.item_tree(db); let variant = &item_tree[loc.id.value]; (variant.fields.clone(), item_tree, krate) @@ -606,13 +606,16 @@ fn any_has_attrs<'db>( id.lookup(db).source(db).map(ast::AnyHasAttrs::new) } -fn attrs_from_item_tree(db: &dyn DefDatabase, id: ItemTreeId) -> RawAttrs { +fn attrs_from_item_tree( + db: &dyn DefDatabase, + id: ItemTreeId, +) -> RawAttrs { let tree = id.item_tree(db); let mod_item = N::id_to_mod_item(id.value); tree.raw_attrs(mod_item.into()).clone() } -fn attrs_from_item_tree_loc<'db, N: ItemTreeNode>( +fn attrs_from_item_tree_loc<'db, N: ItemTreeModItemNode>( db: &(dyn DefDatabase + 'db), lookup: impl Lookup = dyn DefDatabase + 'db, Data = ItemLoc>, ) -> RawAttrs { @@ -620,7 +623,7 @@ fn attrs_from_item_tree_loc<'db, N: ItemTreeNode>( attrs_from_item_tree(db, id) } -fn attrs_from_item_tree_assoc<'db, N: ItemTreeNode>( +fn attrs_from_item_tree_assoc<'db, N: ItemTreeModItemNode>( db: &(dyn DefDatabase + 'db), lookup: impl Lookup = dyn DefDatabase + 'db, Data = AssocItemLoc>, ) -> RawAttrs { diff --git a/crates/hir-def/src/body/pretty.rs b/crates/hir-def/src/body/pretty.rs index a389a283b593f..deb87f87d5e7c 100644 --- a/crates/hir-def/src/body/pretty.rs +++ b/crates/hir-def/src/body/pretty.rs @@ -18,7 +18,7 @@ use super::*; pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBodyId) -> String { let header = match owner { DefWithBodyId::FunctionId(it) => { - it.lookup(db).id.resolved(db, |it| format!("fn {} = ", it.name.display(db.upcast()))) + it.lookup(db).id.resolved(db, |it| format!("fn {}", it.name.display(db.upcast()))) } DefWithBodyId::StaticId(it) => it .lookup(db) diff --git a/crates/hir-def/src/data/adt.rs b/crates/hir-def/src/data/adt.rs index 6e302aea653de..5d44371521397 100644 --- a/crates/hir-def/src/data/adt.rs +++ b/crates/hir-def/src/data/adt.rs @@ -334,7 +334,8 @@ impl EnumVariantData { e: EnumVariantId, ) -> (Arc, DefDiagnostics) { let loc = e.lookup(db); - let krate = loc.container.krate; + let container = loc.parent.lookup(db).container; + let krate = container.krate; let item_tree = loc.id.item_tree(db); let cfg_options = db.crate_graph()[krate].cfg_options.clone(); let variant = &item_tree[loc.id.value]; @@ -343,7 +344,7 @@ impl EnumVariantData { db, krate, loc.id.file_id(), - loc.container.local_id, + container.local_id, &item_tree, &cfg_options, &variant.fields, @@ -395,7 +396,7 @@ impl HasChildSource for VariantId { ( lookup.source(db).map(|it| it.kind()), &item_tree[lookup.id.value].fields, - lookup.container, + lookup.parent.lookup(db).container, ) } VariantId::StructId(it) => { @@ -411,11 +412,7 @@ impl HasChildSource for VariantId { let lookup = it.lookup(db); item_tree = lookup.id.item_tree(db); ( - lookup.source(db).map(|it| { - it.record_field_list() - .map(ast::StructKind::Record) - .unwrap_or(ast::StructKind::Unit) - }), + lookup.source(db).map(|it| it.kind()), &item_tree[lookup.id.value].fields, lookup.container, ) diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index 173aa817b0d53..c37cf52155102 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -337,7 +337,7 @@ from_attrs!( ); /// Trait implemented by all item nodes in the item tree. -pub trait ItemTreeNode: Clone { +pub trait ItemTreeModItemNode: Clone { type Source: AstIdNode + Into; fn ast_id(&self) -> FileAstId; @@ -494,7 +494,7 @@ macro_rules! mod_items { )+ $( - impl ItemTreeNode for $typ { + impl ItemTreeModItemNode for $typ { type Source = $ast; fn ast_id(&self) -> FileAstId { @@ -577,7 +577,7 @@ impl Index for ItemTree { } } -impl Index> for ItemTree { +impl Index> for ItemTree { type Output = N; fn index(&self, id: FileItemTreeId) -> &N { N::lookup(self, id.index()) diff --git a/crates/hir-def/src/item_tree/lower.rs b/crates/hir-def/src/item_tree/lower.rs index 8d19b5000cf4d..f6086ed6d9b24 100644 --- a/crates/hir-def/src/item_tree/lower.rs +++ b/crates/hir-def/src/item_tree/lower.rs @@ -13,7 +13,7 @@ use crate::{ use super::*; -fn id(index: Idx) -> FileItemTreeId { +fn id(index: Idx) -> FileItemTreeId { FileItemTreeId(index) } diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index 1712eaede0920..bcd1f37bec4a3 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -99,8 +99,8 @@ use crate::{ data::adt::VariantData, db::DefDatabase, item_tree::{ - Const, Enum, ExternCrate, Function, Impl, ItemTreeId, ItemTreeNode, Macro2, MacroRules, - Static, Struct, Trait, TraitAlias, TypeAlias, Union, Use, Variant, + Const, Enum, ExternCrate, Function, Impl, ItemTreeId, ItemTreeModItemNode, Macro2, + MacroRules, Static, Struct, Trait, TraitAlias, TypeAlias, Union, Use, Variant, }, }; @@ -213,28 +213,28 @@ impl ModuleId { pub type LocalModuleId = Idx; #[derive(Debug)] -pub struct ItemLoc { +pub struct ItemLoc { pub container: ModuleId, pub id: ItemTreeId, } -impl Clone for ItemLoc { +impl Clone for ItemLoc { fn clone(&self) -> Self { Self { container: self.container, id: self.id } } } -impl Copy for ItemLoc {} +impl Copy for ItemLoc {} -impl PartialEq for ItemLoc { +impl PartialEq for ItemLoc { fn eq(&self, other: &Self) -> bool { self.container == other.container && self.id == other.id } } -impl Eq for ItemLoc {} +impl Eq for ItemLoc {} -impl Hash for ItemLoc { +impl Hash for ItemLoc { fn hash(&self, state: &mut H) { self.container.hash(state); self.id.hash(state); @@ -242,28 +242,28 @@ impl Hash for ItemLoc { } #[derive(Debug)] -pub struct AssocItemLoc { +pub struct AssocItemLoc { pub container: ItemContainerId, pub id: ItemTreeId, } -impl Clone for AssocItemLoc { +impl Clone for AssocItemLoc { fn clone(&self) -> Self { Self { container: self.container, id: self.id } } } -impl Copy for AssocItemLoc {} +impl Copy for AssocItemLoc {} -impl PartialEq for AssocItemLoc { +impl PartialEq for AssocItemLoc { fn eq(&self, other: &Self) -> bool { self.container == other.container && self.id == other.id } } -impl Eq for AssocItemLoc {} +impl Eq for AssocItemLoc {} -impl Hash for AssocItemLoc { +impl Hash for AssocItemLoc { fn hash(&self, state: &mut H) { self.container.hash(state); self.id.hash(state); @@ -297,15 +297,14 @@ pub struct EnumId(salsa::InternId); pub type EnumLoc = ItemLoc; impl_intern!(EnumId, EnumLoc, intern_enum, lookup_intern_enum); -// FIXME: rename to `VariantId`, only enums can ave variants #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct EnumVariantId(salsa::InternId); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct EnumVariantLoc { - pub container: ModuleId, pub id: ItemTreeId, pub parent: EnumId, + pub index: u32, } impl_intern!(EnumVariantId, EnumVariantLoc, intern_enum_variant, lookup_intern_enum_variant); @@ -992,7 +991,8 @@ impl HasModule for ItemContainerId { } } -impl HasModule for AssocItemLoc { +impl HasModule for AssocItemLoc { + #[inline] fn module(&self, db: &dyn DefDatabase) -> ModuleId { self.container.module(db) } @@ -1008,7 +1008,22 @@ impl HasModule for AdtId { } } +impl HasModule for EnumId { + #[inline] + fn module(&self, db: &dyn DefDatabase) -> ModuleId { + self.lookup(db).container + } +} + +impl HasModule for EnumVariantId { + #[inline] + fn module(&self, db: &dyn DefDatabase) -> ModuleId { + self.lookup(db).parent.module(db) + } +} + impl HasModule for ExternCrateId { + #[inline] fn module(&self, db: &dyn DefDatabase) -> ModuleId { self.lookup(db).container } @@ -1017,7 +1032,7 @@ impl HasModule for ExternCrateId { impl HasModule for VariantId { fn module(&self, db: &dyn DefDatabase) -> ModuleId { match self { - VariantId::EnumVariantId(it) => it.lookup(db).container, + VariantId::EnumVariantId(it) => it.lookup(db).parent.module(db), VariantId::StructId(it) => it.lookup(db).container, VariantId::UnionId(it) => it.lookup(db).container, } @@ -1046,7 +1061,7 @@ impl HasModule for TypeOwnerId { TypeOwnerId::TraitAliasId(it) => it.lookup(db).container, TypeOwnerId::TypeAliasId(it) => it.lookup(db).module(db), TypeOwnerId::ImplId(it) => it.lookup(db).container, - TypeOwnerId::EnumVariantId(it) => it.lookup(db).container, + TypeOwnerId::EnumVariantId(it) => it.lookup(db).parent.module(db), } } } @@ -1057,7 +1072,7 @@ impl HasModule for DefWithBodyId { DefWithBodyId::FunctionId(it) => it.lookup(db).module(db), DefWithBodyId::StaticId(it) => it.lookup(db).module(db), DefWithBodyId::ConstId(it) => it.lookup(db).module(db), - DefWithBodyId::VariantId(it) => it.lookup(db).container, + DefWithBodyId::VariantId(it) => it.lookup(db).parent.module(db), DefWithBodyId::InTypeConstId(it) => it.lookup(db).owner.module(db), } } @@ -1072,19 +1087,21 @@ impl HasModule for GenericDefId { GenericDefId::TraitAliasId(it) => it.lookup(db).container, GenericDefId::TypeAliasId(it) => it.lookup(db).module(db), GenericDefId::ImplId(it) => it.lookup(db).container, - GenericDefId::EnumVariantId(it) => it.lookup(db).container, + GenericDefId::EnumVariantId(it) => it.lookup(db).parent.lookup(db).container, GenericDefId::ConstId(it) => it.lookup(db).module(db), } } } impl HasModule for TypeAliasId { + #[inline] fn module(&self, db: &dyn DefDatabase) -> ModuleId { self.lookup(db).module(db) } } impl HasModule for TraitId { + #[inline] fn module(&self, db: &dyn DefDatabase) -> ModuleId { self.lookup(db).container } @@ -1099,7 +1116,7 @@ impl ModuleDefId { ModuleDefId::ModuleId(id) => *id, ModuleDefId::FunctionId(id) => id.lookup(db).module(db), ModuleDefId::AdtId(id) => id.module(db), - ModuleDefId::EnumVariantId(id) => id.lookup(db).container, + ModuleDefId::EnumVariantId(id) => id.lookup(db).parent.module(db), ModuleDefId::ConstId(id) => id.lookup(db).container.module(db), ModuleDefId::StaticId(id) => id.lookup(db).module(db), ModuleDefId::TraitId(id) => id.lookup(db).container, @@ -1118,7 +1135,7 @@ impl AttrDefId { AttrDefId::FieldId(it) => it.parent.module(db).krate, AttrDefId::AdtId(it) => it.module(db).krate, AttrDefId::FunctionId(it) => it.lookup(db).module(db).krate, - AttrDefId::EnumVariantId(it) => it.lookup(db).container.krate, + AttrDefId::EnumVariantId(it) => it.lookup(db).parent.module(db).krate, AttrDefId::StaticId(it) => it.lookup(db).module(db).krate, AttrDefId::ConstId(it) => it.lookup(db).module(db).krate, AttrDefId::TraitId(it) => it.lookup(db).container.krate, diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 760f811ede6a0..893ad47e241a9 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -3,7 +3,7 @@ //! `DefCollector::collect` contains the fixed-point iteration loop which //! resolves imports and expands macros. -use std::{cmp::Ordering, iter, mem}; +use std::{cmp::Ordering, iter, mem, ops::Not}; use base_db::{CrateId, Dependency, Edition, FileId}; use cfg::{CfgExpr, CfgOptions}; @@ -35,8 +35,8 @@ use crate::{ derive_macro_as_call_id, item_scope::{ImportId, ImportOrExternCrate, ImportType, PerNsGlobImports}, item_tree::{ - self, ExternCrate, Fields, FileItemTreeId, ImportKind, ItemTree, ItemTreeId, ItemTreeNode, - Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId, + self, ExternCrate, Fields, FileItemTreeId, ImportKind, ItemTree, ItemTreeId, + ItemTreeModItemNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId, }, macro_call_as_call_id, macro_call_as_call_id_with_eager, nameres::{ @@ -1579,7 +1579,10 @@ impl ModCollector<'_, '_> { let attrs = self.item_tree.attrs(db, krate, item.into()); if let Some(cfg) = attrs.cfg() { if !self.is_cfg_enabled(&cfg) { - self.emit_unconfigured_diagnostic(item.ast_id(self.item_tree).erase(), &cfg); + self.emit_unconfigured_diagnostic( + InFile::new(self.file_id(), item.ast_id(self.item_tree).erase()), + &cfg, + ); return; } } @@ -1717,27 +1720,37 @@ impl ModCollector<'_, '_> { let vis = resolve_vis(def_map, &self.item_tree[it.visibility]); update_def(self.def_collector, enum_.into(), &it.name, vis, false); + let mut index = 0; let variants = FileItemTreeId::range_iter(it.variants.clone()) .filter_map(|variant| { - let attrs = self.item_tree.attrs(db, krate, variant.into()); - if let Some(cfg) = attrs.cfg() { - if !self.is_cfg_enabled(&cfg) { + let is_enabled = self + .item_tree + .attrs(db, krate, variant.into()) + .cfg() + .and_then(|cfg| self.is_cfg_enabled(&cfg).not().then_some(cfg)) + .map_or(Ok(()), Err); + match is_enabled { + Err(cfg) => { self.emit_unconfigured_diagnostic( - self.item_tree[variant.index()].ast_id.erase(), + InFile::new( + self.file_id(), + self.item_tree[variant.index()].ast_id.erase(), + ), &cfg, ); - return None; + None } + Ok(()) => Some({ + let loc = EnumVariantLoc { + id: ItemTreeId::new(self.tree_id, variant), + parent: enum_, + index, + } + .intern(db); + index += 1; + loc + }), } - - Some( - EnumVariantLoc { - container: module, - id: ItemTreeId::new(self.tree_id, variant), - parent: enum_, - } - .intern(db), - ) }) .collect(); self.def_collector.def_map.enum_definitions.insert(enum_, variants); @@ -1927,31 +1940,40 @@ impl ModCollector<'_, '_> { let is_enabled = item_tree .top_level_attrs(db, krate) .cfg() - .map_or(true, |cfg| self.is_cfg_enabled(&cfg)); - if is_enabled { - let module_id = self.push_child_module( - module.name.clone(), - ast_id.value, - Some((file_id, is_mod_rs)), - &self.item_tree[module.visibility], - module_id, - ); - ModCollector { - def_collector: self.def_collector, - macro_depth: self.macro_depth, - module_id, - tree_id: TreeId::new(file_id.into(), None), - item_tree: &item_tree, - mod_dir, + .and_then(|cfg| self.is_cfg_enabled(&cfg).not().then_some(cfg)) + .map_or(Ok(()), Err); + match is_enabled { + Err(cfg) => { + self.emit_unconfigured_diagnostic( + ast_id.map(|it| it.erase()), + &cfg, + ); } - .collect_in_top_module(item_tree.top_level_items()); - let is_macro_use = is_macro_use - || item_tree - .top_level_attrs(db, krate) - .by_key("macro_use") - .exists(); - if is_macro_use { - self.import_all_legacy_macros(module_id); + Ok(()) => { + let module_id = self.push_child_module( + module.name.clone(), + ast_id.value, + Some((file_id, is_mod_rs)), + &self.item_tree[module.visibility], + module_id, + ); + ModCollector { + def_collector: self.def_collector, + macro_depth: self.macro_depth, + module_id, + tree_id: TreeId::new(file_id.into(), None), + item_tree: &item_tree, + mod_dir, + } + .collect_in_top_module(item_tree.top_level_items()); + let is_macro_use = is_macro_use + || item_tree + .top_level_attrs(db, krate) + .by_key("macro_use") + .exists(); + if is_macro_use { + self.import_all_legacy_macros(module_id); + } } } } @@ -2382,8 +2404,7 @@ impl ModCollector<'_, '_> { self.def_collector.cfg_options.check(cfg) != Some(false) } - fn emit_unconfigured_diagnostic(&mut self, ast_id: ErasedFileAstId, cfg: &CfgExpr) { - let ast_id = InFile::new(self.file_id(), ast_id); + fn emit_unconfigured_diagnostic(&mut self, ast_id: InFile, cfg: &CfgExpr) { self.def_collector.def_map.diagnostics.push(DefDiagnostic::unconfigured_code( self.module_id, ast_id, diff --git a/crates/hir-def/src/nameres/path_resolution.rs b/crates/hir-def/src/nameres/path_resolution.rs index 7300a0628f572..01f79f042f789 100644 --- a/crates/hir-def/src/nameres/path_resolution.rs +++ b/crates/hir-def/src/nameres/path_resolution.rs @@ -355,12 +355,12 @@ impl DefMap { ModuleDefId::AdtId(AdtId::EnumId(e)) => { // enum variant cov_mark::hit!(can_import_enum_variant); + let def_map; let loc = e.lookup(db); let tree = loc.id.item_tree(db); let current_def_map = self.krate == loc.container.krate && self.block_id() == loc.container.block; - let def_map; let res = if current_def_map { &self.enum_definitions[&e] } else { diff --git a/crates/hir-def/src/src.rs b/crates/hir-def/src/src.rs index 4698e967eb7d9..9bd8c8d2215e0 100644 --- a/crates/hir-def/src/src.rs +++ b/crates/hir-def/src/src.rs @@ -5,7 +5,7 @@ use la_arena::ArenaMap; use syntax::ast; use crate::{ - db::DefDatabase, item_tree::ItemTreeNode, AssocItemLoc, EnumVariantLoc, ItemLoc, Lookup, + db::DefDatabase, item_tree::ItemTreeModItemNode, AssocItemLoc, EnumVariantLoc, ItemLoc, Lookup, Macro2Loc, MacroRulesLoc, ProcMacroLoc, UseId, }; @@ -14,7 +14,7 @@ pub trait HasSource { fn source(&self, db: &dyn DefDatabase) -> InFile; } -impl HasSource for AssocItemLoc { +impl HasSource for AssocItemLoc { type Value = N::Source; fn source(&self, db: &dyn DefDatabase) -> InFile { @@ -27,7 +27,7 @@ impl HasSource for AssocItemLoc { } } -impl HasSource for ItemLoc { +impl HasSource for ItemLoc { type Value = N::Source; fn source(&self, db: &dyn DefDatabase) -> InFile { diff --git a/crates/hir-def/src/trace.rs b/crates/hir-def/src/trace.rs index 01654f04ccf40..04d5b266194e3 100644 --- a/crates/hir-def/src/trace.rs +++ b/crates/hir-def/src/trace.rs @@ -19,6 +19,10 @@ pub(crate) struct Trace { impl Trace { #[allow(dead_code)] + pub(crate) fn new_for_arena() -> Trace { + Trace { arena: Some(Arena::default()), map: None, len: 0 } + } + pub(crate) fn new_for_map() -> Trace { Trace { arena: None, map: Some(ArenaMap::default()), len: 0 } } diff --git a/crates/hir-def/src/visibility.rs b/crates/hir-def/src/visibility.rs index c73ffa334c3de..3294ce29a4a05 100644 --- a/crates/hir-def/src/visibility.rs +++ b/crates/hir-def/src/visibility.rs @@ -222,11 +222,7 @@ pub(crate) fn field_visibilities_query( db: &dyn DefDatabase, variant_id: VariantId, ) -> Arc> { - let var_data = match variant_id { - VariantId::StructId(it) => db.struct_data(it).variant_data.clone(), - VariantId::UnionId(it) => db.union_data(it).variant_data.clone(), - VariantId::EnumVariantId(it) => db.enum_variant_data(it).variant_data.clone(), - }; + let var_data = variant_id.variant_data(db); let resolver = variant_id.module(db).resolver(db); let mut res = ArenaMap::default(); for (field_id, field_data) in var_data.fields().iter() { diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs index 2e1525ebe178c..dae612e6d25c8 100644 --- a/crates/hir-ty/src/consteval.rs +++ b/crates/hir-ty/src/consteval.rs @@ -257,15 +257,7 @@ pub(crate) fn const_eval_discriminant_variant( let body = db.body(def); if body.exprs[body.body_expr] == Expr::Missing { let loc = variant_id.lookup(db.upcast()); - let parent_id = loc.parent.lookup(db.upcast()).id; - let index = loc.id.value.index().into_raw().into_u32() - - parent_id.item_tree(db.upcast())[parent_id.value] - .variants - .start - .index() - .into_raw() - .into_u32(); - let prev_idx = index.checked_sub(1); + let prev_idx = loc.index.checked_sub(1); let value = match prev_idx { Some(prev_idx) => { 1 + db.const_eval_discriminant( diff --git a/crates/hir-ty/src/inhabitedness.rs b/crates/hir-ty/src/inhabitedness.rs index dda5ddd0bae85..a63556f450dda 100644 --- a/crates/hir-ty/src/inhabitedness.rs +++ b/crates/hir-ty/src/inhabitedness.rs @@ -7,7 +7,7 @@ use chalk_ir::{ }; use hir_def::{ attr::Attrs, data::adt::VariantData, visibility::Visibility, AdtId, EnumVariantId, HasModule, - Lookup, ModuleId, VariantId, + ModuleId, VariantId, }; use rustc_hash::FxHashSet; @@ -30,7 +30,7 @@ pub(crate) fn is_enum_variant_uninhabited_from( target_mod: ModuleId, db: &dyn HirDatabase, ) -> bool { - let is_local = variant.lookup(db.upcast()).container.krate() == target_mod.krate(); + let is_local = variant.module(db.upcast()).krate() == target_mod.krate(); let mut uninhabited_from = UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default() }; diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index e160f05b01383..f66b584e3b599 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -1729,16 +1729,19 @@ fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnS /// Build the type of a tuple struct constructor. fn type_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> Binders { let struct_data = db.struct_data(def); - if let StructKind::Unit = struct_data.variant_data.kind() { - return type_for_adt(db, def.into()); + match struct_data.variant_data.kind() { + StructKind::Record => unreachable!("callers check for valueness of variant"), + StructKind::Unit => return type_for_adt(db, def.into()), + StructKind::Tuple => { + let generics = generics(db.upcast(), AdtId::from(def).into()); + let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST); + make_binders( + db, + &generics, + TyKind::FnDef(CallableDefId::StructId(def).to_chalk(db), substs).intern(Interner), + ) + } } - let generics = generics(db.upcast(), AdtId::from(def).into()); - let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST); - make_binders( - db, - &generics, - TyKind::FnDef(CallableDefId::StructId(def).to_chalk(db), substs).intern(Interner), - ) } fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) -> PolyFnSig { @@ -1756,16 +1759,20 @@ fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) /// Build the type of a tuple enum variant constructor. fn type_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) -> Binders { let e = def.lookup(db.upcast()).parent; - if let StructKind::Unit = db.enum_variant_data(def).variant_data.kind() { - return type_for_adt(db, e.into()); + match db.enum_variant_data(def).variant_data.kind() { + StructKind::Record => unreachable!("callers check for valueness of variant"), + StructKind::Unit => return type_for_adt(db, e.into()), + StructKind::Tuple => { + let generics = generics(db.upcast(), e.into()); + let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST); + make_binders( + db, + &generics, + TyKind::FnDef(CallableDefId::EnumVariantId(def).to_chalk(db), substs) + .intern(Interner), + ) + } } - let generics = generics(db.upcast(), e.into()); - let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST); - make_binders( - db, - &generics, - TyKind::FnDef(CallableDefId::EnumVariantId(def).to_chalk(db), substs).intern(Interner), - ) } fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders { @@ -1813,7 +1820,7 @@ impl CallableDefId { match self { CallableDefId::FunctionId(f) => f.lookup(db).module(db), CallableDefId::StructId(s) => s.lookup(db).container, - CallableDefId::EnumVariantId(e) => e.lookup(db).container, + CallableDefId::EnumVariantId(e) => e.module(db), } .krate() } @@ -1894,12 +1901,8 @@ pub(crate) fn value_ty_query(db: &dyn HirDatabase, def: ValueTyDefId) -> Binders } pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binders { - let impl_loc = impl_id.lookup(db.upcast()); let impl_data = db.impl_data(impl_id); let resolver = impl_id.resolver(db.upcast()); - let _cx = stdx::panic_context::enter(format!( - "impl_self_ty_query({impl_id:?} -> {impl_loc:?} -> {impl_data:?})" - )); let generics = generics(db.upcast(), impl_id.into()); let ctx = TyLoweringContext::new(db, &resolver, impl_id.into()) .with_type_param_mode(ParamLoweringMode::Variable); @@ -1931,12 +1934,8 @@ pub(crate) fn impl_self_ty_recover( } pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option> { - let impl_loc = impl_id.lookup(db.upcast()); let impl_data = db.impl_data(impl_id); let resolver = impl_id.resolver(db.upcast()); - let _cx = stdx::panic_context::enter(format!( - "impl_trait_query({impl_id:?} -> {impl_loc:?} -> {impl_data:?})" - )); let ctx = TyLoweringContext::new(db, &resolver, impl_id.into()) .with_type_param_mode(ParamLoweringMode::Variable); let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders(); diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index 431d09c5650f4..ceb170f6cf7d9 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -751,19 +751,9 @@ impl Evaluator<'_> { Variants::Single { .. } => &layout, Variants::Multiple { variants, .. } => { &variants[match f.parent { - hir_def::VariantId::EnumVariantId(it) => RustcEnumVariantIdx({ - let lookup = it.lookup(self.db.upcast()); - let rustc_enum_variant_idx = - lookup.id.value.index().into_raw().into_u32() - - lookup.id.item_tree(self.db.upcast()) - [lookup.parent.lookup(self.db.upcast()).id.value] - .variants - .start - .index() - .into_raw() - .into_u32(); - rustc_enum_variant_idx as usize - }), + hir_def::VariantId::EnumVariantId(it) => { + RustcEnumVariantIdx(it.lookup(self.db.upcast()).index as usize) + } _ => { return Err(MirEvalError::TypeError( "Multivariant layout only happens for enums", @@ -1604,15 +1594,7 @@ impl Evaluator<'_> { }; let mut discriminant = self.const_eval_discriminant(enum_variant_id)?; let lookup = enum_variant_id.lookup(self.db.upcast()); - let rustc_enum_variant_idx = lookup.id.value.index().into_raw().into_u32() - - lookup.id.item_tree(self.db.upcast()) - [lookup.parent.lookup(self.db.upcast()).id.value] - .variants - .start - .index() - .into_raw() - .into_u32(); - let rustc_enum_variant_idx = RustcEnumVariantIdx(rustc_enum_variant_idx as usize); + let rustc_enum_variant_idx = RustcEnumVariantIdx(lookup.index as usize); let variant_layout = variants[rustc_enum_variant_idx].clone(); let have_tag = match tag_encoding { TagEncoding::Direct => true, diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 246fc231b47f5..91f6065354397 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -44,7 +44,7 @@ use hir_def::{ data::adt::VariantData, generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance}, hir::{BindingAnnotation, BindingId, ExprOrPatId, LabelId, Pat}, - item_tree::ItemTreeNode, + item_tree::ItemTreeModItemNode, lang_item::LangItemTarget, layout::{self, ReprOptions, TargetDataLayout}, nameres::{self, diagnostics::DefDiagnostic}, @@ -1294,7 +1294,7 @@ pub struct Variant { impl Variant { pub fn module(self, db: &dyn HirDatabase) -> Module { - Module { id: self.id.lookup(db.upcast()).container } + Module { id: self.id.module(db.upcast()) } } pub fn parent_enum(self, db: &dyn HirDatabase) -> Enum { @@ -1340,17 +1340,7 @@ impl Variant { layout::Variants::Multiple { variants, .. } => Layout( { let lookup = self.id.lookup(db.upcast()); - let rustc_enum_variant_idx = lookup.id.value.index().into_raw().into_u32() - - lookup.id.item_tree(db.upcast()) - [lookup.parent.lookup(db.upcast()).id.value] - .variants - .start - .index() - .into_raw() - .into_u32(); - let rustc_enum_variant_idx = - RustcEnumVariantIdx(rustc_enum_variant_idx as usize); - + let rustc_enum_variant_idx = RustcEnumVariantIdx(lookup.index as usize); Arc::new(variants[rustc_enum_variant_idx].clone()) }, db.target_data_layout(parent_enum.krate(db).into()).unwrap(), @@ -2838,7 +2828,7 @@ where ID: Lookup = dyn DefDatabase + 'db, Data = AssocItemLoc>, DEF: From, CTOR: FnOnce(DEF) -> AssocItem, - AST: ItemTreeNode, + AST: ItemTreeModItemNode, { match id.lookup(db.upcast()).container { ItemContainerId::TraitId(_) | ItemContainerId::ImplId(_) => Some(ctor(DEF::from(id))), diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs index 1c6157de55958..19c2d3be16b78 100644 --- a/crates/syntax/src/ast/node_ext.rs +++ b/crates/syntax/src/ast/node_ext.rs @@ -440,6 +440,12 @@ impl ast::Struct { } } +impl ast::Union { + pub fn kind(&self) -> StructKind { + StructKind::from_node(self) + } +} + impl ast::RecordExprField { pub fn for_field_name(field_name: &ast::NameRef) -> Option { let candidate = Self::for_name_ref(field_name)?; From a356172f9220a4aa2bec5b5c1554e510ed55a96a Mon Sep 17 00:00:00 2001 From: Moritz Hedtke Date: Mon, 25 Dec 2023 22:58:04 +0100 Subject: [PATCH 0232/1197] internal: re-generate lints.rs --- crates/ide-db/src/generated/lints.rs | 1683 ++++++++++++++------------ 1 file changed, 911 insertions(+), 772 deletions(-) diff --git a/crates/ide-db/src/generated/lints.rs b/crates/ide-db/src/generated/lints.rs index 1cb6ff8627a23..f160def0aff00 100644 --- a/crates/ide-db/src/generated/lints.rs +++ b/crates/ide-db/src/generated/lints.rs @@ -5,6 +5,7 @@ pub struct Lint { pub label: &'static str, pub description: &'static str, } + pub struct LintGroup { pub lint: Lint, pub children: &'static [&'static str], @@ -21,6 +22,10 @@ pub const DEFAULT_LINTS: &[Lint] = &[ description: r##"detects certain glob imports that require reporting an ambiguity error"##, }, Lint { label: "ambiguous_glob_reexports", description: r##"ambiguous glob re-exports"## }, + Lint { + label: "ambiguous_wide_pointer_comparisons", + description: r##"detects ambiguous wide pointer comparisons"##, + }, Lint { label: "anonymous_parameters", description: r##"detects anonymous parameters"## }, Lint { label: "arithmetic_overflow", description: r##"arithmetic operation overflows"## }, Lint { @@ -105,7 +110,7 @@ pub const DEFAULT_LINTS: &[Lint] = &[ }, Lint { label: "deref_into_dyn_supertrait", - description: r##"`Deref` implementation usage with a supertrait trait object for output might be shadowed in the future"##, + description: r##"`Deref` implementation usage with a supertrait trait object for output are shadow by implicit coercion"##, }, Lint { label: "deref_nullptr", @@ -175,7 +180,7 @@ pub const DEFAULT_LINTS: &[Lint] = &[ }, Lint { label: "future_incompatible", - description: r##"lint group for: deref-into-dyn-supertrait, ambiguous-associated-items, ambiguous-glob-imports, byte-slice-in-packed-struct-with-derive, cenum-impl-drop-cast, coherence-leak-check, coinductive-overlap-in-coherence, conflicting-repr-hints, const-evaluatable-unchecked, const-patterns-without-partial-eq, deprecated-cfg-attr-crate-type-name, elided-lifetimes-in-associated-constant, forbidden-lint-groups, ill-formed-attribute-input, illegal-floating-point-literal-pattern, implied-bounds-entailment, indirect-structural-match, invalid-alignment, invalid-doc-attributes, invalid-type-param-default, late-bound-lifetime-arguments, legacy-derive-helpers, macro-expanded-macro-exports-accessed-by-absolute-paths, missing-fragment-specifier, nontrivial-structural-match, order-dependent-trait-objects, patterns-in-fns-without-body, pointer-structural-match, proc-macro-back-compat, proc-macro-derive-resolution-fallback, pub-use-of-private-extern-crate, repr-transparent-external-private-fields, semicolon-in-expressions-from-macros, soft-unstable, suspicious-auto-trait-impls, uninhabited-static, unstable-name-collisions, unstable-syntax-pre-expansion, unsupported-calling-conventions, where-clauses-object-safety"##, + description: r##"lint group for: ambiguous-associated-items, ambiguous-glob-imports, byte-slice-in-packed-struct-with-derive, cenum-impl-drop-cast, coherence-leak-check, coinductive-overlap-in-coherence, conflicting-repr-hints, const-evaluatable-unchecked, const-patterns-without-partial-eq, deprecated-cfg-attr-crate-type-name, elided-lifetimes-in-associated-constant, forbidden-lint-groups, ill-formed-attribute-input, illegal-floating-point-literal-pattern, indirect-structural-match, invalid-doc-attributes, invalid-type-param-default, late-bound-lifetime-arguments, legacy-derive-helpers, macro-expanded-macro-exports-accessed-by-absolute-paths, missing-fragment-specifier, nontrivial-structural-match, order-dependent-trait-objects, patterns-in-fns-without-body, pointer-structural-match, proc-macro-back-compat, proc-macro-derive-resolution-fallback, pub-use-of-private-extern-crate, repr-transparent-external-private-fields, semicolon-in-expressions-from-macros, soft-unstable, suspicious-auto-trait-impls, uninhabited-static, unstable-name-collisions, unstable-syntax-pre-expansion, unsupported-calling-conventions, where-clauses-object-safety, writes-through-immutable-pointer"##, }, Lint { label: "fuzzy_provenance_casts", @@ -193,10 +198,6 @@ pub const DEFAULT_LINTS: &[Lint] = &[ label: "illegal_floating_point_literal_pattern", description: r##"floating-point literals cannot be used in patterns"##, }, - Lint { - label: "implied_bounds_entailment", - description: r##"impl method assumes more implied bounds than its corresponding trait method"##, - }, Lint { label: "improper_ctypes", description: r##"proper use of libc types in foreign modules"##, @@ -226,10 +227,6 @@ pub const DEFAULT_LINTS: &[Lint] = &[ label: "internal_features", description: r##"internal features are not supposed to be used"##, }, - Lint { - label: "invalid_alignment", - description: r##"raw pointers must be aligned before dereferencing"##, - }, Lint { label: "invalid_atomic_ordering", description: r##"usage of invalid atomic ordering in atomic operations and memory fences"##, @@ -582,6 +579,10 @@ pub const DEFAULT_LINTS: &[Lint] = &[ description: r##"enabling track_caller on an async fn is a no-op unless the async_fn_track_caller feature is enabled"##, }, Lint { label: "uninhabited_static", description: r##"uninhabited static"## }, + Lint { + label: "unit_bindings", + description: r##"binding is useless because it has the unit `()` type"##, + }, Lint { label: "unknown_crate_types", description: r##"unknown crate type found in `#[crate_type]` directive"##, @@ -739,16 +740,19 @@ pub const DEFAULT_LINTS: &[Lint] = &[ label: "while_true", description: r##"suggest using `loop { }` instead of `while true { }`"##, }, + Lint { + label: "writes_through_immutable_pointer", + description: r##"shared references are immutable, and pointers derived from them must not be written to"##, + }, ]; pub const DEFAULT_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "future_incompatible", - description: r##"lint group for: deref-into-dyn-supertrait, ambiguous-associated-items, ambiguous-glob-imports, byte-slice-in-packed-struct-with-derive, cenum-impl-drop-cast, coherence-leak-check, coinductive-overlap-in-coherence, conflicting-repr-hints, const-evaluatable-unchecked, const-patterns-without-partial-eq, deprecated-cfg-attr-crate-type-name, elided-lifetimes-in-associated-constant, forbidden-lint-groups, ill-formed-attribute-input, illegal-floating-point-literal-pattern, implied-bounds-entailment, indirect-structural-match, invalid-alignment, invalid-doc-attributes, invalid-type-param-default, late-bound-lifetime-arguments, legacy-derive-helpers, macro-expanded-macro-exports-accessed-by-absolute-paths, missing-fragment-specifier, nontrivial-structural-match, order-dependent-trait-objects, patterns-in-fns-without-body, pointer-structural-match, proc-macro-back-compat, proc-macro-derive-resolution-fallback, pub-use-of-private-extern-crate, repr-transparent-external-private-fields, semicolon-in-expressions-from-macros, soft-unstable, suspicious-auto-trait-impls, uninhabited-static, unstable-name-collisions, unstable-syntax-pre-expansion, unsupported-calling-conventions, where-clauses-object-safety"##, + description: r##"lint group for: ambiguous-associated-items, ambiguous-glob-imports, byte-slice-in-packed-struct-with-derive, cenum-impl-drop-cast, coherence-leak-check, coinductive-overlap-in-coherence, conflicting-repr-hints, const-evaluatable-unchecked, const-patterns-without-partial-eq, deprecated-cfg-attr-crate-type-name, elided-lifetimes-in-associated-constant, forbidden-lint-groups, ill-formed-attribute-input, illegal-floating-point-literal-pattern, indirect-structural-match, invalid-doc-attributes, invalid-type-param-default, late-bound-lifetime-arguments, legacy-derive-helpers, macro-expanded-macro-exports-accessed-by-absolute-paths, missing-fragment-specifier, nontrivial-structural-match, order-dependent-trait-objects, patterns-in-fns-without-body, pointer-structural-match, proc-macro-back-compat, proc-macro-derive-resolution-fallback, pub-use-of-private-extern-crate, repr-transparent-external-private-fields, semicolon-in-expressions-from-macros, soft-unstable, suspicious-auto-trait-impls, uninhabited-static, unstable-name-collisions, unstable-syntax-pre-expansion, unsupported-calling-conventions, where-clauses-object-safety, writes-through-immutable-pointer"##, }, children: &[ - "deref_into_dyn_supertrait", "ambiguous_associated_items", "ambiguous_glob_imports", "byte_slice_in_packed_struct_with_derive", @@ -763,9 +767,7 @@ pub const DEFAULT_LINT_GROUPS: &[LintGroup] = &[ "forbidden_lint_groups", "ill_formed_attribute_input", "illegal_floating_point_literal_pattern", - "implied_bounds_entailment", "indirect_structural_match", - "invalid_alignment", "invalid_doc_attributes", "invalid_type_param_default", "late_bound_lifetime_arguments", @@ -788,6 +790,7 @@ pub const DEFAULT_LINT_GROUPS: &[LintGroup] = &[ "unstable_syntax_pre_expansion", "unsupported_calling_conventions", "where_clauses_object_safety", + "writes_through_immutable_pointer", ], }, LintGroup { @@ -1367,17 +1370,6 @@ The tracking issue for this feature is: [#44874] [#44874]: https://github.com/rust-lang/rust/issues/44874 ------------------------- -"##, - }, - Lint { - label: "arc_unwrap_or_clone", - description: r##"# `arc_unwrap_or_clone` - -The tracking issue for this feature is: [#93610] - -[#93610]: https://github.com/rust-lang/rust/issues/93610 - ------------------------ "##, }, @@ -1757,23 +1749,32 @@ The tracking issue for this feature is: [#62290] "##, }, Lint { - label: "async_fn_in_trait", - description: r##"# `async_fn_in_trait` + label: "async_fn_track_caller", + description: r##"# `async_fn_track_caller` -The tracking issue for this feature is: [#91611] +The tracking issue for this feature is: [#110011] -[#91611]: https://github.com/rust-lang/rust/issues/91611 +[#110011]: https://github.com/rust-lang/rust/issues/110011 ------------------------ "##, }, Lint { - label: "async_fn_track_caller", - description: r##"# `async_fn_track_caller` + label: "async_for_loop", + description: r##"# `async_for_loop` -The tracking issue for this feature is: [#110011] +The tracking issue for this feature is: [#118898] -[#110011]: https://github.com/rust-lang/rust/issues/110011 +[#118898]: https://github.com/rust-lang/rust/issues/118898 + +------------------------ +"##, + }, + Lint { + label: "async_gen_internals", + description: r##"# `async_gen_internals` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. ------------------------ "##, @@ -1819,17 +1820,6 @@ The tracking issue for this feature is: [#76314] [#76314]: https://github.com/rust-lang/rust/issues/76314 ------------------------- -"##, - }, - Lint { - label: "atomic_from_ptr", - description: r##"# `atomic_from_ptr` - -The tracking issue for this feature is: [#108652] - -[#108652]: https://github.com/rust-lang/rust/issues/108652 - ------------------------ "##, }, @@ -2139,6 +2129,17 @@ The tracking issue for this feature is: [#86423] [#86423]: https://github.com/rust-lang/rust/issues/86423 +------------------------ +"##, + }, + Lint { + label: "bufread_skip_until", + description: r##"# `bufread_skip_until` + +The tracking issue for this feature is: [#111735] + +[#111735]: https://github.com/rust-lang/rust/issues/111735 + ------------------------ "##, }, @@ -2172,17 +2173,6 @@ The tracking issue for this feature is: [#88345] [#88345]: https://github.com/rust-lang/rust/issues/88345 ------------------------- -"##, - }, - Lint { - label: "c_str_literals", - description: r##"# `c_str_literals` - -The tracking issue for this feature is: [#105723] - -[#105723]: https://github.com/rust-lang/rust/issues/105723 - ------------------------ "##, }, @@ -2584,8 +2574,8 @@ The tracking issue for this feature is: [#87417] ------------------------ -Allows using the `#[track_caller]` attribute on closures and generators. -Calls made to the closure or generator will have caller information +Allows using the `#[track_caller]` attribute on closures and coroutines. +Calls made to the closure or coroutine will have caller information available through `std::panic::Location::caller()`, just like using `#[track_caller]` on a function. "##, @@ -2839,15 +2829,6 @@ The tracking issue for this feature is: [#91583] [#91583]: https://github.com/rust-lang/rust/issues/91583 ------------------------- -"##, - }, - Lint { - label: "const_assert_type2", - description: r##"# `const_assert_type2` - -This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. - ------------------------ "##, }, @@ -2870,6 +2851,17 @@ The tracking issue for this feature is: [#85368] [#85368]: https://github.com/rust-lang/rust/issues/85368 +------------------------ +"##, + }, + Lint { + label: "const_atomic_from_ptr", + description: r##"# `const_atomic_from_ptr` + +The tracking issue for this feature is: [#108652] + +[#108652]: https://github.com/rust-lang/rust/issues/108652 + ------------------------ "##, }, @@ -2881,6 +2873,17 @@ The tracking issue for this feature is: [#85532] [#85532]: https://github.com/rust-lang/rust/issues/85532 +------------------------ +"##, + }, + Lint { + label: "const_binary_heap_constructor", + description: r##"# `const_binary_heap_constructor` + +The tracking issue for this feature is: [#112353] + +[#112353]: https://github.com/rust-lang/rust/issues/112353 + ------------------------ "##, }, @@ -2954,6 +2957,17 @@ The tracking issue for this feature is: [#106003] [#106003]: https://github.com/rust-lang/rust/issues/106003 +------------------------ +"##, + }, + Lint { + label: "const_cmp", + description: r##"# `const_cmp` + +The tracking issue for this feature is: [#92391] + +[#92391]: https://github.com/rust-lang/rust/issues/92391 + ------------------------ "##, }, @@ -2987,17 +3001,6 @@ The tracking issue for this feature is: [#113219] [#113219]: https://github.com/rust-lang/rust/issues/113219 ------------------------- -"##, - }, - Lint { - label: "const_discriminant", - description: r##"# `const_discriminant` - -The tracking issue for this feature is: [#69821] - -[#69821]: https://github.com/rust-lang/rust/issues/69821 - ------------------------ "##, }, @@ -3120,17 +3123,6 @@ The tracking issue for this feature is: [#79597] This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. ------------------------- -"##, - }, - Lint { - label: "const_inherent_unchecked_arith", - description: r##"# `const_inherent_unchecked_arith` - -The tracking issue for this feature is: [#85122] - -[#85122]: https://github.com/rust-lang/rust/issues/85122 - ------------------------ "##, }, @@ -3273,17 +3265,6 @@ The tracking issue for this feature is: [#75251] This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. ------------------------- -"##, - }, - Lint { - label: "const_maybe_uninit_assume_init_read", - description: r##"# `const_maybe_uninit_assume_init_read` - -The tracking issue for this feature is: [#63567] - -[#63567]: https://github.com/rust-lang/rust/issues/63567 - ------------------------ "##, }, @@ -3306,17 +3287,6 @@ The tracking issue for this feature is: [#63567] [#63567]: https://github.com/rust-lang/rust/issues/63567 ------------------------- -"##, - }, - Lint { - label: "const_maybe_uninit_zeroed", - description: r##"# `const_maybe_uninit_zeroed` - -The tracking issue for this feature is: [#91850] - -[#91850]: https://github.com/rust-lang/rust/issues/91850 - ------------------------ "##, }, @@ -3383,17 +3353,6 @@ The tracking issue for this feature is: [#76654] [#76654]: https://github.com/rust-lang/rust/issues/76654 ------------------------- -"##, - }, - Lint { - label: "const_pointer_byte_offsets", - description: r##"# `const_pointer_byte_offsets` - -The tracking issue for this feature is: [#96283] - -[#96283]: https://github.com/rust-lang/rust/issues/96283 - ------------------------ "##, }, @@ -3784,6 +3743,17 @@ The tracking issue for this feature is: [#67057] This feature is internal to the Rust compiler and is not intended for general use. +------------------------ +"##, + }, + Lint { + label: "core_io_borrowed_buf", + description: r##"# `core_io_borrowed_buf` + +The tracking issue for this feature is: [#117693] + +[#117693]: https://github.com/rust-lang/rust/issues/117693 + ------------------------ "##, }, @@ -3815,119 +3785,391 @@ This feature is internal to the Rust compiler and is not intended for general us "##, }, Lint { - label: "coverage_attribute", - description: r##"# `coverage_attribute` - -The tracking issue for this feature is: [#84605] - -[#84605]: https://github.com/rust-lang/rust/issues/84605 - ---- - -The `coverage` attribute can be used to selectively disable coverage -instrumentation in an annotated function. This might be useful to: + label: "coroutine_clone", + description: r##"# `coroutine_clone` -- Avoid instrumentation overhead in a performance critical function -- Avoid generating coverage for a function that is not meant to be executed, - but still target 100% coverage for the rest of the program. - -## Example - -```rust -#![feature(coverage_attribute)] +The tracking issue for this feature is: [#95360] -// `foo()` will get coverage instrumentation (by default) -fn foo() { - // ... -} +[#95360]: https://github.com/rust-lang/rust/issues/95360 -#[coverage(off)] -fn bar() { - // ... -} -``` +------------------------ "##, }, Lint { - label: "cow_is_borrowed", - description: r##"# `cow_is_borrowed` + label: "coroutine_trait", + description: r##"# `coroutine_trait` -The tracking issue for this feature is: [#65143] +The tracking issue for this feature is: [#43122] -[#65143]: https://github.com/rust-lang/rust/issues/65143 +[#43122]: https://github.com/rust-lang/rust/issues/43122 ------------------------ "##, }, Lint { - label: "csky_target_feature", - description: r##"# `csky_target_feature` + label: "coroutines", + description: r##"# `coroutines` -The tracking issue for this feature is: [#44839] +The tracking issue for this feature is: [#43122] -[#44839]: https://github.com/rust-lang/rust/issues/44839 +[#43122]: https://github.com/rust-lang/rust/issues/43122 ------------------------ -"##, - }, - Lint { - label: "cstr_count_bytes", - description: r##"# `cstr_count_bytes` -The tracking issue for this feature is: [#114441] +The `coroutines` feature gate in Rust allows you to define coroutine or +coroutine literals. A coroutine is a "resumable function" that syntactically +resembles a closure but compiles to much different semantics in the compiler +itself. The primary feature of a coroutine is that it can be suspended during +execution to be resumed at a later date. Coroutines use the `yield` keyword to +"return", and then the caller can `resume` a coroutine to resume execution just +after the `yield` keyword. -[#114441]: https://github.com/rust-lang/rust/issues/114441 +Coroutines are an extra-unstable feature in the compiler right now. Added in +[RFC 2033] they're mostly intended right now as a information/constraint +gathering phase. The intent is that experimentation can happen on the nightly +compiler before actual stabilization. A further RFC will be required to +stabilize coroutines and will likely contain at least a few small +tweaks to the overall design. ------------------------- -"##, - }, - Lint { - label: "cursor_remaining", - description: r##"# `cursor_remaining` +[RFC 2033]: https://github.com/rust-lang/rfcs/pull/2033 -The tracking issue for this feature is: [#86369] +A syntactical example of a coroutine is: -[#86369]: https://github.com/rust-lang/rust/issues/86369 +```rust +#![feature(coroutines, coroutine_trait)] ------------------------- -"##, - }, - Lint { - label: "custom_code_classes_in_docs", - description: r##"# `custom_code_classes_in_docs` +use std::ops::{Coroutine, CoroutineState}; +use std::pin::Pin; -The tracking issue for this feature is: [#79483] +fn main() { + let mut coroutine = || { + yield 1; + return "foo" + }; -[#79483]: https://github.com/rust-lang/rust/issues/79483 + match Pin::new(&mut coroutine).resume(()) { + CoroutineState::Yielded(1) => {} + _ => panic!("unexpected value from resume"), + } + match Pin::new(&mut coroutine).resume(()) { + CoroutineState::Complete("foo") => {} + _ => panic!("unexpected value from resume"), + } +} +``` ------------------------- -"##, - }, - Lint { - label: "custom_inner_attributes", - description: r##"# `custom_inner_attributes` +Coroutines are closure-like literals which can contain a `yield` statement. The +`yield` statement takes an optional expression of a value to yield out of the +coroutine. All coroutine literals implement the `Coroutine` trait in the +`std::ops` module. The `Coroutine` trait has one main method, `resume`, which +resumes execution of the coroutine at the previous suspension point. -The tracking issue for this feature is: [#54726] +An example of the control flow of coroutines is that the following example +prints all numbers in order: -[#54726]: https://github.com/rust-lang/rust/issues/54726 +```rust +#![feature(coroutines, coroutine_trait)] ------------------------- -"##, - }, - Lint { - label: "custom_mir", - description: r##"# `custom_mir` +use std::ops::Coroutine; +use std::pin::Pin; -This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. +fn main() { + let mut coroutine = || { + println!("2"); + yield; + println!("4"); + }; ------------------------- -"##, - }, - Lint { - label: "custom_test_frameworks", - description: r##"# `custom_test_frameworks` + println!("1"); + Pin::new(&mut coroutine).resume(()); + println!("3"); + Pin::new(&mut coroutine).resume(()); + println!("5"); +} +``` -The tracking issue for this feature is: [#50297] +At this time the main intended use case of coroutines is an implementation +primitive for async/await syntax, but coroutines will likely be extended to +ergonomic implementations of iterators and other primitives in the future. +Feedback on the design and usage is always appreciated! + +### The `Coroutine` trait + +The `Coroutine` trait in `std::ops` currently looks like: + +```rust +# #![feature(arbitrary_self_types, coroutine_trait)] +# use std::ops::CoroutineState; +# use std::pin::Pin; + +pub trait Coroutine { + type Yield; + type Return; + fn resume(self: Pin<&mut Self>, resume: R) -> CoroutineState; +} +``` + +The `Coroutine::Yield` type is the type of values that can be yielded with the +`yield` statement. The `Coroutine::Return` type is the returned type of the +coroutine. This is typically the last expression in a coroutine's definition or +any value passed to `return` in a coroutine. The `resume` function is the entry +point for executing the `Coroutine` itself. + +The return value of `resume`, `CoroutineState`, looks like: + +```rust +pub enum CoroutineState { + Yielded(Y), + Complete(R), +} +``` + +The `Yielded` variant indicates that the coroutine can later be resumed. This +corresponds to a `yield` point in a coroutine. The `Complete` variant indicates +that the coroutine is complete and cannot be resumed again. Calling `resume` +after a coroutine has returned `Complete` will likely result in a panic of the +program. + +### Closure-like semantics + +The closure-like syntax for coroutines alludes to the fact that they also have +closure-like semantics. Namely: + +* When created, a coroutine executes no code. A closure literal does not + actually execute any of the closure's code on construction, and similarly a + coroutine literal does not execute any code inside the coroutine when + constructed. + +* Coroutines can capture outer variables by reference or by move, and this can + be tweaked with the `move` keyword at the beginning of the closure. Like + closures all coroutines will have an implicit environment which is inferred by + the compiler. Outer variables can be moved into a coroutine for use as the + coroutine progresses. + +* Coroutine literals produce a value with a unique type which implements the + `std::ops::Coroutine` trait. This allows actual execution of the coroutine + through the `Coroutine::resume` method as well as also naming it in return + types and such. + +* Traits like `Send` and `Sync` are automatically implemented for a `Coroutine` + depending on the captured variables of the environment. Unlike closures, + coroutines also depend on variables live across suspension points. This means + that although the ambient environment may be `Send` or `Sync`, the coroutine + itself may not be due to internal variables live across `yield` points being + not-`Send` or not-`Sync`. Note that coroutines do + not implement traits like `Copy` or `Clone` automatically. + +* Whenever a coroutine is dropped it will drop all captured environment + variables. + +### Coroutines as state machines + +In the compiler, coroutines are currently compiled as state machines. Each +`yield` expression will correspond to a different state that stores all live +variables over that suspension point. Resumption of a coroutine will dispatch on +the current state and then execute internally until a `yield` is reached, at +which point all state is saved off in the coroutine and a value is returned. + +Let's take a look at an example to see what's going on here: + +```rust +#![feature(coroutines, coroutine_trait)] + +use std::ops::Coroutine; +use std::pin::Pin; + +fn main() { + let ret = "foo"; + let mut coroutine = move || { + yield 1; + return ret + }; + + Pin::new(&mut coroutine).resume(()); + Pin::new(&mut coroutine).resume(()); +} +``` + +This coroutine literal will compile down to something similar to: + +```rust +#![feature(arbitrary_self_types, coroutines, coroutine_trait)] + +use std::ops::{Coroutine, CoroutineState}; +use std::pin::Pin; + +fn main() { + let ret = "foo"; + let mut coroutine = { + enum __Coroutine { + Start(&'static str), + Yield1(&'static str), + Done, + } + + impl Coroutine for __Coroutine { + type Yield = i32; + type Return = &'static str; + + fn resume(mut self: Pin<&mut Self>, resume: ()) -> CoroutineState { + use std::mem; + match mem::replace(&mut *self, __Coroutine::Done) { + __Coroutine::Start(s) => { + *self = __Coroutine::Yield1(s); + CoroutineState::Yielded(1) + } + + __Coroutine::Yield1(s) => { + *self = __Coroutine::Done; + CoroutineState::Complete(s) + } + + __Coroutine::Done => { + panic!("coroutine resumed after completion") + } + } + } + } + + __Coroutine::Start(ret) + }; + + Pin::new(&mut coroutine).resume(()); + Pin::new(&mut coroutine).resume(()); +} +``` + +Notably here we can see that the compiler is generating a fresh type, +`__Coroutine` in this case. This type has a number of states (represented here +as an `enum`) corresponding to each of the conceptual states of the coroutine. +At the beginning we're closing over our outer variable `foo` and then that +variable is also live over the `yield` point, so it's stored in both states. + +When the coroutine starts it'll immediately yield 1, but it saves off its state +just before it does so indicating that it has reached the yield point. Upon +resuming again we'll execute the `return ret` which returns the `Complete` +state. + +Here we can also note that the `Done` state, if resumed, panics immediately as +it's invalid to resume a completed coroutine. It's also worth noting that this +is just a rough desugaring, not a normative specification for what the compiler +does. +"##, + }, + Lint { + label: "coverage_attribute", + description: r##"# `coverage_attribute` + +The tracking issue for this feature is: [#84605] + +[#84605]: https://github.com/rust-lang/rust/issues/84605 + +--- + +The `coverage` attribute can be used to selectively disable coverage +instrumentation in an annotated function. This might be useful to: + +- Avoid instrumentation overhead in a performance critical function +- Avoid generating coverage for a function that is not meant to be executed, + but still target 100% coverage for the rest of the program. + +## Example + +```rust +#![feature(coverage_attribute)] + +// `foo()` will get coverage instrumentation (by default) +fn foo() { + // ... +} + +#[coverage(off)] +fn bar() { + // ... +} +``` +"##, + }, + Lint { + label: "cow_is_borrowed", + description: r##"# `cow_is_borrowed` + +The tracking issue for this feature is: [#65143] + +[#65143]: https://github.com/rust-lang/rust/issues/65143 + +------------------------ +"##, + }, + Lint { + label: "csky_target_feature", + description: r##"# `csky_target_feature` + +The tracking issue for this feature is: [#44839] + +[#44839]: https://github.com/rust-lang/rust/issues/44839 + +------------------------ +"##, + }, + Lint { + label: "cstr_count_bytes", + description: r##"# `cstr_count_bytes` + +The tracking issue for this feature is: [#114441] + +[#114441]: https://github.com/rust-lang/rust/issues/114441 + +------------------------ +"##, + }, + Lint { + label: "cursor_remaining", + description: r##"# `cursor_remaining` + +The tracking issue for this feature is: [#86369] + +[#86369]: https://github.com/rust-lang/rust/issues/86369 + +------------------------ +"##, + }, + Lint { + label: "custom_code_classes_in_docs", + description: r##"# `custom_code_classes_in_docs` + +The tracking issue for this feature is: [#79483] + +[#79483]: https://github.com/rust-lang/rust/issues/79483 + +------------------------ +"##, + }, + Lint { + label: "custom_inner_attributes", + description: r##"# `custom_inner_attributes` + +The tracking issue for this feature is: [#54726] + +[#54726]: https://github.com/rust-lang/rust/issues/54726 + +------------------------ +"##, + }, + Lint { + label: "custom_mir", + description: r##"# `custom_mir` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "custom_test_frameworks", + description: r##"# `custom_test_frameworks` + +The tracking issue for this feature is: [#50297] [#50297]: https://github.com/rust-lang/rust/issues/50297 @@ -3967,6 +4209,17 @@ The tracking issue for this feature is: [#46316] [#46316]: https://github.com/rust-lang/rust/issues/46316 +------------------------ +"##, + }, + Lint { + label: "debug_closure_helpers", + description: r##"# `debug_closure_helpers` + +The tracking issue for this feature is: [#117729] + +[#117729]: https://github.com/rust-lang/rust/issues/117729 + ------------------------ "##, }, @@ -4059,6 +4312,83 @@ The tracking issue for this feature is: [#111996] [#111996]: https://github.com/rust-lang/rust/issues/111996 ------------------------ + +The `diagnostic_namespace` feature permits customization of compilation errors. + +## diagnostic::on_unimplemented + +With [#114452] support for `diagnostic::on_unimplemented` was added. + +When used on a trait declaration, the following options are available: + +* `message` to customize the primary error message +* `note` to add a customized note message to an error message +* `label` to customize the label part of the error message + +The attribute will hint to the compiler to use these in error messages: +```rust +// some library +#![feature(diagnostic_namespace)] + +#[diagnostic::on_unimplemented( + message = "cannot insert element", + label = "cannot be put into a table", + note = "see for more information about the Table api" +)] +pub trait Element { + // ... +} +``` + +```rust,compile_fail,E0277 +# #![feature(diagnostic_namespace)] +# +# #[diagnostic::on_unimplemented( +# message = "cannot insert element", +# label = "cannot be put into a table", +# note = "see for more information about the Table api" +# )] +# pub trait Element { +# // ... +# } +# struct Table; +# impl Table { +# fn insert(&self, element: T) { +# // .. +# } +# } +# fn main() { +# let table = Table; +# let element = (); +// user code +table.insert(element); +# } +``` + +```text +error[E0277]: cannot insert element + --> src/main.rs:24:18 + | +24 | table.insert(element); + | ------ ^^^^^^^ cannot be put into a table + | | + | required by a bound introduced by this call + | + = help: the trait `Element` is not implemented for `` + = note: see for more information about the Table api +note: required by a bound in `Table::insert` + --> src/main.rs:15:18 + | +15 | fn insert(&self, element: T) { + | ^^^^^^^ required by this bound in `Table::insert` + +For more information about this error, try `rustc --explain E0277`. +``` + +See [RFC 3368] for more information. + +[#114452]: https://github.com/rust-lang/rust/pull/114452 +[RFC 3368]: https://github.com/rust-lang/rfcs/blob/master/text/3368-diagnostic-attribute-namespace.md "##, }, Lint { @@ -4279,6 +4609,17 @@ The tracking issue for this feature is: [#34761] [#34761]: https://github.com/rust-lang/rust/issues/34761 +------------------------ +"##, + }, + Lint { + label: "duration_abs_diff", + description: r##"# `duration_abs_diff` + +The tracking issue for this feature is: [#117618] + +[#117618]: https://github.com/rust-lang/rust/issues/117618 + ------------------------ "##, }, @@ -4505,6 +4846,17 @@ The tracking issue for this feature is: [#112788] [#112788]: https://github.com/rust-lang/rust/issues/112788 +------------------------ +"##, + }, + Lint { + label: "exposed_provenance", + description: r##"# `exposed_provenance` + +The tracking issue for this feature is: [#95228] + +[#95228]: https://github.com/rust-lang/rust/issues/95228 + ------------------------ "##, }, @@ -4697,28 +5049,6 @@ The tracking issue for this feature is: [#58314] [#58314]: https://github.com/rust-lang/rust/issues/58314 ------------------------- -"##, - }, - Lint { - label: "file_create_new", - description: r##"# `file_create_new` - -The tracking issue for this feature is: [#105135] - -[#105135]: https://github.com/rust-lang/rust/issues/105135 - ------------------------- -"##, - }, - Lint { - label: "file_set_times", - description: r##"# `file_set_times` - -The tracking issue for this feature is: [#98245] - -[#98245]: https://github.com/rust-lang/rust/issues/98245 - ------------------------ "##, }, @@ -4790,6 +5120,17 @@ The tracking issue for this feature is: [#82232] [#82232]: https://github.com/rust-lang/rust/issues/82232 +------------------------ +"##, + }, + Lint { + label: "fn_delegation", + description: r##"# `fn_delegation` + +The tracking issue for this feature is: [#118212] + +[#118212]: https://github.com/rust-lang/rust/issues/118212 + ------------------------ "##, }, @@ -4893,286 +5234,25 @@ The tracking issue for this feature is: [#91642] "##, }, Lint { - label: "gen_future", - description: r##"# `gen_future` + label: "gen_blocks", + description: r##"# `gen_blocks` -The tracking issue for this feature is: [#50547] +The tracking issue for this feature is: [#117078] -[#50547]: https://github.com/rust-lang/rust/issues/50547 +[#117078]: https://github.com/rust-lang/rust/issues/117078 ------------------------ "##, }, Lint { - label: "generator_clone", - description: r##"# `generator_clone` - -The tracking issue for this feature is: [#95360] - -[#95360]: https://github.com/rust-lang/rust/issues/95360 - ------------------------- -"##, - }, - Lint { - label: "generator_trait", - description: r##"# `generator_trait` - -The tracking issue for this feature is: [#43122] - -[#43122]: https://github.com/rust-lang/rust/issues/43122 - ------------------------- -"##, - }, - Lint { - label: "generators", - description: r##"# `generators` + label: "gen_future", + description: r##"# `gen_future` -The tracking issue for this feature is: [#43122] +The tracking issue for this feature is: [#50547] -[#43122]: https://github.com/rust-lang/rust/issues/43122 +[#50547]: https://github.com/rust-lang/rust/issues/50547 ------------------------ - -The `generators` feature gate in Rust allows you to define generator or -coroutine literals. A generator is a "resumable function" that syntactically -resembles a closure but compiles to much different semantics in the compiler -itself. The primary feature of a generator is that it can be suspended during -execution to be resumed at a later date. Generators use the `yield` keyword to -"return", and then the caller can `resume` a generator to resume execution just -after the `yield` keyword. - -Generators are an extra-unstable feature in the compiler right now. Added in -[RFC 2033] they're mostly intended right now as a information/constraint -gathering phase. The intent is that experimentation can happen on the nightly -compiler before actual stabilization. A further RFC will be required to -stabilize generators/coroutines and will likely contain at least a few small -tweaks to the overall design. - -[RFC 2033]: https://github.com/rust-lang/rfcs/pull/2033 - -A syntactical example of a generator is: - -```rust -#![feature(generators, generator_trait)] - -use std::ops::{Generator, GeneratorState}; -use std::pin::Pin; - -fn main() { - let mut generator = || { - yield 1; - return "foo" - }; - - match Pin::new(&mut generator).resume(()) { - GeneratorState::Yielded(1) => {} - _ => panic!("unexpected value from resume"), - } - match Pin::new(&mut generator).resume(()) { - GeneratorState::Complete("foo") => {} - _ => panic!("unexpected value from resume"), - } -} -``` - -Generators are closure-like literals which can contain a `yield` statement. The -`yield` statement takes an optional expression of a value to yield out of the -generator. All generator literals implement the `Generator` trait in the -`std::ops` module. The `Generator` trait has one main method, `resume`, which -resumes execution of the generator at the previous suspension point. - -An example of the control flow of generators is that the following example -prints all numbers in order: - -```rust -#![feature(generators, generator_trait)] - -use std::ops::Generator; -use std::pin::Pin; - -fn main() { - let mut generator = || { - println!("2"); - yield; - println!("4"); - }; - - println!("1"); - Pin::new(&mut generator).resume(()); - println!("3"); - Pin::new(&mut generator).resume(()); - println!("5"); -} -``` - -At this time the main intended use case of generators is an implementation -primitive for async/await syntax, but generators will likely be extended to -ergonomic implementations of iterators and other primitives in the future. -Feedback on the design and usage is always appreciated! - -### The `Generator` trait - -The `Generator` trait in `std::ops` currently looks like: - -```rust -# #![feature(arbitrary_self_types, generator_trait)] -# use std::ops::GeneratorState; -# use std::pin::Pin; - -pub trait Generator { - type Yield; - type Return; - fn resume(self: Pin<&mut Self>, resume: R) -> GeneratorState; -} -``` - -The `Generator::Yield` type is the type of values that can be yielded with the -`yield` statement. The `Generator::Return` type is the returned type of the -generator. This is typically the last expression in a generator's definition or -any value passed to `return` in a generator. The `resume` function is the entry -point for executing the `Generator` itself. - -The return value of `resume`, `GeneratorState`, looks like: - -```rust -pub enum GeneratorState { - Yielded(Y), - Complete(R), -} -``` - -The `Yielded` variant indicates that the generator can later be resumed. This -corresponds to a `yield` point in a generator. The `Complete` variant indicates -that the generator is complete and cannot be resumed again. Calling `resume` -after a generator has returned `Complete` will likely result in a panic of the -program. - -### Closure-like semantics - -The closure-like syntax for generators alludes to the fact that they also have -closure-like semantics. Namely: - -* When created, a generator executes no code. A closure literal does not - actually execute any of the closure's code on construction, and similarly a - generator literal does not execute any code inside the generator when - constructed. - -* Generators can capture outer variables by reference or by move, and this can - be tweaked with the `move` keyword at the beginning of the closure. Like - closures all generators will have an implicit environment which is inferred by - the compiler. Outer variables can be moved into a generator for use as the - generator progresses. - -* Generator literals produce a value with a unique type which implements the - `std::ops::Generator` trait. This allows actual execution of the generator - through the `Generator::resume` method as well as also naming it in return - types and such. - -* Traits like `Send` and `Sync` are automatically implemented for a `Generator` - depending on the captured variables of the environment. Unlike closures, - generators also depend on variables live across suspension points. This means - that although the ambient environment may be `Send` or `Sync`, the generator - itself may not be due to internal variables live across `yield` points being - not-`Send` or not-`Sync`. Note that generators do - not implement traits like `Copy` or `Clone` automatically. - -* Whenever a generator is dropped it will drop all captured environment - variables. - -### Generators as state machines - -In the compiler, generators are currently compiled as state machines. Each -`yield` expression will correspond to a different state that stores all live -variables over that suspension point. Resumption of a generator will dispatch on -the current state and then execute internally until a `yield` is reached, at -which point all state is saved off in the generator and a value is returned. - -Let's take a look at an example to see what's going on here: - -```rust -#![feature(generators, generator_trait)] - -use std::ops::Generator; -use std::pin::Pin; - -fn main() { - let ret = "foo"; - let mut generator = move || { - yield 1; - return ret - }; - - Pin::new(&mut generator).resume(()); - Pin::new(&mut generator).resume(()); -} -``` - -This generator literal will compile down to something similar to: - -```rust -#![feature(arbitrary_self_types, generators, generator_trait)] - -use std::ops::{Generator, GeneratorState}; -use std::pin::Pin; - -fn main() { - let ret = "foo"; - let mut generator = { - enum __Generator { - Start(&'static str), - Yield1(&'static str), - Done, - } - - impl Generator for __Generator { - type Yield = i32; - type Return = &'static str; - - fn resume(mut self: Pin<&mut Self>, resume: ()) -> GeneratorState { - use std::mem; - match mem::replace(&mut *self, __Generator::Done) { - __Generator::Start(s) => { - *self = __Generator::Yield1(s); - GeneratorState::Yielded(1) - } - - __Generator::Yield1(s) => { - *self = __Generator::Done; - GeneratorState::Complete(s) - } - - __Generator::Done => { - panic!("generator resumed after completion") - } - } - } - } - - __Generator::Start(ret) - }; - - Pin::new(&mut generator).resume(()); - Pin::new(&mut generator).resume(()); -} -``` - -Notably here we can see that the compiler is generating a fresh type, -`__Generator` in this case. This type has a number of states (represented here -as an `enum`) corresponding to each of the conceptual states of the generator. -At the beginning we're closing over our outer variable `foo` and then that -variable is also live over the `yield` point, so it's stored in both states. - -When the generator starts it'll immediately yield 1, but it saves off its state -just before it does so indicating that it has reached the yield point. Upon -resuming again we'll execute the `return ret` which returns the `Complete` -state. - -Here we can also note that the `Done` state, if resumed, panics immediately as -it's invalid to resume a completed generator. It's also worth noting that this -is just a rough desugaring, not a normative specification for what the compiler -does. "##, }, Lint { @@ -5652,17 +5732,6 @@ The tracking issue for this feature is: [#113744] [#113744]: https://github.com/rust-lang/rust/issues/113744 ------------------------- -"##, - }, - Lint { - label: "ip_in_core", - description: r##"# `ip_in_core` - -The tracking issue for this feature is: [#108443] - -[#108443]: https://github.com/rust-lang/rust/issues/108443 - ------------------------ "##, }, @@ -5737,8 +5806,8 @@ The tracking issue for this feature is: [#94780] "##, }, Lint { - label: "iter_from_generator", - description: r##"# `iter_from_generator` + label: "iter_from_coroutine", + description: r##"# `iter_from_coroutine` The tracking issue for this feature is: [#43122] @@ -6047,6 +6116,40 @@ This feature has no tracking issue, and is therefore likely internal to the comp This feature is internal to the Rust compiler and is not intended for general use. ------------------------ +"##, + }, + Lint { + label: "lifetime_capture_rules_2024", + description: r##"# `lifetime_capture_rules_2024` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "link_arg_attribute", + description: r##"# `link_arg_attribute` + +The tracking issue for this feature is: [#99427] + +------ + +The `link_arg_attribute` feature allows passing arguments into the linker +from inside of the source code. Order is preserved for link attributes as +they were defined on a single extern block: + +```rust,no_run +#![feature(link_arg_attribute)] + +#[link(kind = "link-arg", name = "--start-group")] +#[link(kind = "static", name = "c")] +#[link(kind = "static", name = "gcc")] +#[link(kind = "link-arg", name = "--end-group")] +extern "C" {} +``` + +[#99427]: https://github.com/rust-lang/rust/issues/99427 "##, }, Lint { @@ -6099,6 +6202,17 @@ The tracking issue for this feature is: [#69210] [#69210]: https://github.com/rust-lang/rust/issues/69210 +------------------------ +"##, + }, + Lint { + label: "linked_list_retain", + description: r##"# `linked_list_retain` + +The tracking issue for this feature is: [#114135] + +[#114135]: https://github.com/rust-lang/rust/issues/114135 + ------------------------ "##, }, @@ -6132,6 +6246,17 @@ The tracking issue for this feature is: [#29598] [#29598]: https://github.com/rust-lang/rust/issues/29598 +------------------------ +"##, + }, + Lint { + label: "loongarch_target_feature", + description: r##"# `loongarch_target_feature` + +The tracking issue for this feature is: [#44839] + +[#44839]: https://github.com/rust-lang/rust/issues/44839 + ------------------------ "##, }, @@ -6513,8 +6638,19 @@ Negative impls are used to declare that `&T: !DerefMut` and `&mut T: !Clone`, a This serves two purposes: -* For proving the correctness of unsafe code, we can use that impl as evidence that no `DerefMut` or `Clone` impl exists. -* It prevents downstream crates from creating such impls. +* For proving the correctness of unsafe code, we can use that impl as evidence that no `DerefMut` or `Clone` impl exists. +* It prevents downstream crates from creating such impls. +"##, + }, + Lint { + label: "never_patterns", + description: r##"# `never_patterns` + +The tracking issue for this feature is: [#118155] + +[#118155]: https://github.com/rust-lang/rust/issues/118155 + +------------------------ "##, }, Lint { @@ -6613,6 +6749,17 @@ The tracking issue for this feature is: [#108185] [#108185]: https://github.com/rust-lang/rust/issues/108185 +------------------------ +"##, + }, + Lint { + label: "non_null_convenience", + description: r##"# `non_null_convenience` + +The tracking issue for this feature is: [#117691] + +[#117691]: https://github.com/rust-lang/rust/issues/117691 + ------------------------ "##, }, @@ -6677,6 +6824,17 @@ The tracking issue for this feature is: [#106655] [#106655]: https://github.com/rust-lang/rust/issues/106655 +------------------------ +"##, + }, + Lint { + label: "offset_of_enum", + description: r##"# `offset_of_enum` + +The tracking issue for this feature is: [#106655] + +[#106655]: https://github.com/rust-lang/rust/issues/106655 + ------------------------ "##, }, @@ -6697,6 +6855,17 @@ The tracking issue for this feature is: [#109737] [#109737]: https://github.com/rust-lang/rust/issues/109737 +------------------------ +"##, + }, + Lint { + label: "once_cell_try_insert", + description: r##"# `once_cell_try_insert` + +The tracking issue for this feature is: [#116693] + +[#116693]: https://github.com/rust-lang/rust/issues/116693 + ------------------------ "##, }, @@ -6752,6 +6921,17 @@ The tracking issue for this feature is: [#70086] [#70086]: https://github.com/rust-lang/rust/issues/70086 +------------------------ +"##, + }, + Lint { + label: "os_str_slice", + description: r##"# `os_str_slice` + +The tracking issue for this feature is: [#118485] + +[#118485]: https://github.com/rust-lang/rust/issues/118485 + ------------------------ "##, }, @@ -6904,135 +7084,6 @@ The tracking issue for this feature is: [#27731] [#27731]: https://github.com/rust-lang/rust/issues/27731 ------------------------- -"##, - }, - Lint { - label: "plugin", - description: r##"# `plugin` - -The tracking issue for this feature is: [#29597] - -[#29597]: https://github.com/rust-lang/rust/issues/29597 - - -This feature is part of "compiler plugins." It will often be used with the -`rustc_private` feature. - ------------------------- - -`rustc` can load compiler plugins, which are user-provided libraries that -extend the compiler's behavior with new lint checks, etc. - -A plugin is a dynamic library crate with a designated *registrar* function that -registers extensions with `rustc`. Other crates can load these extensions using -the crate attribute `#![plugin(...)]`. See the -`rustc_driver::plugin` documentation for more about the -mechanics of defining and loading a plugin. - -In the vast majority of cases, a plugin should *only* be used through -`#![plugin]` and not through an `extern crate` item. Linking a plugin would -pull in all of librustc_ast and librustc as dependencies of your crate. This is -generally unwanted unless you are building another plugin. - -The usual practice is to put compiler plugins in their own crate, separate from -any `macro_rules!` macros or ordinary Rust code meant to be used by consumers -of a library. - -# Lint plugins - -Plugins can extend [Rust's lint -infrastructure](../../reference/attributes/diagnostics.md#lint-check-attributes) with -additional checks for code style, safety, etc. Now let's write a plugin -[`lint-plugin-test.rs`](https://github.com/rust-lang/rust/blob/master/tests/ui-fulldeps/plugin/auxiliary/lint-plugin-test.rs) -that warns about any item named `lintme`. - -```rust,ignore (requires-stage-2) -#![feature(rustc_private)] - -extern crate rustc_ast; - -// Load rustc as a plugin to get macros -extern crate rustc_driver; -extern crate rustc_lint; -#[macro_use] -extern crate rustc_session; - -use rustc_ast::ast; -use rustc_driver::plugin::Registry; -use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; - -declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'"); - -declare_lint_pass!(Pass => [TEST_LINT]); - -impl EarlyLintPass for Pass { - fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) { - if it.ident.name.as_str() == "lintme" { - cx.lint(TEST_LINT, "item is named 'lintme'", |lint| lint.set_span(it.span)); - } - } -} - -#[no_mangle] -fn __rustc_plugin_registrar(reg: &mut Registry) { - reg.lint_store.register_lints(&[&TEST_LINT]); - reg.lint_store.register_early_pass(|| Box::new(Pass)); -} -``` - -Then code like - -```rust,ignore (requires-plugin) -#![feature(plugin)] -#![plugin(lint_plugin_test)] - -fn lintme() { } -``` - -will produce a compiler warning: - -```txt -foo.rs:4:1: 4:16 warning: item is named 'lintme', #[warn(test_lint)] on by default -foo.rs:4 fn lintme() { } - ^~~~~~~~~~~~~~~ -``` - -The components of a lint plugin are: - -* one or more `declare_lint!` invocations, which define static `Lint` structs; - -* a struct holding any state needed by the lint pass (here, none); - -* a `LintPass` - implementation defining how to check each syntax element. A single - `LintPass` may call `span_lint` for several different `Lint`s, but should - register them all through the `get_lints` method. - -Lint passes are syntax traversals, but they run at a late stage of compilation -where type information is available. `rustc`'s [built-in -lints](https://github.com/rust-lang/rust/blob/master/compiler/rustc_lint_defs/src/builtin.rs) -mostly use the same infrastructure as lint plugins, and provide examples of how -to access type information. - -Lints defined by plugins are controlled by the usual [attributes and compiler -flags](../../reference/attributes/diagnostics.md#lint-check-attributes), e.g. -`#[allow(test_lint)]` or `-A test-lint`. These identifiers are derived from the -first argument to `declare_lint!`, with appropriate case and punctuation -conversion. - -You can run `rustc -W help foo.rs` to see a list of lints known to `rustc`, -including those provided by plugins loaded by `foo.rs`. -"##, - }, - Lint { - label: "pointer_byte_offsets", - description: r##"# `pointer_byte_offsets` - -The tracking issue for this feature is: [#96283] - -[#96283]: https://github.com/rust-lang/rust/issues/96283 - ------------------------ "##, }, @@ -7075,17 +7126,6 @@ The tracking issue for this feature is: [#44839] [#44839]: https://github.com/rust-lang/rust/issues/44839 ------------------------- -"##, - }, - Lint { - label: "precise_pointer_size_matching", - description: r##"# `precise_pointer_size_matching` - -The tracking issue for this feature is: [#56354] - -[#56354]: https://github.com/rust-lang/rust/issues/56354 - ------------------------ "##, }, @@ -7248,17 +7288,6 @@ The tracking issue for this feature is: [#42524](https://github.com/rust-lang/ru This feature is internal to the Rust compiler and is not intended for general use. ------------------------- -"##, - }, - Lint { - label: "ptr_addr_eq", - description: r##"# `ptr_addr_eq` - -The tracking issue for this feature is: [#116324] - -[#116324]: https://github.com/rust-lang/rust/issues/116324 - ------------------------ "##, }, @@ -7281,17 +7310,6 @@ The tracking issue for this feature is: [#75402] [#75402]: https://github.com/rust-lang/rust/issues/75402 ------------------------- -"##, - }, - Lint { - label: "ptr_from_ref", - description: r##"# `ptr_from_ref` - -The tracking issue for this feature is: [#106116] - -[#106116]: https://github.com/rust-lang/rust/issues/106116 - ------------------------ "##, }, @@ -7502,28 +7520,6 @@ The tracking issue for this feature is: [#70142] [#70142]: https://github.com/rust-lang/rust/issues/70142 ------------------------- -"##, - }, - Lint { - label: "result_option_inspect", - description: r##"# `result_option_inspect` - -The tracking issue for this feature is: [#91345] - -[#91345]: https://github.com/rust-lang/rust/issues/91345 - ------------------------- -"##, - }, - Lint { - label: "return_position_impl_trait_in_trait", - description: r##"# `return_position_impl_trait_in_trait` - -The tracking issue for this feature is: [#91611] - -[#91611]: https://github.com/rust-lang/rust/issues/91611 - ------------------------ "##, }, @@ -7709,6 +7705,17 @@ The tracking issue for this feature is: [#101730] This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. +------------------------ +"##, + }, + Lint { + label: "seek_seek_relative", + description: r##"# `seek_seek_relative` + +The tracking issue for this feature is: [#117374] + +[#117374]: https://github.com/rust-lang/rust/issues/117374 + ------------------------ "##, }, @@ -7945,6 +7952,17 @@ The tracking issue for this feature is: [#76014] [#76014]: https://github.com/rust-lang/rust/issues/76014 +------------------------ +"##, + }, + Lint { + label: "slice_split_once", + description: r##"# `slice_split_once` + +The tracking issue for this feature is: [#112811] + +[#112811]: https://github.com/rust-lang/rust/issues/112811 + ------------------------ "##, }, @@ -8174,6 +8192,17 @@ The tracking issue for this feature is: [#15701] [#15701]: https://github.com/rust-lang/rust/issues/15701 +------------------------ +"##, + }, + Lint { + label: "str_from_utf16_endian", + description: r##"# `str_from_utf16_endian` + +The tracking issue for this feature is: [#116258] + +[#116258]: https://github.com/rust-lang/rust/issues/116258 + ------------------------ "##, }, @@ -8265,6 +8294,44 @@ The tracking issue for this feature is: [#87121] [#87121]: https://github.com/rust-lang/rust/issues/87121 ------------------------ + +This feature permits pattern matching `String` to `&str` through [its `Deref` implementation]. + +```rust +#![feature(string_deref_patterns)] + +pub enum Value { + String(String), + Number(u32), +} + +pub fn is_it_the_answer(value: Value) -> bool { + match value { + Value::String("42") => true, + Value::Number(42) => true, + _ => false, + } +} +``` + +Without this feature other constructs such as match guards have to be used. + +```rust +# pub enum Value { +# String(String), +# Number(u32), +# } +# +pub fn is_it_the_answer(value: Value) -> bool { + match value { + Value::String(s) if s == "42" => true, + Value::Number(42) => true, + _ => false, + } +} +``` + +[its `Deref` implementation]: https://doc.rust-lang.org/std/string/struct.String.html#impl-Deref-for-String "##, }, Lint { @@ -8526,15 +8593,6 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured However, the optimizer can still modify a testcase in an undesirable manner even when using either of the above. -"##, - }, - Lint { - label: "test_2018_feature", - description: r##"# `test_2018_feature` - -This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. - ------------------------- "##, }, Lint { @@ -8700,37 +8758,6 @@ pub fn main() { println!("{:?}", b); } ``` -"##, - }, - Lint { - label: "trait_upcasting", - description: r##"# `trait_upcasting` - -The tracking issue for this feature is: [#65991] - -[#65991]: https://github.com/rust-lang/rust/issues/65991 - ------------------------- - -The `trait_upcasting` feature adds support for trait upcasting coercion. This allows a -trait object of type `dyn Bar` to be cast to a trait object of type `dyn Foo` -so long as `Bar: Foo`. - -```rust,edition2018 -#![feature(trait_upcasting)] -#![allow(incomplete_features)] - -trait Foo {} - -trait Bar: Foo {} - -impl Foo for i32 {} - -impl Bar for T {} - -let bar: &dyn Bar = &123; -let foo: &dyn Foo = bar; -``` "##, }, Lint { @@ -8850,6 +8877,15 @@ The tracking issue for this feature is: [#48214] [#48214]: https://github.com/rust-lang/rust/issues/48214 +------------------------ +"##, + }, + Lint { + label: "trusted_fused", + description: r##"# `trusted_fused` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + ------------------------ "##, }, @@ -9050,17 +9086,6 @@ fn main () { }; } ``` -"##, - }, - Lint { - label: "type_name_of_val", - description: r##"# `type_name_of_val` - -The tracking issue for this feature is: [#66359] - -[#66359]: https://github.com/rust-lang/rust/issues/66359 - ------------------------- "##, }, Lint { @@ -9122,6 +9147,28 @@ The tracking issue for this feature is: [#85122] [#85122]: https://github.com/rust-lang/rust/issues/85122 +------------------------ +"##, + }, + Lint { + label: "unchecked_neg", + description: r##"# `unchecked_neg` + +The tracking issue for this feature is: [#85122] + +[#85122]: https://github.com/rust-lang/rust/issues/85122 + +------------------------ +"##, + }, + Lint { + label: "unchecked_shifts", + description: r##"# `unchecked_shifts` + +The tracking issue for this feature is: [#85122] + +[#85122]: https://github.com/rust-lang/rust/issues/85122 + ------------------------ "##, }, @@ -9630,9 +9677,9 @@ The tracking issue for this feature is: [#81944] label: "waker_getters", description: r##"# `waker_getters` -The tracking issue for this feature is: [#87021] +The tracking issue for this feature is: [#96992] -[#87021]: https://github.com/rust-lang/rust/issues/87021 +[#96992]: https://github.com/rust-lang/rust/issues/96992 ------------------------ "##, @@ -9712,7 +9759,9 @@ This feature is internal to the Rust compiler and is not intended for general us label: "windows_process_exit_code_from", description: r##"# `windows_process_exit_code_from` -This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. +The tracking issue for this feature is: [#111688] + +[#111688]: https://github.com/rust-lang/rust/issues/111688 ------------------------ "##, @@ -10008,7 +10057,7 @@ table: description: r##"Checks for `warn`/`deny`/`forbid` attributes targeting the whole clippy::restriction category."##, }, Lint { - label: "clippy::blocks_in_if_conditions", + label: "clippy::blocks_in_conditions", description: r##"Checks for `if` conditions that use blocks containing an expression, statements or conditions that use closures with blocks."##, }, @@ -10315,7 +10364,8 @@ with `#[rustfmt::skip]`."##, Lint { label: "clippy::deprecated_semver", description: r##"Checks for `#[deprecated]` annotations with a `since` -field that is not a valid semantic version."##, +field that is not a valid semantic version. Also allows TBD to signal +future deprecation."##, }, Lint { label: "clippy::deref_addrof", @@ -10462,7 +10512,7 @@ if the `never_type` is enabled."##, }, Lint { label: "clippy::empty_line_after_doc_comments", - description: r##"Checks for empty lines after documenation comments."##, + description: r##"Checks for empty lines after documentation comments."##, }, Lint { label: "clippy::empty_line_after_outer_attr", @@ -10777,6 +10827,13 @@ and the *else* part."##, label: "clippy::ignored_unit_patterns", description: r##"Checks for usage of `_` in patterns of type `()`."##, }, + Lint { + label: "clippy::impl_hash_borrow_with_str_and_bytes", + description: r##"This lint is concerned with the semantics of `Borrow` and `Hash` for a +type that implements all three of `Hash`, `Borrow` and `Borrow<[u8]>` +as it is impossible to satisfy the semantics of Borrow and `Hash` for +both `Borrow` and `Borrow<[u8]>`."##, + }, Lint { label: "clippy::impl_trait_in_params", description: r##"Lints when `impl Trait` is being used in a function's parameters."##, @@ -10852,6 +10909,11 @@ following table: |----------|----------|------------|-------| |`>` / `<=`|`\\|` / `^`|`x \\| 2 > 3`|`x > 3`| |`<` / `>=`|`\\|` / `^`|`x ^ 1 < 4` |`x < 4`|"##, + }, + Lint { + label: "clippy::ineffective_open_options", + description: r##"Checks if both `.write(true)` and `.append(true)` methods are called +on a same `OpenOptions`."##, }, Lint { label: "clippy::inefficient_to_string", @@ -10867,6 +10929,11 @@ or tuple struct where a `let` will suffice."##, label: "clippy::infinite_iter", description: r##"Checks for iteration that is guaranteed to be infinite."##, }, + Lint { + label: "clippy::infinite_loop", + description: r##"Checks for infinite loops in a function where the return type is not `!` +and lint accordingly."##, + }, Lint { label: "clippy::inherent_to_string", description: r##"Checks for the definition of inherent methods with a signature of `to_string(&self) -> String`."##, @@ -10997,6 +11064,10 @@ ignoring either the keys or values."##, description: r##"Looks for iterator combinator calls such as `.take(x)` or `.skip(x)` where `x` is greater than the amount of items that an iterator will produce."##, }, + Lint { + label: "clippy::iter_over_hash_type", + description: r##"This is a restriction lint which prevents the use of hash types (i.e., `HashSet` and `HashMap`) in for loops."##, + }, Lint { label: "clippy::iter_overeager_cloned", description: r##"Checks for usage of `_.cloned().()` where call to `.cloned()` can be postponed."##, @@ -11021,6 +11092,10 @@ where `x` is greater than the amount of items that an iterator will produce."##, label: "clippy::iterator_step_by_zero", description: r##"Checks for calling `.step_by(0)` on iterators which panics."##, }, + Lint { + label: "clippy::join_absolute_paths", + description: r##"Checks for calls to `Path::join` that start with a path separator (`\\\\` or `/`)."##, + }, Lint { label: "clippy::just_underscores_and_digits", description: r##"Checks if you have variables whose name consists of just @@ -11192,7 +11267,8 @@ where only the `Some` or `Ok` variant of the iterator element is used."##, Lint { label: "clippy::manual_is_ascii_check", description: r##"Suggests to use dedicated built-in methods, -`is_ascii_(lowercase|uppercase|digit)` for checking on corresponding ascii range"##, +`is_ascii_(lowercase|uppercase|digit|hexdigit)` for checking on corresponding +ascii range"##, }, Lint { label: "clippy::manual_is_finite", @@ -11400,7 +11476,9 @@ and take drastic actions like `panic!`."##, Lint { label: "clippy::maybe_misused_cfg", description: r##"Checks for `#[cfg(features = ...)]` and suggests to replace it with -`#[cfg(feature = ...)]`."##, +`#[cfg(feature = ...)]`. + +It also checks if `cfg(test)` was misspelled."##, }, Lint { label: "clippy::mem_forget", @@ -11478,7 +11556,10 @@ is greater than the largest index used to index into the slice."##, Lint { label: "clippy::missing_enforced_import_renames", description: r##"Checks for imports that do not rename the item as specified -in the `enforce-import-renames` config option."##, +in the `enforce-import-renames` config option. + +Note: Even though this lint is warn-by-default, it will only trigger if +import renames are defined in the clippy.toml file."##, }, Lint { label: "clippy::missing_errors_doc", @@ -11877,7 +11958,8 @@ suggests usage of the `env!` macro."##, }, Lint { label: "clippy::option_filter_map", - description: r##"Checks for indirect collection of populated `Option`"##, + description: r##"Checks for iterators of `Option`s using ``.filter(Option::is_some).map(Option::unwrap)` that may +be replaced with a `.flatten()` call."##, }, Lint { label: "clippy::option_if_let_else", @@ -11887,6 +11969,10 @@ idiomatically done with `Option::map_or` (if the else bit is a pure expression) or `Option::map_or_else` (if the else bit is an impure expression)."##, }, + Lint { + label: "clippy::option_map_or_err_ok", + description: r##"Checks for usage of `_.map_or(Err(_), Ok)`."##, + }, Lint { label: "clippy::option_map_or_none", description: r##"Checks for usage of `_.map_or(None, _)`."##, @@ -12135,7 +12221,7 @@ This is typically done indirectly with the `write!` macro or with `to_string()`. }, Lint { label: "clippy::redundant_as_str", - description: r##"Checks for usage of `as_str()` on a `String`` chained with a method available on the `String` itself."##, + description: r##"Checks for usage of `as_str()` on a `String` chained with a method available on the `String` itself."##, }, Lint { label: "clippy::redundant_async_block", @@ -12198,7 +12284,7 @@ could be used."##, Lint { label: "clippy::redundant_pattern_matching", description: r##"Lint for redundant pattern matching over `Result`, `Option`, -`std::task::Poll` or `std::net::IpAddr`"##, +`std::task::Poll`, `std::net::IpAddr` or `bool`s"##, }, Lint { label: "clippy::redundant_pub_crate", @@ -12244,6 +12330,10 @@ do not change the type."##, The lint will evaluate constant expressions and values as arguments of `.repeat(..)` and emit a message if they are equivalent to `1`. (Related discussion in [rust-clippy#7306](https://github.com/rust-lang/rust-clippy/issues/7306))"##, }, + Lint { + label: "clippy::repeat_vec_with_capacity", + description: r##"Looks for patterns such as `vec![Vec::with_capacity(x); n]` or `iter::repeat(Vec::with_capacity(x))`."##, + }, Lint { label: "clippy::replace_consts", description: r##"Nothing. This lint has been deprecated."##, @@ -12256,6 +12346,11 @@ they are equivalent to `1`. (Related discussion in [rust-clippy#7306](https://gi label: "clippy::rest_pat_in_fully_bound_structs", description: r##"Checks for unnecessary '..' pattern binding on struct when all fields are explicitly matched."##, }, + Lint { + label: "clippy::result_filter_map", + description: r##"Checks for iterators of `Result`s using ``.filter(Result::is_ok).map(Result::unwrap)` that may +be replaced with a `.flatten()` call."##, + }, Lint { label: "clippy::result_large_err", description: r##"Checks for functions that return `Result` with an unusually large @@ -12535,6 +12630,11 @@ and suggest calling `as_bytes().len()` or `to_bytes().len()` respectively instea label: "clippy::struct_excessive_bools", description: r##"Checks for excessive use of bools in structs."##, + }, + Lint { + label: "clippy::struct_field_names", + description: r##"Detects struct fields that are prefixed or suffixed +by the same characters or the name of the struct itself."##, }, Lint { label: "clippy::suboptimal_flops", @@ -12613,6 +12713,11 @@ but there is a space between the unary and its operand."##, label: "clippy::temporary_assignment", description: r##"Checks for construction of a structure or tuple just to assign a value in it."##, + }, + Lint { + label: "clippy::test_attr_in_doctest", + description: r##"Checks for `#[test]` in doctests unless they are marked with +either `ignore`, `no_run` or `compile_fail`."##, }, Lint { label: "clippy::tests_outside_test_module", @@ -12744,6 +12849,11 @@ declarations above a certain complexity threshold."##, label: "clippy::unchecked_duration_subtraction", description: r##"Lints subtraction between an [`Instant`] and a [`Duration`]."##, }, + Lint { + label: "clippy::unconditional_recursion", + description: r##"Checks that there isn't an infinite recursion in `PartialEq` trait +implementation."##, + }, Lint { label: "clippy::undocumented_unsafe_blocks", description: r##"Checks for `unsafe` blocks and impls without a `// SAFETY: ` comment @@ -12778,6 +12888,11 @@ that is not equal to its label: "clippy::unimplemented", description: r##"Checks for usage of `unimplemented!`."##, }, + Lint { + label: "clippy::uninhabited_references", + description: r##"It detects references to uninhabited types, such as `!` and +warns when those are either dereferenced or returned from a function."##, + }, Lint { label: "clippy::uninit_assumed_init", description: r##"Checks for `MaybeUninit::uninit().assume_init()`."##, @@ -12821,6 +12936,11 @@ as returning a large `T` directly may be detrimental to performance."##, label: "clippy::unnecessary_cast", description: r##"Checks for casts to the same type, casts of int literals to integer types, casts of float literals to float types and casts between raw pointers without changing type or constness."##, + }, + Lint { + label: "clippy::unnecessary_fallible_conversions", + description: r##"Checks for calls to `TryInto::try_into` and `TryFrom::try_from` when their infallible counterparts +could be used."##, }, Lint { label: "clippy::unnecessary_filter_map", @@ -12864,7 +12984,8 @@ simpler code: }, Lint { label: "clippy::unnecessary_map_on_constructor", - description: r##"Suggest removing the use of a may (or map_err) method when an Option or Result is being construted."##, + description: r##"Suggests removing the use of a `map()` (or `map_err()`) method when an `Option` or `Result` +is being constructed."##, }, Lint { label: "clippy::unnecessary_mut_passed", @@ -12986,6 +13107,10 @@ types have different ABI, size or alignment."##, label: "clippy::unused_collect", description: r##"Nothing. This lint has been deprecated."##, }, + Lint { + label: "clippy::unused_enumerate_index", + description: r##"Checks for uses of the `enumerate` method where the index is unused (`_`)"##, + }, Lint { label: "clippy::unused_format_specs", description: r##"Detects [formatting parameters] that have no effect on the output of @@ -13130,8 +13255,8 @@ to `trailing_zeros`"##, description: r##"Checks for usage of File::read_to_end and File::read_to_string."##, }, Lint { - label: "clippy::vtable_address_comparisons", - description: r##"Checks for comparisons with an address of a trait vtable."##, + label: "clippy::waker_clone_wake", + description: r##"Checks for usage of `waker.clone().wake()`"##, }, Lint { label: "clippy::while_immutable_condition", @@ -13251,7 +13376,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "clippy::complexity", - description: r##"lint group for: clippy::bind_instead_of_map, clippy::bool_comparison, clippy::borrow_deref_ref, clippy::borrowed_box, clippy::bytes_count_to_len, clippy::char_lit_as_u8, clippy::clone_on_copy, clippy::crosspointer_transmute, clippy::default_constructed_unit_structs, clippy::deprecated_cfg_attr, clippy::deref_addrof, clippy::derivable_impls, clippy::diverging_sub_expression, clippy::double_comparisons, clippy::double_parens, clippy::duration_subsec, clippy::excessive_nesting, clippy::explicit_auto_deref, clippy::explicit_counter_loop, clippy::explicit_write, clippy::extra_unused_lifetimes, clippy::extra_unused_type_parameters, clippy::filter_map_identity, clippy::filter_next, clippy::flat_map_identity, clippy::get_last_with_len, clippy::identity_op, clippy::inspect_for_each, clippy::int_plus_one, clippy::iter_count, clippy::iter_kv_map, clippy::let_with_type_underscore, clippy::manual_filter, clippy::manual_filter_map, clippy::manual_find, clippy::manual_find_map, clippy::manual_flatten, clippy::manual_hash_one, clippy::manual_main_separator_str, clippy::manual_range_patterns, clippy::manual_rem_euclid, clippy::manual_slice_size_calculation, clippy::manual_split_once, clippy::manual_strip, clippy::manual_swap, clippy::manual_unwrap_or, clippy::map_flatten, clippy::map_identity, clippy::match_as_ref, clippy::match_single_binding, clippy::needless_arbitrary_self_type, clippy::needless_bool, clippy::needless_bool_assign, clippy::needless_borrowed_reference, clippy::needless_if, clippy::needless_lifetimes, clippy::needless_match, clippy::needless_option_as_deref, clippy::needless_option_take, clippy::needless_question_mark, clippy::needless_splitn, clippy::needless_update, clippy::neg_cmp_op_on_partial_ord, clippy::no_effect, clippy::nonminimal_bool, clippy::only_used_in_recursion, clippy::option_as_ref_deref, clippy::option_filter_map, clippy::option_map_unit_fn, clippy::or_then_unwrap, clippy::overflow_check_conditional, clippy::partialeq_ne_impl, clippy::precedence, clippy::ptr_offset_with_cast, clippy::range_zip_with_len, clippy::redundant_as_str, clippy::redundant_async_block, clippy::redundant_at_rest_pattern, clippy::redundant_closure_call, clippy::redundant_guards, clippy::redundant_slicing, clippy::repeat_once, clippy::reserve_after_initialization, clippy::result_map_unit_fn, clippy::search_is_some, clippy::seek_from_current, clippy::seek_to_start_instead_of_rewind, clippy::short_circuit_statement, clippy::single_element_loop, clippy::skip_while_next, clippy::string_from_utf8_as_bytes, clippy::strlen_on_c_strings, clippy::temporary_assignment, clippy::too_many_arguments, clippy::transmute_bytes_to_str, clippy::transmute_float_to_int, clippy::transmute_int_to_bool, clippy::transmute_int_to_char, clippy::transmute_int_to_float, clippy::transmute_int_to_non_zero, clippy::transmute_num_to_bytes, clippy::transmute_ptr_to_ref, clippy::transmutes_expressible_as_ptr_casts, clippy::type_complexity, clippy::unit_arg, clippy::unnecessary_cast, clippy::unnecessary_filter_map, clippy::unnecessary_find_map, clippy::unnecessary_literal_unwrap, clippy::unnecessary_map_on_constructor, clippy::unnecessary_operation, clippy::unnecessary_sort_by, clippy::unnecessary_unwrap, clippy::unneeded_wildcard_pattern, clippy::unused_format_specs, clippy::useless_asref, clippy::useless_conversion, clippy::useless_format, clippy::useless_transmute, clippy::vec_box, clippy::while_let_loop, clippy::wildcard_in_or_patterns, clippy::zero_divided_by_zero, clippy::zero_prefixed_literal"##, + description: r##"lint group for: clippy::bind_instead_of_map, clippy::bool_comparison, clippy::borrow_deref_ref, clippy::borrowed_box, clippy::bytes_count_to_len, clippy::char_lit_as_u8, clippy::clone_on_copy, clippy::crosspointer_transmute, clippy::default_constructed_unit_structs, clippy::deprecated_cfg_attr, clippy::deref_addrof, clippy::derivable_impls, clippy::diverging_sub_expression, clippy::double_comparisons, clippy::double_parens, clippy::duration_subsec, clippy::excessive_nesting, clippy::explicit_auto_deref, clippy::explicit_counter_loop, clippy::explicit_write, clippy::extra_unused_lifetimes, clippy::extra_unused_type_parameters, clippy::filter_map_identity, clippy::filter_next, clippy::flat_map_identity, clippy::get_last_with_len, clippy::identity_op, clippy::implied_bounds_in_impls, clippy::inspect_for_each, clippy::int_plus_one, clippy::iter_count, clippy::iter_kv_map, clippy::let_with_type_underscore, clippy::manual_filter, clippy::manual_filter_map, clippy::manual_find, clippy::manual_find_map, clippy::manual_flatten, clippy::manual_hash_one, clippy::manual_main_separator_str, clippy::manual_range_patterns, clippy::manual_rem_euclid, clippy::manual_slice_size_calculation, clippy::manual_split_once, clippy::manual_strip, clippy::manual_swap, clippy::manual_unwrap_or, clippy::map_flatten, clippy::map_identity, clippy::match_as_ref, clippy::match_single_binding, clippy::needless_arbitrary_self_type, clippy::needless_bool, clippy::needless_bool_assign, clippy::needless_borrowed_reference, clippy::needless_if, clippy::needless_lifetimes, clippy::needless_match, clippy::needless_option_as_deref, clippy::needless_option_take, clippy::needless_question_mark, clippy::needless_splitn, clippy::needless_update, clippy::neg_cmp_op_on_partial_ord, clippy::no_effect, clippy::nonminimal_bool, clippy::only_used_in_recursion, clippy::option_as_ref_deref, clippy::option_filter_map, clippy::option_map_unit_fn, clippy::or_then_unwrap, clippy::overflow_check_conditional, clippy::partialeq_ne_impl, clippy::precedence, clippy::ptr_offset_with_cast, clippy::range_zip_with_len, clippy::redundant_as_str, clippy::redundant_async_block, clippy::redundant_at_rest_pattern, clippy::redundant_closure_call, clippy::redundant_guards, clippy::redundant_slicing, clippy::repeat_once, clippy::reserve_after_initialization, clippy::result_filter_map, clippy::result_map_unit_fn, clippy::search_is_some, clippy::seek_from_current, clippy::seek_to_start_instead_of_rewind, clippy::short_circuit_statement, clippy::single_element_loop, clippy::skip_while_next, clippy::string_from_utf8_as_bytes, clippy::strlen_on_c_strings, clippy::temporary_assignment, clippy::too_many_arguments, clippy::transmute_bytes_to_str, clippy::transmute_float_to_int, clippy::transmute_int_to_bool, clippy::transmute_int_to_char, clippy::transmute_int_to_float, clippy::transmute_int_to_non_zero, clippy::transmute_num_to_bytes, clippy::transmute_ptr_to_ref, clippy::transmutes_expressible_as_ptr_casts, clippy::type_complexity, clippy::unit_arg, clippy::unnecessary_cast, clippy::unnecessary_filter_map, clippy::unnecessary_find_map, clippy::unnecessary_literal_unwrap, clippy::unnecessary_map_on_constructor, clippy::unnecessary_operation, clippy::unnecessary_sort_by, clippy::unnecessary_unwrap, clippy::unneeded_wildcard_pattern, clippy::unused_format_specs, clippy::useless_asref, clippy::useless_conversion, clippy::useless_format, clippy::useless_transmute, clippy::vec_box, clippy::while_let_loop, clippy::wildcard_in_or_patterns, clippy::zero_divided_by_zero, clippy::zero_prefixed_literal"##, }, children: &[ "clippy::bind_instead_of_map", @@ -13281,6 +13406,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::flat_map_identity", "clippy::get_last_with_len", "clippy::identity_op", + "clippy::implied_bounds_in_impls", "clippy::inspect_for_each", "clippy::int_plus_one", "clippy::iter_count", @@ -13337,6 +13463,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::redundant_slicing", "clippy::repeat_once", "clippy::reserve_after_initialization", + "clippy::result_filter_map", "clippy::result_map_unit_fn", "clippy::search_is_some", "clippy::seek_from_current", @@ -13383,7 +13510,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "clippy::correctness", - description: r##"lint group for: clippy::absurd_extreme_comparisons, clippy::almost_swapped, clippy::approx_constant, clippy::async_yields_async, clippy::bad_bit_mask, clippy::cast_slice_different_sizes, clippy::deprecated_semver, clippy::derive_ord_xor_partial_ord, clippy::derived_hash_with_manual_eq, clippy::enum_clike_unportable_variant, clippy::eq_op, clippy::erasing_op, clippy::fn_address_comparisons, clippy::if_let_mutex, clippy::if_same_then_else, clippy::ifs_same_cond, clippy::impossible_comparisons, clippy::ineffective_bit_mask, clippy::infinite_iter, clippy::inherent_to_string_shadow_display, clippy::inline_fn_without_body, clippy::invalid_null_ptr_usage, clippy::invalid_regex, clippy::invisible_characters, clippy::iter_next_loop, clippy::iter_skip_zero, clippy::iterator_step_by_zero, clippy::let_underscore_lock, clippy::match_str_case_mismatch, clippy::mem_replace_with_uninit, clippy::min_max, clippy::mismatched_target_os, clippy::mistyped_literal_suffixes, clippy::modulo_one, clippy::mut_from_ref, clippy::never_loop, clippy::non_octal_unix_permissions, clippy::nonsensical_open_options, clippy::not_unsafe_ptr_arg_deref, clippy::option_env_unwrap, clippy::out_of_bounds_indexing, clippy::overly_complex_bool_expr, clippy::panicking_unwrap, clippy::possible_missing_comma, clippy::read_line_without_trim, clippy::read_zero_byte_vec, clippy::recursive_format_impl, clippy::redundant_comparisons, clippy::redundant_locals, clippy::reversed_empty_ranges, clippy::self_assignment, clippy::serde_api_misuse, clippy::size_of_in_element_count, clippy::suspicious_splitn, clippy::transmute_null_to_fn, clippy::transmuting_null, clippy::uninit_assumed_init, clippy::uninit_vec, clippy::unit_cmp, clippy::unit_hash, clippy::unit_return_expecting_ord, clippy::unsound_collection_transmute, clippy::unused_io_amount, clippy::useless_attribute, clippy::vec_resize_to_zero, clippy::vtable_address_comparisons, clippy::while_immutable_condition, clippy::wrong_transmute, clippy::zst_offset"##, + description: r##"lint group for: clippy::absurd_extreme_comparisons, clippy::almost_swapped, clippy::approx_constant, clippy::async_yields_async, clippy::bad_bit_mask, clippy::cast_slice_different_sizes, clippy::deprecated_semver, clippy::derive_ord_xor_partial_ord, clippy::derived_hash_with_manual_eq, clippy::enum_clike_unportable_variant, clippy::eq_op, clippy::erasing_op, clippy::fn_address_comparisons, clippy::if_let_mutex, clippy::ifs_same_cond, clippy::impl_hash_borrow_with_str_and_bytes, clippy::impossible_comparisons, clippy::ineffective_bit_mask, clippy::infinite_iter, clippy::inherent_to_string_shadow_display, clippy::inline_fn_without_body, clippy::invalid_null_ptr_usage, clippy::invalid_regex, clippy::invisible_characters, clippy::iter_next_loop, clippy::iter_skip_zero, clippy::iterator_step_by_zero, clippy::let_underscore_lock, clippy::match_str_case_mismatch, clippy::mem_replace_with_uninit, clippy::min_max, clippy::mismatched_target_os, clippy::mistyped_literal_suffixes, clippy::modulo_one, clippy::mut_from_ref, clippy::never_loop, clippy::non_octal_unix_permissions, clippy::nonsensical_open_options, clippy::not_unsafe_ptr_arg_deref, clippy::option_env_unwrap, clippy::out_of_bounds_indexing, clippy::overly_complex_bool_expr, clippy::panicking_unwrap, clippy::possible_missing_comma, clippy::read_line_without_trim, clippy::recursive_format_impl, clippy::redundant_comparisons, clippy::redundant_locals, clippy::reversed_empty_ranges, clippy::self_assignment, clippy::serde_api_misuse, clippy::size_of_in_element_count, clippy::suspicious_splitn, clippy::transmute_null_to_fn, clippy::transmuting_null, clippy::uninit_assumed_init, clippy::uninit_vec, clippy::unit_cmp, clippy::unit_hash, clippy::unit_return_expecting_ord, clippy::unsound_collection_transmute, clippy::unused_io_amount, clippy::useless_attribute, clippy::vec_resize_to_zero, clippy::while_immutable_condition, clippy::wrong_transmute, clippy::zst_offset"##, }, children: &[ "clippy::absurd_extreme_comparisons", @@ -13400,8 +13527,8 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::erasing_op", "clippy::fn_address_comparisons", "clippy::if_let_mutex", - "clippy::if_same_then_else", "clippy::ifs_same_cond", + "clippy::impl_hash_borrow_with_str_and_bytes", "clippy::impossible_comparisons", "clippy::ineffective_bit_mask", "clippy::infinite_iter", @@ -13431,7 +13558,6 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::panicking_unwrap", "clippy::possible_missing_comma", "clippy::read_line_without_trim", - "clippy::read_zero_byte_vec", "clippy::recursive_format_impl", "clippy::redundant_comparisons", "clippy::redundant_locals", @@ -13451,7 +13577,6 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::unused_io_amount", "clippy::useless_attribute", "clippy::vec_resize_to_zero", - "clippy::vtable_address_comparisons", "clippy::while_immutable_condition", "clippy::wrong_transmute", "clippy::zst_offset", @@ -13484,7 +13609,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "clippy::nursery", - description: r##"lint group for: clippy::as_ptr_cast_mut, clippy::branches_sharing_code, clippy::clear_with_drain, clippy::cognitive_complexity, clippy::collection_is_never_read, clippy::debug_assert_with_mut_call, clippy::derive_partial_eq_without_eq, clippy::empty_line_after_doc_comments, clippy::empty_line_after_outer_attr, clippy::equatable_if_let, clippy::fallible_impl_from, clippy::future_not_send, clippy::implied_bounds_in_impls, clippy::imprecise_flops, clippy::iter_on_empty_collections, clippy::iter_on_single_items, clippy::iter_with_drain, clippy::large_stack_frames, clippy::manual_clamp, clippy::missing_const_for_fn, clippy::mutex_integer, clippy::needless_collect, clippy::needless_pass_by_ref_mut, clippy::non_send_fields_in_send_ty, clippy::nonstandard_macro_braces, clippy::option_if_let_else, clippy::or_fun_call, clippy::path_buf_push_overwrite, clippy::readonly_write_lock, clippy::redundant_clone, clippy::redundant_pub_crate, clippy::significant_drop_in_scrutinee, clippy::significant_drop_tightening, clippy::string_lit_as_bytes, clippy::suboptimal_flops, clippy::suspicious_operation_groupings, clippy::trailing_empty_array, clippy::trait_duplication_in_bounds, clippy::transmute_undefined_repr, clippy::trivial_regex, clippy::tuple_array_conversions, clippy::type_repetition_in_bounds, clippy::unnecessary_struct_initialization, clippy::unused_peekable, clippy::unused_rounding, clippy::use_self, clippy::useless_let_if_seq"##, + description: r##"lint group for: clippy::as_ptr_cast_mut, clippy::branches_sharing_code, clippy::clear_with_drain, clippy::cognitive_complexity, clippy::collection_is_never_read, clippy::debug_assert_with_mut_call, clippy::derive_partial_eq_without_eq, clippy::empty_line_after_doc_comments, clippy::empty_line_after_outer_attr, clippy::equatable_if_let, clippy::fallible_impl_from, clippy::future_not_send, clippy::imprecise_flops, clippy::iter_on_empty_collections, clippy::iter_on_single_items, clippy::iter_with_drain, clippy::large_stack_frames, clippy::manual_clamp, clippy::missing_const_for_fn, clippy::mutex_integer, clippy::needless_collect, clippy::needless_pass_by_ref_mut, clippy::non_send_fields_in_send_ty, clippy::nonstandard_macro_braces, clippy::option_if_let_else, clippy::or_fun_call, clippy::path_buf_push_overwrite, clippy::read_zero_byte_vec, clippy::readonly_write_lock, clippy::redundant_clone, clippy::redundant_pub_crate, clippy::significant_drop_in_scrutinee, clippy::significant_drop_tightening, clippy::string_lit_as_bytes, clippy::suboptimal_flops, clippy::suspicious_operation_groupings, clippy::trailing_empty_array, clippy::trait_duplication_in_bounds, clippy::transmute_undefined_repr, clippy::trivial_regex, clippy::tuple_array_conversions, clippy::type_repetition_in_bounds, clippy::uninhabited_references, clippy::unnecessary_struct_initialization, clippy::unused_peekable, clippy::unused_rounding, clippy::use_self, clippy::useless_let_if_seq"##, }, children: &[ "clippy::as_ptr_cast_mut", @@ -13499,7 +13624,6 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::equatable_if_let", "clippy::fallible_impl_from", "clippy::future_not_send", - "clippy::implied_bounds_in_impls", "clippy::imprecise_flops", "clippy::iter_on_empty_collections", "clippy::iter_on_single_items", @@ -13515,6 +13639,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::option_if_let_else", "clippy::or_fun_call", "clippy::path_buf_push_overwrite", + "clippy::read_zero_byte_vec", "clippy::readonly_write_lock", "clippy::redundant_clone", "clippy::redundant_pub_crate", @@ -13529,6 +13654,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::trivial_regex", "clippy::tuple_array_conversions", "clippy::type_repetition_in_bounds", + "clippy::uninhabited_references", "clippy::unnecessary_struct_initialization", "clippy::unused_peekable", "clippy::unused_rounding", @@ -13539,7 +13665,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "clippy::pedantic", - description: r##"lint group for: clippy::bool_to_int_with_if, clippy::borrow_as_ptr, clippy::case_sensitive_file_extension_comparisons, clippy::cast_lossless, clippy::cast_possible_truncation, clippy::cast_possible_wrap, clippy::cast_precision_loss, clippy::cast_ptr_alignment, clippy::cast_sign_loss, clippy::checked_conversions, clippy::cloned_instead_of_copied, clippy::copy_iterator, clippy::default_trait_access, clippy::doc_link_with_quotes, clippy::doc_markdown, clippy::empty_enum, clippy::enum_glob_use, clippy::expl_impl_clone_on_copy, clippy::explicit_deref_methods, clippy::explicit_into_iter_loop, clippy::explicit_iter_loop, clippy::filter_map_next, clippy::flat_map_option, clippy::float_cmp, clippy::fn_params_excessive_bools, clippy::from_iter_instead_of_collect, clippy::if_not_else, clippy::ignored_unit_patterns, clippy::implicit_clone, clippy::implicit_hasher, clippy::inconsistent_struct_constructor, clippy::index_refutable_slice, clippy::inefficient_to_string, clippy::inline_always, clippy::into_iter_without_iter, clippy::invalid_upcast_comparisons, clippy::items_after_statements, clippy::iter_not_returning_iterator, clippy::iter_without_into_iter, clippy::large_digit_groups, clippy::large_futures, clippy::large_stack_arrays, clippy::large_types_passed_by_value, clippy::linkedlist, clippy::macro_use_imports, clippy::manual_assert, clippy::manual_instant_elapsed, clippy::manual_let_else, clippy::manual_ok_or, clippy::manual_string_new, clippy::many_single_char_names, clippy::map_unwrap_or, clippy::match_bool, clippy::match_on_vec_items, clippy::match_same_arms, clippy::match_wild_err_arm, clippy::match_wildcard_for_single_variants, clippy::maybe_infinite_iter, clippy::mismatching_type_param_order, clippy::missing_errors_doc, clippy::missing_fields_in_debug, clippy::missing_panics_doc, clippy::module_name_repetitions, clippy::must_use_candidate, clippy::mut_mut, clippy::naive_bytecount, clippy::needless_bitwise_bool, clippy::needless_continue, clippy::needless_for_each, clippy::needless_pass_by_value, clippy::needless_raw_string_hashes, clippy::no_effect_underscore_binding, clippy::no_mangle_with_rust_abi, clippy::option_option, clippy::ptr_as_ptr, clippy::ptr_cast_constness, clippy::range_minus_one, clippy::range_plus_one, clippy::redundant_closure_for_method_calls, clippy::redundant_else, clippy::ref_binding_to_reference, clippy::ref_option_ref, clippy::return_self_not_must_use, clippy::same_functions_in_if_condition, clippy::semicolon_if_nothing_returned, clippy::should_panic_without_expect, clippy::similar_names, clippy::single_match_else, clippy::stable_sort_primitive, clippy::string_add_assign, clippy::struct_excessive_bools, clippy::too_many_lines, clippy::transmute_ptr_to_ptr, clippy::trivially_copy_pass_by_ref, clippy::unchecked_duration_subtraction, clippy::unicode_not_nfc, clippy::uninlined_format_args, clippy::unnecessary_box_returns, clippy::unnecessary_join, clippy::unnecessary_wraps, clippy::unnested_or_patterns, clippy::unreadable_literal, clippy::unsafe_derive_deserialize, clippy::unused_async, clippy::unused_self, clippy::used_underscore_binding, clippy::verbose_bit_mask, clippy::wildcard_imports, clippy::zero_sized_map_values"##, + description: r##"lint group for: clippy::bool_to_int_with_if, clippy::borrow_as_ptr, clippy::case_sensitive_file_extension_comparisons, clippy::cast_lossless, clippy::cast_possible_truncation, clippy::cast_possible_wrap, clippy::cast_precision_loss, clippy::cast_ptr_alignment, clippy::cast_sign_loss, clippy::checked_conversions, clippy::cloned_instead_of_copied, clippy::copy_iterator, clippy::default_trait_access, clippy::doc_link_with_quotes, clippy::doc_markdown, clippy::empty_enum, clippy::enum_glob_use, clippy::expl_impl_clone_on_copy, clippy::explicit_deref_methods, clippy::explicit_into_iter_loop, clippy::explicit_iter_loop, clippy::filter_map_next, clippy::flat_map_option, clippy::float_cmp, clippy::fn_params_excessive_bools, clippy::from_iter_instead_of_collect, clippy::if_not_else, clippy::ignored_unit_patterns, clippy::implicit_clone, clippy::implicit_hasher, clippy::inconsistent_struct_constructor, clippy::index_refutable_slice, clippy::inefficient_to_string, clippy::inline_always, clippy::into_iter_without_iter, clippy::invalid_upcast_comparisons, clippy::items_after_statements, clippy::iter_not_returning_iterator, clippy::iter_without_into_iter, clippy::large_digit_groups, clippy::large_futures, clippy::large_stack_arrays, clippy::large_types_passed_by_value, clippy::linkedlist, clippy::macro_use_imports, clippy::manual_assert, clippy::manual_instant_elapsed, clippy::manual_let_else, clippy::manual_ok_or, clippy::manual_string_new, clippy::many_single_char_names, clippy::map_unwrap_or, clippy::match_bool, clippy::match_on_vec_items, clippy::match_same_arms, clippy::match_wild_err_arm, clippy::match_wildcard_for_single_variants, clippy::maybe_infinite_iter, clippy::mismatching_type_param_order, clippy::missing_errors_doc, clippy::missing_fields_in_debug, clippy::missing_panics_doc, clippy::module_name_repetitions, clippy::must_use_candidate, clippy::mut_mut, clippy::naive_bytecount, clippy::needless_bitwise_bool, clippy::needless_continue, clippy::needless_for_each, clippy::needless_pass_by_value, clippy::needless_raw_string_hashes, clippy::no_effect_underscore_binding, clippy::no_mangle_with_rust_abi, clippy::option_option, clippy::ptr_as_ptr, clippy::ptr_cast_constness, clippy::range_minus_one, clippy::range_plus_one, clippy::redundant_closure_for_method_calls, clippy::redundant_else, clippy::ref_binding_to_reference, clippy::ref_option_ref, clippy::return_self_not_must_use, clippy::same_functions_in_if_condition, clippy::semicolon_if_nothing_returned, clippy::should_panic_without_expect, clippy::similar_names, clippy::single_match_else, clippy::stable_sort_primitive, clippy::string_add_assign, clippy::struct_excessive_bools, clippy::struct_field_names, clippy::too_many_lines, clippy::transmute_ptr_to_ptr, clippy::trivially_copy_pass_by_ref, clippy::unchecked_duration_subtraction, clippy::unicode_not_nfc, clippy::uninlined_format_args, clippy::unnecessary_box_returns, clippy::unnecessary_join, clippy::unnecessary_wraps, clippy::unnested_or_patterns, clippy::unreadable_literal, clippy::unsafe_derive_deserialize, clippy::unused_async, clippy::unused_self, clippy::used_underscore_binding, clippy::verbose_bit_mask, clippy::wildcard_imports, clippy::zero_sized_map_values"##, }, children: &[ "clippy::bool_to_int_with_if", @@ -13633,6 +13759,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::stable_sort_primitive", "clippy::string_add_assign", "clippy::struct_excessive_bools", + "clippy::struct_field_names", "clippy::too_many_lines", "clippy::transmute_ptr_to_ptr", "clippy::trivially_copy_pass_by_ref", @@ -13656,7 +13783,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "clippy::perf", - description: r##"lint group for: clippy::box_collection, clippy::box_default, clippy::boxed_local, clippy::cmp_owned, clippy::collapsible_str_replace, clippy::drain_collect, clippy::expect_fun_call, clippy::extend_with_drain, clippy::format_collect, clippy::format_in_format_args, clippy::iter_nth, clippy::iter_overeager_cloned, clippy::large_const_arrays, clippy::large_enum_variant, clippy::manual_memcpy, clippy::manual_retain, clippy::manual_str_repeat, clippy::manual_try_fold, clippy::map_entry, clippy::missing_spin_loop, clippy::redundant_allocation, clippy::result_large_err, clippy::single_char_pattern, clippy::slow_vector_initialization, clippy::to_string_in_format_args, clippy::unnecessary_to_owned, clippy::useless_vec, clippy::vec_init_then_push"##, + description: r##"lint group for: clippy::box_collection, clippy::box_default, clippy::boxed_local, clippy::cmp_owned, clippy::collapsible_str_replace, clippy::drain_collect, clippy::expect_fun_call, clippy::extend_with_drain, clippy::format_collect, clippy::format_in_format_args, clippy::iter_nth, clippy::iter_overeager_cloned, clippy::large_const_arrays, clippy::large_enum_variant, clippy::manual_memcpy, clippy::manual_retain, clippy::manual_str_repeat, clippy::manual_try_fold, clippy::map_entry, clippy::missing_spin_loop, clippy::redundant_allocation, clippy::result_large_err, clippy::single_char_pattern, clippy::slow_vector_initialization, clippy::to_string_in_format_args, clippy::unnecessary_to_owned, clippy::useless_vec, clippy::vec_init_then_push, clippy::waker_clone_wake"##, }, children: &[ "clippy::box_collection", @@ -13687,12 +13814,13 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::unnecessary_to_owned", "clippy::useless_vec", "clippy::vec_init_then_push", + "clippy::waker_clone_wake", ], }, LintGroup { lint: Lint { label: "clippy::restriction", - description: r##"lint group for: clippy::absolute_paths, clippy::alloc_instead_of_core, clippy::allow_attributes, clippy::allow_attributes_without_reason, clippy::arithmetic_side_effects, clippy::as_conversions, clippy::as_underscore, clippy::assertions_on_result_states, clippy::big_endian_bytes, clippy::clone_on_ref_ptr, clippy::create_dir, clippy::dbg_macro, clippy::decimal_literal_representation, clippy::default_numeric_fallback, clippy::default_union_representation, clippy::deref_by_slicing, clippy::disallowed_script_idents, clippy::else_if_without_else, clippy::empty_drop, clippy::empty_structs_with_brackets, clippy::error_impl_error, clippy::exhaustive_enums, clippy::exhaustive_structs, clippy::exit, clippy::expect_used, clippy::filetype_is_file, clippy::float_arithmetic, clippy::float_cmp_const, clippy::fn_to_numeric_cast_any, clippy::format_push_string, clippy::get_unwrap, clippy::host_endian_bytes, clippy::if_then_some_else_none, clippy::impl_trait_in_params, clippy::implicit_return, clippy::indexing_slicing, clippy::inline_asm_x86_att_syntax, clippy::inline_asm_x86_intel_syntax, clippy::integer_division, clippy::large_include_file, clippy::let_underscore_must_use, clippy::let_underscore_untyped, clippy::little_endian_bytes, clippy::lossy_float_literal, clippy::map_err_ignore, clippy::mem_forget, clippy::min_ident_chars, clippy::missing_assert_message, clippy::missing_asserts_for_indexing, clippy::missing_docs_in_private_items, clippy::missing_enforced_import_renames, clippy::missing_inline_in_public_items, clippy::missing_trait_methods, clippy::mixed_read_write_in_expression, clippy::mod_module_files, clippy::modulo_arithmetic, clippy::multiple_inherent_impl, clippy::multiple_unsafe_ops_per_block, clippy::mutex_atomic, clippy::needless_raw_strings, clippy::non_ascii_literal, clippy::panic, clippy::panic_in_result_fn, clippy::partial_pub_fields, clippy::pattern_type_mismatch, clippy::print_stderr, clippy::print_stdout, clippy::pub_use, clippy::pub_with_shorthand, clippy::pub_without_shorthand, clippy::question_mark_used, clippy::rc_buffer, clippy::rc_mutex, clippy::redundant_type_annotations, clippy::ref_patterns, clippy::rest_pat_in_fully_bound_structs, clippy::same_name_method, clippy::self_named_module_files, clippy::semicolon_inside_block, clippy::semicolon_outside_block, clippy::separated_literal_suffix, clippy::shadow_reuse, clippy::shadow_same, clippy::shadow_unrelated, clippy::single_call_fn, clippy::single_char_lifetime_names, clippy::std_instead_of_alloc, clippy::std_instead_of_core, clippy::str_to_string, clippy::string_add, clippy::string_lit_chars_any, clippy::string_slice, clippy::string_to_string, clippy::suspicious_xor_used_as_pow, clippy::tests_outside_test_module, clippy::todo, clippy::try_err, clippy::undocumented_unsafe_blocks, clippy::unimplemented, clippy::unnecessary_safety_comment, clippy::unnecessary_safety_doc, clippy::unnecessary_self_imports, clippy::unneeded_field_pattern, clippy::unreachable, clippy::unseparated_literal_suffix, clippy::unwrap_in_result, clippy::unwrap_used, clippy::use_debug, clippy::verbose_file_reads, clippy::wildcard_enum_match_arm"##, + description: r##"lint group for: clippy::absolute_paths, clippy::alloc_instead_of_core, clippy::allow_attributes, clippy::allow_attributes_without_reason, clippy::arithmetic_side_effects, clippy::as_conversions, clippy::as_underscore, clippy::assertions_on_result_states, clippy::big_endian_bytes, clippy::clone_on_ref_ptr, clippy::create_dir, clippy::dbg_macro, clippy::decimal_literal_representation, clippy::default_numeric_fallback, clippy::default_union_representation, clippy::deref_by_slicing, clippy::disallowed_script_idents, clippy::else_if_without_else, clippy::empty_drop, clippy::empty_structs_with_brackets, clippy::error_impl_error, clippy::exhaustive_enums, clippy::exhaustive_structs, clippy::exit, clippy::expect_used, clippy::filetype_is_file, clippy::float_arithmetic, clippy::float_cmp_const, clippy::fn_to_numeric_cast_any, clippy::format_push_string, clippy::get_unwrap, clippy::host_endian_bytes, clippy::if_then_some_else_none, clippy::impl_trait_in_params, clippy::implicit_return, clippy::indexing_slicing, clippy::infinite_loop, clippy::inline_asm_x86_att_syntax, clippy::inline_asm_x86_intel_syntax, clippy::integer_division, clippy::iter_over_hash_type, clippy::large_include_file, clippy::let_underscore_must_use, clippy::let_underscore_untyped, clippy::little_endian_bytes, clippy::lossy_float_literal, clippy::map_err_ignore, clippy::mem_forget, clippy::min_ident_chars, clippy::missing_assert_message, clippy::missing_asserts_for_indexing, clippy::missing_docs_in_private_items, clippy::missing_inline_in_public_items, clippy::missing_trait_methods, clippy::mixed_read_write_in_expression, clippy::mod_module_files, clippy::modulo_arithmetic, clippy::multiple_inherent_impl, clippy::multiple_unsafe_ops_per_block, clippy::mutex_atomic, clippy::needless_raw_strings, clippy::non_ascii_literal, clippy::panic, clippy::panic_in_result_fn, clippy::partial_pub_fields, clippy::pattern_type_mismatch, clippy::print_stderr, clippy::print_stdout, clippy::pub_use, clippy::pub_with_shorthand, clippy::pub_without_shorthand, clippy::question_mark_used, clippy::rc_buffer, clippy::rc_mutex, clippy::redundant_type_annotations, clippy::ref_patterns, clippy::rest_pat_in_fully_bound_structs, clippy::same_name_method, clippy::self_named_module_files, clippy::semicolon_inside_block, clippy::semicolon_outside_block, clippy::separated_literal_suffix, clippy::shadow_reuse, clippy::shadow_same, clippy::shadow_unrelated, clippy::single_call_fn, clippy::single_char_lifetime_names, clippy::std_instead_of_alloc, clippy::std_instead_of_core, clippy::str_to_string, clippy::string_add, clippy::string_lit_chars_any, clippy::string_slice, clippy::string_to_string, clippy::suspicious_xor_used_as_pow, clippy::tests_outside_test_module, clippy::todo, clippy::try_err, clippy::undocumented_unsafe_blocks, clippy::unimplemented, clippy::unnecessary_safety_comment, clippy::unnecessary_safety_doc, clippy::unnecessary_self_imports, clippy::unneeded_field_pattern, clippy::unreachable, clippy::unseparated_literal_suffix, clippy::unwrap_in_result, clippy::unwrap_used, clippy::use_debug, clippy::verbose_file_reads, clippy::wildcard_enum_match_arm"##, }, children: &[ "clippy::absolute_paths", @@ -13731,9 +13859,11 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::impl_trait_in_params", "clippy::implicit_return", "clippy::indexing_slicing", + "clippy::infinite_loop", "clippy::inline_asm_x86_att_syntax", "clippy::inline_asm_x86_intel_syntax", "clippy::integer_division", + "clippy::iter_over_hash_type", "clippy::large_include_file", "clippy::let_underscore_must_use", "clippy::let_underscore_untyped", @@ -13745,7 +13875,6 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::missing_assert_message", "clippy::missing_asserts_for_indexing", "clippy::missing_docs_in_private_items", - "clippy::missing_enforced_import_renames", "clippy::missing_inline_in_public_items", "clippy::missing_trait_methods", "clippy::mixed_read_write_in_expression", @@ -13810,12 +13939,12 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "clippy::style", - description: r##"lint group for: clippy::assertions_on_constants, clippy::assign_op_pattern, clippy::blocks_in_if_conditions, clippy::bool_assert_comparison, clippy::borrow_interior_mutable_const, clippy::builtin_type_shadow, clippy::bytes_nth, clippy::chars_last_cmp, clippy::chars_next_cmp, clippy::cmp_null, clippy::collapsible_else_if, clippy::collapsible_if, clippy::collapsible_match, clippy::comparison_chain, clippy::comparison_to_empty, clippy::declare_interior_mutable_const, clippy::default_instead_of_iter_empty, clippy::disallowed_macros, clippy::disallowed_methods, clippy::disallowed_names, clippy::disallowed_types, clippy::double_must_use, clippy::double_neg, clippy::duplicate_underscore_argument, clippy::enum_variant_names, clippy::err_expect, clippy::excessive_precision, clippy::field_reassign_with_default, clippy::filter_map_bool_then, clippy::fn_to_numeric_cast, clippy::fn_to_numeric_cast_with_truncation, clippy::for_kv_map, clippy::from_over_into, clippy::from_str_radix_10, clippy::get_first, clippy::implicit_saturating_add, clippy::implicit_saturating_sub, clippy::inconsistent_digit_grouping, clippy::infallible_destructuring_match, clippy::inherent_to_string, clippy::init_numbered_fields, clippy::into_iter_on_ref, clippy::is_digit_ascii_radix, clippy::items_after_test_module, clippy::iter_cloned_collect, clippy::iter_next_slice, clippy::iter_nth_zero, clippy::iter_skip_next, clippy::just_underscores_and_digits, clippy::len_without_is_empty, clippy::len_zero, clippy::let_and_return, clippy::let_unit_value, clippy::main_recursion, clippy::manual_async_fn, clippy::manual_bits, clippy::manual_is_ascii_check, clippy::manual_is_finite, clippy::manual_is_infinite, clippy::manual_map, clippy::manual_next_back, clippy::manual_non_exhaustive, clippy::manual_range_contains, clippy::manual_saturating_arithmetic, clippy::manual_while_let_some, clippy::map_clone, clippy::map_collect_result_unit, clippy::match_like_matches_macro, clippy::match_overlapping_arm, clippy::match_ref_pats, clippy::match_result_ok, clippy::mem_replace_option_with_none, clippy::mem_replace_with_default, clippy::missing_safety_doc, clippy::mixed_case_hex_literals, clippy::module_inception, clippy::must_use_unit, clippy::mut_mutex_lock, clippy::needless_borrow, clippy::needless_borrows_for_generic_args, clippy::needless_doctest_main, clippy::needless_else, clippy::needless_late_init, clippy::needless_parens_on_range_literals, clippy::needless_pub_self, clippy::needless_range_loop, clippy::needless_return, clippy::needless_return_with_question_mark, clippy::neg_multiply, clippy::new_ret_no_self, clippy::new_without_default, clippy::non_minimal_cfg, clippy::obfuscated_if_else, clippy::ok_expect, clippy::op_ref, clippy::option_map_or_none, clippy::partialeq_to_none, clippy::print_literal, clippy::print_with_newline, clippy::println_empty_string, clippy::ptr_arg, clippy::ptr_eq, clippy::question_mark, clippy::redundant_closure, clippy::redundant_field_names, clippy::redundant_pattern, clippy::redundant_pattern_matching, clippy::redundant_static_lifetimes, clippy::result_map_or_into_option, clippy::result_unit_err, clippy::same_item_push, clippy::self_named_constructors, clippy::should_implement_trait, clippy::single_char_add_str, clippy::single_component_path_imports, clippy::single_match, clippy::string_extend_chars, clippy::tabs_in_doc_comments, clippy::to_digit_is_some, clippy::toplevel_ref_arg, clippy::trim_split_whitespace, clippy::unnecessary_fold, clippy::unnecessary_lazy_evaluations, clippy::unnecessary_mut_passed, clippy::unnecessary_owned_empty_strings, clippy::unsafe_removed_from_name, clippy::unused_unit, clippy::unusual_byte_groupings, clippy::unwrap_or_default, clippy::upper_case_acronyms, clippy::while_let_on_iterator, clippy::write_literal, clippy::write_with_newline, clippy::writeln_empty_string, clippy::wrong_self_convention, clippy::zero_ptr"##, + description: r##"lint group for: clippy::assertions_on_constants, clippy::assign_op_pattern, clippy::blocks_in_conditions, clippy::bool_assert_comparison, clippy::borrow_interior_mutable_const, clippy::builtin_type_shadow, clippy::bytes_nth, clippy::chars_last_cmp, clippy::chars_next_cmp, clippy::cmp_null, clippy::collapsible_else_if, clippy::collapsible_if, clippy::collapsible_match, clippy::comparison_chain, clippy::comparison_to_empty, clippy::declare_interior_mutable_const, clippy::default_instead_of_iter_empty, clippy::disallowed_macros, clippy::disallowed_methods, clippy::disallowed_names, clippy::disallowed_types, clippy::double_must_use, clippy::double_neg, clippy::duplicate_underscore_argument, clippy::enum_variant_names, clippy::err_expect, clippy::excessive_precision, clippy::field_reassign_with_default, clippy::filter_map_bool_then, clippy::fn_to_numeric_cast, clippy::fn_to_numeric_cast_with_truncation, clippy::for_kv_map, clippy::from_over_into, clippy::from_str_radix_10, clippy::get_first, clippy::if_same_then_else, clippy::implicit_saturating_add, clippy::implicit_saturating_sub, clippy::inconsistent_digit_grouping, clippy::infallible_destructuring_match, clippy::inherent_to_string, clippy::init_numbered_fields, clippy::into_iter_on_ref, clippy::is_digit_ascii_radix, clippy::items_after_test_module, clippy::iter_cloned_collect, clippy::iter_next_slice, clippy::iter_nth_zero, clippy::iter_skip_next, clippy::just_underscores_and_digits, clippy::len_without_is_empty, clippy::len_zero, clippy::let_and_return, clippy::let_unit_value, clippy::main_recursion, clippy::manual_async_fn, clippy::manual_bits, clippy::manual_is_ascii_check, clippy::manual_is_finite, clippy::manual_is_infinite, clippy::manual_map, clippy::manual_next_back, clippy::manual_non_exhaustive, clippy::manual_range_contains, clippy::manual_saturating_arithmetic, clippy::manual_while_let_some, clippy::map_clone, clippy::map_collect_result_unit, clippy::match_like_matches_macro, clippy::match_overlapping_arm, clippy::match_ref_pats, clippy::match_result_ok, clippy::mem_replace_option_with_none, clippy::mem_replace_with_default, clippy::missing_enforced_import_renames, clippy::missing_safety_doc, clippy::mixed_case_hex_literals, clippy::module_inception, clippy::must_use_unit, clippy::mut_mutex_lock, clippy::needless_borrow, clippy::needless_borrows_for_generic_args, clippy::needless_doctest_main, clippy::needless_else, clippy::needless_late_init, clippy::needless_parens_on_range_literals, clippy::needless_pub_self, clippy::needless_range_loop, clippy::needless_return, clippy::needless_return_with_question_mark, clippy::neg_multiply, clippy::new_ret_no_self, clippy::new_without_default, clippy::non_minimal_cfg, clippy::obfuscated_if_else, clippy::ok_expect, clippy::op_ref, clippy::option_map_or_err_ok, clippy::option_map_or_none, clippy::partialeq_to_none, clippy::print_literal, clippy::print_with_newline, clippy::println_empty_string, clippy::ptr_arg, clippy::ptr_eq, clippy::question_mark, clippy::redundant_closure, clippy::redundant_field_names, clippy::redundant_pattern, clippy::redundant_pattern_matching, clippy::redundant_static_lifetimes, clippy::result_map_or_into_option, clippy::result_unit_err, clippy::same_item_push, clippy::self_named_constructors, clippy::should_implement_trait, clippy::single_char_add_str, clippy::single_component_path_imports, clippy::single_match, clippy::string_extend_chars, clippy::tabs_in_doc_comments, clippy::to_digit_is_some, clippy::toplevel_ref_arg, clippy::trim_split_whitespace, clippy::unnecessary_fallible_conversions, clippy::unnecessary_fold, clippy::unnecessary_lazy_evaluations, clippy::unnecessary_mut_passed, clippy::unnecessary_owned_empty_strings, clippy::unsafe_removed_from_name, clippy::unused_enumerate_index, clippy::unused_unit, clippy::unusual_byte_groupings, clippy::unwrap_or_default, clippy::upper_case_acronyms, clippy::while_let_on_iterator, clippy::write_literal, clippy::write_with_newline, clippy::writeln_empty_string, clippy::wrong_self_convention, clippy::zero_ptr"##, }, children: &[ "clippy::assertions_on_constants", "clippy::assign_op_pattern", - "clippy::blocks_in_if_conditions", + "clippy::blocks_in_conditions", "clippy::bool_assert_comparison", "clippy::borrow_interior_mutable_const", "clippy::builtin_type_shadow", @@ -13848,6 +13977,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::from_over_into", "clippy::from_str_radix_10", "clippy::get_first", + "clippy::if_same_then_else", "clippy::implicit_saturating_add", "clippy::implicit_saturating_sub", "clippy::inconsistent_digit_grouping", @@ -13886,6 +14016,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::match_result_ok", "clippy::mem_replace_option_with_none", "clippy::mem_replace_with_default", + "clippy::missing_enforced_import_renames", "clippy::missing_safety_doc", "clippy::mixed_case_hex_literals", "clippy::module_inception", @@ -13908,6 +14039,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::obfuscated_if_else", "clippy::ok_expect", "clippy::op_ref", + "clippy::option_map_or_err_ok", "clippy::option_map_or_none", "clippy::partialeq_to_none", "clippy::print_literal", @@ -13934,11 +14066,13 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::to_digit_is_some", "clippy::toplevel_ref_arg", "clippy::trim_split_whitespace", + "clippy::unnecessary_fallible_conversions", "clippy::unnecessary_fold", "clippy::unnecessary_lazy_evaluations", "clippy::unnecessary_mut_passed", "clippy::unnecessary_owned_empty_strings", "clippy::unsafe_removed_from_name", + "clippy::unused_enumerate_index", "clippy::unused_unit", "clippy::unusual_byte_groupings", "clippy::unwrap_or_default", @@ -13954,7 +14088,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "clippy::suspicious", - description: r##"lint group for: clippy::almost_complete_range, clippy::arc_with_non_send_sync, clippy::await_holding_invalid_type, clippy::await_holding_lock, clippy::await_holding_refcell_ref, clippy::blanket_clippy_restriction_lints, clippy::cast_abs_to_unsigned, clippy::cast_enum_constructor, clippy::cast_enum_truncation, clippy::cast_nan_to_int, clippy::cast_slice_from_raw_parts, clippy::crate_in_macro_def, clippy::drop_non_drop, clippy::duplicate_mod, clippy::empty_loop, clippy::float_equality_without_abs, clippy::forget_non_drop, clippy::four_forward_slashes, clippy::from_raw_with_void_ptr, clippy::iter_out_of_bounds, clippy::let_underscore_future, clippy::lines_filter_map_ok, clippy::maybe_misused_cfg, clippy::misnamed_getters, clippy::misrefactored_assign_op, clippy::multi_assignments, clippy::mut_range_bound, clippy::mutable_key_type, clippy::no_effect_replace, clippy::non_canonical_clone_impl, clippy::non_canonical_partial_ord_impl, clippy::octal_escapes, clippy::path_ends_with_ext, clippy::permissions_set_readonly_false, clippy::print_in_format_impl, clippy::rc_clone_in_vec_init, clippy::single_range_in_vec_init, clippy::size_of_ref, clippy::suspicious_arithmetic_impl, clippy::suspicious_assignment_formatting, clippy::suspicious_command_arg_space, clippy::suspicious_doc_comments, clippy::suspicious_else_formatting, clippy::suspicious_map, clippy::suspicious_op_assign_impl, clippy::suspicious_to_owned, clippy::suspicious_unary_op_formatting, clippy::swap_ptr_to_ref, clippy::type_id_on_box"##, + description: r##"lint group for: clippy::almost_complete_range, clippy::arc_with_non_send_sync, clippy::await_holding_invalid_type, clippy::await_holding_lock, clippy::await_holding_refcell_ref, clippy::blanket_clippy_restriction_lints, clippy::cast_abs_to_unsigned, clippy::cast_enum_constructor, clippy::cast_enum_truncation, clippy::cast_nan_to_int, clippy::cast_slice_from_raw_parts, clippy::crate_in_macro_def, clippy::drop_non_drop, clippy::duplicate_mod, clippy::empty_loop, clippy::float_equality_without_abs, clippy::forget_non_drop, clippy::four_forward_slashes, clippy::from_raw_with_void_ptr, clippy::ineffective_open_options, clippy::iter_out_of_bounds, clippy::join_absolute_paths, clippy::let_underscore_future, clippy::lines_filter_map_ok, clippy::maybe_misused_cfg, clippy::misnamed_getters, clippy::misrefactored_assign_op, clippy::multi_assignments, clippy::mut_range_bound, clippy::mutable_key_type, clippy::no_effect_replace, clippy::non_canonical_clone_impl, clippy::non_canonical_partial_ord_impl, clippy::octal_escapes, clippy::path_ends_with_ext, clippy::permissions_set_readonly_false, clippy::print_in_format_impl, clippy::rc_clone_in_vec_init, clippy::repeat_vec_with_capacity, clippy::single_range_in_vec_init, clippy::size_of_ref, clippy::suspicious_arithmetic_impl, clippy::suspicious_assignment_formatting, clippy::suspicious_command_arg_space, clippy::suspicious_doc_comments, clippy::suspicious_else_formatting, clippy::suspicious_map, clippy::suspicious_op_assign_impl, clippy::suspicious_to_owned, clippy::suspicious_unary_op_formatting, clippy::swap_ptr_to_ref, clippy::test_attr_in_doctest, clippy::type_id_on_box, clippy::unconditional_recursion"##, }, children: &[ "clippy::almost_complete_range", @@ -13976,7 +14110,9 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::forget_non_drop", "clippy::four_forward_slashes", "clippy::from_raw_with_void_ptr", + "clippy::ineffective_open_options", "clippy::iter_out_of_bounds", + "clippy::join_absolute_paths", "clippy::let_underscore_future", "clippy::lines_filter_map_ok", "clippy::maybe_misused_cfg", @@ -13993,6 +14129,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::permissions_set_readonly_false", "clippy::print_in_format_impl", "clippy::rc_clone_in_vec_init", + "clippy::repeat_vec_with_capacity", "clippy::single_range_in_vec_init", "clippy::size_of_ref", "clippy::suspicious_arithmetic_impl", @@ -14005,7 +14142,9 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::suspicious_to_owned", "clippy::suspicious_unary_op_formatting", "clippy::swap_ptr_to_ref", + "clippy::test_attr_in_doctest", "clippy::type_id_on_box", + "clippy::unconditional_recursion", ], }, ]; From f937673ce2b91ae7538941536428f681fad8b5b5 Mon Sep 17 00:00:00 2001 From: Moritz Hedtke Date: Mon, 25 Dec 2023 23:12:45 +0100 Subject: [PATCH 0233/1197] fix: rename generator to coroutine Follow the rename in nightly (see https://blog.rust-lang.org/inside-rust/2023/10/23/coroutines.html) --- crates/hir-def/src/body.rs | 2 +- crates/hir-def/src/body/lower.rs | 14 ++++----- crates/hir-def/src/body/pretty.rs | 2 +- crates/hir-def/src/hir.rs | 2 +- crates/hir-def/src/lang_item.rs | 4 +-- crates/hir-ty/src/builder.rs | 14 ++++----- crates/hir-ty/src/chalk_db.rs | 18 +++++------ crates/hir-ty/src/db.rs | 6 ++-- crates/hir-ty/src/display.rs | 12 ++++---- crates/hir-ty/src/infer.rs | 2 +- crates/hir-ty/src/infer/closure.rs | 4 +-- crates/hir-ty/src/infer/expr.rs | 12 ++++---- crates/hir-ty/src/mapping.rs | 6 ++-- crates/hir-ty/src/mir.rs | 30 +++++++++---------- crates/hir-ty/src/mir/borrowck.rs | 6 ++-- crates/hir-ty/src/mir/monomorphization.rs | 2 +- crates/hir-ty/src/tests/coercion.rs | 2 +- crates/hir-ty/src/tests/simple.rs | 26 ++++++++-------- .../src/handlers/generate_enum_is_method.rs | 10 +++---- crates/ide-db/src/apply_change.rs | 2 +- crates/ide-db/src/lib.rs | 2 +- crates/test-utils/src/minicore.rs | 22 +++++++------- 22 files changed, 100 insertions(+), 100 deletions(-) diff --git a/crates/hir-def/src/body.rs b/crates/hir-def/src/body.rs index db28c6731ece1..415800b9b79a7 100644 --- a/crates/hir-def/src/body.rs +++ b/crates/hir-def/src/body.rs @@ -37,7 +37,7 @@ pub struct Body { pub pats: Arena, pub bindings: Arena, pub labels: Arena

) { + obj.is_derived(); + Base::::is_base(obj); + Base::<()>::is_base(obj); +} + +fn main() { + let _x: fn(_) = f::<()>; + let _x: fn(_) = f::; +} From 06a41687b160cbb4cbf8fce0b3ad3a2e352e8338 Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Thu, 14 Dec 2023 22:07:53 +0800 Subject: [PATCH 0289/1197] Add unstable `-Z direct-access-external-data` cmdline flag for `rustc` The new flag has been described in the Major Change Proposal at https://github.com/rust-lang/compiler-team/issues/707 --- compiler/rustc_codegen_llvm/src/mono_item.rs | 25 +++++++++++-------- compiler/rustc_interface/src/tests.rs | 1 + compiler/rustc_session/src/options.rs | 2 ++ compiler/rustc_session/src/session.rs | 7 ++++++ compiler/rustc_target/src/spec/mod.rs | 11 ++++++++ .../targets/loongarch64_unknown_linux_gnu.rs | 1 + .../direct-access-external-data.md | 16 ++++++++++++ tests/codegen/direct-access-external-data.rs | 21 ++++++++++++++++ 8 files changed, 74 insertions(+), 10 deletions(-) create mode 100644 src/doc/unstable-book/src/compiler-flags/direct-access-external-data.md create mode 100644 tests/codegen/direct-access-external-data.rs diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index f796ce0990f12..f763071936837 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -123,6 +123,17 @@ impl CodegenCx<'_, '_> { return false; } + // Match clang by only supporting COFF and ELF for now. + if self.tcx.sess.target.is_like_osx { + return false; + } + + // With pie relocation model calls of functions defined in the translation + // unit can use copy relocations. + if self.tcx.sess.relocation_model() == RelocModel::Pie && !is_declaration { + return true; + } + // Thread-local variables generally don't support copy relocations. let is_thread_local_var = llvm::LLVMIsAGlobalVariable(llval) .is_some_and(|v| llvm::LLVMIsThreadLocal(v) == llvm::True); @@ -130,18 +141,12 @@ impl CodegenCx<'_, '_> { return false; } - // Match clang by only supporting COFF and ELF for now. - if self.tcx.sess.target.is_like_osx { - return false; + // Respect the direct-access-external-data to override default behavior if present. + if let Some(direct) = self.tcx.sess.direct_access_external_data() { + return direct; } // Static relocation model should force copy relocations everywhere. - if self.tcx.sess.relocation_model() == RelocModel::Static { - return true; - } - - // With pie relocation model calls of functions defined in the translation - // unit can use copy relocations. - self.tcx.sess.relocation_model() == RelocModel::Pie && !is_declaration + self.tcx.sess.relocation_model() == RelocModel::Static } } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 588139a303c52..948db6a6ea101 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -748,6 +748,7 @@ fn test_unstable_options_tracking_hash() { tracked!(debug_macros, true); tracked!(default_hidden_visibility, Some(true)); tracked!(dep_info_omit_d_target, true); + tracked!(direct_access_external_data, Some(true)); tracked!(dual_proc_macros, true); tracked!(dwarf_version, Some(5)); tracked!(emit_thin_lto, false); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index c97b18ebd66ad..ff8c5f4b3568e 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1553,6 +1553,8 @@ options! { dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED], "in dep-info output, omit targets for tracking dependencies of the dep-info files \ themselves (default: no)"), + direct_access_external_data: Option = (None, parse_opt_bool, [TRACKED], + "Direct or use GOT indirect to reference external data symbols"), dual_proc_macros: bool = (false, parse_bool, [TRACKED], "load proc macros for both target and host, but only link to the target (default: no)"), dump_dep_graph: bool = (false, parse_bool, [UNTRACKED], diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 720599f609544..392485e2238c5 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -793,6 +793,13 @@ impl Session { self.opts.unstable_opts.tls_model.unwrap_or(self.target.tls_model) } + pub fn direct_access_external_data(&self) -> Option { + self.opts + .unstable_opts + .direct_access_external_data + .or(self.target.direct_access_external_data) + } + pub fn split_debuginfo(&self) -> SplitDebuginfo { self.opts.cg.split_debuginfo.unwrap_or(self.target.split_debuginfo) } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 8e26327196a1a..7979be7b5d6e8 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1885,6 +1885,8 @@ pub struct TargetOptions { /// passed, and cannot be disabled even via `-C`. Corresponds to `llc /// -mattr=$features`. pub features: StaticCow, + /// Direct or use GOT indirect to reference external data symbols + pub direct_access_external_data: Option, /// Whether dynamic linking is available on this target. Defaults to false. pub dynamic_linking: bool, /// Whether dynamic linking can export TLS globals. Defaults to true. @@ -2279,6 +2281,7 @@ impl Default for TargetOptions { asm_args: cvs![], cpu: "generic".into(), features: "".into(), + direct_access_external_data: None, dynamic_linking: false, dll_tls_export: true, only_cdylib: false, @@ -2575,6 +2578,12 @@ impl Target { base.$key_name = s as u32; } } ); + ($key_name:ident, Option) => ( { + let name = (stringify!($key_name)).replace("_", "-"); + if let Some(s) = obj.remove(&name).and_then(|b| b.as_bool()) { + base.$key_name = Some(s); + } + } ); ($key_name:ident, Option) => ( { let name = (stringify!($key_name)).replace("_", "-"); if let Some(s) = obj.remove(&name).and_then(|b| b.as_u64()) { @@ -3003,6 +3012,7 @@ impl Target { key!(cpu); key!(features); key!(dynamic_linking, bool); + key!(direct_access_external_data, Option); key!(dll_tls_export, bool); key!(only_cdylib, bool); key!(executables, bool); @@ -3257,6 +3267,7 @@ impl ToJson for Target { target_option_val!(cpu); target_option_val!(features); target_option_val!(dynamic_linking); + target_option_val!(direct_access_external_data); target_option_val!(dll_tls_export); target_option_val!(only_cdylib); target_option_val!(executables); diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs index 0f05e7c475a83..234270c999b2a 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs @@ -11,6 +11,7 @@ pub fn target() -> Target { features: "+f,+d".into(), llvm_abiname: "lp64d".into(), max_atomic_width: Some(64), + direct_access_external_data: Some(false), ..base::linux_gnu::opts() }, } diff --git a/src/doc/unstable-book/src/compiler-flags/direct-access-external-data.md b/src/doc/unstable-book/src/compiler-flags/direct-access-external-data.md new file mode 100644 index 0000000000000..c72df43796038 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/direct-access-external-data.md @@ -0,0 +1,16 @@ +# `direct_access_external_data` + +The tracking issue for this feature is: https://github.com/rust-lang/compiler-team/issues/707 + +------------------------ + +Option `-Z direct-access-external-data` controls how to access symbols of +external data. + +Supported values for this option are: + +- `yes` - Don't use GOT indirection to reference external data symbols. +- `no` - Use GOT indirection to reference external data symbols. + +If the option is not explicitly specified, different targets have different +default values. diff --git a/tests/codegen/direct-access-external-data.rs b/tests/codegen/direct-access-external-data.rs new file mode 100644 index 0000000000000..ec4bfc33518db --- /dev/null +++ b/tests/codegen/direct-access-external-data.rs @@ -0,0 +1,21 @@ +// only-loongarch64-unknown-linux-gnu + +// revisions: DEFAULT DIRECT INDIRECT +// [DEFAULT] compile-flags: -C relocation-model=static +// [DIRECT] compile-flags: -C relocation-model=static -Z direct-access-external-data=yes +// [INDIRECT] compile-flags: -C relocation-model=static -Z direct-access-external-data=no + +#![crate_type = "rlib"] + +// DEFAULT: @VAR = external {{.*}} global i32 +// DIRECT: @VAR = external dso_local {{.*}} global i32 +// INDIRECT: @VAR = external {{.*}} global i32 + +extern "C" { + static VAR: i32; +} + +#[no_mangle] +pub fn get() -> i32 { + unsafe { VAR } +} From 6584e635069dcaca490310ed8e5a9bae467587ef Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 16 Jan 2024 13:36:07 +0100 Subject: [PATCH 0290/1197] minor: Simplify --- crates/ide/src/highlight_related.rs | 9 ++++----- crates/ide/src/references.rs | 19 +------------------ 2 files changed, 5 insertions(+), 23 deletions(-) diff --git a/crates/ide/src/highlight_related.rs b/crates/ide/src/highlight_related.rs index 3aed007f3ea55..3c34778efb5d4 100644 --- a/crates/ide/src/highlight_related.rs +++ b/crates/ide/src/highlight_related.rs @@ -15,10 +15,10 @@ use syntax::{ ast::{self, HasLoopBody}, match_ast, AstNode, SyntaxKind::{self, IDENT, INT_NUMBER}, - SyntaxNode, SyntaxToken, TextRange, T, + SyntaxToken, TextRange, T, }; -use crate::{navigation_target::ToNav, references, NavigationTarget, TryToNav}; +use crate::{navigation_target::ToNav, NavigationTarget, TryToNav}; #[derive(PartialEq, Eq, Hash)] pub struct HighlightedRange { @@ -81,7 +81,7 @@ pub(crate) fn highlight_related( } T![|] if config.closure_captures => highlight_closure_captures(sema, token, file_id), T![move] if config.closure_captures => highlight_closure_captures(sema, token, file_id), - _ if config.references => highlight_references(sema, &syntax, token, pos), + _ if config.references => highlight_references(sema, token, pos), _ => None, } } @@ -129,7 +129,6 @@ fn highlight_closure_captures( fn highlight_references( sema: &Semantics<'_, RootDatabase>, - node: &SyntaxNode, token: SyntaxToken, FilePosition { file_id, offset }: FilePosition, ) -> Option> { @@ -239,7 +238,7 @@ fn highlight_references( continue; } let hl_range = nav.focus_range.map(|range| { - let category = references::decl_mutability(&def, node, range) + let category = matches!(def, Definition::Local(l) if l.is_mut(sema.db)) .then_some(ReferenceCategory::Write); HighlightedRange { range, category } }); diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index 6c0fb0baf2e2b..78fe84f70d3a6 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs @@ -21,7 +21,6 @@ use ide_db::{ use itertools::Itertools; use nohash_hasher::IntMap; use syntax::{ - algo::find_node_at_offset, ast::{self, HasName}, match_ast, AstNode, SyntaxKind::*, @@ -98,9 +97,8 @@ pub(crate) fn find_all_refs( .or_default() .push((extra_ref.focus_or_full_range(), None)); } - let decl_range = nav.focus_or_full_range(); Declaration { - is_mut: decl_mutability(&def, sema.parse(nav.file_id).syntax(), decl_range), + is_mut: matches!(def, Definition::Local(l) if l.is_mut(sema.db)), nav, } }); @@ -189,21 +187,6 @@ pub(crate) fn find_defs<'a>( ) } -pub(crate) fn decl_mutability(def: &Definition, syntax: &SyntaxNode, range: TextRange) -> bool { - match def { - Definition::Local(_) | Definition::Field(_) => {} - _ => return false, - }; - - match find_node_at_offset::(syntax, range.start()) { - Some(stmt) if stmt.initializer().is_some() => match stmt.pat() { - Some(ast::Pat::IdentPat(it)) => it.mut_token().is_some(), - _ => false, - }, - _ => false, - } -} - /// Filter out all non-literal usages for adt-defs fn retain_adt_literal_usages( usages: &mut UsageSearchResult, From 384488c15702e1207b704113f3f4592e3813c29c Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 16 Jan 2024 14:28:47 +0100 Subject: [PATCH 0291/1197] feat: Hover for literals showing additional value information --- crates/hir/src/semantics.rs | 2 +- .../src/handlers/convert_integer_literal.rs | 2 +- crates/ide/src/hover.rs | 60 +++- crates/ide/src/hover/tests.rs | 309 +++++++++++++++++- crates/ide/src/markup.rs | 3 + crates/syntax/src/ast/token_ext.rs | 26 +- 6 files changed, 377 insertions(+), 25 deletions(-) diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index f51fe80931c6f..4267bd4efae4c 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -433,7 +433,7 @@ impl<'db> SemanticsImpl<'db> { .find_map(|token| { self.resolve_offset_in_format_args( ast::String::cast(token)?, - offset - quote.end(), + offset.checked_sub(quote.end())?, ) }) .map(|(range, res)| (range + quote.end(), res)); diff --git a/crates/ide-assists/src/handlers/convert_integer_literal.rs b/crates/ide-assists/src/handlers/convert_integer_literal.rs index ff2195f7e6c4a..fd3378e8c2636 100644 --- a/crates/ide-assists/src/handlers/convert_integer_literal.rs +++ b/crates/ide-assists/src/handlers/convert_integer_literal.rs @@ -20,7 +20,7 @@ pub(crate) fn convert_integer_literal(acc: &mut Assists, ctx: &AssistContext<'_> _ => return None, }; let radix = literal.radix(); - let value = literal.value()?; + let value = literal.value().ok()?; let suffix = literal.suffix(); let range = literal.syntax().text_range(); diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 5ad119ace89db..d06577d3db2c1 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -15,7 +15,7 @@ use ide_db::{ FxIndexSet, RootDatabase, }; use itertools::Itertools; -use syntax::{ast, AstNode, SyntaxKind::*, SyntaxNode, T}; +use syntax::{ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxNode, T}; use crate::{ doc_links::token_as_doc_comment, @@ -268,6 +268,64 @@ fn hover_simple( let c = token.parent().and_then(|x| x.parent()).and_then(ast::ClosureExpr::cast)?; render::closure_expr(sema, config, c) }) + }) + // tokens + .or_else(|| { + let mut res = HoverResult::default(); + match_ast! { + match original_token { + ast::String(string) => { + res.markup = Markup::fenced_block_text(format_args!("{}", string.value()?)); + }, + ast::ByteString(string) => { + res.markup = Markup::fenced_block_text(format_args!("{:?}", string.value()?)); + }, + ast::CString(string) => { + let val = string.value()?; + res.markup = Markup::fenced_block_text(format_args!("{}", std::str::from_utf8(val.as_ref()).ok()?)); + }, + ast::Char(char) => { + let mut res = HoverResult::default(); + res.markup = Markup::fenced_block_text(format_args!("{}", char.value()?)); + }, + ast::Byte(byte) => { + res.markup = Markup::fenced_block_text(format_args!("0x{:X}", byte.value()?)); + }, + ast::FloatNumber(num) => { + res.markup = if num.suffix() == Some("f32") { + match num.value_f32() { + Ok(num) => { + Markup::fenced_block_text(format_args!("{num} (bits: 0x{:X})", num.to_bits())) + }, + Err(e) => { + Markup::fenced_block_text(format_args!("{e}")) + }, + } + } else { + match num.value() { + Ok(num) => { + Markup::fenced_block_text(format_args!("{num} (bits: 0x{:X})", num.to_bits())) + }, + Err(e) => { + Markup::fenced_block_text(format_args!("{e}")) + }, + } + }; + }, + ast::IntNumber(num) => { + res.markup = match num.value() { + Ok(num) => { + Markup::fenced_block_text(format_args!("{num} (0x{num:X}|0x{num:b})")) + }, + Err(e) => { + Markup::fenced_block_text(format_args!("{e}")) + }, + }; + }, + _ => return None + } + } + Some(res) }); result.map(|mut res: HoverResult| { diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index 8ef8f29576532..587a6b66c4fef 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -1473,20 +1473,6 @@ fn foo(Foo { b$0ar }: &Foo) {} ) } -#[test] -fn test_hover_through_literal_string_in_builtin_macro() { - check_hover_no_result( - r#" - #[rustc_builtin_macro] - macro_rules! format {} - - fn foo() { - format!("hel$0lo {}", 0); - } -"#, - ); -} - #[test] fn test_hover_non_ascii_space_doc() { check( @@ -6778,3 +6764,298 @@ fn main() { "#]], ); } + +#[test] +fn string_literal() { + check( + r#" +fn main() { + $0"🦀\u{1f980}\\\x41"; +} +"#, + expect![[r#" + *"🦀\u{1f980}\\\x41"* + ```text + 🦀🦀\A + ``` + "#]], + ); + check( + r#" +fn main() { + $0r"🦀\u{1f980}\\\x41"; +} +"#, + expect![[r#" + *r"🦀\u{1f980}\\\x41"* + ```text + 🦀\u{1f980}\\\x41 + ``` + "#]], + ); +} + +#[test] +fn cstring_literal() { + check( + r#" +fn main() { + $0c"🦀\u{1f980}\\\x41"; +} +"#, + expect![[r#" + *c"🦀\u{1f980}\\\x41"* + ```text + 🦀🦀\A + ``` + "#]], + ); +} + +#[test] +fn byte_string_literal() { + check( + r#" +fn main() { + $0b"\xF0\x9F\xA6\x80\\"; +} +"#, + expect![[r#" + *b"\xF0\x9F\xA6\x80\\"* + ```text + [240, 159, 166, 128, 92] + ``` + "#]], + ); + check( + r#" +fn main() { + $0br"\xF0\x9F\xA6\x80\\"; +} +"#, + expect![[r#" + *br"\xF0\x9F\xA6\x80\\"* + ```text + [92, 120, 70, 48, 92, 120, 57, 70, 92, 120, 65, 54, 92, 120, 56, 48, 92, 92] + ``` + "#]], + ); +} + +#[test] +fn byte_literal() { + check( + r#" +fn main() { + $0b'\xF0'; +} +"#, + expect![[r#" + *b'\xF0'* + ```text + 0xF0 + ``` + "#]], + ); + check( + r#" +fn main() { + $0b'\\'; +} +"#, + expect![[r#" + *b'\\'* + ```text + 0x5C + ``` + "#]], + ); +} + +#[test] +fn char_literal() { + check( + r#" +fn main() { + $0'\x41'; +} +"#, + expect![[r#" + *'\x41'* + + "#]], + ); + check( + r#" +fn main() { + $0'\\'; +} +"#, + expect![[r#" + *'\\'* + + "#]], + ); + check( + r#" +fn main() { + $0'\u{1f980}'; +} +"#, + expect![[r#" + *'\u{1f980}'* + + "#]], + ); +} + +#[test] +fn float_literal() { + check( + r#" +fn main() { + $01.0; +} +"#, + expect![[r#" + *1.0* + ```text + 1 (bits: 0x3FF0000000000000) + ``` + "#]], + ); + check( + r#" +fn main() { + $01.0f32; +} +"#, + expect![[r#" + *1.0f32* + ```text + 1 (bits: 0x3F800000) + ``` + "#]], + ); + check( + r#" +fn main() { + $0134e12; +} +"#, + expect![[r#" + *134e12* + ```text + 134000000000000 (bits: 0x42DE77D399980000) + ``` + "#]], + ); + check( + r#" +fn main() { + $01523527134274733643531312.0; +} +"#, + expect![[r#" + *1523527134274733643531312.0* + ```text + 1523527134274733600000000 (bits: 0x44F429E9249F629B) + ``` + "#]], + ); + check( + r#" +fn main() { + $00.1ea123; +} +"#, + expect![[r#" + *0.1ea123* + ```text + invalid float literal + ``` + "#]], + ); +} + +#[test] +fn int_literal() { + check( + r#" +fn main() { + $034325236457856836345234; +} +"#, + expect![[r#" + *34325236457856836345234* + ```text + 34325236457856836345234 (0x744C659178614489D92|0x111010001001100011001011001000101111000011000010100010010001001110110010010) + ``` + "#]], + ); + check( + r#" +fn main() { + $0134_123424_21; +} +"#, + expect![[r#" + *134_123424_21* + ```text + 13412342421 (0x31F701A95|0x1100011111011100000001101010010101) + ``` + "#]], + ); + check( + r#" +fn main() { + $00x12423423; +} +"#, + expect![[r#" + *0x12423423* + ```text + 306328611 (0x12423423|0x10010010000100011010000100011) + ``` + "#]], + ); + check( + r#" +fn main() { + $00b1111_1111; +} +"#, + expect![[r#" + *0b1111_1111* + ```text + 255 (0xFF|0x11111111) + ``` + "#]], + ); + check( + r#" +fn main() { + $00o12345; +} +"#, + expect![[r#" + *0o12345* + ```text + 5349 (0x14E5|0x1010011100101) + ``` + "#]], + ); + check( + r#" +fn main() { + $00xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_F; +} +"#, + expect![[r#" + *0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_F* + ```text + number too large to fit in target type + ``` + "#]], + ); +} diff --git a/crates/ide/src/markup.rs b/crates/ide/src/markup.rs index 411eb695fbf27..4a4e29fa33b8b 100644 --- a/crates/ide/src/markup.rs +++ b/crates/ide/src/markup.rs @@ -35,4 +35,7 @@ impl Markup { pub fn fenced_block(contents: impl fmt::Display) -> Markup { format!("```rust\n{contents}\n```").into() } + pub fn fenced_block_text(contents: impl fmt::Display) -> Markup { + format!("```text\n{contents}\n```").into() + } } diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs index ede392fc62a2c..44e49d6d44504 100644 --- a/crates/syntax/src/ast/token_ext.rs +++ b/crates/syntax/src/ast/token_ext.rs @@ -1,6 +1,9 @@ //! There are many AstNodes, but only a few tokens, so we hand-write them here. -use std::borrow::Cow; +use std::{ + borrow::Cow, + num::{ParseFloatError, ParseIntError}, +}; use rustc_lexer::unescape::{ unescape_byte, unescape_c_string, unescape_char, unescape_literal, CStrUnit, Mode, @@ -391,10 +394,9 @@ impl ast::IntNumber { (prefix, text, suffix) } - pub fn value(&self) -> Option { + pub fn value(&self) -> Result { let (_, text, _) = self.split_into_parts(); - let value = u128::from_str_radix(&text.replace('_', ""), self.radix() as u32).ok()?; - Some(value) + u128::from_str_radix(&text.replace('_', ""), self.radix() as u32) } pub fn suffix(&self) -> Option<&str> { @@ -445,9 +447,14 @@ impl ast::FloatNumber { } } - pub fn value(&self) -> Option { + pub fn value(&self) -> Result { let (text, _) = self.split_into_parts(); - text.replace('_', "").parse::().ok() + text.replace('_', "").parse::() + } + + pub fn value_f32(&self) -> Result { + let (text, _) = self.split_into_parts(); + text.replace('_', "").parse::() } } @@ -484,12 +491,15 @@ mod tests { } fn check_float_value(lit: &str, expected: impl Into> + Copy) { - assert_eq!(FloatNumber { syntax: make::tokens::literal(lit) }.value(), expected.into()); + assert_eq!( + FloatNumber { syntax: make::tokens::literal(lit) }.value().ok(), + expected.into() + ); assert_eq!(IntNumber { syntax: make::tokens::literal(lit) }.float_value(), expected.into()); } fn check_int_value(lit: &str, expected: impl Into>) { - assert_eq!(IntNumber { syntax: make::tokens::literal(lit) }.value(), expected.into()); + assert_eq!(IntNumber { syntax: make::tokens::literal(lit) }.value().ok(), expected.into()); } #[test] From 7c94c29648bb6cbd7300a736862b8263ff04bc7f Mon Sep 17 00:00:00 2001 From: roife Date: Tue, 16 Jan 2024 21:42:29 +0800 Subject: [PATCH 0292/1197] fix: make let_stmts inserted in inline_call correctly indented --- crates/ide-assists/src/handlers/inline_call.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/crates/ide-assists/src/handlers/inline_call.rs b/crates/ide-assists/src/handlers/inline_call.rs index 2eb7089b7c38e..7bbb92134114e 100644 --- a/crates/ide-assists/src/handlers/inline_call.rs +++ b/crates/ide-assists/src/handlers/inline_call.rs @@ -484,12 +484,10 @@ fn inline( body = make::block_expr(let_stmts, Some(body.into())).clone_for_update(); } } else if let Some(stmt_list) = body.stmt_list() { - ted::insert_all( - ted::Position::after( - stmt_list.l_curly_token().expect("L_CURLY for StatementList is missing."), - ), - let_stmts.into_iter().map(|stmt| stmt.syntax().clone().into()).collect(), - ); + let position = stmt_list.l_curly_token().expect("L_CURLY for StatementList is missing."); + let_stmts.into_iter().rev().for_each(|let_stmt| { + ted::insert(ted::Position::after(position.clone()), let_stmt.syntax().clone()); + }); } let original_indentation = match node { From 8bb1eaee64e170153d21e64cdb437f3d36acd194 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 14 Jan 2024 22:14:48 +0000 Subject: [PATCH 0293/1197] Introduce helper that deals with moving async args into the coroutine --- compiler/rustc_ast_lowering/src/item.rs | 363 +++++++++++++----------- 1 file changed, 193 insertions(+), 170 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index a3ff02f5f6954..c8e639b7a9663 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1082,194 +1082,217 @@ impl<'hir> LoweringContext<'_, 'hir> { let (Some(coroutine_kind), Some(body)) = (coroutine_kind, body) else { return self.lower_fn_body_block(span, decl, body); }; - let closure_id = coroutine_kind.closure_id(); - self.lower_body(|this| { - let mut parameters: Vec> = Vec::new(); - let mut statements: Vec> = Vec::new(); - - // Async function parameters are lowered into the closure body so that they are - // captured and so that the drop order matches the equivalent non-async functions. - // - // from: - // - // async fn foo(: , : , : ) { - // - // } - // - // into: - // - // fn foo(__arg0: , __arg1: , __arg2: ) { - // async move { - // let __arg2 = __arg2; - // let = __arg2; - // let __arg1 = __arg1; - // let = __arg1; - // let __arg0 = __arg0; - // let = __arg0; - // drop-temps { } // see comments later in fn for details - // } - // } - // - // If `` is a simple ident, then it is lowered to a single - // `let = ;` statement as an optimization. - // - // Note that the body is embedded in `drop-temps`; an - // equivalent desugaring would be `return { - // };`. The key point is that we wish to drop all the - // let-bound variables and temporaries created in the body - // (and its tail expression!) before we drop the - // parameters (c.f. rust-lang/rust#64512). - for (index, parameter) in decl.inputs.iter().enumerate() { - let parameter = this.lower_param(parameter); - let span = parameter.pat.span; - - // Check if this is a binding pattern, if so, we can optimize and avoid adding a - // `let = __argN;` statement. In this case, we do not rename the parameter. - let (ident, is_simple_parameter) = match parameter.pat.kind { - hir::PatKind::Binding(hir::BindingAnnotation(ByRef::No, _), _, ident, _) => { - (ident, true) - } - // For `ref mut` or wildcard arguments, we can't reuse the binding, but - // we can keep the same name for the parameter. - // This lets rustdoc render it correctly in documentation. - hir::PatKind::Binding(_, _, ident, _) => (ident, false), - hir::PatKind::Wild => { - (Ident::with_dummy_span(rustc_span::symbol::kw::Underscore), false) - } - _ => { - // Replace the ident for bindings that aren't simple. - let name = format!("__arg{index}"); - let ident = Ident::from_str(&name); - - (ident, false) - } - }; - - let desugared_span = this.mark_span_with_reason(DesugaringKind::Async, span, None); - - // Construct a parameter representing `__argN: ` to replace the parameter of the - // async function. - // - // If this is the simple case, this parameter will end up being the same as the - // original parameter, but with a different pattern id. - let stmt_attrs = this.attrs.get(¶meter.hir_id.local_id).copied(); - let (new_parameter_pat, new_parameter_id) = this.pat_ident(desugared_span, ident); - let new_parameter = hir::Param { - hir_id: parameter.hir_id, - pat: new_parameter_pat, - ty_span: this.lower_span(parameter.ty_span), - span: this.lower_span(parameter.span), - }; + let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments( + decl, + body, + coroutine_kind, + CaptureBy::Value { move_kw: rustc_span::DUMMY_SP }, + ); - if is_simple_parameter { - // If this is the simple case, then we only insert one statement that is - // `let = ;`. We re-use the original argument's pattern so that - // `HirId`s are densely assigned. - let expr = this.expr_ident(desugared_span, ident, new_parameter_id); - let stmt = this.stmt_let_pat( - stmt_attrs, - desugared_span, - Some(expr), - parameter.pat, - hir::LocalSource::AsyncFn, - ); - statements.push(stmt); - } else { - // If this is not the simple case, then we construct two statements: - // - // ``` - // let __argN = __argN; - // let = __argN; - // ``` - // - // The first statement moves the parameter into the closure and thus ensures - // that the drop order is correct. - // - // The second statement creates the bindings that the user wrote. - - // Construct the `let mut __argN = __argN;` statement. It must be a mut binding - // because the user may have specified a `ref mut` binding in the next - // statement. - let (move_pat, move_id) = this.pat_ident_binding_mode( - desugared_span, - ident, - hir::BindingAnnotation::MUT, - ); - let move_expr = this.expr_ident(desugared_span, ident, new_parameter_id); - let move_stmt = this.stmt_let_pat( - None, - desugared_span, - Some(move_expr), - move_pat, - hir::LocalSource::AsyncFn, - ); + // FIXME(async_fn_track_caller): Can this be moved above? + let hir_id = this.lower_node_id(coroutine_kind.closure_id()); + this.maybe_forward_track_caller(body.span, fn_id, hir_id); - // Construct the `let = __argN;` statement. We re-use the original - // parameter's pattern so that `HirId`s are densely assigned. - let pattern_expr = this.expr_ident(desugared_span, ident, move_id); - let pattern_stmt = this.stmt_let_pat( - stmt_attrs, - desugared_span, - Some(pattern_expr), - parameter.pat, - hir::LocalSource::AsyncFn, - ); + (parameters, expr) + }) + } - statements.push(move_stmt); - statements.push(pattern_stmt); - }; + /// Lowers a desugared coroutine body after moving all of the arguments + /// into the body. This is to make sure that the future actually owns the + /// arguments that are passed to the function, and to ensure things like + /// drop order are stable. + fn lower_coroutine_body_with_moved_arguments( + &mut self, + decl: &FnDecl, + body: &Block, + coroutine_kind: CoroutineKind, + capture_clause: CaptureBy, + ) -> (&'hir [hir::Param<'hir>], hir::Expr<'hir>) { + let mut parameters: Vec> = Vec::new(); + let mut statements: Vec> = Vec::new(); + + // Async function parameters are lowered into the closure body so that they are + // captured and so that the drop order matches the equivalent non-async functions. + // + // from: + // + // async fn foo(: , : , : ) { + // + // } + // + // into: + // + // fn foo(__arg0: , __arg1: , __arg2: ) { + // async move { + // let __arg2 = __arg2; + // let = __arg2; + // let __arg1 = __arg1; + // let = __arg1; + // let __arg0 = __arg0; + // let = __arg0; + // drop-temps { } // see comments later in fn for details + // } + // } + // + // If `` is a simple ident, then it is lowered to a single + // `let = ;` statement as an optimization. + // + // Note that the body is embedded in `drop-temps`; an + // equivalent desugaring would be `return { + // };`. The key point is that we wish to drop all the + // let-bound variables and temporaries created in the body + // (and its tail expression!) before we drop the + // parameters (c.f. rust-lang/rust#64512). + for (index, parameter) in decl.inputs.iter().enumerate() { + let parameter = self.lower_param(parameter); + let span = parameter.pat.span; + + // Check if this is a binding pattern, if so, we can optimize and avoid adding a + // `let = __argN;` statement. In this case, we do not rename the parameter. + let (ident, is_simple_parameter) = match parameter.pat.kind { + hir::PatKind::Binding(hir::BindingAnnotation(ByRef::No, _), _, ident, _) => { + (ident, true) + } + // For `ref mut` or wildcard arguments, we can't reuse the binding, but + // we can keep the same name for the parameter. + // This lets rustdoc render it correctly in documentation. + hir::PatKind::Binding(_, _, ident, _) => (ident, false), + hir::PatKind::Wild => { + (Ident::with_dummy_span(rustc_span::symbol::kw::Underscore), false) + } + _ => { + // Replace the ident for bindings that aren't simple. + let name = format!("__arg{index}"); + let ident = Ident::from_str(&name); - parameters.push(new_parameter); - } + (ident, false) + } + }; - let mkbody = |this: &mut LoweringContext<'_, 'hir>| { - // Create a block from the user's function body: - let user_body = this.lower_block_expr(body); + let desugared_span = self.mark_span_with_reason(DesugaringKind::Async, span, None); - // Transform into `drop-temps { }`, an expression: - let desugared_span = - this.mark_span_with_reason(DesugaringKind::Async, user_body.span, None); - let user_body = this.expr_drop_temps(desugared_span, this.arena.alloc(user_body)); + // Construct a parameter representing `__argN: ` to replace the parameter of the + // async function. + // + // If this is the simple case, this parameter will end up being the same as the + // original parameter, but with a different pattern id. + let stmt_attrs = self.attrs.get(¶meter.hir_id.local_id).copied(); + let (new_parameter_pat, new_parameter_id) = self.pat_ident(desugared_span, ident); + let new_parameter = hir::Param { + hir_id: parameter.hir_id, + pat: new_parameter_pat, + ty_span: self.lower_span(parameter.ty_span), + span: self.lower_span(parameter.span), + }; - // As noted above, create the final block like + if is_simple_parameter { + // If this is the simple case, then we only insert one statement that is + // `let = ;`. We re-use the original argument's pattern so that + // `HirId`s are densely assigned. + let expr = self.expr_ident(desugared_span, ident, new_parameter_id); + let stmt = self.stmt_let_pat( + stmt_attrs, + desugared_span, + Some(expr), + parameter.pat, + hir::LocalSource::AsyncFn, + ); + statements.push(stmt); + } else { + // If this is not the simple case, then we construct two statements: // // ``` - // { - // let $param_pattern = $raw_param; - // ... - // drop-temps { } - // } + // let __argN = __argN; + // let = __argN; // ``` - let body = this.block_all( + // + // The first statement moves the parameter into the closure and thus ensures + // that the drop order is correct. + // + // The second statement creates the bindings that the user wrote. + + // Construct the `let mut __argN = __argN;` statement. It must be a mut binding + // because the user may have specified a `ref mut` binding in the next + // statement. + let (move_pat, move_id) = + self.pat_ident_binding_mode(desugared_span, ident, hir::BindingAnnotation::MUT); + let move_expr = self.expr_ident(desugared_span, ident, new_parameter_id); + let move_stmt = self.stmt_let_pat( + None, desugared_span, - this.arena.alloc_from_iter(statements), - Some(user_body), + Some(move_expr), + move_pat, + hir::LocalSource::AsyncFn, ); - this.expr_block(body) - }; - let desugaring_kind = match coroutine_kind { - CoroutineKind::Async { .. } => hir::CoroutineDesugaring::Async, - CoroutineKind::Gen { .. } => hir::CoroutineDesugaring::Gen, - CoroutineKind::AsyncGen { .. } => hir::CoroutineDesugaring::AsyncGen, + // Construct the `let = __argN;` statement. We re-use the original + // parameter's pattern so that `HirId`s are densely assigned. + let pattern_expr = self.expr_ident(desugared_span, ident, move_id); + let pattern_stmt = self.stmt_let_pat( + stmt_attrs, + desugared_span, + Some(pattern_expr), + parameter.pat, + hir::LocalSource::AsyncFn, + ); + + statements.push(move_stmt); + statements.push(pattern_stmt); }; - let coroutine_expr = this.make_desugared_coroutine_expr( - CaptureBy::Value { move_kw: rustc_span::DUMMY_SP }, - closure_id, - None, - body.span, - desugaring_kind, - hir::CoroutineSource::Fn, - mkbody, + + parameters.push(new_parameter); + } + + let mkbody = |this: &mut LoweringContext<'_, 'hir>| { + // Create a block from the user's function body: + let user_body = this.lower_block_expr(body); + + // Transform into `drop-temps { }`, an expression: + let desugared_span = + this.mark_span_with_reason(DesugaringKind::Async, user_body.span, None); + let user_body = this.expr_drop_temps(desugared_span, this.arena.alloc(user_body)); + + // As noted above, create the final block like + // + // ``` + // { + // let $param_pattern = $raw_param; + // ... + // drop-temps { } + // } + // ``` + let body = this.block_all( + desugared_span, + this.arena.alloc_from_iter(statements), + Some(user_body), ); - let hir_id = this.lower_node_id(closure_id); - this.maybe_forward_track_caller(body.span, fn_id, hir_id); - let expr = hir::Expr { hir_id, kind: coroutine_expr, span: this.lower_span(body.span) }; + this.expr_block(body) + }; + let desugaring_kind = match coroutine_kind { + CoroutineKind::Async { .. } => hir::CoroutineDesugaring::Async, + CoroutineKind::Gen { .. } => hir::CoroutineDesugaring::Gen, + CoroutineKind::AsyncGen { .. } => hir::CoroutineDesugaring::AsyncGen, + }; + let closure_id = coroutine_kind.closure_id(); + let coroutine_expr = self.make_desugared_coroutine_expr( + capture_clause, + closure_id, + None, + body.span, + desugaring_kind, + hir::CoroutineSource::Fn, + mkbody, + ); - (this.arena.alloc_from_iter(parameters), expr) - }) + let expr = hir::Expr { + hir_id: self.lower_node_id(closure_id), + kind: coroutine_expr, + span: self.lower_span(body.span), + }; + + (self.arena.alloc_from_iter(parameters), expr) } fn lower_method_sig( From 1696148a894f6e5fd8857400ebede44dedee0e2c Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Tue, 16 Jan 2024 10:19:23 -0500 Subject: [PATCH 0294/1197] Merge into larger interval set This reduces the work done while merging rows. In at least one case (issue 50450), we have thousands of union([range], [20,000 ranges]), which previously inserted each of the 20,000 ranges one by one. Now we only insert one range into the right hand set after copying the set over. --- compiler/rustc_index/src/interval.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compiler/rustc_index/src/interval.rs b/compiler/rustc_index/src/interval.rs index d3cf267dc9d79..0c1180b3e9800 100644 --- a/compiler/rustc_index/src/interval.rs +++ b/compiler/rustc_index/src/interval.rs @@ -236,6 +236,12 @@ impl IntervalSet { I: Step, { assert_eq!(self.domain, other.domain); + if self.map.len() < other.map.len() { + let backup = self.clone(); + self.map.clone_from(&other.map); + return self.union(&backup); + } + let mut did_insert = false; for range in other.iter_intervals() { did_insert |= self.insert_range(range); From 450cb5eda6d1db8b5b45a3775cb5316bb623dc63 Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Sun, 14 Jan 2024 23:23:30 +0100 Subject: [PATCH 0295/1197] Don't ICE if TAIT-defining fn contains a closure with `_` in return type --- .../src/collect/type_of/opaque.rs | 31 +++++++++------- .../ui/type-alias-impl-trait/closure_infer.rs | 35 +++++++++++++++++++ 2 files changed, 54 insertions(+), 12 deletions(-) create mode 100644 tests/ui/type-alias-impl-trait/closure_infer.rs diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs index 1f7ca48234a24..ade24259ed408 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs @@ -135,18 +135,25 @@ impl TaitConstraintLocator<'_> { return; } - if let Some(hir_sig) = self.tcx.hir_node_by_def_id(item_def_id).fn_decl() { - if hir_sig.output.get_infer_ret_ty().is_some() { - let guar = self.tcx.dcx().span_delayed_bug( - hir_sig.output.span(), - "inferring return types and opaque types do not mix well", - ); - self.found = Some(ty::OpaqueHiddenType { - span: DUMMY_SP, - ty: Ty::new_error(self.tcx, guar), - }); - return; - } + // Function items with `_` in their return type already emit an error, skip any + // "non-defining use" errors for them. + // Note that we use `Node::fn_sig` instead of `Node::fn_decl` here, because the former + // excludes closures, which are allowed to have `_` in their return type. + let hir_node = self.tcx.hir_node_by_def_id(item_def_id); + debug_assert!( + !matches!(hir_node, Node::ForeignItem(..)), + "foreign items cannot constrain opaque types", + ); + if let Some(hir_sig) = hir_node.fn_sig() + && hir_sig.decl.output.get_infer_ret_ty().is_some() + { + let guar = self.tcx.dcx().span_delayed_bug( + hir_sig.decl.output.span(), + "inferring return types and opaque types do not mix well", + ); + self.found = + Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: Ty::new_error(self.tcx, guar) }); + return; } // Calling `mir_borrowck` can lead to cycle errors through diff --git a/tests/ui/type-alias-impl-trait/closure_infer.rs b/tests/ui/type-alias-impl-trait/closure_infer.rs new file mode 100644 index 0000000000000..04e2323ec4ae9 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/closure_infer.rs @@ -0,0 +1,35 @@ +// check-pass + +// Regression test for an ICE: https://github.com/rust-lang/rust/issues/119916 + +#![feature(impl_trait_in_assoc_type)] +#![feature(type_alias_impl_trait)] + +// `impl_trait_in_assoc_type` example from the bug report. +pub trait StreamConsumer { + type BarrierStream; + fn execute() -> Self::BarrierStream; +} + +pub struct DispatchExecutor; + +impl StreamConsumer for DispatchExecutor { + type BarrierStream = impl Sized; + fn execute() -> Self::BarrierStream { + || -> _ {} + } +} + +// Functions that constrain TAITs can contain closures with an `_` in the return type. +type Foo = impl Sized; +fn foo() -> Foo { + || -> _ {} +} + +// The `_` in the closure return type can also be the TAIT itself. +type Bar = impl Sized; +fn bar() -> impl FnOnce() -> Bar { + || -> _ {} +} + +fn main() {} From 22833c177e23c1c80e7ad1cbea33d758dcd94c28 Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Mon, 15 Jan 2024 01:21:03 +0100 Subject: [PATCH 0296/1197] add test for non-defining use of TAIT in foreign function item --- tests/ui/type-alias-impl-trait/issue-77179.rs | 5 +++++ tests/ui/type-alias-impl-trait/issue-77179.stderr | 11 ++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/ui/type-alias-impl-trait/issue-77179.rs b/tests/ui/type-alias-impl-trait/issue-77179.rs index 093aeb4b27911..3d6c826d6ac5a 100644 --- a/tests/ui/type-alias-impl-trait/issue-77179.rs +++ b/tests/ui/type-alias-impl-trait/issue-77179.rs @@ -12,3 +12,8 @@ fn test() -> Pointer<_> { fn main() { test(); } + +extern "Rust" { + fn bar() -> Pointer<_>; + //~^ ERROR: the placeholder `_` is not allowed within types +} diff --git a/tests/ui/type-alias-impl-trait/issue-77179.stderr b/tests/ui/type-alias-impl-trait/issue-77179.stderr index 68dd6570d00c0..c5cacfd3cd351 100644 --- a/tests/ui/type-alias-impl-trait/issue-77179.stderr +++ b/tests/ui/type-alias-impl-trait/issue-77179.stderr @@ -7,6 +7,15 @@ LL | fn test() -> Pointer<_> { | | not allowed in type signatures | help: replace with the correct return type: `Pointer` -error: aborting due to 1 previous error +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions + --> $DIR/issue-77179.rs:17:25 + | +LL | fn bar() -> Pointer<_>; + | ^ + | | + | not allowed in type signatures + | help: use type parameters instead: `T` + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0121`. From f1ee076f8188c02a2f4d06fc2fde2f58bdb3d6f4 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 14 Jan 2024 23:12:46 +0000 Subject: [PATCH 0297/1197] Async closures will move params into the future always --- compiler/rustc_ast_lowering/messages.ftl | 4 -- compiler/rustc_ast_lowering/src/errors.rs | 8 ---- compiler/rustc_ast_lowering/src/expr.rs | 39 +++++++------------ compiler/rustc_ast_lowering/src/item.rs | 29 ++++++++------ .../src/error_codes/E0708.md | 6 ++- .../async-borrowck-escaping-closure-error.rs | 3 +- ...ync-borrowck-escaping-closure-error.stderr | 21 ---------- .../no-params-non-move-async-closure.rs | 2 +- .../no-params-non-move-async-closure.stderr | 11 ------ .../suggest-on-bare-closure-call.stderr | 5 --- 10 files changed, 40 insertions(+), 88 deletions(-) delete mode 100644 tests/ui/async-await/async-borrowck-escaping-closure-error.stderr delete mode 100644 tests/ui/async-await/no-params-non-move-async-closure.stderr diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index e7177402db1d7..8615016cda599 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -14,10 +14,6 @@ ast_lowering_assoc_ty_parentheses = ast_lowering_async_coroutines_not_supported = `async` coroutines are not yet supported -ast_lowering_async_non_move_closure_not_supported = - `async` non-`move` closures with parameters are not currently supported - .help = consider using `let` statements to manually capture variables by reference before entering an `async move` closure - ast_lowering_att_syntax_only_x86 = the `att_syntax` option is only supported on x86 diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 2811fe104cd09..4843d36372dcc 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -145,14 +145,6 @@ pub struct ClosureCannotBeStatic { pub fn_decl_span: Span, } -#[derive(Diagnostic, Clone, Copy)] -#[help] -#[diag(ast_lowering_async_non_move_closure_not_supported, code = "E0708")] -pub struct AsyncNonMoveClosureNotSupported { - #[primary_span] - pub fn_decl_span: Span, -} - #[derive(Diagnostic, Clone, Copy)] #[diag(ast_lowering_functional_record_update_destructuring_assignment)] pub struct FunctionalRecordUpdateDestructuringAssignment { diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index e0b1a10c82e7d..0920de48eb87e 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1,6 +1,6 @@ use super::errors::{ - AsyncCoroutinesNotSupported, AsyncNonMoveClosureNotSupported, AwaitOnlyInAsyncFnAndBlocks, - BaseExpressionDoubleDot, ClosureCannotBeStatic, CoroutineTooManyParameters, + AsyncCoroutinesNotSupported, AwaitOnlyInAsyncFnAndBlocks, BaseExpressionDoubleDot, + ClosureCannotBeStatic, CoroutineTooManyParameters, FunctionalRecordUpdateDestructuringAssignment, InclusiveRangeWithNoEnd, MatchArmWithNoBody, NeverPatternWithBody, NeverPatternWithGuard, NotSupportedForLifetimeBinderAsyncClosure, UnderscoreExprLhsAssign, @@ -13,7 +13,6 @@ use rustc_ast::*; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_middle::span_bug; use rustc_session::errors::report_lit_error; use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; @@ -1028,28 +1027,16 @@ impl<'hir> LoweringContext<'_, 'hir> { fn_decl_span: Span, fn_arg_span: Span, ) -> hir::ExprKind<'hir> { - let CoroutineKind::Async { closure_id: inner_closure_id, .. } = coroutine_kind else { - span_bug!(fn_decl_span, "`async gen` and `gen` closures are not supported, yet"); - }; - if let &ClosureBinder::For { span, .. } = binder { self.dcx().emit_err(NotSupportedForLifetimeBinderAsyncClosure { span }); } let (binder_clause, generic_params) = self.lower_closure_binder(binder); - let outer_decl = - FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) }; - let body = self.with_new_scopes(fn_decl_span, |this| { - // FIXME(cramertj): allow `async` non-`move` closures with arguments. - if capture_clause == CaptureBy::Ref && !decl.inputs.is_empty() { - this.dcx().emit_err(AsyncNonMoveClosureNotSupported { fn_decl_span }); - } - // Transform `async |x: u8| -> X { ... }` into // `|x: u8| || -> X { ... }`. - let body_id = this.lower_fn_body(&outer_decl, |this| { + let body_id = this.lower_body(|this| { let async_ret_ty = if let FnRetTy::Ty(ty) = &decl.output { let itctx = ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock); Some(hir::FnRetTy::Return(this.lower_ty(ty, &itctx))) @@ -1057,22 +1044,26 @@ impl<'hir> LoweringContext<'_, 'hir> { None }; - let async_body = this.make_desugared_coroutine_expr( - capture_clause, - inner_closure_id, - async_ret_ty, + let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments( + decl, + |this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)), body.span, - hir::CoroutineDesugaring::Async, + coroutine_kind, hir::CoroutineSource::Closure, - |this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)), + async_ret_ty, ); - let hir_id = this.lower_node_id(inner_closure_id); + + let hir_id = this.lower_node_id(coroutine_kind.closure_id()); this.maybe_forward_track_caller(body.span, closure_hir_id, hir_id); - hir::Expr { hir_id, kind: async_body, span: this.lower_span(body.span) } + + (parameters, expr) }); body_id }); + let outer_decl = + FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) }; + let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params); // We need to lower the declaration outside the new scope, because we // have to conserve the state of being inside a loop condition for the diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index c8e639b7a9663..dd3f7289a60b2 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1085,9 +1085,11 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_body(|this| { let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments( decl, - body, + |this| this.lower_block_expr(body), + body.span, coroutine_kind, - CaptureBy::Value { move_kw: rustc_span::DUMMY_SP }, + hir::CoroutineSource::Fn, + None, ); // FIXME(async_fn_track_caller): Can this be moved above? @@ -1102,12 +1104,14 @@ impl<'hir> LoweringContext<'_, 'hir> { /// into the body. This is to make sure that the future actually owns the /// arguments that are passed to the function, and to ensure things like /// drop order are stable. - fn lower_coroutine_body_with_moved_arguments( + pub fn lower_coroutine_body_with_moved_arguments( &mut self, decl: &FnDecl, - body: &Block, + lower_body: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::Expr<'hir>, + body_span: Span, coroutine_kind: CoroutineKind, - capture_clause: CaptureBy, + coroutine_source: hir::CoroutineSource, + return_type_hint: Option>, ) -> (&'hir [hir::Param<'hir>], hir::Expr<'hir>) { let mut parameters: Vec> = Vec::new(); let mut statements: Vec> = Vec::new(); @@ -1246,7 +1250,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let mkbody = |this: &mut LoweringContext<'_, 'hir>| { // Create a block from the user's function body: - let user_body = this.lower_block_expr(body); + let user_body = lower_body(this); // Transform into `drop-temps { }`, an expression: let desugared_span = @@ -1277,19 +1281,22 @@ impl<'hir> LoweringContext<'_, 'hir> { }; let closure_id = coroutine_kind.closure_id(); let coroutine_expr = self.make_desugared_coroutine_expr( - capture_clause, + // FIXME(async_closures): This should only move locals, + // and not upvars. Capturing closure upvars by ref doesn't + // work right now anyways, so whatever. + CaptureBy::Value { move_kw: rustc_span::DUMMY_SP }, closure_id, - None, - body.span, + return_type_hint, + body_span, desugaring_kind, - hir::CoroutineSource::Fn, + coroutine_source, mkbody, ); let expr = hir::Expr { hir_id: self.lower_node_id(closure_id), kind: coroutine_expr, - span: self.lower_span(body.span), + span: self.lower_span(body_span), }; (self.arena.alloc_from_iter(parameters), expr) diff --git a/compiler/rustc_error_codes/src/error_codes/E0708.md b/compiler/rustc_error_codes/src/error_codes/E0708.md index 9287fc803d1de..61a853ac44606 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0708.md +++ b/compiler/rustc_error_codes/src/error_codes/E0708.md @@ -1,12 +1,14 @@ +#### Note: this error code is no longer emitted by the compiler. + `async` non-`move` closures with parameters are currently not supported. Erroneous code example: -```compile_fail,edition2018,E0708 +```edition2018 #![feature(async_closure)] fn main() { - let add_one = async |num: u8| { // error! + let add_one = async |num: u8| { num + 1 }; } diff --git a/tests/ui/async-await/async-borrowck-escaping-closure-error.rs b/tests/ui/async-await/async-borrowck-escaping-closure-error.rs index e667b72aee530..f8ff9186842b8 100644 --- a/tests/ui/async-await/async-borrowck-escaping-closure-error.rs +++ b/tests/ui/async-await/async-borrowck-escaping-closure-error.rs @@ -1,9 +1,10 @@ // edition:2018 +// check-pass + #![feature(async_closure)] fn foo() -> Box> { let x = 0u32; Box::new((async || x)()) - //~^ ERROR E0373 } fn main() { diff --git a/tests/ui/async-await/async-borrowck-escaping-closure-error.stderr b/tests/ui/async-await/async-borrowck-escaping-closure-error.stderr deleted file mode 100644 index 1d8d1c67bae16..0000000000000 --- a/tests/ui/async-await/async-borrowck-escaping-closure-error.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function - --> $DIR/async-borrowck-escaping-closure-error.rs:5:15 - | -LL | Box::new((async || x)()) - | ^^^^^^^^ - `x` is borrowed here - | | - | may outlive borrowed value `x` - | -note: closure is returned here - --> $DIR/async-borrowck-escaping-closure-error.rs:5:5 - | -LL | Box::new((async || x)()) - | ^^^^^^^^^^^^^^^^^^^^^^^^ -help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword - | -LL | Box::new((async move || x)()) - | ++++ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0373`. diff --git a/tests/ui/async-await/no-params-non-move-async-closure.rs b/tests/ui/async-await/no-params-non-move-async-closure.rs index 3b15f35c260dc..1440d918c50eb 100644 --- a/tests/ui/async-await/no-params-non-move-async-closure.rs +++ b/tests/ui/async-await/no-params-non-move-async-closure.rs @@ -1,8 +1,8 @@ // edition:2018 +// check-pass #![feature(async_closure)] fn main() { let _ = async |x: u8| {}; - //~^ ERROR `async` non-`move` closures with parameters are not currently supported } diff --git a/tests/ui/async-await/no-params-non-move-async-closure.stderr b/tests/ui/async-await/no-params-non-move-async-closure.stderr deleted file mode 100644 index d265955369900..0000000000000 --- a/tests/ui/async-await/no-params-non-move-async-closure.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0708]: `async` non-`move` closures with parameters are not currently supported - --> $DIR/no-params-non-move-async-closure.rs:6:13 - | -LL | let _ = async |x: u8| {}; - | ^^^^^^^^^^^^^ - | - = help: consider using `let` statements to manually capture variables by reference before entering an `async move` closure - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0708`. diff --git a/tests/ui/suggestions/suggest-on-bare-closure-call.stderr b/tests/ui/suggestions/suggest-on-bare-closure-call.stderr index e65a6eb4939d9..77631b36e0f30 100644 --- a/tests/ui/suggestions/suggest-on-bare-closure-call.stderr +++ b/tests/ui/suggestions/suggest-on-bare-closure-call.stderr @@ -18,11 +18,6 @@ LL | let _ = async ||{}(); | ^^-- | | | call expression requires function - | -help: if you meant to create this closure and immediately call it, surround the closure with parentheses - | -LL | let _ = (async ||{})(); - | + + error: aborting due to 2 previous errors From f4e35c60b04b381395150669f1e8656dccc5f94f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 15 Jan 2024 19:24:03 +0000 Subject: [PATCH 0298/1197] Fix async closure call suggestion --- compiler/rustc_hir_typeck/src/callee.rs | 82 +++++++++++-------- .../suggest-on-bare-closure-call.stderr | 5 ++ 2 files changed, 51 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 1a4e03d50cae0..d486f069989ee 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -293,49 +293,59 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { callee_node: &hir::ExprKind<'_>, callee_span: Span, ) { + let hir::ExprKind::Block(..) = callee_node else { + // Only calls on blocks suggested here. + return; + }; + let hir = self.tcx.hir(); - let parent_hir_id = hir.parent_id(hir_id); - let parent_node = self.tcx.hir_node(parent_hir_id); - if let ( - hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, kind, .. }), + let fn_decl_span = if let hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }), + .. + }) = hir.get_parent(hir_id) + { + fn_decl_span + } else if let Some(( + _, + hir::Node::Expr(&hir::Expr { + hir_id: parent_hir_id, + kind: + hir::ExprKind::Closure(&hir::Closure { + kind: + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + hir::CoroutineSource::Closure, + )), + .. + }), .. }), - hir::ExprKind::Block(..), - ) = (parent_node, callee_node) + )) = hir.parent_iter(hir_id).nth(3) { - let fn_decl_span = if matches!( - kind, - hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, - hir::CoroutineSource::Closure - ),) - ) { - // Actually need to unwrap one more layer of HIR to get to - // the _real_ closure... - let async_closure = hir.parent_id(parent_hir_id); - if let hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }), - .. - }) = self.tcx.hir_node(async_closure) - { - fn_decl_span - } else { - return; - } - } else { + // Actually need to unwrap one more layer of HIR to get to + // the _real_ closure... + let async_closure = hir.parent_id(parent_hir_id); + if let hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }), + .. + }) = self.tcx.hir_node(async_closure) + { fn_decl_span - }; + } else { + return; + } + } else { + return; + }; - let start = fn_decl_span.shrink_to_lo(); - let end = callee_span.shrink_to_hi(); - err.multipart_suggestion( - "if you meant to create this closure and immediately call it, surround the \ + let start = fn_decl_span.shrink_to_lo(); + let end = callee_span.shrink_to_hi(); + err.multipart_suggestion( + "if you meant to create this closure and immediately call it, surround the \ closure with parentheses", - vec![(start, "(".to_string()), (end, ")".to_string())], - Applicability::MaybeIncorrect, - ); - } + vec![(start, "(".to_string()), (end, ")".to_string())], + Applicability::MaybeIncorrect, + ); } /// Give appropriate suggestion when encountering `[("a", 0) ("b", 1)]`, where the diff --git a/tests/ui/suggestions/suggest-on-bare-closure-call.stderr b/tests/ui/suggestions/suggest-on-bare-closure-call.stderr index 77631b36e0f30..e65a6eb4939d9 100644 --- a/tests/ui/suggestions/suggest-on-bare-closure-call.stderr +++ b/tests/ui/suggestions/suggest-on-bare-closure-call.stderr @@ -18,6 +18,11 @@ LL | let _ = async ||{}(); | ^^-- | | | call expression requires function + | +help: if you meant to create this closure and immediately call it, surround the closure with parentheses + | +LL | let _ = (async ||{})(); + | + + error: aborting due to 2 previous errors From 04a5ee6f1d6ab1270b95c6c91a718d900a762eb8 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 15 Jan 2024 19:38:53 +0000 Subject: [PATCH 0299/1197] Deal with additional wrapping of async closure body in clippy --- .../clippy_lints/src/async_yields_async.rs | 98 ++++++++++++------- .../src/redundant_closure_call.rs | 20 +++- .../clippy/tests/ui/author/blocks.stdout | 6 +- 3 files changed, 82 insertions(+), 42 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/async_yields_async.rs b/src/tools/clippy/clippy_lints/src/async_yields_async.rs index bb08ac7508bc2..eeaa3de3725fb 100644 --- a/src/tools/clippy/clippy_lints/src/async_yields_async.rs +++ b/src/tools/clippy/clippy_lints/src/async_yields_async.rs @@ -45,50 +45,72 @@ declare_lint_pass!(AsyncYieldsAsync => [ASYNC_YIELDS_ASYNC]); impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - // For functions, with explicitly defined types, don't warn. - // XXXkhuey maybe we should? - if let ExprKind::Closure(Closure { - kind: - ClosureKind::Coroutine(CoroutineKind::Desugared( - CoroutineDesugaring::Async, - CoroutineSource::Block | CoroutineSource::Closure, - )), + let ExprKind::Closure(Closure { + kind: ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, kind)), body: body_id, .. }) = expr.kind - { - if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() { - let typeck_results = cx.tcx.typeck_body(*body_id); - let body = cx.tcx.hir().body(*body_id); - let expr_ty = typeck_results.expr_ty(body.value); + else { + return; + }; - if implements_trait(cx, expr_ty, future_trait_def_id, &[]) { - let return_expr_span = match &body.value.kind { - // XXXkhuey there has to be a better way. - ExprKind::Block(block, _) => block.expr.map(|e| e.span), - ExprKind::Path(QPath::Resolved(_, path)) => Some(path.span), - _ => None, - }; - if let Some(return_expr_span) = return_expr_span { - span_lint_hir_and_then( - cx, - ASYNC_YIELDS_ASYNC, - body.value.hir_id, + let body_expr = match kind { + CoroutineSource::Fn => { + // For functions, with explicitly defined types, don't warn. + // XXXkhuey maybe we should? + return; + }, + CoroutineSource::Block => cx.tcx.hir().body(*body_id).value, + CoroutineSource::Closure => { + // Like `async fn`, async closures are wrapped in an additional block + // to move all of the closure's arguments into the future. + + let async_closure_body = cx.tcx.hir().body(*body_id).value; + let ExprKind::Block(block, _) = async_closure_body.kind else { + return; + }; + let Some(block_expr) = block.expr else { + return; + }; + let ExprKind::DropTemps(body_expr) = block_expr.kind else { + return; + }; + body_expr + }, + }; + + let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() else { + return; + }; + + let typeck_results = cx.tcx.typeck_body(*body_id); + let expr_ty = typeck_results.expr_ty(body_expr); + + if implements_trait(cx, expr_ty, future_trait_def_id, &[]) { + let return_expr_span = match &body_expr.kind { + // XXXkhuey there has to be a better way. + ExprKind::Block(block, _) => block.expr.map(|e| e.span), + ExprKind::Path(QPath::Resolved(_, path)) => Some(path.span), + _ => None, + }; + if let Some(return_expr_span) = return_expr_span { + span_lint_hir_and_then( + cx, + ASYNC_YIELDS_ASYNC, + body_expr.hir_id, + return_expr_span, + "an async construct yields a type which is itself awaitable", + |db| { + db.span_label(body_expr.span, "outer async construct"); + db.span_label(return_expr_span, "awaitable value not awaited"); + db.span_suggestion( return_expr_span, - "an async construct yields a type which is itself awaitable", - |db| { - db.span_label(body.value.span, "outer async construct"); - db.span_label(return_expr_span, "awaitable value not awaited"); - db.span_suggestion( - return_expr_span, - "consider awaiting this value", - format!("{}.await", snippet(cx, return_expr_span, "..")), - Applicability::MaybeIncorrect, - ); - }, + "consider awaiting this value", + format!("{}.await", snippet(cx, return_expr_span, "..")), + Applicability::MaybeIncorrect, ); - } - } + }, + ); } } } diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs index cde08dfcc748d..334e6770ae407 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs @@ -5,7 +5,9 @@ use clippy_utils::sugg::Sugg; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit::{Visitor as HirVisitor, Visitor}; -use rustc_hir::{intravisit as hir_visit, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Node}; +use rustc_hir::{ + intravisit as hir_visit, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, ExprKind, Node, +}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; @@ -166,10 +168,22 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { if coroutine_kind.is_async() && let hir::ExprKind::Closure(closure) = body.kind { - let async_closure_body = cx.tcx.hir().body(closure.body); + // Like `async fn`, async closures are wrapped in an additional block + // to move all of the closure's arguments into the future. + + let async_closure_body = cx.tcx.hir().body(closure.body).value; + let ExprKind::Block(block, _) = async_closure_body.kind else { + return; + }; + let Some(block_expr) = block.expr else { + return; + }; + let ExprKind::DropTemps(body_expr) = block_expr.kind else { + return; + }; // `async x` is a syntax error, so it becomes `async { x }` - if !matches!(async_closure_body.value.kind, hir::ExprKind::Block(_, _)) { + if !matches!(body_expr.kind, hir::ExprKind::Block(_, _)) { hint = hint.blockify(); } diff --git a/src/tools/clippy/tests/ui/author/blocks.stdout b/src/tools/clippy/tests/ui/author/blocks.stdout index 62de661f8ff86..8c4d71e68f80f 100644 --- a/src/tools/clippy/tests/ui/author/blocks.stdout +++ b/src/tools/clippy/tests/ui/author/blocks.stdout @@ -48,7 +48,11 @@ if let ExprKind::Closure { capture_clause: CaptureBy::Value { .. }, fn_decl: fn_ && expr2 = &cx.tcx.hir().body(body_id1).value && let ExprKind::Block(block, None) = expr2.kind && block.stmts.is_empty() - && block.expr.is_none() + && let Some(trailing_expr) = block.expr + && let ExprKind::DropTemps(expr3) = trailing_expr.kind + && let ExprKind::Block(block1, None) = expr3.kind + && block1.stmts.is_empty() + && block1.expr.is_none() { // report your lint here } From f7376a0f8cc4177955e01d88e56aabbfd635a566 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 15 Jan 2024 19:38:53 +0000 Subject: [PATCH 0300/1197] Deal with additional wrapping of async closure body in clippy --- clippy_lints/src/async_yields_async.rs | 98 +++++++++++++--------- clippy_lints/src/redundant_closure_call.rs | 20 ++++- tests/ui/author/blocks.stdout | 6 +- 3 files changed, 82 insertions(+), 42 deletions(-) diff --git a/clippy_lints/src/async_yields_async.rs b/clippy_lints/src/async_yields_async.rs index bb08ac7508bc2..eeaa3de3725fb 100644 --- a/clippy_lints/src/async_yields_async.rs +++ b/clippy_lints/src/async_yields_async.rs @@ -45,50 +45,72 @@ declare_lint_pass!(AsyncYieldsAsync => [ASYNC_YIELDS_ASYNC]); impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - // For functions, with explicitly defined types, don't warn. - // XXXkhuey maybe we should? - if let ExprKind::Closure(Closure { - kind: - ClosureKind::Coroutine(CoroutineKind::Desugared( - CoroutineDesugaring::Async, - CoroutineSource::Block | CoroutineSource::Closure, - )), + let ExprKind::Closure(Closure { + kind: ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, kind)), body: body_id, .. }) = expr.kind - { - if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() { - let typeck_results = cx.tcx.typeck_body(*body_id); - let body = cx.tcx.hir().body(*body_id); - let expr_ty = typeck_results.expr_ty(body.value); + else { + return; + }; - if implements_trait(cx, expr_ty, future_trait_def_id, &[]) { - let return_expr_span = match &body.value.kind { - // XXXkhuey there has to be a better way. - ExprKind::Block(block, _) => block.expr.map(|e| e.span), - ExprKind::Path(QPath::Resolved(_, path)) => Some(path.span), - _ => None, - }; - if let Some(return_expr_span) = return_expr_span { - span_lint_hir_and_then( - cx, - ASYNC_YIELDS_ASYNC, - body.value.hir_id, + let body_expr = match kind { + CoroutineSource::Fn => { + // For functions, with explicitly defined types, don't warn. + // XXXkhuey maybe we should? + return; + }, + CoroutineSource::Block => cx.tcx.hir().body(*body_id).value, + CoroutineSource::Closure => { + // Like `async fn`, async closures are wrapped in an additional block + // to move all of the closure's arguments into the future. + + let async_closure_body = cx.tcx.hir().body(*body_id).value; + let ExprKind::Block(block, _) = async_closure_body.kind else { + return; + }; + let Some(block_expr) = block.expr else { + return; + }; + let ExprKind::DropTemps(body_expr) = block_expr.kind else { + return; + }; + body_expr + }, + }; + + let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() else { + return; + }; + + let typeck_results = cx.tcx.typeck_body(*body_id); + let expr_ty = typeck_results.expr_ty(body_expr); + + if implements_trait(cx, expr_ty, future_trait_def_id, &[]) { + let return_expr_span = match &body_expr.kind { + // XXXkhuey there has to be a better way. + ExprKind::Block(block, _) => block.expr.map(|e| e.span), + ExprKind::Path(QPath::Resolved(_, path)) => Some(path.span), + _ => None, + }; + if let Some(return_expr_span) = return_expr_span { + span_lint_hir_and_then( + cx, + ASYNC_YIELDS_ASYNC, + body_expr.hir_id, + return_expr_span, + "an async construct yields a type which is itself awaitable", + |db| { + db.span_label(body_expr.span, "outer async construct"); + db.span_label(return_expr_span, "awaitable value not awaited"); + db.span_suggestion( return_expr_span, - "an async construct yields a type which is itself awaitable", - |db| { - db.span_label(body.value.span, "outer async construct"); - db.span_label(return_expr_span, "awaitable value not awaited"); - db.span_suggestion( - return_expr_span, - "consider awaiting this value", - format!("{}.await", snippet(cx, return_expr_span, "..")), - Applicability::MaybeIncorrect, - ); - }, + "consider awaiting this value", + format!("{}.await", snippet(cx, return_expr_span, "..")), + Applicability::MaybeIncorrect, ); - } - } + }, + ); } } } diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index cde08dfcc748d..334e6770ae407 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -5,7 +5,9 @@ use clippy_utils::sugg::Sugg; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit::{Visitor as HirVisitor, Visitor}; -use rustc_hir::{intravisit as hir_visit, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Node}; +use rustc_hir::{ + intravisit as hir_visit, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, ExprKind, Node, +}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; @@ -166,10 +168,22 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { if coroutine_kind.is_async() && let hir::ExprKind::Closure(closure) = body.kind { - let async_closure_body = cx.tcx.hir().body(closure.body); + // Like `async fn`, async closures are wrapped in an additional block + // to move all of the closure's arguments into the future. + + let async_closure_body = cx.tcx.hir().body(closure.body).value; + let ExprKind::Block(block, _) = async_closure_body.kind else { + return; + }; + let Some(block_expr) = block.expr else { + return; + }; + let ExprKind::DropTemps(body_expr) = block_expr.kind else { + return; + }; // `async x` is a syntax error, so it becomes `async { x }` - if !matches!(async_closure_body.value.kind, hir::ExprKind::Block(_, _)) { + if !matches!(body_expr.kind, hir::ExprKind::Block(_, _)) { hint = hint.blockify(); } diff --git a/tests/ui/author/blocks.stdout b/tests/ui/author/blocks.stdout index 62de661f8ff86..8c4d71e68f80f 100644 --- a/tests/ui/author/blocks.stdout +++ b/tests/ui/author/blocks.stdout @@ -48,7 +48,11 @@ if let ExprKind::Closure { capture_clause: CaptureBy::Value { .. }, fn_decl: fn_ && expr2 = &cx.tcx.hir().body(body_id1).value && let ExprKind::Block(block, None) = expr2.kind && block.stmts.is_empty() - && block.expr.is_none() + && let Some(trailing_expr) = block.expr + && let ExprKind::DropTemps(expr3) = trailing_expr.kind + && let ExprKind::Block(block1, None) = expr3.kind + && block1.stmts.is_empty() + && block1.expr.is_none() { // report your lint here } From 82e835549223d0f65935e3f96fdb996cc2f0a862 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 16 Jan 2024 16:15:56 +0100 Subject: [PATCH 0301/1197] feat: Show notable trait impls on hover --- crates/hir-def/src/db.rs | 7 +- crates/hir-def/src/lang_item.rs | 40 +- crates/hir/src/lib.rs | 24 + crates/ide-db/src/defs.rs | 24 +- crates/ide/src/hover/render.rs | 79 +++- crates/ide/src/hover/tests.rs | 756 ++++++++++++++++-------------- crates/test-utils/src/minicore.rs | 2 + 7 files changed, 557 insertions(+), 375 deletions(-) diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs index 2fd2f18ee45b0..d25d41c2cfa4d 100644 --- a/crates/hir-def/src/db.rs +++ b/crates/hir-def/src/db.rs @@ -200,7 +200,7 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast Attrs; #[salsa::transparent] - #[salsa::invoke(lang_item::lang_attr_query)] + #[salsa::invoke(lang_item::lang_attr)] fn lang_attr(&self, def: AttrDefId) -> Option; // endregion:attrs @@ -228,6 +228,11 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast Option>; + #[salsa::invoke(crate::lang_item::notable_traits_in_deps)] + fn notable_traits_in_deps(&self, krate: CrateId) -> Arc<[Arc<[TraitId]>]>; + #[salsa::invoke(crate::lang_item::crate_notable_traits)] + fn crate_notable_traits(&self, krate: CrateId) -> Option>; + fn crate_supports_no_std(&self, crate_id: CrateId) -> bool; } diff --git a/crates/hir-def/src/lang_item.rs b/crates/hir-def/src/lang_item.rs index 45ba939b8cfdc..adb2d785439d2 100644 --- a/crates/hir-def/src/lang_item.rs +++ b/crates/hir-def/src/lang_item.rs @@ -184,17 +184,53 @@ impl LangItems { T: Into + Copy, { let _p = profile::span("collect_lang_item"); - if let Some(lang_item) = db.lang_attr(item.into()) { + if let Some(lang_item) = lang_attr(db, item.into()) { self.items.entry(lang_item).or_insert_with(|| constructor(item)); } } } -pub(crate) fn lang_attr_query(db: &dyn DefDatabase, item: AttrDefId) -> Option { +pub(crate) fn lang_attr(db: &dyn DefDatabase, item: AttrDefId) -> Option { let attrs = db.attrs(item); attrs.by_key("lang").string_value().and_then(|it| LangItem::from_str(&it)) } +pub(crate) fn notable_traits_in_deps( + db: &dyn DefDatabase, + krate: CrateId, +) -> Arc<[Arc<[TraitId]>]> { + let _p = profile::span("notable_traits_in_deps").detail(|| format!("{krate:?}")); + let crate_graph = db.crate_graph(); + + Arc::from_iter( + crate_graph.transitive_deps(krate).filter_map(|krate| db.crate_notable_traits(krate)), + ) +} + +pub(crate) fn crate_notable_traits(db: &dyn DefDatabase, krate: CrateId) -> Option> { + let _p = profile::span("crate_notable_traits").detail(|| format!("{krate:?}")); + + let mut traits = Vec::new(); + + let crate_def_map = db.crate_def_map(krate); + + for (_, module_data) in crate_def_map.modules() { + for def in module_data.scope.declarations() { + if let ModuleDefId::TraitId(trait_) = def { + if db.attrs(trait_.into()).has_doc_notable_trait() { + traits.push(trait_); + } + } + } + } + + if traits.is_empty() { + None + } else { + Some(traits.into_iter().collect()) + } +} + pub enum GenericRequirement { None, Minimum(usize), diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index ab42cbeecc5dd..9866393e5408a 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -2844,6 +2844,7 @@ impl AssocItem { AssocItem::TypeAlias(it) => Some(it.name(db)), } } + pub fn module(self, db: &dyn HirDatabase) -> Module { match self { AssocItem::Function(f) => f.module(db), @@ -2851,6 +2852,7 @@ impl AssocItem { AssocItem::TypeAlias(t) => t.module(db), } } + pub fn container(self, db: &dyn HirDatabase) -> AssocItemContainer { let container = match self { AssocItem::Function(it) => it.id.lookup(db.upcast()).container, @@ -2886,6 +2888,27 @@ impl AssocItem { AssocItemContainer::Impl(i) => i.trait_(db), } } + + pub fn as_function(self) -> Option { + match self { + Self::Function(v) => Some(v), + _ => None, + } + } + + pub fn as_const(self) -> Option { + match self { + Self::Const(v) => Some(v), + _ => None, + } + } + + pub fn as_type_alias(self) -> Option { + match self { + Self::TypeAlias(v) => Some(v), + _ => None, + } + } } impl HasVisibility for AssocItem { @@ -3024,6 +3047,7 @@ impl LocalSource { impl Local { pub fn is_param(self, db: &dyn HirDatabase) -> bool { + // FIXME: This parses! let src = self.primary_source(db); match src.source.value { Either::Left(pat) => pat diff --git a/crates/ide-db/src/defs.rs b/crates/ide-db/src/defs.rs index 8f55f30a2dd46..5995b318e8eff 100644 --- a/crates/ide-db/src/defs.rs +++ b/crates/ide-db/src/defs.rs @@ -230,23 +230,15 @@ impl Definition { Definition::BuiltinType(it) => it.name().display(db).to_string(), Definition::Local(it) => { let ty = it.ty(db); - let ty = ty.display_truncated(db, None); + let ty_display = ty.display_truncated(db, None); let is_mut = if it.is_mut(db) { "mut " } else { "" }; - let desc = match it.primary_source(db).into_ident_pat() { - Some(ident) => { - let name = it.name(db); - let let_kw = if ident.syntax().parent().map_or(false, |p| { - p.kind() == SyntaxKind::LET_STMT || p.kind() == SyntaxKind::LET_EXPR - }) { - "let " - } else { - "" - }; - format!("{let_kw}{is_mut}{}: {ty}", name.display(db)) - } - None => format!("{is_mut}self: {ty}"), - }; - desc + if it.is_self(db) { + format!("{is_mut}self: {ty_display}") + } else { + let name = it.name(db); + let let_kw = if it.is_param(db) { "" } else { "let " }; + format!("{let_kw}{is_mut}{}: {ty_display}", name.display(db)) + } } Definition::SelfType(impl_def) => { impl_def.self_ty(db).as_adt().and_then(|adt| Definition::Adt(adt).label(db))? diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index 9d449bd18eeaf..d3a9975b2b2b6 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -1,7 +1,10 @@ //! Logic for rendering the different hover messages +use std::{mem, ops::Not}; + use either::Either; use hir::{ - Adt, AsAssocItem, CaptureKind, HasSource, HirDisplay, Layout, LayoutError, Semantics, TypeInfo, + db::DefDatabase, Adt, AsAssocItem, AssocItem, CaptureKind, HasCrate, HasSource, HirDisplay, + Layout, LayoutError, Semantics, TypeInfo, }; use ide_db::{ base_db::SourceDatabase, @@ -390,7 +393,6 @@ pub(super) fn definition( let mod_path = definition_mod_path(db, &def); let label = def.label(db)?; let docs = def.docs(db, famous_defs); - let value = match def { Definition::Variant(it) => { if !it.parent_enum(db).is_data_carrying(db) { @@ -462,14 +464,75 @@ pub(super) fn definition( _ => None, }; - let label = match (value, layout_info) { - (Some(value), Some(layout_info)) => format!("{layout_info}\n{label} = {value}"), - (Some(value), None) => format!("{label} = {value}"), - (None, Some(layout_info)) => format!("{layout_info}\n{label}"), - (None, None) => label, + let def_ty = match def { + Definition::Local(it) => Some(it.ty(db)), + Definition::GenericParam(hir::GenericParam::ConstParam(it)) => Some(it.ty(db)), + Definition::GenericParam(hir::GenericParam::TypeParam(it)) => Some(it.ty(db)), + Definition::Field(field) => Some(field.ty(db)), + Definition::TupleField(it) => Some(it.ty(db)), + Definition::Function(it) => Some(it.ty(db)), + Definition::Adt(it) => Some(it.ty(db)), + Definition::Const(it) => Some(it.ty(db)), + Definition::Static(it) => Some(it.ty(db)), + Definition::TypeAlias(it) => Some(it.ty(db)), + Definition::BuiltinType(it) => Some(it.ty(db)), + _ => None, }; + let notable_traits = def_ty.and_then(|ty| { + let mut desc = String::new(); + let mut needs_impl_header = true; + for &trait_ in db.notable_traits_in_deps(ty.krate(db).into()).iter().flat_map(|it| &**it) { + let trait_ = trait_.into(); + if ty.impls_trait(db, trait_, &[]) { + let aliases: Vec<_> = trait_ + .items(db) + .into_iter() + .filter_map(AssocItem::as_type_alias) + .map(|alias| (ty.normalize_trait_assoc_type(db, &[], alias), alias.name(db))) + .collect(); + desc.push_str(if mem::take(&mut needs_impl_header) { + " // notable traits impls: " + } else { + ", " + }); + format_to!(desc, "{}", trait_.name(db).display(db),); + if !aliases.is_empty() { + desc.push('<'); + format_to!( + desc, + "{}", + aliases.into_iter().format_with(", ", |(ty, name), f| { + f(&name.display(db))?; + f(&" = ")?; + match ty { + Some(ty) => f(&ty.display(db)), + None => f(&"?"), + } + }) + ); + desc.push('>'); + } + } + } + desc.is_empty().not().then(|| desc) + }); + + let mut desc = String::new(); + if let Some(notable_traits) = notable_traits { + desc.push_str(¬able_traits); + desc.push('\n'); + } + if let Some(layout_info) = layout_info { + desc.push_str(&layout_info); + desc.push('\n'); + } + desc.push_str(&label); + if let Some(value) = value { + desc.push_str(" = "); + desc.push_str(&value); + } - markup(docs.map(Into::into), label, mod_path) + markup(docs.map(Into::into), desc, mod_path) } fn type_info( diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index 587a6b66c4fef..f8693cd1ea63a 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -451,16 +451,16 @@ pub fn foo() -> u32 { 1 } fn main() { let foo_test = fo$0o(); } "#, expect![[r#" - *foo* + *foo* - ```rust - test - ``` + ```rust + test + ``` - ```rust - pub fn foo() -> u32 - ``` - "#]], + ```rust + pub fn foo() -> u32 + ``` + "#]], ); // Use literal `crate` in path @@ -495,16 +495,16 @@ mod m { pub fn foo() -> super::X { super::X } } fn main() { m::f$0oo(); } "#, expect![[r#" - *foo* + *foo* - ```rust - test::m - ``` + ```rust + test::m + ``` - ```rust - pub fn foo() -> super::X - ``` - "#]], + ```rust + pub fn foo() -> super::X + ``` + "#]], ); } @@ -559,18 +559,18 @@ pub fn foo<'a, T: AsRef>(b: &'a T) -> &'a str { } fn main() { let foo_test = fo$0o(); } "#, expect![[r#" - *foo* + *foo* - ```rust - test - ``` + ```rust + test + ``` - ```rust - pub fn foo<'a, T>(b: &'a T) -> &'a str - where - T: AsRef, - ``` - "#]], + ```rust + pub fn foo<'a, T>(b: &'a T) -> &'a str + where + T: AsRef, + ``` + "#]], ); } @@ -583,16 +583,16 @@ pub fn foo$0(a: u32, b: u32) -> u32 {} fn main() { } "#, expect![[r#" - *foo* + *foo* - ```rust - test - ``` + ```rust + test + ``` - ```rust - pub fn foo(a: u32, b: u32) -> u32 - ``` - "#]], + ```rust + pub fn foo(a: u32, b: u32) -> u32 + ``` + "#]], ); } @@ -610,27 +610,27 @@ pub fn foo$0(_: &Path) {} fn main() { } "#, - expect![[r##" - *foo* + expect![[r#" + *foo* - ```rust - test - ``` + ```rust + test + ``` - ```rust - pub fn foo(_: &Path) - ``` + ```rust + pub fn foo(_: &Path) + ``` - --- + --- - # Example + # Example - ``` - # use std::path::Path; - # - foo(Path::new("hello, world!")) - ``` - "##]], + ``` + # use std::path::Path; + # + foo(Path::new("hello, world!")) + ``` + "#]], ); } @@ -643,21 +643,21 @@ pub fn foo$0(_: &Path) {} fn main() { } "##, - expect![[r##" - *foo* + expect![[r#" + *foo* - ```rust - test - ``` + ```rust + test + ``` - ```rust - pub fn foo(_: &Path) - ``` + ```rust + pub fn foo(_: &Path) + ``` - --- + --- - Raw string doc attr - "##]], + Raw string doc attr + "#]], ); } @@ -1040,12 +1040,12 @@ fn hover_for_param_with_multiple_traits() { } fn f(_x$0: impl Deref + DerefMut) {}"#, expect![[r#" - *_x* + *_x* - ```rust - _x: impl Deref + DerefMut - ``` - "#]], + ```rust + _x: impl Deref + DerefMut + ``` + "#]], ) } @@ -1087,15 +1087,15 @@ mod wrapper { fn main() { let foo_test = wrapper::Thing::new$0(); } "#, expect![[r#" - *new* + *new* - ```rust - test::wrapper::Thing - ``` + ```rust + test::wrapper::Thing + ``` - ```rust - pub fn new() -> Thing - ``` + ```rust + pub fn new() -> Thing + ``` "#]], ) } @@ -1299,12 +1299,12 @@ fn test_hover_tuple_field() { check( r#"struct TS(String, i32$0);"#, expect![[r#" - *i32* + *i32* - ```rust - i32 - ``` - "#]], + ```rust + i32 + ``` + "#]], ) } @@ -1319,16 +1319,16 @@ id! { } "#, expect![[r#" - *foo* + *foo* - ```rust - test - ``` + ```rust + test + ``` - ```rust - fn foo() - ``` - "#]], + ```rust + fn foo() + ``` + "#]], ); } @@ -1341,16 +1341,16 @@ fn test_hover_through_attr() { fn foo$0() {} "#, expect![[r#" - *foo* + *foo* - ```rust - test - ``` + ```rust + test + ``` - ```rust - fn foo() - ``` - "#]], + ```rust + fn foo() + ``` + "#]], ); } @@ -1427,16 +1427,16 @@ fn foo() { } "#, expect![[r#" - *bar* + *bar* - ```rust - test - ``` + ```rust + test + ``` - ```rust - fn bar() -> bool - ``` - "#]], + ```rust + fn bar() -> bool + ``` + "#]], ); } @@ -1483,20 +1483,20 @@ fn foo() { } fn bar() { fo$0o(); } ", expect![[r#" - *foo* + *foo* - ```rust - test - ``` + ```rust + test + ``` - ```rust - fn foo() - ``` + ```rust + fn foo() + ``` - --- + --- - \<- ` ` here - "#]], + \<- ` ` here + "#]], ); } @@ -1505,45 +1505,45 @@ fn test_hover_function_show_qualifiers() { check( r#"async fn foo$0() {}"#, expect![[r#" - *foo* + *foo* - ```rust - test - ``` + ```rust + test + ``` - ```rust - async fn foo() - ``` - "#]], + ```rust + async fn foo() + ``` + "#]], ); check( r#"pub const unsafe fn foo$0() {}"#, expect![[r#" - *foo* + *foo* - ```rust - test - ``` + ```rust + test + ``` - ```rust - pub const unsafe fn foo() - ``` - "#]], + ```rust + pub const unsafe fn foo() + ``` + "#]], ); // Top level `pub(crate)` will be displayed as no visibility. check( r#"mod m { pub(crate) async unsafe extern "C" fn foo$0() {} }"#, expect![[r#" - *foo* + *foo* - ```rust - test::m - ``` + ```rust + test::m + ``` - ```rust - pub(crate) async unsafe extern "C" fn foo() - ``` - "#]], + ```rust + pub(crate) async unsafe extern "C" fn foo() + ``` + "#]], ); } @@ -1552,16 +1552,16 @@ fn test_hover_function_show_types() { check( r#"fn foo$0(a: i32, b:i32) -> i32 { 0 }"#, expect![[r#" - *foo* + *foo* - ```rust - test - ``` + ```rust + test + ``` - ```rust - fn foo(a: i32, b: i32) -> i32 - ``` - "#]], + ```rust + fn foo(a: i32, b: i32) -> i32 + ``` + "#]], ); } @@ -1949,39 +1949,39 @@ fn test_hover_no_links() { pub fn fo$0o() {} "#, expect![[r#" - *foo* + *foo* - ```rust - test - ``` + ```rust + test + ``` - ```rust - pub fn foo() - ``` + ```rust + pub fn foo() + ``` - --- + --- - Test cases: - case 1. bare URL: https://www.example.com/ - case 2. inline URL with title: [example](https://www.example.com/) - case 3. code reference: `Result` - case 4. code reference but miss footnote: `String` - case 5. autolink: http://www.example.com/ - case 6. email address: test@example.com - case 7. reference: example - case 8. collapsed link: example - case 9. shortcut link: example - case 10. inline without URL: example - case 11. reference: foo - case 12. reference: foo - case 13. collapsed link: foo - case 14. shortcut link: foo - case 15. inline without URL: foo - case 16. just escaped text: \[foo\] - case 17. inline link: Foo - - [^example]: https://www.example.com/ - "#]], + Test cases: + case 1. bare URL: https://www.example.com/ + case 2. inline URL with title: [example](https://www.example.com/) + case 3. code reference: `Result` + case 4. code reference but miss footnote: `String` + case 5. autolink: http://www.example.com/ + case 6. email address: test@example.com + case 7. reference: example + case 8. collapsed link: example + case 9. shortcut link: example + case 10. inline without URL: example + case 11. reference: foo + case 12. reference: foo + case 13. collapsed link: foo + case 14. shortcut link: foo + case 15. inline without URL: foo + case 16. just escaped text: \[foo\] + case 17. inline link: Foo + + [^example]: https://www.example.com/ + "#]], ); } @@ -2091,20 +2091,20 @@ bar!(); fn foo() { let bar = Bar; bar.fo$0o(); } "#, expect![[r#" - *foo* + *foo* - ```rust - test::Bar - ``` + ```rust + test::Bar + ``` - ```rust - fn foo(&self) - ``` + ```rust + fn foo(&self) + ``` - --- + --- - Do the foo - "#]], + Do the foo + "#]], ); } @@ -2129,20 +2129,20 @@ bar!(); fn foo() { let bar = Bar; bar.fo$0o(); } "#, expect![[r#" - *foo* + *foo* - ```rust - test::Bar - ``` + ```rust + test::Bar + ``` - ```rust - fn foo(&self) - ``` + ```rust + fn foo(&self) + ``` - --- + --- - Do the foo - "#]], + Do the foo + "#]], ); } @@ -3305,7 +3305,7 @@ fn main() { let foo_test = name_with_dashes::wrapper::Thing::new$0(); } ```rust pub fn new() -> Thing ``` - "#]], + "#]], ) } @@ -3327,7 +3327,7 @@ fn main() { ```rust // size = 8, align = 8, niches = 1 - f: &i32 + let f: &i32 ``` --- @@ -3628,24 +3628,24 @@ fn hover_doc_block_style_indent_end() { fn foo$0() {} "#, expect![[r#" - *foo* + *foo* - ```rust - test - ``` + ```rust + test + ``` - ```rust - fn foo() - ``` + ```rust + fn foo() + ``` - --- + --- - foo + foo - ```rust - let x = 3; - ``` - "#]], + ```rust + let x = 3; + ``` + "#]], ); } @@ -3704,12 +3704,12 @@ trait TraitB {} impl Foo where T: Sized {} "#, expect![[r#" - *T* + *T* - ```rust - T: TraitA + TraitB - ``` - "#]], + ```rust + T: TraitA + TraitB + ``` + "#]], ); check( r#" @@ -3718,12 +3718,12 @@ struct Foo(T); impl Foo {} "#, expect![[r#" - *T* + *T* - ```rust - T - ``` - "#]], + ```rust + T + ``` + "#]], ); // lifetimes bounds arent being tracked yet check( @@ -3733,12 +3733,12 @@ struct Foo(T); impl Foo {} "#, expect![[r#" - *T* + *T* - ```rust - T - ``` - "#]], + ```rust + T + ``` + "#]], ); } @@ -3753,12 +3753,12 @@ struct Foo(T); impl Foo {} "#, expect![[r#" - *T* + *T* - ```rust - T: Trait - ``` - "#]], + ```rust + T: Trait + ``` + "#]], ); check( r#" @@ -3768,12 +3768,12 @@ struct Foo(T); impl Foo {} "#, expect![[r#" - *T* + *T* - ```rust - T: Trait + ?Sized - ``` - "#]], + ```rust + T: Trait + ?Sized + ``` + "#]], ); } @@ -3788,12 +3788,12 @@ mod type_param_sized_bounds { fn foo() {} "#, expect![[r#" - *T* + *T* - ```rust - T - ``` - "#]], + ```rust + T + ``` + "#]], ); } @@ -3805,12 +3805,12 @@ fn foo() {} fn foo() {} "#, expect![[r#" - *T* + *T* - ```rust - T - ``` - "#]], + ```rust + T + ``` + "#]], ); } @@ -3822,12 +3822,12 @@ fn foo() {} fn foo() {} "#, expect![[r#" - *T* + *T* - ```rust - T: ?Sized - ``` - "#]], + ```rust + T: ?Sized + ``` + "#]], ); } @@ -3840,12 +3840,12 @@ trait Trait {} fn foo() {} "#, expect![[r#" - *T* + *T* - ```rust - T: Trait - ``` - "#]], + ```rust + T: Trait + ``` + "#]], ); } @@ -3858,12 +3858,12 @@ trait Trait {} fn foo() {} "#, expect![[r#" - *T* + *T* - ```rust - T: Trait - ``` - "#]], + ```rust + T: Trait + ``` + "#]], ); } @@ -3876,12 +3876,12 @@ trait Trait {} fn foo() {} "#, expect![[r#" - *T* + *T* - ```rust - T: Trait + ?Sized - ``` - "#]], + ```rust + T: Trait + ?Sized + ``` + "#]], ); } @@ -3893,12 +3893,12 @@ fn foo() {} fn foo() {} "#, expect![[r#" - *T* + *T* - ```rust - T - ``` - "#]], + ```rust + T + ``` + "#]], ); check( r#" @@ -3907,12 +3907,12 @@ trait Trait {} fn foo() {} "#, expect![[r#" - *T* + *T* - ```rust - T: Trait - ``` - "#]], + ```rust + T: Trait + ``` + "#]], ); } } @@ -3947,12 +3947,12 @@ struct Foo; impl Foo {} "#, expect![[r#" - *LEN* + *LEN* - ```rust - const LEN: usize - ``` - "#]], + ```rust + const LEN: usize + ``` + "#]], ); } @@ -4082,20 +4082,20 @@ fn main() { } "#, expect![[r#" - *B* + *B* - ```rust - test - ``` + ```rust + test + ``` - ```rust - const B: bool = true - ``` + ```rust + const B: bool = true + ``` - --- + --- - true - "#]], + true + "#]], ); check( @@ -4119,16 +4119,16 @@ fn main() { } "#, expect![[r#" - *AA* + *AA* - ```rust - test - ``` + ```rust + test + ``` - ```rust - const AA: A = A { i: 5 } - ``` - "#]], + ```rust + const AA: A = A { i: 5 } + ``` + "#]], ); check( @@ -5045,17 +5045,17 @@ const _: &str$0 = ""; } mod prim_str {} "#, expect![[r#" - *str* + *str* - ```rust - str - ``` + ```rust + str + ``` - --- + --- - Docs for prim_str - [`foo`](https://doc.rust-lang.org/nightly/std/keyword.foo.html) - "#]], + Docs for prim_str + [`foo`](https://doc.rust-lang.org/nightly/std/keyword.foo.html) + "#]], ); } @@ -5081,20 +5081,20 @@ fn main() { } "#, expect![[r#" - *bar* + *bar* - ```rust - test - ``` + ```rust + test + ``` - ```rust - fn bar<'t, T>(s: &mut S<'t, T>, t: u32) -> *mut u32 - where - T: Clone + 't, - 't: 't + 't, - for<'a> T: Clone + 'a, - ``` - "#]], + ```rust + fn bar<'t, T>(s: &mut S<'t, T>, t: u32) -> *mut u32 + where + T: Clone + 't, + 't: 't + 't, + for<'a> T: Clone + 'a, + ``` + "#]], ) } @@ -5164,16 +5164,16 @@ impl T1 for Foo { } "#, expect![[r#" -*Bar* + *Bar* -```rust -test::t2 -``` + ```rust + test::t2 + ``` -```rust -pub type Bar -``` -"#]], + ```rust + pub type Bar + ``` + "#]], ); } #[test] @@ -5186,16 +5186,16 @@ trait A { type Assoc; }"#, expect![[r#" - *Assoc* + *Assoc* - ```rust - test - ``` + ```rust + test + ``` - ```rust - type Assoc - ``` - "#]], + ```rust + type Assoc + ``` + "#]], ); check( r#" @@ -5207,16 +5207,16 @@ trait A { type Assoc; }"#, expect![[r#" - *Assoc* + *Assoc* - ```rust - test - ``` + ```rust + test + ``` - ```rust - type Assoc - ``` - "#]], + ```rust + type Assoc + ``` + "#]], ); check( r#" @@ -5226,16 +5226,16 @@ trait A where type Assoc; }"#, expect![[r#" - *Assoc* + *Assoc* - ```rust - test - ``` + ```rust + test + ``` - ```rust - type Assoc - ``` - "#]], + ```rust + type Assoc + ``` + "#]], ); } @@ -7059,3 +7059,63 @@ fn main() { "#]], ); } + +#[test] +fn notable_local() { + check( + r#" +#[doc(notable_trait)] +trait Notable { + type Assoc; + type Assoc2; +} + +impl Notable for u32 { + type Assoc = &str; + type Assoc2 = char; +} +fn main(notable$0: u32) {} +"#, + expect![[r#" + *notable* + + ```rust + // notable traits impls: Notable + // size = 4, align = 4 + notable: u32 + ``` + "#]], + ); +} + +#[test] +fn notable_foreign() { + check( + r#" +//- minicore: future, iterator +struct S; +#[doc(notable_trait)] +trait Notable {} +impl Notable for S$0 {} +impl core::future::Future for S { + type Output = u32; +} +impl Iterator for S { + type Item = S; +} +"#, + expect![[r#" + *S* + + ```rust + test + ``` + + ```rust + // notable traits impls: Notable, Future, Iterator + // size = 0, align = 1 + struct S + ``` + "#]], + ); +} diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index 3b836dfcd9ad9..b015dd69b528a 100644 --- a/crates/test-utils/src/minicore.rs +++ b/crates/test-utils/src/minicore.rs @@ -1166,6 +1166,7 @@ pub mod future { task::{Context, Poll}, }; + #[doc(notable_trait)] #[lang = "future_trait"] pub trait Future { type Output; @@ -1264,6 +1265,7 @@ pub mod iter { mod traits { mod iterator { + #[doc(notable_trait)] pub trait Iterator { type Item; #[lang = "next"] From ffeaee84afbb24176b9f7375dcb02c5542a8cb64 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 16 Jan 2024 19:59:55 +0100 Subject: [PATCH 0302/1197] Goto type actions for notable trait hovers --- crates/ide/src/hover.rs | 87 +++++++++++++++++++++------ crates/ide/src/hover/render.rs | 100 ++++++++++++++----------------- crates/ide/src/hover/tests.rs | 104 ++++++++++++++++++++++++++++++--- 3 files changed, 212 insertions(+), 79 deletions(-) diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index d06577d3db2c1..5ed3b2dbbcf93 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -3,10 +3,10 @@ mod render; #[cfg(test)] mod tests; -use std::iter; +use std::{iter, ops::Not}; use either::Either; -use hir::{db::DefDatabase, DescendPreference, HasSource, LangItem, Semantics}; +use hir::{db::DefDatabase, DescendPreference, HasCrate, HasSource, LangItem, Semantics}; use ide_db::{ base_db::FileRange, defs::{Definition, IdentClass, NameRefClass, OperatorClass}, @@ -64,7 +64,7 @@ pub enum HoverAction { } impl HoverAction { - fn goto_type_from_targets(db: &RootDatabase, targets: Vec) -> Self { + fn goto_type_from_targets(db: &RootDatabase, targets: Vec) -> Option { let targets = targets .into_iter() .filter_map(|it| { @@ -77,8 +77,8 @@ impl HoverAction { nav: it.try_to_nav(db)?.call_site(), }) }) - .collect(); - HoverAction::GoToType(targets) + .collect::>(); + targets.is_empty().not().then_some(HoverAction::GoToType(targets)) } } @@ -315,7 +315,7 @@ fn hover_simple( ast::IntNumber(num) => { res.markup = match num.value() { Ok(num) => { - Markup::fenced_block_text(format_args!("{num} (0x{num:X}|0x{num:b})")) + Markup::fenced_block_text(format_args!("{num} (0x{num:X}|0b{num:b})")) }, Err(e) => { Markup::fenced_block_text(format_args!("{e}")) @@ -365,25 +365,67 @@ fn hover_ranged( }) } +// FIXME: Why is this pub(crate)? pub(crate) fn hover_for_definition( sema: &Semantics<'_, RootDatabase>, file_id: FileId, - definition: Definition, + def: Definition, scope_node: &SyntaxNode, config: &HoverConfig, ) -> Option { - let famous_defs = match &definition { + let famous_defs = match &def { Definition::BuiltinType(_) => Some(FamousDefs(sema, sema.scope(scope_node)?.krate())), _ => None, }; - render::definition(sema.db, definition, famous_defs.as_ref(), config).map(|markup| { + + let db = sema.db; + let def_ty = match def { + Definition::Local(it) => Some(it.ty(db)), + Definition::GenericParam(hir::GenericParam::ConstParam(it)) => Some(it.ty(db)), + Definition::GenericParam(hir::GenericParam::TypeParam(it)) => Some(it.ty(db)), + Definition::Field(field) => Some(field.ty(db)), + Definition::TupleField(it) => Some(it.ty(db)), + Definition::Function(it) => Some(it.ty(db)), + Definition::Adt(it) => Some(it.ty(db)), + Definition::Const(it) => Some(it.ty(db)), + Definition::Static(it) => Some(it.ty(db)), + Definition::TypeAlias(it) => Some(it.ty(db)), + Definition::BuiltinType(it) => Some(it.ty(db)), + _ => None, + }; + let notable_traits = def_ty + .map(|ty| { + db.notable_traits_in_deps(ty.krate(db).into()) + .iter() + .flat_map(|it| &**it) + .filter_map(move |&trait_| { + let trait_ = trait_.into(); + ty.impls_trait(db, trait_, &[]).then(|| { + ( + trait_, + trait_ + .items(db) + .into_iter() + .filter_map(hir::AssocItem::as_type_alias) + .map(|alias| { + (ty.normalize_trait_assoc_type(db, &[], alias), alias.name(db)) + }) + .collect::>(), + ) + }) + }) + .collect::>() + }) + .unwrap_or_default(); + + render::definition(sema.db, def, famous_defs.as_ref(), ¬able_traits, config).map(|markup| { HoverResult { - markup: render::process_markup(sema.db, definition, &markup, config), + markup: render::process_markup(sema.db, def, &markup, config), actions: [ - show_implementations_action(sema.db, definition), - show_fn_references_action(sema.db, definition), - runnable_action(sema, definition, file_id), - goto_type_action_for_def(sema.db, definition), + show_implementations_action(sema.db, def), + show_fn_references_action(sema.db, def), + runnable_action(sema, def, file_id), + goto_type_action_for_def(sema.db, def, ¬able_traits), ] .into_iter() .flatten() @@ -446,7 +488,11 @@ fn runnable_action( } } -fn goto_type_action_for_def(db: &RootDatabase, def: Definition) -> Option { +fn goto_type_action_for_def( + db: &RootDatabase, + def: Definition, + notable_traits: &[(hir::Trait, Vec<(Option, hir::Name)>)], +) -> Option { let mut targets: Vec = Vec::new(); let mut push_new_def = |item: hir::ModuleDef| { if !targets.contains(&item) { @@ -454,6 +500,13 @@ fn goto_type_action_for_def(db: &RootDatabase, def: Definition) -> Option Option it.ty(db), Definition::Field(field) => field.ty(db), Definition::Function(function) => function.ret_type(db), - _ => return None, + _ => return HoverAction::goto_type_from_targets(db, targets), }; walk_and_push_ty(db, &ty, &mut push_new_def); } - Some(HoverAction::goto_type_from_targets(db, targets)) + HoverAction::goto_type_from_targets(db, targets) } fn walk_and_push_ty( diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index d3a9975b2b2b6..511137f67c8f6 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -3,8 +3,8 @@ use std::{mem, ops::Not}; use either::Either; use hir::{ - db::DefDatabase, Adt, AsAssocItem, AssocItem, CaptureKind, HasCrate, HasSource, HirDisplay, - Layout, LayoutError, Semantics, TypeInfo, + Adt, AsAssocItem, CaptureKind, HasSource, HirDisplay, Layout, LayoutError, Name, Semantics, + Trait, Type, TypeInfo, }; use ide_db::{ base_db::SourceDatabase, @@ -117,7 +117,9 @@ pub(super) fn try_expr( }; walk_and_push_ty(sema.db, &inner_ty, &mut push_new_def); walk_and_push_ty(sema.db, &body_ty, &mut push_new_def); - res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets)); + if let Some(actions) = HoverAction::goto_type_from_targets(sema.db, targets) { + res.actions.push(actions); + } let inner_ty = inner_ty.display(sema.db).to_string(); let body_ty = body_ty.display(sema.db).to_string(); @@ -195,7 +197,9 @@ pub(super) fn deref_expr( ) .into() }; - res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets)); + if let Some(actions) = HoverAction::goto_type_from_targets(sema.db, targets) { + res.actions.push(actions); + } Some(res) } @@ -302,7 +306,9 @@ pub(super) fn struct_rest_pat( Markup::fenced_block(&s) }; - res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets)); + if let Some(actions) = HoverAction::goto_type_from_targets(sema.db, targets) { + res.actions.push(actions); + } res } @@ -388,6 +394,7 @@ pub(super) fn definition( db: &RootDatabase, def: Definition, famous_defs: Option<&FamousDefs<'_, '_>>, + notable_traits: &[(Trait, Vec<(Option, Name)>)], config: &HoverConfig, ) -> Option { let mod_path = definition_mod_path(db, &def); @@ -464,58 +471,35 @@ pub(super) fn definition( _ => None, }; - let def_ty = match def { - Definition::Local(it) => Some(it.ty(db)), - Definition::GenericParam(hir::GenericParam::ConstParam(it)) => Some(it.ty(db)), - Definition::GenericParam(hir::GenericParam::TypeParam(it)) => Some(it.ty(db)), - Definition::Field(field) => Some(field.ty(db)), - Definition::TupleField(it) => Some(it.ty(db)), - Definition::Function(it) => Some(it.ty(db)), - Definition::Adt(it) => Some(it.ty(db)), - Definition::Const(it) => Some(it.ty(db)), - Definition::Static(it) => Some(it.ty(db)), - Definition::TypeAlias(it) => Some(it.ty(db)), - Definition::BuiltinType(it) => Some(it.ty(db)), - _ => None, - }; - let notable_traits = def_ty.and_then(|ty| { + let notable_traits = { let mut desc = String::new(); let mut needs_impl_header = true; - for &trait_ in db.notable_traits_in_deps(ty.krate(db).into()).iter().flat_map(|it| &**it) { - let trait_ = trait_.into(); - if ty.impls_trait(db, trait_, &[]) { - let aliases: Vec<_> = trait_ - .items(db) - .into_iter() - .filter_map(AssocItem::as_type_alias) - .map(|alias| (ty.normalize_trait_assoc_type(db, &[], alias), alias.name(db))) - .collect(); - desc.push_str(if mem::take(&mut needs_impl_header) { - " // notable traits impls: " - } else { - ", " - }); - format_to!(desc, "{}", trait_.name(db).display(db),); - if !aliases.is_empty() { - desc.push('<'); - format_to!( - desc, - "{}", - aliases.into_iter().format_with(", ", |(ty, name), f| { - f(&name.display(db))?; - f(&" = ")?; - match ty { - Some(ty) => f(&ty.display(db)), - None => f(&"?"), - } - }) - ); - desc.push('>'); - } + for (trait_, assoc_types) in notable_traits { + desc.push_str(if mem::take(&mut needs_impl_header) { + " // notable traits implemented: " + } else { + ", " + }); + format_to!(desc, "{}", trait_.name(db).display(db),); + if !assoc_types.is_empty() { + desc.push('<'); + format_to!( + desc, + "{}", + assoc_types.into_iter().format_with(", ", |(ty, name), f| { + f(&name.display(db))?; + f(&" = ")?; + match ty { + Some(ty) => f(&ty.display(db)), + None => f(&"?"), + } + }) + ); + desc.push('>'); } } desc.is_empty().not().then(|| desc) - }); + }; let mut desc = String::new(); if let Some(notable_traits) = notable_traits { @@ -569,7 +553,9 @@ fn type_info( } else { Markup::fenced_block(&original.display(sema.db)) }; - res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets)); + if let Some(actions) = HoverAction::goto_type_from_targets(sema.db, targets) { + res.actions.push(actions); + } Some(res) } @@ -629,7 +615,9 @@ fn closure_ty( ); let mut res = HoverResult::default(); - res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets)); + if let Some(actions) = HoverAction::goto_type_from_targets(sema.db, targets) { + res.actions.push(actions); + } res.markup = markup.into(); Some(res) } @@ -783,7 +771,9 @@ fn keyword_hints( KeywordHint { description, keyword_mod, - actions: vec![HoverAction::goto_type_from_targets(sema.db, targets)], + actions: HoverAction::goto_type_from_targets(sema.db, targets) + .into_iter() + .collect(), } } _ => KeywordHint { diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index f8693cd1ea63a..09548745f6ee3 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -6989,7 +6989,7 @@ fn main() { expect![[r#" *34325236457856836345234* ```text - 34325236457856836345234 (0x744C659178614489D92|0x111010001001100011001011001000101111000011000010100010010001001110110010010) + 34325236457856836345234 (0x744C659178614489D92|0b111010001001100011001011001000101111000011000010100010010001001110110010010) ``` "#]], ); @@ -7002,7 +7002,7 @@ fn main() { expect![[r#" *134_123424_21* ```text - 13412342421 (0x31F701A95|0x1100011111011100000001101010010101) + 13412342421 (0x31F701A95|0b1100011111011100000001101010010101) ``` "#]], ); @@ -7015,7 +7015,7 @@ fn main() { expect![[r#" *0x12423423* ```text - 306328611 (0x12423423|0x10010010000100011010000100011) + 306328611 (0x12423423|0b10010010000100011010000100011) ``` "#]], ); @@ -7028,7 +7028,7 @@ fn main() { expect![[r#" *0b1111_1111* ```text - 255 (0xFF|0x11111111) + 255 (0xFF|0b11111111) ``` "#]], ); @@ -7041,7 +7041,7 @@ fn main() { expect![[r#" *0o12345* ```text - 5349 (0x14E5|0x1010011100101) + 5349 (0x14E5|0b1010011100101) ``` "#]], ); @@ -7080,7 +7080,7 @@ fn main(notable$0: u32) {} *notable* ```rust - // notable traits impls: Notable + // notable traits implemented: Notable // size = 4, align = 4 notable: u32 ``` @@ -7112,10 +7112,100 @@ impl Iterator for S { ``` ```rust - // notable traits impls: Notable, Future, Iterator + // notable traits implemented: Notable, Future, Iterator // size = 0, align = 1 struct S ``` "#]], ); } + +#[test] +fn notable_actions() { + check_actions( + r#" +//- minicore: future, iterator +struct S; +struct S2; +#[doc(notable_trait)] +trait Notable {} +impl Notable for S$0 {} +impl core::future::Future for S { + type Output = u32; +} +impl Iterator for S { + type Item = S2; +} +"#, + expect![[r#" + [ + Implementation( + FilePosition { + file_id: FileId( + 0, + ), + offset: 7, + }, + ), + GoToType( + [ + HoverGotoTypeData { + mod_path: "test::Notable", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 21..59, + focus_range: 49..56, + name: "Notable", + kind: Trait, + description: "trait Notable", + }, + }, + HoverGotoTypeData { + mod_path: "core::future::Future", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 6012..6220, + focus_range: 6077..6083, + name: "Future", + kind: Trait, + container_name: "future", + description: "pub trait Future", + }, + }, + HoverGotoTypeData { + mod_path: "core::iter::traits::iterator::Iterator", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 6850..7316, + focus_range: 6894..6902, + name: "Iterator", + kind: Trait, + container_name: "iterator", + description: "pub trait Iterator", + }, + }, + HoverGotoTypeData { + mod_path: "test::S2", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 10..20, + focus_range: 17..19, + name: "S2", + kind: Struct, + description: "struct S2", + }, + }, + ], + ), + ] + "#]], + ); +} From 0a75a8c0614efbd6dfcf23870a789fd64e16618b Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 16 Jan 2024 20:15:31 +0100 Subject: [PATCH 0303/1197] Notable traits for type info hovers --- crates/ide/src/hover.rs | 55 ++-- crates/ide/src/hover/render.rs | 86 ++--- crates/ide/src/hover/tests.rs | 559 ++++++++++++++++++--------------- 3 files changed, 378 insertions(+), 322 deletions(-) diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 5ed3b2dbbcf93..77a06a97e22d2 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -393,30 +393,7 @@ pub(crate) fn hover_for_definition( Definition::BuiltinType(it) => Some(it.ty(db)), _ => None, }; - let notable_traits = def_ty - .map(|ty| { - db.notable_traits_in_deps(ty.krate(db).into()) - .iter() - .flat_map(|it| &**it) - .filter_map(move |&trait_| { - let trait_ = trait_.into(); - ty.impls_trait(db, trait_, &[]).then(|| { - ( - trait_, - trait_ - .items(db) - .into_iter() - .filter_map(hir::AssocItem::as_type_alias) - .map(|alias| { - (ty.normalize_trait_assoc_type(db, &[], alias), alias.name(db)) - }) - .collect::>(), - ) - }) - }) - .collect::>() - }) - .unwrap_or_default(); + let notable_traits = def_ty.map(|ty| notable_traits(db, &ty)).unwrap_or_default(); render::definition(sema.db, def, famous_defs.as_ref(), ¬able_traits, config).map(|markup| { HoverResult { @@ -434,6 +411,32 @@ pub(crate) fn hover_for_definition( }) } +fn notable_traits( + db: &RootDatabase, + ty: &hir::Type, +) -> Vec<(hir::Trait, Vec<(Option, hir::Name)>)> { + db.notable_traits_in_deps(ty.krate(db).into()) + .iter() + .flat_map(|it| &**it) + .filter_map(move |&trait_| { + let trait_ = trait_.into(); + ty.impls_trait(db, trait_, &[]).then(|| { + ( + trait_, + trait_ + .items(db) + .into_iter() + .filter_map(hir::AssocItem::as_type_alias) + .map(|alias| { + (ty.normalize_trait_assoc_type(db, &[], alias), alias.name(db)) + }) + .collect::>(), + ) + }) + }) + .collect::>() +} + fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option { fn to_action(nav_target: NavigationTarget) -> HoverAction { HoverAction::Implementation(FilePosition { @@ -583,7 +586,9 @@ fn dedupe_or_merge_hover_actions(actions: Vec) -> Vec } if !go_to_type_targets.is_empty() { - deduped_actions.push(HoverAction::GoToType(go_to_type_targets.into_iter().collect())); + deduped_actions.push(HoverAction::GoToType( + go_to_type_targets.into_iter().sorted_by(|a, b| a.mod_path.cmp(&b.mod_path)).collect(), + )); } deduped_actions diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index 511137f67c8f6..787b74fc62c59 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -3,8 +3,8 @@ use std::{mem, ops::Not}; use either::Either; use hir::{ - Adt, AsAssocItem, CaptureKind, HasSource, HirDisplay, Layout, LayoutError, Name, Semantics, - Trait, Type, TypeInfo, + Adt, AsAssocItem, CaptureKind, HasCrate, HasSource, HirDisplay, Layout, LayoutError, Name, + Semantics, Trait, Type, TypeInfo, }; use ide_db::{ base_db::SourceDatabase, @@ -25,7 +25,7 @@ use syntax::{ use crate::{ doc_links::{remove_links, rewrite_links}, - hover::walk_and_push_ty, + hover::{notable_traits, walk_and_push_ty}, HoverAction, HoverConfig, HoverResult, Markup, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind, }; @@ -471,38 +471,8 @@ pub(super) fn definition( _ => None, }; - let notable_traits = { - let mut desc = String::new(); - let mut needs_impl_header = true; - for (trait_, assoc_types) in notable_traits { - desc.push_str(if mem::take(&mut needs_impl_header) { - " // notable traits implemented: " - } else { - ", " - }); - format_to!(desc, "{}", trait_.name(db).display(db),); - if !assoc_types.is_empty() { - desc.push('<'); - format_to!( - desc, - "{}", - assoc_types.into_iter().format_with(", ", |(ty, name), f| { - f(&name.display(db))?; - f(&" = ")?; - match ty { - Some(ty) => f(&ty.display(db)), - None => f(&"?"), - } - }) - ); - desc.push('>'); - } - } - desc.is_empty().not().then(|| desc) - }; - let mut desc = String::new(); - if let Some(notable_traits) = notable_traits { + if let Some(notable_traits) = render_notable_trait_comment(db, notable_traits) { desc.push_str(¬able_traits); desc.push('\n'); } @@ -519,6 +489,39 @@ pub(super) fn definition( markup(docs.map(Into::into), desc, mod_path) } +fn render_notable_trait_comment( + db: &RootDatabase, + notable_traits: &[(Trait, Vec<(Option, Name)>)], +) -> Option { + let mut desc = String::new(); + let mut needs_impl_header = true; + for (trait_, assoc_types) in notable_traits { + desc.push_str(if mem::take(&mut needs_impl_header) { + " // notable traits implemented: " + } else { + ", " + }); + format_to!(desc, "{}", trait_.name(db).display(db),); + if !assoc_types.is_empty() { + desc.push('<'); + format_to!( + desc, + "{}", + assoc_types.into_iter().format_with(", ", |(ty, name), f| { + f(&name.display(db))?; + f(&" = ")?; + match ty { + Some(ty) => f(&ty.display(db)), + None => f(&"?"), + } + }) + ); + desc.push('>'); + } + } + desc.is_empty().not().then(|| desc) +} + fn type_info( sema: &Semantics<'_, RootDatabase>, config: &HoverConfig, @@ -536,8 +539,12 @@ fn type_info( } }; walk_and_push_ty(sema.db, &original, &mut push_new_def); - - res.markup = if let Some(adjusted_ty) = adjusted { + let mut desc = match render_notable_trait_comment(sema.db, ¬able_traits(sema.db, &original)) + { + Some(desc) => desc + "\n", + None => String::new(), + }; + desc += &if let Some(adjusted_ty) = adjusted { walk_and_push_ty(sema.db, &adjusted_ty, &mut push_new_def); let original = original.display(sema.db).to_string(); let adjusted = adjusted_ty.display(sema.db).to_string(); @@ -549,10 +556,10 @@ fn type_info( apad = static_text_diff_len + adjusted.len().max(original.len()), opad = original.len(), ) - .into() } else { - Markup::fenced_block(&original.display(sema.db)) + Markup::fenced_block(&original.display(sema.db)).into() }; + res.markup = desc.into(); if let Some(actions) = HoverAction::goto_type_from_targets(sema.db, targets) { res.actions.push(actions); } @@ -607,6 +614,9 @@ fn closure_ty( { format_to!(markup, "{layout}"); } + if let Some(trait_) = c.fn_trait(sema.db).get_id(sema.db, original.krate(sema.db).into()) { + push_new_def(hir::Trait::from(trait_).into()) + } format_to!( markup, "\n{}\n```{adjusted}\n\n## Captures\n{}", diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index 09548745f6ee3..d8d439c0d2bed 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -400,6 +400,20 @@ fn main() { description: "struct S", }, }, + HoverGotoTypeData { + mod_path: "core::ops::function::FnOnce", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 631..866, + focus_range: 692..698, + name: "FnOnce", + kind: Trait, + container_name: "function", + description: "pub trait FnOnce\nwhere\n Args: Tuple,", + }, + }, ], ), ] @@ -2387,39 +2401,39 @@ struct S{ f1: T } fn main() { let s$0t = S{ f1:Arg(0) }; } "#, expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::S", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 17..37, - focus_range: 24..25, - name: "S", - kind: Struct, - description: "struct S {\n f1: T,\n}", - }, + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "test::Arg", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 0..16, + focus_range: 7..10, + name: "Arg", + kind: Struct, + description: "struct Arg(u32);", }, - HoverGotoTypeData { - mod_path: "test::Arg", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..16, - focus_range: 7..10, - name: "Arg", - kind: Struct, - description: "struct Arg(u32);", - }, + }, + HoverGotoTypeData { + mod_path: "test::S", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 17..37, + focus_range: 24..25, + name: "S", + kind: Struct, + description: "struct S {\n f1: T,\n}", }, - ], - ), - ] - "#]], + }, + ], + ), + ] + "#]], ); } @@ -2446,39 +2460,39 @@ struct S{ f1: T } fn main() { let s$0t = S{ f1: S{ f1: Arg(0) } }; } "#, expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::S", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 17..37, - focus_range: 24..25, - name: "S", - kind: Struct, - description: "struct S {\n f1: T,\n}", - }, + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "test::Arg", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 0..16, + focus_range: 7..10, + name: "Arg", + kind: Struct, + description: "struct Arg(u32);", }, - HoverGotoTypeData { - mod_path: "test::Arg", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..16, - focus_range: 7..10, - name: "Arg", - kind: Struct, - description: "struct Arg(u32);", - }, + }, + HoverGotoTypeData { + mod_path: "test::S", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 17..37, + focus_range: 24..25, + name: "S", + kind: Struct, + description: "struct S {\n f1: T,\n}", }, - ], - ), - ] - "#]], + }, + ], + ), + ] + "#]], ); } @@ -2636,39 +2650,39 @@ fn foo() -> impl Foo + Bar {} fn main() { let s$0t = foo(); } "#, expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::Foo", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..12, - focus_range: 6..9, - name: "Foo", - kind: Trait, - description: "trait Foo", - }, + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "test::Bar", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 13..25, + focus_range: 19..22, + name: "Bar", + kind: Trait, + description: "trait Bar", }, - HoverGotoTypeData { - mod_path: "test::Bar", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 13..25, - focus_range: 19..22, - name: "Bar", - kind: Trait, - description: "trait Bar", - }, + }, + HoverGotoTypeData { + mod_path: "test::Foo", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 0..12, + focus_range: 6..9, + name: "Foo", + kind: Trait, + description: "trait Foo", }, - ], - ), - ] - "#]], + }, + ], + ), + ] + "#]], ); } @@ -2686,65 +2700,65 @@ fn foo() -> impl Foo + Bar {} fn main() { let s$0t = foo(); } "#, expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::Foo", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..15, - focus_range: 6..9, - name: "Foo", - kind: Trait, - description: "trait Foo", - }, + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "test::Bar", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 16..31, + focus_range: 22..25, + name: "Bar", + kind: Trait, + description: "trait Bar", }, - HoverGotoTypeData { - mod_path: "test::Bar", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 16..31, - focus_range: 22..25, - name: "Bar", - kind: Trait, - description: "trait Bar", - }, + }, + HoverGotoTypeData { + mod_path: "test::Foo", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 0..15, + focus_range: 6..9, + name: "Foo", + kind: Trait, + description: "trait Foo", }, - HoverGotoTypeData { - mod_path: "test::S1", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 32..44, - focus_range: 39..41, - name: "S1", - kind: Struct, - description: "struct S1 {}", - }, + }, + HoverGotoTypeData { + mod_path: "test::S1", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 32..44, + focus_range: 39..41, + name: "S1", + kind: Struct, + description: "struct S1 {}", }, - HoverGotoTypeData { - mod_path: "test::S2", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 45..57, - focus_range: 52..54, - name: "S2", - kind: Struct, - description: "struct S2 {}", - }, + }, + HoverGotoTypeData { + mod_path: "test::S2", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 45..57, + focus_range: 52..54, + name: "S2", + kind: Struct, + description: "struct S2 {}", }, - ], - ), - ] - "#]], + }, + ], + ), + ] + "#]], ); } @@ -2790,52 +2804,52 @@ struct S{} fn foo(ar$0g: &impl Foo + Bar) {} "#, expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::Foo", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..12, - focus_range: 6..9, - name: "Foo", - kind: Trait, - description: "trait Foo", - }, + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "test::Bar", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 13..28, + focus_range: 19..22, + name: "Bar", + kind: Trait, + description: "trait Bar", }, - HoverGotoTypeData { - mod_path: "test::Bar", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 13..28, - focus_range: 19..22, - name: "Bar", - kind: Trait, - description: "trait Bar", - }, + }, + HoverGotoTypeData { + mod_path: "test::Foo", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 0..12, + focus_range: 6..9, + name: "Foo", + kind: Trait, + description: "trait Foo", }, - HoverGotoTypeData { - mod_path: "test::S", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 29..39, - focus_range: 36..37, - name: "S", - kind: Struct, - description: "struct S {}", - }, + }, + HoverGotoTypeData { + mod_path: "test::S", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 29..39, + focus_range: 36..37, + name: "S", + kind: Struct, + description: "struct S {}", }, - ], - ), - ] - "#]], + }, + ], + ), + ] + "#]], ); } @@ -3077,65 +3091,65 @@ struct S {} fn foo(a$0rg: &impl ImplTrait>>>) {} "#, expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::ImplTrait", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..21, - focus_range: 6..15, - name: "ImplTrait", - kind: Trait, - description: "trait ImplTrait", - }, + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "test::B", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 43..57, + focus_range: 50..51, + name: "B", + kind: Struct, + description: "struct B {}", }, - HoverGotoTypeData { - mod_path: "test::B", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 43..57, - focus_range: 50..51, - name: "B", - kind: Struct, - description: "struct B {}", - }, + }, + HoverGotoTypeData { + mod_path: "test::DynTrait", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 22..42, + focus_range: 28..36, + name: "DynTrait", + kind: Trait, + description: "trait DynTrait", }, - HoverGotoTypeData { - mod_path: "test::DynTrait", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 22..42, - focus_range: 28..36, - name: "DynTrait", - kind: Trait, - description: "trait DynTrait", - }, + }, + HoverGotoTypeData { + mod_path: "test::ImplTrait", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 0..21, + focus_range: 6..15, + name: "ImplTrait", + kind: Trait, + description: "trait ImplTrait", }, - HoverGotoTypeData { - mod_path: "test::S", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 58..69, - focus_range: 65..66, - name: "S", - kind: Struct, - description: "struct S {}", - }, + }, + HoverGotoTypeData { + mod_path: "test::S", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 58..69, + focus_range: 65..66, + name: "S", + kind: Struct, + description: "struct S {}", }, - ], - ), - ] - "#]], + }, + ], + ), + ] + "#]], ); } @@ -7120,6 +7134,33 @@ impl Iterator for S { ); } +#[test] +fn notable_ranged() { + check_hover_range( + r#" +//- minicore: future, iterator +struct S; +#[doc(notable_trait)] +trait Notable {} +impl Notable for S {} +impl core::future::Future for S { + type Output = u32; +} +impl Iterator for S { + type Item = S; +} +fn main() { + $0S$0; +} +"#, + expect![[r#" + // notable traits implemented: Notable, Future, Iterator + ```rust + S + ```"#]], + ); +} + #[test] fn notable_actions() { check_actions( @@ -7149,19 +7190,6 @@ impl Iterator for S { ), GoToType( [ - HoverGotoTypeData { - mod_path: "test::Notable", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 21..59, - focus_range: 49..56, - name: "Notable", - kind: Trait, - description: "trait Notable", - }, - }, HoverGotoTypeData { mod_path: "core::future::Future", nav: NavigationTarget { @@ -7190,6 +7218,19 @@ impl Iterator for S { description: "pub trait Iterator", }, }, + HoverGotoTypeData { + mod_path: "test::Notable", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 21..59, + focus_range: 49..56, + name: "Notable", + kind: Trait, + description: "trait Notable", + }, + }, HoverGotoTypeData { mod_path: "test::S2", nav: NavigationTarget { From f91ccf9ace393a681922b145e56e7e3fb0041657 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Wed, 10 Jan 2024 11:46:17 -0800 Subject: [PATCH 0304/1197] Remove tcx from SMIR run macro and accept closures Simplify the `run` macro to avoid sometimes unnecessary dependency on `TyCtxt`. Instead, users can use the new internal method `tcx()`. Additionally, extend the macro to accept closures that may capture variables. These are non-backward compatible changes, but they only affect internal APIs which are provided today as helper functions until we have a stable API to start the compiler. --- compiler/rustc_smir/src/rustc_internal/mod.rs | 122 +++++++++++++++--- tests/ui-fulldeps/stable-mir/check_abi.rs | 6 +- .../stable-mir/check_allocation.rs | 6 +- tests/ui-fulldeps/stable-mir/check_defs.rs | 6 +- .../ui-fulldeps/stable-mir/check_instance.rs | 6 +- .../ui-fulldeps/stable-mir/check_item_kind.rs | 6 +- tests/ui-fulldeps/stable-mir/check_ty_fold.rs | 6 +- .../stable-mir/compilation-result.rs | 12 +- tests/ui-fulldeps/stable-mir/crate-info.rs | 6 +- tests/ui-fulldeps/stable-mir/projections.rs | 6 +- tests/ui-fulldeps/stable-mir/smir_internal.rs | 6 +- tests/ui-fulldeps/stable-mir/smir_visitor.rs | 6 +- 12 files changed, 134 insertions(+), 60 deletions(-) diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index 4bac98909add0..7633739f2890a 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -24,14 +24,49 @@ use std::ops::Index; mod internal; pub mod pretty; +/// Convert an internal Rust compiler item into its stable counterpart, if one exists. +/// +/// # Warning +/// +/// This function is unstable, and it's behavior may change at any point. +/// E.g.: Items that were previously supported, may no longer be supported, or its translation may +/// change. +/// +/// # Panics +/// +/// This function will panic if StableMIR has not been properly initialized. pub fn stable<'tcx, S: Stable<'tcx>>(item: S) -> S::T { with_tables(|tables| item.stable(tables)) } +/// Convert a stable item into its internal Rust compiler counterpart, if one exists. +/// +/// # Warning +/// +/// This function is unstable, and it's behavior may change at any point. +/// Not every stable item can be converted to an internal one. +/// Furthermore, items that were previously supported, may no longer be supported in newer versions. +/// +/// # Panics +/// +/// This function will panic if StableMIR has not been properly initialized. pub fn internal<'tcx, S: RustcInternal<'tcx>>(item: S) -> S::T { with_tables(|tables| item.internal(tables)) } +/// Retrieve the internal Rust compiler type context. +/// +/// # Warning +/// +/// This function is unstable, and it's behavior may change at any point. +/// +/// # Panics +/// +/// This function will panic if StableMIR has not been properly initialized. +pub fn tcx<'tcx>() -> TyCtxt<'tcx> { + with_tables(|tables| tables.tcx) +} + impl<'tcx> Index for Tables<'tcx> { type Output = DefId; @@ -190,35 +225,83 @@ where stable_mir::compiler_interface::run(&tables, || init(&tables, f)) } +/// Instantiate and run the compiler with the provided arguments and callback. +/// +/// The callback will be invoked after the compiler ran all its analysis, but before code generation. +/// Note that this macro accepts two different formats for the callback: +/// 1. An ident that resolves to a function that accepts no argument and returns `ControlFlow` +/// ```ignore(needs-extern-crate) +/// # extern crate rustc_driver; +/// # extern crate rustc_interface; +/// # #[macro_use] +/// # extern crate rustc_smir; +/// # extern crate stable_mir; +/// # +/// # fn main() { +/// # use std::ops::ControlFlow; +/// # use stable_mir::CompilerError; +/// fn analyze_code() -> ControlFlow<(), ()> { +/// // Your code goes in here. +/// # ControlFlow::Continue(()) +/// } +/// # let args = vec!["--verbose".to_string()]; +/// let result = run!(args, analyze_code); +/// # assert_eq!(result, Err(CompilerError::Skipped)) +/// # } +/// ``` +/// 2. An expression that represents the body of a closure: +/// ```ignore(needs-extern-crate) +/// # extern crate rustc_driver; +/// # extern crate rustc_interface; +/// # #[macro_use] +/// # extern crate rustc_smir; +/// # extern crate stable_mir; +/// # +/// # fn main() { +/// # use std::ops::ControlFlow; +/// # use stable_mir::CompilerError; +/// fn analyze_code(extra_args: Vec) -> ControlFlow<(), ()> { +/// # let _ = extra_args; +/// // Your code goes in here. +/// # ControlFlow::Continue(()) +/// } +/// # let args = vec!["--verbose".to_string()]; +/// # let extra_args = vec![]; +/// let result = run!(args, analyze_code(extra_args)); +/// # assert_eq!(result, Err(CompilerError::Skipped)) +/// # } +/// ``` #[macro_export] macro_rules! run { - ($args:expr, $callback:expr) => { - run!($args, tcx, $callback) + ($args:expr, $callback_fn:ident) => { + run!($args, $callback_fn()) }; - ($args:expr, $tcx:ident, $callback:expr) => {{ + ($args:expr, $callback:expr) => {{ use rustc_driver::{Callbacks, Compilation, RunCompiler}; use rustc_interface::{interface, Queries}; use stable_mir::CompilerError; use std::ops::ControlFlow; - pub struct StableMir + pub struct StableMir ControlFlow> where B: Send, C: Send, + F: FnOnce() -> ControlFlow + Send, { args: Vec, - callback: fn(TyCtxt<'_>) -> ControlFlow, + callback: Option, result: Option>, } - impl StableMir + impl StableMir where B: Send, C: Send, + F: FnOnce() -> ControlFlow + Send, { /// Creates a new `StableMir` instance, with given test_function and arguments. - pub fn new(args: Vec, callback: fn(TyCtxt<'_>) -> ControlFlow) -> Self { - StableMir { args, callback, result: None } + pub fn new(args: Vec, callback: F) -> Self { + StableMir { args, callback: Some(callback), result: None } } /// Runs the compiler against given target and tests it with `test_function` @@ -238,10 +321,11 @@ macro_rules! run { } } - impl Callbacks for StableMir + impl Callbacks for StableMir where B: Send, C: Send, + F: FnOnce() -> ControlFlow + Send, { /// Called after analysis. Return value instructs the compiler whether to /// continue the compilation afterwards (defaults to `Compilation::Continue`) @@ -251,20 +335,24 @@ macro_rules! run { queries: &'tcx Queries<'tcx>, ) -> Compilation { queries.global_ctxt().unwrap().enter(|tcx| { - rustc_internal::run(tcx, || { - self.result = Some((self.callback)(tcx)); - }) - .unwrap(); - if self.result.as_ref().is_some_and(|val| val.is_continue()) { - Compilation::Continue + if let Some(callback) = self.callback.take() { + rustc_internal::run(tcx, || { + self.result = Some((callback)()); + }) + .unwrap(); + if self.result.as_ref().is_some_and(|val| val.is_continue()) { + Compilation::Continue + } else { + Compilation::Stop + } } else { - Compilation::Stop + Compilation::Continue } }) } } - StableMir::new($args, |$tcx| $callback).run() + StableMir::new($args, || $callback).run() }}; } diff --git a/tests/ui-fulldeps/stable-mir/check_abi.rs b/tests/ui-fulldeps/stable-mir/check_abi.rs index 30b42bc3bfafc..7d7469597afc2 100644 --- a/tests/ui-fulldeps/stable-mir/check_abi.rs +++ b/tests/ui-fulldeps/stable-mir/check_abi.rs @@ -12,14 +12,12 @@ #![feature(ascii_char, ascii_char_variants)] extern crate rustc_hir; -extern crate rustc_middle; #[macro_use] extern crate rustc_smir; extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use stable_mir::abi::{ArgAbi, CallConvention, FieldsShape, PassMode, VariantsShape}; use stable_mir::mir::mono::Instance; @@ -32,7 +30,7 @@ use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; /// This function uses the Stable MIR APIs to get information about the test crate. -fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { +fn test_stable_mir() -> ControlFlow<()> { // Find items in the local crate. let items = stable_mir::all_local_items(); @@ -117,7 +115,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, tcx, test_stable_mir(tcx)).unwrap(); + run!(args, test_stable_mir).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { diff --git a/tests/ui-fulldeps/stable-mir/check_allocation.rs b/tests/ui-fulldeps/stable-mir/check_allocation.rs index 93def93127c88..fb5e13eb13b10 100644 --- a/tests/ui-fulldeps/stable-mir/check_allocation.rs +++ b/tests/ui-fulldeps/stable-mir/check_allocation.rs @@ -14,14 +14,12 @@ #![feature(ascii_char, ascii_char_variants)] extern crate rustc_hir; -extern crate rustc_middle; #[macro_use] extern crate rustc_smir; extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use stable_mir::crate_def::CrateDef; use stable_mir::mir::alloc::GlobalAlloc; @@ -40,7 +38,7 @@ use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; /// This function uses the Stable MIR APIs to get information about the test crate. -fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { +fn test_stable_mir() -> ControlFlow<()> { // Find items in the local crate. let items = stable_mir::all_local_items(); check_foo(*get_item(&items, (ItemKind::Static, "FOO")).unwrap()); @@ -230,7 +228,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, tcx, test_stable_mir(tcx)).unwrap(); + run!(args, test_stable_mir).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { diff --git a/tests/ui-fulldeps/stable-mir/check_defs.rs b/tests/ui-fulldeps/stable-mir/check_defs.rs index e9a2599d8732c..4a124adb2b605 100644 --- a/tests/ui-fulldeps/stable-mir/check_defs.rs +++ b/tests/ui-fulldeps/stable-mir/check_defs.rs @@ -11,7 +11,6 @@ #![feature(assert_matches)] #![feature(control_flow_enum)] -extern crate rustc_middle; #[macro_use] extern crate rustc_smir; extern crate rustc_driver; @@ -20,7 +19,6 @@ extern crate stable_mir; use std::assert_matches::assert_matches; use mir::{mono::Instance, TerminatorKind::*}; -use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use stable_mir::ty::{RigidTy, TyKind, Ty, UintTy}; use stable_mir::*; @@ -30,7 +28,7 @@ use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; /// This function uses the Stable MIR APIs to get information about the test crate. -fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { +fn test_stable_mir() -> ControlFlow<()> { let entry = stable_mir::entry_fn().unwrap(); let main_fn = Instance::try_from(entry).unwrap(); assert_eq!(main_fn.name(), "main"); @@ -113,7 +111,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, tcx, test_stable_mir(tcx)).unwrap(); + run!(args, test_stable_mir).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { diff --git a/tests/ui-fulldeps/stable-mir/check_instance.rs b/tests/ui-fulldeps/stable-mir/check_instance.rs index 5cb07eabf41d3..1e039e5ae514c 100644 --- a/tests/ui-fulldeps/stable-mir/check_instance.rs +++ b/tests/ui-fulldeps/stable-mir/check_instance.rs @@ -11,7 +11,6 @@ #![feature(assert_matches)] #![feature(control_flow_enum)] -extern crate rustc_middle; #[macro_use] extern crate rustc_smir; extern crate rustc_driver; @@ -19,7 +18,6 @@ extern crate rustc_interface; extern crate stable_mir; use mir::{mono::Instance, TerminatorKind::*}; -use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use stable_mir::ty::{RigidTy, TyKind}; use stable_mir::*; @@ -29,7 +27,7 @@ use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; /// This function uses the Stable MIR APIs to get information about the test crate. -fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { +fn test_stable_mir() -> ControlFlow<()> { let items = stable_mir::all_local_items(); // Get all items and split generic vs monomorphic items. @@ -96,7 +94,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, tcx, test_stable_mir(tcx)).unwrap(); + run!(args, test_stable_mir).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { diff --git a/tests/ui-fulldeps/stable-mir/check_item_kind.rs b/tests/ui-fulldeps/stable-mir/check_item_kind.rs index 72e0e09e6e363..0a7f00029f2ac 100644 --- a/tests/ui-fulldeps/stable-mir/check_item_kind.rs +++ b/tests/ui-fulldeps/stable-mir/check_item_kind.rs @@ -11,14 +11,12 @@ #![feature(assert_matches)] #![feature(control_flow_enum)] -extern crate rustc_middle; #[macro_use] extern crate rustc_smir; extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use stable_mir::*; use std::io::Write; @@ -27,7 +25,7 @@ use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; /// This function uses the Stable MIR APIs to get information about the test crate. -fn test_item_kind(_tcx: TyCtxt<'_>) -> ControlFlow<()> { +fn test_item_kind() -> ControlFlow<()> { let items = stable_mir::all_local_items(); assert_eq!(items.len(), 4); // Constructor item. @@ -59,7 +57,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, tcx, test_item_kind(tcx)).unwrap(); + run!(args, test_item_kind).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { diff --git a/tests/ui-fulldeps/stable-mir/check_ty_fold.rs b/tests/ui-fulldeps/stable-mir/check_ty_fold.rs index b90d47d4540ba..14cbf9e9f81f1 100644 --- a/tests/ui-fulldeps/stable-mir/check_ty_fold.rs +++ b/tests/ui-fulldeps/stable-mir/check_ty_fold.rs @@ -12,14 +12,12 @@ #![feature(assert_matches)] #![feature(control_flow_enum)] -extern crate rustc_middle; #[macro_use] extern crate rustc_smir; extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use stable_mir::ty::{RigidTy, TyKind, Ty, }; use stable_mir::mir::{Body, MirVisitor, FieldIdx, Place, ProjectionElem, visit::{Location, @@ -30,7 +28,7 @@ use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; /// This function uses the Stable MIR APIs to get information about the test crate. -fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { +fn test_stable_mir() -> ControlFlow<()> { let main_fn = stable_mir::entry_fn(); let body = main_fn.unwrap().body(); let mut visitor = PlaceVisitor{ body: &body, tested: false}; @@ -87,7 +85,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, tcx, test_stable_mir(tcx)).unwrap(); + run!(args, test_stable_mir).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { diff --git a/tests/ui-fulldeps/stable-mir/compilation-result.rs b/tests/ui-fulldeps/stable-mir/compilation-result.rs index fc56e24814b04..c802316c1d861 100644 --- a/tests/ui-fulldeps/stable-mir/compilation-result.rs +++ b/tests/ui-fulldeps/stable-mir/compilation-result.rs @@ -10,14 +10,12 @@ #![feature(rustc_private)] #![feature(assert_matches)] -extern crate rustc_middle; #[macro_use] extern crate rustc_smir; extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use std::io::Write; @@ -32,7 +30,8 @@ fn main() { test_continue(args.clone()); test_break(args.clone()); test_failed(args.clone()); - test_skipped(args); + test_skipped(args.clone()); + test_captured(args) } fn test_continue(args: Vec) { @@ -59,6 +58,13 @@ fn test_failed(mut args: Vec) { assert_eq!(result, Err(stable_mir::CompilerError::CompilationFailed)); } +/// Test that we are able to pass a closure and set the return according to the captured value. +fn test_captured(args: Vec) { + let captured = "10".to_string(); + let result = run!(args, ControlFlow::Continue::<(), usize>(captured.len())); + assert_eq!(result, Ok(captured.len())); +} + fn generate_input(path: &str) -> std::io::Result<()> { let mut file = std::fs::File::create(path)?; write!( diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs index c2035430a33b8..8258883436f2f 100644 --- a/tests/ui-fulldeps/stable-mir/crate-info.rs +++ b/tests/ui-fulldeps/stable-mir/crate-info.rs @@ -12,7 +12,6 @@ #![feature(control_flow_enum)] extern crate rustc_hir; -extern crate rustc_middle; #[macro_use] extern crate rustc_smir; extern crate rustc_driver; @@ -20,7 +19,6 @@ extern crate rustc_interface; extern crate stable_mir; use rustc_hir::def::DefKind; -use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use stable_mir::ItemKind; use stable_mir::crate_def::CrateDef; @@ -33,7 +31,7 @@ use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; /// This function uses the Stable MIR APIs to get information about the test crate. -fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { +fn test_stable_mir() -> ControlFlow<()> { // Get the local crate using stable_mir API. let local = stable_mir::local_crate(); assert_eq!(&local.name, CRATE_NAME); @@ -194,7 +192,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, tcx, test_stable_mir(tcx)).unwrap(); + run!(args, test_stable_mir).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { diff --git a/tests/ui-fulldeps/stable-mir/projections.rs b/tests/ui-fulldeps/stable-mir/projections.rs index 8c3fda7b6bb1f..40f2d901a2b23 100644 --- a/tests/ui-fulldeps/stable-mir/projections.rs +++ b/tests/ui-fulldeps/stable-mir/projections.rs @@ -12,14 +12,12 @@ #![feature(control_flow_enum)] extern crate rustc_hir; -extern crate rustc_middle; #[macro_use] extern crate rustc_smir; extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use stable_mir::crate_def::CrateDef; use stable_mir::mir::{ProjectionElem, Rvalue, StatementKind}; @@ -32,7 +30,7 @@ use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; /// Tests projections within Place objects -fn test_place_projections(_tcx: TyCtxt<'_>) -> ControlFlow<()> { +fn test_place_projections() -> ControlFlow<()> { let items = stable_mir::all_local_items(); let body = get_item(&items, (ItemKind::Fn, "projections")).unwrap().body(); assert_eq!(body.blocks.len(), 4); @@ -159,7 +157,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, tcx, test_place_projections(tcx)).unwrap(); + run!(args, test_place_projections).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { diff --git a/tests/ui-fulldeps/stable-mir/smir_internal.rs b/tests/ui-fulldeps/stable-mir/smir_internal.rs index b0596b1882383..63a6a5e47e8b6 100644 --- a/tests/ui-fulldeps/stable-mir/smir_internal.rs +++ b/tests/ui-fulldeps/stable-mir/smir_internal.rs @@ -16,17 +16,15 @@ extern crate rustc_smir; extern crate rustc_driver; extern crate rustc_interface; -extern crate rustc_middle; extern crate stable_mir; -use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use std::io::Write; use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; -fn test_translation(_tcx: TyCtxt<'_>) -> ControlFlow<()> { +fn test_translation() -> ControlFlow<()> { let main_fn = stable_mir::entry_fn().unwrap(); let body = main_fn.body(); let orig_ty = body.locals()[0].ty; @@ -48,7 +46,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, tcx, test_translation(tcx)).unwrap(); + run!(args, test_translation).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { diff --git a/tests/ui-fulldeps/stable-mir/smir_visitor.rs b/tests/ui-fulldeps/stable-mir/smir_visitor.rs index 027b0e7d9e85c..d7739770b706a 100644 --- a/tests/ui-fulldeps/stable-mir/smir_visitor.rs +++ b/tests/ui-fulldeps/stable-mir/smir_visitor.rs @@ -11,7 +11,6 @@ #![feature(assert_matches)] #![feature(control_flow_enum)] -extern crate rustc_middle; #[macro_use] extern crate rustc_smir; extern crate rustc_driver; @@ -19,7 +18,6 @@ extern crate rustc_interface; extern crate stable_mir; use std::collections::HashSet; -use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use stable_mir::*; use stable_mir::mir::MirVisitor; @@ -28,7 +26,7 @@ use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; -fn test_visitor(_tcx: TyCtxt<'_>) -> ControlFlow<()> { +fn test_visitor() -> ControlFlow<()> { let main_fn = stable_mir::entry_fn(); let main_body = main_fn.unwrap().body(); let main_visitor = TestVisitor::collect(&main_body); @@ -116,7 +114,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, tcx, test_visitor(tcx)).unwrap(); + run!(args, test_visitor).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { From bc3fb5245a248070b76e535be4f342e2be12a9b5 Mon Sep 17 00:00:00 2001 From: LegionMammal978 Date: Tue, 16 Jan 2024 14:58:42 -0500 Subject: [PATCH 0305/1197] Rename `pointer` field on `Pin` The internal, unstable field of `Pin` can conflict with fields from the inner type accessed via the `Deref` impl. Rename it from `pointer` to `__pointer`, to make it less likely to conflict with anything else. --- .../src/fn_ctxt/suggestions.rs | 2 +- library/core/src/pin.rs | 46 +++++++++++-------- src/etc/natvis/libcore.natvis | 4 +- ...ine_coroutine.main.Inline.panic-abort.diff | 2 +- ...ne_coroutine.main.Inline.panic-unwind.diff | 2 +- .../feature-gate-unsafe_pin_internals.rs | 2 +- tests/ui/pin-macro/cant_access_internals.rs | 2 +- .../ui/pin-macro/cant_access_internals.stderr | 4 +- 8 files changed, 35 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 81b7de7f63497..83c544a9605bd 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -2038,7 +2038,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let field_is_local = sole_field.did.is_local(); let field_is_accessible = sole_field.vis.is_accessible_from(expr.hir_id.owner.def_id, self.tcx) - // Skip suggestions for unstable public fields (for example `Pin::pointer`) + // Skip suggestions for unstable public fields (for example `Pin::__pointer`) && matches!(self.tcx.eval_stability(sole_field.did, None, expr.span, None), EvalResult::Allow | EvalResult::Unmarked); if !field_is_local && !field_is_accessible { diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index bb6c81a486a59..a0227d9130bb7 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -1092,14 +1092,20 @@ pub struct Pin { // - deter downstream users from accessing it (which would be unsound!), // - let the `pin!` macro access it (such a macro requires using struct // literal syntax in order to benefit from lifetime extension). - // Long-term, `unsafe` fields or macro hygiene are expected to offer more robust alternatives. + // + // However, if the `Deref` impl exposes a field with the same name as this + // field, then the two will collide, resulting in a confusing error when the + // user attempts to access the field through a `Pin`. Therefore, the + // name `__pointer` is designed to be unlikely to collide with any other + // field. Long-term, macro hygiene is expected to offer a more robust + // alternative, alongside `unsafe` fields. #[unstable(feature = "unsafe_pin_internals", issue = "none")] #[doc(hidden)] - pub pointer: Ptr, + pub __pointer: Ptr, } // The following implementations aren't derived in order to avoid soundness -// issues. `&self.pointer` should not be accessible to untrusted trait +// issues. `&self.__pointer` should not be accessible to untrusted trait // implementations. // // See for more details. @@ -1212,7 +1218,7 @@ impl> Pin { #[rustc_const_unstable(feature = "const_pin", issue = "76654")] #[stable(feature = "pin_into_inner", since = "1.39.0")] pub const fn into_inner(pin: Pin) -> Ptr { - pin.pointer + pin.__pointer } } @@ -1349,7 +1355,7 @@ impl Pin { #[rustc_const_unstable(feature = "const_pin", issue = "76654")] #[stable(feature = "pin", since = "1.33.0")] pub const unsafe fn new_unchecked(pointer: Ptr) -> Pin { - Pin { pointer } + Pin { __pointer: pointer } } /// Gets a shared reference to the pinned value this [`Pin`] points to. @@ -1363,7 +1369,7 @@ impl Pin { #[inline(always)] pub fn as_ref(&self) -> Pin<&Ptr::Target> { // SAFETY: see documentation on this function - unsafe { Pin::new_unchecked(&*self.pointer) } + unsafe { Pin::new_unchecked(&*self.__pointer) } } /// Unwraps this `Pin`, returning the underlying `Ptr`. @@ -1388,7 +1394,7 @@ impl Pin { #[rustc_const_unstable(feature = "const_pin", issue = "76654")] #[stable(feature = "pin_into_inner", since = "1.39.0")] pub const unsafe fn into_inner_unchecked(pin: Pin) -> Ptr { - pin.pointer + pin.__pointer } } @@ -1426,7 +1432,7 @@ impl Pin { #[inline(always)] pub fn as_mut(&mut self) -> Pin<&mut Ptr::Target> { // SAFETY: see documentation on this function - unsafe { Pin::new_unchecked(&mut *self.pointer) } + unsafe { Pin::new_unchecked(&mut *self.__pointer) } } /// Assigns a new value to the memory location pointed to by the `Pin`. @@ -1455,7 +1461,7 @@ impl Pin { where Ptr::Target: Sized, { - *(self.pointer) = value; + *(self.__pointer) = value; } } @@ -1481,7 +1487,7 @@ impl<'a, T: ?Sized> Pin<&'a T> { U: ?Sized, F: FnOnce(&T) -> &U, { - let pointer = &*self.pointer; + let pointer = &*self.__pointer; let new_pointer = func(pointer); // SAFETY: the safety contract for `new_unchecked` must be @@ -1511,7 +1517,7 @@ impl<'a, T: ?Sized> Pin<&'a T> { #[rustc_const_unstable(feature = "const_pin", issue = "76654")] #[stable(feature = "pin", since = "1.33.0")] pub const fn get_ref(self) -> &'a T { - self.pointer + self.__pointer } } @@ -1522,7 +1528,7 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { #[rustc_const_unstable(feature = "const_pin", issue = "76654")] #[stable(feature = "pin", since = "1.33.0")] pub const fn into_ref(self) -> Pin<&'a T> { - Pin { pointer: self.pointer } + Pin { __pointer: self.__pointer } } /// Gets a mutable reference to the data inside of this `Pin`. @@ -1542,7 +1548,7 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { where T: Unpin, { - self.pointer + self.__pointer } /// Gets a mutable reference to the data inside of this `Pin`. @@ -1560,7 +1566,7 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { #[stable(feature = "pin", since = "1.33.0")] #[rustc_const_unstable(feature = "const_pin", issue = "76654")] pub const unsafe fn get_unchecked_mut(self) -> &'a mut T { - self.pointer + self.__pointer } /// Construct a new pin by mapping the interior value. @@ -1684,21 +1690,21 @@ impl Receiver for Pin {} #[stable(feature = "pin", since = "1.33.0")] impl fmt::Debug for Pin { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&self.pointer, f) + fmt::Debug::fmt(&self.__pointer, f) } } #[stable(feature = "pin", since = "1.33.0")] impl fmt::Display for Pin { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&self.pointer, f) + fmt::Display::fmt(&self.__pointer, f) } } #[stable(feature = "pin", since = "1.33.0")] impl fmt::Pointer for Pin { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Pointer::fmt(&self.pointer, f) + fmt::Pointer::fmt(&self.__pointer, f) } } @@ -1941,16 +1947,16 @@ pub macro pin($value:expr $(,)?) { // instead, dropped _at the end of the enscoping block_. // For instance, // ```rust - // let p = Pin { pointer: &mut }; + // let p = Pin { __pointer: &mut }; // ``` // becomes: // ```rust // let mut anon = ; - // let p = Pin { pointer: &mut anon }; + // let p = Pin { __pointer: &mut anon }; // ``` // which is *exactly* what we want. // // See https://doc.rust-lang.org/1.58.1/reference/destructors.html#temporary-lifetime-extension // for more info. - $crate::pin::Pin::<&mut _> { pointer: &mut { $value } } + $crate::pin::Pin::<&mut _> { __pointer: &mut { $value } } } diff --git a/src/etc/natvis/libcore.natvis b/src/etc/natvis/libcore.natvis index 624d8cc5cc55a..f8569ef2594b4 100644 --- a/src/etc/natvis/libcore.natvis +++ b/src/etc/natvis/libcore.natvis @@ -99,9 +99,9 @@ - Pin({(void*)pointer}: {pointer}) + Pin({(void*)__pointer}: {__pointer}) - pointer + __pointer diff --git a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff index 8e53427e7e060..a38b8246bdef2 100644 --- a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff @@ -36,7 +36,7 @@ - _4 = g() -> [return: bb1, unwind unreachable]; + _4 = {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8 (#0)}; + _3 = &mut _4; -+ _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}> { pointer: _3 }; ++ _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}> { __pointer: _3 }; + StorageDead(_3); + StorageLive(_5); + _5 = const false; diff --git a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff index b06db41af9d40..dc6628ab44c5f 100644 --- a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff @@ -36,7 +36,7 @@ - _4 = g() -> [return: bb1, unwind continue]; + _4 = {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8 (#0)}; + _3 = &mut _4; -+ _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}> { pointer: _3 }; ++ _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}> { __pointer: _3 }; + StorageDead(_3); + StorageLive(_5); + _5 = const false; diff --git a/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.rs b/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.rs index 134ea25b75afb..594a2672d435d 100644 --- a/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.rs +++ b/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.rs @@ -7,7 +7,7 @@ use core::{marker::PhantomPinned, pin::Pin}; /// The `unsafe_pin_internals` is indeed unsound. fn non_unsafe_pin_new_unchecked(pointer: &mut T) -> Pin<&mut T> { - Pin { pointer } + Pin { __pointer: pointer } } fn main() { diff --git a/tests/ui/pin-macro/cant_access_internals.rs b/tests/ui/pin-macro/cant_access_internals.rs index 5826a18b5718b..4aeb6a643d959 100644 --- a/tests/ui/pin-macro/cant_access_internals.rs +++ b/tests/ui/pin-macro/cant_access_internals.rs @@ -8,5 +8,5 @@ use core::{ fn main() { let mut phantom_pinned = pin!(PhantomPinned); - mem::take(phantom_pinned.pointer); //~ ERROR use of unstable library feature 'unsafe_pin_internals' + mem::take(phantom_pinned.__pointer); //~ ERROR use of unstable library feature 'unsafe_pin_internals' } diff --git a/tests/ui/pin-macro/cant_access_internals.stderr b/tests/ui/pin-macro/cant_access_internals.stderr index 2737b84f5995b..444314a9d8bb3 100644 --- a/tests/ui/pin-macro/cant_access_internals.stderr +++ b/tests/ui/pin-macro/cant_access_internals.stderr @@ -1,8 +1,8 @@ error[E0658]: use of unstable library feature 'unsafe_pin_internals' --> $DIR/cant_access_internals.rs:11:15 | -LL | mem::take(phantom_pinned.pointer); - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | mem::take(phantom_pinned.__pointer); + | ^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(unsafe_pin_internals)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date From e12101c4db03b1cd35fcc288f8e6568f552ee51c Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 16 Jan 2024 21:14:39 +0100 Subject: [PATCH 0306/1197] Fix `rustc_abi` build on stable --- compiler/rustc_abi/src/lib.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index ea194e10defd6..c45a4a410f964 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -49,7 +49,14 @@ bitflags! { | ReprFlags::IS_LINEAR.bits(); } } -rustc_data_structures::external_bitflags_debug! { ReprFlags } + +// This is the same as `rustc_data_structures::external_bitflags_debug` but without the +// `rustc_data_structures` to make it build on stable. +impl std::fmt::Debug for ReprFlags { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + bitflags::parser::to_writer(self, f) + } +} #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))] From ee007ab187dc3eb9587a787d1029c539d54710b0 Mon Sep 17 00:00:00 2001 From: novafacing Date: Tue, 16 Jan 2024 13:27:58 -0800 Subject: [PATCH 0307/1197] proc_macro_c_str_literals: Implement Literal::c_string constructor --- library/proc_macro/src/lib.rs | 8 ++++++++ .../feature-gate-proc_macro_c_str_literals.rs | 11 +++++++++++ .../feature-gate-proc_macro_c_str_literals.stderr | 13 +++++++++++++ tests/ui/proc-macro/auxiliary/api/mod.rs | 2 ++ tests/ui/proc-macro/auxiliary/api/parse.rs | 7 +++---- tests/ui/proc-macro/test.rs | 1 + 6 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 tests/ui/feature-gates/feature-gate-proc_macro_c_str_literals.rs create mode 100644 tests/ui/feature-gates/feature-gate-proc_macro_c_str_literals.stderr diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 6e664a162df92..ca83e2be5c147 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -45,6 +45,7 @@ mod diagnostic; #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] pub use diagnostic::{Diagnostic, Level, MultiSpan}; +use std::ffi::CStr; use std::ops::{Range, RangeBounds}; use std::path::PathBuf; use std::str::FromStr; @@ -1351,6 +1352,13 @@ impl Literal { Literal::new(bridge::LitKind::ByteStr, &string, None) } + /// C string literal. + #[unstable(feature = "proc_macro_c_str_literals", issue = "119750")] + pub fn c_string(string: &CStr) -> Literal { + let string = string.to_bytes().escape_ascii().to_string(); + Literal::new(bridge::LitKind::CStr, &string, None) + } + /// Returns the span encompassing this literal. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn span(&self) -> Span { diff --git a/tests/ui/feature-gates/feature-gate-proc_macro_c_str_literals.rs b/tests/ui/feature-gates/feature-gate-proc_macro_c_str_literals.rs new file mode 100644 index 0000000000000..5554c81392553 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-proc_macro_c_str_literals.rs @@ -0,0 +1,11 @@ +// edition: 2021 +// force-host +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +use proc_macro::Literal; + +fn test() { + Literal::c_string(c"a"); //~ ERROR use of unstable library feature 'proc_macro_c_str_literals' +} diff --git a/tests/ui/feature-gates/feature-gate-proc_macro_c_str_literals.stderr b/tests/ui/feature-gates/feature-gate-proc_macro_c_str_literals.stderr new file mode 100644 index 0000000000000..9bba1d50ce362 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-proc_macro_c_str_literals.stderr @@ -0,0 +1,13 @@ +error[E0658]: use of unstable library feature 'proc_macro_c_str_literals' + --> $DIR/feature-gate-proc_macro_c_str_literals.rs:10:5 + | +LL | Literal::c_string(c"a"); + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #119750 for more information + = help: add `#![feature(proc_macro_c_str_literals)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/proc-macro/auxiliary/api/mod.rs b/tests/ui/proc-macro/auxiliary/api/mod.rs index 3bea5d75779aa..5a533b9e17e16 100644 --- a/tests/ui/proc-macro/auxiliary/api/mod.rs +++ b/tests/ui/proc-macro/auxiliary/api/mod.rs @@ -1,10 +1,12 @@ // force-host // no-prefer-dynamic +// edition: 2021 #![crate_type = "proc-macro"] #![crate_name = "proc_macro_api_tests"] #![feature(proc_macro_span)] #![feature(proc_macro_byte_character)] +#![feature(proc_macro_c_str_literals)] #![deny(dead_code)] // catch if a test function is never called extern crate proc_macro; diff --git a/tests/ui/proc-macro/auxiliary/api/parse.rs b/tests/ui/proc-macro/auxiliary/api/parse.rs index 07c9f464961ae..801c616c80404 100644 --- a/tests/ui/proc-macro/auxiliary/api/parse.rs +++ b/tests/ui/proc-macro/auxiliary/api/parse.rs @@ -19,10 +19,8 @@ fn test_display_literal() { "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0", ); - assert_eq!( - Literal::string("a \t ❤ ' \" \u{1}").to_string(), - "\"a \\t ❤ ' \\\" \\u{1}\"", - ); + assert_eq!(Literal::string("a \t ❤ ' \" \u{1}").to_string(), "\"a \\t ❤ ' \\\" \\u{1}\"",); + assert_eq!(Literal::c_string(c"\'\"\x7f\u{7fff}").to_string(), r#"c"\'\"\x7f\xe7\xbf\xbf""#); assert_eq!(Literal::character('a').to_string(), "'a'"); assert_eq!(Literal::character('\t').to_string(), "'\\t'"); assert_eq!(Literal::character('❤').to_string(), "'❤'"); @@ -41,6 +39,7 @@ fn test_parse_literal() { assert_eq!("b'a'".parse::().unwrap().to_string(), "b'a'"); assert_eq!("\"\n\"".parse::().unwrap().to_string(), "\"\n\""); assert_eq!("b\"\"".parse::().unwrap().to_string(), "b\"\""); + assert_eq!("c\"\"".parse::().unwrap().to_string(), "c\"\""); assert_eq!("r##\"\"##".parse::().unwrap().to_string(), "r##\"\"##"); assert_eq!("10ulong".parse::().unwrap().to_string(), "10ulong"); assert_eq!("-10ulong".parse::().unwrap().to_string(), "-10ulong"); diff --git a/tests/ui/proc-macro/test.rs b/tests/ui/proc-macro/test.rs index c96aa73175f2c..2ec620720202b 100644 --- a/tests/ui/proc-macro/test.rs +++ b/tests/ui/proc-macro/test.rs @@ -1,5 +1,6 @@ // check-pass // aux-build:api/mod.rs +// edition: 2021 //! This is for everything that *would* be a #[test] inside of libproc_macro, //! except for the fact that proc_macro objects are not capable of existing From 666030c51b87509a065867f99bf7317a5486470a Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 20 Mar 2023 21:37:36 +0000 Subject: [PATCH 0308/1197] Simplify binary ops. --- compiler/rustc_mir_transform/src/gvn.rs | 111 +++++- .../mir-opt/const_prop/boolean_identities.rs | 7 +- .../boolean_identities.test.GVN.diff | 12 +- .../boxes.main.GVN.panic-abort.diff | 9 +- .../boxes.main.GVN.panic-unwind.diff | 9 +- tests/mir-opt/const_prop/boxes.rs | 2 +- tests/mir-opt/const_prop/mult_by_zero.rs | 3 +- .../const_prop/mult_by_zero.test.GVN.diff | 2 +- .../gvn.arithmetic.GVN.panic-abort.diff | 357 +++++++++++------- .../gvn.arithmetic.GVN.panic-unwind.diff | 357 +++++++++++------- ...vn.arithmetic_checked.GVN.panic-abort.diff | 101 +++-- ...n.arithmetic_checked.GVN.panic-unwind.diff | 101 +++-- .../gvn.comparison.GVN.panic-abort.diff | 10 +- .../gvn.comparison.GVN.panic-unwind.diff | 10 +- .../gvn.fn_pointers.GVN.panic-abort.diff | 18 +- .../gvn.fn_pointers.GVN.panic-unwind.diff | 18 +- tests/mir-opt/gvn.rs | 78 ++-- .../issue_101973.inner.GVN.panic-abort.diff | 17 +- .../issue_101973.inner.GVN.panic-unwind.diff | 17 +- 19 files changed, 808 insertions(+), 431 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index dc3af038d807b..3052369c3ca48 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -345,11 +345,20 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { Some(self.insert(Value::Constant { value, disambiguator })) } + fn insert_bool(&mut self, flag: bool) -> VnIndex { + // Booleans are deterministic. + self.insert(Value::Constant { value: Const::from_bool(self.tcx, flag), disambiguator: 0 }) + } + fn insert_scalar(&mut self, scalar: Scalar, ty: Ty<'tcx>) -> VnIndex { self.insert_constant(Const::from_scalar(self.tcx, scalar, ty)) .expect("scalars are deterministic") } + fn insert_tuple(&mut self, values: Vec) -> VnIndex { + self.insert(Value::Aggregate(AggregateTy::Tuple, VariantIdx::from_u32(0), values)) + } + #[instrument(level = "trace", skip(self), ret)] fn eval_to_const(&mut self, value: VnIndex) -> Option> { use Value::*; @@ -785,14 +794,26 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { Value::Cast { kind, value, from, to } } Rvalue::BinaryOp(op, box (ref mut lhs, ref mut rhs)) => { + let ty = lhs.ty(self.local_decls, self.tcx); let lhs = self.simplify_operand(lhs, location); let rhs = self.simplify_operand(rhs, location); - Value::BinaryOp(op, lhs?, rhs?) + let lhs = lhs?; + let rhs = rhs?; + if let Some(value) = self.simplify_binary(op, false, ty, lhs, rhs) { + return Some(value); + } + Value::BinaryOp(op, lhs, rhs) } Rvalue::CheckedBinaryOp(op, box (ref mut lhs, ref mut rhs)) => { + let ty = lhs.ty(self.local_decls, self.tcx); let lhs = self.simplify_operand(lhs, location); let rhs = self.simplify_operand(rhs, location); - Value::CheckedBinaryOp(op, lhs?, rhs?) + let lhs = lhs?; + let rhs = rhs?; + if let Some(value) = self.simplify_binary(op, true, ty, lhs, rhs) { + return Some(value); + } + Value::CheckedBinaryOp(op, lhs, rhs) } Rvalue::UnaryOp(op, ref mut arg) => { let arg = self.simplify_operand(arg, location)?; @@ -894,6 +915,92 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { Some(self.insert(Value::Aggregate(ty, variant_index, fields))) } + + #[instrument(level = "trace", skip(self), ret)] + fn simplify_binary( + &mut self, + op: BinOp, + checked: bool, + lhs_ty: Ty<'tcx>, + lhs: VnIndex, + rhs: VnIndex, + ) -> Option { + // Floats are weird enough that none of the logic below applies. + let reasonable_ty = + lhs_ty.is_integral() || lhs_ty.is_bool() || lhs_ty.is_char() || lhs_ty.is_any_ptr(); + if !reasonable_ty { + return None; + } + + let layout = self.ecx.layout_of(lhs_ty).ok()?; + + let as_bits = |value| { + let constant = self.evaluated[value].as_ref()?; + let scalar = self.ecx.read_scalar(constant).ok()?; + scalar.to_bits(constant.layout.size).ok() + }; + + // Represent the values as `Ok(bits)` or `Err(VnIndex)`. + let a = as_bits(lhs).ok_or(lhs); + let b = as_bits(rhs).ok_or(rhs); + let result = match (op, a, b) { + // Neutral elements. + (BinOp::Add | BinOp::BitOr | BinOp::BitXor, Ok(0), Err(p)) + | ( + BinOp::Add + | BinOp::BitOr + | BinOp::BitXor + | BinOp::Sub + | BinOp::Offset + | BinOp::Shl + | BinOp::Shr, + Err(p), + Ok(0), + ) + | (BinOp::Mul, Ok(1), Err(p)) + | (BinOp::Mul | BinOp::Div, Err(p), Ok(1)) => p, + // Attempt to simplify `x & ALL_ONES` to `x`, with `ALL_ONES` depending on type size. + (BinOp::BitAnd, Err(p), Ok(ones)) | (BinOp::BitAnd, Ok(ones), Err(p)) + if ones == layout.size.truncate(u128::MAX) + || (layout.ty.is_bool() && ones == 1) => + { + p + } + // Absorbing elements. + (BinOp::Mul | BinOp::BitAnd, _, Ok(0)) + | (BinOp::Rem, _, Ok(1)) + | ( + BinOp::Mul | BinOp::Div | BinOp::Rem | BinOp::BitAnd | BinOp::Shl | BinOp::Shr, + Ok(0), + _, + ) => self.insert_scalar(Scalar::from_uint(0u128, layout.size), lhs_ty), + // Attempt to simplify `x | ALL_ONES` to `ALL_ONES`. + (BinOp::BitOr, _, Ok(ones)) | (BinOp::BitOr, Ok(ones), _) + if ones == layout.size.truncate(u128::MAX) + || (layout.ty.is_bool() && ones == 1) => + { + self.insert_scalar(Scalar::from_uint(ones, layout.size), lhs_ty) + } + // Sub/Xor with itself. + (BinOp::Sub | BinOp::BitXor, a, b) if a == b => { + self.insert_scalar(Scalar::from_uint(0u128, layout.size), lhs_ty) + } + // Comparison: + // - if both operands can be computed as bits, just compare the bits; + // - if we proved that both operands have the same value, we can insert true/false; + // - otherwise, do nothing, as we do not try to prove inequality. + (BinOp::Eq, a, b) if (a.is_ok() && b.is_ok()) || a == b => self.insert_bool(a == b), + (BinOp::Ne, a, b) if (a.is_ok() && b.is_ok()) || a == b => self.insert_bool(a != b), + _ => return None, + }; + + if checked { + let false_val = self.insert_bool(false); + Some(self.insert_tuple(vec![result, false_val])) + } else { + Some(result) + } + } } fn op_to_prop_const<'tcx>( diff --git a/tests/mir-opt/const_prop/boolean_identities.rs b/tests/mir-opt/const_prop/boolean_identities.rs index f6575ac8e5474..3b7ea25ad46eb 100644 --- a/tests/mir-opt/const_prop/boolean_identities.rs +++ b/tests/mir-opt/const_prop/boolean_identities.rs @@ -5,10 +5,9 @@ pub fn test(x: bool, y: bool) -> bool { // CHECK-LABEL: fn test( // CHECK: debug a => [[a:_.*]]; // CHECK: debug b => [[b:_.*]]; - // FIXME(cjgillot) simplify algebraic identity - // CHECK-NOT: [[a]] = const true; - // CHECK-NOT: [[b]] = const false; - // CHECK-NOT: _0 = const false; + // CHECK: [[a]] = const true; + // CHECK: [[b]] = const false; + // CHECK: _0 = const false; let a = (y | true); let b = (x & false); a & b diff --git a/tests/mir-opt/const_prop/boolean_identities.test.GVN.diff b/tests/mir-opt/const_prop/boolean_identities.test.GVN.diff index eca87af752725..0bd8413289e63 100644 --- a/tests/mir-opt/const_prop/boolean_identities.test.GVN.diff +++ b/tests/mir-opt/const_prop/boolean_identities.test.GVN.diff @@ -24,21 +24,23 @@ StorageLive(_4); _4 = _2; - _3 = BitOr(move _4, const true); -+ _3 = BitOr(_2, const true); ++ _3 = const true; StorageDead(_4); - StorageLive(_5); + nop; StorageLive(_6); _6 = _1; - _5 = BitAnd(move _6, const false); -+ _5 = BitAnd(_1, const false); ++ _5 = const false; StorageDead(_6); StorageLive(_7); - _7 = _3; +- _7 = _3; ++ _7 = const true; StorageLive(_8); - _8 = _5; +- _8 = _5; - _0 = BitAnd(move _7, move _8); -+ _0 = BitAnd(_3, _5); ++ _8 = const false; ++ _0 = const false; StorageDead(_8); StorageDead(_7); - StorageDead(_5); diff --git a/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff b/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff index b3fdaa5ee8257..59ee38f5a2b94 100644 --- a/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff +++ b/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff @@ -20,7 +20,8 @@ bb0: { StorageLive(_1); - StorageLive(_2); +- StorageLive(_2); ++ nop; StorageLive(_3); - _4 = SizeOf(i32); - _5 = AlignOf(i32); @@ -39,8 +40,10 @@ StorageDead(_7); _9 = (((_3.0: std::ptr::Unique).0: std::ptr::NonNull).0: *const i32); _2 = (*_9); - _1 = Add(move _2, const 0_i32); - StorageDead(_2); +- _1 = Add(move _2, const 0_i32); +- StorageDead(_2); ++ _1 = _2; ++ nop; drop(_3) -> [return: bb2, unwind unreachable]; } diff --git a/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff index d0350c97253a2..9d87bd809d1f3 100644 --- a/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff +++ b/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff @@ -20,7 +20,8 @@ bb0: { StorageLive(_1); - StorageLive(_2); +- StorageLive(_2); ++ nop; StorageLive(_3); - _4 = SizeOf(i32); - _5 = AlignOf(i32); @@ -39,8 +40,10 @@ StorageDead(_7); _9 = (((_3.0: std::ptr::Unique).0: std::ptr::NonNull).0: *const i32); _2 = (*_9); - _1 = Add(move _2, const 0_i32); - StorageDead(_2); +- _1 = Add(move _2, const 0_i32); +- StorageDead(_2); ++ _1 = _2; ++ nop; drop(_3) -> [return: bb2, unwind: bb3]; } diff --git a/tests/mir-opt/const_prop/boxes.rs b/tests/mir-opt/const_prop/boxes.rs index 5227d7b8b8bad..d2d61f86d5eb4 100644 --- a/tests/mir-opt/const_prop/boxes.rs +++ b/tests/mir-opt/const_prop/boxes.rs @@ -12,7 +12,7 @@ fn main() { // CHECK: debug x => [[x:_.*]]; // CHECK: (*{{_.*}}) = const 42_i32; // CHECK: [[tmp:_.*]] = (*{{_.*}}); - // CHECK: [[x]] = Add(move [[tmp]], const 0_i32); + // CHECK: [[x]] = [[tmp]]; let x = *(#[rustc_box] Box::new(42)) + 0; diff --git a/tests/mir-opt/const_prop/mult_by_zero.rs b/tests/mir-opt/const_prop/mult_by_zero.rs index 2fdb75c3100e9..b8afaeef43fd7 100644 --- a/tests/mir-opt/const_prop/mult_by_zero.rs +++ b/tests/mir-opt/const_prop/mult_by_zero.rs @@ -3,8 +3,7 @@ // EMIT_MIR mult_by_zero.test.GVN.diff fn test(x: i32) -> i32 { // CHECK: fn test( - // FIXME(cjgillot) simplify algebraic identity - // CHECK-NOT: _0 = const 0_i32; + // CHECK: _0 = const 0_i32; x * 0 } diff --git a/tests/mir-opt/const_prop/mult_by_zero.test.GVN.diff b/tests/mir-opt/const_prop/mult_by_zero.test.GVN.diff index e9fb34749c104..6c2aab45d48b5 100644 --- a/tests/mir-opt/const_prop/mult_by_zero.test.GVN.diff +++ b/tests/mir-opt/const_prop/mult_by_zero.test.GVN.diff @@ -10,7 +10,7 @@ StorageLive(_2); _2 = _1; - _0 = Mul(move _2, const 0_i32); -+ _0 = Mul(_1, const 0_i32); ++ _0 = const 0_i32; StorageDead(_2); return; } diff --git a/tests/mir-opt/gvn.arithmetic.GVN.panic-abort.diff b/tests/mir-opt/gvn.arithmetic.GVN.panic-abort.diff index d524ad242fecc..84eb6c5cfe8d4 100644 --- a/tests/mir-opt/gvn.arithmetic.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.arithmetic.GVN.panic-abort.diff @@ -13,13 +13,13 @@ let _8: (); let mut _9: u64; let mut _10: u64; - let _11: (); - let mut _12: u64; + let mut _11: u64; + let _12: (); let mut _13: u64; - let _14: (); - let mut _15: u64; + let mut _14: u64; + let _15: (); let mut _16: u64; - let mut _17: bool; + let mut _17: u64; let _18: (); let mut _19: u64; let mut _20: u64; @@ -51,18 +51,32 @@ let _46: (); let mut _47: u64; let mut _48: u64; - let _49: (); - let mut _50: u64; + let mut _49: bool; + let _50: (); let mut _51: u64; - let _52: (); - let mut _53: u64; + let mut _52: u64; + let _53: (); let mut _54: u64; - let _55: (); - let mut _56: u64; + let mut _55: u64; + let _56: (); let mut _57: u64; - let _58: (); - let mut _59: u64; + let mut _58: u64; + let _59: (); let mut _60: u64; + let mut _61: u64; + let _62: (); + let mut _63: u64; + let mut _64: u64; + let _65: (); + let mut _66: u64; + let mut _67: u64; + let mut _68: u64; + let _69: (); + let mut _70: u64; + let mut _71: u64; + let _72: (); + let mut _73: u64; + let mut _74: u64; bb0: { StorageLive(_2); @@ -70,9 +84,10 @@ StorageLive(_4); _4 = _1; - _3 = Add(move _4, const 0_u64); -+ _3 = Add(_1, const 0_u64); ++ _3 = _1; StorageDead(_4); - _2 = opaque::(move _3) -> [return: bb1, unwind unreachable]; +- _2 = opaque::(move _3) -> [return: bb1, unwind unreachable]; ++ _2 = opaque::(_1) -> [return: bb1, unwind unreachable]; } bb1: { @@ -83,98 +98,101 @@ StorageLive(_7); _7 = _1; - _6 = Sub(move _7, const 0_u64); -+ _6 = Sub(_1, const 0_u64); ++ _6 = _1; StorageDead(_7); - _5 = opaque::(move _6) -> [return: bb2, unwind unreachable]; +- _5 = opaque::(move _6) -> [return: bb2, unwind unreachable]; ++ _5 = opaque::(_1) -> [return: bb2, unwind unreachable]; } bb2: { StorageDead(_6); StorageDead(_5); StorageLive(_8); - StorageLive(_9); +- StorageLive(_9); ++ nop; StorageLive(_10); _10 = _1; -- _9 = Mul(move _10, const 0_u64); -+ _9 = Mul(_1, const 0_u64); + StorageLive(_11); + _11 = _1; +- _9 = Sub(move _10, move _11); ++ _9 = const 0_u64; + StorageDead(_11); StorageDead(_10); - _8 = opaque::(move _9) -> [return: bb3, unwind unreachable]; +- _8 = opaque::(move _9) -> [return: bb3, unwind unreachable]; ++ _8 = opaque::(const 0_u64) -> [return: bb3, unwind unreachable]; } bb3: { - StorageDead(_9); +- StorageDead(_9); ++ nop; StorageDead(_8); - StorageLive(_11); StorageLive(_12); StorageLive(_13); - _13 = _1; -- _12 = Mul(move _13, const 1_u64); -+ _12 = Mul(_1, const 1_u64); - StorageDead(_13); - _11 = opaque::(move _12) -> [return: bb4, unwind unreachable]; + StorageLive(_14); + _14 = _1; +- _13 = Mul(move _14, const 0_u64); ++ _13 = const 0_u64; + StorageDead(_14); +- _12 = opaque::(move _13) -> [return: bb4, unwind unreachable]; ++ _12 = opaque::(const 0_u64) -> [return: bb4, unwind unreachable]; } bb4: { + StorageDead(_13); StorageDead(_12); - StorageDead(_11); - StorageLive(_14); StorageLive(_15); StorageLive(_16); - _16 = _1; -- _17 = Eq(const 0_u64, const 0_u64); -- assert(!move _17, "attempt to divide `{}` by zero", _16) -> [success: bb5, unwind unreachable]; -+ _17 = const true; -+ assert(!const true, "attempt to divide `{}` by zero", _1) -> [success: bb5, unwind unreachable]; + StorageLive(_17); + _17 = _1; +- _16 = Mul(move _17, const 1_u64); ++ _16 = _1; + StorageDead(_17); +- _15 = opaque::(move _16) -> [return: bb5, unwind unreachable]; ++ _15 = opaque::(_1) -> [return: bb5, unwind unreachable]; } bb5: { -- _15 = Div(move _16, const 0_u64); -+ _15 = Div(_1, const 0_u64); StorageDead(_16); - _14 = opaque::(move _15) -> [return: bb6, unwind unreachable]; - } - - bb6: { StorageDead(_15); - StorageDead(_14); StorageLive(_18); StorageLive(_19); StorageLive(_20); _20 = _1; -- _21 = Eq(const 1_u64, const 0_u64); -- assert(!move _21, "attempt to divide `{}` by zero", _20) -> [success: bb7, unwind unreachable]; -+ _21 = const false; -+ assert(!const false, "attempt to divide `{}` by zero", _1) -> [success: bb7, unwind unreachable]; +- _21 = Eq(const 0_u64, const 0_u64); +- assert(!move _21, "attempt to divide `{}` by zero", _20) -> [success: bb6, unwind unreachable]; ++ _21 = const true; ++ assert(!const true, "attempt to divide `{}` by zero", _1) -> [success: bb6, unwind unreachable]; } - bb7: { -- _19 = Div(move _20, const 1_u64); -+ _19 = Div(_1, const 1_u64); + bb6: { +- _19 = Div(move _20, const 0_u64); ++ _19 = Div(_1, const 0_u64); StorageDead(_20); - _18 = opaque::(move _19) -> [return: bb8, unwind unreachable]; + _18 = opaque::(move _19) -> [return: bb7, unwind unreachable]; } - bb8: { + bb7: { StorageDead(_19); StorageDead(_18); StorageLive(_22); StorageLive(_23); StorageLive(_24); _24 = _1; -- _25 = Eq(_24, const 0_u64); -- assert(!move _25, "attempt to divide `{}` by zero", const 0_u64) -> [success: bb9, unwind unreachable]; -+ _25 = Eq(_1, const 0_u64); -+ assert(!_25, "attempt to divide `{}` by zero", const 0_u64) -> [success: bb9, unwind unreachable]; +- _25 = Eq(const 1_u64, const 0_u64); +- assert(!move _25, "attempt to divide `{}` by zero", _24) -> [success: bb8, unwind unreachable]; ++ _25 = const false; ++ assert(!const false, "attempt to divide `{}` by zero", _1) -> [success: bb8, unwind unreachable]; } - bb9: { -- _23 = Div(const 0_u64, move _24); -+ _23 = Div(const 0_u64, _1); + bb8: { +- _23 = Div(move _24, const 1_u64); ++ _23 = _1; StorageDead(_24); - _22 = opaque::(move _23) -> [return: bb10, unwind unreachable]; +- _22 = opaque::(move _23) -> [return: bb9, unwind unreachable]; ++ _22 = opaque::(_1) -> [return: bb9, unwind unreachable]; } - bb10: { + bb9: { StorageDead(_23); StorageDead(_22); StorageLive(_26); @@ -182,79 +200,81 @@ StorageLive(_28); _28 = _1; - _29 = Eq(_28, const 0_u64); -- assert(!move _29, "attempt to divide `{}` by zero", const 1_u64) -> [success: bb11, unwind unreachable]; -+ _29 = _25; -+ assert(!_25, "attempt to divide `{}` by zero", const 1_u64) -> [success: bb11, unwind unreachable]; +- assert(!move _29, "attempt to divide `{}` by zero", const 0_u64) -> [success: bb10, unwind unreachable]; ++ _29 = Eq(_1, const 0_u64); ++ assert(!_29, "attempt to divide `{}` by zero", const 0_u64) -> [success: bb10, unwind unreachable]; } - bb11: { -- _27 = Div(const 1_u64, move _28); -+ _27 = Div(const 1_u64, _1); + bb10: { +- _27 = Div(const 0_u64, move _28); ++ _27 = const 0_u64; StorageDead(_28); - _26 = opaque::(move _27) -> [return: bb12, unwind unreachable]; +- _26 = opaque::(move _27) -> [return: bb11, unwind unreachable]; ++ _26 = opaque::(const 0_u64) -> [return: bb11, unwind unreachable]; } - bb12: { + bb11: { StorageDead(_27); StorageDead(_26); StorageLive(_30); StorageLive(_31); StorageLive(_32); _32 = _1; -- _33 = Eq(const 0_u64, const 0_u64); -- assert(!move _33, "attempt to calculate the remainder of `{}` with a divisor of zero", _32) -> [success: bb13, unwind unreachable]; -+ _33 = const true; -+ assert(!const true, "attempt to calculate the remainder of `{}` with a divisor of zero", _1) -> [success: bb13, unwind unreachable]; +- _33 = Eq(_32, const 0_u64); +- assert(!move _33, "attempt to divide `{}` by zero", const 1_u64) -> [success: bb12, unwind unreachable]; ++ _33 = _29; ++ assert(!_29, "attempt to divide `{}` by zero", const 1_u64) -> [success: bb12, unwind unreachable]; } - bb13: { -- _31 = Rem(move _32, const 0_u64); -+ _31 = Rem(_1, const 0_u64); + bb12: { +- _31 = Div(const 1_u64, move _32); ++ _31 = Div(const 1_u64, _1); StorageDead(_32); - _30 = opaque::(move _31) -> [return: bb14, unwind unreachable]; + _30 = opaque::(move _31) -> [return: bb13, unwind unreachable]; } - bb14: { + bb13: { StorageDead(_31); StorageDead(_30); StorageLive(_34); StorageLive(_35); StorageLive(_36); _36 = _1; -- _37 = Eq(const 1_u64, const 0_u64); -- assert(!move _37, "attempt to calculate the remainder of `{}` with a divisor of zero", _36) -> [success: bb15, unwind unreachable]; -+ _37 = const false; -+ assert(!const false, "attempt to calculate the remainder of `{}` with a divisor of zero", _1) -> [success: bb15, unwind unreachable]; +- _37 = Eq(const 0_u64, const 0_u64); +- assert(!move _37, "attempt to calculate the remainder of `{}` with a divisor of zero", _36) -> [success: bb14, unwind unreachable]; ++ _37 = const true; ++ assert(!const true, "attempt to calculate the remainder of `{}` with a divisor of zero", _1) -> [success: bb14, unwind unreachable]; } - bb15: { -- _35 = Rem(move _36, const 1_u64); -+ _35 = Rem(_1, const 1_u64); + bb14: { +- _35 = Rem(move _36, const 0_u64); ++ _35 = Rem(_1, const 0_u64); StorageDead(_36); - _34 = opaque::(move _35) -> [return: bb16, unwind unreachable]; + _34 = opaque::(move _35) -> [return: bb15, unwind unreachable]; } - bb16: { + bb15: { StorageDead(_35); StorageDead(_34); StorageLive(_38); StorageLive(_39); StorageLive(_40); _40 = _1; -- _41 = Eq(_40, const 0_u64); -- assert(!move _41, "attempt to calculate the remainder of `{}` with a divisor of zero", const 0_u64) -> [success: bb17, unwind unreachable]; -+ _41 = _25; -+ assert(!_25, "attempt to calculate the remainder of `{}` with a divisor of zero", const 0_u64) -> [success: bb17, unwind unreachable]; +- _41 = Eq(const 1_u64, const 0_u64); +- assert(!move _41, "attempt to calculate the remainder of `{}` with a divisor of zero", _40) -> [success: bb16, unwind unreachable]; ++ _41 = const false; ++ assert(!const false, "attempt to calculate the remainder of `{}` with a divisor of zero", _1) -> [success: bb16, unwind unreachable]; } - bb17: { -- _39 = Rem(const 0_u64, move _40); -+ _39 = Rem(const 0_u64, _1); + bb16: { +- _39 = Rem(move _40, const 1_u64); ++ _39 = const 0_u64; StorageDead(_40); - _38 = opaque::(move _39) -> [return: bb18, unwind unreachable]; +- _38 = opaque::(move _39) -> [return: bb17, unwind unreachable]; ++ _38 = opaque::(const 0_u64) -> [return: bb17, unwind unreachable]; } - bb18: { + bb17: { StorageDead(_39); StorageDead(_38); StorageLive(_42); @@ -262,27 +282,35 @@ StorageLive(_44); _44 = _1; - _45 = Eq(_44, const 0_u64); -- assert(!move _45, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_u64) -> [success: bb19, unwind unreachable]; -+ _45 = _25; -+ assert(!_25, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_u64) -> [success: bb19, unwind unreachable]; +- assert(!move _45, "attempt to calculate the remainder of `{}` with a divisor of zero", const 0_u64) -> [success: bb18, unwind unreachable]; ++ _45 = _29; ++ assert(!_29, "attempt to calculate the remainder of `{}` with a divisor of zero", const 0_u64) -> [success: bb18, unwind unreachable]; } - bb19: { -- _43 = Rem(const 1_u64, move _44); -+ _43 = Rem(const 1_u64, _1); + bb18: { +- _43 = Rem(const 0_u64, move _44); ++ _43 = const 0_u64; StorageDead(_44); - _42 = opaque::(move _43) -> [return: bb20, unwind unreachable]; +- _42 = opaque::(move _43) -> [return: bb19, unwind unreachable]; ++ _42 = opaque::(const 0_u64) -> [return: bb19, unwind unreachable]; } - bb20: { + bb19: { StorageDead(_43); StorageDead(_42); StorageLive(_46); StorageLive(_47); StorageLive(_48); _48 = _1; -- _47 = BitAnd(move _48, const 0_u64); -+ _47 = BitAnd(_1, const 0_u64); +- _49 = Eq(_48, const 0_u64); +- assert(!move _49, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_u64) -> [success: bb20, unwind unreachable]; ++ _49 = _29; ++ assert(!_29, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_u64) -> [success: bb20, unwind unreachable]; + } + + bb20: { +- _47 = Rem(const 1_u64, move _48); ++ _47 = Rem(const 1_u64, _1); StorageDead(_48); _46 = opaque::(move _47) -> [return: bb21, unwind unreachable]; } @@ -290,58 +318,121 @@ bb21: { StorageDead(_47); StorageDead(_46); - StorageLive(_49); StorageLive(_50); StorageLive(_51); - _51 = _1; -- _50 = BitOr(move _51, const 0_u64); -+ _50 = BitOr(_1, const 0_u64); - StorageDead(_51); - _49 = opaque::(move _50) -> [return: bb22, unwind unreachable]; + StorageLive(_52); + _52 = _1; +- _51 = BitAnd(move _52, const 0_u64); ++ _51 = const 0_u64; + StorageDead(_52); +- _50 = opaque::(move _51) -> [return: bb22, unwind unreachable]; ++ _50 = opaque::(const 0_u64) -> [return: bb22, unwind unreachable]; } bb22: { + StorageDead(_51); StorageDead(_50); - StorageDead(_49); - StorageLive(_52); StorageLive(_53); StorageLive(_54); - _54 = _1; -- _53 = BitXor(move _54, const 0_u64); -+ _53 = BitXor(_1, const 0_u64); - StorageDead(_54); - _52 = opaque::(move _53) -> [return: bb23, unwind unreachable]; + StorageLive(_55); + _55 = _1; +- _54 = BitAnd(move _55, const _); ++ _54 = _1; + StorageDead(_55); +- _53 = opaque::(move _54) -> [return: bb23, unwind unreachable]; ++ _53 = opaque::(_1) -> [return: bb23, unwind unreachable]; } bb23: { + StorageDead(_54); StorageDead(_53); - StorageDead(_52); - StorageLive(_55); StorageLive(_56); StorageLive(_57); - _57 = _1; -- _56 = Shr(move _57, const 0_i32); -+ _56 = Shr(_1, const 0_i32); - StorageDead(_57); - _55 = opaque::(move _56) -> [return: bb24, unwind unreachable]; + StorageLive(_58); + _58 = _1; +- _57 = BitOr(move _58, const 0_u64); ++ _57 = _1; + StorageDead(_58); +- _56 = opaque::(move _57) -> [return: bb24, unwind unreachable]; ++ _56 = opaque::(_1) -> [return: bb24, unwind unreachable]; } bb24: { + StorageDead(_57); StorageDead(_56); - StorageDead(_55); - StorageLive(_58); StorageLive(_59); StorageLive(_60); - _60 = _1; -- _59 = Shl(move _60, const 0_i32); -+ _59 = Shl(_1, const 0_i32); - StorageDead(_60); - _58 = opaque::(move _59) -> [return: bb25, unwind unreachable]; + StorageLive(_61); + _61 = _1; +- _60 = BitOr(move _61, const _); ++ _60 = const u64::MAX; + StorageDead(_61); +- _59 = opaque::(move _60) -> [return: bb25, unwind unreachable]; ++ _59 = opaque::(const u64::MAX) -> [return: bb25, unwind unreachable]; } bb25: { + StorageDead(_60); StorageDead(_59); - StorageDead(_58); + StorageLive(_62); + StorageLive(_63); + StorageLive(_64); + _64 = _1; +- _63 = BitXor(move _64, const 0_u64); ++ _63 = _1; + StorageDead(_64); +- _62 = opaque::(move _63) -> [return: bb26, unwind unreachable]; ++ _62 = opaque::(_1) -> [return: bb26, unwind unreachable]; + } + + bb26: { + StorageDead(_63); + StorageDead(_62); + StorageLive(_65); + StorageLive(_66); + StorageLive(_67); + _67 = _1; + StorageLive(_68); + _68 = _1; +- _66 = BitXor(move _67, move _68); ++ _66 = const 0_u64; + StorageDead(_68); + StorageDead(_67); +- _65 = opaque::(move _66) -> [return: bb27, unwind unreachable]; ++ _65 = opaque::(const 0_u64) -> [return: bb27, unwind unreachable]; + } + + bb27: { + StorageDead(_66); + StorageDead(_65); + StorageLive(_69); + StorageLive(_70); + StorageLive(_71); + _71 = _1; +- _70 = Shr(move _71, const 0_i32); ++ _70 = _1; + StorageDead(_71); +- _69 = opaque::(move _70) -> [return: bb28, unwind unreachable]; ++ _69 = opaque::(_1) -> [return: bb28, unwind unreachable]; + } + + bb28: { + StorageDead(_70); + StorageDead(_69); + StorageLive(_72); + StorageLive(_73); + StorageLive(_74); + _74 = _1; +- _73 = Shl(move _74, const 0_i32); ++ _73 = _1; + StorageDead(_74); +- _72 = opaque::(move _73) -> [return: bb29, unwind unreachable]; ++ _72 = opaque::(_1) -> [return: bb29, unwind unreachable]; + } + + bb29: { + StorageDead(_73); + StorageDead(_72); _0 = const (); return; } diff --git a/tests/mir-opt/gvn.arithmetic.GVN.panic-unwind.diff b/tests/mir-opt/gvn.arithmetic.GVN.panic-unwind.diff index 9d69353934c79..98e92d2a31042 100644 --- a/tests/mir-opt/gvn.arithmetic.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.arithmetic.GVN.panic-unwind.diff @@ -13,13 +13,13 @@ let _8: (); let mut _9: u64; let mut _10: u64; - let _11: (); - let mut _12: u64; + let mut _11: u64; + let _12: (); let mut _13: u64; - let _14: (); - let mut _15: u64; + let mut _14: u64; + let _15: (); let mut _16: u64; - let mut _17: bool; + let mut _17: u64; let _18: (); let mut _19: u64; let mut _20: u64; @@ -51,18 +51,32 @@ let _46: (); let mut _47: u64; let mut _48: u64; - let _49: (); - let mut _50: u64; + let mut _49: bool; + let _50: (); let mut _51: u64; - let _52: (); - let mut _53: u64; + let mut _52: u64; + let _53: (); let mut _54: u64; - let _55: (); - let mut _56: u64; + let mut _55: u64; + let _56: (); let mut _57: u64; - let _58: (); - let mut _59: u64; + let mut _58: u64; + let _59: (); let mut _60: u64; + let mut _61: u64; + let _62: (); + let mut _63: u64; + let mut _64: u64; + let _65: (); + let mut _66: u64; + let mut _67: u64; + let mut _68: u64; + let _69: (); + let mut _70: u64; + let mut _71: u64; + let _72: (); + let mut _73: u64; + let mut _74: u64; bb0: { StorageLive(_2); @@ -70,9 +84,10 @@ StorageLive(_4); _4 = _1; - _3 = Add(move _4, const 0_u64); -+ _3 = Add(_1, const 0_u64); ++ _3 = _1; StorageDead(_4); - _2 = opaque::(move _3) -> [return: bb1, unwind continue]; +- _2 = opaque::(move _3) -> [return: bb1, unwind continue]; ++ _2 = opaque::(_1) -> [return: bb1, unwind continue]; } bb1: { @@ -83,98 +98,101 @@ StorageLive(_7); _7 = _1; - _6 = Sub(move _7, const 0_u64); -+ _6 = Sub(_1, const 0_u64); ++ _6 = _1; StorageDead(_7); - _5 = opaque::(move _6) -> [return: bb2, unwind continue]; +- _5 = opaque::(move _6) -> [return: bb2, unwind continue]; ++ _5 = opaque::(_1) -> [return: bb2, unwind continue]; } bb2: { StorageDead(_6); StorageDead(_5); StorageLive(_8); - StorageLive(_9); +- StorageLive(_9); ++ nop; StorageLive(_10); _10 = _1; -- _9 = Mul(move _10, const 0_u64); -+ _9 = Mul(_1, const 0_u64); + StorageLive(_11); + _11 = _1; +- _9 = Sub(move _10, move _11); ++ _9 = const 0_u64; + StorageDead(_11); StorageDead(_10); - _8 = opaque::(move _9) -> [return: bb3, unwind continue]; +- _8 = opaque::(move _9) -> [return: bb3, unwind continue]; ++ _8 = opaque::(const 0_u64) -> [return: bb3, unwind continue]; } bb3: { - StorageDead(_9); +- StorageDead(_9); ++ nop; StorageDead(_8); - StorageLive(_11); StorageLive(_12); StorageLive(_13); - _13 = _1; -- _12 = Mul(move _13, const 1_u64); -+ _12 = Mul(_1, const 1_u64); - StorageDead(_13); - _11 = opaque::(move _12) -> [return: bb4, unwind continue]; + StorageLive(_14); + _14 = _1; +- _13 = Mul(move _14, const 0_u64); ++ _13 = const 0_u64; + StorageDead(_14); +- _12 = opaque::(move _13) -> [return: bb4, unwind continue]; ++ _12 = opaque::(const 0_u64) -> [return: bb4, unwind continue]; } bb4: { + StorageDead(_13); StorageDead(_12); - StorageDead(_11); - StorageLive(_14); StorageLive(_15); StorageLive(_16); - _16 = _1; -- _17 = Eq(const 0_u64, const 0_u64); -- assert(!move _17, "attempt to divide `{}` by zero", _16) -> [success: bb5, unwind continue]; -+ _17 = const true; -+ assert(!const true, "attempt to divide `{}` by zero", _1) -> [success: bb5, unwind continue]; + StorageLive(_17); + _17 = _1; +- _16 = Mul(move _17, const 1_u64); ++ _16 = _1; + StorageDead(_17); +- _15 = opaque::(move _16) -> [return: bb5, unwind continue]; ++ _15 = opaque::(_1) -> [return: bb5, unwind continue]; } bb5: { -- _15 = Div(move _16, const 0_u64); -+ _15 = Div(_1, const 0_u64); StorageDead(_16); - _14 = opaque::(move _15) -> [return: bb6, unwind continue]; - } - - bb6: { StorageDead(_15); - StorageDead(_14); StorageLive(_18); StorageLive(_19); StorageLive(_20); _20 = _1; -- _21 = Eq(const 1_u64, const 0_u64); -- assert(!move _21, "attempt to divide `{}` by zero", _20) -> [success: bb7, unwind continue]; -+ _21 = const false; -+ assert(!const false, "attempt to divide `{}` by zero", _1) -> [success: bb7, unwind continue]; +- _21 = Eq(const 0_u64, const 0_u64); +- assert(!move _21, "attempt to divide `{}` by zero", _20) -> [success: bb6, unwind continue]; ++ _21 = const true; ++ assert(!const true, "attempt to divide `{}` by zero", _1) -> [success: bb6, unwind continue]; } - bb7: { -- _19 = Div(move _20, const 1_u64); -+ _19 = Div(_1, const 1_u64); + bb6: { +- _19 = Div(move _20, const 0_u64); ++ _19 = Div(_1, const 0_u64); StorageDead(_20); - _18 = opaque::(move _19) -> [return: bb8, unwind continue]; + _18 = opaque::(move _19) -> [return: bb7, unwind continue]; } - bb8: { + bb7: { StorageDead(_19); StorageDead(_18); StorageLive(_22); StorageLive(_23); StorageLive(_24); _24 = _1; -- _25 = Eq(_24, const 0_u64); -- assert(!move _25, "attempt to divide `{}` by zero", const 0_u64) -> [success: bb9, unwind continue]; -+ _25 = Eq(_1, const 0_u64); -+ assert(!_25, "attempt to divide `{}` by zero", const 0_u64) -> [success: bb9, unwind continue]; +- _25 = Eq(const 1_u64, const 0_u64); +- assert(!move _25, "attempt to divide `{}` by zero", _24) -> [success: bb8, unwind continue]; ++ _25 = const false; ++ assert(!const false, "attempt to divide `{}` by zero", _1) -> [success: bb8, unwind continue]; } - bb9: { -- _23 = Div(const 0_u64, move _24); -+ _23 = Div(const 0_u64, _1); + bb8: { +- _23 = Div(move _24, const 1_u64); ++ _23 = _1; StorageDead(_24); - _22 = opaque::(move _23) -> [return: bb10, unwind continue]; +- _22 = opaque::(move _23) -> [return: bb9, unwind continue]; ++ _22 = opaque::(_1) -> [return: bb9, unwind continue]; } - bb10: { + bb9: { StorageDead(_23); StorageDead(_22); StorageLive(_26); @@ -182,79 +200,81 @@ StorageLive(_28); _28 = _1; - _29 = Eq(_28, const 0_u64); -- assert(!move _29, "attempt to divide `{}` by zero", const 1_u64) -> [success: bb11, unwind continue]; -+ _29 = _25; -+ assert(!_25, "attempt to divide `{}` by zero", const 1_u64) -> [success: bb11, unwind continue]; +- assert(!move _29, "attempt to divide `{}` by zero", const 0_u64) -> [success: bb10, unwind continue]; ++ _29 = Eq(_1, const 0_u64); ++ assert(!_29, "attempt to divide `{}` by zero", const 0_u64) -> [success: bb10, unwind continue]; } - bb11: { -- _27 = Div(const 1_u64, move _28); -+ _27 = Div(const 1_u64, _1); + bb10: { +- _27 = Div(const 0_u64, move _28); ++ _27 = const 0_u64; StorageDead(_28); - _26 = opaque::(move _27) -> [return: bb12, unwind continue]; +- _26 = opaque::(move _27) -> [return: bb11, unwind continue]; ++ _26 = opaque::(const 0_u64) -> [return: bb11, unwind continue]; } - bb12: { + bb11: { StorageDead(_27); StorageDead(_26); StorageLive(_30); StorageLive(_31); StorageLive(_32); _32 = _1; -- _33 = Eq(const 0_u64, const 0_u64); -- assert(!move _33, "attempt to calculate the remainder of `{}` with a divisor of zero", _32) -> [success: bb13, unwind continue]; -+ _33 = const true; -+ assert(!const true, "attempt to calculate the remainder of `{}` with a divisor of zero", _1) -> [success: bb13, unwind continue]; +- _33 = Eq(_32, const 0_u64); +- assert(!move _33, "attempt to divide `{}` by zero", const 1_u64) -> [success: bb12, unwind continue]; ++ _33 = _29; ++ assert(!_29, "attempt to divide `{}` by zero", const 1_u64) -> [success: bb12, unwind continue]; } - bb13: { -- _31 = Rem(move _32, const 0_u64); -+ _31 = Rem(_1, const 0_u64); + bb12: { +- _31 = Div(const 1_u64, move _32); ++ _31 = Div(const 1_u64, _1); StorageDead(_32); - _30 = opaque::(move _31) -> [return: bb14, unwind continue]; + _30 = opaque::(move _31) -> [return: bb13, unwind continue]; } - bb14: { + bb13: { StorageDead(_31); StorageDead(_30); StorageLive(_34); StorageLive(_35); StorageLive(_36); _36 = _1; -- _37 = Eq(const 1_u64, const 0_u64); -- assert(!move _37, "attempt to calculate the remainder of `{}` with a divisor of zero", _36) -> [success: bb15, unwind continue]; -+ _37 = const false; -+ assert(!const false, "attempt to calculate the remainder of `{}` with a divisor of zero", _1) -> [success: bb15, unwind continue]; +- _37 = Eq(const 0_u64, const 0_u64); +- assert(!move _37, "attempt to calculate the remainder of `{}` with a divisor of zero", _36) -> [success: bb14, unwind continue]; ++ _37 = const true; ++ assert(!const true, "attempt to calculate the remainder of `{}` with a divisor of zero", _1) -> [success: bb14, unwind continue]; } - bb15: { -- _35 = Rem(move _36, const 1_u64); -+ _35 = Rem(_1, const 1_u64); + bb14: { +- _35 = Rem(move _36, const 0_u64); ++ _35 = Rem(_1, const 0_u64); StorageDead(_36); - _34 = opaque::(move _35) -> [return: bb16, unwind continue]; + _34 = opaque::(move _35) -> [return: bb15, unwind continue]; } - bb16: { + bb15: { StorageDead(_35); StorageDead(_34); StorageLive(_38); StorageLive(_39); StorageLive(_40); _40 = _1; -- _41 = Eq(_40, const 0_u64); -- assert(!move _41, "attempt to calculate the remainder of `{}` with a divisor of zero", const 0_u64) -> [success: bb17, unwind continue]; -+ _41 = _25; -+ assert(!_25, "attempt to calculate the remainder of `{}` with a divisor of zero", const 0_u64) -> [success: bb17, unwind continue]; +- _41 = Eq(const 1_u64, const 0_u64); +- assert(!move _41, "attempt to calculate the remainder of `{}` with a divisor of zero", _40) -> [success: bb16, unwind continue]; ++ _41 = const false; ++ assert(!const false, "attempt to calculate the remainder of `{}` with a divisor of zero", _1) -> [success: bb16, unwind continue]; } - bb17: { -- _39 = Rem(const 0_u64, move _40); -+ _39 = Rem(const 0_u64, _1); + bb16: { +- _39 = Rem(move _40, const 1_u64); ++ _39 = const 0_u64; StorageDead(_40); - _38 = opaque::(move _39) -> [return: bb18, unwind continue]; +- _38 = opaque::(move _39) -> [return: bb17, unwind continue]; ++ _38 = opaque::(const 0_u64) -> [return: bb17, unwind continue]; } - bb18: { + bb17: { StorageDead(_39); StorageDead(_38); StorageLive(_42); @@ -262,27 +282,35 @@ StorageLive(_44); _44 = _1; - _45 = Eq(_44, const 0_u64); -- assert(!move _45, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_u64) -> [success: bb19, unwind continue]; -+ _45 = _25; -+ assert(!_25, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_u64) -> [success: bb19, unwind continue]; +- assert(!move _45, "attempt to calculate the remainder of `{}` with a divisor of zero", const 0_u64) -> [success: bb18, unwind continue]; ++ _45 = _29; ++ assert(!_29, "attempt to calculate the remainder of `{}` with a divisor of zero", const 0_u64) -> [success: bb18, unwind continue]; } - bb19: { -- _43 = Rem(const 1_u64, move _44); -+ _43 = Rem(const 1_u64, _1); + bb18: { +- _43 = Rem(const 0_u64, move _44); ++ _43 = const 0_u64; StorageDead(_44); - _42 = opaque::(move _43) -> [return: bb20, unwind continue]; +- _42 = opaque::(move _43) -> [return: bb19, unwind continue]; ++ _42 = opaque::(const 0_u64) -> [return: bb19, unwind continue]; } - bb20: { + bb19: { StorageDead(_43); StorageDead(_42); StorageLive(_46); StorageLive(_47); StorageLive(_48); _48 = _1; -- _47 = BitAnd(move _48, const 0_u64); -+ _47 = BitAnd(_1, const 0_u64); +- _49 = Eq(_48, const 0_u64); +- assert(!move _49, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_u64) -> [success: bb20, unwind continue]; ++ _49 = _29; ++ assert(!_29, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_u64) -> [success: bb20, unwind continue]; + } + + bb20: { +- _47 = Rem(const 1_u64, move _48); ++ _47 = Rem(const 1_u64, _1); StorageDead(_48); _46 = opaque::(move _47) -> [return: bb21, unwind continue]; } @@ -290,58 +318,121 @@ bb21: { StorageDead(_47); StorageDead(_46); - StorageLive(_49); StorageLive(_50); StorageLive(_51); - _51 = _1; -- _50 = BitOr(move _51, const 0_u64); -+ _50 = BitOr(_1, const 0_u64); - StorageDead(_51); - _49 = opaque::(move _50) -> [return: bb22, unwind continue]; + StorageLive(_52); + _52 = _1; +- _51 = BitAnd(move _52, const 0_u64); ++ _51 = const 0_u64; + StorageDead(_52); +- _50 = opaque::(move _51) -> [return: bb22, unwind continue]; ++ _50 = opaque::(const 0_u64) -> [return: bb22, unwind continue]; } bb22: { + StorageDead(_51); StorageDead(_50); - StorageDead(_49); - StorageLive(_52); StorageLive(_53); StorageLive(_54); - _54 = _1; -- _53 = BitXor(move _54, const 0_u64); -+ _53 = BitXor(_1, const 0_u64); - StorageDead(_54); - _52 = opaque::(move _53) -> [return: bb23, unwind continue]; + StorageLive(_55); + _55 = _1; +- _54 = BitAnd(move _55, const _); ++ _54 = _1; + StorageDead(_55); +- _53 = opaque::(move _54) -> [return: bb23, unwind continue]; ++ _53 = opaque::(_1) -> [return: bb23, unwind continue]; } bb23: { + StorageDead(_54); StorageDead(_53); - StorageDead(_52); - StorageLive(_55); StorageLive(_56); StorageLive(_57); - _57 = _1; -- _56 = Shr(move _57, const 0_i32); -+ _56 = Shr(_1, const 0_i32); - StorageDead(_57); - _55 = opaque::(move _56) -> [return: bb24, unwind continue]; + StorageLive(_58); + _58 = _1; +- _57 = BitOr(move _58, const 0_u64); ++ _57 = _1; + StorageDead(_58); +- _56 = opaque::(move _57) -> [return: bb24, unwind continue]; ++ _56 = opaque::(_1) -> [return: bb24, unwind continue]; } bb24: { + StorageDead(_57); StorageDead(_56); - StorageDead(_55); - StorageLive(_58); StorageLive(_59); StorageLive(_60); - _60 = _1; -- _59 = Shl(move _60, const 0_i32); -+ _59 = Shl(_1, const 0_i32); - StorageDead(_60); - _58 = opaque::(move _59) -> [return: bb25, unwind continue]; + StorageLive(_61); + _61 = _1; +- _60 = BitOr(move _61, const _); ++ _60 = const u64::MAX; + StorageDead(_61); +- _59 = opaque::(move _60) -> [return: bb25, unwind continue]; ++ _59 = opaque::(const u64::MAX) -> [return: bb25, unwind continue]; } bb25: { + StorageDead(_60); StorageDead(_59); - StorageDead(_58); + StorageLive(_62); + StorageLive(_63); + StorageLive(_64); + _64 = _1; +- _63 = BitXor(move _64, const 0_u64); ++ _63 = _1; + StorageDead(_64); +- _62 = opaque::(move _63) -> [return: bb26, unwind continue]; ++ _62 = opaque::(_1) -> [return: bb26, unwind continue]; + } + + bb26: { + StorageDead(_63); + StorageDead(_62); + StorageLive(_65); + StorageLive(_66); + StorageLive(_67); + _67 = _1; + StorageLive(_68); + _68 = _1; +- _66 = BitXor(move _67, move _68); ++ _66 = const 0_u64; + StorageDead(_68); + StorageDead(_67); +- _65 = opaque::(move _66) -> [return: bb27, unwind continue]; ++ _65 = opaque::(const 0_u64) -> [return: bb27, unwind continue]; + } + + bb27: { + StorageDead(_66); + StorageDead(_65); + StorageLive(_69); + StorageLive(_70); + StorageLive(_71); + _71 = _1; +- _70 = Shr(move _71, const 0_i32); ++ _70 = _1; + StorageDead(_71); +- _69 = opaque::(move _70) -> [return: bb28, unwind continue]; ++ _69 = opaque::(_1) -> [return: bb28, unwind continue]; + } + + bb28: { + StorageDead(_70); + StorageDead(_69); + StorageLive(_72); + StorageLive(_73); + StorageLive(_74); + _74 = _1; +- _73 = Shl(move _74, const 0_i32); ++ _73 = _1; + StorageDead(_74); +- _72 = opaque::(move _73) -> [return: bb29, unwind continue]; ++ _72 = opaque::(_1) -> [return: bb29, unwind continue]; + } + + bb29: { + StorageDead(_73); + StorageDead(_72); _0 = const (); return; } diff --git a/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff b/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff index 6633df3ae702c..a45d9920a6847 100644 --- a/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff @@ -15,11 +15,16 @@ let _10: (); let mut _11: u64; let mut _12: u64; - let mut _13: (u64, bool); - let _14: (); - let mut _15: u64; + let mut _13: u64; + let mut _14: (u64, bool); + let _15: (); let mut _16: u64; - let mut _17: (u64, bool); + let mut _17: u64; + let mut _18: (u64, bool); + let _19: (); + let mut _20: u64; + let mut _21: u64; + let mut _22: (u64, bool); bb0: { StorageLive(_2); @@ -29,13 +34,15 @@ - _5 = CheckedAdd(_4, const 0_u64); - assert(!move (_5.1: bool), "attempt to compute `{} + {}`, which would overflow", move _4, const 0_u64) -> [success: bb1, unwind unreachable]; + _5 = CheckedAdd(_1, const 0_u64); -+ assert(!move (_5.1: bool), "attempt to compute `{} + {}`, which would overflow", _1, const 0_u64) -> [success: bb1, unwind unreachable]; ++ assert(!const false, "attempt to compute `{} + {}`, which would overflow", _1, const 0_u64) -> [success: bb1, unwind unreachable]; } bb1: { - _3 = move (_5.0: u64); +- _3 = move (_5.0: u64); ++ _3 = _1; StorageDead(_4); - _2 = opaque::(move _3) -> [return: bb2, unwind unreachable]; +- _2 = opaque::(move _3) -> [return: bb2, unwind unreachable]; ++ _2 = opaque::(_1) -> [return: bb2, unwind unreachable]; } bb2: { @@ -47,59 +54,95 @@ _8 = _1; - _9 = CheckedSub(_8, const 0_u64); - assert(!move (_9.1: bool), "attempt to compute `{} - {}`, which would overflow", move _8, const 0_u64) -> [success: bb3, unwind unreachable]; -+ _9 = CheckedSub(_1, const 0_u64); -+ assert(!move (_9.1: bool), "attempt to compute `{} - {}`, which would overflow", _1, const 0_u64) -> [success: bb3, unwind unreachable]; ++ _9 = _5; ++ assert(!const false, "attempt to compute `{} - {}`, which would overflow", _1, const 0_u64) -> [success: bb3, unwind unreachable]; } bb3: { - _7 = move (_9.0: u64); +- _7 = move (_9.0: u64); ++ _7 = _1; StorageDead(_8); - _6 = opaque::(move _7) -> [return: bb4, unwind unreachable]; +- _6 = opaque::(move _7) -> [return: bb4, unwind unreachable]; ++ _6 = opaque::(_1) -> [return: bb4, unwind unreachable]; } bb4: { StorageDead(_7); StorageDead(_6); StorageLive(_10); - StorageLive(_11); +- StorageLive(_11); ++ nop; StorageLive(_12); _12 = _1; -- _13 = CheckedMul(_12, const 0_u64); -- assert(!move (_13.1: bool), "attempt to compute `{} * {}`, which would overflow", move _12, const 0_u64) -> [success: bb5, unwind unreachable]; -+ _13 = CheckedMul(_1, const 0_u64); -+ assert(!move (_13.1: bool), "attempt to compute `{} * {}`, which would overflow", _1, const 0_u64) -> [success: bb5, unwind unreachable]; + StorageLive(_13); + _13 = _1; +- _14 = CheckedSub(_12, _13); +- assert(!move (_14.1: bool), "attempt to compute `{} - {}`, which would overflow", move _12, move _13) -> [success: bb5, unwind unreachable]; ++ _14 = const (0_u64, false); ++ assert(!const false, "attempt to compute `{} - {}`, which would overflow", _1, _1) -> [success: bb5, unwind unreachable]; } bb5: { - _11 = move (_13.0: u64); +- _11 = move (_14.0: u64); ++ _11 = const 0_u64; + StorageDead(_13); StorageDead(_12); - _10 = opaque::(move _11) -> [return: bb6, unwind unreachable]; +- _10 = opaque::(move _11) -> [return: bb6, unwind unreachable]; ++ _10 = opaque::(const 0_u64) -> [return: bb6, unwind unreachable]; } bb6: { - StorageDead(_11); +- StorageDead(_11); ++ nop; StorageDead(_10); - StorageLive(_14); StorageLive(_15); StorageLive(_16); - _16 = _1; -- _17 = CheckedMul(_16, const 1_u64); -- assert(!move (_17.1: bool), "attempt to compute `{} * {}`, which would overflow", move _16, const 1_u64) -> [success: bb7, unwind unreachable]; -+ _17 = CheckedMul(_1, const 1_u64); -+ assert(!move (_17.1: bool), "attempt to compute `{} * {}`, which would overflow", _1, const 1_u64) -> [success: bb7, unwind unreachable]; + StorageLive(_17); + _17 = _1; +- _18 = CheckedMul(_17, const 0_u64); +- assert(!move (_18.1: bool), "attempt to compute `{} * {}`, which would overflow", move _17, const 0_u64) -> [success: bb7, unwind unreachable]; ++ _18 = const (0_u64, false); ++ assert(!const false, "attempt to compute `{} * {}`, which would overflow", _1, const 0_u64) -> [success: bb7, unwind unreachable]; } bb7: { - _15 = move (_17.0: u64); - StorageDead(_16); - _14 = opaque::(move _15) -> [return: bb8, unwind unreachable]; +- _16 = move (_18.0: u64); ++ _16 = const 0_u64; + StorageDead(_17); +- _15 = opaque::(move _16) -> [return: bb8, unwind unreachable]; ++ _15 = opaque::(const 0_u64) -> [return: bb8, unwind unreachable]; } bb8: { + StorageDead(_16); StorageDead(_15); - StorageDead(_14); + StorageLive(_19); + StorageLive(_20); + StorageLive(_21); + _21 = _1; +- _22 = CheckedMul(_21, const 1_u64); +- assert(!move (_22.1: bool), "attempt to compute `{} * {}`, which would overflow", move _21, const 1_u64) -> [success: bb9, unwind unreachable]; ++ _22 = _5; ++ assert(!const false, "attempt to compute `{} * {}`, which would overflow", _1, const 1_u64) -> [success: bb9, unwind unreachable]; + } + + bb9: { +- _20 = move (_22.0: u64); ++ _20 = _1; + StorageDead(_21); +- _19 = opaque::(move _20) -> [return: bb10, unwind unreachable]; ++ _19 = opaque::(_1) -> [return: bb10, unwind unreachable]; + } + + bb10: { + StorageDead(_20); + StorageDead(_19); _0 = const (); return; } ++ } ++ ++ ALLOC0 (size: 16, align: 8) { ++ 00 00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ │ .........░░░░░░░ } diff --git a/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff b/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff index d100a77fee5f3..9033b392bd4c1 100644 --- a/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff @@ -15,11 +15,16 @@ let _10: (); let mut _11: u64; let mut _12: u64; - let mut _13: (u64, bool); - let _14: (); - let mut _15: u64; + let mut _13: u64; + let mut _14: (u64, bool); + let _15: (); let mut _16: u64; - let mut _17: (u64, bool); + let mut _17: u64; + let mut _18: (u64, bool); + let _19: (); + let mut _20: u64; + let mut _21: u64; + let mut _22: (u64, bool); bb0: { StorageLive(_2); @@ -29,13 +34,15 @@ - _5 = CheckedAdd(_4, const 0_u64); - assert(!move (_5.1: bool), "attempt to compute `{} + {}`, which would overflow", move _4, const 0_u64) -> [success: bb1, unwind continue]; + _5 = CheckedAdd(_1, const 0_u64); -+ assert(!move (_5.1: bool), "attempt to compute `{} + {}`, which would overflow", _1, const 0_u64) -> [success: bb1, unwind continue]; ++ assert(!const false, "attempt to compute `{} + {}`, which would overflow", _1, const 0_u64) -> [success: bb1, unwind continue]; } bb1: { - _3 = move (_5.0: u64); +- _3 = move (_5.0: u64); ++ _3 = _1; StorageDead(_4); - _2 = opaque::(move _3) -> [return: bb2, unwind continue]; +- _2 = opaque::(move _3) -> [return: bb2, unwind continue]; ++ _2 = opaque::(_1) -> [return: bb2, unwind continue]; } bb2: { @@ -47,59 +54,95 @@ _8 = _1; - _9 = CheckedSub(_8, const 0_u64); - assert(!move (_9.1: bool), "attempt to compute `{} - {}`, which would overflow", move _8, const 0_u64) -> [success: bb3, unwind continue]; -+ _9 = CheckedSub(_1, const 0_u64); -+ assert(!move (_9.1: bool), "attempt to compute `{} - {}`, which would overflow", _1, const 0_u64) -> [success: bb3, unwind continue]; ++ _9 = _5; ++ assert(!const false, "attempt to compute `{} - {}`, which would overflow", _1, const 0_u64) -> [success: bb3, unwind continue]; } bb3: { - _7 = move (_9.0: u64); +- _7 = move (_9.0: u64); ++ _7 = _1; StorageDead(_8); - _6 = opaque::(move _7) -> [return: bb4, unwind continue]; +- _6 = opaque::(move _7) -> [return: bb4, unwind continue]; ++ _6 = opaque::(_1) -> [return: bb4, unwind continue]; } bb4: { StorageDead(_7); StorageDead(_6); StorageLive(_10); - StorageLive(_11); +- StorageLive(_11); ++ nop; StorageLive(_12); _12 = _1; -- _13 = CheckedMul(_12, const 0_u64); -- assert(!move (_13.1: bool), "attempt to compute `{} * {}`, which would overflow", move _12, const 0_u64) -> [success: bb5, unwind continue]; -+ _13 = CheckedMul(_1, const 0_u64); -+ assert(!move (_13.1: bool), "attempt to compute `{} * {}`, which would overflow", _1, const 0_u64) -> [success: bb5, unwind continue]; + StorageLive(_13); + _13 = _1; +- _14 = CheckedSub(_12, _13); +- assert(!move (_14.1: bool), "attempt to compute `{} - {}`, which would overflow", move _12, move _13) -> [success: bb5, unwind continue]; ++ _14 = const (0_u64, false); ++ assert(!const false, "attempt to compute `{} - {}`, which would overflow", _1, _1) -> [success: bb5, unwind continue]; } bb5: { - _11 = move (_13.0: u64); +- _11 = move (_14.0: u64); ++ _11 = const 0_u64; + StorageDead(_13); StorageDead(_12); - _10 = opaque::(move _11) -> [return: bb6, unwind continue]; +- _10 = opaque::(move _11) -> [return: bb6, unwind continue]; ++ _10 = opaque::(const 0_u64) -> [return: bb6, unwind continue]; } bb6: { - StorageDead(_11); +- StorageDead(_11); ++ nop; StorageDead(_10); - StorageLive(_14); StorageLive(_15); StorageLive(_16); - _16 = _1; -- _17 = CheckedMul(_16, const 1_u64); -- assert(!move (_17.1: bool), "attempt to compute `{} * {}`, which would overflow", move _16, const 1_u64) -> [success: bb7, unwind continue]; -+ _17 = CheckedMul(_1, const 1_u64); -+ assert(!move (_17.1: bool), "attempt to compute `{} * {}`, which would overflow", _1, const 1_u64) -> [success: bb7, unwind continue]; + StorageLive(_17); + _17 = _1; +- _18 = CheckedMul(_17, const 0_u64); +- assert(!move (_18.1: bool), "attempt to compute `{} * {}`, which would overflow", move _17, const 0_u64) -> [success: bb7, unwind continue]; ++ _18 = const (0_u64, false); ++ assert(!const false, "attempt to compute `{} * {}`, which would overflow", _1, const 0_u64) -> [success: bb7, unwind continue]; } bb7: { - _15 = move (_17.0: u64); - StorageDead(_16); - _14 = opaque::(move _15) -> [return: bb8, unwind continue]; +- _16 = move (_18.0: u64); ++ _16 = const 0_u64; + StorageDead(_17); +- _15 = opaque::(move _16) -> [return: bb8, unwind continue]; ++ _15 = opaque::(const 0_u64) -> [return: bb8, unwind continue]; } bb8: { + StorageDead(_16); StorageDead(_15); - StorageDead(_14); + StorageLive(_19); + StorageLive(_20); + StorageLive(_21); + _21 = _1; +- _22 = CheckedMul(_21, const 1_u64); +- assert(!move (_22.1: bool), "attempt to compute `{} * {}`, which would overflow", move _21, const 1_u64) -> [success: bb9, unwind continue]; ++ _22 = _5; ++ assert(!const false, "attempt to compute `{} * {}`, which would overflow", _1, const 1_u64) -> [success: bb9, unwind continue]; + } + + bb9: { +- _20 = move (_22.0: u64); ++ _20 = _1; + StorageDead(_21); +- _19 = opaque::(move _20) -> [return: bb10, unwind continue]; ++ _19 = opaque::(_1) -> [return: bb10, unwind continue]; + } + + bb10: { + StorageDead(_20); + StorageDead(_19); _0 = const (); return; } ++ } ++ ++ ALLOC0 (size: 16, align: 8) { ++ 00 00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ │ .........░░░░░░░ } diff --git a/tests/mir-opt/gvn.comparison.GVN.panic-abort.diff b/tests/mir-opt/gvn.comparison.GVN.panic-abort.diff index ee3b9da2122bd..fefdf14bddcd0 100644 --- a/tests/mir-opt/gvn.comparison.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.comparison.GVN.panic-abort.diff @@ -30,10 +30,11 @@ StorageLive(_6); _6 = _1; - _4 = Eq(move _5, move _6); -+ _4 = Eq(_1, _1); ++ _4 = const true; StorageDead(_6); StorageDead(_5); - _3 = opaque::(move _4) -> [return: bb1, unwind unreachable]; +- _3 = opaque::(move _4) -> [return: bb1, unwind unreachable]; ++ _3 = opaque::(const true) -> [return: bb1, unwind unreachable]; } bb1: { @@ -46,10 +47,11 @@ StorageLive(_10); _10 = _1; - _8 = Ne(move _9, move _10); -+ _8 = Ne(_1, _1); ++ _8 = const false; StorageDead(_10); StorageDead(_9); - _7 = opaque::(move _8) -> [return: bb2, unwind unreachable]; +- _7 = opaque::(move _8) -> [return: bb2, unwind unreachable]; ++ _7 = opaque::(const false) -> [return: bb2, unwind unreachable]; } bb2: { diff --git a/tests/mir-opt/gvn.comparison.GVN.panic-unwind.diff b/tests/mir-opt/gvn.comparison.GVN.panic-unwind.diff index a1408fe3434cb..9f19b2b59fa54 100644 --- a/tests/mir-opt/gvn.comparison.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.comparison.GVN.panic-unwind.diff @@ -30,10 +30,11 @@ StorageLive(_6); _6 = _1; - _4 = Eq(move _5, move _6); -+ _4 = Eq(_1, _1); ++ _4 = const true; StorageDead(_6); StorageDead(_5); - _3 = opaque::(move _4) -> [return: bb1, unwind continue]; +- _3 = opaque::(move _4) -> [return: bb1, unwind continue]; ++ _3 = opaque::(const true) -> [return: bb1, unwind continue]; } bb1: { @@ -46,10 +47,11 @@ StorageLive(_10); _10 = _1; - _8 = Ne(move _9, move _10); -+ _8 = Ne(_1, _1); ++ _8 = const false; StorageDead(_10); StorageDead(_9); - _7 = opaque::(move _8) -> [return: bb2, unwind continue]; +- _7 = opaque::(move _8) -> [return: bb2, unwind continue]; ++ _7 = opaque::(const false) -> [return: bb2, unwind continue]; } bb2: { diff --git a/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff b/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff index d8248d22d38b9..0901896af5358 100644 --- a/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff @@ -8,10 +8,10 @@ let mut _3: fn(u8) -> u8; let _5: (); let mut _6: fn(u8) -> u8; - let mut _9: {closure@$DIR/gvn.rs:591:19: 591:21}; + let mut _9: {closure@$DIR/gvn.rs:585:19: 585:21}; let _10: (); let mut _11: fn(); - let mut _13: {closure@$DIR/gvn.rs:591:19: 591:21}; + let mut _13: {closure@$DIR/gvn.rs:585:19: 585:21}; let _14: (); let mut _15: fn(); scope 1 { @@ -19,7 +19,7 @@ let _4: fn(u8) -> u8; scope 2 { debug g => _4; - let _7: {closure@$DIR/gvn.rs:591:19: 591:21}; + let _7: {closure@$DIR/gvn.rs:585:19: 585:21}; scope 3 { debug closure => _7; let _8: fn(); @@ -62,16 +62,16 @@ StorageDead(_6); StorageDead(_5); - StorageLive(_7); -- _7 = {closure@$DIR/gvn.rs:591:19: 591:21}; +- _7 = {closure@$DIR/gvn.rs:585:19: 585:21}; - StorageLive(_8); + nop; -+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21}; ++ _7 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21}; + nop; StorageLive(_9); - _9 = _7; - _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Normal))); -+ _9 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21}; -+ _8 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21} as fn() (PointerCoercion(ClosureFnPointer(Normal))); ++ _9 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21}; ++ _8 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21} as fn() (PointerCoercion(ClosureFnPointer(Normal))); StorageDead(_9); StorageLive(_10); StorageLive(_11); @@ -88,8 +88,8 @@ StorageLive(_13); - _13 = _7; - _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Normal))); -+ _13 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21}; -+ _12 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21} as fn() (PointerCoercion(ClosureFnPointer(Normal))); ++ _13 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21}; ++ _12 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21} as fn() (PointerCoercion(ClosureFnPointer(Normal))); StorageDead(_13); StorageLive(_14); StorageLive(_15); diff --git a/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff b/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff index e38a3d8520927..4b95191ba82a7 100644 --- a/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff @@ -8,10 +8,10 @@ let mut _3: fn(u8) -> u8; let _5: (); let mut _6: fn(u8) -> u8; - let mut _9: {closure@$DIR/gvn.rs:591:19: 591:21}; + let mut _9: {closure@$DIR/gvn.rs:585:19: 585:21}; let _10: (); let mut _11: fn(); - let mut _13: {closure@$DIR/gvn.rs:591:19: 591:21}; + let mut _13: {closure@$DIR/gvn.rs:585:19: 585:21}; let _14: (); let mut _15: fn(); scope 1 { @@ -19,7 +19,7 @@ let _4: fn(u8) -> u8; scope 2 { debug g => _4; - let _7: {closure@$DIR/gvn.rs:591:19: 591:21}; + let _7: {closure@$DIR/gvn.rs:585:19: 585:21}; scope 3 { debug closure => _7; let _8: fn(); @@ -62,16 +62,16 @@ StorageDead(_6); StorageDead(_5); - StorageLive(_7); -- _7 = {closure@$DIR/gvn.rs:591:19: 591:21}; +- _7 = {closure@$DIR/gvn.rs:585:19: 585:21}; - StorageLive(_8); + nop; -+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21}; ++ _7 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21}; + nop; StorageLive(_9); - _9 = _7; - _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Normal))); -+ _9 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21}; -+ _8 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21} as fn() (PointerCoercion(ClosureFnPointer(Normal))); ++ _9 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21}; ++ _8 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21} as fn() (PointerCoercion(ClosureFnPointer(Normal))); StorageDead(_9); StorageLive(_10); StorageLive(_11); @@ -88,8 +88,8 @@ StorageLive(_13); - _13 = _7; - _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Normal))); -+ _13 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21}; -+ _12 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21} as fn() (PointerCoercion(ClosureFnPointer(Normal))); ++ _13 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21}; ++ _12 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21} as fn() (PointerCoercion(ClosureFnPointer(Normal))); StorageDead(_13); StorageLive(_14); StorageLive(_15); diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs index 23e33a0fa49ea..8c06e3a6385a6 100644 --- a/tests/mir-opt/gvn.rs +++ b/tests/mir-opt/gvn.rs @@ -169,66 +169,61 @@ fn repeated_index(x: T, idx: usize) { /// Verify symbolic integer arithmetic simplifications. fn arithmetic(x: u64) { // CHECK-LABEL: fn arithmetic( - // CHECK: [[add:_.*]] = Add(_1, const 0_u64); - // CHECK: opaque::(move [[add]]) + // CHECK: opaque::(_1) opaque(x + 0); - // CHECK: [[sub:_.*]] = Sub(_1, const 0_u64); - // CHECK: opaque::(move [[sub]]) + // CHECK: opaque::(_1) opaque(x - 0); - // CHECK: [[mul0:_.*]] = Mul(_1, const 0_u64); - // CHECK: opaque::(move [[mul0]]) + // CHECK: opaque::(const 0_u64) + opaque(x - x); + // CHECK: opaque::(const 0_u64) opaque(x * 0); - // CHECK: [[mul1:_.*]] = Mul(_1, const 1_u64); - // CHECK: opaque::(move [[mul1]]) + // CHECK: opaque::(_1) opaque(x * 1); + // CHECK: assert(!const true, "attempt to divide `{}` by zero", // CHECK: [[div0:_.*]] = Div(_1, const 0_u64); // CHECK: opaque::(move [[div0]]) opaque(x / 0); - // CHECK: [[div1:_.*]] = Div(_1, const 1_u64); - // CHECK: opaque::(move [[div1]]) + // CHECK: opaque::(_1) opaque(x / 1); - // CHECK: [[zdiv:_.*]] = Div(const 0_u64, _1); - // CHECK: opaque::(move [[zdiv]]) + // CHECK: opaque::(const 0_u64) opaque(0 / x); // CHECK: [[odiv:_.*]] = Div(const 1_u64, _1); // CHECK: opaque::(move [[odiv]]) opaque(1 / x); + // CHECK: assert(!const true, "attempt to calculate the remainder of `{}` with a divisor of zero" // CHECK: [[rem0:_.*]] = Rem(_1, const 0_u64); // CHECK: opaque::(move [[rem0]]) opaque(x % 0); - // CHECK: [[rem1:_.*]] = Rem(_1, const 1_u64); - // CHECK: opaque::(move [[rem1]]) + // CHECK: opaque::(const 0_u64) opaque(x % 1); - // CHECK: [[zrem:_.*]] = Rem(const 0_u64, _1); - // CHECK: opaque::(move [[zrem]]) + // CHECK: opaque::(const 0_u64) opaque(0 % x); // CHECK: [[orem:_.*]] = Rem(const 1_u64, _1); // CHECK: opaque::(move [[orem]]) opaque(1 % x); - // CHECK: [[and:_.*]] = BitAnd(_1, const 0_u64); - // CHECK: opaque::(move [[and]]) + // CHECK: opaque::(const 0_u64) opaque(x & 0); - // CHECK: [[or:_.*]] = BitOr(_1, const 0_u64); - // CHECK: opaque::(move [[or]]) + // CHECK: opaque::(_1) + opaque(x & u64::MAX); + // CHECK: opaque::(_1) opaque(x | 0); - // CHECK: [[xor:_.*]] = BitXor(_1, const 0_u64); - // CHECK: opaque::(move [[xor]]) + // CHECK: opaque::(const u64::MAX) + opaque(x | u64::MAX); + // CHECK: opaque::(_1) opaque(x ^ 0); - // CHECK: [[shr:_.*]] = Shr(_1, const 0_i32); - // CHECK: opaque::(move [[shr]]) + // CHECK: opaque::(const 0_u64) + opaque(x ^ x); + // CHECK: opaque::(_1) opaque(x >> 0); - // CHECK: [[shl:_.*]] = Shl(_1, const 0_i32); - // CHECK: opaque::(move [[shl]]) + // CHECK: opaque::(_1) opaque(x << 0); } fn comparison(x: u64, y: u64) { // CHECK-LABEL: fn comparison( - // CHECK: [[eqxx:_.*]] = Eq(_1, _1); - // CHECK: opaque::(move [[eqxx]]) + // CHECK: opaque::(const true) opaque(x == x); - // CHECK: [[nexx:_.*]] = Ne(_1, _1); - // CHECK: opaque::(move [[nexx]]) + // CHECK: opaque::(const false) opaque(x != x); // CHECK: [[eqxy:_.*]] = Eq(_1, _2); // CHECK: opaque::(move [[eqxy]]) @@ -242,21 +237,20 @@ fn comparison(x: u64, y: u64) { #[rustc_inherit_overflow_checks] fn arithmetic_checked(x: u64) { // CHECK-LABEL: fn arithmetic_checked( - // CHECK: [[cadd:_.*]] = CheckedAdd(_1, const 0_u64); - // CHECK: [[add:_.*]] = move ([[cadd]].0: u64); - // CHECK: opaque::(move [[add]]) + // CHECK: assert(!const false, + // CHECK: opaque::(_1) opaque(x + 0); - // CHECK: [[csub:_.*]] = CheckedSub(_1, const 0_u64); - // CHECK: [[sub:_.*]] = move ([[csub]].0: u64); - // CHECK: opaque::(move [[sub]]) + // CHECK: assert(!const false, + // CHECK: opaque::(_1) opaque(x - 0); - // CHECK: [[cmul0:_.*]] = CheckedMul(_1, const 0_u64); - // CHECK: [[mul0:_.*]] = move ([[cmul0]].0: u64); - // CHECK: opaque::(move [[mul0]]) + // CHECK: assert(!const false, + // CHECK: opaque::(const 0_u64) + opaque(x - x); + // CHECK: assert(!const false, + // CHECK: opaque::(const 0_u64) opaque(x * 0); - // CHECK: [[cmul1:_.*]] = CheckedMul(_1, const 1_u64); - // CHECK: [[mul1:_.*]] = move ([[cmul1]].0: u64); - // CHECK: opaque::(move [[mul1]]) + // CHECK: assert(!const false, + // CHECK: opaque::(_1) opaque(x * 1); } diff --git a/tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff b/tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff index b04728a9b0f58..187290785c032 100644 --- a/tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff +++ b/tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff @@ -19,7 +19,6 @@ scope 1 (inlined imm8) { debug x => _5; let mut _14: u32; - let mut _15: u32; scope 2 { debug out => _4; } @@ -36,14 +35,14 @@ StorageLive(_5); _5 = _1; _4 = const 0_u32; - StorageLive(_15); - StorageLive(_14); -- _14 = Shr(_5, const 0_i32); -+ _14 = Shr(_1, const 0_i32); - _15 = BitAnd(move _14, const 255_u32); - StorageDead(_14); - _4 = BitOr(const 0_u32, move _15); - StorageDead(_15); +- StorageLive(_14); +- _14 = BitAnd(_5, const 255_u32); +- _4 = BitOr(const 0_u32, move _14); +- StorageDead(_14); ++ nop; ++ _14 = BitAnd(_1, const 255_u32); ++ _4 = _14; ++ nop; StorageDead(_5); StorageLive(_6); StorageLive(_7); diff --git a/tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff b/tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff index fcf99ac6918de..99350bac478d9 100644 --- a/tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff +++ b/tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff @@ -19,7 +19,6 @@ scope 1 (inlined imm8) { debug x => _5; let mut _14: u32; - let mut _15: u32; scope 2 { debug out => _4; } @@ -36,14 +35,14 @@ StorageLive(_5); _5 = _1; _4 = const 0_u32; - StorageLive(_15); - StorageLive(_14); -- _14 = Shr(_5, const 0_i32); -+ _14 = Shr(_1, const 0_i32); - _15 = BitAnd(move _14, const 255_u32); - StorageDead(_14); - _4 = BitOr(const 0_u32, move _15); - StorageDead(_15); +- StorageLive(_14); +- _14 = BitAnd(_5, const 255_u32); +- _4 = BitOr(const 0_u32, move _14); +- StorageDead(_14); ++ nop; ++ _14 = BitAnd(_1, const 255_u32); ++ _4 = _14; ++ nop; StorageDead(_5); StorageLive(_6); StorageLive(_7); From 5fc23ad8e6b7a5ef0b5a6936cb043bd85f8bed59 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 25 Mar 2023 22:33:35 +0000 Subject: [PATCH 0309/1197] Simplify unary operations. --- compiler/rustc_mir_transform/src/gvn.rs | 20 +++ .../gvn.fn_pointers.GVN.panic-abort.diff | 18 +-- .../gvn.fn_pointers.GVN.panic-unwind.diff | 18 +-- tests/mir-opt/gvn.rs | 27 ++++ tests/mir-opt/gvn.unary.GVN.panic-abort.diff | 153 ++++++++++++++++++ tests/mir-opt/gvn.unary.GVN.panic-unwind.diff | 153 ++++++++++++++++++ 6 files changed, 371 insertions(+), 18 deletions(-) create mode 100644 tests/mir-opt/gvn.unary.GVN.panic-abort.diff create mode 100644 tests/mir-opt/gvn.unary.GVN.panic-unwind.diff diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 3052369c3ca48..699b218d46d57 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -817,6 +817,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } Rvalue::UnaryOp(op, ref mut arg) => { let arg = self.simplify_operand(arg, location)?; + if let Some(value) = self.simplify_unary(op, arg) { + return Some(value); + } Value::UnaryOp(op, arg) } Rvalue::Discriminant(ref mut place) => { @@ -916,6 +919,23 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { Some(self.insert(Value::Aggregate(ty, variant_index, fields))) } + #[instrument(level = "trace", skip(self), ret)] + fn simplify_unary(&mut self, op: UnOp, value: VnIndex) -> Option { + let value = match (op, self.get(value)) { + (UnOp::Not, Value::UnaryOp(UnOp::Not, inner)) => return Some(*inner), + (UnOp::Neg, Value::UnaryOp(UnOp::Neg, inner)) => return Some(*inner), + (UnOp::Not, Value::BinaryOp(BinOp::Eq, lhs, rhs)) => { + Value::BinaryOp(BinOp::Ne, *lhs, *rhs) + } + (UnOp::Not, Value::BinaryOp(BinOp::Ne, lhs, rhs)) => { + Value::BinaryOp(BinOp::Eq, *lhs, *rhs) + } + _ => return None, + }; + + Some(self.insert(value)) + } + #[instrument(level = "trace", skip(self), ret)] fn simplify_binary( &mut self, diff --git a/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff b/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff index 0901896af5358..02bf95840dafb 100644 --- a/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff @@ -8,10 +8,10 @@ let mut _3: fn(u8) -> u8; let _5: (); let mut _6: fn(u8) -> u8; - let mut _9: {closure@$DIR/gvn.rs:585:19: 585:21}; + let mut _9: {closure@$DIR/gvn.rs:610:19: 610:21}; let _10: (); let mut _11: fn(); - let mut _13: {closure@$DIR/gvn.rs:585:19: 585:21}; + let mut _13: {closure@$DIR/gvn.rs:610:19: 610:21}; let _14: (); let mut _15: fn(); scope 1 { @@ -19,7 +19,7 @@ let _4: fn(u8) -> u8; scope 2 { debug g => _4; - let _7: {closure@$DIR/gvn.rs:585:19: 585:21}; + let _7: {closure@$DIR/gvn.rs:610:19: 610:21}; scope 3 { debug closure => _7; let _8: fn(); @@ -62,16 +62,16 @@ StorageDead(_6); StorageDead(_5); - StorageLive(_7); -- _7 = {closure@$DIR/gvn.rs:585:19: 585:21}; +- _7 = {closure@$DIR/gvn.rs:610:19: 610:21}; - StorageLive(_8); + nop; -+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21}; ++ _7 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21}; + nop; StorageLive(_9); - _9 = _7; - _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Normal))); -+ _9 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21}; -+ _8 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21} as fn() (PointerCoercion(ClosureFnPointer(Normal))); ++ _9 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21}; ++ _8 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21} as fn() (PointerCoercion(ClosureFnPointer(Normal))); StorageDead(_9); StorageLive(_10); StorageLive(_11); @@ -88,8 +88,8 @@ StorageLive(_13); - _13 = _7; - _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Normal))); -+ _13 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21}; -+ _12 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21} as fn() (PointerCoercion(ClosureFnPointer(Normal))); ++ _13 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21}; ++ _12 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21} as fn() (PointerCoercion(ClosureFnPointer(Normal))); StorageDead(_13); StorageLive(_14); StorageLive(_15); diff --git a/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff b/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff index 4b95191ba82a7..c5dcc8a8ec9d8 100644 --- a/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff @@ -8,10 +8,10 @@ let mut _3: fn(u8) -> u8; let _5: (); let mut _6: fn(u8) -> u8; - let mut _9: {closure@$DIR/gvn.rs:585:19: 585:21}; + let mut _9: {closure@$DIR/gvn.rs:610:19: 610:21}; let _10: (); let mut _11: fn(); - let mut _13: {closure@$DIR/gvn.rs:585:19: 585:21}; + let mut _13: {closure@$DIR/gvn.rs:610:19: 610:21}; let _14: (); let mut _15: fn(); scope 1 { @@ -19,7 +19,7 @@ let _4: fn(u8) -> u8; scope 2 { debug g => _4; - let _7: {closure@$DIR/gvn.rs:585:19: 585:21}; + let _7: {closure@$DIR/gvn.rs:610:19: 610:21}; scope 3 { debug closure => _7; let _8: fn(); @@ -62,16 +62,16 @@ StorageDead(_6); StorageDead(_5); - StorageLive(_7); -- _7 = {closure@$DIR/gvn.rs:585:19: 585:21}; +- _7 = {closure@$DIR/gvn.rs:610:19: 610:21}; - StorageLive(_8); + nop; -+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21}; ++ _7 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21}; + nop; StorageLive(_9); - _9 = _7; - _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Normal))); -+ _9 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21}; -+ _8 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21} as fn() (PointerCoercion(ClosureFnPointer(Normal))); ++ _9 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21}; ++ _8 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21} as fn() (PointerCoercion(ClosureFnPointer(Normal))); StorageDead(_9); StorageLive(_10); StorageLive(_11); @@ -88,8 +88,8 @@ StorageLive(_13); - _13 = _7; - _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Normal))); -+ _13 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21}; -+ _12 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21} as fn() (PointerCoercion(ClosureFnPointer(Normal))); ++ _13 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21}; ++ _12 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21} as fn() (PointerCoercion(ClosureFnPointer(Normal))); StorageDead(_13); StorageLive(_14); StorageLive(_15); diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs index 8c06e3a6385a6..f8f4fdcd7323e 100644 --- a/tests/mir-opt/gvn.rs +++ b/tests/mir-opt/gvn.rs @@ -166,6 +166,31 @@ fn repeated_index(x: T, idx: usize) { opaque(a[idx]); } +fn unary(x: i64) { + // CHECK-LABEL: fn unary( + // CHECK: opaque::(_1) + opaque(--x); // This is `x`. + + // CHECK: [[b:_.*]] = Lt(_1, const 13_i64); + // CHECK: opaque::([[b]]) + let b = x < 13; + opaque(!!b); // This is `b`. + + // Both lines should test the same thing. + // CHECK: [[c:_.*]] = Ne(_1, const 15_i64); + // CHECK: opaque::([[c]]) + // CHECK: opaque::([[c]]) + opaque(x != 15); + opaque(!(x == 15)); + + // Both lines should test the same thing. + // CHECK: [[d:_.*]] = Eq(_1, const 35_i64); + // CHECK: opaque::([[d]]) + // CHECK: opaque::([[d]]) + opaque(x == 35); + opaque(!(x != 35)); +} + /// Verify symbolic integer arithmetic simplifications. fn arithmetic(x: u64) { // CHECK-LABEL: fn arithmetic( @@ -623,6 +648,7 @@ fn main() { subexpression_elimination(2, 4, 5); wrap_unwrap(5); repeated_index::(5, 3); + unary(i64::MIN); arithmetic(5); comparison(5, 6); arithmetic_checked(5); @@ -651,6 +677,7 @@ fn identity(x: T) -> T { // EMIT_MIR gvn.subexpression_elimination.GVN.diff // EMIT_MIR gvn.wrap_unwrap.GVN.diff // EMIT_MIR gvn.repeated_index.GVN.diff +// EMIT_MIR gvn.unary.GVN.diff // EMIT_MIR gvn.arithmetic.GVN.diff // EMIT_MIR gvn.comparison.GVN.diff // EMIT_MIR gvn.arithmetic_checked.GVN.diff diff --git a/tests/mir-opt/gvn.unary.GVN.panic-abort.diff b/tests/mir-opt/gvn.unary.GVN.panic-abort.diff new file mode 100644 index 0000000000000..9469032f294e3 --- /dev/null +++ b/tests/mir-opt/gvn.unary.GVN.panic-abort.diff @@ -0,0 +1,153 @@ +- // MIR for `unary` before GVN ++ // MIR for `unary` after GVN + + fn unary(_1: i64) -> () { + debug x => _1; + let mut _0: (); + let _2: (); + let mut _3: i64; + let mut _4: i64; + let mut _5: i64; + let _6: bool; + let mut _7: i64; + let _8: (); + let mut _9: bool; + let mut _10: bool; + let mut _11: bool; + let _12: (); + let mut _13: bool; + let mut _14: i64; + let _15: (); + let mut _16: bool; + let mut _17: bool; + let mut _18: i64; + let _19: (); + let mut _20: bool; + let mut _21: i64; + let _22: (); + let mut _23: bool; + let mut _24: bool; + let mut _25: i64; + scope 1 { + debug b => _6; + } + + bb0: { + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + StorageLive(_5); + _5 = _1; +- _4 = Neg(move _5); ++ _4 = Neg(_1); + StorageDead(_5); +- _3 = Neg(move _4); ++ _3 = _1; + StorageDead(_4); +- _2 = opaque::(move _3) -> [return: bb1, unwind unreachable]; ++ _2 = opaque::(_1) -> [return: bb1, unwind unreachable]; + } + + bb1: { + StorageDead(_3); + StorageDead(_2); +- StorageLive(_6); ++ nop; + StorageLive(_7); + _7 = _1; +- _6 = Lt(move _7, const 13_i64); ++ _6 = Lt(_1, const 13_i64); + StorageDead(_7); + StorageLive(_8); + StorageLive(_9); + StorageLive(_10); + StorageLive(_11); + _11 = _6; +- _10 = Not(move _11); ++ _10 = Not(_6); + StorageDead(_11); +- _9 = Not(move _10); ++ _9 = _6; + StorageDead(_10); +- _8 = opaque::(move _9) -> [return: bb2, unwind unreachable]; ++ _8 = opaque::(_6) -> [return: bb2, unwind unreachable]; + } + + bb2: { + StorageDead(_9); + StorageDead(_8); + StorageLive(_12); +- StorageLive(_13); ++ nop; + StorageLive(_14); + _14 = _1; +- _13 = Ne(move _14, const 15_i64); ++ _13 = Ne(_1, const 15_i64); + StorageDead(_14); +- _12 = opaque::(move _13) -> [return: bb3, unwind unreachable]; ++ _12 = opaque::(_13) -> [return: bb3, unwind unreachable]; + } + + bb3: { +- StorageDead(_13); ++ nop; + StorageDead(_12); + StorageLive(_15); + StorageLive(_16); + StorageLive(_17); + StorageLive(_18); + _18 = _1; +- _17 = Eq(move _18, const 15_i64); ++ _17 = Eq(_1, const 15_i64); + StorageDead(_18); +- _16 = Not(move _17); ++ _16 = _13; + StorageDead(_17); +- _15 = opaque::(move _16) -> [return: bb4, unwind unreachable]; ++ _15 = opaque::(_13) -> [return: bb4, unwind unreachable]; + } + + bb4: { + StorageDead(_16); + StorageDead(_15); + StorageLive(_19); +- StorageLive(_20); ++ nop; + StorageLive(_21); + _21 = _1; +- _20 = Eq(move _21, const 35_i64); ++ _20 = Eq(_1, const 35_i64); + StorageDead(_21); +- _19 = opaque::(move _20) -> [return: bb5, unwind unreachable]; ++ _19 = opaque::(_20) -> [return: bb5, unwind unreachable]; + } + + bb5: { +- StorageDead(_20); ++ nop; + StorageDead(_19); + StorageLive(_22); + StorageLive(_23); + StorageLive(_24); + StorageLive(_25); + _25 = _1; +- _24 = Ne(move _25, const 35_i64); ++ _24 = Ne(_1, const 35_i64); + StorageDead(_25); +- _23 = Not(move _24); ++ _23 = _20; + StorageDead(_24); +- _22 = opaque::(move _23) -> [return: bb6, unwind unreachable]; ++ _22 = opaque::(_20) -> [return: bb6, unwind unreachable]; + } + + bb6: { + StorageDead(_23); + StorageDead(_22); + _0 = const (); +- StorageDead(_6); ++ nop; + return; + } + } + diff --git a/tests/mir-opt/gvn.unary.GVN.panic-unwind.diff b/tests/mir-opt/gvn.unary.GVN.panic-unwind.diff new file mode 100644 index 0000000000000..e672f6fb6ba71 --- /dev/null +++ b/tests/mir-opt/gvn.unary.GVN.panic-unwind.diff @@ -0,0 +1,153 @@ +- // MIR for `unary` before GVN ++ // MIR for `unary` after GVN + + fn unary(_1: i64) -> () { + debug x => _1; + let mut _0: (); + let _2: (); + let mut _3: i64; + let mut _4: i64; + let mut _5: i64; + let _6: bool; + let mut _7: i64; + let _8: (); + let mut _9: bool; + let mut _10: bool; + let mut _11: bool; + let _12: (); + let mut _13: bool; + let mut _14: i64; + let _15: (); + let mut _16: bool; + let mut _17: bool; + let mut _18: i64; + let _19: (); + let mut _20: bool; + let mut _21: i64; + let _22: (); + let mut _23: bool; + let mut _24: bool; + let mut _25: i64; + scope 1 { + debug b => _6; + } + + bb0: { + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + StorageLive(_5); + _5 = _1; +- _4 = Neg(move _5); ++ _4 = Neg(_1); + StorageDead(_5); +- _3 = Neg(move _4); ++ _3 = _1; + StorageDead(_4); +- _2 = opaque::(move _3) -> [return: bb1, unwind continue]; ++ _2 = opaque::(_1) -> [return: bb1, unwind continue]; + } + + bb1: { + StorageDead(_3); + StorageDead(_2); +- StorageLive(_6); ++ nop; + StorageLive(_7); + _7 = _1; +- _6 = Lt(move _7, const 13_i64); ++ _6 = Lt(_1, const 13_i64); + StorageDead(_7); + StorageLive(_8); + StorageLive(_9); + StorageLive(_10); + StorageLive(_11); + _11 = _6; +- _10 = Not(move _11); ++ _10 = Not(_6); + StorageDead(_11); +- _9 = Not(move _10); ++ _9 = _6; + StorageDead(_10); +- _8 = opaque::(move _9) -> [return: bb2, unwind continue]; ++ _8 = opaque::(_6) -> [return: bb2, unwind continue]; + } + + bb2: { + StorageDead(_9); + StorageDead(_8); + StorageLive(_12); +- StorageLive(_13); ++ nop; + StorageLive(_14); + _14 = _1; +- _13 = Ne(move _14, const 15_i64); ++ _13 = Ne(_1, const 15_i64); + StorageDead(_14); +- _12 = opaque::(move _13) -> [return: bb3, unwind continue]; ++ _12 = opaque::(_13) -> [return: bb3, unwind continue]; + } + + bb3: { +- StorageDead(_13); ++ nop; + StorageDead(_12); + StorageLive(_15); + StorageLive(_16); + StorageLive(_17); + StorageLive(_18); + _18 = _1; +- _17 = Eq(move _18, const 15_i64); ++ _17 = Eq(_1, const 15_i64); + StorageDead(_18); +- _16 = Not(move _17); ++ _16 = _13; + StorageDead(_17); +- _15 = opaque::(move _16) -> [return: bb4, unwind continue]; ++ _15 = opaque::(_13) -> [return: bb4, unwind continue]; + } + + bb4: { + StorageDead(_16); + StorageDead(_15); + StorageLive(_19); +- StorageLive(_20); ++ nop; + StorageLive(_21); + _21 = _1; +- _20 = Eq(move _21, const 35_i64); ++ _20 = Eq(_1, const 35_i64); + StorageDead(_21); +- _19 = opaque::(move _20) -> [return: bb5, unwind continue]; ++ _19 = opaque::(_20) -> [return: bb5, unwind continue]; + } + + bb5: { +- StorageDead(_20); ++ nop; + StorageDead(_19); + StorageLive(_22); + StorageLive(_23); + StorageLive(_24); + StorageLive(_25); + _25 = _1; +- _24 = Ne(move _25, const 35_i64); ++ _24 = Ne(_1, const 35_i64); + StorageDead(_25); +- _23 = Not(move _24); ++ _23 = _20; + StorageDead(_24); +- _22 = opaque::(move _23) -> [return: bb6, unwind continue]; ++ _22 = opaque::(_20) -> [return: bb6, unwind continue]; + } + + bb6: { + StorageDead(_23); + StorageDead(_22); + _0 = const (); +- StorageDead(_6); ++ nop; + return; + } + } + From 3c48243b6fd28aeb27c856f8d23433e9f3ebaa0d Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 20 Mar 2023 20:15:59 +0000 Subject: [PATCH 0310/1197] Simplify Len. --- compiler/rustc_mir_transform/src/gvn.rs | 38 +++++++++++++++++-- ...rray_index.main.GVN.32bit.panic-abort.diff | 7 ++-- ...ray_index.main.GVN.32bit.panic-unwind.diff | 7 ++-- ...rray_index.main.GVN.64bit.panic-abort.diff | 7 ++-- ...ray_index.main.GVN.64bit.panic-unwind.diff | 7 ++-- ...rray_index.main.GVN.32bit.panic-abort.diff | 7 ++-- ...ray_index.main.GVN.32bit.panic-unwind.diff | 7 ++-- ...rray_index.main.GVN.64bit.panic-abort.diff | 7 ++-- ...ray_index.main.GVN.64bit.panic-unwind.diff | 7 ++-- .../repeat.main.GVN.32bit.panic-abort.diff | 7 ++-- .../repeat.main.GVN.32bit.panic-unwind.diff | 7 ++-- .../repeat.main.GVN.64bit.panic-abort.diff | 7 ++-- .../repeat.main.GVN.64bit.panic-unwind.diff | 7 ++-- .../gvn.repeated_index.GVN.panic-abort.diff | 13 ++++--- .../gvn.repeated_index.GVN.panic-unwind.diff | 13 ++++--- 15 files changed, 96 insertions(+), 52 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 699b218d46d57..afc75ff1313d8 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -776,10 +776,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } // Operations. - Rvalue::Len(ref mut place) => { - let place = self.simplify_place_value(place, location)?; - Value::Len(place) - } + Rvalue::Len(ref mut place) => return self.simplify_len(place, location), Rvalue::Cast(kind, ref mut value, to) => { let from = value.ty(self.local_decls, self.tcx); let value = self.simplify_operand(value, location)?; @@ -1021,6 +1018,39 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { Some(result) } } + + fn simplify_len(&mut self, place: &mut Place<'tcx>, location: Location) -> Option { + // Trivial case: we are fetching a statically known length. + let place_ty = place.ty(self.local_decls, self.tcx).ty; + if let ty::Array(_, len) = place_ty.kind() { + return self.insert_constant(Const::from_ty_const(*len, self.tcx)); + } + + let mut inner = self.simplify_place_value(place, location)?; + + // The length information is stored in the fat pointer. + // Reborrowing copies length information from one pointer to the other. + while let Value::Address { place: borrowed, .. } = self.get(inner) + && let [PlaceElem::Deref] = borrowed.projection[..] + && let Some(borrowed) = self.locals[borrowed.local] + { + inner = borrowed; + } + + // We have an unsizing cast, which assigns the length to fat pointer metadata. + if let Value::Cast { kind, from, to, .. } = self.get(inner) + && let CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize) = kind + && let Some(from) = from.builtin_deref(true) + && let ty::Array(_, len) = from.ty.kind() + && let Some(to) = to.builtin_deref(true) + && let ty::Slice(..) = to.ty.kind() + { + return self.insert_constant(Const::from_ty_const(*len, self.tcx)); + } + + // Fallback: a symbolic `Len`. + Some(self.insert(Value::Len(inner))) + } } fn op_to_prop_const<'tcx>( diff --git a/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-abort.diff index f9537661e8ca1..6d00dd5b21260 100644 --- a/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-abort.diff @@ -18,11 +18,12 @@ _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; StorageLive(_3); _3 = const 2_usize; - _4 = Len(_2); +- _4 = Len(_2); - _5 = Lt(_3, _4); - assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable]; -+ _5 = Lt(const 2_usize, _4); -+ assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind unreachable]; ++ _4 = const 4_usize; ++ _5 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind unreachable]; } bb1: { diff --git a/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff index 07886779fead4..7e2f72ab31bce 100644 --- a/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff @@ -18,11 +18,12 @@ _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; StorageLive(_3); _3 = const 2_usize; - _4 = Len(_2); +- _4 = Len(_2); - _5 = Lt(_3, _4); - assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue]; -+ _5 = Lt(const 2_usize, _4); -+ assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind continue]; ++ _4 = const 4_usize; ++ _5 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind continue]; } bb1: { diff --git a/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-abort.diff index f9537661e8ca1..6d00dd5b21260 100644 --- a/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-abort.diff @@ -18,11 +18,12 @@ _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; StorageLive(_3); _3 = const 2_usize; - _4 = Len(_2); +- _4 = Len(_2); - _5 = Lt(_3, _4); - assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable]; -+ _5 = Lt(const 2_usize, _4); -+ assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind unreachable]; ++ _4 = const 4_usize; ++ _5 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind unreachable]; } bb1: { diff --git a/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff index 07886779fead4..7e2f72ab31bce 100644 --- a/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff @@ -18,11 +18,12 @@ _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; StorageLive(_3); _3 = const 2_usize; - _4 = Len(_2); +- _4 = Len(_2); - _5 = Lt(_3, _4); - assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue]; -+ _5 = Lt(const 2_usize, _4); -+ assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind continue]; ++ _4 = const 4_usize; ++ _5 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind continue]; } bb1: { diff --git a/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-abort.diff index cf36109fdcbdd..bd987c01ab16f 100644 --- a/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-abort.diff @@ -18,11 +18,12 @@ _2 = [const 0_u8; 5000]; StorageLive(_3); _3 = const 2_usize; - _4 = Len(_2); +- _4 = Len(_2); - _5 = Lt(_3, _4); - assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable]; -+ _5 = Lt(const 2_usize, _4); -+ assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind unreachable]; ++ _4 = const 5000_usize; ++ _5 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind unreachable]; } bb1: { diff --git a/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-unwind.diff index 40ed969718007..e9ebef84ae048 100644 --- a/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-unwind.diff @@ -18,11 +18,12 @@ _2 = [const 0_u8; 5000]; StorageLive(_3); _3 = const 2_usize; - _4 = Len(_2); +- _4 = Len(_2); - _5 = Lt(_3, _4); - assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue]; -+ _5 = Lt(const 2_usize, _4); -+ assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind continue]; ++ _4 = const 5000_usize; ++ _5 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind continue]; } bb1: { diff --git a/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-abort.diff index cf36109fdcbdd..bd987c01ab16f 100644 --- a/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-abort.diff @@ -18,11 +18,12 @@ _2 = [const 0_u8; 5000]; StorageLive(_3); _3 = const 2_usize; - _4 = Len(_2); +- _4 = Len(_2); - _5 = Lt(_3, _4); - assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable]; -+ _5 = Lt(const 2_usize, _4); -+ assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind unreachable]; ++ _4 = const 5000_usize; ++ _5 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind unreachable]; } bb1: { diff --git a/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-unwind.diff index 40ed969718007..e9ebef84ae048 100644 --- a/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-unwind.diff @@ -18,11 +18,12 @@ _2 = [const 0_u8; 5000]; StorageLive(_3); _3 = const 2_usize; - _4 = Len(_2); +- _4 = Len(_2); - _5 = Lt(_3, _4); - assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue]; -+ _5 = Lt(const 2_usize, _4); -+ assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind continue]; ++ _4 = const 5000_usize; ++ _5 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind continue]; } bb1: { diff --git a/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-abort.diff index a52e6e35483d6..71635b8e9c3e7 100644 --- a/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-abort.diff @@ -20,11 +20,12 @@ _3 = [const 42_u32; 8]; StorageLive(_4); _4 = const 2_usize; - _5 = Len(_3); +- _5 = Len(_3); - _6 = Lt(_4, _5); - assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind unreachable]; -+ _6 = Lt(const 2_usize, _5); -+ assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, const 2_usize) -> [success: bb1, unwind unreachable]; ++ _5 = const 8_usize; ++ _6 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind unreachable]; } bb1: { diff --git a/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-unwind.diff index fe0acee71ebe4..84205028d6d2b 100644 --- a/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-unwind.diff @@ -20,11 +20,12 @@ _3 = [const 42_u32; 8]; StorageLive(_4); _4 = const 2_usize; - _5 = Len(_3); +- _5 = Len(_3); - _6 = Lt(_4, _5); - assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind continue]; -+ _6 = Lt(const 2_usize, _5); -+ assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, const 2_usize) -> [success: bb1, unwind continue]; ++ _5 = const 8_usize; ++ _6 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind continue]; } bb1: { diff --git a/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-abort.diff index a52e6e35483d6..71635b8e9c3e7 100644 --- a/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-abort.diff @@ -20,11 +20,12 @@ _3 = [const 42_u32; 8]; StorageLive(_4); _4 = const 2_usize; - _5 = Len(_3); +- _5 = Len(_3); - _6 = Lt(_4, _5); - assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind unreachable]; -+ _6 = Lt(const 2_usize, _5); -+ assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, const 2_usize) -> [success: bb1, unwind unreachable]; ++ _5 = const 8_usize; ++ _6 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind unreachable]; } bb1: { diff --git a/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-unwind.diff index fe0acee71ebe4..84205028d6d2b 100644 --- a/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-unwind.diff @@ -20,11 +20,12 @@ _3 = [const 42_u32; 8]; StorageLive(_4); _4 = const 2_usize; - _5 = Len(_3); +- _5 = Len(_3); - _6 = Lt(_4, _5); - assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind continue]; -+ _6 = Lt(const 2_usize, _5); -+ assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, const 2_usize) -> [success: bb1, unwind continue]; ++ _5 = const 8_usize; ++ _6 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind continue]; } bb1: { diff --git a/tests/mir-opt/gvn.repeated_index.GVN.panic-abort.diff b/tests/mir-opt/gvn.repeated_index.GVN.panic-abort.diff index d937902e89138..8ce05c9b340fe 100644 --- a/tests/mir-opt/gvn.repeated_index.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.repeated_index.GVN.panic-abort.diff @@ -32,11 +32,12 @@ StorageLive(_6); StorageLive(_7); _7 = const 0_usize; - _8 = Len(_3); +- _8 = Len(_3); - _9 = Lt(_7, _8); - assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> [success: bb1, unwind unreachable]; -+ _9 = Lt(const 0_usize, _8); -+ assert(move _9, "index out of bounds: the length is {} but the index is {}", _8, const 0_usize) -> [success: bb1, unwind unreachable]; ++ _8 = const N; ++ _9 = Lt(const 0_usize, const N); ++ assert(move _9, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb1, unwind unreachable]; } bb1: { @@ -57,9 +58,9 @@ - _13 = Len(_3); - _14 = Lt(_12, _13); - assert(move _14, "index out of bounds: the length is {} but the index is {}", move _13, _12) -> [success: bb3, unwind unreachable]; -+ _13 = _8; -+ _14 = Lt(_2, _8); -+ assert(move _14, "index out of bounds: the length is {} but the index is {}", _8, _2) -> [success: bb3, unwind unreachable]; ++ _13 = const N; ++ _14 = Lt(_2, const N); ++ assert(move _14, "index out of bounds: the length is {} but the index is {}", const N, _2) -> [success: bb3, unwind unreachable]; } bb3: { diff --git a/tests/mir-opt/gvn.repeated_index.GVN.panic-unwind.diff b/tests/mir-opt/gvn.repeated_index.GVN.panic-unwind.diff index dd4d24b12ea61..7ed547eeb4ade 100644 --- a/tests/mir-opt/gvn.repeated_index.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.repeated_index.GVN.panic-unwind.diff @@ -32,11 +32,12 @@ StorageLive(_6); StorageLive(_7); _7 = const 0_usize; - _8 = Len(_3); +- _8 = Len(_3); - _9 = Lt(_7, _8); - assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> [success: bb1, unwind continue]; -+ _9 = Lt(const 0_usize, _8); -+ assert(move _9, "index out of bounds: the length is {} but the index is {}", _8, const 0_usize) -> [success: bb1, unwind continue]; ++ _8 = const N; ++ _9 = Lt(const 0_usize, const N); ++ assert(move _9, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb1, unwind continue]; } bb1: { @@ -57,9 +58,9 @@ - _13 = Len(_3); - _14 = Lt(_12, _13); - assert(move _14, "index out of bounds: the length is {} but the index is {}", move _13, _12) -> [success: bb3, unwind continue]; -+ _13 = _8; -+ _14 = Lt(_2, _8); -+ assert(move _14, "index out of bounds: the length is {} but the index is {}", _8, _2) -> [success: bb3, unwind continue]; ++ _13 = const N; ++ _14 = Lt(_2, const N); ++ assert(move _14, "index out of bounds: the length is {} but the index is {}", const N, _2) -> [success: bb3, unwind continue]; } bb3: { From 22ed51e136c8ad3a07d181b90e7610501ea69816 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Tue, 31 Oct 2023 19:29:08 +0000 Subject: [PATCH 0311/1197] Do not read a scalar on a non-scalar layout. --- compiler/rustc_mir_transform/src/gvn.rs | 9 +- tests/mir-opt/gvn.rs | 23 ++ .../gvn.wide_ptr_ops.GVN.panic-abort.diff | 386 ++++++++++++++++++ .../gvn.wide_ptr_ops.GVN.panic-unwind.diff | 386 ++++++++++++++++++ 4 files changed, 802 insertions(+), 2 deletions(-) create mode 100644 tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-abort.diff create mode 100644 tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-unwind.diff diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index afc75ff1313d8..fc14ea2696ff6 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -953,8 +953,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let as_bits = |value| { let constant = self.evaluated[value].as_ref()?; - let scalar = self.ecx.read_scalar(constant).ok()?; - scalar.to_bits(constant.layout.size).ok() + if layout.abi.is_scalar() { + let scalar = self.ecx.read_scalar(constant).ok()?; + scalar.to_bits(constant.layout.size).ok() + } else { + // `constant` is a wide pointer. Do not evaluate to bits. + None + } }; // Represent the values as `Ok(bits)` or `Err(VnIndex)`. diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs index f8f4fdcd7323e..31ea237cbec8a 100644 --- a/tests/mir-opt/gvn.rs +++ b/tests/mir-opt/gvn.rs @@ -644,6 +644,27 @@ fn constant_index_overflow(x: &[T]) { opaque(b) } +fn wide_ptr_ops() { + let a: *const dyn Send = &1 as &dyn Send; + let b: *const dyn Send = &1 as &dyn Send; + let _val = a == b; + let _val = a != b; + let _val = a < b; + let _val = a <= b; + let _val = a > b; + let _val = a >= b; + + let a: *const [u8] = unsafe { transmute((1usize, 1usize)) }; + let b: *const [u8] = unsafe { transmute((1usize, 2usize)) }; + + opaque(!(a == b)); + opaque(a != b); + opaque(a <= b); + opaque(a < b); + opaque(!(a >= b)); + opaque(!(a > b)); +} + fn main() { subexpression_elimination(2, 4, 5); wrap_unwrap(5); @@ -664,6 +685,7 @@ fn main() { fn_pointers(); indirect_static(); constant_index_overflow(&[5, 3]); + wide_ptr_ops(); } #[inline(never)] @@ -692,3 +714,4 @@ fn identity(x: T) -> T { // EMIT_MIR gvn.fn_pointers.GVN.diff // EMIT_MIR gvn.indirect_static.GVN.diff // EMIT_MIR gvn.constant_index_overflow.GVN.diff +// EMIT_MIR gvn.wide_ptr_ops.GVN.diff diff --git a/tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-abort.diff b/tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-abort.diff new file mode 100644 index 0000000000000..e49d759b8fc31 --- /dev/null +++ b/tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-abort.diff @@ -0,0 +1,386 @@ +- // MIR for `wide_ptr_ops` before GVN ++ // MIR for `wide_ptr_ops` after GVN + + fn wide_ptr_ops() -> () { + let mut _0: (); + let _1: *const dyn std::marker::Send; + let mut _2: *const dyn std::marker::Send; + let _3: &dyn std::marker::Send; + let mut _4: &i32; + let _5: &i32; + let _6: i32; + let mut _8: *const dyn std::marker::Send; + let _9: &dyn std::marker::Send; + let mut _10: &i32; + let _11: &i32; + let _12: i32; + let mut _14: *const dyn std::marker::Send; + let mut _15: *const dyn std::marker::Send; + let mut _16: *const dyn std::marker::Send; + let mut _18: *const dyn std::marker::Send; + let mut _19: *const dyn std::marker::Send; + let mut _20: *const dyn std::marker::Send; + let mut _22: *const dyn std::marker::Send; + let mut _23: *const dyn std::marker::Send; + let mut _24: *const dyn std::marker::Send; + let mut _26: *const dyn std::marker::Send; + let mut _27: *const dyn std::marker::Send; + let mut _28: *const dyn std::marker::Send; + let mut _30: *const dyn std::marker::Send; + let mut _31: *const dyn std::marker::Send; + let mut _32: *const dyn std::marker::Send; + let mut _34: *const dyn std::marker::Send; + let mut _35: *const dyn std::marker::Send; + let mut _36: *const dyn std::marker::Send; + let mut _38: (usize, usize); + let mut _40: (usize, usize); + let _41: (); + let mut _42: bool; + let mut _43: bool; + let mut _44: *const [u8]; + let mut _45: *const [u8]; + let _46: (); + let mut _47: bool; + let mut _48: *const [u8]; + let mut _49: *const [u8]; + let _50: (); + let mut _51: bool; + let mut _52: *const [u8]; + let mut _53: *const [u8]; + let _54: (); + let mut _55: bool; + let mut _56: *const [u8]; + let mut _57: *const [u8]; + let _58: (); + let mut _59: bool; + let mut _60: bool; + let mut _61: *const [u8]; + let mut _62: *const [u8]; + let _63: (); + let mut _64: bool; + let mut _65: bool; + let mut _66: *const [u8]; + let mut _67: *const [u8]; + let mut _69: &i32; + scope 1 { + debug a => _1; + let _7: *const dyn std::marker::Send; + let mut _68: &i32; + scope 2 { + debug b => _7; + let _13: bool; + scope 3 { + debug _val => _13; + let _17: bool; + scope 4 { + debug _val => _17; + let _21: bool; + scope 5 { + debug _val => _21; + let _25: bool; + scope 6 { + debug _val => _25; + let _29: bool; + scope 7 { + debug _val => _29; + let _33: bool; + scope 8 { + debug _val => _33; + let _37: *const [u8]; + scope 9 { + debug a => _37; + let _39: *const [u8]; + scope 11 { + debug b => _39; + } + scope 12 { + } + } + scope 10 { + } + } + } + } + } + } + } + } + } + + bb0: { +- StorageLive(_1); ++ nop; + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + StorageLive(_5); + _69 = const _; + _5 = &(*_69); + _4 = &(*_5); + _3 = move _4 as &dyn std::marker::Send (PointerCoercion(Unsize)); + StorageDead(_4); + _2 = &raw const (*_3); + _1 = move _2 as *const dyn std::marker::Send (PointerCoercion(Unsize)); + StorageDead(_2); + StorageDead(_5); + StorageDead(_3); +- StorageLive(_7); ++ nop; + StorageLive(_8); + StorageLive(_9); + StorageLive(_10); + StorageLive(_11); + _68 = const _; + _11 = &(*_68); + _10 = &(*_11); + _9 = move _10 as &dyn std::marker::Send (PointerCoercion(Unsize)); + StorageDead(_10); + _8 = &raw const (*_9); + _7 = move _8 as *const dyn std::marker::Send (PointerCoercion(Unsize)); + StorageDead(_8); + StorageDead(_11); + StorageDead(_9); + StorageLive(_13); + StorageLive(_14); + _14 = _1; +- StorageLive(_15); ++ nop; + StorageLive(_16); + _16 = _7; +- _15 = move _16 as *const dyn std::marker::Send (PointerCoercion(Unsize)); ++ _15 = _7 as *const dyn std::marker::Send (PointerCoercion(Unsize)); + StorageDead(_16); +- _13 = Eq(move _14, move _15); +- StorageDead(_15); ++ _13 = Eq(_1, _15); ++ nop; + StorageDead(_14); + StorageLive(_17); + StorageLive(_18); + _18 = _1; + StorageLive(_19); + StorageLive(_20); + _20 = _7; +- _19 = move _20 as *const dyn std::marker::Send (PointerCoercion(Unsize)); ++ _19 = _15; + StorageDead(_20); +- _17 = Ne(move _18, move _19); ++ _17 = Ne(_1, _15); + StorageDead(_19); + StorageDead(_18); + StorageLive(_21); + StorageLive(_22); + _22 = _1; + StorageLive(_23); + StorageLive(_24); + _24 = _7; +- _23 = move _24 as *const dyn std::marker::Send (PointerCoercion(Unsize)); ++ _23 = _15; + StorageDead(_24); +- _21 = Lt(move _22, move _23); ++ _21 = Lt(_1, _15); + StorageDead(_23); + StorageDead(_22); + StorageLive(_25); + StorageLive(_26); + _26 = _1; + StorageLive(_27); + StorageLive(_28); + _28 = _7; +- _27 = move _28 as *const dyn std::marker::Send (PointerCoercion(Unsize)); ++ _27 = _15; + StorageDead(_28); +- _25 = Le(move _26, move _27); ++ _25 = Le(_1, _15); + StorageDead(_27); + StorageDead(_26); + StorageLive(_29); + StorageLive(_30); + _30 = _1; + StorageLive(_31); + StorageLive(_32); + _32 = _7; +- _31 = move _32 as *const dyn std::marker::Send (PointerCoercion(Unsize)); ++ _31 = _15; + StorageDead(_32); +- _29 = Gt(move _30, move _31); ++ _29 = Gt(_1, _15); + StorageDead(_31); + StorageDead(_30); + StorageLive(_33); + StorageLive(_34); + _34 = _1; + StorageLive(_35); + StorageLive(_36); + _36 = _7; +- _35 = move _36 as *const dyn std::marker::Send (PointerCoercion(Unsize)); ++ _35 = _15; + StorageDead(_36); +- _33 = Ge(move _34, move _35); ++ _33 = Ge(_1, _15); + StorageDead(_35); + StorageDead(_34); +- StorageLive(_37); ++ nop; + StorageLive(_38); +- _38 = (const 1_usize, const 1_usize); +- _37 = move _38 as *const [u8] (Transmute); ++ _38 = const (1_usize, 1_usize); ++ _37 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8]; + StorageDead(_38); +- StorageLive(_39); ++ nop; + StorageLive(_40); +- _40 = (const 1_usize, const 2_usize); +- _39 = move _40 as *const [u8] (Transmute); ++ _40 = const (1_usize, 2_usize); ++ _39 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]; + StorageDead(_40); + StorageLive(_41); +- StorageLive(_42); ++ nop; + StorageLive(_43); + StorageLive(_44); +- _44 = _37; ++ _44 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8]; + StorageLive(_45); +- _45 = _39; +- _43 = Eq(move _44, move _45); ++ _45 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]; ++ _43 = Eq(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]); + StorageDead(_45); + StorageDead(_44); + _42 = Not(move _43); + StorageDead(_43); +- _41 = opaque::(move _42) -> [return: bb1, unwind unreachable]; ++ _41 = opaque::(_42) -> [return: bb1, unwind unreachable]; + } + + bb1: { +- StorageDead(_42); ++ nop; + StorageDead(_41); + StorageLive(_46); + StorageLive(_47); + StorageLive(_48); +- _48 = _37; ++ _48 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8]; + StorageLive(_49); +- _49 = _39; +- _47 = Ne(move _48, move _49); ++ _49 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]; ++ _47 = _42; + StorageDead(_49); + StorageDead(_48); +- _46 = opaque::(move _47) -> [return: bb2, unwind unreachable]; ++ _46 = opaque::(_42) -> [return: bb2, unwind unreachable]; + } + + bb2: { + StorageDead(_47); + StorageDead(_46); + StorageLive(_50); + StorageLive(_51); + StorageLive(_52); +- _52 = _37; ++ _52 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8]; + StorageLive(_53); +- _53 = _39; +- _51 = Le(move _52, move _53); ++ _53 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]; ++ _51 = Le(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]); + StorageDead(_53); + StorageDead(_52); + _50 = opaque::(move _51) -> [return: bb3, unwind unreachable]; + } + + bb3: { + StorageDead(_51); + StorageDead(_50); + StorageLive(_54); + StorageLive(_55); + StorageLive(_56); +- _56 = _37; ++ _56 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8]; + StorageLive(_57); +- _57 = _39; +- _55 = Lt(move _56, move _57); ++ _57 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]; ++ _55 = Lt(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]); + StorageDead(_57); + StorageDead(_56); + _54 = opaque::(move _55) -> [return: bb4, unwind unreachable]; + } + + bb4: { + StorageDead(_55); + StorageDead(_54); + StorageLive(_58); + StorageLive(_59); + StorageLive(_60); + StorageLive(_61); +- _61 = _37; ++ _61 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8]; + StorageLive(_62); +- _62 = _39; +- _60 = Ge(move _61, move _62); ++ _62 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]; ++ _60 = Ge(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]); + StorageDead(_62); + StorageDead(_61); + _59 = Not(move _60); + StorageDead(_60); + _58 = opaque::(move _59) -> [return: bb5, unwind unreachable]; + } + + bb5: { + StorageDead(_59); + StorageDead(_58); + StorageLive(_63); + StorageLive(_64); + StorageLive(_65); + StorageLive(_66); +- _66 = _37; ++ _66 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8]; + StorageLive(_67); +- _67 = _39; +- _65 = Gt(move _66, move _67); ++ _67 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]; ++ _65 = Gt(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]); + StorageDead(_67); + StorageDead(_66); + _64 = Not(move _65); + StorageDead(_65); + _63 = opaque::(move _64) -> [return: bb6, unwind unreachable]; + } + + bb6: { + StorageDead(_64); + StorageDead(_63); + _0 = const (); +- StorageDead(_39); +- StorageDead(_37); ++ nop; ++ nop; + StorageDead(_33); + StorageDead(_29); + StorageDead(_25); + StorageDead(_21); + StorageDead(_17); + StorageDead(_13); +- StorageDead(_7); +- StorageDead(_1); ++ nop; ++ nop; + return; + } ++ } ++ ++ ALLOC1 (size: 16, align: 8) { ++ 01 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 │ ................ ++ } ++ ++ ALLOC0 (size: 16, align: 8) { ++ 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 │ ................ + } + diff --git a/tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-unwind.diff b/tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-unwind.diff new file mode 100644 index 0000000000000..4e5608a4425f7 --- /dev/null +++ b/tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-unwind.diff @@ -0,0 +1,386 @@ +- // MIR for `wide_ptr_ops` before GVN ++ // MIR for `wide_ptr_ops` after GVN + + fn wide_ptr_ops() -> () { + let mut _0: (); + let _1: *const dyn std::marker::Send; + let mut _2: *const dyn std::marker::Send; + let _3: &dyn std::marker::Send; + let mut _4: &i32; + let _5: &i32; + let _6: i32; + let mut _8: *const dyn std::marker::Send; + let _9: &dyn std::marker::Send; + let mut _10: &i32; + let _11: &i32; + let _12: i32; + let mut _14: *const dyn std::marker::Send; + let mut _15: *const dyn std::marker::Send; + let mut _16: *const dyn std::marker::Send; + let mut _18: *const dyn std::marker::Send; + let mut _19: *const dyn std::marker::Send; + let mut _20: *const dyn std::marker::Send; + let mut _22: *const dyn std::marker::Send; + let mut _23: *const dyn std::marker::Send; + let mut _24: *const dyn std::marker::Send; + let mut _26: *const dyn std::marker::Send; + let mut _27: *const dyn std::marker::Send; + let mut _28: *const dyn std::marker::Send; + let mut _30: *const dyn std::marker::Send; + let mut _31: *const dyn std::marker::Send; + let mut _32: *const dyn std::marker::Send; + let mut _34: *const dyn std::marker::Send; + let mut _35: *const dyn std::marker::Send; + let mut _36: *const dyn std::marker::Send; + let mut _38: (usize, usize); + let mut _40: (usize, usize); + let _41: (); + let mut _42: bool; + let mut _43: bool; + let mut _44: *const [u8]; + let mut _45: *const [u8]; + let _46: (); + let mut _47: bool; + let mut _48: *const [u8]; + let mut _49: *const [u8]; + let _50: (); + let mut _51: bool; + let mut _52: *const [u8]; + let mut _53: *const [u8]; + let _54: (); + let mut _55: bool; + let mut _56: *const [u8]; + let mut _57: *const [u8]; + let _58: (); + let mut _59: bool; + let mut _60: bool; + let mut _61: *const [u8]; + let mut _62: *const [u8]; + let _63: (); + let mut _64: bool; + let mut _65: bool; + let mut _66: *const [u8]; + let mut _67: *const [u8]; + let mut _69: &i32; + scope 1 { + debug a => _1; + let _7: *const dyn std::marker::Send; + let mut _68: &i32; + scope 2 { + debug b => _7; + let _13: bool; + scope 3 { + debug _val => _13; + let _17: bool; + scope 4 { + debug _val => _17; + let _21: bool; + scope 5 { + debug _val => _21; + let _25: bool; + scope 6 { + debug _val => _25; + let _29: bool; + scope 7 { + debug _val => _29; + let _33: bool; + scope 8 { + debug _val => _33; + let _37: *const [u8]; + scope 9 { + debug a => _37; + let _39: *const [u8]; + scope 11 { + debug b => _39; + } + scope 12 { + } + } + scope 10 { + } + } + } + } + } + } + } + } + } + + bb0: { +- StorageLive(_1); ++ nop; + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + StorageLive(_5); + _69 = const _; + _5 = &(*_69); + _4 = &(*_5); + _3 = move _4 as &dyn std::marker::Send (PointerCoercion(Unsize)); + StorageDead(_4); + _2 = &raw const (*_3); + _1 = move _2 as *const dyn std::marker::Send (PointerCoercion(Unsize)); + StorageDead(_2); + StorageDead(_5); + StorageDead(_3); +- StorageLive(_7); ++ nop; + StorageLive(_8); + StorageLive(_9); + StorageLive(_10); + StorageLive(_11); + _68 = const _; + _11 = &(*_68); + _10 = &(*_11); + _9 = move _10 as &dyn std::marker::Send (PointerCoercion(Unsize)); + StorageDead(_10); + _8 = &raw const (*_9); + _7 = move _8 as *const dyn std::marker::Send (PointerCoercion(Unsize)); + StorageDead(_8); + StorageDead(_11); + StorageDead(_9); + StorageLive(_13); + StorageLive(_14); + _14 = _1; +- StorageLive(_15); ++ nop; + StorageLive(_16); + _16 = _7; +- _15 = move _16 as *const dyn std::marker::Send (PointerCoercion(Unsize)); ++ _15 = _7 as *const dyn std::marker::Send (PointerCoercion(Unsize)); + StorageDead(_16); +- _13 = Eq(move _14, move _15); +- StorageDead(_15); ++ _13 = Eq(_1, _15); ++ nop; + StorageDead(_14); + StorageLive(_17); + StorageLive(_18); + _18 = _1; + StorageLive(_19); + StorageLive(_20); + _20 = _7; +- _19 = move _20 as *const dyn std::marker::Send (PointerCoercion(Unsize)); ++ _19 = _15; + StorageDead(_20); +- _17 = Ne(move _18, move _19); ++ _17 = Ne(_1, _15); + StorageDead(_19); + StorageDead(_18); + StorageLive(_21); + StorageLive(_22); + _22 = _1; + StorageLive(_23); + StorageLive(_24); + _24 = _7; +- _23 = move _24 as *const dyn std::marker::Send (PointerCoercion(Unsize)); ++ _23 = _15; + StorageDead(_24); +- _21 = Lt(move _22, move _23); ++ _21 = Lt(_1, _15); + StorageDead(_23); + StorageDead(_22); + StorageLive(_25); + StorageLive(_26); + _26 = _1; + StorageLive(_27); + StorageLive(_28); + _28 = _7; +- _27 = move _28 as *const dyn std::marker::Send (PointerCoercion(Unsize)); ++ _27 = _15; + StorageDead(_28); +- _25 = Le(move _26, move _27); ++ _25 = Le(_1, _15); + StorageDead(_27); + StorageDead(_26); + StorageLive(_29); + StorageLive(_30); + _30 = _1; + StorageLive(_31); + StorageLive(_32); + _32 = _7; +- _31 = move _32 as *const dyn std::marker::Send (PointerCoercion(Unsize)); ++ _31 = _15; + StorageDead(_32); +- _29 = Gt(move _30, move _31); ++ _29 = Gt(_1, _15); + StorageDead(_31); + StorageDead(_30); + StorageLive(_33); + StorageLive(_34); + _34 = _1; + StorageLive(_35); + StorageLive(_36); + _36 = _7; +- _35 = move _36 as *const dyn std::marker::Send (PointerCoercion(Unsize)); ++ _35 = _15; + StorageDead(_36); +- _33 = Ge(move _34, move _35); ++ _33 = Ge(_1, _15); + StorageDead(_35); + StorageDead(_34); +- StorageLive(_37); ++ nop; + StorageLive(_38); +- _38 = (const 1_usize, const 1_usize); +- _37 = move _38 as *const [u8] (Transmute); ++ _38 = const (1_usize, 1_usize); ++ _37 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8]; + StorageDead(_38); +- StorageLive(_39); ++ nop; + StorageLive(_40); +- _40 = (const 1_usize, const 2_usize); +- _39 = move _40 as *const [u8] (Transmute); ++ _40 = const (1_usize, 2_usize); ++ _39 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]; + StorageDead(_40); + StorageLive(_41); +- StorageLive(_42); ++ nop; + StorageLive(_43); + StorageLive(_44); +- _44 = _37; ++ _44 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8]; + StorageLive(_45); +- _45 = _39; +- _43 = Eq(move _44, move _45); ++ _45 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]; ++ _43 = Eq(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]); + StorageDead(_45); + StorageDead(_44); + _42 = Not(move _43); + StorageDead(_43); +- _41 = opaque::(move _42) -> [return: bb1, unwind continue]; ++ _41 = opaque::(_42) -> [return: bb1, unwind continue]; + } + + bb1: { +- StorageDead(_42); ++ nop; + StorageDead(_41); + StorageLive(_46); + StorageLive(_47); + StorageLive(_48); +- _48 = _37; ++ _48 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8]; + StorageLive(_49); +- _49 = _39; +- _47 = Ne(move _48, move _49); ++ _49 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]; ++ _47 = _42; + StorageDead(_49); + StorageDead(_48); +- _46 = opaque::(move _47) -> [return: bb2, unwind continue]; ++ _46 = opaque::(_42) -> [return: bb2, unwind continue]; + } + + bb2: { + StorageDead(_47); + StorageDead(_46); + StorageLive(_50); + StorageLive(_51); + StorageLive(_52); +- _52 = _37; ++ _52 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8]; + StorageLive(_53); +- _53 = _39; +- _51 = Le(move _52, move _53); ++ _53 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]; ++ _51 = Le(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]); + StorageDead(_53); + StorageDead(_52); + _50 = opaque::(move _51) -> [return: bb3, unwind continue]; + } + + bb3: { + StorageDead(_51); + StorageDead(_50); + StorageLive(_54); + StorageLive(_55); + StorageLive(_56); +- _56 = _37; ++ _56 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8]; + StorageLive(_57); +- _57 = _39; +- _55 = Lt(move _56, move _57); ++ _57 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]; ++ _55 = Lt(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]); + StorageDead(_57); + StorageDead(_56); + _54 = opaque::(move _55) -> [return: bb4, unwind continue]; + } + + bb4: { + StorageDead(_55); + StorageDead(_54); + StorageLive(_58); + StorageLive(_59); + StorageLive(_60); + StorageLive(_61); +- _61 = _37; ++ _61 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8]; + StorageLive(_62); +- _62 = _39; +- _60 = Ge(move _61, move _62); ++ _62 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]; ++ _60 = Ge(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]); + StorageDead(_62); + StorageDead(_61); + _59 = Not(move _60); + StorageDead(_60); + _58 = opaque::(move _59) -> [return: bb5, unwind continue]; + } + + bb5: { + StorageDead(_59); + StorageDead(_58); + StorageLive(_63); + StorageLive(_64); + StorageLive(_65); + StorageLive(_66); +- _66 = _37; ++ _66 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8]; + StorageLive(_67); +- _67 = _39; +- _65 = Gt(move _66, move _67); ++ _67 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]; ++ _65 = Gt(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]); + StorageDead(_67); + StorageDead(_66); + _64 = Not(move _65); + StorageDead(_65); + _63 = opaque::(move _64) -> [return: bb6, unwind continue]; + } + + bb6: { + StorageDead(_64); + StorageDead(_63); + _0 = const (); +- StorageDead(_39); +- StorageDead(_37); ++ nop; ++ nop; + StorageDead(_33); + StorageDead(_29); + StorageDead(_25); + StorageDead(_21); + StorageDead(_17); + StorageDead(_13); +- StorageDead(_7); +- StorageDead(_1); ++ nop; ++ nop; + return; + } ++ } ++ ++ ALLOC1 (size: 16, align: 8) { ++ 01 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 │ ................ ++ } ++ ++ ALLOC0 (size: 16, align: 8) { ++ 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 │ ................ + } + From 166fe54eba4b691b9c69b2a3a24e5b82bd9848e3 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 8 Jan 2024 22:44:38 +0000 Subject: [PATCH 0312/1197] Explain side-effects from simplify_operand. --- compiler/rustc_mir_transform/src/gvn.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index fc14ea2696ff6..7a8e3b87b9bf2 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -794,6 +794,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let ty = lhs.ty(self.local_decls, self.tcx); let lhs = self.simplify_operand(lhs, location); let rhs = self.simplify_operand(rhs, location); + // Only short-circuit options after we called `simplify_operand` + // on both operands for side effect. let lhs = lhs?; let rhs = rhs?; if let Some(value) = self.simplify_binary(op, false, ty, lhs, rhs) { @@ -805,6 +807,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let ty = lhs.ty(self.local_decls, self.tcx); let lhs = self.simplify_operand(lhs, location); let rhs = self.simplify_operand(rhs, location); + // Only short-circuit options after we called `simplify_operand` + // on both operands for side effect. let lhs = lhs?; let rhs = rhs?; if let Some(value) = self.simplify_binary(op, true, ty, lhs, rhs) { From 0cc2102c4a615fa8f259de491675d9e64606b022 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 8 Jan 2024 22:54:05 +0000 Subject: [PATCH 0313/1197] Expand match over binops. --- compiler/rustc_mir_transform/src/gvn.rs | 33 ++++++++++++++----------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 7a8e3b87b9bf2..390ec3e1a36ac 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -966,12 +966,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } }; - // Represent the values as `Ok(bits)` or `Err(VnIndex)`. - let a = as_bits(lhs).ok_or(lhs); - let b = as_bits(rhs).ok_or(rhs); + // Represent the values as `Left(bits)` or `Right(VnIndex)`. + use Either::{Left, Right}; + let a = as_bits(lhs).map_or(Right(lhs), Left); + let b = as_bits(rhs).map_or(Right(rhs), Left); let result = match (op, a, b) { // Neutral elements. - (BinOp::Add | BinOp::BitOr | BinOp::BitXor, Ok(0), Err(p)) + (BinOp::Add | BinOp::BitOr | BinOp::BitXor, Left(0), Right(p)) | ( BinOp::Add | BinOp::BitOr @@ -980,28 +981,28 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { | BinOp::Offset | BinOp::Shl | BinOp::Shr, - Err(p), - Ok(0), + Right(p), + Left(0), ) - | (BinOp::Mul, Ok(1), Err(p)) - | (BinOp::Mul | BinOp::Div, Err(p), Ok(1)) => p, + | (BinOp::Mul, Left(1), Right(p)) + | (BinOp::Mul | BinOp::Div, Right(p), Left(1)) => p, // Attempt to simplify `x & ALL_ONES` to `x`, with `ALL_ONES` depending on type size. - (BinOp::BitAnd, Err(p), Ok(ones)) | (BinOp::BitAnd, Ok(ones), Err(p)) + (BinOp::BitAnd, Right(p), Left(ones)) | (BinOp::BitAnd, Left(ones), Right(p)) if ones == layout.size.truncate(u128::MAX) || (layout.ty.is_bool() && ones == 1) => { p } // Absorbing elements. - (BinOp::Mul | BinOp::BitAnd, _, Ok(0)) - | (BinOp::Rem, _, Ok(1)) + (BinOp::Mul | BinOp::BitAnd, _, Left(0)) + | (BinOp::Rem, _, Left(1)) | ( BinOp::Mul | BinOp::Div | BinOp::Rem | BinOp::BitAnd | BinOp::Shl | BinOp::Shr, - Ok(0), + Left(0), _, ) => self.insert_scalar(Scalar::from_uint(0u128, layout.size), lhs_ty), // Attempt to simplify `x | ALL_ONES` to `ALL_ONES`. - (BinOp::BitOr, _, Ok(ones)) | (BinOp::BitOr, Ok(ones), _) + (BinOp::BitOr, _, Left(ones)) | (BinOp::BitOr, Left(ones), _) if ones == layout.size.truncate(u128::MAX) || (layout.ty.is_bool() && ones == 1) => { @@ -1015,8 +1016,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // - if both operands can be computed as bits, just compare the bits; // - if we proved that both operands have the same value, we can insert true/false; // - otherwise, do nothing, as we do not try to prove inequality. - (BinOp::Eq, a, b) if (a.is_ok() && b.is_ok()) || a == b => self.insert_bool(a == b), - (BinOp::Ne, a, b) if (a.is_ok() && b.is_ok()) || a == b => self.insert_bool(a != b), + (BinOp::Eq, Left(a), Left(b)) => self.insert_bool(a == b), + (BinOp::Eq, a, b) if a == b => self.insert_bool(true), + (BinOp::Ne, Left(a), Left(b)) => self.insert_bool(a != b), + (BinOp::Ne, a, b) if a == b => self.insert_bool(false), _ => return None, }; From 2564811e7b7464d4e2ab8cd5a826bf7c2f9f7d8b Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Tue, 16 Jan 2024 14:31:25 -0800 Subject: [PATCH 0314/1197] Remove tcx function and make `internal` fn safer I added `tcx` argument to `internal` to force 'tcx to be the same lifetime as TyCtxt. The only other solution I could think is to change this function to be `unsafe`. --- compiler/rustc_smir/src/rustc_internal/mod.rs | 78 ++++++++++++------- compiler/rustc_smir/src/rustc_smir/context.rs | 5 +- .../stable-mir/check_trait_queries.rs | 4 +- .../stable-mir/compilation-result.rs | 10 +-- tests/ui-fulldeps/stable-mir/smir_internal.rs | 8 +- 5 files changed, 66 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index 7633739f2890a..873bd94e88fb9 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -28,7 +28,7 @@ pub mod pretty; /// /// # Warning /// -/// This function is unstable, and it's behavior may change at any point. +/// This function is unstable, and its behavior may change at any point. /// E.g.: Items that were previously supported, may no longer be supported, or its translation may /// change. /// @@ -50,23 +50,12 @@ pub fn stable<'tcx, S: Stable<'tcx>>(item: S) -> S::T { /// # Panics /// /// This function will panic if StableMIR has not been properly initialized. -pub fn internal<'tcx, S: RustcInternal<'tcx>>(item: S) -> S::T { +pub fn internal<'tcx, S: RustcInternal<'tcx>>(tcx: TyCtxt<'tcx>, item: S) -> S::T { + // The tcx argument ensures that the item won't outlive the type context. + let _ = tcx; with_tables(|tables| item.internal(tables)) } -/// Retrieve the internal Rust compiler type context. -/// -/// # Warning -/// -/// This function is unstable, and it's behavior may change at any point. -/// -/// # Panics -/// -/// This function will panic if StableMIR has not been properly initialized. -pub fn tcx<'tcx>() -> TyCtxt<'tcx> { - with_tables(|tables| tables.tcx) -} - impl<'tcx> Index for Tables<'tcx> { type Output = DefId; @@ -227,7 +216,7 @@ where /// Instantiate and run the compiler with the provided arguments and callback. /// -/// The callback will be invoked after the compiler ran all its analysis, but before code generation. +/// The callback will be invoked after the compiler ran all its analyses, but before code generation. /// Note that this macro accepts two different formats for the callback: /// 1. An ident that resolves to a function that accepts no argument and returns `ControlFlow` /// ```ignore(needs-extern-crate) @@ -249,7 +238,7 @@ where /// # assert_eq!(result, Err(CompilerError::Skipped)) /// # } /// ``` -/// 2. An expression that represents the body of a closure: +/// 2. A closure expression: /// ```ignore(needs-extern-crate) /// # extern crate rustc_driver; /// # extern crate rustc_interface; @@ -267,26 +256,63 @@ where /// } /// # let args = vec!["--verbose".to_string()]; /// # let extra_args = vec![]; -/// let result = run!(args, analyze_code(extra_args)); +/// let result = run!(args, || analyze_code(extra_args)); /// # assert_eq!(result, Err(CompilerError::Skipped)) /// # } /// ``` #[macro_export] macro_rules! run { ($args:expr, $callback_fn:ident) => { - run!($args, $callback_fn()) + run_driver!($args, || $callback_fn()) + }; + ($args:expr, $callback:expr) => { + run_driver!($args, $callback) }; - ($args:expr, $callback:expr) => {{ +} + +/// Instantiate and run the compiler with the provided arguments and callback. +/// +/// This is similar to `run` but it invokes the callback with the compiler's `TyCtxt`, +/// which can be used to invoke internal APIs. +#[macro_export] +macro_rules! run_with_tcx { + ($args:expr, $callback_fn:ident) => { + run_driver!($args, |tcx| $callback_fn(tcx), with_tcx) + }; + ($args:expr, $callback:expr) => { + run_driver!($args, $callback, with_tcx) + }; +} + +/// Optionally include an ident. This is needed due to macro hygiene. +#[macro_export] +#[doc(hidden)] +macro_rules! optional { + (with_tcx $ident:ident) => { + $ident + }; +} + +/// Prefer using [run] and [run_with_tcx] instead. +/// +/// This macro implements the instantiation of a StableMIR driver, and it will invoke +/// the given callback after the compiler analyses. +/// +/// The third argument determines whether the callback requires `tcx` as an argument. +#[macro_export] +#[doc(hidden)] +macro_rules! run_driver { + ($args:expr, $callback:expr $(, $with_tcx:ident)?) => {{ use rustc_driver::{Callbacks, Compilation, RunCompiler}; use rustc_interface::{interface, Queries}; use stable_mir::CompilerError; use std::ops::ControlFlow; - pub struct StableMir ControlFlow> + pub struct StableMir ControlFlow> where B: Send, C: Send, - F: FnOnce() -> ControlFlow + Send, + F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow + Send, { args: Vec, callback: Option, @@ -297,7 +323,7 @@ macro_rules! run { where B: Send, C: Send, - F: FnOnce() -> ControlFlow + Send, + F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow + Send, { /// Creates a new `StableMir` instance, with given test_function and arguments. pub fn new(args: Vec, callback: F) -> Self { @@ -325,7 +351,7 @@ macro_rules! run { where B: Send, C: Send, - F: FnOnce() -> ControlFlow + Send, + F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow + Send, { /// Called after analysis. Return value instructs the compiler whether to /// continue the compilation afterwards (defaults to `Compilation::Continue`) @@ -337,7 +363,7 @@ macro_rules! run { queries.global_ctxt().unwrap().enter(|tcx| { if let Some(callback) = self.callback.take() { rustc_internal::run(tcx, || { - self.result = Some((callback)()); + self.result = Some(callback($(optional!($with_tcx tcx))?)); }) .unwrap(); if self.result.as_ref().is_some_and(|val| val.is_continue()) { @@ -352,7 +378,7 @@ macro_rules! run { } } - StableMir::new($args, || $callback).run() + StableMir::new($args, $callback).run() }}; } diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index fffc454804d29..2a2626654a013 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -29,7 +29,7 @@ use stable_mir::{Crate, CrateItem, CrateNum, DefId, Error, Filename, ItemKind, S use std::cell::RefCell; use std::iter; -use crate::rustc_internal::{internal, RustcInternal}; +use crate::rustc_internal::RustcInternal; use crate::rustc_smir::builder::BodyBuilder; use crate::rustc_smir::{alloc, new_item_kind, smir_crate, Stable, Tables}; @@ -322,7 +322,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { } fn const_literal(&self, cnst: &stable_mir::ty::Const) -> String { - internal(cnst).to_string() + let mut tables = self.0.borrow_mut(); + cnst.internal(&mut *tables).to_string() } fn span_of_an_item(&self, def_id: stable_mir::DefId) -> Span { diff --git a/tests/ui-fulldeps/stable-mir/check_trait_queries.rs b/tests/ui-fulldeps/stable-mir/check_trait_queries.rs index fb1197e4ecc40..c9fbe15ffb03f 100644 --- a/tests/ui-fulldeps/stable-mir/check_trait_queries.rs +++ b/tests/ui-fulldeps/stable-mir/check_trait_queries.rs @@ -11,14 +11,12 @@ #![feature(assert_matches)] #![feature(control_flow_enum)] -extern crate rustc_middle; #[macro_use] extern crate rustc_smir; extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use stable_mir::CrateDef; use std::collections::HashSet; @@ -83,7 +81,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, test_traits()).unwrap(); + run!(args, test_traits).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { diff --git a/tests/ui-fulldeps/stable-mir/compilation-result.rs b/tests/ui-fulldeps/stable-mir/compilation-result.rs index c802316c1d861..e6dd9fa132d83 100644 --- a/tests/ui-fulldeps/stable-mir/compilation-result.rs +++ b/tests/ui-fulldeps/stable-mir/compilation-result.rs @@ -35,33 +35,33 @@ fn main() { } fn test_continue(args: Vec) { - let result = run!(args, ControlFlow::Continue::<(), bool>(true)); + let result = run!(args, || ControlFlow::Continue::<(), bool>(true)); assert_eq!(result, Ok(true)); } fn test_break(args: Vec) { - let result = run!(args, ControlFlow::Break::(false)); + let result = run!(args, || ControlFlow::Break::(false)); assert_eq!(result, Err(stable_mir::CompilerError::Interrupted(false))); } #[allow(unreachable_code)] fn test_skipped(mut args: Vec) { args.push("--version".to_string()); - let result = run!(args, unreachable!() as ControlFlow<()>); + let result = run!(args, || unreachable!() as ControlFlow<()>); assert_eq!(result, Err(stable_mir::CompilerError::Skipped)); } #[allow(unreachable_code)] fn test_failed(mut args: Vec) { args.push("--cfg=broken".to_string()); - let result = run!(args, unreachable!() as ControlFlow<()>); + let result = run!(args, || unreachable!() as ControlFlow<()>); assert_eq!(result, Err(stable_mir::CompilerError::CompilationFailed)); } /// Test that we are able to pass a closure and set the return according to the captured value. fn test_captured(args: Vec) { let captured = "10".to_string(); - let result = run!(args, ControlFlow::Continue::<(), usize>(captured.len())); + let result = run!(args, || ControlFlow::Continue::<(), usize>(captured.len())); assert_eq!(result, Ok(captured.len())); } diff --git a/tests/ui-fulldeps/stable-mir/smir_internal.rs b/tests/ui-fulldeps/stable-mir/smir_internal.rs index 63a6a5e47e8b6..b0811364c09f4 100644 --- a/tests/ui-fulldeps/stable-mir/smir_internal.rs +++ b/tests/ui-fulldeps/stable-mir/smir_internal.rs @@ -16,19 +16,21 @@ extern crate rustc_smir; extern crate rustc_driver; extern crate rustc_interface; +extern crate rustc_middle; extern crate stable_mir; +use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use std::io::Write; use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; -fn test_translation() -> ControlFlow<()> { +fn test_translation(tcx: TyCtxt) -> ControlFlow<()> { let main_fn = stable_mir::entry_fn().unwrap(); let body = main_fn.body(); let orig_ty = body.locals()[0].ty; - let rustc_ty = rustc_internal::internal(&orig_ty); + let rustc_ty = rustc_internal::internal(tcx, &orig_ty); assert!(rustc_ty.is_unit()); ControlFlow::Continue(()) } @@ -46,7 +48,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, test_translation).unwrap(); + run_with_tcx!(args, test_translation).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { From 7e1e61a4478b690113c86bf7b547e829969fe29d Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Tue, 16 Jan 2024 18:34:44 -0500 Subject: [PATCH 0315/1197] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 84976cd699f4a..1cff2ee6b92e0 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 84976cd699f4aea56cb3a90ce3eedeed9e20d5a5 +Subproject commit 1cff2ee6b92e0ad3f87c44b70b28f788b2528b3c From b99c3ae6d66762b9faf863fa8078f5aad8b36205 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 15 Jan 2024 22:31:02 +0000 Subject: [PATCH 0316/1197] Get rid of the hir_owner query. --- compiler/rustc_hir/src/hir.rs | 2 +- .../rustc_incremental/src/assert_dep_graph.rs | 8 ++- .../src/persist/dirty_clean.rs | 3 +- compiler/rustc_middle/src/hir/map/mod.rs | 58 +++++++++---------- compiler/rustc_middle/src/hir/mod.rs | 35 +++-------- compiler/rustc_middle/src/query/erase.rs | 5 -- compiler/rustc_middle/src/query/mod.rs | 8 --- 7 files changed, 42 insertions(+), 77 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 6b347f7035a3b..309850d04d367 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -841,7 +841,7 @@ pub struct OwnerNodes<'tcx> { } impl<'tcx> OwnerNodes<'tcx> { - fn node(&self) -> OwnerNode<'tcx> { + pub fn node(&self) -> OwnerNode<'tcx> { use rustc_index::Idx; let node = self.nodes[ItemLocalId::new(0)].as_ref().unwrap().node; let node = node.as_owner().unwrap(); // Indexing must ensure it is an OwnerNode. diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs index 7b8d91702b39d..6f909a0cc9db4 100644 --- a/compiler/rustc_incremental/src/assert_dep_graph.rs +++ b/compiler/rustc_incremental/src/assert_dep_graph.rs @@ -128,9 +128,11 @@ impl<'tcx> IfThisChanged<'tcx> { if attr.has_name(sym::rustc_if_this_changed) { let dep_node_interned = self.argument(attr); let dep_node = match dep_node_interned { - None => { - DepNode::from_def_path_hash(self.tcx, def_path_hash, dep_kinds::hir_owner) - } + None => DepNode::from_def_path_hash( + self.tcx, + def_path_hash, + dep_kinds::hir_owner_nodes, + ), Some(n) => { match DepNode::from_label_string(self.tcx, n.as_str(), def_path_hash) { Ok(n) => n, diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs index f6acc60190a8f..842cc9fae9b4d 100644 --- a/compiler/rustc_incremental/src/persist/dirty_clean.rs +++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs @@ -57,8 +57,7 @@ const BASE_FN: &[&str] = &[ /// DepNodes for Hir, which is pretty much everything const BASE_HIR: &[&str] = &[ - // hir_owner and hir_owner_nodes should be computed for all nodes - label_strs::hir_owner, + // hir_owner_nodes should be computed for all nodes label_strs::hir_owner_nodes, ]; diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 1574f0f1b31fe..949b786e3a7d2 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -1,4 +1,4 @@ -use crate::hir::{ModuleItems, Owner}; +use crate::hir::ModuleItems; use crate::middle::debugger_visualizer::DebuggerVisualizerFile; use crate::query::LocalCrate; use crate::ty::TyCtxt; @@ -108,7 +108,7 @@ impl<'hir> Iterator for ParentOwnerIterator<'hir> { if self.current_id.local_id.index() != 0 { self.current_id.local_id = ItemLocalId::new(0); if let Some(node) = self.map.tcx.hir_owner(self.current_id.owner) { - return Some((self.current_id.owner, node.node)); + return Some((self.current_id.owner, node)); } } if self.current_id == CRATE_HIR_ID { @@ -126,23 +126,23 @@ impl<'hir> Iterator for ParentOwnerIterator<'hir> { // If this `HirId` doesn't have an entry, skip it and look for its `parent_id`. if let Some(node) = self.map.tcx.hir_owner(self.current_id.owner) { - return Some((self.current_id.owner, node.node)); + return Some((self.current_id.owner, node)); } } } } impl<'tcx> TyCtxt<'tcx> { + #[inline] + fn hir_owner(self, owner: OwnerId) -> Option> { + Some(self.hir_owner_nodes(owner).as_owner()?.node()) + } + /// Retrieves the `hir::Node` corresponding to `id`, returning `None` if cannot be found. pub fn opt_hir_node(self, id: HirId) -> Option> { - if id.local_id == ItemLocalId::from_u32(0) { - let owner = self.hir_owner(id.owner)?; - Some(owner.node.into()) - } else { - let owner = self.hir_owner_nodes(id.owner).as_owner()?; - let node = owner.nodes[id.local_id].as_ref()?; - Some(node.node) - } + let owner = self.hir_owner_nodes(id.owner).as_owner()?; + let node = owner.nodes[id.local_id].as_ref()?; + Some(node.node) } /// Retrieves the `hir::Node` corresponding to `id`, returning `None` if cannot be found. @@ -174,7 +174,7 @@ impl<'hir> Map<'hir> { #[inline] pub fn root_module(self) -> &'hir Mod<'hir> { - match self.tcx.hir_owner(CRATE_OWNER_ID).map(|o| o.node) { + match self.tcx.hir_owner(CRATE_OWNER_ID) { Some(OwnerNode::Crate(item)) => item, _ => bug!(), } @@ -242,27 +242,27 @@ impl<'hir> Map<'hir> { pub fn get_generics(self, id: LocalDefId) -> Option<&'hir Generics<'hir>> { let node = self.tcx.hir_owner(OwnerId { def_id: id })?; - node.node.generics() + node.generics() } pub fn owner(self, id: OwnerId) -> OwnerNode<'hir> { - self.tcx.hir_owner(id).unwrap_or_else(|| bug!("expected owner for {:?}", id)).node + self.tcx.hir_owner(id).unwrap_or_else(|| bug!("expected owner for {:?}", id)) } pub fn item(self, id: ItemId) -> &'hir Item<'hir> { - self.tcx.hir_owner(id.owner_id).unwrap().node.expect_item() + self.tcx.hir_owner(id.owner_id).unwrap().expect_item() } pub fn trait_item(self, id: TraitItemId) -> &'hir TraitItem<'hir> { - self.tcx.hir_owner(id.owner_id).unwrap().node.expect_trait_item() + self.tcx.hir_owner(id.owner_id).unwrap().expect_trait_item() } pub fn impl_item(self, id: ImplItemId) -> &'hir ImplItem<'hir> { - self.tcx.hir_owner(id.owner_id).unwrap().node.expect_impl_item() + self.tcx.hir_owner(id.owner_id).unwrap().expect_impl_item() } pub fn foreign_item(self, id: ForeignItemId) -> &'hir ForeignItem<'hir> { - self.tcx.hir_owner(id.owner_id).unwrap().node.expect_foreign_item() + self.tcx.hir_owner(id.owner_id).unwrap().expect_foreign_item() } pub fn body(self, id: BodyId) -> &'hir Body<'hir> { @@ -436,7 +436,7 @@ impl<'hir> Map<'hir> { pub fn get_module(self, module: LocalModDefId) -> (&'hir Mod<'hir>, Span, HirId) { let hir_id = HirId::make_owner(module.to_local_def_id()); - match self.tcx.hir_owner(hir_id.owner).map(|o| o.node) { + match self.tcx.hir_owner(hir_id.owner) { Some(OwnerNode::Item(&Item { span, kind: ItemKind::Mod(m), .. })) => (m, span, hir_id), Some(OwnerNode::Crate(item)) => (item, item.spans.inner_span, hir_id), node => panic!("not a module: {node:?}"), @@ -726,11 +726,10 @@ impl<'hir> Map<'hir> { pub fn get_foreign_abi(self, hir_id: HirId) -> Abi { let parent = self.get_parent_item(hir_id); - if let Some(node) = self.tcx.hir_owner(parent) { - if let OwnerNode::Item(Item { kind: ItemKind::ForeignMod { abi, .. }, .. }) = node.node - { - return *abi; - } + if let Some(node) = self.tcx.hir_owner(parent) + && let OwnerNode::Item(Item { kind: ItemKind::ForeignMod { abi, .. }, .. }) = node + { + return *abi; } bug!( "expected foreign mod or inlined parent, found {}", @@ -742,33 +741,32 @@ impl<'hir> Map<'hir> { self.tcx .hir_owner(OwnerId { def_id }) .unwrap_or_else(|| bug!("expected owner for {:?}", def_id)) - .node } pub fn expect_item(self, id: LocalDefId) -> &'hir Item<'hir> { match self.tcx.hir_owner(OwnerId { def_id: id }) { - Some(Owner { node: OwnerNode::Item(item), .. }) => item, + Some(OwnerNode::Item(item)) => item, _ => bug!("expected item, found {}", self.node_to_string(HirId::make_owner(id))), } } pub fn expect_impl_item(self, id: LocalDefId) -> &'hir ImplItem<'hir> { match self.tcx.hir_owner(OwnerId { def_id: id }) { - Some(Owner { node: OwnerNode::ImplItem(item), .. }) => item, + Some(OwnerNode::ImplItem(item)) => item, _ => bug!("expected impl item, found {}", self.node_to_string(HirId::make_owner(id))), } } pub fn expect_trait_item(self, id: LocalDefId) -> &'hir TraitItem<'hir> { match self.tcx.hir_owner(OwnerId { def_id: id }) { - Some(Owner { node: OwnerNode::TraitItem(item), .. }) => item, + Some(OwnerNode::TraitItem(item)) => item, _ => bug!("expected trait item, found {}", self.node_to_string(HirId::make_owner(id))), } } pub fn get_fn_output(self, def_id: LocalDefId) -> Option<&'hir FnRetTy<'hir>> { match self.tcx.hir_owner(OwnerId { def_id }) { - Some(Owner { node, .. }) => node.fn_decl().map(|fn_decl| &fn_decl.output), + Some(node) => node.fn_decl().map(|fn_decl| &fn_decl.output), _ => None, } } @@ -782,7 +780,7 @@ impl<'hir> Map<'hir> { pub fn expect_foreign_item(self, id: OwnerId) -> &'hir ForeignItem<'hir> { match self.tcx.hir_owner(id) { - Some(Owner { node: OwnerNode::ForeignItem(item), .. }) => item, + Some(OwnerNode::ForeignItem(item)) => item, _ => { bug!( "expected foreign item, found {}", diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index af99c7d55c37b..2d4d5deaefa93 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -8,34 +8,12 @@ pub mod place; use crate::query::Providers; use crate::ty::{EarlyBinder, ImplSubject, TyCtxt}; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{try_par_for_each_in, DynSend, DynSync}; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::*; -use rustc_query_system::ich::StableHashingContext; use rustc_span::{ErrorGuaranteed, ExpnId, DUMMY_SP}; -/// Top-level HIR node for current owner. This only contains the node for which -/// `HirId::local_id == 0`, and excludes bodies. -/// -/// This struct exists to encapsulate all access to the hir_owner query in this module, and to -/// implement HashStable without hashing bodies. -#[derive(Copy, Clone, Debug)] -pub struct Owner<'tcx> { - node: OwnerNode<'tcx>, -} - -impl<'a, 'tcx> HashStable> for Owner<'tcx> { - #[inline] - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - // Perform a shallow hash instead using the deep hash saved in `OwnerNodes`. This lets us - // differentiate queries that depend on the full HIR tree from those that only depend on - // the item signature. - hcx.without_hir_bodies(|hcx| self.node.hash_stable(hcx, hasher)); - } -} - /// Gather the LocalDefId for each item-like within a module, including items contained within /// bodies. The Ids are in visitor order. This is used to partition a pass between modules. #[derive(Debug, HashStable, Encodable, Decodable)] @@ -149,11 +127,6 @@ pub fn provide(providers: &mut Providers) { providers.hir_crate_items = map::hir_crate_items; providers.crate_hash = map::crate_hash; providers.hir_module_items = map::hir_module_items; - providers.hir_owner = |tcx, id| { - let owner = tcx.hir_crate(()).owners.get(id.def_id)?.as_owner()?; - let node = owner.node(); - Some(Owner { node }) - }; providers.opt_local_def_id_to_hir_id = |tcx, id| { let owner = tcx.hir_crate(()).owners[id].map(|_| ()); Some(match owner { @@ -162,7 +135,13 @@ pub fn provide(providers: &mut Providers) { MaybeOwner::NonOwner(hir_id) => hir_id, }) }; - providers.hir_owner_nodes = |tcx, id| tcx.hir_crate(()).owners[id.def_id].map(|i| &i.nodes); + providers.hir_owner_nodes = |tcx, id| { + if let Some(i) = tcx.hir_crate(()).owners.get(id.def_id) { + i.map(|i| &i.nodes) + } else { + MaybeOwner::Phantom + } + }; providers.hir_owner_parent = |tcx, id| { // Accessing the local_parent is ok since its value is hashed as part of `id`'s DefPathHash. tcx.opt_local_parent(id.def_id).map_or(CRATE_HIR_ID, |parent| { diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index b9200f1abf161..168e7affe99b0 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -160,10 +160,6 @@ impl EraseType for Option<&'_ [T]> { type Result = [u8; size_of::>()]; } -impl EraseType for Option> { - type Result = [u8; size_of::>>()]; -} - impl EraseType for Option> { type Result = [u8; size_of::>>()]; } @@ -320,7 +316,6 @@ macro_rules! tcx_lifetime { } tcx_lifetime! { - rustc_middle::hir::Owner, rustc_middle::middle::exported_symbols::ExportedSymbol, rustc_middle::mir::Const, rustc_middle::mir::DestructuredConstant, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 1dc7722088108..89e712d47f5f7 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -174,14 +174,6 @@ rustc_queries! { cache_on_disk_if { true } } - /// Gives access to the HIR node for the HIR owner `key`. - /// - /// This can be conveniently accessed by methods on `tcx.hir()`. - /// Avoid calling this query directly. - query hir_owner(key: hir::OwnerId) -> Option> { - desc { |tcx| "getting HIR owner of `{}`", tcx.def_path_str(key) } - } - /// Gives access to the HIR ID for the given `LocalDefId` owner `key` if any. /// /// Definitions that were generated with no HIR, would be fed to return `None`. From 20a8a23cb33fbc59fe89d64fa5dd51ccf33df415 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Tue, 16 Jan 2024 23:46:07 +0000 Subject: [PATCH 0317/1197] Bless incremental tests. --- tests/incremental/dirty_clean.rs | 5 +- tests/incremental/hash-module-order.rs | 4 +- tests/incremental/hashes/consts.rs | 10 +- tests/incremental/hashes/enum_constructors.rs | 36 +- tests/incremental/hashes/enum_defs.rs | 134 +++--- tests/incremental/hashes/extern_mods.rs | 12 +- .../incremental/hashes/function_interfaces.rs | 76 ++-- tests/incremental/hashes/if_expressions.rs | 16 +- .../hashes/indexing_expressions.rs | 12 +- tests/incremental/hashes/inherent_impls.rs | 128 +++--- tests/incremental/hashes/match_expressions.rs | 28 +- tests/incremental/hashes/statics.rs | 22 +- .../incremental/hashes/struct_constructors.rs | 24 +- tests/incremental/hashes/struct_defs.rs | 66 +-- tests/incremental/hashes/trait_defs.rs | 398 +++++++++--------- tests/incremental/hashes/trait_impls.rs | 100 ++--- tests/incremental/hashes/type_defs.rs | 32 +- 17 files changed, 533 insertions(+), 570 deletions(-) diff --git a/tests/incremental/dirty_clean.rs b/tests/incremental/dirty_clean.rs index 11d999ab32859..87a8696b1899f 100644 --- a/tests/incremental/dirty_clean.rs +++ b/tests/incremental/dirty_clean.rs @@ -26,12 +26,11 @@ mod y { use x; #[rustc_clean( - except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of,fn_sig", + except="hir_owner_nodes,generics_of,predicates_of,type_of,fn_sig", cfg="cfail2", )] pub fn y() { - //[cfail2]~^ ERROR `hir_owner(y)` should be dirty but is not - //[cfail2]~| ERROR `hir_owner_nodes(y)` should be dirty but is not + //[cfail2]~^ ERROR `hir_owner_nodes(y)` should be dirty but is not //[cfail2]~| ERROR `generics_of(y)` should be dirty but is not //[cfail2]~| ERROR `predicates_of(y)` should be dirty but is not //[cfail2]~| ERROR `type_of(y)` should be dirty but is not diff --git a/tests/incremental/hash-module-order.rs b/tests/incremental/hash-module-order.rs index fe9af9eeb370c..f9244d8adbf35 100644 --- a/tests/incremental/hash-module-order.rs +++ b/tests/incremental/hash-module-order.rs @@ -12,14 +12,14 @@ #![feature(rustc_attrs)] #[cfg(rpass1)] -#[rustc_clean(cfg="rpass1",except="hir_owner")] +#[rustc_clean(cfg="rpass1",except="hir_owner_nodes")] mod foo { struct First; struct Second; } #[cfg(rpass2)] -#[rustc_clean(cfg="rpass2",except="hir_owner")] +#[rustc_clean(cfg="rpass2",except="hir_owner_nodes")] mod foo { struct Second; struct First; diff --git a/tests/incremental/hashes/consts.rs b/tests/incremental/hashes/consts.rs index eaef63386ffd5..7cba3c159e600 100644 --- a/tests/incremental/hashes/consts.rs +++ b/tests/incremental/hashes/consts.rs @@ -19,7 +19,7 @@ const CONST_VISIBILITY: u8 = 0; #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] pub const CONST_VISIBILITY: u8 = 0; @@ -29,7 +29,7 @@ pub const CONST_VISIBILITY: u8 = 0; const CONST_CHANGE_TYPE_1: i32 = 0; #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] const CONST_CHANGE_TYPE_1: u32 = 0; @@ -39,7 +39,7 @@ const CONST_CHANGE_TYPE_1: u32 = 0; const CONST_CHANGE_TYPE_2: Option = None; #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] const CONST_CHANGE_TYPE_2: Option = None; @@ -99,11 +99,11 @@ mod const_change_type_indirectly { #[cfg(not(cfail1))] use super::ReferencedType2 as Type; - #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] + #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] const CONST_CHANGE_TYPE_INDIRECTLY_1: Type = Type; - #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] + #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] const CONST_CHANGE_TYPE_INDIRECTLY_2: Option = None; } diff --git a/tests/incremental/hashes/enum_constructors.rs b/tests/incremental/hashes/enum_constructors.rs index f685fe46d70d0..0a88dd4e15537 100644 --- a/tests/incremental/hashes/enum_constructors.rs +++ b/tests/incremental/hashes/enum_constructors.rs @@ -148,17 +148,9 @@ pub mod change_constructor_path_indirectly_struct_like { #[cfg(not(any(cfail1,cfail4)))] use super::Enum2 as TheEnum; - #[rustc_clean( - cfg="cfail2", - except="fn_sig,hir_owner,hir_owner_nodes,optimized_mir,\ - typeck" - )] + #[rustc_clean(cfg="cfail2", except="fn_sig,hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean( - cfg="cfail5", - except="fn_sig,hir_owner,hir_owner_nodes,optimized_mir,\ - typeck" - )] + #[rustc_clean(cfg="cfail5", except="fn_sig,hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn function() -> TheEnum { TheEnum::Struct { @@ -261,17 +253,9 @@ pub mod change_constructor_path_indirectly_tuple_like { #[cfg(not(any(cfail1,cfail4)))] use super::Enum2 as TheEnum; - #[rustc_clean( - cfg="cfail2", - except="fn_sig,hir_owner,hir_owner_nodes,optimized_mir,\ - typeck" - )] + #[rustc_clean(cfg="cfail2", except="fn_sig,hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean( - cfg="cfail5", - except="fn_sig,hir_owner,hir_owner_nodes,optimized_mir,\ - typeck" - )] + #[rustc_clean(cfg="cfail5", except="fn_sig,hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn function() -> TheEnum { TheEnum::Tuple(0, 1, 2) @@ -350,17 +334,9 @@ pub mod change_constructor_path_indirectly_c_like { #[cfg(not(any(cfail1,cfail4)))] use super::Clike2 as TheEnum; - #[rustc_clean( - cfg="cfail2", - except="fn_sig,hir_owner,hir_owner_nodes,optimized_mir,\ - typeck" - )] + #[rustc_clean(cfg="cfail2", except="fn_sig,hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean( - cfg="cfail5", - except="fn_sig,hir_owner,hir_owner_nodes,optimized_mir,\ - typeck" - )] + #[rustc_clean(cfg="cfail5", except="fn_sig,hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn function() -> TheEnum { TheEnum::B diff --git a/tests/incremental/hashes/enum_defs.rs b/tests/incremental/hashes/enum_defs.rs index bc83723a908f2..cb7a4e61e4f57 100644 --- a/tests/incremental/hashes/enum_defs.rs +++ b/tests/incremental/hashes/enum_defs.rs @@ -31,7 +31,7 @@ enum EnumVisibility { A } #[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] pub enum EnumVisibility { A } @@ -45,9 +45,9 @@ enum EnumChangeNameCStyleVariant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumChangeNameCStyleVariant { Variant1, @@ -64,9 +64,9 @@ enum EnumChangeNameTupleStyleVariant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumChangeNameTupleStyleVariant { Variant1, @@ -83,9 +83,9 @@ enum EnumChangeNameStructStyleVariant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumChangeNameStructStyleVariant { Variant1, @@ -118,9 +118,9 @@ enum EnumChangeValueCStyleVariant1 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumChangeValueCStyleVariant1 { Variant1, @@ -136,9 +136,9 @@ enum EnumAddCStyleVariant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumAddCStyleVariant { Variant1, @@ -155,9 +155,9 @@ enum EnumRemoveCStyleVariant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumRemoveCStyleVariant { Variant1, @@ -172,9 +172,9 @@ enum EnumAddTupleStyleVariant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumAddTupleStyleVariant { Variant1, @@ -191,9 +191,9 @@ enum EnumRemoveTupleStyleVariant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumRemoveTupleStyleVariant { Variant1, @@ -208,9 +208,9 @@ enum EnumAddStructStyleVariant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumAddStructStyleVariant { Variant1, @@ -227,9 +227,9 @@ enum EnumRemoveStructStyleVariant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumRemoveStructStyleVariant { Variant1, @@ -244,9 +244,9 @@ enum EnumChangeFieldTypeTupleStyleVariant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] enum EnumChangeFieldTypeTupleStyleVariant { Variant1(u32, @@ -263,9 +263,9 @@ enum EnumChangeFieldTypeStructStyleVariant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] enum EnumChangeFieldTypeStructStyleVariant { Variant1, @@ -284,9 +284,9 @@ enum EnumChangeFieldNameStructStyleVariant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumChangeFieldNameStructStyleVariant { Variant1 { a: u32, c: u32 }, @@ -301,9 +301,9 @@ enum EnumChangeOrderTupleStyleVariant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] enum EnumChangeOrderTupleStyleVariant { Variant1( @@ -320,9 +320,9 @@ enum EnumChangeFieldOrderStructStyleVariant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumChangeFieldOrderStructStyleVariant { Variant1 { b: f32, a: u32 }, @@ -337,9 +337,9 @@ enum EnumAddFieldTupleStyleVariant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumAddFieldTupleStyleVariant { Variant1(u32, u32, u32), @@ -354,9 +354,9 @@ enum EnumAddFieldStructStyleVariant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumAddFieldStructStyleVariant { Variant1 { a: u32, b: u32, c: u32 }, @@ -411,9 +411,9 @@ enum EnumChangeNameOfTypeParameter { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,generics_of,predicates_of,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,generics_of,predicates_of,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumChangeNameOfTypeParameter { Variant1(T), @@ -429,9 +429,9 @@ enum EnumAddTypeParameter { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,generics_of,predicates_of,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,generics_of,predicates_of,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumAddTypeParameter { Variant1(S), @@ -447,9 +447,9 @@ enum EnumChangeNameOfLifetimeParameter<'a> { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,generics_of,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,generics_of,type_of")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,generics_of,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumChangeNameOfLifetimeParameter<'b> { Variant1(&'b u32), @@ -465,9 +465,9 @@ enum EnumAddLifetimeParameter<'a> { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,generics_of,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,generics_of,type_of")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,generics_of,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumAddLifetimeParameter<'a, 'b> { Variant1(&'a u32), @@ -484,9 +484,9 @@ enum EnumAddLifetimeParameterBound<'a, 'b> { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,predicates_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,predicates_of")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail6")] enum EnumAddLifetimeParameterBound<'a, 'b: 'a> { Variant1(&'a u32), @@ -501,9 +501,9 @@ enum EnumAddLifetimeBoundToParameter<'a, T> { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,predicates_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,predicates_of")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail6")] enum EnumAddLifetimeBoundToParameter<'a, T: 'a> { Variant1(T), @@ -519,9 +519,9 @@ enum EnumAddTraitBound { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,generics_of,predicates_of,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,generics_of,predicates_of,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumAddTraitBound { Variant1(T), @@ -537,9 +537,9 @@ enum EnumAddLifetimeParameterBoundWhere<'a, 'b> { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,predicates_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,predicates_of")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail6")] enum EnumAddLifetimeParameterBoundWhere<'a, 'b> where 'b: 'a { Variant1(&'a u32), @@ -556,9 +556,9 @@ enum EnumAddLifetimeBoundToParameterWhere<'a, T> { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,predicates_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,predicates_of")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail6")] enum EnumAddLifetimeBoundToParameterWhere<'a, T> where T: 'a { Variant1(T), @@ -574,9 +574,9 @@ enum EnumAddTraitBoundWhere { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,generics_of,predicates_of,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,generics_of,predicates_of,type_of")] #[rustc_clean(cfg="cfail6")] enum EnumAddTraitBoundWhere where T: Sync { Variant1(T), @@ -592,9 +592,9 @@ enum EnumSwapUsageTypeParameters { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] enum EnumSwapUsageTypeParameters { Variant1 { @@ -615,9 +615,9 @@ enum EnumSwapUsageLifetimeParameters<'a, 'b> { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] enum EnumSwapUsageLifetimeParameters<'a, 'b> { Variant1 { @@ -642,9 +642,9 @@ mod change_field_type_indirectly_tuple_style { #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedType2 as FieldType; - #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] + #[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")] + #[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] enum TupleStyle { Variant1( @@ -662,9 +662,9 @@ mod change_field_type_indirectly_struct_style { #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedType2 as FieldType; - #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] + #[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")] + #[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] enum StructStyle { Variant1 { @@ -687,9 +687,9 @@ mod change_trait_bound_indirectly { #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedTrait2 as Trait; - #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,predicates_of")] + #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,predicates_of")] + #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail6")] enum Enum { Variant1(T) @@ -705,9 +705,9 @@ mod change_trait_bound_indirectly_where { #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedTrait2 as Trait; - #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,predicates_of")] + #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,predicates_of")] + #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail6")] enum Enum where T: Trait { Variant1(T) diff --git a/tests/incremental/hashes/extern_mods.rs b/tests/incremental/hashes/extern_mods.rs index 1906843c7a247..93a8fcfea3214 100644 --- a/tests/incremental/hashes/extern_mods.rs +++ b/tests/incremental/hashes/extern_mods.rs @@ -24,9 +24,9 @@ extern "C" { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg = "cfail2", except = "hir_owner_nodes")] #[rustc_clean(cfg = "cfail3")] -#[rustc_clean(cfg = "cfail5", except = "hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg = "cfail5", except = "hir_owner_nodes")] #[rustc_clean(cfg = "cfail6")] extern "C" { pub fn change_function_name2(c: i64) -> i32; @@ -129,9 +129,9 @@ extern "C" { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg = "cfail2", except = "hir_owner_nodes")] #[rustc_clean(cfg = "cfail3")] -#[rustc_clean(cfg = "cfail5", except = "hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg = "cfail5", except = "hir_owner_nodes")] #[rustc_clean(cfg = "cfail6")] extern "rust-call" { pub fn change_calling_convention(c: (i32,)); @@ -159,9 +159,9 @@ extern "C" { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg = "cfail2", except = "hir_owner_nodes")] #[rustc_clean(cfg = "cfail3")] -#[rustc_clean(cfg = "cfail5", except = "hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg = "cfail5", except = "hir_owner_nodes")] #[rustc_clean(cfg = "cfail6")] extern "C" { pub fn add_function1(c: i32); diff --git a/tests/incremental/hashes/function_interfaces.rs b/tests/incremental/hashes/function_interfaces.rs index 23b81705f9aa0..2aaaf94492c2f 100644 --- a/tests/incremental/hashes/function_interfaces.rs +++ b/tests/incremental/hashes/function_interfaces.rs @@ -25,12 +25,12 @@ pub fn add_parameter() {} #[cfg(not(any(cfail1,cfail4)))] #[rustc_clean( cfg = "cfail2", - except = "hir_owner, hir_owner_nodes, optimized_mir, typeck, fn_sig" + except = "hir_owner_nodes, optimized_mir, typeck, fn_sig" )] #[rustc_clean(cfg = "cfail3")] #[rustc_clean( cfg = "cfail5", - except = "hir_owner, hir_owner_nodes, optimized_mir, typeck, fn_sig" + except = "hir_owner_nodes, optimized_mir, typeck, fn_sig" )] #[rustc_clean(cfg = "cfail6")] pub fn add_parameter(p: i32) {} @@ -41,9 +41,9 @@ pub fn add_parameter(p: i32) {} pub fn add_return_type() {} #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_nodes")] +#[rustc_clean(cfg = "cfail2", except = "hir_owner_nodes")] #[rustc_clean(cfg = "cfail3")] -#[rustc_clean(cfg = "cfail5", except = "hir_owner, hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg = "cfail5", except = "hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg = "cfail6")] pub fn add_return_type() -> () {} @@ -55,12 +55,12 @@ pub fn type_of_parameter(p: i32) {} #[cfg(not(any(cfail1,cfail4)))] #[rustc_clean( cfg = "cfail2", - except = "hir_owner, hir_owner_nodes, optimized_mir, typeck, fn_sig" + except = "hir_owner_nodes, optimized_mir, typeck, fn_sig" )] #[rustc_clean(cfg = "cfail3")] #[rustc_clean( cfg = "cfail5", - except = "hir_owner, hir_owner_nodes, optimized_mir, typeck, fn_sig" + except = "hir_owner_nodes, optimized_mir, typeck, fn_sig" )] #[rustc_clean(cfg = "cfail6")] pub fn type_of_parameter(p: i64) {} @@ -73,12 +73,12 @@ pub fn type_of_parameter_ref(p: &i32) {} #[cfg(not(any(cfail1,cfail4)))] #[rustc_clean( cfg = "cfail2", - except = "hir_owner, hir_owner_nodes, optimized_mir, typeck, fn_sig" + except = "hir_owner_nodes, optimized_mir, typeck, fn_sig" )] #[rustc_clean(cfg = "cfail3")] #[rustc_clean( cfg = "cfail5", - except = "hir_owner, hir_owner_nodes, optimized_mir, typeck, fn_sig" + except = "hir_owner_nodes, optimized_mir, typeck, fn_sig" )] #[rustc_clean(cfg = "cfail6")] pub fn type_of_parameter_ref(p: &mut i32) {} @@ -91,12 +91,12 @@ pub fn order_of_parameters(p1: i32, p2: i64) {} #[cfg(not(any(cfail1,cfail4)))] #[rustc_clean( cfg = "cfail2", - except = "hir_owner, hir_owner_nodes, optimized_mir, typeck, fn_sig" + except = "hir_owner_nodes, optimized_mir, typeck, fn_sig" )] #[rustc_clean(cfg = "cfail3")] #[rustc_clean( cfg = "cfail5", - except = "hir_owner, hir_owner_nodes, optimized_mir, typeck, fn_sig" + except = "hir_owner_nodes, optimized_mir, typeck, fn_sig" )] #[rustc_clean(cfg = "cfail6")] pub fn order_of_parameters(p2: i64, p1: i32) {} @@ -109,12 +109,12 @@ pub fn make_unsafe() {} #[cfg(not(any(cfail1,cfail4)))] #[rustc_clean( cfg = "cfail2", - except = "hir_owner, hir_owner_nodes, optimized_mir, typeck, fn_sig" + except = "hir_owner_nodes, optimized_mir, typeck, fn_sig" )] #[rustc_clean(cfg = "cfail3")] #[rustc_clean( cfg = "cfail5", - except = "hir_owner, hir_owner_nodes, optimized_mir, typeck, fn_sig" + except = "hir_owner_nodes, optimized_mir, typeck, fn_sig" )] #[rustc_clean(cfg = "cfail6")] pub unsafe fn make_unsafe() {} @@ -125,9 +125,9 @@ pub unsafe fn make_unsafe() {} pub fn make_extern() {} #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_nodes, typeck, fn_sig")] +#[rustc_clean(cfg = "cfail2", except = "hir_owner_nodes, typeck, fn_sig")] #[rustc_clean(cfg = "cfail3")] -#[rustc_clean(cfg = "cfail5", except = "hir_owner, hir_owner_nodes, typeck, fn_sig")] +#[rustc_clean(cfg = "cfail5", except = "hir_owner_nodes, typeck, fn_sig")] #[rustc_clean(cfg = "cfail6")] pub extern "C" fn make_extern() {} @@ -139,12 +139,12 @@ pub fn type_parameter () {} #[cfg(not(any(cfail1,cfail4)))] #[rustc_clean( cfg = "cfail2", - except = "hir_owner, hir_owner_nodes, generics_of, type_of, predicates_of" + except = "hir_owner_nodes, generics_of, type_of, predicates_of" )] #[rustc_clean(cfg = "cfail3")] #[rustc_clean( cfg = "cfail5", - except = "hir_owner, hir_owner_nodes, generics_of, type_of, predicates_of" + except = "hir_owner_nodes, generics_of, type_of, predicates_of" )] #[rustc_clean(cfg = "cfail6")] pub fn type_parameter() {} @@ -155,9 +155,9 @@ pub fn type_parameter() {} pub fn lifetime_parameter () {} #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_nodes, generics_of,fn_sig")] +#[rustc_clean(cfg = "cfail2", except = "hir_owner_nodes, generics_of,fn_sig")] #[rustc_clean(cfg = "cfail3")] -#[rustc_clean(cfg = "cfail5", except = "hir_owner, hir_owner_nodes, generics_of,fn_sig")] +#[rustc_clean(cfg = "cfail5", except = "hir_owner_nodes, generics_of,fn_sig")] #[rustc_clean(cfg = "cfail6")] pub fn lifetime_parameter<'a>() {} @@ -167,7 +167,7 @@ pub fn lifetime_parameter<'a>() {} pub fn trait_bound() {} #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_nodes, predicates_of")] +#[rustc_clean(cfg = "cfail2", except = "hir_owner_nodes, predicates_of")] #[rustc_clean(cfg = "cfail3")] pub fn trait_bound() {} @@ -177,9 +177,9 @@ pub fn trait_bound() {} pub fn builtin_bound() {} #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_nodes, predicates_of")] +#[rustc_clean(cfg = "cfail2", except = "hir_owner_nodes, predicates_of")] #[rustc_clean(cfg = "cfail3")] -#[rustc_clean(cfg = "cfail5", except = "hir_owner, hir_owner_nodes, predicates_of")] +#[rustc_clean(cfg = "cfail5", except = "hir_owner_nodes, predicates_of")] #[rustc_clean(cfg = "cfail6")] pub fn builtin_bound() {} @@ -191,12 +191,12 @@ pub fn lifetime_bound<'a, T>() {} #[cfg(not(any(cfail1,cfail4)))] #[rustc_clean( cfg = "cfail2", - except = "hir_owner, hir_owner_nodes, generics_of, type_of, predicates_of,fn_sig" + except = "hir_owner_nodes, generics_of, type_of, predicates_of,fn_sig" )] #[rustc_clean(cfg = "cfail3")] #[rustc_clean( cfg = "cfail5", - except = "hir_owner, hir_owner_nodes, generics_of, type_of, predicates_of,fn_sig,optimized_mir" + except = "hir_owner_nodes, generics_of, type_of, predicates_of,fn_sig,optimized_mir" )] #[rustc_clean(cfg = "cfail6")] pub fn lifetime_bound<'a, T: 'a>() {} @@ -207,7 +207,7 @@ pub fn lifetime_bound<'a, T: 'a>() {} pub fn second_trait_bound() {} #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_nodes, predicates_of")] +#[rustc_clean(cfg = "cfail2", except = "hir_owner_nodes, predicates_of")] #[rustc_clean(cfg = "cfail3")] pub fn second_trait_bound() {} @@ -217,9 +217,9 @@ pub fn second_trait_bound() {} pub fn second_builtin_bound() {} #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_nodes, predicates_of")] +#[rustc_clean(cfg = "cfail2", except = "hir_owner_nodes, predicates_of")] #[rustc_clean(cfg = "cfail3")] -#[rustc_clean(cfg = "cfail5", except = "hir_owner, hir_owner_nodes, predicates_of")] +#[rustc_clean(cfg = "cfail5", except = "hir_owner_nodes, predicates_of")] #[rustc_clean(cfg = "cfail6")] pub fn second_builtin_bound() {} @@ -231,12 +231,12 @@ pub fn second_lifetime_bound<'a, 'b, T: 'a >() {} #[cfg(not(any(cfail1,cfail4)))] #[rustc_clean( cfg = "cfail2", - except = "hir_owner, hir_owner_nodes, generics_of, type_of, predicates_of,fn_sig" + except = "hir_owner_nodes, generics_of, type_of, predicates_of,fn_sig" )] #[rustc_clean(cfg = "cfail3")] #[rustc_clean( cfg = "cfail5", - except = "hir_owner, hir_owner_nodes, generics_of, type_of, predicates_of,fn_sig" + except = "hir_owner_nodes, generics_of, type_of, predicates_of,fn_sig" )] #[rustc_clean(cfg = "cfail6")] pub fn second_lifetime_bound<'a, 'b, T: 'a + 'b>() {} @@ -302,9 +302,9 @@ pub fn return_impl_trait() -> i32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_nodes, typeck, fn_sig")] +#[rustc_clean(cfg = "cfail2", except = "hir_owner_nodes, typeck, fn_sig")] #[rustc_clean(cfg = "cfail3")] -#[rustc_clean(cfg = "cfail5", except = "hir_owner, hir_owner_nodes, typeck, fn_sig, optimized_mir")] +#[rustc_clean(cfg = "cfail5", except = "hir_owner_nodes, typeck, fn_sig, optimized_mir")] #[rustc_clean(cfg = "cfail6")] pub fn return_impl_trait() -> impl Clone { 0 @@ -339,12 +339,12 @@ pub mod change_return_type_indirectly { #[rustc_clean( cfg = "cfail2", - except = "hir_owner, hir_owner_nodes, optimized_mir, typeck, fn_sig" + except = "hir_owner_nodes, optimized_mir, typeck, fn_sig" )] #[rustc_clean(cfg = "cfail3")] #[rustc_clean( cfg = "cfail5", - except = "hir_owner, hir_owner_nodes, optimized_mir, typeck, fn_sig" + except = "hir_owner_nodes, optimized_mir, typeck, fn_sig" )] #[rustc_clean(cfg = "cfail6")] pub fn indirect_return_type() -> ReturnType { @@ -362,12 +362,12 @@ pub mod change_parameter_type_indirectly { #[rustc_clean( cfg = "cfail2", - except = "hir_owner, hir_owner_nodes, optimized_mir, typeck, fn_sig" + except = "hir_owner_nodes, optimized_mir, typeck, fn_sig" )] #[rustc_clean(cfg = "cfail3")] #[rustc_clean( cfg = "cfail5", - except = "hir_owner, hir_owner_nodes, optimized_mir, typeck, fn_sig" + except = "hir_owner_nodes, optimized_mir, typeck, fn_sig" )] #[rustc_clean(cfg = "cfail6")] pub fn indirect_parameter_type(p: ParameterType) {} @@ -384,9 +384,9 @@ pub mod change_trait_bound_indirectly { #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedTrait2 as Trait; - #[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_nodes, predicates_of")] + #[rustc_clean(cfg = "cfail2", except = "hir_owner_nodes, predicates_of")] #[rustc_clean(cfg = "cfail3")] - #[rustc_clean(cfg = "cfail5", except = "hir_owner, hir_owner_nodes, predicates_of")] + #[rustc_clean(cfg = "cfail5", except = "hir_owner_nodes, predicates_of")] #[rustc_clean(cfg = "cfail6")] pub fn indirect_trait_bound(p: T) {} } @@ -399,9 +399,9 @@ pub mod change_trait_bound_indirectly_in_where_clause { #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedTrait2 as Trait; - #[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_nodes, predicates_of")] + #[rustc_clean(cfg = "cfail2", except = "hir_owner_nodes, predicates_of")] #[rustc_clean(cfg = "cfail3")] - #[rustc_clean(cfg = "cfail5", except = "hir_owner, hir_owner_nodes, predicates_of")] + #[rustc_clean(cfg = "cfail5", except = "hir_owner_nodes, predicates_of")] #[rustc_clean(cfg = "cfail6")] pub fn indirect_trait_bound_where(p: T) where diff --git a/tests/incremental/hashes/if_expressions.rs b/tests/incremental/hashes/if_expressions.rs index 937fd3ac879a9..cd80f8aa00a59 100644 --- a/tests/incremental/hashes/if_expressions.rs +++ b/tests/incremental/hashes/if_expressions.rs @@ -27,9 +27,9 @@ pub fn change_condition(x: bool) -> u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn change_condition(x: bool) -> u32 { if !x { @@ -103,9 +103,9 @@ pub fn add_else_branch(x: bool) -> u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,typeck")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,typeck")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck")] #[rustc_clean(cfg="cfail6")] pub fn add_else_branch(x: bool) -> u32 { let mut ret = 1; @@ -156,9 +156,9 @@ pub fn change_then_branch_if_let(x: Option) -> u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn change_then_branch_if_let(x: Option) -> u32 { if let Some(x) = x { @@ -209,9 +209,9 @@ pub fn add_else_branch_if_let(x: Option) -> u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,typeck")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,typeck,optimized_mir")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn add_else_branch_if_let(x: Option) -> u32 { let mut ret = 1; diff --git a/tests/incremental/hashes/indexing_expressions.rs b/tests/incremental/hashes/indexing_expressions.rs index b1ac6f6fa6c2b..4bccec61a7ce3 100644 --- a/tests/incremental/hashes/indexing_expressions.rs +++ b/tests/incremental/hashes/indexing_expressions.rs @@ -74,9 +74,9 @@ fn add_lower_bound(slice: &[u32]) -> &[u32] { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,typeck", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,typeck", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn add_lower_bound(slice: &[u32]) -> &[u32] { &slice[3..4] @@ -91,9 +91,9 @@ fn add_upper_bound(slice: &[u32]) -> &[u32] { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,typeck", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,typeck", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn add_upper_bound(slice: &[u32]) -> &[u32] { &slice[3..7] @@ -125,9 +125,9 @@ fn exclusive_to_inclusive_range(slice: &[u32]) -> &[u32] { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,typeck", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,typeck", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn exclusive_to_inclusive_range(slice: &[u32]) -> &[u32] { &slice[3..=7] diff --git a/tests/incremental/hashes/inherent_impls.rs b/tests/incremental/hashes/inherent_impls.rs index 285f857c9cbcf..853fbc79fc878 100644 --- a/tests/incremental/hashes/inherent_impls.rs +++ b/tests/incremental/hashes/inherent_impls.rs @@ -26,9 +26,9 @@ impl Foo { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,associated_item_def_ids")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,associated_item_def_ids")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,associated_item_def_ids")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,associated_item_def_ids")] #[rustc_clean(cfg="cfail6")] impl Foo { #[rustc_clean(cfg="cfail3")] @@ -115,7 +115,7 @@ impl Foo { impl Foo { //-------------------------- //-------------------------- - //-------------------------------------------------------------- + //---------------------------------------------------- //-------------------------- pub fn method_privacy() { } } @@ -128,7 +128,7 @@ impl Foo { impl Foo { #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")] + #[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] fn method_privacy() { } } @@ -138,31 +138,31 @@ impl Foo { impl Foo { //------------ //--------------- - //--------------------------------------------------------------------------------------------- + //----------------------------------------------------------------------------------- // //-------------------------- //------------ //--------------- - //--------------------------------------------------------------------------------------------- + //----------------------------------------------------------------------------------- // //-------------------------- pub fn method_selfness() { } } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] impl Foo { #[rustc_clean( cfg="cfail2", - except="hir_owner,hir_owner_nodes,fn_sig,generics_of,typeck,associated_item,optimized_mir", + except="hir_owner_nodes,fn_sig,generics_of,typeck,associated_item,optimized_mir", )] #[rustc_clean(cfg="cfail3")] #[rustc_clean( cfg="cfail5", - except="hir_owner,hir_owner_nodes,fn_sig,generics_of,typeck,associated_item,optimized_mir", + except="hir_owner_nodes,fn_sig,generics_of,typeck,associated_item,optimized_mir", )] #[rustc_clean(cfg="cfail6")] pub fn method_selfness(&self) { } @@ -171,9 +171,9 @@ impl Foo { // Change Method Selfmutness --------------------------------------------------- #[cfg(any(cfail1,cfail4))] impl Foo { - //------------------------------------------------------------------------------------------ + //-------------------------------------------------------------------------------- //-------------------------- - //------------------------------------------------------------------------------------------ + //-------------------------------------------------------------------------------- //-------------------------- pub fn method_selfmutness(& self) { } } @@ -184,9 +184,9 @@ impl Foo { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl Foo { - #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir")] + #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,fn_sig,typeck,optimized_mir")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir")] + #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,fn_sig,typeck,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn method_selfmutness(&mut self) { } } @@ -200,9 +200,9 @@ impl Foo { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,associated_item_def_ids")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,associated_item_def_ids")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,associated_item_def_ids")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,associated_item_def_ids")] #[rustc_clean(cfg="cfail6")] impl Foo { #[rustc_clean(cfg="cfail2")] @@ -221,9 +221,9 @@ impl Foo { // Add Method Parameter -------------------------------------------------------- #[cfg(any(cfail1,cfail4))] impl Foo { - //------------------------------------------------------------------------------------------ + //-------------------------------------------------------------------------------- //-------------------------- - //------------------------------------------------------------------------------------------ + //-------------------------------------------------------------------------------- //-------------------------- pub fn add_method_parameter(&self ) { } } @@ -234,9 +234,9 @@ impl Foo { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl Foo { - #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir")] + #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,fn_sig,typeck,optimized_mir")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir")] + #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,fn_sig,typeck,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn add_method_parameter(&self, _: i32) { } } @@ -271,9 +271,9 @@ impl Foo { // Change Method Return Type --------------------------------------------------- #[cfg(any(cfail1,cfail4))] impl Foo { - //------------------------------------------------------------------------------------------ + //-------------------------------------------------------------------------------- //-------------------------- - //------------------------------------------------------------------------------------------ + //-------------------------------------------------------------------------------- //-------------------------- pub fn change_method_return_type(&self) -> u16 { 0 } } @@ -284,9 +284,9 @@ impl Foo { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl Foo { - #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,fn_sig,optimized_mir,typeck")] + #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,fn_sig,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,fn_sig,optimized_mir,typeck")] + #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,fn_sig,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn change_method_return_type(&self) -> u32 { 0 } } @@ -348,9 +348,9 @@ impl Foo { // Make method unsafe ---------------------------------------------------------- #[cfg(any(cfail1,cfail4))] impl Foo { - //------------------------------------------------------------------------------------------ + //-------------------------------------------------------------------------------- //-------------------------- - //------------------------------------------------------------------------------------------ + //-------------------------------------------------------------------------------- //-------------------------- pub fn make_method_unsafe(&self) { } } @@ -361,9 +361,9 @@ impl Foo { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl Foo { - #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir")] + #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,fn_sig,typeck,optimized_mir")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir")] + #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,fn_sig,typeck,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub unsafe fn make_method_unsafe(&self) { } } @@ -373,9 +373,9 @@ impl Foo { // Make method extern ---------------------------------------------------------- #[cfg(any(cfail1,cfail4))] impl Foo { - //---------------------------------------------------------------------------- + //------------------------------------------------------------------ //-------------------------- - //---------------------------------------------------------------------------- + //------------------------------------------------------------------ //-------------------------- pub fn make_method_extern(&self) { } } @@ -386,9 +386,9 @@ impl Foo { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl Foo { - #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,fn_sig,typeck")] + #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,fn_sig,typeck")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,fn_sig,typeck")] + #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,fn_sig,typeck")] #[rustc_clean(cfg="cfail6")] pub extern "C" fn make_method_extern(&self) { } } @@ -398,9 +398,9 @@ impl Foo { // Change method calling convention -------------------------------------------- #[cfg(any(cfail1,cfail4))] impl Foo { - //---------------------------------------------------------------------------- + //------------------------------------------------------------------ //-------------------------- - //---------------------------------------------------------------------------- + //------------------------------------------------------------------ //-------------------------- pub extern "C" fn change_method_calling_convention(&self) { } } @@ -411,9 +411,9 @@ impl Foo { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl Foo { - #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,fn_sig,typeck")] + #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,fn_sig,typeck")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,fn_sig,typeck")] + #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,fn_sig,typeck")] #[rustc_clean(cfg="cfail6")] pub extern "system" fn change_method_calling_convention(&self) { } } @@ -432,9 +432,9 @@ impl Foo { // ---------------------------------------------------------- // ----------------------------------------------------------- // ---------------------------------------------------------- - // -------------------------------------------------------------------- + // ---------------------------------------------------------- // ------------------------- - // -------------------------------------------------------------------------------- + // ---------------------------------------------------------------------- // ------------------------- pub fn add_lifetime_parameter_to_method (&self) { } } @@ -454,9 +454,9 @@ impl Foo { // if we lower generics before the body, then the `HirId` for // things in the body will be affected. So if you start to see // `typeck` appear dirty, that might be the cause. -nmatsakis - #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,fn_sig")] + #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,fn_sig")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,fn_sig,generics_of")] + #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,fn_sig,generics_of")] #[rustc_clean(cfg="cfail6")] pub fn add_lifetime_parameter_to_method<'a>(&self) { } } @@ -477,12 +477,12 @@ impl Foo { // ------------------------------------------------- // ----------- // -------------- - // ---------------------------------------------------------------------- + // ------------------------------------------------------------ // // ------------------------- // ----------- // -------------- - // ---------------------------------------------------------------------- + // ------------------------------------------------------------ // // ------------------------- pub fn add_type_parameter_to_method (&self) { } @@ -505,12 +505,12 @@ impl Foo { // appear dirty, that might be the cause. -nmatsakis #[rustc_clean( cfg="cfail2", - except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of", + except="hir_owner_nodes,generics_of,predicates_of,type_of", )] #[rustc_clean(cfg="cfail3")] #[rustc_clean( cfg="cfail5", - except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of", + except="hir_owner_nodes,generics_of,predicates_of,type_of", )] #[rustc_clean(cfg="cfail6")] pub fn add_type_parameter_to_method(&self) { } @@ -523,12 +523,12 @@ impl Foo { impl Foo { //------------ //--------------- - //----------------------------------------------------------------------------- + //------------------------------------------------------------------- // //-------------------------- //------------ //--------------- - //----------------------------------------------------------------------------- + //------------------------------------------------------------------- // //-------------------------- pub fn add_lifetime_bound_to_lifetime_param_of_method<'a, 'b >(&self) { } @@ -542,12 +542,12 @@ impl Foo { impl Foo { #[rustc_clean( cfg="cfail2", - except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of,fn_sig" + except="hir_owner_nodes,generics_of,predicates_of,type_of,fn_sig" )] #[rustc_clean(cfg="cfail3")] #[rustc_clean( cfg="cfail5", - except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of,fn_sig" + except="hir_owner_nodes,generics_of,predicates_of,type_of,fn_sig" )] #[rustc_clean(cfg="cfail6")] pub fn add_lifetime_bound_to_lifetime_param_of_method<'a, 'b: 'a>(&self) { } @@ -569,12 +569,12 @@ impl Foo { // ------------------------------------------------- // ----------- // -------------- - // ---------------------------------------------------------------------------- + // ------------------------------------------------------------------ // // ------------------------- // ----------- // -------------- - // ---------------------------------------------------------------------------- + // ------------------------------------------------------------------ // // ------------------------- pub fn add_lifetime_bound_to_type_param_of_method<'a, T >(&self) { } @@ -597,12 +597,12 @@ impl Foo { // appear dirty, that might be the cause. -nmatsakis #[rustc_clean( cfg="cfail2", - except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of,fn_sig" + except="hir_owner_nodes,generics_of,predicates_of,type_of,fn_sig" )] #[rustc_clean(cfg="cfail3")] #[rustc_clean( cfg="cfail5", - except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of,fn_sig" + except="hir_owner_nodes,generics_of,predicates_of,type_of,fn_sig" )] #[rustc_clean(cfg="cfail6")] pub fn add_lifetime_bound_to_type_param_of_method<'a, T: 'a>(&self) { } @@ -622,9 +622,9 @@ impl Foo { // ------------------------------------------------------------ // ------------------------------------------------------ // ------------------------------------------------- - // --------------------------------------------------------------------------- + // ----------------------------------------------------------------- // ------------------------- - // --------------------------------------------------------------------------- + // ----------------------------------------------------------------- // ------------------------- pub fn add_trait_bound_to_type_param_of_method(&self) { } } @@ -644,9 +644,9 @@ impl Foo { // generics before the body, then the `HirId` for things in the // body will be affected. So if you start to see `typeck` // appear dirty, that might be the cause. -nmatsakis - #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,predicates_of")] + #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,predicates_of")] + #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail6")] pub fn add_trait_bound_to_type_param_of_method(&self) { } } @@ -689,9 +689,9 @@ impl Bar { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,generics_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,generics_of")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,generics_of")] #[rustc_clean(cfg="cfail6")] impl Bar { #[rustc_clean( @@ -716,9 +716,9 @@ impl Bar { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] impl Bar { #[rustc_clean(cfg="cfail2", except="fn_sig,optimized_mir,typeck")] @@ -737,9 +737,9 @@ impl Bar { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] impl Bar { #[rustc_clean(cfg="cfail2")] @@ -758,9 +758,9 @@ impl Bar { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] impl Bar { #[rustc_clean(cfg="cfail2")] diff --git a/tests/incremental/hashes/match_expressions.rs b/tests/incremental/hashes/match_expressions.rs index ecb19480d6547..ebcf1708a7aaa 100644 --- a/tests/incremental/hashes/match_expressions.rs +++ b/tests/incremental/hashes/match_expressions.rs @@ -28,9 +28,9 @@ pub fn add_arm(x: u32) -> u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn add_arm(x: u32) -> u32 { match x { @@ -79,9 +79,9 @@ pub fn add_guard_clause(x: u32, y: bool) -> u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn add_guard_clause(x: u32, y: bool) -> u32 { match x { @@ -104,9 +104,9 @@ pub fn change_guard_clause(x: u32, y: bool) -> u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn change_guard_clause(x: u32, y: bool) -> u32 { match x { @@ -129,9 +129,9 @@ pub fn add_at_binding(x: u32) -> u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn add_at_binding(x: u32) -> u32 { match x { @@ -178,9 +178,9 @@ pub fn change_simple_name_to_pattern(x: u32) -> u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn change_simple_name_to_pattern(x: u32) -> u32 { match (x, x & 1) { @@ -273,9 +273,9 @@ pub fn add_amp_to_binding_in_pattern(x: u32) -> u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn add_amp_to_binding_in_pattern(x: u32) -> u32 { match (&x, x & 1) { @@ -322,9 +322,9 @@ pub fn add_alternative_to_arm(x: u32) -> u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn add_alternative_to_arm(x: u32) -> u32 { match x { diff --git a/tests/incremental/hashes/statics.rs b/tests/incremental/hashes/statics.rs index bb83f8300d06d..2adf05390bc4e 100644 --- a/tests/incremental/hashes/statics.rs +++ b/tests/incremental/hashes/statics.rs @@ -26,7 +26,7 @@ static STATIC_VISIBILITY: u8 = 0; #[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] pub static STATIC_VISIBILITY: u8 = 0; @@ -36,9 +36,9 @@ pub static STATIC_VISIBILITY: u8 = 0; static STATIC_MUTABILITY: u8 = 0; #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] static mut STATIC_MUTABILITY: u8 = 0; @@ -87,9 +87,9 @@ static STATIC_THREAD_LOCAL: u8 = 0; static STATIC_CHANGE_TYPE_1: i16 = 0; #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] static STATIC_CHANGE_TYPE_1: u64 = 0; @@ -99,9 +99,9 @@ static STATIC_CHANGE_TYPE_1: u64 = 0; static STATIC_CHANGE_TYPE_2: Option = None; #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] static STATIC_CHANGE_TYPE_2: Option = None; @@ -169,15 +169,15 @@ mod static_change_type_indirectly { #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedType2 as Type; - #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] + #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] + #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] static STATIC_CHANGE_TYPE_INDIRECTLY_1: Type = Type; - #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] + #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] + #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] static STATIC_CHANGE_TYPE_INDIRECTLY_2: Option = None; } diff --git a/tests/incremental/hashes/struct_constructors.rs b/tests/incremental/hashes/struct_constructors.rs index e50e5674c661e..eabb8683e0296 100644 --- a/tests/incremental/hashes/struct_constructors.rs +++ b/tests/incremental/hashes/struct_constructors.rs @@ -90,9 +90,9 @@ pub fn add_field_regular_struct() -> RegularStruct { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn add_field_regular_struct() -> RegularStruct { let struct1 = RegularStruct { @@ -185,15 +185,9 @@ pub mod change_constructor_path_indirectly_regular_struct { #[cfg(not(any(cfail1,cfail4)))] use super::RegularStruct2 as Struct; - #[rustc_clean( - cfg="cfail2", - except="fn_sig,hir_owner,hir_owner_nodes,optimized_mir,typeck" - )] + #[rustc_clean(cfg="cfail2", except="fn_sig,hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean( - cfg="cfail5", - except="fn_sig,hir_owner,hir_owner_nodes,optimized_mir,typeck" - )] + #[rustc_clean(cfg="cfail5", except="fn_sig,hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn function() -> Struct { Struct { @@ -251,15 +245,9 @@ pub mod change_constructor_path_indirectly_tuple_struct { #[cfg(not(any(cfail1,cfail4)))] use super::TupleStruct2 as Struct; - #[rustc_clean( - cfg="cfail5", - except="fn_sig,hir_owner,hir_owner_nodes,optimized_mir,typeck" - )] + #[rustc_clean(cfg="cfail5", except="fn_sig,hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] - #[rustc_clean( - cfg="cfail2", - except="fn_sig,hir_owner,hir_owner_nodes,optimized_mir,typeck" - )] + #[rustc_clean(cfg="cfail2", except="fn_sig,hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] pub fn function() -> Struct { Struct(0, 1, 2) diff --git a/tests/incremental/hashes/struct_defs.rs b/tests/incremental/hashes/struct_defs.rs index 4a2706b4f0100..6ea4d890e4d54 100644 --- a/tests/incremental/hashes/struct_defs.rs +++ b/tests/incremental/hashes/struct_defs.rs @@ -51,9 +51,9 @@ struct LayoutC; struct TupleStructFieldType(i32); #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] // Note that changing the type of a field does not change the type of the struct or enum, but // adding/removing fields or changing a fields name or visibility does. @@ -68,9 +68,9 @@ struct TupleStructFieldType( struct TupleStructAddField(i32); #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,type_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,type_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] struct TupleStructAddField( i32, @@ -86,7 +86,7 @@ struct TupleStructFieldVisibility( char); #[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] struct TupleStructFieldVisibility(pub char); @@ -97,9 +97,9 @@ struct TupleStructFieldVisibility(pub char); struct RecordStructFieldType { x: f32 } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] // Note that changing the type of a field does not change the type of the struct or enum, but // adding/removing fields or changing a fields name or visibility does. @@ -114,9 +114,9 @@ struct RecordStructFieldType { struct RecordStructFieldName { x: f32 } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,type_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,type_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] struct RecordStructFieldName { y: f32 } @@ -127,9 +127,9 @@ struct RecordStructFieldName { y: f32 } struct RecordStructAddField { x: f32 } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,type_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,type_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] struct RecordStructAddField { x: f32, @@ -144,7 +144,7 @@ struct RecordStructFieldVisibility { x: f32 } #[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="type_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail6")] struct RecordStructFieldVisibility { pub x: f32 } @@ -155,9 +155,9 @@ struct RecordStructFieldVisibility { pub x: f32 } struct AddLifetimeParameter<'a>(&'a f32, &'a f64); #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of,generics_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,type_of,generics_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of,generics_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,type_of,generics_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] struct AddLifetimeParameter<'a, 'b>(&'a f32, &'b f64); @@ -168,9 +168,9 @@ struct AddLifetimeParameter<'a, 'b>(&'a f32, &'b f64); struct AddLifetimeParameterBound<'a, 'b>(&'a f32, &'b f64); #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] struct AddLifetimeParameterBound<'a, 'b: 'a>( &'a f32, @@ -181,9 +181,9 @@ struct AddLifetimeParameterBound<'a, 'b: 'a>( struct AddLifetimeParameterBoundWhereClause<'a, 'b>(&'a f32, &'b f64); #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] struct AddLifetimeParameterBoundWhereClause<'a, 'b>( &'a f32, @@ -197,9 +197,9 @@ struct AddLifetimeParameterBoundWhereClause<'a, 'b>( struct AddTypeParameter(T1, T1); #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of,generics_of,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,type_of,generics_of,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of,generics_of,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,type_of,generics_of,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] struct AddTypeParameter( // The field contains the parent's Generics, so it's dirty even though its @@ -215,9 +215,9 @@ struct AddTypeParameter( struct AddTypeParameterBound(T); #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] struct AddTypeParameterBound( T @@ -228,9 +228,9 @@ struct AddTypeParameterBound( struct AddTypeParameterBoundWhereClause(T); #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] struct AddTypeParameterBoundWhereClause( T @@ -257,7 +257,7 @@ struct Visibility; #[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] pub struct Visibility; @@ -271,9 +271,9 @@ mod tuple_struct_change_field_type_indirectly { #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedType2 as FieldType; - #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] struct TupleStruct( FieldType @@ -288,9 +288,9 @@ mod record_struct_change_field_type_indirectly { #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedType2 as FieldType; - #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] struct RecordStruct { _x: FieldType @@ -310,9 +310,9 @@ mod change_trait_bound_indirectly { #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedTrait2 as Trait; - #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] struct Struct(T); } @@ -324,9 +324,9 @@ mod change_trait_bound_indirectly_in_where_clause { #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedTrait2 as Trait; - #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] struct Struct(T) where T : Trait; } diff --git a/tests/incremental/hashes/trait_defs.rs b/tests/incremental/hashes/trait_defs.rs index 7b8c6245d2d4d..0a5eba7397722 100644 --- a/tests/incremental/hashes/trait_defs.rs +++ b/tests/incremental/hashes/trait_defs.rs @@ -30,7 +30,7 @@ trait TraitVisibility { } #[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] pub trait TraitVisibility { } @@ -41,9 +41,9 @@ pub trait TraitVisibility { } trait TraitUnsafety { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] unsafe trait TraitUnsafety { } @@ -55,9 +55,9 @@ trait TraitAddMethod { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub trait TraitAddMethod { fn method(); @@ -72,9 +72,9 @@ trait TraitChangeMethodName { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeMethodName { fn methodChanged(); @@ -85,9 +85,9 @@ trait TraitChangeMethodName { // Add return type to method #[cfg(any(cfail1,cfail4))] trait TraitAddReturnType { - //--------------------------------------------------------------------- + //----------------------------------------------------------- //-------------------------- - //--------------------------------------------------------------------- + //----------------------------------------------------------- //-------------------------- fn method() ; } @@ -98,9 +98,9 @@ trait TraitAddReturnType { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddReturnType { - #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method() -> u32; } @@ -110,9 +110,9 @@ trait TraitAddReturnType { // Change return type of method #[cfg(any(cfail1,cfail4))] trait TraitChangeReturnType { - // -------------------------------------------------------------------- + // ---------------------------------------------------------- // ------------------------- - // -------------------------------------------------------------------- + // ---------------------------------------------------------- // ------------------------- fn method() -> u32; } @@ -123,9 +123,9 @@ trait TraitChangeReturnType { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeReturnType { - #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method() -> u64; } @@ -135,9 +135,9 @@ trait TraitChangeReturnType { // Add parameter to method #[cfg(any(cfail1,cfail4))] trait TraitAddParameterToMethod { - // -------------------------------------------------------------------- + // ---------------------------------------------------------- // ------------------------- - // -------------------------------------------------------------------- + // ---------------------------------------------------------- // ------------------------- fn method( ); } @@ -148,9 +148,9 @@ trait TraitAddParameterToMethod { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddParameterToMethod { - #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(a: u32); } @@ -161,9 +161,9 @@ trait TraitAddParameterToMethod { #[cfg(any(cfail1,cfail4))] trait TraitChangeMethodParameterName { //------------------------------------------------------ - //-------------------------------------------------------------- + //---------------------------------------------------- //-------------------------- - //-------------------------------------------------------------- + //---------------------------------------------------- //-------------------------- fn method(a: u32); @@ -181,9 +181,9 @@ trait TraitChangeMethodParameterName { #[rustc_clean(cfg="cfail6")] trait TraitChangeMethodParameterName { // FIXME(#38501) This should preferably always be clean. - #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(b: u32); @@ -199,9 +199,9 @@ trait TraitChangeMethodParameterName { // Change type of method parameter (i32 => i64) #[cfg(any(cfail1,cfail4))] trait TraitChangeMethodParameterType { - // -------------------------------------------------------------------- + // ---------------------------------------------------------- // ------------------------- - // -------------------------------------------------------------------- + // ---------------------------------------------------------- // ------------------------- fn method(a: i32); } @@ -212,9 +212,9 @@ trait TraitChangeMethodParameterType { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeMethodParameterType { - #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(a: i64); } @@ -224,9 +224,9 @@ trait TraitChangeMethodParameterType { // Change type of method parameter (&i32 => &mut i32) #[cfg(any(cfail1,cfail4))] trait TraitChangeMethodParameterTypeRef { - // -------------------------------------------------------------------- + // ---------------------------------------------------------- // ------------------------- - // -------------------------------------------------------------------- + // ---------------------------------------------------------- // ------------------------- fn method(a: & i32); } @@ -237,9 +237,9 @@ trait TraitChangeMethodParameterTypeRef { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeMethodParameterTypeRef { - #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(a: &mut i32); } @@ -249,9 +249,9 @@ trait TraitChangeMethodParameterTypeRef { // Change order of method parameters #[cfg(any(cfail1,cfail4))] trait TraitChangeMethodParametersOrder { - // -------------------------------------------------------------------- + // ---------------------------------------------------------- // ------------------------- - // -------------------------------------------------------------------- + // ---------------------------------------------------------- // ------------------------- fn method(a: i32, b: i64); } @@ -262,9 +262,9 @@ trait TraitChangeMethodParametersOrder { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeMethodParametersOrder { - #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(b: i64, a: i32); } @@ -274,22 +274,22 @@ trait TraitChangeMethodParametersOrder { // Add default implementation to method #[cfg(any(cfail1,cfail4))] trait TraitAddMethodAutoImplementation { - // ------------------------------------------------------------- + // --------------------------------------------------- // ------------------------- - // ------------------------------------------------------------- + // --------------------------------------------------- // ------------------------- fn method() ; } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] +#[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] +#[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddMethodAutoImplementation { - #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method() {} } @@ -304,9 +304,9 @@ trait TraitChangeOrderOfMethods { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeOrderOfMethods { fn method1(); @@ -318,9 +318,9 @@ trait TraitChangeOrderOfMethods { // Change mode of self parameter #[cfg(any(cfail1,cfail4))] trait TraitChangeModeSelfRefToMut { - // -------------------------------------------------------------------- + // ---------------------------------------------------------- // ------------------------- - // -------------------------------------------------------------------- + // ---------------------------------------------------------- // ------------------------- fn method(& self); } @@ -331,9 +331,9 @@ trait TraitChangeModeSelfRefToMut { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeModeSelfRefToMut { - #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(&mut self); } @@ -342,9 +342,9 @@ trait TraitChangeModeSelfRefToMut { #[cfg(any(cfail1,cfail4))] trait TraitChangeModeSelfOwnToMut: Sized { - // ---------------------------------------------------------------------------------- + // ------------------------------------------------------------------------ // ------------------------- - // ---------------------------------------------------------------------------------- + // ------------------------------------------------------------------------ // ------------------------- fn method( self) {} } @@ -355,9 +355,9 @@ trait TraitChangeModeSelfOwnToMut: Sized { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeModeSelfOwnToMut: Sized { - #[rustc_clean(except="hir_owner,hir_owner_nodes,typeck,optimized_mir", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes,typeck,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes,typeck,optimized_mir", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes,typeck,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(mut self) {} } @@ -366,9 +366,9 @@ trait TraitChangeModeSelfOwnToMut: Sized { #[cfg(any(cfail1,cfail4))] trait TraitChangeModeSelfOwnToRef { - // -------------------------------------------------------------------------------- + // ---------------------------------------------------------------------- // ------------------------- - // -------------------------------------------------------------------------------- + // ---------------------------------------------------------------------- // ------------------------- fn method( self); } @@ -379,9 +379,9 @@ trait TraitChangeModeSelfOwnToRef { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeModeSelfOwnToRef { - #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,generics_of", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes,fn_sig,generics_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,generics_of", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes,fn_sig,generics_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(&self); } @@ -391,22 +391,22 @@ trait TraitChangeModeSelfOwnToRef { // Add unsafe modifier to method #[cfg(any(cfail1,cfail4))] trait TraitAddUnsafeModifier { - // -------------------------------------------------------------------- + // ---------------------------------------------------------- // ------------------------- - // -------------------------------------------------------------------- + // ---------------------------------------------------------- // ------------------------- - fn method() ; + fn method(); } #[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner", cfg="cfail5")] +#[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddUnsafeModifier { - #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] unsafe fn method(); } @@ -416,9 +416,9 @@ trait TraitAddUnsafeModifier { // Add extern modifier to method #[cfg(any(cfail1,cfail4))] trait TraitAddExternModifier { - // -------------------------------------------------------------------- + // ---------------------------------------------------------- // ------------------------- - // -------------------------------------------------------------------- + // ---------------------------------------------------------- // ------------------------- fn method(); } @@ -429,9 +429,9 @@ trait TraitAddExternModifier { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddExternModifier { - #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] extern "C" fn method(); } @@ -441,9 +441,9 @@ trait TraitAddExternModifier { // Change extern "C" to extern "stdcall" #[cfg(any(cfail1,cfail4))] trait TraitChangeExternCToRustIntrinsic { - // -------------------------------------------------------------------- + // ---------------------------------------------------------- // ------------------------- - // -------------------------------------------------------------------- + // ---------------------------------------------------------- // ------------------------- extern "C" fn method(); } @@ -454,9 +454,9 @@ trait TraitChangeExternCToRustIntrinsic { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeExternCToRustIntrinsic { - #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] extern "stdcall" fn method(); } @@ -466,10 +466,10 @@ trait TraitChangeExternCToRustIntrinsic { // Add type parameter to method #[cfg(any(cfail1,cfail4))] trait TraitAddTypeParameterToMethod { - // -------------------------------------------------------------------------------- + // ---------------------------------------------------------------------- // --------------- // ------------------------- - // -------------------------------------------------------------------------------- + // ---------------------------------------------------------------------- // --------------- // ------------------------- fn method (); @@ -481,10 +481,10 @@ trait TraitAddTypeParameterToMethod { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddTypeParameterToMethod { - #[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of", + #[rustc_clean(except="hir_owner_nodes,generics_of,predicates_of,type_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of", + #[rustc_clean(except="hir_owner_nodes,generics_of,predicates_of,type_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(); @@ -495,9 +495,9 @@ trait TraitAddTypeParameterToMethod { // Add lifetime parameter to method #[cfg(any(cfail1,cfail4))] trait TraitAddLifetimeParameterToMethod { - // -------------------------------------------------------------------------------- + // ---------------------------------------------------------------------- // ------------------------- - // -------------------------------------------------------------------------------- + // ---------------------------------------------------------------------- // ------------------------- fn method (); } @@ -508,9 +508,9 @@ trait TraitAddLifetimeParameterToMethod { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddLifetimeParameterToMethod { - #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,generics_of", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes,fn_sig,generics_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,generics_of", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes,fn_sig,generics_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method<'a>(); } @@ -524,9 +524,9 @@ trait ReferencedTrait1 { } // Add trait bound to method type parameter #[cfg(any(cfail1,cfail4))] trait TraitAddTraitBoundToMethodTypeParameter { - // --------------------------------------------------------------------------- + // ----------------------------------------------------------------- // ------------------------- - // --------------------------------------------------------------------------- + // ----------------------------------------------------------------- // ------------------------- fn method(); } @@ -537,9 +537,9 @@ trait TraitAddTraitBoundToMethodTypeParameter { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddTraitBoundToMethodTypeParameter { - #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(); } @@ -549,9 +549,9 @@ trait TraitAddTraitBoundToMethodTypeParameter { // Add builtin bound to method type parameter #[cfg(any(cfail1,cfail4))] trait TraitAddBuiltinBoundToMethodTypeParameter { - // --------------------------------------------------------------------------- + // ----------------------------------------------------------------- // ------------------------- - // --------------------------------------------------------------------------- + // ----------------------------------------------------------------- // ------------------------- fn method(); } @@ -562,9 +562,9 @@ trait TraitAddBuiltinBoundToMethodTypeParameter { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddBuiltinBoundToMethodTypeParameter { - #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(); } @@ -575,12 +575,12 @@ trait TraitAddBuiltinBoundToMethodTypeParameter { #[cfg(any(cfail1,cfail4))] trait TraitAddLifetimeBoundToMethodLifetimeParameter { // ----------- - // ----------------------------------------------------------------------------- + // ------------------------------------------------------------------- // -------------- // // ------------------------- // ----------- - // ----------------------------------------------------------------------------- + // ------------------------------------------------------------------- // -------------- // // ------------------------- @@ -594,12 +594,12 @@ trait TraitAddLifetimeBoundToMethodLifetimeParameter { #[rustc_clean(cfg="cfail6")] trait TraitAddLifetimeBoundToMethodLifetimeParameter { #[rustc_clean( - except="hir_owner,hir_owner_nodes,generics_of,predicates_of,fn_sig,type_of", + except="hir_owner_nodes,generics_of,predicates_of,fn_sig,type_of", cfg="cfail2", )] #[rustc_clean(cfg="cfail3")] #[rustc_clean( - except="hir_owner,hir_owner_nodes,generics_of,predicates_of,fn_sig,type_of", + except="hir_owner_nodes,generics_of,predicates_of,fn_sig,type_of", cfg="cfail5", )] #[rustc_clean(cfg="cfail6")] @@ -611,9 +611,9 @@ trait TraitAddLifetimeBoundToMethodLifetimeParameter { // Add second trait bound to method type parameter #[cfg(any(cfail1,cfail4))] trait TraitAddSecondTraitBoundToMethodTypeParameter { - // --------------------------------------------------------------------------- + // ----------------------------------------------------------------- // ------------------------- - // --------------------------------------------------------------------------- + // ----------------------------------------------------------------- // ------------------------- fn method(); } @@ -624,9 +624,9 @@ trait TraitAddSecondTraitBoundToMethodTypeParameter { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddSecondTraitBoundToMethodTypeParameter { - #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(); } @@ -636,9 +636,9 @@ trait TraitAddSecondTraitBoundToMethodTypeParameter { // Add second builtin bound to method type parameter #[cfg(any(cfail1,cfail4))] trait TraitAddSecondBuiltinBoundToMethodTypeParameter { - // --------------------------------------------------------------------------- + // ----------------------------------------------------------------- // ------------------------- - // --------------------------------------------------------------------------- + // ----------------------------------------------------------------- // ------------------------- fn method(); } @@ -649,9 +649,9 @@ trait TraitAddSecondBuiltinBoundToMethodTypeParameter { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddSecondBuiltinBoundToMethodTypeParameter { - #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(); } @@ -662,12 +662,12 @@ trait TraitAddSecondBuiltinBoundToMethodTypeParameter { #[cfg(any(cfail1,cfail4))] trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter { // ----------- - // ----------------------------------------------------------------------------- + // ------------------------------------------------------------------- // -------------- // // ------------------------- // ----------- - // ----------------------------------------------------------------------------- + // ------------------------------------------------------------------- // -------------- // // ------------------------- @@ -681,12 +681,12 @@ trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter { #[rustc_clean(cfg="cfail6")] trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter { #[rustc_clean( - except="hir_owner,hir_owner_nodes,generics_of,predicates_of,fn_sig,type_of", + except="hir_owner_nodes,generics_of,predicates_of,fn_sig,type_of", cfg="cfail2", )] #[rustc_clean(cfg="cfail3")] #[rustc_clean( - except="hir_owner,hir_owner_nodes,generics_of,predicates_of,fn_sig,type_of", + except="hir_owner_nodes,generics_of,predicates_of,fn_sig,type_of", cfg="cfail5", )] #[rustc_clean(cfg="cfail6")] @@ -710,9 +710,9 @@ trait TraitAddAssociatedType { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddAssociatedType { #[rustc_clean(cfg="cfail3")] @@ -731,9 +731,9 @@ trait TraitAddAssociatedType { // Add trait bound to associated type #[cfg(any(cfail1,cfail4))] trait TraitAddTraitBoundToAssociatedType { - // ------------------------------------------------------------- + // --------------------------------------------------- // ------------------------- - // ------------------------------------------------------------- + // --------------------------------------------------- // ------------------------- type Associated ; @@ -749,9 +749,9 @@ trait TraitAddTraitBoundToAssociatedType { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddTraitBoundToAssociatedType { - #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] type Associated: ReferencedTrait0; @@ -763,9 +763,9 @@ trait TraitAddTraitBoundToAssociatedType { // Add lifetime bound to associated type #[cfg(any(cfail1,cfail4))] trait TraitAddLifetimeBoundToAssociatedType<'a> { - // ------------------------------------------------------------- + // --------------------------------------------------- // ------------------------- - // ------------------------------------------------------------- + // --------------------------------------------------- // ------------------------- type Associated ; @@ -778,9 +778,9 @@ trait TraitAddLifetimeBoundToAssociatedType<'a> { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddLifetimeBoundToAssociatedType<'a> { - #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] type Associated: 'a; @@ -792,9 +792,9 @@ trait TraitAddLifetimeBoundToAssociatedType<'a> { // Add default to associated type #[cfg(any(cfail1,cfail4))] trait TraitAddDefaultToAssociatedType { - //-------------------------------------------------------------- + //---------------------------------------------------- //-------------------------- - //-------------------------------------------------------------- + //---------------------------------------------------- //-------------------------- type Associated ; @@ -802,14 +802,14 @@ trait TraitAddDefaultToAssociatedType { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] +#[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] +#[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddDefaultToAssociatedType { - #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] type Associated = ReferenceType0; @@ -825,9 +825,9 @@ trait TraitAddAssociatedConstant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddAssociatedConstant { const Value: u32; @@ -840,9 +840,9 @@ trait TraitAddAssociatedConstant { // Add initializer to associated constant #[cfg(any(cfail1,cfail4))] trait TraitAddInitializerToAssociatedConstant { - //-------------------------------------------------------------- + //---------------------------------------------------- //-------------------------- - //-------------------------------------------------------------- + //---------------------------------------------------- //-------------------------- const Value: u32 ; @@ -854,14 +854,14 @@ trait TraitAddInitializerToAssociatedConstant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] +#[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] +#[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddInitializerToAssociatedConstant { - #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] const Value: u32 = 1; @@ -877,9 +877,9 @@ trait TraitAddInitializerToAssociatedConstant { // Change type of associated constant #[cfg(any(cfail1,cfail4))] trait TraitChangeTypeOfAssociatedConstant { - // --------------------------------------------------------------------- + // ----------------------------------------------------------- // ------------------------- - // --------------------------------------------------------------------- + // ----------------------------------------------------------- // ------------------------- const Value: u32; @@ -896,9 +896,9 @@ trait TraitChangeTypeOfAssociatedConstant { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeTypeOfAssociatedConstant { - #[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes,type_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes,type_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] const Value: f64; @@ -916,9 +916,9 @@ trait TraitChangeTypeOfAssociatedConstant { trait TraitAddSuperTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddSuperTrait : ReferencedTrait0 { } @@ -929,9 +929,9 @@ trait TraitAddSuperTrait : ReferencedTrait0 { } trait TraitAddBuiltiBound { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddBuiltiBound : Send { } @@ -942,9 +942,9 @@ trait TraitAddBuiltiBound : Send { } trait TraitAddStaticLifetimeBound { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddStaticLifetimeBound : 'static { } @@ -955,9 +955,9 @@ trait TraitAddStaticLifetimeBound : 'static { } trait TraitAddTraitAsSecondBound : ReferencedTrait0 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddTraitAsSecondBound : ReferencedTrait0 + ReferencedTrait1 { } @@ -965,9 +965,9 @@ trait TraitAddTraitAsSecondBound : ReferencedTrait0 + ReferencedTrait1 { } trait TraitAddTraitAsSecondBoundFromBuiltin : Send { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddTraitAsSecondBoundFromBuiltin : Send + ReferencedTrait0 { } @@ -978,9 +978,9 @@ trait TraitAddTraitAsSecondBoundFromBuiltin : Send + ReferencedTrait0 { } trait TraitAddBuiltinBoundAsSecondBound : ReferencedTrait0 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddBuiltinBoundAsSecondBound : ReferencedTrait0 + Send { } @@ -988,9 +988,9 @@ trait TraitAddBuiltinBoundAsSecondBound : ReferencedTrait0 + Send { } trait TraitAddBuiltinBoundAsSecondBoundFromBuiltin : Send { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddBuiltinBoundAsSecondBoundFromBuiltin: Send + Copy { } @@ -1001,9 +1001,9 @@ trait TraitAddBuiltinBoundAsSecondBoundFromBuiltin: Send + Copy { } trait TraitAddStaticBoundAsSecondBound : ReferencedTrait0 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddStaticBoundAsSecondBound : ReferencedTrait0 + 'static { } @@ -1011,9 +1011,9 @@ trait TraitAddStaticBoundAsSecondBound : ReferencedTrait0 + 'static { } trait TraitAddStaticBoundAsSecondBoundFromBuiltin : Send { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddStaticBoundAsSecondBoundFromBuiltin : Send + 'static { } @@ -1024,9 +1024,9 @@ trait TraitAddStaticBoundAsSecondBoundFromBuiltin : Send + 'static { } trait TraitAddTypeParameterToTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddTypeParameterToTrait { } @@ -1037,9 +1037,9 @@ trait TraitAddTypeParameterToTrait { } trait TraitAddLifetimeParameterToTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddLifetimeParameterToTrait<'a> { } @@ -1050,9 +1050,9 @@ trait TraitAddLifetimeParameterToTrait<'a> { } trait TraitAddTraitBoundToTypeParameterOfTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddTraitBoundToTypeParameterOfTrait { } @@ -1063,9 +1063,9 @@ trait TraitAddTraitBoundToTypeParameterOfTrait { } trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T> { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T: 'a> { } @@ -1076,9 +1076,9 @@ trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T: 'a> { } trait TraitAddLifetimeBoundToLifetimeParameterOfTrait<'a, 'b> { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddLifetimeBoundToLifetimeParameterOfTrait<'a: 'b, 'b> { } @@ -1089,9 +1089,9 @@ trait TraitAddLifetimeBoundToLifetimeParameterOfTrait<'a: 'b, 'b> { } trait TraitAddBuiltinBoundToTypeParameterOfTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddBuiltinBoundToTypeParameterOfTrait { } @@ -1102,9 +1102,9 @@ trait TraitAddBuiltinBoundToTypeParameterOfTrait { } trait TraitAddSecondTypeParameterToTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddSecondTypeParameterToTrait { } @@ -1115,9 +1115,9 @@ trait TraitAddSecondTypeParameterToTrait { } trait TraitAddSecondLifetimeParameterToTrait<'a> { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddSecondLifetimeParameterToTrait<'a, 'b> { } @@ -1128,9 +1128,9 @@ trait TraitAddSecondLifetimeParameterToTrait<'a, 'b> { } trait TraitAddSecondTraitBoundToTypeParameterOfTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddSecondTraitBoundToTypeParameterOfTrait { } @@ -1141,9 +1141,9 @@ trait TraitAddSecondTraitBoundToTypeParameterOfTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddSecondLifetimeBoundToTypeParameterOfTrait<'a, 'b, T: 'a + 'b> { } @@ -1154,9 +1154,9 @@ trait TraitAddSecondLifetimeBoundToTypeParameterOfTrait<'a, 'b, T: 'a + 'b> { } trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTrait<'a: 'b, 'b, 'c> { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTrait<'a: 'b + 'c, 'b, 'c> { } @@ -1167,9 +1167,9 @@ trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTrait<'a: 'b + 'c, 'b, 'c> trait TraitAddSecondBuiltinBoundToTypeParameterOfTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddSecondBuiltinBoundToTypeParameterOfTrait { } @@ -1185,9 +1185,9 @@ struct ReferenceType1 {} trait TraitAddTraitBoundToTypeParameterOfTraitWhere { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddTraitBoundToTypeParameterOfTraitWhere where T: ReferencedTrait0 { } @@ -1198,9 +1198,9 @@ trait TraitAddTraitBoundToTypeParameterOfTraitWhere where T: ReferencedTrait0 trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> where T: 'a { } @@ -1211,9 +1211,9 @@ trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> where T: 'a { } trait TraitAddLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b> { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b> where 'a: 'b { } @@ -1224,9 +1224,9 @@ trait TraitAddLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b> where 'a: 'b trait TraitAddBuiltinBoundToTypeParameterOfTraitWhere { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddBuiltinBoundToTypeParameterOfTraitWhere where T: Send { } @@ -1237,9 +1237,9 @@ trait TraitAddBuiltinBoundToTypeParameterOfTraitWhere where T: Send { } trait TraitAddSecondTraitBoundToTypeParameterOfTraitWhere where T: ReferencedTrait0 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddSecondTraitBoundToTypeParameterOfTraitWhere where T: ReferencedTrait0 + ReferencedTrait1 { } @@ -1251,9 +1251,9 @@ trait TraitAddSecondTraitBoundToTypeParameterOfTraitWhere trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: 'a { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: 'a + 'b { } @@ -1264,9 +1264,9 @@ trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b, 'c> where 'a: 'b { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b, 'c> where 'a: 'b + 'c { } @@ -1277,9 +1277,9 @@ trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b, 'c> whe trait TraitAddSecondBuiltinBoundToTypeParameterOfTraitWhere where T: Send { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddSecondBuiltinBoundToTypeParameterOfTraitWhere where T: Send + Sync { } @@ -1296,9 +1296,9 @@ mod change_return_type_of_method_indirectly_use { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeReturnType { - #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method() -> ReturnType; } @@ -1318,9 +1318,9 @@ mod change_method_parameter_type_indirectly_by_use { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeArgType { - #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes,fn_sig", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(a: ArgType); } @@ -1340,9 +1340,9 @@ mod change_method_parameter_type_bound_indirectly_by_use { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeBoundOfMethodTypeParameter { - #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(a: T); } @@ -1363,9 +1363,9 @@ mod change_method_parameter_type_bound_indirectly_by_use_where { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeBoundOfMethodTypeParameterWhere { - #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(a: T) where T: Bound; } @@ -1380,9 +1380,9 @@ mod change_method_type_parameter_bound_indirectly { #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedTrait1 as Bound; - #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeTraitBound { fn method(a: T); @@ -1399,9 +1399,9 @@ mod change_method_type_parameter_bound_indirectly_where { #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedTrait1 as Bound; - #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeTraitBoundWhere where T: Bound { fn method(a: T); diff --git a/tests/incremental/hashes/trait_impls.rs b/tests/incremental/hashes/trait_impls.rs index 3b2e18d17a96b..028598244de73 100644 --- a/tests/incremental/hashes/trait_impls.rs +++ b/tests/incremental/hashes/trait_impls.rs @@ -32,9 +32,9 @@ impl ChangeMethodNameTrait for Foo { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub trait ChangeMethodNameTrait { #[rustc_clean(cfg="cfail3")] @@ -43,9 +43,9 @@ pub trait ChangeMethodNameTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl ChangeMethodNameTrait for Foo { #[rustc_clean(cfg="cfail3")] @@ -141,18 +141,18 @@ pub trait ChangeMethodSelfnessTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl ChangeMethodSelfnessTrait for Foo { #[rustc_clean( - except="hir_owner,hir_owner_nodes,associated_item,generics_of,fn_sig,typeck,optimized_mir", + except="hir_owner_nodes,associated_item,generics_of,fn_sig,typeck,optimized_mir", cfg="cfail2", )] #[rustc_clean(cfg="cfail3")] #[rustc_clean( - except="hir_owner,hir_owner_nodes,associated_item,generics_of,fn_sig,typeck,optimized_mir", + except="hir_owner_nodes,associated_item,generics_of,fn_sig,typeck,optimized_mir", cfg="cfail5", )] #[rustc_clean(cfg="cfail6")] @@ -179,18 +179,18 @@ pub trait RemoveMethodSelfnessTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl RemoveMethodSelfnessTrait for Foo { #[rustc_clean( - except="hir_owner,hir_owner_nodes,associated_item,generics_of,fn_sig,typeck,optimized_mir", + except="hir_owner_nodes,associated_item,generics_of,fn_sig,typeck,optimized_mir", cfg="cfail2", )] #[rustc_clean(cfg="cfail3")] #[rustc_clean( - except="hir_owner,hir_owner_nodes,associated_item,generics_of,fn_sig,typeck,optimized_mir", + except="hir_owner_nodes,associated_item,generics_of,fn_sig,typeck,optimized_mir", cfg="cfail5", )] #[rustc_clean(cfg="cfail6")] @@ -206,9 +206,9 @@ pub trait ChangeMethodSelfmutnessTrait { #[cfg(any(cfail1,cfail4))] impl ChangeMethodSelfmutnessTrait for Foo { - // ----------------------------------------------------------------------------------------- + // ------------------------------------------------------------------------------- // ------------------------- - // ----------------------------------------------------------------------------------------- + // ------------------------------------------------------------------------------- // ------------------------- fn method_name(& self) {} } @@ -224,9 +224,9 @@ pub trait ChangeMethodSelfmutnessTrait { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl ChangeMethodSelfmutnessTrait for Foo { - #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method_name(&mut self) {} } @@ -249,9 +249,9 @@ pub trait ChangeItemKindTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl ChangeItemKindTrait for Foo { type name = (); @@ -277,9 +277,9 @@ pub trait RemoveItemTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl RemoveItemTrait for Foo { type TypeName = (); @@ -304,9 +304,9 @@ pub trait AddItemTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl AddItemTrait for Foo { type TypeName = (); @@ -317,9 +317,9 @@ impl AddItemTrait for Foo { #[cfg(any(cfail1,cfail4))] pub trait ChangeHasValueTrait { - //-------------------------------------------------------------- + //---------------------------------------------------- //-------------------------- - //-------------------------------------------------------------- + //---------------------------------------------------- //-------------------------- fn method_name() ; } @@ -330,14 +330,14 @@ impl ChangeHasValueTrait for Foo { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] +#[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] +#[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub trait ChangeHasValueTrait { - #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method_name() { } } @@ -359,9 +359,9 @@ pub trait AddDefaultTrait { #[cfg(any(cfail1,cfail4))] impl AddDefaultTrait for Foo { - // ------------------------------------------------------------- + // --------------------------------------------------- // ------------------------- - // ------------------------------------------------------------- + // --------------------------------------------------- // ------------------------- fn method_name() { } } @@ -372,9 +372,9 @@ impl AddDefaultTrait for Foo { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl AddDefaultTrait for Foo { - #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] default fn method_name() { } } @@ -388,9 +388,9 @@ pub trait AddArgumentTrait { #[cfg(any(cfail1,cfail4))] impl AddArgumentTrait for Foo { - // ----------------------------------------------------------------------------------------- + // ------------------------------------------------------------------------------- // ------------------------- - // ----------------------------------------------------------------------------------------- + // ------------------------------------------------------------------------------- // ------------------------- fn method_name(&self ) { } } @@ -406,9 +406,9 @@ pub trait AddArgumentTrait { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl AddArgumentTrait for Foo { - #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method_name(&self, _x: u32) { } } @@ -422,9 +422,9 @@ pub trait ChangeArgumentTypeTrait { #[cfg(any(cfail1,cfail4))] impl ChangeArgumentTypeTrait for Foo { - // ----------------------------------------------------------------------------------------- + // ------------------------------------------------------------------------------- // ------------------------- - // ----------------------------------------------------------------------------------------- + // ------------------------------------------------------------------------------- // ------------------------- fn method_name(&self, _x: u32 ) { } } @@ -440,9 +440,9 @@ pub trait ChangeArgumentTypeTrait { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl ChangeArgumentTypeTrait for Foo { - #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail2")] + #[rustc_clean(except="hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail5")] + #[rustc_clean(except="hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method_name(&self, _x: char) { } } @@ -462,18 +462,18 @@ impl AddTypeParameterToImpl for Bar { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,impl_trait_ref", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,generics_of,impl_trait_ref", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,impl_trait_ref", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,generics_of,impl_trait_ref", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl AddTypeParameterToImpl for Bar { #[rustc_clean( - except="hir_owner,hir_owner_nodes,generics_of,fn_sig,type_of,typeck,optimized_mir", + except="hir_owner_nodes,generics_of,fn_sig,type_of,typeck,optimized_mir", cfg="cfail2", )] #[rustc_clean(cfg="cfail3")] #[rustc_clean( - except="hir_owner,hir_owner_nodes,generics_of,fn_sig,type_of,typeck,optimized_mir", + except="hir_owner_nodes,generics_of,fn_sig,type_of,typeck,optimized_mir", cfg="cfail5", )] #[rustc_clean(cfg="cfail6")] @@ -493,9 +493,9 @@ impl ChangeSelfTypeOfImpl for u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,impl_trait_ref", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes,impl_trait_ref", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,impl_trait_ref", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes,impl_trait_ref", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl ChangeSelfTypeOfImpl for u64 { #[rustc_clean(except="fn_sig,typeck,optimized_mir", cfg="cfail2")] @@ -518,9 +518,9 @@ impl AddLifetimeBoundToImplParameter for T { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl AddLifetimeBoundToImplParameter for T { #[rustc_clean(cfg="cfail2")] @@ -543,9 +543,9 @@ impl AddTraitBoundToImplParameter for T { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] +#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")] +#[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl AddTraitBoundToImplParameter for T { #[rustc_clean(cfg="cfail2")] diff --git a/tests/incremental/hashes/type_defs.rs b/tests/incremental/hashes/type_defs.rs index 79398eb07fe44..206c0595d5464 100644 --- a/tests/incremental/hashes/type_defs.rs +++ b/tests/incremental/hashes/type_defs.rs @@ -24,7 +24,7 @@ type ChangePrimitiveType = i32; #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type ChangePrimitiveType = i64; @@ -35,7 +35,7 @@ type ChangePrimitiveType = i64; type ChangeMutability = &'static i32; #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type ChangeMutability = &'static mut i32; @@ -46,7 +46,7 @@ type ChangeMutability = &'static mut i32; type ChangeLifetime<'a> = (&'static i32, &'a i32); #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type ChangeLifetime<'a> = (&'a i32, &'a i32); @@ -60,7 +60,7 @@ struct Struct2; type ChangeTypeStruct = Struct1; #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type ChangeTypeStruct = Struct2; @@ -71,7 +71,7 @@ type ChangeTypeStruct = Struct2; type ChangeTypeTuple = (u32, u64); #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type ChangeTypeTuple = (u32, i64); @@ -91,7 +91,7 @@ enum Enum2 { type ChangeTypeEnum = Enum1; #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type ChangeTypeEnum = Enum2; @@ -102,7 +102,7 @@ type ChangeTypeEnum = Enum2; type AddTupleField = (i32, i64); #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type AddTupleField = (i32, i64, i16); @@ -113,7 +113,7 @@ type AddTupleField = (i32, i64, i16); type ChangeNestedTupleField = (i32, (i64, i16)); #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type ChangeNestedTupleField = (i32, (i64, i8)); @@ -124,7 +124,7 @@ type ChangeNestedTupleField = (i32, (i64, i8)); type AddTypeParam = (T1, T1); #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type AddTypeParam = (T1, T2); @@ -135,7 +135,7 @@ type AddTypeParam = (T1, T2); type AddTypeParamBound = (T1, u32); #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type AddTypeParamBound = (T1, u32); @@ -146,7 +146,7 @@ type AddTypeParamBound = (T1, u32); type AddTypeParamBoundWhereClause where T1: Clone = (T1, u32); #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type AddTypeParamBoundWhereClause where T1: Clone+Copy = (T1, u32); @@ -157,7 +157,7 @@ type AddTypeParamBoundWhereClause where T1: Clone+Copy = (T1, u32); type AddLifetimeParam<'a> = (&'a u32, &'a u32); #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type AddLifetimeParam<'a, 'b> = (&'a u32, &'b u32); @@ -168,7 +168,7 @@ type AddLifetimeParam<'a, 'b> = (&'a u32, &'b u32); type AddLifetimeParamBound<'a, 'b> = (&'a u32, &'b u32); #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type AddLifetimeParamBound<'a, 'b: 'a> = (&'a u32, &'b u32); @@ -181,7 +181,7 @@ where 'b: 'a = (&'a u32, &'b u32, &'c u32); #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type AddLifetimeParamBoundWhereClause<'a, 'b, 'c> where 'b: 'a, @@ -200,7 +200,7 @@ mod change_trait_bound_indirectly { #[cfg(not(cfail1))] use super::ReferencedTrait2 as Trait; - #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] + #[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type ChangeTraitBoundIndirectly = (T, u32); } @@ -214,7 +214,7 @@ mod change_trait_bound_indirectly_in_where_clause { #[cfg(not(cfail1))] use super::ReferencedTrait2 as Trait; - #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] + #[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type ChangeTraitBoundIndirectly where T : Trait = (T, u32); } From d59968b5f65c8b703f66913181d30d31df113d70 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Tue, 16 Jan 2024 23:23:31 +0000 Subject: [PATCH 0318/1197] Simplify BodyId hashing. --- compiler/rustc_ast_lowering/src/lib.rs | 6 ++-- compiler/rustc_hir/src/hir.rs | 2 +- compiler/rustc_hir/src/stable_hash_impls.rs | 7 ---- compiler/rustc_query_system/src/ich/hcx.rs | 35 ------------------- .../rustc_query_system/src/ich/impls_hir.rs | 22 ------------ .../src/ich/impls_syntax.rs | 2 ++ compiler/rustc_query_system/src/ich/mod.rs | 1 - 7 files changed, 6 insertions(+), 69 deletions(-) delete mode 100644 compiler/rustc_query_system/src/ich/impls_hir.rs diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 5387880b6e62c..057fe65d0afad 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -662,9 +662,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let (opt_hash_including_bodies, attrs_hash) = if self.tcx.needs_crate_hash() { self.tcx.with_stable_hashing_context(|mut hcx| { let mut stable_hasher = StableHasher::new(); - hcx.with_hir_bodies(node.def_id(), &bodies, |hcx| { - node.hash_stable(hcx, &mut stable_hasher) - }); + node.hash_stable(&mut hcx, &mut stable_hasher); + // Bodies are stored out of line, so we need to pull them explicitly in the hash. + bodies.hash_stable(&mut hcx, &mut stable_hasher); let h1 = stable_hasher.finish(); let mut stable_hasher = StableHasher::new(); diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 309850d04d367..6773f7a4c6698 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1302,7 +1302,7 @@ pub enum UnsafeSource { UserProvided, } -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] pub struct BodyId { pub hir_id: HirId, } diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs index 97fa710b35499..baa1635f7313f 100644 --- a/compiler/rustc_hir/src/stable_hash_impls.rs +++ b/compiler/rustc_hir/src/stable_hash_impls.rs @@ -12,7 +12,6 @@ use rustc_span::def_id::DefPathHash; pub trait HashStableContext: rustc_ast::HashStableContext + rustc_target::HashStableContext { - fn hash_body_id(&mut self, _: BodyId, hasher: &mut StableHasher); } impl ToStableHashKey for HirId { @@ -80,12 +79,6 @@ impl ToStableHashKey for ForeignItemId } } -impl HashStable for BodyId { - fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { - hcx.hash_body_id(*self, hasher) - } -} - // The following implementations of HashStable for `ItemId`, `TraitItemId`, and // `ImplItemId` deserve special attention. Normally we do not hash `NodeId`s within // the HIR, since they just signify a HIR nodes own path. But `ItemId` et al diff --git a/compiler/rustc_query_system/src/ich/hcx.rs b/compiler/rustc_query_system/src/ich/hcx.rs index eec0433ae68d2..e7eb9694f4738 100644 --- a/compiler/rustc_query_system/src/ich/hcx.rs +++ b/compiler/rustc_query_system/src/ich/hcx.rs @@ -1,10 +1,8 @@ use crate::ich; use rustc_ast as ast; -use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::stable_hasher::{HashStable, HashingControls, StableHasher}; use rustc_data_structures::sync::Lrc; -use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::definitions::DefPathHash; use rustc_session::cstore::Untracked; @@ -23,7 +21,6 @@ pub struct StableHashingContext<'a> { // The value of `-Z incremental-ignore-spans`. // This field should only be used by `unstable_opts_incremental_ignore_span` incremental_ignore_spans: bool, - pub(super) body_resolver: BodyResolver<'a>, // Very often, we are hashing something that does not need the // `CachingSourceMapView`, so we initialize it lazily. raw_source_map: &'a SourceMap, @@ -31,26 +28,12 @@ pub struct StableHashingContext<'a> { hashing_controls: HashingControls, } -/// The `BodyResolver` allows mapping a `BodyId` to the corresponding `hir::Body`. -/// We could also just store a plain reference to the `hir::Crate` but we want -/// to avoid that the crate is used to get untracked access to all of the HIR. -#[derive(Clone, Copy)] -pub(super) enum BodyResolver<'tcx> { - Forbidden, - Ignore, - Traverse { - owner: hir::OwnerId, - bodies: &'tcx SortedMap>, - }, -} - impl<'a> StableHashingContext<'a> { #[inline] pub fn new(sess: &'a Session, untracked: &'a Untracked) -> Self { let hash_spans_initial = !sess.opts.unstable_opts.incremental_ignore_spans; StableHashingContext { - body_resolver: BodyResolver::Forbidden, untracked, incremental_ignore_spans: sess.opts.unstable_opts.incremental_ignore_spans, caching_source_map: None, @@ -59,24 +42,6 @@ impl<'a> StableHashingContext<'a> { } } - #[inline] - pub fn without_hir_bodies(&mut self, f: impl FnOnce(&mut StableHashingContext<'_>)) { - f(&mut StableHashingContext { body_resolver: BodyResolver::Ignore, ..self.clone() }); - } - - #[inline] - pub fn with_hir_bodies( - &mut self, - owner: hir::OwnerId, - bodies: &SortedMap>, - f: impl FnOnce(&mut StableHashingContext<'_>), - ) { - f(&mut StableHashingContext { - body_resolver: BodyResolver::Traverse { owner, bodies }, - ..self.clone() - }); - } - #[inline] pub fn while_hashing_spans(&mut self, hash_spans: bool, f: F) { let prev_hash_spans = self.hashing_controls.hash_spans; diff --git a/compiler/rustc_query_system/src/ich/impls_hir.rs b/compiler/rustc_query_system/src/ich/impls_hir.rs deleted file mode 100644 index aa008d404c3ea..0000000000000 --- a/compiler/rustc_query_system/src/ich/impls_hir.rs +++ /dev/null @@ -1,22 +0,0 @@ -//! This module contains `HashStable` implementations for various HIR data -//! types in no particular order. - -use crate::ich::hcx::BodyResolver; -use crate::ich::StableHashingContext; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_hir as hir; - -impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> { - #[inline] - fn hash_body_id(&mut self, id: hir::BodyId, hasher: &mut StableHasher) { - let hcx = self; - match hcx.body_resolver { - BodyResolver::Forbidden => panic!("Hashing HIR bodies is forbidden."), - BodyResolver::Ignore => {} - BodyResolver::Traverse { owner, bodies } => { - assert_eq!(id.hir_id.owner, owner); - bodies[&id.hir_id.local_id].hash_stable(hcx, hasher); - } - } - } -} diff --git a/compiler/rustc_query_system/src/ich/impls_syntax.rs b/compiler/rustc_query_system/src/ich/impls_syntax.rs index d170cd36ca6aa..5bd4fe04848fb 100644 --- a/compiler/rustc_query_system/src/ich/impls_syntax.rs +++ b/compiler/rustc_query_system/src/ich/impls_syntax.rs @@ -57,6 +57,8 @@ impl<'ctx> rustc_ast::HashStableContext for StableHashingContext<'ctx> { } } +impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> {} + impl<'a> HashStable> for SourceFile { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let SourceFile { diff --git a/compiler/rustc_query_system/src/ich/mod.rs b/compiler/rustc_query_system/src/ich/mod.rs index 0a1c350b2db13..86e3ecb1eddb7 100644 --- a/compiler/rustc_query_system/src/ich/mod.rs +++ b/compiler/rustc_query_system/src/ich/mod.rs @@ -4,7 +4,6 @@ pub use self::hcx::StableHashingContext; use rustc_span::symbol::{sym, Symbol}; mod hcx; -mod impls_hir; mod impls_syntax; pub const IGNORED_ATTRIBUTES: &[Symbol] = &[ From 37a5464bc8e630beee4377ec7ccc0ee912291907 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 14 Jan 2024 02:00:45 +0000 Subject: [PATCH 0319/1197] Eagerly instantiate closure ty --- compiler/rustc_hir_typeck/src/closure.rs | 146 +++++++++--------- ...re-print-generic-trim-off-verbose-2.stderr | 2 +- .../closure-print-generic-verbose-2.stderr | 2 +- .../print/closure-print-verbose.stderr | 2 +- 4 files changed, 73 insertions(+), 79 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 57fdfa4ecb6ea..d11198d7fd4e7 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -68,12 +68,58 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!(?bound_sig, ?liberated_sig); + let parent_args = + GenericArgs::identity_for_item(tcx, tcx.typeck_root_def_id(expr_def_id.to_def_id())); + + let tupled_upvars_ty = self.next_root_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::ClosureSynthetic, + span: expr_span, + }); + // FIXME: We could probably actually just unify this further -- // instead of having a `FnSig` and a `Option`, // we can have a `ClosureSignature { Coroutine { .. }, Closure { .. } }`, // similar to how `ty::GenSig` is a distinct data structure. - let coroutine_types = match closure.kind { - hir::ClosureKind::Closure => None, + let (closure_ty, coroutine_types) = match closure.kind { + hir::ClosureKind::Closure => { + // Tuple up the arguments and insert the resulting function type into + // the `closures` table. + let sig = bound_sig.map_bound(|sig| { + tcx.mk_fn_sig( + [Ty::new_tup(tcx, sig.inputs())], + sig.output(), + sig.c_variadic, + sig.unsafety, + sig.abi, + ) + }); + + debug!(?sig, ?expected_kind); + + let closure_kind_ty = match expected_kind { + Some(kind) => Ty::from_closure_kind(tcx, kind), + + // Create a type variable (for now) to represent the closure kind. + // It will be unified during the upvar inference phase (`upvar.rs`) + None => self.next_root_ty_var(TypeVariableOrigin { + // FIXME(eddyb) distinguish closure kind inference variables from the rest. + kind: TypeVariableOriginKind::ClosureSynthetic, + span: expr_span, + }), + }; + + let closure_args = ty::ClosureArgs::new( + tcx, + ty::ClosureArgsParts { + parent_args, + closure_kind_ty, + closure_sig_as_fn_ptr_ty: Ty::new_fn_ptr(tcx, sig), + tupled_upvars_ty, + }, + ); + + (Ty::new_closure(tcx, expr_def_id.to_def_id(), closure_args.args), None) + } hir::ClosureKind::Coroutine(kind) => { let yield_ty = match kind { hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) @@ -119,74 +165,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Resume type defaults to `()` if the coroutine has no argument. let resume_ty = liberated_sig.inputs().get(0).copied().unwrap_or(tcx.types.unit); - Some(CoroutineTypes { resume_ty, yield_ty }) - } - }; - - check_fn( - &mut FnCtxt::new(self, self.param_env, closure.def_id), - liberated_sig, - coroutine_types, - closure.fn_decl, - expr_def_id, - body, - // Closure "rust-call" ABI doesn't support unsized params - false, - ); - - let parent_args = - GenericArgs::identity_for_item(tcx, tcx.typeck_root_def_id(expr_def_id.to_def_id())); - - let tupled_upvars_ty = self.next_root_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::ClosureSynthetic, - span: expr_span, - }); - - match closure.kind { - hir::ClosureKind::Closure => { - assert_eq!(coroutine_types, None); - // Tuple up the arguments and insert the resulting function type into - // the `closures` table. - let sig = bound_sig.map_bound(|sig| { - tcx.mk_fn_sig( - [Ty::new_tup(tcx, sig.inputs())], - sig.output(), - sig.c_variadic, - sig.unsafety, - sig.abi, - ) - }); - - debug!(?sig, ?expected_kind); - - let closure_kind_ty = match expected_kind { - Some(kind) => Ty::from_closure_kind(tcx, kind), - - // Create a type variable (for now) to represent the closure kind. - // It will be unified during the upvar inference phase (`upvar.rs`) - None => self.next_root_ty_var(TypeVariableOrigin { - // FIXME(eddyb) distinguish closure kind inference variables from the rest. - kind: TypeVariableOriginKind::ClosureSynthetic, - span: expr_span, - }), - }; - - let closure_args = ty::ClosureArgs::new( - tcx, - ty::ClosureArgsParts { - parent_args, - closure_kind_ty, - closure_sig_as_fn_ptr_ty: Ty::new_fn_ptr(tcx, sig), - tupled_upvars_ty, - }, - ); - - Ty::new_closure(tcx, expr_def_id.to_def_id(), closure_args.args) - } - hir::ClosureKind::Coroutine(_) => { - let Some(CoroutineTypes { resume_ty, yield_ty }) = coroutine_types else { - bug!("expected coroutine to have yield/resume types"); - }; let interior = self.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span: body.value.span, @@ -209,9 +187,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, ); - Ty::new_coroutine(tcx, expr_def_id.to_def_id(), coroutine_args.args) + ( + Ty::new_coroutine(tcx, expr_def_id.to_def_id(), coroutine_args.args), + Some(CoroutineTypes { resume_ty, yield_ty }), + ) } - } + }; + + check_fn( + &mut FnCtxt::new(self, self.param_env, closure.def_id), + liberated_sig, + coroutine_types, + closure.fn_decl, + expr_def_id, + body, + // Closure "rust-call" ABI doesn't support unsized params + false, + ); + + closure_ty } /// Given the expected type, figures out what it can about this closure we @@ -683,10 +677,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) } // All `gen {}` and `async gen {}` must return unit. - hir::ClosureKind::Coroutine( - hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) - | hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _), - ) => self.tcx.types.unit, + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Gen | hir::CoroutineDesugaring::AsyncGen, + _, + )) => self.tcx.types.unit, // For async blocks, we just fall back to `_` here. // For closures/coroutines, we know nothing about the return diff --git a/tests/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr b/tests/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr index 1a13255429f00..02d75ff1228d6 100644 --- a/tests/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr +++ b/tests/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr @@ -9,7 +9,7 @@ LL | let c1 : () = c; | expected due to this | = note: expected unit type `()` - found closure `{mod1::f::{closure#0} closure_args=(unavailable) args=[T, ?16t, extern "rust-call" fn(()), ?15t]}` + found closure `{mod1::f::{closure#0} closure_args=(unavailable) args=[T, ?8t, extern "rust-call" fn(()), ?7t]}` help: use parentheses to call this closure | LL | let c1 : () = c(); diff --git a/tests/ui/closures/print/closure-print-generic-verbose-2.stderr b/tests/ui/closures/print/closure-print-generic-verbose-2.stderr index 8553817247d54..a536768898988 100644 --- a/tests/ui/closures/print/closure-print-generic-verbose-2.stderr +++ b/tests/ui/closures/print/closure-print-generic-verbose-2.stderr @@ -9,7 +9,7 @@ LL | let c1 : () = c; | expected due to this | = note: expected unit type `()` - found closure `{f::{closure#0} closure_args=(unavailable) args=[T, ?16t, extern "rust-call" fn(()), ?15t]}` + found closure `{f::{closure#0} closure_args=(unavailable) args=[T, ?8t, extern "rust-call" fn(()), ?7t]}` help: use parentheses to call this closure | LL | let c1 : () = c(); diff --git a/tests/ui/closures/print/closure-print-verbose.stderr b/tests/ui/closures/print/closure-print-verbose.stderr index 3d0af5eb171c8..fca8f25792ac3 100644 --- a/tests/ui/closures/print/closure-print-verbose.stderr +++ b/tests/ui/closures/print/closure-print-verbose.stderr @@ -7,7 +7,7 @@ LL | let foo: fn(u8) -> u8 = |v: u8| { a += v; a }; | expected due to this | = note: expected fn pointer `fn(u8) -> u8` - found closure `{main::{closure#0} closure_args=(unavailable) args=[i8, extern "rust-call" fn((u8,)) -> u8, ?6t]}` + found closure `{main::{closure#0} closure_args=(unavailable) args=[i8, extern "rust-call" fn((u8,)) -> u8, ?4t]}` note: closures can only be coerced to `fn` types if they do not capture any variables --> $DIR/closure-print-verbose.rs:10:39 | From b82d1d32b4c4a998c0a88ea7156edc2c5b4e1439 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 16 Jan 2024 18:07:49 +1100 Subject: [PATCH 0320/1197] Inline `create_dump_file_with_basename` --- compiler/rustc_middle/src/mir/pretty.rs | 35 +++++++++---------------- 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 239929a2c0ef6..5144c9b8c13f4 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -205,26 +205,6 @@ fn dump_path(tcx: TyCtxt<'_>, basename: &str, extension: &str) -> PathBuf { file_path } -/// Attempts to open the MIR dump file with the given name and extension. -fn create_dump_file_with_basename( - tcx: TyCtxt<'_>, - file_basename: &str, - extension: &str, -) -> io::Result> { - let file_path = dump_path(tcx, file_basename, extension); - if let Some(parent) = file_path.parent() { - fs::create_dir_all(parent).map_err(|e| { - io::Error::new( - e.kind(), - format!("IO error creating MIR dump directory: {parent:?}; {e}"), - ) - })?; - } - Ok(io::BufWriter::new(fs::File::create(&file_path).map_err(|e| { - io::Error::new(e.kind(), format!("IO error creating MIR dump file: {file_path:?}; {e}")) - })?)) -} - /// Attempts to open a file where we should dump a given MIR or other /// bit of MIR-related data. Used by `mir-dump`, but also by other /// bits of code (e.g., NLL inference) that dump graphviz data or @@ -237,11 +217,22 @@ pub fn create_dump_file<'tcx>( disambiguator: &dyn Display, body: &Body<'tcx>, ) -> io::Result> { - create_dump_file_with_basename( + let file_path = dump_path( tcx, &dump_file_basename(tcx, pass_num, pass_name, disambiguator, body), extension, - ) + ); + if let Some(parent) = file_path.parent() { + fs::create_dir_all(parent).map_err(|e| { + io::Error::new( + e.kind(), + format!("IO error creating MIR dump directory: {parent:?}; {e}"), + ) + })?; + } + Ok(io::BufWriter::new(fs::File::create(&file_path).map_err(|e| { + io::Error::new(e.kind(), format!("IO error creating MIR dump file: {file_path:?}; {e}")) + })?)) } /////////////////////////////////////////////////////////////////////////// From 1ec567b99aa961435ee9b825d70d1f471ac7388b Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 16 Jan 2024 18:14:44 +1100 Subject: [PATCH 0321/1197] Inline `dump_file_basename` into `dump_path` --- compiler/rustc_middle/src/mir/pretty.rs | 29 +++++++++---------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 5144c9b8c13f4..2cf6410990e8d 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -142,15 +142,17 @@ fn dump_matched_mir_node<'tcx, F>( } } -/// Returns the file basename portion (without extension) of a filename path -/// where we should dump a MIR representation output files. -fn dump_file_basename<'tcx>( +/// Returns the path to the filename where we should dump a given MIR. +/// Also used by other bits of code (e.g., NLL inference) that dump +/// graphviz data or other things. +fn dump_path<'tcx>( tcx: TyCtxt<'tcx>, + extension: &str, pass_num: bool, pass_name: &str, disambiguator: &dyn Display, body: &Body<'tcx>, -) -> String { +) -> PathBuf { let source = body.source; let promotion_id = match source.promoted { Some(id) => format!("-{id:?}"), @@ -186,19 +188,12 @@ fn dump_file_basename<'tcx>( _ => String::new(), }; - format!( - "{crate_name}.{item_name}{shim_disambiguator}{promotion_id}{pass_num}.{pass_name}.{disambiguator}", - ) -} - -/// Returns the path to the filename where we should dump a given MIR. -/// Also used by other bits of code (e.g., NLL inference) that dump -/// graphviz data or other things. -fn dump_path(tcx: TyCtxt<'_>, basename: &str, extension: &str) -> PathBuf { let mut file_path = PathBuf::new(); file_path.push(Path::new(&tcx.sess.opts.unstable_opts.dump_mir_dir)); - let file_name = format!("{basename}.{extension}",); + let file_name = format!( + "{crate_name}.{item_name}{shim_disambiguator}{promotion_id}{pass_num}.{pass_name}.{disambiguator}.{extension}", + ); file_path.push(&file_name); @@ -217,11 +212,7 @@ pub fn create_dump_file<'tcx>( disambiguator: &dyn Display, body: &Body<'tcx>, ) -> io::Result> { - let file_path = dump_path( - tcx, - &dump_file_basename(tcx, pass_num, pass_name, disambiguator, body), - extension, - ); + let file_path = dump_path(tcx, extension, pass_num, pass_name, disambiguator, body); if let Some(parent) = file_path.parent() { fs::create_dir_all(parent).map_err(|e| { io::Error::new( From 19d6f068ee75d258a5f14d609894af49943f907e Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 17 Jan 2024 02:59:47 +0100 Subject: [PATCH 0322/1197] Don't rely on contiguous `VariantId`s outside of rustc --- Cargo.lock | 1 + compiler/rustc_pattern_analysis/Cargo.toml | 1 + .../rustc_pattern_analysis/src/constructor.rs | 11 +++-- compiler/rustc_pattern_analysis/src/lib.rs | 42 ++++++++++++++++++- 4 files changed, 49 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f85d523fc1bcc..0df01e5e29af9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4355,6 +4355,7 @@ name = "rustc_pattern_analysis" version = "0.0.0" dependencies = [ "derivative", + "rustc-hash", "rustc_apfloat", "rustc_arena", "rustc_data_structures", diff --git a/compiler/rustc_pattern_analysis/Cargo.toml b/compiler/rustc_pattern_analysis/Cargo.toml index 7cc585bea3af7..1d0e1cb7e6a57 100644 --- a/compiler/rustc_pattern_analysis/Cargo.toml +++ b/compiler/rustc_pattern_analysis/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start derivative = "2.2.0" +rustc-hash = "1.1.0" rustc_apfloat = "0.2.0" rustc_arena = { path = "../rustc_arena", optional = true } rustc_data_structures = { path = "../rustc_data_structures", optional = true } diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs index c1042d5b66eca..76098505b7944 100644 --- a/compiler/rustc_pattern_analysis/src/constructor.rs +++ b/compiler/rustc_pattern_analysis/src/constructor.rs @@ -155,13 +155,13 @@ use std::iter::once; use smallvec::SmallVec; use rustc_apfloat::ieee::{DoubleS, IeeeFloat, SingleS}; -use rustc_index::bit_set::{BitSet, GrowableBitSet}; -use rustc_index::IndexVec; +use rustc_index::bit_set::GrowableBitSet; use self::Constructor::*; use self::MaybeInfiniteInt::*; use self::SliceKind::*; +use crate::index; use crate::usefulness::PlaceCtxt; use crate::TypeCx; @@ -804,7 +804,10 @@ pub enum ConstructorSet { Struct { empty: bool }, /// This type has the following list of constructors. If `variants` is empty and /// `non_exhaustive` is false, don't use this; use `NoConstructors` instead. - Variants { variants: IndexVec, non_exhaustive: bool }, + Variants { + variants: index::IdxContainer, + non_exhaustive: bool, + }, /// The type is `&T`. Ref, /// The type is a union. @@ -904,7 +907,7 @@ impl ConstructorSet { } } ConstructorSet::Variants { variants, non_exhaustive } => { - let mut seen_set: BitSet<_> = BitSet::new_empty(variants.len()); + let mut seen_set = index::IdxSet::new_empty(variants.len()); for idx in seen.iter().map(|c| c.as_variant().unwrap()) { seen_set.insert(idx); } diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs index ed10a5155084d..867924180dd3d 100644 --- a/compiler/rustc_pattern_analysis/src/lib.rs +++ b/compiler/rustc_pattern_analysis/src/lib.rs @@ -21,7 +21,45 @@ rustc_fluent_macro::fluent_messages! { "../messages.ftl" } use std::fmt; -use rustc_index::Idx; +#[cfg(feature = "rustc")] +pub mod index { + // Faster version when the indices of variants are `0..variants.len()`. + pub use rustc_index::bit_set::BitSet as IdxSet; + pub use rustc_index::Idx; + pub use rustc_index::IndexVec as IdxContainer; +} +#[cfg(not(feature = "rustc"))] +pub mod index { + // Slower version when the indices of variants are something else. + pub trait Idx: Copy + PartialEq + Eq + std::hash::Hash {} + impl Idx for T {} + + #[derive(Debug)] + pub struct IdxContainer(pub rustc_hash::FxHashMap); + impl IdxContainer { + pub fn len(&self) -> usize { + self.0.len() + } + pub fn iter_enumerated(&self) -> impl Iterator { + self.0.iter().map(|(k, v)| (*k, v)) + } + } + + #[derive(Debug)] + pub struct IdxSet(pub rustc_hash::FxHashSet); + impl IdxSet { + pub fn new_empty(_len: usize) -> Self { + Self(Default::default()) + } + pub fn contains(&self, elem: T) -> bool { + self.0.contains(&elem) + } + pub fn insert(&mut self, elem: T) { + self.0.insert(elem); + } + } +} + #[cfg(feature = "rustc")] use rustc_middle::ty::Ty; #[cfg(feature = "rustc")] @@ -50,7 +88,7 @@ pub trait TypeCx: Sized + fmt::Debug { /// Errors that can abort analysis. type Error: fmt::Debug; /// The index of an enum variant. - type VariantIdx: Clone + Idx; + type VariantIdx: Clone + index::Idx + fmt::Debug; /// A string literal type StrLit: Clone + PartialEq + fmt::Debug; /// Extra data to store in a match arm. From 7889e99b553840de211482e4c86b2a145a968432 Mon Sep 17 00:00:00 2001 From: Lieselotte <52315535+she3py@users.noreply.github.com> Date: Wed, 17 Jan 2024 03:14:16 +0100 Subject: [PATCH 0323/1197] Add `PatKind::Err` --- compiler/rustc_ast/src/ast.rs | 6 +++++- compiler/rustc_ast/src/mut_visit.rs | 2 +- compiler/rustc_ast/src/visit.rs | 2 +- compiler/rustc_ast_lowering/src/pat.rs | 1 + compiler/rustc_ast_pretty/src/pprust/state.rs | 5 +++++ compiler/rustc_hir/src/hir.rs | 7 +++++-- compiler/rustc_hir/src/intravisit.rs | 2 +- compiler/rustc_hir_analysis/src/check/region.rs | 3 ++- compiler/rustc_hir_pretty/src/lib.rs | 5 +++++ compiler/rustc_hir_typeck/src/expr_use_visitor.rs | 10 +++++++--- compiler/rustc_hir_typeck/src/mem_categorization.rs | 3 ++- compiler/rustc_hir_typeck/src/pat.rs | 7 +++++-- compiler/rustc_lint/src/unused.rs | 2 +- compiler/rustc_mir_build/src/thir/pattern/mod.rs | 2 ++ compiler/rustc_passes/src/hir_stats.rs | 6 ++++-- src/librustdoc/clean/utils.rs | 4 +++- src/tools/clippy/clippy_lints/src/equatable_if_let.rs | 3 ++- .../clippy/clippy_lints/src/matches/match_same_arms.rs | 5 ++++- .../clippy/clippy_lints/src/unnested_or_patterns.rs | 2 +- src/tools/clippy/clippy_lints/src/utils/author.rs | 1 + src/tools/clippy/clippy_utils/src/hir_utils.rs | 2 +- src/tools/clippy/clippy_utils/src/lib.rs | 1 + src/tools/rustfmt/src/patterns.rs | 9 ++++++--- 23 files changed, 66 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 21077c312bdc8..d0d98eb3d62d1 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -625,7 +625,8 @@ impl Pat { | PatKind::Range(..) | PatKind::Ident(..) | PatKind::Path(..) - | PatKind::MacCall(_) => {} + | PatKind::MacCall(_) + | PatKind::Err(_) => {} } } @@ -809,6 +810,9 @@ pub enum PatKind { /// A macro pattern; pre-expansion. MacCall(P), + + /// Placeholder for a pattern that wasn't syntactically well formed in some way. + Err(ErrorGuaranteed), } /// Whether the `..` is present in a struct fields pattern. diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 450555d0cb56d..90677151d2506 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1267,7 +1267,7 @@ pub fn noop_visit_pat(pat: &mut P, vis: &mut T) { let Pat { id, kind, span, tokens } = pat.deref_mut(); vis.visit_id(id); match kind { - PatKind::Wild | PatKind::Rest | PatKind::Never => {} + PatKind::Wild | PatKind::Rest | PatKind::Never | PatKind::Err(_) => {} PatKind::Ident(_binding_mode, ident, sub) => { vis.visit_ident(ident); visit_opt(sub, |sub| vis.visit_pat(sub)); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 3617df931e2a2..89f50d3a0a7b8 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -568,7 +568,7 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) { walk_list!(visitor, visit_expr, lower_bound); walk_list!(visitor, visit_expr, upper_bound); } - PatKind::Wild | PatKind::Rest | PatKind::Never => {} + PatKind::Wild | PatKind::Rest | PatKind::Never | PatKind::Err(_) => {} PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => { walk_list!(visitor, visit_pat, elems); } diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 1c405fac7e40a..0af141ff99a27 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -109,6 +109,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // return inner to be processed in next loop PatKind::Paren(inner) => pattern = inner, PatKind::MacCall(_) => panic!("{:?} shouldn't exist here", pattern.span), + PatKind::Err(guar) => break hir::PatKind::Err(*guar), } }; diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index f4b424259deef..c2fd4558fd76e 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1519,6 +1519,11 @@ impl<'a> State<'a> { self.pclose(); } PatKind::MacCall(m) => self.print_mac(m), + PatKind::Err(_) => { + self.popen(); + self.word("/*ERROR*/"); + self.pclose(); + } } self.ann.post(self, AnnNode::Pat(pat)) } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 6b347f7035a3b..6d5917c7b99f2 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1015,7 +1015,7 @@ impl<'hir> Pat<'hir> { use PatKind::*; match self.kind { - Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) => true, + Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => true, Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_short_(it), Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)), TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().all(|p| p.walk_short_(it)), @@ -1042,7 +1042,7 @@ impl<'hir> Pat<'hir> { use PatKind::*; match self.kind { - Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) => {} + Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => {} Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_(it), Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)), TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)), @@ -1205,6 +1205,9 @@ pub enum PatKind<'hir> { /// PatKind::Slice([Binding(a), Binding(b)], Some(Wild), [Binding(c), Binding(d)]) /// ``` Slice(&'hir [Pat<'hir>], Option<&'hir Pat<'hir>>, &'hir [Pat<'hir>]), + + /// A placeholder for a pattern that wasn't well formed in some way. + Err(ErrorGuaranteed), } /// A statement. diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index adc090258093a..116de6fb04d99 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -655,7 +655,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) { walk_list!(visitor, visit_expr, lower_bound); walk_list!(visitor, visit_expr, upper_bound); } - PatKind::Never | PatKind::Wild => (), + PatKind::Never | PatKind::Wild | PatKind::Err(_) => (), PatKind::Slice(prepatterns, ref slice_pattern, postpatterns) => { walk_list!(visitor, visit_pat, prepatterns); walk_list!(visitor, visit_pat, slice_pattern); diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 5d5a4789734a7..1c0a1a6951398 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -681,7 +681,8 @@ fn resolve_local<'tcx>( | PatKind::Never | PatKind::Path(_) | PatKind::Lit(_) - | PatKind::Range(_, _, _) => false, + | PatKind::Range(_, _, _) + | PatKind::Err(_) => false, } } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index d36e0892d19d9..e76303bc6dfa1 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1838,6 +1838,11 @@ impl<'a> State<'a> { self.commasep(Inconsistent, after, |s, p| s.print_pat(p)); self.word("]"); } + PatKind::Err(_) => { + self.popen(); + self.word("/*ERROR*/"); + self.pclose(); + } } self.ann.post(self, AnnNode::Pat(pat)) } diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index ed3dd1e39dfc9..3ecf6c5e428be 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -458,11 +458,15 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { needs_to_be_read = true; } } - PatKind::Or(_) | PatKind::Box(_) | PatKind::Ref(..) | PatKind::Wild => { + PatKind::Or(_) + | PatKind::Box(_) + | PatKind::Ref(..) + | PatKind::Wild + | PatKind::Err(_) => { // If the PatKind is Or, Box, or Ref, the decision is made later // as these patterns contains subpatterns - // If the PatKind is Wild, the decision is made based on the other patterns being - // examined + // If the PatKind is Wild or Err, the decision is made based on the other patterns + // being examined } } })? diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs index ce3a4b4c80ce7..1ce0240f7b830 100644 --- a/compiler/rustc_hir_typeck/src/mem_categorization.rs +++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs @@ -767,7 +767,8 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { | PatKind::Lit(..) | PatKind::Range(..) | PatKind::Never - | PatKind::Wild => { + | PatKind::Wild + | PatKind::Err(_) => { // always ok } } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 95813cb68a664..fe8c36dbe069d 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -177,7 +177,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { PatInfo { binding_mode: def_bm, top_info: ti, decl_origin: pat_info.decl_origin }; let ty = match pat.kind { - PatKind::Wild => expected, + PatKind::Wild | PatKind::Err(_) => expected, // FIXME(never_patterns): check the type is uninhabited. If that is not possible within // typeck, do that in a later phase. PatKind::Never => expected, @@ -325,6 +325,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { PatKind::Ref(..) => AdjustMode::Reset, // A `_` pattern works with any expected type, so there's no need to do anything. PatKind::Wild + // A malformed pattern doesn't have an expected type, so let's just accept any type. + | PatKind::Err(_) // Bindings also work with whatever the expected type is, // and moreover if we peel references off, that will give us the wrong binding type. // Also, we can have a subpattern `binding @ pat`. @@ -754,7 +756,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | PatKind::Box(..) | PatKind::Ref(..) | PatKind::Lit(..) - | PatKind::Range(..) => break 'block None, + | PatKind::Range(..) + | PatKind::Err(_) => break 'block None, }, // Don't provide suggestions in other cases diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 0f4528d1d5c2b..39decf1faabf1 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -1166,7 +1166,7 @@ impl EarlyLintPass for UnusedParens { // Do not lint on `(..)` as that will result in the other arms being useless. Paren(_) // The other cases do not contain sub-patterns. - | Wild | Never | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) => {}, + | Wild | Never | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) | Err(_) => {}, // These are list-like patterns; parens can always be removed. TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps { self.check_unused_parens_pat(cx, p, false, false, keep_space); diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index c4987634b78b3..ff7e985bdfdcc 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -345,6 +345,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } hir::PatKind::Or(pats) => PatKind::Or { pats: self.lower_patterns(pats) }, + + hir::PatKind::Err(guar) => PatKind::Error(guar), }; Box::new(Pat { span, ty, kind }) diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index ff29fc5929c76..528a52f42255e 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -303,7 +303,8 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { Ref, Lit, Range, - Slice + Slice, + Err ] ); hir_visit::walk_pat(self, p) @@ -576,7 +577,8 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { Rest, Never, Paren, - MacCall + MacCall, + Err ] ); ast_visit::walk_pat(self, p) diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 437517598ac49..b2b20c95a7e6a 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -312,7 +312,9 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol { Symbol::intern(&match p.kind { // FIXME(never_patterns): does this make sense? - PatKind::Wild | PatKind::Never | PatKind::Struct(..) => return kw::Underscore, + PatKind::Wild | PatKind::Err(_) | PatKind::Never | PatKind::Struct(..) => { + return kw::Underscore; + } PatKind::Binding(_, _, ident, _) => return ident.name, PatKind::TupleStruct(ref p, ..) | PatKind::Path(ref p) => qpath_to_string(p), PatKind::Or(pats) => { diff --git a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs index 3c43529425265..4e728d61b853a 100644 --- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs +++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs @@ -51,7 +51,8 @@ fn unary_pattern(pat: &Pat<'_>) -> bool { | PatKind::Binding(..) | PatKind::Wild | PatKind::Never - | PatKind::Or(_) => false, + | PatKind::Or(_) + | PatKind::Err(_) => false, PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)), PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => etc.as_opt_usize().is_none() && array_rec(a), PatKind::Ref(x, _) | PatKind::Box(x) => unary_pattern(x), diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs index c823d07e2bd3d..5ca161e93096d 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs @@ -11,7 +11,7 @@ use rustc_hir::{Arm, Expr, ExprKind, HirId, HirIdMap, HirIdMapEntry, HirIdSet, P use rustc_lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::Symbol; +use rustc_span::{ErrorGuaranteed, Symbol}; use super::MATCH_SAME_ARMS; @@ -167,6 +167,8 @@ enum NormalizedPat<'a> { /// contains everything afterwards. Note that either side, or both sides, may contain zero /// patterns. Slice(&'a [Self], Option<&'a [Self]>), + /// A placeholder for a pattern that wasn't well formed in some way. + Err(ErrorGuaranteed), } #[derive(Clone, Copy)] @@ -329,6 +331,7 @@ impl<'a> NormalizedPat<'a> { arena.alloc_from_iter(front.iter().map(|pat| Self::from_pat(cx, arena, pat))), wild_pat.map(|_| &*arena.alloc_from_iter(back.iter().map(|pat| Self::from_pat(cx, arena, pat)))), ), + PatKind::Err(guar) => Self::Err(guar), } } diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs index 77adcdd0e6bfb..7246214f9bf87 100644 --- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs @@ -226,7 +226,7 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec>, focus_idx: us // Therefore they are not some form of constructor `C`, // with which a pattern `C(p_0)` may be formed, // which we would want to join with other `C(p_j)`s. - Ident(.., None) | Lit(_) | Wild | Never | Path(..) | Range(..) | Rest | MacCall(_) + Ident(.., None) | Lit(_) | Wild | Err(_) | Never | Path(..) | Range(..) | Rest | MacCall(_) // Skip immutable refs, as grouping them saves few characters, // and almost always requires adding parens (increasing noisiness). // In the case of only two patterns, replacement adds net characters. diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 8d38b87e1d794..b26ebe5cee321 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -710,6 +710,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { self.slice(start, |pat| self.pat(pat)); self.slice(end, |pat| self.pat(pat)); }, + PatKind::Err(_) => kind!("Err"), } } diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 482eaed77d1d3..979b117db256a 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -1007,7 +1007,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } e.hash(&mut self.s); }, - PatKind::Never | PatKind::Wild => {}, + PatKind::Never | PatKind::Wild | PatKind::Err(_) => {}, } } diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index cdf8528f48a27..2e54690d123cc 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1733,6 +1733,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { }, } }, + PatKind::Err(_) => true, } } diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs index 0fa6edaa5d78b..7f57627943209 100644 --- a/src/tools/rustfmt/src/patterns.rs +++ b/src/tools/rustfmt/src/patterns.rs @@ -40,9 +40,11 @@ pub(crate) fn is_short_pattern(pat: &ast::Pat, pat_str: &str) -> bool { fn is_short_pattern_inner(pat: &ast::Pat) -> bool { match pat.kind { - ast::PatKind::Rest | ast::PatKind::Never | ast::PatKind::Wild | ast::PatKind::Lit(_) => { - true - } + ast::PatKind::Rest + | ast::PatKind::Never + | ast::PatKind::Wild + | ast::PatKind::Err(_) + | ast::PatKind::Lit(_) => true, ast::PatKind::Ident(_, _, ref pat) => pat.is_none(), ast::PatKind::Struct(..) | ast::PatKind::MacCall(..) @@ -274,6 +276,7 @@ impl Rewrite for Pat { PatKind::Paren(ref pat) => pat .rewrite(context, shape.offset_left(1)?.sub_width(1)?) .map(|inner_pat| format!("({})", inner_pat)), + PatKind::Err(_) => None, } } } From 33e1e6f783cb3a725f2ff0f134400031890d6f7f Mon Sep 17 00:00:00 2001 From: Lieselotte <52315535+she3py@users.noreply.github.com> Date: Wed, 17 Jan 2024 03:14:16 +0100 Subject: [PATCH 0324/1197] Add `PatKind::Err` --- clippy_lints/src/equatable_if_let.rs | 3 ++- clippy_lints/src/matches/match_same_arms.rs | 5 ++++- clippy_lints/src/unnested_or_patterns.rs | 2 +- clippy_lints/src/utils/author.rs | 1 + clippy_utils/src/hir_utils.rs | 2 +- clippy_utils/src/lib.rs | 1 + 6 files changed, 10 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/equatable_if_let.rs b/clippy_lints/src/equatable_if_let.rs index 3c43529425265..4e728d61b853a 100644 --- a/clippy_lints/src/equatable_if_let.rs +++ b/clippy_lints/src/equatable_if_let.rs @@ -51,7 +51,8 @@ fn unary_pattern(pat: &Pat<'_>) -> bool { | PatKind::Binding(..) | PatKind::Wild | PatKind::Never - | PatKind::Or(_) => false, + | PatKind::Or(_) + | PatKind::Err(_) => false, PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)), PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => etc.as_opt_usize().is_none() && array_rec(a), PatKind::Ref(x, _) | PatKind::Box(x) => unary_pattern(x), diff --git a/clippy_lints/src/matches/match_same_arms.rs b/clippy_lints/src/matches/match_same_arms.rs index c823d07e2bd3d..5ca161e93096d 100644 --- a/clippy_lints/src/matches/match_same_arms.rs +++ b/clippy_lints/src/matches/match_same_arms.rs @@ -11,7 +11,7 @@ use rustc_hir::{Arm, Expr, ExprKind, HirId, HirIdMap, HirIdMapEntry, HirIdSet, P use rustc_lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::Symbol; +use rustc_span::{ErrorGuaranteed, Symbol}; use super::MATCH_SAME_ARMS; @@ -167,6 +167,8 @@ enum NormalizedPat<'a> { /// contains everything afterwards. Note that either side, or both sides, may contain zero /// patterns. Slice(&'a [Self], Option<&'a [Self]>), + /// A placeholder for a pattern that wasn't well formed in some way. + Err(ErrorGuaranteed), } #[derive(Clone, Copy)] @@ -329,6 +331,7 @@ impl<'a> NormalizedPat<'a> { arena.alloc_from_iter(front.iter().map(|pat| Self::from_pat(cx, arena, pat))), wild_pat.map(|_| &*arena.alloc_from_iter(back.iter().map(|pat| Self::from_pat(cx, arena, pat)))), ), + PatKind::Err(guar) => Self::Err(guar), } } diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs index 77adcdd0e6bfb..7246214f9bf87 100644 --- a/clippy_lints/src/unnested_or_patterns.rs +++ b/clippy_lints/src/unnested_or_patterns.rs @@ -226,7 +226,7 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec>, focus_idx: us // Therefore they are not some form of constructor `C`, // with which a pattern `C(p_0)` may be formed, // which we would want to join with other `C(p_j)`s. - Ident(.., None) | Lit(_) | Wild | Never | Path(..) | Range(..) | Rest | MacCall(_) + Ident(.., None) | Lit(_) | Wild | Err(_) | Never | Path(..) | Range(..) | Rest | MacCall(_) // Skip immutable refs, as grouping them saves few characters, // and almost always requires adding parens (increasing noisiness). // In the case of only two patterns, replacement adds net characters. diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 8d38b87e1d794..b26ebe5cee321 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -710,6 +710,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { self.slice(start, |pat| self.pat(pat)); self.slice(end, |pat| self.pat(pat)); }, + PatKind::Err(_) => kind!("Err"), } } diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 482eaed77d1d3..979b117db256a 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -1007,7 +1007,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } e.hash(&mut self.s); }, - PatKind::Never | PatKind::Wild => {}, + PatKind::Never | PatKind::Wild | PatKind::Err(_) => {}, } } diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index cdf8528f48a27..2e54690d123cc 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1733,6 +1733,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { }, } }, + PatKind::Err(_) => true, } } From db7125f008cfd72e8951c9a863178956e2cbacc3 Mon Sep 17 00:00:00 2001 From: Robert Grosse <999674+Storyyeller@users.noreply.github.com> Date: Tue, 16 Jan 2024 20:48:22 -0800 Subject: [PATCH 0325/1197] Fix typo in comments (in_place_collect) --- library/alloc/src/vec/in_place_collect.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/vec/in_place_collect.rs b/library/alloc/src/vec/in_place_collect.rs index 0a2280545dac3..ec5f32539f2c2 100644 --- a/library/alloc/src/vec/in_place_collect.rs +++ b/library/alloc/src/vec/in_place_collect.rs @@ -9,7 +9,7 @@ //! or [`BinaryHeap`], the adapters guarantee to consume enough items per step to make room //! for the results (represented by [`InPlaceIterable`]), provide transitive access to `source` //! (via [`SourceIter`]) and thus the underlying allocation. -//! And finally there are alignment and size constriants to consider, this is currently ensured via +//! And finally there are alignment and size constraints to consider, this is currently ensured via //! const eval instead of trait bounds in the specialized [`SpecFromIter`] implementation. //! //! [`BinaryHeap`]: crate::collections::BinaryHeap From aa72e549cf779f82170203f70cc519fbbbfaa98b Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Tue, 16 Jan 2024 21:33:43 -0800 Subject: [PATCH 0326/1197] Un-hide `iter::repeat_n` --- library/core/src/iter/sources/repeat_n.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/core/src/iter/sources/repeat_n.rs b/library/core/src/iter/sources/repeat_n.rs index 0b0445850bf52..db2f8b7ac283f 100644 --- a/library/core/src/iter/sources/repeat_n.rs +++ b/library/core/src/iter/sources/repeat_n.rs @@ -59,7 +59,6 @@ use crate::num::NonZeroUsize; /// ``` #[inline] #[unstable(feature = "iter_repeat_n", issue = "104434")] -#[doc(hidden)] // waiting on ACP#120 to decide whether to expose publicly pub fn repeat_n(element: T, count: usize) -> RepeatN { let mut element = ManuallyDrop::new(element); @@ -79,7 +78,6 @@ pub fn repeat_n(element: T, count: usize) -> RepeatN { /// See its documentation for more. #[derive(Clone, Debug)] #[unstable(feature = "iter_repeat_n", issue = "104434")] -#[doc(hidden)] // waiting on ACP#120 to decide whether to expose publicly pub struct RepeatN { count: usize, // Invariant: has been dropped iff count == 0. From d48498f360373eb64de942758b7876871564964b Mon Sep 17 00:00:00 2001 From: roife Date: Wed, 17 Jan 2024 13:49:07 +0800 Subject: [PATCH 0327/1197] fix: better handling of SelfParam in inline_call --- .../ide-assists/src/handlers/inline_call.rs | 52 ++++++++++++++++--- crates/syntax/src/ast/make.rs | 3 ++ 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/crates/ide-assists/src/handlers/inline_call.rs b/crates/ide-assists/src/handlers/inline_call.rs index 7bbb92134114e..206802e93c028 100644 --- a/crates/ide-assists/src/handlers/inline_call.rs +++ b/crates/ide-assists/src/handlers/inline_call.rs @@ -15,7 +15,7 @@ use ide_db::{ }; use itertools::{izip, Itertools}; use syntax::{ - ast::{self, edit::IndentLevel, edit_in_place::Indent, HasArgList, PathExpr}, + ast::{self, edit::IndentLevel, edit_in_place::Indent, HasArgList, Pat, PathExpr}, ted, AstNode, NodeOrToken, SyntaxKind, }; @@ -278,7 +278,7 @@ fn get_fn_params( let mut params = Vec::new(); if let Some(self_param) = param_list.self_param() { - // FIXME this should depend on the receiver as well as the self_param + // Keep `ref` and `mut` and transform them into `&` and `mut` later params.push(( make::ident_pat( self_param.amp_token().is_some(), @@ -409,16 +409,56 @@ fn inline( let mut let_stmts = Vec::new(); // Inline parameter expressions or generate `let` statements depending on whether inlining works or not. - for ((pat, param_ty, _), usages, expr) in izip!(params, param_use_nodes, arguments) { + for ((pat, param_ty, param), usages, expr) in izip!(params, param_use_nodes, arguments) { // izip confuses RA due to our lack of hygiene info currently losing us type info causing incorrect errors let usages: &[ast::PathExpr] = &usages; let expr: &ast::Expr = expr; let mut insert_let_stmt = || { let ty = sema.type_of_expr(expr).filter(TypeInfo::has_adjustment).and(param_ty.clone()); - let_stmts.push( - make::let_stmt(pat.clone(), ty, Some(expr.clone())).clone_for_update().into(), - ); + + let is_self = param + .name(sema.db) + .and_then(|name| name.as_text()) + .is_some_and(|name| name == "self"); + + if is_self { + let mut this_pat = make::ident_pat(false, false, make::name("this")); + let mut expr = expr.clone(); + match pat { + Pat::IdentPat(pat) => match (pat.ref_token(), pat.mut_token()) { + // self => let this = obj + (None, None) => {} + // mut self => let mut this = obj + (None, Some(_)) => { + this_pat = make::ident_pat(false, true, make::name("this")); + } + // &self => let this = &obj + (Some(_), None) => { + expr = make::expr_ref(expr, false); + } + // let foo = &mut X; &mut self => let this = &mut obj + // let mut foo = X; &mut self => let this = &mut *obj (reborrow) + (Some(_), Some(_)) => { + let should_reborrow = sema + .type_of_expr(&expr) + .map(|ty| ty.original.is_mutable_reference()); + expr = if let Some(true) = should_reborrow { + make::expr_reborrow(expr) + } else { + make::expr_ref(expr, true) + }; + } + }, + _ => {} + }; + let_stmts + .push(make::let_stmt(this_pat.into(), ty, Some(expr)).clone_for_update().into()) + } else { + let_stmts.push( + make::let_stmt(pat.clone(), ty, Some(expr.clone())).clone_for_update().into(), + ); + } }; // check if there is a local var in the function that conflicts with parameter diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index b1dd1fe8c829a..62d64319e3858 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs @@ -595,6 +595,9 @@ pub fn expr_macro_call(f: ast::Expr, arg_list: ast::ArgList) -> ast::Expr { pub fn expr_ref(expr: ast::Expr, exclusive: bool) -> ast::Expr { expr_from_text(&if exclusive { format!("&mut {expr}") } else { format!("&{expr}") }) } +pub fn expr_reborrow(expr: ast::Expr) -> ast::Expr { + expr_from_text(&format!("&mut *{expr}")) +} pub fn expr_closure(pats: impl IntoIterator, expr: ast::Expr) -> ast::Expr { let params = pats.into_iter().join(", "); expr_from_text(&format!("|{params}| {expr}")) From 920e99aacb917ad0608b0520661baae785aa0ae6 Mon Sep 17 00:00:00 2001 From: roife Date: Wed, 17 Jan 2024 13:50:50 +0800 Subject: [PATCH 0328/1197] test: add tests for variant kinds of SelfParam in inline_call --- .../ide-assists/src/handlers/inline_call.rs | 86 +++++++++++++++++-- 1 file changed, 81 insertions(+), 5 deletions(-) diff --git a/crates/ide-assists/src/handlers/inline_call.rs b/crates/ide-assists/src/handlers/inline_call.rs index 206802e93c028..bb87b9b6c912e 100644 --- a/crates/ide-assists/src/handlers/inline_call.rs +++ b/crates/ide-assists/src/handlers/inline_call.rs @@ -759,7 +759,7 @@ impl Foo { fn main() { let x = { - let ref this = Foo(3); + let this = &Foo(3); Foo(this.0 + 2) }; } @@ -795,7 +795,7 @@ impl Foo { fn main() { let x = { - let ref this = Foo(3); + let this = &Foo(3); Foo(this.0 + 2) }; } @@ -833,7 +833,7 @@ impl Foo { fn main() { let mut foo = Foo(3); { - let ref mut this = foo; + let this = &mut foo; this.0 = 0; }; } @@ -920,7 +920,7 @@ impl Foo { } fn bar(&self) { { - let ref this = self; + let this = &self; this; this; }; @@ -1595,7 +1595,7 @@ impl Enum { fn a() -> bool { { - let ref this = Enum::A; + let this = &Enum::A; this == &Enum::A || this == &Enum::B } } @@ -1657,6 +1657,82 @@ fn main() { a as A }; } +"#, + ) + } + + #[test] + fn method_by_reborrow() { + check_assist( + inline_call, + r#" +pub struct Foo(usize); + +impl Foo { + fn add1(&mut self) { + self.0 += 1; + } +} + +pub fn main() { + let f = &mut Foo(0); + f.add1$0(); +} +"#, + r#" +pub struct Foo(usize); + +impl Foo { + fn add1(&mut self) { + self.0 += 1; + } +} + +pub fn main() { + let f = &mut Foo(0); + { + let this = &mut *f; + this.0 += 1; + }; +} +"#, + ) + } + + #[test] + fn method_by_mut() { + check_assist( + inline_call, + r#" +pub struct Foo(usize); + +impl Foo { + fn add1(mut self) { + self.0 += 1; + } +} + +pub fn main() { + let mut f = Foo(0); + f.add1$0(); +} +"#, + r#" +pub struct Foo(usize); + +impl Foo { + fn add1(mut self) { + self.0 += 1; + } +} + +pub fn main() { + let mut f = Foo(0); + { + let mut this = f; + this.0 += 1; + }; +} "#, ) } From 21723cb0513a6cba95556822138dd7cb65ea3ac8 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 17 Jan 2024 09:43:04 +0100 Subject: [PATCH 0329/1197] Run metadata on sysroot for CI metrics --- crates/rust-analyzer/src/cli/analysis_stats.rs | 1 + crates/rust-analyzer/src/cli/flags.rs | 4 ++++ xtask/src/metrics.rs | 6 +++++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index e69302dbaccf3..f601f004420e6 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -63,6 +63,7 @@ impl flags::AnalysisStats { true => None, false => Some(RustLibSource::Discover), }; + cargo_config.sysroot_query_metadata = self.query_sysroot_metadata; let no_progress = &|_| (); let mut db_load_sw = self.stop_watch(); diff --git a/crates/rust-analyzer/src/cli/flags.rs b/crates/rust-analyzer/src/cli/flags.rs index 5633c0c488aa7..cc9e2a7ce26f8 100644 --- a/crates/rust-analyzer/src/cli/flags.rs +++ b/crates/rust-analyzer/src/cli/flags.rs @@ -71,6 +71,9 @@ xflags::xflags! { optional --with-deps /// Don't load sysroot crates (`std`, `core` & friends). optional --no-sysroot + /// Run cargo metadata on the sysroot to analyze its third-pary dependencies. + /// Requires --no-sysroot to not be set. + optional --query-sysroot-metadata /// Don't run build scripts or load `OUT_DIR` values by running `cargo check` before analysis. optional --disable-build-scripts @@ -206,6 +209,7 @@ pub struct AnalysisStats { pub only: Option, pub with_deps: bool, pub no_sysroot: bool, + pub query_sysroot_metadata: bool, pub disable_build_scripts: bool, pub disable_proc_macros: bool, pub skip_lowering: bool, diff --git a/xtask/src/metrics.rs b/xtask/src/metrics.rs index 845928432c4fd..db4e1b35829a1 100644 --- a/xtask/src/metrics.rs +++ b/xtask/src/metrics.rs @@ -113,7 +113,11 @@ impl Metrics { ) -> anyhow::Result<()> { assert!(Path::new(path).exists(), "unable to find bench in {path}"); eprintln!("\nMeasuring analysis-stats/{name}"); - let output = cmd!(sh, "./target/release/rust-analyzer -q analysis-stats {path}").read()?; + let output = cmd!( + sh, + "./target/release/rust-analyzer -q analysis-stats {path} --query-sysroot-metadata" + ) + .read()?; for (metric, value, unit) in parse_metrics(&output) { self.report(&format!("analysis-stats/{name}/{metric}"), value, unit.into()); } From a87034c2977369c8e7670dbe477e3196c45e4615 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 7 Dec 2023 14:16:11 +0000 Subject: [PATCH 0330/1197] tests: add sanity-check assembly test for every target Adds a basic assembly test checking that each target can produce assembly and update the target tier policy to require this. Signed-off-by: David Wood --- .../spec/targets/asmjs_unknown_emscripten.rs | 7 - src/doc/rustc/src/target-tier-policy.md | 2 + src/tools/tidy/src/lib.rs | 1 + src/tools/tidy/src/main.rs | 1 + src/tools/tidy/src/target_policy.rs | 52 ++ tests/assembly/targets/targets-elf.rs | 633 ++++++++++++++++++ tests/assembly/targets/targets-nvptx.rs | 21 + tests/assembly/targets/targets-pe.rs | 93 +++ 8 files changed, 803 insertions(+), 7 deletions(-) delete mode 100644 compiler/rustc_target/src/spec/targets/asmjs_unknown_emscripten.rs create mode 100644 src/tools/tidy/src/target_policy.rs create mode 100644 tests/assembly/targets/targets-elf.rs create mode 100644 tests/assembly/targets/targets-nvptx.rs create mode 100644 tests/assembly/targets/targets-pe.rs diff --git a/compiler/rustc_target/src/spec/targets/asmjs_unknown_emscripten.rs b/compiler/rustc_target/src/spec/targets/asmjs_unknown_emscripten.rs deleted file mode 100644 index e4768c67af55e..0000000000000 --- a/compiler/rustc_target/src/spec/targets/asmjs_unknown_emscripten.rs +++ /dev/null @@ -1,7 +0,0 @@ -use crate::spec::{targets::wasm32_unknown_emscripten, LinkerFlavor, Target}; - -pub fn target() -> Target { - let mut target = wasm32_unknown_emscripten::target(); - target.add_post_link_args(LinkerFlavor::EmCc, &["-sWASM=0", "--memory-init-file", "0"]); - target -} diff --git a/src/doc/rustc/src/target-tier-policy.md b/src/doc/rustc/src/target-tier-policy.md index 95932db14e1f6..48b58f6f06adb 100644 --- a/src/doc/rustc/src/target-tier-policy.md +++ b/src/doc/rustc/src/target-tier-policy.md @@ -246,6 +246,8 @@ approved by the appropriate team for that shared code before acceptance. introducing unconditional uses of features that another variation of the target may not have; use conditional compilation or runtime detection, as appropriate, to let each target run code supported by that target. +- Tier 3 targets must be able to produce assembly using at least one of + rustc's supported backends from any host target. If a tier 3 target stops meeting these requirements, or the target maintainers no longer have interest or time, or the target shows no signs of activity and diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index eb0a2fda290d9..9514998703346 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -70,6 +70,7 @@ pub mod pal; pub mod rustdoc_css_themes; pub mod rustdoc_gui_tests; pub mod style; +pub mod target_policy; pub mod target_specific_tests; pub mod tests_placement; pub mod ui_tests; diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 9f92b8995b79e..a9340c40f4433 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -109,6 +109,7 @@ fn main() { // Checks that only make sense for the compiler. check!(error_codes, &root_path, &[&compiler_path, &librustdoc_path], verbose); check!(fluent_alphabetical, &compiler_path, bless); + check!(target_policy, &root_path); // Checks that only make sense for the std libs. check!(pal, &library_path); diff --git a/src/tools/tidy/src/target_policy.rs b/src/tools/tidy/src/target_policy.rs new file mode 100644 index 0000000000000..ca6590d1502a2 --- /dev/null +++ b/src/tools/tidy/src/target_policy.rs @@ -0,0 +1,52 @@ +//! Tests for target tier policy compliance. +//! +//! As of writing, only checks that sanity-check assembly test for targets doesn't miss any targets. + +use crate::walk::{filter_not_rust, walk}; +use std::{collections::HashSet, path::Path}; + +const TARGET_DEFINITIONS_PATH: &str = "compiler/rustc_target/src/spec/targets/"; +const ASSEMBLY_TEST_PATH: &str = "tests/assembly/targets/"; +const REVISION_LINE_START: &str = "// revisions: "; +const EXCEPTIONS: &[&str] = &[ + // FIXME: disabled since it fails on CI saying the csky component is missing + "csky_unknown_linux_gnuabiv2", + "csky_unknown_linux_gnuabiv2hf", +]; + +pub fn check(root_path: &Path, bad: &mut bool) { + let mut targets_to_find = HashSet::new(); + + let definitions_path = root_path.join(TARGET_DEFINITIONS_PATH); + for defn in ignore::WalkBuilder::new(&definitions_path) + .max_depth(Some(1)) + .filter_entry(|e| !filter_not_rust(e.path())) + .build() + { + let defn = defn.unwrap(); + // Skip directory itself. + if defn.path() == definitions_path { + continue; + } + + let path = defn.path(); + let target_name = path.file_stem().unwrap().to_string_lossy().into_owned(); + let _ = targets_to_find.insert(target_name); + } + + walk(&root_path.join(ASSEMBLY_TEST_PATH), |_, _| false, &mut |_, contents| { + for line in contents.lines() { + let Some(_) = line.find(REVISION_LINE_START) else { + continue; + }; + let (_, target_name) = line.split_at(REVISION_LINE_START.len()); + targets_to_find.remove(target_name); + } + }); + + for target in targets_to_find { + if !EXCEPTIONS.contains(&target.as_str()) { + tidy_error!(bad, "{ASSEMBLY_TEST_PATH}: missing assembly test for {target}") + } + } +} diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs new file mode 100644 index 0000000000000..72a35f38ecadb --- /dev/null +++ b/tests/assembly/targets/targets-elf.rs @@ -0,0 +1,633 @@ +// assembly-output: emit-asm +// ignore-tidy-linelength +// revisions: aarch64_apple_darwin +// [aarch64_apple_darwin] compile-flags: --target aarch64-apple-darwin +// [aarch64_apple_darwin] needs-llvm-components: aarch64 +// revisions: aarch64_apple_ios +// [aarch64_apple_ios] compile-flags: --target aarch64-apple-ios +// [aarch64_apple_ios] needs-llvm-components: aarch64 +// revisions: aarch64_apple_ios_macabi +// [aarch64_apple_ios_macabi] compile-flags: --target aarch64-apple-ios-macabi +// [aarch64_apple_ios_macabi] needs-llvm-components: aarch64 +// revisions: aarch64_apple_ios_sim +// [aarch64_apple_ios_sim] compile-flags: --target aarch64-apple-ios-sim +// [aarch64_apple_ios_sim] needs-llvm-components: aarch64 +// revisions: aarch64_apple_tvos +// [aarch64_apple_tvos] compile-flags: --target aarch64-apple-tvos +// [aarch64_apple_tvos] needs-llvm-components: aarch64 +// revisions: aarch64_apple_tvos_sim +// [aarch64_apple_tvos_sim] compile-flags: --target aarch64-apple-tvos-sim +// [aarch64_apple_tvos_sim] needs-llvm-components: aarch64 +// revisions: aarch64_apple_watchos +// [aarch64_apple_watchos] compile-flags: --target aarch64-apple-watchos +// [aarch64_apple_watchos] needs-llvm-components: aarch64 +// revisions: aarch64_apple_watchos_sim +// [aarch64_apple_watchos_sim] compile-flags: --target aarch64-apple-watchos-sim +// [aarch64_apple_watchos_sim] needs-llvm-components: aarch64 +// revisions: aarch64_be_unknown_linux_gnu +// [aarch64_be_unknown_linux_gnu] compile-flags: --target aarch64_be-unknown-linux-gnu +// [aarch64_be_unknown_linux_gnu] needs-llvm-components: aarch64 +// revisions: aarch64_be_unknown_linux_gnu_ilp32 +// [aarch64_be_unknown_linux_gnu_ilp32] compile-flags: --target aarch64_be-unknown-linux-gnu_ilp32 +// [aarch64_be_unknown_linux_gnu_ilp32] needs-llvm-components: aarch64 +// revisions: aarch64_be_unknown_netbsd +// [aarch64_be_unknown_netbsd] compile-flags: --target aarch64_be-unknown-netbsd +// [aarch64_be_unknown_netbsd] needs-llvm-components: aarch64 +// revisions: aarch64_fuchsia +// [aarch64_fuchsia] compile-flags: --target aarch64-fuchsia +// [aarch64_fuchsia] needs-llvm-components: aarch64 +// revisions: aarch64_kmc_solid_asp3 +// [aarch64_kmc_solid_asp3] compile-flags: --target aarch64-kmc-solid_asp3 +// [aarch64_kmc_solid_asp3] needs-llvm-components: aarch64 +// revisions: aarch64_linux_android +// [aarch64_linux_android] compile-flags: --target aarch64-linux-android +// [aarch64_linux_android] needs-llvm-components: aarch64 +// revisions: aarch64_nintendo_switch_freestanding +// [aarch64_nintendo_switch_freestanding] compile-flags: --target aarch64-nintendo-switch-freestanding +// [aarch64_nintendo_switch_freestanding] needs-llvm-components: aarch64 +// revisions: aarch64_unknown_freebsd +// [aarch64_unknown_freebsd] compile-flags: --target aarch64-unknown-freebsd +// [aarch64_unknown_freebsd] needs-llvm-components: aarch64 +// revisions: aarch64_unknown_fuchsia +// [aarch64_unknown_fuchsia] compile-flags: --target aarch64-unknown-fuchsia +// [aarch64_unknown_fuchsia] needs-llvm-components: aarch64 +// revisions: aarch64_unknown_hermit +// [aarch64_unknown_hermit] compile-flags: --target aarch64-unknown-hermit +// [aarch64_unknown_hermit] needs-llvm-components: aarch64 +// revisions: aarch64_unknown_illumos +// [aarch64_unknown_illumos] compile-flags: --target aarch64-unknown-illumos +// [aarch64_unknown_illumos] needs-llvm-components: aarch64 +// revisions: aarch64_unknown_linux_gnu +// [aarch64_unknown_linux_gnu] compile-flags: --target aarch64-unknown-linux-gnu +// [aarch64_unknown_linux_gnu] needs-llvm-components: aarch64 +// revisions: aarch64_unknown_linux_gnu_ilp32 +// [aarch64_unknown_linux_gnu_ilp32] compile-flags: --target aarch64-unknown-linux-gnu_ilp32 +// [aarch64_unknown_linux_gnu_ilp32] needs-llvm-components: aarch64 +// revisions: aarch64_unknown_linux_musl +// [aarch64_unknown_linux_musl] compile-flags: --target aarch64-unknown-linux-musl +// [aarch64_unknown_linux_musl] needs-llvm-components: aarch64 +// revisions: aarch64_unknown_linux_ohos +// [aarch64_unknown_linux_ohos] compile-flags: --target aarch64-unknown-linux-ohos +// [aarch64_unknown_linux_ohos] needs-llvm-components: aarch64 +// revisions: aarch64_unknown_netbsd +// [aarch64_unknown_netbsd] compile-flags: --target aarch64-unknown-netbsd +// [aarch64_unknown_netbsd] needs-llvm-components: aarch64 +// revisions: aarch64_unknown_none +// [aarch64_unknown_none] compile-flags: --target aarch64-unknown-none +// [aarch64_unknown_none] needs-llvm-components: aarch64 +// revisions: aarch64_unknown_none_softfloat +// [aarch64_unknown_none_softfloat] compile-flags: --target aarch64-unknown-none-softfloat +// [aarch64_unknown_none_softfloat] needs-llvm-components: aarch64 +// revisions: aarch64_unknown_nto_qnx_710 +// [aarch64_unknown_nto_qnx_710] compile-flags: --target aarch64-unknown-nto-qnx710 +// [aarch64_unknown_nto_qnx_710] needs-llvm-components: aarch64 +// revisions: aarch64_unknown_openbsd +// [aarch64_unknown_openbsd] compile-flags: --target aarch64-unknown-openbsd +// [aarch64_unknown_openbsd] needs-llvm-components: aarch64 +// revisions: aarch64_unknown_redox +// [aarch64_unknown_redox] compile-flags: --target aarch64-unknown-redox +// [aarch64_unknown_redox] needs-llvm-components: aarch64 +// revisions: aarch64_unknown_teeos +// [aarch64_unknown_teeos] compile-flags: --target aarch64-unknown-teeos +// [aarch64_unknown_teeos] needs-llvm-components: aarch64 +// revisions: aarch64_wrs_vxworks +// [aarch64_wrs_vxworks] compile-flags: --target aarch64-wrs-vxworks +// [aarch64_wrs_vxworks] needs-llvm-components: aarch64 +// revisions: arm64_32_apple_watchos +// [arm64_32_apple_watchos] compile-flags: --target arm64_32-apple-watchos +// [arm64_32_apple_watchos] needs-llvm-components: aarch64 +// revisions: arm64e_apple_darwin +// [arm64e_apple_darwin] compile-flags: --target arm64e-apple-darwin +// [arm64e_apple_darwin] needs-llvm-components: aarch64 +// revisions: arm64e_apple_ios +// [arm64e_apple_ios] compile-flags: --target arm64e-apple-ios +// [arm64e_apple_ios] needs-llvm-components: aarch64 +// revisions: arm_linux_androideabi +// [arm_linux_androideabi] compile-flags: --target arm-linux-androideabi +// [arm_linux_androideabi] needs-llvm-components: arm +// revisions: arm_unknown_linux_gnueabi +// [arm_unknown_linux_gnueabi] compile-flags: --target arm-unknown-linux-gnueabi +// [arm_unknown_linux_gnueabi] needs-llvm-components: arm +// revisions: arm_unknown_linux_gnueabihf +// [arm_unknown_linux_gnueabihf] compile-flags: --target arm-unknown-linux-gnueabihf +// [arm_unknown_linux_gnueabihf] needs-llvm-components: arm +// revisions: arm_unknown_linux_musleabi +// [arm_unknown_linux_musleabi] compile-flags: --target arm-unknown-linux-musleabi +// [arm_unknown_linux_musleabi] needs-llvm-components: arm +// revisions: arm_unknown_linux_musleabihf +// [arm_unknown_linux_musleabihf] compile-flags: --target arm-unknown-linux-musleabihf +// [arm_unknown_linux_musleabihf] needs-llvm-components: arm +// revisions: armeb_unknown_linux_gnueabi +// [armeb_unknown_linux_gnueabi] compile-flags: --target armeb-unknown-linux-gnueabi +// [armeb_unknown_linux_gnueabi] needs-llvm-components: arm +// revisions: armebv7r_none_eabi +// [armebv7r_none_eabi] compile-flags: --target armebv7r-none-eabi +// [armebv7r_none_eabi] needs-llvm-components: arm +// revisions: armebv7r_none_eabihf +// [armebv7r_none_eabihf] compile-flags: --target armebv7r-none-eabihf +// [armebv7r_none_eabihf] needs-llvm-components: arm +// revisions: armv4t_none_eabi +// [armv4t_none_eabi] compile-flags: --target armv4t-none-eabi +// [armv4t_none_eabi] needs-llvm-components: arm +// revisions: armv4t_unknown_linux_gnueabi +// [armv4t_unknown_linux_gnueabi] compile-flags: --target armv4t-unknown-linux-gnueabi +// [armv4t_unknown_linux_gnueabi] needs-llvm-components: arm +// revisions: armv5te_none_eabi +// [armv5te_none_eabi] compile-flags: --target armv5te-none-eabi +// [armv5te_none_eabi] needs-llvm-components: arm +// revisions: armv5te_unknown_linux_gnueabi +// [armv5te_unknown_linux_gnueabi] compile-flags: --target armv5te-unknown-linux-gnueabi +// [armv5te_unknown_linux_gnueabi] needs-llvm-components: arm +// revisions: armv5te_unknown_linux_musleabi +// [armv5te_unknown_linux_musleabi] compile-flags: --target armv5te-unknown-linux-musleabi +// [armv5te_unknown_linux_musleabi] needs-llvm-components: arm +// revisions: armv5te_unknown_linux_uclibceabi +// [armv5te_unknown_linux_uclibceabi] compile-flags: --target armv5te-unknown-linux-uclibceabi +// [armv5te_unknown_linux_uclibceabi] needs-llvm-components: arm +// revisions: armv6_unknown_freebsd +// [armv6_unknown_freebsd] compile-flags: --target armv6-unknown-freebsd +// [armv6_unknown_freebsd] needs-llvm-components: arm +// revisions: armv6_unknown_netbsd_eabihf +// [armv6_unknown_netbsd_eabihf] compile-flags: --target armv6-unknown-netbsd-eabihf +// [armv6_unknown_netbsd_eabihf] needs-llvm-components: arm +// revisions: armv6k_nintendo_3ds +// [armv6k_nintendo_3ds] compile-flags: --target armv6k-nintendo-3ds +// [armv6k_nintendo_3ds] needs-llvm-components: arm +// revisions: armv7_linux_androideabi +// [armv7_linux_androideabi] compile-flags: --target armv7-linux-androideabi +// [armv7_linux_androideabi] needs-llvm-components: arm +// revisions: armv7_sony_vita_newlibeabihf +// [armv7_sony_vita_newlibeabihf] compile-flags: --target armv7-sony-vita-newlibeabihf +// [armv7_sony_vita_newlibeabihf] needs-llvm-components: arm +// revisions: armv7_unknown_freebsd +// [armv7_unknown_freebsd] compile-flags: --target armv7-unknown-freebsd +// [armv7_unknown_freebsd] needs-llvm-components: arm +// revisions: armv7_unknown_linux_gnueabi +// [armv7_unknown_linux_gnueabi] compile-flags: --target armv7-unknown-linux-gnueabi +// [armv7_unknown_linux_gnueabi] needs-llvm-components: arm +// revisions: armv7_unknown_linux_gnueabihf +// [armv7_unknown_linux_gnueabihf] compile-flags: --target armv7-unknown-linux-gnueabihf +// [armv7_unknown_linux_gnueabihf] needs-llvm-components: arm +// revisions: armv7_unknown_linux_musleabi +// [armv7_unknown_linux_musleabi] compile-flags: --target armv7-unknown-linux-musleabi +// [armv7_unknown_linux_musleabi] needs-llvm-components: arm +// revisions: armv7_unknown_linux_musleabihf +// [armv7_unknown_linux_musleabihf] compile-flags: --target armv7-unknown-linux-musleabihf +// [armv7_unknown_linux_musleabihf] needs-llvm-components: arm +// revisions: armv7_unknown_linux_ohos +// [armv7_unknown_linux_ohos] compile-flags: --target armv7-unknown-linux-ohos +// [armv7_unknown_linux_ohos] needs-llvm-components: arm +// revisions: armv7_unknown_linux_uclibceabi +// [armv7_unknown_linux_uclibceabi] compile-flags: --target armv7-unknown-linux-uclibceabi +// [armv7_unknown_linux_uclibceabi] needs-llvm-components: arm +// revisions: armv7_unknown_linux_uclibceabihf +// [armv7_unknown_linux_uclibceabihf] compile-flags: --target armv7-unknown-linux-uclibceabihf +// [armv7_unknown_linux_uclibceabihf] needs-llvm-components: arm +// revisions: armv7_unknown_netbsd_eabihf +// [armv7_unknown_netbsd_eabihf] compile-flags: --target armv7-unknown-netbsd-eabihf +// [armv7_unknown_netbsd_eabihf] needs-llvm-components: arm +// revisions: armv7_wrs_vxworks_eabihf +// [armv7_wrs_vxworks_eabihf] compile-flags: --target armv7-wrs-vxworks-eabihf +// [armv7_wrs_vxworks_eabihf] needs-llvm-components: arm +// revisions: armv7a_kmc_solid_asp3_eabi +// [armv7a_kmc_solid_asp3_eabi] compile-flags: --target armv7a-kmc-solid_asp3-eabi +// [armv7a_kmc_solid_asp3_eabi] needs-llvm-components: arm +// revisions: armv7a_kmc_solid_asp3_eabihf +// [armv7a_kmc_solid_asp3_eabihf] compile-flags: --target armv7a-kmc-solid_asp3-eabihf +// [armv7a_kmc_solid_asp3_eabihf] needs-llvm-components: arm +// revisions: armv7a_none_eabi +// [armv7a_none_eabi] compile-flags: --target armv7a-none-eabi +// [armv7a_none_eabi] needs-llvm-components: arm +// revisions: armv7a_none_eabihf +// [armv7a_none_eabihf] compile-flags: --target armv7a-none-eabihf +// [armv7a_none_eabihf] needs-llvm-components: arm +// revisions: armv7k_apple_watchos +// [armv7k_apple_watchos] compile-flags: --target armv7k-apple-watchos +// [armv7k_apple_watchos] needs-llvm-components: arm +// revisions: armv7r_none_eabi +// [armv7r_none_eabi] compile-flags: --target armv7r-none-eabi +// [armv7r_none_eabi] needs-llvm-components: arm +// revisions: armv7r_none_eabihf +// [armv7r_none_eabihf] compile-flags: --target armv7r-none-eabihf +// [armv7r_none_eabihf] needs-llvm-components: arm +// revisions: armv7s_apple_ios +// [armv7s_apple_ios] compile-flags: --target armv7s-apple-ios +// [armv7s_apple_ios] needs-llvm-components: arm +// FIXME: disabled since it fails on CI saying the csky component is missing +/* + revisions: csky_unknown_linux_gnuabiv2 + [csky_unknown_linux_gnuabiv2] compile-flags: --target csky-unknown-linux-gnuabiv2 + [csky_unknown_linux_gnuabiv2] needs-llvm-components: csky + revisions: csky_unknown_linux_gnuabiv2hf + [csky_unknown_linux_gnuabiv2hf] compile-flags: --target csky-unknown-linux-gnuabiv2hf + [csky_unknown_linux_gnuabiv2hf] needs-llvm-components: csky +*/ +// revisions: hexagon_unknown_linux_musl +// [hexagon_unknown_linux_musl] compile-flags: --target hexagon-unknown-linux-musl +// [hexagon_unknown_linux_musl] needs-llvm-components: hexagon +// revisions: hexagon_unknown_none_elf +// [hexagon_unknown_none_elf] compile-flags: --target hexagon-unknown-none-elf +// [hexagon_unknown_none_elf] needs-llvm-components: hexagon +// revisions: i386_apple_ios +// [i386_apple_ios] compile-flags: --target i386-apple-ios +// [i386_apple_ios] needs-llvm-components: x86 +// revisions: i586_pc_nto_qnx700 +// [i586_pc_nto_qnx700] compile-flags: --target i586-pc-nto-qnx700 +// [i586_pc_nto_qnx700] needs-llvm-components: x86 +// revisions: i586_unknown_linux_gnu +// [i586_unknown_linux_gnu] compile-flags: --target i586-unknown-linux-gnu +// [i586_unknown_linux_gnu] needs-llvm-components: x86 +// revisions: i586_unknown_linux_musl +// [i586_unknown_linux_musl] compile-flags: --target i586-unknown-linux-musl +// [i586_unknown_linux_musl] needs-llvm-components: x86 +// revisions: i586_unknown_netbsd +// [i586_unknown_netbsd] compile-flags: --target i586-unknown-netbsd +// [i586_unknown_netbsd] needs-llvm-components: x86 +// revisions: i686_apple_darwin +// [i686_apple_darwin] compile-flags: --target i686-apple-darwin +// [i686_apple_darwin] needs-llvm-components: x86 +// revisions: i686_linux_android +// [i686_linux_android] compile-flags: --target i686-linux-android +// [i686_linux_android] needs-llvm-components: x86 +// revisions: i686_unknown_freebsd +// [i686_unknown_freebsd] compile-flags: --target i686-unknown-freebsd +// [i686_unknown_freebsd] needs-llvm-components: x86 +// revisions: i686_unknown_haiku +// [i686_unknown_haiku] compile-flags: --target i686-unknown-haiku +// [i686_unknown_haiku] needs-llvm-components: x86 +// revisions: i686_unknown_hurd_gnu +// [i686_unknown_hurd_gnu] compile-flags: --target i686-unknown-hurd-gnu +// [i686_unknown_hurd_gnu] needs-llvm-components: x86 +// revisions: i686_unknown_linux_gnu +// [i686_unknown_linux_gnu] compile-flags: --target i686-unknown-linux-gnu +// [i686_unknown_linux_gnu] needs-llvm-components: x86 +// revisions: i686_unknown_linux_musl +// [i686_unknown_linux_musl] compile-flags: --target i686-unknown-linux-musl +// [i686_unknown_linux_musl] needs-llvm-components: x86 +// revisions: i686_unknown_netbsd +// [i686_unknown_netbsd] compile-flags: --target i686-unknown-netbsd +// [i686_unknown_netbsd] needs-llvm-components: x86 +// revisions: i686_unknown_openbsd +// [i686_unknown_openbsd] compile-flags: --target i686-unknown-openbsd +// [i686_unknown_openbsd] needs-llvm-components: x86 +// revisions: i686_wrs_vxworks +// [i686_wrs_vxworks] compile-flags: --target i686-wrs-vxworks +// [i686_wrs_vxworks] needs-llvm-components: x86 +// revisions: loongarch64_unknown_linux_gnu +// [loongarch64_unknown_linux_gnu] compile-flags: --target loongarch64-unknown-linux-gnu +// [loongarch64_unknown_linux_gnu] needs-llvm-components: loongarch +// revisions: loongarch64_unknown_none +// [loongarch64_unknown_none] compile-flags: --target loongarch64-unknown-none +// [loongarch64_unknown_none] needs-llvm-components: loongarch +// revisions: loongarch64_unknown_none_softfloat +// [loongarch64_unknown_none_softfloat] compile-flags: --target loongarch64-unknown-none-softfloat +// [loongarch64_unknown_none_softfloat] needs-llvm-components: loongarch +// revisions: m68k_unknown_linux_gnu +// [m68k_unknown_linux_gnu] compile-flags: --target m68k-unknown-linux-gnu +// [m68k_unknown_linux_gnu] needs-llvm-components: m68k +// revisions: mips64_openwrt_linux_musl +// [mips64_openwrt_linux_musl] compile-flags: --target mips64-openwrt-linux-musl +// [mips64_openwrt_linux_musl] needs-llvm-components: mips +// revisions: mips64_unknown_linux_gnuabi64 +// [mips64_unknown_linux_gnuabi64] compile-flags: --target mips64-unknown-linux-gnuabi64 +// [mips64_unknown_linux_gnuabi64] needs-llvm-components: mips +// revisions: mips64_unknown_linux_muslabi64 +// [mips64_unknown_linux_muslabi64] compile-flags: --target mips64-unknown-linux-muslabi64 +// [mips64_unknown_linux_muslabi64] needs-llvm-components: mips +// revisions: mips64el_unknown_linux_gnuabi64 +// [mips64el_unknown_linux_gnuabi64] compile-flags: --target mips64el-unknown-linux-gnuabi64 +// [mips64el_unknown_linux_gnuabi64] needs-llvm-components: mips +// revisions: mips64el_unknown_linux_muslabi64 +// [mips64el_unknown_linux_muslabi64] compile-flags: --target mips64el-unknown-linux-muslabi64 +// [mips64el_unknown_linux_muslabi64] needs-llvm-components: mips +// revisions: mips_unknown_linux_gnu +// [mips_unknown_linux_gnu] compile-flags: --target mips-unknown-linux-gnu +// [mips_unknown_linux_gnu] needs-llvm-components: mips +// revisions: mips_unknown_linux_musl +// [mips_unknown_linux_musl] compile-flags: --target mips-unknown-linux-musl +// [mips_unknown_linux_musl] needs-llvm-components: mips +// revisions: mips_unknown_linux_uclibc +// [mips_unknown_linux_uclibc] compile-flags: --target mips-unknown-linux-uclibc +// [mips_unknown_linux_uclibc] needs-llvm-components: mips +// revisions: mipsel_sony_psp +// [mipsel_sony_psp] compile-flags: --target mipsel-sony-psp +// [mipsel_sony_psp] needs-llvm-components: mips +// revisions: mipsel_sony_psx +// [mipsel_sony_psx] compile-flags: --target mipsel-sony-psx +// [mipsel_sony_psx] needs-llvm-components: mips +// revisions: mipsel_unknown_linux_gnu +// [mipsel_unknown_linux_gnu] compile-flags: --target mipsel-unknown-linux-gnu +// [mipsel_unknown_linux_gnu] needs-llvm-components: mips +// revisions: mipsel_unknown_linux_musl +// [mipsel_unknown_linux_musl] compile-flags: --target mipsel-unknown-linux-musl +// [mipsel_unknown_linux_musl] needs-llvm-components: mips +// revisions: mipsel_unknown_linux_uclibc +// [mipsel_unknown_linux_uclibc] compile-flags: --target mipsel-unknown-linux-uclibc +// [mipsel_unknown_linux_uclibc] needs-llvm-components: mips +// revisions: mipsel_unknown_netbsd +// [mipsel_unknown_netbsd] compile-flags: --target mipsel-unknown-netbsd +// [mipsel_unknown_netbsd] needs-llvm-components: mips +// revisions: mipsel_unknown_none +// [mipsel_unknown_none] compile-flags: --target mipsel-unknown-none +// [mipsel_unknown_none] needs-llvm-components: mips +// revisions: mipsisa32r6_unknown_linux_gnu +// [mipsisa32r6_unknown_linux_gnu] compile-flags: --target mipsisa32r6-unknown-linux-gnu +// [mipsisa32r6_unknown_linux_gnu] needs-llvm-components: mips +// revisions: mipsisa32r6el_unknown_linux_gnu +// [mipsisa32r6el_unknown_linux_gnu] compile-flags: --target mipsisa32r6el-unknown-linux-gnu +// [mipsisa32r6el_unknown_linux_gnu] needs-llvm-components: mips +// revisions: mipsisa64r6_unknown_linux_gnuabi64 +// [mipsisa64r6_unknown_linux_gnuabi64] compile-flags: --target mipsisa64r6-unknown-linux-gnuabi64 +// [mipsisa64r6_unknown_linux_gnuabi64] needs-llvm-components: mips +// revisions: mipsisa64r6el_unknown_linux_gnuabi64 +// [mipsisa64r6el_unknown_linux_gnuabi64] compile-flags: --target mipsisa64r6el-unknown-linux-gnuabi64 +// [mipsisa64r6el_unknown_linux_gnuabi64] needs-llvm-components: mips +// revisions: msp430_none_elf +// [msp430_none_elf] compile-flags: --target msp430-none-elf +// [msp430_none_elf] needs-llvm-components: msp430 +// revisions: powerpc64_unknown_freebsd +// [powerpc64_unknown_freebsd] compile-flags: --target powerpc64-unknown-freebsd +// [powerpc64_unknown_freebsd] needs-llvm-components: powerpc +// revisions: powerpc64_unknown_linux_gnu +// [powerpc64_unknown_linux_gnu] compile-flags: --target powerpc64-unknown-linux-gnu +// [powerpc64_unknown_linux_gnu] needs-llvm-components: powerpc +// revisions: powerpc64_unknown_linux_musl +// [powerpc64_unknown_linux_musl] compile-flags: --target powerpc64-unknown-linux-musl +// [powerpc64_unknown_linux_musl] needs-llvm-components: powerpc +// revisions: powerpc64_unknown_openbsd +// [powerpc64_unknown_openbsd] compile-flags: --target powerpc64-unknown-openbsd +// [powerpc64_unknown_openbsd] needs-llvm-components: powerpc +// revisions: powerpc64_wrs_vxworks +// [powerpc64_wrs_vxworks] compile-flags: --target powerpc64-wrs-vxworks +// [powerpc64_wrs_vxworks] needs-llvm-components: powerpc +// revisions: powerpc64le_unknown_freebsd +// [powerpc64le_unknown_freebsd] compile-flags: --target powerpc64le-unknown-freebsd +// [powerpc64le_unknown_freebsd] needs-llvm-components: powerpc +// revisions: powerpc64le_unknown_linux_gnu +// [powerpc64le_unknown_linux_gnu] compile-flags: --target powerpc64le-unknown-linux-gnu +// [powerpc64le_unknown_linux_gnu] needs-llvm-components: powerpc +// revisions: powerpc64le_unknown_linux_musl +// [powerpc64le_unknown_linux_musl] compile-flags: --target powerpc64le-unknown-linux-musl +// [powerpc64le_unknown_linux_musl] needs-llvm-components: powerpc +// revisions: powerpc_unknown_freebsd +// [powerpc_unknown_freebsd] compile-flags: --target powerpc-unknown-freebsd +// [powerpc_unknown_freebsd] needs-llvm-components: powerpc +// revisions: powerpc_unknown_linux_gnu +// [powerpc_unknown_linux_gnu] compile-flags: --target powerpc-unknown-linux-gnu +// [powerpc_unknown_linux_gnu] needs-llvm-components: powerpc +// revisions: powerpc_unknown_linux_gnuspe +// [powerpc_unknown_linux_gnuspe] compile-flags: --target powerpc-unknown-linux-gnuspe +// [powerpc_unknown_linux_gnuspe] needs-llvm-components: powerpc +// revisions: powerpc_unknown_linux_musl +// [powerpc_unknown_linux_musl] compile-flags: --target powerpc-unknown-linux-musl +// [powerpc_unknown_linux_musl] needs-llvm-components: powerpc +// revisions: powerpc_unknown_netbsd +// [powerpc_unknown_netbsd] compile-flags: --target powerpc-unknown-netbsd +// [powerpc_unknown_netbsd] needs-llvm-components: powerpc +// revisions: powerpc_unknown_openbsd +// [powerpc_unknown_openbsd] compile-flags: --target powerpc-unknown-openbsd +// [powerpc_unknown_openbsd] needs-llvm-components: powerpc +// revisions: powerpc_wrs_vxworks +// [powerpc_wrs_vxworks] compile-flags: --target powerpc-wrs-vxworks +// [powerpc_wrs_vxworks] needs-llvm-components: powerpc +// revisions: powerpc_wrs_vxworks_spe +// [powerpc_wrs_vxworks_spe] compile-flags: --target powerpc-wrs-vxworks-spe +// [powerpc_wrs_vxworks_spe] needs-llvm-components: powerpc +// revisions: riscv32gc_unknown_linux_gnu +// [riscv32gc_unknown_linux_gnu] compile-flags: --target riscv32gc-unknown-linux-gnu +// [riscv32gc_unknown_linux_gnu] needs-llvm-components: riscv +// revisions: riscv32gc_unknown_linux_musl +// [riscv32gc_unknown_linux_musl] compile-flags: --target riscv32gc-unknown-linux-musl +// [riscv32gc_unknown_linux_musl] needs-llvm-components: riscv +// revisions: riscv32i_unknown_none_elf +// [riscv32i_unknown_none_elf] compile-flags: --target riscv32i-unknown-none-elf +// [riscv32i_unknown_none_elf] needs-llvm-components: riscv +// revisions: riscv32im_unknown_none_elf +// [riscv32im_unknown_none_elf] compile-flags: --target riscv32im-unknown-none-elf +// [riscv32im_unknown_none_elf] needs-llvm-components: riscv +// revisions: riscv32imac_esp_espidf +// [riscv32imac_esp_espidf] compile-flags: --target riscv32imac-esp-espidf +// [riscv32imac_esp_espidf] needs-llvm-components: riscv +// revisions: riscv32imac_unknown_none_elf +// [riscv32imac_unknown_none_elf] compile-flags: --target riscv32imac-unknown-none-elf +// [riscv32imac_unknown_none_elf] needs-llvm-components: riscv +// revisions: riscv32imac_unknown_xous_elf +// [riscv32imac_unknown_xous_elf] compile-flags: --target riscv32imac-unknown-xous-elf +// [riscv32imac_unknown_xous_elf] needs-llvm-components: riscv +// revisions: riscv32imafc_unknown_none_elf +// [riscv32imafc_unknown_none_elf] compile-flags: --target riscv32imafc-unknown-none-elf +// [riscv32imafc_unknown_none_elf] needs-llvm-components: riscv +// revisions: riscv32imafc_esp_espidf +// [riscv32imafc_esp_espidf] compile-flags: --target riscv32imafc-esp-espidf +// [riscv32imafc_esp_espidf] needs-llvm-components: riscv +// revisions: riscv32imc_esp_espidf +// [riscv32imc_esp_espidf] compile-flags: --target riscv32imc-esp-espidf +// [riscv32imc_esp_espidf] needs-llvm-components: riscv +// revisions: riscv32imc_unknown_none_elf +// [riscv32imc_unknown_none_elf] compile-flags: --target riscv32imc-unknown-none-elf +// [riscv32imc_unknown_none_elf] needs-llvm-components: riscv +// revisions: riscv64_linux_android +// [riscv64_linux_android] compile-flags: --target riscv64-linux-android +// [riscv64_linux_android] needs-llvm-components: riscv +// revisions: riscv64gc_unknown_freebsd +// [riscv64gc_unknown_freebsd] compile-flags: --target riscv64gc-unknown-freebsd +// [riscv64gc_unknown_freebsd] needs-llvm-components: riscv +// revisions: riscv64gc_unknown_fuchsia +// [riscv64gc_unknown_fuchsia] compile-flags: --target riscv64gc-unknown-fuchsia +// [riscv64gc_unknown_fuchsia] needs-llvm-components: riscv +// revisions: riscv64gc_unknown_hermit +// [riscv64gc_unknown_hermit] compile-flags: --target riscv64gc-unknown-hermit +// [riscv64gc_unknown_hermit] needs-llvm-components: riscv +// revisions: riscv64gc_unknown_linux_gnu +// [riscv64gc_unknown_linux_gnu] compile-flags: --target riscv64gc-unknown-linux-gnu +// [riscv64gc_unknown_linux_gnu] needs-llvm-components: riscv +// revisions: riscv64gc_unknown_linux_musl +// [riscv64gc_unknown_linux_musl] compile-flags: --target riscv64gc-unknown-linux-musl +// [riscv64gc_unknown_linux_musl] needs-llvm-components: riscv +// revisions: riscv64gc_unknown_netbsd +// [riscv64gc_unknown_netbsd] compile-flags: --target riscv64gc-unknown-netbsd +// [riscv64gc_unknown_netbsd] needs-llvm-components: riscv +// revisions: riscv64gc_unknown_none_elf +// [riscv64gc_unknown_none_elf] compile-flags: --target riscv64gc-unknown-none-elf +// [riscv64gc_unknown_none_elf] needs-llvm-components: riscv +// revisions: riscv64gc_unknown_openbsd +// [riscv64gc_unknown_openbsd] compile-flags: --target riscv64gc-unknown-openbsd +// [riscv64gc_unknown_openbsd] needs-llvm-components: riscv +// revisions: riscv64imac_unknown_none_elf +// [riscv64imac_unknown_none_elf] compile-flags: --target riscv64imac-unknown-none-elf +// [riscv64imac_unknown_none_elf] needs-llvm-components: riscv +// revisions: s390x_unknown_linux_gnu +// [s390x_unknown_linux_gnu] compile-flags: --target s390x-unknown-linux-gnu +// [s390x_unknown_linux_gnu] needs-llvm-components: systemz +// revisions: s390x_unknown_linux_musl +// [s390x_unknown_linux_musl] compile-flags: --target s390x-unknown-linux-musl +// [s390x_unknown_linux_musl] needs-llvm-components: systemz +// revisions: sparc64_unknown_linux_gnu +// [sparc64_unknown_linux_gnu] compile-flags: --target sparc64-unknown-linux-gnu +// [sparc64_unknown_linux_gnu] needs-llvm-components: sparc +// revisions: sparc64_unknown_netbsd +// [sparc64_unknown_netbsd] compile-flags: --target sparc64-unknown-netbsd +// [sparc64_unknown_netbsd] needs-llvm-components: sparc +// revisions: sparc64_unknown_openbsd +// [sparc64_unknown_openbsd] compile-flags: --target sparc64-unknown-openbsd +// [sparc64_unknown_openbsd] needs-llvm-components: sparc +// revisions: sparc_unknown_linux_gnu +// [sparc_unknown_linux_gnu] compile-flags: --target sparc-unknown-linux-gnu +// [sparc_unknown_linux_gnu] needs-llvm-components: sparc +// revisions: sparc_unknown_none_elf +// [sparc_unknown_none_elf] compile-flags: --target sparc-unknown-none-elf +// [sparc_unknown_none_elf] needs-llvm-components: sparc +// revisions: sparcv9_sun_solaris +// [sparcv9_sun_solaris] compile-flags: --target sparcv9-sun-solaris +// [sparcv9_sun_solaris] needs-llvm-components: sparc +// revisions: thumbv4t_none_eabi +// [thumbv4t_none_eabi] compile-flags: --target thumbv4t-none-eabi +// [thumbv4t_none_eabi] needs-llvm-components: arm +// revisions: thumbv5te_none_eabi +// [thumbv5te_none_eabi] compile-flags: --target thumbv5te-none-eabi +// [thumbv5te_none_eabi] needs-llvm-components: arm +// revisions: thumbv6m_none_eabi +// [thumbv6m_none_eabi] compile-flags: --target thumbv6m-none-eabi +// [thumbv6m_none_eabi] needs-llvm-components: arm +// revisions: thumbv7em_none_eabi +// [thumbv7em_none_eabi] compile-flags: --target thumbv7em-none-eabi +// [thumbv7em_none_eabi] needs-llvm-components: arm +// revisions: thumbv7em_none_eabihf +// [thumbv7em_none_eabihf] compile-flags: --target thumbv7em-none-eabihf +// [thumbv7em_none_eabihf] needs-llvm-components: arm +// revisions: thumbv7m_none_eabi +// [thumbv7m_none_eabi] compile-flags: --target thumbv7m-none-eabi +// [thumbv7m_none_eabi] needs-llvm-components: arm +// revisions: thumbv7neon_linux_androideabi +// [thumbv7neon_linux_androideabi] compile-flags: --target thumbv7neon-linux-androideabi +// [thumbv7neon_linux_androideabi] needs-llvm-components: arm +// revisions: thumbv7neon_unknown_linux_gnueabihf +// [thumbv7neon_unknown_linux_gnueabihf] compile-flags: --target thumbv7neon-unknown-linux-gnueabihf +// [thumbv7neon_unknown_linux_gnueabihf] needs-llvm-components: arm +// revisions: thumbv7neon_unknown_linux_musleabihf +// [thumbv7neon_unknown_linux_musleabihf] compile-flags: --target thumbv7neon-unknown-linux-musleabihf +// [thumbv7neon_unknown_linux_musleabihf] needs-llvm-components: arm +// revisions: thumbv8m_base_none_eabi +// [thumbv8m_base_none_eabi] compile-flags: --target thumbv8m.base-none-eabi +// [thumbv8m_base_none_eabi] needs-llvm-components: arm +// revisions: thumbv8m_main_none_eabi +// [thumbv8m_main_none_eabi] compile-flags: --target thumbv8m.main-none-eabi +// [thumbv8m_main_none_eabi] needs-llvm-components: arm +// revisions: thumbv8m_main_none_eabihf +// [thumbv8m_main_none_eabihf] compile-flags: --target thumbv8m.main-none-eabihf +// [thumbv8m_main_none_eabihf] needs-llvm-components: arm +// revisions: wasm32_unknown_emscripten +// [wasm32_unknown_emscripten] compile-flags: --target wasm32-unknown-emscripten +// [wasm32_unknown_emscripten] needs-llvm-components: webassembly +// revisions: wasm32_unknown_unknown +// [wasm32_unknown_unknown] compile-flags: --target wasm32-unknown-unknown +// [wasm32_unknown_unknown] needs-llvm-components: webassembly +// revisions: wasm32_wasi +// [wasm32_wasi] compile-flags: --target wasm32-wasi +// [wasm32_wasi] needs-llvm-components: webassembly +// revisions: wasm32_wasi_preview1_threads +// [wasm32_wasi_preview1_threads] compile-flags: --target wasm32-wasi-preview1-threads +// [wasm32_wasi_preview1_threads] needs-llvm-components: webassembly +// revisions: wasm64_unknown_unknown +// [wasm64_unknown_unknown] compile-flags: --target wasm64-unknown-unknown +// [wasm64_unknown_unknown] needs-llvm-components: webassembly +// revisions: x86_64_apple_darwin +// [x86_64_apple_darwin] compile-flags: --target x86_64-apple-darwin +// [x86_64_apple_darwin] needs-llvm-components: x86 +// revisions: x86_64_apple_ios +// [x86_64_apple_ios] compile-flags: --target x86_64-apple-ios +// [x86_64_apple_ios] needs-llvm-components: x86 +// revisions: x86_64_apple_ios_macabi +// [x86_64_apple_ios_macabi] compile-flags: --target x86_64-apple-ios-macabi +// [x86_64_apple_ios_macabi] needs-llvm-components: x86 +// revisions: x86_64_apple_tvos +// [x86_64_apple_tvos] compile-flags: --target x86_64-apple-tvos +// [x86_64_apple_tvos] needs-llvm-components: x86 +// revisions: x86_64_apple_watchos_sim +// [x86_64_apple_watchos_sim] compile-flags: --target x86_64-apple-watchos-sim +// [x86_64_apple_watchos_sim] needs-llvm-components: x86 +// revisions: x86_64_fortanix_unknown_sgx +// [x86_64_fortanix_unknown_sgx] compile-flags: --target x86_64-fortanix-unknown-sgx +// [x86_64_fortanix_unknown_sgx] needs-llvm-components: x86 +// revisions: x86_64_fuchsia +// [x86_64_fuchsia] compile-flags: --target x86_64-fuchsia +// [x86_64_fuchsia] needs-llvm-components: x86 +// revisions: x86_64_linux_android +// [x86_64_linux_android] compile-flags: --target x86_64-linux-android +// [x86_64_linux_android] needs-llvm-components: x86 +// revisions: x86_64_pc_nto_qnx710 +// [x86_64_pc_nto_qnx710] compile-flags: --target x86_64-pc-nto-qnx710 +// [x86_64_pc_nto_qnx710] needs-llvm-components: x86 +// revisions: x86_64_pc_solaris +// [x86_64_pc_solaris] compile-flags: --target x86_64-pc-solaris +// [x86_64_pc_solaris] needs-llvm-components: x86 +// revisions: x86_64_unikraft_linux_musl +// [x86_64_unikraft_linux_musl] compile-flags: --target x86_64-unikraft-linux-musl +// [x86_64_unikraft_linux_musl] needs-llvm-components: x86 +// revisions: x86_64_unknown_dragonfly +// [x86_64_unknown_dragonfly] compile-flags: --target x86_64-unknown-dragonfly +// [x86_64_unknown_dragonfly] needs-llvm-components: x86 +// revisions: x86_64_unknown_freebsd +// [x86_64_unknown_freebsd] compile-flags: --target x86_64-unknown-freebsd +// [x86_64_unknown_freebsd] needs-llvm-components: x86 +// revisions: x86_64_unknown_fuchsia +// [x86_64_unknown_fuchsia] compile-flags: --target x86_64-unknown-fuchsia +// [x86_64_unknown_fuchsia] needs-llvm-components: x86 +// revisions: x86_64_unknown_haiku +// [x86_64_unknown_haiku] compile-flags: --target x86_64-unknown-haiku +// [x86_64_unknown_haiku] needs-llvm-components: x86 +// revisions: x86_64_unknown_hermit +// [x86_64_unknown_hermit] compile-flags: --target x86_64-unknown-hermit +// [x86_64_unknown_hermit] needs-llvm-components: x86 +// revisions: x86_64_unknown_illumos +// [x86_64_unknown_illumos] compile-flags: --target x86_64-unknown-illumos +// [x86_64_unknown_illumos] needs-llvm-components: x86 +// revisions: x86_64_unknown_l4re_uclibc +// [x86_64_unknown_l4re_uclibc] compile-flags: --target x86_64-unknown-l4re-uclibc +// [x86_64_unknown_l4re_uclibc] needs-llvm-components: x86 +// revisions: x86_64_unknown_linux_gnu +// [x86_64_unknown_linux_gnu] compile-flags: --target x86_64-unknown-linux-gnu +// [x86_64_unknown_linux_gnu] needs-llvm-components: x86 +// revisions: x86_64_unknown_linux_gnux32 +// [x86_64_unknown_linux_gnux32] compile-flags: --target x86_64-unknown-linux-gnux32 +// [x86_64_unknown_linux_gnux32] needs-llvm-components: x86 +// revisions: x86_64_unknown_linux_musl +// [x86_64_unknown_linux_musl] compile-flags: --target x86_64-unknown-linux-musl +// [x86_64_unknown_linux_musl] needs-llvm-components: x86 +// revisions: x86_64_unknown_linux_ohos +// [x86_64_unknown_linux_ohos] compile-flags: --target x86_64-unknown-linux-ohos +// [x86_64_unknown_linux_ohos] needs-llvm-components: x86 +// revisions: x86_64_unknown_netbsd +// [x86_64_unknown_netbsd] compile-flags: --target x86_64-unknown-netbsd +// [x86_64_unknown_netbsd] needs-llvm-components: x86 +// revisions: x86_64_unknown_none +// [x86_64_unknown_none] compile-flags: --target x86_64-unknown-none +// [x86_64_unknown_none] needs-llvm-components: x86 +// revisions: x86_64_unknown_openbsd +// [x86_64_unknown_openbsd] compile-flags: --target x86_64-unknown-openbsd +// [x86_64_unknown_openbsd] needs-llvm-components: x86 +// revisions: x86_64_unknown_redox +// [x86_64_unknown_redox] compile-flags: --target x86_64-unknown-redox +// [x86_64_unknown_redox] needs-llvm-components: x86 +// revisions: x86_64_wrs_vxworks +// [x86_64_wrs_vxworks] compile-flags: --target x86_64-wrs-vxworks +// [x86_64_wrs_vxworks] needs-llvm-components: x86 +// revisions: x86_64h_apple_darwin +// [x86_64h_apple_darwin] compile-flags: --target x86_64h-apple-darwin +// [x86_64h_apple_darwin] needs-llvm-components: x86 + +// Sanity-check that each target can produce assembly code. + +#![feature(no_core, lang_items)] +#![no_std] +#![no_core] +#![crate_type = "lib"] + +#[lang = "sized"] +trait Sized {} + +pub fn test() -> u8 { + 42 +} + +// CHECK: .section diff --git a/tests/assembly/targets/targets-nvptx.rs b/tests/assembly/targets/targets-nvptx.rs new file mode 100644 index 0000000000000..0633423040008 --- /dev/null +++ b/tests/assembly/targets/targets-nvptx.rs @@ -0,0 +1,21 @@ +// assembly-output: emit-asm +// ignore-tidy-linelength +// revisions: nvptx64_nvidia_cuda +// [nvptx64_nvidia_cuda] compile-flags: --target nvptx64-nvidia-cuda +// [nvptx64_nvidia_cuda] needs-llvm-components: nvptx + +// Sanity-check that each target can produce assembly code. + +#![feature(no_core, lang_items)] +#![no_std] +#![no_core] +#![crate_type = "lib"] + +#[lang = "sized"] +trait Sized {} + +pub fn test() -> u8 { + 42 +} + +// CHECK: .version diff --git a/tests/assembly/targets/targets-pe.rs b/tests/assembly/targets/targets-pe.rs new file mode 100644 index 0000000000000..7398d7ef79007 --- /dev/null +++ b/tests/assembly/targets/targets-pe.rs @@ -0,0 +1,93 @@ +// assembly-output: emit-asm +// ignore-tidy-linelength +// revisions: aarch64_pc_windows_msvc +// [aarch64_pc_windows_msvc] compile-flags: --target aarch64-pc-windows-msvc +// [aarch64_pc_windows_msvc] needs-llvm-components: aarch64 +// revisions: aarch64_pc_windows_gnullvm +// [aarch64_pc_windows_gnullvm] compile-flags: --target aarch64-pc-windows-gnullvm +// [aarch64_pc_windows_gnullvm] needs-llvm-components: aarch64 +// revisions: aarch64_unknown_uefi +// [aarch64_unknown_uefi] compile-flags: --target aarch64-unknown-uefi +// [aarch64_unknown_uefi] needs-llvm-components: aarch64 +// revisions: aarch64_uwp_windows_msvc +// [aarch64_uwp_windows_msvc] compile-flags: --target aarch64-uwp-windows-msvc +// [aarch64_uwp_windows_msvc] needs-llvm-components: aarch64 +// revisions: avr_unknown_gnu_atmega328 +// [avr_unknown_gnu_atmega328] compile-flags: --target avr-unknown-gnu-atmega328 +// [avr_unknown_gnu_atmega328] needs-llvm-components: avr +// revisions: bpfeb_unknown_none +// [bpfeb_unknown_none] compile-flags: --target bpfeb-unknown-none +// [bpfeb_unknown_none] needs-llvm-components: bpf +// revisions: bpfel_unknown_none +// [bpfel_unknown_none] compile-flags: --target bpfel-unknown-none +// [bpfel_unknown_none] needs-llvm-components: bpf +// revisions: i586_pc_windows_msvc +// [i586_pc_windows_msvc] compile-flags: --target i586-pc-windows-msvc +// [i586_pc_windows_msvc] needs-llvm-components: x86 +// revisions: i686_pc_windows_gnu +// [i686_pc_windows_gnu] compile-flags: --target i686-pc-windows-gnu +// [i686_pc_windows_gnu] needs-llvm-components: x86 +// revisions: i686_pc_windows_msvc +// [i686_pc_windows_msvc] compile-flags: --target i686-pc-windows-msvc +// [i686_pc_windows_msvc] needs-llvm-components: x86 +// revisions: i686_pc_windows_gnullvm +// [i686_pc_windows_gnullvm] compile-flags: --target i686-pc-windows-gnullvm +// [i686_pc_windows_gnullvm] needs-llvm-components: x86 +// revisions: i686_uwp_windows_gnu +// [i686_uwp_windows_gnu] compile-flags: --target i686-uwp-windows-gnu +// [i686_uwp_windows_gnu] needs-llvm-components: x86 +// revisions: i686_unknown_uefi +// [i686_unknown_uefi] compile-flags: --target i686-unknown-uefi +// [i686_unknown_uefi] needs-llvm-components: x86 +// revisions: i686_uwp_windows_msvc +// [i686_uwp_windows_msvc] compile-flags: --target i686-uwp-windows-msvc +// [i686_uwp_windows_msvc] needs-llvm-components: x86 +// revisions: i686_win7_windows_msvc +// [i686_win7_windows_msvc] compile-flags: --target i686-win7-windows-msvc +// [i686_win7_windows_msvc] needs-llvm-components: x86 +// revisions: powerpc64_ibm_aix +// [powerpc64_ibm_aix] compile-flags: --target powerpc64-ibm-aix +// [powerpc64_ibm_aix] needs-llvm-components: powerpc +// revisions: thumbv7a_uwp_windows_msvc +// [thumbv7a_uwp_windows_msvc] compile-flags: --target thumbv7a-uwp-windows-msvc +// [thumbv7a_uwp_windows_msvc] needs-llvm-components: arm +// revisions: thumbv7a_pc_windows_msvc +// [thumbv7a_pc_windows_msvc] compile-flags: --target thumbv7a-pc-windows-msvc +// [thumbv7a_pc_windows_msvc] needs-llvm-components: arm +// revisions: x86_64_pc_windows_gnu +// [x86_64_pc_windows_gnu] compile-flags: --target x86_64-pc-windows-gnu +// [x86_64_pc_windows_gnu] needs-llvm-components: x86 +// revisions: x86_64_pc_windows_gnullvm +// [x86_64_pc_windows_gnullvm] compile-flags: --target x86_64-pc-windows-gnullvm +// [x86_64_pc_windows_gnullvm] needs-llvm-components: x86 +// revisions: x86_64_pc_windows_msvc +// [x86_64_pc_windows_msvc] compile-flags: --target x86_64-pc-windows-msvc +// [x86_64_pc_windows_msvc] needs-llvm-components: x86 +// revisions: x86_64_unknown_uefi +// [x86_64_unknown_uefi] compile-flags: --target x86_64-unknown-uefi +// [x86_64_unknown_uefi] needs-llvm-components: x86 +// revisions: x86_64_uwp_windows_gnu +// [x86_64_uwp_windows_gnu] compile-flags: --target x86_64-uwp-windows-gnu +// [x86_64_uwp_windows_gnu] needs-llvm-components: x86 +// revisions: x86_64_uwp_windows_msvc +// [x86_64_uwp_windows_msvc] compile-flags: --target x86_64-uwp-windows-msvc +// [x86_64_uwp_windows_msvc] needs-llvm-components: x86 +// revisions: x86_64_win7_windows_msvc +// [x86_64_win7_windows_msvc] compile-flags: --target x86_64-win7-windows-msvc +// [x86_64_win7_windows_msvc] needs-llvm-components: x86 + +// Sanity-check that each target can produce assembly code. + +#![feature(no_core, lang_items)] +#![no_std] +#![no_core] +#![crate_type = "lib"] + +#[lang = "sized"] +trait Sized {} + +pub fn test() -> u8 { + 42 +} + +// CHECK: .file From 1b9a01340b50cf015ec99519814628d6a28b7cfa Mon Sep 17 00:00:00 2001 From: Aldan Tanneo Date: Wed, 17 Jan 2024 10:47:33 +0100 Subject: [PATCH 0331/1197] specialize `Bytes` on `StdinLock<'_>` by using the underlying `BufReader` --- library/std/src/io/stdio.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 05b21eeb40f71..261b570dee74f 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -8,7 +8,9 @@ use crate::io::prelude::*; use crate::cell::{Cell, RefCell}; use crate::fmt; use crate::fs::File; -use crate::io::{self, BorrowedCursor, BufReader, IoSlice, IoSliceMut, LineWriter, Lines}; +use crate::io::{ + self, BorrowedCursor, BufReader, IoSlice, IoSliceMut, LineWriter, Lines, SpecReadByte, +}; use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sync::{Arc, Mutex, MutexGuard, OnceLock, ReentrantMutex, ReentrantMutexGuard}; use crate::sys::stdio; @@ -483,6 +485,13 @@ impl Read for StdinLock<'_> { } } +impl SpecReadByte for StdinLock<'_> { + #[inline] + fn spec_read_byte(&mut self) -> Option> { + BufReader::spec_read_byte(&mut *self.inner) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl BufRead for StdinLock<'_> { fn fill_buf(&mut self) -> io::Result<&[u8]> { From 4db93c57507dd7c2c3a5cfe9509b67494824a829 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 11 Jan 2024 21:30:45 +0000 Subject: [PATCH 0332/1197] Stop using track_errors for some forever unstable rustc_attr analyses --- .../src/collect/type_of/opaque.rs | 8 +++++--- compiler/rustc_hir_analysis/src/lib.rs | 10 +++------- compiler/rustc_hir_analysis/src/outlives/test.rs | 8 +++++--- compiler/rustc_hir_analysis/src/variance/test.rs | 13 ++++++++----- 4 files changed, 21 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs index 1f7ca48234a24..4f4453867957c 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs @@ -5,20 +5,22 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{self as hir, def, Expr, ImplItem, Item, Node, TraitItem}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; -use rustc_span::{sym, DUMMY_SP}; +use rustc_span::{sym, ErrorGuaranteed, DUMMY_SP}; use crate::errors::{TaitForwardCompat, TypeOf, UnconstrainedOpaqueType}; -pub fn test_opaque_hidden_types(tcx: TyCtxt<'_>) { +pub fn test_opaque_hidden_types(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { + let mut res = Ok(()); if tcx.has_attr(CRATE_DEF_ID, sym::rustc_hidden_type_of_opaques) { for id in tcx.hir().items() { if matches!(tcx.def_kind(id.owner_id), DefKind::OpaqueTy) { let type_of = tcx.type_of(id.owner_id).instantiate_identity(); - tcx.dcx().emit_err(TypeOf { span: tcx.def_span(id.owner_id), type_of }); + res = Err(tcx.dcx().emit_err(TypeOf { span: tcx.def_span(id.owner_id), type_of })); } } } + res } /// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index f5abb7261c00d..16e530ca946c7 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -169,9 +169,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { // FIXME(matthewjasper) We shouldn't need to use `track_errors` anywhere in this function // or the compiler in general. if tcx.features().rustc_attrs { - tcx.sess.track_errors(|| { - tcx.sess.time("outlives_testing", || outlives::test::test_inferred_outlives(tcx)); - })?; + tcx.sess.time("outlives_testing", || outlives::test::test_inferred_outlives(tcx))?; } tcx.sess.track_errors(|| { @@ -190,9 +188,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { })?; if tcx.features().rustc_attrs { - tcx.sess.track_errors(|| { - tcx.sess.time("variance_testing", || variance::test::test_variance(tcx)); - })?; + tcx.sess.time("variance_testing", || variance::test::test_variance(tcx))?; } tcx.sess.time("wf_checking", || { @@ -200,7 +196,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { })?; if tcx.features().rustc_attrs { - tcx.sess.track_errors(|| collect::test_opaque_hidden_types(tcx))?; + collect::test_opaque_hidden_types(tcx)?; } // Freeze definitions as we don't add new ones at this point. This improves performance by diff --git a/compiler/rustc_hir_analysis/src/outlives/test.rs b/compiler/rustc_hir_analysis/src/outlives/test.rs index dea3f1a993087..60cd8c39fa022 100644 --- a/compiler/rustc_hir_analysis/src/outlives/test.rs +++ b/compiler/rustc_hir_analysis/src/outlives/test.rs @@ -1,7 +1,8 @@ use rustc_middle::ty::{self, TyCtxt}; -use rustc_span::symbol::sym; +use rustc_span::{symbol::sym, ErrorGuaranteed}; -pub fn test_inferred_outlives(tcx: TyCtxt<'_>) { +pub fn test_inferred_outlives(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { + let mut res = Ok(()); for id in tcx.hir().items() { // For unit testing: check for a special "rustc_outlives" // attribute and report an error with various results if found. @@ -22,7 +23,8 @@ pub fn test_inferred_outlives(tcx: TyCtxt<'_>) { for p in pred { err.note(p); } - err.emit(); + res = Err(err.emit()); } } + res } diff --git a/compiler/rustc_hir_analysis/src/variance/test.rs b/compiler/rustc_hir_analysis/src/variance/test.rs index 5264d5aa26f21..c211e1af046af 100644 --- a/compiler/rustc_hir_analysis/src/variance/test.rs +++ b/compiler/rustc_hir_analysis/src/variance/test.rs @@ -2,19 +2,21 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::CRATE_DEF_ID; use rustc_middle::ty::TyCtxt; use rustc_span::symbol::sym; +use rustc_span::ErrorGuaranteed; use crate::errors; -pub fn test_variance(tcx: TyCtxt<'_>) { +pub fn test_variance(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { + let mut res = Ok(()); if tcx.has_attr(CRATE_DEF_ID, sym::rustc_variance_of_opaques) { for id in tcx.hir().items() { if matches!(tcx.def_kind(id.owner_id), DefKind::OpaqueTy) { let variances_of = tcx.variances_of(id.owner_id); - tcx.dcx().emit_err(errors::VariancesOf { + res = Err(tcx.dcx().emit_err(errors::VariancesOf { span: tcx.def_span(id.owner_id), variances_of: format!("{variances_of:?}"), - }); + })); } } } @@ -25,10 +27,11 @@ pub fn test_variance(tcx: TyCtxt<'_>) { if tcx.has_attr(id.owner_id, sym::rustc_variance) { let variances_of = tcx.variances_of(id.owner_id); - tcx.dcx().emit_err(errors::VariancesOf { + res = Err(tcx.dcx().emit_err(errors::VariancesOf { span: tcx.def_span(id.owner_id), variances_of: format!("{variances_of:?}"), - }); + })); } } + res } From b1ce8a4ecdcdb179d023d9fd1061575ba651aeeb Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 11 Jan 2024 22:13:39 +0000 Subject: [PATCH 0333/1197] Move `check_mod_impl_wf` query call out of track_errors and bubble errors up instead. --- .../rustc_hir_analysis/src/impl_wf_check.rs | 46 ++++-- .../src/impl_wf_check/min_specialization.rs | 132 +++++++++++------- compiler/rustc_hir_analysis/src/lib.rs | 15 +- compiler/rustc_middle/src/query/mod.rs | 3 +- .../in-trait/return-dont-satisfy-bounds.rs | 2 + .../return-dont-satisfy-bounds.stderr | 26 +++- .../specializing-constness-2.stderr | 14 +- 7 files changed, 163 insertions(+), 75 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index 3f9b1f384d790..2fe08ead72b2a 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -17,7 +17,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::{LocalDefId, LocalModDefId}; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; -use rustc_span::{Span, Symbol}; +use rustc_span::{ErrorGuaranteed, Span, Symbol}; mod min_specialization; @@ -51,24 +51,29 @@ mod min_specialization; /// impl<'a> Trait for Bar { type X = &'a i32; } /// // ^ 'a is unused and appears in assoc type, error /// ``` -fn check_mod_impl_wf(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { +fn check_mod_impl_wf(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) -> Result<(), ErrorGuaranteed> { let min_specialization = tcx.features().min_specialization; let module = tcx.hir_module_items(module_def_id); + let mut res = Ok(()); for id in module.items() { if matches!(tcx.def_kind(id.owner_id), DefKind::Impl { .. }) { - enforce_impl_params_are_constrained(tcx, id.owner_id.def_id); + res = res.and(enforce_impl_params_are_constrained(tcx, id.owner_id.def_id)); if min_specialization { - check_min_specialization(tcx, id.owner_id.def_id); + res = res.and(check_min_specialization(tcx, id.owner_id.def_id)); } } } + res } pub fn provide(providers: &mut Providers) { *providers = Providers { check_mod_impl_wf, ..*providers }; } -fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) { +fn enforce_impl_params_are_constrained( + tcx: TyCtxt<'_>, + impl_def_id: LocalDefId, +) -> Result<(), ErrorGuaranteed> { // Every lifetime used in an associated type must be constrained. let impl_self_ty = tcx.type_of(impl_def_id).instantiate_identity(); if impl_self_ty.references_error() { @@ -80,7 +85,10 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) "potentially unconstrained type parameters weren't evaluated: {impl_self_ty:?}", ), ); - return; + // This is super fishy, but our current `rustc_hir_analysis::check_crate` pipeline depends on + // `type_of` having been called much earlier, and thus this value being read from cache. + // Compilation must continue in order for other important diagnostics to keep showing up. + return Ok(()); } let impl_generics = tcx.generics_of(impl_def_id); let impl_predicates = tcx.predicates_of(impl_def_id); @@ -113,13 +121,19 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) }) .collect(); + let mut res = Ok(()); for param in &impl_generics.params { match param.kind { // Disallow ANY unconstrained type parameters. ty::GenericParamDefKind::Type { .. } => { let param_ty = ty::ParamTy::for_def(param); if !input_parameters.contains(&cgp::Parameter::from(param_ty)) { - report_unused_parameter(tcx, tcx.def_span(param.def_id), "type", param_ty.name); + res = Err(report_unused_parameter( + tcx, + tcx.def_span(param.def_id), + "type", + param_ty.name, + )); } } ty::GenericParamDefKind::Lifetime => { @@ -127,27 +141,28 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) if lifetimes_in_associated_types.contains(¶m_lt) && // (*) !input_parameters.contains(¶m_lt) { - report_unused_parameter( + res = Err(report_unused_parameter( tcx, tcx.def_span(param.def_id), "lifetime", param.name, - ); + )); } } ty::GenericParamDefKind::Const { .. } => { let param_ct = ty::ParamConst::for_def(param); if !input_parameters.contains(&cgp::Parameter::from(param_ct)) { - report_unused_parameter( + res = Err(report_unused_parameter( tcx, tcx.def_span(param.def_id), "const", param_ct.name, - ); + )); } } } } + res // (*) This is a horrible concession to reality. I think it'd be // better to just ban unconstrained lifetimes outright, but in @@ -169,7 +184,12 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) // used elsewhere are not projected back out. } -fn report_unused_parameter(tcx: TyCtxt<'_>, span: Span, kind: &str, name: Symbol) { +fn report_unused_parameter( + tcx: TyCtxt<'_>, + span: Span, + kind: &str, + name: Symbol, +) -> ErrorGuaranteed { let mut err = struct_span_code_err!( tcx.dcx(), span, @@ -188,5 +208,5 @@ fn report_unused_parameter(tcx: TyCtxt<'_>, span: Span, kind: &str, name: Symbol "proving the result of expressions other than the parameter are unique is not supported", ); } - err.emit(); + err.emit() } diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 93dd2342a4d13..6d685aec663b2 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -82,10 +82,14 @@ use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::{self, translate_args_with_cause, wf, ObligationCtxt}; -pub(super) fn check_min_specialization(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) { +pub(super) fn check_min_specialization( + tcx: TyCtxt<'_>, + impl_def_id: LocalDefId, +) -> Result<(), ErrorGuaranteed> { if let Some(node) = parent_specialization_node(tcx, impl_def_id) { - check_always_applicable(tcx, impl_def_id, node); + check_always_applicable(tcx, impl_def_id, node)?; } + Ok(()) } fn parent_specialization_node(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId) -> Option { @@ -109,42 +113,58 @@ fn parent_specialization_node(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId) -> Opti /// Check that `impl1` is a sound specialization #[instrument(level = "debug", skip(tcx))] -fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node) { +fn check_always_applicable( + tcx: TyCtxt<'_>, + impl1_def_id: LocalDefId, + impl2_node: Node, +) -> Result<(), ErrorGuaranteed> { let span = tcx.def_span(impl1_def_id); - check_has_items(tcx, impl1_def_id, impl2_node, span); - - if let Ok((impl1_args, impl2_args)) = get_impl_args(tcx, impl1_def_id, impl2_node) { - let impl2_def_id = impl2_node.def_id(); - debug!(?impl2_def_id, ?impl2_args); - - let parent_args = if impl2_node.is_from_trait() { - impl2_args.to_vec() - } else { - unconstrained_parent_impl_args(tcx, impl2_def_id, impl2_args) - }; - - check_constness(tcx, impl1_def_id, impl2_node, span); - check_static_lifetimes(tcx, &parent_args, span); - check_duplicate_params(tcx, impl1_args, &parent_args, span); - check_predicates(tcx, impl1_def_id, impl1_args, impl2_node, impl2_args, span); - } + let mut res = check_has_items(tcx, impl1_def_id, impl2_node, span); + + let (impl1_args, impl2_args) = get_impl_args(tcx, impl1_def_id, impl2_node)?; + let impl2_def_id = impl2_node.def_id(); + debug!(?impl2_def_id, ?impl2_args); + + let parent_args = if impl2_node.is_from_trait() { + impl2_args.to_vec() + } else { + unconstrained_parent_impl_args(tcx, impl2_def_id, impl2_args) + }; + + res = res.and(check_constness(tcx, impl1_def_id, impl2_node, span)); + res = res.and(check_static_lifetimes(tcx, &parent_args, span)); + res = res.and(check_duplicate_params(tcx, impl1_args, &parent_args, span)); + res = res.and(check_predicates(tcx, impl1_def_id, impl1_args, impl2_node, impl2_args, span)); + + res } -fn check_has_items(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node, span: Span) { +fn check_has_items( + tcx: TyCtxt<'_>, + impl1_def_id: LocalDefId, + impl2_node: Node, + span: Span, +) -> Result<(), ErrorGuaranteed> { if let Node::Impl(impl2_id) = impl2_node && tcx.associated_item_def_ids(impl1_def_id).is_empty() { let base_impl_span = tcx.def_span(impl2_id); - tcx.dcx().emit_err(errors::EmptySpecialization { span, base_impl_span }); + return Err(tcx.dcx().emit_err(errors::EmptySpecialization { span, base_impl_span })); } + Ok(()) } /// Check that the specializing impl `impl1` is at least as const as the base /// impl `impl2` -fn check_constness(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node, span: Span) { +fn check_constness( + tcx: TyCtxt<'_>, + impl1_def_id: LocalDefId, + impl2_node: Node, + span: Span, +) -> Result<(), ErrorGuaranteed> { if impl2_node.is_from_trait() { // This isn't a specialization - return; + return Ok(()); } let impl1_constness = tcx.constness(impl1_def_id.to_def_id()); @@ -152,9 +172,10 @@ fn check_constness(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node, if let hir::Constness::Const = impl2_constness { if let hir::Constness::NotConst = impl1_constness { - tcx.dcx().emit_err(errors::ConstSpecialize { span }); + return Err(tcx.dcx().emit_err(errors::ConstSpecialize { span })); } } + Ok(()) } /// Given a specializing impl `impl1`, and the base impl `impl2`, returns two @@ -290,15 +311,17 @@ fn check_duplicate_params<'tcx>( impl1_args: GenericArgsRef<'tcx>, parent_args: &Vec>, span: Span, -) { +) -> Result<(), ErrorGuaranteed> { let mut base_params = cgp::parameters_for(parent_args, true); base_params.sort_by_key(|param| param.0); if let (_, [duplicate, ..]) = base_params.partition_dedup() { let param = impl1_args[duplicate.0 as usize]; - tcx.dcx() + return Err(tcx + .dcx() .struct_span_err(span, format!("specializing impl repeats parameter `{param}`")) - .emit(); + .emit()); } + Ok(()) } /// Check that `'static` lifetimes are not introduced by the specializing impl. @@ -313,10 +336,11 @@ fn check_static_lifetimes<'tcx>( tcx: TyCtxt<'tcx>, parent_args: &Vec>, span: Span, -) { +) -> Result<(), ErrorGuaranteed> { if tcx.any_free_region_meets(parent_args, |r| r.is_static()) { - tcx.dcx().emit_err(errors::StaticSpecialize { span }); + return Err(tcx.dcx().emit_err(errors::StaticSpecialize { span })); } + Ok(()) } /// Check whether predicates on the specializing impl (`impl1`) are allowed. @@ -337,7 +361,7 @@ fn check_predicates<'tcx>( impl2_node: Node, impl2_args: GenericArgsRef<'tcx>, span: Span, -) { +) -> Result<(), ErrorGuaranteed> { let impl1_predicates: Vec<_> = traits::elaborate( tcx, tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_args).into_iter(), @@ -399,14 +423,16 @@ fn check_predicates<'tcx>( } impl2_predicates.extend(traits::elaborate(tcx, always_applicable_traits)); + let mut res = Ok(()); for (clause, span) in impl1_predicates { if !impl2_predicates .iter() .any(|pred2| trait_predicates_eq(tcx, clause.as_predicate(), *pred2, span)) { - check_specialization_on(tcx, clause, span) + res = res.and(check_specialization_on(tcx, clause, span)) } } + res } /// Checks if some predicate on the specializing impl (`predicate1`) is the same @@ -443,19 +469,26 @@ fn trait_predicates_eq<'tcx>( } #[instrument(level = "debug", skip(tcx))] -fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, clause: ty::Clause<'tcx>, span: Span) { +fn check_specialization_on<'tcx>( + tcx: TyCtxt<'tcx>, + clause: ty::Clause<'tcx>, + span: Span, +) -> Result<(), ErrorGuaranteed> { match clause.kind().skip_binder() { // Global predicates are either always true or always false, so we // are fine to specialize on. - _ if clause.is_global() => (), + _ if clause.is_global() => Ok(()), // We allow specializing on explicitly marked traits with no associated // items. ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity: _ }) => { - if !matches!( + if matches!( trait_specialization_kind(tcx, clause), Some(TraitSpecializationKind::Marker) ) { - tcx.dcx() + Ok(()) + } else { + Err(tcx + .dcx() .struct_span_err( span, format!( @@ -463,17 +496,16 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, clause: ty::Clause<'tcx>, sp tcx.def_path_str(trait_ref.def_id), ), ) - .emit(); + .emit()) } } - ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => { - tcx.dcx() - .struct_span_err( - span, - format!("cannot specialize on associated type `{projection_ty} == {term}`",), - ) - .emit(); - } + ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => Err(tcx + .dcx() + .struct_span_err( + span, + format!("cannot specialize on associated type `{projection_ty} == {term}`",), + ) + .emit()), ty::ClauseKind::ConstArgHasType(..) => { // FIXME(min_specialization), FIXME(const_generics): // It probably isn't right to allow _every_ `ConstArgHasType` but I am somewhat unsure @@ -483,12 +515,12 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, clause: ty::Clause<'tcx>, sp // While we do not support constructs like `` there is probably no risk of // soundness bugs, but when we support generic const parameter types this will need to be // revisited. + Ok(()) } - _ => { - tcx.dcx() - .struct_span_err(span, format!("cannot specialize on predicate `{clause}`")) - .emit(); - } + _ => Err(tcx + .dcx() + .struct_span_err(span, format!("cannot specialize on predicate `{clause}`")) + .emit()), } } diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 16e530ca946c7..1a370ad10cf72 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -166,17 +166,18 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { tcx.hir().for_each_module(|module| tcx.ensure().collect_mod_item_types(module)) }); - // FIXME(matthewjasper) We shouldn't need to use `track_errors` anywhere in this function - // or the compiler in general. if tcx.features().rustc_attrs { tcx.sess.time("outlives_testing", || outlives::test::test_inferred_outlives(tcx))?; } - tcx.sess.track_errors(|| { - tcx.sess.time("coherence_checking", || { - // Check impls constrain their parameters - tcx.hir().for_each_module(|module| tcx.ensure().check_mod_impl_wf(module)); + tcx.sess.time("coherence_checking", || { + // Check impls constrain their parameters + let res = + tcx.hir().try_par_for_each_module(|module| tcx.ensure().check_mod_impl_wf(module)); + // FIXME(matthewjasper) We shouldn't need to use `track_errors` anywhere in this function + // or the compiler in general. + res.and(tcx.sess.track_errors(|| { for &trait_def_id in tcx.all_local_trait_impls(()).keys() { tcx.ensure().coherent_trait(trait_def_id); } @@ -184,7 +185,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { // these queries are executed for side-effects (error reporting): tcx.ensure().crate_inherent_impls(()); tcx.ensure().crate_inherent_impls_overlap_check(()); - }); + })) })?; if tcx.features().rustc_attrs { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 1dc7722088108..6e5870df7c14e 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -961,8 +961,9 @@ rustc_queries! { desc { |tcx| "checking deathness of variables in {}", describe_as_module(key, tcx) } } - query check_mod_impl_wf(key: LocalModDefId) -> () { + query check_mod_impl_wf(key: LocalModDefId) -> Result<(), ErrorGuaranteed> { desc { |tcx| "checking that impls are well-formed in {}", describe_as_module(key, tcx) } + ensure_forwards_result_if_red } query check_mod_type_wf(key: LocalModDefId) -> Result<(), ErrorGuaranteed> { diff --git a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs index ad73b12feb531..ff265e576b90f 100644 --- a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs +++ b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs @@ -7,6 +7,8 @@ struct Bar; impl Foo for Bar { fn foo>(self) -> impl Foo { //~^ ERROR: the trait bound `impl Foo: Foo` is not satisfied [E0277] + //~| ERROR: the trait bound `Bar: Foo` is not satisfied [E0277] + //~| ERROR: impl has stricter requirements than trait self } } diff --git a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr index db587d069f8b8..638de01f91393 100644 --- a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr +++ b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr @@ -11,6 +11,28 @@ note: required by a bound in `Foo::{opaque#0}` LL | fn foo(self) -> impl Foo; | ^^^^^^ required by this bound in `Foo::{opaque#0}` -error: aborting due to 1 previous error +error[E0276]: impl has stricter requirements than trait + --> $DIR/return-dont-satisfy-bounds.rs:8:16 + | +LL | fn foo(self) -> impl Foo; + | -------------------------------- definition of `foo` from trait +... +LL | fn foo>(self) -> impl Foo { + | ^^^^^^^ impl has extra requirement `F2: Foo` + +error[E0277]: the trait bound `Bar: Foo` is not satisfied + --> $DIR/return-dont-satisfy-bounds.rs:8:34 + | +LL | fn foo>(self) -> impl Foo { + | ^^^^^^^^^^^^ the trait `Foo` is not implemented for `Bar` +... +LL | self + | ---- return type was inferred to be `Bar` here + | + = help: the trait `Foo` is implemented for `Bar` + = help: for that trait implementation, expected `char`, found `u8` + +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0276, E0277. +For more information about an error, try `rustc --explain E0276`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr index 5210a6942010d..e5b9493b3ce11 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr @@ -7,6 +7,16 @@ LL | impl A for T { LL | impl const A for T { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation -error: aborting due to 1 previous error +error[E0308]: mismatched types + --> $DIR/specializing-constness-2.rs:27:5 + | +LL | ::a(); + | ^^^^^^^^^^^^^ expected `host`, found `true` + | + = note: expected constant `host` + found constant `true` + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0119`. +Some errors have detailed explanations: E0119, E0308. +For more information about an error, try `rustc --explain E0119`. From 49347ee12dd23c357d45374a6e442e2c32fa4202 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 12 Jan 2024 08:57:07 +0000 Subject: [PATCH 0334/1197] Make crate_inherent_impls_overlap_check bubble up its errors --- .../src/coherence/inherent_impls_overlap.rs | 46 +++++++++++-------- compiler/rustc_hir_analysis/src/lib.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 3 +- 3 files changed, 31 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs index 4c3455c7240f6..d66f073b1b4c0 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs @@ -6,16 +6,18 @@ use rustc_hir::def_id::DefId; use rustc_index::IndexVec; use rustc_middle::traits::specialization_graph::OverlapMode; use rustc_middle::ty::{self, TyCtxt}; -use rustc_span::Symbol; +use rustc_span::{ErrorGuaranteed, Symbol}; use rustc_trait_selection::traits::{self, SkipLeakCheck}; use smallvec::SmallVec; use std::collections::hash_map::Entry; -pub fn crate_inherent_impls_overlap_check(tcx: TyCtxt<'_>, (): ()) { +pub fn crate_inherent_impls_overlap_check(tcx: TyCtxt<'_>, (): ()) -> Result<(), ErrorGuaranteed> { let mut inherent_overlap_checker = InherentOverlapChecker { tcx }; + let mut res = Ok(()); for id in tcx.hir().items() { - inherent_overlap_checker.check_item(id); + res = res.and(inherent_overlap_checker.check_item(id)); } + res } struct InherentOverlapChecker<'tcx> { @@ -58,10 +60,11 @@ impl<'tcx> InherentOverlapChecker<'tcx> { == item2.ident(self.tcx).normalize_to_macros_2_0() } - fn check_for_duplicate_items_in_impl(&self, impl_: DefId) { + fn check_for_duplicate_items_in_impl(&self, impl_: DefId) -> Result<(), ErrorGuaranteed> { let impl_items = self.tcx.associated_items(impl_); let mut seen_items = FxHashMap::default(); + let mut res = Ok(()); for impl_item in impl_items.in_definition_order() { let span = self.tcx.def_span(impl_item.def_id); let ident = impl_item.ident(self.tcx); @@ -70,7 +73,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> { match seen_items.entry(norm_ident) { Entry::Occupied(entry) => { let former = entry.get(); - struct_span_code_err!( + res = Err(struct_span_code_err!( self.tcx.dcx(), span, E0592, @@ -79,13 +82,14 @@ impl<'tcx> InherentOverlapChecker<'tcx> { ) .with_span_label(span, format!("duplicate definitions for `{ident}`")) .with_span_label(*former, format!("other definition for `{ident}`")) - .emit(); + .emit()); } Entry::Vacant(entry) => { entry.insert(span); } } } + res } fn check_for_common_items_in_impls( @@ -93,10 +97,11 @@ impl<'tcx> InherentOverlapChecker<'tcx> { impl1: DefId, impl2: DefId, overlap: traits::OverlapResult<'_>, - ) { + ) -> Result<(), ErrorGuaranteed> { let impl_items1 = self.tcx.associated_items(impl1); let impl_items2 = self.tcx.associated_items(impl2); + let mut res = Ok(()); for &item1 in impl_items1.in_definition_order() { let collision = impl_items2 .filter_by_name_unhygienic(item1.name) @@ -128,9 +133,10 @@ impl<'tcx> InherentOverlapChecker<'tcx> { traits::add_placeholder_note(&mut err); } - err.emit(); + res = Err(err.emit()); } } + res } fn check_for_overlapping_inherent_impls( @@ -138,7 +144,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> { overlap_mode: OverlapMode, impl1_def_id: DefId, impl2_def_id: DefId, - ) { + ) -> Result<(), ErrorGuaranteed> { let maybe_overlap = traits::overlapping_impls( self.tcx, impl1_def_id, @@ -150,14 +156,16 @@ impl<'tcx> InherentOverlapChecker<'tcx> { ); if let Some(overlap) = maybe_overlap { - self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id, overlap); + self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id, overlap) + } else { + Ok(()) } } - fn check_item(&mut self, id: hir::ItemId) { + fn check_item(&mut self, id: hir::ItemId) -> Result<(), ErrorGuaranteed> { let def_kind = self.tcx.def_kind(id.owner_id); if !matches!(def_kind, DefKind::Enum | DefKind::Struct | DefKind::Trait | DefKind::Union) { - return; + return Ok(()); } let impls = self.tcx.inherent_impls(id.owner_id); @@ -173,17 +181,18 @@ impl<'tcx> InherentOverlapChecker<'tcx> { // otherwise switch to an allocating algorithm with // faster asymptotic runtime. const ALLOCATING_ALGO_THRESHOLD: usize = 500; + let mut res = Ok(()); if impls.len() < ALLOCATING_ALGO_THRESHOLD { for (i, &(&impl1_def_id, impl_items1)) in impls_items.iter().enumerate() { - self.check_for_duplicate_items_in_impl(impl1_def_id); + res = res.and(self.check_for_duplicate_items_in_impl(impl1_def_id)); for &(&impl2_def_id, impl_items2) in &impls_items[(i + 1)..] { if self.impls_have_common_items(impl_items1, impl_items2) { - self.check_for_overlapping_inherent_impls( + res = res.and(self.check_for_overlapping_inherent_impls( overlap_mode, impl1_def_id, impl2_def_id, - ); + )); } } } @@ -315,20 +324,21 @@ impl<'tcx> InherentOverlapChecker<'tcx> { impl_blocks.sort_unstable(); for (i, &impl1_items_idx) in impl_blocks.iter().enumerate() { let &(&impl1_def_id, impl_items1) = &impls_items[impl1_items_idx]; - self.check_for_duplicate_items_in_impl(impl1_def_id); + res = res.and(self.check_for_duplicate_items_in_impl(impl1_def_id)); for &impl2_items_idx in impl_blocks[(i + 1)..].iter() { let &(&impl2_def_id, impl_items2) = &impls_items[impl2_items_idx]; if self.impls_have_common_items(impl_items1, impl_items2) { - self.check_for_overlapping_inherent_impls( + res = res.and(self.check_for_overlapping_inherent_impls( overlap_mode, impl1_def_id, impl2_def_id, - ); + )); } } } } } + res } } diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 1a370ad10cf72..da9a97db9a4b4 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -184,8 +184,8 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { // these queries are executed for side-effects (error reporting): tcx.ensure().crate_inherent_impls(()); - tcx.ensure().crate_inherent_impls_overlap_check(()); })) + .and(tcx.ensure().crate_inherent_impls_overlap_check(())) })?; if tcx.features().rustc_attrs { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 6e5870df7c14e..15f0dc0208d5e 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1019,8 +1019,9 @@ rustc_queries! { /// Checks all types in the crate for overlap in their inherent impls. Reports errors. /// Not meant to be used directly outside of coherence. - query crate_inherent_impls_overlap_check(_: ()) -> () { + query crate_inherent_impls_overlap_check(_: ()) -> Result<(), ErrorGuaranteed> { desc { "check for overlap between inherent impls defined in this crate" } + ensure_forwards_result_if_red } /// Checks whether all impls in the crate pass the overlap check, returning From 557b11187090b0ec749b07858c6ac18f95b7490e Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 12 Jan 2024 14:29:54 +0000 Subject: [PATCH 0335/1197] Make crate_inherent_impls fallible and stop using `track_errors` for it --- .../rustc_hir_analysis/src/astconv/mod.rs | 2 +- .../src/coherence/inherent_impls.rs | 79 +++++++++++-------- .../src/coherence/inherent_impls_overlap.rs | 2 +- compiler/rustc_hir_analysis/src/lib.rs | 5 +- compiler/rustc_hir_typeck/src/expr.rs | 3 +- compiler/rustc_hir_typeck/src/method/probe.rs | 6 +- .../rustc_hir_typeck/src/method/suggest.rs | 19 +++-- .../src/rmeta/decoder/cstore_impl.rs | 4 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 4 +- compiler/rustc_middle/src/arena.rs | 1 + compiler/rustc_middle/src/query/erase.rs | 4 + compiler/rustc_middle/src/query/mod.rs | 10 +-- compiler/rustc_middle/src/query/plumbing.rs | 12 ++- compiler/rustc_middle/src/ty/trait_def.rs | 18 ++++- compiler/rustc_monomorphize/src/collector.rs | 2 +- .../rustc_resolve/src/late/diagnostics.rs | 6 +- src/librustdoc/clean/inline.rs | 4 +- src/librustdoc/clean/types.rs | 4 +- .../passes/collect_intra_doc_links.rs | 3 +- 19 files changed, 115 insertions(+), 73 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 9f4f1413650f9..b9e72a3b1ea93 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -1446,7 +1446,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } let candidates: Vec<_> = tcx - .inherent_impls(adt_did) + .inherent_impls(adt_did)? .iter() .filter_map(|&impl_| Some((impl_, self.lookup_assoc_ty_unchecked(name, block, impl_)?))) .collect(); diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index 3162004a6348c..abef365c3ca3c 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -13,32 +13,41 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::fast_reject::{simplify_type, SimplifiedType, TreatParams}; use rustc_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt}; use rustc_span::symbol::sym; +use rustc_span::ErrorGuaranteed; use crate::errors; /// On-demand query: yields a map containing all types mapped to their inherent impls. -pub fn crate_inherent_impls(tcx: TyCtxt<'_>, (): ()) -> CrateInherentImpls { +pub fn crate_inherent_impls( + tcx: TyCtxt<'_>, + (): (), +) -> Result<&'_ CrateInherentImpls, ErrorGuaranteed> { let mut collect = InherentCollect { tcx, impls_map: Default::default() }; + let mut res = Ok(()); for id in tcx.hir().items() { - collect.check_item(id); + res = res.and(collect.check_item(id)); } - collect.impls_map + res?; + Ok(tcx.arena.alloc(collect.impls_map)) } -pub fn crate_incoherent_impls(tcx: TyCtxt<'_>, simp: SimplifiedType) -> &[DefId] { - let crate_map = tcx.crate_inherent_impls(()); - tcx.arena.alloc_from_iter( +pub fn crate_incoherent_impls( + tcx: TyCtxt<'_>, + simp: SimplifiedType, +) -> Result<&[DefId], ErrorGuaranteed> { + let crate_map = tcx.crate_inherent_impls(())?; + Ok(tcx.arena.alloc_from_iter( crate_map.incoherent_impls.get(&simp).unwrap_or(&Vec::new()).iter().map(|d| d.to_def_id()), - ) + )) } /// On-demand query: yields a vector of the inherent impls for a specific type. -pub fn inherent_impls(tcx: TyCtxt<'_>, ty_def_id: LocalDefId) -> &[DefId] { - let crate_map = tcx.crate_inherent_impls(()); - match crate_map.inherent_impls.get(&ty_def_id) { +pub fn inherent_impls(tcx: TyCtxt<'_>, ty_def_id: LocalDefId) -> Result<&[DefId], ErrorGuaranteed> { + let crate_map = tcx.crate_inherent_impls(())?; + Ok(match crate_map.inherent_impls.get(&ty_def_id) { Some(v) => &v[..], None => &[], - } + }) } struct InherentCollect<'tcx> { @@ -47,14 +56,19 @@ struct InherentCollect<'tcx> { } impl<'tcx> InherentCollect<'tcx> { - fn check_def_id(&mut self, impl_def_id: LocalDefId, self_ty: Ty<'tcx>, ty_def_id: DefId) { + fn check_def_id( + &mut self, + impl_def_id: LocalDefId, + self_ty: Ty<'tcx>, + ty_def_id: DefId, + ) -> Result<(), ErrorGuaranteed> { if let Some(ty_def_id) = ty_def_id.as_local() { // Add the implementation to the mapping from implementation to base // type def ID, if there is a base type for this implementation and // the implementation does not have any associated traits. let vec = self.impls_map.inherent_impls.entry(ty_def_id).or_default(); vec.push(impl_def_id.to_def_id()); - return; + return Ok(()); } if self.tcx.features().rustc_attrs { @@ -62,18 +76,16 @@ impl<'tcx> InherentCollect<'tcx> { if !self.tcx.has_attr(ty_def_id, sym::rustc_has_incoherent_inherent_impls) { let impl_span = self.tcx.def_span(impl_def_id); - self.tcx.dcx().emit_err(errors::InherentTyOutside { span: impl_span }); - return; + return Err(self.tcx.dcx().emit_err(errors::InherentTyOutside { span: impl_span })); } for &impl_item in items { if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) { let impl_span = self.tcx.def_span(impl_def_id); - self.tcx.dcx().emit_err(errors::InherentTyOutsideRelevant { + return Err(self.tcx.dcx().emit_err(errors::InherentTyOutsideRelevant { span: impl_span, help_span: self.tcx.def_span(impl_item), - }); - return; + })); } } @@ -82,24 +94,28 @@ impl<'tcx> InherentCollect<'tcx> { } else { bug!("unexpected self type: {:?}", self_ty); } + Ok(()) } else { let impl_span = self.tcx.def_span(impl_def_id); - self.tcx.dcx().emit_err(errors::InherentTyOutsideNew { span: impl_span }); + Err(self.tcx.dcx().emit_err(errors::InherentTyOutsideNew { span: impl_span })) } } - fn check_primitive_impl(&mut self, impl_def_id: LocalDefId, ty: Ty<'tcx>) { + fn check_primitive_impl( + &mut self, + impl_def_id: LocalDefId, + ty: Ty<'tcx>, + ) -> Result<(), ErrorGuaranteed> { let items = self.tcx.associated_item_def_ids(impl_def_id); if !self.tcx.hir().rustc_coherence_is_core() { if self.tcx.features().rustc_attrs { for &impl_item in items { if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) { let span = self.tcx.def_span(impl_def_id); - self.tcx.dcx().emit_err(errors::InherentTyOutsidePrimitive { + return Err(self.tcx.dcx().emit_err(errors::InherentTyOutsidePrimitive { span, help_span: self.tcx.def_span(impl_item), - }); - return; + })); } } } else { @@ -108,8 +124,7 @@ impl<'tcx> InherentCollect<'tcx> { if let ty::Ref(_, subty, _) = ty.kind() { note = Some(errors::InherentPrimitiveTyNote { subty: *subty }); } - self.tcx.dcx().emit_err(errors::InherentPrimitiveTy { span, note }); - return; + return Err(self.tcx.dcx().emit_err(errors::InherentPrimitiveTy { span, note })); } } @@ -118,11 +133,12 @@ impl<'tcx> InherentCollect<'tcx> { } else { bug!("unexpected primitive type: {:?}", ty); } + Ok(()) } - fn check_item(&mut self, id: hir::ItemId) { + fn check_item(&mut self, id: hir::ItemId) -> Result<(), ErrorGuaranteed> { if !matches!(self.tcx.def_kind(id.owner_id), DefKind::Impl { of_trait: false }) { - return; + return Ok(()); } let id = id.owner_id.def_id; @@ -132,10 +148,10 @@ impl<'tcx> InherentCollect<'tcx> { ty::Adt(def, _) => self.check_def_id(id, self_ty, def.did()), ty::Foreign(did) => self.check_def_id(id, self_ty, did), ty::Dynamic(data, ..) if data.principal_def_id().is_some() => { - self.check_def_id(id, self_ty, data.principal_def_id().unwrap()); + self.check_def_id(id, self_ty, data.principal_def_id().unwrap()) } ty::Dynamic(..) => { - self.tcx.dcx().emit_err(errors::InherentDyn { span: item_span }); + Err(self.tcx.dcx().emit_err(errors::InherentDyn { span: item_span })) } ty::Bool | ty::Char @@ -151,7 +167,7 @@ impl<'tcx> InherentCollect<'tcx> { | ty::FnPtr(_) | ty::Tuple(..) => self.check_primitive_impl(id, self_ty), ty::Alias(..) | ty::Param(_) => { - self.tcx.dcx().emit_err(errors::InherentNominal { span: item_span }); + Err(self.tcx.dcx().emit_err(errors::InherentNominal { span: item_span })) } ty::FnDef(..) | ty::Closure(..) @@ -162,7 +178,8 @@ impl<'tcx> InherentCollect<'tcx> { | ty::Infer(_) => { bug!("unexpected impl self type of impl: {:?} {:?}", id, self_ty); } - ty::Error(_) => {} + // We could bail out here, but that will silence other useful errors. + ty::Error(_) => Ok(()), } } } diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs index d66f073b1b4c0..63ea02720145e 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs @@ -168,7 +168,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> { return Ok(()); } - let impls = self.tcx.inherent_impls(id.owner_id); + let impls = self.tcx.inherent_impls(id.owner_id)?; let overlap_mode = OverlapMode::get(self.tcx, id.owner_id.to_def_id()); diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index da9a97db9a4b4..08956d222d2ad 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -181,10 +181,9 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { for &trait_def_id in tcx.all_local_trait_impls(()).keys() { tcx.ensure().coherent_trait(trait_def_id); } - - // these queries are executed for side-effects (error reporting): - tcx.ensure().crate_inherent_impls(()); })) + // these queries are executed for side-effects (error reporting): + .and(tcx.ensure().crate_inherent_impls(())) .and(tcx.ensure().crate_inherent_impls_overlap_check(())) })?; diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index ac8701a33d44e..065052d9a5d27 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2104,7 +2104,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut items = self .tcx .inherent_impls(def_id) - .iter() + .into_iter() + .flatten() .flat_map(|i| self.tcx.associated_items(i).in_definition_order()) // Only assoc fn with no receivers. .filter(|item| { diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 10c31d8c641c7..4dc802008d032 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -711,14 +711,14 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsCandidateKey) else { bug!("unexpected incoherent type: {:?}", self_ty) }; - for &impl_def_id in self.tcx.incoherent_impls(simp) { + for &impl_def_id in self.tcx.incoherent_impls(simp).into_iter().flatten() { self.assemble_inherent_impl_probe(impl_def_id); } } fn assemble_inherent_impl_candidates_for_type(&mut self, def_id: DefId) { - let impl_def_ids = self.tcx.at(self.span).inherent_impls(def_id); - for &impl_def_id in impl_def_ids.iter() { + let impl_def_ids = self.tcx.at(self.span).inherent_impls(def_id).into_iter().flatten(); + for &impl_def_id in impl_def_ids { self.assemble_inherent_impl_probe(impl_def_id); } } diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 3bf1e1312b318..0b8a25eedafad 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -359,7 +359,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let ty::Adt(adt_def, _) = ty.kind() { self.tcx .inherent_impls(adt_def.did()) - .iter() + .into_iter() + .flatten() .any(|def_id| self.associated_value(*def_id, item_name).is_some()) } else { false @@ -1048,7 +1049,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut inherent_impls_candidate = self .tcx .inherent_impls(adt.did()) - .iter() + .into_iter() + .flatten() .copied() .filter(|def_id| { if let Some(assoc) = self.associated_value(*def_id, item_name) { @@ -1103,7 +1105,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "the {item_kind} was found for\n{type_candidates}{additional_types}" )); } else { - 'outer: for inherent_impl_did in self.tcx.inherent_impls(adt.did()) { + 'outer: for inherent_impl_did in + self.tcx.inherent_impls(adt.did()).into_iter().flatten() + { for inherent_method in self.tcx.associated_items(inherent_impl_did).in_definition_order() { @@ -1457,9 +1461,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty::Adt(adt_def, _) = rcvr_ty.kind() else { return; }; - let mut items = self - .tcx - .inherent_impls(adt_def.did()) + // FIXME(oli-obk): try out bubbling this error up one level and cancelling the other error in that case. + let Ok(impls) = self.tcx.inherent_impls(adt_def.did()) else { return }; + let mut items = impls .iter() .flat_map(|i| self.tcx.associated_items(i).in_definition_order()) // Only assoc fn with no receivers. @@ -1823,7 +1827,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { simplify_type(tcx, ty, TreatParams::AsCandidateKey) .and_then(|simp| { tcx.incoherent_impls(simp) - .iter() + .into_iter() + .flatten() .find_map(|&id| self.associated_value(id, item_name)) }) .is_some() diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 912c2f36eb3c8..c3d6c21c4027d 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -283,7 +283,7 @@ provide! { tcx, def_id, other, cdata, tcx.arena.alloc_from_iter(cdata.get_associated_item_or_field_def_ids(def_id.index)) } associated_item => { cdata.get_associated_item(def_id.index, tcx.sess) } - inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) } + inherent_impls => { Ok(cdata.get_inherent_implementations_for_type(tcx, def_id.index)) } item_attrs => { tcx.arena.alloc_from_iter(cdata.get_item_attrs(def_id.index, tcx.sess)) } is_mir_available => { cdata.is_item_mir_available(def_id.index) } is_ctfe_mir_available => { cdata.is_ctfe_mir_available(def_id.index) } @@ -328,7 +328,7 @@ provide! { tcx, def_id, other, cdata, traits => { tcx.arena.alloc_from_iter(cdata.get_traits()) } trait_impls_in_crate => { tcx.arena.alloc_from_iter(cdata.get_trait_impls()) } implementations_of_trait => { cdata.get_implementations_of_trait(tcx, other) } - crate_incoherent_impls => { cdata.get_incoherent_impls(tcx, other) } + crate_incoherent_impls => { Ok(cdata.get_incoherent_impls(tcx, other)) } dep_kind => { cdata.dep_kind } module_children => { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index a458b528a97cb..2d4e49e27d9b9 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1485,7 +1485,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } let inherent_impls = tcx.with_stable_hashing_context(|hcx| { - tcx.crate_inherent_impls(()).inherent_impls.to_sorted(&hcx, true) + tcx.crate_inherent_impls(()).unwrap().inherent_impls.to_sorted(&hcx, true) }); for (def_id, impls) in inherent_impls { record_defaulted_array!(self.tables.inherent_impls[def_id.to_def_id()] <- impls.iter().map(|def_id| { @@ -2028,7 +2028,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { empty_proc_macro!(self); let tcx = self.tcx; let all_impls = tcx.with_stable_hashing_context(|hcx| { - tcx.crate_inherent_impls(()).incoherent_impls.to_sorted(&hcx, true) + tcx.crate_inherent_impls(()).unwrap().incoherent_impls.to_sorted(&hcx, true) }); let all_impls: Vec<_> = all_impls diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 8a4fd01437f91..e745913fabc37 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -114,6 +114,7 @@ macro_rules! arena_types { [] mod_child: rustc_middle::metadata::ModChild, [] features: rustc_feature::Features, [decode] specialization_graph: rustc_middle::traits::specialization_graph::Graph, + [] crate_inherent_impls: rustc_middle::ty::CrateInherentImpls, ]); ) } diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index b9200f1abf161..a49825bdd708d 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -78,6 +78,10 @@ impl EraseType for Result<&'_ T, rustc_errors::ErrorGuaranteed> { type Result = [u8; size_of::>()]; } +impl EraseType for Result<&'_ [T], rustc_errors::ErrorGuaranteed> { + type Result = [u8; size_of::>()]; +} + impl EraseType for Result<&'_ T, traits::CodegenObligationError> { type Result = [u8; size_of::>()]; } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 15f0dc0208d5e..b3aa02e1aa38f 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -859,13 +859,13 @@ rustc_queries! { /// Maps a `DefId` of a type to a list of its inherent impls. /// Contains implementations of methods that are inherent to a type. /// Methods in these implementations don't need to be exported. - query inherent_impls(key: DefId) -> &'tcx [DefId] { + query inherent_impls(key: DefId) -> Result<&'tcx [DefId], ErrorGuaranteed> { desc { |tcx| "collecting inherent impls for `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern } - query incoherent_impls(key: SimplifiedType) -> &'tcx [DefId] { + query incoherent_impls(key: SimplifiedType) -> Result<&'tcx [DefId], ErrorGuaranteed> { desc { |tcx| "collecting all inherent impls for `{:?}`", key } } @@ -1012,9 +1012,9 @@ rustc_queries! { /// Gets a complete map from all types to their inherent impls. /// Not meant to be used directly outside of coherence. - query crate_inherent_impls(k: ()) -> &'tcx CrateInherentImpls { - arena_cache + query crate_inherent_impls(k: ()) -> Result<&'tcx CrateInherentImpls, ErrorGuaranteed> { desc { "finding all inherent impls defined in crate" } + ensure_forwards_result_if_red } /// Checks all types in the crate for overlap in their inherent impls. Reports errors. @@ -1647,7 +1647,7 @@ rustc_queries! { /// /// Do not call this directly, but instead use the `incoherent_impls` query. /// This query is only used to get the data necessary for that query. - query crate_incoherent_impls(key: (CrateNum, SimplifiedType)) -> &'tcx [DefId] { + query crate_incoherent_impls(key: (CrateNum, SimplifiedType)) -> Result<&'tcx [DefId], ErrorGuaranteed> { desc { |tcx| "collecting all impls for a type in a crate" } separate_provide_extern } diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index a41d4f1ad5897..8d88488e1675d 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -174,7 +174,7 @@ pub fn query_ensure<'tcx, Cache>( } #[inline] -pub fn query_ensure_error_guaranteed<'tcx, Cache>( +pub fn query_ensure_error_guaranteed<'tcx, Cache, T>( tcx: TyCtxt<'tcx>, execute_query: fn(TyCtxt<'tcx>, Span, Cache::Key, QueryMode) -> Option, query_cache: &Cache, @@ -182,14 +182,16 @@ pub fn query_ensure_error_guaranteed<'tcx, Cache>( check_cache: bool, ) -> Result<(), ErrorGuaranteed> where - Cache: QueryCache>>, + Cache: QueryCache>>, + Result: EraseType, { let key = key.into_query_param(); if let Some(res) = try_get_cached(tcx, query_cache, &key) { - super::erase::restore(res) + super::erase::restore(res).map(drop) } else { execute_query(tcx, DUMMY_SP, key, QueryMode::Ensure { check_cache }) .map(super::erase::restore) + .map(|res| res.map(drop)) // Either we actually executed the query, which means we got a full `Result`, // or we can just assume the query succeeded, because it was green in the // incremental cache. If it is green, that means that the previous compilation @@ -205,7 +207,7 @@ macro_rules! query_ensure { query_ensure($($args)*) }; ([(ensure_forwards_result_if_red) $($rest:tt)*]$($args:tt)*) => { - query_ensure_error_guaranteed($($args)*) + query_ensure_error_guaranteed($($args)*).map(|_| ()) }; ([$other:tt $($modifiers:tt)*]$($args:tt)*) => { query_ensure!([$($modifiers)*]$($args)*) @@ -667,5 +669,7 @@ mod sealed { pub use sealed::IntoQueryParam; +use super::erase::EraseType; + #[derive(Copy, Clone, Debug, HashStable)] pub struct CyclePlaceholder(pub ErrorGuaranteed); diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index 227a0753d0429..d85b541d36386 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -254,16 +254,28 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait } /// Query provider for `incoherent_impls`. -pub(super) fn incoherent_impls_provider(tcx: TyCtxt<'_>, simp: SimplifiedType) -> &[DefId] { +pub(super) fn incoherent_impls_provider( + tcx: TyCtxt<'_>, + simp: SimplifiedType, +) -> Result<&[DefId], ErrorGuaranteed> { let mut impls = Vec::new(); + let mut res = Ok(()); for cnum in iter::once(LOCAL_CRATE).chain(tcx.crates(()).iter().copied()) { - for &impl_def_id in tcx.crate_incoherent_impls((cnum, simp)) { + let incoherent_impls = match tcx.crate_incoherent_impls((cnum, simp)) { + Ok(impls) => impls, + Err(e) => { + res = Err(e); + continue; + } + }; + for &impl_def_id in incoherent_impls { impls.push(impl_def_id) } } debug!(?impls); + res?; - tcx.arena.alloc_slice(&impls) + Ok(tcx.arena.alloc_slice(&impls)) } diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 070580860c16a..20e70f87b75e8 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1433,7 +1433,7 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt } fn assoc_fn_of_type<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, fn_ident: Ident) -> Option { - for impl_def_id in tcx.inherent_impls(def_id) { + for impl_def_id in tcx.inherent_impls(def_id).ok()? { if let Some(new) = tcx.associated_items(impl_def_id).find_by_name_and_kind( tcx, fn_ident, diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 58ff4d8c79349..5a95f2083f666 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1745,12 +1745,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { // Doing analysis on local `DefId`s would cause infinite recursion. return; } + let Ok(impls) = self.r.tcx.inherent_impls(def_id) else { return }; // Look at all the associated functions without receivers in the type's // inherent impls to look for builders that return `Self` - let mut items = self - .r - .tcx - .inherent_impls(def_id) + let mut items = impls .iter() .flat_map(|i| self.r.tcx.associated_items(i).in_definition_order()) // Only assoc fn with no receivers. diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 014bcb1a88172..aab974ad79edd 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -312,7 +312,7 @@ pub(crate) fn build_impls( let tcx = cx.tcx; // for each implementation of an item represented by `did`, build the clean::Item for that impl - for &did in tcx.inherent_impls(did).iter() { + for &did in tcx.inherent_impls(did).into_iter().flatten() { build_impl(cx, did, attrs, ret); } @@ -325,7 +325,7 @@ pub(crate) fn build_impls( if tcx.has_attr(did, sym::rustc_has_incoherent_inherent_impls) { let type_ = if tcx.is_trait(did) { SimplifiedType::Trait(did) } else { SimplifiedType::Adt(did) }; - for &did in tcx.incoherent_impls(type_) { + for &did in tcx.incoherent_impls(type_).into_iter().flatten() { build_impl(cx, did, attrs, ret); } } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 90eb783c7caee..6710193f9611a 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1862,7 +1862,7 @@ impl PrimitiveType { .get(self) .into_iter() .flatten() - .flat_map(move |&simp| tcx.incoherent_impls(simp)) + .flat_map(move |&simp| tcx.incoherent_impls(simp).into_iter().flatten()) .copied() } @@ -1870,7 +1870,7 @@ impl PrimitiveType { Self::simplified_types() .values() .flatten() - .flat_map(move |&simp| tcx.incoherent_impls(simp)) + .flat_map(move |&simp| tcx.incoherent_impls(simp).into_iter().flatten()) .copied() } diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index dbff33dc1ecfc..30b3e5c784dc1 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -624,7 +624,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // Checks if item_name belongs to `impl SomeItem` let mut assoc_items: Vec<_> = tcx .inherent_impls(did) - .iter() + .into_iter() + .flatten() .flat_map(|&imp| { filter_assoc_items_by_name_and_namespace( tcx, From 18e66432c40e8c136b5d0fab27137fdabd579ae0 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 12 Jan 2024 16:58:29 +0000 Subject: [PATCH 0336/1197] Fix clippy --- src/tools/clippy/clippy_lints/src/derive.rs | 3 ++- src/tools/clippy/clippy_lints/src/inherent_impl.rs | 3 ++- .../clippy/clippy_lints/src/iter_without_into_iter.rs | 2 +- src/tools/clippy/clippy_lints/src/len_zero.rs | 5 +++-- src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs | 3 ++- src/tools/clippy/clippy_utils/src/lib.rs | 8 +++++--- 6 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs index d8abe411030b6..d1fe9f5cbece7 100644 --- a/src/tools/clippy/clippy_lints/src/derive.rs +++ b/src/tools/clippy/clippy_lints/src/derive.rs @@ -386,7 +386,8 @@ fn check_unsafe_derive_deserialize<'tcx>( && cx .tcx .inherent_impls(def.did()) - .iter() + .into_iter() + .flatten() .map(|imp_did| cx.tcx.hir().expect_item(imp_did.expect_local())) .any(|imp| has_unsafe(cx, imp)) { diff --git a/src/tools/clippy/clippy_lints/src/inherent_impl.rs b/src/tools/clippy/clippy_lints/src/inherent_impl.rs index e4781752e757b..fb7b82ec304ef 100644 --- a/src/tools/clippy/clippy_lints/src/inherent_impl.rs +++ b/src/tools/clippy/clippy_lints/src/inherent_impl.rs @@ -53,9 +53,10 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl { // List of spans to lint. (lint_span, first_span) let mut lint_spans = Vec::new(); + let Ok(impls) = cx.tcx.crate_inherent_impls(()) else { return }; let inherent_impls = cx .tcx - .with_stable_hashing_context(|hcx| cx.tcx.crate_inherent_impls(()).inherent_impls.to_sorted(&hcx, true)); + .with_stable_hashing_context(|hcx| impls.inherent_impls.to_sorted(&hcx, true)); for (_, impl_ids) in inherent_impls.into_iter().filter(|(&id, impls)| { impls.len() > 1 diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs index 903d3a2ab8960..82a37bb4f278a 100644 --- a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs +++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs @@ -139,7 +139,7 @@ fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl Iter fn adt_has_inherent_method(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> bool { if let Some(ty_did) = ty.ty_adt_def().map(ty::AdtDef::did) { - cx.tcx.inherent_impls(ty_did).iter().any(|&did| { + cx.tcx.inherent_impls(ty_did).into_iter().flatten().any(|&did| { cx.tcx .associated_items(did) .filter_by_name_unhygienic(method_name) diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index c09d3d1862b0c..c1ab020117ca6 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -441,7 +441,8 @@ fn check_for_is_empty( let is_empty = cx .tcx .inherent_impls(impl_ty) - .iter() + .into_iter() + .flatten() .flat_map(|&id| cx.tcx.associated_items(id).filter_by_name_unhygienic(is_empty)) .find(|item| item.kind == AssocKind::Fn); @@ -605,7 +606,7 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { /// Checks the inherent impl's items for an `is_empty(self)` method. fn has_is_empty_impl(cx: &LateContext<'_>, id: DefId) -> bool { let is_empty = sym!(is_empty); - cx.tcx.inherent_impls(id).iter().any(|imp| { + cx.tcx.inherent_impls(id).into_iter().flatten().any(|imp| { cx.tcx .associated_items(*imp) .filter_by_name_unhygienic(is_empty) diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs index e38c66f6741d2..0602eeaa70417 100644 --- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs +++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs @@ -73,7 +73,8 @@ pub(super) fn check<'tcx>( let has_suggested_method = receiver_ty.ty_adt_def().is_some_and(|adt_def| { cx.tcx .inherent_impls(adt_def.did()) - .iter() + .into_iter() + .flatten() .flat_map(|impl_id| cx.tcx.associated_items(impl_id).filter_by_name_unhygienic(sugg)) .any(|assoc| { assoc.fn_has_self_parameter diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index cdf8528f48a27..1a4b22799f2ab 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -534,10 +534,11 @@ fn find_primitive_impls<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator SimplifiedType::Uint(UintTy::U128), "f32" => SimplifiedType::Float(FloatTy::F32), "f64" => SimplifiedType::Float(FloatTy::F64), - _ => return [].iter().copied(), + #[allow(trivial_casts)] + _ => return Result::<_, rustc_errors::ErrorGuaranteed>::Ok(&[] as &[_]).into_iter().flatten().copied(), }; - tcx.incoherent_impls(ty).iter().copied() + tcx.incoherent_impls(ty).into_iter().flatten().copied() } fn non_local_item_children_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec { @@ -663,7 +664,8 @@ pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Vec { // `impl S { ... }` let inherent_impl_children = tcx .inherent_impls(def_id) - .iter() + .into_iter() + .flatten() .flat_map(|&impl_def_id| item_children_by_name(tcx, impl_def_id, segment)); let direct_children = item_children_by_name(tcx, def_id, segment); From 4488653ec6e4591ebfc43470cd3718f1f2c4fce2 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 12 Jan 2024 16:58:29 +0000 Subject: [PATCH 0337/1197] Fix clippy --- clippy_lints/src/derive.rs | 3 ++- clippy_lints/src/inherent_impl.rs | 3 ++- clippy_lints/src/iter_without_into_iter.rs | 2 +- clippy_lints/src/len_zero.rs | 5 +++-- clippy_lints/src/methods/or_fun_call.rs | 3 ++- clippy_utils/src/lib.rs | 8 +++++--- 6 files changed, 15 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index d8abe411030b6..d1fe9f5cbece7 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -386,7 +386,8 @@ fn check_unsafe_derive_deserialize<'tcx>( && cx .tcx .inherent_impls(def.did()) - .iter() + .into_iter() + .flatten() .map(|imp_did| cx.tcx.hir().expect_item(imp_did.expect_local())) .any(|imp| has_unsafe(cx, imp)) { diff --git a/clippy_lints/src/inherent_impl.rs b/clippy_lints/src/inherent_impl.rs index e4781752e757b..fb7b82ec304ef 100644 --- a/clippy_lints/src/inherent_impl.rs +++ b/clippy_lints/src/inherent_impl.rs @@ -53,9 +53,10 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl { // List of spans to lint. (lint_span, first_span) let mut lint_spans = Vec::new(); + let Ok(impls) = cx.tcx.crate_inherent_impls(()) else { return }; let inherent_impls = cx .tcx - .with_stable_hashing_context(|hcx| cx.tcx.crate_inherent_impls(()).inherent_impls.to_sorted(&hcx, true)); + .with_stable_hashing_context(|hcx| impls.inherent_impls.to_sorted(&hcx, true)); for (_, impl_ids) in inherent_impls.into_iter().filter(|(&id, impls)| { impls.len() > 1 diff --git a/clippy_lints/src/iter_without_into_iter.rs b/clippy_lints/src/iter_without_into_iter.rs index 903d3a2ab8960..82a37bb4f278a 100644 --- a/clippy_lints/src/iter_without_into_iter.rs +++ b/clippy_lints/src/iter_without_into_iter.rs @@ -139,7 +139,7 @@ fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl Iter fn adt_has_inherent_method(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> bool { if let Some(ty_did) = ty.ty_adt_def().map(ty::AdtDef::did) { - cx.tcx.inherent_impls(ty_did).iter().any(|&did| { + cx.tcx.inherent_impls(ty_did).into_iter().flatten().any(|&did| { cx.tcx .associated_items(did) .filter_by_name_unhygienic(method_name) diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index c09d3d1862b0c..c1ab020117ca6 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -441,7 +441,8 @@ fn check_for_is_empty( let is_empty = cx .tcx .inherent_impls(impl_ty) - .iter() + .into_iter() + .flatten() .flat_map(|&id| cx.tcx.associated_items(id).filter_by_name_unhygienic(is_empty)) .find(|item| item.kind == AssocKind::Fn); @@ -605,7 +606,7 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { /// Checks the inherent impl's items for an `is_empty(self)` method. fn has_is_empty_impl(cx: &LateContext<'_>, id: DefId) -> bool { let is_empty = sym!(is_empty); - cx.tcx.inherent_impls(id).iter().any(|imp| { + cx.tcx.inherent_impls(id).into_iter().flatten().any(|imp| { cx.tcx .associated_items(*imp) .filter_by_name_unhygienic(is_empty) diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index e38c66f6741d2..0602eeaa70417 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -73,7 +73,8 @@ pub(super) fn check<'tcx>( let has_suggested_method = receiver_ty.ty_adt_def().is_some_and(|adt_def| { cx.tcx .inherent_impls(adt_def.did()) - .iter() + .into_iter() + .flatten() .flat_map(|impl_id| cx.tcx.associated_items(impl_id).filter_by_name_unhygienic(sugg)) .any(|assoc| { assoc.fn_has_self_parameter diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index cdf8528f48a27..1a4b22799f2ab 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -534,10 +534,11 @@ fn find_primitive_impls<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator SimplifiedType::Uint(UintTy::U128), "f32" => SimplifiedType::Float(FloatTy::F32), "f64" => SimplifiedType::Float(FloatTy::F64), - _ => return [].iter().copied(), + #[allow(trivial_casts)] + _ => return Result::<_, rustc_errors::ErrorGuaranteed>::Ok(&[] as &[_]).into_iter().flatten().copied(), }; - tcx.incoherent_impls(ty).iter().copied() + tcx.incoherent_impls(ty).into_iter().flatten().copied() } fn non_local_item_children_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec { @@ -663,7 +664,8 @@ pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Vec { // `impl S { ... }` let inherent_impl_children = tcx .inherent_impls(def_id) - .iter() + .into_iter() + .flatten() .flat_map(|&impl_def_id| item_children_by_name(tcx, impl_def_id, segment)); let direct_children = item_children_by_name(tcx, def_id, segment); From 12c19a2bb777a87c10afe1a7ea7fbee00def730d Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 17 Jan 2024 10:38:50 +0000 Subject: [PATCH 0338/1197] target: fix powerpc64-unknown-linux-musl datalayout In LLVM 17, PowerPC targets started including function pointer alignments in data layouts, and in Rust's update to that version (#114048), we added the function pointer alignments. `powerpc64-unknown-linux-musl` had `Fi64` set but this seems incorrect, and the code in LLVM would always have computed `Fn32` because it is a MUSL target. Signed-off-by: David Wood --- .../src/spec/targets/powerpc64_unknown_linux_musl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs index e2e707f4a1ac4..90df3c696846b 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64-unknown-linux-musl".into(), pointer_width: 64, - data_layout: "E-m:e-Fi64-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), + data_layout: "E-m:e-Fn32-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), arch: "powerpc64".into(), options: TargetOptions { endian: Endian::Big, mcount: "_mcount".into(), ..base }, } From 5916da2c29d7e0f12057a44702c12cb40edb38f8 Mon Sep 17 00:00:00 2001 From: Johann Hemmann Date: Mon, 8 Jan 2024 19:40:13 +0100 Subject: [PATCH 0339/1197] Handle `macro_rules!` as MACRO_CALL It's a call of the third token is neither IDENT or TRY --- crates/parser/src/grammar/items.rs | 26 +++++- .../err/0026_macro_rules_as_macro_name.rast | 25 ++++++ .../err/0026_macro_rules_as_macro_name.rs | 2 + .../ok/0208_macro_rules_as_macro_name.rast | 84 +++++++++++++++++++ .../ok/0208_macro_rules_as_macro_name.rs | 7 ++ 5 files changed, 142 insertions(+), 2 deletions(-) create mode 100644 crates/parser/test_data/parser/inline/err/0026_macro_rules_as_macro_name.rast create mode 100644 crates/parser/test_data/parser/inline/err/0026_macro_rules_as_macro_name.rs create mode 100644 crates/parser/test_data/parser/inline/ok/0208_macro_rules_as_macro_name.rast create mode 100644 crates/parser/test_data/parser/inline/ok/0208_macro_rules_as_macro_name.rs diff --git a/crates/parser/src/grammar/items.rs b/crates/parser/src/grammar/items.rs index 34fd3420f1c99..5050cad5e81f2 100644 --- a/crates/parser/src/grammar/items.rs +++ b/crates/parser/src/grammar/items.rs @@ -58,7 +58,21 @@ pub(super) fn item_or_macro(p: &mut Parser<'_>, stop_on_r_curly: bool) { Err(m) => m, }; - if paths::is_use_path_start(p) { + // test macro_rules_as_macro_name + // macro_rules! {} + // macro_rules! {}; + // macro_rules! (); + // macro_rules! []; + // fn main() { + // let foo = macro_rules!(); + // } + + // test_err macro_rules_as_macro_name + // macro_rules! () + // macro_rules! [] + if paths::is_use_path_start(p) + || (p.at_contextual_kw(T![macro_rules]) && p.nth_at(1, BANG) && !p.nth_at(2, IDENT)) + { match macro_call(p) { BlockLike::Block => (), BlockLike::NotBlock => { @@ -228,7 +242,15 @@ fn opt_item_without_modifiers(p: &mut Parser<'_>, m: Marker) -> Result<(), Marke IDENT if p.at_contextual_kw(T![union]) && p.nth(1) == IDENT => adt::union(p, m), T![macro] => macro_def(p, m), - IDENT if p.at_contextual_kw(T![macro_rules]) && p.nth(1) == BANG => macro_rules(p, m), + // check if current token is "macro_rules" followed by "!" followed by an identifier or "try" + // try is keyword since the 2018 edition and the parser is not edition aware (yet!) + IDENT + if p.at_contextual_kw(T![macro_rules]) + && p.nth_at(1, BANG) + && (p.nth_at(2, IDENT) || p.nth_at(2, T![try])) => + { + macro_rules(p, m) + } T![const] if (la == IDENT || la == T![_] || la == T![mut]) => consts::konst(p, m), T![static] if (la == IDENT || la == T![_] || la == T![mut]) => consts::static_(p, m), diff --git a/crates/parser/test_data/parser/inline/err/0026_macro_rules_as_macro_name.rast b/crates/parser/test_data/parser/inline/err/0026_macro_rules_as_macro_name.rast new file mode 100644 index 0000000000000..d5ab611629c50 --- /dev/null +++ b/crates/parser/test_data/parser/inline/err/0026_macro_rules_as_macro_name.rast @@ -0,0 +1,25 @@ +SOURCE_FILE + MACRO_CALL + PATH + PATH_SEGMENT + NAME_REF + IDENT "macro_rules" + BANG "!" + WHITESPACE " " + TOKEN_TREE + L_PAREN "(" + R_PAREN ")" + WHITESPACE "\n" + MACRO_CALL + PATH + PATH_SEGMENT + NAME_REF + IDENT "macro_rules" + BANG "!" + WHITESPACE " " + TOKEN_TREE + L_BRACK "[" + R_BRACK "]" + WHITESPACE "\n" +error 15: expected SEMICOLON +error 31: expected SEMICOLON diff --git a/crates/parser/test_data/parser/inline/err/0026_macro_rules_as_macro_name.rs b/crates/parser/test_data/parser/inline/err/0026_macro_rules_as_macro_name.rs new file mode 100644 index 0000000000000..be633aa6990ef --- /dev/null +++ b/crates/parser/test_data/parser/inline/err/0026_macro_rules_as_macro_name.rs @@ -0,0 +1,2 @@ +macro_rules! () +macro_rules! [] diff --git a/crates/parser/test_data/parser/inline/ok/0208_macro_rules_as_macro_name.rast b/crates/parser/test_data/parser/inline/ok/0208_macro_rules_as_macro_name.rast new file mode 100644 index 0000000000000..c3e0f8a5e02de --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/0208_macro_rules_as_macro_name.rast @@ -0,0 +1,84 @@ +SOURCE_FILE + MACRO_CALL + PATH + PATH_SEGMENT + NAME_REF + IDENT "macro_rules" + BANG "!" + WHITESPACE " " + TOKEN_TREE + L_CURLY "{" + R_CURLY "}" + WHITESPACE "\n" + MACRO_CALL + PATH + PATH_SEGMENT + NAME_REF + IDENT "macro_rules" + BANG "!" + WHITESPACE " " + TOKEN_TREE + L_CURLY "{" + R_CURLY "}" + SEMICOLON ";" + WHITESPACE "\n" + MACRO_CALL + PATH + PATH_SEGMENT + NAME_REF + IDENT "macro_rules" + BANG "!" + WHITESPACE " " + TOKEN_TREE + L_PAREN "(" + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n" + MACRO_CALL + PATH + PATH_SEGMENT + NAME_REF + IDENT "macro_rules" + BANG "!" + WHITESPACE " " + TOKEN_TREE + L_BRACK "[" + R_BRACK "]" + SEMICOLON ";" + WHITESPACE "\n" + FN + FN_KW "fn" + WHITESPACE " " + NAME + IDENT "main" + PARAM_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + LET_STMT + LET_KW "let" + WHITESPACE " " + IDENT_PAT + NAME + IDENT "foo" + WHITESPACE " " + EQ "=" + WHITESPACE " " + MACRO_EXPR + MACRO_CALL + PATH + PATH_SEGMENT + NAME_REF + IDENT "macro_rules" + BANG "!" + TOKEN_TREE + L_PAREN "(" + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n" + R_CURLY "}" + WHITESPACE "\n" diff --git a/crates/parser/test_data/parser/inline/ok/0208_macro_rules_as_macro_name.rs b/crates/parser/test_data/parser/inline/ok/0208_macro_rules_as_macro_name.rs new file mode 100644 index 0000000000000..2ab949b63638a --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/0208_macro_rules_as_macro_name.rs @@ -0,0 +1,7 @@ +macro_rules! {} +macro_rules! {}; +macro_rules! (); +macro_rules! []; +fn main() { + let foo = macro_rules!(); +} From 341f0a1390e2549359f5c83d72674a84c69fe3d8 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 17 Jan 2024 14:33:24 +0300 Subject: [PATCH 0340/1197] revert temporary patch #108288 Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/compile.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 190f0fe3cddcf..a6a5af22d2520 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1678,13 +1678,6 @@ impl Step for Assemble { // when not performing a full bootstrap). builder.ensure(Rustc::new(build_compiler, target_compiler.host)); - // FIXME: For now patch over problems noted in #90244 by early returning here, even though - // we've not properly assembled the target sysroot. A full fix is pending further investigation, - // for now full bootstrap usage is rare enough that this is OK. - if target_compiler.stage >= 3 && !builder.config.full_bootstrap { - return target_compiler; - } - for &backend in builder.config.rust_codegen_backends.iter() { if backend == "llvm" { continue; // Already built as part of rustc From 76c67dd2291a662b40b9867c0f6bb564e5783889 Mon Sep 17 00:00:00 2001 From: Johann Hemmann Date: Wed, 17 Jan 2024 12:24:18 +0100 Subject: [PATCH 0341/1197] Fix test --- crates/parser/src/grammar/items.rs | 2 +- .../err/0026_macro_rules_as_macro_name.rast | 18 ++++++++++++++++-- .../err/0026_macro_rules_as_macro_name.rs | 1 + .../ok/0208_macro_rules_as_macro_name.rast | 12 ------------ .../ok/0208_macro_rules_as_macro_name.rs | 1 - 5 files changed, 18 insertions(+), 16 deletions(-) diff --git a/crates/parser/src/grammar/items.rs b/crates/parser/src/grammar/items.rs index 5050cad5e81f2..7934761705540 100644 --- a/crates/parser/src/grammar/items.rs +++ b/crates/parser/src/grammar/items.rs @@ -60,7 +60,6 @@ pub(super) fn item_or_macro(p: &mut Parser<'_>, stop_on_r_curly: bool) { // test macro_rules_as_macro_name // macro_rules! {} - // macro_rules! {}; // macro_rules! (); // macro_rules! []; // fn main() { @@ -68,6 +67,7 @@ pub(super) fn item_or_macro(p: &mut Parser<'_>, stop_on_r_curly: bool) { // } // test_err macro_rules_as_macro_name + // macro_rules! {}; // macro_rules! () // macro_rules! [] if paths::is_use_path_start(p) diff --git a/crates/parser/test_data/parser/inline/err/0026_macro_rules_as_macro_name.rast b/crates/parser/test_data/parser/inline/err/0026_macro_rules_as_macro_name.rast index d5ab611629c50..79d428a41c875 100644 --- a/crates/parser/test_data/parser/inline/err/0026_macro_rules_as_macro_name.rast +++ b/crates/parser/test_data/parser/inline/err/0026_macro_rules_as_macro_name.rast @@ -1,4 +1,17 @@ SOURCE_FILE + MACRO_CALL + PATH + PATH_SEGMENT + NAME_REF + IDENT "macro_rules" + BANG "!" + WHITESPACE " " + TOKEN_TREE + L_CURLY "{" + R_CURLY "}" + ERROR + SEMICOLON ";" + WHITESPACE "\n" MACRO_CALL PATH PATH_SEGMENT @@ -21,5 +34,6 @@ SOURCE_FILE L_BRACK "[" R_BRACK "]" WHITESPACE "\n" -error 15: expected SEMICOLON -error 31: expected SEMICOLON +error 15: expected an item +error 32: expected SEMICOLON +error 48: expected SEMICOLON diff --git a/crates/parser/test_data/parser/inline/err/0026_macro_rules_as_macro_name.rs b/crates/parser/test_data/parser/inline/err/0026_macro_rules_as_macro_name.rs index be633aa6990ef..e8d402443d60a 100644 --- a/crates/parser/test_data/parser/inline/err/0026_macro_rules_as_macro_name.rs +++ b/crates/parser/test_data/parser/inline/err/0026_macro_rules_as_macro_name.rs @@ -1,2 +1,3 @@ +macro_rules! {}; macro_rules! () macro_rules! [] diff --git a/crates/parser/test_data/parser/inline/ok/0208_macro_rules_as_macro_name.rast b/crates/parser/test_data/parser/inline/ok/0208_macro_rules_as_macro_name.rast index c3e0f8a5e02de..b997250ab4d27 100644 --- a/crates/parser/test_data/parser/inline/ok/0208_macro_rules_as_macro_name.rast +++ b/crates/parser/test_data/parser/inline/ok/0208_macro_rules_as_macro_name.rast @@ -10,18 +10,6 @@ SOURCE_FILE L_CURLY "{" R_CURLY "}" WHITESPACE "\n" - MACRO_CALL - PATH - PATH_SEGMENT - NAME_REF - IDENT "macro_rules" - BANG "!" - WHITESPACE " " - TOKEN_TREE - L_CURLY "{" - R_CURLY "}" - SEMICOLON ";" - WHITESPACE "\n" MACRO_CALL PATH PATH_SEGMENT diff --git a/crates/parser/test_data/parser/inline/ok/0208_macro_rules_as_macro_name.rs b/crates/parser/test_data/parser/inline/ok/0208_macro_rules_as_macro_name.rs index 2ab949b63638a..4c2ea378cbf93 100644 --- a/crates/parser/test_data/parser/inline/ok/0208_macro_rules_as_macro_name.rs +++ b/crates/parser/test_data/parser/inline/ok/0208_macro_rules_as_macro_name.rs @@ -1,5 +1,4 @@ macro_rules! {} -macro_rules! {}; macro_rules! (); macro_rules! []; fn main() { From 0bdbf497b64600ab5a852b88d220e632203d9e77 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 17 Jan 2024 13:23:00 +0100 Subject: [PATCH 0342/1197] fix: Fix progress reporting getting stuck --- crates/ide/src/hover/render.rs | 66 +++++++++++++++++++++------ crates/ide/src/hover/tests.rs | 6 +-- crates/load-cargo/src/lib.rs | 2 +- crates/rust-analyzer/src/main_loop.rs | 16 +++---- crates/vfs-notify/src/lib.rs | 6 +-- crates/vfs/src/loader.rs | 2 +- 6 files changed, 66 insertions(+), 32 deletions(-) diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index 787b74fc62c59..5a517522663d4 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -497,7 +497,7 @@ fn render_notable_trait_comment( let mut needs_impl_header = true; for (trait_, assoc_types) in notable_traits { desc.push_str(if mem::take(&mut needs_impl_header) { - " // notable traits implemented: " + " // Implements notable traits: " } else { ", " }); @@ -530,6 +530,7 @@ fn type_info( if let Some(res) = closure_ty(sema, config, &ty) { return Some(res); }; + let db = sema.db; let TypeInfo { original, adjusted } = ty; let mut res = HoverResult::default(); let mut targets: Vec = Vec::new(); @@ -538,29 +539,64 @@ fn type_info( targets.push(item); } }; - walk_and_push_ty(sema.db, &original, &mut push_new_def); - let mut desc = match render_notable_trait_comment(sema.db, ¬able_traits(sema.db, &original)) - { - Some(desc) => desc + "\n", - None => String::new(), - }; - desc += &if let Some(adjusted_ty) = adjusted { - walk_and_push_ty(sema.db, &adjusted_ty, &mut push_new_def); - let original = original.display(sema.db).to_string(); - let adjusted = adjusted_ty.display(sema.db).to_string(); + walk_and_push_ty(db, &original, &mut push_new_def); + + res.markup = if let Some(adjusted_ty) = adjusted { + walk_and_push_ty(db, &adjusted_ty, &mut push_new_def); + + let notable = { + let mut desc = String::new(); + let mut needs_impl_header = true; + for (trait_, assoc_types) in notable_traits(db, &original) { + desc.push_str(if mem::take(&mut needs_impl_header) { + "Implements Notable Traits: " + } else { + ", " + }); + format_to!(desc, "{}", trait_.name(db).display(db),); + if !assoc_types.is_empty() { + desc.push('<'); + format_to!( + desc, + "{}", + assoc_types.into_iter().format_with(", ", |(ty, name), f| { + f(&name.display(db))?; + f(&" = ")?; + match ty { + Some(ty) => f(&ty.display(db)), + None => f(&"?"), + } + }) + ); + desc.push('>'); + } + } + if !desc.is_empty() { + desc.push('\n'); + } + desc + }; + + let original = original.display(db).to_string(); + let adjusted = adjusted_ty.display(db).to_string(); let static_text_diff_len = "Coerced to: ".len() - "Type: ".len(); format!( - "```text\nType: {:>apad$}\nCoerced to: {:>opad$}\n```\n", + "```text\nType: {:>apad$}\nCoerced to: {:>opad$}\n{notable}```\n", original, adjusted, apad = static_text_diff_len + adjusted.len().max(original.len()), opad = original.len(), ) + .into() } else { - Markup::fenced_block(&original.display(sema.db)).into() + let mut desc = match render_notable_trait_comment(db, ¬able_traits(db, &original)) { + Some(desc) => desc + "\n", + None => String::new(), + }; + format_to!(desc, "{}", original.display(db)); + Markup::fenced_block(&desc) }; - res.markup = desc.into(); - if let Some(actions) = HoverAction::goto_type_from_targets(sema.db, targets) { + if let Some(actions) = HoverAction::goto_type_from_targets(db, targets) { res.actions.push(actions); } Some(res) diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index d8d439c0d2bed..348308d7100ad 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -7094,7 +7094,7 @@ fn main(notable$0: u32) {} *notable* ```rust - // notable traits implemented: Notable + // Implements notable traits: Notable // size = 4, align = 4 notable: u32 ``` @@ -7126,7 +7126,7 @@ impl Iterator for S { ``` ```rust - // notable traits implemented: Notable, Future, Iterator + // Implements notable traits: Notable, Future, Iterator // size = 0, align = 1 struct S ``` @@ -7154,8 +7154,8 @@ fn main() { } "#, expect![[r#" - // notable traits implemented: Notable, Future, Iterator ```rust + // Implements notable traits: Notable, Future, Iterator S ```"#]], ); diff --git a/crates/load-cargo/src/lib.rs b/crates/load-cargo/src/lib.rs index 8f02f20ad1b94..6c65e6a04fc16 100644 --- a/crates/load-cargo/src/lib.rs +++ b/crates/load-cargo/src/lib.rs @@ -318,7 +318,7 @@ fn load_crate_graph( for task in receiver { match task { vfs::loader::Message::Progress { n_done, n_total, .. } => { - if n_done == n_total { + if n_done == Some(n_total) { break; } } diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index b2cec1554cfca..6a073307c0d38 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -589,19 +589,17 @@ impl GlobalState { vfs::loader::Message::Progress { n_total, n_done, dir, config_version } => { always!(config_version <= self.vfs_config_version); + let state = match n_done { + None => Progress::Begin, + Some(done) if done == n_total => Progress::End, + Some(_) => Progress::Report, + }; + let n_done = n_done.unwrap_or_default(); + self.vfs_progress_config_version = config_version; self.vfs_progress_n_total = n_total; self.vfs_progress_n_done = n_done; - let state = if n_done == 0 { - Progress::Begin - } else if n_done < n_total { - Progress::Report - } else { - assert_eq!(n_done, n_total); - Progress::End - }; - let mut message = format!("{n_done}/{n_total}"); if let Some(dir) = dir { message += &format!( diff --git a/crates/vfs-notify/src/lib.rs b/crates/vfs-notify/src/lib.rs index 00df1377c7275..15a0ea5409a15 100644 --- a/crates/vfs-notify/src/lib.rs +++ b/crates/vfs-notify/src/lib.rs @@ -105,7 +105,7 @@ impl NotifyActor { let n_total = config.load.len(); self.send(loader::Message::Progress { n_total, - n_done: 0, + n_done: None, config_version, dir: None, }); @@ -120,14 +120,14 @@ impl NotifyActor { let files = self.load_entry(entry, watch, |file| loader::Message::Progress { n_total, - n_done: i, + n_done: Some(i), dir: Some(file), config_version, }); self.send(loader::Message::Loaded { files }); self.send(loader::Message::Progress { n_total, - n_done: i + 1, + n_done: Some(i + 1), config_version, dir: None, }); diff --git a/crates/vfs/src/loader.rs b/crates/vfs/src/loader.rs index cdc94751df453..e49849d230776 100644 --- a/crates/vfs/src/loader.rs +++ b/crates/vfs/src/loader.rs @@ -52,7 +52,7 @@ pub enum Message { /// The total files to be loaded. n_total: usize, /// The files that have been loaded successfully. - n_done: usize, + n_done: Option, /// The dir being loaded, `None` if its for a file. dir: Option, /// The [`Config`] version. From 83591268ab03217a7f01462e5f9b35a3d6e0e749 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 17 Jan 2024 13:43:18 +0100 Subject: [PATCH 0343/1197] minor: Make use of some new `SmolStr` improvements --- crates/hir-expand/src/name.rs | 22 +++++++++---------- crates/hir-expand/src/quote.rs | 9 ++++---- crates/hir/src/lib.rs | 6 ++--- crates/ide-completion/src/completions.rs | 8 +++++-- crates/ide-completion/src/completions/dot.rs | 8 +++++-- .../src/completions/extern_abi.rs | 5 +++-- .../src/completions/item_list/trait_impl.rs | 12 +++++----- .../ide-completion/src/completions/record.rs | 18 +++++++++++---- crates/ide-completion/src/completions/use_.rs | 4 ++-- crates/ide-completion/src/item.rs | 14 ++++++------ crates/ide-completion/src/render.rs | 4 ++-- crates/ide-completion/src/render/function.rs | 9 ++++---- crates/ide-completion/src/render/macro_.rs | 4 ++-- crates/ide/src/inlay_hints/discriminant.rs | 2 +- crates/ide/src/inlay_hints/fn_lifetime_fn.rs | 4 ++-- crates/ide/src/navigation_target.rs | 4 ++-- crates/mbe/src/expander/transcriber.rs | 6 ++--- crates/syntax/src/lib.rs | 2 +- 18 files changed, 80 insertions(+), 61 deletions(-) diff --git a/crates/hir-expand/src/name.rs b/crates/hir-expand/src/name.rs index 3d8d01e25566c..91c362399e773 100644 --- a/crates/hir-expand/src/name.rs +++ b/crates/hir-expand/src/name.rs @@ -2,7 +2,7 @@ use std::fmt; -use syntax::{ast, utils::is_raw_identifier, SmolStr}; +use syntax::{ast, format_smolstr, utils::is_raw_identifier, SmolStr}; /// `Name` is a wrapper around string, which is used in hir for both references /// and declarations. In theory, names should also carry hygiene info, but we are @@ -69,8 +69,8 @@ impl Name { } /// Shortcut to create inline plain text name. Panics if `text.len() > 22` - const fn new_inline(text: &str) -> Name { - Name::new_text(SmolStr::new_inline(text)) + const fn new_static(text: &'static str) -> Name { + Name::new_text(SmolStr::new_static(text)) } /// Resolve a name from the text of token. @@ -83,7 +83,7 @@ impl Name { // Rust, e.g. "try" in Rust 2015. Even in such cases, we keep track of them in their // escaped form. None if is_raw_identifier(raw_text) => { - Name::new_text(SmolStr::from_iter(["r#", raw_text])) + Name::new_text(format_smolstr!("r#{}", raw_text)) } _ => Name::new_text(raw_text.into()), } @@ -99,7 +99,7 @@ impl Name { /// name is equal only to itself. It's not clear how to implement this in /// salsa though, so we punt on that bit for a moment. pub const fn missing() -> Name { - Name::new_inline("[missing name]") + Name::new_static("[missing name]") } /// Returns true if this is a fake name for things missing in the source code. See @@ -119,7 +119,7 @@ impl Name { use std::sync::atomic::{AtomicUsize, Ordering}; static CNT: AtomicUsize = AtomicUsize::new(0); let c = CNT.fetch_add(1, Ordering::Relaxed); - Name::new_text(format!("{c}").into()) + Name::new_text(format_smolstr!("{c}")) } /// Returns the tuple index this name represents if it is a tuple field. @@ -260,7 +260,7 @@ pub mod known { $( #[allow(bad_style)] pub const $ident: super::Name = - super::Name::new_inline(stringify!($ident)); + super::Name::new_static(stringify!($ident)); )* }; } @@ -471,11 +471,11 @@ pub mod known { ); // self/Self cannot be used as an identifier - pub const SELF_PARAM: super::Name = super::Name::new_inline("self"); - pub const SELF_TYPE: super::Name = super::Name::new_inline("Self"); + pub const SELF_PARAM: super::Name = super::Name::new_static("self"); + pub const SELF_TYPE: super::Name = super::Name::new_static("Self"); - pub const STATIC_LIFETIME: super::Name = super::Name::new_inline("'static"); - pub const DOLLAR_CRATE: super::Name = super::Name::new_inline("$crate"); + pub const STATIC_LIFETIME: super::Name = super::Name::new_static("'static"); + pub const DOLLAR_CRATE: super::Name = super::Name::new_static("$crate"); #[macro_export] macro_rules! name { diff --git a/crates/hir-expand/src/quote.rs b/crates/hir-expand/src/quote.rs index a3b84afd2ae4c..91f8c5a5a557f 100644 --- a/crates/hir-expand/src/quote.rs +++ b/crates/hir-expand/src/quote.rs @@ -1,11 +1,12 @@ //! A simplified version of quote-crate like quasi quote macro use span::Span; +use syntax::format_smolstr; use crate::name::Name; -pub(crate) fn dollar_crate(span: Span) -> tt::Ident { - tt::Ident { text: syntax::SmolStr::new_inline("$crate"), span } +pub(crate) const fn dollar_crate(span: Span) -> tt::Ident { + tt::Ident { text: syntax::SmolStr::new_static("$crate"), span } } // A helper macro quote macro @@ -214,8 +215,8 @@ impl_to_to_tokentrees! { _span: crate::tt::Literal => self { self }; _span: crate::tt::Ident => self { self }; _span: crate::tt::Punct => self { self }; - span: &str => self { crate::tt::Literal{text: format!("\"{}\"", self.escape_default()).into(), span}}; - span: String => self { crate::tt::Literal{text: format!("\"{}\"", self.escape_default()).into(), span}}; + span: &str => self { crate::tt::Literal{text: format_smolstr!("\"{}\"", self.escape_default()), span}}; + span: String => self { crate::tt::Literal{text: format_smolstr!("\"{}\"", self.escape_default()), span}}; span: Name => self { crate::tt::Ident{text: self.to_smol_str(), span}}; } diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 9866393e5408a..392ac56d61501 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -81,7 +81,7 @@ use rustc_hash::FxHashSet; use stdx::{impl_from, never}; use syntax::{ ast::{self, HasAttrs as _, HasName}, - AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, TextRange, T, + format_smolstr, AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, TextRange, T, }; use triomphe::Arc; @@ -4284,9 +4284,9 @@ impl Type { .filter_map(|arg| { // arg can be either a `Ty` or `constant` if let Some(ty) = arg.ty(Interner) { - Some(SmolStr::new(ty.display(db).to_string())) + Some(format_smolstr!("{}", ty.display(db))) } else if let Some(const_) = arg.constant(Interner) { - Some(SmolStr::new_inline(&const_.display(db).to_string())) + Some(format_smolstr!("{}", const_.display(db))) } else { None } diff --git a/crates/ide-completion/src/completions.rs b/crates/ide-completion/src/completions.rs index 7d38c638a8ed5..4d3d0b4d1a6f5 100644 --- a/crates/ide-completion/src/completions.rs +++ b/crates/ide-completion/src/completions.rs @@ -26,7 +26,7 @@ use std::iter; use hir::{known, HasAttrs, ScopeDef, Variant}; use ide_db::{imports::import_assets::LocatedImport, RootDatabase, SymbolKind}; -use syntax::ast; +use syntax::{ast, SmolStr}; use crate::{ context::{ @@ -80,7 +80,11 @@ impl Completions { } pub(crate) fn add_keyword(&mut self, ctx: &CompletionContext<'_>, keyword: &'static str) { - let item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), keyword); + let item = CompletionItem::new( + CompletionItemKind::Keyword, + ctx.source_range(), + SmolStr::new_static(keyword), + ); item.add_to(self, ctx.db); } diff --git a/crates/ide-completion/src/completions/dot.rs b/crates/ide-completion/src/completions/dot.rs index 53a1c8405c2c1..e5fdac327cdb6 100644 --- a/crates/ide-completion/src/completions/dot.rs +++ b/crates/ide-completion/src/completions/dot.rs @@ -1,6 +1,7 @@ //! Completes references after dot (fields and method calls). use ide_db::FxHashSet; +use syntax::SmolStr; use crate::{ context::{CompletionContext, DotAccess, DotAccessKind, ExprCtx, PathCompletionCtx, Qualified}, @@ -20,8 +21,11 @@ pub(crate) fn complete_dot( // Suggest .await syntax for types that implement Future trait if receiver_ty.impls_into_future(ctx.db) { - let mut item = - CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), "await"); + let mut item = CompletionItem::new( + CompletionItemKind::Keyword, + ctx.source_range(), + SmolStr::new_static("await"), + ); item.detail("expr.await"); item.add_to(acc, ctx.db); } diff --git a/crates/ide-completion/src/completions/extern_abi.rs b/crates/ide-completion/src/completions/extern_abi.rs index e411c1c869c55..75017cf66f8db 100644 --- a/crates/ide-completion/src/completions/extern_abi.rs +++ b/crates/ide-completion/src/completions/extern_abi.rs @@ -1,7 +1,7 @@ //! Completes function abi strings. use syntax::{ ast::{self, IsString}, - AstNode, AstToken, + AstNode, AstToken, SmolStr, }; use crate::{ @@ -53,7 +53,8 @@ pub(crate) fn complete_extern_abi( let abi_str = expanded; let source_range = abi_str.text_range_between_quotes()?; for &abi in SUPPORTED_CALLING_CONVENTIONS { - CompletionItem::new(CompletionItemKind::Keyword, source_range, abi).add_to(acc, ctx.db); + CompletionItem::new(CompletionItemKind::Keyword, source_range, SmolStr::new_static(abi)) + .add_to(acc, ctx.db); } Some(()) } diff --git a/crates/ide-completion/src/completions/item_list/trait_impl.rs b/crates/ide-completion/src/completions/item_list/trait_impl.rs index b0e4d8a5acd10..3c4b89ca742ec 100644 --- a/crates/ide-completion/src/completions/item_list/trait_impl.rs +++ b/crates/ide-completion/src/completions/item_list/trait_impl.rs @@ -38,7 +38,7 @@ use ide_db::{ }; use syntax::{ ast::{self, edit_in_place::AttrsOwnerEdit, HasTypeBounds}, - AstNode, SyntaxElement, SyntaxKind, TextRange, T, + format_smolstr, AstNode, SmolStr, SyntaxElement, SyntaxKind, TextRange, T, }; use text_edit::TextEdit; @@ -180,7 +180,7 @@ fn add_function_impl( ) { let fn_name = func.name(ctx.db); - let label = format!( + let label = format_smolstr!( "fn {}({})", fn_name.display(ctx.db), if func.assoc_fn_params(ctx.db).is_empty() { "" } else { ".." } @@ -254,7 +254,7 @@ fn add_type_alias_impl( ) { let alias_name = type_alias.name(ctx.db).unescaped().to_smol_str(); - let label = format!("type {alias_name} ="); + let label = format_smolstr!("type {alias_name} ="); let mut item = CompletionItem::new(SymbolKind::TypeAlias, replacement_range, label); item.lookup_by(format!("type {alias_name}")) @@ -329,7 +329,7 @@ fn add_const_impl( let replacement = format!("{label} "); let mut item = CompletionItem::new(SymbolKind::Const, replacement_range, label); - item.lookup_by(format!("const {const_name}")) + item.lookup_by(format_smolstr!("const {const_name}")) .set_documentation(const_.docs(ctx.db)) .set_relevance(CompletionRelevance { is_item_from_trait: true, @@ -348,7 +348,7 @@ fn add_const_impl( } } -fn make_const_compl_syntax(const_: &ast::Const, needs_whitespace: bool) -> String { +fn make_const_compl_syntax(const_: &ast::Const, needs_whitespace: bool) -> SmolStr { let const_ = if needs_whitespace { insert_whitespace_into_node::insert_ws_into(const_.syntax().clone()) } else { @@ -368,7 +368,7 @@ fn make_const_compl_syntax(const_: &ast::Const, needs_whitespace: bool) -> Strin let syntax = const_.text().slice(range).to_string(); - format!("{} =", syntax.trim_end()) + format_smolstr!("{} =", syntax.trim_end()) } fn function_declaration(node: &ast::Fn, needs_whitespace: bool) -> String { diff --git a/crates/ide-completion/src/completions/record.rs b/crates/ide-completion/src/completions/record.rs index 46213deb0afef..e53d1cc6322eb 100644 --- a/crates/ide-completion/src/completions/record.rs +++ b/crates/ide-completion/src/completions/record.rs @@ -1,6 +1,9 @@ //! Complete fields in record literals and patterns. use ide_db::SymbolKind; -use syntax::ast::{self, Expr}; +use syntax::{ + ast::{self, Expr}, + SmolStr, +}; use crate::{ context::{DotAccess, DotAccessKind, PatternContext}, @@ -66,8 +69,11 @@ pub(crate) fn complete_record_expr_fields( } if dot_prefix { cov_mark::hit!(functional_update_one_dot); - let mut item = - CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), ".."); + let mut item = CompletionItem::new( + CompletionItemKind::Snippet, + ctx.source_range(), + SmolStr::new_static(".."), + ); item.insert_text("."); item.add_to(acc, ctx.db); return; @@ -91,7 +97,11 @@ pub(crate) fn add_default_update( // FIXME: This should make use of scope_def like completions so we get all the other goodies // that is we should handle this like actually completing the default function let completion_text = "..Default::default()"; - let mut item = CompletionItem::new(SymbolKind::Field, ctx.source_range(), completion_text); + let mut item = CompletionItem::new( + SymbolKind::Field, + ctx.source_range(), + SmolStr::new_static(completion_text), + ); let completion_text = completion_text.strip_prefix(ctx.token.text()).unwrap_or(completion_text); item.insert_text(completion_text).set_relevance(CompletionRelevance { diff --git a/crates/ide-completion/src/completions/use_.rs b/crates/ide-completion/src/completions/use_.rs index 81107c1f419d2..27e9d1d6cfe0c 100644 --- a/crates/ide-completion/src/completions/use_.rs +++ b/crates/ide-completion/src/completions/use_.rs @@ -2,7 +2,7 @@ use hir::ScopeDef; use ide_db::{FxHashSet, SymbolKind}; -use syntax::{ast, AstNode}; +use syntax::{ast, format_smolstr, AstNode}; use crate::{ context::{CompletionContext, PathCompletionCtx, Qualified}, @@ -108,7 +108,7 @@ pub(crate) fn complete_use_path( let item = CompletionItem::new( CompletionItemKind::SymbolKind(SymbolKind::Enum), ctx.source_range(), - format!("{}::", e.name(ctx.db).display(ctx.db)), + format_smolstr!("{}::", e.name(ctx.db).display(ctx.db)), ); acc.add(item.build(ctx.db)); } diff --git a/crates/ide-completion/src/item.rs b/crates/ide-completion/src/item.rs index affd9b729646d..5935a6c56327f 100644 --- a/crates/ide-completion/src/item.rs +++ b/crates/ide-completion/src/item.rs @@ -10,7 +10,7 @@ use ide_db::{ use itertools::Itertools; use smallvec::SmallVec; use stdx::{impl_from, never}; -use syntax::{SmolStr, TextRange, TextSize}; +use syntax::{format_smolstr, SmolStr, TextRange, TextSize}; use text_edit::TextEdit; use crate::{ @@ -442,7 +442,7 @@ impl Builder { if !self.doc_aliases.is_empty() { let doc_aliases = self.doc_aliases.iter().join(", "); - label_detail.replace(SmolStr::from(format!(" (alias {doc_aliases})"))); + label_detail.replace(format_smolstr!(" (alias {doc_aliases})")); let lookup_doc_aliases = self .doc_aliases .iter() @@ -459,21 +459,21 @@ impl Builder { // after typing a comma or space. .join(""); if !lookup_doc_aliases.is_empty() { - lookup = SmolStr::from(format!("{lookup}{lookup_doc_aliases}")); + lookup = format_smolstr!("{lookup}{lookup_doc_aliases}"); } } if let [import_edit] = &*self.imports_to_add { // snippets can have multiple imports, but normal completions only have up to one - label_detail.replace(SmolStr::from(format!( + label_detail.replace(format_smolstr!( "{} (use {})", label_detail.as_deref().unwrap_or_default(), import_edit.import_path.display(db) - ))); + )); } else if let Some(trait_name) = self.trait_name { - label_detail.replace(SmolStr::from(format!( + label_detail.replace(format_smolstr!( "{} (as {trait_name})", label_detail.as_deref().unwrap_or_default(), - ))); + )); } let text_edit = match self.text_edit { diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs index 8c0e6694761ed..9f5c011dc39d6 100644 --- a/crates/ide-completion/src/render.rs +++ b/crates/ide-completion/src/render.rs @@ -17,7 +17,7 @@ use ide_db::{ imports::import_assets::LocatedImport, RootDatabase, SnippetCap, SymbolKind, }; -use syntax::{AstNode, SmolStr, SyntaxKind, TextRange}; +use syntax::{format_smolstr, AstNode, SmolStr, SyntaxKind, TextRange}; use text_edit::TextEdit; use crate::{ @@ -202,7 +202,7 @@ fn field_with_receiver( ) -> SmolStr { receiver.map_or_else( || field_name.into(), - |receiver| format!("{}.{field_name}", receiver.display(db)).into(), + |receiver| format_smolstr!("{}.{field_name}", receiver.display(db)), ) } diff --git a/crates/ide-completion/src/render/function.rs b/crates/ide-completion/src/render/function.rs index 6ad84eba33bea..dfe78de1d6ff0 100644 --- a/crates/ide-completion/src/render/function.rs +++ b/crates/ide-completion/src/render/function.rs @@ -4,7 +4,7 @@ use hir::{db::HirDatabase, AsAssocItem, HirDisplay}; use ide_db::{SnippetCap, SymbolKind}; use itertools::Itertools; use stdx::{format_to, to_lower_snake_case}; -use syntax::{AstNode, SmolStr}; +use syntax::{format_smolstr, AstNode, SmolStr}; use crate::{ context::{CompletionContext, DotAccess, DotAccessKind, PathCompletionCtx, PathKind}, @@ -52,13 +52,12 @@ fn render( let (call, escaped_call) = match &func_kind { FuncKind::Method(_, Some(receiver)) => ( - format!( + format_smolstr!( "{}.{}", receiver.unescaped().display(ctx.db()), name.unescaped().display(ctx.db()) - ) - .into(), - format!("{}.{}", receiver.display(ctx.db()), name.display(ctx.db())).into(), + ), + format_smolstr!("{}.{}", receiver.display(ctx.db()), name.display(ctx.db())), ), _ => (name.unescaped().to_smol_str(), name.to_smol_str()), }; diff --git a/crates/ide-completion/src/render/macro_.rs b/crates/ide-completion/src/render/macro_.rs index 68d175c2bd50e..915a245ab6b4c 100644 --- a/crates/ide-completion/src/render/macro_.rs +++ b/crates/ide-completion/src/render/macro_.rs @@ -2,7 +2,7 @@ use hir::HirDisplay; use ide_db::{documentation::Documentation, SymbolKind}; -use syntax::SmolStr; +use syntax::{format_smolstr, SmolStr}; use crate::{ context::{PathCompletionCtx, PathKind, PatternContext}, @@ -94,7 +94,7 @@ fn label( ) -> SmolStr { if needs_bang { if ctx.snippet_cap().is_some() { - SmolStr::from_iter([&*name, "!", bra, "…", ket]) + format_smolstr!("{name}!{bra}…{ket}",) } else { banged_name(name) } diff --git a/crates/ide/src/inlay_hints/discriminant.rs b/crates/ide/src/inlay_hints/discriminant.rs index 26dc6fa8b9c78..06cce147d2a16 100644 --- a/crates/ide/src/inlay_hints/discriminant.rs +++ b/crates/ide/src/inlay_hints/discriminant.rs @@ -74,7 +74,7 @@ fn variant_hints( }, Some(InlayTooltip::String(match &d { Ok(_) => "enum variant discriminant".into(), - Err(e) => format!("{e:?}").into(), + Err(e) => format!("{e:?}"), })), None, ); diff --git a/crates/ide/src/inlay_hints/fn_lifetime_fn.rs b/crates/ide/src/inlay_hints/fn_lifetime_fn.rs index 7b05e32ad86fe..725ec27155f4e 100644 --- a/crates/ide/src/inlay_hints/fn_lifetime_fn.rs +++ b/crates/ide/src/inlay_hints/fn_lifetime_fn.rs @@ -4,11 +4,11 @@ //! ``` use ide_db::{syntax_helpers::node_ext::walk_ty, FxHashMap}; use itertools::Itertools; -use syntax::SmolStr; use syntax::{ ast::{self, AstNode, HasGenericParams, HasName}, SyntaxToken, }; +use syntax::{format_smolstr, SmolStr}; use crate::{InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind, LifetimeElisionHints}; @@ -80,7 +80,7 @@ pub(super) fn hints( let mut gen_idx_name = { let mut gen = (0u8..).map(|idx| match idx { idx if idx < 10 => SmolStr::from_iter(['\'', (idx + 48) as char]), - idx => format!("'{idx}").into(), + idx => format_smolstr!("'{idx}"), }); move || gen.next().unwrap_or_default() }; diff --git a/crates/ide/src/navigation_target.rs b/crates/ide/src/navigation_target.rs index bc0574ca86ed2..9e60989c60a80 100644 --- a/crates/ide/src/navigation_target.rs +++ b/crates/ide/src/navigation_target.rs @@ -17,7 +17,7 @@ use ide_db::{ use stdx::never; use syntax::{ ast::{self, HasName}, - AstNode, SmolStr, SyntaxNode, TextRange, + format_smolstr, AstNode, SmolStr, SyntaxNode, TextRange, }; /// `NavigationTarget` represents an element in the editor's UI which you can @@ -457,7 +457,7 @@ impl TryToNav for hir::Field { |(FileRange { file_id, range: full_range }, focus_range)| { NavigationTarget::from_syntax( file_id, - format!("{}", self.index()).into(), + format_smolstr!("{}", self.index()), focus_range, full_range, SymbolKind::Field, diff --git a/crates/mbe/src/expander/transcriber.rs b/crates/mbe/src/expander/transcriber.rs index 6e79cdaa0b9d0..822b712f1ce1b 100644 --- a/crates/mbe/src/expander/transcriber.rs +++ b/crates/mbe/src/expander/transcriber.rs @@ -96,19 +96,19 @@ impl Bindings { | MetaVarKind::Expr | MetaVarKind::Ident => { Fragment::Tokens(tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: SmolStr::new_inline("missing"), + text: SmolStr::new_static("missing"), span, }))) } MetaVarKind::Lifetime => { Fragment::Tokens(tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: SmolStr::new_inline("'missing"), + text: SmolStr::new_static("'missing"), span, }))) } MetaVarKind::Literal => { Fragment::Tokens(tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: SmolStr::new_inline("\"missing\""), + text: SmolStr::new_static("\"missing\""), span, }))) } diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs index 1b41596a5f27b..21ed1310f56b7 100644 --- a/crates/syntax/src/lib.rs +++ b/crates/syntax/src/lib.rs @@ -70,7 +70,7 @@ pub use rowan::{ api::Preorder, Direction, GreenNode, NodeOrToken, SyntaxText, TextRange, TextSize, TokenAtOffset, WalkEvent, }; -pub use smol_str::SmolStr; +pub use smol_str::{format_smolstr, SmolStr}; /// `Parse` is the result of the parsing: a syntax tree and a collection of /// errors. From d6b99b9c920f3c12326b0e7110236e9fe7c7ba52 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 17 Jan 2024 14:23:41 +0000 Subject: [PATCH 0344/1197] Use FnOnceOutput instead of FnOnce where expected --- compiler/rustc_middle/src/ty/print/pretty.rs | 2 +- .../opaque-used-in-extraneous-argument.rs | 21 +++++ .../opaque-used-in-extraneous-argument.stderr | 78 +++++++++++++++++++ 3 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 tests/ui/impl-trait/opaque-used-in-extraneous-argument.rs create mode 100644 tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 6c9000c45f61b..4028de27cae14 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1013,7 +1013,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { .extend( // Group the return ty with its def id, if we had one. entry.return_ty.map(|ty| { - (tcx.require_lang_item(LangItem::FnOnce, None), ty) + (tcx.require_lang_item(LangItem::FnOnceOutput, None), ty) }), ); } diff --git a/tests/ui/impl-trait/opaque-used-in-extraneous-argument.rs b/tests/ui/impl-trait/opaque-used-in-extraneous-argument.rs new file mode 100644 index 0000000000000..529913479ef4b --- /dev/null +++ b/tests/ui/impl-trait/opaque-used-in-extraneous-argument.rs @@ -0,0 +1,21 @@ +//! This is a regression test to avoid an ICE in diagnostics code. +//! A typo in the compiler used to get the DefId of FnOnce, and +//! use it where an associated item was expected. + +fn frob() -> impl Fn + '_ {} +//~^ ERROR missing lifetime specifier +//~| ERROR cannot find type `P` +//~| ERROR cannot find type `T` +//~| ERROR `Fn`-family traits' type parameters is subject to change + +fn open_parent<'path>() { + todo!() +} + +fn main() { + let old_path = frob("hello"); + //~^ ERROR function takes 0 arguments + + open_parent(&old_path) + //~^ ERROR function takes 0 arguments +} diff --git a/tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr b/tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr new file mode 100644 index 0000000000000..b54b9f908b2a4 --- /dev/null +++ b/tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr @@ -0,0 +1,78 @@ +error[E0106]: missing lifetime specifier + --> $DIR/opaque-used-in-extraneous-argument.rs:5:39 + | +LL | fn frob() -> impl Fn + '_ {} + | ^^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`, or if you will only have owned values + | +LL | fn frob() -> impl Fn + 'static {} + | ~~~~~~~ + +error[E0412]: cannot find type `P` in this scope + --> $DIR/opaque-used-in-extraneous-argument.rs:5:22 + | +LL | fn frob() -> impl Fn + '_ {} + | ^ not found in this scope + | +help: you might be missing a type parameter + | +LL | fn frob