From 8d2beb50c2b228f4bd6f8e2d81d82c9e1f5e5ba2 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 27 Mar 2023 21:22:36 -0500 Subject: [PATCH 01/69] Allow access to `OsStr` bytes `OsStr` has historically kept its implementation details private out of concern for locking us into a specific encoding on Windows. This is an alternative to #95290 which proposed specifying the encoding on Windows. Instead, this only specifies that for cross-platform code, `OsStr`'s encoding is a superset of UTF-8 and defines rules for safely interacting with it At minimum, this can greatly simplify the `os_str_bytes` crate and every arg parser that interacts with `OsStr` directly (which is most of those that support invalid UTF-8). --- library/std/src/ffi/mod.rs | 8 ++++ library/std/src/ffi/os_str.rs | 56 +++++++++++++++++++++++- library/std/src/sys/unix/os_str.rs | 9 +++- library/std/src/sys/unix/os_str/tests.rs | 9 ++-- library/std/src/sys/windows/os_str.rs | 10 +++++ library/std/src/sys_common/wtf8.rs | 8 +++- 6 files changed, 91 insertions(+), 9 deletions(-) diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs index d987bf69b257..3ddb8748753e 100644 --- a/library/std/src/ffi/mod.rs +++ b/library/std/src/ffi/mod.rs @@ -127,6 +127,14 @@ //! trait, which provides a [`from_wide`] method to convert a native Windows //! string (without the terminating nul character) to an [`OsString`]. //! +//! ## On all platforms +//! +//! On all platforms, [`OsStr`] consists of a sequence of bytes that is encoded as a superset of +//! UTF-8; see [`OsString`] for more details on its encoding on different platforms. +//! +//! For limited, inexpensive conversions from and to bytes, see [`OsStr::as_os_str_bytes`] and +//! [`OsStr::from_os_str_bytes_unchecked`]. +//! //! [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value //! [Unicode code point]: https://www.unicode.org/glossary/#code_point //! [`env::set_var()`]: crate::env::set_var "env::set_var" diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 5c0541d3caf3..25ab2196688b 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -667,6 +667,45 @@ impl OsStr { s.as_ref() } + /// Converts a slice of bytes to an OS string slice without checking that the string contains + /// valid `OsStr`-encoded data. + /// + /// See the [module's toplevel documentation about conversions][conversions] for safe, + /// cross-platform [conversions] from/to native representations. + /// + /// # Safety + /// + /// `OsStr`'s encoding is an unspecified superset of UTF-8 and callers must + /// pass in bytes that originated as a mixture of validated UTF-8 and bytes from + /// [`OsStr::as_os_str_bytes`] from within the same rust version built for the same target + /// platform. The bytes from `OsStr::as_os_str_bytes` may be split either + /// immediately before or immediately after some valid non-empty UTF-8 substring + /// + /// # Example + /// + /// ``` + /// #![feature(os_str_bytes)] + /// + /// use std::ffi::OsStr; + /// + /// let os_str = OsStr::new("Mary had a little lamb"); + /// let bytes = os_str.as_os_str_bytes(); + /// let words = bytes.split(|b| *b == b' '); + /// let words: Vec<&OsStr> = words.map(|word| { + /// // SAFETY: + /// // - Each `word` only contains content that originated from `OsStr::as_os_str_bytes` + /// // - Only split with ASCII whitespace which is a non-empty UTF-8 substring + /// unsafe { OsStr::from_os_str_bytes_unchecked(word) } + /// }).collect(); + /// ``` + /// + /// [conversions]: super#conversions + #[inline] + #[unstable(feature = "os_str_bytes", issue = "111544")] + pub fn from_os_str_bytes_unchecked(bytes: &[u8]) -> &Self { + Self::from_inner(Slice::from_os_str_bytes_unchecked(bytes)) + } + #[inline] fn from_inner(inner: &Slice) -> &OsStr { // SAFETY: OsStr is just a wrapper of Slice, @@ -837,13 +876,28 @@ impl OsStr { OsString { inner: Buf::from_box(boxed) } } + /// Converts an OS string slice to a byte slice. To convert the byte slice back into an OS + /// string slice, use the [`OsStr::from_os_str_bytes_unchecked`] function. + /// + /// Note: As the encoding is unspecified, any sub-slice of bytes that is not valid UTF-8 should + /// be treated as opaque and only comparable within the same rust version built for the same + /// target platform. See [`OsString`] for more encoding details and [`std::ffi`] for + /// platform-specific, specified conversions. + /// + /// [`std::ffi`]: crate::ffi + #[inline] + #[unstable(feature = "os_str_bytes", issue = "111544")] + pub fn as_os_str_bytes(&self) -> &[u8] { + self.inner.as_os_str_bytes() + } + /// Gets the underlying byte representation. /// /// Note: it is *crucial* that this API is not externally public, to avoid /// revealing the internal, platform-specific encodings. #[inline] pub(crate) fn bytes(&self) -> &[u8] { - unsafe { &*(&self.inner as *const _ as *const [u8]) } + self.as_os_str_bytes() } /// Converts this string to its ASCII lower case equivalent in-place. diff --git a/library/std/src/sys/unix/os_str.rs b/library/std/src/sys/unix/os_str.rs index 488217f39413..142fcb9ed0b7 100644 --- a/library/std/src/sys/unix/os_str.rs +++ b/library/std/src/sys/unix/os_str.rs @@ -193,13 +193,18 @@ impl Buf { impl Slice { #[inline] - fn from_u8_slice(s: &[u8]) -> &Slice { + pub fn as_os_str_bytes(&self) -> &[u8] { + &self.inner + } + + #[inline] + pub unsafe fn from_os_str_bytes_unchecked(s: &[u8]) -> &Slice { unsafe { mem::transmute(s) } } #[inline] pub fn from_str(s: &str) -> &Slice { - Slice::from_u8_slice(s.as_bytes()) + unsafe { Slice::from_os_str_bytes_unchecked(s.as_bytes()) } } pub fn to_str(&self) -> Option<&str> { diff --git a/library/std/src/sys/unix/os_str/tests.rs b/library/std/src/sys/unix/os_str/tests.rs index 22ba0c923504..91bc0e61a4a5 100644 --- a/library/std/src/sys/unix/os_str/tests.rs +++ b/library/std/src/sys/unix/os_str/tests.rs @@ -2,7 +2,7 @@ use super::*; #[test] fn slice_debug_output() { - let input = Slice::from_u8_slice(b"\xF0hello,\tworld"); + let input = unsafe { Slice::from_os_str_bytes_unchecked(b"\xF0hello,\tworld") }; let expected = r#""\xF0hello,\tworld""#; let output = format!("{input:?}"); @@ -11,8 +11,7 @@ fn slice_debug_output() { #[test] fn display() { - assert_eq!( - "Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye", - Slice::from_u8_slice(b"Hello\xC0\x80 There\xE6\x83 Goodbye").to_string(), - ); + assert_eq!("Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye", unsafe { + Slice::from_os_str_bytes_unchecked(b"Hello\xC0\x80 There\xE6\x83 Goodbye").to_string() + },); } diff --git a/library/std/src/sys/windows/os_str.rs b/library/std/src/sys/windows/os_str.rs index 2f2b0e56e088..611f0d040f0e 100644 --- a/library/std/src/sys/windows/os_str.rs +++ b/library/std/src/sys/windows/os_str.rs @@ -151,6 +151,16 @@ impl Buf { } impl Slice { + #[inline] + pub fn as_os_str_bytes(&self) -> &[u8] { + self.inner.as_bytes() + } + + #[inline] + pub unsafe fn from_os_str_bytes_unchecked(s: &[u8]) -> &Slice { + mem::transmute(Wtf8::from_bytes_unchecked(s)) + } + #[inline] pub fn from_str(s: &str) -> &Slice { unsafe { mem::transmute(Wtf8::from_str(s)) } diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs index ff96c35fb0ba..31bb0ad25a65 100644 --- a/library/std/src/sys_common/wtf8.rs +++ b/library/std/src/sys_common/wtf8.rs @@ -570,7 +570,7 @@ impl Wtf8 { /// Since the byte slice is not checked for valid WTF-8, this functions is /// marked unsafe. #[inline] - unsafe fn from_bytes_unchecked(value: &[u8]) -> &Wtf8 { + pub unsafe fn from_bytes_unchecked(value: &[u8]) -> &Wtf8 { mem::transmute(value) } @@ -614,6 +614,12 @@ impl Wtf8 { Wtf8CodePoints { bytes: self.bytes.iter() } } + /// Access raw bytes of WTF-8 data + #[inline] + pub fn as_bytes(&self) -> &[u8] { + &self.bytes + } + /// Tries to convert the string to UTF-8 and return a `&str` slice. /// /// Returns `None` if the string contains surrogates. From 7f1a6cd421d699aa249a282d7b5b7a8f486e3b01 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Sat, 13 May 2023 18:47:14 +0200 Subject: [PATCH 02/69] refactor: Remove redundant, private OsStr::bytes --- library/std/src/ffi/os_str.rs | 27 +++++++------------ library/std/src/path.rs | 16 +++++------ library/std/src/sys/common/small_c_string.rs | 2 +- library/std/src/sys/common/tests.rs | 4 +-- library/std/src/sys/unix/path.rs | 2 +- .../src/sys/unix/process/process_common.rs | 4 +-- library/std/src/sys/windows/args.rs | 6 +++-- library/std/src/sys/windows/path.rs | 24 ++++++++--------- library/std/src/sys/windows/process.rs | 4 +-- 9 files changed, 41 insertions(+), 48 deletions(-) diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 25ab2196688b..90cbd57a9298 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -702,7 +702,7 @@ impl OsStr { /// [conversions]: super#conversions #[inline] #[unstable(feature = "os_str_bytes", issue = "111544")] - pub fn from_os_str_bytes_unchecked(bytes: &[u8]) -> &Self { + pub unsafe fn from_os_str_bytes_unchecked(bytes: &[u8]) -> &Self { Self::from_inner(Slice::from_os_str_bytes_unchecked(bytes)) } @@ -891,15 +891,6 @@ impl OsStr { self.inner.as_os_str_bytes() } - /// Gets the underlying byte representation. - /// - /// Note: it is *crucial* that this API is not externally public, to avoid - /// revealing the internal, platform-specific encodings. - #[inline] - pub(crate) fn bytes(&self) -> &[u8] { - self.as_os_str_bytes() - } - /// Converts this string to its ASCII lower case equivalent in-place. /// /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', @@ -1185,7 +1176,7 @@ impl Default for &OsStr { impl PartialEq for OsStr { #[inline] fn eq(&self, other: &OsStr) -> bool { - self.bytes().eq(other.bytes()) + self.as_os_str_bytes().eq(other.as_os_str_bytes()) } } @@ -1212,23 +1203,23 @@ impl Eq for OsStr {} impl PartialOrd for OsStr { #[inline] fn partial_cmp(&self, other: &OsStr) -> Option { - self.bytes().partial_cmp(other.bytes()) + self.as_os_str_bytes().partial_cmp(other.as_os_str_bytes()) } #[inline] fn lt(&self, other: &OsStr) -> bool { - self.bytes().lt(other.bytes()) + self.as_os_str_bytes().lt(other.as_os_str_bytes()) } #[inline] fn le(&self, other: &OsStr) -> bool { - self.bytes().le(other.bytes()) + self.as_os_str_bytes().le(other.as_os_str_bytes()) } #[inline] fn gt(&self, other: &OsStr) -> bool { - self.bytes().gt(other.bytes()) + self.as_os_str_bytes().gt(other.as_os_str_bytes()) } #[inline] fn ge(&self, other: &OsStr) -> bool { - self.bytes().ge(other.bytes()) + self.as_os_str_bytes().ge(other.as_os_str_bytes()) } } @@ -1247,7 +1238,7 @@ impl PartialOrd for OsStr { impl Ord for OsStr { #[inline] fn cmp(&self, other: &OsStr) -> cmp::Ordering { - self.bytes().cmp(other.bytes()) + self.as_os_str_bytes().cmp(other.as_os_str_bytes()) } } @@ -1297,7 +1288,7 @@ impl_cmp!(Cow<'a, OsStr>, OsString); impl Hash for OsStr { #[inline] fn hash(&self, state: &mut H) { - self.bytes().hash(state) + self.as_os_str_bytes().hash(state) } } diff --git a/library/std/src/path.rs b/library/std/src/path.rs index febdeb514634..6f770d4c91b1 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -193,7 +193,7 @@ impl<'a> Prefix<'a> { fn len(&self) -> usize { use self::Prefix::*; fn os_str_len(s: &OsStr) -> usize { - s.bytes().len() + s.as_os_str_bytes().len() } match *self { Verbatim(x) => 4 + os_str_len(x), @@ -330,7 +330,7 @@ fn has_physical_root(s: &[u8], prefix: Option>) -> bool { // basic workhorse for splitting stem and extension fn rsplit_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) { - if file.bytes() == b".." { + if file.as_os_str_bytes() == b".." { return (Some(file), None); } @@ -338,7 +338,7 @@ fn rsplit_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) { // and back. This is safe to do because (1) we only look at ASCII // contents of the encoding and (2) new &OsStr values are produced // only from ASCII-bounded slices of existing &OsStr values. - let mut iter = file.bytes().rsplitn(2, |b| *b == b'.'); + let mut iter = file.as_os_str_bytes().rsplitn(2, |b| *b == b'.'); let after = iter.next(); let before = iter.next(); if before == Some(b"") { @@ -349,7 +349,7 @@ fn rsplit_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) { } fn split_file_at_dot(file: &OsStr) -> (&OsStr, Option<&OsStr>) { - let slice = file.bytes(); + let slice = file.as_os_str_bytes(); if slice == b".." { return (file, None); } @@ -1481,17 +1481,17 @@ impl PathBuf { fn _set_extension(&mut self, extension: &OsStr) -> bool { let file_stem = match self.file_stem() { None => return false, - Some(f) => f.bytes(), + Some(f) => f.as_os_str_bytes(), }; // truncate until right after the file stem let end_file_stem = file_stem[file_stem.len()..].as_ptr().addr(); - let start = self.inner.bytes().as_ptr().addr(); + let start = self.inner.as_os_str_bytes().as_ptr().addr(); let v = self.as_mut_vec(); v.truncate(end_file_stem.wrapping_sub(start)); // add the new extension, if any - let new = extension.bytes(); + let new = extension.as_os_str_bytes(); if !new.is_empty() { v.reserve_exact(new.len() + 1); v.push(b'.'); @@ -2015,7 +2015,7 @@ impl Path { } // The following (private!) function reveals the byte encoding used for OsStr. fn as_u8_slice(&self) -> &[u8] { - self.inner.bytes() + self.inner.as_os_str_bytes() } /// Directly wraps a string slice as a `Path` slice. diff --git a/library/std/src/sys/common/small_c_string.rs b/library/std/src/sys/common/small_c_string.rs index 01acd5191351..963d17a47e4c 100644 --- a/library/std/src/sys/common/small_c_string.rs +++ b/library/std/src/sys/common/small_c_string.rs @@ -19,7 +19,7 @@ pub fn run_path_with_cstr(path: &Path, f: F) -> io::Result where F: FnOnce(&CStr) -> io::Result, { - run_with_cstr(path.as_os_str().bytes(), f) + run_with_cstr(path.as_os_str().as_os_str_bytes(), f) } #[inline] diff --git a/library/std/src/sys/common/tests.rs b/library/std/src/sys/common/tests.rs index fb6f5d6af837..0a1cbcbe8ef3 100644 --- a/library/std/src/sys/common/tests.rs +++ b/library/std/src/sys/common/tests.rs @@ -8,7 +8,7 @@ use core::iter::repeat; fn stack_allocation_works() { let path = Path::new("abc"); let result = run_path_with_cstr(path, |p| { - assert_eq!(p, &*CString::new(path.as_os_str().bytes()).unwrap()); + assert_eq!(p, &*CString::new(path.as_os_str().as_os_str_bytes()).unwrap()); Ok(42) }); assert_eq!(result.unwrap(), 42); @@ -25,7 +25,7 @@ fn heap_allocation_works() { let path = repeat("a").take(384).collect::(); let path = Path::new(&path); let result = run_path_with_cstr(path, |p| { - assert_eq!(p, &*CString::new(path.as_os_str().bytes()).unwrap()); + assert_eq!(p, &*CString::new(path.as_os_str().as_os_str_bytes()).unwrap()); Ok(42) }); assert_eq!(result.unwrap(), 42); diff --git a/library/std/src/sys/unix/path.rs b/library/std/src/sys/unix/path.rs index a98a69e2db8e..935245f637b8 100644 --- a/library/std/src/sys/unix/path.rs +++ b/library/std/src/sys/unix/path.rs @@ -30,7 +30,7 @@ pub(crate) fn absolute(path: &Path) -> io::Result { // Get the components, skipping the redundant leading "." component if it exists. let mut components = path.strip_prefix(".").unwrap_or(path).components(); - let path_os = path.as_os_str().bytes(); + let path_os = path.as_os_str().as_os_str_bytes(); let mut normalized = if path.is_absolute() { // "If a pathname begins with two successive characters, the diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs index afd03d79c0ba..640648e87074 100644 --- a/library/std/src/sys/unix/process/process_common.rs +++ b/library/std/src/sys/unix/process/process_common.rs @@ -164,9 +164,9 @@ pub enum ProgramKind { impl ProgramKind { fn new(program: &OsStr) -> Self { - if program.bytes().starts_with(b"/") { + if program.as_os_str_bytes().starts_with(b"/") { Self::Absolute - } else if program.bytes().contains(&b'/') { + } else if program.as_os_str_bytes().contains(&b'/') { // If the program has more than one component in it, it is a relative path. Self::Relative } else { diff --git a/library/std/src/sys/windows/args.rs b/library/std/src/sys/windows/args.rs index 5bfd8b52ed08..6b597f499bcd 100644 --- a/library/std/src/sys/windows/args.rs +++ b/library/std/src/sys/windows/args.rs @@ -226,7 +226,7 @@ pub(crate) fn append_arg(cmd: &mut Vec, arg: &Arg, force_quotes: bool) -> i // that it actually gets passed through on the command line or otherwise // it will be dropped entirely when parsed on the other end. ensure_no_nuls(arg)?; - let arg_bytes = arg.bytes(); + let arg_bytes = arg.as_os_str_bytes(); let (quote, escape) = match quote { Quote::Always => (true, true), Quote::Auto => { @@ -297,7 +297,9 @@ pub(crate) fn make_bat_command_line( // * `|<>` pipe/redirect characters. const SPECIAL: &[u8] = b"\t &()[]{}^=;!'+,`~%|<>"; let force_quotes = match arg { - Arg::Regular(arg) if !force_quotes => arg.bytes().iter().any(|c| SPECIAL.contains(c)), + Arg::Regular(arg) if !force_quotes => { + arg.as_os_str_bytes().iter().any(|c| SPECIAL.contains(c)) + } _ => force_quotes, }; append_arg(&mut cmd, arg, force_quotes)?; diff --git a/library/std/src/sys/windows/path.rs b/library/std/src/sys/windows/path.rs index c3573d14c7f9..7a65d901ad2e 100644 --- a/library/std/src/sys/windows/path.rs +++ b/library/std/src/sys/windows/path.rs @@ -33,12 +33,12 @@ pub fn is_verbatim_sep(b: u8) -> bool { /// Returns true if `path` looks like a lone filename. pub(crate) fn is_file_name(path: &OsStr) -> bool { - !path.bytes().iter().copied().any(is_sep_byte) + !path.as_os_str_bytes().iter().copied().any(is_sep_byte) } pub(crate) fn has_trailing_slash(path: &OsStr) -> bool { - let is_verbatim = path.bytes().starts_with(br"\\?\"); + let is_verbatim = path.as_os_str_bytes().starts_with(br"\\?\"); let is_separator = if is_verbatim { is_verbatim_sep } else { is_sep_byte }; - if let Some(&c) = path.bytes().last() { is_separator(c) } else { false } + if let Some(&c) = path.as_os_str_bytes().last() { is_separator(c) } else { false } } /// Appends a suffix to a path. @@ -60,7 +60,7 @@ impl<'a, const LEN: usize> PrefixParser<'a, LEN> { fn get_prefix(path: &OsStr) -> [u8; LEN] { let mut prefix = [0; LEN]; // SAFETY: Only ASCII characters are modified. - for (i, &ch) in path.bytes().iter().take(LEN).enumerate() { + for (i, &ch) in path.as_os_str_bytes().iter().take(LEN).enumerate() { prefix[i] = if ch == b'/' { b'\\' } else { ch }; } prefix @@ -93,7 +93,7 @@ impl<'a> PrefixParserSlice<'a, '_> { } fn prefix_bytes(&self) -> &'a [u8] { - &self.path.bytes()[..self.index] + &self.path.as_os_str_bytes()[..self.index] } fn finish(self) -> &'a OsStr { @@ -101,7 +101,7 @@ impl<'a> PrefixParserSlice<'a, '_> { // &[u8] and back. This is safe to do because (1) we only look at ASCII // contents of the encoding and (2) new &OsStr values are produced only // from ASCII-bounded slices of existing &OsStr values. - unsafe { bytes_as_os_str(&self.path.bytes()[self.index..]) } + unsafe { bytes_as_os_str(&self.path.as_os_str_bytes()[self.index..]) } } } @@ -173,7 +173,7 @@ fn parse_drive(path: &OsStr) -> Option { drive.is_ascii_alphabetic() } - match path.bytes() { + match path.as_os_str_bytes() { [drive, b':', ..] if is_valid_drive_letter(drive) => Some(drive.to_ascii_uppercase()), _ => None, } @@ -182,7 +182,7 @@ fn parse_drive(path: &OsStr) -> Option { // Parses a drive prefix exactly, e.g. "C:" fn parse_drive_exact(path: &OsStr) -> Option { // only parse two bytes: the drive letter and the drive separator - if path.bytes().get(2).map(|&x| is_sep_byte(x)).unwrap_or(true) { + if path.as_os_str_bytes().get(2).map(|&x| is_sep_byte(x)).unwrap_or(true) { parse_drive(path) } else { None @@ -196,15 +196,15 @@ fn parse_drive_exact(path: &OsStr) -> Option { fn parse_next_component(path: &OsStr, verbatim: bool) -> (&OsStr, &OsStr) { let separator = if verbatim { is_verbatim_sep } else { is_sep_byte }; - match path.bytes().iter().position(|&x| separator(x)) { + match path.as_os_str_bytes().iter().position(|&x| separator(x)) { Some(separator_start) => { let separator_end = separator_start + 1; - let component = &path.bytes()[..separator_start]; + let component = &path.as_os_str_bytes()[..separator_start]; // Panic safe // The max `separator_end` is `bytes.len()` and `bytes[bytes.len()..]` is a valid index. - let path = &path.bytes()[separator_end..]; + let path = &path.as_os_str_bytes()[separator_end..]; // SAFETY: `path` is a valid wtf8 encoded slice and each of the separators ('/', '\') // is encoded in a single byte, therefore `bytes[separator_start]` and @@ -329,7 +329,7 @@ pub(crate) fn absolute(path: &Path) -> io::Result { // Verbatim paths should not be modified. if prefix.map(|x| x.is_verbatim()).unwrap_or(false) { // NULs in verbatim paths are rejected for consistency. - if path.bytes().contains(&0) { + if path.as_os_str_bytes().contains(&0) { return Err(io::const_io_error!( io::ErrorKind::InvalidInput, "strings passed to WinAPI cannot contain NULs", diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs index df3667c0fd78..a573a05c39cd 100644 --- a/library/std/src/sys/windows/process.rs +++ b/library/std/src/sys/windows/process.rs @@ -395,7 +395,7 @@ fn resolve_exe<'a>( // Test if the file name has the `exe` extension. // This does a case-insensitive `ends_with`. let has_exe_suffix = if exe_path.len() >= EXE_SUFFIX.len() { - exe_path.bytes()[exe_path.len() - EXE_SUFFIX.len()..] + exe_path.as_os_str_bytes()[exe_path.len() - EXE_SUFFIX.len()..] .eq_ignore_ascii_case(EXE_SUFFIX.as_bytes()) } else { false @@ -425,7 +425,7 @@ fn resolve_exe<'a>( // From the `CreateProcessW` docs: // > If the file name does not contain an extension, .exe is appended. // Note that this rule only applies when searching paths. - let has_extension = exe_path.bytes().contains(&b'.'); + let has_extension = exe_path.as_os_str_bytes().contains(&b'.'); // Search the directories given by `search_paths`. let result = search_paths(parent_paths, child_paths, |mut path| { From 7b9290384e88e6960bc574e83219df50df5fe4e1 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Sat, 13 May 2023 19:09:00 +0200 Subject: [PATCH 03/69] refactor: Remove bespoke from_os_str_bytes_unchecked --- library/std/src/path.rs | 36 +++++++++++++---------------- library/std/src/sys/windows/path.rs | 20 ++++++---------- 2 files changed, 23 insertions(+), 33 deletions(-) diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 6f770d4c91b1..28cd3c4e4dbd 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -299,20 +299,6 @@ where } } -unsafe fn u8_slice_as_os_str(s: &[u8]) -> &OsStr { - // SAFETY: See note at the top of this module to understand why this and - // `OsStr::bytes` are used: - // - // This casts are safe as OsStr is internally a wrapper around [u8] on all - // platforms. - // - // Note that currently this relies on the special knowledge that std has; - // these types are single-element structs but are not marked - // repr(transparent) or repr(C) which would make these casts not allowable - // outside std. - unsafe { &*(s as *const [u8] as *const OsStr) } -} - // Detect scheme on Redox fn has_redox_scheme(s: &[u8]) -> bool { cfg!(target_os = "redox") && s.contains(&b':') @@ -344,7 +330,12 @@ fn rsplit_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) { if before == Some(b"") { (Some(file), None) } else { - unsafe { (before.map(|s| u8_slice_as_os_str(s)), after.map(|s| u8_slice_as_os_str(s))) } + unsafe { + ( + before.map(|s| OsStr::from_os_str_bytes_unchecked(s)), + after.map(|s| OsStr::from_os_str_bytes_unchecked(s)), + ) + } } } @@ -364,7 +355,12 @@ fn split_file_at_dot(file: &OsStr) -> (&OsStr, Option<&OsStr>) { }; let before = &slice[..i]; let after = &slice[i + 1..]; - unsafe { (u8_slice_as_os_str(before), Some(u8_slice_as_os_str(after))) } + unsafe { + ( + OsStr::from_os_str_bytes_unchecked(before), + Some(OsStr::from_os_str_bytes_unchecked(after)), + ) + } } //////////////////////////////////////////////////////////////////////////////// @@ -743,7 +739,7 @@ impl<'a> Components<'a> { // separately via `include_cur_dir` b".." => Some(Component::ParentDir), b"" => None, - _ => Some(Component::Normal(unsafe { u8_slice_as_os_str(comp) })), + _ => Some(Component::Normal(unsafe { OsStr::from_os_str_bytes_unchecked(comp) })), } } @@ -900,7 +896,7 @@ impl<'a> Iterator for Components<'a> { let raw = &self.path[..self.prefix_len()]; self.path = &self.path[self.prefix_len()..]; return Some(Component::Prefix(PrefixComponent { - raw: unsafe { u8_slice_as_os_str(raw) }, + raw: unsafe { OsStr::from_os_str_bytes_unchecked(raw) }, parsed: self.prefix.unwrap(), })); } @@ -972,7 +968,7 @@ impl<'a> DoubleEndedIterator for Components<'a> { State::Prefix if self.prefix_len() > 0 => { self.back = State::Done; return Some(Component::Prefix(PrefixComponent { - raw: unsafe { u8_slice_as_os_str(self.path) }, + raw: unsafe { OsStr::from_os_str_bytes_unchecked(self.path) }, parsed: self.prefix.unwrap(), })); } @@ -2011,7 +2007,7 @@ impl Path { // The following (private!) function allows construction of a path from a u8 // slice, which is only safe when it is known to follow the OsStr encoding. unsafe fn from_u8_slice(s: &[u8]) -> &Path { - unsafe { Path::new(u8_slice_as_os_str(s)) } + unsafe { Path::new(OsStr::from_os_str_bytes_unchecked(s)) } } // The following (private!) function reveals the byte encoding used for OsStr. fn as_u8_slice(&self) -> &[u8] { diff --git a/library/std/src/sys/windows/path.rs b/library/std/src/sys/windows/path.rs index 7a65d901ad2e..c9c2d10e6c44 100644 --- a/library/std/src/sys/windows/path.rs +++ b/library/std/src/sys/windows/path.rs @@ -1,7 +1,6 @@ use super::{c, fill_utf16_buf, to_u16s}; use crate::ffi::{OsStr, OsString}; use crate::io; -use crate::mem; use crate::path::{Path, PathBuf, Prefix}; use crate::ptr; @@ -11,16 +10,6 @@ mod tests; pub const MAIN_SEP_STR: &str = "\\"; pub const MAIN_SEP: char = '\\'; -/// # Safety -/// -/// `bytes` must be a valid wtf8 encoded slice -#[inline] -unsafe fn bytes_as_os_str(bytes: &[u8]) -> &OsStr { - // &OsStr is layout compatible with &Slice, which is compatible with &Wtf8, - // which is compatible with &[u8]. - mem::transmute(bytes) -} - #[inline] pub fn is_sep_byte(b: u8) -> bool { b == b'/' || b == b'\\' @@ -101,7 +90,7 @@ impl<'a> PrefixParserSlice<'a, '_> { // &[u8] and back. This is safe to do because (1) we only look at ASCII // contents of the encoding and (2) new &OsStr values are produced only // from ASCII-bounded slices of existing &OsStr values. - unsafe { bytes_as_os_str(&self.path.as_os_str_bytes()[self.index..]) } + unsafe { OsStr::from_os_str_bytes_unchecked(&self.path.as_os_str_bytes()[self.index..]) } } } @@ -210,7 +199,12 @@ fn parse_next_component(path: &OsStr, verbatim: bool) -> (&OsStr, &OsStr) { // is encoded in a single byte, therefore `bytes[separator_start]` and // `bytes[separator_end]` must be code point boundaries and thus // `bytes[..separator_start]` and `bytes[separator_end..]` are valid wtf8 slices. - unsafe { (bytes_as_os_str(component), bytes_as_os_str(path)) } + unsafe { + ( + OsStr::from_os_str_bytes_unchecked(component), + OsStr::from_os_str_bytes_unchecked(path), + ) + } } None => (path, OsStr::new("")), } From f9aaad0939e1507990f02676e7f70b88a85a9aea Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 16 May 2023 21:03:29 -0500 Subject: [PATCH 04/69] docs: Add examples of OsStr safety violation --- library/std/src/ffi/os_str.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 90cbd57a9298..d40c6d317492 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -678,8 +678,10 @@ impl OsStr { /// `OsStr`'s encoding is an unspecified superset of UTF-8 and callers must /// pass in bytes that originated as a mixture of validated UTF-8 and bytes from /// [`OsStr::as_os_str_bytes`] from within the same rust version built for the same target - /// platform. The bytes from `OsStr::as_os_str_bytes` may be split either - /// immediately before or immediately after some valid non-empty UTF-8 substring + /// platform. For example, reconstructing an `OsStr` from bytes sent over the network or stored + /// in a file will likely violate these safety rules. The bytes from `OsStr::as_os_str_bytes` + /// may be split either immediately before or immediately after some valid non-empty UTF-8 + /// substring /// /// # Example /// @@ -881,8 +883,9 @@ impl OsStr { /// /// Note: As the encoding is unspecified, any sub-slice of bytes that is not valid UTF-8 should /// be treated as opaque and only comparable within the same rust version built for the same - /// target platform. See [`OsString`] for more encoding details and [`std::ffi`] for - /// platform-specific, specified conversions. + /// target platform. For example, sending the slice over the network or storing it in a file + /// will likely result in incompatible byte slices See [`OsString`] for more encoding details + /// and [`std::ffi`] for platform-specific, specified conversions. /// /// [`std::ffi`]: crate::ffi #[inline] From 5d177afe9591afc0e04b0d9cdfffa79c27c8af64 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 17 May 2023 09:34:25 -0500 Subject: [PATCH 05/69] docs: Clarify OsStr is self-synchronizing --- library/std/src/ffi/os_str.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index d40c6d317492..dd92b9cf76a4 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -670,18 +670,22 @@ impl OsStr { /// Converts a slice of bytes to an OS string slice without checking that the string contains /// valid `OsStr`-encoded data. /// + /// The byte encoding is an unspecified, platform-specific, self-synchronizing superset of UTF-8. + /// By being a self-synchronizing superset of UTF-8, this encoding is also a superset of 7-bit + /// ASCII. + /// /// See the [module's toplevel documentation about conversions][conversions] for safe, /// cross-platform [conversions] from/to native representations. /// /// # Safety /// - /// `OsStr`'s encoding is an unspecified superset of UTF-8 and callers must - /// pass in bytes that originated as a mixture of validated UTF-8 and bytes from - /// [`OsStr::as_os_str_bytes`] from within the same rust version built for the same target - /// platform. For example, reconstructing an `OsStr` from bytes sent over the network or stored - /// in a file will likely violate these safety rules. The bytes from `OsStr::as_os_str_bytes` - /// may be split either immediately before or immediately after some valid non-empty UTF-8 - /// substring + /// As the encoding is unspecified, callers must pass in bytes that originated as a mixture of + /// validated UTF-8 and bytes from [`OsStr::as_os_str_bytes`] from within the same rust version + /// built for the same target platform. For example, reconstructing an `OsStr` from bytes sent + /// over the network or stored in a file will likely violate these safety rules. + /// + /// Due to the encoding being self-synchronizing, the bytes from [`OsStr::as_os_str_bytes`] can be + /// split either immediately before or immediately after any valid non-empty UTF-8 substring. /// /// # Example /// @@ -881,6 +885,10 @@ impl OsStr { /// Converts an OS string slice to a byte slice. To convert the byte slice back into an OS /// string slice, use the [`OsStr::from_os_str_bytes_unchecked`] function. /// + /// The byte encoding is an unspecified, platform-specific, self-synchronizing superset of UTF-8. + /// By being a self-synchronizing superset of UTF-8, this encoding is also a superset of 7-bit + /// ASCII. + /// /// Note: As the encoding is unspecified, any sub-slice of bytes that is not valid UTF-8 should /// be treated as opaque and only comparable within the same rust version built for the same /// target platform. For example, sending the slice over the network or storing it in a file From e6a35c49533dd734f178b04677404df0da518737 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 19 May 2023 19:41:41 -0500 Subject: [PATCH 06/69] docs: Add missing period --- library/std/src/ffi/os_str.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index dd92b9cf76a4..bb577acf769d 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -892,7 +892,7 @@ impl OsStr { /// Note: As the encoding is unspecified, any sub-slice of bytes that is not valid UTF-8 should /// be treated as opaque and only comparable within the same rust version built for the same /// target platform. For example, sending the slice over the network or storing it in a file - /// will likely result in incompatible byte slices See [`OsString`] for more encoding details + /// will likely result in incompatible byte slices. See [`OsString`] for more encoding details /// and [`std::ffi`] for platform-specific, specified conversions. /// /// [`std::ffi`]: crate::ffi From 25e395653df2a91fc9a76dfd3ef050f1c7ba9fca Mon Sep 17 00:00:00 2001 From: Caio Date: Sun, 14 May 2023 09:49:20 -0300 Subject: [PATCH 07/69] Move tests --- src/tools/tidy/src/ui_tests.rs | 4 ++-- tests/ui/{issues => async-await}/issue-78115.rs | 0 tests/ui/{issues => coercion}/issue-3794.rs | 0 tests/ui/{issues => consts}/issue-16538.mir.stderr | 0 tests/ui/{issues => consts}/issue-16538.rs | 0 tests/ui/{issues => consts}/issue-16538.thir.stderr | 0 tests/ui/{issues => consts}/issue-28822.rs | 0 tests/ui/{issues => enum-discriminant}/issue-50689.rs | 0 tests/ui/{issues => extern}/issue-1251.rs | 0 tests/ui/{issues => for-loop-while}/issue-1257.rs | 0 tests/ui/{issues => mir}/issue-29798.rs | 0 tests/ui/{ => pattern}/issue-94866.rs | 0 tests/ui/{ => pattern}/issue-94866.stderr | 0 tests/ui/{issues => recursion}/issue-3008-1.rs | 0 tests/ui/{issues => recursion}/issue-3008-1.stderr | 0 tests/ui/{issues => recursion}/issue-3008-2.rs | 0 tests/ui/{issues => recursion}/issue-3008-2.stderr | 0 tests/ui/{issues => recursion}/issue-3008-3.rs | 0 tests/ui/{issues => recursion}/issue-3008-3.stderr | 0 tests/ui/{issues => typeck}/issue-1871.rs | 0 tests/ui/{issues => typeck}/issue-1871.stderr | 0 tests/ui/{issues => typeck}/issue-2063-resource.rs | 0 tests/ui/{issues => typeck}/issue-2063.rs | 0 tests/ui/{issues => where-clauses}/issue-50825-1.rs | 0 tests/ui/{issues => where-clauses}/issue-50825.rs | 0 25 files changed, 2 insertions(+), 2 deletions(-) rename tests/ui/{issues => async-await}/issue-78115.rs (100%) rename tests/ui/{issues => coercion}/issue-3794.rs (100%) rename tests/ui/{issues => consts}/issue-16538.mir.stderr (100%) rename tests/ui/{issues => consts}/issue-16538.rs (100%) rename tests/ui/{issues => consts}/issue-16538.thir.stderr (100%) rename tests/ui/{issues => consts}/issue-28822.rs (100%) rename tests/ui/{issues => enum-discriminant}/issue-50689.rs (100%) rename tests/ui/{issues => extern}/issue-1251.rs (100%) rename tests/ui/{issues => for-loop-while}/issue-1257.rs (100%) rename tests/ui/{issues => mir}/issue-29798.rs (100%) rename tests/ui/{ => pattern}/issue-94866.rs (100%) rename tests/ui/{ => pattern}/issue-94866.stderr (100%) rename tests/ui/{issues => recursion}/issue-3008-1.rs (100%) rename tests/ui/{issues => recursion}/issue-3008-1.stderr (100%) rename tests/ui/{issues => recursion}/issue-3008-2.rs (100%) rename tests/ui/{issues => recursion}/issue-3008-2.stderr (100%) rename tests/ui/{issues => recursion}/issue-3008-3.rs (100%) rename tests/ui/{issues => recursion}/issue-3008-3.stderr (100%) rename tests/ui/{issues => typeck}/issue-1871.rs (100%) rename tests/ui/{issues => typeck}/issue-1871.stderr (100%) rename tests/ui/{issues => typeck}/issue-2063-resource.rs (100%) rename tests/ui/{issues => typeck}/issue-2063.rs (100%) rename tests/ui/{issues => where-clauses}/issue-50825-1.rs (100%) rename tests/ui/{issues => where-clauses}/issue-50825.rs (100%) diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index be3a5d3aa0f0..3e9bf18a2871 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -10,8 +10,8 @@ use std::path::{Path, PathBuf}; const ENTRY_LIMIT: usize = 900; // FIXME: The following limits should be reduced eventually. -const ISSUES_ENTRY_LIMIT: usize = 1920; -const ROOT_ENTRY_LIMIT: usize = 896; +const ISSUES_ENTRY_LIMIT: usize = 1898; +const ROOT_ENTRY_LIMIT: usize = 894; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files diff --git a/tests/ui/issues/issue-78115.rs b/tests/ui/async-await/issue-78115.rs similarity index 100% rename from tests/ui/issues/issue-78115.rs rename to tests/ui/async-await/issue-78115.rs diff --git a/tests/ui/issues/issue-3794.rs b/tests/ui/coercion/issue-3794.rs similarity index 100% rename from tests/ui/issues/issue-3794.rs rename to tests/ui/coercion/issue-3794.rs diff --git a/tests/ui/issues/issue-16538.mir.stderr b/tests/ui/consts/issue-16538.mir.stderr similarity index 100% rename from tests/ui/issues/issue-16538.mir.stderr rename to tests/ui/consts/issue-16538.mir.stderr diff --git a/tests/ui/issues/issue-16538.rs b/tests/ui/consts/issue-16538.rs similarity index 100% rename from tests/ui/issues/issue-16538.rs rename to tests/ui/consts/issue-16538.rs diff --git a/tests/ui/issues/issue-16538.thir.stderr b/tests/ui/consts/issue-16538.thir.stderr similarity index 100% rename from tests/ui/issues/issue-16538.thir.stderr rename to tests/ui/consts/issue-16538.thir.stderr diff --git a/tests/ui/issues/issue-28822.rs b/tests/ui/consts/issue-28822.rs similarity index 100% rename from tests/ui/issues/issue-28822.rs rename to tests/ui/consts/issue-28822.rs diff --git a/tests/ui/issues/issue-50689.rs b/tests/ui/enum-discriminant/issue-50689.rs similarity index 100% rename from tests/ui/issues/issue-50689.rs rename to tests/ui/enum-discriminant/issue-50689.rs diff --git a/tests/ui/issues/issue-1251.rs b/tests/ui/extern/issue-1251.rs similarity index 100% rename from tests/ui/issues/issue-1251.rs rename to tests/ui/extern/issue-1251.rs diff --git a/tests/ui/issues/issue-1257.rs b/tests/ui/for-loop-while/issue-1257.rs similarity index 100% rename from tests/ui/issues/issue-1257.rs rename to tests/ui/for-loop-while/issue-1257.rs diff --git a/tests/ui/issues/issue-29798.rs b/tests/ui/mir/issue-29798.rs similarity index 100% rename from tests/ui/issues/issue-29798.rs rename to tests/ui/mir/issue-29798.rs diff --git a/tests/ui/issue-94866.rs b/tests/ui/pattern/issue-94866.rs similarity index 100% rename from tests/ui/issue-94866.rs rename to tests/ui/pattern/issue-94866.rs diff --git a/tests/ui/issue-94866.stderr b/tests/ui/pattern/issue-94866.stderr similarity index 100% rename from tests/ui/issue-94866.stderr rename to tests/ui/pattern/issue-94866.stderr diff --git a/tests/ui/issues/issue-3008-1.rs b/tests/ui/recursion/issue-3008-1.rs similarity index 100% rename from tests/ui/issues/issue-3008-1.rs rename to tests/ui/recursion/issue-3008-1.rs diff --git a/tests/ui/issues/issue-3008-1.stderr b/tests/ui/recursion/issue-3008-1.stderr similarity index 100% rename from tests/ui/issues/issue-3008-1.stderr rename to tests/ui/recursion/issue-3008-1.stderr diff --git a/tests/ui/issues/issue-3008-2.rs b/tests/ui/recursion/issue-3008-2.rs similarity index 100% rename from tests/ui/issues/issue-3008-2.rs rename to tests/ui/recursion/issue-3008-2.rs diff --git a/tests/ui/issues/issue-3008-2.stderr b/tests/ui/recursion/issue-3008-2.stderr similarity index 100% rename from tests/ui/issues/issue-3008-2.stderr rename to tests/ui/recursion/issue-3008-2.stderr diff --git a/tests/ui/issues/issue-3008-3.rs b/tests/ui/recursion/issue-3008-3.rs similarity index 100% rename from tests/ui/issues/issue-3008-3.rs rename to tests/ui/recursion/issue-3008-3.rs diff --git a/tests/ui/issues/issue-3008-3.stderr b/tests/ui/recursion/issue-3008-3.stderr similarity index 100% rename from tests/ui/issues/issue-3008-3.stderr rename to tests/ui/recursion/issue-3008-3.stderr diff --git a/tests/ui/issues/issue-1871.rs b/tests/ui/typeck/issue-1871.rs similarity index 100% rename from tests/ui/issues/issue-1871.rs rename to tests/ui/typeck/issue-1871.rs diff --git a/tests/ui/issues/issue-1871.stderr b/tests/ui/typeck/issue-1871.stderr similarity index 100% rename from tests/ui/issues/issue-1871.stderr rename to tests/ui/typeck/issue-1871.stderr diff --git a/tests/ui/issues/issue-2063-resource.rs b/tests/ui/typeck/issue-2063-resource.rs similarity index 100% rename from tests/ui/issues/issue-2063-resource.rs rename to tests/ui/typeck/issue-2063-resource.rs diff --git a/tests/ui/issues/issue-2063.rs b/tests/ui/typeck/issue-2063.rs similarity index 100% rename from tests/ui/issues/issue-2063.rs rename to tests/ui/typeck/issue-2063.rs diff --git a/tests/ui/issues/issue-50825-1.rs b/tests/ui/where-clauses/issue-50825-1.rs similarity index 100% rename from tests/ui/issues/issue-50825-1.rs rename to tests/ui/where-clauses/issue-50825-1.rs diff --git a/tests/ui/issues/issue-50825.rs b/tests/ui/where-clauses/issue-50825.rs similarity index 100% rename from tests/ui/issues/issue-50825.rs rename to tests/ui/where-clauses/issue-50825.rs From 41d414e3f44fa728c0231d2ef69bdf60313e2431 Mon Sep 17 00:00:00 2001 From: Caio Date: Wed, 24 May 2023 19:54:13 -0300 Subject: [PATCH 08/69] Address comments --- tests/ui/{mir => consts}/issue-29798.rs | 0 tests/ui/{recursion => enum-discriminant}/issue-3008-1.rs | 0 tests/ui/{recursion => enum-discriminant}/issue-3008-1.stderr | 0 tests/ui/{recursion => enum-discriminant}/issue-3008-2.rs | 0 tests/ui/{recursion => enum-discriminant}/issue-3008-2.stderr | 0 tests/ui/{recursion => enum-discriminant}/issue-3008-3.rs | 0 tests/ui/{recursion => enum-discriminant}/issue-3008-3.stderr | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{mir => consts}/issue-29798.rs (100%) rename tests/ui/{recursion => enum-discriminant}/issue-3008-1.rs (100%) rename tests/ui/{recursion => enum-discriminant}/issue-3008-1.stderr (100%) rename tests/ui/{recursion => enum-discriminant}/issue-3008-2.rs (100%) rename tests/ui/{recursion => enum-discriminant}/issue-3008-2.stderr (100%) rename tests/ui/{recursion => enum-discriminant}/issue-3008-3.rs (100%) rename tests/ui/{recursion => enum-discriminant}/issue-3008-3.stderr (100%) diff --git a/tests/ui/mir/issue-29798.rs b/tests/ui/consts/issue-29798.rs similarity index 100% rename from tests/ui/mir/issue-29798.rs rename to tests/ui/consts/issue-29798.rs diff --git a/tests/ui/recursion/issue-3008-1.rs b/tests/ui/enum-discriminant/issue-3008-1.rs similarity index 100% rename from tests/ui/recursion/issue-3008-1.rs rename to tests/ui/enum-discriminant/issue-3008-1.rs diff --git a/tests/ui/recursion/issue-3008-1.stderr b/tests/ui/enum-discriminant/issue-3008-1.stderr similarity index 100% rename from tests/ui/recursion/issue-3008-1.stderr rename to tests/ui/enum-discriminant/issue-3008-1.stderr diff --git a/tests/ui/recursion/issue-3008-2.rs b/tests/ui/enum-discriminant/issue-3008-2.rs similarity index 100% rename from tests/ui/recursion/issue-3008-2.rs rename to tests/ui/enum-discriminant/issue-3008-2.rs diff --git a/tests/ui/recursion/issue-3008-2.stderr b/tests/ui/enum-discriminant/issue-3008-2.stderr similarity index 100% rename from tests/ui/recursion/issue-3008-2.stderr rename to tests/ui/enum-discriminant/issue-3008-2.stderr diff --git a/tests/ui/recursion/issue-3008-3.rs b/tests/ui/enum-discriminant/issue-3008-3.rs similarity index 100% rename from tests/ui/recursion/issue-3008-3.rs rename to tests/ui/enum-discriminant/issue-3008-3.rs diff --git a/tests/ui/recursion/issue-3008-3.stderr b/tests/ui/enum-discriminant/issue-3008-3.stderr similarity index 100% rename from tests/ui/recursion/issue-3008-3.stderr rename to tests/ui/enum-discriminant/issue-3008-3.stderr From 38c712f45889c237d5ac08258f0a40dccb9adbba Mon Sep 17 00:00:00 2001 From: AngelicosPhosphoros Date: Sun, 21 May 2023 21:53:02 +0400 Subject: [PATCH 09/69] Added build instructions for cranelift backend as part of Rust repo All other instructions assume that user works with separate repository than Rust compiler repository. When one follows default instructions, cranelift codegen tries to use different sys-root and compiler internal crates which leads to compiler errors when building it. I needed to do all this steps while adding new intrinsic to rustc. --- compiler/rustc_codegen_cranelift/Readme.md | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/compiler/rustc_codegen_cranelift/Readme.md b/compiler/rustc_codegen_cranelift/Readme.md index c5222982aa73..26dccf309e1e 100644 --- a/compiler/rustc_codegen_cranelift/Readme.md +++ b/compiler/rustc_codegen_cranelift/Readme.md @@ -42,6 +42,32 @@ This will build your project with rustc_codegen_cranelift instead of the usual L For additional ways to use rustc_codegen_cranelift like the JIT mode see [usage.md](docs/usage.md). +## Building and testing with changes in rustc code + +This is useful when changing code in `rustc_codegen_cranelift` as part of changing [main Rust repository](https://github.com/rust-lang/rust/). +This can happen, for example, when you are implementing a new compiler intrinsic. + +Instruction below uses `$RustCheckoutDir` as substitute for any folder where you cloned Rust repository. + +You need to do this steps to successfully compile and use the cranelift backend with your changes in rustc code: + +1. `cd $RustCheckoutDir` +2. Run `python x.py setup` and choose option for compiler (`b`). +3. Build compiler and necessary tools: `python x.py build --stage=2 compiler library/std src/tools/rustdoc src/tools/rustfmt` + * (Optional) You can also build cargo by adding `src/tools/cargo` to previous command. +4. Copy exectutable files from `./build/host/stage2-tools//release` +to `./build/host/stage2/bin/`. Note that you would need to do this every time you rebuilt `rust` repository. +5. Copy cargo from another toolchain: `cp $(rustup which cargo) .build//stage2/bin/cargo` + * Another option is to build it at step 3 and copy with other executables at step 4. +6. Link your new `rustc` to toolchain: `rustup toolchain link stage2 ./build/host/stage2/`. +7. (Windows only) compile y.rs: `rustc +stage2 -O y.rs`. +8. You need to prefix every `./y.rs` (or `y` if you built `y.rs`) command by `rustup run stage2` to make cg_clif use your local changes in rustc. + + * `rustup run stage2 ./y.rs prepare` + * `rustup run stage2 ./y.rs build` + * (Optional) run tests: `rustup run stage2 ./y.rs test` +9. 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`. + ## Configuration See the documentation on the `BackendConfig` struct in [config.rs](src/config.rs) for all From 9b6a6b13c54897301dc81485e41579442ee04654 Mon Sep 17 00:00:00 2001 From: klensy Date: Fri, 26 May 2023 13:03:47 +0300 Subject: [PATCH 10/69] deps: bump crates update iana-time-zone-haiku to drop bumch of cxx* deps cargo update -p iana-time-zone-haiku Updating crates.io index Updating cc v1.0.77 -> v1.0.79 Removing codespan-reporting v0.11.1 Removing cxx v1.0.94 Removing cxx-build v1.0.94 Removing cxxbridge-flags v1.0.94 Removing cxxbridge-macro v1.0.94 Updating iana-time-zone-haiku v0.1.1 -> v0.1.2 Removing link-cplusplus v1.0.8 Removing scratch v1.0.5 fixes known issue https://github.com/crossbeam-rs/crossbeam/pull/972 cargo update -p crossbeam-channel Updating crates.io index Updating crossbeam-channel v0.5.6 -> v0.5.8 dedupes memoffset versions cargo update -p crossbeam-epoch Updating crates.io index Updating crossbeam-epoch v0.9.13 -> v0.9.14 Removing memoffset v0.7.1 dedupes bstr versions cargo update -p ignore -p opener Updating crates.io index Removing bstr v0.2.17 Updating globset v0.4.9 -> v0.4.10 Updating ignore v0.4.18 -> v0.4.20 Updating opener v0.5.0 -> v0.5.2 --- Cargo.lock | 142 ++++----------------------- compiler/rustc_query_impl/Cargo.toml | 2 +- src/tools/tidy/src/deps.rs | 1 - 3 files changed, 22 insertions(+), 123 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0369442f11cf..739abf13e0bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -270,17 +270,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "bstr" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" -dependencies = [ - "lazy_static", - "memchr", - "regex-automata 0.1.10", -] - [[package]] name = "bstr" version = "1.3.0" @@ -417,9 +406,9 @@ version = "0.1.0" [[package]] name = "cc" -version = "1.0.77" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" [[package]] name = "cfg-if" @@ -666,16 +655,6 @@ dependencies = [ "rustc-semver", ] -[[package]] -name = "codespan-reporting" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] - [[package]] name = "collect-license-metadata" version = "0.1.0" @@ -842,9 +821,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.6" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" dependencies = [ "cfg-if", "crossbeam-utils", @@ -863,14 +842,14 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.13" +version = "0.9.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" +checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", - "memoffset 0.7.1", + "memoffset", "scopeguard", ] @@ -943,50 +922,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "cxx" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f61f1b6389c3fe1c316bf8a4dccc90a38208354b330925bce1f74a6c4756eb93" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12cee708e8962df2aeb38f594aae5d827c022b6460ac71a7a3e2c3c2aae5a07b" -dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2", - "quote", - "scratch", - "syn 2.0.8", -] - -[[package]] -name = "cxxbridge-flags" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7944172ae7e4068c533afbb984114a56c46e9ccddda550499caa222902c7f7bb" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.8", -] - [[package]] name = "datafrog" version = "2.0.1" @@ -1273,7 +1208,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3cf3a800ff6e860c863ca6d4b16fd999db8b752819c1606884047b73e468535" dependencies = [ - "memoffset 0.8.0", + "memoffset", "rustc_version", ] @@ -1548,12 +1483,12 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[package]] name = "globset" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a" +checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" dependencies = [ "aho-corasick", - "bstr 0.2.17", + "bstr", "fnv", "log", "regex", @@ -1688,12 +1623,11 @@ dependencies = [ [[package]] name = "iana-time-zone-haiku" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" dependencies = [ - "cxx", - "cxx-build", + "cc", ] [[package]] @@ -1780,11 +1714,10 @@ checksum = "c3360c7b59e5ffa2653671fb74b4741a5d343c03f331c0a4aeda42b5c2b0ec7d" [[package]] name = "ignore" -version = "0.4.18" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713f1b139373f96a2e0ce3ac931cd01ee973c3c5dd7c40c0c2efe96ad2b6751d" +checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492" dependencies = [ - "crossbeam-utils", "globset", "lazy_static", "log", @@ -2035,15 +1968,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "link-cplusplus" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" -dependencies = [ - "cc", -] - [[package]] name = "linkchecker" version = "0.1.0" @@ -2224,24 +2148,6 @@ dependencies = [ "libc", ] -[[package]] -name = "memoffset" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg", -] - -[[package]] -name = "memoffset" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" -dependencies = [ - "autocfg", -] - [[package]] name = "memoffset" version = "0.8.0" @@ -2439,11 +2345,11 @@ checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "opener" -version = "0.5.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea3ebcd72a54701f56345f16785a6d3ac2df7e986d273eb4395c0b01db17952" +checksum = "293c15678e37254c15bd2f092314abb4e51d7fdde05c2021279c12631b54f005" dependencies = [ - "bstr 0.2.17", + "bstr", "winapi", ] @@ -4082,7 +3988,7 @@ version = "0.0.0" dependencies = [ "field-offset", "measureme", - "memoffset 0.6.5", + "memoffset", "rustc-rayon-core", "rustc_ast", "rustc_data_structures", @@ -4521,12 +4427,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -[[package]] -name = "scratch" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" - [[package]] name = "self_cell" version = "0.10.2" @@ -5225,7 +5125,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "191a442639ea102fa62671026047e51d574bfda44b7fdf32151d7314624c1cd2" dependencies = [ - "bstr 1.3.0", + "bstr", "cargo-platform", "cargo_metadata 0.15.3", "color-eyre", diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml index e596993465c1..c9353b6fc9fb 100644 --- a/compiler/rustc_query_impl/Cargo.toml +++ b/compiler/rustc_query_impl/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] -memoffset = { version = "0.6.0", features = ["unstable_const"] } +memoffset = { version = "0.8.0", features = ["unstable_const"] } field-offset = "0.3.5" measureme = "10.0.0" rustc_ast = { path = "../rustc_ast" } diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 2e7781109311..db2b7910b711 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -38,7 +38,6 @@ const LICENSES: &[&str] = &[ const EXCEPTIONS: &[(&str, &str)] = &[ // tidy-alphabetical-start ("ar_archive_writer", "Apache-2.0 WITH LLVM-exception"), // rustc - ("codespan-reporting", "Apache-2.0"), // cxx via iana-time-zone-haiku via time, only on haiku ("colored", "MPL-2.0"), // rustfmt ("dissimilar", "Apache-2.0"), // rustdoc, rustc_lexer (few tests) via expect-test, (dev deps) ("fluent-langneg", "Apache-2.0"), // rustc (fluent translations) From 5f66c4192111e4fda5ccbdb714e97e18ac6adcc4 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 26 May 2023 14:53:24 +0000 Subject: [PATCH 11/69] Add regression test --- tests/codegen/const_scalar_pair.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 tests/codegen/const_scalar_pair.rs diff --git a/tests/codegen/const_scalar_pair.rs b/tests/codegen/const_scalar_pair.rs new file mode 100644 index 000000000000..16e6484585c9 --- /dev/null +++ b/tests/codegen/const_scalar_pair.rs @@ -0,0 +1,10 @@ +// compile-flags: --crate-type=lib -Copt-level=0 -Zmir-opt-level=0 -C debuginfo=2 + +// CHECK: @0 = private unnamed_addr constant <{ [8 x i8] }> <{ [8 x i8] c"\01\00\00\00\02\00\00\00" }>, align 4 + +#![feature(inline_const)] + +pub fn foo() -> (i32, i32) { + // CHECK: %0 = load i32, ptr @0, align 4 + const { (1, 2) } +} From 164d041e303e9c98daaf35301fa88ba6844277dd Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 19 May 2023 15:48:43 +0000 Subject: [PATCH 12/69] Stop creating intermediate places just to immediate convert them to operands --- compiler/rustc_codegen_gcc/src/common.rs | 42 +++++------ compiler/rustc_codegen_gcc/src/consts.rs | 17 +---- compiler/rustc_codegen_llvm/src/common.rs | 49 +++++------- compiler/rustc_codegen_ssa/src/mir/operand.rs | 75 ++++++++++++++++++- .../rustc_codegen_ssa/src/traits/consts.rs | 12 +-- tests/codegen/const_scalar_pair.rs | 4 +- 6 files changed, 113 insertions(+), 86 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index ac04b61a3067..bad87db47323 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -1,17 +1,15 @@ use gccjit::LValue; use gccjit::{RValue, Type, ToRValue}; -use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::{ BaseTypeMethods, ConstMethods, - DerivedTypeMethods, MiscMethods, StaticMethods, }; use rustc_middle::mir::Mutability; -use rustc_middle::ty::layout::{TyAndLayout, LayoutOf}; +use rustc_middle::ty::layout::{LayoutOf}; use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar}; -use rustc_target::abi::{self, HasDataLayout, Pointer, Size}; +use rustc_target::abi::{self, HasDataLayout, Pointer}; use crate::consts::const_alloc_to_gcc; use crate::context::CodegenCx; @@ -240,28 +238,26 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { const_alloc_to_gcc(self, alloc) } - fn from_const_alloc(&self, layout: TyAndLayout<'tcx>, alloc: ConstAllocation<'tcx>, offset: Size) -> PlaceRef<'tcx, RValue<'gcc>> { - assert_eq!(alloc.inner().align, layout.align.abi); - let ty = self.type_ptr_to(layout.gcc_type(self)); - let value = - if layout.size == Size::ZERO { - let value = self.const_usize(alloc.inner().align.bytes()); - self.const_bitcast(value, ty) - } - else { - let init = const_alloc_to_gcc(self, alloc); - let base_addr = self.static_addr_of(init, alloc.inner().align, None); - - let array = self.const_bitcast(base_addr, self.type_i8p()); - let value = self.context.new_array_access(None, array, self.const_usize(offset.bytes())).get_address(None); - self.const_bitcast(value, ty) - }; - PlaceRef::new_sized(value, layout) - } - fn const_ptrcast(&self, val: RValue<'gcc>, ty: Type<'gcc>) -> RValue<'gcc> { self.context.new_cast(None, val, ty) } + + fn const_bitcast(&self, value: RValue<'gcc>, typ: Type<'gcc>) -> RValue<'gcc> { + if value.get_type() == self.bool_type.make_pointer() { + if let Some(pointee) = typ.get_pointee() { + if pointee.dyncast_vector().is_some() { + panic!() + } + } + } + // NOTE: since bitcast makes a value non-constant, don't bitcast if not necessary as some + // SIMD builtins require a constant value. + self.bitcast_if_needed(value, typ) + } + + fn const_ptr_byte_offset(&self, base_addr: Self::Value, offset: abi::Size) -> Self::Value { + self.context.new_array_access(None, base_addr, self.const_usize(offset.bytes())).get_address(None) + } } pub trait SignType<'gcc, 'tcx> { diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs index 792ab8f890d8..873f652e6f14 100644 --- a/compiler/rustc_codegen_gcc/src/consts.rs +++ b/compiler/rustc_codegen_gcc/src/consts.rs @@ -1,6 +1,6 @@ #[cfg(feature = "master")] use gccjit::FnAttribute; -use gccjit::{Function, GlobalKind, LValue, RValue, ToRValue, Type}; +use gccjit::{Function, GlobalKind, LValue, RValue, ToRValue}; use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods, DerivedTypeMethods, StaticMethods}; use rustc_middle::span_bug; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; @@ -16,21 +16,6 @@ use crate::context::CodegenCx; use crate::errors::InvalidMinimumAlignment; use crate::type_of::LayoutGccExt; -impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { - pub fn const_bitcast(&self, value: RValue<'gcc>, typ: Type<'gcc>) -> RValue<'gcc> { - if value.get_type() == self.bool_type.make_pointer() { - if let Some(pointee) = typ.get_pointee() { - if pointee.dyncast_vector().is_some() { - panic!() - } - } - } - // NOTE: since bitcast makes a value non-constant, don't bitcast if not necessary as some - // SIMD builtins require a constant value. - self.bitcast_if_needed(value, typ) - } -} - fn set_global_alignment<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, gv: LValue<'gcc>, mut align: Align) { // The target may require greater alignment for globals than the type does. // Note: GCC and Clang also allow `__attribute__((aligned))` on variables, diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index 9127fba388ba..a3910fef9549 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -8,16 +8,15 @@ use crate::type_of::LayoutLlvmExt; use crate::value::Value; use rustc_ast::Mutability; -use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::*; use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher}; use rustc_hir::def_id::DefId; use rustc_middle::bug; use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar}; -use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; +use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::TyCtxt; use rustc_session::cstore::{DllCallingConvention, DllImport, PeImportNameType}; -use rustc_target::abi::{self, AddressSpace, HasDataLayout, Pointer, Size}; +use rustc_target::abi::{self, AddressSpace, HasDataLayout, Pointer}; use rustc_target::spec::Target; use libc::{c_char, c_uint}; @@ -307,38 +306,24 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { const_alloc_to_llvm(self, alloc) } - fn from_const_alloc( - &self, - layout: TyAndLayout<'tcx>, - alloc: ConstAllocation<'tcx>, - offset: Size, - ) -> PlaceRef<'tcx, &'ll Value> { - let alloc_align = alloc.inner().align; - assert_eq!(alloc_align, layout.align.abi); - let llty = self.type_ptr_to(layout.llvm_type(self)); - let llval = if layout.size == Size::ZERO { - let llval = self.const_usize(alloc_align.bytes()); - unsafe { llvm::LLVMConstIntToPtr(llval, llty) } - } else { - let init = const_alloc_to_llvm(self, alloc); - let base_addr = self.static_addr_of(init, alloc_align, None); - - let llval = unsafe { - llvm::LLVMRustConstInBoundsGEP2( - self.type_i8(), - self.const_bitcast(base_addr, self.type_i8p()), - &self.const_usize(offset.bytes()), - 1, - ) - }; - self.const_bitcast(llval, llty) - }; - PlaceRef::new_sized(llval, layout) - } - fn const_ptrcast(&self, val: &'ll Value, ty: &'ll Type) -> &'ll Value { consts::ptrcast(val, ty) } + + fn const_bitcast(&self, val: &'ll Value, ty: &'ll Type) -> &'ll Value { + self.const_bitcast(val, ty) + } + + fn const_ptr_byte_offset(&self, base_addr: Self::Value, offset: abi::Size) -> Self::Value { + unsafe { + llvm::LLVMRustConstInBoundsGEP2( + self.type_i8(), + self.const_bitcast(base_addr, self.type_i8p()), + &self.const_usize(offset.bytes()), + 1, + ) + } + } } /// Get the [LLVM type][Type] of a [`Value`]. diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 2301c3ef13e2..4000c9540ce5 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -8,10 +8,10 @@ use crate::traits::*; use crate::MemFlags; use rustc_middle::mir; -use rustc_middle::mir::interpret::{ConstValue, Pointer, Scalar}; +use rustc_middle::mir::interpret::{alloc_range, ConstValue, Pointer, Scalar}; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::Ty; -use rustc_target::abi::{Abi, Align, Size}; +use rustc_target::abi::{self, Abi, Align, Size}; use std::fmt; @@ -115,13 +115,82 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { OperandValue::Pair(a_llval, b_llval) } ConstValue::ByRef { alloc, offset } => { - return bx.load_operand(bx.from_const_alloc(layout, alloc, offset)); + return Self::from_const_alloc(bx, layout, alloc, offset); } }; OperandRef { val, layout } } + fn from_const_alloc>( + bx: &mut Bx, + layout: TyAndLayout<'tcx>, + alloc: rustc_middle::mir::interpret::ConstAllocation<'tcx>, + offset: Size, + ) -> Self { + let alloc_align = alloc.inner().align; + assert_eq!(alloc_align, layout.align.abi); + let ty = bx.type_ptr_to(bx.cx().backend_type(layout)); + + let read_scalar = |start, size, s: abi::Scalar, ty| { + let val = alloc + .0 + .read_scalar( + bx, + alloc_range(start, size), + /*read_provenance*/ matches!(s.primitive(), abi::Pointer(_)), + ) + .unwrap(); + bx.scalar_to_backend(val, s, ty) + }; + + // It may seem like all types with `Scalar` or `ScalarPair` ABI are fair game at this point. + // However, `MaybeUninit` is considered a `Scalar` as far as its layout is concerned -- + // and yet cannot be represented by an interpreter `Scalar`, since we have to handle the + // case where some of the bytes are initialized and others are not. So, we need an extra + // check that walks over the type of `mplace` to make sure it is truly correct to treat this + // like a `Scalar` (or `ScalarPair`). + match layout.abi { + Abi::Scalar(s @ abi::Scalar::Initialized { .. }) => { + let size = s.size(bx); + assert_eq!(size, layout.size, "abi::Scalar size does not match layout size"); + let val = read_scalar(Size::ZERO, size, s, ty); + OperandRef { val: OperandValue::Immediate(val), layout } + } + Abi::ScalarPair( + a @ abi::Scalar::Initialized { .. }, + b @ abi::Scalar::Initialized { .. }, + ) => { + let (a_size, b_size) = (a.size(bx), b.size(bx)); + let b_offset = a_size.align_to(b.align(bx).abi); + assert!(b_offset.bytes() > 0); + let a_val = read_scalar( + Size::ZERO, + a_size, + a, + bx.scalar_pair_element_backend_type(layout, 0, true), + ); + let b_val = read_scalar( + b_offset, + b_size, + b, + bx.scalar_pair_element_backend_type(layout, 1, true), + ); + OperandRef { val: OperandValue::Pair(a_val, b_val), layout } + } + _ if layout.is_zst() => OperandRef::new_zst(bx, layout), + _ => { + // Neither a scalar nor scalar pair. Load from a place + let init = bx.const_data_from_alloc(alloc); + let base_addr = bx.static_addr_of(init, alloc_align, None); + + let llval = bx.const_ptr_byte_offset(base_addr, offset); + let llval = bx.const_bitcast(llval, ty); + bx.load_operand(PlaceRef::new_sized(llval, layout)) + } + } + } + /// Asserts that this operand refers to a scalar and returns /// a reference to its value. pub fn immediate(self) -> V { diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs index 61906302779e..dc2fc3964801 100644 --- a/compiler/rustc_codegen_ssa/src/traits/consts.rs +++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs @@ -1,8 +1,6 @@ use super::BackendTypes; -use crate::mir::place::PlaceRef; use rustc_middle::mir::interpret::{ConstAllocation, Scalar}; -use rustc_middle::ty::layout::TyAndLayout; -use rustc_target::abi::{self, Size}; +use rustc_target::abi; pub trait ConstMethods<'tcx>: BackendTypes { // Constant constructors @@ -30,12 +28,8 @@ pub trait ConstMethods<'tcx>: BackendTypes { fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value; fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: Self::Type) -> Self::Value; - fn from_const_alloc( - &self, - layout: TyAndLayout<'tcx>, - alloc: ConstAllocation<'tcx>, - offset: Size, - ) -> PlaceRef<'tcx, Self::Value>; fn const_ptrcast(&self, val: Self::Value, ty: Self::Type) -> Self::Value; + fn const_bitcast(&self, val: Self::Value, ty: Self::Type) -> Self::Value; + fn const_ptr_byte_offset(&self, val: Self::Value, offset: abi::Size) -> Self::Value; } diff --git a/tests/codegen/const_scalar_pair.rs b/tests/codegen/const_scalar_pair.rs index 16e6484585c9..8f32c50b7988 100644 --- a/tests/codegen/const_scalar_pair.rs +++ b/tests/codegen/const_scalar_pair.rs @@ -1,10 +1,8 @@ // compile-flags: --crate-type=lib -Copt-level=0 -Zmir-opt-level=0 -C debuginfo=2 -// CHECK: @0 = private unnamed_addr constant <{ [8 x i8] }> <{ [8 x i8] c"\01\00\00\00\02\00\00\00" }>, align 4 - #![feature(inline_const)] pub fn foo() -> (i32, i32) { - // CHECK: %0 = load i32, ptr @0, align 4 + // CHECK: ret { i32, i32 } { i32 1, i32 2 } const { (1, 2) } } From 976adf3d6de5eb708cd9b346e7749eb2cac00ea9 Mon Sep 17 00:00:00 2001 From: Boxy Date: Fri, 26 May 2023 18:54:59 +0100 Subject: [PATCH 13/69] better `TyKind::Debug` --- compiler/rustc_middle/src/ty/context.rs | 10 +++ compiler/rustc_middle/src/ty/mod.rs | 2 +- compiler/rustc_middle/src/ty/print/pretty.rs | 62 +++++----------- .../rustc_middle/src/ty/structural_impls.rs | 59 +++++++++++++-- compiler/rustc_middle/src/ty/sty.rs | 3 +- compiler/rustc_type_ir/src/lib.rs | 23 ++++-- .../rustc_type_ir/src/structural_impls.rs | 21 +++++- compiler/rustc_type_ir/src/sty.rs | 72 +++++++++++++------ tests/ui/thir-print/thir-flat.stdout | 2 +- 9 files changed, 176 insertions(+), 78 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 2bde55bc4fd3..0cde46ae4c2a 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -115,6 +115,16 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type FreeRegion = ty::FreeRegion; type RegionVid = ty::RegionVid; type PlaceholderRegion = ty::PlaceholderRegion; + + fn ty_and_mut_to_parts( + TypeAndMut { ty, mutbl }: TypeAndMut<'tcx>, + ) -> (Self::Ty, Self::Mutability) { + (ty, mutbl) + } + + fn mutability_is_mut(mutbl: Self::Mutability) -> bool { + mutbl.is_mut() + } } type InternedSet<'tcx, T> = ShardedHashMap, ()>; diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index a8d0dca37ff9..025432fcaa80 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1496,7 +1496,7 @@ impl<'tcx> OpaqueHiddenType<'tcx> { /// identified by both a universe, as well as a name residing within that universe. Distinct bound /// regions/types/consts within the same universe simply have an unknown relationship to one /// another. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] #[derive(HashStable, TyEncodable, TyDecodable)] pub struct Placeholder { pub universe: UniverseIndex, diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index a064174e2616..1c216960d118 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -685,29 +685,30 @@ pub trait PrettyPrinter<'tcx>: } ty::FnPtr(ref bare_fn) => p!(print(bare_fn)), ty::Infer(infer_ty) => { - let verbose = self.should_print_verbose(); + if self.should_print_verbose() { + p!(write("{:?}", ty.kind())); + return Ok(self); + } + if let ty::TyVar(ty_vid) = infer_ty { if let Some(name) = self.ty_infer_name(ty_vid) { p!(write("{}", name)) } else { - if verbose { - p!(write("{:?}", infer_ty)) - } else { - p!(write("{}", infer_ty)) - } + p!(write("{}", infer_ty)) } } else { - if verbose { p!(write("{:?}", infer_ty)) } else { p!(write("{}", infer_ty)) } + p!(write("{}", infer_ty)) } } ty::Error(_) => p!("[type error]"), ty::Param(ref param_ty) => p!(print(param_ty)), ty::Bound(debruijn, bound_ty) => match bound_ty.kind { - ty::BoundTyKind::Anon => debug_bound_var(&mut self, debruijn, bound_ty.var)?, + ty::BoundTyKind::Anon => { + rustc_type_ir::debug_bound_var(&mut self, debruijn, bound_ty.var)? + } ty::BoundTyKind::Param(_, s) => match self.should_print_verbose() { - true if debruijn == ty::INNERMOST => p!(write("^{}", s)), - true => p!(write("^{}_{}", debruijn.index(), s)), - false => p!(write("{}", s)), + true => p!(write("{:?}", ty.kind())), + false => p!(write("{s}")), }, }, ty::Adt(def, substs) => { @@ -740,10 +741,11 @@ pub trait PrettyPrinter<'tcx>: } } ty::Placeholder(placeholder) => match placeholder.bound.kind { - ty::BoundTyKind::Anon => { - debug_placeholder_var(&mut self, placeholder.universe, placeholder.bound.var)?; - } - ty::BoundTyKind::Param(_, name) => p!(write("{}", name)), + ty::BoundTyKind::Anon => p!(write("{placeholder:?}")), + ty::BoundTyKind::Param(_, name) => match self.should_print_verbose() { + true => p!(write("{:?}", ty.kind())), + false => p!(write("{name}")), + }, }, ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { // We use verbose printing in 'NO_QUERIES' mode, to @@ -1372,11 +1374,9 @@ pub trait PrettyPrinter<'tcx>: } ty::ConstKind::Bound(debruijn, bound_var) => { - debug_bound_var(&mut self, debruijn, bound_var)? + rustc_type_ir::debug_bound_var(&mut self, debruijn, bound_var)? } - ty::ConstKind::Placeholder(placeholder) => { - debug_placeholder_var(&mut self, placeholder.universe, placeholder.bound)?; - }, + ty::ConstKind::Placeholder(placeholder) => p!(write("{placeholder:?}")), // FIXME(generic_const_exprs): // write out some legible representation of an abstract const? ty::ConstKind::Expr(_) => p!("[const expr]"), @@ -3065,27 +3065,3 @@ pub struct OpaqueFnEntry<'tcx> { fn_trait_ref: Option>, return_ty: Option>>, } - -pub fn debug_bound_var( - fmt: &mut T, - debruijn: ty::DebruijnIndex, - var: ty::BoundVar, -) -> Result<(), std::fmt::Error> { - if debruijn == ty::INNERMOST { - write!(fmt, "^{}", var.index()) - } else { - write!(fmt, "^{}_{}", debruijn.index(), var.index()) - } -} - -pub fn debug_placeholder_var( - fmt: &mut T, - universe: ty::UniverseIndex, - bound: ty::BoundVar, -) -> Result<(), std::fmt::Error> { - if universe == ty::UniverseIndex::ROOT { - write!(fmt, "!{}", bound.index()) - } else { - write!(fmt, "!{}_{}", universe.index(), bound.index()) - } -} diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 16cb6c910463..a965450d27d4 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -88,7 +88,35 @@ impl fmt::Debug for ty::FreeRegion { impl<'tcx> fmt::Debug for ty::FnSig<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "({:?}; c_variadic: {})->{:?}", self.inputs(), self.c_variadic, self.output()) + let ty::FnSig { inputs_and_output: _, c_variadic, unsafety, abi } = self; + + write!(f, "{}", unsafety.prefix_str())?; + match abi { + rustc_target::spec::abi::Abi::Rust => (), + abi => write!(f, "extern \"{abi:?}\" ")?, + }; + + write!(f, "fn(")?; + let inputs = self.inputs(); + match inputs.len() { + 0 if *c_variadic => write!(f, "...)")?, + 0 => write!(f, ")")?, + _ => { + for ty in &self.inputs()[0..(self.inputs().len() - 1)] { + write!(f, "{ty:?}, ")?; + } + write!(f, "{:?}", self.inputs().last().unwrap())?; + if *c_variadic { + write!(f, "...")?; + } + write!(f, ")")?; + } + } + + match self.output().kind() { + ty::Tuple(list) if list.is_empty() => Ok(()), + _ => write!(f, " -> {:?}", self.output()), + } } } @@ -216,20 +244,37 @@ impl<'tcx> fmt::Debug for ty::ConstKind<'tcx> { match self { Param(param) => write!(f, "{param:?}"), Infer(var) => write!(f, "{var:?}"), - Bound(debruijn, var) => ty::print::debug_bound_var(f, *debruijn, *var), - Placeholder(placeholder) => { - ty::print::debug_placeholder_var(f, placeholder.universe, placeholder.bound) - } + Bound(debruijn, var) => rustc_type_ir::debug_bound_var(f, *debruijn, *var), + Placeholder(placeholder) => write!(f, "{placeholder:?}"), Unevaluated(uv) => { f.debug_tuple("Unevaluated").field(&uv.substs).field(&uv.def).finish() } Value(valtree) => write!(f, "{valtree:?}"), - Error(_) => write!(f, "[const error]"), + Error(_) => write!(f, "{{const error}}"), Expr(expr) => write!(f, "{expr:?}"), } } } +impl fmt::Debug for ty::BoundTy { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.kind { + ty::BoundTyKind::Anon => write!(f, "{:?}", self.var), + ty::BoundTyKind::Param(_, sym) => write!(f, "{sym:?}"), + } + } +} + +impl fmt::Debug for ty::Placeholder { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.universe == ty::UniverseIndex::ROOT { + write!(f, "!{:?}", self.bound) + } else { + write!(f, "!{}_{:?}", self.universe.index(), self.bound) + } + } +} + /////////////////////////////////////////////////////////////////////////// // Atomic structs // @@ -294,6 +339,7 @@ TrivialTypeTraversalAndLiftImpls! { crate::ty::AliasRelationDirection, crate::ty::Placeholder, crate::ty::Placeholder, + crate::ty::Placeholder, crate::ty::ClosureKind, crate::ty::FreeRegion, crate::ty::InferTy, @@ -310,7 +356,6 @@ TrivialTypeTraversalAndLiftImpls! { interpret::Scalar, rustc_target::abi::Size, ty::BoundVar, - ty::Placeholder, } TrivialTypeTraversalAndLiftImpls! { diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index e6d51c4ec977..0b722d9368bc 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1511,10 +1511,11 @@ impl Atom for RegionVid { rustc_index::newtype_index! { #[derive(HashStable)] + #[debug_format = "{}"] pub struct BoundVar {} } -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] #[derive(HashStable)] pub struct BoundTy { pub var: BoundVar, diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index f6b44bdf27ef..ae16fbb162e5 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -52,7 +52,7 @@ pub trait Interner: Sized { type PolyFnSig: Clone + Debug + Hash + Ord; type ListBinderExistentialPredicate: Clone + Debug + Hash + Ord; type BinderListTy: Clone + Debug + Hash + Ord; - type ListTy: Clone + Debug + Hash + Ord; + type ListTy: Clone + Debug + Hash + Ord + IntoIterator; type AliasTy: Clone + Debug + Hash + Ord; type ParamTy: Clone + Debug + Hash + Ord; type BoundTy: Clone + Debug + Hash + Ord; @@ -67,6 +67,9 @@ pub trait Interner: Sized { type FreeRegion: Clone + Debug + Hash + Ord; type RegionVid: Clone + Debug + Hash + Ord; type PlaceholderRegion: Clone + Debug + Hash + Ord; + + fn ty_and_mut_to_parts(ty_and_mut: Self::TypeAndMut) -> (Self::Ty, Self::Mutability); + fn mutability_is_mut(mutbl: Self::Mutability) -> bool; } /// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter` @@ -390,7 +393,19 @@ impl DebruijnIndex { } } -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub fn debug_bound_var( + fmt: &mut T, + debruijn: DebruijnIndex, + var: impl std::fmt::Debug, +) -> Result<(), std::fmt::Error> { + if debruijn == INNERMOST { + write!(fmt, "^{:?}", var) + } else { + write!(fmt, "^{}_{:?}", debruijn.index(), var) + } +} + +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Encodable, Decodable, HashStable_Generic)] pub enum IntTy { Isize, @@ -448,7 +463,7 @@ impl IntTy { } } -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Debug)] +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] #[derive(Encodable, Decodable, HashStable_Generic)] pub enum UintTy { Usize, @@ -506,7 +521,7 @@ impl UintTy { } } -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Encodable, Decodable, HashStable_Generic)] pub enum FloatTy { F32, diff --git a/compiler/rustc_type_ir/src/structural_impls.rs b/compiler/rustc_type_ir/src/structural_impls.rs index 45a2e9023c9c..553d7f31b2d1 100644 --- a/compiler/rustc_type_ir/src/structural_impls.rs +++ b/compiler/rustc_type_ir/src/structural_impls.rs @@ -4,11 +4,12 @@ use crate::fold::{FallibleTypeFolder, TypeFoldable}; use crate::visit::{TypeVisitable, TypeVisitor}; -use crate::Interner; +use crate::{FloatTy, IntTy, Interner, UintTy}; use rustc_data_structures::functor::IdFunctor; use rustc_data_structures::sync::Lrc; use rustc_index::{Idx, IndexVec}; +use core::fmt; use std::ops::ControlFlow; /////////////////////////////////////////////////////////////////////////// @@ -163,3 +164,21 @@ impl, Ix: Idx> TypeVisitable for IndexVec) -> fmt::Result { + write!(f, "{}", self.name_str()) + } +} + +impl fmt::Debug for UintTy { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.name_str()) + } +} + +impl fmt::Debug for FloatTy { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.name_str()) + } +} diff --git a/compiler/rustc_type_ir/src/sty.rs b/compiler/rustc_type_ir/src/sty.rs index f7344bacc028..fa18f921ee4b 100644 --- a/compiler/rustc_type_ir/src/sty.rs +++ b/compiler/rustc_type_ir/src/sty.rs @@ -294,7 +294,7 @@ impl Clone for TyKind { Str => Str, Array(t, c) => Array(t.clone(), c.clone()), Slice(t) => Slice(t.clone()), - RawPtr(t) => RawPtr(t.clone()), + RawPtr(p) => RawPtr(p.clone()), Ref(r, t, m) => Ref(r.clone(), t.clone(), m.clone()), FnDef(d, s) => FnDef(d.clone(), s.clone()), FnPtr(s) => FnPtr(s.clone()), @@ -499,33 +499,65 @@ impl hash::Hash for TyKind { impl fmt::Debug for TyKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Bool => f.write_str("Bool"), - Char => f.write_str("Char"), - Int(i) => f.debug_tuple_field1_finish("Int", i), - Uint(u) => f.debug_tuple_field1_finish("Uint", u), - Float(float) => f.debug_tuple_field1_finish("Float", float), + Bool => write!(f, "bool"), + Char => write!(f, "char"), + Int(i) => write!(f, "{i:?}"), + Uint(u) => write!(f, "{u:?}"), + Float(float) => write!(f, "{float:?}"), Adt(d, s) => f.debug_tuple_field2_finish("Adt", d, s), Foreign(d) => f.debug_tuple_field1_finish("Foreign", d), - Str => f.write_str("Str"), - Array(t, c) => f.debug_tuple_field2_finish("Array", t, c), - Slice(t) => f.debug_tuple_field1_finish("Slice", t), - RawPtr(t) => f.debug_tuple_field1_finish("RawPtr", t), - Ref(r, t, m) => f.debug_tuple_field3_finish("Ref", r, t, m), + Str => write!(f, "str"), + Array(t, c) => write!(f, "[{t:?}; {c:?}]"), + Slice(t) => write!(f, "[{t:?}]"), + RawPtr(p) => { + let (ty, mutbl) = I::ty_and_mut_to_parts(p.clone()); + match I::mutability_is_mut(mutbl) { + true => write!(f, "*mut "), + false => write!(f, "*const "), + }?; + write!(f, "{ty:?}") + } + Ref(r, t, m) => match I::mutability_is_mut(m.clone()) { + true => write!(f, "&{r:?} mut {t:?}"), + false => write!(f, "&{r:?} {t:?}"), + }, FnDef(d, s) => f.debug_tuple_field2_finish("FnDef", d, s), - FnPtr(s) => f.debug_tuple_field1_finish("FnPtr", s), - Dynamic(p, r, repr) => f.debug_tuple_field3_finish("Dynamic", p, r, repr), + FnPtr(s) => write!(f, "{s:?}"), + Dynamic(p, r, repr) => match repr { + DynKind::Dyn => write!(f, "dyn {p:?} + {r:?}"), + DynKind::DynStar => write!(f, "dyn* {p:?} + {r:?}"), + }, Closure(d, s) => f.debug_tuple_field2_finish("Closure", d, s), Generator(d, s, m) => f.debug_tuple_field3_finish("Generator", d, s, m), GeneratorWitness(g) => f.debug_tuple_field1_finish("GeneratorWitness", g), GeneratorWitnessMIR(d, s) => f.debug_tuple_field2_finish("GeneratorWitnessMIR", d, s), - Never => f.write_str("Never"), - Tuple(t) => f.debug_tuple_field1_finish("Tuple", t), + Never => write!(f, "!"), + Tuple(t) => { + let mut iter = t.clone().into_iter(); + + write!(f, "(")?; + + match iter.next() { + None => return write!(f, ")"), + Some(ty) => write!(f, "{ty:?}")?, + }; + + match iter.next() { + None => return write!(f, ",)"), + Some(ty) => write!(f, "{ty:?})")?, + } + + for ty in iter { + write!(f, ", {ty:?}")?; + } + write!(f, ")") + } Alias(i, a) => f.debug_tuple_field2_finish("Alias", i, a), - Param(p) => f.debug_tuple_field1_finish("Param", p), - Bound(d, b) => f.debug_tuple_field2_finish("Bound", d, b), - Placeholder(p) => f.debug_tuple_field1_finish("Placeholder", p), - Infer(t) => f.debug_tuple_field1_finish("Infer", t), - TyKind::Error(e) => f.debug_tuple_field1_finish("Error", e), + Param(p) => write!(f, "{p:?}"), + Bound(d, b) => crate::debug_bound_var(f, *d, b), + Placeholder(p) => write!(f, "{p:?}"), + Infer(t) => write!(f, "{t:?}"), + TyKind::Error(_) => write!(f, "{{type error}}"), } } } diff --git a/tests/ui/thir-print/thir-flat.stdout b/tests/ui/thir-print/thir-flat.stdout index 9d467f73d097..b0aa44b56aa9 100644 --- a/tests/ui/thir-print/thir-flat.stdout +++ b/tests/ui/thir-print/thir-flat.stdout @@ -1,7 +1,7 @@ DefId(0:3 ~ thir_flat[7b97]::main): Thir { body_type: Fn( - ([]; c_variadic: false)->(), + fn(), ), arms: [], blocks: [ From 7f8846a9ef4426d18b911783ab83b83a80a852d1 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 13 May 2023 17:12:45 +0200 Subject: [PATCH 14/69] Uplift clippy::invalid_utf8_in_unchecked as invalid_from_utf8_unchecked --- compiler/rustc_lint/messages.ftl | 4 + compiler/rustc_lint/src/invalid_from_utf8.rs | 85 ++++++++++++++++++++ compiler/rustc_lint/src/lib.rs | 3 + compiler/rustc_lint/src/lints.rs | 10 +++ compiler/rustc_span/src/symbol.rs | 2 + library/core/src/str/converts.rs | 2 + tests/ui/lint/invalid_from_utf8.rs | 49 +++++++++++ tests/ui/lint/invalid_from_utf8.stderr | 56 +++++++++++++ 8 files changed, 211 insertions(+) create mode 100644 compiler/rustc_lint/src/invalid_from_utf8.rs create mode 100644 tests/ui/lint/invalid_from_utf8.rs create mode 100644 tests/ui/lint/invalid_from_utf8.stderr diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index d34a3afcba53..35edb4584780 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -304,6 +304,10 @@ lint_improper_ctypes_union_layout_help = consider adding a `#[repr(C)]` or `#[re lint_improper_ctypes_union_layout_reason = this union has unspecified layout lint_improper_ctypes_union_non_exhaustive = this union is non-exhaustive +# FIXME: we should ordinalize $valid_up_to when we add support for doing so +lint_invalid_from_utf8_unchecked = calls to `{$method}` with a invalid literal are undefined behavior + .label = the literal was valid UTF-8 up to the {$valid_up_to} bytes + lint_lintpass_by_hand = implementing `LintPass` by hand .help = try using `declare_lint_pass!` or `impl_lint_pass!` instead diff --git a/compiler/rustc_lint/src/invalid_from_utf8.rs b/compiler/rustc_lint/src/invalid_from_utf8.rs new file mode 100644 index 000000000000..2118deba5c71 --- /dev/null +++ b/compiler/rustc_lint/src/invalid_from_utf8.rs @@ -0,0 +1,85 @@ +use std::str::Utf8Error; + +use rustc_ast::{BorrowKind, LitKind}; +use rustc_hir::{Expr, ExprKind}; +use rustc_span::source_map::Spanned; +use rustc_span::sym; + +use crate::lints::InvalidFromUtf8UncheckedDiag; +use crate::{LateContext, LateLintPass, LintContext}; + +declare_lint! { + /// The `invalid_from_utf8_unchecked` lint checks for calls to + /// `std::str::from_utf8_unchecked` and `std::str::from_utf8_unchecked_mut` + /// with an invalid UTF-8 literal. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// # #[allow(unused)] + /// unsafe { + /// std::str::from_utf8_unchecked(b"Ru\x82st"); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Creating such a `str` would result in undefined behavior as per documentation + /// for `std::str::from_utf8_unchecked` and `std::str::from_utf8_unchecked_mut`. + pub INVALID_FROM_UTF8_UNCHECKED, + Deny, + "using a non UTF-8 literal in `std::str::from_utf8_unchecked`" +} + +declare_lint_pass!(InvalidFromUtf8 => [INVALID_FROM_UTF8_UNCHECKED]); + +impl<'tcx> LateLintPass<'tcx> for InvalidFromUtf8 { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if let ExprKind::Call(path, [arg]) = expr.kind + && let ExprKind::Path(ref qpath) = path.kind + && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() + && let Some(diag_item) = cx.tcx.get_diagnostic_name(def_id) + && [sym::str_from_utf8_unchecked, sym::str_from_utf8_unchecked_mut].contains(&diag_item) + { + let lint = |utf8_error: Utf8Error| { + let method = diag_item.as_str().strip_prefix("str_").unwrap(); + cx.emit_spanned_lint(INVALID_FROM_UTF8_UNCHECKED, expr.span, InvalidFromUtf8UncheckedDiag { + method: format!("std::str::{method}"), + valid_up_to: utf8_error.valid_up_to(), + label: arg.span, + }) + }; + + match &arg.kind { + ExprKind::Lit(Spanned { node: lit, .. }) => { + if let LitKind::ByteStr(bytes, _) = &lit + && let Err(utf8_error) = std::str::from_utf8(bytes) + { + lint(utf8_error); + } + }, + ExprKind::AddrOf(BorrowKind::Ref, _, Expr { kind: ExprKind::Array(args), .. }) => { + let elements = args.iter().map(|e|{ + match &e.kind { + ExprKind::Lit(Spanned { node: lit, .. }) => match lit { + LitKind::Byte(b) => Some(*b), + LitKind::Int(b, _) => Some(*b as u8), + _ => None + } + _ => None + } + }).collect::>>(); + + if let Some(elements) = elements + && let Err(utf8_error) = std::str::from_utf8(&elements) + { + lint(utf8_error); + } + } + _ => {} + } + } + } +} diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index dfddfe09ab3c..c62109b29862 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -60,6 +60,7 @@ mod expect; mod for_loops_over_fallibles; pub mod hidden_unicode_codepoints; mod internal; +mod invalid_from_utf8; mod late; mod let_underscore; mod levels; @@ -102,6 +103,7 @@ use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums; use for_loops_over_fallibles::*; use hidden_unicode_codepoints::*; use internal::*; +use invalid_from_utf8::*; use let_underscore::*; use map_unit_fn::*; use methods::*; @@ -207,6 +209,7 @@ late_lint_methods!( HardwiredLints: HardwiredLints, ImproperCTypesDeclarations: ImproperCTypesDeclarations, ImproperCTypesDefinitions: ImproperCTypesDefinitions, + InvalidFromUtf8: InvalidFromUtf8, VariantSizeDifferences: VariantSizeDifferences, BoxPointers: BoxPointers, PathStatements: PathStatements, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index de1c2be28757..5969bc5ca5a3 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -699,6 +699,16 @@ pub struct ForgetCopyDiag<'a> { pub label: Span, } +// invalid_from_utf8.rs +#[derive(LintDiagnostic)] +#[diag(lint_invalid_from_utf8_unchecked)] +pub struct InvalidFromUtf8UncheckedDiag { + pub method: String, + pub valid_up_to: usize, + #[label] + pub label: Span, +} + // hidden_unicode_codepoints.rs #[derive(LintDiagnostic)] #[diag(lint_hidden_unicode_codepoints)] diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 874d578fe1db..4fc73c4ae864 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1454,6 +1454,8 @@ symbols! { stop_after_dataflow, store, str, + str_from_utf8_unchecked, + str_from_utf8_unchecked_mut, str_split_whitespace, str_trim, str_trim_end, diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs index 5f8748206d76..12fac0567cb4 100644 --- a/library/core/src/str/converts.rs +++ b/library/core/src/str/converts.rs @@ -167,6 +167,7 @@ pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_from_utf8_unchecked", since = "1.55.0")] +#[rustc_diagnostic_item = "str_from_utf8_unchecked"] pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { // SAFETY: the caller must guarantee that the bytes `v` are valid UTF-8. // Also relies on `&str` and `&[u8]` having the same layout. @@ -194,6 +195,7 @@ pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { #[must_use] #[stable(feature = "str_mut_extras", since = "1.20.0")] #[rustc_const_unstable(feature = "const_str_from_utf8_unchecked_mut", issue = "91005")] +#[rustc_diagnostic_item = "str_from_utf8_unchecked_mut"] pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { // SAFETY: the caller must guarantee that the bytes `v` // are valid UTF-8, thus the cast to `*mut str` is safe. diff --git a/tests/ui/lint/invalid_from_utf8.rs b/tests/ui/lint/invalid_from_utf8.rs new file mode 100644 index 000000000000..4a27c659c73d --- /dev/null +++ b/tests/ui/lint/invalid_from_utf8.rs @@ -0,0 +1,49 @@ +// check-pass + +#![feature(concat_bytes)] +#![warn(invalid_from_utf8_unchecked)] + +pub fn from_utf8_unchecked_mut() { + // Valid + unsafe { + std::str::from_utf8_unchecked_mut(&mut [99, 108, 105, 112, 112, 121]); + std::str::from_utf8_unchecked_mut(&mut [b'c', b'l', b'i', b'p', b'p', b'y']); + + let x = 0xA0; + std::str::from_utf8_unchecked_mut(&mut [0xC0, x]); + } + + // Invalid + unsafe { + std::str::from_utf8_unchecked_mut(&mut [99, 108, 130, 105, 112, 112, 121]); + //~^ WARN calls to `std::str::from_utf8_unchecked_mut` + std::str::from_utf8_unchecked_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); + //~^ WARN calls to `std::str::from_utf8_unchecked_mut` + } +} + +pub fn from_utf8_unchecked() { + // Valid + unsafe { + std::str::from_utf8_unchecked(&[99, 108, 105, 112, 112, 121]); + std::str::from_utf8_unchecked(&[b'c', b'l', b'i', b'p', b'p', b'y']); + std::str::from_utf8_unchecked(b"clippy"); + + let x = 0xA0; + std::str::from_utf8_unchecked(&[0xC0, x]); + } + + // Invalid + unsafe { + std::str::from_utf8_unchecked(&[99, 108, 130, 105, 112, 112, 121]); + //~^ WARN calls to `std::str::from_utf8_unchecked` + std::str::from_utf8_unchecked(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); + //~^ WARN calls to `std::str::from_utf8_unchecked` + std::str::from_utf8_unchecked(b"cl\x82ippy"); + //~^ WARN calls to `std::str::from_utf8_unchecked` + std::str::from_utf8_unchecked(concat_bytes!(b"cl", b"\x82ippy")); + //~^ WARN calls to `std::str::from_utf8_unchecked` + } +} + +fn main() {} diff --git a/tests/ui/lint/invalid_from_utf8.stderr b/tests/ui/lint/invalid_from_utf8.stderr new file mode 100644 index 000000000000..63cd906237dd --- /dev/null +++ b/tests/ui/lint/invalid_from_utf8.stderr @@ -0,0 +1,56 @@ +warning: calls to `std::str::from_utf8_unchecked_mut` with a invalid literal are undefined behavior + --> $DIR/invalid_from_utf8.rs:18:9 + | +LL | std::str::from_utf8_unchecked_mut(&mut [99, 108, 130, 105, 112, 112, 121]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + | +note: the lint level is defined here + --> $DIR/invalid_from_utf8.rs:4:9 + | +LL | #![warn(invalid_from_utf8_unchecked)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: calls to `std::str::from_utf8_unchecked_mut` with a invalid literal are undefined behavior + --> $DIR/invalid_from_utf8.rs:20:9 + | +LL | std::str::from_utf8_unchecked_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------------------------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior + --> $DIR/invalid_from_utf8.rs:38:9 + | +LL | std::str::from_utf8_unchecked(&[99, 108, 130, 105, 112, 112, 121]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior + --> $DIR/invalid_from_utf8.rs:40:9 + | +LL | std::str::from_utf8_unchecked(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior + --> $DIR/invalid_from_utf8.rs:42:9 + | +LL | std::str::from_utf8_unchecked(b"cl\x82ippy"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior + --> $DIR/invalid_from_utf8.rs:44:9 + | +LL | std::str::from_utf8_unchecked(concat_bytes!(b"cl", b"\x82ippy")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: 6 warnings emitted + From a0612d90b08e2ee3fac4e807f56e51dd665ec882 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 13 May 2023 18:11:27 +0200 Subject: [PATCH 15/69] Drop uplifted clippy::invalid_utf8_in_unchecked --- .../clippy/clippy_lints/src/declared_lints.rs | 1 - .../src/invalid_utf8_in_unchecked.rs | 74 ------------- src/tools/clippy/clippy_lints/src/lib.rs | 2 - .../clippy/clippy_lints/src/renamed_lints.rs | 1 + .../tests/ui/invalid_utf8_in_unchecked.rs | 20 ---- .../tests/ui/invalid_utf8_in_unchecked.stderr | 22 ---- src/tools/clippy/tests/ui/rename.fixed | 2 + src/tools/clippy/tests/ui/rename.rs | 2 + src/tools/clippy/tests/ui/rename.stderr | 104 +++++++++--------- 9 files changed, 60 insertions(+), 168 deletions(-) delete mode 100644 src/tools/clippy/clippy_lints/src/invalid_utf8_in_unchecked.rs delete mode 100644 src/tools/clippy/tests/ui/invalid_utf8_in_unchecked.rs delete mode 100644 src/tools/clippy/tests/ui/invalid_utf8_in_unchecked.stderr diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index 423eee47742e..0ae95b045e03 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -212,7 +212,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::instant_subtraction::UNCHECKED_DURATION_SUBTRACTION_INFO, crate::int_plus_one::INT_PLUS_ONE_INFO, crate::invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS_INFO, - crate::invalid_utf8_in_unchecked::INVALID_UTF8_IN_UNCHECKED_INFO, crate::items_after_statements::ITEMS_AFTER_STATEMENTS_INFO, crate::items_after_test_module::ITEMS_AFTER_TEST_MODULE_INFO, crate::iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR_INFO, diff --git a/src/tools/clippy/clippy_lints/src/invalid_utf8_in_unchecked.rs b/src/tools/clippy/clippy_lints/src/invalid_utf8_in_unchecked.rs deleted file mode 100644 index 6a4861747d26..000000000000 --- a/src/tools/clippy/clippy_lints/src/invalid_utf8_in_unchecked.rs +++ /dev/null @@ -1,74 +0,0 @@ -use clippy_utils::diagnostics::span_lint; -use clippy_utils::{match_function_call, paths}; -use rustc_ast::{BorrowKind, LitKind}; -use rustc_hir::{Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Spanned; -use rustc_span::Span; - -declare_clippy_lint! { - /// ### What it does - /// Checks for `std::str::from_utf8_unchecked` with an invalid UTF-8 literal - /// - /// ### Why is this bad? - /// Creating such a `str` would result in undefined behavior - /// - /// ### Example - /// ```rust - /// # #[allow(unused)] - /// unsafe { - /// std::str::from_utf8_unchecked(b"cl\x82ippy"); - /// } - /// ``` - #[clippy::version = "1.64.0"] - pub INVALID_UTF8_IN_UNCHECKED, - correctness, - "using a non UTF-8 literal in `std::std::from_utf8_unchecked`" -} -declare_lint_pass!(InvalidUtf8InUnchecked => [INVALID_UTF8_IN_UNCHECKED]); - -impl<'tcx> LateLintPass<'tcx> for InvalidUtf8InUnchecked { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if let Some([arg]) = match_function_call(cx, expr, &paths::STR_FROM_UTF8_UNCHECKED) { - match &arg.kind { - ExprKind::Lit(Spanned { node: lit, .. }) => { - if let LitKind::ByteStr(bytes, _) = &lit - && std::str::from_utf8(bytes).is_err() - { - lint(cx, expr.span); - } - }, - ExprKind::AddrOf(BorrowKind::Ref, _, Expr { kind: ExprKind::Array(args), .. }) => { - let elements = args.iter().map(|e|{ - match &e.kind { - ExprKind::Lit(Spanned { node: lit, .. }) => match lit { - LitKind::Byte(b) => Some(*b), - #[allow(clippy::cast_possible_truncation)] - LitKind::Int(b, _) => Some(*b as u8), - _ => None - } - _ => None - } - }).collect::>>(); - - if let Some(elements) = elements - && std::str::from_utf8(&elements).is_err() - { - lint(cx, expr.span); - } - } - _ => {} - } - } - } -} - -fn lint(cx: &LateContext<'_>, span: Span) { - span_lint( - cx, - INVALID_UTF8_IN_UNCHECKED, - span, - "non UTF-8 literal in `std::str::from_utf8_unchecked`", - ); -} diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index b442a4ac5f61..fcca595c2bc4 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -157,7 +157,6 @@ mod inline_fn_without_body; mod instant_subtraction; mod int_plus_one; mod invalid_upcast_comparisons; -mod invalid_utf8_in_unchecked; mod items_after_statements; mod items_after_test_module; mod iter_not_returning_iterator; @@ -937,7 +936,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move |_| Box::new(manual_retain::ManualRetain::new(msrv()))); let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold; store.register_late_pass(move |_| Box::new(operators::Operators::new(verbose_bit_mask_threshold))); - store.register_late_pass(|_| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked)); store.register_late_pass(|_| Box::::default()); store.register_late_pass(move |_| Box::new(instant_subtraction::InstantSubtraction::new(msrv()))); store.register_late_pass(|_| Box::new(partialeq_to_none::PartialeqToNone)); diff --git a/src/tools/clippy/clippy_lints/src/renamed_lints.rs b/src/tools/clippy/clippy_lints/src/renamed_lints.rs index b0db56bb417e..7c2a100efdac 100644 --- a/src/tools/clippy/clippy_lints/src/renamed_lints.rs +++ b/src/tools/clippy/clippy_lints/src/renamed_lints.rs @@ -43,6 +43,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[ ("clippy::into_iter_on_array", "array_into_iter"), ("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"), ("clippy::invalid_ref", "invalid_value"), + ("clippy::invalid_utf8_in_unchecked", "invalid_from_utf8_unchecked"), ("clippy::let_underscore_drop", "let_underscore_drop"), ("clippy::mem_discriminant_non_enum", "enum_intrinsics_non_enums"), ("clippy::panic_params", "non_fmt_panics"), diff --git a/src/tools/clippy/tests/ui/invalid_utf8_in_unchecked.rs b/src/tools/clippy/tests/ui/invalid_utf8_in_unchecked.rs deleted file mode 100644 index 3dc096d3197f..000000000000 --- a/src/tools/clippy/tests/ui/invalid_utf8_in_unchecked.rs +++ /dev/null @@ -1,20 +0,0 @@ -#![warn(clippy::invalid_utf8_in_unchecked)] - -fn main() { - // Valid - unsafe { - std::str::from_utf8_unchecked(&[99, 108, 105, 112, 112, 121]); - std::str::from_utf8_unchecked(&[b'c', b'l', b'i', b'p', b'p', b'y']); - std::str::from_utf8_unchecked(b"clippy"); - - let x = 0xA0; - std::str::from_utf8_unchecked(&[0xC0, x]); - } - - // Invalid - unsafe { - std::str::from_utf8_unchecked(&[99, 108, 130, 105, 112, 112, 121]); - std::str::from_utf8_unchecked(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); - std::str::from_utf8_unchecked(b"cl\x82ippy"); - } -} diff --git a/src/tools/clippy/tests/ui/invalid_utf8_in_unchecked.stderr b/src/tools/clippy/tests/ui/invalid_utf8_in_unchecked.stderr deleted file mode 100644 index c89cd2758ee9..000000000000 --- a/src/tools/clippy/tests/ui/invalid_utf8_in_unchecked.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error: non UTF-8 literal in `std::str::from_utf8_unchecked` - --> $DIR/invalid_utf8_in_unchecked.rs:16:9 - | -LL | std::str::from_utf8_unchecked(&[99, 108, 130, 105, 112, 112, 121]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::invalid-utf8-in-unchecked` implied by `-D warnings` - -error: non UTF-8 literal in `std::str::from_utf8_unchecked` - --> $DIR/invalid_utf8_in_unchecked.rs:17:9 - | -LL | std::str::from_utf8_unchecked(&[b'c', b'l', b'/x82', b'i', b'p', b'p', b'y']); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: non UTF-8 literal in `std::str::from_utf8_unchecked` - --> $DIR/invalid_utf8_in_unchecked.rs:18:9 - | -LL | std::str::from_utf8_unchecked(b"cl/x82ippy"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 3 previous errors - diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed index dfe45dec8a74..53ac65473b82 100644 --- a/src/tools/clippy/tests/ui/rename.fixed +++ b/src/tools/clippy/tests/ui/rename.fixed @@ -38,6 +38,7 @@ #![allow(array_into_iter)] #![allow(invalid_atomic_ordering)] #![allow(invalid_value)] +#![allow(invalid_from_utf8_unchecked)] #![allow(let_underscore_drop)] #![allow(enum_intrinsics_non_enums)] #![allow(non_fmt_panics)] @@ -87,6 +88,7 @@ #![warn(array_into_iter)] #![warn(invalid_atomic_ordering)] #![warn(invalid_value)] +#![warn(invalid_from_utf8_unchecked)] #![warn(let_underscore_drop)] #![warn(enum_intrinsics_non_enums)] #![warn(non_fmt_panics)] diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs index ce8eca5a3081..722c0b3eb275 100644 --- a/src/tools/clippy/tests/ui/rename.rs +++ b/src/tools/clippy/tests/ui/rename.rs @@ -38,6 +38,7 @@ #![allow(array_into_iter)] #![allow(invalid_atomic_ordering)] #![allow(invalid_value)] +#![allow(invalid_from_utf8_unchecked)] #![allow(let_underscore_drop)] #![allow(enum_intrinsics_non_enums)] #![allow(non_fmt_panics)] @@ -87,6 +88,7 @@ #![warn(clippy::into_iter_on_array)] #![warn(clippy::invalid_atomic_ordering)] #![warn(clippy::invalid_ref)] +#![warn(clippy::invalid_utf8_in_unchecked)] #![warn(clippy::let_underscore_drop)] #![warn(clippy::mem_discriminant_non_enum)] #![warn(clippy::panic_params)] diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr index 3fca60aa2ebd..1ff839176602 100644 --- a/src/tools/clippy/tests/ui/rename.stderr +++ b/src/tools/clippy/tests/ui/rename.stderr @@ -1,5 +1,5 @@ error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range` - --> $DIR/rename.rs:49:9 + --> $DIR/rename.rs:50:9 | LL | #![warn(clippy::almost_complete_letter_range)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range` @@ -7,286 +7,292 @@ LL | #![warn(clippy::almost_complete_letter_range)] = note: `-D renamed-and-removed-lints` implied by `-D warnings` error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names` - --> $DIR/rename.rs:50:9 + --> $DIR/rename.rs:51:9 | LL | #![warn(clippy::blacklisted_name)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names` error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:51:9 + --> $DIR/rename.rs:52:9 | LL | #![warn(clippy::block_in_if_condition_expr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:52:9 + --> $DIR/rename.rs:53:9 | LL | #![warn(clippy::block_in_if_condition_stmt)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` - --> $DIR/rename.rs:53:9 + --> $DIR/rename.rs:54:9 | LL | #![warn(clippy::box_vec)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection` error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` - --> $DIR/rename.rs:54:9 + --> $DIR/rename.rs:55:9 | LL | #![warn(clippy::const_static_lifetime)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` - --> $DIR/rename.rs:55:9 + --> $DIR/rename.rs:56:9 | LL | #![warn(clippy::cyclomatic_complexity)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq` - --> $DIR/rename.rs:56:9 + --> $DIR/rename.rs:57:9 | LL | #![warn(clippy::derive_hash_xor_eq)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq` error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods` - --> $DIR/rename.rs:57:9 + --> $DIR/rename.rs:58:9 | LL | #![warn(clippy::disallowed_method)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods` error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types` - --> $DIR/rename.rs:58:9 + --> $DIR/rename.rs:59:9 | LL | #![warn(clippy::disallowed_type)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types` error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression` - --> $DIR/rename.rs:59:9 + --> $DIR/rename.rs:60:9 | LL | #![warn(clippy::eval_order_dependence)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression` error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` - --> $DIR/rename.rs:60:9 + --> $DIR/rename.rs:61:9 | LL | #![warn(clippy::identity_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` - --> $DIR/rename.rs:61:9 + --> $DIR/rename.rs:62:9 | LL | #![warn(clippy::if_let_some_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects` - --> $DIR/rename.rs:62:9 + --> $DIR/rename.rs:63:9 | LL | #![warn(clippy::integer_arithmetic)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects` error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr` - --> $DIR/rename.rs:63:9 + --> $DIR/rename.rs:64:9 | LL | #![warn(clippy::logic_bug)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr` error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` - --> $DIR/rename.rs:64:9 + --> $DIR/rename.rs:65:9 | LL | #![warn(clippy::new_without_default_derive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map` - --> $DIR/rename.rs:65:9 + --> $DIR/rename.rs:66:9 | LL | #![warn(clippy::option_and_then_some)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map` error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:66:9 + --> $DIR/rename.rs:67:9 | LL | #![warn(clippy::option_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:67:9 + --> $DIR/rename.rs:68:9 | LL | #![warn(clippy::option_map_unwrap_or)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:68:9 + --> $DIR/rename.rs:69:9 | LL | #![warn(clippy::option_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:69:9 + --> $DIR/rename.rs:70:9 | LL | #![warn(clippy::option_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow` - --> $DIR/rename.rs:70:9 + --> $DIR/rename.rs:71:9 | LL | #![warn(clippy::ref_in_deref)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow` error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:71:9 + --> $DIR/rename.rs:72:9 | LL | #![warn(clippy::result_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:72:9 + --> $DIR/rename.rs:73:9 | LL | #![warn(clippy::result_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:73:9 + --> $DIR/rename.rs:74:9 | LL | #![warn(clippy::result_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` - --> $DIR/rename.rs:74:9 + --> $DIR/rename.rs:75:9 | LL | #![warn(clippy::single_char_push_str)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str` error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` - --> $DIR/rename.rs:75:9 + --> $DIR/rename.rs:76:9 | LL | #![warn(clippy::stutter)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl` - --> $DIR/rename.rs:76:9 + --> $DIR/rename.rs:77:9 | LL | #![warn(clippy::to_string_in_display)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl` error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` - --> $DIR/rename.rs:77:9 + --> $DIR/rename.rs:78:9 | LL | #![warn(clippy::zero_width_space)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op` - --> $DIR/rename.rs:78:9 + --> $DIR/rename.rs:79:9 | LL | #![warn(clippy::clone_double_ref)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op` error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` - --> $DIR/rename.rs:79:9 + --> $DIR/rename.rs:80:9 | LL | #![warn(clippy::drop_bounds)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types` - --> $DIR/rename.rs:80:9 + --> $DIR/rename.rs:81:9 | LL | #![warn(clippy::drop_copy)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types` error: lint `clippy::drop_ref` has been renamed to `dropping_references` - --> $DIR/rename.rs:81:9 + --> $DIR/rename.rs:82:9 | LL | #![warn(clippy::drop_ref)] | ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references` error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:82:9 + --> $DIR/rename.rs:83:9 | LL | #![warn(clippy::for_loop_over_option)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:83:9 + --> $DIR/rename.rs:84:9 | LL | #![warn(clippy::for_loop_over_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:84:9 + --> $DIR/rename.rs:85:9 | LL | #![warn(clippy::for_loops_over_fallibles)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types` - --> $DIR/rename.rs:85:9 + --> $DIR/rename.rs:86:9 | LL | #![warn(clippy::forget_copy)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types` error: lint `clippy::forget_ref` has been renamed to `forgetting_references` - --> $DIR/rename.rs:86:9 + --> $DIR/rename.rs:87:9 | LL | #![warn(clippy::forget_ref)] | ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references` error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` - --> $DIR/rename.rs:87:9 + --> $DIR/rename.rs:88:9 | LL | #![warn(clippy::into_iter_on_array)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` - --> $DIR/rename.rs:88:9 + --> $DIR/rename.rs:89:9 | LL | #![warn(clippy::invalid_atomic_ordering)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` error: lint `clippy::invalid_ref` has been renamed to `invalid_value` - --> $DIR/rename.rs:89:9 + --> $DIR/rename.rs:90:9 | LL | #![warn(clippy::invalid_ref)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` +error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked` + --> $DIR/rename.rs:91:9 + | +LL | #![warn(clippy::invalid_utf8_in_unchecked)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked` + error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop` - --> $DIR/rename.rs:90:9 + --> $DIR/rename.rs:92:9 | LL | #![warn(clippy::let_underscore_drop)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop` error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> $DIR/rename.rs:91:9 + --> $DIR/rename.rs:93:9 | LL | #![warn(clippy::mem_discriminant_non_enum)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` - --> $DIR/rename.rs:92:9 + --> $DIR/rename.rs:94:9 | LL | #![warn(clippy::panic_params)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally` - --> $DIR/rename.rs:93:9 + --> $DIR/rename.rs:95:9 | LL | #![warn(clippy::positional_named_format_parameters)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally` error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` - --> $DIR/rename.rs:94:9 + --> $DIR/rename.rs:96:9 | LL | #![warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` - --> $DIR/rename.rs:95:9 + --> $DIR/rename.rs:97:9 | LL | #![warn(clippy::unknown_clippy_lints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` error: lint `clippy::unused_label` has been renamed to `unused_labels` - --> $DIR/rename.rs:96:9 + --> $DIR/rename.rs:98:9 | LL | #![warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` -error: aborting due to 48 previous errors +error: aborting due to 49 previous errors From 7f99c7d3e64143bdeda8f519a656ad1963162fb2 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 13 May 2023 18:33:19 +0200 Subject: [PATCH 16/69] Add invalid_from_utf8 analogous to invalid_from_utf8_unchecked --- compiler/rustc_lint/messages.ftl | 4 ++ compiler/rustc_lint/src/invalid_from_utf8.rs | 49 +++++++++++--- compiler/rustc_lint/src/lints.rs | 21 ++++-- compiler/rustc_span/src/symbol.rs | 2 + library/core/src/str/converts.rs | 2 + tests/ui/lint/invalid_from_utf8.rs | 44 +++++++++++++ tests/ui/lint/invalid_from_utf8.stderr | 68 ++++++++++++++++++-- 7 files changed, 169 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 35edb4584780..e707ac41a050 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -304,6 +304,10 @@ lint_improper_ctypes_union_layout_help = consider adding a `#[repr(C)]` or `#[re lint_improper_ctypes_union_layout_reason = this union has unspecified layout lint_improper_ctypes_union_non_exhaustive = this union is non-exhaustive +# FIXME: we should ordinalize $valid_up_to when we add support for doing so +lint_invalid_from_utf8_checked = calls to `{$method}` with a invalid literal always return an error + .label = the literal was valid UTF-8 up to the {$valid_up_to} bytes + # FIXME: we should ordinalize $valid_up_to when we add support for doing so lint_invalid_from_utf8_unchecked = calls to `{$method}` with a invalid literal are undefined behavior .label = the literal was valid UTF-8 up to the {$valid_up_to} bytes diff --git a/compiler/rustc_lint/src/invalid_from_utf8.rs b/compiler/rustc_lint/src/invalid_from_utf8.rs index 2118deba5c71..3291286ad679 100644 --- a/compiler/rustc_lint/src/invalid_from_utf8.rs +++ b/compiler/rustc_lint/src/invalid_from_utf8.rs @@ -5,7 +5,7 @@ use rustc_hir::{Expr, ExprKind}; use rustc_span::source_map::Spanned; use rustc_span::sym; -use crate::lints::InvalidFromUtf8UncheckedDiag; +use crate::lints::InvalidFromUtf8Diag; use crate::{LateContext, LateLintPass, LintContext}; declare_lint! { @@ -33,7 +33,30 @@ declare_lint! { "using a non UTF-8 literal in `std::str::from_utf8_unchecked`" } -declare_lint_pass!(InvalidFromUtf8 => [INVALID_FROM_UTF8_UNCHECKED]); +declare_lint! { + /// The `invalid_from_utf8` lint checks for calls to + /// `std::str::from_utf8` and `std::str::from_utf8_mut` + /// with an invalid UTF-8 literal. + /// + /// ### Example + /// + /// ```rust + /// # #[allow(unused)] + /// std::str::from_utf8(b"Ru\x82st"); + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Trying to create such a `str` would always return an error as per documentation + /// for `std::str::from_utf8` and `std::str::from_utf8_mut`. + pub INVALID_FROM_UTF8, + Warn, + "using a non UTF-8 literal in `std::str::from_utf8`" +} + +declare_lint_pass!(InvalidFromUtf8 => [INVALID_FROM_UTF8_UNCHECKED, INVALID_FROM_UTF8]); impl<'tcx> LateLintPass<'tcx> for InvalidFromUtf8 { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { @@ -41,15 +64,25 @@ impl<'tcx> LateLintPass<'tcx> for InvalidFromUtf8 { && let ExprKind::Path(ref qpath) = path.kind && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() && let Some(diag_item) = cx.tcx.get_diagnostic_name(def_id) - && [sym::str_from_utf8_unchecked, sym::str_from_utf8_unchecked_mut].contains(&diag_item) + && [sym::str_from_utf8, sym::str_from_utf8_mut, + sym::str_from_utf8_unchecked, sym::str_from_utf8_unchecked_mut].contains(&diag_item) { let lint = |utf8_error: Utf8Error| { + let label = arg.span; let method = diag_item.as_str().strip_prefix("str_").unwrap(); - cx.emit_spanned_lint(INVALID_FROM_UTF8_UNCHECKED, expr.span, InvalidFromUtf8UncheckedDiag { - method: format!("std::str::{method}"), - valid_up_to: utf8_error.valid_up_to(), - label: arg.span, - }) + let method = format!("std::str::{method}"); + let valid_up_to = utf8_error.valid_up_to(); + let is_unchecked_variant = diag_item.as_str().contains("unchecked"); + + cx.emit_spanned_lint( + if is_unchecked_variant { INVALID_FROM_UTF8_UNCHECKED } else { INVALID_FROM_UTF8 }, + expr.span, + if is_unchecked_variant { + InvalidFromUtf8Diag::Unchecked { method, valid_up_to, label } + } else { + InvalidFromUtf8Diag::Checked { method, valid_up_to, label } + } + ) }; match &arg.kind { diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 5969bc5ca5a3..dcfef84f550b 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -701,12 +701,21 @@ pub struct ForgetCopyDiag<'a> { // invalid_from_utf8.rs #[derive(LintDiagnostic)] -#[diag(lint_invalid_from_utf8_unchecked)] -pub struct InvalidFromUtf8UncheckedDiag { - pub method: String, - pub valid_up_to: usize, - #[label] - pub label: Span, +pub enum InvalidFromUtf8Diag { + #[diag(lint_invalid_from_utf8_unchecked)] + Unchecked { + method: String, + valid_up_to: usize, + #[label] + label: Span, + }, + #[diag(lint_invalid_from_utf8_checked)] + Checked { + method: String, + valid_up_to: usize, + #[label] + label: Span, + }, } // hidden_unicode_codepoints.rs diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 4fc73c4ae864..1185563ea806 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1454,6 +1454,8 @@ symbols! { stop_after_dataflow, store, str, + str_from_utf8, + str_from_utf8_mut, str_from_utf8_unchecked, str_from_utf8_unchecked_mut, str_split_whitespace, diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs index 12fac0567cb4..0f23cf7ae239 100644 --- a/library/core/src/str/converts.rs +++ b/library/core/src/str/converts.rs @@ -84,6 +84,7 @@ use super::Utf8Error; #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_from_utf8_shared", since = "1.63.0")] #[rustc_allow_const_fn_unstable(str_internals)] +#[rustc_diagnostic_item = "str_from_utf8"] pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { // FIXME: This should use `?` again, once it's `const` match run_utf8_validation(v) { @@ -127,6 +128,7 @@ pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { /// errors that can be returned. #[stable(feature = "str_mut_extras", since = "1.20.0")] #[rustc_const_unstable(feature = "const_str_from_utf8", issue = "91006")] +#[rustc_diagnostic_item = "str_from_utf8_mut"] pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { // This should use `?` again, once it's `const` match run_utf8_validation(v) { diff --git a/tests/ui/lint/invalid_from_utf8.rs b/tests/ui/lint/invalid_from_utf8.rs index 4a27c659c73d..9c8c636812e0 100644 --- a/tests/ui/lint/invalid_from_utf8.rs +++ b/tests/ui/lint/invalid_from_utf8.rs @@ -2,6 +2,7 @@ #![feature(concat_bytes)] #![warn(invalid_from_utf8_unchecked)] +#![warn(invalid_from_utf8)] pub fn from_utf8_unchecked_mut() { // Valid @@ -46,4 +47,47 @@ pub fn from_utf8_unchecked() { } } +pub fn from_utf8_mut() { + // Valid + { + std::str::from_utf8_mut(&mut [99, 108, 105, 112, 112, 121]); + std::str::from_utf8_mut(&mut [b'c', b'l', b'i', b'p', b'p', b'y']); + + let x = 0xa0; + std::str::from_utf8_mut(&mut [0xc0, x]); + } + + // Invalid + { + std::str::from_utf8_mut(&mut [99, 108, 130, 105, 112, 112, 121]); + //~^ WARN calls to `std::str::from_utf8_mut` + std::str::from_utf8_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); + //~^ WARN calls to `std::str::from_utf8_mut` + } +} + +pub fn from_utf8() { + // Valid + { + std::str::from_utf8(&[99, 108, 105, 112, 112, 121]); + std::str::from_utf8(&[b'c', b'l', b'i', b'p', b'p', b'y']); + std::str::from_utf8(b"clippy"); + + let x = 0xA0; + std::str::from_utf8(&[0xC0, x]); + } + + // Invalid + { + std::str::from_utf8(&[99, 108, 130, 105, 112, 112, 121]); + //~^ WARN calls to `std::str::from_utf8` + std::str::from_utf8(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); + //~^ WARN calls to `std::str::from_utf8` + std::str::from_utf8(b"cl\x82ippy"); + //~^ WARN calls to `std::str::from_utf8` + std::str::from_utf8(concat_bytes!(b"cl", b"\x82ippy")); + //~^ WARN calls to `std::str::from_utf8` + } +} + fn main() {} diff --git a/tests/ui/lint/invalid_from_utf8.stderr b/tests/ui/lint/invalid_from_utf8.stderr index 63cd906237dd..8e00d3bf872f 100644 --- a/tests/ui/lint/invalid_from_utf8.stderr +++ b/tests/ui/lint/invalid_from_utf8.stderr @@ -1,5 +1,5 @@ warning: calls to `std::str::from_utf8_unchecked_mut` with a invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:18:9 + --> $DIR/invalid_from_utf8.rs:19:9 | LL | std::str::from_utf8_unchecked_mut(&mut [99, 108, 130, 105, 112, 112, 121]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------^ @@ -13,7 +13,7 @@ LL | #![warn(invalid_from_utf8_unchecked)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `std::str::from_utf8_unchecked_mut` with a invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:20:9 + --> $DIR/invalid_from_utf8.rs:21:9 | LL | std::str::from_utf8_unchecked_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------------------------------------------------^ @@ -21,7 +21,7 @@ LL | std::str::from_utf8_unchecked_mut(&mut [b'c', b'l', b'\x82', b'i', | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:38:9 + --> $DIR/invalid_from_utf8.rs:39:9 | LL | std::str::from_utf8_unchecked(&[99, 108, 130, 105, 112, 112, 121]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------------------------^ @@ -29,7 +29,7 @@ LL | std::str::from_utf8_unchecked(&[99, 108, 130, 105, 112, 112, 121]); | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:40:9 + --> $DIR/invalid_from_utf8.rs:41:9 | LL | std::str::from_utf8_unchecked(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------------------^ @@ -37,7 +37,7 @@ LL | std::str::from_utf8_unchecked(&[b'c', b'l', b'\x82', b'i', b'p', b' | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:42:9 + --> $DIR/invalid_from_utf8.rs:43:9 | LL | std::str::from_utf8_unchecked(b"cl\x82ippy"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------^ @@ -45,12 +45,66 @@ LL | std::str::from_utf8_unchecked(b"cl\x82ippy"); | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:44:9 + --> $DIR/invalid_from_utf8.rs:45:9 | LL | std::str::from_utf8_unchecked(concat_bytes!(b"cl", b"\x82ippy")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------^ | | | the literal was valid UTF-8 up to the 2 bytes -warning: 6 warnings emitted +warning: calls to `std::str::from_utf8_mut` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:62:9 + | +LL | std::str::from_utf8_mut(&mut [99, 108, 130, 105, 112, 112, 121]); + | ^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + | +note: the lint level is defined here + --> $DIR/invalid_from_utf8.rs:5:9 + | +LL | #![warn(invalid_from_utf8)] + | ^^^^^^^^^^^^^^^^^ + +warning: calls to `std::str::from_utf8_mut` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:64:9 + | +LL | std::str::from_utf8_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); + | ^^^^^^^^^^^^^^^^^^^^^^^^--------------------------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: calls to `std::str::from_utf8` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:82:9 + | +LL | std::str::from_utf8(&[99, 108, 130, 105, 112, 112, 121]); + | ^^^^^^^^^^^^^^^^^^^^-----------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: calls to `std::str::from_utf8` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:84:9 + | +LL | std::str::from_utf8(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); + | ^^^^^^^^^^^^^^^^^^^^----------------------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: calls to `std::str::from_utf8` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:86:9 + | +LL | std::str::from_utf8(b"cl\x82ippy"); + | ^^^^^^^^^^^^^^^^^^^^-------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: calls to `std::str::from_utf8` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:88:9 + | +LL | std::str::from_utf8(concat_bytes!(b"cl", b"\x82ippy")); + | ^^^^^^^^^^^^^^^^^^^^---------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: 12 warnings emitted From b84c190b9ac872fc07ac59c9ec7712dba5b4c2f8 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 13 May 2023 21:49:58 +0200 Subject: [PATCH 17/69] Allow newly uplifted invalid_from_utf8 lint --- library/alloc/tests/str.rs | 2 ++ tests/ui/process/process-panic-after-fork.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs index c1dbbde08b6b..0ba5d088f617 100644 --- a/library/alloc/tests/str.rs +++ b/library/alloc/tests/str.rs @@ -1,3 +1,5 @@ +#![cfg_attr(not(bootstrap), allow(invalid_from_utf8))] + use std::assert_matches::assert_matches; use std::borrow::Cow; use std::cmp::Ordering::{Equal, Greater, Less}; diff --git a/tests/ui/process/process-panic-after-fork.rs b/tests/ui/process/process-panic-after-fork.rs index da2683121735..7c2fc296bb02 100644 --- a/tests/ui/process/process-panic-after-fork.rs +++ b/tests/ui/process/process-panic-after-fork.rs @@ -11,6 +11,8 @@ #![feature(never_type)] #![feature(panic_always_abort)] +#![allow(invalid_from_utf8)] + extern crate libc; use std::alloc::{GlobalAlloc, Layout}; From 00c92bd873c24ee5386bc08ec854391358a8be6c Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 27 May 2023 17:35:17 +0000 Subject: [PATCH 18/69] Check nested obligations during coercion unify --- compiler/rustc_hir_typeck/src/coercion.rs | 19 ++++++++++++++++++- tests/ui/impl-trait/autoderef.rs | 2 ++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 08c4082e885d..369dd4ae5950 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -62,6 +62,7 @@ use rustc_span::{self, BytePos, DesugaringKind, Span}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::{ self, NormalizeExt, ObligationCause, ObligationCauseCode, ObligationCtxt, }; @@ -144,12 +145,28 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { debug!("unify(a: {:?}, b: {:?}, use_lub: {})", a, b, self.use_lub); self.commit_if_ok(|_| { let at = self.at(&self.cause, self.fcx.param_env); - if self.use_lub { + + let res = if self.use_lub { at.lub(DefineOpaqueTypes::Yes, b, a) } else { at.sup(DefineOpaqueTypes::Yes, b, a) .map(|InferOk { value: (), obligations }| InferOk { value: a, obligations }) + }; + + // In the new solver, lazy norm may allow us to shallowly equate + // more types, but we emit possibly impossible-to-satisfy obligations. + // Filter these cases out to make sure our coercion is more accurate. + if self.tcx.trait_solver_next() { + if let Ok(res) = &res { + for obligation in &res.obligations { + if !self.predicate_may_hold(&obligation) { + return Err(TypeError::Mismatch); + } + } + } } + + res }) } diff --git a/tests/ui/impl-trait/autoderef.rs b/tests/ui/impl-trait/autoderef.rs index 5e4f4995447e..0d07a549640f 100644 --- a/tests/ui/impl-trait/autoderef.rs +++ b/tests/ui/impl-trait/autoderef.rs @@ -1,3 +1,5 @@ +// revisions: current next +//[next] compile-flag: -Ztrait-solver=next // check-pass use std::path::Path; From 5c780d9926a34422f649a678d437950c0672781e Mon Sep 17 00:00:00 2001 From: sladynnunes Date: Sun, 28 May 2023 01:37:25 -0700 Subject: [PATCH 19/69] Migrate to Askama --- src/librustdoc/html/render/print_item.rs | 26 +++++++++++++++--------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 62027a3fa194..9fb7d9e64d81 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1420,30 +1420,36 @@ fn item_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: write!(w, "{}", document(cx, it, None, HeadingOffset::H2)) } -fn item_proc_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, m: &clean::ProcMacro) { - wrap_item(w, |w| { +fn item_proc_macro( + w: &mut impl fmt::Write, + cx: &mut Context<'_>, + it: &clean::Item, + m: &clean::ProcMacro, +) { + let mut buffer = Buffer::new(); + wrap_item(&mut buffer, |buffer| { let name = it.name.expect("proc-macros always have names"); match m.kind { MacroKind::Bang => { - write!(w, "{}!() {{ /* proc-macro */ }}", name); + write!(buffer, "{}!() {{ /* proc-macro */ }}", name); } MacroKind::Attr => { - write!(w, "#[{}]", name); + write!(buffer, "#[{}]", name); } MacroKind::Derive => { - write!(w, "#[derive({})]", name); + write!(buffer, "#[derive({})]", name); if !m.helpers.is_empty() { - w.push_str("\n{\n"); - w.push_str(" // Attributes available to this derive:\n"); + buffer.push_str("\n{\n"); + buffer.push_str(" // Attributes available to this derive:\n"); for attr in &m.helpers { - writeln!(w, " #[{}]", attr); + writeln!(buffer, " #[{}]", attr); } - w.push_str("}\n"); + buffer.push_str("}\n"); } } } }); - write!(w, "{}", document(cx, it, None, HeadingOffset::H2)) + write!(w, "{}{}", buffer.into_inner(), document(cx, it, None, HeadingOffset::H2)).unwrap(); } fn item_primitive(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) { From 08d149ca85b1afe0c554310bd203bd9d1a3f8bb2 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 29 May 2023 13:46:10 +0200 Subject: [PATCH 20/69] EarlyBinder::new -> EarlyBinder::bind --- compiler/rustc_codegen_cranelift/src/common.rs | 2 +- .../rustc_codegen_llvm/src/debuginfo/create_scope_map.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/mod.rs | 2 +- compiler/rustc_const_eval/src/interpret/eval_context.rs | 2 +- compiler/rustc_hir_analysis/src/astconv/mod.rs | 2 +- .../rustc_hir_analysis/src/check/compare_impl_item.rs | 4 ++-- compiler/rustc_hir_analysis/src/check/dropck.rs | 2 +- compiler/rustc_hir_analysis/src/check/wfcheck.rs | 2 +- compiler/rustc_hir_analysis/src/collect.rs | 4 ++-- compiler/rustc_hir_analysis/src/collect/item_bounds.rs | 4 ++-- compiler/rustc_hir_analysis/src/collect/type_of.rs | 4 ++-- compiler/rustc_hir_analysis/src/outlives/explicit.rs | 2 +- .../rustc_hir_analysis/src/outlives/implicit_infer.rs | 2 +- compiler/rustc_metadata/src/rmeta/decoder.rs | 2 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 2 +- compiler/rustc_middle/src/mir/mod.rs | 2 +- compiler/rustc_middle/src/ty/adt.rs | 2 +- compiler/rustc_middle/src/ty/consts.rs | 2 +- compiler/rustc_middle/src/ty/generics.rs | 4 ++-- .../src/ty/inhabitedness/inhabited_predicate.rs | 4 ++-- compiler/rustc_middle/src/ty/mod.rs | 2 +- compiler/rustc_middle/src/ty/sty.rs | 2 +- compiler/rustc_middle/src/ty/subst.rs | 2 +- compiler/rustc_middle/src/ty/util.rs | 2 +- compiler/rustc_middle/src/values.rs | 4 ++-- .../rustc_mir_transform/src/function_item_references.rs | 2 +- compiler/rustc_mir_transform/src/inline.rs | 8 ++++---- compiler/rustc_mir_transform/src/inline/cycle.rs | 2 +- compiler/rustc_mir_transform/src/shim.rs | 2 +- compiler/rustc_monomorphize/src/collector.rs | 2 +- compiler/rustc_monomorphize/src/util.rs | 4 ++-- compiler/rustc_symbol_mangling/src/v0.rs | 2 +- compiler/rustc_trait_selection/src/traits/mod.rs | 2 +- .../rustc_trait_selection/src/traits/object_safety.rs | 2 +- .../src/traits/query/dropck_outlives.rs | 6 +++--- compiler/rustc_ty_utils/src/assoc.rs | 2 +- compiler/rustc_ty_utils/src/consts.rs | 2 +- compiler/rustc_ty_utils/src/layout.rs | 2 +- compiler/rustc_ty_utils/src/needs_drop.rs | 2 +- compiler/rustc_ty_utils/src/ty.rs | 2 +- src/librustdoc/clean/blanket_impl.rs | 2 +- src/tools/clippy/clippy_lints/src/dereference.rs | 2 +- src/tools/clippy/clippy_lints/src/eta_reduction.rs | 2 +- .../clippy/clippy_lints/src/methods/needless_collect.rs | 2 +- .../clippy_lints/src/methods/unnecessary_to_owned.rs | 4 ++-- src/tools/clippy/clippy_utils/src/consts.rs | 2 +- 46 files changed, 60 insertions(+), 60 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index 70cb6dfd66f2..67fd6d793e0b 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -361,7 +361,7 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> { self.instance.subst_mir_and_normalize_erasing_regions( self.tcx, ty::ParamEnv::reveal_all(), - ty::EarlyBinder::new(value), + ty::EarlyBinder::bind(value), ) } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs index 6cb9e163b404..64961baf272f 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs @@ -93,7 +93,7 @@ fn make_mir_scope<'ll, 'tcx>( let callee = cx.tcx.subst_and_normalize_erasing_regions( instance.substs, ty::ParamEnv::reveal_all(), - ty::EarlyBinder::new(callee), + ty::EarlyBinder::bind(callee), ); let callee_fn_abi = cx.fn_abi_of_instance(callee, ty::List::empty()); cx.dbg_scope_fn(callee, callee_fn_abi, None) diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 51393a5d774d..004140032026 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -111,7 +111,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.instance.subst_mir_and_normalize_erasing_regions( self.cx.tcx(), ty::ParamEnv::reveal_all(), - ty::EarlyBinder::new(value), + ty::EarlyBinder::bind(value), ) } } diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 9195ae163bc6..91ccdef7215c 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -497,7 +497,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { .try_subst_mir_and_normalize_erasing_regions( *self.tcx, self.param_env, - ty::EarlyBinder::new(value), + ty::EarlyBinder::bind(value), ) .map_err(|_| err_inval!(TooGeneric)) } diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 284ae0e1e58a..2013d68b51f3 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -1278,7 +1278,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // params (and trait ref's late bound params). This logic is very similar to // `Predicate::subst_supertrait`, and it's no coincidence why. let shifted_output = tcx.shift_bound_var_indices(num_bound_vars, output); - let subst_output = ty::EarlyBinder::new(shifted_output).subst(tcx, substs); + let subst_output = ty::EarlyBinder::bind(shifted_output).subst(tcx, substs); let bound_vars = tcx.late_bound_vars(binding.hir_id); ty::Binder::bind_with_vars(subst_output, bound_vars) diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index e33330e259c3..3eb41882bf82 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -795,14 +795,14 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( }) }); debug!(%ty); - collected_tys.insert(def_id, ty::EarlyBinder::new(ty)); + collected_tys.insert(def_id, ty::EarlyBinder::bind(ty)); } Err(err) => { let reported = tcx.sess.delay_span_bug( return_span, format!("could not fully resolve: {ty} => {err:?}"), ); - collected_tys.insert(def_id, ty::EarlyBinder::new(tcx.ty_error(reported))); + collected_tys.insert(def_id, ty::EarlyBinder::bind(tcx.ty_error(reported))); } } } diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index eeb69c389cd8..90cc6b108218 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -128,7 +128,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( // We don't need to normalize this param-env or anything, since we're only // substituting it with free params, so no additional param-env normalization // can occur on top of what has been done in the param_env query itself. - let param_env = ty::EarlyBinder::new(tcx.param_env(adt_def_id)) + let param_env = ty::EarlyBinder::bind(tcx.param_env(adt_def_id)) .subst(tcx, adt_to_impl_substs) .with_constness(tcx.constness(drop_impl_def_id)); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 4c513c4d8cc6..9411259e70a8 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1398,7 +1398,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id } let mut param_count = CountParams::default(); let has_region = pred.visit_with(&mut param_count).is_break(); - let substituted_pred = ty::EarlyBinder::new(pred).subst(tcx, substs); + let substituted_pred = ty::EarlyBinder::bind(pred).subst(tcx, substs); // Don't check non-defaulted params, dependent defaults (including lifetimes) // or preds with multiple params. if substituted_pred.has_non_region_param() || param_count.params.len() > 1 || has_region diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 75d99fee152e..dceff531a087 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1124,7 +1124,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder( @@ -1312,7 +1312,7 @@ fn impl_trait_ref( check_impl_constness(tcx, impl_.constness, ast_trait_ref), ) }) - .map(ty::EarlyBinder::new) + .map(ty::EarlyBinder::bind) } fn check_impl_constness( diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 03c8c59402e7..b92d561fb86a 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -86,7 +86,7 @@ pub(super) fn explicit_item_bounds( Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => { let item = tcx.hir().get_by_def_id(opaque_def_id.expect_local()).expect_item(); let opaque_ty = item.expect_opaque_ty(); - return ty::EarlyBinder::new(opaque_type_bounds( + return ty::EarlyBinder::bind(opaque_type_bounds( tcx, opaque_def_id.expect_local(), opaque_ty.bounds, @@ -124,7 +124,7 @@ pub(super) fn explicit_item_bounds( } _ => bug!("item_bounds called on {:?}", def_id), }; - ty::EarlyBinder::new(bounds) + ty::EarlyBinder::bind(bounds) } pub(super) fn item_bounds( diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 0b57d6965856..65ab00fda817 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -323,7 +323,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder { - return ty::EarlyBinder::new(tcx.ty_error_with_message( + return ty::EarlyBinder::bind(tcx.ty_error_with_message( DUMMY_SP, "Could not collect return position impl trait in trait tys", )); @@ -497,7 +497,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder( diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs index d7f11d3fd9d3..7ce48fe1c012 100644 --- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs +++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs @@ -68,7 +68,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { } } - ty::EarlyBinder::new(required_predicates) + ty::EarlyBinder::bind(required_predicates) }) } } diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs index ced994aa6366..71dca918fc5e 100644 --- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs +++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs @@ -74,7 +74,7 @@ pub(super) fn infer_predicates( if item_required_predicates.len() > item_predicates_len { predicates_added = true; global_inferred_outlives - .insert(item_did.to_def_id(), ty::EarlyBinder::new(item_required_predicates)); + .insert(item_did.to_def_id(), ty::EarlyBinder::bind(item_required_predicates)); } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 731bbb1edfb7..91be65da93ab 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -851,7 +851,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } else { tcx.arena.alloc_from_iter(lazy.decode((self, tcx))) }; - ty::EarlyBinder::new(&*output) + ty::EarlyBinder::bind(&*output) } fn get_variant( diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index e3a0ce373879..6fe808f3686d 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1727,7 +1727,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { ty::Closure(_, substs) => { let constness = self.tcx.constness(def_id.to_def_id()); self.tables.constness.set_some(def_id.to_def_id().index, constness); - record!(self.tables.fn_sig[def_id.to_def_id()] <- ty::EarlyBinder::new(substs.as_closure().sig())); + record!(self.tables.fn_sig[def_id.to_def_id()] <- ty::EarlyBinder::bind(substs.as_closure().sig())); } _ => bug!("closure that is neither generator nor closure"), diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 34e47de969c1..63cdba7f327f 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -476,7 +476,7 @@ impl<'tcx> Body<'tcx> { /// Returns the return type; it always return first element from `local_decls` array. #[inline] pub fn bound_return_ty(&self) -> ty::EarlyBinder> { - ty::EarlyBinder::new(self.local_decls[RETURN_PLACE].ty) + ty::EarlyBinder::bind(self.local_decls[RETURN_PLACE].ty) } /// Gets the location of the terminator for the given block. diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 2b99fcad2675..e067d2a984fd 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -573,7 +573,7 @@ impl<'tcx> AdtDef<'tcx> { /// Due to normalization being eager, this applies even if /// the associated type is behind a pointer (e.g., issue #31299). pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> ty::EarlyBinder<&'tcx [Ty<'tcx>]> { - ty::EarlyBinder::new(tcx.adt_sized_constraint(self.did())) + ty::EarlyBinder::bind(tcx.adt_sized_constraint(self.did())) } } diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 5fcbc4a9ed49..aecb46556b04 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -254,5 +254,5 @@ pub fn const_param_default(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBind "`const_param_default` expected a generic parameter with a constant" ), }; - ty::EarlyBinder::new(Const::from_anon_const(tcx, default_def_id)) + ty::EarlyBinder::bind(Const::from_anon_const(tcx, default_def_id)) } diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index b27ee8cbad0f..a5ab6d91a57d 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -343,7 +343,7 @@ impl<'tcx> GenericPredicates<'tcx> { substs: SubstsRef<'tcx>, ) -> impl Iterator, Span)> + DoubleEndedIterator + ExactSizeIterator { - EarlyBinder::new(self.predicates).subst_iter_copied(tcx, substs) + EarlyBinder::bind(self.predicates).subst_iter_copied(tcx, substs) } #[instrument(level = "debug", skip(self, tcx))] @@ -358,7 +358,7 @@ impl<'tcx> GenericPredicates<'tcx> { } instantiated .predicates - .extend(self.predicates.iter().map(|(p, _)| EarlyBinder::new(*p).subst(tcx, substs))); + .extend(self.predicates.iter().map(|(p, _)| EarlyBinder::bind(*p).subst(tcx, substs))); instantiated.spans.extend(self.predicates.iter().map(|(_, sp)| *sp)); } diff --git a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs index b3cc27e3f783..d48672b2baae 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs @@ -158,7 +158,7 @@ impl<'tcx> InhabitedPredicate<'tcx> { fn subst_opt(self, tcx: TyCtxt<'tcx>, substs: ty::SubstsRef<'tcx>) -> Option { match self { Self::ConstIsZero(c) => { - let c = ty::EarlyBinder::new(c).subst(tcx, substs); + let c = ty::EarlyBinder::bind(c).subst(tcx, substs); let pred = match c.kind().try_to_target_usize(tcx) { Some(0) => Self::True, Some(1..) => Self::False, @@ -167,7 +167,7 @@ impl<'tcx> InhabitedPredicate<'tcx> { Some(pred) } Self::GenericType(t) => { - Some(ty::EarlyBinder::new(t).subst(tcx, substs).inhabited_predicate(tcx)) + Some(ty::EarlyBinder::bind(t).subst(tcx, substs).inhabited_predicate(tcx)) } Self::And(&[a, b]) => match a.subst_opt(tcx, substs) { None => b.subst_opt(tcx, substs).map(|b| a.and(tcx, b)), diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 4b2c7e8ef311..2598b5602059 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -764,7 +764,7 @@ impl<'tcx> Predicate<'tcx> { let shifted_pred = tcx.shift_bound_var_indices(trait_bound_vars.len(), bound_pred.skip_binder()); // 2) Self: Bar1<'a, '^0.1> -> T: Bar1<'^0.0, '^0.1> - let new = EarlyBinder::new(shifted_pred).subst(tcx, trait_ref.skip_binder().substs); + let new = EarlyBinder::bind(shifted_pred).subst(tcx, trait_ref.skip_binder().substs); // 3) ['x] + ['b] -> ['x, 'b] let bound_vars = tcx.mk_bound_variable_kinds_from_iter(trait_bound_vars.iter().chain(pred_bound_vars)); diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 82f79a0c0887..63c8fc6328c9 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -568,7 +568,7 @@ impl<'tcx> GeneratorSubsts<'tcx> { let layout = tcx.generator_layout(def_id).unwrap(); layout.variant_fields.iter().map(move |variant| { variant.iter().map(move |field| { - ty::EarlyBinder::new(layout.field_tys[*field].ty).subst(tcx, self.substs) + ty::EarlyBinder::bind(layout.field_tys[*field].ty).subst(tcx, self.substs) }) }) } diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 8691a3070bcf..8685a22d9ca8 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -545,7 +545,7 @@ impl<'tcx, T> !TypeFoldable> for ty::EarlyBinder {} impl<'tcx, T> !TypeVisitable> for ty::EarlyBinder {} impl EarlyBinder { - pub fn new(inner: T) -> EarlyBinder { + pub fn bind(inner: T) -> EarlyBinder { EarlyBinder(inner) } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index dade50df5d96..311f63adc7f4 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -709,7 +709,7 @@ impl<'tcx> TyCtxt<'tcx> { .as_ref() .map_or_else(|| [].iter(), |l| l.field_tys.iter()) .filter(|decl| !decl.ignore_for_traits) - .map(|decl| ty::EarlyBinder::new(decl.ty)) + .map(|decl| ty::EarlyBinder::bind(decl.ty)) } /// Normalizes all opaque types in the given value, replacing them diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index 58374f6b3bd7..a00c77ccbcdc 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -96,13 +96,13 @@ impl<'tcx> Value, DepKind> for Representability { impl<'tcx> Value, DepKind> for ty::EarlyBinder> { fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo]) -> Self { - ty::EarlyBinder::new(Ty::from_cycle_error(tcx, cycle)) + ty::EarlyBinder::bind(Ty::from_cycle_error(tcx, cycle)) } } impl<'tcx> Value, DepKind> for ty::EarlyBinder>> { fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo]) -> Self { - ty::EarlyBinder::new(ty::Binder::from_cycle_error(tcx, cycle)) + ty::EarlyBinder::bind(ty::Binder::from_cycle_error(tcx, cycle)) } } diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs index c0458126840d..b1c9c4acc40e 100644 --- a/compiler/rustc_mir_transform/src/function_item_references.rs +++ b/compiler/rustc_mir_transform/src/function_item_references.rs @@ -83,7 +83,7 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> { // If the inner type matches the type bound by `Pointer` if inner_ty == bound_ty { // Do a substitution using the parameters from the callsite - let subst_ty = EarlyBinder::new(inner_ty).subst(self.tcx, substs_ref); + let subst_ty = EarlyBinder::bind(inner_ty).subst(self.tcx, substs_ref); if let Some((fn_id, fn_substs)) = FunctionItemRefChecker::is_fn_ref(subst_ty) { diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index e27d48fa8f65..55b9f084c39f 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -192,7 +192,7 @@ impl<'tcx> Inliner<'tcx> { let Ok(callee_body) = callsite.callee.try_subst_mir_and_normalize_erasing_regions( self.tcx, self.param_env, - ty::EarlyBinder::new(callee_body.clone()), + ty::EarlyBinder::bind(callee_body.clone()), ) else { return Err("failed to normalize callee body"); }; @@ -455,7 +455,7 @@ impl<'tcx> Inliner<'tcx> { // If the place doesn't actually need dropping, treat it like a regular goto. let ty = callsite .callee - .subst_mir(self.tcx, ty::EarlyBinder::new(&place.ty(callee_body, tcx).ty)); + .subst_mir(self.tcx, ty::EarlyBinder::bind(&place.ty(callee_body, tcx).ty)); if ty.needs_drop(tcx, self.param_env) && let UnwindAction::Cleanup(unwind) = unwind { work_list.push(unwind); } @@ -790,7 +790,7 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> { // If the place doesn't actually need dropping, treat it like a regular goto. let ty = self .instance - .subst_mir(tcx, ty::EarlyBinder::new(&place.ty(self.callee_body, tcx).ty)); + .subst_mir(tcx, ty::EarlyBinder::bind(&place.ty(self.callee_body, tcx).ty)); if ty.needs_drop(tcx, self.param_env) { self.cost += CALL_PENALTY; if let UnwindAction::Cleanup(_) = unwind { @@ -801,7 +801,7 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> { } } TerminatorKind::Call { func: Operand::Constant(ref f), unwind, .. } => { - let fn_ty = self.instance.subst_mir(tcx, ty::EarlyBinder::new(&f.literal.ty())); + let fn_ty = self.instance.subst_mir(tcx, ty::EarlyBinder::bind(&f.literal.ty())); self.cost += if let ty::FnDef(def_id, _) = *fn_ty.kind() && tcx.is_intrinsic(def_id) { // Don't give intrinsics the extra penalty for calls INSTR_COST diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index 00842e9d6659..8a10445f8377 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -47,7 +47,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( let Ok(substs) = caller.try_subst_mir_and_normalize_erasing_regions( tcx, param_env, - ty::EarlyBinder::new(substs), + ty::EarlyBinder::bind(substs), ) else { trace!(?caller, ?param_env, ?substs, "cannot normalize, skipping"); continue; diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 522220f3d77c..ae726dea9442 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -69,7 +69,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' // of this function. Is this intentional? if let Some(ty::Generator(gen_def_id, substs, _)) = ty.map(Ty::kind) { let body = tcx.optimized_mir(*gen_def_id).generator_drop().unwrap(); - let body = EarlyBinder::new(body.clone()).subst(tcx, substs); + let body = EarlyBinder::bind(body.clone()).subst(tcx, substs); debug!("make_shim({:?}) = {:?}", instance, body); return body; } diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 8874aa7d3ca9..cefa64d27acb 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -677,7 +677,7 @@ impl<'a, 'tcx> MirNeighborCollector<'a, 'tcx> { self.instance.subst_mir_and_normalize_erasing_regions( self.tcx, ty::ParamEnv::reveal_all(), - ty::EarlyBinder::new(value), + ty::EarlyBinder::bind(value), ) } } diff --git a/compiler/rustc_monomorphize/src/util.rs b/compiler/rustc_monomorphize/src/util.rs index 772f15201536..f6a80b0431fc 100644 --- a/compiler/rustc_monomorphize/src/util.rs +++ b/compiler/rustc_monomorphize/src/util.rs @@ -29,12 +29,12 @@ pub(crate) fn dump_closure_profile<'tcx>(tcx: TyCtxt<'tcx>, closure_instance: In let before_feature_tys = tcx.subst_and_normalize_erasing_regions( closure_instance.substs, param_env, - ty::EarlyBinder::new(before_feature_tys), + ty::EarlyBinder::bind(before_feature_tys), ); let after_feature_tys = tcx.subst_and_normalize_erasing_regions( closure_instance.substs, param_env, - ty::EarlyBinder::new(after_feature_tys), + ty::EarlyBinder::bind(after_feature_tys), ); let new_size = tcx diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 55901bfbde9c..0a805e2422d4 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -274,7 +274,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { let mut param_env = self.tcx.param_env_reveal_all_normalized(impl_def_id); if !substs.is_empty() { - param_env = EarlyBinder::new(param_env).subst(self.tcx, substs); + param_env = EarlyBinder::bind(param_env).subst(self.tcx, substs); } match &mut impl_trait_ref { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 0f84032d9ef6..4b38687eebee 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -487,7 +487,7 @@ fn is_impossible_method(tcx: TyCtxt<'_>, (impl_def_id, trait_item_def_id): (DefI tcx, ObligationCause::dummy_with_span(*span), param_env, - ty::EarlyBinder::new(*pred).subst(tcx, impl_trait_ref.substs), + ty::EarlyBinder::bind(*pred).subst(tcx, impl_trait_ref.substs), ) }) }); diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 0be21156b6c9..9582479941b6 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -642,7 +642,7 @@ fn receiver_for_self_ty<'tcx>( if param.index == 0 { self_ty.into() } else { tcx.mk_param_from_def(param) } }); - let result = EarlyBinder::new(receiver_ty).subst(tcx, substs); + let result = EarlyBinder::bind(receiver_ty).subst(tcx, substs); debug!( "receiver_for_self_ty({:?}, {:?}, {:?}) = {:?}", receiver_ty, self_ty, method_def_id, result diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index 0a1b1b10b007..709c3f432e60 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -307,13 +307,13 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( // there, but that needs some way to handle cycles. constraints .dtorck_types - .extend(dtorck_types.iter().map(|t| EarlyBinder::new(*t).subst(tcx, substs))); + .extend(dtorck_types.iter().map(|t| EarlyBinder::bind(*t).subst(tcx, substs))); constraints .outlives - .extend(outlives.iter().map(|t| EarlyBinder::new(*t).subst(tcx, substs))); + .extend(outlives.iter().map(|t| EarlyBinder::bind(*t).subst(tcx, substs))); constraints .overflows - .extend(overflows.iter().map(|t| EarlyBinder::new(*t).subst(tcx, substs))); + .extend(overflows.iter().map(|t| EarlyBinder::bind(*t).subst(tcx, substs))); } // Objects must be alive in order for their destructor diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 0925b3956de3..57b4183d3367 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -301,7 +301,7 @@ fn associated_type_for_impl_trait_in_trait( trait_assoc_ty.impl_defaultness(tcx.impl_defaultness(fn_def_id)); // Copy type_of of the opaque. - trait_assoc_ty.type_of(ty::EarlyBinder::new(tcx.mk_opaque( + trait_assoc_ty.type_of(ty::EarlyBinder::bind(tcx.mk_opaque( opaque_ty_def_id.to_def_id(), InternalSubsts::identity_for_item(tcx, opaque_ty_def_id), ))); diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index bb723c9997ac..ce77df0df5dc 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -419,7 +419,7 @@ pub fn thir_abstract_const( let root_span = body.exprs[body_id].span; - Ok(Some(ty::EarlyBinder::new(recurse_build(tcx, body, body_id, root_span)?))) + Ok(Some(ty::EarlyBinder::bind(recurse_build(tcx, body, body_id, root_span)?))) } pub fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 0e5b23ca423e..7015778e24b8 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -610,7 +610,7 @@ fn generator_layout<'tcx>( ) -> Result, LayoutError<'tcx>> { use SavedLocalEligibility::*; let tcx = cx.tcx; - let subst_field = |ty: Ty<'tcx>| EarlyBinder::new(ty).subst(tcx, substs); + let subst_field = |ty: Ty<'tcx>| EarlyBinder::bind(ty).subst(tcx, substs); let Some(info) = tcx.generator_layout(def_id) else { return Err(LayoutError::Unknown(ty)); diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index 075fde6ddb65..9d593dc5e04e 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -210,7 +210,7 @@ fn drop_tys_helper<'tcx>( match subty.kind() { ty::Adt(adt_id, subst) => { for subty in tcx.adt_drop_tys(adt_id.did())? { - vec.push(EarlyBinder::new(subty).subst(tcx, subst)); + vec.push(EarlyBinder::bind(subty).subst(tcx, subst)); } } _ => vec.push(subty), diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 52bc386cb009..0228f8586350 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -506,7 +506,7 @@ fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option BlanketImplFinder<'a, 'tcx> { let infcx = cx.tcx.infer_ctxt().build(); let substs = infcx.fresh_substs_for_item(DUMMY_SP, item_def_id); let impl_ty = ty.subst(infcx.tcx, substs); - let param_env = EarlyBinder::new(param_env).subst(infcx.tcx, substs); + let param_env = EarlyBinder::bind(param_env).subst(infcx.tcx, substs); let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id); let impl_trait_ref = trait_ref.subst(infcx.tcx, impl_substs); diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index a418a910ba8e..a1d2147cb496 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -1219,7 +1219,7 @@ fn needless_borrow_impl_arg_position<'tcx>( return false; } - let predicate = EarlyBinder::new(predicate).subst(cx.tcx, &substs_with_referent_ty); + let predicate = EarlyBinder::bind(predicate).subst(cx.tcx, &substs_with_referent_ty); let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate); let infcx = cx.tcx.infer_ctxt().build(); infcx.predicate_must_hold_modulo_regions(&obligation) diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs index af2aac6ac0d0..c919b4de65de 100644 --- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs +++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs @@ -243,7 +243,7 @@ fn get_ufcs_type_name<'tcx>(cx: &LateContext<'tcx>, method_def_id: DefId, substs | ty::Ref(..) | ty::Slice(_) | ty::Tuple(_) => { - format!("<{}>", EarlyBinder::new(ty).subst(cx.tcx, substs)) + format!("<{}>", EarlyBinder::bind(ty).subst(cx.tcx, substs)) }, _ => ty.to_string(), } diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs index d4cc14bb8563..99f810c27cf8 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs @@ -241,7 +241,7 @@ fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) - && let proj_ty = cx.tcx.mk_projection(iter_item.def_id, substs) && let Ok(item_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, proj_ty) { - item_ty == EarlyBinder::new(search_ty).subst(cx.tcx, cx.typeck_results().node_substs(call_id)) + item_ty == EarlyBinder::bind(search_ty).subst(cx.tcx, cx.typeck_results().node_substs(call_id)) } else { false } diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index fdacfa49e92d..309d2157b76e 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -428,7 +428,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< })); if trait_predicates.any(|predicate| { - let predicate = EarlyBinder::new(predicate).subst(cx.tcx, new_subst); + let predicate = EarlyBinder::bind(predicate).subst(cx.tcx, new_subst); let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate); !cx.tcx.infer_ctxt().build().predicate_must_hold_modulo_regions(&obligation) }) { @@ -438,7 +438,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< let output_ty = fn_sig.output(); if output_ty.contains(*param_ty) { if let Ok(new_ty) = cx.tcx.try_subst_and_normalize_erasing_regions( - new_subst, cx.param_env, EarlyBinder::new(output_ty)) { + new_subst, cx.param_env, EarlyBinder::bind(output_ty)) { expr = parent_expr; ty = new_ty; continue; diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 843538e1eb2d..cc3183759ae7 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -462,7 +462,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { let substs = if self.substs.is_empty() { substs } else { - EarlyBinder::new(substs).subst(self.lcx.tcx, self.substs) + EarlyBinder::bind(substs).subst(self.lcx.tcx, self.substs) }; let result = self From 8d406b8459a56b96b283689a999b9c83c41f4f24 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 29 May 2023 13:44:39 +0000 Subject: [PATCH 21/69] Add a test for issue 110457 --- .../auxiliary/egui_inspect_derive.rs | 90 +++++++++++++++++++ .../issue-110457-same-span-closures/main.rs | 47 ++++++++++ 2 files changed, 137 insertions(+) create mode 100644 tests/incremental/issue-110457-same-span-closures/auxiliary/egui_inspect_derive.rs create mode 100644 tests/incremental/issue-110457-same-span-closures/main.rs diff --git a/tests/incremental/issue-110457-same-span-closures/auxiliary/egui_inspect_derive.rs b/tests/incremental/issue-110457-same-span-closures/auxiliary/egui_inspect_derive.rs new file mode 100644 index 000000000000..e7d91235e735 --- /dev/null +++ b/tests/incremental/issue-110457-same-span-closures/auxiliary/egui_inspect_derive.rs @@ -0,0 +1,90 @@ +// force-host +// no-prefer-dynamic +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +use proc_macro::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; + +#[proc_macro] +pub fn expand(_: TokenStream) -> TokenStream { + // Hand expansion/rewriting of + // ``` + // quote! { + // output_mut(|o| o.copied_text = "".into()); + // output_mut(|o| o.copied_text = format!("{:?}", self.tile_db)); + // }.into() + // ``` + stream([ + ident("output_mut"), + group( + Delimiter::Parenthesis, + [ + or(), + ident("o"), + or(), + ident("o"), + dot(), + ident("copied_text"), + eq(), + string(""), + dot(), + ident("into"), + group(Delimiter::Parenthesis, []), + ], + ), + semi(), + ident("output_mut"), + group( + Delimiter::Parenthesis, + [ + or(), + ident("o"), + or(), + ident("o"), + dot(), + ident("copied_text"), + eq(), + ident("format"), + bang(), + group( + Delimiter::Parenthesis, + [string("{:?}"), comma(), ident("self"), dot(), ident("tile_db")], + ), + ], + ), + semi(), + ]) +} + +fn stream(s: impl IntoIterator) -> TokenStream { + s.into_iter().collect() +} + +fn ident(i: &str) -> TokenTree { + TokenTree::Ident(Ident::new(i, Span::call_site())) +} +fn group(d: Delimiter, s: impl IntoIterator) -> TokenTree { + TokenTree::Group(Group::new(d, s.into_iter().collect())) +} +fn semi() -> TokenTree { + TokenTree::Punct(Punct::new(';', Spacing::Alone)) +} +fn or() -> TokenTree { + TokenTree::Punct(Punct::new('|', Spacing::Alone)) +} +fn dot() -> TokenTree { + TokenTree::Punct(Punct::new('.', Spacing::Alone)) +} +fn eq() -> TokenTree { + TokenTree::Punct(Punct::new('=', Spacing::Alone)) +} +fn bang() -> TokenTree { + TokenTree::Punct(Punct::new('!', Spacing::Alone)) +} +fn comma() -> TokenTree { + TokenTree::Punct(Punct::new(',', Spacing::Alone)) +} +fn string(s: &str) -> TokenTree { + TokenTree::Literal(Literal::string(s)) +} diff --git a/tests/incremental/issue-110457-same-span-closures/main.rs b/tests/incremental/issue-110457-same-span-closures/main.rs new file mode 100644 index 000000000000..b44fda3d36a2 --- /dev/null +++ b/tests/incremental/issue-110457-same-span-closures/main.rs @@ -0,0 +1,47 @@ +// aux-build: egui_inspect_derive.rs +// revisions: cpass1 cpass2 + +extern crate egui_inspect_derive; + +pub struct TileDef { + pub layer: (), + #[cfg(cpass2)] + pub blend_graphic: String, +} + +pub(crate) struct GameState { + pub(crate) tile_db: TileDb, +} + +impl GameState { + fn inspect_mut(&mut self) { + egui_inspect_derive::expand! {} + } +} + +fn new() -> GameState { + loop {} +} + +fn main() { + let mut app = new(); + app.inspect_mut(); +} +// this is actually used +pub struct TileDb { + unknown_bg: TileDef, +} + +impl std::fmt::Debug for TileDb { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + loop {} + } +} + +pub struct PlatformOutput { + pub copied_text: String, +} + +pub fn output_mut(writer: impl FnOnce(&mut PlatformOutput) -> R) -> R { + loop {} +} From f333932ba8b473c2ed85752cbdb3b58a11acf421 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 29 May 2023 15:59:45 +0200 Subject: [PATCH 22/69] Update browser-ui-test version to 0.16.5 --- .../docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version index 806935b827ff..3ccca1e8b89b 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version @@ -1 +1 @@ -0.16.4 \ No newline at end of file +0.16.5 \ No newline at end of file From 17e3d1cd4a25744e68bdf2c9792adcc580c015b6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 29 May 2023 16:03:56 +0200 Subject: [PATCH 23/69] Migrate GUI colors test to original CSS color format --- tests/rustdoc-gui/target.goml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/rustdoc-gui/target.goml b/tests/rustdoc-gui/target.goml index 0c514fc68642..c5e7f813dd19 100644 --- a/tests/rustdoc-gui/target.goml +++ b/tests/rustdoc-gui/target.goml @@ -25,11 +25,11 @@ call-function: ("check-style", { }) call-function: ("check-style", { "theme": "dark", - "background": "rgb(73, 74, 61)", - "border": "rgb(187, 116, 16)", + "background": "#494a3d", + "border": "#bb7410", }) call-function: ("check-style", { "theme": "light", - "background": "rgb(253, 255, 211)", - "border": "rgb(173, 124, 55)", + "background": "#fdffd3", + "border": "#ad7c37", }) From c62d49e75eb8d03c039e59878de4529f656f26b4 Mon Sep 17 00:00:00 2001 From: Caio Date: Mon, 29 May 2023 12:07:41 -0300 Subject: [PATCH 24/69] Address comment --- tests/ui/{enum-discriminant => structs-enums}/issue-3008-1.rs | 0 tests/ui/{enum-discriminant => structs-enums}/issue-3008-1.stderr | 0 tests/ui/{enum-discriminant => structs-enums}/issue-3008-2.rs | 0 tests/ui/{enum-discriminant => structs-enums}/issue-3008-2.stderr | 0 tests/ui/{enum-discriminant => structs-enums}/issue-3008-3.rs | 0 tests/ui/{enum-discriminant => structs-enums}/issue-3008-3.stderr | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{enum-discriminant => structs-enums}/issue-3008-1.rs (100%) rename tests/ui/{enum-discriminant => structs-enums}/issue-3008-1.stderr (100%) rename tests/ui/{enum-discriminant => structs-enums}/issue-3008-2.rs (100%) rename tests/ui/{enum-discriminant => structs-enums}/issue-3008-2.stderr (100%) rename tests/ui/{enum-discriminant => structs-enums}/issue-3008-3.rs (100%) rename tests/ui/{enum-discriminant => structs-enums}/issue-3008-3.stderr (100%) diff --git a/tests/ui/enum-discriminant/issue-3008-1.rs b/tests/ui/structs-enums/issue-3008-1.rs similarity index 100% rename from tests/ui/enum-discriminant/issue-3008-1.rs rename to tests/ui/structs-enums/issue-3008-1.rs diff --git a/tests/ui/enum-discriminant/issue-3008-1.stderr b/tests/ui/structs-enums/issue-3008-1.stderr similarity index 100% rename from tests/ui/enum-discriminant/issue-3008-1.stderr rename to tests/ui/structs-enums/issue-3008-1.stderr diff --git a/tests/ui/enum-discriminant/issue-3008-2.rs b/tests/ui/structs-enums/issue-3008-2.rs similarity index 100% rename from tests/ui/enum-discriminant/issue-3008-2.rs rename to tests/ui/structs-enums/issue-3008-2.rs diff --git a/tests/ui/enum-discriminant/issue-3008-2.stderr b/tests/ui/structs-enums/issue-3008-2.stderr similarity index 100% rename from tests/ui/enum-discriminant/issue-3008-2.stderr rename to tests/ui/structs-enums/issue-3008-2.stderr diff --git a/tests/ui/enum-discriminant/issue-3008-3.rs b/tests/ui/structs-enums/issue-3008-3.rs similarity index 100% rename from tests/ui/enum-discriminant/issue-3008-3.rs rename to tests/ui/structs-enums/issue-3008-3.rs diff --git a/tests/ui/enum-discriminant/issue-3008-3.stderr b/tests/ui/structs-enums/issue-3008-3.stderr similarity index 100% rename from tests/ui/enum-discriminant/issue-3008-3.stderr rename to tests/ui/structs-enums/issue-3008-3.stderr From cfd062341125ae3abbf2e7a7e30cfb1e8ac0c6e3 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 29 May 2023 17:15:48 +0200 Subject: [PATCH 25/69] unique borrows are mutating uses --- compiler/rustc_borrowck/src/def_use.rs | 1 - compiler/rustc_borrowck/src/type_check/mod.rs | 4 ++-- compiler/rustc_codegen_ssa/src/mir/analyze.rs | 1 - .../src/transform/check_consts/check.rs | 4 +--- compiler/rustc_middle/src/mir/visit.rs | 10 +++------- compiler/rustc_mir_dataflow/src/impls/liveness.rs | 3 +-- compiler/rustc_mir_transform/src/const_prop.rs | 1 - compiler/rustc_mir_transform/src/copy_prop.rs | 1 - compiler/rustc_mir_transform/src/ssa.rs | 1 - 9 files changed, 7 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_borrowck/src/def_use.rs b/compiler/rustc_borrowck/src/def_use.rs index b775739fed2a..b719a610e07c 100644 --- a/compiler/rustc_borrowck/src/def_use.rs +++ b/compiler/rustc_borrowck/src/def_use.rs @@ -50,7 +50,6 @@ pub fn categorize(context: PlaceContext) -> Option { PlaceContext::MutatingUse(MutatingUseContext::Borrow) | PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) | PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) | - PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow) | // `PlaceMention` and `AscribeUserType` both evaluate the place, which must not // contain dangling references. diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 51a84ce6cade..dc5121e1a2ae 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -766,8 +766,8 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { PlaceContext::MutatingUse(_) => ty::Invariant, PlaceContext::NonUse(StorageDead | StorageLive | VarDebugInfo) => ty::Invariant, PlaceContext::NonMutatingUse( - Inspect | Copy | Move | PlaceMention | SharedBorrow | ShallowBorrow | UniqueBorrow - | AddressOf | Projection, + Inspect | Copy | Move | PlaceMention | SharedBorrow | ShallowBorrow | AddressOf + | Projection, ) => ty::Covariant, PlaceContext::NonUse(AscribeUserTy(variance)) => variance, } diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index 835074806e90..22c1f05974dd 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -234,7 +234,6 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> | PlaceContext::NonMutatingUse( NonMutatingUseContext::Inspect | NonMutatingUseContext::SharedBorrow - | NonMutatingUseContext::UniqueBorrow | NonMutatingUseContext::ShallowBorrow | NonMutatingUseContext::AddressOf | NonMutatingUseContext::Projection, diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 138bc3eb74a4..57d939747aab 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -412,9 +412,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { BorrowKind::Shallow => { PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) } - BorrowKind::Unique => { - PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow) - } + BorrowKind::Unique => PlaceContext::MutatingUse(MutatingUseContext::Borrow), BorrowKind::Mut { .. } => { PlaceContext::MutatingUse(MutatingUseContext::Borrow) } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 942654b30749..8d44e929afde 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -650,8 +650,8 @@ macro_rules! make_mir_visitor { BorrowKind::Shallow => PlaceContext::NonMutatingUse( NonMutatingUseContext::ShallowBorrow ), - BorrowKind::Unique => PlaceContext::NonMutatingUse( - NonMutatingUseContext::UniqueBorrow + BorrowKind::Unique => PlaceContext::MutatingUse( + MutatingUseContext::Borrow ), BorrowKind::Mut { .. } => PlaceContext::MutatingUse(MutatingUseContext::Borrow), @@ -1265,8 +1265,6 @@ pub enum NonMutatingUseContext { SharedBorrow, /// Shallow borrow. ShallowBorrow, - /// Unique borrow. - UniqueBorrow, /// AddressOf for *const pointer. AddressOf, /// PlaceMention statement. @@ -1345,9 +1343,7 @@ impl PlaceContext { matches!( self, PlaceContext::NonMutatingUse( - NonMutatingUseContext::SharedBorrow - | NonMutatingUseContext::ShallowBorrow - | NonMutatingUseContext::UniqueBorrow + NonMutatingUseContext::SharedBorrow | NonMutatingUseContext::ShallowBorrow ) | PlaceContext::MutatingUse(MutatingUseContext::Borrow) ) } diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index aeca0073304e..6ae6bdc17d50 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -199,8 +199,7 @@ impl DefUse { | NonMutatingUseContext::Move | NonMutatingUseContext::PlaceMention | NonMutatingUseContext::ShallowBorrow - | NonMutatingUseContext::SharedBorrow - | NonMutatingUseContext::UniqueBorrow, + | NonMutatingUseContext::SharedBorrow, ) => Some(DefUse::Use), PlaceContext::MutatingUse(MutatingUseContext::Projection) diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index a5d18fff89bd..1ba1951afdef 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -772,7 +772,6 @@ impl<'tcx> Visitor<'tcx> for CanConstProp { // mutation. | NonMutatingUse(NonMutatingUseContext::SharedBorrow) | NonMutatingUse(NonMutatingUseContext::ShallowBorrow) - | NonMutatingUse(NonMutatingUseContext::UniqueBorrow) | NonMutatingUse(NonMutatingUseContext::AddressOf) | MutatingUse(MutatingUseContext::Borrow) | MutatingUse(MutatingUseContext::AddressOf) => { diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs index 319f3a797051..3df459dfa79b 100644 --- a/compiler/rustc_mir_transform/src/copy_prop.rs +++ b/compiler/rustc_mir_transform/src/copy_prop.rs @@ -130,7 +130,6 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> { PlaceContext::NonMutatingUse( NonMutatingUseContext::SharedBorrow | NonMutatingUseContext::ShallowBorrow - | NonMutatingUseContext::UniqueBorrow | NonMutatingUseContext::AddressOf, ) => true, // For debuginfo, merging locals is ok. diff --git a/compiler/rustc_mir_transform/src/ssa.rs b/compiler/rustc_mir_transform/src/ssa.rs index e8e4246b7970..7a0d3a025f36 100644 --- a/compiler/rustc_mir_transform/src/ssa.rs +++ b/compiler/rustc_mir_transform/src/ssa.rs @@ -216,7 +216,6 @@ impl<'tcx> Visitor<'tcx> for SsaVisitor<'_> { PlaceContext::NonMutatingUse( NonMutatingUseContext::SharedBorrow | NonMutatingUseContext::ShallowBorrow - | NonMutatingUseContext::UniqueBorrow | NonMutatingUseContext::AddressOf, ) | PlaceContext::MutatingUse(_) => { From b5732508dd4b2a855a61cab77d75c1fa612324eb Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 29 May 2023 17:20:42 +0200 Subject: [PATCH 26/69] add tests --- .../unique-borrows-are-invariant-1.rs | 18 +++++++++++ .../unique-borrows-are-invariant-1.stderr | 14 +++++++++ .../unique-borrows-are-invariant-2.rs | 31 +++++++++++++++++++ .../unique-borrows-are-invariant-2.stderr | 15 +++++++++ 4 files changed, 78 insertions(+) create mode 100644 tests/ui/closures/2229_closure_analysis/unique-borrows-are-invariant-1.rs create mode 100644 tests/ui/closures/2229_closure_analysis/unique-borrows-are-invariant-1.stderr create mode 100644 tests/ui/closures/2229_closure_analysis/unique-borrows-are-invariant-2.rs create mode 100644 tests/ui/closures/2229_closure_analysis/unique-borrows-are-invariant-2.stderr diff --git a/tests/ui/closures/2229_closure_analysis/unique-borrows-are-invariant-1.rs b/tests/ui/closures/2229_closure_analysis/unique-borrows-are-invariant-1.rs new file mode 100644 index 000000000000..f21ef43fb7cc --- /dev/null +++ b/tests/ui/closures/2229_closure_analysis/unique-borrows-are-invariant-1.rs @@ -0,0 +1,18 @@ +// edition:2021 + +// regression test for #112056 + +fn extend_lifetime<'a, 'b>(x: &mut (&'a str,), y: &'b str) { + let mut closure = |input| x.0 = input; + //~^ ERROR: lifetime may not live long enough + closure(y); +} + +fn main() { + let mut tuple = ("static",); + { + let x = String::from("temporary"); + extend_lifetime(&mut tuple, &x); + } + println!("{}", tuple.0); +} diff --git a/tests/ui/closures/2229_closure_analysis/unique-borrows-are-invariant-1.stderr b/tests/ui/closures/2229_closure_analysis/unique-borrows-are-invariant-1.stderr new file mode 100644 index 000000000000..730823281abc --- /dev/null +++ b/tests/ui/closures/2229_closure_analysis/unique-borrows-are-invariant-1.stderr @@ -0,0 +1,14 @@ +error: lifetime may not live long enough + --> $DIR/unique-borrows-are-invariant-1.rs:6:31 + | +LL | fn extend_lifetime<'a, 'b>(x: &mut (&'a str,), y: &'b str) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | let mut closure = |input| x.0 = input; + | ^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + +error: aborting due to previous error + diff --git a/tests/ui/closures/2229_closure_analysis/unique-borrows-are-invariant-2.rs b/tests/ui/closures/2229_closure_analysis/unique-borrows-are-invariant-2.rs new file mode 100644 index 000000000000..dd9d986c2089 --- /dev/null +++ b/tests/ui/closures/2229_closure_analysis/unique-borrows-are-invariant-2.rs @@ -0,0 +1,31 @@ +// edition:2021 + +// regression test for #112056 + +struct Spooky<'b> { + owned: Option<&'static u32>, + borrowed: &'b &'static u32, +} + +impl<'b> Spooky<'b> { + fn create_self_reference<'a>(&'a mut self) { + let mut closure = || { + if let Some(owned) = &self.owned { + let borrow: &'a &'static u32 = owned; + self.borrowed = borrow; + //~^ ERROR: lifetime may not live long enough + } + }; + closure(); + } +} + +fn main() { + let mut spooky: Spooky<'static> = Spooky { + owned: Some(&1), + borrowed: &&1, + }; + spooky.create_self_reference(); + spooky.owned = None; + println!("{}", **spooky.borrowed); +} diff --git a/tests/ui/closures/2229_closure_analysis/unique-borrows-are-invariant-2.stderr b/tests/ui/closures/2229_closure_analysis/unique-borrows-are-invariant-2.stderr new file mode 100644 index 000000000000..66ba0fe3547a --- /dev/null +++ b/tests/ui/closures/2229_closure_analysis/unique-borrows-are-invariant-2.stderr @@ -0,0 +1,15 @@ +error: lifetime may not live long enough + --> $DIR/unique-borrows-are-invariant-2.rs:15:17 + | +LL | impl<'b> Spooky<'b> { + | -- lifetime `'b` defined here +LL | fn create_self_reference<'a>(&'a mut self) { + | -- lifetime `'a` defined here +... +LL | self.borrowed = borrow; + | ^^^^^^^^^^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b` + | + = help: consider adding the following bound: `'a: 'b` + +error: aborting due to previous error + From 25f8f4cf953975dba37051ac1565e4999418c996 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 29 May 2023 17:49:19 +0200 Subject: [PATCH 27/69] add FIXME --- compiler/rustc_middle/src/mir/syntax.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 6d6d71bc87b1..3e474c1d377e 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -220,6 +220,11 @@ pub enum BorrowKind { /// immutable, but not aliasable. This solves the problem. For /// simplicity, we don't give users the way to express this /// borrow, it's just used when translating closures. + /// + // FIXME(#112072): This is wrong. Unique borrows are mutable borrows except + // that they do not require their pointee to be marked as a mutable. + // They should still be treated as mutable borrows in every other way, + // e.g. for variance or overlap checking. Unique, /// Data is mutable and not aliasable. From e33e20824ff7b69bc053b8843883652c9692c5c1 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 29 May 2023 17:54:53 +0000 Subject: [PATCH 28/69] Rename `tcx.mk_re_*` => `Region::new_*` --- .../src/diagnostics/bound_region_errors.rs | 39 +++---- compiler/rustc_borrowck/src/nll.rs | 2 +- .../rustc_borrowck/src/region_infer/mod.rs | 6 +- .../src/region_infer/opaque_types.rs | 3 +- compiler/rustc_borrowck/src/type_check/mod.rs | 2 +- .../rustc_borrowck/src/universal_regions.rs | 11 +- .../rustc_hir_analysis/src/astconv/mod.rs | 32 +++--- .../src/check/compare_impl_item.rs | 10 +- .../rustc_hir_analysis/src/check/dropck.rs | 2 +- .../rustc_hir_analysis/src/check/intrinsic.rs | 16 ++- .../rustc_hir_analysis/src/check/wfcheck.rs | 39 ++++--- compiler/rustc_hir_analysis/src/collect.rs | 2 +- .../src/collect/predicates_of.rs | 13 ++- .../src/generator_interior/mod.rs | 8 +- .../src/infer/canonical/canonicalizer.rs | 2 +- .../rustc_infer/src/infer/canonical/mod.rs | 2 +- .../src/infer/canonical/query_response.rs | 13 +-- .../nice_region_error/placeholder_error.rs | 10 +- .../src/infer/higher_ranked/mod.rs | 6 +- .../src/infer/lexical_region_resolve/mod.rs | 2 +- compiler/rustc_infer/src/infer/mod.rs | 2 +- .../infer/region_constraints/leak_check.rs | 8 +- .../src/infer/region_constraints/mod.rs | 8 +- compiler/rustc_middle/src/infer/canonical.rs | 2 +- compiler/rustc_middle/src/mir/query.rs | 2 +- compiler/rustc_middle/src/ty/codec.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 93 +--------------- compiler/rustc_middle/src/ty/fold.rs | 13 +-- compiler/rustc_middle/src/ty/generics.rs | 2 +- compiler/rustc_middle/src/ty/opaque_types.rs | 2 +- compiler/rustc_middle/src/ty/print/pretty.rs | 19 ++-- compiler/rustc_middle/src/ty/sty.rs | 101 +++++++++++++++++- compiler/rustc_mir_build/src/thir/cx/mod.rs | 2 +- .../src/solve/assembly/structural_traits.rs | 2 +- .../src/solve/canonicalize.rs | 2 +- .../src/traits/project.rs | 4 +- .../src/traits/select/confirmation.rs | 3 +- .../src/traits/select/mod.rs | 2 +- compiler/rustc_traits/src/chalk/db.rs | 2 +- compiler/rustc_traits/src/chalk/lowering.rs | 24 +++-- compiler/rustc_ty_utils/src/abi.rs | 4 +- compiler/rustc_ty_utils/src/ty.rs | 5 +- 42 files changed, 291 insertions(+), 233 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index f41795d60a0b..cfcf31fce32b 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -180,24 +180,25 @@ trait TypeOpInfo<'tcx> { return; }; - let placeholder_region = tcx.mk_re_placeholder(ty::Placeholder { - universe: adjusted_universe.into(), - bound: placeholder.bound, - }); + let placeholder_region = ty::Region::new_placeholder( + tcx, + ty::Placeholder { universe: adjusted_universe.into(), bound: placeholder.bound }, + ); - let error_region = - if let RegionElement::PlaceholderRegion(error_placeholder) = error_element { - let adjusted_universe = - error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32()); - adjusted_universe.map(|adjusted| { - tcx.mk_re_placeholder(ty::Placeholder { - universe: adjusted.into(), - bound: error_placeholder.bound, - }) - }) - } else { - None - }; + let error_region = if let RegionElement::PlaceholderRegion(error_placeholder) = + error_element + { + let adjusted_universe = + error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32()); + adjusted_universe.map(|adjusted| { + ty::Region::new_placeholder( + tcx, + ty::Placeholder { universe: adjusted.into(), bound: error_placeholder.bound }, + ) + }) + } else { + None + }; debug!(?placeholder_region); @@ -390,7 +391,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>( error_region, ®ion_constraints, |vid| ocx.infcx.region_var_origin(vid), - |vid| ocx.infcx.universe_of_region(ocx.infcx.tcx.mk_re_var(vid)), + |vid| ocx.infcx.universe_of_region(ty::Region::new_var(ocx.infcx.tcx, vid)), ) } @@ -411,7 +412,7 @@ fn try_extract_error_from_region_constraints<'tcx>( } // FIXME: Should this check the universe of the var? Constraint::VarSubReg(vid, sup) if sup == placeholder_region => { - Some((infcx.tcx.mk_re_var(vid), cause.clone())) + Some((ty::Region::new_var(infcx.tcx, vid), cause.clone())) } _ => None, } diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 889acb3acbed..b5014a3f479c 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -441,7 +441,7 @@ fn for_each_region_constraint<'tcx>( let subject = match req.subject { ClosureOutlivesSubject::Region(subject) => format!("{:?}", subject), ClosureOutlivesSubject::Ty(ty) => { - format!("{:?}", ty.instantiate(tcx, |vid| tcx.mk_re_var(vid))) + format!("{:?}", ty.instantiate(tcx, |vid| ty::Region::new_var(tcx, vid))) } }; with_msg(format!("where {}: {:?}", subject, req.outlived_free_region,))?; diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 50b246b1478f..2a0cb49672b8 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -1158,7 +1158,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { .universal_regions_outlived_by(r_scc) .filter(|&u_r| !self.universal_regions.is_local_free_region(u_r)) .find(|&u_r| self.eval_equal(u_r, r_vid)) - .map(|u_r| tcx.mk_re_var(u_r)) + .map(|u_r| ty::Region::new_var(tcx, u_r)) // In the case of a failure, use `ReErased`. We will eventually // return `None` in this case. .unwrap_or(tcx.lifetimes.re_erased) @@ -1355,7 +1355,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let vid = self.to_region_vid(r); let scc = self.constraint_sccs.scc(vid); let repr = self.scc_representatives[scc]; - tcx.mk_re_var(repr) + ty::Region::new_var(tcx, repr) }) } @@ -1779,7 +1779,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } // If not, report an error. - let member_region = infcx.tcx.mk_re_var(member_region_vid); + let member_region = ty::Region::new_var(infcx.tcx, member_region_vid); errors_buffer.push(RegionErrorKind::UnexpectedHiddenRegion { span: m_c.definition_span, hidden_ty: m_c.hidden_ty, diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 7fc89e89a359..33f07c1d8fc4 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -92,7 +92,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { } None => { subst_regions.push(vid); - infcx.tcx.mk_re_error_with_message( + ty::Region::new_error_with_message( + infcx.tcx, concrete_type.span, "opaque type with non-universal region substs", ) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 51a84ce6cade..03f933681bc2 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -139,7 +139,7 @@ pub(crate) fn type_check<'mir, 'tcx>( upvars: &[Upvar<'tcx>], use_polonius: bool, ) -> MirTypeckResults<'tcx> { - let implicit_region_bound = infcx.tcx.mk_re_var(universal_regions.fr_fn_body); + let implicit_region_bound = ty::Region::new_var(infcx.tcx, universal_regions.fr_fn_body); let mut constraints = MirTypeckRegionConstraints { placeholder_indices: PlaceholderIndices::default(), placeholder_index_to_region: IndexVec::default(), diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 56f078f2da81..c871703429a5 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -500,7 +500,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { .next_nll_region_var(FR, || RegionCtxt::Free(Symbol::intern("c-variadic"))) .as_var(); - let region = self.infcx.tcx.mk_re_var(reg_vid); + let region = ty::Region::new_var(self.infcx.tcx, reg_vid); let va_list_ty = self.infcx.tcx.type_of(va_list_did).subst(self.infcx.tcx, &[region.into()]); @@ -660,7 +660,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind: ty::BrEnv, }; - let env_region = tcx.mk_re_late_bound(ty::INNERMOST, br); + let env_region = ty::Region::new_late_bound(tcx, ty::INNERMOST, br); let closure_ty = tcx.closure_env_ty(def_id, substs, env_region).unwrap(); // The "inputs" of the closure in the @@ -778,7 +778,8 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> { { let (value, _map) = self.tcx.replace_late_bound_regions(value, |br| { debug!(?br); - let liberated_region = self.tcx.mk_re_free(all_outlive_scope.to_def_id(), br.kind); + let liberated_region = + ty::Region::new_free(self.tcx, all_outlive_scope.to_def_id(), br.kind); let region_vid = { let name = match br.kind.get_name() { Some(name) => name, @@ -889,7 +890,7 @@ impl<'tcx> UniversalRegionIndices<'tcx> { where T: TypeFoldable>, { - tcx.fold_regions(value, |region, _| tcx.mk_re_var(self.to_region_vid(region))) + tcx.fold_regions(value, |region, _| ty::Region::new_var(tcx, self.to_region_vid(region))) } } @@ -929,7 +930,7 @@ fn for_each_late_bound_region_in_item<'tcx>( for bound_var in tcx.late_bound_vars(tcx.hir().local_def_id_to_hir_id(mir_def_id)) { let ty::BoundVariableKind::Region(bound_region) = bound_var else { continue; }; - let liberated_region = tcx.mk_re_free(mir_def_id.to_def_id(), bound_region); + let liberated_region = ty::Region::new_free(tcx, mir_def_id.to_def_id(), bound_region); f(liberated_region); } } diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 284ae0e1e58a..d9796e8ffe0b 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -239,7 +239,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { var: ty::BoundVar::from_u32(index), kind: ty::BrNamed(def_id, name), }; - tcx.mk_re_late_bound(debruijn, br) + ty::Region::new_late_bound(tcx, debruijn, br) } Some(rbv::ResolvedArg::EarlyBound(def_id)) => { @@ -247,12 +247,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let item_def_id = tcx.hir().ty_param_owner(def_id.expect_local()); let generics = tcx.generics_of(item_def_id); let index = generics.param_def_id_to_index[&def_id]; - tcx.mk_re_early_bound(ty::EarlyBoundRegion { def_id, index, name }) + ty::Region::new_early_bound(tcx, ty::EarlyBoundRegion { def_id, index, name }) } Some(rbv::ResolvedArg::Free(scope, id)) => { let name = lifetime_name(id.expect_local()); - tcx.mk_re_free(scope, ty::BrNamed(id, name)) + ty::Region::new_free(tcx, scope, ty::BrNamed(id, name)) // (*) -- not late-bound, won't change } @@ -269,7 +269,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // elision. `resolve_lifetime` should have // reported an error in this case -- but if // not, let's error out. - tcx.mk_re_error_with_message( + ty::Region::new_error_with_message( + tcx, lifetime.ident.span, "unelided lifetime in signature", ) @@ -485,7 +486,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { debug!(?param, "unelided lifetime in signature"); // This indicates an illegal lifetime in a non-assoc-trait position - tcx.mk_re_error_with_message( + ty::Region::new_error_with_message( + tcx, self.span, "unelided lifetime in signature", ) @@ -1219,15 +1221,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let substs = candidate.skip_binder().substs.extend_to(tcx, assoc_item.def_id, |param, _| { let subst = match param.kind { - GenericParamDefKind::Lifetime => tcx - .mk_re_late_bound( - ty::INNERMOST, - ty::BoundRegion { - var: ty::BoundVar::from_usize(num_bound_vars), - kind: ty::BoundRegionKind::BrNamed(param.def_id, param.name), - }, - ) - .into(), + GenericParamDefKind::Lifetime => ty::Region::new_late_bound( + tcx, + ty::INNERMOST, + ty::BoundRegion { + var: ty::BoundVar::from_usize(num_bound_vars), + kind: ty::BoundRegionKind::BrNamed(param.def_id, param.name), + }, + ) + .into(), GenericParamDefKind::Type { .. } => tcx .mk_bound( ty::INNERMOST, @@ -1804,7 +1806,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } else { err.emit() }; - tcx.mk_re_error(e) + ty::Region::new_error(tcx, e) }) } }) diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index e33330e259c3..bd7cb5a30ec6 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -472,7 +472,8 @@ impl<'tcx> TypeFolder> for RemapLateBound<'_, 'tcx> { fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { if let ty::ReFree(fr) = *r { - self.tcx.mk_re_free( + ty::Region::new_free( + self.tcx, fr.scope, self.mapping.get(&fr.bound_region).copied().unwrap_or(fr.bound_region), ) @@ -786,9 +787,9 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( } let Some(ty::ReEarlyBound(e)) = map.get(®ion.into()).map(|r| r.expect_region().kind()) else { - return tcx.mk_re_error_with_message(return_span, "expected ReFree to map to ReEarlyBound") + return ty::Region::new_error_with_message(tcx, return_span, "expected ReFree to map to ReEarlyBound") }; - tcx.mk_re_early_bound(ty::EarlyBoundRegion { + ty::Region::new_early_bound(tcx, ty::EarlyBoundRegion { def_id: e.def_id, name: e.name, index: (e.index as usize - num_trait_substs + num_impl_substs) as u32, @@ -1933,7 +1934,8 @@ pub(super) fn check_type_bounds<'tcx>( let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name); let bound_var = ty::BoundVariableKind::Region(kind); bound_vars.push(bound_var); - tcx.mk_re_late_bound( + ty::Region::new_late_bound( + tcx, ty::INNERMOST, ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind }, ) diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index eeb69c389cd8..897e4135fa03 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -183,7 +183,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( } RegionResolutionError::SubSupConflict(_, _, _, a, _, b, _) => format!("{b}: {a}"), RegionResolutionError::UpperBoundUniverseConflict(a, _, _, _, b) => { - format!("{b}: {a}", a = tcx.mk_re_var(a)) + format!("{b}: {a}", a = ty::Region::new_var(tcx, a)) } }; guar = Some( diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index fbd4a577d68f..1f18017f00b9 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -145,11 +145,13 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { ]); let mk_va_list_ty = |mutbl| { tcx.lang_items().va_list().map(|did| { - let region = tcx.mk_re_late_bound( + let region = ty::Region::new_late_bound( + tcx, ty::INNERMOST, ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(None) }, ); - let env_region = tcx.mk_re_late_bound( + let env_region = ty::Region::new_late_bound( + tcx, ty::INNERMOST, ty::BoundRegion { var: ty::BoundVar::from_u32(1), kind: ty::BrEnv }, ); @@ -393,7 +395,12 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(None) }; ( 1, - vec![tcx.mk_imm_ref(tcx.mk_re_late_bound(ty::INNERMOST, br), param(0))], + vec![ + tcx.mk_imm_ref( + ty::Region::new_late_bound(tcx, ty::INNERMOST, br), + param(0), + ), + ], tcx.mk_projection(discriminant_def_id, tcx.mk_substs(&[param(0).into()])), ) } @@ -443,7 +450,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { sym::raw_eq => { let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(None) }; - let param_ty = tcx.mk_imm_ref(tcx.mk_re_late_bound(ty::INNERMOST, br), param(0)); + let param_ty = + tcx.mk_imm_ref(ty::Region::new_late_bound(tcx, ty::INNERMOST, br), param(0)); (1, vec![param_ty; 2], tcx.types.bool) } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 4c513c4d8cc6..7295d1dc0fdc 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -556,11 +556,14 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable>>( // Same for the region. In our example, 'a corresponds // to the 'me parameter. let region_param = gat_generics.param_at(*region_a_idx, tcx); - let region_param = tcx.mk_re_early_bound(ty::EarlyBoundRegion { - def_id: region_param.def_id, - index: region_param.index, - name: region_param.name, - }); + let region_param = ty::Region::new_early_bound( + tcx, + ty::EarlyBoundRegion { + def_id: region_param.def_id, + index: region_param.index, + name: region_param.name, + }, + ); // The predicate we expect to see. (In our example, // `Self: 'me`.) let clause = ty::PredicateKind::Clause(ty::Clause::TypeOutlives( @@ -593,18 +596,24 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable>>( debug!("required clause: {region_a} must outlive {region_b}"); // Translate into the generic parameters of the GAT. let region_a_param = gat_generics.param_at(*region_a_idx, tcx); - let region_a_param = tcx.mk_re_early_bound(ty::EarlyBoundRegion { - def_id: region_a_param.def_id, - index: region_a_param.index, - name: region_a_param.name, - }); + let region_a_param = ty::Region::new_early_bound( + tcx, + ty::EarlyBoundRegion { + def_id: region_a_param.def_id, + index: region_a_param.index, + name: region_a_param.name, + }, + ); // Same for the region. let region_b_param = gat_generics.param_at(*region_b_idx, tcx); - let region_b_param = tcx.mk_re_early_bound(ty::EarlyBoundRegion { - def_id: region_b_param.def_id, - index: region_b_param.index, - name: region_b_param.name, - }); + let region_b_param = ty::Region::new_early_bound( + tcx, + ty::EarlyBoundRegion { + def_id: region_b_param.def_id, + index: region_b_param.index, + name: region_b_param.name, + }, + ); // The predicate we expect to see. let clause = ty::PredicateKind::Clause(ty::Clause::RegionOutlives( ty::OutlivesPredicate(region_a_param, region_b_param), diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 75d99fee152e..e7a8fd8ffd79 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -440,7 +440,7 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { self.tcx.replace_late_bound_regions_uncached( poly_trait_ref, |_| { - self.tcx.mk_re_early_bound(ty::EarlyBoundRegion { + ty::Region::new_early_bound(self.tcx, ty::EarlyBoundRegion { def_id: item_def_id, index: 0, name: Symbol::intern(<_name), diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index e5b5dae551e8..70d950eddd8a 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -306,11 +306,14 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen let Some(dup_index) = generics.param_def_id_to_index(tcx, dup_def) else { bug!() }; - let dup_region = tcx.mk_re_early_bound(ty::EarlyBoundRegion { - def_id: dup_def, - index: dup_index, - name: duplicate.name.ident().name, - }); + let dup_region = ty::Region::new_early_bound( + tcx, + ty::EarlyBoundRegion { + def_id: dup_def, + index: dup_index, + name: duplicate.name.ident().name, + }, + ); predicates.push(( ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::RegionOutlives( ty::OutlivesPredicate(orig_region, dup_region), diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs index 427d6f8803c1..fb28233bfb1c 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs @@ -269,7 +269,7 @@ pub fn resolve_interior<'a, 'tcx>( }, _ => mk_bound_region(ty::BrAnon(None)), }; - let r = fcx.tcx.mk_re_late_bound(current_depth, br); + let r = ty::Region::new_late_bound(fcx.tcx, current_depth, br); r }); captured_tys.insert(ty).then(|| { @@ -295,7 +295,11 @@ pub fn resolve_interior<'a, 'tcx>( let var = ty::BoundVar::from_usize(bound_vars.len()); bound_vars.push(ty::BoundVariableKind::Region(kind)); counter += 1; - fcx.tcx.mk_re_late_bound(ty::INNERMOST, ty::BoundRegion { var, kind }) + ty::Region::new_late_bound( + fcx.tcx, + ty::INNERMOST, + ty::BoundRegion { var, kind }, + ) }, types: &mut |b| bug!("unexpected bound ty in binder: {b:?}"), consts: &mut |b, ty| bug!("unexpected bound ct in binder: {b:?} {ty}"), diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 427d05c8b4da..bf53a73f3983 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -771,7 +771,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { ) -> ty::Region<'tcx> { let var = self.canonical_var(info, r.into()); let br = ty::BoundRegion { var, kind: ty::BrAnon(None) }; - self.interner().mk_re_late_bound(self.binder_index, br) + ty::Region::new_late_bound(self.interner(), self.binder_index, br) } /// Given a type variable `ty_var` of the given kind, first check diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs index 2abdd5b0aec8..c8c318c3f024 100644 --- a/compiler/rustc_infer/src/infer/canonical/mod.rs +++ b/compiler/rustc_infer/src/infer/canonical/mod.rs @@ -141,7 +141,7 @@ impl<'tcx> InferCtxt<'tcx> { CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion { universe, bound }) => { let universe_mapped = universe_map(universe); let placeholder_mapped = ty::PlaceholderRegion { universe: universe_mapped, bound }; - self.tcx.mk_re_placeholder(placeholder_mapped).into() + ty::Region::new_placeholder(self.tcx, placeholder_mapped).into() } CanonicalVarKind::Const(ui, ty) => self diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 88256c819f4d..2cf8d8c702d4 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -668,14 +668,15 @@ pub fn make_query_region_constraints<'tcx>( let constraint = match *k { // Swap regions because we are going from sub (<=) to outlives // (>=). - Constraint::VarSubVar(v1, v2) => { - ty::OutlivesPredicate(tcx.mk_re_var(v2).into(), tcx.mk_re_var(v1)) - } + Constraint::VarSubVar(v1, v2) => ty::OutlivesPredicate( + ty::Region::new_var(tcx, v2).into(), + ty::Region::new_var(tcx, v1), + ), Constraint::VarSubReg(v1, r2) => { - ty::OutlivesPredicate(r2.into(), tcx.mk_re_var(v1)) + ty::OutlivesPredicate(r2.into(), ty::Region::new_var(tcx, v1)) } Constraint::RegSubVar(r1, v2) => { - ty::OutlivesPredicate(tcx.mk_re_var(v2).into(), r1) + ty::OutlivesPredicate(ty::Region::new_var(tcx, v2).into(), r1) } Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r2.into(), r1), }; @@ -719,7 +720,7 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> { } fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx> { - self.infcx.tcx.mk_re_placeholder(placeholder) + ty::Region::new_placeholder(self.infcx.tcx, placeholder) } fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> { diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs index c9c1f0aeaac8..0b3bc1ce6b38 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -79,7 +79,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { sup_placeholder @ Region(Interned(RePlaceholder(_), _)), _, )) => self.try_report_trait_placeholder_mismatch( - Some(self.tcx().mk_re_var(*vid)), + Some(ty::Region::new_var(self.tcx(), *vid)), cause, Some(*sub_placeholder), Some(*sup_placeholder), @@ -95,7 +95,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { _, _, )) => self.try_report_trait_placeholder_mismatch( - Some(self.tcx().mk_re_var(*vid)), + Some(ty::Region::new_var(self.tcx(), *vid)), cause, Some(*sub_placeholder), None, @@ -111,7 +111,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { sup_placeholder @ Region(Interned(RePlaceholder(_), _)), _, )) => self.try_report_trait_placeholder_mismatch( - Some(self.tcx().mk_re_var(*vid)), + Some(ty::Region::new_var(self.tcx(), *vid)), cause, None, Some(*sup_placeholder), @@ -127,7 +127,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { sup_placeholder @ Region(Interned(RePlaceholder(_), _)), _, )) => self.try_report_trait_placeholder_mismatch( - Some(self.tcx().mk_re_var(*vid)), + Some(ty::Region::new_var(self.tcx(), *vid)), cause, None, Some(*sup_placeholder), @@ -141,7 +141,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { SubregionOrigin::Subtype(box TypeTrace { cause, values }), sup_placeholder @ Region(Interned(RePlaceholder(_), _)), )) => self.try_report_trait_placeholder_mismatch( - Some(self.tcx().mk_re_var(*vid)), + Some(ty::Region::new_var(self.tcx(), *vid)), cause, None, Some(*sup_placeholder), diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs index c304cd25c9c4..1c298e7d4ecd 100644 --- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs +++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs @@ -82,8 +82,10 @@ impl<'tcx> InferCtxt<'tcx> { let delegate = FnMutDelegate { regions: &mut |br: ty::BoundRegion| { - self.tcx - .mk_re_placeholder(ty::PlaceholderRegion { universe: next_universe, bound: br }) + ty::Region::new_placeholder( + self.tcx, + ty::PlaceholderRegion { universe: next_universe, bound: br }, + ) }, types: &mut |bound_ty: ty::BoundTy| { self.tcx.mk_placeholder(ty::PlaceholderType { diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index 8482ae2aa38c..485e34fe2bf9 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -347,7 +347,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // name the placeholder, then the placeholder is // larger; otherwise, the only ancestor is `'static`. Err(placeholder) if empty_ui.can_name(placeholder.universe) => { - self.tcx().mk_re_placeholder(placeholder) + ty::Region::new_placeholder(self.tcx(), placeholder) } Err(_) => self.tcx().lifetimes.re_static, }; diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index cd99fc312129..b49282726fd2 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1065,7 +1065,7 @@ impl<'tcx> InferCtxt<'tcx> { ) -> ty::Region<'tcx> { let region_var = self.inner.borrow_mut().unwrap_region_constraints().new_region_var(universe, origin); - self.tcx.mk_re_var(region_var) + ty::Region::new_var(self.tcx, region_var) } /// Return the universe that the region `r` was created in. For diff --git a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs index 89cfc9ea3d14..5f4093c1c3c1 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs @@ -280,7 +280,7 @@ impl<'me, 'tcx> LeakCheck<'me, 'tcx> { placeholder1: ty::PlaceholderRegion, placeholder2: ty::PlaceholderRegion, ) -> TypeError<'tcx> { - self.error(placeholder1, self.tcx.mk_re_placeholder(placeholder2)) + self.error(placeholder1, ty::Region::new_placeholder(self.tcx, placeholder2)) } fn error( @@ -413,13 +413,13 @@ impl<'tcx> MiniGraph<'tcx> { for undo_entry in undo_log { match undo_entry { &AddConstraint(Constraint::VarSubVar(a, b)) => { - each_edge(tcx.mk_re_var(a), tcx.mk_re_var(b)); + each_edge(ty::Region::new_var(tcx, a), ty::Region::new_var(tcx, b)); } &AddConstraint(Constraint::RegSubVar(a, b)) => { - each_edge(a, tcx.mk_re_var(b)); + each_edge(a, ty::Region::new_var(tcx, b)); } &AddConstraint(Constraint::VarSubReg(a, b)) => { - each_edge(tcx.mk_re_var(a), b); + each_edge(ty::Region::new_var(tcx, a), b); } &AddConstraint(Constraint::RegSubReg(a, b)) => { each_edge(a, b); diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index c7a307b89e41..cd8d23bf635c 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -610,13 +610,13 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { let resolved = ut .probe_value(root_vid) .get_value_ignoring_universes() - .unwrap_or_else(|| tcx.mk_re_var(root_vid)); + .unwrap_or_else(|| ty::Region::new_var(tcx, root_vid)); // Don't resolve a variable to a region that it cannot name. if self.var_universe(vid).can_name(self.universe(resolved)) { resolved } else { - tcx.mk_re_var(vid) + ty::Region::new_var(tcx, vid) } } @@ -637,7 +637,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { ) -> Region<'tcx> { let vars = TwoRegions { a, b }; if let Some(&c) = self.combine_map(t).get(&vars) { - return tcx.mk_re_var(c); + return ty::Region::new_var(tcx, c); } let a_universe = self.universe(a); let b_universe = self.universe(b); @@ -645,7 +645,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { let c = self.new_region_var(c_universe, MiscVariable(origin.span())); self.combine_map(t).insert(vars, c); self.undo_log.push(AddCombination(t, vars)); - let new_r = tcx.mk_re_var(c); + let new_r = ty::Region::new_var(tcx, c); for old_r in [a, b] { match t { Glb => self.make_subregion(origin.clone(), new_r, old_r), diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 56171314944c..29dae67bfca7 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -415,7 +415,7 @@ impl<'tcx> CanonicalVarValues<'tcx> { var: ty::BoundVar::from_usize(i), kind: ty::BrAnon(None), }; - tcx.mk_re_late_bound(ty::INNERMOST, br).into() + ty::Region::new_late_bound(tcx, ty::INNERMOST, br).into() } CanonicalVarKind::Const(_, ty) | CanonicalVarKind::PlaceholderConst(_, ty) => tcx diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 53fd2dd23a70..a15c419da7ac 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -413,7 +413,7 @@ impl<'tcx> ClosureOutlivesSubjectTy<'tcx> { ty::ReVar(vid) => { let br = ty::BoundRegion { var: ty::BoundVar::new(vid.index()), kind: ty::BrAnon(None) }; - tcx.mk_re_late_bound(depth, br) + ty::Region::new_late_bound(tcx, depth, br) } _ => bug!("unexpected region in ClosureOutlivesSubjectTy: {r:?}"), }); diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 7fc75674da53..76f52bc34ed1 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -264,7 +264,7 @@ impl<'tcx, D: TyDecoder>> Decodable for mir::Place<'tcx> { impl<'tcx, D: TyDecoder>> Decodable for ty::Region<'tcx> { fn decode(decoder: &mut D) -> Self { - decoder.interner().mk_region_from_kind(Decodable::decode(decoder)) + ty::Region::new_from_kind(decoder.interner(), Decodable::decode(decoder)) } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 0464336627f8..8bbe0c98e9f2 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -713,34 +713,6 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_ty_from_kind(Error(reported)) } - /// Constructs a `RegionKind::ReError` lifetime. - #[track_caller] - pub fn mk_re_error(self, reported: ErrorGuaranteed) -> Region<'tcx> { - self.intern_region(ty::ReError(reported)) - } - - /// Constructs a `RegionKind::ReError` lifetime and registers a `delay_span_bug` to ensure it - /// gets used. - #[track_caller] - pub fn mk_re_error_misc(self) -> Region<'tcx> { - self.mk_re_error_with_message( - DUMMY_SP, - "RegionKind::ReError constructed but no error reported", - ) - } - - /// Constructs a `RegionKind::ReError` lifetime and registers a `delay_span_bug` with the given - /// `msg` to ensure it gets used. - #[track_caller] - pub fn mk_re_error_with_message>( - self, - span: S, - msg: &'static str, - ) -> Region<'tcx> { - let reported = self.sess.delay_span_bug(span, msg); - self.mk_re_error(reported) - } - /// Like [TyCtxt::ty_error] but for constants, with current `ErrorGuaranteed` #[track_caller] pub fn const_error(self, ty: Ty<'tcx>, reported: ErrorGuaranteed) -> Const<'tcx> { @@ -1519,9 +1491,9 @@ macro_rules! direct_interners { // Functions with a `mk_` prefix are intended for use outside this file and // crate. Functions with an `intern_` prefix are intended for use within this -// file only, and have a corresponding `mk_` function. +// crate only, and have a corresponding `mk_` function. direct_interners! { - region: intern_region(RegionKind<'tcx>): Region -> Region<'tcx>, + region: pub(crate) intern_region(RegionKind<'tcx>): Region -> Region<'tcx>, const_: intern_const(ConstData<'tcx>): Const -> Const<'tcx>, const_allocation: pub mk_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>, layout: pub mk_layout(LayoutS): Layout -> Layout<'tcx>, @@ -1996,7 +1968,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn mk_param_from_def(self, param: &ty::GenericParamDef) -> GenericArg<'tcx> { match param.kind { GenericParamDefKind::Lifetime => { - self.mk_re_early_bound(param.to_early_bound_region_data()).into() + ty::Region::new_early_bound(self, param.to_early_bound_region_data()).into() } GenericParamDefKind::Type { .. } => self.mk_ty_param(param.index, param.name).into(), GenericParamDefKind::Const { .. } => self @@ -2036,65 +2008,6 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_alias(ty::Opaque, self.mk_alias_ty(def_id, substs)) } - #[inline] - pub fn mk_re_early_bound(self, early_bound_region: ty::EarlyBoundRegion) -> Region<'tcx> { - self.intern_region(ty::ReEarlyBound(early_bound_region)) - } - - #[inline] - pub fn mk_re_late_bound( - self, - debruijn: ty::DebruijnIndex, - bound_region: ty::BoundRegion, - ) -> Region<'tcx> { - // Use a pre-interned one when possible. - if let ty::BoundRegion { var, kind: ty::BrAnon(None) } = bound_region - && let Some(inner) = self.lifetimes.re_late_bounds.get(debruijn.as_usize()) - && let Some(re) = inner.get(var.as_usize()).copied() - { - re - } else { - self.intern_region(ty::ReLateBound(debruijn, bound_region)) - } - } - - #[inline] - pub fn mk_re_free(self, scope: DefId, bound_region: ty::BoundRegionKind) -> Region<'tcx> { - self.intern_region(ty::ReFree(ty::FreeRegion { scope, bound_region })) - } - - #[inline] - pub fn mk_re_var(self, v: ty::RegionVid) -> Region<'tcx> { - // Use a pre-interned one when possible. - self.lifetimes - .re_vars - .get(v.as_usize()) - .copied() - .unwrap_or_else(|| self.intern_region(ty::ReVar(v))) - } - - #[inline] - pub fn mk_re_placeholder(self, placeholder: ty::PlaceholderRegion) -> Region<'tcx> { - self.intern_region(ty::RePlaceholder(placeholder)) - } - - // Avoid this in favour of more specific `mk_re_*` methods, where possible, - // to avoid the cost of the `match`. - pub fn mk_region_from_kind(self, kind: ty::RegionKind<'tcx>) -> Region<'tcx> { - match kind { - ty::ReEarlyBound(region) => self.mk_re_early_bound(region), - ty::ReLateBound(debruijn, region) => self.mk_re_late_bound(debruijn, region), - ty::ReFree(ty::FreeRegion { scope, bound_region }) => { - self.mk_re_free(scope, bound_region) - } - ty::ReStatic => self.lifetimes.re_static, - ty::ReVar(vid) => self.mk_re_var(vid), - ty::RePlaceholder(region) => self.mk_re_placeholder(region), - ty::ReErased => self.lifetimes.re_erased, - ty::ReError(reported) => self.mk_re_error(reported), - } - } - pub fn mk_place_field(self, place: Place<'tcx>, f: FieldIdx, ty: Ty<'tcx>) -> Place<'tcx> { self.mk_place_elem(place, PlaceElem::Field(f, ty)) } diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 25890eb15cde..149ce29b8d94 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -213,7 +213,7 @@ where // debruijn index. Then we adjust it to the // correct depth. assert_eq!(debruijn1, ty::INNERMOST); - self.tcx.mk_re_late_bound(debruijn, br) + ty::Region::new_late_bound(self.tcx, debruijn, br) } else { region } @@ -328,7 +328,7 @@ impl<'tcx> TyCtxt<'tcx> { T: TypeFoldable>, { self.replace_late_bound_regions_uncached(value, |br| { - self.mk_re_free(all_outlive_scope, br.kind) + ty::Region::new_free(self, all_outlive_scope, br.kind) }) } @@ -341,7 +341,8 @@ impl<'tcx> TyCtxt<'tcx> { value, FnMutDelegate { regions: &mut |r: ty::BoundRegion| { - self.mk_re_late_bound( + ty::Region::new_late_bound( + self, ty::INNERMOST, ty::BoundRegion { var: shift_bv(r.var), kind: r.kind }, ) @@ -383,7 +384,7 @@ impl<'tcx> TyCtxt<'tcx> { .or_insert_with(|| ty::BoundVariableKind::Region(ty::BrAnon(None))) .expect_region(); let br = ty::BoundRegion { var, kind }; - self.tcx.mk_re_late_bound(ty::INNERMOST, br) + ty::Region::new_late_bound(self.tcx, ty::INNERMOST, br) } fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx> { let entry = self.map.entry(bt.var); @@ -451,7 +452,7 @@ impl<'tcx> TypeFolder> for Shifter<'tcx> { match *r { ty::ReLateBound(debruijn, br) if debruijn >= self.current_index => { let debruijn = debruijn.shifted_in(self.amount); - self.tcx.mk_re_late_bound(debruijn, br) + ty::Region::new_late_bound(self.tcx, debruijn, br) } _ => r, } @@ -492,7 +493,7 @@ pub fn shift_region<'tcx>( ) -> ty::Region<'tcx> { match *region { ty::ReLateBound(debruijn, br) if amount > 0 => { - tcx.mk_re_late_bound(debruijn.shifted_in(amount), br) + ty::Region::new_late_bound(tcx, debruijn.shifted_in(amount), br) } _ => region, } diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index b27ee8cbad0f..76a6a421282e 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -100,7 +100,7 @@ impl GenericParamDef { preceding_substs: &[ty::GenericArg<'tcx>], ) -> ty::GenericArg<'tcx> { match &self.kind { - ty::GenericParamDefKind::Lifetime => tcx.mk_re_error_misc().into(), + ty::GenericParamDefKind::Lifetime => ty::Region::new_error_misc(tcx).into(), ty::GenericParamDefKind::Type { .. } => tcx.ty_error_misc().into(), ty::GenericParamDefKind::Const { .. } => { tcx.const_error_misc(tcx.type_of(self.def_id).subst(tcx, preceding_substs)).into() diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs index 1b336b7bfc6e..d1ed7be3d2e4 100644 --- a/compiler/rustc_middle/src/ty/opaque_types.rs +++ b/compiler/rustc_middle/src/ty/opaque_types.rs @@ -141,7 +141,7 @@ impl<'tcx> TypeFolder> for ReverseMapper<'tcx> { ) .emit(); - self.interner().mk_re_error(e) + ty::Region::new_error(self.interner(), e) } } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index d6c88ea96ca4..3e698ce54ad9 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -184,7 +184,7 @@ impl<'tcx> RegionHighlightMode<'tcx> { /// Convenience wrapper for `highlighting_region`. pub fn highlighting_region_vid(&mut self, vid: ty::RegionVid, number: usize) { - self.highlighting_region(self.tcx.mk_re_var(vid), number) + self.highlighting_region(ty::Region::new_var(self.tcx, vid), number) } /// Returns `Some(n)` with the number to use for the given region, if any. @@ -2303,7 +2303,7 @@ impl<'a, 'tcx> ty::TypeFolder> for RegionFolder<'a, 'tcx> { }; if let ty::ReLateBound(debruijn1, br) = *region { assert_eq!(debruijn1, ty::INNERMOST); - self.tcx.mk_re_late_bound(self.current_index, br) + ty::Region::new_late_bound(self.tcx, self.current_index, br) } else { region } @@ -2415,7 +2415,8 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { if let Some(lt_idx) = lifetime_idx { if lt_idx > binder_level_idx { let kind = ty::BrNamed(CRATE_DEF_ID.to_def_id(), name); - return tcx.mk_re_late_bound( + return ty::Region::new_late_bound( + tcx, ty::INNERMOST, ty::BoundRegion { var: br.var, kind }, ); @@ -2430,7 +2431,8 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { if let Some(lt_idx) = lifetime_idx { if lt_idx > binder_level_idx { let kind = ty::BrNamed(def_id, name); - return tcx.mk_re_late_bound( + return ty::Region::new_late_bound( + tcx, ty::INNERMOST, ty::BoundRegion { var: br.var, kind }, ); @@ -2443,7 +2445,8 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { if let Some(lt_idx) = lifetime_idx { if lt_idx > binder_level_idx { let kind = br.kind; - return tcx.mk_re_late_bound( + return ty::Region::new_late_bound( + tcx, ty::INNERMOST, ty::BoundRegion { var: br.var, kind }, ); @@ -2458,7 +2461,11 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { start_or_continue(&mut self, "for<", ", "); do_continue(&mut self, name); } - tcx.mk_re_late_bound(ty::INNERMOST, ty::BoundRegion { var: br.var, kind }) + ty::Region::new_late_bound( + tcx, + ty::INNERMOST, + ty::BoundRegion { var: br.var, kind }, + ) }; let mut folder = RegionFolder { tcx, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 82f79a0c0887..421163acb541 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -15,14 +15,14 @@ use hir::def::DefKind; use polonius_engine::Atom; use rustc_data_structures::captures::Captures; use rustc_data_structures::intern::Interned; -use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg}; +use rustc_errors::{DiagnosticArgValue, ErrorGuaranteed, IntoDiagnosticArg, MultiSpan}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::LangItem; use rustc_index::Idx; use rustc_macros::HashStable; use rustc_span::symbol::{kw, sym, Symbol}; -use rustc_span::Span; +use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT}; use rustc_target::spec::abi::{self, Abi}; use std::borrow::Cow; @@ -1459,6 +1459,103 @@ impl ParamConst { #[rustc_pass_by_value] pub struct Region<'tcx>(pub Interned<'tcx, RegionKind<'tcx>>); +impl<'tcx> Region<'tcx> { + #[inline] + pub fn new_early_bound( + tcx: TyCtxt<'tcx>, + early_bound_region: ty::EarlyBoundRegion, + ) -> Region<'tcx> { + tcx.intern_region(ty::ReEarlyBound(early_bound_region)) + } + + #[inline] + pub fn new_late_bound( + tcx: TyCtxt<'tcx>, + debruijn: ty::DebruijnIndex, + bound_region: ty::BoundRegion, + ) -> Region<'tcx> { + // Use a pre-interned one when possible. + if let ty::BoundRegion { var, kind: ty::BrAnon(None) } = bound_region + && let Some(inner) = tcx.lifetimes.re_late_bounds.get(debruijn.as_usize()) + && let Some(re) = inner.get(var.as_usize()).copied() + { + re + } else { + tcx.intern_region(ty::ReLateBound(debruijn, bound_region)) + } + } + + #[inline] + pub fn new_free( + tcx: TyCtxt<'tcx>, + scope: DefId, + bound_region: ty::BoundRegionKind, + ) -> Region<'tcx> { + tcx.intern_region(ty::ReFree(ty::FreeRegion { scope, bound_region })) + } + + #[inline] + pub fn new_var(tcx: TyCtxt<'tcx>, v: ty::RegionVid) -> Region<'tcx> { + // Use a pre-interned one when possible. + tcx.lifetimes + .re_vars + .get(v.as_usize()) + .copied() + .unwrap_or_else(|| tcx.intern_region(ty::ReVar(v))) + } + + #[inline] + pub fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderRegion) -> Region<'tcx> { + tcx.intern_region(ty::RePlaceholder(placeholder)) + } + + /// Constructs a `RegionKind::ReError` region. + #[track_caller] + pub fn new_error(tcx: TyCtxt<'tcx>, reported: ErrorGuaranteed) -> Region<'tcx> { + tcx.intern_region(ty::ReError(reported)) + } + + /// Constructs a `RegionKind::ReError` region and registers a `delay_span_bug` to ensure it + /// gets used. + #[track_caller] + pub fn new_error_misc(tcx: TyCtxt<'tcx>) -> Region<'tcx> { + Region::new_error_with_message( + tcx, + DUMMY_SP, + "RegionKind::ReError constructed but no error reported", + ) + } + + /// Constructs a `RegionKind::ReError` region and registers a `delay_span_bug` with the given + /// `msg` to ensure it gets used. + #[track_caller] + pub fn new_error_with_message>( + tcx: TyCtxt<'tcx>, + span: S, + msg: &'static str, + ) -> Region<'tcx> { + let reported = tcx.sess.delay_span_bug(span, msg); + Region::new_error(tcx, reported) + } + + /// Avoid this in favour of more specific `new_*` methods, where possible, + /// to avoid the cost of the `match`. + pub fn new_from_kind(tcx: TyCtxt<'tcx>, kind: RegionKind<'tcx>) -> Region<'tcx> { + match kind { + ty::ReEarlyBound(region) => Region::new_early_bound(tcx, region), + ty::ReLateBound(debruijn, region) => Region::new_late_bound(tcx, debruijn, region), + ty::ReFree(ty::FreeRegion { scope, bound_region }) => { + Region::new_free(tcx, scope, bound_region) + } + ty::ReStatic => tcx.lifetimes.re_static, + ty::ReVar(vid) => Region::new_var(tcx, vid), + ty::RePlaceholder(region) => Region::new_placeholder(tcx, region), + ty::ReErased => tcx.lifetimes.re_erased, + ty::ReError(reported) => Region::new_error(tcx, reported), + } + } +} + impl<'tcx> Deref for Region<'tcx> { type Target = RegionKind<'tcx>; diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index 463f639defe9..d00fb754c641 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -142,7 +142,7 @@ impl<'tcx> Cx<'tcx> { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind: ty::BrEnv, }; - let env_region = self.tcx.mk_re_late_bound(ty::INNERMOST, br); + let env_region = ty::Region::new_late_bound(self.tcx, ty::INNERMOST, br); let closure_env_ty = self.tcx.closure_env_ty(closure_def_id, closure_substs, env_region).unwrap(); let liberated_closure_env_ty = self.tcx.erase_late_bound_regions( diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index 1071b8fc7026..0f3f8f1ac2cb 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -96,7 +96,7 @@ pub(in crate::solve) fn replace_erased_lifetimes_with_bound_vars<'tcx>( let br = ty::BoundRegion { var: ty::BoundVar::from_u32(counter), kind: ty::BrAnon(None) }; counter += 1; - tcx.mk_re_late_bound(current_depth, br) + ty::Region::new_late_bound(tcx, current_depth, br) } // All free regions should be erased here. r => bug!("unexpected region: {r:?}"), diff --git a/compiler/rustc_trait_selection/src/solve/canonicalize.rs b/compiler/rustc_trait_selection/src/solve/canonicalize.rs index ff4bff10cc8a..29bdb5ff67da 100644 --- a/compiler/rustc_trait_selection/src/solve/canonicalize.rs +++ b/compiler/rustc_trait_selection/src/solve/canonicalize.rs @@ -255,7 +255,7 @@ impl<'tcx> TypeFolder> for Canonicalizer<'_, 'tcx> { }), ); let br = ty::BoundRegion { var, kind: BrAnon(None) }; - self.interner().mk_re_late_bound(self.binder_index, br) + ty::Region::new_late_bound(self.interner(), self.binder_index, br) } fn fold_ty(&mut self, mut t: Ty<'tcx>) -> Ty<'tcx> { diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 51069897120a..65af0bb1c4e1 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -824,7 +824,7 @@ impl<'tcx> TypeFolder> for BoundVarReplacer<'_, 'tcx> { let universe = self.universe_for(debruijn); let p = ty::PlaceholderRegion { universe, bound: br }; self.mapped_regions.insert(p, br); - self.infcx.tcx.mk_re_placeholder(p) + ty::Region::new_placeholder(self.infcx.tcx, p) } _ => r, } @@ -945,7 +945,7 @@ impl<'tcx> TypeFolder> for PlaceholderReplacer<'_, 'tcx> { let db = ty::DebruijnIndex::from_usize( self.universe_indices.len() - index + self.current_index.as_usize() - 1, ); - self.interner().mk_re_late_bound(db, *replace_var) + ty::Region::new_late_bound(self.interner(), db, *replace_var) } None => r1, } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 0245dfd333be..4e961c3ee733 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -550,7 +550,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name); let bound_var = ty::BoundVariableKind::Region(kind); bound_vars.push(bound_var); - tcx.mk_re_late_bound( + ty::Region::new_late_bound( + tcx, ty::INNERMOST, ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index ed380f32b72f..ac4f845a0052 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -3027,7 +3027,7 @@ fn bind_generator_hidden_types_above<'tcx>( kind: ty::BrAnon(None), }; counter += 1; - tcx.mk_re_late_bound(current_depth, br) + ty::Region::new_late_bound(tcx, current_depth, br) } r => bug!("unexpected region: {r:?}"), }) diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index 1d3ea96666f2..38f94c388618 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -727,7 +727,7 @@ fn bound_vars_for_item(tcx: TyCtxt<'_>, def_id: DefId) -> SubstsRef<'_> { var: ty::BoundVar::from_usize(substs.len()), kind: ty::BrAnon(None), }; - tcx.mk_re_late_bound(ty::INNERMOST, br).into() + ty::Region::new_late_bound(tcx, ty::INNERMOST, br).into() } ty::GenericParamDefKind::Const { .. } => tcx diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index e447ab94f640..e6c6e0f13df3 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -542,7 +542,8 @@ impl<'tcx> LowerInto<'tcx, Region<'tcx>> for &chalk_ir::Lifetime) -> Region<'tcx> { let tcx = interner.tcx; match self.data(interner) { - chalk_ir::LifetimeData::BoundVar(var) => tcx.mk_re_late_bound( + chalk_ir::LifetimeData::BoundVar(var) => ty::Region::new_late_bound( + tcx, ty::DebruijnIndex::from_u32(var.debruijn.depth()), ty::BoundRegion { var: ty::BoundVar::from_usize(var.index), @@ -550,13 +551,16 @@ impl<'tcx> LowerInto<'tcx, Region<'tcx>> for &chalk_ir::Lifetime unimplemented!(), - chalk_ir::LifetimeData::Placeholder(p) => tcx.mk_re_placeholder(ty::Placeholder { - universe: ty::UniverseIndex::from_usize(p.ui.counter), - bound: ty::BoundRegion { - var: ty::BoundVar::from_usize(p.idx), - kind: ty::BoundRegionKind::BrAnon(None), + chalk_ir::LifetimeData::Placeholder(p) => ty::Region::new_placeholder( + tcx, + ty::Placeholder { + universe: ty::UniverseIndex::from_usize(p.ui.counter), + bound: ty::BoundRegion { + var: ty::BoundVar::from_usize(p.idx), + kind: ty::BoundRegionKind::BrAnon(None), + }, }, - }), + ), chalk_ir::LifetimeData::Static => tcx.lifetimes.re_static, chalk_ir::LifetimeData::Erased => tcx.lifetimes.re_erased, chalk_ir::LifetimeData::Phantom(void, _) => match *void {}, @@ -1051,7 +1055,7 @@ impl<'a, 'tcx> TypeFolder> for NamedBoundVarSubstitutor<'a, 'tcx> { ty::BrNamed(def_id, _name) => match self.named_parameters.get(&def_id) { Some(_) => { let new_br = ty::BoundRegion { var: br.var, kind: ty::BrAnon(None) }; - return self.tcx.mk_re_late_bound(index, new_br); + return ty::Region::new_late_bound(self.tcx, index, new_br); } None => panic!("Missing `BrNamed`."), }, @@ -1142,7 +1146,7 @@ impl<'tcx> TypeFolder> for ParamsSubstitutor<'tcx> { var: ty::BoundVar::from_u32(*idx), kind: ty::BrAnon(None), }; - self.tcx.mk_re_late_bound(self.binder_index, br) + ty::Region::new_late_bound(self.tcx, self.binder_index, br) } None => { let idx = self.named_regions.len() as u32; @@ -1151,7 +1155,7 @@ impl<'tcx> TypeFolder> for ParamsSubstitutor<'tcx> { kind: ty::BrAnon(None), }; self.named_regions.insert(_re.def_id, idx); - self.tcx.mk_re_late_bound(self.binder_index, br) + ty::Region::new_late_bound(self.tcx, self.binder_index, br) } }, diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 15c191046166..5b3ffc9fc36d 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -81,7 +81,7 @@ fn fn_sig_for_fn_abi<'tcx>( var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind: ty::BoundRegionKind::BrEnv, }; - let env_region = tcx.mk_re_late_bound(ty::INNERMOST, br); + let env_region = ty::Region::new_late_bound(tcx, ty::INNERMOST, br); let env_ty = tcx.closure_env_ty(def_id, substs, env_region).unwrap(); let sig = sig.skip_binder(); @@ -106,7 +106,7 @@ fn fn_sig_for_fn_abi<'tcx>( var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind: ty::BoundRegionKind::BrEnv, }; - let env_ty = tcx.mk_mut_ref(tcx.mk_re_late_bound(ty::INNERMOST, br), ty); + let env_ty = tcx.mk_mut_ref(ty::Region::new_late_bound(tcx, ty::INNERMOST, br), ty); let pin_did = tcx.require_lang_item(LangItem::Pin, None); let pin_adt_ref = tcx.adt_def(pin_did); diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 52bc386cb009..190a7765ff11 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -287,12 +287,13 @@ impl<'tcx> TypeVisitor> for ImplTraitInTraitFinder<'_, 'tcx> { let shifted_alias_ty = self.tcx.fold_regions(unshifted_alias_ty, |re, depth| { if let ty::ReLateBound(index, bv) = re.kind() { if depth != ty::INNERMOST { - return self.tcx.mk_re_error_with_message( + return ty::Region::new_error_with_message( + self.tcx, DUMMY_SP, "we shouldn't walk non-predicate binders with `impl Trait`...", ); } - self.tcx.mk_re_late_bound(index.shifted_out_to_binder(self.depth), bv) + ty::Region::new_late_bound(self.tcx, index.shifted_out_to_binder(self.depth), bv) } else { re } From c571558fd948f22bda9b91e541e72ec1cb189c80 Mon Sep 17 00:00:00 2001 From: jyn Date: Thu, 25 May 2023 13:31:54 -0500 Subject: [PATCH 29/69] Give a more helpful error when calling `cargo_crates_in_set` for an alias Before: ``` thread 'main' panicked at 'no entry found for key', builder.rs:110:30 ``` After: ``` thread 'main' panicked at 'missing crate for path library', check.rs:89:26 ``` --- src/bootstrap/builder.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 2fa445506bc4..caab40fcd9dd 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -103,11 +103,14 @@ impl RunConfig<'_> { } /// Return a list of crate names selected by `run.paths`. + #[track_caller] pub fn cargo_crates_in_set(&self) -> Interned> { let mut crates = Vec::new(); for krate in &self.paths { let path = krate.assert_single_path(); - let crate_name = self.builder.crate_paths[&path.path]; + let Some(crate_name) = self.builder.crate_paths.get(&path.path) else { + panic!("missing crate for path {}", path.path.display()) + }; crates.push(crate_name.to_string()); } INTERNER.intern_list(crates) From 564e3adfdfdd761a8fa94e5e33abd04ae5f14675 Mon Sep 17 00:00:00 2001 From: jyn Date: Wed, 24 May 2023 19:39:16 -0500 Subject: [PATCH 30/69] Allow checking individual crates This is useful for profiling metadata generation. This comes very close to removing all_krates, but doesn't quite - there's one last usage left in `doc`. --- src/bootstrap/check.rs | 77 ++++++++++++++++++++++++++++++++---------- 1 file changed, 60 insertions(+), 17 deletions(-) diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index b11be96cefe6..a4fcaa5e196e 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -1,6 +1,6 @@ //! Implementation of compiling the compiler and standard library, in "check"-based modes. -use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step}; +use crate::builder::{crate_description, Builder, Kind, RunConfig, ShouldRun, Step}; use crate::cache::Interned; use crate::compile::{add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo}; use crate::config::TargetSelection; @@ -12,6 +12,12 @@ use std::path::{Path, PathBuf}; #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct Std { pub target: TargetSelection, + /// Whether to build only a subset of crates. + /// + /// This shouldn't be used from other steps; see the comment on [`compile::Rustc`]. + /// + /// [`compile::Rustc`]: crate::compile::Rustc + crates: Interned>, } /// Returns args for the subcommand itself (not for cargo) @@ -66,16 +72,24 @@ fn cargo_subcommand(kind: Kind) -> &'static str { } } +impl Std { + pub fn new(target: TargetSelection) -> Self { + Self { target, crates: INTERNER.intern_list(vec![]) } + } +} + impl Step for Std { type Output = (); const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.all_krates("sysroot").path("library") + let crates = run.builder.in_tree_crates("sysroot", None); + run.crates(crates).path("library") } fn make_run(run: RunConfig<'_>) { - run.builder.ensure(Std { target: run.target }); + let crates = run.cargo_crates_in_set(); + run.builder.ensure(Std { target: run.target, crates }); } fn run(self, builder: &Builder<'_>) { @@ -97,7 +111,14 @@ impl Step for Std { cargo.arg("--lib"); } - let _guard = builder.msg_check("library artifacts", target); + for krate in &*self.crates { + cargo.arg("-p").arg(krate); + } + + let _guard = builder.msg_check( + format_args!("library artifacts{}", crate_description(&self.crates)), + target, + ); run_cargo( builder, cargo, @@ -117,7 +138,8 @@ impl Step for Std { } // don't run on std twice with x.py clippy - if builder.kind == Kind::Clippy { + // don't check test dependencies if we haven't built libtest + if builder.kind == Kind::Clippy || !self.crates.is_empty() { return; } @@ -147,8 +169,8 @@ impl Step for Std { // Explicitly pass -p for all dependencies krates -- this will force cargo // to also check the tests/benches/examples for these crates, rather // than just the leaf crate. - for krate in builder.in_tree_crates("test", Some(target)) { - cargo.arg("-p").arg(krate.name); + for krate in &*self.crates { + cargo.arg("-p").arg(krate); } let _guard = builder.msg_check("library test/bench/example targets", target); @@ -167,6 +189,22 @@ impl Step for Std { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct Rustc { pub target: TargetSelection, + /// Whether to build only a subset of crates. + /// + /// This shouldn't be used from other steps; see the comment on [`compile::Rustc`]. + /// + /// [`compile::Rustc`]: crate::compile::Rustc + crates: Interned>, +} + +impl Rustc { + pub fn new(target: TargetSelection, builder: &Builder<'_>) -> Self { + let mut crates = vec![]; + for krate in builder.in_tree_crates("rustc-main", None) { + crates.push(krate.name.to_string()); + } + Self { target, crates: INTERNER.intern_list(crates) } + } } impl Step for Rustc { @@ -175,11 +213,13 @@ impl Step for Rustc { const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.all_krates("rustc-main").path("compiler") + let crates = run.builder.in_tree_crates("rustc-main", None); + run.crates(crates).path("compiler") } fn make_run(run: RunConfig<'_>) { - run.builder.ensure(Rustc { target: run.target }); + let crates = run.cargo_crates_in_set(); + run.builder.ensure(Rustc { target: run.target, crates }); } /// Builds the compiler. @@ -200,7 +240,7 @@ impl Step for Rustc { builder.ensure(crate::compile::Std::new(compiler, compiler.host)); builder.ensure(crate::compile::Std::new(compiler, target)); } else { - builder.ensure(Std { target }); + builder.ensure(Std::new(target)); } let mut cargo = builder.cargo( @@ -218,14 +258,17 @@ impl Step for Rustc { cargo.arg("--all-targets"); } - // Explicitly pass -p for all compiler krates -- this will force cargo + // Explicitly pass -p for all compiler crates -- this will force cargo // to also check the tests/benches/examples for these crates, rather // than just the leaf crate. - for krate in builder.in_tree_crates("rustc-main", Some(target)) { - cargo.arg("-p").arg(krate.name); + for krate in &*self.crates { + cargo.arg("-p").arg(krate); } - let _guard = builder.msg_check("compiler artifacts", target); + let _guard = builder.msg_check( + format_args!("compiler artifacts{}", crate_description(&self.crates)), + target, + ); run_cargo( builder, cargo, @@ -268,7 +311,7 @@ impl Step for CodegenBackend { let target = self.target; let backend = self.backend; - builder.ensure(Rustc { target }); + builder.ensure(Rustc::new(target, builder)); let mut cargo = builder.cargo( compiler, @@ -318,7 +361,7 @@ impl Step for RustAnalyzer { let compiler = builder.compiler(builder.top_stage, builder.config.build); let target = self.target; - builder.ensure(Std { target }); + builder.ensure(Std::new(target)); let mut cargo = prepare_tool_cargo( builder, @@ -386,7 +429,7 @@ macro_rules! tool_check_step { let compiler = builder.compiler(builder.top_stage, builder.config.build); let target = self.target; - builder.ensure(Rustc { target }); + builder.ensure(Rustc::new(target, builder)); let mut cargo = prepare_tool_cargo( builder, From 20372f1817e9498f00100c149b4f47fc8ba00329 Mon Sep 17 00:00:00 2001 From: jyn Date: Thu, 25 May 2023 13:37:24 -0500 Subject: [PATCH 31/69] Add a `make_run_crates` function and use it Rustc and Std This fixes the panic from the previous commit. --- src/bootstrap/check.rs | 8 +++++--- src/bootstrap/compile.rs | 19 ++++++++++++------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index a4fcaa5e196e..09835516f7bd 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -2,7 +2,9 @@ use crate::builder::{crate_description, Builder, Kind, RunConfig, ShouldRun, Step}; use crate::cache::Interned; -use crate::compile::{add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo}; +use crate::compile::{ + add_to_sysroot, make_run_crates, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, +}; use crate::config::TargetSelection; use crate::tool::{prepare_tool_cargo, SourceType}; use crate::INTERNER; @@ -88,7 +90,7 @@ impl Step for Std { } fn make_run(run: RunConfig<'_>) { - let crates = run.cargo_crates_in_set(); + let crates = make_run_crates(&run, "library"); run.builder.ensure(Std { target: run.target, crates }); } @@ -218,7 +220,7 @@ impl Step for Rustc { } fn make_run(run: RunConfig<'_>) { - let crates = run.cargo_crates_in_set(); + let crates = make_run_crates(&run, "compiler"); run.builder.ensure(Rustc { target: run.target, crates }); } diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 33addb90da37..7b9c4c0f3b3a 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -48,6 +48,17 @@ impl Std { } } +/// Given an `alias` selected by the `Step` and the paths passed on the command line, +/// return a list of the crates that should be built. +/// +/// Normally, people will pass *just* `library` if they pass it. +/// But it's possible (although strange) to pass something like `library std core`. +/// Build all crates anyway, as if they hadn't passed the other args. +pub(crate) fn make_run_crates(run: &RunConfig<'_>, alias: &str) -> Interned> { + let has_alias = run.paths.iter().any(|set| set.assert_single_path().path.ends_with(alias)); + if has_alias { Default::default() } else { run.cargo_crates_in_set() } +} + impl Step for Std { type Output = (); const DEFAULT: bool = true; @@ -62,16 +73,10 @@ impl Step for Std { } fn make_run(run: RunConfig<'_>) { - // Normally, people will pass *just* library if they pass it. - // But it's possible (although strange) to pass something like `library std core`. - // Build all crates anyway, as if they hadn't passed the other args. - let has_library = - run.paths.iter().any(|set| set.assert_single_path().path.ends_with("library")); - let crates = if has_library { Default::default() } else { run.cargo_crates_in_set() }; run.builder.ensure(Std { compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), target: run.target, - crates, + crates: make_run_crates(&run, "library"), }); } From cb4b7f631980e6f78a486be46ec653ad322ce12e Mon Sep 17 00:00:00 2001 From: jyn Date: Thu, 25 May 2023 13:33:43 -0500 Subject: [PATCH 32/69] Extend `msg` and `description` to work with any subcommand Previously `description` only supported `Testing` and `Benchmarking`, and `msg` gave weird results for `doc` (it would say `Docing`). --- src/bootstrap/builder.rs | 8 ++++++-- src/bootstrap/lib.rs | 4 ++-- src/bootstrap/test.rs | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index caab40fcd9dd..b2e9ba144d6b 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -644,12 +644,16 @@ impl Kind { } } - pub fn test_description(&self) -> &'static str { + pub fn description(&self) -> String { match self { Kind::Test => "Testing", Kind::Bench => "Benchmarking", - _ => panic!("not a test command: {}!", self.as_str()), + Kind::Doc => "Documenting", + Kind::Run => "Running", + Kind::Suggest => "Suggesting", + _ => return format!("{self:?}"), } + .to_owned() } } diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index fb76dffd0715..f7d30de67eba 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -1020,8 +1020,8 @@ impl Build { host: impl Into>, target: impl Into>, ) -> Option { - let action = action.into(); - let msg = |fmt| format!("{action:?}ing stage{stage} {what}{fmt}"); + let action = action.into().description(); + let msg = |fmt| format!("{action} stage{stage} {what}{fmt}"); let msg = if let Some(target) = target.into() { let host = host.into().unwrap(); if host == target { diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 44cd84be705a..25941fc64c50 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -101,7 +101,7 @@ impl Step for CrateBootstrap { ); builder.info(&format!( "{} {} stage0 ({})", - builder.kind.test_description(), + builder.kind.description(), path, bootstrap_host, )); From 58e18ddf86e67a1210a60ab4a0ad5e1adfbbc819 Mon Sep 17 00:00:00 2001 From: jyn Date: Thu, 25 May 2023 13:39:10 -0500 Subject: [PATCH 33/69] Switch doc::{Std, Rustc} to `crate_or_deps` Previously they were using `all_krates` and various hacks to determine which crates to document. Switch them to `crate_or_deps` so `ShouldRun` tells them which crate to document instead of having to guess. This also makes a few other refactors: - Remove the now unused `all_krates`; new code should only use `crate_or_deps`. - Add tests for documenting Std - Remove the unnecessary `run_cargo_rustdoc_for` closure so that we only run cargo once - Give a more helpful error message when documenting a no_std target - Use `builder.msg` in the Steps instead of `builder.info` --- src/bootstrap/builder.rs | 19 ---- src/bootstrap/builder/tests.rs | 14 +++ src/bootstrap/dist.rs | 6 +- src/bootstrap/doc.rs | 173 +++++++++++++++------------------ src/bootstrap/test.rs | 12 +-- 5 files changed, 100 insertions(+), 124 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index b2e9ba144d6b..b16e34c0b935 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -430,25 +430,6 @@ impl<'a> ShouldRun<'a> { } } - /// Indicates it should run if the command-line selects the given crate or - /// any of its (local) dependencies. - /// - /// Compared to `krate`, this treats the dependencies as aliases for the - /// same job. Generally it is preferred to use `krate`, and treat each - /// individual path separately. For example `./x.py test src/liballoc` - /// (which uses `krate`) will test just `liballoc`. However, `./x.py check - /// src/liballoc` (which uses `all_krates`) will check all of `libtest`. - /// `all_krates` should probably be removed at some point. - pub fn all_krates(mut self, name: &str) -> Self { - let mut set = BTreeSet::new(); - for krate in self.builder.in_tree_crates(name, None) { - let path = krate.local_path(self.builder); - set.insert(TaskPath { path, kind: Some(self.kind) }); - } - self.paths.insert(PathSet::Set(set)); - self - } - /// Indicates it should run if the command-line selects the given crate or /// any of its (local) dependencies. /// diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs index edca8fe9b13a..d76b830b0e53 100644 --- a/src/bootstrap/builder/tests.rs +++ b/src/bootstrap/builder/tests.rs @@ -1,5 +1,6 @@ use super::*; use crate::config::{Config, DryRun, TargetSelection}; +use crate::doc::DocumentationFormat; use std::thread; fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config { @@ -66,6 +67,16 @@ macro_rules! std { }; } +macro_rules! doc_std { + ($host:ident => $target:ident, stage = $stage:literal) => { + doc::Std::new( + $stage, + TargetSelection::from_user(stringify!($target)), + DocumentationFormat::HTML, + ) + }; +} + macro_rules! rustc { ($host:ident => $target:ident, stage = $stage:literal) => { compile::Rustc::new( @@ -144,6 +155,9 @@ fn alias_and_path_for_library() { first(cache.all::()), &[std!(A => A, stage = 0), std!(A => A, stage = 1)] ); + + let mut cache = run_build(&["library".into(), "core".into()], configure("doc", &["A"], &["A"])); + assert_eq!(first(cache.all::()), &[doc_std!(A => A, stage = 0)]); } #[test] diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index b49845386da1..46fc5b80e99d 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -106,11 +106,7 @@ impl Step for JsonDocs { /// Builds the `rust-docs-json` installer component. fn run(self, builder: &Builder<'_>) -> Option { let host = self.host; - builder.ensure(crate::doc::Std { - stage: builder.top_stage, - target: host, - format: DocumentationFormat::JSON, - }); + builder.ensure(crate::doc::Std::new(builder.top_stage, host, DocumentationFormat::JSON)); let dest = "share/doc/rust/json"; diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index b52c3b68cc4f..357cd778b6c3 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -16,6 +16,7 @@ use crate::builder::crate_description; use crate::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step}; use crate::cache::{Interned, INTERNER}; use crate::compile; +use crate::compile::make_run_crates; use crate::config::{Config, TargetSelection}; use crate::tool::{self, prepare_tool_cargo, SourceType, Tool}; use crate::util::{symlink_dir, t, up_to_date}; @@ -87,15 +88,6 @@ book!( StyleGuide, "src/doc/style-guide", "style-guide"; ); -// "library/std" -> ["library", "std"] -// -// Used for deciding whether a particular step is one requested by the user on -// the `x.py doc` command line, which determines whether `--open` will open that -// page. -pub(crate) fn components_simplified(path: &PathBuf) -> Vec<&str> { - path.iter().map(|component| component.to_str().unwrap_or("???")).collect() -} - #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct UnstableBook { target: TargetSelection, @@ -425,11 +417,18 @@ impl Step for SharedAssets { } } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Std { pub stage: u32, pub target: TargetSelection, pub format: DocumentationFormat, + crates: Interned>, +} + +impl Std { + pub(crate) fn new(stage: u32, target: TargetSelection, format: DocumentationFormat) -> Self { + Std { stage, target, format, crates: INTERNER.intern_list(vec![]) } + } } impl Step for Std { @@ -438,7 +437,7 @@ impl Step for Std { fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; - run.all_krates("sysroot").path("library").default_condition(builder.config.docs) + run.crate_or_deps("sysroot").path("library").default_condition(builder.config.docs) } fn make_run(run: RunConfig<'_>) { @@ -450,6 +449,7 @@ impl Step for Std { } else { DocumentationFormat::HTML }, + crates: make_run_crates(&run, "library"), }); } @@ -457,7 +457,7 @@ impl Step for Std { /// /// This will generate all documentation for the standard library and its /// dependencies. This is largely just a wrapper around `cargo doc`. - fn run(self, builder: &Builder<'_>) { + fn run(mut self, builder: &Builder<'_>) { let stage = self.stage; let target = self.target; let out = match self.format { @@ -487,25 +487,7 @@ impl Step for Std { extra_args.push(OsStr::new("--disable-minification")); } - let requested_crates = builder - .paths - .iter() - .map(components_simplified) - .filter_map(|path| { - if path.len() >= 2 && path.get(0) == Some(&"library") { - // single crate - Some(path[1].to_owned()) - } else if !path.is_empty() { - // ?? - Some(path[0].to_owned()) - } else { - // all library crates - None - } - }) - .collect::>(); - - doc_std(builder, self.format, stage, target, &out, &extra_args, &requested_crates); + doc_std(builder, self.format, stage, target, &out, &extra_args, &self.crates); // Don't open if the format is json if let DocumentationFormat::JSON = self.format { @@ -514,7 +496,11 @@ impl Step for Std { // Look for library/std, library/core etc in the `x.py doc` arguments and // open the corresponding rendered docs. - for requested_crate in requested_crates { + if self.crates.is_empty() { + self.crates = INTERNER.intern_list(vec!["library".to_owned()]); + }; + + for requested_crate in &*self.crates { if requested_crate == "library" { // For `x.py doc library --open`, open `std` by default. let index = out.join("std").join("index.html"); @@ -538,7 +524,7 @@ impl Step for Std { /// or remote link. const STD_PUBLIC_CRATES: [&str; 5] = ["core", "alloc", "std", "proc_macro", "test"]; -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum DocumentationFormat { HTML, JSON, @@ -566,21 +552,19 @@ fn doc_std( extra_args: &[&OsStr], requested_crates: &[String], ) { - builder.info(&format!( - "Documenting{} stage{} library ({}) in {} format", - crate_description(requested_crates), - stage, - target, - format.as_str() - )); if builder.no_std(target) == Some(true) { panic!( "building std documentation for no_std target {target} is not supported\n\ - Set `docs = false` in the config to disable documentation." + Set `docs = false` in the config to disable documentation, or pass `--exclude doc::library`." ); } + let compiler = builder.compiler(stage, builder.config.build); + let description = + format!("library{} in {} format", crate_description(&requested_crates), format.as_str()); + let _guard = builder.msg(Kind::Doc, stage, &description, compiler.host, target); + let target_doc_dir_name = if format == DocumentationFormat::JSON { "json-doc" } else { "doc" }; let target_dir = builder.stage_out(compiler, Mode::Std).join(target.triple).join(target_doc_dir_name); @@ -590,35 +574,27 @@ fn doc_std( // as a function parameter. let out_dir = target_dir.join(target.triple).join("doc"); - let run_cargo_rustdoc_for = |package: &str| { - let mut cargo = builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "rustdoc"); - compile::std_cargo(builder, target, compiler.stage, &mut cargo); - cargo - .arg("--target-dir") - .arg(&*target_dir.to_string_lossy()) - .arg("-p") - .arg(package) - .arg("-Zskip-rustdoc-fingerprint") - .arg("--") - .arg("-Z") - .arg("unstable-options") - .arg("--resource-suffix") - .arg(&builder.version) - .args(extra_args); - if builder.config.library_docs_private_items { - cargo.arg("--document-private-items").arg("--document-hidden-items"); - } - builder.run(&mut cargo.into()); - }; + let mut cargo = builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "rustdoc"); + compile::std_cargo(builder, target, compiler.stage, &mut cargo); + cargo.arg("--target-dir").arg(&*target_dir.to_string_lossy()).arg("-Zskip-rustdoc-fingerprint"); - for krate in STD_PUBLIC_CRATES { - run_cargo_rustdoc_for(krate); - if requested_crates.iter().any(|p| p == krate) { - // No need to document more of the libraries if we have the one we want. - break; - } + for krate in requested_crates { + cargo.arg("-p").arg(krate); } + cargo + .arg("--") + .arg("-Z") + .arg("unstable-options") + .arg("--resource-suffix") + .arg(&builder.version) + .args(extra_args); + + if builder.config.library_docs_private_items { + cargo.arg("--document-private-items").arg("--document-hidden-items"); + } + + builder.run(&mut cargo.into()); builder.cp_r(&out_dir, &out); } @@ -626,6 +602,28 @@ fn doc_std( pub struct Rustc { pub stage: u32, pub target: TargetSelection, + crates: Interned>, +} + +impl Rustc { + pub(crate) fn new(stage: u32, target: TargetSelection, builder: &Builder<'_>) -> Self { + // Find dependencies for top level crates. + let root_crates = vec![ + INTERNER.intern_str("rustc_driver"), + INTERNER.intern_str("rustc_codegen_llvm"), + INTERNER.intern_str("rustc_codegen_ssa"), + ]; + let crates: Vec<_> = root_crates + .iter() + .flat_map(|krate| { + builder + .in_tree_crates(krate, Some(target)) + .into_iter() + .map(|krate| krate.name.to_string()) + }) + .collect(); + Self { stage, target, crates: INTERNER.intern_list(crates) } + } } impl Step for Rustc { @@ -641,7 +639,11 @@ impl Step for Rustc { } fn make_run(run: RunConfig<'_>) { - run.builder.ensure(Rustc { stage: run.builder.top_stage, target: run.target }); + run.builder.ensure(Rustc { + stage: run.builder.top_stage, + target: run.target, + crates: make_run_crates(&run, "compiler"), + }); } /// Generates compiler documentation. @@ -654,15 +656,6 @@ impl Step for Rustc { let stage = self.stage; let target = self.target; - let paths = builder - .paths - .iter() - .filter(|path| { - let components = components_simplified(path); - components.len() >= 2 && components[0] == "compiler" - }) - .collect::>(); - // This is the intended out directory for compiler documentation. let out = builder.compiler_doc_out(target); t!(fs::create_dir_all(&out)); @@ -672,7 +665,13 @@ impl Step for Rustc { let compiler = builder.compiler(stage, builder.config.build); builder.ensure(compile::Std::new(compiler, builder.config.build)); - builder.info(&format!("Documenting stage{} compiler ({})", stage, target)); + let _guard = builder.msg( + Kind::Doc, + stage, + &format!("compiler{}", crate_description(&self.crates)), + compiler.host, + target, + ); // This uses a shared directory so that librustdoc documentation gets // correctly built and merged with the rustc documentation. This is @@ -710,22 +709,8 @@ impl Step for Rustc { cargo.rustdocflag("--extern-html-root-url"); cargo.rustdocflag("ena=https://docs.rs/ena/latest/"); - let root_crates = if paths.is_empty() { - vec![ - INTERNER.intern_str("rustc_driver"), - INTERNER.intern_str("rustc_codegen_llvm"), - INTERNER.intern_str("rustc_codegen_ssa"), - ] - } else { - paths.into_iter().map(|p| builder.crate_paths[p]).collect() - }; - // Find dependencies for top level crates. - let compiler_crates = root_crates.iter().flat_map(|krate| { - builder.in_tree_crates(krate, Some(target)).into_iter().map(|krate| krate.name) - }); - let mut to_open = None; - for krate in compiler_crates { + for krate in &*self.crates { // Create all crate output directories first to make sure rustdoc uses // relative links. // FIXME: Cargo should probably do this itself. @@ -785,7 +770,7 @@ macro_rules! tool_doc { if true $(&& $rustc_tool)? { // Build rustc docs so that we generate relative links. - builder.ensure(Rustc { stage, target }); + builder.ensure(Rustc::new(stage, target, builder)); // Rustdoc needs the rustc sysroot available to build. // FIXME: is there a way to only ensure `check::Rustc` here? Last time I tried it failed diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 25941fc64c50..960abb31b201 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -220,7 +220,7 @@ impl Step for HtmlCheck { } // Ensure that a few different kinds of documentation are available. builder.default_doc(&[]); - builder.ensure(crate::doc::Rustc { target: self.target, stage: builder.top_stage }); + builder.ensure(crate::doc::Rustc::new(builder.top_stage, self.target, builder)); try_run(builder, builder.tool_cmd(Tool::HtmlChecker).arg(builder.doc_out(self.target))); } @@ -886,11 +886,11 @@ impl Step for RustdocJSStd { command.arg("--test-file").arg(path); } } - builder.ensure(crate::doc::Std { - target: self.target, - stage: builder.top_stage, - format: DocumentationFormat::HTML, - }); + builder.ensure(crate::doc::Std::new( + builder.top_stage, + self.target, + DocumentationFormat::HTML, + )); builder.run(&mut command); } else { builder.info("No nodejs found, skipping \"tests/rustdoc-js-std\" tests"); From 3e765a7f719951a9c1b69a13487e9f817e5a03b1 Mon Sep 17 00:00:00 2001 From: jyn Date: Thu, 25 May 2023 13:52:30 -0500 Subject: [PATCH 34/69] Switch Steps from crates to crate_or_deps where possible and document why the single remaining place can't switch --- src/bootstrap/builder.rs | 2 ++ src/bootstrap/check.rs | 6 ++---- src/bootstrap/compile.rs | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index b16e34c0b935..cf9ae4f08181 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -442,6 +442,8 @@ impl<'a> ShouldRun<'a> { /// Indicates it should run if the command-line selects any of the given crates. /// /// `make_run` will be called a single time with all matching command-line paths. + /// + /// Prefer [`ShouldRun::crate_or_deps`] to this function where possible. pub(crate) fn crates(mut self, crates: Vec<&Crate>) -> Self { for krate in crates { let path = krate.local_path(self.builder); diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 09835516f7bd..f5a93854bf2c 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -85,8 +85,7 @@ impl Step for Std { const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - let crates = run.builder.in_tree_crates("sysroot", None); - run.crates(crates).path("library") + run.crate_or_deps("sysroot").path("library") } fn make_run(run: RunConfig<'_>) { @@ -215,8 +214,7 @@ impl Step for Rustc { const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - let crates = run.builder.in_tree_crates("rustc-main", None); - run.crates(crates).path("compiler") + run.crate_or_deps("rustc-main").path("compiler") } fn make_run(run: RunConfig<'_>) { diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 7b9c4c0f3b3a..a7ebd018a879 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -620,6 +620,8 @@ impl Step for Rustc { fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let mut crates = run.builder.in_tree_crates("rustc-main", None); for (i, krate) in crates.iter().enumerate() { + // We can't allow `build rustc` as an alias for this Step, because that's reserved by `Assemble`. + // Ideally Assemble would use `build compiler` instead, but that seems too confusing to be worth the breaking change. if krate.name == "rustc-main" { crates.swap_remove(i); break; From 71770d5e6e5c6d77777e7f9c86f7c9533882c449 Mon Sep 17 00:00:00 2001 From: jyn Date: Thu, 25 May 2023 14:00:55 -0500 Subject: [PATCH 35/69] Document `ShouldRun::paths` --- src/bootstrap/builder.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index cf9ae4f08181..30359e47e73b 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -473,7 +473,15 @@ impl<'a> ShouldRun<'a> { self.paths(&[path]) } - // multiple aliases for the same job + /// Multiple aliases for the same job. + /// + /// This differs from [`path`] in that multiple calls to path will end up calling `make_run` + /// multiple times, whereas a single call to `paths` will only ever generate a single call to + /// `paths`. + /// + /// This is analogous to `all_krates`, although `all_krates` is gone now. Prefer [`path`] where possible. + /// + /// [`path`]: ShouldRun::path pub fn paths(mut self, paths: &[&str]) -> Self { static SUBMODULES_PATHS: OnceCell> = OnceCell::new(); From c28ee603c8ddc2f171bee4ba02336fb6a3479010 Mon Sep 17 00:00:00 2001 From: jyn Date: Thu, 25 May 2023 15:14:56 -0500 Subject: [PATCH 36/69] Fix bugs in `doc` refactor - Switch from `cargo rustdoc` to `cargo doc` This allows passing `-p` to multiple packages. - Remove `OsStr` support It doesn't work with RUSTDOCFLAGS, and we don't support non-utf8 paths anyway. - Pass `-p std` for each crate in the standard library By default cargo only documents the top-level crate, which is `sysroot` and has no docs. --- src/bootstrap/doc.rs | 67 +++++++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 26 deletions(-) diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 357cd778b6c3..3de85c91516c 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -7,7 +7,6 @@ //! Everything here is basically just a shim around calling either `rustbook` or //! `rustdoc`. -use std::ffi::OsStr; use std::fs; use std::io; use std::path::{Path, PathBuf}; @@ -471,20 +470,21 @@ impl Step for Std { builder.ensure(SharedAssets { target: self.target }); } - let index_page = builder.src.join("src/doc/index.md").into_os_string(); + let index_page = builder + .src + .join("src/doc/index.md") + .into_os_string() + .into_string() + .expect("non-utf8 paths are unsupported"); let mut extra_args = match self.format { - DocumentationFormat::HTML => vec![ - OsStr::new("--markdown-css"), - OsStr::new("rust.css"), - OsStr::new("--markdown-no-toc"), - OsStr::new("--index-page"), - &index_page, - ], - DocumentationFormat::JSON => vec![OsStr::new("--output-format"), OsStr::new("json")], + DocumentationFormat::HTML => { + vec!["--markdown-css", "rust.css", "--markdown-no-toc", "--index-page", &index_page] + } + DocumentationFormat::JSON => vec!["--output-format", "json"], }; if !builder.config.docs_minification { - extra_args.push(OsStr::new("--disable-minification")); + extra_args.push("--disable-minification"); } doc_std(builder, self.format, stage, target, &out, &extra_args, &self.crates); @@ -549,7 +549,7 @@ fn doc_std( stage: u32, target: TargetSelection, out: &Path, - extra_args: &[&OsStr], + extra_args: &[&str], requested_crates: &[String], ) { if builder.no_std(target) == Some(true) { @@ -574,24 +574,39 @@ fn doc_std( // as a function parameter. let out_dir = target_dir.join(target.triple).join("doc"); - let mut cargo = builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "rustdoc"); + let mut cargo = builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "doc"); compile::std_cargo(builder, target, compiler.stage, &mut cargo); - cargo.arg("--target-dir").arg(&*target_dir.to_string_lossy()).arg("-Zskip-rustdoc-fingerprint"); - - for krate in requested_crates { - cargo.arg("-p").arg(krate); + cargo + .arg("--no-deps") + .arg("--target-dir") + .arg(&*target_dir.to_string_lossy()) + .arg("-Zskip-rustdoc-fingerprint") + .rustdocflag("-Z") + .rustdocflag("unstable-options") + .rustdocflag("--resource-suffix") + .rustdocflag(&builder.version); + for arg in extra_args { + cargo.rustdocflag(arg); } - cargo - .arg("--") - .arg("-Z") - .arg("unstable-options") - .arg("--resource-suffix") - .arg(&builder.version) - .args(extra_args); - if builder.config.library_docs_private_items { - cargo.arg("--document-private-items").arg("--document-hidden-items"); + cargo.rustdocflag("--document-private-items").rustdocflag("--document-hidden-items"); + } + + // HACK: because we use `--manifest-path library/sysroot/Cargo.toml`, cargo thinks we only want to document that specific crate, not its dependencies. + // Override its default. + let built_crates = if requested_crates.is_empty() { + builder + .in_tree_crates("sysroot", None) + .into_iter() + .map(|krate| krate.name.to_string()) + .collect() + } else { + requested_crates.to_vec() + }; + + for krate in built_crates { + cargo.arg("-p").arg(krate); } builder.run(&mut cargo.into()); From 7105f2ea7397c86a70ffa73bf663001e3048c94c Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Mon, 29 May 2023 23:01:02 +0300 Subject: [PATCH 37/69] improve `rustdoc-gui-test` to find local `node_modules` Signed-off-by: ozkanonur --- src/tools/rustdoc-gui-test/src/main.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/tools/rustdoc-gui-test/src/main.rs b/src/tools/rustdoc-gui-test/src/main.rs index 8dc18dfaea2d..af9b4e9d6800 100644 --- a/src/tools/rustdoc-gui-test/src/main.rs +++ b/src/tools/rustdoc-gui-test/src/main.rs @@ -143,6 +143,16 @@ If you want to install the `browser-ui-test` dependency, run `npm install browse } let mut command = Command::new(&config.nodejs); + + if let Ok(current_dir) = env::current_dir() { + let local_node_modules = current_dir.join("node_modules"); + if local_node_modules.exists() { + // Link the local node_modules if exists. + // This is useful when we run rustdoc-gui-test from outside of the source root. + env::set_var("NODE_PATH", local_node_modules); + } + } + command .arg(config.rust_src.join("src/tools/rustdoc-gui/tester.js")) .arg("--jobs") From 11fa1764ee4819aa674ca861c5e9a8fafd7a59e6 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Mon, 29 May 2023 12:29:36 -0700 Subject: [PATCH 38/69] Make `TrustedStep` require `Copy` All the implementations of the trait already are `Copy`, and this seems to be enough to simplify the implementations enough to make the MIR inliner willing to inline basics like `Range::next`. --- library/core/src/iter/range.rs | 25 ++-- library/core/src/iter/traits/marker.rs | 2 +- ...nge_iter.forward_loop.PreCodegen.after.mir | 108 +++++++++++++----- ..._iter.range_iter_next.PreCodegen.after.mir | 52 ++++++++- 4 files changed, 142 insertions(+), 45 deletions(-) diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index 0171d89812fe..462f7170a55b 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -619,9 +619,10 @@ impl RangeIteratorImpl for ops::Range { #[inline] fn spec_next(&mut self) -> Option { if self.start < self.end { + let old = self.start; // SAFETY: just checked precondition - let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) }; - Some(mem::replace(&mut self.start, n)) + self.start = unsafe { Step::forward_unchecked(old, 1) }; + Some(old) } else { None } @@ -629,15 +630,15 @@ impl RangeIteratorImpl for ops::Range { #[inline] fn spec_nth(&mut self, n: usize) -> Option { - if let Some(plus_n) = Step::forward_checked(self.start.clone(), n) { + if let Some(plus_n) = Step::forward_checked(self.start, n) { if plus_n < self.end { // SAFETY: just checked precondition - self.start = unsafe { Step::forward_unchecked(plus_n.clone(), 1) }; + self.start = unsafe { Step::forward_unchecked(plus_n, 1) }; return Some(plus_n); } } - self.start = self.end.clone(); + self.start = self.end; None } @@ -655,7 +656,7 @@ impl RangeIteratorImpl for ops::Range { // then steps_between either returns a bound to which we clamp or returns None which // together with the initial inequality implies more than usize::MAX steps. // Otherwise 0 is returned which always safe to use. - self.start = unsafe { Step::forward_unchecked(self.start.clone(), taken) }; + self.start = unsafe { Step::forward_unchecked(self.start, taken) }; NonZeroUsize::new(n - taken).map_or(Ok(()), Err) } @@ -664,8 +665,8 @@ impl RangeIteratorImpl for ops::Range { fn spec_next_back(&mut self) -> Option { if self.start < self.end { // SAFETY: just checked precondition - self.end = unsafe { Step::backward_unchecked(self.end.clone(), 1) }; - Some(self.end.clone()) + self.end = unsafe { Step::backward_unchecked(self.end, 1) }; + Some(self.end) } else { None } @@ -673,15 +674,15 @@ impl RangeIteratorImpl for ops::Range { #[inline] fn spec_nth_back(&mut self, n: usize) -> Option { - if let Some(minus_n) = Step::backward_checked(self.end.clone(), n) { + if let Some(minus_n) = Step::backward_checked(self.end, n) { if minus_n > self.start { // SAFETY: just checked precondition self.end = unsafe { Step::backward_unchecked(minus_n, 1) }; - return Some(self.end.clone()); + return Some(self.end); } } - self.end = self.start.clone(); + self.end = self.start; None } @@ -696,7 +697,7 @@ impl RangeIteratorImpl for ops::Range { let taken = available.min(n); // SAFETY: same as the spec_advance_by() implementation - self.end = unsafe { Step::backward_unchecked(self.end.clone(), taken) }; + self.end = unsafe { Step::backward_unchecked(self.end, taken) }; NonZeroUsize::new(n - taken).map_or(Ok(()), Err) } diff --git a/library/core/src/iter/traits/marker.rs b/library/core/src/iter/traits/marker.rs index af02848233d9..c21a2aac1c9a 100644 --- a/library/core/src/iter/traits/marker.rs +++ b/library/core/src/iter/traits/marker.rs @@ -86,4 +86,4 @@ pub unsafe trait InPlaceIterable: Iterator {} /// for details. Consumers are free to rely on the invariants in unsafe code. #[unstable(feature = "trusted_step", issue = "85731")] #[rustc_specialization_trait] -pub unsafe trait TrustedStep: Step {} +pub unsafe trait TrustedStep: Step + Copy {} diff --git a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.mir index 9856cdd5688b..693939e75f4f 100644 --- a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.mir @@ -8,19 +8,32 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () { let mut _4: std::ops::Range; // in scope 0 at $DIR/range_iter.rs:+1:14: +1:24 let mut _5: std::ops::Range; // in scope 0 at $DIR/range_iter.rs:+1:14: +1:24 let mut _6: &mut std::ops::Range; // in scope 0 at $DIR/range_iter.rs:+1:14: +1:24 - let mut _7: std::option::Option; // in scope 0 at $DIR/range_iter.rs:+1:14: +1:24 - let mut _8: isize; // in scope 0 at $DIR/range_iter.rs:+1:5: +3:6 - let mut _10: &impl Fn(u32); // in scope 0 at $DIR/range_iter.rs:+2:9: +2:10 - let mut _11: (u32,); // in scope 0 at $DIR/range_iter.rs:+2:9: +2:13 - let _12: (); // in scope 0 at $DIR/range_iter.rs:+1:14: +1:24 + let mut _10: std::option::Option; // in scope 0 at $DIR/range_iter.rs:+1:14: +1:24 + let mut _13: isize; // in scope 0 at $DIR/range_iter.rs:+1:5: +3:6 + let mut _15: &impl Fn(u32); // in scope 0 at $DIR/range_iter.rs:+2:9: +2:10 + let mut _16: (u32,); // in scope 0 at $DIR/range_iter.rs:+2:9: +2:13 + let _17: (); // in scope 0 at $DIR/range_iter.rs:+1:14: +1:24 scope 1 { debug iter => _5; // in scope 1 at $DIR/range_iter.rs:+1:14: +1:24 - let _9: u32; // in scope 1 at $DIR/range_iter.rs:+1:9: +1:10 + let _14: u32; // in scope 1 at $DIR/range_iter.rs:+1:9: +1:10 scope 2 { - debug x => _9; // in scope 2 at $DIR/range_iter.rs:+1:9: +1:10 + debug x => _14; // in scope 2 at $DIR/range_iter.rs:+1:9: +1:10 } scope 4 (inlined iter::range::>::next) { // at $DIR/range_iter.rs:21:14: 21:24 debug self => _6; // in scope 4 at $SRC_DIR/core/src/iter/range.rs:LL:COL + scope 5 (inlined as iter::range::RangeIteratorImpl>::spec_next) { // at $SRC_DIR/core/src/iter/range.rs:LL:COL + debug self => _6; // in scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + let mut _7: &u32; // in scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + let mut _8: &u32; // in scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + let mut _9: bool; // in scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + let _11: u32; // in scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + let mut _12: u32; // in scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + scope 6 { + debug old => _11; // in scope 6 at $SRC_DIR/core/src/iter/range.rs:LL:COL + scope 7 { + } + } + } } } scope 3 (inlined as IntoIterator>::into_iter) { // at $DIR/range_iter.rs:21:14: 21:24 @@ -35,57 +48,92 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () { } bb1: { - StorageLive(_7); // scope 1 at $DIR/range_iter.rs:+1:14: +1:24 + StorageLive(_10); // scope 1 at $DIR/range_iter.rs:+1:14: +1:24 _6 = &mut _5; // scope 1 at $DIR/range_iter.rs:+1:14: +1:24 - _7 = as iter::range::RangeIteratorImpl>::spec_next(_6) -> [return: bb2, unwind: bb8]; // scope 4 at $SRC_DIR/core/src/iter/range.rs:LL:COL + StorageLive(_11); // scope 4 at $SRC_DIR/core/src/iter/range.rs:LL:COL + StorageLive(_9); // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + StorageLive(_7); // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + _7 = &((*_6).0: u32); // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + StorageLive(_8); // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + _8 = &((*_6).1: u32); // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + _9 = ::lt(move _7, move _8) -> [return: bb2, unwind: bb12]; // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/iter/range.rs:LL:COL - // + literal: Const { ty: for<'a> fn(&'a mut std::ops::Range) -> Option< as iter::range::RangeIteratorImpl>::Item> { as iter::range::RangeIteratorImpl>::spec_next}, val: Value() } + // + literal: Const { ty: for<'a, 'b> fn(&'a u32, &'b u32) -> bool {::lt}, val: Value() } } bb2: { - _8 = discriminant(_7); // scope 1 at $DIR/range_iter.rs:+1:14: +1:24 - switchInt(move _8) -> [0: bb3, 1: bb5, otherwise: bb7]; // scope 1 at $DIR/range_iter.rs:+1:14: +1:24 + StorageDead(_8); // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + StorageDead(_7); // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + switchInt(move _9) -> [0: bb3, otherwise: bb4]; // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL } bb3: { - StorageDead(_7); // scope 1 at $DIR/range_iter.rs:+3:5: +3:6 - StorageDead(_5); // scope 0 at $DIR/range_iter.rs:+3:5: +3:6 - drop(_3) -> bb4; // scope 0 at $DIR/range_iter.rs:+4:1: +4:2 + _10 = Option::::None; // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + goto -> bb6; // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL } bb4: { - return; // scope 0 at $DIR/range_iter.rs:+4:2: +4:2 + _11 = ((*_6).0: u32); // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + StorageLive(_12); // scope 6 at $SRC_DIR/core/src/iter/range.rs:LL:COL + _12 = ::forward_unchecked(_11, const 1_usize) -> [return: bb5, unwind: bb12]; // scope 7 at $SRC_DIR/core/src/iter/range.rs:LL:COL + // mir::Constant + // + span: $SRC_DIR/core/src/iter/range.rs:LL:COL + // + literal: Const { ty: unsafe fn(u32, usize) -> u32 {::forward_unchecked}, val: Value() } } bb5: { - _9 = ((_7 as Some).0: u32); // scope 1 at $DIR/range_iter.rs:+1:9: +1:10 - StorageLive(_10); // scope 2 at $DIR/range_iter.rs:+2:9: +2:10 - _10 = &_3; // scope 2 at $DIR/range_iter.rs:+2:9: +2:10 - StorageLive(_11); // scope 2 at $DIR/range_iter.rs:+2:9: +2:13 - _11 = (_9,); // scope 2 at $DIR/range_iter.rs:+2:9: +2:13 - _12 = >::call(move _10, move _11) -> [return: bb6, unwind: bb8]; // scope 2 at $DIR/range_iter.rs:+2:9: +2:13 + ((*_6).0: u32) = move _12; // scope 6 at $SRC_DIR/core/src/iter/range.rs:LL:COL + StorageDead(_12); // scope 6 at $SRC_DIR/core/src/iter/range.rs:LL:COL + _10 = Option::::Some(_11); // scope 6 at $SRC_DIR/core/src/iter/range.rs:LL:COL + goto -> bb6; // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + } + + bb6: { + StorageDead(_9); // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + StorageDead(_11); // scope 4 at $SRC_DIR/core/src/iter/range.rs:LL:COL + _13 = discriminant(_10); // scope 1 at $DIR/range_iter.rs:+1:14: +1:24 + switchInt(move _13) -> [0: bb7, 1: bb9, otherwise: bb11]; // scope 1 at $DIR/range_iter.rs:+1:14: +1:24 + } + + bb7: { + StorageDead(_10); // scope 1 at $DIR/range_iter.rs:+3:5: +3:6 + StorageDead(_5); // scope 0 at $DIR/range_iter.rs:+3:5: +3:6 + drop(_3) -> bb8; // scope 0 at $DIR/range_iter.rs:+4:1: +4:2 + } + + bb8: { + return; // scope 0 at $DIR/range_iter.rs:+4:2: +4:2 + } + + bb9: { + _14 = ((_10 as Some).0: u32); // scope 1 at $DIR/range_iter.rs:+1:9: +1:10 + StorageLive(_15); // scope 2 at $DIR/range_iter.rs:+2:9: +2:10 + _15 = &_3; // scope 2 at $DIR/range_iter.rs:+2:9: +2:10 + StorageLive(_16); // scope 2 at $DIR/range_iter.rs:+2:9: +2:13 + _16 = (_14,); // scope 2 at $DIR/range_iter.rs:+2:9: +2:13 + _17 = >::call(move _15, move _16) -> [return: bb10, unwind: bb12]; // scope 2 at $DIR/range_iter.rs:+2:9: +2:13 // mir::Constant // + span: $DIR/range_iter.rs:22:9: 22:10 // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a impl Fn(u32), (u32,)) -> >::Output {>::call}, val: Value() } } - bb6: { - StorageDead(_11); // scope 2 at $DIR/range_iter.rs:+2:12: +2:13 - StorageDead(_10); // scope 2 at $DIR/range_iter.rs:+2:12: +2:13 - StorageDead(_7); // scope 1 at $DIR/range_iter.rs:+3:5: +3:6 + bb10: { + StorageDead(_16); // scope 2 at $DIR/range_iter.rs:+2:12: +2:13 + StorageDead(_15); // scope 2 at $DIR/range_iter.rs:+2:12: +2:13 + StorageDead(_10); // scope 1 at $DIR/range_iter.rs:+3:5: +3:6 goto -> bb1; // scope 1 at $DIR/range_iter.rs:+1:5: +3:6 } - bb7: { + bb11: { unreachable; // scope 1 at $DIR/range_iter.rs:+1:14: +1:24 } - bb8 (cleanup): { - drop(_3) -> [return: bb9, unwind terminate]; // scope 0 at $DIR/range_iter.rs:+4:1: +4:2 + bb12 (cleanup): { + drop(_3) -> [return: bb13, unwind terminate]; // scope 0 at $DIR/range_iter.rs:+4:1: +4:2 } - bb9 (cleanup): { + bb13 (cleanup): { resume; // scope 0 at $DIR/range_iter.rs:+0:1: +4:2 } } diff --git a/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.mir index cae46e2b0bbc..668ec31c6c13 100644 --- a/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.mir @@ -5,16 +5,64 @@ fn range_iter_next(_1: &mut std::ops::Range) -> Option { let mut _0: std::option::Option; // return place in scope 0 at $DIR/range_iter.rs:+0:48: +0:59 scope 1 (inlined iter::range::>::next) { // at $DIR/range_iter.rs:11:8: 11:14 debug self => _1; // in scope 1 at $SRC_DIR/core/src/iter/range.rs:LL:COL + scope 2 (inlined as iter::range::RangeIteratorImpl>::spec_next) { // at $SRC_DIR/core/src/iter/range.rs:LL:COL + debug self => _1; // in scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + let mut _2: &u32; // in scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + let mut _3: &u32; // in scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + let mut _4: bool; // in scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + let _5: u32; // in scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + let mut _6: u32; // in scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + scope 3 { + debug old => _5; // in scope 3 at $SRC_DIR/core/src/iter/range.rs:LL:COL + scope 4 { + } + } + } } bb0: { - _0 = as iter::range::RangeIteratorImpl>::spec_next(_1) -> bb1; // scope 1 at $SRC_DIR/core/src/iter/range.rs:LL:COL + StorageLive(_5); // scope 1 at $SRC_DIR/core/src/iter/range.rs:LL:COL + StorageLive(_4); // scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + StorageLive(_2); // scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + _2 = &((*_1).0: u32); // scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + StorageLive(_3); // scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + _3 = &((*_1).1: u32); // scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + _4 = ::lt(move _2, move _3) -> bb1; // scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/iter/range.rs:LL:COL - // + literal: Const { ty: for<'a> fn(&'a mut std::ops::Range) -> Option< as iter::range::RangeIteratorImpl>::Item> { as iter::range::RangeIteratorImpl>::spec_next}, val: Value() } + // + literal: Const { ty: for<'a, 'b> fn(&'a u32, &'b u32) -> bool {::lt}, val: Value() } } bb1: { + StorageDead(_3); // scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + StorageDead(_2); // scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + switchInt(move _4) -> [0: bb2, otherwise: bb3]; // scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + } + + bb2: { + _0 = Option::::None; // scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + goto -> bb5; // scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + } + + bb3: { + _5 = ((*_1).0: u32); // scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + StorageLive(_6); // scope 3 at $SRC_DIR/core/src/iter/range.rs:LL:COL + _6 = ::forward_unchecked(_5, const 1_usize) -> bb4; // scope 4 at $SRC_DIR/core/src/iter/range.rs:LL:COL + // mir::Constant + // + span: $SRC_DIR/core/src/iter/range.rs:LL:COL + // + literal: Const { ty: unsafe fn(u32, usize) -> u32 {::forward_unchecked}, val: Value() } + } + + bb4: { + ((*_1).0: u32) = move _6; // scope 3 at $SRC_DIR/core/src/iter/range.rs:LL:COL + StorageDead(_6); // scope 3 at $SRC_DIR/core/src/iter/range.rs:LL:COL + _0 = Option::::Some(_5); // scope 3 at $SRC_DIR/core/src/iter/range.rs:LL:COL + goto -> bb5; // scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + } + + bb5: { + StorageDead(_4); // scope 2 at $SRC_DIR/core/src/iter/range.rs:LL:COL + StorageDead(_5); // scope 1 at $SRC_DIR/core/src/iter/range.rs:LL:COL return; // scope 0 at $DIR/range_iter.rs:+2:2: +2:2 } } From 50e01f4d68bba911e2e01ececbe5eca496ee3242 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Mon, 29 May 2023 13:57:18 -0700 Subject: [PATCH 39/69] Update a MIRI fake-time test that this makes "faster" --- src/tools/miri/tests/pass/shims/time-with-isolation2.stdout | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/tests/pass/shims/time-with-isolation2.stdout b/src/tools/miri/tests/pass/shims/time-with-isolation2.stdout index 641e469f50c2..c68b40b744bf 100644 --- a/src/tools/miri/tests/pass/shims/time-with-isolation2.stdout +++ b/src/tools/miri/tests/pass/shims/time-with-isolation2.stdout @@ -1 +1 @@ -The loop took around 13s +The loop took around 7s From 6c18d1eceff68ede8b0692985fd9b704c7942530 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Mon, 29 May 2023 21:55:40 +0000 Subject: [PATCH 40/69] offset_of: Don't require type to be sized --- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 11 ++++++++--- tests/ui/offset-of/offset-of-unsized.rs | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 tests/ui/offset-of/offset-of-unsized.rs diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 6e7065713b81..0255b6603805 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -668,11 +668,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Rvalue::NullaryOp(ref null_op, ty) => { let ty = self.monomorphize(ty); - assert!(bx.cx().type_is_sized(ty)); let layout = bx.cx().layout_of(ty); let val = match null_op { - mir::NullOp::SizeOf => layout.size.bytes(), - mir::NullOp::AlignOf => layout.align.abi.bytes(), + mir::NullOp::SizeOf => { + assert!(bx.cx().type_is_sized(ty)); + layout.size.bytes() + } + mir::NullOp::AlignOf => { + assert!(bx.cx().type_is_sized(ty)); + layout.align.abi.bytes() + } mir::NullOp::OffsetOf(fields) => { layout.offset_of_subfield(bx.cx(), fields.iter().map(|f| f.index())).bytes() } diff --git a/tests/ui/offset-of/offset-of-unsized.rs b/tests/ui/offset-of/offset-of-unsized.rs new file mode 100644 index 000000000000..666387e615ef --- /dev/null +++ b/tests/ui/offset-of/offset-of-unsized.rs @@ -0,0 +1,15 @@ +// build-pass +// regression test for #112051 + +#![feature(offset_of)] + +struct S { + a: u64, + b: T, +} +trait Tr {} + +fn main() { + let _a = core::mem::offset_of!(S, a); + let _b = core::mem::offset_of!((u64, dyn Tr), 0); +} From 000cd9b5fb9aad0c4fc3e3172387aac79d50a1d3 Mon Sep 17 00:00:00 2001 From: reez12g Date: Tue, 30 May 2023 13:56:57 +0900 Subject: [PATCH 41/69] fix comment on Allocator trait --- library/core/src/alloc/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index ff390322d552..452bc482cc1a 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -94,8 +94,9 @@ impl fmt::Display for AllocError { /// /// # Safety /// -/// * Memory blocks returned from an allocator must point to valid memory and retain their validity -/// until the instance and all of its copies and clones are dropped, +/// * Memory blocks returned from an allocator that are [*currently allocated*] must point to +/// valid memory and retain their validity while they are [*currently allocated*] and at +/// least one of the instance and all of its clones has not been dropped. /// /// * copying, cloning, or moving the allocator must not invalidate memory blocks returned from this /// allocator. A copied or cloned allocator must behave like the same allocator, and From 472230d192b8bace6ddbe825d68ccd27d0d5ef1d Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Tue, 30 May 2023 00:34:50 -0700 Subject: [PATCH 42/69] Remove array_zip `[T; N]::zip` is "eager" but most zips are mapped. This causes poor optimization in generated code. This is a fundamental design issue and "zip" is "prime real estate" in terms of function names, so let's free it up again. --- library/core/src/array/mod.rs | 23 ----------------------- tests/codegen/array-map.rs | 11 ----------- tests/codegen/autovectorize-f32x4.rs | 11 ----------- 3 files changed, 45 deletions(-) diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index fec92320a4b5..76b3589b9e4b 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -538,29 +538,6 @@ impl [T; N] { drain_array_with(self, |iter| try_from_trusted_iterator(iter.map(f))) } - /// 'Zips up' two arrays into a single array of pairs. - /// - /// `zip()` returns a new array where every element is a tuple where the - /// first element comes from the first array, and the second element comes - /// from the second array. In other words, it zips two arrays together, - /// into a single one. - /// - /// # Examples - /// - /// ``` - /// #![feature(array_zip)] - /// let x = [1, 2, 3]; - /// let y = [4, 5, 6]; - /// let z = x.zip(y); - /// assert_eq!(z, [(1, 4), (2, 5), (3, 6)]); - /// ``` - #[unstable(feature = "array_zip", issue = "80094")] - pub fn zip(self, rhs: [U; N]) -> [(T, U); N] { - drain_array_with(self, |lhs| { - drain_array_with(rhs, |rhs| from_trusted_iterator(crate::iter::zip(lhs, rhs))) - }) - } - /// Returns a slice containing the entire array. Equivalent to `&s[..]`. #[stable(feature = "array_as_slice", since = "1.57.0")] #[rustc_const_stable(feature = "array_as_slice", since = "1.57.0")] diff --git a/tests/codegen/array-map.rs b/tests/codegen/array-map.rs index 3706ddf99fd9..24f3f43d0787 100644 --- a/tests/codegen/array-map.rs +++ b/tests/codegen/array-map.rs @@ -4,7 +4,6 @@ // ignore-debug (the extra assertions get in the way) #![crate_type = "lib"] -#![feature(array_zip)] // CHECK-LABEL: @short_integer_map #[no_mangle] @@ -16,16 +15,6 @@ pub fn short_integer_map(x: [u32; 8]) -> [u32; 8] { x.map(|x| 2 * x + 1) } -// CHECK-LABEL: @short_integer_zip_map -#[no_mangle] -pub fn short_integer_zip_map(x: [u32; 8], y: [u32; 8]) -> [u32; 8] { - // CHECK: %[[A:.+]] = load <8 x i32> - // CHECK: %[[B:.+]] = load <8 x i32> - // CHECK: sub <8 x i32> %[[B]], %[[A]] - // CHECK: store <8 x i32> - x.zip(y).map(|(x, y)| x - y) -} - // This test is checking that LLVM can SRoA away a bunch of the overhead, // like fully moving the iterators to registers. Notably, previous implementations // of `map` ended up `alloca`ing the whole `array::IntoIterator`, meaning both a diff --git a/tests/codegen/autovectorize-f32x4.rs b/tests/codegen/autovectorize-f32x4.rs index 9ecea53f1c05..474ff1c4e91b 100644 --- a/tests/codegen/autovectorize-f32x4.rs +++ b/tests/codegen/autovectorize-f32x4.rs @@ -1,7 +1,6 @@ // compile-flags: -C opt-level=3 -Z merge-functions=disabled // only-x86_64 #![crate_type = "lib"] -#![feature(array_zip)] // CHECK-LABEL: @auto_vectorize_direct #[no_mangle] @@ -31,13 +30,3 @@ pub fn auto_vectorize_loop(a: [f32; 4], b: [f32; 4]) -> [f32; 4] { } c } - -// CHECK-LABEL: @auto_vectorize_array_zip_map -#[no_mangle] -pub fn auto_vectorize_array_zip_map(a: [f32; 4], b: [f32; 4]) -> [f32; 4] { -// CHECK: load <4 x float> -// CHECK: load <4 x float> -// CHECK: fadd <4 x float> -// CHECK: store <4 x float> - a.zip(b).map(|(a, b)| a + b) -} From 97d4a38de9fd6efb4588a7262cd9c66c2093e29f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 29 May 2023 09:56:37 +1000 Subject: [PATCH 43/69] Remove `-Zcgu-partitioning-strategy`. This option was introduced three years ago, but it's never been meaningfully used, and `default` is the only acceptable value. Also, I think the `Partition` trait presents an interface that is too closely tied to the existing strategy and would probably be wrong for other strategies. (My rule of thumb is to not make something generic until there are at least two instances of it, to avoid this kind of problem.) Also, I don't think providing multiple partitioning strategies to the user is a good idea, because the compiler already has enough obscure knobs. This commit removes the option, along with the `Partition` trait, and the `Partitioner` and `DefaultPartitioning` types. I left the existing code in `compiler/rustc_monomorphize/src/partitioning/default.rs`, though I could be persuaded that moving it into `compiler/rustc_monomorphize/src/partitioning/mod.rs` is better. --- .../src/partitioning/default.rs | 555 +++++++++--------- .../src/partitioning/mod.rs | 121 +--- compiler/rustc_session/src/options.rs | 2 - 3 files changed, 279 insertions(+), 399 deletions(-) diff --git a/compiler/rustc_monomorphize/src/partitioning/default.rs b/compiler/rustc_monomorphize/src/partitioning/default.rs index 603b3ddc106e..71cbee3b1669 100644 --- a/compiler/rustc_monomorphize/src/partitioning/default.rs +++ b/compiler/rustc_monomorphize/src/partitioning/default.rs @@ -15,326 +15,319 @@ use rustc_span::symbol::Symbol; use super::PartitioningCx; use crate::collector::InliningMap; -use crate::partitioning::{MonoItemPlacement, Partition, PlacedRootMonoItems}; +use crate::partitioning::{MonoItemPlacement, PlacedRootMonoItems}; -pub struct DefaultPartitioning; +// This modules implements the default (and only) partitioning strategy. -impl<'tcx> Partition<'tcx> for DefaultPartitioning { - fn place_root_mono_items( - &mut self, - cx: &PartitioningCx<'_, 'tcx>, - mono_items: &mut I, - ) -> PlacedRootMonoItems<'tcx> - where - I: Iterator>, - { - let mut roots = FxHashSet::default(); - let mut codegen_units = FxHashMap::default(); - let is_incremental_build = cx.tcx.sess.opts.incremental.is_some(); - let mut internalization_candidates = FxHashSet::default(); +pub(super) fn place_root_mono_items<'tcx, I>( + cx: &PartitioningCx<'_, 'tcx>, + mono_items: &mut I, +) -> PlacedRootMonoItems<'tcx> +where + I: Iterator>, +{ + let mut roots = FxHashSet::default(); + let mut codegen_units = FxHashMap::default(); + let is_incremental_build = cx.tcx.sess.opts.incremental.is_some(); + let mut internalization_candidates = FxHashSet::default(); - // Determine if monomorphizations instantiated in this crate will be made - // available to downstream crates. This depends on whether we are in - // share-generics mode and whether the current crate can even have - // downstream crates. - let export_generics = - cx.tcx.sess.opts.share_generics() && cx.tcx.local_crate_exports_generics(); + // Determine if monomorphizations instantiated in this crate will be made + // available to downstream crates. This depends on whether we are in + // share-generics mode and whether the current crate can even have + // downstream crates. + let export_generics = + cx.tcx.sess.opts.share_generics() && cx.tcx.local_crate_exports_generics(); - let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx); - let cgu_name_cache = &mut FxHashMap::default(); + let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx); + let cgu_name_cache = &mut FxHashMap::default(); - for mono_item in mono_items { - match mono_item.instantiation_mode(cx.tcx) { - InstantiationMode::GloballyShared { .. } => {} - InstantiationMode::LocalCopy => continue, - } + for mono_item in mono_items { + match mono_item.instantiation_mode(cx.tcx) { + InstantiationMode::GloballyShared { .. } => {} + InstantiationMode::LocalCopy => continue, + } - let characteristic_def_id = characteristic_def_id_of_mono_item(cx.tcx, mono_item); - let is_volatile = is_incremental_build && mono_item.is_generic_fn(); + let characteristic_def_id = characteristic_def_id_of_mono_item(cx.tcx, mono_item); + let is_volatile = is_incremental_build && mono_item.is_generic_fn(); - let codegen_unit_name = match characteristic_def_id { - Some(def_id) => compute_codegen_unit_name( - cx.tcx, - cgu_name_builder, - def_id, - is_volatile, - cgu_name_cache, - ), - None => fallback_cgu_name(cgu_name_builder), - }; - - let codegen_unit = codegen_units - .entry(codegen_unit_name) - .or_insert_with(|| CodegenUnit::new(codegen_unit_name)); - - let mut can_be_internalized = true; - let (linkage, visibility) = mono_item_linkage_and_visibility( + let codegen_unit_name = match characteristic_def_id { + Some(def_id) => compute_codegen_unit_name( cx.tcx, - &mono_item, - &mut can_be_internalized, - export_generics, - ); - if visibility == Visibility::Hidden && can_be_internalized { - internalization_candidates.insert(mono_item); - } + cgu_name_builder, + def_id, + is_volatile, + cgu_name_cache, + ), + None => fallback_cgu_name(cgu_name_builder), + }; - codegen_unit.items_mut().insert(mono_item, (linkage, visibility)); - roots.insert(mono_item); + let codegen_unit = codegen_units + .entry(codegen_unit_name) + .or_insert_with(|| CodegenUnit::new(codegen_unit_name)); + + let mut can_be_internalized = true; + let (linkage, visibility) = mono_item_linkage_and_visibility( + cx.tcx, + &mono_item, + &mut can_be_internalized, + export_generics, + ); + if visibility == Visibility::Hidden && can_be_internalized { + internalization_candidates.insert(mono_item); } - // Always ensure we have at least one CGU; otherwise, if we have a - // crate with just types (for example), we could wind up with no CGU. - if codegen_units.is_empty() { - let codegen_unit_name = fallback_cgu_name(cgu_name_builder); - codegen_units.insert(codegen_unit_name, CodegenUnit::new(codegen_unit_name)); - } - - let codegen_units = codegen_units.into_values().collect(); - PlacedRootMonoItems { codegen_units, roots, internalization_candidates } + codegen_unit.items_mut().insert(mono_item, (linkage, visibility)); + roots.insert(mono_item); } - fn merge_codegen_units( - &mut self, - cx: &PartitioningCx<'_, 'tcx>, - codegen_units: &mut Vec>, - ) { - assert!(cx.target_cgu_count >= 1); - - // Note that at this point in time the `codegen_units` here may not be - // in a deterministic order (but we know they're deterministically the - // same set). We want this merging to produce a deterministic ordering - // of codegen units from the input. - // - // Due to basically how we've implemented the merging below (merge the - // two smallest into each other) we're sure to start off with a - // deterministic order (sorted by name). This'll mean that if two cgus - // have the same size the stable sort below will keep everything nice - // and deterministic. - codegen_units.sort_by(|a, b| a.name().as_str().cmp(b.name().as_str())); - - // This map keeps track of what got merged into what. - let mut cgu_contents: FxHashMap> = - codegen_units.iter().map(|cgu| (cgu.name(), vec![cgu.name()])).collect(); - - // Merge the two smallest codegen units until the target size is - // reached. - while codegen_units.len() > cx.target_cgu_count { - // Sort small cgus to the back - codegen_units.sort_by_cached_key(|cgu| cmp::Reverse(cgu.size_estimate())); - let mut smallest = codegen_units.pop().unwrap(); - let second_smallest = codegen_units.last_mut().unwrap(); - - // Move the mono-items from `smallest` to `second_smallest` - second_smallest.modify_size_estimate(smallest.size_estimate()); - for (k, v) in smallest.items_mut().drain() { - second_smallest.items_mut().insert(k, v); - } - - // Record that `second_smallest` now contains all the stuff that was - // in `smallest` before. - let mut consumed_cgu_names = cgu_contents.remove(&smallest.name()).unwrap(); - cgu_contents.get_mut(&second_smallest.name()).unwrap().append(&mut consumed_cgu_names); - - debug!( - "CodegenUnit {} merged into CodegenUnit {}", - smallest.name(), - second_smallest.name() - ); - } - - let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx); - - if cx.tcx.sess.opts.incremental.is_some() { - // If we are doing incremental compilation, we want CGU names to - // reflect the path of the source level module they correspond to. - // For CGUs that contain the code of multiple modules because of the - // merging done above, we use a concatenation of the names of all - // contained CGUs. - let new_cgu_names: FxHashMap = cgu_contents - .into_iter() - // This `filter` makes sure we only update the name of CGUs that - // were actually modified by merging. - .filter(|(_, cgu_contents)| cgu_contents.len() > 1) - .map(|(current_cgu_name, cgu_contents)| { - let mut cgu_contents: Vec<&str> = - cgu_contents.iter().map(|s| s.as_str()).collect(); - - // Sort the names, so things are deterministic and easy to - // predict. We are sorting primitive `&str`s here so we can - // use unstable sort. - cgu_contents.sort_unstable(); - - (current_cgu_name, cgu_contents.join("--")) - }) - .collect(); - - for cgu in codegen_units.iter_mut() { - if let Some(new_cgu_name) = new_cgu_names.get(&cgu.name()) { - if cx.tcx.sess.opts.unstable_opts.human_readable_cgu_names { - cgu.set_name(Symbol::intern(&new_cgu_name)); - } else { - // If we don't require CGU names to be human-readable, - // we use a fixed length hash of the composite CGU name - // instead. - let new_cgu_name = CodegenUnit::mangle_name(&new_cgu_name); - cgu.set_name(Symbol::intern(&new_cgu_name)); - } - } - } - } else { - // If we are compiling non-incrementally we just generate simple CGU - // names containing an index. - for (index, cgu) in codegen_units.iter_mut().enumerate() { - let numbered_codegen_unit_name = - cgu_name_builder.build_cgu_name_no_mangle(LOCAL_CRATE, &["cgu"], Some(index)); - cgu.set_name(numbered_codegen_unit_name); - } - } + // Always ensure we have at least one CGU; otherwise, if we have a + // crate with just types (for example), we could wind up with no CGU. + if codegen_units.is_empty() { + let codegen_unit_name = fallback_cgu_name(cgu_name_builder); + codegen_units.insert(codegen_unit_name, CodegenUnit::new(codegen_unit_name)); } - fn place_inlined_mono_items( - &mut self, - cx: &PartitioningCx<'_, 'tcx>, - codegen_units: &mut [CodegenUnit<'tcx>], - roots: FxHashSet>, - ) -> FxHashMap, MonoItemPlacement> { - let mut mono_item_placements = FxHashMap::default(); + let codegen_units = codegen_units.into_values().collect(); + PlacedRootMonoItems { codegen_units, roots, internalization_candidates } +} - let single_codegen_unit = codegen_units.len() == 1; +pub(super) fn merge_codegen_units<'tcx>( + cx: &PartitioningCx<'_, 'tcx>, + codegen_units: &mut Vec>, +) { + assert!(cx.target_cgu_count >= 1); - for old_codegen_unit in codegen_units.iter_mut() { - // Collect all items that need to be available in this codegen unit. - let mut reachable = FxHashSet::default(); - for root in old_codegen_unit.items().keys() { - follow_inlining(*root, cx.inlining_map, &mut reachable); - } + // Note that at this point in time the `codegen_units` here may not be + // in a deterministic order (but we know they're deterministically the + // same set). We want this merging to produce a deterministic ordering + // of codegen units from the input. + // + // Due to basically how we've implemented the merging below (merge the + // two smallest into each other) we're sure to start off with a + // deterministic order (sorted by name). This'll mean that if two cgus + // have the same size the stable sort below will keep everything nice + // and deterministic. + codegen_units.sort_by(|a, b| a.name().as_str().cmp(b.name().as_str())); - let mut new_codegen_unit = CodegenUnit::new(old_codegen_unit.name()); + // This map keeps track of what got merged into what. + let mut cgu_contents: FxHashMap> = + codegen_units.iter().map(|cgu| (cgu.name(), vec![cgu.name()])).collect(); - // Add all monomorphizations that are not already there. - for mono_item in reachable { - if let Some(linkage) = old_codegen_unit.items().get(&mono_item) { - // This is a root, just copy it over. - new_codegen_unit.items_mut().insert(mono_item, *linkage); + // Merge the two smallest codegen units until the target size is + // reached. + while codegen_units.len() > cx.target_cgu_count { + // Sort small cgus to the back + codegen_units.sort_by_cached_key(|cgu| cmp::Reverse(cgu.size_estimate())); + let mut smallest = codegen_units.pop().unwrap(); + let second_smallest = codegen_units.last_mut().unwrap(); + + // Move the mono-items from `smallest` to `second_smallest` + second_smallest.modify_size_estimate(smallest.size_estimate()); + for (k, v) in smallest.items_mut().drain() { + second_smallest.items_mut().insert(k, v); + } + + // Record that `second_smallest` now contains all the stuff that was + // in `smallest` before. + let mut consumed_cgu_names = cgu_contents.remove(&smallest.name()).unwrap(); + cgu_contents.get_mut(&second_smallest.name()).unwrap().append(&mut consumed_cgu_names); + + debug!( + "CodegenUnit {} merged into CodegenUnit {}", + smallest.name(), + second_smallest.name() + ); + } + + let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx); + + if cx.tcx.sess.opts.incremental.is_some() { + // If we are doing incremental compilation, we want CGU names to + // reflect the path of the source level module they correspond to. + // For CGUs that contain the code of multiple modules because of the + // merging done above, we use a concatenation of the names of all + // contained CGUs. + let new_cgu_names: FxHashMap = cgu_contents + .into_iter() + // This `filter` makes sure we only update the name of CGUs that + // were actually modified by merging. + .filter(|(_, cgu_contents)| cgu_contents.len() > 1) + .map(|(current_cgu_name, cgu_contents)| { + let mut cgu_contents: Vec<&str> = cgu_contents.iter().map(|s| s.as_str()).collect(); + + // Sort the names, so things are deterministic and easy to + // predict. We are sorting primitive `&str`s here so we can + // use unstable sort. + cgu_contents.sort_unstable(); + + (current_cgu_name, cgu_contents.join("--")) + }) + .collect(); + + for cgu in codegen_units.iter_mut() { + if let Some(new_cgu_name) = new_cgu_names.get(&cgu.name()) { + if cx.tcx.sess.opts.unstable_opts.human_readable_cgu_names { + cgu.set_name(Symbol::intern(&new_cgu_name)); } else { - if roots.contains(&mono_item) { - bug!( - "GloballyShared mono-item inlined into other CGU: \ - {:?}", - mono_item - ); - } - - // This is a CGU-private copy. - new_codegen_unit - .items_mut() - .insert(mono_item, (Linkage::Internal, Visibility::Default)); - } - - if !single_codegen_unit { - // If there is more than one codegen unit, we need to keep track - // in which codegen units each monomorphization is placed. - match mono_item_placements.entry(mono_item) { - Entry::Occupied(e) => { - let placement = e.into_mut(); - debug_assert!(match *placement { - MonoItemPlacement::SingleCgu { cgu_name } => { - cgu_name != new_codegen_unit.name() - } - MonoItemPlacement::MultipleCgus => true, - }); - *placement = MonoItemPlacement::MultipleCgus; - } - Entry::Vacant(e) => { - e.insert(MonoItemPlacement::SingleCgu { - cgu_name: new_codegen_unit.name(), - }); - } - } + // If we don't require CGU names to be human-readable, + // we use a fixed length hash of the composite CGU name + // instead. + let new_cgu_name = CodegenUnit::mangle_name(&new_cgu_name); + cgu.set_name(Symbol::intern(&new_cgu_name)); } } - - *old_codegen_unit = new_codegen_unit; } - - return mono_item_placements; - - fn follow_inlining<'tcx>( - mono_item: MonoItem<'tcx>, - inlining_map: &InliningMap<'tcx>, - visited: &mut FxHashSet>, - ) { - if !visited.insert(mono_item) { - return; - } - - inlining_map.with_inlining_candidates(mono_item, |target| { - follow_inlining(target, inlining_map, visited); - }); + } else { + // If we are compiling non-incrementally we just generate simple CGU + // names containing an index. + for (index, cgu) in codegen_units.iter_mut().enumerate() { + let numbered_codegen_unit_name = + cgu_name_builder.build_cgu_name_no_mangle(LOCAL_CRATE, &["cgu"], Some(index)); + cgu.set_name(numbered_codegen_unit_name); } } +} - fn internalize_symbols( - &mut self, - cx: &PartitioningCx<'_, 'tcx>, - codegen_units: &mut [CodegenUnit<'tcx>], - mono_item_placements: FxHashMap, MonoItemPlacement>, - internalization_candidates: FxHashSet>, - ) { - if codegen_units.len() == 1 { - // Fast path for when there is only one codegen unit. In this case we - // can internalize all candidates, since there is nowhere else they - // could be accessed from. - for cgu in codegen_units { - for candidate in &internalization_candidates { - cgu.items_mut().insert(*candidate, (Linkage::Internal, Visibility::Default)); +pub(super) fn place_inlined_mono_items<'tcx>( + cx: &PartitioningCx<'_, 'tcx>, + codegen_units: &mut [CodegenUnit<'tcx>], + roots: FxHashSet>, +) -> FxHashMap, MonoItemPlacement> { + let mut mono_item_placements = FxHashMap::default(); + + let single_codegen_unit = codegen_units.len() == 1; + + for old_codegen_unit in codegen_units.iter_mut() { + // Collect all items that need to be available in this codegen unit. + let mut reachable = FxHashSet::default(); + for root in old_codegen_unit.items().keys() { + follow_inlining(*root, cx.inlining_map, &mut reachable); + } + + let mut new_codegen_unit = CodegenUnit::new(old_codegen_unit.name()); + + // Add all monomorphizations that are not already there. + for mono_item in reachable { + if let Some(linkage) = old_codegen_unit.items().get(&mono_item) { + // This is a root, just copy it over. + new_codegen_unit.items_mut().insert(mono_item, *linkage); + } else { + if roots.contains(&mono_item) { + bug!( + "GloballyShared mono-item inlined into other CGU: \ + {:?}", + mono_item + ); } + + // This is a CGU-private copy. + new_codegen_unit + .items_mut() + .insert(mono_item, (Linkage::Internal, Visibility::Default)); } + if !single_codegen_unit { + // If there is more than one codegen unit, we need to keep track + // in which codegen units each monomorphization is placed. + match mono_item_placements.entry(mono_item) { + Entry::Occupied(e) => { + let placement = e.into_mut(); + debug_assert!(match *placement { + MonoItemPlacement::SingleCgu { cgu_name } => { + cgu_name != new_codegen_unit.name() + } + MonoItemPlacement::MultipleCgus => true, + }); + *placement = MonoItemPlacement::MultipleCgus; + } + Entry::Vacant(e) => { + e.insert(MonoItemPlacement::SingleCgu { + cgu_name: new_codegen_unit.name(), + }); + } + } + } + } + + *old_codegen_unit = new_codegen_unit; + } + + return mono_item_placements; + + fn follow_inlining<'tcx>( + mono_item: MonoItem<'tcx>, + inlining_map: &InliningMap<'tcx>, + visited: &mut FxHashSet>, + ) { + if !visited.insert(mono_item) { return; } - // Build a map from every monomorphization to all the monomorphizations that - // reference it. - let mut accessor_map: FxHashMap, Vec>> = Default::default(); - cx.inlining_map.iter_accesses(|accessor, accessees| { - for accessee in accessees { - accessor_map.entry(*accessee).or_default().push(accessor); - } + inlining_map.with_inlining_candidates(mono_item, |target| { + follow_inlining(target, inlining_map, visited); }); + } +} - // For each internalization candidates in each codegen unit, check if it is - // accessed from outside its defining codegen unit. +pub(super) fn internalize_symbols<'tcx>( + cx: &PartitioningCx<'_, 'tcx>, + codegen_units: &mut [CodegenUnit<'tcx>], + mono_item_placements: FxHashMap, MonoItemPlacement>, + internalization_candidates: FxHashSet>, +) { + if codegen_units.len() == 1 { + // Fast path for when there is only one codegen unit. In this case we + // can internalize all candidates, since there is nowhere else they + // could be accessed from. for cgu in codegen_units { - let home_cgu = MonoItemPlacement::SingleCgu { cgu_name: cgu.name() }; + for candidate in &internalization_candidates { + cgu.items_mut().insert(*candidate, (Linkage::Internal, Visibility::Default)); + } + } - for (accessee, linkage_and_visibility) in cgu.items_mut() { - if !internalization_candidates.contains(accessee) { - // This item is no candidate for internalizing, so skip it. + return; + } + + // Build a map from every monomorphization to all the monomorphizations that + // reference it. + let mut accessor_map: FxHashMap, Vec>> = Default::default(); + cx.inlining_map.iter_accesses(|accessor, accessees| { + for accessee in accessees { + accessor_map.entry(*accessee).or_default().push(accessor); + } + }); + + // For each internalization candidates in each codegen unit, check if it is + // accessed from outside its defining codegen unit. + for cgu in codegen_units { + let home_cgu = MonoItemPlacement::SingleCgu { cgu_name: cgu.name() }; + + for (accessee, linkage_and_visibility) in cgu.items_mut() { + if !internalization_candidates.contains(accessee) { + // This item is no candidate for internalizing, so skip it. + continue; + } + debug_assert_eq!(mono_item_placements[accessee], home_cgu); + + if let Some(accessors) = accessor_map.get(accessee) { + if accessors + .iter() + .filter_map(|accessor| { + // Some accessors might not have been + // instantiated. We can safely ignore those. + mono_item_placements.get(accessor) + }) + .any(|placement| *placement != home_cgu) + { + // Found an accessor from another CGU, so skip to the next + // item without marking this one as internal. continue; } - debug_assert_eq!(mono_item_placements[accessee], home_cgu); - - if let Some(accessors) = accessor_map.get(accessee) { - if accessors - .iter() - .filter_map(|accessor| { - // Some accessors might not have been - // instantiated. We can safely ignore those. - mono_item_placements.get(accessor) - }) - .any(|placement| *placement != home_cgu) - { - // Found an accessor from another CGU, so skip to the next - // item without marking this one as internal. - continue; - } - } - - // If we got here, we did not find any accesses from other CGUs, - // so it's fine to make this monomorphization internal. - *linkage_and_visibility = (Linkage::Internal, Visibility::Default); } + + // If we got here, we did not find any accesses from other CGUs, + // so it's fine to make this monomorphization internal. + *linkage_and_visibility = (Linkage::Internal, Visibility::Default); } } } diff --git a/compiler/rustc_monomorphize/src/partitioning/mod.rs b/compiler/rustc_monomorphize/src/partitioning/mod.rs index d0b23ca9ea44..2843c361e0ac 100644 --- a/compiler/rustc_monomorphize/src/partitioning/mod.rs +++ b/compiler/rustc_monomorphize/src/partitioning/mod.rs @@ -113,74 +113,7 @@ use rustc_span::symbol::Symbol; use crate::collector::InliningMap; use crate::collector::{self, MonoItemCollectionMode}; -use crate::errors::{ - CouldntDumpMonoStats, SymbolAlreadyDefined, UnknownCguCollectionMode, UnknownPartitionStrategy, -}; - -enum Partitioner { - Default(default::DefaultPartitioning), - // Other partitioning strategies can go here. - Unknown, -} - -impl<'tcx> Partition<'tcx> for Partitioner { - fn place_root_mono_items( - &mut self, - cx: &PartitioningCx<'_, 'tcx>, - mono_items: &mut I, - ) -> PlacedRootMonoItems<'tcx> - where - I: Iterator>, - { - match self { - Partitioner::Default(partitioner) => partitioner.place_root_mono_items(cx, mono_items), - Partitioner::Unknown => cx.tcx.sess.emit_fatal(UnknownPartitionStrategy), - } - } - - fn merge_codegen_units( - &mut self, - cx: &PartitioningCx<'_, 'tcx>, - codegen_units: &mut Vec>, - ) { - match self { - Partitioner::Default(partitioner) => partitioner.merge_codegen_units(cx, codegen_units), - Partitioner::Unknown => cx.tcx.sess.emit_fatal(UnknownPartitionStrategy), - } - } - - fn place_inlined_mono_items( - &mut self, - cx: &PartitioningCx<'_, 'tcx>, - codegen_units: &mut [CodegenUnit<'tcx>], - roots: FxHashSet>, - ) -> FxHashMap, MonoItemPlacement> { - match self { - Partitioner::Default(partitioner) => { - partitioner.place_inlined_mono_items(cx, codegen_units, roots) - } - Partitioner::Unknown => cx.tcx.sess.emit_fatal(UnknownPartitionStrategy), - } - } - - fn internalize_symbols( - &mut self, - cx: &PartitioningCx<'_, 'tcx>, - codegen_units: &mut [CodegenUnit<'tcx>], - mono_item_placements: FxHashMap, MonoItemPlacement>, - internalization_candidates: FxHashSet>, - ) { - match self { - Partitioner::Default(partitioner) => partitioner.internalize_symbols( - cx, - codegen_units, - mono_item_placements, - internalization_candidates, - ), - Partitioner::Unknown => cx.tcx.sess.emit_fatal(UnknownPartitionStrategy), - } - } -} +use crate::errors::{CouldntDumpMonoStats, SymbolAlreadyDefined, UnknownCguCollectionMode}; struct PartitioningCx<'a, 'tcx> { tcx: TyCtxt<'tcx>, @@ -194,49 +127,6 @@ pub struct PlacedRootMonoItems<'tcx> { internalization_candidates: FxHashSet>, } -trait Partition<'tcx> { - fn place_root_mono_items( - &mut self, - cx: &PartitioningCx<'_, 'tcx>, - mono_items: &mut I, - ) -> PlacedRootMonoItems<'tcx> - where - I: Iterator>; - - fn merge_codegen_units( - &mut self, - cx: &PartitioningCx<'_, 'tcx>, - codegen_units: &mut Vec>, - ); - - fn place_inlined_mono_items( - &mut self, - cx: &PartitioningCx<'_, 'tcx>, - codegen_units: &mut [CodegenUnit<'tcx>], - roots: FxHashSet>, - ) -> FxHashMap, MonoItemPlacement>; - - fn internalize_symbols( - &mut self, - cx: &PartitioningCx<'_, 'tcx>, - codegen_units: &mut [CodegenUnit<'tcx>], - mono_item_placements: FxHashMap, MonoItemPlacement>, - internalization_candidates: FxHashSet>, - ); -} - -fn get_partitioner(tcx: TyCtxt<'_>) -> Partitioner { - let strategy = match &tcx.sess.opts.unstable_opts.cgu_partitioning_strategy { - None => "default", - Some(s) => &s[..], - }; - - match strategy { - "default" => Partitioner::Default(default::DefaultPartitioning), - _ => Partitioner::Unknown, - } -} - fn partition<'tcx, I>( tcx: TyCtxt<'tcx>, mono_items: &mut I, @@ -248,14 +138,13 @@ where { let _prof_timer = tcx.prof.generic_activity("cgu_partitioning"); - let mut partitioner = get_partitioner(tcx); let cx = &PartitioningCx { tcx, target_cgu_count: max_cgu_count, inlining_map }; // In the first step, we place all regular monomorphizations into their // respective 'home' codegen unit. Regular monomorphizations are all // functions and statics defined in the local crate. let PlacedRootMonoItems { mut codegen_units, roots, internalization_candidates } = { let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_roots"); - partitioner.place_root_mono_items(cx, mono_items) + default::place_root_mono_items(cx, mono_items) }; for cgu in &mut codegen_units { @@ -269,7 +158,7 @@ where // estimates. { let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_merge_cgus"); - partitioner.merge_codegen_units(cx, &mut codegen_units); + default::merge_codegen_units(cx, &mut codegen_units); debug_dump(tcx, "POST MERGING", &codegen_units); } @@ -279,7 +168,7 @@ where // local functions the definition of which is marked with `#[inline]`. let mono_item_placements = { let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_inline_items"); - partitioner.place_inlined_mono_items(cx, &mut codegen_units, roots) + default::place_inlined_mono_items(cx, &mut codegen_units, roots) }; for cgu in &mut codegen_units { @@ -292,7 +181,7 @@ where // more freedom to optimize. if !tcx.sess.link_dead_code() { let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_internalize_symbols"); - partitioner.internalize_symbols( + default::internalize_symbols( cx, &mut codegen_units, mono_item_placements, diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 007e720823bf..7cc2b2c880c6 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1372,8 +1372,6 @@ options! { "set options for branch target identification and pointer authentication on AArch64"), cf_protection: CFProtection = (CFProtection::None, parse_cfprotection, [TRACKED], "instrument control-flow architecture protection"), - cgu_partitioning_strategy: Option = (None, parse_opt_string, [TRACKED], - "the codegen unit partitioning strategy to use"), codegen_backend: Option = (None, parse_opt_string, [TRACKED], "the backend to use"), combine_cgu: bool = (false, parse_bool, [TRACKED], From 66cf072ac8fa10648d5eccbacb75c7423204af1e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 30 May 2023 17:39:44 +1000 Subject: [PATCH 44/69] Merge `default.rs` into `mod.rs`. Within `compiler/rustc_monomorphize/src/partitioning/`, because the previous commit removed the need for `default.rs` to be a separate file. --- .../src/partitioning/default.rs | 637 ----------------- .../src/partitioning/mod.rs | 644 +++++++++++++++++- 2 files changed, 632 insertions(+), 649 deletions(-) delete mode 100644 compiler/rustc_monomorphize/src/partitioning/default.rs diff --git a/compiler/rustc_monomorphize/src/partitioning/default.rs b/compiler/rustc_monomorphize/src/partitioning/default.rs deleted file mode 100644 index 71cbee3b1669..000000000000 --- a/compiler/rustc_monomorphize/src/partitioning/default.rs +++ /dev/null @@ -1,637 +0,0 @@ -use std::cmp; -use std::collections::hash_map::Entry; - -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_hir::def::DefKind; -use rustc_hir::def_id::{DefId, LOCAL_CRATE}; -use rustc_hir::definitions::DefPathDataName; -use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel}; -use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, Linkage, Visibility}; -use rustc_middle::mir::mono::{InstantiationMode, MonoItem}; -use rustc_middle::ty::print::characteristic_def_id_of_type; -use rustc_middle::ty::{self, visit::TypeVisitableExt, InstanceDef, TyCtxt}; -use rustc_span::symbol::Symbol; - -use super::PartitioningCx; -use crate::collector::InliningMap; -use crate::partitioning::{MonoItemPlacement, PlacedRootMonoItems}; - -// This modules implements the default (and only) partitioning strategy. - -pub(super) fn place_root_mono_items<'tcx, I>( - cx: &PartitioningCx<'_, 'tcx>, - mono_items: &mut I, -) -> PlacedRootMonoItems<'tcx> -where - I: Iterator>, -{ - let mut roots = FxHashSet::default(); - let mut codegen_units = FxHashMap::default(); - let is_incremental_build = cx.tcx.sess.opts.incremental.is_some(); - let mut internalization_candidates = FxHashSet::default(); - - // Determine if monomorphizations instantiated in this crate will be made - // available to downstream crates. This depends on whether we are in - // share-generics mode and whether the current crate can even have - // downstream crates. - let export_generics = - cx.tcx.sess.opts.share_generics() && cx.tcx.local_crate_exports_generics(); - - let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx); - let cgu_name_cache = &mut FxHashMap::default(); - - for mono_item in mono_items { - match mono_item.instantiation_mode(cx.tcx) { - InstantiationMode::GloballyShared { .. } => {} - InstantiationMode::LocalCopy => continue, - } - - let characteristic_def_id = characteristic_def_id_of_mono_item(cx.tcx, mono_item); - let is_volatile = is_incremental_build && mono_item.is_generic_fn(); - - let codegen_unit_name = match characteristic_def_id { - Some(def_id) => compute_codegen_unit_name( - cx.tcx, - cgu_name_builder, - def_id, - is_volatile, - cgu_name_cache, - ), - None => fallback_cgu_name(cgu_name_builder), - }; - - let codegen_unit = codegen_units - .entry(codegen_unit_name) - .or_insert_with(|| CodegenUnit::new(codegen_unit_name)); - - let mut can_be_internalized = true; - let (linkage, visibility) = mono_item_linkage_and_visibility( - cx.tcx, - &mono_item, - &mut can_be_internalized, - export_generics, - ); - if visibility == Visibility::Hidden && can_be_internalized { - internalization_candidates.insert(mono_item); - } - - codegen_unit.items_mut().insert(mono_item, (linkage, visibility)); - roots.insert(mono_item); - } - - // Always ensure we have at least one CGU; otherwise, if we have a - // crate with just types (for example), we could wind up with no CGU. - if codegen_units.is_empty() { - let codegen_unit_name = fallback_cgu_name(cgu_name_builder); - codegen_units.insert(codegen_unit_name, CodegenUnit::new(codegen_unit_name)); - } - - let codegen_units = codegen_units.into_values().collect(); - PlacedRootMonoItems { codegen_units, roots, internalization_candidates } -} - -pub(super) fn merge_codegen_units<'tcx>( - cx: &PartitioningCx<'_, 'tcx>, - codegen_units: &mut Vec>, -) { - assert!(cx.target_cgu_count >= 1); - - // Note that at this point in time the `codegen_units` here may not be - // in a deterministic order (but we know they're deterministically the - // same set). We want this merging to produce a deterministic ordering - // of codegen units from the input. - // - // Due to basically how we've implemented the merging below (merge the - // two smallest into each other) we're sure to start off with a - // deterministic order (sorted by name). This'll mean that if two cgus - // have the same size the stable sort below will keep everything nice - // and deterministic. - codegen_units.sort_by(|a, b| a.name().as_str().cmp(b.name().as_str())); - - // This map keeps track of what got merged into what. - let mut cgu_contents: FxHashMap> = - codegen_units.iter().map(|cgu| (cgu.name(), vec![cgu.name()])).collect(); - - // Merge the two smallest codegen units until the target size is - // reached. - while codegen_units.len() > cx.target_cgu_count { - // Sort small cgus to the back - codegen_units.sort_by_cached_key(|cgu| cmp::Reverse(cgu.size_estimate())); - let mut smallest = codegen_units.pop().unwrap(); - let second_smallest = codegen_units.last_mut().unwrap(); - - // Move the mono-items from `smallest` to `second_smallest` - second_smallest.modify_size_estimate(smallest.size_estimate()); - for (k, v) in smallest.items_mut().drain() { - second_smallest.items_mut().insert(k, v); - } - - // Record that `second_smallest` now contains all the stuff that was - // in `smallest` before. - let mut consumed_cgu_names = cgu_contents.remove(&smallest.name()).unwrap(); - cgu_contents.get_mut(&second_smallest.name()).unwrap().append(&mut consumed_cgu_names); - - debug!( - "CodegenUnit {} merged into CodegenUnit {}", - smallest.name(), - second_smallest.name() - ); - } - - let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx); - - if cx.tcx.sess.opts.incremental.is_some() { - // If we are doing incremental compilation, we want CGU names to - // reflect the path of the source level module they correspond to. - // For CGUs that contain the code of multiple modules because of the - // merging done above, we use a concatenation of the names of all - // contained CGUs. - let new_cgu_names: FxHashMap = cgu_contents - .into_iter() - // This `filter` makes sure we only update the name of CGUs that - // were actually modified by merging. - .filter(|(_, cgu_contents)| cgu_contents.len() > 1) - .map(|(current_cgu_name, cgu_contents)| { - let mut cgu_contents: Vec<&str> = cgu_contents.iter().map(|s| s.as_str()).collect(); - - // Sort the names, so things are deterministic and easy to - // predict. We are sorting primitive `&str`s here so we can - // use unstable sort. - cgu_contents.sort_unstable(); - - (current_cgu_name, cgu_contents.join("--")) - }) - .collect(); - - for cgu in codegen_units.iter_mut() { - if let Some(new_cgu_name) = new_cgu_names.get(&cgu.name()) { - if cx.tcx.sess.opts.unstable_opts.human_readable_cgu_names { - cgu.set_name(Symbol::intern(&new_cgu_name)); - } else { - // If we don't require CGU names to be human-readable, - // we use a fixed length hash of the composite CGU name - // instead. - let new_cgu_name = CodegenUnit::mangle_name(&new_cgu_name); - cgu.set_name(Symbol::intern(&new_cgu_name)); - } - } - } - } else { - // If we are compiling non-incrementally we just generate simple CGU - // names containing an index. - for (index, cgu) in codegen_units.iter_mut().enumerate() { - let numbered_codegen_unit_name = - cgu_name_builder.build_cgu_name_no_mangle(LOCAL_CRATE, &["cgu"], Some(index)); - cgu.set_name(numbered_codegen_unit_name); - } - } -} - -pub(super) fn place_inlined_mono_items<'tcx>( - cx: &PartitioningCx<'_, 'tcx>, - codegen_units: &mut [CodegenUnit<'tcx>], - roots: FxHashSet>, -) -> FxHashMap, MonoItemPlacement> { - let mut mono_item_placements = FxHashMap::default(); - - let single_codegen_unit = codegen_units.len() == 1; - - for old_codegen_unit in codegen_units.iter_mut() { - // Collect all items that need to be available in this codegen unit. - let mut reachable = FxHashSet::default(); - for root in old_codegen_unit.items().keys() { - follow_inlining(*root, cx.inlining_map, &mut reachable); - } - - let mut new_codegen_unit = CodegenUnit::new(old_codegen_unit.name()); - - // Add all monomorphizations that are not already there. - for mono_item in reachable { - if let Some(linkage) = old_codegen_unit.items().get(&mono_item) { - // This is a root, just copy it over. - new_codegen_unit.items_mut().insert(mono_item, *linkage); - } else { - if roots.contains(&mono_item) { - bug!( - "GloballyShared mono-item inlined into other CGU: \ - {:?}", - mono_item - ); - } - - // This is a CGU-private copy. - new_codegen_unit - .items_mut() - .insert(mono_item, (Linkage::Internal, Visibility::Default)); - } - - if !single_codegen_unit { - // If there is more than one codegen unit, we need to keep track - // in which codegen units each monomorphization is placed. - match mono_item_placements.entry(mono_item) { - Entry::Occupied(e) => { - let placement = e.into_mut(); - debug_assert!(match *placement { - MonoItemPlacement::SingleCgu { cgu_name } => { - cgu_name != new_codegen_unit.name() - } - MonoItemPlacement::MultipleCgus => true, - }); - *placement = MonoItemPlacement::MultipleCgus; - } - Entry::Vacant(e) => { - e.insert(MonoItemPlacement::SingleCgu { - cgu_name: new_codegen_unit.name(), - }); - } - } - } - } - - *old_codegen_unit = new_codegen_unit; - } - - return mono_item_placements; - - fn follow_inlining<'tcx>( - mono_item: MonoItem<'tcx>, - inlining_map: &InliningMap<'tcx>, - visited: &mut FxHashSet>, - ) { - if !visited.insert(mono_item) { - return; - } - - inlining_map.with_inlining_candidates(mono_item, |target| { - follow_inlining(target, inlining_map, visited); - }); - } -} - -pub(super) fn internalize_symbols<'tcx>( - cx: &PartitioningCx<'_, 'tcx>, - codegen_units: &mut [CodegenUnit<'tcx>], - mono_item_placements: FxHashMap, MonoItemPlacement>, - internalization_candidates: FxHashSet>, -) { - if codegen_units.len() == 1 { - // Fast path for when there is only one codegen unit. In this case we - // can internalize all candidates, since there is nowhere else they - // could be accessed from. - for cgu in codegen_units { - for candidate in &internalization_candidates { - cgu.items_mut().insert(*candidate, (Linkage::Internal, Visibility::Default)); - } - } - - return; - } - - // Build a map from every monomorphization to all the monomorphizations that - // reference it. - let mut accessor_map: FxHashMap, Vec>> = Default::default(); - cx.inlining_map.iter_accesses(|accessor, accessees| { - for accessee in accessees { - accessor_map.entry(*accessee).or_default().push(accessor); - } - }); - - // For each internalization candidates in each codegen unit, check if it is - // accessed from outside its defining codegen unit. - for cgu in codegen_units { - let home_cgu = MonoItemPlacement::SingleCgu { cgu_name: cgu.name() }; - - for (accessee, linkage_and_visibility) in cgu.items_mut() { - if !internalization_candidates.contains(accessee) { - // This item is no candidate for internalizing, so skip it. - continue; - } - debug_assert_eq!(mono_item_placements[accessee], home_cgu); - - if let Some(accessors) = accessor_map.get(accessee) { - if accessors - .iter() - .filter_map(|accessor| { - // Some accessors might not have been - // instantiated. We can safely ignore those. - mono_item_placements.get(accessor) - }) - .any(|placement| *placement != home_cgu) - { - // Found an accessor from another CGU, so skip to the next - // item without marking this one as internal. - continue; - } - } - - // If we got here, we did not find any accesses from other CGUs, - // so it's fine to make this monomorphization internal. - *linkage_and_visibility = (Linkage::Internal, Visibility::Default); - } - } -} - -fn characteristic_def_id_of_mono_item<'tcx>( - tcx: TyCtxt<'tcx>, - mono_item: MonoItem<'tcx>, -) -> Option { - match mono_item { - MonoItem::Fn(instance) => { - let def_id = match instance.def { - ty::InstanceDef::Item(def) => def, - ty::InstanceDef::VTableShim(..) - | ty::InstanceDef::ReifyShim(..) - | ty::InstanceDef::FnPtrShim(..) - | ty::InstanceDef::ClosureOnceShim { .. } - | ty::InstanceDef::Intrinsic(..) - | ty::InstanceDef::DropGlue(..) - | ty::InstanceDef::Virtual(..) - | ty::InstanceDef::CloneShim(..) - | ty::InstanceDef::ThreadLocalShim(..) - | ty::InstanceDef::FnPtrAddrShim(..) => return None, - }; - - // If this is a method, we want to put it into the same module as - // its self-type. If the self-type does not provide a characteristic - // DefId, we use the location of the impl after all. - - if tcx.trait_of_item(def_id).is_some() { - let self_ty = instance.substs.type_at(0); - // This is a default implementation of a trait method. - return characteristic_def_id_of_type(self_ty).or(Some(def_id)); - } - - if let Some(impl_def_id) = tcx.impl_of_method(def_id) { - if tcx.sess.opts.incremental.is_some() - && tcx.trait_id_of_impl(impl_def_id) == tcx.lang_items().drop_trait() - { - // Put `Drop::drop` into the same cgu as `drop_in_place` - // since `drop_in_place` is the only thing that can - // call it. - return None; - } - - // When polymorphization is enabled, methods which do not depend on their generic - // parameters, but the self-type of their impl block do will fail to normalize. - if !tcx.sess.opts.unstable_opts.polymorphize || !instance.has_param() { - // This is a method within an impl, find out what the self-type is: - let impl_self_ty = tcx.subst_and_normalize_erasing_regions( - instance.substs, - ty::ParamEnv::reveal_all(), - tcx.type_of(impl_def_id), - ); - if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) { - return Some(def_id); - } - } - } - - Some(def_id) - } - MonoItem::Static(def_id) => Some(def_id), - MonoItem::GlobalAsm(item_id) => Some(item_id.owner_id.to_def_id()), - } -} - -fn compute_codegen_unit_name( - tcx: TyCtxt<'_>, - name_builder: &mut CodegenUnitNameBuilder<'_>, - def_id: DefId, - volatile: bool, - cache: &mut CguNameCache, -) -> Symbol { - // Find the innermost module that is not nested within a function. - let mut current_def_id = def_id; - let mut cgu_def_id = None; - // Walk backwards from the item we want to find the module for. - loop { - if current_def_id.is_crate_root() { - if cgu_def_id.is_none() { - // If we have not found a module yet, take the crate root. - cgu_def_id = Some(def_id.krate.as_def_id()); - } - break; - } else if tcx.def_kind(current_def_id) == DefKind::Mod { - if cgu_def_id.is_none() { - cgu_def_id = Some(current_def_id); - } - } else { - // If we encounter something that is not a module, throw away - // any module that we've found so far because we now know that - // it is nested within something else. - cgu_def_id = None; - } - - current_def_id = tcx.parent(current_def_id); - } - - let cgu_def_id = cgu_def_id.unwrap(); - - *cache.entry((cgu_def_id, volatile)).or_insert_with(|| { - let def_path = tcx.def_path(cgu_def_id); - - let components = def_path.data.iter().map(|part| match part.data.name() { - DefPathDataName::Named(name) => name, - DefPathDataName::Anon { .. } => unreachable!(), - }); - - let volatile_suffix = volatile.then_some("volatile"); - - name_builder.build_cgu_name(def_path.krate, components, volatile_suffix) - }) -} - -// Anything we can't find a proper codegen unit for goes into this. -fn fallback_cgu_name(name_builder: &mut CodegenUnitNameBuilder<'_>) -> Symbol { - name_builder.build_cgu_name(LOCAL_CRATE, &["fallback"], Some("cgu")) -} - -fn mono_item_linkage_and_visibility<'tcx>( - tcx: TyCtxt<'tcx>, - mono_item: &MonoItem<'tcx>, - can_be_internalized: &mut bool, - export_generics: bool, -) -> (Linkage, Visibility) { - if let Some(explicit_linkage) = mono_item.explicit_linkage(tcx) { - return (explicit_linkage, Visibility::Default); - } - let vis = mono_item_visibility(tcx, mono_item, can_be_internalized, export_generics); - (Linkage::External, vis) -} - -type CguNameCache = FxHashMap<(DefId, bool), Symbol>; - -fn static_visibility<'tcx>( - tcx: TyCtxt<'tcx>, - can_be_internalized: &mut bool, - def_id: DefId, -) -> Visibility { - if tcx.is_reachable_non_generic(def_id) { - *can_be_internalized = false; - default_visibility(tcx, def_id, false) - } else { - Visibility::Hidden - } -} - -fn mono_item_visibility<'tcx>( - tcx: TyCtxt<'tcx>, - mono_item: &MonoItem<'tcx>, - can_be_internalized: &mut bool, - export_generics: bool, -) -> Visibility { - let instance = match mono_item { - // This is pretty complicated; see below. - MonoItem::Fn(instance) => instance, - - // Misc handling for generics and such, but otherwise: - MonoItem::Static(def_id) => return static_visibility(tcx, can_be_internalized, *def_id), - MonoItem::GlobalAsm(item_id) => { - return static_visibility(tcx, can_be_internalized, item_id.owner_id.to_def_id()); - } - }; - - let def_id = match instance.def { - InstanceDef::Item(def_id) | InstanceDef::DropGlue(def_id, Some(_)) => def_id, - - // We match the visibility of statics here - InstanceDef::ThreadLocalShim(def_id) => { - return static_visibility(tcx, can_be_internalized, def_id); - } - - // These are all compiler glue and such, never exported, always hidden. - InstanceDef::VTableShim(..) - | InstanceDef::ReifyShim(..) - | InstanceDef::FnPtrShim(..) - | InstanceDef::Virtual(..) - | InstanceDef::Intrinsic(..) - | InstanceDef::ClosureOnceShim { .. } - | InstanceDef::DropGlue(..) - | InstanceDef::CloneShim(..) - | InstanceDef::FnPtrAddrShim(..) => return Visibility::Hidden, - }; - - // The `start_fn` lang item is actually a monomorphized instance of a - // function in the standard library, used for the `main` function. We don't - // want to export it so we tag it with `Hidden` visibility but this symbol - // is only referenced from the actual `main` symbol which we unfortunately - // don't know anything about during partitioning/collection. As a result we - // forcibly keep this symbol out of the `internalization_candidates` set. - // - // FIXME: eventually we don't want to always force this symbol to have - // hidden visibility, it should indeed be a candidate for - // internalization, but we have to understand that it's referenced - // from the `main` symbol we'll generate later. - // - // This may be fixable with a new `InstanceDef` perhaps? Unsure! - if tcx.lang_items().start_fn() == Some(def_id) { - *can_be_internalized = false; - return Visibility::Hidden; - } - - let is_generic = instance.substs.non_erasable_generics().next().is_some(); - - // Upstream `DefId` instances get different handling than local ones. - let Some(def_id) = def_id.as_local() else { - return if export_generics && is_generic { - // If it is an upstream monomorphization and we export generics, we must make - // it available to downstream crates. - *can_be_internalized = false; - default_visibility(tcx, def_id, true) - } else { - Visibility::Hidden - }; - }; - - if is_generic { - if export_generics { - if tcx.is_unreachable_local_definition(def_id) { - // This instance cannot be used from another crate. - Visibility::Hidden - } else { - // This instance might be useful in a downstream crate. - *can_be_internalized = false; - default_visibility(tcx, def_id.to_def_id(), true) - } - } else { - // We are not exporting generics or the definition is not reachable - // for downstream crates, we can internalize its instantiations. - Visibility::Hidden - } - } else { - // If this isn't a generic function then we mark this a `Default` if - // this is a reachable item, meaning that it's a symbol other crates may - // access when they link to us. - if tcx.is_reachable_non_generic(def_id.to_def_id()) { - *can_be_internalized = false; - debug_assert!(!is_generic); - return default_visibility(tcx, def_id.to_def_id(), false); - } - - // If this isn't reachable then we're gonna tag this with `Hidden` - // visibility. In some situations though we'll want to prevent this - // symbol from being internalized. - // - // There's two categories of items here: - // - // * First is weak lang items. These are basically mechanisms for - // libcore to forward-reference symbols defined later in crates like - // the standard library or `#[panic_handler]` definitions. The - // definition of these weak lang items needs to be referencable by - // libcore, so we're no longer a candidate for internalization. - // Removal of these functions can't be done by LLVM but rather must be - // done by the linker as it's a non-local decision. - // - // * Second is "std internal symbols". Currently this is primarily used - // for allocator symbols. Allocators are a little weird in their - // implementation, but the idea is that the compiler, at the last - // minute, defines an allocator with an injected object file. The - // `alloc` crate references these symbols (`__rust_alloc`) and the - // definition doesn't get hooked up until a linked crate artifact is - // generated. - // - // The symbols synthesized by the compiler (`__rust_alloc`) are thin - // veneers around the actual implementation, some other symbol which - // implements the same ABI. These symbols (things like `__rg_alloc`, - // `__rdl_alloc`, `__rde_alloc`, etc), are all tagged with "std - // internal symbols". - // - // The std-internal symbols here **should not show up in a dll as an - // exported interface**, so they return `false` from - // `is_reachable_non_generic` above and we'll give them `Hidden` - // visibility below. Like the weak lang items, though, we can't let - // LLVM internalize them as this decision is left up to the linker to - // omit them, so prevent them from being internalized. - let attrs = tcx.codegen_fn_attrs(def_id); - if attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) { - *can_be_internalized = false; - } - - Visibility::Hidden - } -} - -fn default_visibility(tcx: TyCtxt<'_>, id: DefId, is_generic: bool) -> Visibility { - if !tcx.sess.target.default_hidden_visibility { - return Visibility::Default; - } - - // Generic functions never have export-level C. - if is_generic { - return Visibility::Hidden; - } - - // Things with export level C don't get instantiated in - // downstream crates. - if !id.is_local() { - return Visibility::Hidden; - } - - // C-export level items remain at `Default`, all other internal - // items become `Hidden`. - match tcx.reachable_non_generics(id.krate).get(&id) { - Some(SymbolExportInfo { level: SymbolExportLevel::C, .. }) => Visibility::Default, - _ => Visibility::Hidden, - } -} diff --git a/compiler/rustc_monomorphize/src/partitioning/mod.rs b/compiler/rustc_monomorphize/src/partitioning/mod.rs index 2843c361e0ac..be9c349c3841 100644 --- a/compiler/rustc_monomorphize/src/partitioning/mod.rs +++ b/compiler/rustc_monomorphize/src/partitioning/mod.rs @@ -92,22 +92,26 @@ //! source-level module, functions from the same module will be available for //! inlining, even when they are not marked `#[inline]`. -mod default; - use std::cmp; +use std::collections::hash_map::Entry; use std::fs::{self, File}; use std::io::{BufWriter, Write}; use std::path::{Path, PathBuf}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync; -use rustc_hir::def_id::{DefIdSet, LOCAL_CRATE}; +use rustc_hir::def::DefKind; +use rustc_hir::def_id::{DefId, DefIdSet, LOCAL_CRATE}; +use rustc_hir::definitions::DefPathDataName; +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel}; use rustc_middle::mir; -use rustc_middle::mir::mono::MonoItem; -use rustc_middle::mir::mono::{CodegenUnit, Linkage}; +use rustc_middle::mir::mono::{ + CodegenUnit, CodegenUnitNameBuilder, InstantiationMode, Linkage, MonoItem, Visibility, +}; use rustc_middle::query::Providers; -use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::print::{characteristic_def_id_of_type, with_no_trimmed_paths}; +use rustc_middle::ty::{self, visit::TypeVisitableExt, InstanceDef, TyCtxt}; use rustc_session::config::{DumpMonoStatsFormat, SwitchWithOptPath}; use rustc_span::symbol::Symbol; @@ -121,7 +125,7 @@ struct PartitioningCx<'a, 'tcx> { inlining_map: &'a InliningMap<'tcx>, } -pub struct PlacedRootMonoItems<'tcx> { +struct PlacedRootMonoItems<'tcx> { codegen_units: Vec>, roots: FxHashSet>, internalization_candidates: FxHashSet>, @@ -144,7 +148,7 @@ where // functions and statics defined in the local crate. let PlacedRootMonoItems { mut codegen_units, roots, internalization_candidates } = { let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_roots"); - default::place_root_mono_items(cx, mono_items) + place_root_mono_items(cx, mono_items) }; for cgu in &mut codegen_units { @@ -158,7 +162,7 @@ where // estimates. { let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_merge_cgus"); - default::merge_codegen_units(cx, &mut codegen_units); + merge_codegen_units(cx, &mut codegen_units); debug_dump(tcx, "POST MERGING", &codegen_units); } @@ -168,7 +172,7 @@ where // local functions the definition of which is marked with `#[inline]`. let mono_item_placements = { let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_inline_items"); - default::place_inlined_mono_items(cx, &mut codegen_units, roots) + place_inlined_mono_items(cx, &mut codegen_units, roots) }; for cgu in &mut codegen_units { @@ -181,7 +185,7 @@ where // more freedom to optimize. if !tcx.sess.link_dead_code() { let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_internalize_symbols"); - default::internalize_symbols( + internalize_symbols( cx, &mut codegen_units, mono_item_placements, @@ -229,6 +233,175 @@ where codegen_units } +fn place_root_mono_items<'tcx, I>( + cx: &PartitioningCx<'_, 'tcx>, + mono_items: &mut I, +) -> PlacedRootMonoItems<'tcx> +where + I: Iterator>, +{ + let mut roots = FxHashSet::default(); + let mut codegen_units = FxHashMap::default(); + let is_incremental_build = cx.tcx.sess.opts.incremental.is_some(); + let mut internalization_candidates = FxHashSet::default(); + + // Determine if monomorphizations instantiated in this crate will be made + // available to downstream crates. This depends on whether we are in + // share-generics mode and whether the current crate can even have + // downstream crates. + let export_generics = + cx.tcx.sess.opts.share_generics() && cx.tcx.local_crate_exports_generics(); + + let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx); + let cgu_name_cache = &mut FxHashMap::default(); + + for mono_item in mono_items { + match mono_item.instantiation_mode(cx.tcx) { + InstantiationMode::GloballyShared { .. } => {} + InstantiationMode::LocalCopy => continue, + } + + let characteristic_def_id = characteristic_def_id_of_mono_item(cx.tcx, mono_item); + let is_volatile = is_incremental_build && mono_item.is_generic_fn(); + + let codegen_unit_name = match characteristic_def_id { + Some(def_id) => compute_codegen_unit_name( + cx.tcx, + cgu_name_builder, + def_id, + is_volatile, + cgu_name_cache, + ), + None => fallback_cgu_name(cgu_name_builder), + }; + + let codegen_unit = codegen_units + .entry(codegen_unit_name) + .or_insert_with(|| CodegenUnit::new(codegen_unit_name)); + + let mut can_be_internalized = true; + let (linkage, visibility) = mono_item_linkage_and_visibility( + cx.tcx, + &mono_item, + &mut can_be_internalized, + export_generics, + ); + if visibility == Visibility::Hidden && can_be_internalized { + internalization_candidates.insert(mono_item); + } + + codegen_unit.items_mut().insert(mono_item, (linkage, visibility)); + roots.insert(mono_item); + } + + // Always ensure we have at least one CGU; otherwise, if we have a + // crate with just types (for example), we could wind up with no CGU. + if codegen_units.is_empty() { + let codegen_unit_name = fallback_cgu_name(cgu_name_builder); + codegen_units.insert(codegen_unit_name, CodegenUnit::new(codegen_unit_name)); + } + + let codegen_units = codegen_units.into_values().collect(); + PlacedRootMonoItems { codegen_units, roots, internalization_candidates } +} + +fn merge_codegen_units<'tcx>( + cx: &PartitioningCx<'_, 'tcx>, + codegen_units: &mut Vec>, +) { + assert!(cx.target_cgu_count >= 1); + + // Note that at this point in time the `codegen_units` here may not be + // in a deterministic order (but we know they're deterministically the + // same set). We want this merging to produce a deterministic ordering + // of codegen units from the input. + // + // Due to basically how we've implemented the merging below (merge the + // two smallest into each other) we're sure to start off with a + // deterministic order (sorted by name). This'll mean that if two cgus + // have the same size the stable sort below will keep everything nice + // and deterministic. + codegen_units.sort_by(|a, b| a.name().as_str().cmp(b.name().as_str())); + + // This map keeps track of what got merged into what. + let mut cgu_contents: FxHashMap> = + codegen_units.iter().map(|cgu| (cgu.name(), vec![cgu.name()])).collect(); + + // Merge the two smallest codegen units until the target size is + // reached. + while codegen_units.len() > cx.target_cgu_count { + // Sort small cgus to the back + codegen_units.sort_by_cached_key(|cgu| cmp::Reverse(cgu.size_estimate())); + let mut smallest = codegen_units.pop().unwrap(); + let second_smallest = codegen_units.last_mut().unwrap(); + + // Move the mono-items from `smallest` to `second_smallest` + second_smallest.modify_size_estimate(smallest.size_estimate()); + for (k, v) in smallest.items_mut().drain() { + second_smallest.items_mut().insert(k, v); + } + + // Record that `second_smallest` now contains all the stuff that was + // in `smallest` before. + let mut consumed_cgu_names = cgu_contents.remove(&smallest.name()).unwrap(); + cgu_contents.get_mut(&second_smallest.name()).unwrap().append(&mut consumed_cgu_names); + + debug!( + "CodegenUnit {} merged into CodegenUnit {}", + smallest.name(), + second_smallest.name() + ); + } + + let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx); + + if cx.tcx.sess.opts.incremental.is_some() { + // If we are doing incremental compilation, we want CGU names to + // reflect the path of the source level module they correspond to. + // For CGUs that contain the code of multiple modules because of the + // merging done above, we use a concatenation of the names of all + // contained CGUs. + let new_cgu_names: FxHashMap = cgu_contents + .into_iter() + // This `filter` makes sure we only update the name of CGUs that + // were actually modified by merging. + .filter(|(_, cgu_contents)| cgu_contents.len() > 1) + .map(|(current_cgu_name, cgu_contents)| { + let mut cgu_contents: Vec<&str> = cgu_contents.iter().map(|s| s.as_str()).collect(); + + // Sort the names, so things are deterministic and easy to + // predict. We are sorting primitive `&str`s here so we can + // use unstable sort. + cgu_contents.sort_unstable(); + + (current_cgu_name, cgu_contents.join("--")) + }) + .collect(); + + for cgu in codegen_units.iter_mut() { + if let Some(new_cgu_name) = new_cgu_names.get(&cgu.name()) { + if cx.tcx.sess.opts.unstable_opts.human_readable_cgu_names { + cgu.set_name(Symbol::intern(&new_cgu_name)); + } else { + // If we don't require CGU names to be human-readable, + // we use a fixed length hash of the composite CGU name + // instead. + let new_cgu_name = CodegenUnit::mangle_name(&new_cgu_name); + cgu.set_name(Symbol::intern(&new_cgu_name)); + } + } + } + } else { + // If we are compiling non-incrementally we just generate simple CGU + // names containing an index. + for (index, cgu) in codegen_units.iter_mut().enumerate() { + let numbered_codegen_unit_name = + cgu_name_builder.build_cgu_name_no_mangle(LOCAL_CRATE, &["cgu"], Some(index)); + cgu.set_name(numbered_codegen_unit_name); + } + } +} + /// For symbol internalization, we need to know whether a symbol/mono-item is /// accessed from outside the codegen unit it is defined in. This type is used /// to keep track of that. @@ -238,6 +411,453 @@ enum MonoItemPlacement { MultipleCgus, } +fn place_inlined_mono_items<'tcx>( + cx: &PartitioningCx<'_, 'tcx>, + codegen_units: &mut [CodegenUnit<'tcx>], + roots: FxHashSet>, +) -> FxHashMap, MonoItemPlacement> { + let mut mono_item_placements = FxHashMap::default(); + + let single_codegen_unit = codegen_units.len() == 1; + + for old_codegen_unit in codegen_units.iter_mut() { + // Collect all items that need to be available in this codegen unit. + let mut reachable = FxHashSet::default(); + for root in old_codegen_unit.items().keys() { + follow_inlining(*root, cx.inlining_map, &mut reachable); + } + + let mut new_codegen_unit = CodegenUnit::new(old_codegen_unit.name()); + + // Add all monomorphizations that are not already there. + for mono_item in reachable { + if let Some(linkage) = old_codegen_unit.items().get(&mono_item) { + // This is a root, just copy it over. + new_codegen_unit.items_mut().insert(mono_item, *linkage); + } else { + if roots.contains(&mono_item) { + bug!( + "GloballyShared mono-item inlined into other CGU: \ + {:?}", + mono_item + ); + } + + // This is a CGU-private copy. + new_codegen_unit + .items_mut() + .insert(mono_item, (Linkage::Internal, Visibility::Default)); + } + + if !single_codegen_unit { + // If there is more than one codegen unit, we need to keep track + // in which codegen units each monomorphization is placed. + match mono_item_placements.entry(mono_item) { + Entry::Occupied(e) => { + let placement = e.into_mut(); + debug_assert!(match *placement { + MonoItemPlacement::SingleCgu { cgu_name } => { + cgu_name != new_codegen_unit.name() + } + MonoItemPlacement::MultipleCgus => true, + }); + *placement = MonoItemPlacement::MultipleCgus; + } + Entry::Vacant(e) => { + e.insert(MonoItemPlacement::SingleCgu { + cgu_name: new_codegen_unit.name(), + }); + } + } + } + } + + *old_codegen_unit = new_codegen_unit; + } + + return mono_item_placements; + + fn follow_inlining<'tcx>( + mono_item: MonoItem<'tcx>, + inlining_map: &InliningMap<'tcx>, + visited: &mut FxHashSet>, + ) { + if !visited.insert(mono_item) { + return; + } + + inlining_map.with_inlining_candidates(mono_item, |target| { + follow_inlining(target, inlining_map, visited); + }); + } +} + +fn internalize_symbols<'tcx>( + cx: &PartitioningCx<'_, 'tcx>, + codegen_units: &mut [CodegenUnit<'tcx>], + mono_item_placements: FxHashMap, MonoItemPlacement>, + internalization_candidates: FxHashSet>, +) { + if codegen_units.len() == 1 { + // Fast path for when there is only one codegen unit. In this case we + // can internalize all candidates, since there is nowhere else they + // could be accessed from. + for cgu in codegen_units { + for candidate in &internalization_candidates { + cgu.items_mut().insert(*candidate, (Linkage::Internal, Visibility::Default)); + } + } + + return; + } + + // Build a map from every monomorphization to all the monomorphizations that + // reference it. + let mut accessor_map: FxHashMap, Vec>> = Default::default(); + cx.inlining_map.iter_accesses(|accessor, accessees| { + for accessee in accessees { + accessor_map.entry(*accessee).or_default().push(accessor); + } + }); + + // For each internalization candidates in each codegen unit, check if it is + // accessed from outside its defining codegen unit. + for cgu in codegen_units { + let home_cgu = MonoItemPlacement::SingleCgu { cgu_name: cgu.name() }; + + for (accessee, linkage_and_visibility) in cgu.items_mut() { + if !internalization_candidates.contains(accessee) { + // This item is no candidate for internalizing, so skip it. + continue; + } + debug_assert_eq!(mono_item_placements[accessee], home_cgu); + + if let Some(accessors) = accessor_map.get(accessee) { + if accessors + .iter() + .filter_map(|accessor| { + // Some accessors might not have been + // instantiated. We can safely ignore those. + mono_item_placements.get(accessor) + }) + .any(|placement| *placement != home_cgu) + { + // Found an accessor from another CGU, so skip to the next + // item without marking this one as internal. + continue; + } + } + + // If we got here, we did not find any accesses from other CGUs, + // so it's fine to make this monomorphization internal. + *linkage_and_visibility = (Linkage::Internal, Visibility::Default); + } + } +} + +fn characteristic_def_id_of_mono_item<'tcx>( + tcx: TyCtxt<'tcx>, + mono_item: MonoItem<'tcx>, +) -> Option { + match mono_item { + MonoItem::Fn(instance) => { + let def_id = match instance.def { + ty::InstanceDef::Item(def) => def, + ty::InstanceDef::VTableShim(..) + | ty::InstanceDef::ReifyShim(..) + | ty::InstanceDef::FnPtrShim(..) + | ty::InstanceDef::ClosureOnceShim { .. } + | ty::InstanceDef::Intrinsic(..) + | ty::InstanceDef::DropGlue(..) + | ty::InstanceDef::Virtual(..) + | ty::InstanceDef::CloneShim(..) + | ty::InstanceDef::ThreadLocalShim(..) + | ty::InstanceDef::FnPtrAddrShim(..) => return None, + }; + + // If this is a method, we want to put it into the same module as + // its self-type. If the self-type does not provide a characteristic + // DefId, we use the location of the impl after all. + + if tcx.trait_of_item(def_id).is_some() { + let self_ty = instance.substs.type_at(0); + // This is a default implementation of a trait method. + return characteristic_def_id_of_type(self_ty).or(Some(def_id)); + } + + if let Some(impl_def_id) = tcx.impl_of_method(def_id) { + if tcx.sess.opts.incremental.is_some() + && tcx.trait_id_of_impl(impl_def_id) == tcx.lang_items().drop_trait() + { + // Put `Drop::drop` into the same cgu as `drop_in_place` + // since `drop_in_place` is the only thing that can + // call it. + return None; + } + + // When polymorphization is enabled, methods which do not depend on their generic + // parameters, but the self-type of their impl block do will fail to normalize. + if !tcx.sess.opts.unstable_opts.polymorphize || !instance.has_param() { + // This is a method within an impl, find out what the self-type is: + let impl_self_ty = tcx.subst_and_normalize_erasing_regions( + instance.substs, + ty::ParamEnv::reveal_all(), + tcx.type_of(impl_def_id), + ); + if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) { + return Some(def_id); + } + } + } + + Some(def_id) + } + MonoItem::Static(def_id) => Some(def_id), + MonoItem::GlobalAsm(item_id) => Some(item_id.owner_id.to_def_id()), + } +} + +fn compute_codegen_unit_name( + tcx: TyCtxt<'_>, + name_builder: &mut CodegenUnitNameBuilder<'_>, + def_id: DefId, + volatile: bool, + cache: &mut CguNameCache, +) -> Symbol { + // Find the innermost module that is not nested within a function. + let mut current_def_id = def_id; + let mut cgu_def_id = None; + // Walk backwards from the item we want to find the module for. + loop { + if current_def_id.is_crate_root() { + if cgu_def_id.is_none() { + // If we have not found a module yet, take the crate root. + cgu_def_id = Some(def_id.krate.as_def_id()); + } + break; + } else if tcx.def_kind(current_def_id) == DefKind::Mod { + if cgu_def_id.is_none() { + cgu_def_id = Some(current_def_id); + } + } else { + // If we encounter something that is not a module, throw away + // any module that we've found so far because we now know that + // it is nested within something else. + cgu_def_id = None; + } + + current_def_id = tcx.parent(current_def_id); + } + + let cgu_def_id = cgu_def_id.unwrap(); + + *cache.entry((cgu_def_id, volatile)).or_insert_with(|| { + let def_path = tcx.def_path(cgu_def_id); + + let components = def_path.data.iter().map(|part| match part.data.name() { + DefPathDataName::Named(name) => name, + DefPathDataName::Anon { .. } => unreachable!(), + }); + + let volatile_suffix = volatile.then_some("volatile"); + + name_builder.build_cgu_name(def_path.krate, components, volatile_suffix) + }) +} + +// Anything we can't find a proper codegen unit for goes into this. +fn fallback_cgu_name(name_builder: &mut CodegenUnitNameBuilder<'_>) -> Symbol { + name_builder.build_cgu_name(LOCAL_CRATE, &["fallback"], Some("cgu")) +} + +fn mono_item_linkage_and_visibility<'tcx>( + tcx: TyCtxt<'tcx>, + mono_item: &MonoItem<'tcx>, + can_be_internalized: &mut bool, + export_generics: bool, +) -> (Linkage, Visibility) { + if let Some(explicit_linkage) = mono_item.explicit_linkage(tcx) { + return (explicit_linkage, Visibility::Default); + } + let vis = mono_item_visibility(tcx, mono_item, can_be_internalized, export_generics); + (Linkage::External, vis) +} + +type CguNameCache = FxHashMap<(DefId, bool), Symbol>; + +fn static_visibility<'tcx>( + tcx: TyCtxt<'tcx>, + can_be_internalized: &mut bool, + def_id: DefId, +) -> Visibility { + if tcx.is_reachable_non_generic(def_id) { + *can_be_internalized = false; + default_visibility(tcx, def_id, false) + } else { + Visibility::Hidden + } +} + +fn mono_item_visibility<'tcx>( + tcx: TyCtxt<'tcx>, + mono_item: &MonoItem<'tcx>, + can_be_internalized: &mut bool, + export_generics: bool, +) -> Visibility { + let instance = match mono_item { + // This is pretty complicated; see below. + MonoItem::Fn(instance) => instance, + + // Misc handling for generics and such, but otherwise: + MonoItem::Static(def_id) => return static_visibility(tcx, can_be_internalized, *def_id), + MonoItem::GlobalAsm(item_id) => { + return static_visibility(tcx, can_be_internalized, item_id.owner_id.to_def_id()); + } + }; + + let def_id = match instance.def { + InstanceDef::Item(def_id) | InstanceDef::DropGlue(def_id, Some(_)) => def_id, + + // We match the visibility of statics here + InstanceDef::ThreadLocalShim(def_id) => { + return static_visibility(tcx, can_be_internalized, def_id); + } + + // These are all compiler glue and such, never exported, always hidden. + InstanceDef::VTableShim(..) + | InstanceDef::ReifyShim(..) + | InstanceDef::FnPtrShim(..) + | InstanceDef::Virtual(..) + | InstanceDef::Intrinsic(..) + | InstanceDef::ClosureOnceShim { .. } + | InstanceDef::DropGlue(..) + | InstanceDef::CloneShim(..) + | InstanceDef::FnPtrAddrShim(..) => return Visibility::Hidden, + }; + + // The `start_fn` lang item is actually a monomorphized instance of a + // function in the standard library, used for the `main` function. We don't + // want to export it so we tag it with `Hidden` visibility but this symbol + // is only referenced from the actual `main` symbol which we unfortunately + // don't know anything about during partitioning/collection. As a result we + // forcibly keep this symbol out of the `internalization_candidates` set. + // + // FIXME: eventually we don't want to always force this symbol to have + // hidden visibility, it should indeed be a candidate for + // internalization, but we have to understand that it's referenced + // from the `main` symbol we'll generate later. + // + // This may be fixable with a new `InstanceDef` perhaps? Unsure! + if tcx.lang_items().start_fn() == Some(def_id) { + *can_be_internalized = false; + return Visibility::Hidden; + } + + let is_generic = instance.substs.non_erasable_generics().next().is_some(); + + // Upstream `DefId` instances get different handling than local ones. + let Some(def_id) = def_id.as_local() else { + return if export_generics && is_generic { + // If it is an upstream monomorphization and we export generics, we must make + // it available to downstream crates. + *can_be_internalized = false; + default_visibility(tcx, def_id, true) + } else { + Visibility::Hidden + }; + }; + + if is_generic { + if export_generics { + if tcx.is_unreachable_local_definition(def_id) { + // This instance cannot be used from another crate. + Visibility::Hidden + } else { + // This instance might be useful in a downstream crate. + *can_be_internalized = false; + default_visibility(tcx, def_id.to_def_id(), true) + } + } else { + // We are not exporting generics or the definition is not reachable + // for downstream crates, we can internalize its instantiations. + Visibility::Hidden + } + } else { + // If this isn't a generic function then we mark this a `Default` if + // this is a reachable item, meaning that it's a symbol other crates may + // access when they link to us. + if tcx.is_reachable_non_generic(def_id.to_def_id()) { + *can_be_internalized = false; + debug_assert!(!is_generic); + return default_visibility(tcx, def_id.to_def_id(), false); + } + + // If this isn't reachable then we're gonna tag this with `Hidden` + // visibility. In some situations though we'll want to prevent this + // symbol from being internalized. + // + // There's two categories of items here: + // + // * First is weak lang items. These are basically mechanisms for + // libcore to forward-reference symbols defined later in crates like + // the standard library or `#[panic_handler]` definitions. The + // definition of these weak lang items needs to be referencable by + // libcore, so we're no longer a candidate for internalization. + // Removal of these functions can't be done by LLVM but rather must be + // done by the linker as it's a non-local decision. + // + // * Second is "std internal symbols". Currently this is primarily used + // for allocator symbols. Allocators are a little weird in their + // implementation, but the idea is that the compiler, at the last + // minute, defines an allocator with an injected object file. The + // `alloc` crate references these symbols (`__rust_alloc`) and the + // definition doesn't get hooked up until a linked crate artifact is + // generated. + // + // The symbols synthesized by the compiler (`__rust_alloc`) are thin + // veneers around the actual implementation, some other symbol which + // implements the same ABI. These symbols (things like `__rg_alloc`, + // `__rdl_alloc`, `__rde_alloc`, etc), are all tagged with "std + // internal symbols". + // + // The std-internal symbols here **should not show up in a dll as an + // exported interface**, so they return `false` from + // `is_reachable_non_generic` above and we'll give them `Hidden` + // visibility below. Like the weak lang items, though, we can't let + // LLVM internalize them as this decision is left up to the linker to + // omit them, so prevent them from being internalized. + let attrs = tcx.codegen_fn_attrs(def_id); + if attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) { + *can_be_internalized = false; + } + + Visibility::Hidden + } +} + +fn default_visibility(tcx: TyCtxt<'_>, id: DefId, is_generic: bool) -> Visibility { + if !tcx.sess.target.default_hidden_visibility { + return Visibility::Default; + } + + // Generic functions never have export-level C. + if is_generic { + return Visibility::Hidden; + } + + // Things with export level C don't get instantiated in + // downstream crates. + if !id.is_local() { + return Visibility::Hidden; + } + + // C-export level items remain at `Default`, all other internal + // items become `Hidden`. + match tcx.reachable_non_generics(id.krate).get(&id) { + Some(SymbolExportInfo { level: SymbolExportLevel::C, .. }) => Visibility::Default, + _ => Visibility::Hidden, + } +} fn debug_dump<'a, 'tcx: 'a>(tcx: TyCtxt<'tcx>, label: &str, cgus: &[CodegenUnit<'tcx>]) { let dump = move || { use std::fmt::Write; From 5ed014977e59f886a51844fcae8eab80467e45e6 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 30 May 2023 17:41:35 +1000 Subject: [PATCH 45/69] Rename `partitioning/mod.rs` as `partitioning.rs`. Because it's now the only file within `compiler/rustc_monomorphize/src/partitioning/`. --- .../src/{partitioning/mod.rs => partitioning.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename compiler/rustc_monomorphize/src/{partitioning/mod.rs => partitioning.rs} (100%) diff --git a/compiler/rustc_monomorphize/src/partitioning/mod.rs b/compiler/rustc_monomorphize/src/partitioning.rs similarity index 100% rename from compiler/rustc_monomorphize/src/partitioning/mod.rs rename to compiler/rustc_monomorphize/src/partitioning.rs From 2803c66006b37a12c16e15cdb9873565f4c585d2 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Tue, 30 May 2023 10:53:46 +0300 Subject: [PATCH 46/69] create `build_helper/src/util` mod Signed-off-by: ozkanonur --- src/bootstrap/builder.rs | 4 +-- src/bootstrap/compile.rs | 2 +- src/bootstrap/config.rs | 13 +++++----- src/bootstrap/download.rs | 5 ++-- src/bootstrap/flags.rs | 4 +-- src/bootstrap/format.rs | 4 +-- src/bootstrap/lib.rs | 19 +++----------- src/bootstrap/render_tests.rs | 2 +- src/bootstrap/sanity.rs | 2 +- src/bootstrap/setup.rs | 4 +-- src/bootstrap/test.rs | 8 +++--- src/bootstrap/tool.rs | 2 +- src/bootstrap/toolstate.rs | 8 +++--- src/bootstrap/util.rs | 25 +++--------------- src/tools/build_helper/src/lib.rs | 1 + src/tools/build_helper/src/util.rs | 41 ++++++++++++++++++++++++++++++ 16 files changed, 79 insertions(+), 65 deletions(-) create mode 100644 src/tools/build_helper/src/util.rs diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 2fa445506bc4..90f2ac6ffcaf 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -378,7 +378,7 @@ impl StepDescription { eprintln!( "note: if you are adding a new Step to bootstrap itself, make sure you register it with `describe!`" ); - crate::detail_exit(1); + crate::detail_exit_macro!(1); } } } @@ -1357,7 +1357,7 @@ impl<'a> Builder<'a> { "error: `x.py clippy` requires a host `rustc` toolchain with the `clippy` component" ); eprintln!("help: try `rustup component add clippy`"); - crate::detail_exit(1); + crate::detail_exit_macro!(1); }); if !t!(std::str::from_utf8(&output.stdout)).contains("nightly") { rustflags.arg("--cfg=bootstrap"); diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 33addb90da37..79295ecab38a 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -1679,7 +1679,7 @@ pub fn run_cargo( }); if !ok { - crate::detail_exit(1); + crate::detail_exit_macro!(1); } // Ok now we need to actually find all the files listed in `toplevel`. We've diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 41aca0210f67..45ad1547eb77 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -23,6 +23,7 @@ use crate::channel::{self, GitInfo}; pub use crate::flags::Subcommand; use crate::flags::{Color, Flags, Warnings}; use crate::util::{exe, output, t}; +use build_helper::detail_exit_macro; use once_cell::sync::OnceCell; use serde::{Deserialize, Deserializer}; use serde_derive::Deserialize; @@ -579,7 +580,7 @@ macro_rules! define_config { panic!("overriding existing option") } else { eprintln!("overriding existing option: `{}`", stringify!($field)); - crate::detail_exit(2); + detail_exit_macro!(2); } } else { self.$field = other.$field; @@ -678,7 +679,7 @@ impl Merge for Option { panic!("overriding existing option") } else { eprintln!("overriding existing option"); - crate::detail_exit(2); + detail_exit_macro!(2); } } else { *self = other; @@ -944,7 +945,7 @@ impl Config { .and_then(|table: toml::Value| TomlConfig::deserialize(table)) .unwrap_or_else(|err| { eprintln!("failed to parse TOML configuration '{}': {err}", file.display()); - crate::detail_exit(2); + detail_exit_macro!(2); }) } Self::parse_inner(args, get_toml) @@ -978,7 +979,7 @@ impl Config { eprintln!( "Cannot use both `llvm_bolt_profile_generate` and `llvm_bolt_profile_use` at the same time" ); - crate::detail_exit(1); + detail_exit_macro!(1); } // Infer the rest of the configuration. @@ -1094,7 +1095,7 @@ impl Config { } } eprintln!("failed to parse override `{option}`: `{err}"); - crate::detail_exit(2) + detail_exit_macro!(2) } toml.merge(override_toml, ReplaceOpt::Override); @@ -1810,7 +1811,7 @@ impl Config { println!("help: maybe your repository history is too shallow?"); println!("help: consider disabling `download-rustc`"); println!("help: or fetch enough history to include one upstream commit"); - crate::detail_exit(1); + crate::detail_exit_macro!(1); } // Warn if there were changes to the compiler or standard library since the ancestor commit. diff --git a/src/bootstrap/download.rs b/src/bootstrap/download.rs index c7969d2a2c7b..12780df21757 100644 --- a/src/bootstrap/download.rs +++ b/src/bootstrap/download.rs @@ -7,6 +7,7 @@ use std::{ process::{Command, Stdio}, }; +use build_helper::util::try_run; use once_cell::sync::OnceCell; use xz2::bufread::XzDecoder; @@ -14,7 +15,7 @@ use crate::{ config::RustfmtMetadata, llvm::detect_llvm_sha, t, - util::{check_run, exe, program_out_of_date, try_run}, + util::{check_run, exe, program_out_of_date}, Config, }; @@ -245,7 +246,7 @@ impl Config { if !help_on_error.is_empty() { eprintln!("{}", help_on_error); } - crate::detail_exit(1); + crate::detail_exit_macro!(1); } } diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 80e715777984..dc05f47ee9cd 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -193,7 +193,7 @@ impl Flags { } else { panic!("No paths available for subcommand `{}`", subcommand.as_str()); } - crate::detail_exit(0); + crate::detail_exit_macro!(0); } Flags::parse_from(it) @@ -538,7 +538,7 @@ pub fn get_completion(shell: G, path: &Path) -> Opt } else { std::fs::read_to_string(path).unwrap_or_else(|_| { eprintln!("couldn't read {}", path.display()); - crate::detail_exit(1) + crate::detail_exit_macro!(1) }) }; let mut buf = Vec::new(); diff --git a/src/bootstrap/format.rs b/src/bootstrap/format.rs index d8d3f300a350..ebf068b2cb16 100644 --- a/src/bootstrap/format.rs +++ b/src/bootstrap/format.rs @@ -40,7 +40,7 @@ fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl F code, run `./x.py fmt` instead.", cmd_debug, ); - crate::detail_exit(1); + crate::detail_exit_macro!(1); } true } @@ -196,7 +196,7 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) { let rustfmt_path = build.initial_rustfmt().unwrap_or_else(|| { eprintln!("./x.py fmt is not supported on this channel"); - crate::detail_exit(1); + crate::detail_exit_macro!(1); }); assert!(rustfmt_path.exists(), "{}", rustfmt_path.display()); let src = build.src.clone(); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index fb76dffd0715..3c56787b65eb 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -27,6 +27,7 @@ use std::process::{Command, Stdio}; use std::str; use build_helper::ci::{gha, CiEnv}; +use build_helper::detail_exit_macro; use channel::GitInfo; use config::{DryRun, Target}; use filetime::FileTime; @@ -699,7 +700,7 @@ impl Build { for failure in failures.iter() { eprintln!(" - {}\n", failure); } - detail_exit(1); + detail_exit_macro!(1); } #[cfg(feature = "build-metrics")] @@ -1482,7 +1483,7 @@ impl Build { "Error: Unable to find the stamp file {}, did you try to keep a nonexistent build stage?", stamp.display() ); - crate::detail_exit(1); + crate::detail_exit_macro!(1); } let mut paths = Vec::new(); @@ -1674,7 +1675,7 @@ Alternatively, set `download-ci-llvm = true` in that `[llvm]` section to download LLVM rather than building it. " ); - detail_exit(1); + detail_exit_macro!(1); } } @@ -1739,18 +1740,6 @@ fn chmod(path: &Path, perms: u32) { #[cfg(windows)] fn chmod(_path: &Path, _perms: u32) {} -/// If code is not 0 (successful exit status), exit status is 101 (rust's default error code.) -/// If the test is running and code is an error code, it will cause a panic. -fn detail_exit(code: i32) -> ! { - // if in test and code is an error code, panic with status code provided - if cfg!(test) { - panic!("status code: {}", code); - } else { - // otherwise,exit with provided status code - std::process::exit(code); - } -} - impl Compiler { pub fn with_stage(mut self, stage: u32) -> Compiler { self.stage = stage; diff --git a/src/bootstrap/render_tests.rs b/src/bootstrap/render_tests.rs index fa0a4806618b..872b75f6c159 100644 --- a/src/bootstrap/render_tests.rs +++ b/src/bootstrap/render_tests.rs @@ -30,7 +30,7 @@ pub(crate) fn try_run_tests(builder: &Builder<'_>, cmd: &mut Command) -> bool { if !run_tests(builder, cmd) { if builder.fail_fast { - crate::detail_exit(1); + crate::detail_exit_macro!(1); } else { let mut failures = builder.delayed_failures.borrow_mut(); failures.push(format!("{cmd:?}")); diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index 140259b02135..8f5ba42736b1 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -104,7 +104,7 @@ You should install cmake, or set `download-ci-llvm = true` in the than building it. " ); - crate::detail_exit(1); + crate::detail_exit_macro!(1); } } diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs index 09f26862b4ab..40038df83321 100644 --- a/src/bootstrap/setup.rs +++ b/src/bootstrap/setup.rs @@ -194,7 +194,7 @@ fn setup_config_toml(path: &PathBuf, profile: Profile, config: &Config) { "note: this will use the configuration in {}", profile.include_path(&config.src).display() ); - crate::detail_exit(1); + crate::detail_exit_macro!(1); } let settings = format!( @@ -380,7 +380,7 @@ pub fn interactive_path() -> io::Result { io::stdin().read_line(&mut input)?; if input.is_empty() { eprintln!("EOF on stdin, when expecting answer to question. Giving up."); - crate::detail_exit(1); + crate::detail_exit_macro!(1); } break match parse_with_abbrev(&input) { Ok(profile) => profile, diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 44cd84be705a..7ea4919267ee 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -773,7 +773,7 @@ impl Step for Clippy { } if !builder.config.cmd.bless() { - crate::detail_exit(1); + crate::detail_exit_macro!(1); } let mut cargo = builder.cargo(compiler, Mode::ToolRustc, SourceType::InTree, host, "run"); @@ -1085,7 +1085,7 @@ help: to skip test's attempt to check tidiness, pass `--exclude src/tools/tidy` PATH = inferred_rustfmt_dir.display(), CHAN = builder.config.channel, ); - crate::detail_exit(1); + crate::detail_exit_macro!(1); } crate::format::format(&builder, !builder.config.cmd.bless(), &[]); } @@ -1108,7 +1108,7 @@ help: to skip test's attempt to check tidiness, pass `--exclude src/tools/tidy` eprintln!( "x.py completions were changed; run `x.py run generate-completions` to update them" ); - crate::detail_exit(1); + crate::detail_exit_macro!(1); } } } @@ -1329,7 +1329,7 @@ help: to test the compiler, use `--stage 1` instead help: to test the standard library, use `--stage 0 library/std` instead note: if you're sure you want to do this, please open an issue as to why. In the meantime, you can override this with `COMPILETEST_FORCE_STAGE0=1`." ); - crate::detail_exit(1); + crate::detail_exit_macro!(1); } let mut compiler = self.compiler; diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index b3791efaf58c..0f0a3bb8775d 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -116,7 +116,7 @@ impl Step for ToolBuild { if !is_expected { if !is_optional_tool { - crate::detail_exit(1); + crate::detail_exit_macro!(1); } else { None } diff --git a/src/bootstrap/toolstate.rs b/src/bootstrap/toolstate.rs index 7aab88a1a736..9c4d0ea265dd 100644 --- a/src/bootstrap/toolstate.rs +++ b/src/bootstrap/toolstate.rs @@ -91,7 +91,7 @@ fn print_error(tool: &str, submodule: &str) { eprintln!("If you do NOT intend to update '{}', please ensure you did not accidentally", tool); eprintln!("change the submodule at '{}'. You may ask your reviewer for the", submodule); eprintln!("proper steps."); - crate::detail_exit(3); + crate::detail_exit_macro!(3); } fn check_changed_files(toolstates: &HashMap, ToolState>) { @@ -106,7 +106,7 @@ fn check_changed_files(toolstates: &HashMap, ToolState>) { Ok(o) => o, Err(e) => { eprintln!("Failed to get changed files: {:?}", e); - crate::detail_exit(1); + crate::detail_exit_macro!(1); } }; @@ -177,7 +177,7 @@ impl Step for ToolStateCheck { } if did_error { - crate::detail_exit(1); + crate::detail_exit_macro!(1); } check_changed_files(&toolstates); @@ -223,7 +223,7 @@ impl Step for ToolStateCheck { } if did_error { - crate::detail_exit(1); + crate::detail_exit_macro!(1); } if builder.config.channel == "nightly" && env::var_os("TOOLSTATE_PUBLISH").is_some() { diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index 9bfdc77e6b6c..e4bbccdb067c 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -3,6 +3,7 @@ //! Simple things like testing the various filesystem operations here and there, //! not a lot of interesting happenings here unfortunately. +use build_helper::util::{fail, try_run}; use std::env; use std::fs; use std::io; @@ -230,25 +231,10 @@ pub fn is_valid_test_suite_arg<'a, P: AsRef>( pub fn run(cmd: &mut Command, print_cmd_on_fail: bool) { if !try_run(cmd, print_cmd_on_fail) { - crate::detail_exit(1); + crate::detail_exit_macro!(1); } } -pub fn try_run(cmd: &mut Command, print_cmd_on_fail: bool) -> bool { - let status = match cmd.status() { - Ok(status) => status, - Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}", cmd, e)), - }; - if !status.success() && print_cmd_on_fail { - println!( - "\n\ncommand did not execute successfully: {:?}\n\ - expected success, got: {}\n\n", - cmd, status - ); - } - status.success() -} - pub fn check_run(cmd: &mut Command, print_cmd_on_fail: bool) -> bool { let status = match cmd.status() { Ok(status) => status, @@ -269,7 +255,7 @@ pub fn check_run(cmd: &mut Command, print_cmd_on_fail: bool) -> bool { pub fn run_suppressed(cmd: &mut Command) { if !try_run_suppressed(cmd) { - crate::detail_exit(1); + crate::detail_exit_macro!(1); } } @@ -374,11 +360,6 @@ fn dir_up_to_date(src: &Path, threshold: SystemTime) -> bool { }) } -fn fail(s: &str) -> ! { - eprintln!("\n\n{}\n\n", s); - crate::detail_exit(1); -} - /// Copied from `std::path::absolute` until it stabilizes. /// /// FIXME: this shouldn't exist. diff --git a/src/tools/build_helper/src/lib.rs b/src/tools/build_helper/src/lib.rs index d3d2323db853..3fa970373b3f 100644 --- a/src/tools/build_helper/src/lib.rs +++ b/src/tools/build_helper/src/lib.rs @@ -1,2 +1,3 @@ pub mod ci; pub mod git; +pub mod util; diff --git a/src/tools/build_helper/src/util.rs b/src/tools/build_helper/src/util.rs new file mode 100644 index 000000000000..731095023a96 --- /dev/null +++ b/src/tools/build_helper/src/util.rs @@ -0,0 +1,41 @@ +use std::process::Command; + +/// Invokes `build_helper::util::detail_exit` with `cfg!(test)` +#[macro_export] +macro_rules! detail_exit_macro { + ($code:expr) => { + build_helper::util::detail_exit($code, cfg!(test)); + }; +} + +/// If code is not 0 (successful exit status), exit status is 101 (rust's default error code.) +/// If `is_test` true and code is an error code, it will cause a panic. +pub fn detail_exit(code: i32, is_test: bool) -> ! { + // if in test and code is an error code, panic with status code provided + if is_test { + panic!("status code: {}", code); + } else { + // otherwise,exit with provided status code + std::process::exit(code); + } +} + +pub fn fail(s: &str) -> ! { + eprintln!("\n\n{}\n\n", s); + detail_exit(1, cfg!(test)); +} + +pub fn try_run(cmd: &mut Command, print_cmd_on_fail: bool) -> bool { + let status = match cmd.status() { + Ok(status) => status, + Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}", cmd, e)), + }; + if !status.success() && print_cmd_on_fail { + println!( + "\n\ncommand did not execute successfully: {:?}\n\ + expected success, got: {}\n\n", + cmd, status + ); + } + status.success() +} From c64db2cfa7d0e4a9331d280044715c49bbea6e2d Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Tue, 30 May 2023 10:54:40 +0300 Subject: [PATCH 47/69] use `build_helper::util::try_run` in rustdoc-gui-test Signed-off-by: ozkanonur --- Cargo.lock | 1 + src/tools/rustdoc-gui-test/Cargo.toml | 1 + src/tools/rustdoc-gui-test/src/main.rs | 18 +----------------- 3 files changed, 3 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 443e6d09156f..71e4f803477b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4383,6 +4383,7 @@ dependencies = [ name = "rustdoc-gui-test" version = "0.1.0" dependencies = [ + "build_helper", "compiletest", "getopts", "walkdir", diff --git a/src/tools/rustdoc-gui-test/Cargo.toml b/src/tools/rustdoc-gui-test/Cargo.toml index f0c5b367117e..4cb200ebc7c5 100644 --- a/src/tools/rustdoc-gui-test/Cargo.toml +++ b/src/tools/rustdoc-gui-test/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] +build_helper = { path = "../build_helper" } compiletest = { path = "../compiletest" } getopts = "0.2" walkdir = "2" diff --git a/src/tools/rustdoc-gui-test/src/main.rs b/src/tools/rustdoc-gui-test/src/main.rs index af9b4e9d6800..3f60a90f87a2 100644 --- a/src/tools/rustdoc-gui-test/src/main.rs +++ b/src/tools/rustdoc-gui-test/src/main.rs @@ -1,3 +1,4 @@ +use build_helper::util::try_run; use compiletest::header::TestProps; use config::Config; use std::path::{Path, PathBuf}; @@ -60,23 +61,6 @@ fn find_librs>(path: P) -> Option { None } -// FIXME: move `bootstrap::util::try_run` into `build_helper` crate -// and use that one instead of creating this function. -fn try_run(cmd: &mut Command, print_cmd_on_fail: bool) -> bool { - let status = match cmd.status() { - Ok(status) => status, - Err(e) => panic!("failed to execute command: {:?}\nerror: {}", cmd, e), - }; - if !status.success() && print_cmd_on_fail { - println!( - "\n\ncommand did not execute successfully: {:?}\n\ - expected success, got: {}\n\n", - cmd, status - ); - } - status.success() -} - fn main() { let config = Arc::new(Config::from_args(env::args().collect())); From e11ffb62dfda4850b971310b6f721141ba29f267 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Tue, 30 May 2023 17:57:37 +0800 Subject: [PATCH 48/69] Don't typecheck suggested method call Only make the use-dot-operator-to-call-method suggestion, but do not double down and use the recovered type to perform method call typechecking as it will produce confusing diagnostics on the "fixed" code. --- compiler/rustc_hir_typeck/src/callee.rs | 46 ++++++++----------------- tests/ui/typeck/issue-106929.rs | 13 +++++++ tests/ui/typeck/issue-106929.stderr | 15 ++++++++ 3 files changed, 42 insertions(+), 32 deletions(-) create mode 100644 tests/ui/typeck/issue-106929.rs create mode 100644 tests/ui/typeck/issue-106929.stderr diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 655ab94eb48d..4389ad6ef267 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -420,20 +420,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .steal_diagnostic(segment.ident.span, StashKey::CallIntoMethod) { // Try suggesting `foo(a)` -> `a.foo()` if possible. - if let Some(ty) = - self.suggest_call_as_method( - &mut diag, - segment, - arg_exprs, - call_expr, - expected - ) - { - diag.emit(); - return ty; - } else { - diag.emit(); - } + self.suggest_call_as_method( + &mut diag, + segment, + arg_exprs, + call_expr, + expected + ); + diag.emit(); } let err = self.report_invalid_callee(call_expr, callee_expr, callee_ty, arg_exprs); @@ -496,9 +490,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { arg_exprs: &'tcx [hir::Expr<'tcx>], call_expr: &'tcx hir::Expr<'tcx>, expected: Expectation<'tcx>, - ) -> Option> { + ) { if let [callee_expr, rest @ ..] = arg_exprs { - let callee_ty = self.typeck_results.borrow().expr_ty_adjusted_opt(callee_expr)?; + let Some(callee_ty) = self.typeck_results.borrow().expr_ty_adjusted_opt(callee_expr) else { + return; + }; // First, do a probe with `IsSuggestion(true)` to avoid emitting // any strange errors. If it's successful, then we'll do a true @@ -513,7 +509,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ProbeScope::AllTraits, expected.only_has_type(self), ) else { - return None; + return; }; let pick = self.confirm_method( @@ -525,7 +521,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { segment, ); if pick.illegal_sized_bound.is_some() { - return None; + return; } let up_to_rcvr_span = segment.ident.span.until(callee_expr.span); @@ -567,22 +563,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sugg, Applicability::MaybeIncorrect, ); - - // Let's check the method fully now - let return_ty = self.check_method_argument_types( - segment.ident.span, - call_expr, - Ok(pick.callee), - rest, - TupleArgumentsFlag::DontTupleArguments, - expected, - ); - - return Some(return_ty); } } - - None } fn report_invalid_callee( diff --git a/tests/ui/typeck/issue-106929.rs b/tests/ui/typeck/issue-106929.rs new file mode 100644 index 000000000000..91342229ae1a --- /dev/null +++ b/tests/ui/typeck/issue-106929.rs @@ -0,0 +1,13 @@ +struct Client; + +impl Client { + fn post(&self, _: T, _: T) {} +} + +fn f() { + let c = Client; + post(c, ()); + //~^ ERROR cannot find function `post` in this scope +} + +fn main() {} diff --git a/tests/ui/typeck/issue-106929.stderr b/tests/ui/typeck/issue-106929.stderr new file mode 100644 index 000000000000..f744e5a41f0c --- /dev/null +++ b/tests/ui/typeck/issue-106929.stderr @@ -0,0 +1,15 @@ +error[E0425]: cannot find function `post` in this scope + --> $DIR/issue-106929.rs:9:5 + | +LL | post(c, ()); + | ^^^^ not found in this scope + | +help: use the `.` operator to call the method `post` on `&Client` + | +LL - post(c, ()); +LL + c.post(()); + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. From 200ed9f8cd49e823c788b6ce1096030d9c40ec02 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 23 May 2023 16:32:59 +0200 Subject: [PATCH 49/69] leak_check: remove unused codepath --- compiler/rustc_hir_typeck/src/coercion.rs | 2 +- .../src/infer/higher_ranked/mod.rs | 7 +----- .../infer/region_constraints/leak_check.rs | 25 ++++--------------- compiler/rustc_middle/src/ty/error.rs | 13 ---------- .../src/traits/coherence.rs | 2 +- .../src/traits/select/mod.rs | 2 +- 6 files changed, 9 insertions(+), 42 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 369dd4ae5950..ee36936a06ec 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -824,7 +824,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // want the coerced type to be the actual supertype of these two, // but for now, we want to just error to ensure we don't lock // ourselves into a specific behavior with NLL. - self.leak_check(false, snapshot)?; + self.leak_check(snapshot)?; result }) diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs index 1c298e7d4ecd..00e108206835 100644 --- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs +++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs @@ -108,11 +108,7 @@ impl<'tcx> InferCtxt<'tcx> { /// See [RegionConstraintCollector::leak_check][1]. /// /// [1]: crate::infer::region_constraints::RegionConstraintCollector::leak_check - pub fn leak_check( - &self, - overly_polymorphic: bool, - snapshot: &CombinedSnapshot<'tcx>, - ) -> RelateResult<'tcx, ()> { + pub fn leak_check(&self, snapshot: &CombinedSnapshot<'tcx>) -> RelateResult<'tcx, ()> { // If the user gave `-Zno-leak-check`, or we have been // configured to skip the leak check, then skip the leak check // completely. The leak check is deprecated. Any legitimate @@ -125,7 +121,6 @@ impl<'tcx> InferCtxt<'tcx> { self.inner.borrow_mut().unwrap_region_constraints().leak_check( self.tcx, - overly_polymorphic, self.universe(), snapshot, ) diff --git a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs index 5f4093c1c3c1..7b9e6983212a 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs @@ -65,13 +65,12 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { pub fn leak_check( &mut self, tcx: TyCtxt<'tcx>, - overly_polymorphic: bool, max_universe: ty::UniverseIndex, snapshot: &CombinedSnapshot<'tcx>, ) -> RelateResult<'tcx, ()> { debug!( - "leak_check(max_universe={:?}, snapshot.universe={:?}, overly_polymorphic={:?})", - max_universe, snapshot.universe, overly_polymorphic + "leak_check(max_universe={:?}, snapshot.universe={:?})", + max_universe, snapshot.universe ); assert!(UndoLogs::>::in_snapshot(&self.undo_log)); @@ -84,14 +83,8 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { let mini_graph = &MiniGraph::new(tcx, self.undo_log.region_constraints(), &self.storage.data.verifys); - let mut leak_check = LeakCheck::new( - tcx, - universe_at_start_of_snapshot, - max_universe, - overly_polymorphic, - mini_graph, - self, - ); + let mut leak_check = + LeakCheck::new(tcx, universe_at_start_of_snapshot, max_universe, mini_graph, self); leak_check.assign_placeholder_values()?; leak_check.propagate_scc_value()?; Ok(()) @@ -101,8 +94,6 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { struct LeakCheck<'me, 'tcx> { tcx: TyCtxt<'tcx>, universe_at_start_of_snapshot: ty::UniverseIndex, - /// Only used when reporting region errors. - overly_polymorphic: bool, mini_graph: &'me MiniGraph<'tcx>, rcc: &'me RegionConstraintCollector<'me, 'tcx>, @@ -132,7 +123,6 @@ impl<'me, 'tcx> LeakCheck<'me, 'tcx> { tcx: TyCtxt<'tcx>, universe_at_start_of_snapshot: ty::UniverseIndex, max_universe: ty::UniverseIndex, - overly_polymorphic: bool, mini_graph: &'me MiniGraph<'tcx>, rcc: &'me RegionConstraintCollector<'me, 'tcx>, ) -> Self { @@ -140,7 +130,6 @@ impl<'me, 'tcx> LeakCheck<'me, 'tcx> { Self { tcx, universe_at_start_of_snapshot, - overly_polymorphic, mini_graph, rcc, scc_placeholders: IndexVec::from_elem_n(None, mini_graph.sccs.num_sccs()), @@ -289,11 +278,7 @@ impl<'me, 'tcx> LeakCheck<'me, 'tcx> { other_region: ty::Region<'tcx>, ) -> TypeError<'tcx> { debug!("error: placeholder={:?}, other_region={:?}", placeholder, other_region); - if self.overly_polymorphic { - TypeError::RegionsOverlyPolymorphic(placeholder.bound.kind, other_region) - } else { - TypeError::RegionsInsufficientlyPolymorphic(placeholder.bound.kind, other_region) - } + TypeError::RegionsInsufficientlyPolymorphic(placeholder.bound.kind, other_region) } } diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 49ab9b79e96f..66293f19eef6 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -45,7 +45,6 @@ pub enum TypeError<'tcx> { RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>), RegionsInsufficientlyPolymorphic(BoundRegionKind, Region<'tcx>), - RegionsOverlyPolymorphic(BoundRegionKind, Region<'tcx>), RegionsPlaceholderMismatch, Sorts(ExpectedFound>), @@ -74,7 +73,6 @@ impl TypeError<'_> { match self { TypeError::RegionsDoesNotOutlive(_, _) | TypeError::RegionsInsufficientlyPolymorphic(_, _) - | TypeError::RegionsOverlyPolymorphic(_, _) | TypeError::RegionsPlaceholderMismatch => true, _ => false, } @@ -98,11 +96,6 @@ impl<'tcx> TypeError<'tcx> { } } - let br_string = |br: ty::BoundRegionKind| match br { - ty::BrNamed(_, name) => format!(" {}", name), - _ => String::new(), - }; - match self { CyclicTy(_) => "cyclic type of infinite size".into(), CyclicConst(_) => "encountered a self-referencing constant".into(), @@ -144,11 +137,6 @@ impl<'tcx> TypeError<'tcx> { RegionsInsufficientlyPolymorphic(..) => { "one type is more general than the other".into() } - RegionsOverlyPolymorphic(br, _) => format!( - "expected concrete lifetime, found bound lifetime parameter{}", - br_string(br) - ) - .into(), RegionsPlaceholderMismatch => "one type is more general than the other".into(), ArgumentSorts(values, _) | Sorts(values) => { let expected = values.expected.sort_string(tcx); @@ -228,7 +216,6 @@ impl<'tcx> TypeError<'tcx> { | FieldMisMatch(..) | RegionsDoesNotOutlive(..) | RegionsInsufficientlyPolymorphic(..) - | RegionsOverlyPolymorphic(..) | RegionsPlaceholderMismatch | Traits(_) | ProjectionMismatched(_) diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index e8c5a8fab2a3..dda77c2a461d 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -200,7 +200,7 @@ fn overlap_within_probe<'cx, 'tcx>( // We disable the leak when creating the `snapshot` by using // `infcx.probe_maybe_disable_leak_check`. - if infcx.leak_check(true, snapshot).is_err() { + if infcx.leak_check(snapshot).is_err() { debug!("overlap: leak check failed"); return None; } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index ac4f845a0052..2c0b911c8050 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -563,7 +563,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx.probe(|snapshot| -> Result { let result = op(self)?; - match self.infcx.leak_check(true, snapshot) { + match self.infcx.leak_check(snapshot) { Ok(()) => {} Err(_) => return Ok(EvaluatedToErr), } From 0a6ae29fe855a07b204c5b0e490c59c3ab3d443a Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 23 May 2023 18:10:30 +0200 Subject: [PATCH 50/69] coherence: don't add hidden types for opaques we can otherwise assign a hidden type to the opaque which causes ICE if we don't use `take_opaque_types` during coherence. This is annoying so I didn't bother. Added a test showing the behavior this prevents. --- .../rustc_infer/src/infer/opaque_types.rs | 32 +++++++++++++------ .../coherence_different_hidden_ty.rs | 25 +++++++++++++++ .../coherence_different_hidden_ty.stderr | 12 +++++++ 3 files changed, 59 insertions(+), 10 deletions(-) create mode 100644 tests/ui/type-alias-impl-trait/coherence_different_hidden_ty.rs create mode 100644 tests/ui/type-alias-impl-trait/coherence_different_hidden_ty.stderr diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 9d5ec228d827..105a3f08c820 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -533,17 +533,29 @@ impl<'tcx> InferCtxt<'tcx> { // these are the same span, but not in cases like `-> (impl // Foo, impl Bar)`. let span = cause.span; - let prev = self.inner.borrow_mut().opaque_types().register( - opaque_type_key, - OpaqueHiddenType { ty: hidden_ty, span }, - origin, - ); - let mut obligations = if let Some(prev) = prev { - self.at(&cause, param_env) - .eq_exp(DefineOpaqueTypes::Yes, a_is_expected, prev, hidden_ty)? - .obligations + let mut obligations = if self.intercrate { + // During intercrate we do not define opaque types but instead always + // force ambiguity unless the hidden type is known to not implement + // our trait. + vec![traits::Obligation::new( + self.tcx, + cause.clone(), + param_env, + ty::PredicateKind::Ambiguous, + )] } else { - Vec::new() + let prev = self.inner.borrow_mut().opaque_types().register( + opaque_type_key, + OpaqueHiddenType { ty: hidden_ty, span }, + origin, + ); + if let Some(prev) = prev { + self.at(&cause, param_env) + .eq_exp(DefineOpaqueTypes::Yes, a_is_expected, prev, hidden_ty)? + .obligations + } else { + Vec::new() + } }; self.add_item_bounds_for_hidden_type( diff --git a/tests/ui/type-alias-impl-trait/coherence_different_hidden_ty.rs b/tests/ui/type-alias-impl-trait/coherence_different_hidden_ty.rs new file mode 100644 index 000000000000..39b3d535ad45 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/coherence_different_hidden_ty.rs @@ -0,0 +1,25 @@ +// When checking whether these two impls overlap, we could detect that we +// would require the hidden type of `TAIT` to be equal to both `u32` and `i32` +// and therefore accept them as disjoint. That is annoying to implement with +// the current system because we would have to add the following to each +// returning branch in coherence. +// +// let _ = infcx.take_opaque_types(); +// +// @lcnr: Because of this I decided to not bother and cause this to fail instead. +// In the future we can definitely modify the compiler to accept this +// again. +#![feature(type_alias_impl_trait)] + +trait Trait {} + +type TAIT = impl Sized; + +impl Trait for (TAIT, TAIT) {} + +impl Trait for (u32, i32) {} +//~^ ERROR conflicting implementations of trait `Trait` for type `(TAIT, TAIT)` + +fn define() -> TAIT {} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/coherence_different_hidden_ty.stderr b/tests/ui/type-alias-impl-trait/coherence_different_hidden_ty.stderr new file mode 100644 index 000000000000..f2aee798608a --- /dev/null +++ b/tests/ui/type-alias-impl-trait/coherence_different_hidden_ty.stderr @@ -0,0 +1,12 @@ +error[E0119]: conflicting implementations of trait `Trait` for type `(TAIT, TAIT)` + --> $DIR/coherence_different_hidden_ty.rs:20:1 + | +LL | impl Trait for (TAIT, TAIT) {} + | --------------------------- first implementation here +LL | +LL | impl Trait for (u32, i32) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(TAIT, TAIT)` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. From aa13288e22d11a08c165804c659a4eca2820ab9e Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 23 May 2023 18:16:41 +0200 Subject: [PATCH 51/69] remove unused revision --- .../coherence-inherited-subtyping.re.stderr | 14 -------------- .../ui/coherence/coherence-inherited-subtyping.rs | 2 -- ...stderr => coherence-inherited-subtyping.stderr} | 2 +- 3 files changed, 1 insertion(+), 17 deletions(-) delete mode 100644 tests/ui/coherence/coherence-inherited-subtyping.re.stderr rename tests/ui/coherence/{coherence-inherited-subtyping.old.stderr => coherence-inherited-subtyping.stderr} (90%) diff --git a/tests/ui/coherence/coherence-inherited-subtyping.re.stderr b/tests/ui/coherence/coherence-inherited-subtyping.re.stderr deleted file mode 100644 index 4701bc0b1397..000000000000 --- a/tests/ui/coherence/coherence-inherited-subtyping.re.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0592]: duplicate definitions with name `method1` - --> $DIR/coherence-inherited-subtyping.rs:14:5 - | -LL | fn method1(&self) {} - | ^^^^^^^^^^^^^^^^^ duplicate definitions for `method1` -... -LL | fn method1(&self) {} - | ----------------- other definition for `method1` - | - = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0592`. diff --git a/tests/ui/coherence/coherence-inherited-subtyping.rs b/tests/ui/coherence/coherence-inherited-subtyping.rs index 8587eb77950c..f35cd2103da4 100644 --- a/tests/ui/coherence/coherence-inherited-subtyping.rs +++ b/tests/ui/coherence/coherence-inherited-subtyping.rs @@ -4,8 +4,6 @@ // Note: This scenario is currently accepted, but as part of the // universe transition (#56105) may eventually become an error. -// revisions: old re - struct Foo { t: T, } diff --git a/tests/ui/coherence/coherence-inherited-subtyping.old.stderr b/tests/ui/coherence/coherence-inherited-subtyping.stderr similarity index 90% rename from tests/ui/coherence/coherence-inherited-subtyping.old.stderr rename to tests/ui/coherence/coherence-inherited-subtyping.stderr index 4701bc0b1397..f60b2aa2735d 100644 --- a/tests/ui/coherence/coherence-inherited-subtyping.old.stderr +++ b/tests/ui/coherence/coherence-inherited-subtyping.stderr @@ -1,5 +1,5 @@ error[E0592]: duplicate definitions with name `method1` - --> $DIR/coherence-inherited-subtyping.rs:14:5 + --> $DIR/coherence-inherited-subtyping.rs:12:5 | LL | fn method1(&self) {} | ^^^^^^^^^^^^^^^^^ duplicate definitions for `method1` From 2a4467da9f82a8d7be9b8c9f575a64b9a2df5961 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 23 May 2023 18:17:09 +0200 Subject: [PATCH 52/69] add FIXME to a test which seems wrong. --- tests/ui/type-alias-impl-trait/coherence_generalization.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/ui/type-alias-impl-trait/coherence_generalization.rs b/tests/ui/type-alias-impl-trait/coherence_generalization.rs index 5c9ad9498b6d..679b2b0f1888 100644 --- a/tests/ui/type-alias-impl-trait/coherence_generalization.rs +++ b/tests/ui/type-alias-impl-trait/coherence_generalization.rs @@ -1,5 +1,7 @@ // check-pass +// FIXME(type_alias_impl_trait): What does this test? This needs a comment +// explaining what we're worried about here. #![feature(type_alias_impl_trait)] trait Trait {} type Opaque = impl Sized; From a0245bb3cb51c0e9a19c20abac6473da446832e0 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 23 May 2023 18:56:25 +0200 Subject: [PATCH 53/69] rework the leak_check to take the outer_universe clean up coherence to not rely on probes anymore --- compiler/rustc_hir_typeck/src/coercion.rs | 4 +- compiler/rustc_infer/src/infer/at.rs | 2 +- .../src/infer/higher_ranked/mod.rs | 15 ++- compiler/rustc_infer/src/infer/mod.rs | 55 +++----- .../infer/region_constraints/leak_check.rs | 125 ++++++++++-------- .../src/infer/region_constraints/mod.rs | 11 +- compiler/rustc_infer/src/infer/undo_log.rs | 9 -- .../src/traits/coherence.rs | 111 +++++++++------- .../src/traits/query/evaluate_obligation.rs | 2 +- .../src/traits/select/mod.rs | 10 +- 10 files changed, 178 insertions(+), 166 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index ee36936a06ec..905781ec8f59 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -808,6 +808,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { G: FnOnce(Ty<'tcx>) -> Vec>, { self.commit_if_ok(|snapshot| { + let outer_universe = self.infcx.universe(); + let result = if let ty::FnPtr(fn_ty_b) = b.kind() && let (hir::Unsafety::Normal, hir::Unsafety::Unsafe) = (fn_ty_a.unsafety(), fn_ty_b.unsafety()) @@ -824,7 +826,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // want the coerced type to be the actual supertype of these two, // but for now, we want to just error to ensure we don't lock // ourselves into a specific behavior with NLL. - self.leak_check(snapshot)?; + self.leak_check(outer_universe, Some(snapshot))?; result }) diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 0c8854e962ab..6b2dd0a2b4fe 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -70,8 +70,8 @@ impl<'tcx> InferCtxt<'tcx> { tcx: self.tcx, defining_use_anchor: self.defining_use_anchor, considering_regions: self.considering_regions, + skip_leak_check: self.skip_leak_check, inner: self.inner.clone(), - skip_leak_check: self.skip_leak_check.clone(), lexical_region_resolutions: self.lexical_region_resolutions.clone(), selection_cache: self.selection_cache.clone(), evaluation_cache: self.evaluation_cache.clone(), diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs index 00e108206835..974bc2f1153d 100644 --- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs +++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs @@ -105,24 +105,31 @@ impl<'tcx> InferCtxt<'tcx> { self.tcx.replace_bound_vars_uncached(binder, delegate) } - /// See [RegionConstraintCollector::leak_check][1]. + /// See [RegionConstraintCollector::leak_check][1]. We only check placeholder + /// leaking into `outer_universe`, i.e. placeholders which cannot be named by that + /// universe. /// /// [1]: crate::infer::region_constraints::RegionConstraintCollector::leak_check - pub fn leak_check(&self, snapshot: &CombinedSnapshot<'tcx>) -> RelateResult<'tcx, ()> { + pub fn leak_check( + &self, + outer_universe: ty::UniverseIndex, + only_consider_snapshot: Option<&CombinedSnapshot<'tcx>>, + ) -> RelateResult<'tcx, ()> { // If the user gave `-Zno-leak-check`, or we have been // configured to skip the leak check, then skip the leak check // completely. The leak check is deprecated. Any legitimate // subtyping errors that it would have caught will now be // caught later on, during region checking. However, we // continue to use it for a transition period. - if self.tcx.sess.opts.unstable_opts.no_leak_check || self.skip_leak_check.get() { + if self.tcx.sess.opts.unstable_opts.no_leak_check || self.skip_leak_check { return Ok(()); } self.inner.borrow_mut().unwrap_region_constraints().leak_check( self.tcx, + outer_universe, self.universe(), - snapshot, + only_consider_snapshot, ) } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index b49282726fd2..447d4c9f84bc 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -251,14 +251,13 @@ pub struct InferCtxt<'tcx> { /// solving is left to borrowck instead. pub considering_regions: bool, - pub inner: RefCell>, - /// If set, this flag causes us to skip the 'leak check' during /// higher-ranked subtyping operations. This flag is a temporary one used /// to manage the removal of the leak-check: for the time being, we still run the - /// leak-check, but we issue warnings. This flag can only be set to true - /// when entering a snapshot. - skip_leak_check: Cell, + /// leak-check, but we issue warnings. + skip_leak_check: bool, + + pub inner: RefCell>, /// Once region inference is done, the values for each variable. lexical_region_resolutions: RefCell>>, @@ -543,6 +542,7 @@ pub struct InferCtxtBuilder<'tcx> { tcx: TyCtxt<'tcx>, defining_use_anchor: DefiningAnchor, considering_regions: bool, + skip_leak_check: bool, /// Whether we are in coherence mode. intercrate: bool, } @@ -557,6 +557,7 @@ impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> { tcx: self, defining_use_anchor: DefiningAnchor::Error, considering_regions: true, + skip_leak_check: false, intercrate: false, } } @@ -584,6 +585,11 @@ impl<'tcx> InferCtxtBuilder<'tcx> { self } + pub fn skip_leak_check(mut self, skip_leak_check: bool) -> Self { + self.skip_leak_check = skip_leak_check; + self + } + /// Given a canonical value `C` as a starting point, create an /// inference context that contains each of the bound values /// within instantiated as a fresh variable. The `f` closure is @@ -605,11 +611,18 @@ impl<'tcx> InferCtxtBuilder<'tcx> { } pub fn build(&mut self) -> InferCtxt<'tcx> { - let InferCtxtBuilder { tcx, defining_use_anchor, considering_regions, intercrate } = *self; + let InferCtxtBuilder { + tcx, + defining_use_anchor, + considering_regions, + skip_leak_check, + intercrate, + } = *self; InferCtxt { tcx, defining_use_anchor, considering_regions, + skip_leak_check, inner: RefCell::new(InferCtxtInner::new()), lexical_region_resolutions: RefCell::new(None), selection_cache: Default::default(), @@ -619,7 +632,6 @@ impl<'tcx> InferCtxtBuilder<'tcx> { tainted_by_errors: Cell::new(None), err_count_on_creation: tcx.sess.err_count(), in_snapshot: Cell::new(false), - skip_leak_check: Cell::new(false), universe: Cell::new(ty::UniverseIndex::ROOT), intercrate, } @@ -815,32 +827,9 @@ impl<'tcx> InferCtxt<'tcx> { r } - /// If `should_skip` is true, then execute `f` then unroll any bindings it creates. - #[instrument(skip(self, f), level = "debug")] - pub fn probe_maybe_skip_leak_check(&self, should_skip: bool, f: F) -> R - where - F: FnOnce(&CombinedSnapshot<'tcx>) -> R, - { - let snapshot = self.start_snapshot(); - let was_skip_leak_check = self.skip_leak_check.get(); - if should_skip { - self.skip_leak_check.set(true); - } - let r = f(&snapshot); - self.rollback_to("probe", snapshot); - self.skip_leak_check.set(was_skip_leak_check); - r - } - - /// Scan the constraints produced since `snapshot` began and returns: - /// - /// - `None` -- if none of them involves "region outlives" constraints. - /// - `Some(true)` -- if there are `'a: 'b` constraints where `'a` or `'b` is a placeholder. - /// - `Some(false)` -- if there are `'a: 'b` constraints but none involve placeholders. - pub fn region_constraints_added_in_snapshot( - &self, - snapshot: &CombinedSnapshot<'tcx>, - ) -> Option { + /// Scan the constraints produced since `snapshot` and check whether + /// we added any region constraints. + pub fn region_constraints_added_in_snapshot(&self, snapshot: &CombinedSnapshot<'tcx>) -> bool { self.inner .borrow_mut() .unwrap_region_constraints() diff --git a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs index 7b9e6983212a..dd65f66ccd14 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs @@ -3,7 +3,6 @@ use crate::infer::CombinedSnapshot; use rustc_data_structures::{ fx::FxIndexMap, graph::{scc::Sccs, vec_graph::VecGraph}, - undo_log::UndoLogs, }; use rustc_index::Idx; use rustc_middle::ty::error::TypeError; @@ -13,7 +12,9 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { /// Searches new universes created during `snapshot`, looking for /// placeholders that may "leak" out from the universes they are contained /// in. If any leaking placeholders are found, then an `Err` is returned - /// (typically leading to the snapshot being reversed). + /// (typically leading to the snapshot being reversed). This algorithm + /// only looks at placeholders which cannot be named by `outer_universe`, + /// as this is the universe we're currently checking for a leak. /// /// The leak check *used* to be the only way we had to handle higher-ranked /// obligations. Now that we have integrated universes into the region @@ -55,6 +56,12 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { /// * if they must also be equal to a placeholder P, and U cannot name P, report an error, as that /// indicates `P: R` and `R` is in an incompatible universe /// + /// To improve performance and for the old trait solver caching to be sound, this takes + /// an optional snapshot in which case we only look at region constraints added in that + /// snapshot. If we were to not do that the `leak_check` during evaluation can rely on + /// region constraints added outside of that evaluation. As that is not reflected in the + /// cache key this would be unsound. + /// /// # Historical note /// /// Older variants of the leak check used to report errors for these @@ -62,29 +69,21 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { /// /// * R: P1, even if R cannot name P1, because R = 'static is a valid sol'n /// * R: P1, R: P2, as above + #[instrument(level = "debug", skip(self, tcx, only_consider_snapshot), ret)] pub fn leak_check( &mut self, tcx: TyCtxt<'tcx>, + outer_universe: ty::UniverseIndex, max_universe: ty::UniverseIndex, - snapshot: &CombinedSnapshot<'tcx>, + only_consider_snapshot: Option<&CombinedSnapshot<'tcx>>, ) -> RelateResult<'tcx, ()> { - debug!( - "leak_check(max_universe={:?}, snapshot.universe={:?})", - max_universe, snapshot.universe - ); - - assert!(UndoLogs::>::in_snapshot(&self.undo_log)); - - let universe_at_start_of_snapshot = snapshot.universe; - if universe_at_start_of_snapshot == max_universe { + if outer_universe == max_universe { return Ok(()); } - let mini_graph = - &MiniGraph::new(tcx, self.undo_log.region_constraints(), &self.storage.data.verifys); + let mini_graph = &MiniGraph::new(tcx, &self, only_consider_snapshot); - let mut leak_check = - LeakCheck::new(tcx, universe_at_start_of_snapshot, max_universe, mini_graph, self); + let mut leak_check = LeakCheck::new(tcx, outer_universe, max_universe, mini_graph, self); leak_check.assign_placeholder_values()?; leak_check.propagate_scc_value()?; Ok(()) @@ -93,7 +92,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { struct LeakCheck<'me, 'tcx> { tcx: TyCtxt<'tcx>, - universe_at_start_of_snapshot: ty::UniverseIndex, + outer_universe: ty::UniverseIndex, mini_graph: &'me MiniGraph<'tcx>, rcc: &'me RegionConstraintCollector<'me, 'tcx>, @@ -121,7 +120,7 @@ struct LeakCheck<'me, 'tcx> { impl<'me, 'tcx> LeakCheck<'me, 'tcx> { fn new( tcx: TyCtxt<'tcx>, - universe_at_start_of_snapshot: ty::UniverseIndex, + outer_universe: ty::UniverseIndex, max_universe: ty::UniverseIndex, mini_graph: &'me MiniGraph<'tcx>, rcc: &'me RegionConstraintCollector<'me, 'tcx>, @@ -129,7 +128,7 @@ impl<'me, 'tcx> LeakCheck<'me, 'tcx> { let dummy_scc_universe = SccUniverse { universe: max_universe, region: None }; Self { tcx, - universe_at_start_of_snapshot, + outer_universe, mini_graph, rcc, scc_placeholders: IndexVec::from_elem_n(None, mini_graph.sccs.num_sccs()), @@ -154,7 +153,7 @@ impl<'me, 'tcx> LeakCheck<'me, 'tcx> { // Detect those SCCs that directly contain a placeholder if let ty::RePlaceholder(placeholder) = **region { - if self.universe_at_start_of_snapshot.cannot_name(placeholder.universe) { + if self.outer_universe.cannot_name(placeholder.universe) { self.assign_scc_value(scc, placeholder)?; } } @@ -364,56 +363,70 @@ struct MiniGraph<'tcx> { } impl<'tcx> MiniGraph<'tcx> { - fn new<'a>( + fn new( tcx: TyCtxt<'tcx>, - undo_log: impl Iterator>, - verifys: &[Verify<'tcx>], - ) -> Self - where - 'tcx: 'a, - { + region_constraints: &RegionConstraintCollector<'_, 'tcx>, + only_consider_snapshot: Option<&CombinedSnapshot<'tcx>>, + ) -> Self { let mut nodes = FxIndexMap::default(); let mut edges = Vec::new(); // Note that if `R2: R1`, we get a callback `r1, r2`, so `target` is first parameter. - Self::iterate_undo_log(tcx, undo_log, verifys, |target, source| { - let source_node = Self::add_node(&mut nodes, source); - let target_node = Self::add_node(&mut nodes, target); - edges.push((source_node, target_node)); - }); + Self::iterate_region_constraints( + tcx, + region_constraints, + only_consider_snapshot, + |target, source| { + let source_node = Self::add_node(&mut nodes, source); + let target_node = Self::add_node(&mut nodes, target); + edges.push((source_node, target_node)); + }, + ); let graph = VecGraph::new(nodes.len(), edges); let sccs = Sccs::new(&graph); Self { nodes, sccs } } /// Invokes `each_edge(R1, R2)` for each edge where `R2: R1` - fn iterate_undo_log<'a>( + fn iterate_region_constraints( tcx: TyCtxt<'tcx>, - undo_log: impl Iterator>, - verifys: &[Verify<'tcx>], + region_constraints: &RegionConstraintCollector<'_, 'tcx>, + only_consider_snapshot: Option<&CombinedSnapshot<'tcx>>, mut each_edge: impl FnMut(ty::Region<'tcx>, ty::Region<'tcx>), - ) where - 'tcx: 'a, - { - for undo_entry in undo_log { - match undo_entry { - &AddConstraint(Constraint::VarSubVar(a, b)) => { - each_edge(ty::Region::new_var(tcx, a), ty::Region::new_var(tcx, b)); + ) { + let mut each_constraint = |constraint| match constraint { + &Constraint::VarSubVar(a, b) => { + each_edge(ty::Region::new_var(tcx, a), ty::Region::new_var(tcx, b)); + } + &Constraint::RegSubVar(a, b) => { + each_edge(a, ty::Region::new_var(tcx, b)); + } + &Constraint::VarSubReg(a, b) => { + each_edge(ty::Region::new_var(tcx, a), b); + } + &Constraint::RegSubReg(a, b) => { + each_edge(a, b); + } + }; + + if let Some(snapshot) = only_consider_snapshot { + for undo_entry in + region_constraints.undo_log.region_constraints_in_snapshot(&snapshot.undo_snapshot) + { + match undo_entry { + AddConstraint(constraint) => { + each_constraint(constraint); + } + &AddVerify(i) => span_bug!( + region_constraints.data().verifys[i].origin.span(), + "we never add verifications while doing higher-ranked things", + ), + &AddCombination(..) | &AddVar(..) => {} } - &AddConstraint(Constraint::RegSubVar(a, b)) => { - each_edge(a, ty::Region::new_var(tcx, b)); - } - &AddConstraint(Constraint::VarSubReg(a, b)) => { - each_edge(ty::Region::new_var(tcx, a), b); - } - &AddConstraint(Constraint::RegSubReg(a, b)) => { - each_edge(a, b); - } - &AddVerify(i) => span_bug!( - verifys[i].origin.span(), - "we never add verifications while doing higher-ranked things", - ), - &AddCombination(..) | &AddVar(..) => {} + } + } else { + for (constraint, _origin) in ®ion_constraints.data().constraints { + each_constraint(constraint) } } } diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index cd8d23bf635c..613da8a0b457 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -400,7 +400,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { data } - pub(super) fn data(&self) -> &RegionConstraintData<'tcx> { + pub fn data(&self) -> &RegionConstraintData<'tcx> { &self.data } @@ -683,15 +683,10 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { } /// See `InferCtxt::region_constraints_added_in_snapshot`. - pub fn region_constraints_added_in_snapshot(&self, mark: &Snapshot<'tcx>) -> Option { + pub fn region_constraints_added_in_snapshot(&self, mark: &Snapshot<'tcx>) -> bool { self.undo_log .region_constraints_in_snapshot(mark) - .map(|&elt| match elt { - AddConstraint(constraint) => Some(constraint.involves_placeholders()), - _ => None, - }) - .max() - .unwrap_or(None) + .any(|&elt| matches!(elt, AddConstraint(_))) } #[inline] diff --git a/compiler/rustc_infer/src/infer/undo_log.rs b/compiler/rustc_infer/src/infer/undo_log.rs index 955c54e85157..8dd1a7c5f21f 100644 --- a/compiler/rustc_infer/src/infer/undo_log.rs +++ b/compiler/rustc_infer/src/infer/undo_log.rs @@ -183,15 +183,6 @@ impl<'tcx> InferCtxtUndoLogs<'tcx> { self.logs[s.undo_len..].iter().any(|log| matches!(log, UndoLog::OpaqueTypes(..))) } - pub(crate) fn region_constraints( - &self, - ) -> impl Iterator> + Clone { - self.logs.iter().filter_map(|log| match log { - UndoLog::RegionConstraintCollector(log) => Some(log), - _ => None, - }) - } - fn assert_open_snapshot(&self, snapshot: &Snapshot<'tcx>) { // Failures here may indicate a failure to follow a stack discipline. assert!(self.logs.len() >= snapshot.undo_len); diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index dda77c2a461d..d6fd457de06d 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -5,7 +5,7 @@ //! [trait-specialization]: https://rustc-dev-guide.rust-lang.org/traits/specialization.html use crate::infer::outlives::env::OutlivesEnvironment; -use crate::infer::{CombinedSnapshot, InferOk}; +use crate::infer::InferOk; use crate::traits::outlives_bounds::InferCtxtExt as _; use crate::traits::select::IntercrateAmbiguityCause; use crate::traits::util::impl_subject_and_oblig; @@ -62,6 +62,21 @@ pub fn add_placeholder_note(err: &mut Diagnostic) { ); } +#[derive(Debug, Clone, Copy)] +enum TrackAmbiguityCauses { + Yes, + No, +} + +impl TrackAmbiguityCauses { + fn is_yes(self) -> bool { + match self { + TrackAmbiguityCauses::Yes => true, + TrackAmbiguityCauses::No => false, + } + } +} + /// If there are types that satisfy both impls, returns `Some` /// with a suitably-freshened `ImplHeader` with those types /// substituted. Otherwise, returns `None`. @@ -97,29 +112,28 @@ pub fn overlapping_impls( return None; } - let infcx = tcx - .infer_ctxt() - .with_opaque_type_inference(DefiningAnchor::Bubble) - .intercrate(true) - .build(); - let selcx = &mut SelectionContext::new(&infcx); - let overlaps = - overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).is_some(); - if !overlaps { - return None; - } + let _overlap_with_bad_diagnostics = overlap( + tcx, + TrackAmbiguityCauses::No, + skip_leak_check, + impl1_def_id, + impl2_def_id, + overlap_mode, + )?; // In the case where we detect an error, run the check again, but // this time tracking intercrate ambiguity causes for better // diagnostics. (These take time and can lead to false errors.) - let infcx = tcx - .infer_ctxt() - .with_opaque_type_inference(DefiningAnchor::Bubble) - .intercrate(true) - .build(); - let selcx = &mut SelectionContext::new(&infcx); - selcx.enable_tracking_intercrate_ambiguity_causes(); - Some(overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).unwrap()) + let overlap = overlap( + tcx, + TrackAmbiguityCauses::Yes, + skip_leak_check, + impl1_def_id, + impl2_def_id, + overlap_mode, + ) + .unwrap(); + Some(overlap) } fn with_fresh_ty_vars<'cx, 'tcx>( @@ -146,40 +160,34 @@ fn with_fresh_ty_vars<'cx, 'tcx>( /// Can both impl `a` and impl `b` be satisfied by a common type (including /// where-clauses)? If so, returns an `ImplHeader` that unifies the two impls. -fn overlap<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, +#[instrument(level = "debug", skip(tcx))] +fn overlap<'tcx>( + tcx: TyCtxt<'tcx>, + track_ambiguity_causes: TrackAmbiguityCauses, skip_leak_check: SkipLeakCheck, impl1_def_id: DefId, impl2_def_id: DefId, overlap_mode: OverlapMode, ) -> Option> { - debug!( - "overlap(impl1_def_id={:?}, impl2_def_id={:?}, overlap_mode={:?})", - impl1_def_id, impl2_def_id, overlap_mode - ); - - selcx.infcx.probe_maybe_skip_leak_check(skip_leak_check.is_yes(), |snapshot| { - overlap_within_probe(selcx, impl1_def_id, impl2_def_id, overlap_mode, snapshot) - }) -} - -fn overlap_within_probe<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - impl1_def_id: DefId, - impl2_def_id: DefId, - overlap_mode: OverlapMode, - snapshot: &CombinedSnapshot<'tcx>, -) -> Option> { - let infcx = selcx.infcx; - if overlap_mode.use_negative_impl() { - if negative_impl(infcx.tcx, impl1_def_id, impl2_def_id) - || negative_impl(infcx.tcx, impl2_def_id, impl1_def_id) + if negative_impl(tcx, impl1_def_id, impl2_def_id) + || negative_impl(tcx, impl2_def_id, impl1_def_id) { return None; } } + let infcx = tcx + .infer_ctxt() + .with_opaque_type_inference(DefiningAnchor::Bubble) + .skip_leak_check(skip_leak_check.is_yes()) + .intercrate(true) + .build(); + let selcx = &mut SelectionContext::new(&infcx); + if track_ambiguity_causes.is_yes() { + selcx.enable_tracking_intercrate_ambiguity_causes(); + } + // For the purposes of this check, we don't bring any placeholder // types into scope; instead, we replace the generic types with // fresh type variables, and hence we do our evaluations in an @@ -198,18 +206,23 @@ fn overlap_within_probe<'cx, 'tcx>( } } - // We disable the leak when creating the `snapshot` by using - // `infcx.probe_maybe_disable_leak_check`. - if infcx.leak_check(snapshot).is_err() { + // We toggle the `leak_check` by using `skip_leak_check` when constructing the + // inference context, so this may be a noop. + if infcx.leak_check(ty::UniverseIndex::ROOT, None).is_err() { debug!("overlap: leak check failed"); return None; } let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes(); debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes); - - let involves_placeholder = - matches!(selcx.infcx.region_constraints_added_in_snapshot(snapshot), Some(true)); + let involves_placeholder = infcx + .inner + .borrow_mut() + .unwrap_region_constraints() + .data() + .constraints + .iter() + .any(|c| c.0.involves_placeholders()); let impl_header = selcx.infcx.resolve_vars_if_possible(impl1_header); Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder }) diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index edbe2de8105e..a8a74d7501ab 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -90,7 +90,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { Ok(EvaluationResult::EvaluatedToAmbig) } else if self.opaque_types_added_in_snapshot(snapshot) { Ok(EvaluationResult::EvaluatedToOkModuloOpaqueTypes) - } else if self.region_constraints_added_in_snapshot(snapshot).is_some() { + } else if self.region_constraints_added_in_snapshot(snapshot) { Ok(EvaluationResult::EvaluatedToOkModuloRegions) } else { Ok(EvaluationResult::EvaluatedToOk) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 2c0b911c8050..42c1b629ac24 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -561,9 +561,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { op: impl FnOnce(&mut Self) -> Result, ) -> Result { self.infcx.probe(|snapshot| -> Result { + let outer_universe = self.infcx.universe(); let result = op(self)?; - match self.infcx.leak_check(snapshot) { + match self.infcx.leak_check(outer_universe, Some(snapshot)) { Ok(()) => {} Err(_) => return Ok(EvaluatedToErr), } @@ -572,9 +573,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Ok(result.max(EvaluatedToOkModuloOpaqueTypes)); } - match self.infcx.region_constraints_added_in_snapshot(snapshot) { - None => Ok(result), - Some(_) => Ok(result.max(EvaluatedToOkModuloRegions)), + if self.infcx.region_constraints_added_in_snapshot(snapshot) { + Ok(result.max(EvaluatedToOkModuloRegions)) + } else { + Ok(result) } }) } From 6b92d45342f14f7a38355923f75ab3702852ad8a Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 23 May 2023 19:00:47 +0200 Subject: [PATCH 54/69] change redundant `clear()` to assertion --- compiler/rustc_infer/src/infer/undo_log.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_infer/src/infer/undo_log.rs b/compiler/rustc_infer/src/infer/undo_log.rs index 8dd1a7c5f21f..25d06b21ec84 100644 --- a/compiler/rustc_infer/src/infer/undo_log.rs +++ b/compiler/rustc_infer/src/infer/undo_log.rs @@ -138,11 +138,9 @@ impl<'tcx> InferCtxtInner<'tcx> { } if self.undo_log.num_open_snapshots == 1 { - // The root snapshot. It's safe to clear the undo log because - // there's no snapshot further out that we might need to roll back - // to. + // After the root snapshot the undo log should be empty. assert!(snapshot.undo_len == 0); - self.undo_log.logs.clear(); + assert!(self.undo_log.logs.is_empty()); } self.undo_log.num_open_snapshots -= 1; From 04056b5c04e0574d5631f04baab99d6fcd778550 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 23 May 2023 19:17:10 +0200 Subject: [PATCH 55/69] update revision names --- tests/ui/coinduction/canonicalization-rerun.rs | 4 ++-- .../{issue-95230.new.stderr => issue-95230.next.stderr} | 0 tests/ui/higher-rank-trait-bounds/issue-95230.rs | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) rename tests/ui/higher-rank-trait-bounds/{issue-95230.new.stderr => issue-95230.next.stderr} (100%) diff --git a/tests/ui/coinduction/canonicalization-rerun.rs b/tests/ui/coinduction/canonicalization-rerun.rs index b10ba3a810fd..c68895fc4e63 100644 --- a/tests/ui/coinduction/canonicalization-rerun.rs +++ b/tests/ui/coinduction/canonicalization-rerun.rs @@ -1,6 +1,6 @@ // check-pass -// revisions: old new -//[new] compile-flags: -Ztrait-solver=next +// revisions: old next +//[next] compile-flags: -Ztrait-solver=next // If we use canonical goals during trait solving we have to reevaluate // the root goal of a cycle until we hit a fixpoint. diff --git a/tests/ui/higher-rank-trait-bounds/issue-95230.new.stderr b/tests/ui/higher-rank-trait-bounds/issue-95230.next.stderr similarity index 100% rename from tests/ui/higher-rank-trait-bounds/issue-95230.new.stderr rename to tests/ui/higher-rank-trait-bounds/issue-95230.next.stderr diff --git a/tests/ui/higher-rank-trait-bounds/issue-95230.rs b/tests/ui/higher-rank-trait-bounds/issue-95230.rs index 769b6a925376..49a1584d54e0 100644 --- a/tests/ui/higher-rank-trait-bounds/issue-95230.rs +++ b/tests/ui/higher-rank-trait-bounds/issue-95230.rs @@ -1,7 +1,7 @@ -// revisions: old new -//[new] compile-flags: -Ztrait-solver=next +// revisions: old next +//[next] compile-flags: -Ztrait-solver=next //[old] check-pass -//[new] known-bug: #109764 +//[next] known-bug: #109764 pub struct Bar From 6f9041bd1572239bec2d8653b84ea4ddd2a7d22d Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 23 May 2023 19:34:17 +0200 Subject: [PATCH 56/69] add the leak check to the new solver --- .../src/solve/eval_ctxt/canonical.rs | 5 ++++ .../higher-ranked/leak-check-in-selection.rs | 24 +++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 tests/ui/higher-ranked/leak-check-in-selection.rs diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs index fdb209fbff87..91a093f30bd5 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -137,6 +137,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { #[instrument(level = "debug", skip(self), ret)] fn compute_external_query_constraints(&self) -> Result, NoSolution> { + self.infcx.leak_check(ty::UniverseIndex::ROOT, None).map_err(|e| { + debug!(?e, "failed the leak check"); + NoSolution + })?; + // Cannot use `take_registered_region_obligations` as we may compute the response // inside of a `probe` whenever we have multiple choices inside of the solver. let region_obligations = self.infcx.inner.borrow().region_obligations().to_owned(); diff --git a/tests/ui/higher-ranked/leak-check-in-selection.rs b/tests/ui/higher-ranked/leak-check-in-selection.rs new file mode 100644 index 000000000000..e8d6cff856c9 --- /dev/null +++ b/tests/ui/higher-ranked/leak-check-in-selection.rs @@ -0,0 +1,24 @@ +// run-pass +// revisions: old next +//[next] compile-flags: -Ztrait-solver=next +#![allow(coherence_leak_check)] + +trait Trait: Sized { + fn is_higher_ranked(self) -> bool; +} + +impl Trait for for<'a> fn(&'a ()) { + fn is_higher_ranked(self) -> bool { + true + } +} +impl<'a> Trait for fn(&'a ()) { + fn is_higher_ranked(self) -> bool { + false + } +} + +fn main() { + let x: for<'a> fn(&'a ()) = |&()| (); + assert!(x.is_higher_ranked()); +} From 5119f7da18eb7f10457d3e4b2c1d60f8d94a4cbf Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 23 May 2023 20:04:51 +0200 Subject: [PATCH 57/69] directory size limit :< --- src/tools/tidy/src/ui_tests.rs | 2 +- tests/ui/{ => higher-ranked}/higher-lifetime-bounds.rs | 0 tests/ui/{ => higher-ranked}/higher-lifetime-bounds.stderr | 0 .../subtype}/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr | 0 .../subtype}/hr-subtype.bound_a_vs_free_x.stderr | 0 .../subtype}/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr | 0 .../subtype}/hr-subtype.free_inv_x_vs_free_inv_y.stderr | 0 .../subtype}/hr-subtype.free_x_vs_free_y.stderr | 0 tests/ui/{hr-subtype => higher-ranked/subtype}/hr-subtype.rs | 0 .../subtype}/placeholder-pattern-fail.rs | 0 .../subtype}/placeholder-pattern-fail.stderr | 0 .../subtype}/placeholder-pattern.rs | 0 tests/ui/{hr-subtype => higher-ranked/subtype}/return-static.rs | 0 .../trait-bounds}/complex.rs | 0 .../trait-bounds}/due-to-where-clause.rs | 0 .../trait-bounds}/due-to-where-clause.stderr | 0 .../trait-bounds}/fn-ptr.classic.stderr | 0 .../trait-bounds}/fn-ptr.rs | 0 .../trait-bounds}/hang-on-deeply-nested-dyn.rs | 0 .../trait-bounds}/hang-on-deeply-nested-dyn.stderr | 2 +- .../trait-bounds}/hrtb-binder-levels-in-object-types.rs | 0 .../trait-bounds}/hrtb-cache-issue-54302.rs | 0 .../trait-bounds}/hrtb-cache-issue-54302.stderr | 0 .../trait-bounds}/hrtb-conflate-regions.rs | 0 .../trait-bounds}/hrtb-conflate-regions.stderr | 0 .../trait-bounds}/hrtb-debruijn-in-receiver.rs | 0 .../trait-bounds}/hrtb-debruijn-in-receiver.stderr | 0 .../trait-bounds}/hrtb-debruijn-object-types-in-closures.rs | 0 .../trait-bounds}/hrtb-exists-forall-fn.rs | 0 .../trait-bounds}/hrtb-exists-forall-fn.stderr | 0 .../trait-bounds}/hrtb-exists-forall-trait-contravariant.rs | 0 .../trait-bounds}/hrtb-exists-forall-trait-contravariant.stderr | 0 .../trait-bounds}/hrtb-exists-forall-trait-covariant.rs | 0 .../trait-bounds}/hrtb-exists-forall-trait-invariant.rs | 0 .../trait-bounds}/hrtb-exists-forall-trait-invariant.stderr | 0 .../trait-bounds}/hrtb-fn-like-trait-object.rs | 0 .../trait-bounds}/hrtb-fn-like-trait.rs | 0 .../trait-bounds}/hrtb-higher-ranker-supertraits-transitive.rs | 0 .../hrtb-higher-ranker-supertraits-transitive.stderr | 0 .../trait-bounds}/hrtb-higher-ranker-supertraits.rs | 0 .../trait-bounds}/hrtb-higher-ranker-supertraits.stderr | 0 .../trait-bounds}/hrtb-identity-fn-borrows.rs | 0 .../trait-bounds}/hrtb-identity-fn-borrows.stderr | 0 .../trait-bounds}/hrtb-just-for-static.rs | 0 .../trait-bounds}/hrtb-just-for-static.stderr | 0 .../trait-bounds}/hrtb-malformed-lifetime-generics.rs | 0 .../trait-bounds}/hrtb-malformed-lifetime-generics.stderr | 0 .../trait-bounds}/hrtb-opt-in-copy.rs | 0 .../trait-bounds}/hrtb-parse.rs | 0 .../trait-bounds}/hrtb-perfect-forwarding.polonius.stderr | 0 .../trait-bounds}/hrtb-perfect-forwarding.rs | 0 .../trait-bounds}/hrtb-perfect-forwarding.stderr | 0 .../trait-bounds}/hrtb-precedence-of-plus-where-clause.rs | 0 .../trait-bounds}/hrtb-precedence-of-plus.rs | 0 .../trait-bounds}/hrtb-resolve-lifetime.rs | 0 .../trait-bounds}/hrtb-trait-object-paren-notation.rs | 0 .../trait-bounds}/hrtb-trait-object-passed-to-closure.rs | 0 .../trait-bounds}/hrtb-type-outlives.rs | 0 .../trait-bounds}/hrtb-unboxed-closure-trait.rs | 0 .../trait-bounds}/hrtb-wrong-kind.rs | 0 .../trait-bounds}/hrtb-wrong-kind.stderr | 0 .../trait-bounds}/issue-100689.rs | 0 .../trait-bounds}/issue-102899.rs | 0 .../trait-bounds}/issue-30786.rs | 0 .../trait-bounds}/issue-30786.stderr | 2 +- .../trait-bounds}/issue-36139-normalize-closure-sig.rs | 0 .../trait-bounds}/issue-39292.rs | 0 .../trait-bounds}/issue-42114.rs | 0 .../trait-bounds}/issue-43623.rs | 0 .../trait-bounds}/issue-46989.rs | 0 .../trait-bounds}/issue-46989.stderr | 0 .../trait-bounds}/issue-57639.rs | 0 .../trait-bounds}/issue-58451.rs | 0 .../trait-bounds}/issue-58451.stderr | 0 .../trait-bounds}/issue-59311.rs | 0 .../trait-bounds}/issue-59311.stderr | 0 .../trait-bounds}/issue-60283.rs | 0 .../trait-bounds}/issue-62203-hrtb-ice.rs | 0 .../trait-bounds}/issue-62203-hrtb-ice.stderr | 0 .../trait-bounds}/issue-88446.rs | 0 .../trait-bounds}/issue-88586-hr-self-outlives-in-trait-def.rs | 0 .../trait-bounds}/issue-90177.rs | 0 .../trait-bounds}/issue-95034.rs | 0 .../trait-bounds}/issue-95230.next.stderr | 0 .../trait-bounds}/issue-95230.rs | 0 .../trait-bounds}/normalize-under-binder/issue-44005.rs | 0 .../trait-bounds}/normalize-under-binder/issue-56556.rs | 0 .../trait-bounds}/normalize-under-binder/issue-62529-1.rs | 0 .../trait-bounds}/normalize-under-binder/issue-62529-2.rs | 0 .../trait-bounds}/normalize-under-binder/issue-62529-3.rs | 0 .../trait-bounds}/normalize-under-binder/issue-62529-3.stderr | 0 .../trait-bounds}/normalize-under-binder/issue-62529-4.rs | 0 .../trait-bounds}/normalize-under-binder/issue-62529-5.rs | 0 .../trait-bounds}/normalize-under-binder/issue-62529-6.rs | 0 .../trait-bounds}/normalize-under-binder/issue-70120.rs | 0 .../normalize-under-binder/issue-71955.migrate.stderr | 0 .../trait-bounds}/normalize-under-binder/issue-71955.rs | 0 .../trait-bounds}/normalize-under-binder/issue-71955.stderr | 0 .../trait-bounds}/normalize-under-binder/issue-74261.rs | 0 .../trait-bounds}/normalize-under-binder/issue-76956.rs | 0 .../trait-bounds}/normalize-under-binder/issue-80706.rs | 0 .../trait-bounds}/normalize-under-binder/issue-80956.rs | 0 .../trait-bounds}/normalize-under-binder/issue-81809.rs | 0 .../trait-bounds}/normalize-under-binder/issue-85455.rs | 0 .../trait-bounds}/normalize-under-binder/issue-85455.stderr | 0 .../trait-bounds}/normalize-under-binder/issue-89118.rs | 0 .../trait-bounds}/normalize-under-binder/issue-89118.stderr | 0 .../trait-bounds}/normalize-under-binder/issue-89436.rs | 0 .../trait-bounds}/normalize-under-binder/issue-90612.rs | 0 .../trait-bounds}/normalize-under-binder/issue-90638.rs | 0 .../trait-bounds}/normalize-under-binder/issue-90875.rs | 0 .../trait-bounds}/normalize-under-binder/issue-90950.rs | 0 .../trait-bounds}/normalize-under-binder/issue-90950.stderr | 0 .../normalize-under-binder/norm-before-method-resolution.rs | 0 .../normalize-under-binder/norm-before-method-resolution.stderr | 0 115 files changed, 3 insertions(+), 3 deletions(-) rename tests/ui/{ => higher-ranked}/higher-lifetime-bounds.rs (100%) rename tests/ui/{ => higher-ranked}/higher-lifetime-bounds.stderr (100%) rename tests/ui/{hr-subtype => higher-ranked/subtype}/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr (100%) rename tests/ui/{hr-subtype => higher-ranked/subtype}/hr-subtype.bound_a_vs_free_x.stderr (100%) rename tests/ui/{hr-subtype => higher-ranked/subtype}/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr (100%) rename tests/ui/{hr-subtype => higher-ranked/subtype}/hr-subtype.free_inv_x_vs_free_inv_y.stderr (100%) rename tests/ui/{hr-subtype => higher-ranked/subtype}/hr-subtype.free_x_vs_free_y.stderr (100%) rename tests/ui/{hr-subtype => higher-ranked/subtype}/hr-subtype.rs (100%) rename tests/ui/{hr-subtype => higher-ranked/subtype}/placeholder-pattern-fail.rs (100%) rename tests/ui/{hr-subtype => higher-ranked/subtype}/placeholder-pattern-fail.stderr (100%) rename tests/ui/{hr-subtype => higher-ranked/subtype}/placeholder-pattern.rs (100%) rename tests/ui/{hr-subtype => higher-ranked/subtype}/return-static.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/complex.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/due-to-where-clause.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/due-to-where-clause.stderr (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/fn-ptr.classic.stderr (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/fn-ptr.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hang-on-deeply-nested-dyn.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hang-on-deeply-nested-dyn.stderr (91%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-binder-levels-in-object-types.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-cache-issue-54302.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-cache-issue-54302.stderr (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-conflate-regions.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-conflate-regions.stderr (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-debruijn-in-receiver.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-debruijn-in-receiver.stderr (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-debruijn-object-types-in-closures.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-exists-forall-fn.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-exists-forall-fn.stderr (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-exists-forall-trait-contravariant.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-exists-forall-trait-contravariant.stderr (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-exists-forall-trait-covariant.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-exists-forall-trait-invariant.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-exists-forall-trait-invariant.stderr (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-fn-like-trait-object.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-fn-like-trait.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-higher-ranker-supertraits-transitive.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-higher-ranker-supertraits-transitive.stderr (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-higher-ranker-supertraits.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-higher-ranker-supertraits.stderr (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-identity-fn-borrows.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-identity-fn-borrows.stderr (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-just-for-static.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-just-for-static.stderr (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-malformed-lifetime-generics.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-malformed-lifetime-generics.stderr (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-opt-in-copy.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-parse.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-perfect-forwarding.polonius.stderr (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-perfect-forwarding.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-perfect-forwarding.stderr (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-precedence-of-plus-where-clause.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-precedence-of-plus.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-resolve-lifetime.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-trait-object-paren-notation.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-trait-object-passed-to-closure.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-type-outlives.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-unboxed-closure-trait.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-wrong-kind.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/hrtb-wrong-kind.stderr (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/issue-100689.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/issue-102899.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/issue-30786.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/issue-30786.stderr (97%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/issue-36139-normalize-closure-sig.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/issue-39292.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/issue-42114.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/issue-43623.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/issue-46989.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/issue-46989.stderr (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/issue-57639.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/issue-58451.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/issue-58451.stderr (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/issue-59311.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/issue-59311.stderr (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/issue-60283.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/issue-62203-hrtb-ice.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/issue-62203-hrtb-ice.stderr (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/issue-88446.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/issue-88586-hr-self-outlives-in-trait-def.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/issue-90177.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/issue-95034.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/issue-95230.next.stderr (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/issue-95230.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/normalize-under-binder/issue-44005.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/normalize-under-binder/issue-56556.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/normalize-under-binder/issue-62529-1.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/normalize-under-binder/issue-62529-2.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/normalize-under-binder/issue-62529-3.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/normalize-under-binder/issue-62529-3.stderr (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/normalize-under-binder/issue-62529-4.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/normalize-under-binder/issue-62529-5.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/normalize-under-binder/issue-62529-6.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/normalize-under-binder/issue-70120.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/normalize-under-binder/issue-71955.migrate.stderr (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/normalize-under-binder/issue-71955.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/normalize-under-binder/issue-71955.stderr (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/normalize-under-binder/issue-74261.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/normalize-under-binder/issue-76956.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/normalize-under-binder/issue-80706.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/normalize-under-binder/issue-80956.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/normalize-under-binder/issue-81809.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/normalize-under-binder/issue-85455.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/normalize-under-binder/issue-85455.stderr (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/normalize-under-binder/issue-89118.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/normalize-under-binder/issue-89118.stderr (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/normalize-under-binder/issue-89436.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/normalize-under-binder/issue-90612.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/normalize-under-binder/issue-90638.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/normalize-under-binder/issue-90875.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/normalize-under-binder/issue-90950.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/normalize-under-binder/issue-90950.stderr (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/normalize-under-binder/norm-before-method-resolution.rs (100%) rename tests/ui/{higher-rank-trait-bounds => higher-ranked/trait-bounds}/normalize-under-binder/norm-before-method-resolution.stderr (100%) diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 3e9bf18a2871..01ef4abd3dca 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -11,7 +11,7 @@ use std::path::{Path, PathBuf}; const ENTRY_LIMIT: usize = 900; // FIXME: The following limits should be reduced eventually. const ISSUES_ENTRY_LIMIT: usize = 1898; -const ROOT_ENTRY_LIMIT: usize = 894; +const ROOT_ENTRY_LIMIT: usize = 891; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files diff --git a/tests/ui/higher-lifetime-bounds.rs b/tests/ui/higher-ranked/higher-lifetime-bounds.rs similarity index 100% rename from tests/ui/higher-lifetime-bounds.rs rename to tests/ui/higher-ranked/higher-lifetime-bounds.rs diff --git a/tests/ui/higher-lifetime-bounds.stderr b/tests/ui/higher-ranked/higher-lifetime-bounds.stderr similarity index 100% rename from tests/ui/higher-lifetime-bounds.stderr rename to tests/ui/higher-ranked/higher-lifetime-bounds.stderr diff --git a/tests/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr b/tests/ui/higher-ranked/subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr similarity index 100% rename from tests/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr rename to tests/ui/higher-ranked/subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr diff --git a/tests/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr b/tests/ui/higher-ranked/subtype/hr-subtype.bound_a_vs_free_x.stderr similarity index 100% rename from tests/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr rename to tests/ui/higher-ranked/subtype/hr-subtype.bound_a_vs_free_x.stderr diff --git a/tests/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr b/tests/ui/higher-ranked/subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr similarity index 100% rename from tests/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr rename to tests/ui/higher-ranked/subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr diff --git a/tests/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr b/tests/ui/higher-ranked/subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr similarity index 100% rename from tests/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr rename to tests/ui/higher-ranked/subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr diff --git a/tests/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr b/tests/ui/higher-ranked/subtype/hr-subtype.free_x_vs_free_y.stderr similarity index 100% rename from tests/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr rename to tests/ui/higher-ranked/subtype/hr-subtype.free_x_vs_free_y.stderr diff --git a/tests/ui/hr-subtype/hr-subtype.rs b/tests/ui/higher-ranked/subtype/hr-subtype.rs similarity index 100% rename from tests/ui/hr-subtype/hr-subtype.rs rename to tests/ui/higher-ranked/subtype/hr-subtype.rs diff --git a/tests/ui/hr-subtype/placeholder-pattern-fail.rs b/tests/ui/higher-ranked/subtype/placeholder-pattern-fail.rs similarity index 100% rename from tests/ui/hr-subtype/placeholder-pattern-fail.rs rename to tests/ui/higher-ranked/subtype/placeholder-pattern-fail.rs diff --git a/tests/ui/hr-subtype/placeholder-pattern-fail.stderr b/tests/ui/higher-ranked/subtype/placeholder-pattern-fail.stderr similarity index 100% rename from tests/ui/hr-subtype/placeholder-pattern-fail.stderr rename to tests/ui/higher-ranked/subtype/placeholder-pattern-fail.stderr diff --git a/tests/ui/hr-subtype/placeholder-pattern.rs b/tests/ui/higher-ranked/subtype/placeholder-pattern.rs similarity index 100% rename from tests/ui/hr-subtype/placeholder-pattern.rs rename to tests/ui/higher-ranked/subtype/placeholder-pattern.rs diff --git a/tests/ui/hr-subtype/return-static.rs b/tests/ui/higher-ranked/subtype/return-static.rs similarity index 100% rename from tests/ui/hr-subtype/return-static.rs rename to tests/ui/higher-ranked/subtype/return-static.rs diff --git a/tests/ui/higher-rank-trait-bounds/complex.rs b/tests/ui/higher-ranked/trait-bounds/complex.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/complex.rs rename to tests/ui/higher-ranked/trait-bounds/complex.rs diff --git a/tests/ui/higher-rank-trait-bounds/due-to-where-clause.rs b/tests/ui/higher-ranked/trait-bounds/due-to-where-clause.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/due-to-where-clause.rs rename to tests/ui/higher-ranked/trait-bounds/due-to-where-clause.rs diff --git a/tests/ui/higher-rank-trait-bounds/due-to-where-clause.stderr b/tests/ui/higher-ranked/trait-bounds/due-to-where-clause.stderr similarity index 100% rename from tests/ui/higher-rank-trait-bounds/due-to-where-clause.stderr rename to tests/ui/higher-ranked/trait-bounds/due-to-where-clause.stderr diff --git a/tests/ui/higher-rank-trait-bounds/fn-ptr.classic.stderr b/tests/ui/higher-ranked/trait-bounds/fn-ptr.classic.stderr similarity index 100% rename from tests/ui/higher-rank-trait-bounds/fn-ptr.classic.stderr rename to tests/ui/higher-ranked/trait-bounds/fn-ptr.classic.stderr diff --git a/tests/ui/higher-rank-trait-bounds/fn-ptr.rs b/tests/ui/higher-ranked/trait-bounds/fn-ptr.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/fn-ptr.rs rename to tests/ui/higher-ranked/trait-bounds/fn-ptr.rs diff --git a/tests/ui/higher-rank-trait-bounds/hang-on-deeply-nested-dyn.rs b/tests/ui/higher-ranked/trait-bounds/hang-on-deeply-nested-dyn.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hang-on-deeply-nested-dyn.rs rename to tests/ui/higher-ranked/trait-bounds/hang-on-deeply-nested-dyn.rs diff --git a/tests/ui/higher-rank-trait-bounds/hang-on-deeply-nested-dyn.stderr b/tests/ui/higher-ranked/trait-bounds/hang-on-deeply-nested-dyn.stderr similarity index 91% rename from tests/ui/higher-rank-trait-bounds/hang-on-deeply-nested-dyn.stderr rename to tests/ui/higher-ranked/trait-bounds/hang-on-deeply-nested-dyn.stderr index 3662cbfb9ba1..a9d649b82852 100644 --- a/tests/ui/higher-rank-trait-bounds/hang-on-deeply-nested-dyn.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hang-on-deeply-nested-dyn.stderr @@ -14,7 +14,7 @@ LL | f | ^ expected `&dyn Fn(&dyn Fn(&dyn Fn(&...)))`, found `&dyn Fn(u32)` | = note: expected reference `&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&...)))))))))))` - the full type name has been written to '$TEST_BUILD_DIR/higher-rank-trait-bounds/hang-on-deeply-nested-dyn/hang-on-deeply-nested-dyn.long-type-hash.txt' + the full type name has been written to '$TEST_BUILD_DIR/higher-ranked/trait-bounds/hang-on-deeply-nested-dyn/hang-on-deeply-nested-dyn.long-type-hash.txt' found reference `&dyn Fn(u32)` error: aborting due to previous error diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-binder-levels-in-object-types.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-binder-levels-in-object-types.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-binder-levels-in-object-types.rs rename to tests/ui/higher-ranked/trait-bounds/hrtb-binder-levels-in-object-types.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-cache-issue-54302.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-cache-issue-54302.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-cache-issue-54302.rs rename to tests/ui/higher-ranked/trait-bounds/hrtb-cache-issue-54302.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-cache-issue-54302.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-cache-issue-54302.stderr similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-cache-issue-54302.stderr rename to tests/ui/higher-ranked/trait-bounds/hrtb-cache-issue-54302.stderr diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-conflate-regions.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-conflate-regions.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-conflate-regions.rs rename to tests/ui/higher-ranked/trait-bounds/hrtb-conflate-regions.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-conflate-regions.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-conflate-regions.stderr similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-conflate-regions.stderr rename to tests/ui/higher-ranked/trait-bounds/hrtb-conflate-regions.stderr diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-debruijn-in-receiver.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-debruijn-in-receiver.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-debruijn-in-receiver.rs rename to tests/ui/higher-ranked/trait-bounds/hrtb-debruijn-in-receiver.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-debruijn-in-receiver.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-debruijn-in-receiver.stderr similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-debruijn-in-receiver.stderr rename to tests/ui/higher-ranked/trait-bounds/hrtb-debruijn-in-receiver.stderr diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-debruijn-object-types-in-closures.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-debruijn-object-types-in-closures.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-debruijn-object-types-in-closures.rs rename to tests/ui/higher-ranked/trait-bounds/hrtb-debruijn-object-types-in-closures.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-fn.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-fn.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-fn.rs rename to tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-fn.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-fn.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-fn.stderr similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-fn.stderr rename to tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-fn.stderr diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-contravariant.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-contravariant.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-contravariant.rs rename to tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-contravariant.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-contravariant.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-contravariant.stderr similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-contravariant.stderr rename to tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-contravariant.stderr diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-covariant.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-covariant.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-covariant.rs rename to tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-covariant.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-invariant.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-invariant.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-invariant.rs rename to tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-invariant.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-invariant.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-invariant.stderr similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-invariant.stderr rename to tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-invariant.stderr diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-fn-like-trait-object.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-fn-like-trait-object.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-fn-like-trait-object.rs rename to tests/ui/higher-ranked/trait-bounds/hrtb-fn-like-trait-object.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-fn-like-trait.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-fn-like-trait.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-fn-like-trait.rs rename to tests/ui/higher-ranked/trait-bounds/hrtb-fn-like-trait.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits-transitive.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits-transitive.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits-transitive.rs rename to tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits-transitive.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr rename to tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits.rs rename to tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.stderr similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits.stderr rename to tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.stderr diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-identity-fn-borrows.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-identity-fn-borrows.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-identity-fn-borrows.rs rename to tests/ui/higher-ranked/trait-bounds/hrtb-identity-fn-borrows.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-identity-fn-borrows.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-identity-fn-borrows.stderr similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-identity-fn-borrows.stderr rename to tests/ui/higher-ranked/trait-bounds/hrtb-identity-fn-borrows.stderr diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-just-for-static.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-just-for-static.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-just-for-static.rs rename to tests/ui/higher-ranked/trait-bounds/hrtb-just-for-static.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-just-for-static.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-just-for-static.stderr similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-just-for-static.stderr rename to tests/ui/higher-ranked/trait-bounds/hrtb-just-for-static.stderr diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-malformed-lifetime-generics.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-malformed-lifetime-generics.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-malformed-lifetime-generics.rs rename to tests/ui/higher-ranked/trait-bounds/hrtb-malformed-lifetime-generics.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-malformed-lifetime-generics.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-malformed-lifetime-generics.stderr similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-malformed-lifetime-generics.stderr rename to tests/ui/higher-ranked/trait-bounds/hrtb-malformed-lifetime-generics.stderr diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-opt-in-copy.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-opt-in-copy.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-opt-in-copy.rs rename to tests/ui/higher-ranked/trait-bounds/hrtb-opt-in-copy.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-parse.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-parse.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-parse.rs rename to tests/ui/higher-ranked/trait-bounds/hrtb-parse.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.polonius.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.polonius.stderr similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.polonius.stderr rename to tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.polonius.stderr diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.rs rename to tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.stderr similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.stderr rename to tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.stderr diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-precedence-of-plus-where-clause.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-precedence-of-plus-where-clause.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-precedence-of-plus-where-clause.rs rename to tests/ui/higher-ranked/trait-bounds/hrtb-precedence-of-plus-where-clause.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-precedence-of-plus.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-precedence-of-plus.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-precedence-of-plus.rs rename to tests/ui/higher-ranked/trait-bounds/hrtb-precedence-of-plus.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-resolve-lifetime.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-resolve-lifetime.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-resolve-lifetime.rs rename to tests/ui/higher-ranked/trait-bounds/hrtb-resolve-lifetime.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-trait-object-paren-notation.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-trait-object-paren-notation.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-trait-object-paren-notation.rs rename to tests/ui/higher-ranked/trait-bounds/hrtb-trait-object-paren-notation.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-trait-object-passed-to-closure.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-trait-object-passed-to-closure.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-trait-object-passed-to-closure.rs rename to tests/ui/higher-ranked/trait-bounds/hrtb-trait-object-passed-to-closure.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-type-outlives.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-type-outlives.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-type-outlives.rs rename to tests/ui/higher-ranked/trait-bounds/hrtb-type-outlives.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-unboxed-closure-trait.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-unboxed-closure-trait.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-unboxed-closure-trait.rs rename to tests/ui/higher-ranked/trait-bounds/hrtb-unboxed-closure-trait.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-wrong-kind.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-wrong-kind.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-wrong-kind.rs rename to tests/ui/higher-ranked/trait-bounds/hrtb-wrong-kind.rs diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-wrong-kind.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-wrong-kind.stderr similarity index 100% rename from tests/ui/higher-rank-trait-bounds/hrtb-wrong-kind.stderr rename to tests/ui/higher-ranked/trait-bounds/hrtb-wrong-kind.stderr diff --git a/tests/ui/higher-rank-trait-bounds/issue-100689.rs b/tests/ui/higher-ranked/trait-bounds/issue-100689.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/issue-100689.rs rename to tests/ui/higher-ranked/trait-bounds/issue-100689.rs diff --git a/tests/ui/higher-rank-trait-bounds/issue-102899.rs b/tests/ui/higher-ranked/trait-bounds/issue-102899.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/issue-102899.rs rename to tests/ui/higher-ranked/trait-bounds/issue-102899.rs diff --git a/tests/ui/higher-rank-trait-bounds/issue-30786.rs b/tests/ui/higher-ranked/trait-bounds/issue-30786.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/issue-30786.rs rename to tests/ui/higher-ranked/trait-bounds/issue-30786.rs diff --git a/tests/ui/higher-rank-trait-bounds/issue-30786.stderr b/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr similarity index 97% rename from tests/ui/higher-rank-trait-bounds/issue-30786.stderr rename to tests/ui/higher-ranked/trait-bounds/issue-30786.stderr index 6ec34d11a7e9..f32ba57200d5 100644 --- a/tests/ui/higher-rank-trait-bounds/issue-30786.stderr +++ b/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr @@ -31,7 +31,7 @@ LL | pub struct Filter { LL | let count = filter.countx(); | ^^^^^^ method cannot be called due to unsatisfied trait bounds | - = note: the full type name has been written to '$TEST_BUILD_DIR/higher-rank-trait-bounds/issue-30786/issue-30786.long-type-hash.txt' + = note: the full type name has been written to '$TEST_BUILD_DIR/higher-ranked/trait-bounds/issue-30786/issue-30786.long-type-hash.txt' note: the following trait bounds were not satisfied: `&'a mut &Filter fn(&'a u64) -> &'a u64 {identity::}>, [closure@$DIR/issue-30786.rs:131:30: 131:37]>: Stream` `&'a mut &mut Filter fn(&'a u64) -> &'a u64 {identity::}>, [closure@$DIR/issue-30786.rs:131:30: 131:37]>: Stream` diff --git a/tests/ui/higher-rank-trait-bounds/issue-36139-normalize-closure-sig.rs b/tests/ui/higher-ranked/trait-bounds/issue-36139-normalize-closure-sig.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/issue-36139-normalize-closure-sig.rs rename to tests/ui/higher-ranked/trait-bounds/issue-36139-normalize-closure-sig.rs diff --git a/tests/ui/higher-rank-trait-bounds/issue-39292.rs b/tests/ui/higher-ranked/trait-bounds/issue-39292.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/issue-39292.rs rename to tests/ui/higher-ranked/trait-bounds/issue-39292.rs diff --git a/tests/ui/higher-rank-trait-bounds/issue-42114.rs b/tests/ui/higher-ranked/trait-bounds/issue-42114.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/issue-42114.rs rename to tests/ui/higher-ranked/trait-bounds/issue-42114.rs diff --git a/tests/ui/higher-rank-trait-bounds/issue-43623.rs b/tests/ui/higher-ranked/trait-bounds/issue-43623.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/issue-43623.rs rename to tests/ui/higher-ranked/trait-bounds/issue-43623.rs diff --git a/tests/ui/higher-rank-trait-bounds/issue-46989.rs b/tests/ui/higher-ranked/trait-bounds/issue-46989.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/issue-46989.rs rename to tests/ui/higher-ranked/trait-bounds/issue-46989.rs diff --git a/tests/ui/higher-rank-trait-bounds/issue-46989.stderr b/tests/ui/higher-ranked/trait-bounds/issue-46989.stderr similarity index 100% rename from tests/ui/higher-rank-trait-bounds/issue-46989.stderr rename to tests/ui/higher-ranked/trait-bounds/issue-46989.stderr diff --git a/tests/ui/higher-rank-trait-bounds/issue-57639.rs b/tests/ui/higher-ranked/trait-bounds/issue-57639.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/issue-57639.rs rename to tests/ui/higher-ranked/trait-bounds/issue-57639.rs diff --git a/tests/ui/higher-rank-trait-bounds/issue-58451.rs b/tests/ui/higher-ranked/trait-bounds/issue-58451.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/issue-58451.rs rename to tests/ui/higher-ranked/trait-bounds/issue-58451.rs diff --git a/tests/ui/higher-rank-trait-bounds/issue-58451.stderr b/tests/ui/higher-ranked/trait-bounds/issue-58451.stderr similarity index 100% rename from tests/ui/higher-rank-trait-bounds/issue-58451.stderr rename to tests/ui/higher-ranked/trait-bounds/issue-58451.stderr diff --git a/tests/ui/higher-rank-trait-bounds/issue-59311.rs b/tests/ui/higher-ranked/trait-bounds/issue-59311.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/issue-59311.rs rename to tests/ui/higher-ranked/trait-bounds/issue-59311.rs diff --git a/tests/ui/higher-rank-trait-bounds/issue-59311.stderr b/tests/ui/higher-ranked/trait-bounds/issue-59311.stderr similarity index 100% rename from tests/ui/higher-rank-trait-bounds/issue-59311.stderr rename to tests/ui/higher-ranked/trait-bounds/issue-59311.stderr diff --git a/tests/ui/higher-rank-trait-bounds/issue-60283.rs b/tests/ui/higher-ranked/trait-bounds/issue-60283.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/issue-60283.rs rename to tests/ui/higher-ranked/trait-bounds/issue-60283.rs diff --git a/tests/ui/higher-rank-trait-bounds/issue-62203-hrtb-ice.rs b/tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/issue-62203-hrtb-ice.rs rename to tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.rs diff --git a/tests/ui/higher-rank-trait-bounds/issue-62203-hrtb-ice.stderr b/tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.stderr similarity index 100% rename from tests/ui/higher-rank-trait-bounds/issue-62203-hrtb-ice.stderr rename to tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.stderr diff --git a/tests/ui/higher-rank-trait-bounds/issue-88446.rs b/tests/ui/higher-ranked/trait-bounds/issue-88446.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/issue-88446.rs rename to tests/ui/higher-ranked/trait-bounds/issue-88446.rs diff --git a/tests/ui/higher-rank-trait-bounds/issue-88586-hr-self-outlives-in-trait-def.rs b/tests/ui/higher-ranked/trait-bounds/issue-88586-hr-self-outlives-in-trait-def.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/issue-88586-hr-self-outlives-in-trait-def.rs rename to tests/ui/higher-ranked/trait-bounds/issue-88586-hr-self-outlives-in-trait-def.rs diff --git a/tests/ui/higher-rank-trait-bounds/issue-90177.rs b/tests/ui/higher-ranked/trait-bounds/issue-90177.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/issue-90177.rs rename to tests/ui/higher-ranked/trait-bounds/issue-90177.rs diff --git a/tests/ui/higher-rank-trait-bounds/issue-95034.rs b/tests/ui/higher-ranked/trait-bounds/issue-95034.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/issue-95034.rs rename to tests/ui/higher-ranked/trait-bounds/issue-95034.rs diff --git a/tests/ui/higher-rank-trait-bounds/issue-95230.next.stderr b/tests/ui/higher-ranked/trait-bounds/issue-95230.next.stderr similarity index 100% rename from tests/ui/higher-rank-trait-bounds/issue-95230.next.stderr rename to tests/ui/higher-ranked/trait-bounds/issue-95230.next.stderr diff --git a/tests/ui/higher-rank-trait-bounds/issue-95230.rs b/tests/ui/higher-ranked/trait-bounds/issue-95230.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/issue-95230.rs rename to tests/ui/higher-ranked/trait-bounds/issue-95230.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-44005.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-44005.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-44005.rs rename to tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-44005.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-56556.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-56556.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-56556.rs rename to tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-56556.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-1.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.rs rename to tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-1.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-2.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-2.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-2.rs rename to tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-2.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-3.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-3.rs rename to tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-3.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.stderr similarity index 100% rename from tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-3.stderr rename to tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.stderr diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-4.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-4.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-4.rs rename to tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-4.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-5.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-5.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-5.rs rename to tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-5.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-6.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-6.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-6.rs rename to tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-6.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-70120.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-70120.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-70120.rs rename to tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-70120.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.migrate.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.migrate.stderr similarity index 100% rename from tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.migrate.stderr rename to tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.migrate.stderr diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.rs rename to tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr similarity index 100% rename from tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr rename to tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-74261.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-74261.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-74261.rs rename to tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-74261.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-76956.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-76956.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-76956.rs rename to tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-76956.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-80706.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-80706.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-80706.rs rename to tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-80706.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-80956.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-80956.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-80956.rs rename to tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-80956.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-81809.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-81809.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-81809.rs rename to tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-81809.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-85455.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs rename to tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-85455.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-85455.stderr similarity index 100% rename from tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr rename to tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-85455.stderr diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.rs rename to tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.stderr similarity index 100% rename from tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.stderr rename to tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.stderr diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89436.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89436.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89436.rs rename to tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89436.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90612.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90612.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90612.rs rename to tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90612.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90638.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90638.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90638.rs rename to tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90638.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90875.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90875.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90875.rs rename to tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90875.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90950.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90950.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90950.rs rename to tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90950.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90950.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90950.stderr similarity index 100% rename from tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90950.stderr rename to tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90950.stderr diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/norm-before-method-resolution.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.rs similarity index 100% rename from tests/ui/higher-rank-trait-bounds/normalize-under-binder/norm-before-method-resolution.rs rename to tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.rs diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/norm-before-method-resolution.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.stderr similarity index 100% rename from tests/ui/higher-rank-trait-bounds/normalize-under-binder/norm-before-method-resolution.stderr rename to tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.stderr From dccc8db17dafa8b56bbfa1e57249845cb95cbe04 Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 26 May 2023 14:06:41 +0200 Subject: [PATCH 58/69] coinductive cycle leak check test --- .../leak-check-coinductive-cycle.rs | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 tests/ui/traits/new-solver/leak-check-coinductive-cycle.rs diff --git a/tests/ui/traits/new-solver/leak-check-coinductive-cycle.rs b/tests/ui/traits/new-solver/leak-check-coinductive-cycle.rs new file mode 100644 index 000000000000..1f7d4a49c901 --- /dev/null +++ b/tests/ui/traits/new-solver/leak-check-coinductive-cycle.rs @@ -0,0 +1,33 @@ +// check-pass +// compile-flags: -Ztrait-solver=next +#![feature(rustc_attrs)] + +#[rustc_coinductive] +trait Trait {} +impl<'a, 'b, T> Trait for (&'a (), &'b ()) +where + 'b: 'a, + &'a (): Trait, +{} + +impl Trait for &'static () {} +impl<'a> Trait for &'a () +where + for<'b> (&'a (), &'b ()): Trait, +{} + + +fn impls_trait, U>() {} + +fn main() { + // This infers to `impls_trait::<(&'static (), &'static ()), i32>();` + // + // In the first attempt we have 2 candidates for `&'a (): Trait<_>` + // and we get ambiguity. The result is therefore ambiguity with a `'b: 'a` + // constraint. The next attempt then uses that provisional result when + // trying to apply `impl<'a> Trait for &'a ()`. This means we get a + // `for<'b> 'b: 'a` bound which fails the leak check. Because of this we + // end up with a single impl for `&'a (): Trait<_>` which infers `_` to `i32` + // and succeeds. + impls_trait::<(&(), &()), _>(); +} From 0b81f992e9cc41d4fb957f1b9d2a99b1f73f8160 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 29 May 2023 14:35:11 +0200 Subject: [PATCH 59/69] update universe used by the leak check --- .../rustc_trait_selection/src/solve/eval_ctxt/canonical.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs index 91a093f30bd5..bca2343e4242 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -137,7 +137,9 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { #[instrument(level = "debug", skip(self), ret)] fn compute_external_query_constraints(&self) -> Result, NoSolution> { - self.infcx.leak_check(ty::UniverseIndex::ROOT, None).map_err(|e| { + // We only check for leaks from universes which were entered inside + // of the query. + self.infcx.leak_check(self.max_input_universe, None).map_err(|e| { debug!(?e, "failed the leak check"); NoSolution })?; From 5528757ffecd11f4f63cf37209382dfdccc522c2 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 30 May 2023 16:31:40 +0200 Subject: [PATCH 60/69] Fix re-export of doc hidden item inside private item not displayed --- src/librustdoc/visit_ast.rs | 57 +++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 6b7ad4cf21ae..abb9229fbd51 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -267,6 +267,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let is_no_inline = use_attrs.lists(sym::doc).has_word(sym::no_inline) || use_attrs.lists(sym::doc).has_word(sym::hidden); + if is_no_inline { + return false; + } + // For cross-crate impl inlining we need to know whether items are // reachable in documentation -- a previously unreachable item can be // made reachable by cross-crate inlining which we're checking here. @@ -281,31 +285,38 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { }; let is_private = !self.cx.cache.effective_visibilities.is_directly_public(tcx, ori_res_did); - let is_hidden = inherits_doc_hidden(tcx, res_did, None); + let is_hidden = tcx.is_doc_hidden(ori_res_did); + let item = tcx.hir().get_by_def_id(res_did); - // Only inline if requested or if the item would otherwise be stripped. - if (!please_inline && !is_private && !is_hidden) || is_no_inline { - return false; - } - - if !please_inline && - let Some(item_def_id) = reexport_chain(tcx, def_id, res_did).iter() + if !please_inline { + let inherits_hidden = inherits_doc_hidden(tcx, res_did, None); + // Only inline if requested or if the item would otherwise be stripped. + // + // If it's a doc hidden module, we need to keep it in case some of its inner items + // are re-exported. + if (!is_private && !inherits_hidden) || ( + is_hidden && + !matches!(item, Node::Item(&hir::Item { kind: hir::ItemKind::Mod(_), .. })) + ) { + return false; + } else if let Some(item_def_id) = reexport_chain(tcx, def_id, res_did).iter() .flat_map(|reexport| reexport.id()).map(|id| id.expect_local()) .chain(iter::once(res_did)).nth(1) && - item_def_id != def_id && - self - .cx - .cache - .effective_visibilities - .is_directly_public(tcx, item_def_id.to_def_id()) && - !inherits_doc_hidden(tcx, item_def_id, None) - { - // The imported item is public and not `doc(hidden)` so no need to inline it. - return false; + item_def_id != def_id && + self + .cx + .cache + .effective_visibilities + .is_directly_public(tcx, item_def_id.to_def_id()) && + !inherits_doc_hidden(tcx, item_def_id, None) + { + // The imported item is public and not `doc(hidden)` so no need to inline it. + return false; + } } let is_bang_macro = matches!( - tcx.hir().get_by_def_id(res_did), + item, Node::Item(&hir::Item { kind: hir::ItemKind::Macro(_, MacroKind::Bang), .. }) ); @@ -317,12 +328,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { // Bang macros are handled a bit on their because of how they are handled by the // compiler. If they have `#[doc(hidden)]` and the re-export doesn't have // `#[doc(inline)]`, then we don't inline it. - Node::Item(_) - if is_bang_macro - && !please_inline - && renamed.is_some() - && self.cx.tcx.is_doc_hidden(ori_res_did) => - { + Node::Item(_) if is_bang_macro && !please_inline && renamed.is_some() && is_hidden => { return false; } Node::Item(&hir::Item { kind: hir::ItemKind::Mod(ref m), .. }) if glob => { @@ -455,6 +461,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { is_glob, please_inline, ) { + debug!("Inlining {:?}", item.owner_id.def_id); continue; } } From 9906504c64a5adfbce3b6bb6a467e4d2d6f39af8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 30 May 2023 17:43:56 +0200 Subject: [PATCH 61/69] Add regression test for re-export of doc hidden item inside private item not displayed --- .../reexport-doc-hidden-inside-private.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 tests/rustdoc/reexport-doc-hidden-inside-private.rs diff --git a/tests/rustdoc/reexport-doc-hidden-inside-private.rs b/tests/rustdoc/reexport-doc-hidden-inside-private.rs new file mode 100644 index 000000000000..1e4216d3c0ca --- /dev/null +++ b/tests/rustdoc/reexport-doc-hidden-inside-private.rs @@ -0,0 +1,16 @@ +// This test ensures that a re-export of `#[doc(hidden)]` item inside a private +// module will still be displayed (the re-export, not the item). + +#![crate_name = "foo"] + +mod private_module { + #[doc(hidden)] + pub struct Public; +} + +// @has 'foo/index.html' +// @has - '//*[@id="reexport.Foo"]/code' 'pub use crate::private_module::Public as Foo;' +pub use crate::private_module::Public as Foo; +// Glob re-exports with no visible items should not be displayed. +// @count - '//*[@class="item-table"]/li' 1 +pub use crate::private_module::*; From 1862fcb1df05b116443ad3b27028616a180ffadb Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 30 May 2023 12:07:03 -0700 Subject: [PATCH 62/69] rustdoc: simplify `clean` by removing `FnRetTy` The default fn ret ty is always unit. Just use that. Looking back at the time when `FnRetTy` (then called `FunctionRetTy`) was first added to rustdoc, it seems to originally be there because `-> !` was a special form: the never type didn't exist back then. https://github.com/rust-lang/rust/commit/eb01b17b06eb35542bb80ff7456043b0ed5572ba#diff-384affc1b4190940f114f3fcebbf969e7e18657a71ef9001da6b223a036687d9L921-L924 --- src/librustdoc/clean/mod.rs | 9 ++--- src/librustdoc/clean/types.rs | 44 ++++++++-------------- src/librustdoc/html/format.rs | 39 +++++++++---------- src/librustdoc/html/render/mod.rs | 7 +++- src/librustdoc/html/render/print_item.rs | 3 +- src/librustdoc/html/render/search_index.rs | 23 +++-------- src/librustdoc/json/conversions.rs | 5 +-- 7 files changed, 49 insertions(+), 81 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 03adc19e359c..5fd867189fd7 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1111,8 +1111,8 @@ fn clean_fn_decl_with_args<'tcx>( args: Arguments, ) -> FnDecl { let output = match decl.output { - hir::FnRetTy::Return(typ) => Return(clean_ty(typ, cx)), - hir::FnRetTy::DefaultReturn(..) => DefaultReturn, + hir::FnRetTy::Return(typ) => clean_ty(typ, cx), + hir::FnRetTy::DefaultReturn(..) => Type::Tuple(Vec::new()), }; FnDecl { inputs: args, output, c_variadic: decl.c_variadic } } @@ -1126,10 +1126,7 @@ fn clean_fn_decl_from_did_and_sig<'tcx>( // We assume all empty tuples are default return type. This theoretically can discard `-> ()`, // but shouldn't change any code meaning. - let output = match clean_middle_ty(sig.output(), cx, None) { - Type::Tuple(inner) if inner.is_empty() => DefaultReturn, - ty => Return(ty), - }; + let output = clean_middle_ty(sig.output(), cx, None); FnDecl { output, diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index e9ccea2cf270..1999a6b671d3 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -42,7 +42,6 @@ use crate::formats::item_type::ItemType; use crate::html::render::Context; use crate::passes::collect_intra_doc_links::UrlFragment; -pub(crate) use self::FnRetTy::*; pub(crate) use self::ItemKind::*; pub(crate) use self::SelfTy::*; pub(crate) use self::Type::{ @@ -1353,7 +1352,7 @@ pub(crate) struct Function { #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub(crate) struct FnDecl { pub(crate) inputs: Arguments, - pub(crate) output: FnRetTy, + pub(crate) output: Type, pub(crate) c_variadic: bool, } @@ -1371,18 +1370,16 @@ impl FnDecl { /// /// This function will panic if the return type does not match the expected sugaring for async /// functions. - pub(crate) fn sugared_async_return_type(&self) -> FnRetTy { - match &self.output { - FnRetTy::Return(Type::ImplTrait(bounds)) => match &bounds[0] { - GenericBound::TraitBound(PolyTrait { trait_, .. }, ..) => { - let bindings = trait_.bindings().unwrap(); - let ret_ty = bindings[0].term(); - let ty = ret_ty.ty().expect("Unexpected constant return term"); - FnRetTy::Return(ty.clone()) - } - _ => panic!("unexpected desugaring of async function"), - }, - _ => panic!("unexpected desugaring of async function"), + pub(crate) fn sugared_async_return_type(&self) -> Type { + if let Type::ImplTrait(v) = &self.output && + let [GenericBound::TraitBound(PolyTrait { trait_, .. }, _ )] = &v[..] + { + let bindings = trait_.bindings().unwrap(); + let ret_ty = bindings[0].term(); + let ty = ret_ty.ty().expect("Unexpected constant return term"); + ty.clone() + } else { + panic!("unexpected desugaring of async function") } } } @@ -1425,21 +1422,6 @@ impl Argument { } } -#[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub(crate) enum FnRetTy { - Return(Type), - DefaultReturn, -} - -impl FnRetTy { - pub(crate) fn as_return(&self) -> Option<&Type> { - match self { - Return(ret) => Some(ret), - DefaultReturn => None, - } - } -} - #[derive(Clone, Debug)] pub(crate) struct Trait { pub(crate) def_id: DefId, @@ -1641,6 +1623,10 @@ impl Type { matches!(self, Type::ImplTrait(_)) } + pub(crate) fn is_unit(&self) -> bool { + matches!(self, Type::Tuple(v) if v.is_empty()) + } + pub(crate) fn projection(&self) -> Option<(&Type, DefId, PathSegment)> { if let QPath(box QPathData { self_type, trait_, assoc, .. }) = self { Some((self_type, trait_.as_ref()?.def_id(), assoc.clone())) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index d963d6092c48..f26d74629dd9 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1257,9 +1257,9 @@ impl clean::Impl { }; primitive_link_fragment(f, PrimitiveType::Tuple, &format!("fn ({name}₁, {name}₂, …, {name}ₙ{ellipsis})"), "#trait-implementations-1", cx)?; // Write output. - if let clean::FnRetTy::Return(ty) = &bare_fn.decl.output { + if !bare_fn.decl.output.is_unit() { write!(f, " -> ")?; - fmt_type(ty, f, use_absolute, cx)?; + fmt_type(&bare_fn.decl.output, f, use_absolute, cx)?; } } else if let Some(ty) = self.kind.as_blanket_ty() { fmt_type(ty, f, use_absolute, cx)?; @@ -1296,22 +1296,6 @@ impl clean::Arguments { } } -impl clean::FnRetTy { - pub(crate) fn print<'a, 'tcx: 'a>( - &'a self, - cx: &'a Context<'tcx>, - ) -> impl fmt::Display + 'a + Captures<'tcx> { - display_fn(move |f| match self { - clean::Return(clean::Tuple(tys)) if tys.is_empty() => Ok(()), - clean::Return(ty) if f.alternate() => { - write!(f, " -> {:#}", ty.print(cx)) - } - clean::Return(ty) => write!(f, " -> {}", ty.print(cx)), - clean::DefaultReturn => Ok(()), - }) - } -} - impl clean::BareFunctionDecl { fn print_hrtb_with_space<'a, 'tcx: 'a>( &'a self, @@ -1366,7 +1350,7 @@ impl clean::FnDecl { "({args:#}{ellipsis}){arrow:#}", args = self.inputs.print(cx), ellipsis = ellipsis, - arrow = self.output.print(cx) + arrow = self.print_output(cx) ) } else { write!( @@ -1374,7 +1358,7 @@ impl clean::FnDecl { "({args}{ellipsis}){arrow}", args = self.inputs.print(cx), ellipsis = ellipsis, - arrow = self.output.print(cx) + arrow = self.print_output(cx) ) } }) @@ -1464,9 +1448,22 @@ impl clean::FnDecl { Some(n) => write!(f, "\n{})", Indent(n))?, }; - fmt::Display::fmt(&self.output.print(cx), f)?; + fmt::Display::fmt(&self.print_output(cx), f)?; Ok(()) } + + pub(crate) fn print_output<'a, 'tcx: 'a>( + &'a self, + cx: &'a Context<'tcx>, + ) -> impl fmt::Display + 'a + Captures<'tcx> { + display_fn(move |f| match &self.output { + clean::Tuple(tys) if tys.is_empty() => Ok(()), + ty if f.alternate() => { + write!(f, " -> {:#}", ty.print(cx)) + } + ty => write!(f, " -> {}", ty.print(cx)), + }) + } } pub(crate) fn visibility_print_with_space<'a, 'tcx: 'a>( diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 42e27d35a94b..a5223bd6309d 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -844,7 +844,7 @@ fn assoc_method( + name.as_str().len() + generics_len; - let notable_traits = d.output.as_return().and_then(|output| notable_traits_button(output, cx)); + let notable_traits = notable_traits_button(&d.output, cx); let (indent, indent_str, end_newline) = if parent == ItemType::Trait { header_len += 4; @@ -1282,6 +1282,11 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &mut Context<'_>) -> Option { let mut has_notable_trait = false; + if ty.is_unit() { + // Very common fast path. + return None; + } + let did = ty.def_id(cx.cache())?; // Box has pass-through impls for Read, Write, Iterator, and Future when the diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index d2dc47af7ac4..1da266e41a59 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -587,8 +587,7 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle + name.as_str().len() + generics_len; - let notable_traits = - f.decl.output.as_return().and_then(|output| notable_traits_button(output, cx)); + let notable_traits = notable_traits_button(&f.decl.output, cx); wrap_item(w, |w| { w.reserve(header_len); diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 846299f02e33..f34be120d292 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -7,7 +7,7 @@ use rustc_span::symbol::Symbol; use serde::ser::{Serialize, SerializeStruct, Serializer}; use crate::clean; -use crate::clean::types::{FnRetTy, Function, Generics, ItemId, Type, WherePredicate}; +use crate::clean::types::{Function, Generics, ItemId, Type, WherePredicate}; use crate::formats::cache::{Cache, OrphanImplItem}; use crate::formats::item_type::ItemType; use crate::html::format::join_with_double_colon; @@ -656,22 +656,9 @@ fn get_fn_inputs_and_outputs<'tcx>( } let mut ret_types = Vec::new(); - match decl.output { - FnRetTy::Return(ref return_type) => { - add_generics_and_bounds_as_types( - self_, - generics, - return_type, - tcx, - 0, - &mut ret_types, - cache, - ); - if ret_types.is_empty() { - ret_types.push(get_index_type(return_type, vec![])); - } - } - _ => {} - }; + add_generics_and_bounds_as_types(self_, generics, &decl.output, tcx, 0, &mut ret_types, cache); + if ret_types.is_empty() { + ret_types.push(get_index_type(&decl.output, vec![])); + } (all_types, ret_types) } diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 935bb721f180..91cd55b1113a 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -624,10 +624,7 @@ impl FromWithTcx for FnDecl { .into_iter() .map(|arg| (arg.name.to_string(), arg.type_.into_tcx(tcx))) .collect(), - output: match output { - clean::FnRetTy::Return(t) => Some(t.into_tcx(tcx)), - clean::FnRetTy::DefaultReturn => None, - }, + output: if output.is_unit() { None } else { Some(output.into_tcx(tcx)) }, c_variadic, } } From 5abff3753a7c806251a384295ea577b1ee0ddbff Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Tue, 30 May 2023 23:58:20 +0100 Subject: [PATCH 63/69] Explicit set `workspace.resolver = "1"` rust-lang/cargo#10910 starts emitting warning if resolver is not set for 2021 edition package. We want to surpress the warning for now. --- Cargo.toml | 1 + library/portable-simd/Cargo.toml | 2 +- .../docker/host-x86_64/test-various/uefi_qemu_test/Cargo.toml | 1 + src/etc/test-float-parse/Cargo.toml | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 8eb378afe428..6e84df5c693b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,5 @@ [workspace] +resolver = "1" members = [ "compiler/rustc", "library/std", diff --git a/library/portable-simd/Cargo.toml b/library/portable-simd/Cargo.toml index 9802386e4566..d1732aaec2f9 100644 --- a/library/portable-simd/Cargo.toml +++ b/library/portable-simd/Cargo.toml @@ -1,5 +1,5 @@ [workspace] - +resolver = "1" members = [ "crates/core_simd", "crates/std_float", diff --git a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.toml b/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.toml index fa8e5b3d0806..2d17cf7d47a8 100644 --- a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.toml +++ b/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.toml @@ -4,6 +4,7 @@ version = "0.0.0" edition = "2021" [workspace] +resolver = "1" [dependencies] r-efi = "4.1.0" diff --git a/src/etc/test-float-parse/Cargo.toml b/src/etc/test-float-parse/Cargo.toml index 7ee19a0b6d91..6d7b227d0ad3 100644 --- a/src/etc/test-float-parse/Cargo.toml +++ b/src/etc/test-float-parse/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" publish = false [workspace] +resolver = "1" [dependencies] rand = "0.4" From 6f07116e8a5e5f2338d8b1c92be916c35a1857b7 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Tue, 30 May 2023 23:36:40 +0100 Subject: [PATCH 64/69] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 64fb38c97ac4..f7b95e31642e 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 64fb38c97ac4d3a327fc9032c862dd28c8833b17 +Subproject commit f7b95e31642e09c2b6eabb18ed75007dda6677a0 From 1e9b69bf3f07bca48d6c665e4375136f1c600f15 Mon Sep 17 00:00:00 2001 From: Boxy Date: Wed, 31 May 2023 02:13:47 +0100 Subject: [PATCH 65/69] move hack to `normalize_param_env_or_error` --- compiler/rustc_middle/src/ty/relate.rs | 11 ---- .../rustc_trait_selection/src/traits/mod.rs | 60 ++++++++++++++++++- 2 files changed, 57 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 3bbe6a23b662..8bcae3d9ab7c 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -589,17 +589,6 @@ pub fn structurally_relate_consts<'tcx, R: TypeRelation<'tcx>>( debug!("{}.structurally_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b); let tcx = relation.tcx(); - // HACK(const_generics): We still need to eagerly evaluate consts when - // relating them because during `normalize_param_env_or_error`, - // we may relate an evaluated constant in a obligation against - // an unnormalized (i.e. unevaluated) const in the param-env. - // FIXME(generic_const_exprs): Once we always lazily unify unevaluated constants - // these `eval` calls can be removed. - if !tcx.features().generic_const_exprs { - a = a.eval(tcx, relation.param_env()); - b = b.eval(tcx, relation.param_env()); - } - if tcx.features().generic_const_exprs { a = tcx.expand_abstract_consts(a); b = tcx.expand_abstract_consts(b); diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 4b38687eebee..f7389bda159e 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -32,7 +32,7 @@ use rustc_errors::ErrorGuaranteed; use rustc_middle::query::Providers; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; -use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeSuperVisitable}; +use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFolder, TypeSuperVisitable}; use rustc_middle::ty::{InternalSubsts, SubstsRef}; use rustc_span::def_id::DefId; use rustc_span::Span; @@ -272,8 +272,62 @@ pub fn normalize_param_env_or_error<'tcx>( // parameter environments once for every fn as it goes, // and errors will get reported then; so outside of type inference we // can be sure that no errors should occur. - let mut predicates: Vec<_> = - util::elaborate(tcx, unnormalized_env.caller_bounds().into_iter()).collect(); + let mut predicates: Vec<_> = util::elaborate( + tcx, + unnormalized_env.caller_bounds().into_iter().map(|predicate| { + if tcx.features().generic_const_exprs { + return predicate; + } + + struct ConstNormalizer<'tcx>(TyCtxt<'tcx>); + + impl<'tcx> TypeFolder> for ConstNormalizer<'tcx> { + fn interner(&self) -> TyCtxt<'tcx> { + self.0 + } + + fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> { + // While it is pretty sus to be evaluating things with an empty param env, it + // should actually be okay since without `feature(generic_const_exprs)` the only + // const arguments that have a non-empty param env are array repeat counts. These + // do not appear in the type system though. + c.eval(self.0, ty::ParamEnv::empty()) + } + } + + // This whole normalization step is a hack to work around the fact that + // `normalize_param_env_or_error` is fundamentally broken from using an + // unnormalized param env with a trait solver that expects the param env + // to be normalized. + // + // When normalizing the param env we can end up evaluating obligations + // that have been normalized but can only be proven via a where clause + // which is still in its unnormalized form. example: + // + // Attempting to prove `T: Trait<::Assoc>` in a param env + // with a `T: Trait<::Assoc>` where clause will fail because + // we first normalize obligations before proving them so we end up proving + // `T: Trait`. Since lazy normalization is not implemented equating `u8` + // with `::Assoc` fails outright so we incorrectly believe that + // we cannot prove `T: Trait`. + // + // The same thing is true for const generics- attempting to prove + // `T: Trait` with the same thing as a where clauses + // will fail. After normalization we may be attempting to prove `T: Trait<4>` with + // the unnormalized where clause `T: Trait`. In order + // for the obligation to hold `4` must be equal to `ConstKind::Unevaluated(...)` + // but as we do not have lazy norm implemented, equating the two consts fails outright. + // + // Ideally we would not normalize consts here at all but it is required for backwards + // compatibility. Eventually when lazy norm is implemented this can just be removed. + // We do not normalize types here as there is no backwards compatibility requirement + // for us to do so. + // + // FIXME(-Ztrait-solver=next): remove this hack since we have deferred projection equality + predicate.fold_with(&mut ConstNormalizer(tcx)) + }), + ) + .collect(); debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates); From 21cf9ea7ed5f87c905f1548d1855b02ee61b5aec Mon Sep 17 00:00:00 2001 From: Boxy Date: Fri, 26 May 2023 14:44:28 +0100 Subject: [PATCH 66/69] update test to not rely on super_relate_consts hack --- .../new-solver/structural-resolve-field.rs | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/tests/ui/traits/new-solver/structural-resolve-field.rs b/tests/ui/traits/new-solver/structural-resolve-field.rs index 01899c9ad645..c492d927696b 100644 --- a/tests/ui/traits/new-solver/structural-resolve-field.rs +++ b/tests/ui/traits/new-solver/structural-resolve-field.rs @@ -1,13 +1,35 @@ // compile-flags: -Ztrait-solver=next // check-pass -#[derive(Default)] struct Foo { x: i32, } +impl MyDefault for Foo { + fn my_default() -> Self { + Self { + x: 0, + } + } +} + +trait MyDefault { + fn my_default() -> Self; +} + +impl MyDefault for [Foo; 0] { + fn my_default() -> Self { + [] + } +} +impl MyDefault for [Foo; 1] { + fn my_default() -> Self { + [Foo::my_default(); 1] + } +} + fn main() { - let mut xs = <[Foo; 1]>::default(); + let mut xs = <[Foo; 1]>::my_default(); xs[0].x = 1; (&mut xs[0]).x = 2; } From 374f5a8091f5dadff364cda8b19f8806e268e984 Mon Sep 17 00:00:00 2001 From: ScottMcMurray Date: Tue, 30 May 2023 20:38:07 -0700 Subject: [PATCH 67/69] Test from_fn autovectorizes --- tests/codegen/autovectorize-f32x4.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/codegen/autovectorize-f32x4.rs b/tests/codegen/autovectorize-f32x4.rs index 474ff1c4e91b..54392be707f5 100644 --- a/tests/codegen/autovectorize-f32x4.rs +++ b/tests/codegen/autovectorize-f32x4.rs @@ -30,3 +30,13 @@ pub fn auto_vectorize_loop(a: [f32; 4], b: [f32; 4]) -> [f32; 4] { } c } + +// CHECK-LABEL: @auto_vectorize_array_from_fn +#[no_mangle] +pub fn auto_vectorize_array_from_fn(a: [f32; 4], b: [f32; 4]) -> [f32; 4] { +// CHECK: load <4 x float> +// CHECK: load <4 x float> +// CHECK: fadd <4 x float> +// CHECK: store <4 x float> + std::array::from_fn(|i| a[i] + b[i]) +} From 70e6b2680cbe87262d73d1c79616df54b8ca5440 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 May 2023 10:44:29 +0200 Subject: [PATCH 68/69] 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 2851208e7806..f24d448e9808 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -498553fc04f6a3fdc53412320f4e913bc53bc267 +617d3d6d722c432cdcbf210e6db55c3bdeafe381 From 1191bea6ab6402bd10ea69cd2aa837331cd452b3 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 1 Jun 2023 10:03:27 +1000 Subject: [PATCH 69/69] Improve CGU debug printing. - Add more total and per-CGU measurements. - Ensure CGUs are sorted by name before the first `debug_dump` calls, for deterministic output. - Print items within CGUs in sorted-by-name order, for deterministic output. - Add some assertions and comments clarifying sortedness of CGUs at various points. An example, before: ``` INITIAL PARTITIONING (5 CodegenUnits, max=29, min=1, max/min=29.0): CodegenUnit scev95ysd7g4b0z estimated size 2: - fn <() as std::process::Termination>::report [(External, Hidden)] [h082b15a6d07338dcE] estimated size 2 CodegenUnit 1j0frgtl72rsz24q estimated size 29: - fn std::rt::lang_start::<()>::{closure#0} [(External, Hidden)] [h695c7b5d6a212565E] estimated size 17 - fn std::rt::lang_start::<()> [(External, Hidden)] [h4ca942948e9cb931E] estimated size 12 CodegenUnit 5dbzi1e5qm0d7kj2 estimated size 4: - fn <[closure@std::rt::lang_start<()>::{closure#0}] as std::ops::FnOnce<()>>::call_once - shim [(External, Hidden)] [h24eaa44f03b2b233E] estimated size 1 - fn >::call_once - shim(fn()) [(External, Hidden)] [hf338f5339c3711acE] estimated size 1 - fn <[closure@std::rt::lang_start<()>::{closure#0}] as std::ops::FnOnce<()>>::call_once - shim(vtable) [(External, Hidden)] [h595d414cbb7651d5E] estimated size 1 - fn std::ptr::drop_in_place::<[closure@std::rt::lang_start<()>::{closure#0}]> - shim(None) [(External, Hidden)] [h17a19dcdb40600daE] estimated size 1 CodegenUnit 220m1mqa2mlbg7r3 estimated size 1: - fn main [(External, Hidden)] [hb29587cdb6db5f42E] estimated size 1 CodegenUnit 4ulbh241f7tvyn7x estimated size 6: - fn std::sys_common::backtrace::__rust_begin_short_backtrace:: [(External, Hidden)] [h41dada2c21a1259dE] estimated size 6 ``` and after: ``` INITIAL PARTITIONING (9 items, total_size=42; 5 CGUs, max_size=29, min_size=1, max_size/min_size=29.0): - CGU[0] 1j0frgtl72rsz24q (2 items, size=29): - fn std::rt::lang_start::<()> [(External, Hidden)] [h4ca942948e9cb931E] (size=12) - fn std::rt::lang_start::<()>::{closure#0} [(External, Hidden)] [h695c7b5d6a212565E] (size=17) - CGU[1] 220m1mqa2mlbg7r3 (1 items, size=1): - fn main [(External, Hidden)] [hb29587cdb6db5f42E] (size=1) - CGU[2] 4ulbh241f7tvyn7x (1 items, size=6): - fn std::sys_common::backtrace::__rust_begin_short_backtrace:: [(External, Hidden)] [h41dada2c21a1259dE] (size=6) - CGU[3] 5dbzi1e5qm0d7kj2 (4 items, size=4): - fn <[closure@std::rt::lang_start<()>::{closure#0}] as std::ops::FnOnce<()>>::call_once - shim(vtable) [(External, Hidden)] [h595d414cbb7651d5E] (size=1) - fn <[closure@std::rt::lang_start<()>::{closure#0}] as std::ops::FnOnce<()>>::call_once - shim [(External, Hidden)] [h24eaa44f03b2b233E] (size=1) - fn >::call_once - shim(fn()) [(External, Hidden)] [hf338f5339c3711acE] (size=1) - fn std::ptr::drop_in_place::<[closure@std::rt::lang_start<()>::{closure#0}]> - shim(None) [(External, Hidden)] [h17a19dcdb40600daE] (size=1) - CGU[4] scev95ysd7g4b0z (1 items, size=2): - fn <() as std::process::Termination>::report [(External, Hidden)] [h082b15a6d07338dcE] (size=2) ``` --- compiler/rustc_middle/src/mir/mono.rs | 2 + compiler/rustc_monomorphize/src/lib.rs | 1 + .../rustc_monomorphize/src/partitioning.rs | 68 +++++++++++-------- 3 files changed, 43 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index f31b343c9470..1511e2552355 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -291,10 +291,12 @@ impl<'tcx> CodegenUnit<'tcx> { self.primary = true; } + /// The order of these items is non-determinstic. pub fn items(&self) -> &FxHashMap, (Linkage, Visibility)> { &self.items } + /// The order of these items is non-determinstic. pub fn items_mut(&mut self) -> &mut FxHashMap, (Linkage, Visibility)> { &mut self.items } diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index ecc50c3f664f..89dadc782f2d 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -1,4 +1,5 @@ #![feature(array_windows)] +#![feature(is_sorted)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] #![deny(rustc::untranslatable_diagnostic)] diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index be9c349c3841..1b872484eb1e 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -126,11 +126,14 @@ struct PartitioningCx<'a, 'tcx> { } struct PlacedRootMonoItems<'tcx> { + /// The codegen units, sorted by name to make things deterministic. codegen_units: Vec>, + roots: FxHashSet>, internalization_candidates: FxHashSet>, } +// The output CGUs are sorted by name. fn partition<'tcx, I>( tcx: TyCtxt<'tcx>, mono_items: &mut I, @@ -143,6 +146,7 @@ where let _prof_timer = tcx.prof.generic_activity("cgu_partitioning"); let cx = &PartitioningCx { tcx, target_cgu_count: max_cgu_count, inlining_map }; + // In the first step, we place all regular monomorphizations into their // respective 'home' codegen unit. Regular monomorphizations are all // functions and statics defined in the local crate. @@ -225,8 +229,8 @@ where dead_code_cgu.make_code_coverage_dead_code_cgu(); } - // Finally, sort by codegen unit name, so that we get deterministic results. - codegen_units.sort_by(|a, b| a.name().as_str().cmp(b.name().as_str())); + // Ensure CGUs are sorted by name, so that we get deterministic results. + assert!(codegen_units.is_sorted_by(|a, b| Some(a.name().as_str().cmp(b.name().as_str())))); debug_dump(tcx, "FINAL", &codegen_units); @@ -301,27 +305,22 @@ where codegen_units.insert(codegen_unit_name, CodegenUnit::new(codegen_unit_name)); } - let codegen_units = codegen_units.into_values().collect(); + let mut codegen_units: Vec<_> = codegen_units.into_values().collect(); + codegen_units.sort_by(|a, b| a.name().as_str().cmp(b.name().as_str())); + PlacedRootMonoItems { codegen_units, roots, internalization_candidates } } +// This function requires the CGUs to be sorted by name on input, and ensures +// they are sorted by name on return, for deterministic behaviour. fn merge_codegen_units<'tcx>( cx: &PartitioningCx<'_, 'tcx>, codegen_units: &mut Vec>, ) { assert!(cx.target_cgu_count >= 1); - // Note that at this point in time the `codegen_units` here may not be - // in a deterministic order (but we know they're deterministically the - // same set). We want this merging to produce a deterministic ordering - // of codegen units from the input. - // - // Due to basically how we've implemented the merging below (merge the - // two smallest into each other) we're sure to start off with a - // deterministic order (sorted by name). This'll mean that if two cgus - // have the same size the stable sort below will keep everything nice - // and deterministic. - codegen_units.sort_by(|a, b| a.name().as_str().cmp(b.name().as_str())); + // A sorted order here ensures merging is deterministic. + assert!(codegen_units.is_sorted_by(|a, b| Some(a.name().as_str().cmp(b.name().as_str())))); // This map keeps track of what got merged into what. let mut cgu_contents: FxHashMap> = @@ -400,6 +399,9 @@ fn merge_codegen_units<'tcx>( cgu.set_name(numbered_codegen_unit_name); } } + + // A sorted order here ensures what follows can be deterministic. + codegen_units.sort_by(|a, b| a.name().as_str().cmp(b.name().as_str())); } /// For symbol internalization, we need to know whether a symbol/mono-item is @@ -858,36 +860,46 @@ fn default_visibility(tcx: TyCtxt<'_>, id: DefId, is_generic: bool) -> Visibilit _ => Visibility::Hidden, } } + fn debug_dump<'a, 'tcx: 'a>(tcx: TyCtxt<'tcx>, label: &str, cgus: &[CodegenUnit<'tcx>]) { let dump = move || { use std::fmt::Write; let num_cgus = cgus.len(); - let max = cgus.iter().map(|cgu| cgu.size_estimate()).max().unwrap(); - let min = cgus.iter().map(|cgu| cgu.size_estimate()).min().unwrap(); - let ratio = max as f64 / min as f64; + let num_items: usize = cgus.iter().map(|cgu| cgu.items().len()).sum(); + let total_size: usize = cgus.iter().map(|cgu| cgu.size_estimate()).sum(); + let max_size = cgus.iter().map(|cgu| cgu.size_estimate()).max().unwrap(); + let min_size = cgus.iter().map(|cgu| cgu.size_estimate()).min().unwrap(); + let max_min_size_ratio = max_size as f64 / min_size as f64; let s = &mut String::new(); let _ = writeln!( s, - "{label} ({num_cgus} CodegenUnits, max={max}, min={min}, max/min={ratio:.1}):" + "{label} ({num_items} items, total_size={total_size}; {num_cgus} CGUs, \ + max_size={max_size}, min_size={min_size}, max_size/min_size={max_min_size_ratio:.1}):" ); - for cgu in cgus { - let _ = - writeln!(s, "CodegenUnit {} estimated size {}:", cgu.name(), cgu.size_estimate()); + for (i, cgu) in cgus.iter().enumerate() { + let num_items = cgu.items().len(); + let _ = writeln!( + s, + "- CGU[{i}] {} ({num_items} items, size={}):", + cgu.name(), + cgu.size_estimate() + ); - for (mono_item, linkage) in cgu.items() { - let symbol_name = mono_item.symbol_name(tcx).name; + // The order of `cgu.items()` is non-deterministic; sort it by name + // to give deterministic output. + let mut items: Vec<_> = cgu.items().iter().collect(); + items.sort_by_key(|(item, _)| item.symbol_name(tcx).name); + for (item, linkage) in items { + let symbol_name = item.symbol_name(tcx).name; let symbol_hash_start = symbol_name.rfind('h'); let symbol_hash = symbol_hash_start.map_or("", |i| &symbol_name[i..]); + let size = item.size_estimate(tcx); let _ = with_no_trimmed_paths!(writeln!( s, - " - {} [{:?}] [{}] estimated size {}", - mono_item, - linkage, - symbol_hash, - mono_item.size_estimate(tcx) + " - {item} [{linkage:?}] [{symbol_hash}] (size={size})" )); }