From 1f34e11d1b7708700e696e9950ac503be594c264 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Fri, 28 Oct 2022 23:27:28 +0400 Subject: [PATCH 001/230] Lift `T: Sized` bounds from some `strict_provenance` pointer methods --- library/core/src/ptr/const_ptr.rs | 24 ++++++------------------ library/core/src/ptr/mut_ptr.rs | 24 ++++++------------------ 2 files changed, 12 insertions(+), 36 deletions(-) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index ed16c5f051f7b..49831dbe44bc2 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -178,14 +178,11 @@ impl *const T { #[must_use] #[inline] #[unstable(feature = "strict_provenance", issue = "95228")] - pub fn addr(self) -> usize - where - T: Sized, - { + pub fn addr(self) -> usize { // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. // SAFETY: Pointer-to-integer transmutes are valid (if you are okay with losing the // provenance). - unsafe { mem::transmute(self) } + unsafe { mem::transmute(self.cast::<()>()) } } /// Gets the "address" portion of the pointer, and 'exposes' the "provenance" part for future @@ -215,12 +212,9 @@ impl *const T { #[must_use] #[inline] #[unstable(feature = "strict_provenance", issue = "95228")] - pub fn expose_addr(self) -> usize - where - T: Sized, - { + pub fn expose_addr(self) -> usize { // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. - self as usize + self.cast::<()>() as usize } /// Creates a new pointer with the given address. @@ -238,10 +232,7 @@ impl *const T { #[must_use] #[inline] #[unstable(feature = "strict_provenance", issue = "95228")] - pub fn with_addr(self, addr: usize) -> Self - where - T: Sized, - { + pub fn with_addr(self, addr: usize) -> Self { // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. // // In the mean-time, this operation is defined to be "as if" it was @@ -264,10 +255,7 @@ impl *const T { #[must_use] #[inline] #[unstable(feature = "strict_provenance", issue = "95228")] - pub fn map_addr(self, f: impl FnOnce(usize) -> usize) -> Self - where - T: Sized, - { + pub fn map_addr(self, f: impl FnOnce(usize) -> usize) -> Self { self.with_addr(f(self.addr())) } diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 6764002bcd434..578e27fec7a06 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -188,14 +188,11 @@ impl *mut T { #[must_use] #[inline] #[unstable(feature = "strict_provenance", issue = "95228")] - pub fn addr(self) -> usize - where - T: Sized, - { + pub fn addr(self) -> usize { // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. // SAFETY: Pointer-to-integer transmutes are valid (if you are okay with losing the // provenance). - unsafe { mem::transmute(self) } + unsafe { mem::transmute(self.cast::<()>()) } } /// Gets the "address" portion of the pointer, and 'exposes' the "provenance" part for future @@ -225,12 +222,9 @@ impl *mut T { #[must_use] #[inline] #[unstable(feature = "strict_provenance", issue = "95228")] - pub fn expose_addr(self) -> usize - where - T: Sized, - { + pub fn expose_addr(self) -> usize { // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. - self as usize + self.cast::<()>() as usize } /// Creates a new pointer with the given address. @@ -248,10 +242,7 @@ impl *mut T { #[must_use] #[inline] #[unstable(feature = "strict_provenance", issue = "95228")] - pub fn with_addr(self, addr: usize) -> Self - where - T: Sized, - { + pub fn with_addr(self, addr: usize) -> Self { // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. // // In the mean-time, this operation is defined to be "as if" it was @@ -274,10 +265,7 @@ impl *mut T { #[must_use] #[inline] #[unstable(feature = "strict_provenance", issue = "95228")] - pub fn map_addr(self, f: impl FnOnce(usize) -> usize) -> Self - where - T: Sized, - { + pub fn map_addr(self, f: impl FnOnce(usize) -> usize) -> Self { self.with_addr(f(self.addr())) } From 662f1f20e4497cdd1459d15686706fe27d56d335 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 7 Nov 2022 11:58:58 +0000 Subject: [PATCH 002/230] Lift `T: Sized` bounds from some `strict_provenance` `NonNull` methods --- library/core/src/ptr/non_null.rs | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 7264d57ba6aed..f728c0e223392 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -268,10 +268,7 @@ impl NonNull { #[must_use] #[inline] #[unstable(feature = "strict_provenance", issue = "95228")] - pub fn addr(self) -> NonZeroUsize - where - T: Sized, - { + pub fn addr(self) -> NonZeroUsize { // SAFETY: The pointer is guaranteed by the type to be non-null, // meaning that the address will be non-zero. unsafe { NonZeroUsize::new_unchecked(self.pointer.addr()) } @@ -286,10 +283,7 @@ impl NonNull { #[must_use] #[inline] #[unstable(feature = "strict_provenance", issue = "95228")] - pub fn with_addr(self, addr: NonZeroUsize) -> Self - where - T: Sized, - { + pub fn with_addr(self, addr: NonZeroUsize) -> Self { // SAFETY: The result of `ptr::from::with_addr` is non-null because `addr` is guaranteed to be non-zero. unsafe { NonNull::new_unchecked(self.pointer.with_addr(addr.get()) as *mut _) } } @@ -303,10 +297,7 @@ impl NonNull { #[must_use] #[inline] #[unstable(feature = "strict_provenance", issue = "95228")] - pub fn map_addr(self, f: impl FnOnce(NonZeroUsize) -> NonZeroUsize) -> Self - where - T: Sized, - { + pub fn map_addr(self, f: impl FnOnce(NonZeroUsize) -> NonZeroUsize) -> Self { self.with_addr(f(self.addr())) } From dbc0ed2a109a3409bd21529ca8375a43d5580739 Mon Sep 17 00:00:00 2001 From: Lukas Bergdoll Date: Sun, 20 Nov 2022 20:35:40 +0100 Subject: [PATCH 003/230] Unify stable and unstable sort implementations in same core module This moves the stable sort implementation to the core::slice::sort module. By virtue of being in core it can't access `Vec`. The two `Vec` used by merge sort, `buf` and `runs`, are modelled as custom types that implement the very limited required `Vec` interface with the help of provided allocation and free functions. This is done to allow future re-use of functions and logic between stable and unstable sort. Such as `insert_head`. --- library/alloc/src/slice.rs | 348 +++-------------------- library/core/src/slice/mod.rs | 8 +- library/core/src/slice/sort.rs | 494 +++++++++++++++++++++++++++++++++ 3 files changed, 540 insertions(+), 310 deletions(-) diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 1b61ede3476c3..e5d614ab1ff67 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -19,10 +19,12 @@ use core::cmp::Ordering::{self, Less}; use core::mem::{self, SizedTypeProperties}; #[cfg(not(no_global_oom_handling))] use core::ptr; +#[cfg(not(no_global_oom_handling))] +use core::slice::sort; use crate::alloc::Allocator; #[cfg(not(no_global_oom_handling))] -use crate::alloc::Global; +use crate::alloc::{self, Global}; #[cfg(not(no_global_oom_handling))] use crate::borrow::ToOwned; use crate::boxed::Box; @@ -203,7 +205,7 @@ impl [T] { where T: Ord, { - merge_sort(self, T::lt); + stable_sort(self, T::lt); } /// Sorts the slice with a comparator function. @@ -259,7 +261,7 @@ impl [T] { where F: FnMut(&T, &T) -> Ordering, { - merge_sort(self, |a, b| compare(a, b) == Less); + stable_sort(self, |a, b| compare(a, b) == Less); } /// Sorts the slice with a key extraction function. @@ -302,7 +304,7 @@ impl [T] { F: FnMut(&T) -> K, K: Ord, { - merge_sort(self, |a, b| f(a).lt(&f(b))); + stable_sort(self, |a, b| f(a).lt(&f(b))); } /// Sorts the slice with a key extraction function. @@ -809,324 +811,52 @@ impl ToOwned for [T] { // Sorting //////////////////////////////////////////////////////////////////////////////// -/// Inserts `v[0]` into pre-sorted sequence `v[1..]` so that whole `v[..]` becomes sorted. -/// -/// This is the integral subroutine of insertion sort. -#[cfg(not(no_global_oom_handling))] -fn insert_head(v: &mut [T], is_less: &mut F) -where - F: FnMut(&T, &T) -> bool, -{ - if v.len() >= 2 && is_less(&v[1], &v[0]) { - unsafe { - // There are three ways to implement insertion here: - // - // 1. Swap adjacent elements until the first one gets to its final destination. - // However, this way we copy data around more than is necessary. If elements are big - // structures (costly to copy), this method will be slow. - // - // 2. Iterate until the right place for the first element is found. Then shift the - // elements succeeding it to make room for it and finally place it into the - // remaining hole. This is a good method. - // - // 3. Copy the first element into a temporary variable. Iterate until the right place - // for it is found. As we go along, copy every traversed element into the slot - // preceding it. Finally, copy data from the temporary variable into the remaining - // hole. This method is very good. Benchmarks demonstrated slightly better - // performance than with the 2nd method. - // - // All methods were benchmarked, and the 3rd showed best results. So we chose that one. - let tmp = mem::ManuallyDrop::new(ptr::read(&v[0])); - - // Intermediate state of the insertion process is always tracked by `hole`, which - // serves two purposes: - // 1. Protects integrity of `v` from panics in `is_less`. - // 2. Fills the remaining hole in `v` in the end. - // - // Panic safety: - // - // If `is_less` panics at any point during the process, `hole` will get dropped and - // fill the hole in `v` with `tmp`, thus ensuring that `v` still holds every object it - // initially held exactly once. - let mut hole = InsertionHole { src: &*tmp, dest: &mut v[1] }; - ptr::copy_nonoverlapping(&v[1], &mut v[0], 1); - - for i in 2..v.len() { - if !is_less(&v[i], &*tmp) { - break; - } - ptr::copy_nonoverlapping(&v[i], &mut v[i - 1], 1); - hole.dest = &mut v[i]; - } - // `hole` gets dropped and thus copies `tmp` into the remaining hole in `v`. - } - } - - // When dropped, copies from `src` into `dest`. - struct InsertionHole { - src: *const T, - dest: *mut T, - } - - impl Drop for InsertionHole { - fn drop(&mut self) { - unsafe { - ptr::copy_nonoverlapping(self.src, self.dest, 1); - } - } - } -} - -/// Merges non-decreasing runs `v[..mid]` and `v[mid..]` using `buf` as temporary storage, and -/// stores the result into `v[..]`. -/// -/// # Safety -/// -/// The two slices must be non-empty and `mid` must be in bounds. Buffer `buf` must be long enough -/// to hold a copy of the shorter slice. Also, `T` must not be a zero-sized type. -#[cfg(not(no_global_oom_handling))] -unsafe fn merge(v: &mut [T], mid: usize, buf: *mut T, is_less: &mut F) -where - F: FnMut(&T, &T) -> bool, -{ - let len = v.len(); - let v = v.as_mut_ptr(); - let (v_mid, v_end) = unsafe { (v.add(mid), v.add(len)) }; - - // The merge process first copies the shorter run into `buf`. Then it traces the newly copied - // run and the longer run forwards (or backwards), comparing their next unconsumed elements and - // copying the lesser (or greater) one into `v`. - // - // As soon as the shorter run is fully consumed, the process is done. If the longer run gets - // consumed first, then we must copy whatever is left of the shorter run into the remaining - // hole in `v`. - // - // Intermediate state of the process is always tracked by `hole`, which serves two purposes: - // 1. Protects integrity of `v` from panics in `is_less`. - // 2. Fills the remaining hole in `v` if the longer run gets consumed first. - // - // Panic safety: - // - // If `is_less` panics at any point during the process, `hole` will get dropped and fill the - // hole in `v` with the unconsumed range in `buf`, thus ensuring that `v` still holds every - // object it initially held exactly once. - let mut hole; - - if mid <= len - mid { - // The left run is shorter. - unsafe { - ptr::copy_nonoverlapping(v, buf, mid); - hole = MergeHole { start: buf, end: buf.add(mid), dest: v }; - } - - // Initially, these pointers point to the beginnings of their arrays. - let left = &mut hole.start; - let mut right = v_mid; - let out = &mut hole.dest; - - while *left < hole.end && right < v_end { - // Consume the lesser side. - // If equal, prefer the left run to maintain stability. - unsafe { - let to_copy = if is_less(&*right, &**left) { - get_and_increment(&mut right) - } else { - get_and_increment(left) - }; - ptr::copy_nonoverlapping(to_copy, get_and_increment(out), 1); - } - } - } else { - // The right run is shorter. - unsafe { - ptr::copy_nonoverlapping(v_mid, buf, len - mid); - hole = MergeHole { start: buf, end: buf.add(len - mid), dest: v_mid }; - } - - // Initially, these pointers point past the ends of their arrays. - let left = &mut hole.dest; - let right = &mut hole.end; - let mut out = v_end; - - while v < *left && buf < *right { - // Consume the greater side. - // If equal, prefer the right run to maintain stability. - unsafe { - let to_copy = if is_less(&*right.sub(1), &*left.sub(1)) { - decrement_and_get(left) - } else { - decrement_and_get(right) - }; - ptr::copy_nonoverlapping(to_copy, decrement_and_get(&mut out), 1); - } - } - } - // Finally, `hole` gets dropped. If the shorter run was not fully consumed, whatever remains of - // it will now be copied into the hole in `v`. - - unsafe fn get_and_increment(ptr: &mut *mut T) -> *mut T { - let old = *ptr; - *ptr = unsafe { ptr.add(1) }; - old - } - - unsafe fn decrement_and_get(ptr: &mut *mut T) -> *mut T { - *ptr = unsafe { ptr.sub(1) }; - *ptr - } - - // When dropped, copies the range `start..end` into `dest..`. - struct MergeHole { - start: *mut T, - end: *mut T, - dest: *mut T, - } - - impl Drop for MergeHole { - fn drop(&mut self) { - // `T` is not a zero-sized type, and these are pointers into a slice's elements. - unsafe { - let len = self.end.sub_ptr(self.start); - ptr::copy_nonoverlapping(self.start, self.dest, len); - } - } - } -} - -/// This merge sort borrows some (but not all) ideas from TimSort, which is described in detail -/// [here](https://github.com/python/cpython/blob/main/Objects/listsort.txt). -/// -/// The algorithm identifies strictly descending and non-descending subsequences, which are called -/// natural runs. There is a stack of pending runs yet to be merged. Each newly found run is pushed -/// onto the stack, and then some pairs of adjacent runs are merged until these two invariants are -/// satisfied: -/// -/// 1. for every `i` in `1..runs.len()`: `runs[i - 1].len > runs[i].len` -/// 2. for every `i` in `2..runs.len()`: `runs[i - 2].len > runs[i - 1].len + runs[i].len` -/// -/// The invariants ensure that the total running time is *O*(*n* \* log(*n*)) worst-case. +#[inline] #[cfg(not(no_global_oom_handling))] -fn merge_sort(v: &mut [T], mut is_less: F) +fn stable_sort(v: &mut [T], mut is_less: F) where F: FnMut(&T, &T) -> bool, { - // Slices of up to this length get sorted using insertion sort. - const MAX_INSERTION: usize = 20; - // Very short runs are extended using insertion sort to span at least this many elements. - const MIN_RUN: usize = 10; - - // Sorting has no meaningful behavior on zero-sized types. if T::IS_ZST { + // Sorting has no meaningful behavior on zero-sized types. Do nothing. return; } - let len = v.len(); - - // Short arrays get sorted in-place via insertion sort to avoid allocations. - if len <= MAX_INSERTION { - if len >= 2 { - for i in (0..len - 1).rev() { - insert_head(&mut v[i..], &mut is_less); - } - } - return; - } - - // Allocate a buffer to use as scratch memory. We keep the length 0 so we can keep in it - // shallow copies of the contents of `v` without risking the dtors running on copies if - // `is_less` panics. When merging two sorted runs, this buffer holds a copy of the shorter run, - // which will always have length at most `len / 2`. - let mut buf = Vec::with_capacity(len / 2); + let elem_alloc_fn = |len: usize| -> *mut T { + // SAFETY: Creating the layout is safe as long as merge_sort never calls this with len > + // v.len(). Alloc in general will only be used as 'shadow-region' to store temporary swap + // elements. + unsafe { alloc::alloc(alloc::Layout::array::(len).unwrap_unchecked()) as *mut T } + }; - // In order to identify natural runs in `v`, we traverse it backwards. That might seem like a - // strange decision, but consider the fact that merges more often go in the opposite direction - // (forwards). According to benchmarks, merging forwards is slightly faster than merging - // backwards. To conclude, identifying runs by traversing backwards improves performance. - let mut runs = vec![]; - let mut end = len; - while end > 0 { - // Find the next natural run, and reverse it if it's strictly descending. - let mut start = end - 1; - if start > 0 { - start -= 1; - unsafe { - if is_less(v.get_unchecked(start + 1), v.get_unchecked(start)) { - while start > 0 && is_less(v.get_unchecked(start), v.get_unchecked(start - 1)) { - start -= 1; - } - v[start..end].reverse(); - } else { - while start > 0 && !is_less(v.get_unchecked(start), v.get_unchecked(start - 1)) - { - start -= 1; - } - } - } - } - - // Insert some more elements into the run if it's too short. Insertion sort is faster than - // merge sort on short sequences, so this significantly improves performance. - while start > 0 && end - start < MIN_RUN { - start -= 1; - insert_head(&mut v[start..end], &mut is_less); + let elem_dealloc_fn = |buf_ptr: *mut T, len: usize| { + // SAFETY: Creating the layout is safe as long as merge_sort never calls this with len > + // v.len(). The caller must ensure that buf_ptr was created by elem_alloc_fn with the same + // len. + unsafe { + alloc::dealloc(buf_ptr as *mut u8, alloc::Layout::array::(len).unwrap_unchecked()); } + }; - // Push this run onto the stack. - runs.push(Run { start, len: end - start }); - end = start; - - // Merge some pairs of adjacent runs to satisfy the invariants. - while let Some(r) = collapse(&runs) { - let left = runs[r + 1]; - let right = runs[r]; - unsafe { - merge( - &mut v[left.start..right.start + right.len], - left.len, - buf.as_mut_ptr(), - &mut is_less, - ); - } - runs[r] = Run { start: left.start, len: left.len + right.len }; - runs.remove(r + 1); + let run_alloc_fn = |len: usize| -> *mut sort::TimSortRun { + // SAFETY: Creating the layout is safe as long as merge_sort never calls this with an + // obscene length or 0. + unsafe { + alloc::alloc(alloc::Layout::array::(len).unwrap_unchecked()) + as *mut sort::TimSortRun } - } - - // Finally, exactly one run must remain in the stack. - debug_assert!(runs.len() == 1 && runs[0].start == 0 && runs[0].len == len); + }; - // Examines the stack of runs and identifies the next pair of runs to merge. More specifically, - // if `Some(r)` is returned, that means `runs[r]` and `runs[r + 1]` must be merged next. If the - // algorithm should continue building a new run instead, `None` is returned. - // - // TimSort is infamous for its buggy implementations, as described here: - // http://envisage-project.eu/timsort-specification-and-verification/ - // - // The gist of the story is: we must enforce the invariants on the top four runs on the stack. - // Enforcing them on just top three is not sufficient to ensure that the invariants will still - // hold for *all* runs in the stack. - // - // This function correctly checks invariants for the top four runs. Additionally, if the top - // run starts at index 0, it will always demand a merge operation until the stack is fully - // collapsed, in order to complete the sort. - #[inline] - fn collapse(runs: &[Run]) -> Option { - let n = runs.len(); - if n >= 2 - && (runs[n - 1].start == 0 - || runs[n - 2].len <= runs[n - 1].len - || (n >= 3 && runs[n - 3].len <= runs[n - 2].len + runs[n - 1].len) - || (n >= 4 && runs[n - 4].len <= runs[n - 3].len + runs[n - 2].len)) - { - if n >= 3 && runs[n - 3].len < runs[n - 1].len { Some(n - 3) } else { Some(n - 2) } - } else { - None + let run_dealloc_fn = |buf_ptr: *mut sort::TimSortRun, len: usize| { + // SAFETY: The caller must ensure that buf_ptr was created by elem_alloc_fn with the same + // len. + unsafe { + alloc::dealloc( + buf_ptr as *mut u8, + alloc::Layout::array::(len).unwrap_unchecked(), + ); } - } + }; - #[derive(Clone, Copy)] - struct Run { - start: usize, - len: usize, - } + sort::merge_sort(v, &mut is_less, elem_alloc_fn, elem_dealloc_fn, run_alloc_fn, run_dealloc_fn); } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index ad90e00b8a095..4075c0c3c1a7a 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -28,13 +28,19 @@ use crate::slice; /// Pure rust memchr implementation, taken from rust-memchr pub mod memchr; +#[unstable( + feature = "slice_internals", + issue = "none", + reason = "exposed from core to be reused in std;" +)] +pub mod sort; + mod ascii; mod cmp; mod index; mod iter; mod raw; mod rotate; -mod sort; mod specialize; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs index 87f77b7f21d62..07c68bf6aa40a 100644 --- a/library/core/src/slice/sort.rs +++ b/library/core/src/slice/sort.rs @@ -5,6 +5,11 @@ //! //! Unstable sorting is compatible with libcore because it doesn't allocate memory, unlike our //! stable sorting implementation. +//! +//! In addition it also contains the core logic of the stable sort used by `slice::sort` based on +//! TimSort. + +#![allow(unused)] // FIXME debug use crate::cmp; use crate::mem::{self, MaybeUninit, SizedTypeProperties}; @@ -883,6 +888,7 @@ fn partition_at_index_loop<'a, T, F>( } } +/// Reorder the slice such that the element at `index` is at its final sorted position. pub fn partition_at_index( v: &mut [T], index: usize, @@ -927,3 +933,491 @@ where let pivot = &mut pivot[0]; (left, pivot, right) } + +/// Inserts `v[0]` into pre-sorted sequence `v[1..]` so that whole `v[..]` becomes sorted. +/// +/// This is the integral subroutine of insertion sort. +fn insert_head(v: &mut [T], is_less: &mut F) +where + F: FnMut(&T, &T) -> bool, +{ + if v.len() >= 2 && is_less(&v[1], &v[0]) { + unsafe { + // There are three ways to implement insertion here: + // + // 1. Swap adjacent elements until the first one gets to its final destination. + // However, this way we copy data around more than is necessary. If elements are big + // structures (costly to copy), this method will be slow. + // + // 2. Iterate until the right place for the first element is found. Then shift the + // elements succeeding it to make room for it and finally place it into the + // remaining hole. This is a good method. + // + // 3. Copy the first element into a temporary variable. Iterate until the right place + // for it is found. As we go along, copy every traversed element into the slot + // preceding it. Finally, copy data from the temporary variable into the remaining + // hole. This method is very good. Benchmarks demonstrated slightly better + // performance than with the 2nd method. + // + // All methods were benchmarked, and the 3rd showed best results. So we chose that one. + let tmp = mem::ManuallyDrop::new(ptr::read(&v[0])); + + // Intermediate state of the insertion process is always tracked by `hole`, which + // serves two purposes: + // 1. Protects integrity of `v` from panics in `is_less`. + // 2. Fills the remaining hole in `v` in the end. + // + // Panic safety: + // + // If `is_less` panics at any point during the process, `hole` will get dropped and + // fill the hole in `v` with `tmp`, thus ensuring that `v` still holds every object it + // initially held exactly once. + let mut hole = InsertionHole { src: &*tmp, dest: &mut v[1] }; + ptr::copy_nonoverlapping(&v[1], &mut v[0], 1); + + for i in 2..v.len() { + if !is_less(&v[i], &*tmp) { + break; + } + ptr::copy_nonoverlapping(&v[i], &mut v[i - 1], 1); + hole.dest = &mut v[i]; + } + // `hole` gets dropped and thus copies `tmp` into the remaining hole in `v`. + } + } + + // When dropped, copies from `src` into `dest`. + struct InsertionHole { + src: *const T, + dest: *mut T, + } + + impl Drop for InsertionHole { + fn drop(&mut self) { + unsafe { + ptr::copy_nonoverlapping(self.src, self.dest, 1); + } + } + } +} + +/// Merges non-decreasing runs `v[..mid]` and `v[mid..]` using `buf` as temporary storage, and +/// stores the result into `v[..]`. +/// +/// # Safety +/// +/// The two slices must be non-empty and `mid` must be in bounds. Buffer `buf` must be long enough +/// to hold a copy of the shorter slice. Also, `T` must not be a zero-sized type. +unsafe fn merge(v: &mut [T], mid: usize, buf: *mut T, is_less: &mut F) +where + F: FnMut(&T, &T) -> bool, +{ + let len = v.len(); + let v = v.as_mut_ptr(); + let (v_mid, v_end) = unsafe { (v.add(mid), v.add(len)) }; + + // The merge process first copies the shorter run into `buf`. Then it traces the newly copied + // run and the longer run forwards (or backwards), comparing their next unconsumed elements and + // copying the lesser (or greater) one into `v`. + // + // As soon as the shorter run is fully consumed, the process is done. If the longer run gets + // consumed first, then we must copy whatever is left of the shorter run into the remaining + // hole in `v`. + // + // Intermediate state of the process is always tracked by `hole`, which serves two purposes: + // 1. Protects integrity of `v` from panics in `is_less`. + // 2. Fills the remaining hole in `v` if the longer run gets consumed first. + // + // Panic safety: + // + // If `is_less` panics at any point during the process, `hole` will get dropped and fill the + // hole in `v` with the unconsumed range in `buf`, thus ensuring that `v` still holds every + // object it initially held exactly once. + let mut hole; + + if mid <= len - mid { + // The left run is shorter. + unsafe { + ptr::copy_nonoverlapping(v, buf, mid); + hole = MergeHole { start: buf, end: buf.add(mid), dest: v }; + } + + // Initially, these pointers point to the beginnings of their arrays. + let left = &mut hole.start; + let mut right = v_mid; + let out = &mut hole.dest; + + while *left < hole.end && right < v_end { + // Consume the lesser side. + // If equal, prefer the left run to maintain stability. + unsafe { + let to_copy = if is_less(&*right, &**left) { + get_and_increment(&mut right) + } else { + get_and_increment(left) + }; + ptr::copy_nonoverlapping(to_copy, get_and_increment(out), 1); + } + } + } else { + // The right run is shorter. + unsafe { + ptr::copy_nonoverlapping(v_mid, buf, len - mid); + hole = MergeHole { start: buf, end: buf.add(len - mid), dest: v_mid }; + } + + // Initially, these pointers point past the ends of their arrays. + let left = &mut hole.dest; + let right = &mut hole.end; + let mut out = v_end; + + while v < *left && buf < *right { + // Consume the greater side. + // If equal, prefer the right run to maintain stability. + unsafe { + let to_copy = if is_less(&*right.sub(1), &*left.sub(1)) { + decrement_and_get(left) + } else { + decrement_and_get(right) + }; + ptr::copy_nonoverlapping(to_copy, decrement_and_get(&mut out), 1); + } + } + } + // Finally, `hole` gets dropped. If the shorter run was not fully consumed, whatever remains of + // it will now be copied into the hole in `v`. + + unsafe fn get_and_increment(ptr: &mut *mut T) -> *mut T { + let old = *ptr; + *ptr = unsafe { ptr.add(1) }; + old + } + + unsafe fn decrement_and_get(ptr: &mut *mut T) -> *mut T { + *ptr = unsafe { ptr.sub(1) }; + *ptr + } + + // When dropped, copies the range `start..end` into `dest..`. + struct MergeHole { + start: *mut T, + end: *mut T, + dest: *mut T, + } + + impl Drop for MergeHole { + fn drop(&mut self) { + // `T` is not a zero-sized type, and these are pointers into a slice's elements. + unsafe { + let len = self.end.sub_ptr(self.start); + ptr::copy_nonoverlapping(self.start, self.dest, len); + } + } + } +} + +/// This merge sort borrows some (but not all) ideas from TimSort, which used to be described in +/// detail [here](https://github.com/python/cpython/blob/main/Objects/listsort.txt). However Python +/// has switched to a Powersort based implementation. +/// +/// The algorithm identifies strictly descending and non-descending subsequences, which are called +/// natural runs. There is a stack of pending runs yet to be merged. Each newly found run is pushed +/// onto the stack, and then some pairs of adjacent runs are merged until these two invariants are +/// satisfied: +/// +/// 1. for every `i` in `1..runs.len()`: `runs[i - 1].len > runs[i].len` +/// 2. for every `i` in `2..runs.len()`: `runs[i - 2].len > runs[i - 1].len + runs[i].len` +/// +/// The invariants ensure that the total running time is *O*(*n* \* log(*n*)) worst-case. +pub fn merge_sort( + v: &mut [T], + is_less: &mut CmpF, + elem_alloc_fn: ElemAllocF, + elem_dealloc_fn: ElemDeallocF, + run_alloc_fn: RunAllocF, + run_dealloc_fn: RunDeallocF, +) where + CmpF: FnMut(&T, &T) -> bool, + ElemAllocF: Fn(usize) -> *mut T, + ElemDeallocF: Fn(*mut T, usize), + RunAllocF: Fn(usize) -> *mut TimSortRun, + RunDeallocF: Fn(*mut TimSortRun, usize), +{ + // Slices of up to this length get sorted using insertion sort. + const MAX_INSERTION: usize = 20; + // Very short runs are extended using insertion sort to span at least this many elements. + const MIN_RUN: usize = 10; + + // The caller should have already checked that. + debug_assert!(!T::IS_ZST); + + let len = v.len(); + + // Short arrays get sorted in-place via insertion sort to avoid allocations. + if len <= MAX_INSERTION { + if len >= 2 { + for i in (0..len - 1).rev() { + insert_head(&mut v[i..], is_less); + } + } + return; + } + + // Allocate a buffer to use as scratch memory. We keep the length 0 so we can keep in it + // shallow copies of the contents of `v` without risking the dtors running on copies if + // `is_less` panics. When merging two sorted runs, this buffer holds a copy of the shorter run, + // which will always have length at most `len / 2`. + let mut buf = BufGuard::new(len / 2, elem_alloc_fn, elem_dealloc_fn); + let buf_ptr = buf.buf_ptr; + + let mut runs = RunVec::new(run_alloc_fn, run_dealloc_fn); + + // In order to identify natural runs in `v`, we traverse it backwards. That might seem like a + // strange decision, but consider the fact that merges more often go in the opposite direction + // (forwards). According to benchmarks, merging forwards is slightly faster than merging + // backwards. To conclude, identifying runs by traversing backwards improves performance. + let mut end = len; + while end > 0 { + // Find the next natural run, and reverse it if it's strictly descending. + let mut start = end - 1; + if start > 0 { + start -= 1; + unsafe { + if is_less(v.get_unchecked(start + 1), v.get_unchecked(start)) { + while start > 0 && is_less(v.get_unchecked(start), v.get_unchecked(start - 1)) { + start -= 1; + } + v[start..end].reverse(); + } else { + while start > 0 && !is_less(v.get_unchecked(start), v.get_unchecked(start - 1)) + { + start -= 1; + } + } + } + } + + // Insert some more elements into the run if it's too short. Insertion sort is faster than + // merge sort on short sequences, so this significantly improves performance. + while start > 0 && end - start < MIN_RUN { + start -= 1; + insert_head(&mut v[start..end], is_less); + } + + // Push this run onto the stack. + runs.push(TimSortRun { start, len: end - start }); + end = start; + + // Merge some pairs of adjacent runs to satisfy the invariants. + while let Some(r) = collapse(runs.as_slice()) { + let left = runs[r + 1]; + let right = runs[r]; + unsafe { + merge(&mut v[left.start..right.start + right.len], left.len, buf_ptr, is_less); + } + runs[r] = TimSortRun { start: left.start, len: left.len + right.len }; + runs.remove(r + 1); + } + } + + // Finally, exactly one run must remain in the stack. + debug_assert!(runs.len() == 1 && runs[0].start == 0 && runs[0].len == len); + + // Examines the stack of runs and identifies the next pair of runs to merge. More specifically, + // if `Some(r)` is returned, that means `runs[r]` and `runs[r + 1]` must be merged next. If the + // algorithm should continue building a new run instead, `None` is returned. + // + // TimSort is infamous for its buggy implementations, as described here: + // http://envisage-project.eu/timsort-specification-and-verification/ + // + // The gist of the story is: we must enforce the invariants on the top four runs on the stack. + // Enforcing them on just top three is not sufficient to ensure that the invariants will still + // hold for *all* runs in the stack. + // + // This function correctly checks invariants for the top four runs. Additionally, if the top + // run starts at index 0, it will always demand a merge operation until the stack is fully + // collapsed, in order to complete the sort. + #[inline] + fn collapse(runs: &[TimSortRun]) -> Option { + let n = runs.len(); + if n >= 2 + && (runs[n - 1].start == 0 + || runs[n - 2].len <= runs[n - 1].len + || (n >= 3 && runs[n - 3].len <= runs[n - 2].len + runs[n - 1].len) + || (n >= 4 && runs[n - 4].len <= runs[n - 3].len + runs[n - 2].len)) + { + if n >= 3 && runs[n - 3].len < runs[n - 1].len { Some(n - 3) } else { Some(n - 2) } + } else { + None + } + } + + // Extremely basic versions of Vec. + // Their use is super limited and by having the code here, it allows reuse between the sort + // implementations. + struct BufGuard + where + ElemAllocF: Fn(usize) -> *mut T, + ElemDeallocF: Fn(*mut T, usize), + { + buf_ptr: *mut T, + capacity: usize, + elem_alloc_fn: ElemAllocF, + elem_dealloc_fn: ElemDeallocF, + } + + impl BufGuard + where + ElemAllocF: Fn(usize) -> *mut T, + ElemDeallocF: Fn(*mut T, usize), + { + fn new(len: usize, elem_alloc_fn: ElemAllocF, elem_dealloc_fn: ElemDeallocF) -> Self { + Self { buf_ptr: elem_alloc_fn(len), capacity: len, elem_alloc_fn, elem_dealloc_fn } + } + } + + impl Drop for BufGuard + where + ElemAllocF: Fn(usize) -> *mut T, + ElemDeallocF: Fn(*mut T, usize), + { + fn drop(&mut self) { + (self.elem_dealloc_fn)(self.buf_ptr, self.capacity); + } + } + + struct RunVec + where + RunAllocF: Fn(usize) -> *mut TimSortRun, + RunDeallocF: Fn(*mut TimSortRun, usize), + { + buf_ptr: *mut TimSortRun, + capacity: usize, + len: usize, + run_alloc_fn: RunAllocF, + run_dealloc_fn: RunDeallocF, + } + + impl RunVec + where + RunAllocF: Fn(usize) -> *mut TimSortRun, + RunDeallocF: Fn(*mut TimSortRun, usize), + { + fn new(run_alloc_fn: RunAllocF, run_dealloc_fn: RunDeallocF) -> Self { + // Most slices can be sorted with at most 16 runs in-flight. + const START_RUN_CAPACITY: usize = 16; + + Self { + buf_ptr: run_alloc_fn(START_RUN_CAPACITY), + capacity: START_RUN_CAPACITY, + len: 0, + run_alloc_fn, + run_dealloc_fn, + } + } + + fn push(&mut self, val: TimSortRun) { + if self.len == self.capacity { + let old_capacity = self.capacity; + let old_buf_ptr = self.buf_ptr; + + self.capacity = self.capacity * 2; + self.buf_ptr = (self.run_alloc_fn)(self.capacity); + + // SAFETY: buf_ptr new and old were correctly allocated and old_buf_ptr has + // old_capacity valid elements. + unsafe { + ptr::copy_nonoverlapping(old_buf_ptr, self.buf_ptr, old_capacity); + } + + (self.run_dealloc_fn)(old_buf_ptr, old_capacity); + } + + // SAFETY: The invariant was just checked. + unsafe { + self.buf_ptr.add(self.len).write(val); + } + self.len += 1; + } + + fn remove(&mut self, index: usize) { + if index >= self.len { + panic!("Index out of bounds"); + } + + // SAFETY: buf_ptr needs to be valid and len invariant upheld. + unsafe { + // the place we are taking from. + let ptr = self.buf_ptr.add(index); + + // Shift everything down to fill in that spot. + ptr::copy(ptr.add(1), ptr, self.len - index - 1); + } + self.len -= 1; + } + + fn as_slice(&self) -> &[TimSortRun] { + // SAFETY: Safe as long as buf_ptr is valid and len invariant was upheld. + unsafe { &*ptr::slice_from_raw_parts(self.buf_ptr, self.len) } + } + + fn len(&self) -> usize { + self.len + } + } + + impl core::ops::Index for RunVec + where + RunAllocF: Fn(usize) -> *mut TimSortRun, + RunDeallocF: Fn(*mut TimSortRun, usize), + { + type Output = TimSortRun; + + fn index(&self, index: usize) -> &Self::Output { + if index < self.len { + // SAFETY: buf_ptr and len invariant must be upheld. + unsafe { + return &*(self.buf_ptr.add(index)); + } + } + + panic!("Index out of bounds"); + } + } + + impl core::ops::IndexMut for RunVec + where + RunAllocF: Fn(usize) -> *mut TimSortRun, + RunDeallocF: Fn(*mut TimSortRun, usize), + { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + if index < self.len { + // SAFETY: buf_ptr and len invariant must be upheld. + unsafe { + return &mut *(self.buf_ptr.add(index)); + } + } + + panic!("Index out of bounds"); + } + } + + impl Drop for RunVec + where + RunAllocF: Fn(usize) -> *mut TimSortRun, + RunDeallocF: Fn(*mut TimSortRun, usize), + { + fn drop(&mut self) { + // As long as TimSortRun is Copy we don't need to drop them individually but just the + // whole allocation. + (self.run_dealloc_fn)(self.buf_ptr, self.capacity); + } + } +} + +/// Internal type used by merge_sort. +#[derive(Clone, Copy, Debug)] +pub struct TimSortRun { + len: usize, + start: usize, +} From 1ec59cdcd16fb2821bdf5944c3bbef51c57f7a5c Mon Sep 17 00:00:00 2001 From: Lukas Bergdoll Date: Mon, 21 Nov 2022 14:20:31 +0100 Subject: [PATCH 004/230] Remove debug unused --- library/core/src/slice/sort.rs | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs index 07c68bf6aa40a..8ef3535af2d53 100644 --- a/library/core/src/slice/sort.rs +++ b/library/core/src/slice/sort.rs @@ -9,8 +9,6 @@ //! In addition it also contains the core logic of the stable sort used by `slice::sort` based on //! TimSort. -#![allow(unused)] // FIXME debug - use crate::cmp; use crate::mem::{self, MaybeUninit, SizedTypeProperties}; use crate::ptr; @@ -1167,7 +1165,7 @@ pub fn merge_sort( // shallow copies of the contents of `v` without risking the dtors running on copies if // `is_less` panics. When merging two sorted runs, this buffer holds a copy of the shorter run, // which will always have length at most `len / 2`. - let mut buf = BufGuard::new(len / 2, elem_alloc_fn, elem_dealloc_fn); + let buf = BufGuard::new(len / 2, elem_alloc_fn, elem_dealloc_fn); let buf_ptr = buf.buf_ptr; let mut runs = RunVec::new(run_alloc_fn, run_dealloc_fn); @@ -1255,30 +1253,33 @@ pub fn merge_sort( // Extremely basic versions of Vec. // Their use is super limited and by having the code here, it allows reuse between the sort // implementations. - struct BufGuard + struct BufGuard where - ElemAllocF: Fn(usize) -> *mut T, ElemDeallocF: Fn(*mut T, usize), { buf_ptr: *mut T, capacity: usize, - elem_alloc_fn: ElemAllocF, elem_dealloc_fn: ElemDeallocF, } - impl BufGuard + impl BufGuard where - ElemAllocF: Fn(usize) -> *mut T, ElemDeallocF: Fn(*mut T, usize), { - fn new(len: usize, elem_alloc_fn: ElemAllocF, elem_dealloc_fn: ElemDeallocF) -> Self { - Self { buf_ptr: elem_alloc_fn(len), capacity: len, elem_alloc_fn, elem_dealloc_fn } + fn new( + len: usize, + elem_alloc_fn: ElemAllocF, + elem_dealloc_fn: ElemDeallocF, + ) -> Self + where + ElemAllocF: Fn(usize) -> *mut T, + { + Self { buf_ptr: elem_alloc_fn(len), capacity: len, elem_dealloc_fn } } } - impl Drop for BufGuard + impl Drop for BufGuard where - ElemAllocF: Fn(usize) -> *mut T, ElemDeallocF: Fn(*mut T, usize), { fn drop(&mut self) { From 4b5844fbe95a35370c19d74f9b70286897c3e153 Mon Sep 17 00:00:00 2001 From: Lukas Bergdoll Date: Mon, 21 Nov 2022 14:30:56 +0100 Subject: [PATCH 005/230] Document all unsafe blocks There were several unsafe blocks in the existing implementation that were not documented with a SAFETY comment. --- library/core/src/slice/sort.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs index 8ef3535af2d53..3da00b8f79672 100644 --- a/library/core/src/slice/sort.rs +++ b/library/core/src/slice/sort.rs @@ -940,6 +940,7 @@ where F: FnMut(&T, &T) -> bool, { if v.len() >= 2 && is_less(&v[1], &v[0]) { + // SAFETY: Copy tmp back even if panic, and ensure unique observation. unsafe { // There are three ways to implement insertion here: // @@ -992,6 +993,7 @@ where impl Drop for InsertionHole { fn drop(&mut self) { + // SAFETY: The caller must ensure that src and dest are correctly set. unsafe { ptr::copy_nonoverlapping(self.src, self.dest, 1); } @@ -1012,6 +1014,8 @@ where { let len = v.len(); let v = v.as_mut_ptr(); + + // SAFETY: mid and len must be in-bounds of v. let (v_mid, v_end) = unsafe { (v.add(mid), v.add(len)) }; // The merge process first copies the shorter run into `buf`. Then it traces the newly copied @@ -1035,6 +1039,8 @@ where if mid <= len - mid { // The left run is shorter. + + // SAFETY: buf must have enough capacity for `v[..mid]`. unsafe { ptr::copy_nonoverlapping(v, buf, mid); hole = MergeHole { start: buf, end: buf.add(mid), dest: v }; @@ -1048,6 +1054,8 @@ where while *left < hole.end && right < v_end { // Consume the lesser side. // If equal, prefer the left run to maintain stability. + + // SAFETY: left and right must be valid and part of v same for out. unsafe { let to_copy = if is_less(&*right, &**left) { get_and_increment(&mut right) @@ -1059,6 +1067,8 @@ where } } else { // The right run is shorter. + + // SAFETY: buf must have enough capacity for `v[mid..]`. unsafe { ptr::copy_nonoverlapping(v_mid, buf, len - mid); hole = MergeHole { start: buf, end: buf.add(len - mid), dest: v_mid }; @@ -1072,6 +1082,8 @@ where while v < *left && buf < *right { // Consume the greater side. // If equal, prefer the right run to maintain stability. + + // SAFETY: left and right must be valid and part of v same for out. unsafe { let to_copy = if is_less(&*right.sub(1), &*left.sub(1)) { decrement_and_get(left) @@ -1087,11 +1099,14 @@ where unsafe fn get_and_increment(ptr: &mut *mut T) -> *mut T { let old = *ptr; + + // SAFETY: ptr.add(1) must still be a valid pointer and part of `v`. *ptr = unsafe { ptr.add(1) }; old } unsafe fn decrement_and_get(ptr: &mut *mut T) -> *mut T { + // SAFETY: ptr.sub(1) must still be a valid pointer and part of `v`. *ptr = unsafe { ptr.sub(1) }; *ptr } @@ -1105,7 +1120,7 @@ where impl Drop for MergeHole { fn drop(&mut self) { - // `T` is not a zero-sized type, and these are pointers into a slice's elements. + // SAFETY: `T` is not a zero-sized type, and these are pointers into a slice's elements. unsafe { let len = self.end.sub_ptr(self.start); ptr::copy_nonoverlapping(self.start, self.dest, len); @@ -1180,6 +1195,8 @@ pub fn merge_sort( let mut start = end - 1; if start > 0 { start -= 1; + + // SAFETY: The v.get_unchecked must be fed with correct inbound indicies. unsafe { if is_less(v.get_unchecked(start + 1), v.get_unchecked(start)) { while start > 0 && is_less(v.get_unchecked(start), v.get_unchecked(start - 1)) { @@ -1210,6 +1227,8 @@ pub fn merge_sort( while let Some(r) = collapse(runs.as_slice()) { let left = runs[r + 1]; let right = runs[r]; + // SAFETY: `buf_ptr` must hold enough capacity for the shorter of the two sides, and + // neither side may be on length 0. unsafe { merge(&mut v[left.start..right.start + right.len], left.len, buf_ptr, is_less); } From 0fb426ace4ed07bc023863ebd8103ac49fba1283 Mon Sep 17 00:00:00 2001 From: Chris Wailes Date: Mon, 26 Sep 2022 15:50:56 -0700 Subject: [PATCH 006/230] Update CI to use Android NDK r25b This commit updates the CI definitions to use the most recent Android LTS NDK release: r25b. Changes since the last NDK used by Rust negate the need to generate "standalone toolchains" and newer NDKs can be used in-place. See https://developer.android.com/ndk/guides/other_build_systems#overview --- src/bootstrap/cc_detect.rs | 24 ++++++++++++++----- .../docker/host-x86_64/arm-android/Dockerfile | 6 ++--- .../host-x86_64/dist-android/Dockerfile | 23 +++++++----------- src/ci/docker/scripts/android-ndk.sh | 22 ++--------------- 4 files changed, 31 insertions(+), 44 deletions(-) diff --git a/src/bootstrap/cc_detect.rs b/src/bootstrap/cc_detect.rs index 7128d542acfe9..65c882fb801e5 100644 --- a/src/bootstrap/cc_detect.rs +++ b/src/bootstrap/cc_detect.rs @@ -47,6 +47,8 @@ fn cc2ar(cc: &Path, target: TargetSelection) -> Option { Some(PathBuf::from("ar")) } else if target.contains("vxworks") { Some(PathBuf::from("wr-ar")) + } else if target.contains("android") { + Some(cc.parent().unwrap().join(PathBuf::from("llvm-ar"))) } else { let parent = cc.parent().unwrap(); let file = cc.file_name().unwrap().to_str().unwrap(); @@ -219,12 +221,22 @@ fn set_compiler( } pub(crate) fn ndk_compiler(compiler: Language, triple: &str, ndk: &Path) -> PathBuf { - let triple_translated = triple - .replace("armv7neon", "arm") - .replace("armv7", "arm") - .replace("thumbv7neon", "arm") - .replace("thumbv7", "arm"); - let compiler = format!("{}-{}", triple_translated, compiler.clang()); + let mut triple_iter = triple.split("-"); + let triple_translated = if let Some(arch) = triple_iter.next() { + let arch_new = match arch { + "arm" | "armv7" | "armv7neon" | "thumbv7" | "thumbv7neon" => "armv7a", + other => other, + }; + std::iter::once(arch_new).chain(triple_iter).collect::>().join("-") + } else { + triple.to_string() + }; + + // API 19 is the earliest API level supported by NDK r25b but AArch64 and x86_64 support + // begins at API level 21. + let api_level = + if triple.contains("aarch64") || triple.contains("x86_64") { "21" } else { "19" }; + let compiler = format!("{}{}-{}", triple_translated, api_level, compiler.clang()); ndk.join("bin").join(compiler) } diff --git a/src/ci/docker/host-x86_64/arm-android/Dockerfile b/src/ci/docker/host-x86_64/arm-android/Dockerfile index 7a875c960e133..b6b4fdc67a949 100644 --- a/src/ci/docker/host-x86_64/arm-android/Dockerfile +++ b/src/ci/docker/host-x86_64/arm-android/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ubuntu:22.10 ARG DEBIAN_FRONTEND=noninteractive COPY scripts/android-base-apt-get.sh /scripts/ @@ -6,7 +6,7 @@ RUN sh /scripts/android-base-apt-get.sh COPY scripts/android-ndk.sh /scripts/ RUN . /scripts/android-ndk.sh && \ - download_and_make_toolchain android-ndk-r15c-linux-x86_64.zip arm 14 + download_ndk android-ndk-r25b-linux.zip RUN dpkg --add-architecture i386 && \ apt-get update && \ @@ -30,7 +30,7 @@ ENV PATH=$PATH:/android/sdk/platform-tools ENV TARGETS=arm-linux-androideabi -ENV RUST_CONFIGURE_ARGS --arm-linux-androideabi-ndk=/android/ndk/arm-14 +ENV RUST_CONFIGURE_ARGS --arm-linux-androideabi-ndk=/android/ndk/toolchains/llvm/prebuilt/linux-x86_64/ ENV SCRIPT python3 ../x.py --stage 2 test --host='' --target $TARGETS diff --git a/src/ci/docker/host-x86_64/dist-android/Dockerfile b/src/ci/docker/host-x86_64/dist-android/Dockerfile index 2328db4ab8b1d..9c6f648896b51 100644 --- a/src/ci/docker/host-x86_64/dist-android/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-android/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ubuntu:22.10 COPY scripts/android-base-apt-get.sh /scripts/ RUN sh /scripts/android-base-apt-get.sh @@ -6,14 +6,7 @@ RUN sh /scripts/android-base-apt-get.sh # ndk COPY scripts/android-ndk.sh /scripts/ RUN . /scripts/android-ndk.sh && \ - download_ndk android-ndk-r15c-linux-x86_64.zip && \ - make_standalone_toolchain arm 14 && \ - make_standalone_toolchain x86 14 && \ - make_standalone_toolchain arm 21 && \ - make_standalone_toolchain x86 21 && \ - make_standalone_toolchain arm64 21 && \ - make_standalone_toolchain x86_64 21 && \ - remove_ndk + download_ndk android-ndk-r25b-linux.zip # env ENV TARGETS=arm-linux-androideabi @@ -26,12 +19,12 @@ ENV TARGETS=$TARGETS,x86_64-linux-android ENV RUST_CONFIGURE_ARGS \ --enable-extended \ --enable-profiler \ - --arm-linux-androideabi-ndk=/android/ndk/arm-14 \ - --armv7-linux-androideabi-ndk=/android/ndk/arm-14 \ - --thumbv7neon-linux-androideabi-ndk=/android/ndk/arm-14 \ - --i686-linux-android-ndk=/android/ndk/x86-14 \ - --aarch64-linux-android-ndk=/android/ndk/arm64-21 \ - --x86_64-linux-android-ndk=/android/ndk/x86_64-21 \ + --arm-linux-androideabi-ndk=/android/ndk/toolchains/llvm/prebuilt/linux-x86_64/ \ + --armv7-linux-androideabi-ndk=/android/ndk/toolchains/llvm/prebuilt/linux-x86_64/ \ + --thumbv7neon-linux-androideabi-ndk=/android/ndk/toolchains/llvm/prebuilt/linux-x86_64/ \ + --i686-linux-android-ndk=/android/ndk/toolchains/llvm/prebuilt/linux-x86_64/ \ + --aarch64-linux-android-ndk=/android/ndk/toolchains/llvm/prebuilt/linux-x86_64/ \ + --x86_64-linux-android-ndk=/android/ndk/toolchains/llvm/prebuilt/linux-x86_64/ \ --disable-docs ENV SCRIPT python3 ../x.py dist --host='' --target $TARGETS diff --git a/src/ci/docker/scripts/android-ndk.sh b/src/ci/docker/scripts/android-ndk.sh index ba70c62ea3081..4dd6ac274fd5b 100644 --- a/src/ci/docker/scripts/android-ndk.sh +++ b/src/ci/docker/scripts/android-ndk.sh @@ -4,28 +4,10 @@ set -ex URL=https://dl.google.com/android/repository download_ndk() { - mkdir -p /android/ndk - cd /android/ndk + mkdir /android/ + cd /android curl -fO $URL/$1 unzip -q $1 rm $1 mv android-ndk-* ndk } - -make_standalone_toolchain() { - # See https://developer.android.com/ndk/guides/standalone_toolchain.htm - python3 /android/ndk/ndk/build/tools/make_standalone_toolchain.py \ - --install-dir /android/ndk/$1-$2 \ - --arch $1 \ - --api $2 -} - -remove_ndk() { - rm -rf /android/ndk/ndk -} - -download_and_make_toolchain() { - download_ndk $1 && \ - make_standalone_toolchain $2 $3 && \ - remove_ndk -} From 8915ba7b1b6433032400ace217e765bd96686763 Mon Sep 17 00:00:00 2001 From: Alex Touchet Date: Wed, 28 Dec 2022 21:47:09 -0800 Subject: [PATCH 007/230] Improve Markdown styling in README --- README.md | 163 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 90 insertions(+), 73 deletions(-) diff --git a/README.md b/README.md index ac39435a8c7fb..0eb7c4b266a9f 100644 --- a/README.md +++ b/README.md @@ -3,10 +3,11 @@ This is the main source code repository for [Rust]. It contains the compiler, standard library, and documentation. -[Rust]: https://www.rust-lang.org +[Rust]: https://www.rust-lang.org/ **Note: this README is for _users_ rather than _contributors_.** -If you wish to _contribute_ to the compiler, you should read [CONTRIBUTING.md](CONTRIBUTING.md) instead. +If you wish to _contribute_ to the compiler, you should read +[CONTRIBUTING.md](CONTRIBUTING.md) instead. ## Quick Start @@ -20,13 +21,15 @@ Read ["Installation"] from [The Book]. The Rust build system uses a Python script called `x.py` to build the compiler, which manages the bootstrapping process. It lives at the root of the project. -The `x.py` command can be run directly on most Unix systems in the following format: +The `x.py` command can be run directly on most Unix systems in the following +format: ```sh ./x.py [flags] ``` -This is how the documentation and examples assume you are running `x.py`. Some alternative ways are: +This is how the documentation and examples assume you are running `x.py`. +Some alternative ways are: ```sh # On a Unix shell if you don't have the necessary `python3` command @@ -39,8 +42,8 @@ x.py [flags] python x.py [flags] ``` -More information about `x.py` can be found -by running it with the `--help` flag or reading the [rustc dev guide][rustcguidebuild]. +More information about `x.py` can be found by running it with the `--help` flag +or reading the [rustc dev guide][rustcguidebuild]. [gettingstarted]: https://rustc-dev-guide.rust-lang.org/getting-started.html [rustcguidebuild]: https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html @@ -49,24 +52,29 @@ by running it with the `--help` flag or reading the [rustc dev guide][rustcguide Make sure you have installed the dependencies: - * `python` 3 or 2.7 - * `git` - * A C compiler (when building for the host, `cc` is enough; cross-compiling may need additional compilers) - * `curl` (not needed on Windows) - * `pkg-config` if you are compiling on Linux and targeting Linux - * `libiconv` (already included with glibc on Debian-based distros) +* `python` 3 or 2.7 +* `git` +* A C compiler (when building for the host, `cc` is enough; cross-compiling may + need additional compilers) +* `curl` (not needed on Windows) +* `pkg-config` if you are compiling on Linux and targeting Linux +* `libiconv` (already included with glibc on Debian-based distros) -To build cargo, you'll also need OpenSSL (`libssl-dev` or `openssl-devel` on most Unix distros). +To build Cargo, you'll also need OpenSSL (`libssl-dev` or `openssl-devel` on +most Unix distros). If building LLVM from source, you'll need additional tools: * `g++`, `clang++`, or MSVC with versions listed on [LLVM's documentation](https://llvm.org/docs/GettingStarted.html#host-c-toolchain-both-compiler-and-standard-library) -* `ninja`, or GNU `make` 3.81 or later (ninja is recommended, especially on Windows) +* `ninja`, or GNU `make` 3.81 or later (Ninja is recommended, especially on + Windows) * `cmake` 3.13.4 or later -* `libstdc++-static` may be required on some Linux distributions such as Fedora and Ubuntu +* `libstdc++-static` may be required on some Linux distributions such as Fedora + and Ubuntu -On tier 1 or tier 2 with host tools platforms, you can also choose to download LLVM by setting `llvm.download-ci-llvm = true`. +On tier 1 or tier 2 with host tools platforms, you can also choose to download +LLVM by setting `llvm.download-ci-llvm = true`. Otherwise, you'll need LLVM installed and `llvm-config` in your path. See [the rustc-dev-guide for more info][sysllvm]. @@ -86,34 +94,37 @@ See [the rustc-dev-guide for more info][sysllvm]. 2. Configure the build settings: - The Rust build system uses a file named `config.toml` in the root of the - source tree to determine various configuration settings for the build. - Set up the defaults intended for distros to get started. You can see a full list of options - in `config.toml.example`. + The Rust build system uses a file named `config.toml` in the root of the + source tree to determine various configuration settings for the build. + Set up the defaults intended for distros to get started. You can see a full + list of options in `config.toml.example`. - ```sh - printf 'profile = "user" \nchangelog-seen = 2 \n' > config.toml - ``` + ```sh + printf 'profile = "user" \nchangelog-seen = 2 \n' > config.toml + ``` - If you plan to use `x.py install` to create an installation, it is recommended - that you set the `prefix` value in the `[install]` section to a directory. + If you plan to use `x.py install` to create an installation, it is + recommended that you set the `prefix` value in the `[install]` section to a + directory. 3. Build and install: - ```sh - ./x.py build && ./x.py install - ``` + ```sh + ./x.py build && ./x.py install + ``` - When complete, `./x.py install` will place several programs into - `$PREFIX/bin`: `rustc`, the Rust compiler, and `rustdoc`, the - API-documentation tool. If you've set `profile = "user"` or `build.extended = true`, it will - also include [Cargo], Rust's package manager. + When complete, `./x.py install` will place several programs into + `$PREFIX/bin`: `rustc`, the Rust compiler, and `rustdoc`, the + API-documentation tool. If you've set `profile = "user"` or + `build.extended = true`, it will also include [Cargo], Rust's package + manager. [Cargo]: https://github.com/rust-lang/cargo ### Building on Windows -On Windows, we suggest using [winget] to install dependencies by running the following in a terminal: +On Windows, we suggest using [winget] to install dependencies by running the +following in a terminal: ```powershell winget install -e Python.Python.3 @@ -121,17 +132,19 @@ winget install -e Kitware.CMake winget install -e Git.Git ``` -Then edit your system's `PATH` variable and add: `C:\Program Files\CMake\bin`. See -[this guide on editing the system `PATH`](https://www.java.com/en/download/help/path.html) from the -Java documentation. +Then edit your system's `PATH` variable and add: `C:\Program Files\CMake\bin`. +See +[this guide on editing the system `PATH`](https://www.java.com/en/download/help/path.html) +from the Java documentation. [winget]: https://github.com/microsoft/winget-cli There are two prominent ABIs in use on Windows: the native (MSVC) ABI used by Visual Studio and the GNU ABI used by the GCC toolchain. Which version of Rust you need depends largely on what C/C++ libraries you want to interoperate with. -Use the MSVC build of Rust to interop with software produced by Visual Studio and -the GNU build to interop with GNU software built using the MinGW/MSYS2 toolchain. +Use the MSVC build of Rust to interop with software produced by Visual Studio +and the GNU build to interop with GNU software built using the MinGW/MSYS2 +toolchain. #### MinGW @@ -144,7 +157,7 @@ the GNU build to interop with GNU software built using the MinGW/MSYS2 toolchain 2. Run `mingw32_shell.bat` or `mingw64_shell.bat` from the MSYS2 installation directory (e.g. `C:\msys64`), depending on whether you want 32-bit or 64-bit Rust. (As of the latest version of MSYS2 you have to run `msys2_shell.cmd - -mingw32` or `msys2_shell.cmd -mingw64` from the command line instead) + -mingw32` or `msys2_shell.cmd -mingw64` from the command line instead.) 3. From this terminal, install the required tools: @@ -153,11 +166,11 @@ the GNU build to interop with GNU software built using the MinGW/MSYS2 toolchain pacman -Sy pacman-mirrors # Install build tools needed for Rust. If you're building a 32-bit compiler, - # then replace "x86_64" below with "i686". If you've already got git, python, - # or CMake installed and in PATH you can remove them from this list. Note - # that it is important that you do **not** use the 'python2', 'cmake' and 'ninja' - # packages from the 'msys2' subsystem. The build has historically been known - # to fail with these packages. + # then replace "x86_64" below with "i686". If you've already got Git, Python, + # or CMake installed and in PATH you can remove them from this list. + # Note that it is important that you do **not** use the 'python2', 'cmake', + # and 'ninja' packages from the 'msys2' subsystem. + # The build has historically been known to fail with these packages. pacman -S git \ make \ diffutils \ @@ -178,12 +191,12 @@ the GNU build to interop with GNU software built using the MinGW/MSYS2 toolchain MSVC builds of Rust additionally require an installation of Visual Studio 2017 (or later) so `rustc` can use its linker. The simplest way is to get -[Visual Studio], check the “C++ build tools” and “Windows 10 SDK” workload. +[Visual Studio], check the "C++ build tools" and "Windows 10 SDK" workload. [Visual Studio]: https://visualstudio.microsoft.com/downloads/ -(If you're installing cmake yourself, be careful that “C++ CMake tools for -Windows” doesn't get included under “Individual components”.) +(If you're installing CMake yourself, be careful that "C++ CMake tools for +Windows" doesn't get included under "Individual components".) With these dependencies installed, you can build the compiler in a `cmd.exe` shell with: @@ -192,10 +205,11 @@ shell with: python x.py build ``` -Right now, building Rust only works with some known versions of Visual Studio. If -you have a more recent version installed and the build system doesn't understand, -you may need to force rustbuild to use an older version. This can be done -by manually calling the appropriate vcvars file before running the bootstrap. +Right now, building Rust only works with some known versions of Visual Studio. +If you have a more recent version installed and the build system doesn't +understand, you may need to force rustbuild to use an older version. +This can be done by manually calling the appropriate vcvars file before running +the bootstrap. ```batch CALL "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" @@ -215,9 +229,9 @@ Windows build triples are: - `x86_64-pc-windows-msvc` The build triple can be specified by either specifying `--build=` when -invoking `x.py` commands, or by creating a `config.toml` file (as described -in [Installing From Source](#installing-from-source)), and modifying the -`build` option under the `[build]` section. +invoking `x.py` commands, or by creating a `config.toml` file (as described in +[Installing from Source](#installing-from-source)), and modifying the `build` +option under the `[build]` section. ### Configure and Make @@ -229,33 +243,35 @@ configure script and makefile (the latter of which just invokes `x.py`). make && sudo make install ``` -`configure` generates a `config.toml` which can also be used with normal `x.py` invocations. +`configure` generates a `config.toml` which can also be used with normal `x.py` +invocations. ## Building Documentation -If you’d like to build the documentation, it’s almost the same: +If you'd like to build the documentation, it's almost the same: ```sh ./x.py doc ``` The generated documentation will appear under `doc` in the `build` directory for -the ABI used. I.e., if the ABI was `x86_64-pc-windows-msvc`, the directory will be -`build\x86_64-pc-windows-msvc\doc`. +the ABI used. That is, if the ABI was `x86_64-pc-windows-msvc`, the directory +will be `build\x86_64-pc-windows-msvc\doc`. ## Notes -Since the Rust compiler is written in Rust, it must be built by a -precompiled "snapshot" version of itself (made in an earlier stage of -development). As such, source builds require an Internet connection to -fetch snapshots, and an OS that can execute the available snapshot binaries. +Since the Rust compiler is written in Rust, it must be built by a precompiled +"snapshot" version of itself (made in an earlier stage of development). +As such, source builds require an Internet connection to fetch snapshots, and an +OS that can execute the available snapshot binaries. -See https://doc.rust-lang.org/nightly/rustc/platform-support.html for a list of supported platforms. -Only "host tools" platforms have a pre-compiled snapshot binary available; to compile for a platform -without host tools you must cross-compile. +See https://doc.rust-lang.org/nightly/rustc/platform-support.html for a list of +supported platforms. +Only "host tools" platforms have a pre-compiled snapshot binary available; to +compile for a platform without host tools you must cross-compile. -You may find that other platforms work, but these are our officially -supported build environments that are most likely to work. +You may find that other platforms work, but these are our officially supported +build environments that are most likely to work. ## Getting Help @@ -267,9 +283,9 @@ See [CONTRIBUTING.md](CONTRIBUTING.md). ## License -Rust is primarily distributed under the terms of both the MIT license -and the Apache License (Version 2.0), with portions covered by various -BSD-like licenses. +Rust is primarily distributed under the terms of both the MIT license and the +Apache License (Version 2.0), with portions covered by various BSD-like +licenses. See [LICENSE-APACHE](LICENSE-APACHE), [LICENSE-MIT](LICENSE-MIT), and [COPYRIGHT](COPYRIGHT) for details. @@ -277,13 +293,14 @@ See [LICENSE-APACHE](LICENSE-APACHE), [LICENSE-MIT](LICENSE-MIT), and ## Trademark [The Rust Foundation][rust-foundation] owns and protects the Rust and Cargo -trademarks and logos (the “Rust Trademarks”). +trademarks and logos (the "Rust Trademarks"). -If you want to use these names or brands, please read the [media guide][media-guide]. +If you want to use these names or brands, please read the +[media guide][media-guide]. Third-party logos may be subject to third-party copyrights and trademarks. See [Licenses][policies-licenses] for details. [rust-foundation]: https://foundation.rust-lang.org/ -[media-guide]: https://www.rust-lang.org/policies/media-guide +[media-guide]: https://foundation.rust-lang.org/policies/logo-policy-and-media-guide/ [policies-licenses]: https://www.rust-lang.org/policies/licenses From 799fa60c07784bb033d1e1bcdcc7f671ea47d617 Mon Sep 17 00:00:00 2001 From: Krasimir Georgiev Date: Sat, 24 Dec 2022 08:19:20 +0000 Subject: [PATCH 008/230] llvm-wrapper: adapt for LLVM API change No functional changes intended. The LLVM commit https://github.com/llvm/llvm-project/commit/e6b02214c68df2c9f826e02310c9352ac652e456 added `TargetExtTyID` to the `TypeID` enum. This adapts `RustWrapper` accordingly. --- .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 279b699185421..a26da9d548fb6 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1349,18 +1349,16 @@ extern "C" LLVMTypeKind LLVMRustGetTypeKind(LLVMTypeRef Ty) { return LLVMBFloatTypeKind; case Type::X86_AMXTyID: return LLVMX86_AMXTypeKind; -#if LLVM_VERSION_GE(15, 0) && LLVM_VERSION_LT(16, 0) - case Type::DXILPointerTyID: - report_fatal_error("Rust does not support DirectX typed pointers."); - break; -#endif -#if LLVM_VERSION_GE(16, 0) - case Type::TypedPointerTyID: - report_fatal_error("Rust does not support typed pointers."); - break; -#endif + default: + { + std::string error; + llvm::raw_string_ostream stream(error); + stream << "Rust does not support the TypeID: " << unwrap(Ty)->getTypeID() + << " for the type: " << *unwrap(Ty); + stream.flush(); + report_fatal_error(error.c_str()); + } } - report_fatal_error("Unhandled TypeID."); } DEFINE_SIMPLE_CONVERSION_FUNCTIONS(SMDiagnostic, LLVMSMDiagnosticRef) From ee59533167706986ab6fe912a6fb246f7917022e Mon Sep 17 00:00:00 2001 From: mllken Date: Wed, 4 Jan 2023 12:47:43 +0700 Subject: [PATCH 009/230] relax reference requirement on from_abstract_name --- library/std/src/os/net/linux_ext/addr.rs | 2 +- library/std/src/os/unix/net/addr.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/os/net/linux_ext/addr.rs b/library/std/src/os/net/linux_ext/addr.rs index df3fc8e6a3b66..85065984fbbb1 100644 --- a/library/std/src/os/net/linux_ext/addr.rs +++ b/library/std/src/os/net/linux_ext/addr.rs @@ -38,7 +38,7 @@ pub trait SocketAddrExt: Sealed { /// Ok(()) /// } /// ``` - fn from_abstract_name(name: &N) -> crate::io::Result + fn from_abstract_name(name: N) -> crate::io::Result where N: AsRef<[u8]>; diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index 81ac829d21bc8..ece2b33bddf36 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -256,7 +256,7 @@ impl linux_ext::addr::SocketAddrExt for SocketAddr { if let AddressKind::Abstract(name) = self.address() { Some(name) } else { None } } - fn from_abstract_name(name: &N) -> crate::io::Result + fn from_abstract_name(name: N) -> crate::io::Result where N: AsRef<[u8]>, { From 13e25b82f0d3afc7bcfc6cd1617e8e4287172960 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 25 Dec 2022 18:10:11 -0500 Subject: [PATCH 010/230] Improve the documentation of `black_box` --- library/core/src/hint.rs | 69 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index e8d724ab1ef4e..5a76e86692336 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -219,6 +219,75 @@ pub fn spin_loop() { /// backend used. Programs cannot rely on `black_box` for *correctness* in any way. /// /// [`std::convert::identity`]: crate::convert::identity +/// +/// # When is this useful? +/// +/// First and foremost: `black_box` does _not_ guarantee any exact behavior and, in some cases, may +/// do nothing at all. As such, it **must not be relied upon to control critical program behavior.** +/// This _immediately_ precludes any direct use of this function for cryptographic or security +/// purposes. +/// +/// While not suitable in those mission-critical cases, `back_box`'s functionality can generally be +/// relied upon for benchmarking, and should be used there. It will try to ensure that the +/// compiler doesn't optimize away part of the intended test code based on context. For +/// example: +/// +/// ``` +/// fn contains(haystack: &[&str], needle: &str) -> bool { +/// haystack.iter().any(|x| x == &needle) +/// } +/// +/// pub fn benchmark() { +/// let haystack = vec!["abc", "def", "ghi", "jkl", "mno"]; +/// let needle = "ghi"; +/// for _ in 0..10 { +/// contains(&haystack, needle); +/// } +/// } +/// ``` +/// +/// The compiler could theoretically make optimizations like the following: +/// +/// - `needle` and `haystack` are always the same, move the call to `contains` outside the loop and +/// delete the loop +/// - Inline `contains` +/// - `needle` and `haystack` have values known at compile time, `contains` is always true. Remove +/// the call and replace with `true` +/// - Nothing is done with the result of `contains`: delete this function call entirely +/// - `benchmark` now has no purpose: delete this function +/// +/// It is not likely that all of the above happens, but the compiler is definitely able to make some +/// optimizations that could result in a very inaccurate benchmark. This is where `black_box` comes +/// in: +/// +/// ``` +/// use std::hint::black_box; +/// +/// // Same `contains` function +/// fn contains(haystack: &[&str], needle: &str) -> bool { +/// haystack.iter().any(|x| x == &needle) +/// } +/// +/// pub fn benchmark() { +/// let haystack = vec!["abc", "def", "ghi", "jkl", "mno"]; +/// let needle = "ghi"; +/// for _ in 0..10 { +/// // Adjust our benchmark loop contents +/// black_box(contains(black_box(&haystack), black_box(needle))); +/// } +/// } +/// ``` +/// +/// This essentially tells the compiler to block optimizations across any calls to `black_box`. So, +/// it now: +/// +/// - Treats both arguments to `contains` as unpredictable: the body of `contains` can no longer be +/// optimized based on argument values +/// - Treats the call to `contains` and its result as volatile: the body of `benchmark` cannot +/// optimize this away +/// +/// This makes our benchmark much more realistic to how the function would be used in situ, where +/// arguments are usually not known at compile time and the result is used in some way. #[inline] #[stable(feature = "bench_black_box", since = "1.66.0")] #[rustc_const_unstable(feature = "const_black_box", issue = "none")] From b7bb8a5ce98eddeed8c16229925688d1c2abfbc9 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 5 Jan 2023 18:23:16 +0000 Subject: [PATCH 011/230] Do not filter substs in `remap_generic_params_to_declaration_params`. The relevant filtering should have been performed by borrowck. --- .../src/region_infer/opaque_types.rs | 2 +- compiler/rustc_hir_typeck/src/writeback.rs | 1 - compiler/rustc_middle/src/ty/mod.rs | 27 +------------ tests/ui/impl-trait/issues/issue-105826.rs | 39 +++++++++++++++++++ 4 files changed, 41 insertions(+), 28 deletions(-) create mode 100644 tests/ui/impl-trait/issues/issue-105826.rs diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 767f9fe39c68b..5f9b4e74e9c5a 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -250,7 +250,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { } let definition_ty = instantiated_ty - .remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false, origin) + .remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false) .ty; if !check_opaque_type_parameter_valid( diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 8c24b6006444a..30ef7f3ba2927 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -564,7 +564,6 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { opaque_type_key, self.fcx.infcx.tcx, true, - decl.origin, ); self.typeck_results.concrete_opaque_types.insert(opaque_type_key.def_id, hidden_type); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index f01d74539a12e..d5f2fe3ac3792 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -28,7 +28,6 @@ use crate::ty::util::Discr; pub use adt::*; pub use assoc::*; pub use generics::*; -use hir::OpaqueTyOrigin; use rustc_ast as ast; use rustc_ast::node_id::NodeMap; use rustc_attr as attr; @@ -1316,7 +1315,6 @@ impl<'tcx> OpaqueHiddenType<'tcx> { tcx: TyCtxt<'tcx>, // typeck errors have subpar spans for opaque types, so delay error reporting until borrowck. ignore_errors: bool, - origin: OpaqueTyOrigin, ) -> Self { let OpaqueTypeKey { def_id, substs } = opaque_type_key; @@ -1332,30 +1330,7 @@ impl<'tcx> OpaqueHiddenType<'tcx> { // This zip may have several times the same lifetime in `substs` paired with a different // lifetime from `id_substs`. Simply `collect`ing the iterator is the correct behaviour: // it will pick the last one, which is the one we introduced in the impl-trait desugaring. - let map = substs.iter().zip(id_substs); - - let map: FxHashMap, GenericArg<'tcx>> = match origin { - // HACK: The HIR lowering for async fn does not generate - // any `+ Captures<'x>` bounds for the `impl Future<...>`, so all async fns with lifetimes - // would now fail to compile. We should probably just make hir lowering fill this in properly. - OpaqueTyOrigin::AsyncFn(_) => map.collect(), - OpaqueTyOrigin::FnReturn(_) | OpaqueTyOrigin::TyAlias => { - // Opaque types may only use regions that are bound. So for - // ```rust - // type Foo<'a, 'b, 'c> = impl Trait<'a> + 'b; - // ``` - // we may not use `'c` in the hidden type. - let variances = tcx.variances_of(def_id); - debug!(?variances); - - map.filter(|(_, v)| { - let ty::GenericArgKind::Lifetime(lt) = v.unpack() else { return true }; - let ty::ReEarlyBound(ebr) = lt.kind() else { bug!() }; - variances[ebr.index as usize] == ty::Variance::Invariant - }) - .collect() - } - }; + let map = substs.iter().zip(id_substs).collect(); debug!("map = {:#?}", map); // Convert the type from the function into a type valid outside diff --git a/tests/ui/impl-trait/issues/issue-105826.rs b/tests/ui/impl-trait/issues/issue-105826.rs new file mode 100644 index 0000000000000..06dc2d4c8d34b --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-105826.rs @@ -0,0 +1,39 @@ +// check-pass + +use std::io::Write; + +struct A(Vec); + +struct B<'a> { + one: &'a mut A, + two: &'a mut Vec, + three: Vec, +} + +impl<'a> B<'a> { + fn one(&mut self) -> &mut impl Write { + &mut self.one.0 + } + fn two(&mut self) -> &mut impl Write { + &mut *self.two + } + fn three(&mut self) -> &mut impl Write { + &mut self.three + } +} + +struct C<'a>(B<'a>); + +impl<'a> C<'a> { + fn one(&mut self) -> &mut impl Write { + self.0.one() + } + fn two(&mut self) -> &mut impl Write { + self.0.two() + } + fn three(&mut self) -> &mut impl Write { + self.0.three() + } +} + +fn main() {} From 0be510ee7171c1498b1fcb4278dfa9976154c7bf Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 12 Jan 2023 04:19:45 +0000 Subject: [PATCH 012/230] RPITITs are not suggestable --- compiler/rustc_middle/src/ty/diagnostics.rs | 17 +++++++---- .../in-trait/missing-send-bound.rs | 21 ++++++++++++++ .../in-trait/missing-send-bound.stderr | 29 +++++++++++++++++++ 3 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 tests/ui/async-await/in-trait/missing-send-bound.rs create mode 100644 tests/ui/async-await/in-trait/missing-send-bound.stderr diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 8c22df7395f10..638bde27d8c69 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -4,12 +4,13 @@ use std::ops::ControlFlow; use crate::ty::{ visit::TypeVisitable, AliasTy, Const, ConstKind, DefIdTree, InferConst, InferTy, Opaque, - PolyTraitPredicate, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, + PolyTraitPredicate, Projection, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, }; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, Diagnostic, DiagnosticArgValue, IntoDiagnosticArg}; use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::WherePredicate; use rustc_span::Span; @@ -443,7 +444,7 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> { type BreakTy = (); fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { - match t.kind() { + match *t.kind() { Infer(InferTy::TyVar(_)) if self.infer_suggestable => {} FnDef(..) @@ -458,9 +459,9 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> { } Alias(Opaque, AliasTy { def_id, .. }) => { - let parent = self.tcx.parent(*def_id); - if let hir::def::DefKind::TyAlias | hir::def::DefKind::AssocTy = self.tcx.def_kind(parent) - && let Alias(Opaque, AliasTy { def_id: parent_opaque_def_id, .. }) = self.tcx.type_of(parent).kind() + let parent = self.tcx.parent(def_id); + if let DefKind::TyAlias | DefKind::AssocTy = self.tcx.def_kind(parent) + && let Alias(Opaque, AliasTy { def_id: parent_opaque_def_id, .. }) = *self.tcx.type_of(parent).kind() && parent_opaque_def_id == def_id { // Okay @@ -469,6 +470,12 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> { } } + Alias(Projection, AliasTy { def_id, .. }) => { + if self.tcx.def_kind(def_id) != DefKind::AssocTy { + return ControlFlow::Break(()); + } + } + Param(param) => { // FIXME: It would be nice to make this not use string manipulation, // but it's pretty hard to do this, since `ty::ParamTy` is missing diff --git a/tests/ui/async-await/in-trait/missing-send-bound.rs b/tests/ui/async-await/in-trait/missing-send-bound.rs new file mode 100644 index 0000000000000..78922b59b27b7 --- /dev/null +++ b/tests/ui/async-await/in-trait/missing-send-bound.rs @@ -0,0 +1,21 @@ +// edition:2021 + +#![feature(async_fn_in_trait)] +//~^ WARN the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes + +trait Foo { + async fn bar(); +} + +async fn test() { + T::bar().await; +} + +fn test2() { + assert_is_send(test::()); + //~^ ERROR future cannot be sent between threads safely +} + +fn assert_is_send(_: impl Send) {} + +fn main() {} diff --git a/tests/ui/async-await/in-trait/missing-send-bound.stderr b/tests/ui/async-await/in-trait/missing-send-bound.stderr new file mode 100644 index 0000000000000..5cedf3ddb0f68 --- /dev/null +++ b/tests/ui/async-await/in-trait/missing-send-bound.stderr @@ -0,0 +1,29 @@ +warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/missing-send-bound.rs:3:12 + | +LL | #![feature(async_fn_in_trait)] + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #91611 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: future cannot be sent between threads safely + --> $DIR/missing-send-bound.rs:15:20 + | +LL | assert_is_send(test::()); + | ^^^^^^^^^^^ future returned by `test` is not `Send` + | + = help: within `impl Future`, the trait `Send` is not implemented for `impl Future` +note: future is not `Send` as it awaits another future which is not `Send` + --> $DIR/missing-send-bound.rs:11:5 + | +LL | T::bar().await; + | ^^^^^^^^ await occurs here on type `impl Future`, which is not `Send` +note: required by a bound in `assert_is_send` + --> $DIR/missing-send-bound.rs:19:27 + | +LL | fn assert_is_send(_: impl Send) {} + | ^^^^ required by this bound in `assert_is_send` + +error: aborting due to previous error; 1 warning emitted + From 741c65344b4f2c860cb1237f431ebe0da418b0f1 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Thu, 12 Jan 2023 11:28:47 +0000 Subject: [PATCH 013/230] Remove an `unwrap()` from parser that can be written as if-let-chain --- compiler/rustc_parse/src/parser/expr.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index f5093fb02a875..1f6e33971050d 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1709,10 +1709,10 @@ impl<'a> Parser<'a> { fn parse_break_expr(&mut self) -> PResult<'a, P> { let lo = self.prev_token.span; let mut label = self.eat_label(); - let kind = if label.is_some() && self.token == token::Colon { + let kind = if self.token == token::Colon && let Some(label) = label.take() { // The value expression can be a labeled loop, see issue #86948, e.g.: // `loop { break 'label: loop { break 'label 42; }; }` - let lexpr = self.parse_labeled_expr(label.take().unwrap(), true)?; + let lexpr = self.parse_labeled_expr(label, true)?; self.sess.emit_err(LabeledLoopInBreak { span: lexpr.span, sub: WrapExpressionInParentheses { From b0609889d7ca7f11dcb90880caf97fdf411a9374 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Thu, 12 Jan 2023 19:25:32 +0000 Subject: [PATCH 014/230] Add a test for recovery of unticked labels --- tests/ui/parser/recover-unticked-labels.rs | 5 ++++ .../ui/parser/recover-unticked-labels.stderr | 25 +++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 tests/ui/parser/recover-unticked-labels.rs create mode 100644 tests/ui/parser/recover-unticked-labels.stderr diff --git a/tests/ui/parser/recover-unticked-labels.rs b/tests/ui/parser/recover-unticked-labels.rs new file mode 100644 index 0000000000000..88bd15d0ca8b9 --- /dev/null +++ b/tests/ui/parser/recover-unticked-labels.rs @@ -0,0 +1,5 @@ +fn main() { + 'label: loop { break label } //~ error: cannot find value `label` in this scope + 'label: loop { break label 0 } //~ error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `0` + 'label: loop { continue label } //~ error: expected one of `.`, `;`, `?`, `}`, or an operator, found `label` +} diff --git a/tests/ui/parser/recover-unticked-labels.stderr b/tests/ui/parser/recover-unticked-labels.stderr new file mode 100644 index 0000000000000..3b48c1224b3ad --- /dev/null +++ b/tests/ui/parser/recover-unticked-labels.stderr @@ -0,0 +1,25 @@ +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `0` + --> $DIR/recover-unticked-labels.rs:3:32 + | +LL | 'label: loop { break label 0 } + | ^ expected one of 8 possible tokens + +error: expected one of `.`, `;`, `?`, `}`, or an operator, found `label` + --> $DIR/recover-unticked-labels.rs:4:29 + | +LL | 'label: loop { continue label } + | ^^^^^ expected one of `.`, `;`, `?`, `}`, or an operator + +error[E0425]: cannot find value `label` in this scope + --> $DIR/recover-unticked-labels.rs:2:26 + | +LL | 'label: loop { break label } + | ------ ^^^^^ + | | | + | | not found in this scope + | | help: use the similarly named label: `'label` + | a label with a similar name exists + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0425`. From 96de375e6773836e47c69fd23e55c77c509a5419 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Mon, 9 Jan 2023 16:19:36 -0800 Subject: [PATCH 015/230] Add a test case for #102383 --- tests/ui/async-await/await-sequence.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 tests/ui/async-await/await-sequence.rs diff --git a/tests/ui/async-await/await-sequence.rs b/tests/ui/async-await/await-sequence.rs new file mode 100644 index 0000000000000..726c4284ec15e --- /dev/null +++ b/tests/ui/async-await/await-sequence.rs @@ -0,0 +1,21 @@ +// edition:2021 +// compile-flags: -Z drop-tracking +// build-pass + +use std::collections::HashMap; + +fn main() { + let _ = real_main(); +} + +async fn nop() {} + +async fn real_main() { + nop().await; + nop().await; + nop().await; + nop().await; + + let mut map: HashMap<(), ()> = HashMap::new(); + map.insert((), nop().await); +} From d32f3fe14ecab069ceebe73063061f6aef05c217 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Mon, 9 Jan 2023 17:07:52 -0800 Subject: [PATCH 016/230] [drop tracking] Visit break expressions This fixes #102383 by remembering to visit the expression in `break expr` when building the drop tracking CFG. Missing this step was causing an off-by-one error which meant after a number of awaits we'd be looking for dropped values at the wrong point in the code. Additionally, this changes the order of traversal for assignment expressions to visit the rhs and then the lhs. This matches what is done elsewhere. --- .../drop_ranges/cfg_build.rs | 21 +++++++++++++++---- .../drop_ranges/cfg_visualize.rs | 13 ++++++++---- .../src/generator_interior/mod.rs | 18 ++++++++++++---- 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs index 16806fdba4fbc..b3dd3031db2a9 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs @@ -304,8 +304,8 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> { let mut reinit = None; match expr.kind { ExprKind::Assign(lhs, rhs, _) => { - self.visit_expr(lhs); self.visit_expr(rhs); + self.visit_expr(lhs); reinit = Some(lhs); } @@ -433,7 +433,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> { self.drop_ranges.add_control_edge(self.expr_index, *target) }), - ExprKind::Break(destination, ..) => { + ExprKind::Break(destination, value) => { // destination either points to an expression or to a block. We use // find_target_expression_from_destination to use the last expression of the block // if destination points to a block. @@ -443,7 +443,11 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> { // will refer to the end of the block due to the post order traversal. self.find_target_expression_from_destination(destination).map_or((), |target| { self.drop_ranges.add_control_edge_hir_id(self.expr_index, target) - }) + }); + + if let Some(value) = value { + self.visit_expr(value); + } } ExprKind::Call(f, args) => { @@ -465,6 +469,12 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> { ExprKind::AddrOf(..) | ExprKind::Array(..) + // FIXME(eholk): We probably need special handling for AssignOps. The ScopeTree builder + // in region.rs runs both lhs then rhs and rhs then lhs and then sets all yields to be + // the latest they show up in either traversal. With the older scope-based + // approximation, this was fine, but it's probably not right now. What we probably want + // to do instead is still run both orders, but consider anything that showed up as a + // yield in either order. | ExprKind::AssignOp(..) | ExprKind::Binary(..) | ExprKind::Block(..) @@ -502,6 +512,9 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> { // Increment expr_count here to match what InteriorVisitor expects. self.expr_index = self.expr_index + 1; + + // Save a node mapping to get better CFG visualization + self.drop_ranges.add_node_mapping(pat.hir_id, self.expr_index); } } @@ -521,7 +534,7 @@ impl DropRangesBuilder { } }); } - debug!("hir_id_map: {:?}", tracked_value_map); + debug!("hir_id_map: {:#?}", tracked_value_map); let num_values = tracked_value_map.len(); Self { tracked_value_map, diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_visualize.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_visualize.rs index c0a0bfe8e1c00..e8d31be79d9c9 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_visualize.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_visualize.rs @@ -2,6 +2,7 @@ //! flow graph when needed for debugging. use rustc_graphviz as dot; +use rustc_hir::{Expr, ExprKind, Node}; use rustc_middle::ty::TyCtxt; use super::{DropRangesBuilder, PostOrderId}; @@ -80,10 +81,14 @@ impl<'a> dot::Labeller<'a> for DropRangesGraph<'_, '_> { .post_order_map .iter() .find(|(_hir_id, &post_order_id)| post_order_id == *n) - .map_or("".into(), |(hir_id, _)| self - .tcx - .hir() - .node_to_string(*hir_id)) + .map_or("".into(), |(hir_id, _)| format!( + "{}{}", + self.tcx.hir().node_to_string(*hir_id), + match self.tcx.hir().find(*hir_id) { + Some(Node::Expr(Expr { kind: ExprKind::Yield(..), .. })) => " (yield)", + _ => "", + } + )) ) .into(), ) diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs index 7990d95310be5..7af5260538568 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs @@ -71,10 +71,8 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { yield_data.expr_and_pat_count, self.expr_count, source_span ); - if self.fcx.sess().opts.unstable_opts.drop_tracking - && self - .drop_ranges - .is_dropped_at(hir_id, yield_data.expr_and_pat_count) + if self + .is_dropped_at_yield_location(hir_id, yield_data.expr_and_pat_count) { debug!("value is dropped at yield point; not recording"); return false; @@ -173,6 +171,18 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { } } } + + /// If drop tracking is enabled, consult drop_ranges to see if a value is + /// known to be dropped at a yield point and therefore can be omitted from + /// the generator witness. + fn is_dropped_at_yield_location(&self, value_hir_id: HirId, yield_location: usize) -> bool { + // short-circuit if drop tracking is not enabled. + if !self.fcx.sess().opts.unstable_opts.drop_tracking { + return false; + } + + self.drop_ranges.is_dropped_at(value_hir_id, yield_location) + } } pub fn resolve_interior<'a, 'tcx>( From 57d822a904e440b6020d39274ac40a0ed68d55c9 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Thu, 12 Jan 2023 19:40:22 +0000 Subject: [PATCH 017/230] Recover labels written as identifiers --- compiler/rustc_parse/src/parser/expr.rs | 57 +++++++++++++++++-- tests/ui/parser/recover-unticked-labels.fixed | 7 +++ tests/ui/parser/recover-unticked-labels.rs | 8 ++- .../ui/parser/recover-unticked-labels.stderr | 20 +++---- 4 files changed, 74 insertions(+), 18 deletions(-) create mode 100644 tests/ui/parser/recover-unticked-labels.fixed diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 1f6e33971050d..84c049efc5014 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1346,9 +1346,6 @@ impl<'a> Parser<'a> { err.span_label(sp, "while parsing this `loop` expression"); err }) - } else if self.eat_keyword(kw::Continue) { - let kind = ExprKind::Continue(self.eat_label()); - Ok(self.mk_expr(lo.to(self.prev_token.span), kind)) } else if self.eat_keyword(kw::Match) { let match_sp = self.prev_token.span; self.parse_match_expr().map_err(|mut err| { @@ -1372,6 +1369,8 @@ impl<'a> Parser<'a> { self.parse_try_block(lo) } else if self.eat_keyword(kw::Return) { self.parse_return_expr() + } else if self.eat_keyword(kw::Continue) { + self.parse_continue_expr(lo) } else if self.eat_keyword(kw::Break) { self.parse_break_expr() } else if self.eat_keyword(kw::Yield) { @@ -1724,8 +1723,8 @@ impl<'a> Parser<'a> { } else if self.token != token::OpenDelim(Delimiter::Brace) || !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL) { - let expr = self.parse_expr_opt()?; - if let Some(expr) = &expr { + let mut expr = self.parse_expr_opt()?; + if let Some(expr) = &mut expr { if label.is_some() && matches!( expr.kind, @@ -1743,7 +1742,19 @@ impl<'a> Parser<'a> { BuiltinLintDiagnostics::BreakWithLabelAndLoop(expr.span), ); } + + // Recover `break label aaaaa` + if self.may_recover() + && let ExprKind::Path(None, p) = &expr.kind + && let [segment] = &*p.segments + && let &ast::PathSegment { ident, args: None, .. } = segment + && let Some(next) = self.parse_expr_opt()? + { + label = Some(self.recover_ident_into_label(ident)); + *expr = next; + } } + expr } else { None @@ -1752,6 +1763,23 @@ impl<'a> Parser<'a> { self.maybe_recover_from_bad_qpath(expr) } + /// Parse `"continue" label?`. + fn parse_continue_expr(&mut self, lo: Span) -> PResult<'a, P> { + let mut label = self.eat_label(); + + // Recover `continue label` -> `continue 'label` + if self.may_recover() + && label.is_none() + && let Some((ident, _)) = self.token.ident() + { + self.bump(); + label = Some(self.recover_ident_into_label(ident)); + } + + let kind = ExprKind::Continue(label); + Ok(self.mk_expr(lo.to(self.prev_token.span), kind)) + } + /// Parse `"yield" expr?`. fn parse_yield_expr(&mut self) -> PResult<'a, P> { let lo = self.prev_token.span; @@ -3037,6 +3065,25 @@ impl<'a> Parser<'a> { false } + /// Converts an ident into 'label and emits an "expected a label, found an identifier" error. + fn recover_ident_into_label(&mut self, ident: Ident) -> Label { + // Convert `label` -> `'label`, + // so that nameres doesn't complain about non-existing label + let label = format!("'{}", ident.name); + let ident = Ident { name: Symbol::intern(&label), span: ident.span }; + + self.struct_span_err(ident.span, "expected a label, found an identifier") + .span_suggestion( + ident.span, + "labels start with a tick", + label, + Applicability::MachineApplicable, + ) + .emit(); + + Label { ident } + } + /// Parses `ident (COLON expr)?`. fn parse_expr_field(&mut self) -> PResult<'a, ExprField> { let attrs = self.parse_outer_attributes()?; diff --git a/tests/ui/parser/recover-unticked-labels.fixed b/tests/ui/parser/recover-unticked-labels.fixed new file mode 100644 index 0000000000000..159d995b8dad3 --- /dev/null +++ b/tests/ui/parser/recover-unticked-labels.fixed @@ -0,0 +1,7 @@ +// run-rustfix + +fn main() { + 'label: loop { break 'label }; //~ error: cannot find value `label` in this scope + 'label: loop { break 'label 0 }; //~ error: expected a label, found an identifier + 'label: loop { continue 'label }; //~ error: expected a label, found an identifier +} diff --git a/tests/ui/parser/recover-unticked-labels.rs b/tests/ui/parser/recover-unticked-labels.rs index 88bd15d0ca8b9..56034de68449f 100644 --- a/tests/ui/parser/recover-unticked-labels.rs +++ b/tests/ui/parser/recover-unticked-labels.rs @@ -1,5 +1,7 @@ +// run-rustfix + fn main() { - 'label: loop { break label } //~ error: cannot find value `label` in this scope - 'label: loop { break label 0 } //~ error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `0` - 'label: loop { continue label } //~ error: expected one of `.`, `;`, `?`, `}`, or an operator, found `label` + 'label: loop { break label }; //~ error: cannot find value `label` in this scope + 'label: loop { break label 0 }; //~ error: expected a label, found an identifier + 'label: loop { continue label }; //~ error: expected a label, found an identifier } diff --git a/tests/ui/parser/recover-unticked-labels.stderr b/tests/ui/parser/recover-unticked-labels.stderr index 3b48c1224b3ad..c115dffb10e9c 100644 --- a/tests/ui/parser/recover-unticked-labels.stderr +++ b/tests/ui/parser/recover-unticked-labels.stderr @@ -1,19 +1,19 @@ -error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `0` - --> $DIR/recover-unticked-labels.rs:3:32 +error: expected a label, found an identifier + --> $DIR/recover-unticked-labels.rs:5:26 | -LL | 'label: loop { break label 0 } - | ^ expected one of 8 possible tokens +LL | 'label: loop { break label 0 }; + | ^^^^^ help: labels start with a tick: `'label` -error: expected one of `.`, `;`, `?`, `}`, or an operator, found `label` - --> $DIR/recover-unticked-labels.rs:4:29 +error: expected a label, found an identifier + --> $DIR/recover-unticked-labels.rs:6:29 | -LL | 'label: loop { continue label } - | ^^^^^ expected one of `.`, `;`, `?`, `}`, or an operator +LL | 'label: loop { continue label }; + | ^^^^^ help: labels start with a tick: `'label` error[E0425]: cannot find value `label` in this scope - --> $DIR/recover-unticked-labels.rs:2:26 + --> $DIR/recover-unticked-labels.rs:4:26 | -LL | 'label: loop { break label } +LL | 'label: loop { break label }; | ------ ^^^^^ | | | | | not found in this scope From 50a46128dab2dcd71838dac67beb04304d42ecae Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 13 Jan 2023 12:58:40 -0800 Subject: [PATCH 018/230] Update LLVM to 15.0.7 This commit pulls in rust-lang/llvm-project#143 which updates the LLVM version used by rustc to 15.0.7, namely pulling in https://reviews.llvm.org/D136110 which is needed for some work I'm working on with wasm. --- src/llvm-project | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm-project b/src/llvm-project index 9ad24035fea8d..6c0bab9ef2d4c 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 9ad24035fea8d309753f5e39e6eb53d1d0eb39ce +Subproject commit 6c0bab9ef2d4c692e91e9f61e2d27514346d49f3 From 8cf7f40a895f476ecd3216b11ff673389135b652 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 30 Nov 2022 20:41:02 +0000 Subject: [PATCH 019/230] Check ADT fields for copy implementations considering regions --- .../src/coherence/builtin.rs | 6 ++- compiler/rustc_lint/src/builtin.rs | 18 ++++--- .../rustc_trait_selection/src/traits/misc.rs | 50 +++++++++++++------ ...py-is-not-modulo-regions.not_static.stderr | 12 +++++ .../ui/traits/copy-is-not-modulo-regions.rs | 19 +++++++ .../src/needless_pass_by_value.rs | 4 +- 6 files changed, 83 insertions(+), 26 deletions(-) create mode 100644 src/test/ui/traits/copy-is-not-modulo-regions.not_static.stderr create mode 100644 src/test/ui/traits/copy-is-not-modulo-regions.rs diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 2e2c1591e9b44..0926d5ccf2d57 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -13,7 +13,9 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::ty::adjustment::CoerceUnsizedInfo; use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitable}; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; -use rustc_trait_selection::traits::misc::{can_type_implement_copy, CopyImplementationError}; +use rustc_trait_selection::traits::misc::{ + type_allowed_to_implement_copy, CopyImplementationError, +}; use rustc_trait_selection::traits::predicate_for_trait_def; use rustc_trait_selection::traits::{self, ObligationCause}; use std::collections::BTreeMap; @@ -82,7 +84,7 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) { }; let cause = traits::ObligationCause::misc(span, impl_hir_id); - match can_type_implement_copy(tcx, param_env, self_type, cause) { + match type_allowed_to_implement_copy(tcx, param_env, self_type, cause) { Ok(()) => {} Err(CopyImplementationError::InfrigingFields(fields)) => { let mut err = struct_span_err!( diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 6f445426df70e..fe188162cf85b 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -72,7 +72,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, InnerSpan, Span}; use rustc_target::abi::{Abi, VariantIdx}; use rustc_trait_selection::infer::{InferCtxtExt, TyCtxtInferExt}; -use rustc_trait_selection::traits::{self, misc::can_type_implement_copy, EvaluationResult}; +use rustc_trait_selection::traits::{self, misc::type_allowed_to_implement_copy}; use crate::nonstandard_style::{method_context, MethodLateContext}; @@ -709,12 +709,14 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { // We shouldn't recommend implementing `Copy` on stateful things, // such as iterators. - if let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator) { - if cx.tcx.infer_ctxt().build().type_implements_trait(iter_trait, [ty], param_env) - == EvaluationResult::EvaluatedToOk - { - return; - } + if let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator) + && cx.tcx + .infer_ctxt() + .build() + .type_implements_trait(iter_trait, [ty], param_env) + .must_apply_modulo_regions() + { + return; } // Default value of clippy::trivially_copy_pass_by_ref @@ -726,7 +728,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { } } - if can_type_implement_copy( + if type_allowed_to_implement_copy( cx.tcx, param_env, ty, diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index b6ded4ce5a396..b87412f7de160 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -1,9 +1,9 @@ //! Miscellaneous type-system utilities that are too small to deserve their own modules. -use crate::infer::InferCtxtExt as _; use crate::traits::{self, ObligationCause}; use rustc_hir as hir; +use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable}; @@ -16,14 +16,16 @@ pub enum CopyImplementationError<'tcx> { HasDestructor, } -pub fn can_type_implement_copy<'tcx>( +/// Checks that the fields of the type (an ADT) all implement copy. +/// +/// If fields don't implement copy, return an error containing a list of +/// those violating fields. If it's not an ADT, returns `Err(NotAnAdt)`. +pub fn type_allowed_to_implement_copy<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, self_type: Ty<'tcx>, parent_cause: ObligationCause<'tcx>, ) -> Result<(), CopyImplementationError<'tcx>> { - // FIXME: (@jroesch) float this code up - let infcx = tcx.infer_ctxt().build(); let (adt, substs) = match self_type.kind() { // These types used to have a builtin impl. // Now libcore provides that impl. @@ -42,9 +44,14 @@ pub fn can_type_implement_copy<'tcx>( _ => return Err(CopyImplementationError::NotAnAdt), }; + let copy_def_id = tcx.require_lang_item(hir::LangItem::Copy, Some(parent_cause.span)); let mut infringing = Vec::new(); for variant in adt.variants() { for field in &variant.fields { + // Do this per-field to get better error messages. + let infcx = tcx.infer_ctxt().build(); + let ocx = traits::ObligationCtxt::new(&infcx); + let ty = field.ty(tcx, substs); if ty.references_error() { continue; @@ -63,21 +70,36 @@ pub fn can_type_implement_copy<'tcx>( } else { ObligationCause::dummy_with_span(span) }; - match traits::fully_normalize(&infcx, cause, param_env, ty) { - Ok(ty) => { - if !infcx.type_is_copy_modulo_regions(param_env, ty, span) { - infringing.push((field, ty)); - } - } - Err(errors) => { - infcx.err_ctxt().report_fulfillment_errors(&errors, None); - } - }; + + let ty = ocx.normalize(&cause, param_env, ty); + let normalization_errors = ocx.select_where_possible(); + if !normalization_errors.is_empty() { + // Don't report this as a field that doesn't implement Copy, + // but instead just implement this as a field that isn't WF. + infcx.err_ctxt().report_fulfillment_errors(&normalization_errors, None); + continue; + } + + ocx.register_bound(cause, param_env, ty, copy_def_id); + if !ocx.select_all_or_error().is_empty() { + infringing.push((field, ty)); + } + + let outlives_env = OutlivesEnvironment::new(param_env); + infcx.process_registered_region_obligations( + outlives_env.region_bound_pairs(), + param_env, + ); + if !infcx.resolve_regions(&outlives_env).is_empty() { + infringing.push((field, ty)); + } } } + if !infringing.is_empty() { return Err(CopyImplementationError::InfrigingFields(infringing)); } + if adt.has_dtor(tcx) { return Err(CopyImplementationError::HasDestructor); } diff --git a/src/test/ui/traits/copy-is-not-modulo-regions.not_static.stderr b/src/test/ui/traits/copy-is-not-modulo-regions.not_static.stderr new file mode 100644 index 0000000000000..1c4d2136677d0 --- /dev/null +++ b/src/test/ui/traits/copy-is-not-modulo-regions.not_static.stderr @@ -0,0 +1,12 @@ +error[E0204]: the trait `Copy` may not be implemented for this type + --> $DIR/copy-is-not-modulo-regions.rs:13:21 + | +LL | struct Bar<'lt>(Foo<'lt>); + | -------- this field does not implement `Copy` +... +LL | impl<'any> Copy for Bar<'any> {} + | ^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0204`. diff --git a/src/test/ui/traits/copy-is-not-modulo-regions.rs b/src/test/ui/traits/copy-is-not-modulo-regions.rs new file mode 100644 index 0000000000000..adb8702376977 --- /dev/null +++ b/src/test/ui/traits/copy-is-not-modulo-regions.rs @@ -0,0 +1,19 @@ +// revisions: not_static yes_static +//[yes_static] check-pass + +#[derive(Clone)] +struct Foo<'lt>(&'lt ()); + +impl Copy for Foo<'static> {} + +#[derive(Clone)] +struct Bar<'lt>(Foo<'lt>); + +#[cfg(not_static)] +impl<'any> Copy for Bar<'any> {} +//[not_static]~^ the trait `Copy` may not be implemented for this type + +#[cfg(yes_static)] +impl<'any> Copy for Bar<'static> {} + +fn main() {} diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index 1249db5dc4792..8c9d4c5cfe66f 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -24,7 +24,7 @@ use rustc_span::symbol::kw; use rustc_span::{sym, Span}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits; -use rustc_trait_selection::traits::misc::can_type_implement_copy; +use rustc_trait_selection::traits::misc::type_allowed_to_implement_copy; use std::borrow::Cow; declare_clippy_lint! { @@ -200,7 +200,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { let sugg = |diag: &mut Diagnostic| { if let ty::Adt(def, ..) = ty.kind() { if let Some(span) = cx.tcx.hir().span_if_local(def.did()) { - if can_type_implement_copy( + if type_allowed_to_implement_copy( cx.tcx, cx.param_env, ty, From 333c6bf523019fd1565a5236d3c727172ec844f2 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 9 Dec 2022 19:58:46 +0000 Subject: [PATCH 020/230] copy self type is implied wf --- compiler/rustc_trait_selection/src/traits/misc.rs | 15 ++++++++++++++- src/test/ui/traits/copy-requires-self-wf.rs | 14 ++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/traits/copy-requires-self-wf.rs diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index b87412f7de160..46eea628a3441 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -2,6 +2,7 @@ use crate::traits::{self, ObligationCause}; +use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::TyCtxtInferExt; @@ -9,6 +10,8 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable}; use crate::traits::error_reporting::TypeErrCtxtExt; +use super::outlives_bounds::InferCtxtExt; + #[derive(Clone)] pub enum CopyImplementationError<'tcx> { InfrigingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>)>), @@ -45,6 +48,7 @@ pub fn type_allowed_to_implement_copy<'tcx>( }; let copy_def_id = tcx.require_lang_item(hir::LangItem::Copy, Some(parent_cause.span)); + let mut infringing = Vec::new(); for variant in adt.variants() { for field in &variant.fields { @@ -85,7 +89,16 @@ pub fn type_allowed_to_implement_copy<'tcx>( infringing.push((field, ty)); } - let outlives_env = OutlivesEnvironment::new(param_env); + // Check regions assuming the self type of the impl is WF + let outlives_env = OutlivesEnvironment::with_bounds( + param_env, + Some(&infcx), + infcx.implied_bounds_tys( + param_env, + parent_cause.body_id, + FxIndexSet::from_iter([self_type]), + ), + ); infcx.process_registered_region_obligations( outlives_env.region_bound_pairs(), param_env, diff --git a/src/test/ui/traits/copy-requires-self-wf.rs b/src/test/ui/traits/copy-requires-self-wf.rs new file mode 100644 index 0000000000000..9abfdfab9d06d --- /dev/null +++ b/src/test/ui/traits/copy-requires-self-wf.rs @@ -0,0 +1,14 @@ +// check-pass + +#[derive(Clone)] +struct A<'a, T>(&'a T); + +impl<'a, T: Copy + 'a> Copy for A<'a, T> {} + +#[derive(Clone)] +struct B<'a, T>(A<'a, T>); + +// `T: '_` should be implied by `WF(B<'_, T>)`. +impl Copy for B<'_, T> {} + +fn main() {} From 16cfadbfe835cadd24dc65481ab3ad0b5b627c5a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 9 Dec 2022 20:59:26 +0000 Subject: [PATCH 021/230] Suggest lifetime bound in illegal Copy impl --- .../src/coherence/builtin.rs | 106 +++++++++++------- .../rustc_trait_selection/src/traits/misc.rs | 44 +++++--- ...py-is-not-modulo-regions.not_static.stderr | 10 ++ 3 files changed, 103 insertions(+), 57 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 0926d5ccf2d57..e642572e3dab2 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -7,14 +7,14 @@ use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; use rustc_hir::ItemKind; -use rustc_infer::infer; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::infer::{self, RegionResolutionError}; use rustc_middle::ty::adjustment::CoerceUnsizedInfo; use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitable}; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::misc::{ - type_allowed_to_implement_copy, CopyImplementationError, + type_allowed_to_implement_copy, CopyImplementationError, InfringingFieldsReason, }; use rustc_trait_selection::traits::predicate_for_trait_def; use rustc_trait_selection::traits::{self, ObligationCause}; @@ -99,50 +99,70 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) { let mut errors: BTreeMap<_, Vec<_>> = Default::default(); let mut bounds = vec![]; - for (field, ty) in fields { + for (field, ty, reason) in fields { let field_span = tcx.def_span(field.did); - let field_ty_span = match tcx.hir().get_if_local(field.did) { - Some(hir::Node::Field(field_def)) => field_def.ty.span, - _ => field_span, - }; err.span_label(field_span, "this field does not implement `Copy`"); - // Spin up a new FulfillmentContext, so we can get the _precise_ reason - // why this field does not implement Copy. This is useful because sometimes - // it is not immediately clear why Copy is not implemented for a field, since - // all we point at is the field itself. - let infcx = tcx.infer_ctxt().ignoring_regions().build(); - for error in traits::fully_solve_bound( - &infcx, - traits::ObligationCause::dummy_with_span(field_ty_span), - param_env, - ty, - tcx.require_lang_item(LangItem::Copy, Some(span)), - ) { - let error_predicate = error.obligation.predicate; - // Only note if it's not the root obligation, otherwise it's trivial and - // should be self-explanatory (i.e. a field literally doesn't implement Copy). - - // FIXME: This error could be more descriptive, especially if the error_predicate - // contains a foreign type or if it's a deeply nested type... - if error_predicate != error.root_obligation.predicate { - errors - .entry((ty.to_string(), error_predicate.to_string())) - .or_default() - .push(error.obligation.cause.span); + + match reason { + InfringingFieldsReason::Fulfill(fulfillment_errors) => { + for error in fulfillment_errors { + let error_predicate = error.obligation.predicate; + // Only note if it's not the root obligation, otherwise it's trivial and + // should be self-explanatory (i.e. a field literally doesn't implement Copy). + + // FIXME: This error could be more descriptive, especially if the error_predicate + // contains a foreign type or if it's a deeply nested type... + if error_predicate != error.root_obligation.predicate { + errors + .entry((ty.to_string(), error_predicate.to_string())) + .or_default() + .push(error.obligation.cause.span); + } + if let ty::PredicateKind::Clause(ty::Clause::Trait( + ty::TraitPredicate { + trait_ref, + polarity: ty::ImplPolarity::Positive, + .. + }, + )) = error_predicate.kind().skip_binder() + { + let ty = trait_ref.self_ty(); + if let ty::Param(_) = ty.kind() { + bounds.push(( + format!("{ty}"), + trait_ref.print_only_trait_path().to_string(), + Some(trait_ref.def_id), + )); + } + } + } } - if let ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate { - trait_ref, - polarity: ty::ImplPolarity::Positive, - .. - })) = error_predicate.kind().skip_binder() - { - let ty = trait_ref.self_ty(); - if let ty::Param(_) = ty.kind() { - bounds.push(( - format!("{ty}"), - trait_ref.print_only_trait_path().to_string(), - Some(trait_ref.def_id), - )); + InfringingFieldsReason::Regions(region_errors) => { + for error in region_errors { + let ty = ty.to_string(); + match error { + RegionResolutionError::ConcreteFailure(origin, a, b) => { + let predicate = format!("{b}: {a}"); + errors + .entry((ty.clone(), predicate.clone())) + .or_default() + .push(origin.span()); + if let ty::RegionKind::ReEarlyBound(ebr) = *b && ebr.has_name() { + bounds.push((b.to_string(), a.to_string(), None)); + } + } + RegionResolutionError::GenericBoundFailure(origin, a, b) => { + let predicate = format!("{a}: {b}"); + errors + .entry((ty.clone(), predicate.clone())) + .or_default() + .push(origin.span()); + if let infer::region_constraints::GenericKind::Param(_) = a { + bounds.push((a.to_string(), b.to_string(), None)); + } + } + _ => continue, + } } } } diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index 46eea628a3441..0de44dba0ddd0 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -4,21 +4,25 @@ use crate::traits::{self, ObligationCause}; use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; -use rustc_infer::infer::outlives::env::OutlivesEnvironment; -use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; +use rustc_infer::{infer::outlives::env::OutlivesEnvironment, traits::FulfillmentError}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable}; use crate::traits::error_reporting::TypeErrCtxtExt; use super::outlives_bounds::InferCtxtExt; -#[derive(Clone)] pub enum CopyImplementationError<'tcx> { - InfrigingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>)>), + InfrigingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>), NotAnAdt, HasDestructor, } +pub enum InfringingFieldsReason<'tcx> { + Fulfill(Vec>), + Regions(Vec>), +} + /// Checks that the fields of the type (an ADT) all implement copy. /// /// If fields don't implement copy, return an error containing a list of @@ -60,22 +64,27 @@ pub fn type_allowed_to_implement_copy<'tcx>( if ty.references_error() { continue; } - let span = tcx.def_span(field.did); + + let field_span = tcx.def_span(field.did); + let field_ty_span = match tcx.hir().get_if_local(field.did) { + Some(hir::Node::Field(field_def)) => field_def.ty.span, + _ => field_span, + }; + // FIXME(compiler-errors): This gives us better spans for bad // projection types like in issue-50480. // If the ADT has substs, point to the cause we are given. // If it does not, then this field probably doesn't normalize // to begin with, and point to the bad field's span instead. - let cause = if field + let normalization_cause = if field .ty(tcx, traits::InternalSubsts::identity_for_item(tcx, adt.did())) .has_non_region_param() { parent_cause.clone() } else { - ObligationCause::dummy_with_span(span) + ObligationCause::dummy_with_span(field_ty_span) }; - - let ty = ocx.normalize(&cause, param_env, ty); + let ty = ocx.normalize(&normalization_cause, param_env, ty); let normalization_errors = ocx.select_where_possible(); if !normalization_errors.is_empty() { // Don't report this as a field that doesn't implement Copy, @@ -84,9 +93,15 @@ pub fn type_allowed_to_implement_copy<'tcx>( continue; } - ocx.register_bound(cause, param_env, ty, copy_def_id); - if !ocx.select_all_or_error().is_empty() { - infringing.push((field, ty)); + ocx.register_bound( + ObligationCause::dummy_with_span(field_ty_span), + param_env, + ty, + copy_def_id, + ); + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { + infringing.push((field, ty, InfringingFieldsReason::Fulfill(errors))); } // Check regions assuming the self type of the impl is WF @@ -103,8 +118,9 @@ pub fn type_allowed_to_implement_copy<'tcx>( outlives_env.region_bound_pairs(), param_env, ); - if !infcx.resolve_regions(&outlives_env).is_empty() { - infringing.push((field, ty)); + let errors = infcx.resolve_regions(&outlives_env); + if !errors.is_empty() { + infringing.push((field, ty, InfringingFieldsReason::Regions(errors))); } } } diff --git a/src/test/ui/traits/copy-is-not-modulo-regions.not_static.stderr b/src/test/ui/traits/copy-is-not-modulo-regions.not_static.stderr index 1c4d2136677d0..edd94d2010b96 100644 --- a/src/test/ui/traits/copy-is-not-modulo-regions.not_static.stderr +++ b/src/test/ui/traits/copy-is-not-modulo-regions.not_static.stderr @@ -6,6 +6,16 @@ LL | struct Bar<'lt>(Foo<'lt>); ... LL | impl<'any> Copy for Bar<'any> {} | ^^^^^^^^^ + | +note: the `Copy` impl for `Foo<'any>` requires that `'any: 'static` + --> $DIR/copy-is-not-modulo-regions.rs:10:17 + | +LL | struct Bar<'lt>(Foo<'lt>); + | ^^^^^^^^ +help: consider restricting type parameter `'any` + | +LL | impl<'any: 'static> Copy for Bar<'any> {} + | +++++++++ error: aborting due to previous error From 6ec8c13e15824d5b0dbdca5ab404d15af3e68f48 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 11 Jan 2023 20:16:12 +0000 Subject: [PATCH 022/230] Rebase and move UI tests --- .../ui/traits/copy-is-not-modulo-regions.not_static.stderr | 0 {src/test => tests}/ui/traits/copy-is-not-modulo-regions.rs | 0 {src/test => tests}/ui/traits/copy-requires-self-wf.rs | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename {src/test => tests}/ui/traits/copy-is-not-modulo-regions.not_static.stderr (100%) rename {src/test => tests}/ui/traits/copy-is-not-modulo-regions.rs (100%) rename {src/test => tests}/ui/traits/copy-requires-self-wf.rs (100%) diff --git a/src/test/ui/traits/copy-is-not-modulo-regions.not_static.stderr b/tests/ui/traits/copy-is-not-modulo-regions.not_static.stderr similarity index 100% rename from src/test/ui/traits/copy-is-not-modulo-regions.not_static.stderr rename to tests/ui/traits/copy-is-not-modulo-regions.not_static.stderr diff --git a/src/test/ui/traits/copy-is-not-modulo-regions.rs b/tests/ui/traits/copy-is-not-modulo-regions.rs similarity index 100% rename from src/test/ui/traits/copy-is-not-modulo-regions.rs rename to tests/ui/traits/copy-is-not-modulo-regions.rs diff --git a/src/test/ui/traits/copy-requires-self-wf.rs b/tests/ui/traits/copy-requires-self-wf.rs similarity index 100% rename from src/test/ui/traits/copy-requires-self-wf.rs rename to tests/ui/traits/copy-requires-self-wf.rs From 75074e0e528cf8a50310bc0de19f73b60e8c8304 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 11 Jan 2023 20:26:12 +0000 Subject: [PATCH 023/230] Delay normalization bugs instead of reporting them --- .../rustc_trait_selection/src/traits/misc.rs | 12 +++----- .../traits/copy-impl-cannot-normalize.stderr | 10 +++++++ tests/ui/traits/issue-50480.rs | 2 -- tests/ui/traits/issue-50480.stderr | 28 ++++--------------- 4 files changed, 19 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index 0de44dba0ddd0..a41a601f2db07 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -8,8 +8,6 @@ use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; use rustc_infer::{infer::outlives::env::OutlivesEnvironment, traits::FulfillmentError}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable}; -use crate::traits::error_reporting::TypeErrCtxtExt; - use super::outlives_bounds::InferCtxtExt; pub enum CopyImplementationError<'tcx> { @@ -60,8 +58,8 @@ pub fn type_allowed_to_implement_copy<'tcx>( let infcx = tcx.infer_ctxt().build(); let ocx = traits::ObligationCtxt::new(&infcx); - let ty = field.ty(tcx, substs); - if ty.references_error() { + let unnormalized_ty = field.ty(tcx, substs); + if unnormalized_ty.references_error() { continue; } @@ -84,12 +82,10 @@ pub fn type_allowed_to_implement_copy<'tcx>( } else { ObligationCause::dummy_with_span(field_ty_span) }; - let ty = ocx.normalize(&normalization_cause, param_env, ty); + let ty = ocx.normalize(&normalization_cause, param_env, unnormalized_ty); let normalization_errors = ocx.select_where_possible(); if !normalization_errors.is_empty() { - // Don't report this as a field that doesn't implement Copy, - // but instead just implement this as a field that isn't WF. - infcx.err_ctxt().report_fulfillment_errors(&normalization_errors, None); + tcx.sess.delay_span_bug(field_span, format!("couldn't normalize struct field `{unnormalized_ty}` when checking Copy implementation")); continue; } diff --git a/tests/ui/traits/copy-impl-cannot-normalize.stderr b/tests/ui/traits/copy-impl-cannot-normalize.stderr index 68b95b42b3463..86c511c089567 100644 --- a/tests/ui/traits/copy-impl-cannot-normalize.stderr +++ b/tests/ui/traits/copy-impl-cannot-normalize.stderr @@ -4,6 +4,16 @@ error[E0277]: the trait bound `T: TraitFoo` is not satisfied LL | impl Copy for Foo {} | ^^^^^^ the trait `TraitFoo` is not implemented for `T` | +note: required for `Foo` to implement `Clone` + --> $DIR/copy-impl-cannot-normalize.rs:12:9 + | +LL | impl Clone for Foo + | ^^^^^ ^^^^^^ +LL | where +LL | T: TraitFoo, + | -------- unsatisfied trait bound introduced here +note: required by a bound in `Copy` + --> $SRC_DIR/core/src/marker.rs:LL:COL help: consider restricting type parameter `T` | LL | impl Copy for Foo {} diff --git a/tests/ui/traits/issue-50480.rs b/tests/ui/traits/issue-50480.rs index 10597caf5b2dc..005939e0c46e4 100644 --- a/tests/ui/traits/issue-50480.rs +++ b/tests/ui/traits/issue-50480.rs @@ -5,13 +5,11 @@ struct Foo(N, NotDefined, ::Item, Vec, String); //~| ERROR cannot find type `NotDefined` in this scope //~| ERROR cannot find type `N` in this scope //~| ERROR cannot find type `N` in this scope -//~| ERROR `i32` is not an iterator #[derive(Clone, Copy)] //~^ ERROR the trait `Copy` may not be implemented for this type struct Bar(T, N, NotDefined, ::Item, Vec, String); //~^ ERROR cannot find type `NotDefined` in this scope //~| ERROR cannot find type `N` in this scope -//~| ERROR `i32` is not an iterator fn main() {} diff --git a/tests/ui/traits/issue-50480.stderr b/tests/ui/traits/issue-50480.stderr index aa8384e980539..5063fdca09273 100644 --- a/tests/ui/traits/issue-50480.stderr +++ b/tests/ui/traits/issue-50480.stderr @@ -38,7 +38,7 @@ LL | struct Foo(N, NotDefined, ::Item, Vec, St | ++++++++++++ error[E0412]: cannot find type `N` in this scope - --> $DIR/issue-50480.rs:12:18 + --> $DIR/issue-50480.rs:11:18 | LL | struct Bar(T, N, NotDefined, ::Item, Vec, String); | - ^ @@ -55,20 +55,11 @@ LL | struct Bar(T, N, NotDefined, ::Item, Vec, Strin | +++ error[E0412]: cannot find type `NotDefined` in this scope - --> $DIR/issue-50480.rs:12:21 + --> $DIR/issue-50480.rs:11:21 | LL | struct Bar(T, N, NotDefined, ::Item, Vec, String); | ^^^^^^^^^^ not found in this scope -error[E0277]: `i32` is not an iterator - --> $DIR/issue-50480.rs:3:27 - | -LL | struct Foo(N, NotDefined, ::Item, Vec, String); - | ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator - | - = help: the trait `Iterator` is not implemented for `i32` - = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` - error[E0204]: the trait `Copy` may not be implemented for this type --> $DIR/issue-50480.rs:1:17 | @@ -82,17 +73,8 @@ LL | struct Foo(N, NotDefined, ::Item, Vec, String); | = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: `i32` is not an iterator - --> $DIR/issue-50480.rs:12:33 - | -LL | struct Bar(T, N, NotDefined, ::Item, Vec, String); - | ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator - | - = help: the trait `Iterator` is not implemented for `i32` - = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` - error[E0204]: the trait `Copy` may not be implemented for this type - --> $DIR/issue-50480.rs:10:17 + --> $DIR/issue-50480.rs:9:17 | LL | #[derive(Clone, Copy)] | ^^^^ @@ -104,7 +86,7 @@ LL | struct Bar(T, N, NotDefined, ::Item, Vec, String); | = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 10 previous errors +error: aborting due to 8 previous errors -Some errors have detailed explanations: E0204, E0277, E0412. +Some errors have detailed explanations: E0204, E0412. For more information about an error, try `rustc --explain E0204`. From 1babece1e8888151b1b248367eb1017450dc107c Mon Sep 17 00:00:00 2001 From: Ezra Shaw Date: Fri, 13 Jan 2023 14:14:26 +1300 Subject: [PATCH 024/230] suggest fix for attempted integer identifier in patterns --- .../locales/en-US/mir_build.ftl | 2 ++ compiler/rustc_mir_build/src/errors.rs | 15 ++++++++ .../src/thir/pattern/check_match.rs | 20 ++++++++--- .../ui/consts/const-match-check.eval1.stderr | 4 +++ .../ui/consts/const-match-check.eval2.stderr | 4 +++ .../consts/const-match-check.matchck.stderr | 16 +++++++++ tests/ui/pattern/issue-106552.rs | 7 ++++ tests/ui/pattern/issue-106552.stderr | 35 +++++++++++++++++++ 8 files changed, 99 insertions(+), 4 deletions(-) create mode 100644 tests/ui/pattern/issue-106552.rs create mode 100644 tests/ui/pattern/issue-106552.stderr diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl index a082c0b61fa7e..224855fff8b56 100644 --- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl +++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl @@ -364,3 +364,5 @@ mir_build_suggest_let_else = you might want to use `let else` to handle the {$co [one] variant that isn't *[other] variants that aren't } matched + +mir_build_suggest_attempted_int_lit = alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 06523b0a1de84..7f81aef1c7321 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -770,6 +770,8 @@ pub(crate) struct PatternNotCovered<'s, 'tcx> { #[subdiagnostic] pub let_suggestion: Option, #[subdiagnostic] + pub misc_suggestion: Option, + #[subdiagnostic] pub res_defined_here: Option, } @@ -848,3 +850,16 @@ pub enum SuggestLet { count: usize, }, } + +#[derive(Subdiagnostic)] +pub enum MiscPatternSuggestion { + #[suggestion( + mir_build_suggest_attempted_int_lit, + code = "_", + applicability = "maybe-incorrect" + )] + AttemptedIntegerLiteral { + #[primary_span] + start_span: Span, + }, +} diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index e13c0662ef85f..34e637f594842 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -6,8 +6,9 @@ use super::{PatCtxt, PatternError}; use crate::errors::*; +use hir::{ExprKind, PatKind}; use rustc_arena::TypedArena; -use rustc_ast::Mutability; +use rustc_ast::{LitKind, Mutability}; use rustc_errors::{ struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, }; @@ -389,7 +390,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { return; } - let (inform, interpreted_as_const, res_defined_here,let_suggestion) = + let (inform, interpreted_as_const, res_defined_here,let_suggestion, misc_suggestion) = if let hir::PatKind::Path(hir::QPath::Resolved( None, hir::Path { @@ -413,6 +414,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { } }, None, + None, ) } else if let Some(span) = sp && self.tcx.sess.source_map().is_span_accessible(span) { let mut bindings = vec![]; @@ -426,10 +428,19 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { let end_span = semi_span.shrink_to_lo(); let count = witnesses.len(); + // If the pattern to match is an integer literal: + let int_suggestion = if + let PatKind::Lit(expr) = &pat.kind + && bindings.is_empty() + && let ExprKind::Lit(Spanned { node: LitKind::Int(_, _), span }) = expr.kind { + // Then give a suggestion, the user might've meant to create a binding instead. + Some(MiscPatternSuggestion::AttemptedIntegerLiteral { start_span: span.shrink_to_lo() }) + } else { None }; + let let_suggestion = if bindings.is_empty() {SuggestLet::If{start_span, semi_span, count}} else{ SuggestLet::Else{end_span, count }}; - (sp.map(|_|Inform), None, None, Some(let_suggestion)) + (sp.map(|_|Inform), None, None, Some(let_suggestion), int_suggestion) } else{ - (sp.map(|_|Inform), None, None, None) + (sp.map(|_|Inform), None, None, None, None) }; let adt_defined_here = try { @@ -453,6 +464,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { _p: (), pattern_ty, let_suggestion, + misc_suggestion, res_defined_here, adt_defined_here, }); diff --git a/tests/ui/consts/const-match-check.eval1.stderr b/tests/ui/consts/const-match-check.eval1.stderr index 1caf1617e213c..08fcd1deab1d3 100644 --- a/tests/ui/consts/const-match-check.eval1.stderr +++ b/tests/ui/consts/const-match-check.eval1.stderr @@ -11,6 +11,10 @@ help: you might want to use `if let` to ignore the variants that aren't matched | LL | A = { if let 0 = 0 { todo!() } 0 }, | ++ ~~~~~~~~~~~ +help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits + | +LL | A = { let _0 = 0; 0 }, + | + error: aborting due to previous error diff --git a/tests/ui/consts/const-match-check.eval2.stderr b/tests/ui/consts/const-match-check.eval2.stderr index f038ba1c8ed85..5d86ca4bfd17b 100644 --- a/tests/ui/consts/const-match-check.eval2.stderr +++ b/tests/ui/consts/const-match-check.eval2.stderr @@ -11,6 +11,10 @@ help: you might want to use `if let` to ignore the variants that aren't matched | LL | let x: [i32; { if let 0 = 0 { todo!() } 0 }] = []; | ++ ~~~~~~~~~~~ +help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits + | +LL | let x: [i32; { let _0 = 0; 0 }] = []; + | + error: aborting due to previous error diff --git a/tests/ui/consts/const-match-check.matchck.stderr b/tests/ui/consts/const-match-check.matchck.stderr index b1921f8a41e48..c8f66bb0fc027 100644 --- a/tests/ui/consts/const-match-check.matchck.stderr +++ b/tests/ui/consts/const-match-check.matchck.stderr @@ -11,6 +11,10 @@ help: you might want to use `if let` to ignore the variants that aren't matched | LL | const X: i32 = { if let 0 = 0 { todo!() } 0 }; | ++ ~~~~~~~~~~~ +help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits + | +LL | const X: i32 = { let _0 = 0; 0 }; + | + error[E0005]: refutable pattern in local binding --> $DIR/const-match-check.rs:8:23 @@ -25,6 +29,10 @@ help: you might want to use `if let` to ignore the variants that aren't matched | LL | static Y: i32 = { if let 0 = 0 { todo!() } 0 }; | ++ ~~~~~~~~~~~ +help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits + | +LL | static Y: i32 = { let _0 = 0; 0 }; + | + error[E0005]: refutable pattern in local binding --> $DIR/const-match-check.rs:13:26 @@ -39,6 +47,10 @@ help: you might want to use `if let` to ignore the variants that aren't matched | LL | const X: i32 = { if let 0 = 0 { todo!() } 0 }; | ++ ~~~~~~~~~~~ +help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits + | +LL | const X: i32 = { let _0 = 0; 0 }; + | + error[E0005]: refutable pattern in local binding --> $DIR/const-match-check.rs:19:26 @@ -53,6 +65,10 @@ help: you might want to use `if let` to ignore the variants that aren't matched | LL | const X: i32 = { if let 0 = 0 { todo!() } 0 }; | ++ ~~~~~~~~~~~ +help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits + | +LL | const X: i32 = { let _0 = 0; 0 }; + | + error: aborting due to 4 previous errors diff --git a/tests/ui/pattern/issue-106552.rs b/tests/ui/pattern/issue-106552.rs new file mode 100644 index 0000000000000..aa2c141e05ef2 --- /dev/null +++ b/tests/ui/pattern/issue-106552.rs @@ -0,0 +1,7 @@ +fn main() { + let 5 = 6; + //~^ error refutable pattern in local binding [E0005] + + let x @ 5 = 6; + //~^ error refutable pattern in local binding [E0005] +} diff --git a/tests/ui/pattern/issue-106552.stderr b/tests/ui/pattern/issue-106552.stderr new file mode 100644 index 0000000000000..ed5d40c096850 --- /dev/null +++ b/tests/ui/pattern/issue-106552.stderr @@ -0,0 +1,35 @@ +error[E0005]: refutable pattern in local binding + --> $DIR/issue-106552.rs:2:9 + | +LL | let 5 = 6; + | ^ patterns `i32::MIN..=4_i32` and `6_i32..=i32::MAX` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html + = note: the matched value is of type `i32` +help: you might want to use `if let` to ignore the variants that aren't matched + | +LL | if let 5 = 6 { todo!() } + | ++ ~~~~~~~~~~~ +help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits + | +LL | let _5 = 6; + | + + +error[E0005]: refutable pattern in local binding + --> $DIR/issue-106552.rs:5:9 + | +LL | let x @ 5 = 6; + | ^^^^^ patterns `i32::MIN..=4_i32` and `6_i32..=i32::MAX` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html + = note: the matched value is of type `i32` +help: you might want to use `let else` to handle the variants that aren't matched + | +LL | let x @ 5 = 6 else { todo!() }; + | ++++++++++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0005`. From 1ea6862db3830c86355d9179a4cee9410711f68f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 13 Jan 2023 23:53:28 +0000 Subject: [PATCH 025/230] Unify Opaque/Projection handling in region outlives code --- .../src/type_check/free_region_relations.rs | 9 +--- .../rustc_hir_analysis/src/outlives/utils.rs | 20 +++----- .../src/infer/error_reporting/mod.rs | 9 ++-- .../src/infer/outlives/components.rs | 15 +++--- .../rustc_infer/src/infer/outlives/env.rs | 8 +--- .../src/infer/outlives/obligations.rs | 48 +++++-------------- .../rustc_infer/src/infer/outlives/verify.rs | 14 ++---- .../src/infer/region_constraints/mod.rs | 20 ++++---- compiler/rustc_infer/src/traits/util.rs | 13 +---- compiler/rustc_middle/src/traits/query.rs | 6 +-- .../rustc_middle/src/ty/structural_impls.rs | 1 + .../src/implied_outlives_bounds.rs | 5 +- 12 files changed, 54 insertions(+), 114 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index 09cf870bcf35a..4976456afcb31 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -359,14 +359,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { .insert(ty::OutlivesPredicate(GenericKind::Param(param_b), r_a)); } - OutlivesBound::RegionSubProjection(r_a, projection_b) => { + OutlivesBound::RegionSubAlias(r_a, kind, alias_b) => { self.region_bound_pairs - .insert(ty::OutlivesPredicate(GenericKind::Projection(projection_b), r_a)); - } - - OutlivesBound::RegionSubOpaque(r_a, def_id, substs) => { - self.region_bound_pairs - .insert(ty::OutlivesPredicate(GenericKind::Opaque(def_id, substs), r_a)); + .insert(ty::OutlivesPredicate(GenericKind::Alias(kind, alias_b), r_a)); } } } diff --git a/compiler/rustc_hir_analysis/src/outlives/utils.rs b/compiler/rustc_hir_analysis/src/outlives/utils.rs index b51b740d08e2e..7d38a6e5f33c1 100644 --- a/compiler/rustc_hir_analysis/src/outlives/utils.rs +++ b/compiler/rustc_hir_analysis/src/outlives/utils.rs @@ -80,8 +80,8 @@ pub(crate) fn insert_outlives_predicate<'tcx>( .or_insert(span); } - Component::Projection(proj_ty) => { - // This would arise from something like: + Component::Alias(kind, alias) => { + // This would either arise from something like: // // ``` // struct Foo<'a, T: Iterator> { @@ -89,15 +89,7 @@ pub(crate) fn insert_outlives_predicate<'tcx>( // } // ``` // - // Here we want to add an explicit `where ::Item: 'a`. - let ty: Ty<'tcx> = tcx.mk_projection(proj_ty.def_id, proj_ty.substs); - required_predicates - .entry(ty::OutlivesPredicate(ty.into(), outlived_region)) - .or_insert(span); - } - - Component::Opaque(def_id, substs) => { - // This would arise from something like: + // or: // // ```rust // type Opaque = impl Sized; @@ -105,9 +97,9 @@ pub(crate) fn insert_outlives_predicate<'tcx>( // struct Ss<'a, T>(&'a Opaque); // ``` // - // Here we want to have an implied bound `Opaque: 'a` - - let ty = tcx.mk_opaque(def_id, substs); + // Here we want to add an explicit `where ::Item: 'a` + // or `Opaque: 'a` depending on the alias kind. + let ty: Ty<'tcx> = tcx.mk_ty(ty::Alias(kind, alias)); required_predicates .entry(ty::OutlivesPredicate(ty.into(), outlived_region)) .or_insert(span); diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 533a3c768eb16..7fbe49ce92233 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2256,9 +2256,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let labeled_user_string = match bound_kind { GenericKind::Param(ref p) => format!("the parameter type `{}`", p), - GenericKind::Projection(ref p) => format!("the associated type `{}`", p), - GenericKind::Opaque(def_id, substs) => { - format!("the opaque type `{}`", self.tcx.def_path_str_with_substs(def_id, substs)) + GenericKind::Alias(ty::Projection, ref p) => format!("the associated type `{}`", p), + GenericKind::Alias(ty::Opaque, ref p) => { + format!( + "the opaque type `{}`", + self.tcx.def_path_str_with_substs(p.def_id, p.substs) + ) } }; diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs index aa2b5d067d266..31451192bc50e 100644 --- a/compiler/rustc_infer/src/infer/outlives/components.rs +++ b/compiler/rustc_infer/src/infer/outlives/components.rs @@ -3,9 +3,8 @@ // RFC for reference. use rustc_data_structures::sso::SsoHashSet; -use rustc_hir::def_id::DefId; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; -use rustc_middle::ty::{self, SubstsRef, Ty, TyCtxt, TypeVisitable}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable}; use smallvec::{smallvec, SmallVec}; #[derive(Debug)] @@ -23,7 +22,7 @@ pub enum Component<'tcx> { // is not in a position to judge which is the best technique, so // we just product the projection as a component and leave it to // the consumer to decide (but see `EscapingProjection` below). - Projection(ty::AliasTy<'tcx>), + Alias(ty::AliasKind, ty::AliasTy<'tcx>), // In the case where a projection has escaping regions -- meaning // regions bound within the type itself -- we always use @@ -46,8 +45,6 @@ pub enum Component<'tcx> { // them. This gives us room to improve the regionck reasoning in // the future without breaking backwards compat. EscapingProjection(Vec>), - - Opaque(DefId, SubstsRef<'tcx>), } /// Push onto `out` all the things that must outlive `'a` for the condition @@ -130,8 +127,8 @@ fn compute_components<'tcx>( // outlives any other lifetime, which is unsound. // See https://github.com/rust-lang/rust/issues/84305 for // more details. - ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { - out.push(Component::Opaque(def_id, substs)); + ty::Alias(ty::Opaque, data) => { + out.push(Component::Alias(ty::Opaque, data)); }, // For projections, we prefer to generate an obligation like @@ -142,7 +139,7 @@ fn compute_components<'tcx>( // trait-ref. Therefore, if we see any higher-ranked regions, // we simply fallback to the most restrictive rule, which // requires that `Pi: 'a` for all `i`. - ty::Alias(ty::Projection, ref data) => { + ty::Alias(ty::Projection, data) => { if !data.has_escaping_bound_vars() { // best case: no escaping regions, so push the // projection and skip the subtree (thus generating no @@ -150,7 +147,7 @@ fn compute_components<'tcx>( // the rules OutlivesProjectionEnv, // OutlivesProjectionTraitDef, and // OutlivesProjectionComponents to regionck. - out.push(Component::Projection(*data)); + out.push(Component::Alias(ty::Projection, data)); } else { // fallback case: hard code // OutlivesProjectionComponents. Continue walking diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs index 33543135ddb0e..52c3d97f24111 100644 --- a/compiler/rustc_infer/src/infer/outlives/env.rs +++ b/compiler/rustc_infer/src/infer/outlives/env.rs @@ -138,13 +138,9 @@ impl<'tcx> OutlivesEnvironmentBuilder<'tcx> { self.region_bound_pairs .insert(ty::OutlivesPredicate(GenericKind::Param(param_b), r_a)); } - OutlivesBound::RegionSubProjection(r_a, projection_b) => { + OutlivesBound::RegionSubAlias(r_a, kind, projection_b) => { self.region_bound_pairs - .insert(ty::OutlivesPredicate(GenericKind::Projection(projection_b), r_a)); - } - OutlivesBound::RegionSubOpaque(r_a, def_id, substs) => { - self.region_bound_pairs - .insert(ty::OutlivesPredicate(GenericKind::Opaque(def_id, substs), r_a)); + .insert(ty::OutlivesPredicate(GenericKind::Alias(kind, projection_b), r_a)); } OutlivesBound::RegionSubRegion(r_a, r_b) => { if let (ReEarlyBound(_) | ReFree(_), ReVar(vid_b)) = (r_a.kind(), r_b.kind()) { diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index a85e6a19b11b6..4a93597a643f8 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -266,11 +266,8 @@ where Component::Param(param_ty) => { self.param_ty_must_outlive(origin, region, *param_ty); } - Component::Opaque(def_id, substs) => { - self.opaque_must_outlive(*def_id, substs, origin, region) - } - Component::Projection(projection_ty) => { - self.projection_must_outlive(origin, region, *projection_ty); + Component::Alias(kind, data) => { + self.alias_must_outlive(*kind, *data, origin, region) } Component::EscapingProjection(subcomponents) => { self.components_must_outlive(origin, &subcomponents, region, category); @@ -305,44 +302,25 @@ where } #[instrument(level = "debug", skip(self))] - fn opaque_must_outlive( + fn alias_must_outlive( &mut self, - def_id: DefId, - substs: SubstsRef<'tcx>, + kind: ty::AliasKind, + data: ty::AliasTy<'tcx>, origin: infer::SubregionOrigin<'tcx>, region: ty::Region<'tcx>, ) { self.generic_must_outlive( origin, region, - GenericKind::Opaque(def_id, substs), - def_id, - substs, - true, + GenericKind::Alias(kind, data), + data.def_id, + data.substs, + kind == ty::Opaque, |ty| match *ty.kind() { - ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => (def_id, substs), - _ => bug!("expected only projection types from env, not {:?}", ty), - }, - ); - } - - #[instrument(level = "debug", skip(self))] - fn projection_must_outlive( - &mut self, - origin: infer::SubregionOrigin<'tcx>, - region: ty::Region<'tcx>, - projection_ty: ty::AliasTy<'tcx>, - ) { - self.generic_must_outlive( - origin, - region, - GenericKind::Projection(projection_ty), - projection_ty.def_id, - projection_ty.substs, - false, - |ty| match ty.kind() { - ty::Alias(ty::Projection, projection_ty) => { - (projection_ty.def_id, projection_ty.substs) + ty::Alias(filter_kind, ty::AliasTy { def_id, substs, .. }) + if kind == filter_kind => + { + (def_id, substs) } _ => bug!("expected only projection types from env, not {:?}", ty), }, diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index 40bbec8ddd091..66bbf47c3b6e6 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -170,16 +170,10 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { match *component { Component::Region(lt) => VerifyBound::OutlivedBy(lt), Component::Param(param_ty) => self.param_bound(param_ty), - Component::Opaque(did, substs) => self.projection_opaque_bounds( - GenericKind::Opaque(did, substs), - did, - substs, - visited, - ), - Component::Projection(projection_ty) => self.projection_opaque_bounds( - GenericKind::Projection(projection_ty), - projection_ty.def_id, - projection_ty.substs, + Component::Alias(kind, data) => self.projection_opaque_bounds( + GenericKind::Alias(kind, data), + data.def_id, + data.substs, visited, ), Component::EscapingProjection(ref components) => { diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index 9a427ceacd0a7..fda5ffe784678 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -12,10 +12,8 @@ use rustc_data_structures::intern::Interned; use rustc_data_structures::sync::Lrc; use rustc_data_structures::undo_log::UndoLogs; use rustc_data_structures::unify as ut; -use rustc_hir::def_id::DefId; use rustc_index::vec::IndexVec; use rustc_middle::infer::unify_key::{RegionVidKey, UnifiedRegion}; -use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::ReStatic; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{ReLateBound, ReVar}; @@ -169,8 +167,7 @@ pub struct Verify<'tcx> { #[derive(Copy, Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)] pub enum GenericKind<'tcx> { Param(ty::ParamTy), - Projection(ty::AliasTy<'tcx>), - Opaque(DefId, SubstsRef<'tcx>), + Alias(ty::AliasKind, ty::AliasTy<'tcx>), } /// Describes the things that some `GenericKind` value `G` is known to @@ -749,9 +746,9 @@ impl<'tcx> fmt::Debug for GenericKind<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { GenericKind::Param(ref p) => write!(f, "{:?}", p), - GenericKind::Projection(ref p) => write!(f, "{:?}", p), - GenericKind::Opaque(def_id, substs) => ty::tls::with(|tcx| { - write!(f, "{}", tcx.def_path_str_with_substs(def_id, tcx.lift(substs).unwrap())) + GenericKind::Alias(ty::Projection, ref p) => write!(f, "{:?}", p), + GenericKind::Alias(ty::Opaque, ref p) => ty::tls::with(|tcx| { + write!(f, "{}", tcx.def_path_str_with_substs(p.def_id, tcx.lift(p.substs).unwrap())) }), } } @@ -761,9 +758,9 @@ impl<'tcx> fmt::Display for GenericKind<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { GenericKind::Param(ref p) => write!(f, "{}", p), - GenericKind::Projection(ref p) => write!(f, "{}", p), - GenericKind::Opaque(def_id, substs) => ty::tls::with(|tcx| { - write!(f, "{}", tcx.def_path_str_with_substs(def_id, tcx.lift(substs).unwrap())) + GenericKind::Alias(ty::Projection, ref p) => write!(f, "{}", p), + GenericKind::Alias(ty::Opaque, ref p) => ty::tls::with(|tcx| { + write!(f, "{}", tcx.def_path_str_with_substs(p.def_id, tcx.lift(p.substs).unwrap())) }), } } @@ -773,8 +770,7 @@ impl<'tcx> GenericKind<'tcx> { pub fn to_ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { match *self { GenericKind::Param(ref p) => p.to_ty(tcx), - GenericKind::Projection(ref p) => tcx.mk_projection(p.def_id, p.substs), - GenericKind::Opaque(def_id, substs) => tcx.mk_opaque(def_id, substs), + GenericKind::Alias(kind, data) => tcx.mk_ty(ty::Alias(kind, data)), } } } diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 8f0bd3a9abe5e..6fedb0ed8ac53 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -249,17 +249,8 @@ impl<'tcx> Elaborator<'tcx> { Component::UnresolvedInferenceVariable(_) => None, - Component::Opaque(def_id, substs) => { - let ty = tcx.mk_opaque(def_id, substs); - Some(ty::PredicateKind::Clause(ty::Clause::TypeOutlives( - ty::OutlivesPredicate(ty, r_min), - ))) - } - - Component::Projection(projection) => { - // We might end up here if we have `Foo<::Assoc>: 'a`. - // With this, we can deduce that `::Assoc: 'a`. - let ty = tcx.mk_projection(projection.def_id, projection.substs); + Component::Alias(kind, data) => { + let ty = tcx.mk_ty(ty::Alias(kind, data)); Some(ty::PredicateKind::Clause(ty::Clause::TypeOutlives( ty::OutlivesPredicate(ty, r_min), ))) diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index 543f5b87e00bc..2a68315fefc56 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -8,9 +8,8 @@ use crate::error::DropCheckOverflow; use crate::infer::canonical::{Canonical, QueryResponse}; use crate::ty::error::TypeError; -use crate::ty::subst::{GenericArg, SubstsRef}; +use crate::ty::subst::GenericArg; use crate::ty::{self, Ty, TyCtxt}; -use rustc_hir::def_id::DefId; use rustc_span::source_map::Span; pub mod type_op { @@ -214,6 +213,5 @@ pub struct NormalizationResult<'tcx> { pub enum OutlivesBound<'tcx> { RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>), RegionSubParam(ty::Region<'tcx>, ty::ParamTy), - RegionSubProjection(ty::Region<'tcx>, ty::AliasTy<'tcx>), - RegionSubOpaque(ty::Region<'tcx>, DefId, SubstsRef<'tcx>), + RegionSubAlias(ty::Region<'tcx>, ty::AliasKind, ty::AliasTy<'tcx>), } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 30073b541ecbd..8f64eb3e4baf6 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -227,6 +227,7 @@ TrivialTypeTraversalAndLiftImpls! { crate::ty::BoundRegionKind, crate::ty::AssocItem, crate::ty::AssocKind, + crate::ty::AliasKind, crate::ty::Placeholder, crate::ty::ClosureKind, crate::ty::FreeRegion, diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index 010233d7718c2..d457a4a2beaf5 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -154,9 +154,8 @@ fn implied_bounds_from_components<'tcx>( match component { Component::Region(r) => Some(OutlivesBound::RegionSubRegion(sub_region, r)), Component::Param(p) => Some(OutlivesBound::RegionSubParam(sub_region, p)), - Component::Projection(p) => Some(OutlivesBound::RegionSubProjection(sub_region, p)), - Component::Opaque(def_id, substs) => { - Some(OutlivesBound::RegionSubOpaque(sub_region, def_id, substs)) + Component::Alias(kind, p) => { + Some(OutlivesBound::RegionSubAlias(sub_region, kind, p)) } Component::EscapingProjection(_) => // If the projection has escaping regions, don't From 05f664a441542c4f50ea8336cfa403c327ee8ecb Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 14 Jan 2023 04:47:06 +0000 Subject: [PATCH 026/230] new trait solver: rebase impl substs for gats correctly --- compiler/rustc_trait_selection/src/solve/project_goals.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 3d649bea19ddf..25588138c4310 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -171,7 +171,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { let impl_substs_with_gat = goal.predicate.projection_ty.substs.rebase_onto( tcx, goal_trait_ref.def_id, - impl_trait_ref.substs, + impl_substs, ); let substs = translate_substs( acx.infcx, From be1a6db9f8978113021e3f1214ea66700a22fe9a Mon Sep 17 00:00:00 2001 From: Ezra Shaw Date: Mon, 9 Jan 2023 23:21:31 +1300 Subject: [PATCH 027/230] fix: don't emit `E0711` if `staged_api` not enabled --- compiler/rustc_passes/src/lib_features.rs | 6 ++++++ tests/ui/stability-attribute/issue-106589.rs | 10 ++++++++++ tests/ui/stability-attribute/issue-106589.stderr | 15 +++++++++++++++ 3 files changed, 31 insertions(+) create mode 100644 tests/ui/stability-attribute/issue-106589.rs create mode 100644 tests/ui/stability-attribute/issue-106589.stderr diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs index b5843c0ae488b..4c6a9b23fdf12 100644 --- a/compiler/rustc_passes/src/lib_features.rs +++ b/compiler/rustc_passes/src/lib_features.rs @@ -137,6 +137,12 @@ impl<'tcx> Visitor<'tcx> for LibFeatureCollector<'tcx> { } fn lib_features(tcx: TyCtxt<'_>, (): ()) -> LibFeatures { + // If `staged_api` is not enabled then we aren't allowed to define lib + // features; there is no point collecting them. + if !tcx.features().staged_api { + return new_lib_features(); + } + let mut collector = LibFeatureCollector::new(tcx); tcx.hir().walk_attributes(&mut collector); collector.lib_features diff --git a/tests/ui/stability-attribute/issue-106589.rs b/tests/ui/stability-attribute/issue-106589.rs new file mode 100644 index 0000000000000..3cad9a3d28324 --- /dev/null +++ b/tests/ui/stability-attribute/issue-106589.rs @@ -0,0 +1,10 @@ +// #![feature(staged_api)] // note: `staged_api` not enabled + +#![stable(feature = "foo", since = "1.0.0")] +//~^ ERROR stability attributes may not be used outside of the standard library + +#[unstable(feature = "foo", issue = "none")] +//~^ ERROR stability attributes may not be used outside of the standard library +fn foo_unstable() {} + +fn main() {} diff --git a/tests/ui/stability-attribute/issue-106589.stderr b/tests/ui/stability-attribute/issue-106589.stderr new file mode 100644 index 0000000000000..ccf3f7164e3e1 --- /dev/null +++ b/tests/ui/stability-attribute/issue-106589.stderr @@ -0,0 +1,15 @@ +error[E0734]: stability attributes may not be used outside of the standard library + --> $DIR/issue-106589.rs:6:1 + | +LL | #[unstable(feature = "foo", issue = "none")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0734]: stability attributes may not be used outside of the standard library + --> $DIR/issue-106589.rs:3:1 + | +LL | #![stable(feature = "foo", since = "1.0.0")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0734`. From 7d99866bfc43f34dbdd84f4bf982c48a51b70a99 Mon Sep 17 00:00:00 2001 From: yukang Date: Sat, 24 Dec 2022 02:41:06 +0800 Subject: [PATCH 028/230] fix #105061, Fix unused_parens issue for higher ranked function pointers --- compiler/rustc_lint/src/early.rs | 6 ++++++ compiler/rustc_lint/src/unused.rs | 1 - tests/ui/lint/unused/issue-105061.rs | 17 +++++++++++++++++ tests/ui/lint/unused/issue-105061.stderr | 20 ++++++++++++++++++++ 4 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 tests/ui/lint/unused/issue-105061.rs create mode 100644 tests/ui/lint/unused/issue-105061.stderr diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index f9b2df4959224..3901751c79fb0 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -248,6 +248,12 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> } fn visit_where_predicate(&mut self, p: &'a ast::WherePredicate) { + use rustc_ast::{WhereBoundPredicate, WherePredicate}; + if let WherePredicate::BoundPredicate(WhereBoundPredicate { bounded_ty, .. }) = p && + let ast::TyKind::BareFn(b) = &bounded_ty.kind && + b.generic_params.len() > 0 { + return; + } ast_visit::walk_where_predicate(self, p); } diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index ac2b32b44e6a1..94a3313810717 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -1002,7 +1002,6 @@ impl EarlyLintPass for UnusedParens { if let ast::TyKind::Paren(r) = &ty.kind { match &r.kind { ast::TyKind::TraitObject(..) => {} - ast::TyKind::BareFn(b) if b.generic_params.len() > 0 => {} ast::TyKind::ImplTrait(_, bounds) if bounds.len() > 1 => {} ast::TyKind::Array(_, len) => { self.check_unused_delims_expr( diff --git a/tests/ui/lint/unused/issue-105061.rs b/tests/ui/lint/unused/issue-105061.rs new file mode 100644 index 0000000000000..92d636d0ac62d --- /dev/null +++ b/tests/ui/lint/unused/issue-105061.rs @@ -0,0 +1,17 @@ +#![warn(unused)] +#![deny(warnings)] + +struct Inv<'a>(&'a mut &'a ()); + +trait Trait {} +impl Trait for (for<'a> fn(Inv<'a>),) {} + + +fn with_bound() +where + ((for<'a> fn(Inv<'a>)),): Trait, //~ ERROR unnecessary parentheses around type +{} + +fn main() { + with_bound(); +} diff --git a/tests/ui/lint/unused/issue-105061.stderr b/tests/ui/lint/unused/issue-105061.stderr new file mode 100644 index 0000000000000..f07aa2012df5f --- /dev/null +++ b/tests/ui/lint/unused/issue-105061.stderr @@ -0,0 +1,20 @@ +error: unnecessary parentheses around type + --> $DIR/issue-105061.rs:12:6 + | +LL | ((for<'a> fn(Inv<'a>)),): Trait, + | ^ ^ + | +note: the lint level is defined here + --> $DIR/issue-105061.rs:2:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(unused_parens)]` implied by `#[deny(warnings)]` +help: remove these parentheses + | +LL - ((for<'a> fn(Inv<'a>)),): Trait, +LL + (for<'a> fn(Inv<'a>),): Trait, + | + +error: aborting due to previous error + From c67903ef21d18024f14609a7996fcf14b6b8d5b6 Mon Sep 17 00:00:00 2001 From: yukang Date: Sat, 14 Jan 2023 16:52:46 +0800 Subject: [PATCH 029/230] fix issues in unused lint --- compiler/rustc_lint/src/early.rs | 8 +--- compiler/rustc_lint/src/lib.rs | 2 +- compiler/rustc_lint/src/passes.rs | 3 ++ compiler/rustc_lint/src/unused.rs | 51 +++++++++++++++++----- library/std/src/io/error/repr_bitpacked.rs | 8 ++-- 5 files changed, 50 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 3901751c79fb0..337a19dd024d2 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -248,13 +248,9 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> } fn visit_where_predicate(&mut self, p: &'a ast::WherePredicate) { - use rustc_ast::{WhereBoundPredicate, WherePredicate}; - if let WherePredicate::BoundPredicate(WhereBoundPredicate { bounded_ty, .. }) = p && - let ast::TyKind::BareFn(b) = &bounded_ty.kind && - b.generic_params.len() > 0 { - return; - } + lint_callback!(self, enter_where_predicate, p); ast_visit::walk_where_predicate(self, p); + lint_callback!(self, exit_where_predicate, p); } fn visit_poly_trait_ref(&mut self, t: &'a ast::PolyTraitRef) { diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 3d818154cb94f..d6be4da03286f 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -145,7 +145,7 @@ early_lint_methods!( [ pub BuiltinCombinedEarlyLintPass, [ - UnusedParens: UnusedParens, + UnusedParens: UnusedParens::new(), UnusedBraces: UnusedBraces, UnusedImportBraces: UnusedImportBraces, UnsafeCode: UnsafeCode, diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs index 5558156a4b9ef..0bf01c4e56781 100644 --- a/compiler/rustc_lint/src/passes.rs +++ b/compiler/rustc_lint/src/passes.rs @@ -171,6 +171,9 @@ macro_rules! early_lint_methods { /// Counterpart to `enter_lint_attrs`. fn exit_lint_attrs(a: &[ast::Attribute]); + + fn enter_where_predicate(a: &ast::WherePredicate); + fn exit_where_predicate(a: &ast::WherePredicate); ]); ) } diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 94a3313810717..65f2644a858af 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -824,7 +824,17 @@ declare_lint! { "`if`, `match`, `while` and `return` do not need parentheses" } -declare_lint_pass!(UnusedParens => [UNUSED_PARENS]); +pub struct UnusedParens { + with_self_ty_parens: bool, +} + +impl UnusedParens { + pub fn new() -> Self { + Self { with_self_ty_parens: false } + } +} + +impl_lint_pass!(UnusedParens => [UNUSED_PARENS]); impl UnusedDelimLint for UnusedParens { const DELIM_STR: &'static str = "parentheses"; @@ -999,20 +1009,22 @@ impl EarlyLintPass for UnusedParens { } fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) { + if let ast::TyKind::Array(_, len) = &ty.kind { + self.check_unused_delims_expr( + cx, + &len.value, + UnusedDelimsCtx::ArrayLenExpr, + false, + None, + None, + ); + } if let ast::TyKind::Paren(r) = &ty.kind { match &r.kind { ast::TyKind::TraitObject(..) => {} + ast::TyKind::BareFn(b) + if self.with_self_ty_parens && b.generic_params.len() > 0 => {} ast::TyKind::ImplTrait(_, bounds) if bounds.len() > 1 => {} - ast::TyKind::Array(_, len) => { - self.check_unused_delims_expr( - cx, - &len.value, - UnusedDelimsCtx::ArrayLenExpr, - false, - None, - None, - ); - } _ => { let spans = if let Some(r) = r.span.find_ancestor_inside(ty.span) { Some((ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi()))) @@ -1028,6 +1040,23 @@ impl EarlyLintPass for UnusedParens { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) { ::check_item(self, cx, item) } + + fn enter_where_predicate(&mut self, _: &EarlyContext<'_>, pred: &ast::WherePredicate) { + use rustc_ast::{WhereBoundPredicate, WherePredicate}; + if let WherePredicate::BoundPredicate(WhereBoundPredicate { + bounded_ty, + bound_generic_params, + .. + }) = pred && + let ast::TyKind::Paren(_) = &bounded_ty.kind && + bound_generic_params.is_empty() { + self.with_self_ty_parens = true; + } + } + + fn exit_where_predicate(&mut self, _: &EarlyContext<'_>, _: &ast::WherePredicate) { + self.with_self_ty_parens = false; + } } declare_lint! { diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs index 601c01c2128c8..3581484050dd1 100644 --- a/library/std/src/io/error/repr_bitpacked.rs +++ b/library/std/src/io/error/repr_bitpacked.rs @@ -374,10 +374,10 @@ static_assert!((TAG_MASK + 1).is_power_of_two()); static_assert!(align_of::() >= TAG_MASK + 1); static_assert!(align_of::() >= TAG_MASK + 1); -static_assert!(@usize_eq: (TAG_MASK & TAG_SIMPLE_MESSAGE), TAG_SIMPLE_MESSAGE); -static_assert!(@usize_eq: (TAG_MASK & TAG_CUSTOM), TAG_CUSTOM); -static_assert!(@usize_eq: (TAG_MASK & TAG_OS), TAG_OS); -static_assert!(@usize_eq: (TAG_MASK & TAG_SIMPLE), TAG_SIMPLE); +static_assert!(@usize_eq: TAG_MASK & TAG_SIMPLE_MESSAGE, TAG_SIMPLE_MESSAGE); +static_assert!(@usize_eq: TAG_MASK & TAG_CUSTOM, TAG_CUSTOM); +static_assert!(@usize_eq: TAG_MASK & TAG_OS, TAG_OS); +static_assert!(@usize_eq: TAG_MASK & TAG_SIMPLE, TAG_SIMPLE); // This is obviously true (`TAG_CUSTOM` is `0b01`), but in `Repr::new_custom` we // offset a pointer by this value, and expect it to both be within the same From 644ee8d2507f80dab7408c90102517e8c9321b5e Mon Sep 17 00:00:00 2001 From: yukang Date: Sat, 14 Jan 2023 17:03:25 +0800 Subject: [PATCH 030/230] add test case for issue 105601 --- .../ui/lint/unused/issue-105061-array-lint.rs | 11 ++++ .../unused/issue-105061-array-lint.stderr | 56 +++++++++++++++++++ .../lint/unused/issue-105061-should-lint.rs | 17 ++++++ .../unused/issue-105061-should-lint.stderr | 20 +++++++ 4 files changed, 104 insertions(+) create mode 100644 tests/ui/lint/unused/issue-105061-array-lint.rs create mode 100644 tests/ui/lint/unused/issue-105061-array-lint.stderr create mode 100644 tests/ui/lint/unused/issue-105061-should-lint.rs create mode 100644 tests/ui/lint/unused/issue-105061-should-lint.stderr diff --git a/tests/ui/lint/unused/issue-105061-array-lint.rs b/tests/ui/lint/unused/issue-105061-array-lint.rs new file mode 100644 index 0000000000000..9b06a4fde04d7 --- /dev/null +++ b/tests/ui/lint/unused/issue-105061-array-lint.rs @@ -0,0 +1,11 @@ +#![warn(unused)] +#![deny(warnings)] + +fn main() { + let _x: ([u32; 3]); //~ ERROR unnecessary parentheses around type + let _y: [u8; (3)]; //~ ERROR unnecessary parentheses around const expression + let _z: ([u8; (3)]); + //~^ ERROR unnecessary parentheses around const expression + //~| ERROR unnecessary parentheses around type + +} diff --git a/tests/ui/lint/unused/issue-105061-array-lint.stderr b/tests/ui/lint/unused/issue-105061-array-lint.stderr new file mode 100644 index 0000000000000..7eb761aee431f --- /dev/null +++ b/tests/ui/lint/unused/issue-105061-array-lint.stderr @@ -0,0 +1,56 @@ +error: unnecessary parentheses around type + --> $DIR/issue-105061-array-lint.rs:5:13 + | +LL | let _x: ([u32; 3]); + | ^ ^ + | +note: the lint level is defined here + --> $DIR/issue-105061-array-lint.rs:2:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(unused_parens)]` implied by `#[deny(warnings)]` +help: remove these parentheses + | +LL - let _x: ([u32; 3]); +LL + let _x: [u32; 3]; + | + +error: unnecessary parentheses around const expression + --> $DIR/issue-105061-array-lint.rs:6:18 + | +LL | let _y: [u8; (3)]; + | ^ ^ + | +help: remove these parentheses + | +LL - let _y: [u8; (3)]; +LL + let _y: [u8; 3]; + | + +error: unnecessary parentheses around type + --> $DIR/issue-105061-array-lint.rs:7:13 + | +LL | let _z: ([u8; (3)]); + | ^ ^ + | +help: remove these parentheses + | +LL - let _z: ([u8; (3)]); +LL + let _z: [u8; (3)]; + | + +error: unnecessary parentheses around const expression + --> $DIR/issue-105061-array-lint.rs:7:19 + | +LL | let _z: ([u8; (3)]); + | ^ ^ + | +help: remove these parentheses + | +LL - let _z: ([u8; (3)]); +LL + let _z: ([u8; 3]); + | + +error: aborting due to 4 previous errors + diff --git a/tests/ui/lint/unused/issue-105061-should-lint.rs b/tests/ui/lint/unused/issue-105061-should-lint.rs new file mode 100644 index 0000000000000..ff47e1734f7b0 --- /dev/null +++ b/tests/ui/lint/unused/issue-105061-should-lint.rs @@ -0,0 +1,17 @@ +#![warn(unused)] +#![deny(warnings)] + +struct Inv<'a>(&'a mut &'a ()); + +trait Trait<'a> {} +impl<'b> Trait<'b> for for<'a> fn(Inv<'a>) {} + + +fn with_bound() +where + for<'b> (for<'a> fn(Inv<'a>)): Trait<'b>, //~ ERROR unnecessary parentheses around type +{} + +fn main() { + with_bound(); +} diff --git a/tests/ui/lint/unused/issue-105061-should-lint.stderr b/tests/ui/lint/unused/issue-105061-should-lint.stderr new file mode 100644 index 0000000000000..60b1af71e0e56 --- /dev/null +++ b/tests/ui/lint/unused/issue-105061-should-lint.stderr @@ -0,0 +1,20 @@ +error: unnecessary parentheses around type + --> $DIR/issue-105061-should-lint.rs:12:13 + | +LL | for<'b> (for<'a> fn(Inv<'a>)): Trait<'b>, + | ^ ^ + | +note: the lint level is defined here + --> $DIR/issue-105061-should-lint.rs:2:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(unused_parens)]` implied by `#[deny(warnings)]` +help: remove these parentheses + | +LL - for<'b> (for<'a> fn(Inv<'a>)): Trait<'b>, +LL + for<'b> for<'a> fn(Inv<'a>): Trait<'b>, + | + +error: aborting due to previous error + From 1c327e1133579fc2657ea68c5ed883e3dd848443 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 14 Jan 2023 11:40:52 +0000 Subject: [PATCH 031/230] Add test. --- tests/mir-opt/inline/issue_106141.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 tests/mir-opt/inline/issue_106141.rs diff --git a/tests/mir-opt/inline/issue_106141.rs b/tests/mir-opt/inline/issue_106141.rs new file mode 100644 index 0000000000000..81f3ef948acfc --- /dev/null +++ b/tests/mir-opt/inline/issue_106141.rs @@ -0,0 +1,22 @@ +pub fn outer() -> usize { + inner() +} + +fn index() -> usize { + loop {} +} + +#[inline] +fn inner() -> usize { + let buffer = &[true]; + let index = index(); + if buffer[index] { + index + } else { + 0 + } +} + +fn main() { + outer(); +} From de9a5b076aeabf6c359be31575fc96504254f72d Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 14 Jan 2023 12:01:27 +0000 Subject: [PATCH 032/230] Make the inlining destination a `Local`. --- compiler/rustc_mir_transform/src/inline.rs | 46 ++++++++++------ .../inline_into_box_place.main.Inline.diff | 18 +++--- .../inline/issue_106141.outer.Inline.diff | 55 +++++++++++++++++++ tests/mir-opt/inline/issue_106141.rs | 2 + 4 files changed, 96 insertions(+), 25 deletions(-) create mode 100644 tests/mir-opt/inline/issue_106141.outer.Inline.diff diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 4219e6280ebbc..f652e07915405 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -542,6 +542,21 @@ impl<'tcx> Inliner<'tcx> { destination }; + // Always create a local to hold the destination, as `RETURN_PLACE` may appear + // where a full `Place` is not allowed. + let (remap_destination, destination_local) = if let Some(d) = dest.as_local() { + (false, d) + } else { + ( + true, + self.new_call_temp( + caller_body, + &callsite, + destination.ty(caller_body, self.tcx).ty, + ), + ) + }; + // Copy the arguments if needed. let args: Vec<_> = self.make_call_args(args, &callsite, caller_body, &callee_body); @@ -560,7 +575,7 @@ impl<'tcx> Inliner<'tcx> { new_locals: Local::new(caller_body.local_decls.len()).., new_scopes: SourceScope::new(caller_body.source_scopes.len()).., new_blocks: BasicBlock::new(caller_body.basic_blocks.len()).., - destination: dest, + destination: destination_local, callsite_scope: caller_body.source_scopes[callsite.source_info.scope].clone(), callsite, cleanup_block: cleanup, @@ -591,6 +606,16 @@ impl<'tcx> Inliner<'tcx> { // To avoid repeated O(n) insert, push any new statements to the end and rotate // the slice once. let mut n = 0; + if remap_destination { + caller_body[block].statements.push(Statement { + source_info: callsite.source_info, + kind: StatementKind::Assign(Box::new(( + dest, + Rvalue::Use(Operand::Move(destination_local.into())), + ))), + }); + n += 1; + } for local in callee_body.vars_and_temps_iter().rev() { if !callee_body.local_decls[local].internal && integrator.always_live_locals.contains(local) @@ -959,7 +984,7 @@ struct Integrator<'a, 'tcx> { new_locals: RangeFrom, new_scopes: RangeFrom, new_blocks: RangeFrom, - destination: Place<'tcx>, + destination: Local, callsite_scope: SourceScopeData<'tcx>, callsite: &'a CallSite<'tcx>, cleanup_block: Option, @@ -972,7 +997,7 @@ struct Integrator<'a, 'tcx> { impl Integrator<'_, '_> { fn map_local(&self, local: Local) -> Local { let new = if local == RETURN_PLACE { - self.destination.local + self.destination } else { let idx = local.index() - 1; if idx < self.args.len() { @@ -1054,21 +1079,6 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> { } fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) { - for elem in place.projection { - // FIXME: Make sure that return place is not used in an indexing projection, since it - // won't be rebased as it is supposed to be. - assert_ne!(ProjectionElem::Index(RETURN_PLACE), elem); - } - - // If this is the `RETURN_PLACE`, we need to rebase any projections onto it. - let dest_proj_len = self.destination.projection.len(); - if place.local == RETURN_PLACE && dest_proj_len > 0 { - let mut projs = Vec::with_capacity(dest_proj_len + place.projection.len()); - projs.extend(self.destination.projection); - projs.extend(place.projection); - - place.projection = self.tcx.intern_place_elems(&*projs); - } // Handles integrating any locals that occur in the base // or projections self.super_place(place, context, location) diff --git a/tests/mir-opt/inline/inline_into_box_place.main.Inline.diff b/tests/mir-opt/inline/inline_into_box_place.main.Inline.diff index 2a4dc9e3e8099..a28da146e3786 100644 --- a/tests/mir-opt/inline/inline_into_box_place.main.Inline.diff +++ b/tests/mir-opt/inline/inline_into_box_place.main.Inline.diff @@ -11,13 +11,14 @@ let mut _6: (); // in scope 0 at $DIR/inline_into_box_place.rs:+1:42: +1:43 let mut _7: *const std::vec::Vec; // in scope 0 at $DIR/inline_into_box_place.rs:+1:29: +1:43 + let mut _8: &mut std::vec::Vec; // in scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43 ++ let mut _9: std::vec::Vec; // in scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43 scope 1 { debug _x => _1; // in scope 1 at $DIR/inline_into_box_place.rs:+1:9: +1:11 } scope 2 { } + scope 3 (inlined Vec::::new) { // at $DIR/inline_into_box_place.rs:8:33: 8:43 -+ let mut _9: alloc::raw_vec::RawVec; // in scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL ++ let mut _10: alloc::raw_vec::RawVec; // in scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + } bb0: { @@ -37,8 +38,9 @@ - (*_7) = Vec::::new() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43 + StorageLive(_8); // scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43 + _8 = &mut (*_7); // scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43 -+ StorageLive(_9); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL -+ _9 = const _; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL ++ StorageLive(_9); // scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43 ++ StorageLive(_10); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL ++ _10 = const _; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL // mir::Constant - // + span: $DIR/inline_into_box_place.rs:8:33: 8:41 - // + user_ty: UserType(1) @@ -49,10 +51,12 @@ + // + span: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + // + user_ty: UserType(0) + // + literal: Const { ty: alloc::raw_vec::RawVec, val: Unevaluated(alloc::raw_vec::RawVec::::NEW, [u32], None) } -+ Deinit((*_8)); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL -+ ((*_8).0: alloc::raw_vec::RawVec) = move _9; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL -+ ((*_8).1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL -+ StorageDead(_9); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL ++ Deinit(_9); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL ++ (_9.0: alloc::raw_vec::RawVec) = move _10; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL ++ (_9.1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL ++ StorageDead(_10); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL ++ (*_8) = move _9; // scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43 ++ StorageDead(_9); // scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43 + StorageDead(_8); // scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43 _1 = move _5; // scope 0 at $DIR/inline_into_box_place.rs:+1:29: +1:43 StorageDead(_5); // scope 0 at $DIR/inline_into_box_place.rs:+1:42: +1:43 diff --git a/tests/mir-opt/inline/issue_106141.outer.Inline.diff b/tests/mir-opt/inline/issue_106141.outer.Inline.diff new file mode 100644 index 0000000000000..97361fa5f4c3b --- /dev/null +++ b/tests/mir-opt/inline/issue_106141.outer.Inline.diff @@ -0,0 +1,55 @@ +- // MIR for `outer` before Inline ++ // MIR for `outer` after Inline + + fn outer() -> usize { + let mut _0: usize; // return place in scope 0 at $DIR/issue_106141.rs:+0:19: +0:24 ++ scope 1 (inlined inner) { // at $DIR/issue_106141.rs:2:5: 2:12 ++ let mut _1: bool; // in scope 1 at $DIR/issue_106141.rs:13:8: 13:21 ++ let mut _2: bool; // in scope 1 at $DIR/issue_106141.rs:13:8: 13:21 ++ let mut _3: &[bool; 1]; // in scope 1 at $DIR/issue_106141.rs:11:18: 11:25 ++ scope 2 { ++ debug buffer => _3; // in scope 2 at $DIR/issue_106141.rs:11:9: 11:15 ++ scope 3 { ++ debug index => _0; // in scope 3 at $DIR/issue_106141.rs:12:9: 12:14 ++ } ++ } ++ } + + bb0: { +- _0 = inner() -> bb1; // scope 0 at $DIR/issue_106141.rs:+1:5: +1:12 ++ StorageLive(_3); // scope 0 at $DIR/issue_106141.rs:+1:5: +1:12 ++ _3 = const _; // scope 1 at $DIR/issue_106141.rs:11:18: 11:25 + // mir::Constant +- // + span: $DIR/issue_106141.rs:2:5: 2:10 +- // + literal: Const { ty: fn() -> usize {inner}, val: Value() } ++ // + span: $DIR/issue_106141.rs:11:18: 11:25 ++ // + literal: Const { ty: &[bool; 1], val: Unevaluated(inner, [], Some(promoted[0])) } ++ _0 = index() -> bb1; // scope 2 at $DIR/issue_106141.rs:12:17: 12:24 ++ // mir::Constant ++ // + span: $DIR/issue_106141.rs:12:17: 12:22 ++ // + literal: Const { ty: fn() -> usize {index}, val: Value() } + } + + bb1: { ++ StorageLive(_1); // scope 3 at $DIR/issue_106141.rs:13:8: 13:21 ++ _2 = Lt(_0, const 1_usize); // scope 3 at $DIR/issue_106141.rs:13:8: 13:21 ++ assert(move _2, "index out of bounds: the length is {} but the index is {}", const 1_usize, _0) -> bb2; // scope 3 at $DIR/issue_106141.rs:13:8: 13:21 ++ } ++ ++ bb2: { ++ _1 = (*_3)[_0]; // scope 3 at $DIR/issue_106141.rs:13:8: 13:21 ++ switchInt(move _1) -> [0: bb3, otherwise: bb4]; // scope 3 at $DIR/issue_106141.rs:13:8: 13:21 ++ } ++ ++ bb3: { ++ _0 = const 0_usize; // scope 3 at $DIR/issue_106141.rs:16:9: 16:10 ++ goto -> bb4; // scope 3 at $DIR/issue_106141.rs:13:5: 17:6 ++ } ++ ++ bb4: { ++ StorageDead(_1); // scope 3 at $DIR/issue_106141.rs:17:5: 17:6 ++ StorageDead(_3); // scope 0 at $DIR/issue_106141.rs:+1:5: +1:12 + return; // scope 0 at $DIR/issue_106141.rs:+2:2: +2:2 + } + } + diff --git a/tests/mir-opt/inline/issue_106141.rs b/tests/mir-opt/inline/issue_106141.rs index 81f3ef948acfc..c8288b7f3419d 100644 --- a/tests/mir-opt/inline/issue_106141.rs +++ b/tests/mir-opt/inline/issue_106141.rs @@ -20,3 +20,5 @@ fn inner() -> usize { fn main() { outer(); } + +// EMIT_MIR issue_106141.outer.Inline.diff From 869df76764d867818ca9e96f665f8645e38f9ce9 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Fri, 6 Jan 2023 11:28:05 +0000 Subject: [PATCH 033/230] Heuristically undo path prefix mappings. Because the compiler produces better diagnostics if it can find the source of (potentially remapped) dependencies. --- compiler/rustc_span/src/source_map.rs | 63 +++++++++++++++++-- compiler/rustc_span/src/source_map/tests.rs | 43 +++++++++++++ tests/ui/errors/auxiliary/remapped_dep.rs | 3 + ...emap-path-prefix-reverse.local-self.stderr | 14 +++++ ...p-path-prefix-reverse.remapped-self.stderr | 14 +++++ tests/ui/errors/remap-path-prefix-reverse.rs | 23 +++++++ tests/ui/{ => errors}/remap-path-prefix.rs | 7 +++ .../ui/{ => errors}/remap-path-prefix.stderr | 2 +- 8 files changed, 162 insertions(+), 7 deletions(-) create mode 100644 tests/ui/errors/auxiliary/remapped_dep.rs create mode 100644 tests/ui/errors/remap-path-prefix-reverse.local-self.stderr create mode 100644 tests/ui/errors/remap-path-prefix-reverse.remapped-self.stderr create mode 100644 tests/ui/errors/remap-path-prefix-reverse.rs rename tests/ui/{ => errors}/remap-path-prefix.rs (58%) rename tests/ui/{ => errors}/remap-path-prefix.stderr (82%) diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index fa09b4faa441f..58857730e41b6 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -17,7 +17,7 @@ use rustc_data_structures::stable_hasher::StableHasher; use rustc_data_structures::sync::{AtomicU32, Lrc, MappedReadGuard, ReadGuard, RwLock}; use std::cmp; use std::hash::Hash; -use std::path::{Path, PathBuf}; +use std::path::{self, Path, PathBuf}; use std::sync::atomic::Ordering; use std::fs; @@ -1071,12 +1071,24 @@ impl SourceMap { pub fn ensure_source_file_source_present(&self, source_file: Lrc) -> bool { source_file.add_external_src(|| { - match source_file.name { - FileName::Real(ref name) if let Some(local_path) = name.local_path() => { - self.file_loader.read_file(local_path).ok() + let FileName::Real(ref name) = source_file.name else { + return None; + }; + + let local_path: Cow<'_, Path> = match name { + RealFileName::LocalPath(local_path) => local_path.into(), + RealFileName::Remapped { local_path: Some(local_path), .. } => local_path.into(), + RealFileName::Remapped { local_path: None, virtual_name } => { + // The compiler produces better error messages if the sources of dependencies + // are available. Attempt to undo any path mapping so we can find remapped + // dependencies. + // We can only use the heuristic because `add_external_src` checks the file + // content hash. + self.path_mapping.reverse_map_prefix_heuristically(virtual_name)?.into() } - _ => None, - } + }; + + self.file_loader.read_file(&local_path).ok() }) } @@ -1277,4 +1289,43 @@ impl FilePathMapping { } } } + + /// Attempts to (heuristically) reverse a prefix mapping. + /// + /// Returns [`Some`] if there is exactly one mapping where the "to" part is + /// a prefix of `path` and has at least one non-empty + /// [`Normal`](path::Component::Normal) component. The component + /// restriction exists to avoid reverse mapping overly generic paths like + /// `/` or `.`). + /// + /// This is a heuristic and not guaranteed to return the actual original + /// path! Do not rely on the result unless you have other means to verify + /// that the mapping is correct (e.g. by checking the file content hash). + #[instrument(level = "debug", skip(self), ret)] + fn reverse_map_prefix_heuristically(&self, path: &Path) -> Option { + let mut found = None; + + for (from, to) in self.mapping.iter() { + let has_normal_component = to.components().any(|c| match c { + path::Component::Normal(s) => !s.is_empty(), + _ => false, + }); + + if !has_normal_component { + continue; + } + + let Ok(rest) = path.strip_prefix(to) else { + continue; + }; + + if found.is_some() { + return None; + } + + found = Some(from.join(rest)); + } + + found + } } diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs index 3cab59e8dbe6c..b4919af65fd0b 100644 --- a/compiler/rustc_span/src/source_map/tests.rs +++ b/compiler/rustc_span/src/source_map/tests.rs @@ -344,6 +344,10 @@ fn map_path_prefix(mapping: &FilePathMapping, p: &str) -> String { mapping.map_prefix(path(p)).0.to_string_lossy().to_string() } +fn reverse_map_prefix(mapping: &FilePathMapping, p: &str) -> Option { + mapping.reverse_map_prefix_heuristically(&path(p)).map(|q| q.to_string_lossy().to_string()) +} + #[test] fn path_prefix_remapping() { // Relative to relative @@ -480,6 +484,45 @@ fn path_prefix_remapping_expand_to_absolute() { ); } +#[test] +fn path_prefix_remapping_reverse() { + // Ignores options without alphanumeric chars. + { + let mapping = + &FilePathMapping::new(vec![(path("abc"), path("/")), (path("def"), path("."))]); + + assert_eq!(reverse_map_prefix(mapping, "/hello.rs"), None); + assert_eq!(reverse_map_prefix(mapping, "./hello.rs"), None); + } + + // Returns `None` if multiple options match. + { + let mapping = &FilePathMapping::new(vec![ + (path("abc"), path("/redacted")), + (path("def"), path("/redacted")), + ]); + + assert_eq!(reverse_map_prefix(mapping, "/redacted/hello.rs"), None); + } + + // Distinct reverse mappings. + { + let mapping = &FilePathMapping::new(vec![ + (path("abc"), path("/redacted")), + (path("def/ghi"), path("/fake/dir")), + ]); + + assert_eq!( + reverse_map_prefix(mapping, "/redacted/path/hello.rs"), + Some(path_str("abc/path/hello.rs")) + ); + assert_eq!( + reverse_map_prefix(mapping, "/fake/dir/hello.rs"), + Some(path_str("def/ghi/hello.rs")) + ); + } +} + #[test] fn test_next_point() { let sm = SourceMap::new(FilePathMapping::empty()); diff --git a/tests/ui/errors/auxiliary/remapped_dep.rs b/tests/ui/errors/auxiliary/remapped_dep.rs new file mode 100644 index 0000000000000..ef26f1cd883fb --- /dev/null +++ b/tests/ui/errors/auxiliary/remapped_dep.rs @@ -0,0 +1,3 @@ +// compile-flags: --remap-path-prefix={{src-base}}/errors/auxiliary=remapped-aux + +pub struct SomeStruct {} // This line should be show as part of the error. diff --git a/tests/ui/errors/remap-path-prefix-reverse.local-self.stderr b/tests/ui/errors/remap-path-prefix-reverse.local-self.stderr new file mode 100644 index 0000000000000..2584e3e88a6e5 --- /dev/null +++ b/tests/ui/errors/remap-path-prefix-reverse.local-self.stderr @@ -0,0 +1,14 @@ +error[E0423]: expected value, found struct `remapped_dep::SomeStruct` + --> $DIR/remap-path-prefix-reverse.rs:22:13 + | +LL | let _ = remapped_dep::SomeStruct; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `remapped_dep::SomeStruct {}` + | + ::: remapped-aux/remapped_dep.rs:3:1 + | +LL | pub struct SomeStruct {} // This line should be show as part of the error. + | --------------------- `remapped_dep::SomeStruct` defined here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0423`. diff --git a/tests/ui/errors/remap-path-prefix-reverse.remapped-self.stderr b/tests/ui/errors/remap-path-prefix-reverse.remapped-self.stderr new file mode 100644 index 0000000000000..e710183322acc --- /dev/null +++ b/tests/ui/errors/remap-path-prefix-reverse.remapped-self.stderr @@ -0,0 +1,14 @@ +error[E0423]: expected value, found struct `remapped_dep::SomeStruct` + --> remapped/errors/remap-path-prefix-reverse.rs:22:13 + | +LL | let _ = remapped_dep::SomeStruct; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `remapped_dep::SomeStruct {}` + | + ::: remapped-aux/remapped_dep.rs:3:1 + | +LL | pub struct SomeStruct {} // This line should be show as part of the error. + | --------------------- `remapped_dep::SomeStruct` defined here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0423`. diff --git a/tests/ui/errors/remap-path-prefix-reverse.rs b/tests/ui/errors/remap-path-prefix-reverse.rs new file mode 100644 index 0000000000000..635c4164e0f8e --- /dev/null +++ b/tests/ui/errors/remap-path-prefix-reverse.rs @@ -0,0 +1,23 @@ +// aux-build:remapped_dep.rs +// compile-flags: --remap-path-prefix={{src-base}}/errors/auxiliary=remapped-aux + +// The remapped paths are not normalized by compiletest. +// normalize-stderr-test: "\\(errors)" -> "/$1" + +// revisions: local-self remapped-self +// [remapped-self]compile-flags: --remap-path-prefix={{src-base}}=remapped + +// The paths from `remapped-self` aren't recognized by compiletest, so we +// cannot use line-specific patterns for the actual error. +// error-pattern: E0423 + +// Verify that the expected source code is shown. +// error-pattern: pub struct SomeStruct {} // This line should be show + +extern crate remapped_dep; + +fn main() { + // The actual error is irrelevant. The important part it that is should show + // a snippet of the dependency's source. + let _ = remapped_dep::SomeStruct; +} diff --git a/tests/ui/remap-path-prefix.rs b/tests/ui/errors/remap-path-prefix.rs similarity index 58% rename from tests/ui/remap-path-prefix.rs rename to tests/ui/errors/remap-path-prefix.rs index 2eef970997708..29b9c7be30122 100644 --- a/tests/ui/remap-path-prefix.rs +++ b/tests/ui/errors/remap-path-prefix.rs @@ -1,5 +1,12 @@ // compile-flags: --remap-path-prefix={{src-base}}=remapped +// The remapped paths are not normalized by compiletest. +// normalize-stderr-test: "\\(errors)" -> "/$1" + +// The remapped paths aren't recognized by compiletest, so we +// cannot use line-specific patterns. +// error-pattern: E0425 + fn main() { // We cannot actually put an ERROR marker here because // the file name in the error message is not what the diff --git a/tests/ui/remap-path-prefix.stderr b/tests/ui/errors/remap-path-prefix.stderr similarity index 82% rename from tests/ui/remap-path-prefix.stderr rename to tests/ui/errors/remap-path-prefix.stderr index ad6a35d1256cd..2f421283e6995 100644 --- a/tests/ui/remap-path-prefix.stderr +++ b/tests/ui/errors/remap-path-prefix.stderr @@ -1,5 +1,5 @@ error[E0425]: cannot find value `ferris` in this scope - --> remapped/remap-path-prefix.rs:8:5 + --> remapped/errors/remap-path-prefix.rs:15:5 | LL | ferris | ^^^^^^ not found in this scope From 389d52c1eb724b4242b6a8ac36c694c6e68b8dd2 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 14 Jan 2023 17:04:02 +0000 Subject: [PATCH 034/230] Remove visit_place. --- compiler/rustc_mir_transform/src/inline.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index f652e07915405..28c9080d38d7d 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -1078,12 +1078,6 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> { *span = span.fresh_expansion(self.expn_data); } - fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) { - // Handles integrating any locals that occur in the base - // or projections - self.super_place(place, context, location) - } - fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) { self.in_cleanup_block = data.is_cleanup; self.super_basic_block_data(block, data); From 3a3f70c94e280cbd8354874438643d15ca6ef319 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sat, 14 Jan 2023 10:58:55 -0700 Subject: [PATCH 035/230] rustdoc: remove redundant item kind class from `.item-decl > pre` This class originated in the very first commit of `rustdoc_ng`, and was used to add a color border around the item decl based on its kind. https://github.com/rust-lang/rust/blob/4fd061c426902b0904c65e64a3780b21f9ab3afb/src/rustdoc_ng/html/static/main.css#L102-L106 The item decl no longer has a border, and there aren't any kind-specific styles in modern rustdoc's rendering of this UI item. Most of this commit is updating test cases so that they use `item-decl` to find the `
` tag instead of relying on the fact that the class name
had `rust {kind}` in it while other `
` tags only had class `rust`.
---
 src/librustdoc/html/render/print_item.rs      | 32 ++++++++---------
 tests/rustdoc-gui/code-tags.goml              | 10 +++---
 tests/rustdoc-gui/font-weight.goml            |  6 ++--
 tests/rustdoc-gui/list_code_block.goml        |  2 +-
 tests/rustdoc/array-links.rs                  |  8 ++---
 tests/rustdoc/assoc-consts.rs                 |  2 +-
 tests/rustdoc/assoc-item-cast.rs              |  2 +-
 tests/rustdoc/assoc-types.rs                  | 12 +++----
 tests/rustdoc/async-fn.rs                     | 30 ++++++++--------
 tests/rustdoc/attributes.rs                   |  6 ++--
 tests/rustdoc/auxiliary/issue-85454.rs        |  2 +-
 tests/rustdoc/const-fn.rs                     |  2 +-
 tests/rustdoc/const-generics/add-impl.rs      |  2 +-
 .../const-generics/const-generic-defaults.rs  |  2 +-
 .../const-generics/const-generics-docs.rs     | 36 +++++++++----------
 tests/rustdoc/const-generics/const-impl.rs    |  2 +-
 .../const-generics/generic_const_exprs.rs     |  2 +-
 tests/rustdoc/const-generics/type-alias.rs    |  2 +-
 tests/rustdoc/const-intrinsic.rs              |  6 ++--
 tests/rustdoc/fn-pointer-arg-name.rs          |  2 +-
 ...ide-complex-unevaluated-const-arguments.rs |  2 +-
 tests/rustdoc/inline-default-methods.rs       |  4 +--
 tests/rustdoc/inline_cross/dyn_trait.rs       |  4 +--
 tests/rustdoc/inline_cross/impl_trait.rs      | 32 ++++++++---------
 tests/rustdoc/issue-20646.rs                  |  4 +--
 tests/rustdoc/issue-20727-2.rs                | 12 +++----
 tests/rustdoc/issue-20727-3.rs                | 12 +++----
 tests/rustdoc/issue-20727-4.rs                | 20 +++++------
 tests/rustdoc/issue-20727.rs                  | 12 +++----
 tests/rustdoc/issue-22038.rs                  |  8 ++---
 tests/rustdoc/issue-33302.rs                  |  6 ++--
 tests/rustdoc/issue-85454.rs                  |  4 +--
 tests/rustdoc/issue-98697.rs                  |  4 +--
 tests/rustdoc/legacy-const-generic.rs         |  4 +--
 tests/rustdoc/lifetime-name.rs                |  2 +-
 tests/rustdoc/mut-params.rs                   |  4 +--
 tests/rustdoc/normalize-assoc-item.rs         | 16 ++++-----
 tests/rustdoc/pub-method.rs                   |  2 +-
 tests/rustdoc/range-arg-pattern.rs            |  2 +-
 tests/rustdoc/reexports-priv.rs               | 16 ++++-----
 tests/rustdoc/reexports.rs                    |  8 ++---
 tests/rustdoc/rfc-2632-const-trait-impl.rs    | 16 ++++-----
 tests/rustdoc/safe-intrinsic.rs               |  6 ++--
 tests/rustdoc/slice-links.rs                  |  8 ++---
 tests/rustdoc/struct-arg-pattern.rs           |  2 +-
 tests/rustdoc/test-parens.rs                  |  2 +-
 tests/rustdoc/toggle-item-contents.rs         |  4 +--
 tests/rustdoc/tuple-struct-fields-doc.rs      |  2 +-
 tests/rustdoc/tuples.rs                       | 12 +++----
 tests/rustdoc/unit-return.rs                  |  8 ++---
 tests/rustdoc/where-sized.rs                  |  4 +--
 .../rustdoc/where.SWhere_Simd_item-decl.html  |  2 +-
 .../where.SWhere_TraitWhere_item-decl.html    |  2 +-
 tests/rustdoc/where.rs                        |  2 +-
 .../whitespace-after-where-clause.enum.html   |  2 +-
 .../whitespace-after-where-clause.enum2.html  |  2 +-
 .../whitespace-after-where-clause.struct.html |  2 +-
 ...whitespace-after-where-clause.struct2.html |  2 +-
 .../whitespace-after-where-clause.trait.html  |  2 +-
 .../whitespace-after-where-clause.trait2.html |  2 +-
 .../whitespace-after-where-clause.union.html  |  2 +-
 .../whitespace-after-where-clause.union2.html |  2 +-
 tests/rustdoc/wrapping.rs                     |  4 +--
 63 files changed, 218 insertions(+), 218 deletions(-)

diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index d6e57decdcf18..3b0c018694ad4 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -531,7 +531,7 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle
         f.decl.output.as_return().and_then(|output| notable_traits_button(output, cx));
 
     wrap_into_item_decl(w, |w| {
-        wrap_item(w, "fn", |w| {
+        wrap_item(w, |w| {
             render_attributes_in_pre(w, it, "");
             w.reserve(header_len);
             write!(
@@ -570,7 +570,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
 
     // Output the trait definition
     wrap_into_item_decl(w, |w| {
-        wrap_item(w, "trait", |w| {
+        wrap_item(w, |w| {
             render_attributes_in_pre(w, it, "");
             write!(
                 w,
@@ -1051,7 +1051,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
 
 fn item_trait_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::TraitAlias) {
     wrap_into_item_decl(w, |w| {
-        wrap_item(w, "trait-alias", |w| {
+        wrap_item(w, |w| {
             render_attributes_in_pre(w, it, "");
             write!(
                 w,
@@ -1075,7 +1075,7 @@ fn item_trait_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &
 
 fn item_opaque_ty(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::OpaqueTy) {
     wrap_into_item_decl(w, |w| {
-        wrap_item(w, "opaque", |w| {
+        wrap_item(w, |w| {
             render_attributes_in_pre(w, it, "");
             write!(
                 w,
@@ -1099,7 +1099,7 @@ fn item_opaque_ty(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &cl
 
 fn item_typedef(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Typedef) {
     fn write_content(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Typedef) {
-        wrap_item(w, "typedef", |w| {
+        wrap_item(w, |w| {
             render_attributes_in_pre(w, it, "");
             write!(w, "{}", visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx));
             write!(
@@ -1128,7 +1128,7 @@ fn item_typedef(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clea
 
 fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Union) {
     wrap_into_item_decl(w, |w| {
-        wrap_item(w, "union", |w| {
+        wrap_item(w, |w| {
             render_attributes_in_pre(w, it, "");
             render_union(w, it, Some(&s.generics), &s.fields, "", cx);
         });
@@ -1193,7 +1193,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
     let tcx = cx.tcx();
     let count_variants = e.variants().count();
     wrap_into_item_decl(w, |w| {
-        wrap_item(w, "enum", |w| {
+        wrap_item(w, |w| {
             render_attributes_in_pre(w, it, "");
             write!(
                 w,
@@ -1357,17 +1357,17 @@ fn item_proc_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, m: &c
         let name = it.name.expect("proc-macros always have names");
         match m.kind {
             MacroKind::Bang => {
-                wrap_item(w, "macro", |w| {
+                wrap_item(w, |w| {
                     write!(w, "{}!() {{ /* proc-macro */ }}", name);
                 });
             }
             MacroKind::Attr => {
-                wrap_item(w, "attr", |w| {
+                wrap_item(w, |w| {
                     write!(w, "#[{}]", name);
                 });
             }
             MacroKind::Derive => {
-                wrap_item(w, "derive", |w| {
+                wrap_item(w, |w| {
                     write!(w, "#[derive({})]", name);
                     if !m.helpers.is_empty() {
                         w.push_str("\n{\n");
@@ -1401,7 +1401,7 @@ fn item_primitive(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) {
 
 fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &clean::Constant) {
     wrap_into_item_decl(w, |w| {
-        wrap_item(w, "const", |w| {
+        wrap_item(w, |w| {
             let tcx = cx.tcx();
             render_attributes_in_code(w, it);
 
@@ -1451,7 +1451,7 @@ fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &cle
 
 fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Struct) {
     wrap_into_item_decl(w, |w| {
-        wrap_item(w, "struct", |w| {
+        wrap_item(w, |w| {
             render_attributes_in_code(w, it);
             render_struct(w, it, Some(&s.generics), s.ctor_kind, &s.fields, "", true, cx);
         });
@@ -1504,7 +1504,7 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean
 
 fn item_static(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) {
     wrap_into_item_decl(w, |w| {
-        wrap_item(w, "static", |w| {
+        wrap_item(w, |w| {
             render_attributes_in_code(w, it);
             write!(
                 w,
@@ -1521,7 +1521,7 @@ fn item_static(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean
 
 fn item_foreign_type(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) {
     wrap_into_item_decl(w, |w| {
-        wrap_item(w, "foreigntype", |w| {
+        wrap_item(w, |w| {
             w.write_str("extern {\n");
             render_attributes_in_code(w, it);
             write!(
@@ -1618,11 +1618,11 @@ where
     w.write_str("")
 }
 
-fn wrap_item(w: &mut Buffer, item_name: &str, f: F)
+fn wrap_item(w: &mut Buffer, f: F)
 where
     F: FnOnce(&mut Buffer),
 {
-    w.write_fmt(format_args!("
", item_name));
+    w.write_str(r#"
"#);
     f(w);
     w.write_str("
"); } diff --git a/tests/rustdoc-gui/code-tags.goml b/tests/rustdoc-gui/code-tags.goml index 94c1a6525aaa5..8561f537f3d32 100644 --- a/tests/rustdoc-gui/code-tags.goml +++ b/tests/rustdoc-gui/code-tags.goml @@ -9,16 +9,16 @@ size: (1080, 600) // Check that their content is inside

 assert-count: (".example-wrap pre > code", 4)
 // Check that function signature is inside 

-assert: "pre.rust.fn > code"
+assert: ".item-decl pre.rust > code"
 
 goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
-assert: "pre.rust.struct > code"
+assert: ".item-decl pre.rust > code"
 
 goto: "file://" + |DOC_PATH| + "/test_docs/enum.AnEnum.html"
-assert: "pre.rust.enum > code"
+assert: ".item-decl pre.rust > code"
 
 goto: "file://" + |DOC_PATH| + "/test_docs/trait.AnotherOne.html"
-assert: "pre.rust.trait > code"
+assert: ".item-decl pre.rust > code"
 
 goto: "file://" + |DOC_PATH| + "/test_docs/type.SomeType.html"
-assert: "pre.rust.typedef > code"
+assert: ".item-decl pre.rust > code"
diff --git a/tests/rustdoc-gui/font-weight.goml b/tests/rustdoc-gui/font-weight.goml
index 8ba005b0c35a0..fafb156317866 100644
--- a/tests/rustdoc-gui/font-weight.goml
+++ b/tests/rustdoc-gui/font-weight.goml
@@ -20,7 +20,7 @@ goto: "file://" + |DOC_PATH| + "/lib2/trait.Trait.html"
 // This is a complex selector, so here's how it works:
 //
 // * //*[@class='item-decl'] — selects element of any tag with classes docblock and item-decl
-// * /pre[@class='rust trait'] — selects immediate child with tag pre and classes rust and trait
+// * /pre[@class='rust'] — selects immediate child with tag pre and class rust
 // * /code — selects immediate child with tag code
 // * /a[@class='constant'] — selects immediate child with tag a and class constant
 // * //text() — selects child that is text node
@@ -29,11 +29,11 @@ goto: "file://" + |DOC_PATH| + "/lib2/trait.Trait.html"
 // This uses '/parent::*' as a proxy for the style of the text node.
 // We can't just select the '' because intermediate tags could be added.
 assert-count: (
-    "//*[@class='item-decl']/pre[@class='rust trait']/code/a[@class='constant']//text()/parent::*",
+    "//*[@class='item-decl']/pre[@class='rust']/code/a[@class='constant']//text()/parent::*",
     1,
 )
 assert-css: (
-    "//*[@class='item-decl']/pre[@class='rust trait']/code/a[@class='constant']//text()/parent::*",
+    "//*[@class='item-decl']/pre[@class='rust']/code/a[@class='constant']//text()/parent::*",
     {"font-weight": "400"},
 )
 
diff --git a/tests/rustdoc-gui/list_code_block.goml b/tests/rustdoc-gui/list_code_block.goml
index 3423a449de478..c527cfbfcbc56 100644
--- a/tests/rustdoc-gui/list_code_block.goml
+++ b/tests/rustdoc-gui/list_code_block.goml
@@ -1,4 +1,4 @@
 // This test checks that code blocks in list are supported.
 goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
 goto: "./fn.check_list_code_block.html"
-assert: ("pre.rust.fn")
+assert: (".item-decl pre.rust")
diff --git a/tests/rustdoc/array-links.rs b/tests/rustdoc/array-links.rs
index 07f92ac51b9f5..e7c0ee2de1a7a 100644
--- a/tests/rustdoc/array-links.rs
+++ b/tests/rustdoc/array-links.rs
@@ -4,25 +4,25 @@
 pub struct MyBox(*const T);
 
 // @has 'foo/fn.alpha.html'
-// @snapshot link_slice_u32 - '//pre[@class="rust fn"]/code'
+// @snapshot link_slice_u32 - '//div[@class="item-decl"]/pre[@class="rust"]/code'
 pub fn alpha() -> &'static [u32; 1] {
     loop {}
 }
 
 // @has 'foo/fn.beta.html'
-// @snapshot link_slice_generic - '//pre[@class="rust fn"]/code'
+// @snapshot link_slice_generic - '//div[@class="item-decl"]/pre[@class="rust"]/code'
 pub fn beta() -> &'static [T; 1] {
     loop {}
 }
 
 // @has 'foo/fn.gamma.html'
-// @snapshot link_box_u32 - '//pre[@class="rust fn"]/code'
+// @snapshot link_box_u32 - '//div[@class="item-decl"]/pre[@class="rust"]/code'
 pub fn gamma() -> MyBox<[u32; 1]> {
     loop {}
 }
 
 // @has 'foo/fn.delta.html'
-// @snapshot link_box_generic - '//pre[@class="rust fn"]/code'
+// @snapshot link_box_generic - '//div[@class="item-decl"]/pre[@class="rust"]/code'
 pub fn delta() -> MyBox<[T; 1]> {
     loop {}
 }
diff --git a/tests/rustdoc/assoc-consts.rs b/tests/rustdoc/assoc-consts.rs
index 3da19a13e5331..77b139b644f3a 100644
--- a/tests/rustdoc/assoc-consts.rs
+++ b/tests/rustdoc/assoc-consts.rs
@@ -1,5 +1,5 @@
 pub trait Foo {
-    // @has assoc_consts/trait.Foo.html '//*[@class="rust trait"]' \
+    // @has assoc_consts/trait.Foo.html '//div[@class="item-decl"]/pre[@class="rust"]' \
     //      'const FOO: usize = 13usize;'
     // @has - '//*[@id="associatedconstant.FOO"]' 'const FOO: usize'
     const FOO: usize = 12 + 1;
diff --git a/tests/rustdoc/assoc-item-cast.rs b/tests/rustdoc/assoc-item-cast.rs
index a409d64131afd..ab9702a24f469 100644
--- a/tests/rustdoc/assoc-item-cast.rs
+++ b/tests/rustdoc/assoc-item-cast.rs
@@ -10,5 +10,5 @@ pub trait AsExpression {
 }
 
 // @has foo/type.AsExprOf.html
-// @has - '//pre[@class="rust typedef"]' 'type AsExprOf = >::Expression;'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'type AsExprOf = >::Expression;'
 pub type AsExprOf = >::Expression;
diff --git a/tests/rustdoc/assoc-types.rs b/tests/rustdoc/assoc-types.rs
index a9e5b8d001928..de36c8ffeff0f 100644
--- a/tests/rustdoc/assoc-types.rs
+++ b/tests/rustdoc/assoc-types.rs
@@ -12,8 +12,8 @@ pub trait Index {
 }
 
 // @has assoc_types/fn.use_output.html
-// @has - '//*[@class="rust fn"]' '-> &T::Output'
-// @has - '//*[@class="rust fn"]//a[@href="trait.Index.html#associatedtype.Output"]' 'Output'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' '-> &T::Output'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]//a[@href="trait.Index.html#associatedtype.Output"]' 'Output'
 pub fn use_output>(obj: &T, index: usize) -> &T::Output {
     obj.index(index)
 }
@@ -23,13 +23,13 @@ pub trait Feed {
 }
 
 // @has assoc_types/fn.use_input.html
-// @has - '//*[@class="rust fn"]' 'T::Input'
-// @has - '//*[@class="rust fn"]//a[@href="trait.Feed.html#associatedtype.Input"]' 'Input'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'T::Input'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]//a[@href="trait.Feed.html#associatedtype.Input"]' 'Input'
 pub fn use_input(_feed: &T, _element: T::Input) { }
 
 // @has assoc_types/fn.cmp_input.html
-// @has - '//*[@class="rust fn"]' 'where T::Input: PartialEq'
-// @has - '//*[@class="rust fn"]//a[@href="trait.Feed.html#associatedtype.Input"]' 'Input'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'where T::Input: PartialEq'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]//a[@href="trait.Feed.html#associatedtype.Input"]' 'Input'
 pub fn cmp_input(a: &T::Input, b: &U::Input) -> bool
     where T::Input: PartialEq
 {
diff --git a/tests/rustdoc/async-fn.rs b/tests/rustdoc/async-fn.rs
index af765c51ace39..fb7ebb5f82239 100644
--- a/tests/rustdoc/async-fn.rs
+++ b/tests/rustdoc/async-fn.rs
@@ -1,35 +1,35 @@
 // edition:2018
-// @has async_fn/fn.foo.html '//pre[@class="rust fn"]' 'pub async fn foo() -> Option'
+// @has async_fn/fn.foo.html '//div[@class="item-decl"]/pre[@class="rust"]' 'pub async fn foo() -> Option'
 pub async fn foo() -> Option {
     None
 }
 
-// @has async_fn/fn.bar.html '//pre[@class="rust fn"]' 'pub async fn bar(a: i32, b: i32) -> i32'
+// @has async_fn/fn.bar.html '//div[@class="item-decl"]/pre[@class="rust"]' 'pub async fn bar(a: i32, b: i32) -> i32'
 pub async fn bar(a: i32, b: i32) -> i32 {
     0
 }
 
-// @has async_fn/fn.baz.html '//pre[@class="rust fn"]' 'pub async fn baz(a: T) -> T'
+// @has async_fn/fn.baz.html '//div[@class="item-decl"]/pre[@class="rust"]' 'pub async fn baz(a: T) -> T'
 pub async fn baz(a: T) -> T {
     a
 }
 
-// @has async_fn/fn.qux.html '//pre[@class="rust fn"]' 'pub async unsafe fn qux() -> char'
+// @has async_fn/fn.qux.html '//div[@class="item-decl"]/pre[@class="rust"]' 'pub async unsafe fn qux() -> char'
 pub async unsafe fn qux() -> char {
     '⚠'
 }
 
-// @has async_fn/fn.mut_args.html '//pre[@class="rust fn"]' 'pub async fn mut_args(a: usize)'
+// @has async_fn/fn.mut_args.html '//div[@class="item-decl"]/pre[@class="rust"]' 'pub async fn mut_args(a: usize)'
 pub async fn mut_args(mut a: usize) {}
 
-// @has async_fn/fn.mut_ref.html '//pre[@class="rust fn"]' 'pub async fn mut_ref(x: i32)'
+// @has async_fn/fn.mut_ref.html '//div[@class="item-decl"]/pre[@class="rust"]' 'pub async fn mut_ref(x: i32)'
 pub async fn mut_ref(ref mut x: i32) {}
 
 trait Bar {}
 
 impl Bar for () {}
 
-// @has async_fn/fn.quux.html '//pre[@class="rust fn"]' 'pub async fn quux() -> impl Bar'
+// @has async_fn/fn.quux.html '//div[@class="item-decl"]/pre[@class="rust"]' 'pub async fn quux() -> impl Bar'
 pub async fn quux() -> impl Bar {
     ()
 }
@@ -50,27 +50,27 @@ pub trait Pattern<'a> {}
 
 pub trait Trait {}
 // @has async_fn/fn.const_generics.html
-// @has - '//pre[@class="rust fn"]' 'pub async fn const_generics(_: impl Trait)'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub async fn const_generics(_: impl Trait)'
 pub async fn const_generics(_: impl Trait) {}
 
 // test that elided lifetimes are properly elided and not displayed as `'_`
 // regression test for #63037
 // @has async_fn/fn.elided.html
-// @has - '//pre[@class="rust fn"]' 'pub async fn elided(foo: &str) -> &str'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub async fn elided(foo: &str) -> &str'
 pub async fn elided(foo: &str) -> &str {}
 // This should really be shown as written, but for implementation reasons it's difficult.
 // See `impl Clean for TyKind::Ref`.
 // @has async_fn/fn.user_elided.html
-// @has - '//pre[@class="rust fn"]' 'pub async fn user_elided(foo: &str) -> &str'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub async fn user_elided(foo: &str) -> &str'
 pub async fn user_elided(foo: &'_ str) -> &str {}
 // @has async_fn/fn.static_trait.html
-// @has - '//pre[@class="rust fn"]' 'pub async fn static_trait(foo: &str) -> Box'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub async fn static_trait(foo: &str) -> Box'
 pub async fn static_trait(foo: &str) -> Box {}
 // @has async_fn/fn.lifetime_for_trait.html
-// @has - '//pre[@class="rust fn"]' "pub async fn lifetime_for_trait(foo: &str) -> Box"
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "pub async fn lifetime_for_trait(foo: &str) -> Box"
 pub async fn lifetime_for_trait(foo: &str) -> Box {}
 // @has async_fn/fn.elided_in_input_trait.html
-// @has - '//pre[@class="rust fn"]' "pub async fn elided_in_input_trait(t: impl Pattern<'_>)"
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "pub async fn elided_in_input_trait(t: impl Pattern<'_>)"
 pub async fn elided_in_input_trait(t: impl Pattern<'_>) {}
 
 struct AsyncFdReadyGuard<'a, T> { x: &'a T }
@@ -88,8 +88,8 @@ impl Foo {
 
 // test named lifetimes, just in case
 // @has async_fn/fn.named.html
-// @has - '//pre[@class="rust fn"]' "pub async fn named<'a, 'b>(foo: &'a str) -> &'b str"
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "pub async fn named<'a, 'b>(foo: &'a str) -> &'b str"
 pub async fn named<'a, 'b>(foo: &'a str) -> &'b str {}
 // @has async_fn/fn.named_trait.html
-// @has - '//pre[@class="rust fn"]' "pub async fn named_trait<'a, 'b>(foo: impl Pattern<'a>) -> impl Pattern<'b>"
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "pub async fn named_trait<'a, 'b>(foo: impl Pattern<'a>) -> impl Pattern<'b>"
 pub async fn named_trait<'a, 'b>(foo: impl Pattern<'a>) -> impl Pattern<'b> {}
diff --git a/tests/rustdoc/attributes.rs b/tests/rustdoc/attributes.rs
index a36dadced87d7..70e2e5c29508c 100644
--- a/tests/rustdoc/attributes.rs
+++ b/tests/rustdoc/attributes.rs
@@ -1,13 +1,13 @@
 #![crate_name = "foo"]
 
-// @has foo/fn.f.html '//*[@class="rust fn"]' '#[no_mangle]'
+// @has foo/fn.f.html '//div[@class="item-decl"]/pre[@class="rust"]' '#[no_mangle]'
 #[no_mangle]
 pub extern "C" fn f() {}
 
-// @has foo/fn.g.html '//*[@class="rust fn"]' '#[export_name = "bar"]'
+// @has foo/fn.g.html '//div[@class="item-decl"]/pre[@class="rust"]' '#[export_name = "bar"]'
 #[export_name = "bar"]
 pub extern "C" fn g() {}
 
-// @has foo/struct.Repr.html '//*[@class="item-decl"]' '#[repr(C, align(8))]'
+// @has foo/struct.Repr.html '//div[@class="item-decl"]' '#[repr(C, align(8))]'
 #[repr(C, align(8))]
 pub struct Repr;
diff --git a/tests/rustdoc/auxiliary/issue-85454.rs b/tests/rustdoc/auxiliary/issue-85454.rs
index 45664dfc3823d..5143968bbd439 100644
--- a/tests/rustdoc/auxiliary/issue-85454.rs
+++ b/tests/rustdoc/auxiliary/issue-85454.rs
@@ -1,5 +1,5 @@
 // @has issue_85454/trait.FromResidual.html
-// @has - '//pre[@class="rust trait"]' 'pub trait FromResidual::Residual> { fn from_residual(residual: R) -> Self; }'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub trait FromResidual::Residual> { fn from_residual(residual: R) -> Self; }'
 pub trait FromResidual::Residual> {
     fn from_residual(residual: R) -> Self;
 }
diff --git a/tests/rustdoc/const-fn.rs b/tests/rustdoc/const-fn.rs
index 28eba849ace07..4366ad4d0adac 100644
--- a/tests/rustdoc/const-fn.rs
+++ b/tests/rustdoc/const-fn.rs
@@ -1,7 +1,7 @@
 #![crate_name = "foo"]
 
 // @has foo/fn.bar.html
-// @has - '//*[@class="rust fn"]' 'pub const fn bar() -> '
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub const fn bar() -> '
 /// foo
 pub const fn bar() -> usize {
     2
diff --git a/tests/rustdoc/const-generics/add-impl.rs b/tests/rustdoc/const-generics/add-impl.rs
index 6cbae9abebb73..b5226ad3f78bd 100644
--- a/tests/rustdoc/const-generics/add-impl.rs
+++ b/tests/rustdoc/const-generics/add-impl.rs
@@ -2,7 +2,7 @@
 
 use std::ops::Add;
 
-// @has foo/struct.Simd.html '//pre[@class="rust struct"]' 'pub struct Simd'
+// @has foo/struct.Simd.html '//div[@class="item-decl"]/pre[@class="rust"]' 'pub struct Simd'
 pub struct Simd {
     inner: T,
 }
diff --git a/tests/rustdoc/const-generics/const-generic-defaults.rs b/tests/rustdoc/const-generics/const-generic-defaults.rs
index 2693d9b596993..acc3b853e5679 100644
--- a/tests/rustdoc/const-generics/const-generic-defaults.rs
+++ b/tests/rustdoc/const-generics/const-generic-defaults.rs
@@ -1,5 +1,5 @@
 #![crate_name = "foo"]
 
-// @has foo/struct.Foo.html '//pre[@class="rust struct"]' \
+// @has foo/struct.Foo.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'pub struct Foo(_);'
 pub struct Foo(T);
diff --git a/tests/rustdoc/const-generics/const-generics-docs.rs b/tests/rustdoc/const-generics/const-generics-docs.rs
index 5bf76e3c46908..543332d2c320b 100644
--- a/tests/rustdoc/const-generics/const-generics-docs.rs
+++ b/tests/rustdoc/const-generics/const-generics-docs.rs
@@ -3,21 +3,21 @@
 #![crate_name = "foo"]
 
 extern crate extern_crate;
-// @has foo/fn.extern_fn.html '//pre[@class="rust fn"]' \
+// @has foo/fn.extern_fn.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'pub fn extern_fn() -> impl Iterator'
 pub use extern_crate::extern_fn;
-// @has foo/struct.ExternTy.html '//pre[@class="rust struct"]' \
+// @has foo/struct.ExternTy.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'pub struct ExternTy {'
 pub use extern_crate::ExternTy;
-// @has foo/type.TyAlias.html '//pre[@class="rust typedef"]' \
+// @has foo/type.TyAlias.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'type TyAlias = ExternTy;'
 pub use extern_crate::TyAlias;
-// @has foo/trait.WTrait.html '//pre[@class="rust trait"]' \
+// @has foo/trait.WTrait.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'pub trait WTrait'
-// @has - '//*[@class="rust trait"]' 'fn hey() -> usize'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'fn hey() -> usize'
 pub use extern_crate::WTrait;
 
-// @has foo/trait.Trait.html '//pre[@class="rust trait"]' \
+// @has foo/trait.Trait.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'pub trait Trait'
 // @has - '//*[@id="impl-Trait%3C1%3E-for-u8"]//h3[@class="code-header"]' 'impl Trait<1> for u8'
 // @has - '//*[@id="impl-Trait%3C2%3E-for-u8"]//h3[@class="code-header"]' 'impl Trait<2> for u8'
@@ -30,10 +30,10 @@ impl Trait<2> for u8 {}
 impl Trait<{1 + 2}> for u8 {}
 impl Trait for [u8; N] {}
 
-// @has foo/struct.Foo.html '//pre[@class="rust struct"]' \
+// @has foo/struct.Foo.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'pub struct Foowhere u8: Trait'
 pub struct Foo where u8: Trait;
-// @has foo/struct.Bar.html '//pre[@class="rust struct"]' 'pub struct Bar(_)'
+// @has foo/struct.Bar.html '//div[@class="item-decl"]/pre[@class="rust"]' 'pub struct Bar(_)'
 pub struct Bar([T; N]);
 
 // @has foo/struct.Foo.html '//*[@id="impl-Foo%3CM%3E"]/h3[@class="code-header"]' 'impl Foowhere u8: Trait'
@@ -56,32 +56,32 @@ impl Bar {
     }
 }
 
-// @has foo/fn.test.html '//pre[@class="rust fn"]' \
+// @has foo/fn.test.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'pub fn test() -> impl Traitwhere u8: Trait'
 pub fn test() -> impl Trait where u8: Trait {
     2u8
 }
 
-// @has foo/fn.a_sink.html '//pre[@class="rust fn"]' \
+// @has foo/fn.a_sink.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'pub async fn a_sink(v: [u8; N]) -> impl Trait'
 pub async fn a_sink(v: [u8; N]) -> impl Trait {
     v
 }
 
-// @has foo/fn.b_sink.html '//pre[@class="rust fn"]' \
+// @has foo/fn.b_sink.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'pub async fn b_sink(_: impl Trait)'
 pub async fn b_sink(_: impl Trait) {}
 
-// @has foo/fn.concrete.html '//pre[@class="rust fn"]' \
+// @has foo/fn.concrete.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'pub fn concrete() -> [u8; 22]'
 pub fn concrete() -> [u8; 3 + std::mem::size_of::() << 1] {
     Default::default()
 }
 
-// @has foo/type.Faz.html '//pre[@class="rust typedef"]' \
+// @has foo/type.Faz.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'type Faz = [u8; N];'
 pub type Faz = [u8; N];
-// @has foo/type.Fiz.html '//pre[@class="rust typedef"]' \
+// @has foo/type.Fiz.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'type Fiz = [[u8; N]; 48];'
 pub type Fiz = [[u8; N]; 3 << 4];
 
@@ -91,7 +91,7 @@ macro_rules! define_me {
     }
 }
 
-// @has foo/struct.Foz.html '//pre[@class="rust struct"]' \
+// @has foo/struct.Foz.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'pub struct Foz(_);'
 define_me!(Foz);
 
@@ -103,13 +103,13 @@ impl Q for [u8; N] {
     const ASSOC: usize = N;
 }
 
-// @has foo/fn.q_user.html '//pre[@class="rust fn"]' \
+// @has foo/fn.q_user.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'pub fn q_user() -> [u8; 13]'
 pub fn q_user() -> [u8; <[u8; 13] as Q>::ASSOC] {
     [0; <[u8; 13] as Q>::ASSOC]
 }
 
-// @has foo/union.Union.html '//pre[@class="rust union"]' \
+// @has foo/union.Union.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'pub union Union'
 pub union Union {
     // @has - //pre "pub arr: [u8; N]"
@@ -118,7 +118,7 @@ pub union Union {
     pub another_arr: [(); N],
 }
 
-// @has foo/enum.Enum.html '//pre[@class="rust enum"]' \
+// @has foo/enum.Enum.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'pub enum Enum'
 pub enum Enum {
     // @has - //pre "Variant([u8; N])"
diff --git a/tests/rustdoc/const-generics/const-impl.rs b/tests/rustdoc/const-generics/const-impl.rs
index 75ee84279be3c..726fb8f0c3416 100644
--- a/tests/rustdoc/const-generics/const-impl.rs
+++ b/tests/rustdoc/const-generics/const-impl.rs
@@ -8,7 +8,7 @@ pub enum Order {
     Unsorted,
 }
 
-// @has foo/struct.VSet.html '//pre[@class="rust struct"]' 'pub struct VSet'
+// @has foo/struct.VSet.html '//div[@class="item-decl"]/pre[@class="rust"]' 'pub struct VSet'
 // @has foo/struct.VSet.html '//*[@id="impl-Send-for-VSet%3CT%2C%20ORDER%3E"]/h3[@class="code-header"]' 'impl Send for VSet'
 // @has foo/struct.VSet.html '//*[@id="impl-Sync-for-VSet%3CT%2C%20ORDER%3E"]/h3[@class="code-header"]' 'impl Sync for VSet'
 pub struct VSet {
diff --git a/tests/rustdoc/const-generics/generic_const_exprs.rs b/tests/rustdoc/const-generics/generic_const_exprs.rs
index 215ee228eb857..c53cf6dcd0570 100644
--- a/tests/rustdoc/const-generics/generic_const_exprs.rs
+++ b/tests/rustdoc/const-generics/generic_const_exprs.rs
@@ -2,6 +2,6 @@
 #![feature(generic_const_exprs)]
 #![allow(incomplete_features)]
 // make sure that `ConstEvaluatable` predicates dont cause rustdoc to ICE #77647
-// @has foo/struct.Ice.html '//pre[@class="rust struct"]' \
+// @has foo/struct.Ice.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'pub struct Ice;'
 pub struct Ice where [(); N + 1]:;
diff --git a/tests/rustdoc/const-generics/type-alias.rs b/tests/rustdoc/const-generics/type-alias.rs
index ebda5b1940455..72473a112440c 100644
--- a/tests/rustdoc/const-generics/type-alias.rs
+++ b/tests/rustdoc/const-generics/type-alias.rs
@@ -1,4 +1,4 @@
 #![crate_name = "foo"]
 
-// @has foo/type.CellIndex.html '//pre[@class="rust typedef"]' 'type CellIndex = [i64; D];'
+// @has foo/type.CellIndex.html '//div[@class="item-decl"]/pre[@class="rust"]' 'type CellIndex = [i64; D];'
 pub type CellIndex = [i64; D];
diff --git a/tests/rustdoc/const-intrinsic.rs b/tests/rustdoc/const-intrinsic.rs
index 2fc486d01dae0..42f6ac7923bf2 100644
--- a/tests/rustdoc/const-intrinsic.rs
+++ b/tests/rustdoc/const-intrinsic.rs
@@ -6,20 +6,20 @@
 
 extern "rust-intrinsic" {
     // @has 'foo/fn.transmute.html'
-    // @has - '//pre[@class="rust fn"]' 'pub const unsafe extern "rust-intrinsic" fn transmute(_: T) -> U'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub const unsafe extern "rust-intrinsic" fn transmute(_: T) -> U'
     #[stable(since="1.0.0", feature="rust1")]
     #[rustc_const_stable(feature = "const_transmute", since = "1.56.0")]
     pub fn transmute(_: T) -> U;
 
     // @has 'foo/fn.unreachable.html'
-    // @has - '//pre[@class="rust fn"]' 'pub unsafe extern "rust-intrinsic" fn unreachable() -> !'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub unsafe extern "rust-intrinsic" fn unreachable() -> !'
     #[stable(since="1.0.0", feature="rust1")]
     pub fn unreachable() -> !;
 }
 
 extern "C" {
     // @has 'foo/fn.needs_drop.html'
-    // @has - '//pre[@class="rust fn"]' 'pub unsafe extern "C" fn needs_drop() -> !'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub unsafe extern "C" fn needs_drop() -> !'
     #[stable(since="1.0.0", feature="rust1")]
     pub fn needs_drop() -> !;
 }
diff --git a/tests/rustdoc/fn-pointer-arg-name.rs b/tests/rustdoc/fn-pointer-arg-name.rs
index 4293d849df52c..96c64ac4e0211 100644
--- a/tests/rustdoc/fn-pointer-arg-name.rs
+++ b/tests/rustdoc/fn-pointer-arg-name.rs
@@ -1,5 +1,5 @@
 #![crate_name = "foo"]
 
 // @has foo/fn.f.html
-// @has - '//*[@class="rust fn"]' 'pub fn f(callback: fn(len: usize, foo: u32))'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub fn f(callback: fn(len: usize, foo: u32))'
 pub fn f(callback: fn(len: usize, foo: u32)) {}
diff --git a/tests/rustdoc/hide-complex-unevaluated-const-arguments.rs b/tests/rustdoc/hide-complex-unevaluated-const-arguments.rs
index 644a6e1cf33c5..406157ce26c80 100644
--- a/tests/rustdoc/hide-complex-unevaluated-const-arguments.rs
+++ b/tests/rustdoc/hide-complex-unevaluated-const-arguments.rs
@@ -63,7 +63,7 @@ impl Helper for St {
 // this test as long as one can ensure that private fields are not leaked!
 //
 // @has hide_complex_unevaluated_const_arguments/trait.Sub.html \
-//      '//*[@class="rust trait"]' \
+//      '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'pub trait Sub: Sup<{ _ }, { _ }> { }'
 pub trait Sub: Sup<{ 90 * 20 * 4 }, { Struct { private: () } }> {}
 
diff --git a/tests/rustdoc/inline-default-methods.rs b/tests/rustdoc/inline-default-methods.rs
index c97644e7f8723..a4ca928f3331b 100644
--- a/tests/rustdoc/inline-default-methods.rs
+++ b/tests/rustdoc/inline-default-methods.rs
@@ -4,6 +4,6 @@
 extern crate inline_default_methods;
 
 // @has inline_default_methods/trait.Foo.html
-// @has - '//*[@class="rust trait"]' 'fn bar(&self);'
-// @has - '//*[@class="rust trait"]' 'fn foo(&mut self) { ... }'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'fn bar(&self);'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'fn foo(&mut self) { ... }'
 pub use inline_default_methods::Foo;
diff --git a/tests/rustdoc/inline_cross/dyn_trait.rs b/tests/rustdoc/inline_cross/dyn_trait.rs
index fa760540e4365..0da8bfc3a9ae3 100644
--- a/tests/rustdoc/inline_cross/dyn_trait.rs
+++ b/tests/rustdoc/inline_cross/dyn_trait.rs
@@ -22,10 +22,10 @@ pub use dyn_trait::Ty2;
 pub use dyn_trait::Ty3;
 
 // @has user/fn.func0.html
-// @has - '//pre[@class="rust fn"]' "func0(_: &dyn Fn())"
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "func0(_: &dyn Fn())"
 // FIXME(fmease): Show placeholder-lifetime bound, render "func0(_: &(dyn Fn() + '_))"
 pub use dyn_trait::func0;
 
 // @has user/fn.func1.html
-// @has - '//pre[@class="rust fn"]' "func1<'func>(_: &(dyn Fn() + 'func))"
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "func1<'func>(_: &(dyn Fn() + 'func))"
 pub use dyn_trait::func1;
diff --git a/tests/rustdoc/inline_cross/impl_trait.rs b/tests/rustdoc/inline_cross/impl_trait.rs
index 9c4f646592038..e8587209b6165 100644
--- a/tests/rustdoc/inline_cross/impl_trait.rs
+++ b/tests/rustdoc/inline_cross/impl_trait.rs
@@ -4,37 +4,37 @@
 extern crate impl_trait_aux;
 
 // @has impl_trait/fn.func.html
-// @has - '//pre[@class="rust fn"]' "pub fn func<'a>(_x: impl Clone + Into> + 'a)"
-// @!has - '//pre[@class="rust fn"]' 'where'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "pub fn func<'a>(_x: impl Clone + Into> + 'a)"
+// @!has - '//div[@class="item-decl"]/pre[@class="rust"]' 'where'
 pub use impl_trait_aux::func;
 
 // @has impl_trait/fn.func2.html
-// @has - '//pre[@class="rust fn"]' "func2("
-// @has - '//pre[@class="rust fn"]' "_x: impl Deref> + Iterator,"
-// @has - '//pre[@class="rust fn"]' "_y: impl Iterator)"
-// @!has - '//pre[@class="rust fn"]' 'where'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "func2("
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "_x: impl Deref> + Iterator,"
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "_y: impl Iterator)"
+// @!has - '//div[@class="item-decl"]/pre[@class="rust"]' 'where'
 pub use impl_trait_aux::func2;
 
 // @has impl_trait/fn.func3.html
-// @has - '//pre[@class="rust fn"]' "func3("
-// @has - '//pre[@class="rust fn"]' "_x: impl Iterator> + Clone)"
-// @!has - '//pre[@class="rust fn"]' 'where'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "func3("
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "_x: impl Iterator> + Clone)"
+// @!has - '//div[@class="item-decl"]/pre[@class="rust"]' 'where'
 pub use impl_trait_aux::func3;
 
 // @has impl_trait/fn.func4.html
-// @has - '//pre[@class="rust fn"]' "func4("
-// @has - '//pre[@class="rust fn"]' "T: Iterator,"
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "func4("
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "T: Iterator,"
 pub use impl_trait_aux::func4;
 
 // @has impl_trait/fn.func5.html
-// @has - '//pre[@class="rust fn"]' "func5("
-// @has - '//pre[@class="rust fn"]' "_f: impl for<'any> Fn(&'any str, &'any str) -> bool + for<'r> Other = ()>,"
-// @has - '//pre[@class="rust fn"]' "_a: impl for<'alpha, 'beta> Auxiliary<'alpha, Item<'beta> = fn(_: &'beta ())>"
-// @!has - '//pre[@class="rust fn"]' 'where'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "func5("
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "_f: impl for<'any> Fn(&'any str, &'any str) -> bool + for<'r> Other = ()>,"
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "_a: impl for<'alpha, 'beta> Auxiliary<'alpha, Item<'beta> = fn(_: &'beta ())>"
+// @!has - '//div[@class="item-decl"]/pre[@class="rust"]' 'where'
 pub use impl_trait_aux::func5;
 
 // @has impl_trait/fn.async_fn.html
-// @has - '//pre[@class="rust fn"]' "pub async fn async_fn()"
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "pub async fn async_fn()"
 pub use impl_trait_aux::async_fn;
 
 // @has impl_trait/struct.Foo.html
diff --git a/tests/rustdoc/issue-20646.rs b/tests/rustdoc/issue-20646.rs
index 2589e27f21502..a774b0ca7cd7a 100644
--- a/tests/rustdoc/issue-20646.rs
+++ b/tests/rustdoc/issue-20646.rs
@@ -13,7 +13,7 @@ pub trait Trait {
 }
 
 // @has issue_20646/fn.fun.html \
-//      '//*[@class="rust fn"]' 'where T: Trait'
+//      '//div[@class="item-decl"]/pre[@class="rust"]' 'where T: Trait'
 pub fn fun(_: T) where T: Trait {}
 
 pub mod reexport {
@@ -21,6 +21,6 @@ pub mod reexport {
     //      '//*[@id="associatedtype.Output"]' \
     //      'type Output'
     // @has issue_20646/reexport/fn.fun.html \
-    //      '//*[@class="rust fn"]' 'where T: Trait'
+    //      '//div[@class="item-decl"]/pre[@class="rust"]' 'where T: Trait'
     pub use issue_20646::{Trait, fun};
 }
diff --git a/tests/rustdoc/issue-20727-2.rs b/tests/rustdoc/issue-20727-2.rs
index 022ff290e1a71..026b4f5acc912 100644
--- a/tests/rustdoc/issue-20727-2.rs
+++ b/tests/rustdoc/issue-20727-2.rs
@@ -5,18 +5,18 @@ extern crate issue_20727;
 
 // @has issue_20727_2/trait.Add.html
 pub trait Add {
-    // @has - '//*[@class="rust trait"]' 'trait Add {'
-    // @has - '//*[@class="rust trait"]' 'type Output;'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'trait Add {'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'type Output;'
     type Output;
 
-    // @has - '//*[@class="rust trait"]' 'fn add(self, rhs: RHS) -> Self::Output;'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'fn add(self, rhs: RHS) -> Self::Output;'
     fn add(self, rhs: RHS) -> Self::Output;
 }
 
 // @has issue_20727_2/reexport/trait.Add.html
 pub mod reexport {
-    // @has - '//*[@class="rust trait"]' 'trait Add {'
-    // @has - '//*[@class="rust trait"]' 'type Output;'
-    // @has - '//*[@class="rust trait"]' 'fn add(self, rhs: RHS) -> Self::Output;'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'trait Add {'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'type Output;'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'fn add(self, rhs: RHS) -> Self::Output;'
     pub use issue_20727::Add;
 }
diff --git a/tests/rustdoc/issue-20727-3.rs b/tests/rustdoc/issue-20727-3.rs
index 52032b75aeaf5..741ce8023d7e7 100644
--- a/tests/rustdoc/issue-20727-3.rs
+++ b/tests/rustdoc/issue-20727-3.rs
@@ -7,18 +7,18 @@ pub trait Bar {}
 
 // @has issue_20727_3/trait.Deref2.html
 pub trait Deref2 {
-    // @has - '//*[@class="rust trait"]' 'trait Deref2 {'
-    // @has - '//*[@class="rust trait"]' 'type Target: Bar;'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'trait Deref2 {'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'type Target: Bar;'
     type Target: Bar;
 
-    // @has - '//*[@class="rust trait"]' 'fn deref(&self) -> Self::Target;'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'fn deref(&self) -> Self::Target;'
     fn deref(&self) -> Self::Target;
 }
 
 // @has issue_20727_3/reexport/trait.Deref2.html
 pub mod reexport {
-    // @has - '//*[@class="rust trait"]' 'trait Deref2 {'
-    // @has - '//*[@class="rust trait"]' 'type Target: Bar;'
-    // @has - '//*[@class="rust trait"]' 'fn deref(&self) -> Self::Target;'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'trait Deref2 {'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'type Target: Bar;'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'fn deref(&self) -> Self::Target;'
     pub use issue_20727::Deref2;
 }
diff --git a/tests/rustdoc/issue-20727-4.rs b/tests/rustdoc/issue-20727-4.rs
index 643f938759093..b8fac4da6eadf 100644
--- a/tests/rustdoc/issue-20727-4.rs
+++ b/tests/rustdoc/issue-20727-4.rs
@@ -5,36 +5,36 @@ extern crate issue_20727;
 
 // @has issue_20727_4/trait.Index.html
 pub trait Index {
-    // @has - '//*[@class="rust trait"]' 'trait Index {'
-    // @has - '//*[@class="rust trait"]' 'type Output: ?Sized'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'trait Index {'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'type Output: ?Sized'
     type Output: ?Sized;
 
-    // @has - '//*[@class="rust trait"]' \
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' \
     //        'fn index(&self, index: Idx) -> &Self::Output'
     fn index(&self, index: Idx) -> &Self::Output;
 }
 
 // @has issue_20727_4/trait.IndexMut.html
 pub trait IndexMut: Index {
-    // @has - '//*[@class="rust trait"]' \
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' \
     //        'trait IndexMut: Index {'
-    // @has - '//*[@class="rust trait"]' \
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' \
     //        'fn index_mut(&mut self, index: Idx) -> &mut Self::Output;'
     fn index_mut(&mut self, index: Idx) -> &mut Self::Output;
 }
 
 pub mod reexport {
     // @has issue_20727_4/reexport/trait.Index.html
-    // @has - '//*[@class="rust trait"]' 'trait Indexwhere Idx: ?Sized,{'
-    // @has - '//*[@class="rust trait"]' 'type Output: ?Sized'
-    // @has - '//*[@class="rust trait"]' \
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'trait Indexwhere Idx: ?Sized,{'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'type Output: ?Sized'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' \
     //        'fn index(&self, index: Idx) -> &Self::Output'
     pub use issue_20727::Index;
 
     // @has issue_20727_4/reexport/trait.IndexMut.html
-    // @has - '//*[@class="rust trait"]' \
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' \
     //        'trait IndexMut: Indexwhere Idx: ?Sized,{'
-    // @has - '//*[@class="rust trait"]' \
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' \
     //        'fn index_mut(&mut self, index: Idx) -> &mut Self::Output;'
     pub use issue_20727::IndexMut;
 }
diff --git a/tests/rustdoc/issue-20727.rs b/tests/rustdoc/issue-20727.rs
index c1a98cd57daf8..df334821cccc9 100644
--- a/tests/rustdoc/issue-20727.rs
+++ b/tests/rustdoc/issue-20727.rs
@@ -5,20 +5,20 @@ extern crate issue_20727;
 
 // @has issue_20727/trait.Deref.html
 pub trait Deref {
-    // @has - '//*[@class="rust trait"]' 'trait Deref {'
-    // @has - '//*[@class="rust trait"]' 'type Target: ?Sized;'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'trait Deref {'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'type Target: ?Sized;'
     type Target: ?Sized;
 
-    // @has - '//*[@class="rust trait"]' \
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' \
     //        "fn deref<'a>(&'a self) -> &'a Self::Target;"
     fn deref<'a>(&'a self) -> &'a Self::Target;
 }
 
 // @has issue_20727/reexport/trait.Deref.html
 pub mod reexport {
-    // @has - '//*[@class="rust trait"]' 'trait Deref {'
-    // @has - '//*[@class="rust trait"]' 'type Target: ?Sized;'
-    // @has - '//*[@class="rust trait"]' \
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'trait Deref {'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'type Target: ?Sized;'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' \
     //      "fn deref<'a>(&'a self) -> &'a Self::Target;"
     pub use issue_20727::Deref;
 }
diff --git a/tests/rustdoc/issue-22038.rs b/tests/rustdoc/issue-22038.rs
index ff5813dac8099..19e626ba13235 100644
--- a/tests/rustdoc/issue-22038.rs
+++ b/tests/rustdoc/issue-22038.rs
@@ -1,19 +1,19 @@
 extern "C" {
     // @has issue_22038/fn.foo1.html \
-    //      '//*[@class="rust fn"]' 'pub unsafe extern "C" fn foo1()'
+    //      '//div[@class="item-decl"]/pre[@class="rust"]' 'pub unsafe extern "C" fn foo1()'
     pub fn foo1();
 }
 
 extern "system" {
     // @has issue_22038/fn.foo2.html \
-    //      '//*[@class="rust fn"]' 'pub unsafe extern "system" fn foo2()'
+    //      '//div[@class="item-decl"]/pre[@class="rust"]' 'pub unsafe extern "system" fn foo2()'
     pub fn foo2();
 }
 
 // @has issue_22038/fn.bar.html \
-//      '//*[@class="rust fn"]' 'pub extern "C" fn bar()'
+//      '//div[@class="item-decl"]/pre[@class="rust"]' 'pub extern "C" fn bar()'
 pub extern "C" fn bar() {}
 
 // @has issue_22038/fn.baz.html \
-//      '//*[@class="rust fn"]' 'pub extern "system" fn baz()'
+//      '//div[@class="item-decl"]/pre[@class="rust"]' 'pub extern "system" fn baz()'
 pub extern "system" fn baz() {}
diff --git a/tests/rustdoc/issue-33302.rs b/tests/rustdoc/issue-33302.rs
index 1e4791e01253d..b4c52e2f17a6d 100644
--- a/tests/rustdoc/issue-33302.rs
+++ b/tests/rustdoc/issue-33302.rs
@@ -6,17 +6,17 @@ macro_rules! make {
         pub struct S;
 
         // @has issue_33302/constant.CST.html \
-        //        '//pre[@class="rust const"]' 'pub const CST: i32'
+        //        '//div[@class="item-decl"]/pre[@class="rust"]' 'pub const CST: i32'
         pub const CST: i32 = ($n * $n);
         // @has issue_33302/static.ST.html \
-        //        '//pre[@class="rust static"]' 'pub static ST: i32'
+        //        '//div[@class="item-decl"]/pre[@class="rust"]' 'pub static ST: i32'
         pub static ST: i32 = ($n * $n);
 
         pub trait T {
             fn ignore(_: &X) {}
             const C: X;
             // @has issue_33302/trait.T.html \
-            //        '//*[@class="rust trait"]' 'const D: i32'
+            //        '//div[@class="item-decl"]/pre[@class="rust"]' 'const D: i32'
             // @has - '//*[@id="associatedconstant.D"]' 'const D: i32'
             const D: i32 = ($n * $n);
         }
diff --git a/tests/rustdoc/issue-85454.rs b/tests/rustdoc/issue-85454.rs
index 3351b5c8350fd..74fc22b31dc0c 100644
--- a/tests/rustdoc/issue-85454.rs
+++ b/tests/rustdoc/issue-85454.rs
@@ -5,7 +5,7 @@
 extern crate issue_85454;
 
 // @has foo/trait.FromResidual.html
-// @has - '//pre[@class="rust trait"]' 'pub trait FromResidual::Residual> { fn from_residual(residual: R) -> Self; }'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub trait FromResidual::Residual> { fn from_residual(residual: R) -> Self; }'
 pub trait FromResidual::Residual> {
     fn from_residual(residual: R) -> Self;
 }
@@ -24,6 +24,6 @@ pub enum ControlFlow {
 
 pub mod reexport {
     // @has foo/reexport/trait.FromResidual.html
-    // @has - '//pre[@class="rust trait"]' 'pub trait FromResidual::Residual> { fn from_residual(residual: R) -> Self; }'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub trait FromResidual::Residual> { fn from_residual(residual: R) -> Self; }'
     pub use issue_85454::*;
 }
diff --git a/tests/rustdoc/issue-98697.rs b/tests/rustdoc/issue-98697.rs
index d50268509b2c1..884b63ac97ffc 100644
--- a/tests/rustdoc/issue-98697.rs
+++ b/tests/rustdoc/issue-98697.rs
@@ -8,8 +8,8 @@
 
 extern crate issue_98697_reexport_with_anonymous_lifetime;
 
-// @has issue_98697/fn.repro.html '//pre[@class="rust fn"]/code' 'fn repro()where F: Fn(&str)'
-// @!has issue_98697/fn.repro.html '//pre[@class="rust fn"]/code' 'for<'
+// @has issue_98697/fn.repro.html '//div[@class="item-decl"]/pre[@class="rust"]/code' 'fn repro()where F: Fn(&str)'
+// @!has issue_98697/fn.repro.html '//div[@class="item-decl"]/pre[@class="rust"]/code' 'for<'
 pub use issue_98697_reexport_with_anonymous_lifetime::repro;
 
 // @has issue_98697/struct.Extra.html '//div[@id="trait-implementations-list"]//h3[@class="code-header"]' 'impl MyTrait<&Extra> for Extra'
diff --git a/tests/rustdoc/legacy-const-generic.rs b/tests/rustdoc/legacy-const-generic.rs
index 46a50e2fc30b4..14533624e448e 100644
--- a/tests/rustdoc/legacy-const-generic.rs
+++ b/tests/rustdoc/legacy-const-generic.rs
@@ -2,14 +2,14 @@
 #![feature(rustc_attrs)]
 
 // @has 'foo/fn.foo.html'
-// @has - '//*[@class="rust fn"]' 'fn foo(x: usize, const Y: usize, z: usize) -> [usize; 3]'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'fn foo(x: usize, const Y: usize, z: usize) -> [usize; 3]'
 #[rustc_legacy_const_generics(1)]
 pub fn foo(x: usize, z: usize) -> [usize; 3] {
     [x, Y, z]
 }
 
 // @has 'foo/fn.bar.html'
-// @has - '//*[@class="rust fn"]' 'fn bar(x: usize, const Y: usize, const Z: usize) -> [usize; 3]'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'fn bar(x: usize, const Y: usize, const Z: usize) -> [usize; 3]'
 #[rustc_legacy_const_generics(1, 2)]
 pub fn bar(x: usize) -> [usize; 3] {
     [x, Y, z]
diff --git a/tests/rustdoc/lifetime-name.rs b/tests/rustdoc/lifetime-name.rs
index 5d30a745a61a6..0fb6605910907 100644
--- a/tests/rustdoc/lifetime-name.rs
+++ b/tests/rustdoc/lifetime-name.rs
@@ -1,5 +1,5 @@
 #![crate_name = "foo"]
 
 // @has 'foo/type.Resolutions.html'
-// @has - '//*[@class="rust typedef"]' "pub type Resolutions<'tcx> = &'tcx u8;"
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "pub type Resolutions<'tcx> = &'tcx u8;"
 pub type Resolutions<'tcx> = &'tcx u8;
diff --git a/tests/rustdoc/mut-params.rs b/tests/rustdoc/mut-params.rs
index f3ea699583917..3b862e651c909 100644
--- a/tests/rustdoc/mut-params.rs
+++ b/tests/rustdoc/mut-params.rs
@@ -13,6 +13,6 @@ impl Foo {
     pub fn bar(mut bar: ()) {}
 }
 
-// @count foo/fn.baz.html '//*[@class="rust fn"]' 1
-// @!has - '//*[@class="rust fn"]' 'mut'
+// @count foo/fn.baz.html '//div[@class="item-decl"]/pre[@class="rust"]' 1
+// @!has - '//div[@class="item-decl"]/pre[@class="rust"]' 'mut'
 pub fn baz(mut foo: Foo) {}
diff --git a/tests/rustdoc/normalize-assoc-item.rs b/tests/rustdoc/normalize-assoc-item.rs
index db56f68526b3f..659480479fd13 100644
--- a/tests/rustdoc/normalize-assoc-item.rs
+++ b/tests/rustdoc/normalize-assoc-item.rs
@@ -19,12 +19,12 @@ impl Trait for isize {
     type X = <() as Trait>::X;
 }
 
-// @has 'normalize_assoc_item/fn.f.html' '//pre[@class="rust fn"]' 'pub fn f() -> isize'
+// @has 'normalize_assoc_item/fn.f.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub fn f() -> isize'
 pub fn f() -> ::X {
     0
 }
 
-// @has 'normalize_assoc_item/fn.f2.html' '//pre[@class="rust fn"]' 'pub fn f2() -> fn() -> i32'
+// @has 'normalize_assoc_item/fn.f2.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub fn f2() -> fn() -> i32'
 pub fn f2() -> ::X {
     todo!()
 }
@@ -49,10 +49,10 @@ impl Trait for Generic {
 // These can't be normalized because they depend on a generic parameter.
 // However the user can choose whether the text should be displayed as `Inner::X` or `::X`.
 
-// @has 'normalize_assoc_item/struct.Unknown.html' '//pre[@class="rust struct"]' 'pub struct Unknown(pub ::X);'
+// @has 'normalize_assoc_item/struct.Unknown.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub struct Unknown(pub ::X);'
 pub struct Unknown(pub ::X);
 
-// @has 'normalize_assoc_item/struct.Unknown2.html' '//pre[@class="rust struct"]' 'pub struct Unknown2(pub Inner::X);'
+// @has 'normalize_assoc_item/struct.Unknown2.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub struct Unknown2(pub Inner::X);'
 pub struct Unknown2(pub Inner::X);
 
 trait Lifetimes<'a> {
@@ -63,20 +63,20 @@ impl<'a> Lifetimes<'a> for usize {
     type Y = &'a isize;
 }
 
-// @has 'normalize_assoc_item/fn.g.html' '//pre[@class="rust fn"]' "pub fn g() -> &isize"
+// @has 'normalize_assoc_item/fn.g.html' '//div[@class="item-decl"]/pre[@class="rust"]' "pub fn g() -> &isize"
 pub fn g() -> >::Y {
     &0
 }
 
-// @has 'normalize_assoc_item/constant.A.html' '//pre[@class="rust const"]' "pub const A: &isize"
+// @has 'normalize_assoc_item/constant.A.html' '//div[@class="item-decl"]/pre[@class="rust"]' "pub const A: &isize"
 pub const A: >::Y = &0;
 
 // test cross-crate re-exports
 extern crate inner;
-// @has 'normalize_assoc_item/fn.foo.html' '//pre[@class="rust fn"]' "pub fn foo() -> i32"
+// @has 'normalize_assoc_item/fn.foo.html' '//div[@class="item-decl"]/pre[@class="rust"]' "pub fn foo() -> i32"
 pub use inner::foo;
 
-// @has 'normalize_assoc_item/fn.h.html' '//pre[@class="rust fn"]' "pub fn h() -> IntoIter"
+// @has 'normalize_assoc_item/fn.h.html' '//div[@class="item-decl"]/pre[@class="rust"]' "pub fn h() -> IntoIter"
 pub fn h() ->  as IntoIterator>::IntoIter {
     vec![].into_iter()
 }
diff --git a/tests/rustdoc/pub-method.rs b/tests/rustdoc/pub-method.rs
index fa7de0aff6a22..0dca3f672cd3c 100644
--- a/tests/rustdoc/pub-method.rs
+++ b/tests/rustdoc/pub-method.rs
@@ -3,7 +3,7 @@
 #![crate_name = "foo"]
 
 // @has foo/fn.bar.html
-// @has - '//*[@class="rust fn"]' 'pub fn bar() -> '
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub fn bar() -> '
 /// foo
 pub fn bar() -> usize {
     2
diff --git a/tests/rustdoc/range-arg-pattern.rs b/tests/rustdoc/range-arg-pattern.rs
index 756939ae3773c..bdbcc47c9f28d 100644
--- a/tests/rustdoc/range-arg-pattern.rs
+++ b/tests/rustdoc/range-arg-pattern.rs
@@ -1,5 +1,5 @@
 #![crate_name = "foo"]
 
 // @has foo/fn.f.html
-// @has - '//*[@class="rust fn"]' 'pub fn f(_: u8)'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub fn f(_: u8)'
 pub fn f(0u8..=255: u8) {}
diff --git a/tests/rustdoc/reexports-priv.rs b/tests/rustdoc/reexports-priv.rs
index 11364e7f707ef..35c90ba5d7b89 100644
--- a/tests/rustdoc/reexports-priv.rs
+++ b/tests/rustdoc/reexports-priv.rs
@@ -32,7 +32,7 @@ pub(self) use reexports::BarSelf;
 // @!has 'foo/enum.BarLocal.html'
 use reexports::BarLocal;
 
-// @has 'foo/fn.foo.html' '//*[@class="rust fn"]' 'pub fn foo()'
+// @has 'foo/fn.foo.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub fn foo()'
 pub use reexports::foo;
 // @!has 'foo/fn.foo_crate.html'
 pub(crate) use reexports::foo_crate;
@@ -41,7 +41,7 @@ pub(self) use reexports::foo_self;
 // @!has 'foo/fn.foo_local.html'
 use reexports::foo_local;
 
-// @has 'foo/type.Type.html' '//*[@class="rust typedef"]' 'pub type Type ='
+// @has 'foo/type.Type.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub type Type ='
 pub use reexports::Type;
 // @!has 'foo/type.TypeCrate.html'
 pub(crate) use reexports::TypeCrate;
@@ -94,22 +94,22 @@ pub mod outer {
         // @!has 'foo/outer/inner/enum.BarLocal.html'
         use reexports::BarLocal;
 
-        // @has 'foo/outer/inner/fn.foo.html' '//*[@class="rust fn"]' 'pub fn foo()'
+        // @has 'foo/outer/inner/fn.foo.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub fn foo()'
         pub use reexports::foo;
-        // @has 'foo/outer/inner/fn.foo_crate.html' '//*[@class="rust fn"]' 'pub(crate) fn foo_crate()'
+        // @has 'foo/outer/inner/fn.foo_crate.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub(crate) fn foo_crate()'
         pub(crate) use reexports::foo_crate;
-        // @has 'foo/outer/inner/fn.foo_super.html' '//*[@class="rust fn"]' 'pub(in outer) fn foo_super()'
+        // @has 'foo/outer/inner/fn.foo_super.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub(in outer) fn foo_super()'
         pub(super) use::reexports::foo_super;
         // @!has 'foo/outer/inner/fn.foo_self.html'
         pub(self) use reexports::foo_self;
         // @!has 'foo/outer/inner/fn.foo_local.html'
         use reexports::foo_local;
 
-        // @has 'foo/outer/inner/type.Type.html' '//*[@class="rust typedef"]' 'pub type Type ='
+        // @has 'foo/outer/inner/type.Type.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub type Type ='
         pub use reexports::Type;
-        // @has 'foo/outer/inner/type.TypeCrate.html' '//*[@class="rust typedef"]' 'pub(crate) type TypeCrate ='
+        // @has 'foo/outer/inner/type.TypeCrate.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub(crate) type TypeCrate ='
         pub(crate) use reexports::TypeCrate;
-        // @has 'foo/outer/inner/type.TypeSuper.html' '//*[@class="rust typedef"]' 'pub(in outer) type TypeSuper ='
+        // @has 'foo/outer/inner/type.TypeSuper.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub(in outer) type TypeSuper ='
         pub(super) use reexports::TypeSuper;
         // @!has 'foo/outer/inner/type.TypeSelf.html'
         pub(self) use reexports::TypeSelf;
diff --git a/tests/rustdoc/reexports.rs b/tests/rustdoc/reexports.rs
index 9aa6d7224baca..65d305c6d2c42 100644
--- a/tests/rustdoc/reexports.rs
+++ b/tests/rustdoc/reexports.rs
@@ -31,7 +31,7 @@ pub(self) use reexports::BarSelf;
 // @!has 'foo/enum.BarLocal.html'
 use reexports::BarLocal;
 
-// @has 'foo/fn.foo.html' '//*[@class="rust fn"]' 'pub fn foo()'
+// @has 'foo/fn.foo.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub fn foo()'
 pub use reexports::foo;
 // @!has 'foo/fn.foo_crate.html'
 pub(crate) use reexports::foo_crate;
@@ -40,7 +40,7 @@ pub(self) use reexports::foo_self;
 // @!has 'foo/fn.foo_local.html'
 use reexports::foo_local;
 
-// @has 'foo/type.Type.html' '//*[@class="rust typedef"]' 'pub type Type ='
+// @has 'foo/type.Type.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub type Type ='
 pub use reexports::Type;
 // @!has 'foo/type.TypeCrate.html'
 pub(crate) use reexports::TypeCrate;
@@ -93,7 +93,7 @@ pub mod outer {
         // @!has 'foo/outer/inner/enum.BarLocal.html'
         use reexports::BarLocal;
 
-        // @has 'foo/outer/inner/fn.foo.html' '//*[@class="rust fn"]' 'pub fn foo()'
+        // @has 'foo/outer/inner/fn.foo.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub fn foo()'
         pub use reexports::foo;
         // @!has 'foo/outer/inner/fn.foo_crate.html'
         pub(crate) use reexports::foo_crate;
@@ -104,7 +104,7 @@ pub mod outer {
         // @!has 'foo/outer/inner/fn.foo_local.html'
         use reexports::foo_local;
 
-        // @has 'foo/outer/inner/type.Type.html' '//*[@class="rust typedef"]' 'pub type Type ='
+        // @has 'foo/outer/inner/type.Type.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub type Type ='
         pub use reexports::Type;
         // @!has 'foo/outer/inner/type.TypeCrate.html'
         pub(crate) use reexports::TypeCrate;
diff --git a/tests/rustdoc/rfc-2632-const-trait-impl.rs b/tests/rustdoc/rfc-2632-const-trait-impl.rs
index 7ed9d6729b647..a229a4e29fefb 100644
--- a/tests/rustdoc/rfc-2632-const-trait-impl.rs
+++ b/tests/rustdoc/rfc-2632-const-trait-impl.rs
@@ -12,10 +12,10 @@ use std::marker::Destruct;
 
 pub struct S(T);
 
-// @!has foo/trait.Tr.html '//pre[@class="rust trait"]/code/a[@class="trait"]' '~const'
-// @has - '//pre[@class="rust trait"]/code/a[@class="trait"]' 'Clone'
-// @!has - '//pre[@class="rust trait"]/code/span[@class="where"]' '~const'
-// @has - '//pre[@class="rust trait"]/code/span[@class="where"]' ': Clone'
+// @!has foo/trait.Tr.html '//div[@class="item-decl"]/pre[@class="rust"]/code/a[@class="trait"]' '~const'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]/code/a[@class="trait"]' 'Clone'
+// @!has - '//div[@class="item-decl"]/pre[@class="rust"]/code/span[@class="where"]' '~const'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]/code/span[@class="where"]' ': Clone'
 #[const_trait]
 pub trait Tr {
     // @!has - '//section[@id="method.a"]/h4[@class="code-header"]' '~const'
@@ -45,10 +45,10 @@ where
     }
 }
 
-// @!has foo/fn.foo.html '//pre[@class="rust fn"]/code/a[@class="trait"]' '~const'
-// @has - '//pre[@class="rust fn"]/code/a[@class="trait"]' 'Clone'
-// @!has - '//pre[@class="rust fn"]/code/span[@class="where fmt-newline"]' '~const'
-// @has - '//pre[@class="rust fn"]/code/span[@class="where fmt-newline"]' ': Clone'
+// @!has foo/fn.foo.html '//div[@class="item-decl"]/pre[@class="rust"]/code/a[@class="trait"]' '~const'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]/code/a[@class="trait"]' 'Clone'
+// @!has - '//div[@class="item-decl"]/pre[@class="rust"]/code/span[@class="where fmt-newline"]' '~const'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]/code/span[@class="where fmt-newline"]' ': Clone'
 pub const fn foo()
 where
     Option: ~const Clone + ~const Destruct,
diff --git a/tests/rustdoc/safe-intrinsic.rs b/tests/rustdoc/safe-intrinsic.rs
index d08abdaeb1411..0b65bf1dfed0f 100644
--- a/tests/rustdoc/safe-intrinsic.rs
+++ b/tests/rustdoc/safe-intrinsic.rs
@@ -7,16 +7,16 @@
 
 extern "rust-intrinsic" {
     // @has 'foo/fn.abort.html'
-    // @has - '//pre[@class="rust fn"]' 'pub extern "rust-intrinsic" fn abort() -> !'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub extern "rust-intrinsic" fn abort() -> !'
     #[rustc_safe_intrinsic]
     pub fn abort() -> !;
     // @has 'foo/fn.unreachable.html'
-    // @has - '//pre[@class="rust fn"]' 'pub unsafe extern "rust-intrinsic" fn unreachable() -> !'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub unsafe extern "rust-intrinsic" fn unreachable() -> !'
     pub fn unreachable() -> !;
 }
 
 extern "C" {
     // @has 'foo/fn.needs_drop.html'
-    // @has - '//pre[@class="rust fn"]' 'pub unsafe extern "C" fn needs_drop() -> !'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub unsafe extern "C" fn needs_drop() -> !'
     pub fn needs_drop() -> !;
 }
diff --git a/tests/rustdoc/slice-links.rs b/tests/rustdoc/slice-links.rs
index 9a78e963e3036..67137fdcab274 100644
--- a/tests/rustdoc/slice-links.rs
+++ b/tests/rustdoc/slice-links.rs
@@ -4,25 +4,25 @@
 pub struct MyBox(*const T);
 
 // @has 'foo/fn.alpha.html'
-// @snapshot link_slice_u32 - '//pre[@class="rust fn"]/code'
+// @snapshot link_slice_u32 - '//div[@class="item-decl"]/pre[@class="rust"]/code'
 pub fn alpha() -> &'static [u32] {
     loop {}
 }
 
 // @has 'foo/fn.beta.html'
-// @snapshot link_slice_generic - '//pre[@class="rust fn"]/code'
+// @snapshot link_slice_generic - '//div[@class="item-decl"]/pre[@class="rust"]/code'
 pub fn beta() -> &'static [T] {
     loop {}
 }
 
 // @has 'foo/fn.gamma.html'
-// @snapshot link_box_u32 - '//pre[@class="rust fn"]/code'
+// @snapshot link_box_u32 - '//div[@class="item-decl"]/pre[@class="rust"]/code'
 pub fn gamma() -> MyBox<[u32]> {
     loop {}
 }
 
 // @has 'foo/fn.delta.html'
-// @snapshot link_box_generic - '//pre[@class="rust fn"]/code'
+// @snapshot link_box_generic - '//div[@class="item-decl"]/pre[@class="rust"]/code'
 pub fn delta() -> MyBox<[T]> {
     loop {}
 }
diff --git a/tests/rustdoc/struct-arg-pattern.rs b/tests/rustdoc/struct-arg-pattern.rs
index 3c0369e3d3413..3bfb43a0bef2c 100644
--- a/tests/rustdoc/struct-arg-pattern.rs
+++ b/tests/rustdoc/struct-arg-pattern.rs
@@ -4,7 +4,7 @@ struct BodyId {
     hir_id: usize,
 }
 
-// @has 'foo/fn.body_owner.html' '//*[@class="rust fn"]' 'pub fn body_owner(_: BodyId)'
+// @has 'foo/fn.body_owner.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub fn body_owner(_: BodyId)'
 pub fn body_owner(BodyId { hir_id }: BodyId) {
     // ...
 }
diff --git a/tests/rustdoc/test-parens.rs b/tests/rustdoc/test-parens.rs
index d9b9c7957d9a1..f5fdb1f52bf8e 100644
--- a/tests/rustdoc/test-parens.rs
+++ b/tests/rustdoc/test-parens.rs
@@ -1,5 +1,5 @@
 #![crate_name = "foo"]
 
 // @has foo/fn.foo.html
-// @has - '//*[@class="rust fn"]' "_: &(dyn ToString + 'static)"
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "_: &(dyn ToString + 'static)"
 pub fn foo(_: &(ToString + 'static)) {}
diff --git a/tests/rustdoc/toggle-item-contents.rs b/tests/rustdoc/toggle-item-contents.rs
index 87240f233ff2a..5d34ec09b66dc 100644
--- a/tests/rustdoc/toggle-item-contents.rs
+++ b/tests/rustdoc/toggle-item-contents.rs
@@ -81,8 +81,8 @@ pub enum EnumStructVariant {
 }
 
 // @has 'toggle_item_contents/enum.LargeEnum.html'
-// @count - '//*[@class="rust enum"]//details[@class="toggle type-contents-toggle"]' 1
-// @has - '//*[@class="rust enum"]//details[@class="toggle type-contents-toggle"]' 'Show 13 variants'
+// @count - '//div[@class="item-decl"]/pre//details[@class="toggle type-contents-toggle"]' 1
+// @has - '//div[@class="item-decl"]/pre//details[@class="toggle type-contents-toggle"]' 'Show 13 variants'
 pub enum LargeEnum {
     A, B, C, D, E, F(u8), G, H, I, J, K, L, M
 }
diff --git a/tests/rustdoc/tuple-struct-fields-doc.rs b/tests/rustdoc/tuple-struct-fields-doc.rs
index 8ab1143d1f70e..d72c10f2b2542 100644
--- a/tests/rustdoc/tuple-struct-fields-doc.rs
+++ b/tests/rustdoc/tuple-struct-fields-doc.rs
@@ -19,7 +19,7 @@ pub struct Foo(
 );
 
 // @has foo/enum.Bar.html
-// @has - '//pre[@class="rust enum"]' 'BarVariant(String),'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'BarVariant(String),'
 // @matches - '//*[@id="variant.BarVariant.fields"]/h4' '^Tuple Fields$'
 // @has - '//*[@id="variant.BarVariant.field.0"]' '0: String'
 // @has - '//*[@id="variant.BarVariant.fields"]//*[@class="docblock"]' 'Hello docs'
diff --git a/tests/rustdoc/tuples.rs b/tests/rustdoc/tuples.rs
index 62e2f9e7ef244..e716de8b55c8f 100644
--- a/tests/rustdoc/tuples.rs
+++ b/tests/rustdoc/tuples.rs
@@ -1,20 +1,20 @@
 #![crate_name = "foo"]
 
 // @has foo/fn.tuple0.html //pre 'pub fn tuple0(x: ())'
-// @snapshot link_unit - '//pre[@class="rust fn"]/code'
+// @snapshot link_unit - '//div[@class="item-decl"]/pre[@class="rust"]/code'
 pub fn tuple0(x: ()) -> () { x }
 // @has foo/fn.tuple1.html //pre 'pub fn tuple1(x: (i32,)) -> (i32,)'
-// @snapshot link1_i32 - '//pre[@class="rust fn"]/code'
+// @snapshot link1_i32 - '//div[@class="item-decl"]/pre[@class="rust"]/code'
 pub fn tuple1(x: (i32,)) -> (i32,) { x }
 // @has foo/fn.tuple2.html //pre 'pub fn tuple2(x: (i32, i32)) -> (i32, i32)'
-// @snapshot link2_i32 - '//pre[@class="rust fn"]/code'
+// @snapshot link2_i32 - '//div[@class="item-decl"]/pre[@class="rust"]/code'
 pub fn tuple2(x: (i32, i32)) -> (i32, i32) { x }
 // @has foo/fn.tuple1_t.html //pre 'pub fn tuple1_t(x: (T,)) -> (T,)'
-// @snapshot link1_t - '//pre[@class="rust fn"]/code'
+// @snapshot link1_t - '//div[@class="item-decl"]/pre[@class="rust"]/code'
 pub fn tuple1_t(x: (T,)) -> (T,) { x }
 // @has foo/fn.tuple2_t.html //pre 'pub fn tuple2_t(x: (T, T)) -> (T, T)'
-// @snapshot link2_t - '//pre[@class="rust fn"]/code'
+// @snapshot link2_t - '//div[@class="item-decl"]/pre[@class="rust"]/code'
 pub fn tuple2_t(x: (T, T)) -> (T, T) { x }
 // @has foo/fn.tuple2_tu.html //pre 'pub fn tuple2_tu(x: (T, U)) -> (T, U)'
-// @snapshot link2_tu - '//pre[@class="rust fn"]/code'
+// @snapshot link2_tu - '//div[@class="item-decl"]/pre[@class="rust"]/code'
 pub fn tuple2_tu(x: (T, U)) -> (T, U) { x }
diff --git a/tests/rustdoc/unit-return.rs b/tests/rustdoc/unit-return.rs
index ae3a6031519fb..353cd1c477249 100644
--- a/tests/rustdoc/unit-return.rs
+++ b/tests/rustdoc/unit-return.rs
@@ -4,14 +4,14 @@
 
 extern crate unit_return;
 
-// @has 'foo/fn.f0.html' '//*[@class="rust fn"]' 'F: FnMut(u8) + Clone'
+// @has 'foo/fn.f0.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'F: FnMut(u8) + Clone'
 pub fn f0(f: F) {}
 
-// @has 'foo/fn.f1.html' '//*[@class="rust fn"]' 'F: FnMut(u16) + Clone'
+// @has 'foo/fn.f1.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'F: FnMut(u16) + Clone'
 pub fn f1 () + Clone>(f: F) {}
 
-// @has 'foo/fn.f2.html' '//*[@class="rust fn"]' 'F: FnMut(u32) + Clone'
+// @has 'foo/fn.f2.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'F: FnMut(u32) + Clone'
 pub use unit_return::f2;
 
-// @has 'foo/fn.f3.html' '//*[@class="rust fn"]' 'F: FnMut(u64) + Clone'
+// @has 'foo/fn.f3.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'F: FnMut(u64) + Clone'
 pub use unit_return::f3;
diff --git a/tests/rustdoc/where-sized.rs b/tests/rustdoc/where-sized.rs
index fe7cad8c3ef84..c0c085e6ac725 100644
--- a/tests/rustdoc/where-sized.rs
+++ b/tests/rustdoc/where-sized.rs
@@ -1,6 +1,6 @@
 #![crate_name = "foo"]
 
 // @has foo/fn.foo.html
-// @has - '//*[@class="rust fn"]' 'pub fn foo(_: &X)'
-// @has - '//*[@class="rust fn"]' 'where X: ?Sized,'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub fn foo(_: &X)'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'where X: ?Sized,'
 pub fn foo(_: &X) where X: ?Sized {}
diff --git a/tests/rustdoc/where.SWhere_Simd_item-decl.html b/tests/rustdoc/where.SWhere_Simd_item-decl.html
index 6c1b5d3151352..f84cb3753cb93 100644
--- a/tests/rustdoc/where.SWhere_Simd_item-decl.html
+++ b/tests/rustdoc/where.SWhere_Simd_item-decl.html
@@ -1 +1 @@
-
\ No newline at end of file
+
pub struct Simd<T>(_)
where
    T: MyTrait
;
\ No newline at end of file diff --git a/tests/rustdoc/where.SWhere_TraitWhere_item-decl.html b/tests/rustdoc/where.SWhere_TraitWhere_item-decl.html index d5d6c556d8001..85b626674274c 100644 --- a/tests/rustdoc/where.SWhere_TraitWhere_item-decl.html +++ b/tests/rustdoc/where.SWhere_TraitWhere_item-decl.html @@ -1,4 +1,4 @@ -
pub trait TraitWhere {
+
pub trait TraitWhere {
     type Item<'a>
    where
        Self: 'a
; fn func(self)
    where
        Self: Sized
, diff --git a/tests/rustdoc/where.rs b/tests/rustdoc/where.rs index 8b5bce28f5a2a..3ac0c6872a821 100644 --- a/tests/rustdoc/where.rs +++ b/tests/rustdoc/where.rs @@ -57,6 +57,6 @@ pub enum Foxtrot { Foxtrot1(F) } // "impl MyTrait for Foxtrotwhere F: MyTrait" impl MyTrait for Foxtrotwhere F: MyTrait {} -// @has foo/type.Golf.html '//pre[@class="rust typedef"]' \ +// @has foo/type.Golf.html '//div[@class="item-decl"]/pre[@class="rust"]' \ // "type Golfwhere T: Clone, = (T, T)" pub type Golf where T: Clone = (T, T); diff --git a/tests/rustdoc/whitespace-after-where-clause.enum.html b/tests/rustdoc/whitespace-after-where-clause.enum.html index f7663e4616ae6..20bde549a0378 100644 --- a/tests/rustdoc/whitespace-after-where-clause.enum.html +++ b/tests/rustdoc/whitespace-after-where-clause.enum.html @@ -1,4 +1,4 @@ -
pub enum Cow<'a, B>where
    B: ToOwned<dyn Clone> + ?Sized + 'a,
{ +
pub enum Cow<'a, B>where
    B: ToOwned<dyn Clone> + ?Sized + 'a,
{ Borrowed(&'a B), Whatever(u32), }
\ No newline at end of file diff --git a/tests/rustdoc/whitespace-after-where-clause.enum2.html b/tests/rustdoc/whitespace-after-where-clause.enum2.html index ac7d775982110..d9fc0c22309db 100644 --- a/tests/rustdoc/whitespace-after-where-clause.enum2.html +++ b/tests/rustdoc/whitespace-after-where-clause.enum2.html @@ -1,4 +1,4 @@ -
pub enum Cow2<'a, B: ?Sized + ToOwned<dyn Clone> + 'a> {
+
pub enum Cow2<'a, B: ?Sized + ToOwned<dyn Clone> + 'a> {
     Borrowed(&'a B),
     Whatever(u32),
 }
\ No newline at end of file diff --git a/tests/rustdoc/whitespace-after-where-clause.struct.html b/tests/rustdoc/whitespace-after-where-clause.struct.html index fa3f224e7ad0f..f375265d7c183 100644 --- a/tests/rustdoc/whitespace-after-where-clause.struct.html +++ b/tests/rustdoc/whitespace-after-where-clause.struct.html @@ -1,4 +1,4 @@ -
pub struct Struct<'a, B>where
    B: ToOwned<dyn Clone> + ?Sized + 'a,
{ +
pub struct Struct<'a, B>where
    B: ToOwned<dyn Clone> + ?Sized + 'a,
{ pub a: &'a B, pub b: u32, }
\ No newline at end of file diff --git a/tests/rustdoc/whitespace-after-where-clause.struct2.html b/tests/rustdoc/whitespace-after-where-clause.struct2.html index fb06b0f77c5ce..1c59962eb1c58 100644 --- a/tests/rustdoc/whitespace-after-where-clause.struct2.html +++ b/tests/rustdoc/whitespace-after-where-clause.struct2.html @@ -1,4 +1,4 @@ -
pub struct Struct2<'a, B: ?Sized + ToOwned<dyn Clone> + 'a> {
+
pub struct Struct2<'a, B: ?Sized + ToOwned<dyn Clone> + 'a> {
     pub a: &'a B,
     pub b: u32,
 }
\ No newline at end of file diff --git a/tests/rustdoc/whitespace-after-where-clause.trait.html b/tests/rustdoc/whitespace-after-where-clause.trait.html index 50cfe362328b6..a2df06e7736af 100644 --- a/tests/rustdoc/whitespace-after-where-clause.trait.html +++ b/tests/rustdoc/whitespace-after-where-clause.trait.html @@ -1,4 +1,4 @@ -
pub trait ToOwned<T>where
    T: Clone,
{ +
pub trait ToOwned<T>where
    T: Clone,
{ type Owned; fn to_owned(&self) -> Self::Owned; diff --git a/tests/rustdoc/whitespace-after-where-clause.trait2.html b/tests/rustdoc/whitespace-after-where-clause.trait2.html index 21eb89b75011b..2bfd6f7685a67 100644 --- a/tests/rustdoc/whitespace-after-where-clause.trait2.html +++ b/tests/rustdoc/whitespace-after-where-clause.trait2.html @@ -1,4 +1,4 @@ -
pub trait ToOwned2<T: Clone> {
+
pub trait ToOwned2<T: Clone> {
     type Owned;
 
     fn to_owned(&self) -> Self::Owned;
diff --git a/tests/rustdoc/whitespace-after-where-clause.union.html b/tests/rustdoc/whitespace-after-where-clause.union.html
index 7bb177debc3a8..066f8f87b160b 100644
--- a/tests/rustdoc/whitespace-after-where-clause.union.html
+++ b/tests/rustdoc/whitespace-after-where-clause.union.html
@@ -1,3 +1,3 @@
-
pub union Union<'a, B>where
    B: ToOwned<dyn Clone> + ?Sized + 'a,
{ +
pub union Union<'a, B>where
    B: ToOwned<dyn Clone> + ?Sized + 'a,
{ /* private fields */ }
\ No newline at end of file diff --git a/tests/rustdoc/whitespace-after-where-clause.union2.html b/tests/rustdoc/whitespace-after-where-clause.union2.html index 0d237df53c7f4..6b48c5dbd3e28 100644 --- a/tests/rustdoc/whitespace-after-where-clause.union2.html +++ b/tests/rustdoc/whitespace-after-where-clause.union2.html @@ -1,3 +1,3 @@ -
pub union Union2<'a, B: ?Sized + ToOwned<dyn Clone> + 'a> {
+
pub union Union2<'a, B: ?Sized + ToOwned<dyn Clone> + 'a> {
     /* private fields */
 }
\ No newline at end of file diff --git a/tests/rustdoc/wrapping.rs b/tests/rustdoc/wrapping.rs index 8d8221bcdf293..178b8adc3f04a 100644 --- a/tests/rustdoc/wrapping.rs +++ b/tests/rustdoc/wrapping.rs @@ -1,5 +1,5 @@ use std::fmt::Debug; -// @has 'wrapping/fn.foo.html' '//pre[@class="rust fn"]' 'pub fn foo() -> impl Debug' -// @count - '//pre[@class="rust fn"]/br' 0 +// @has 'wrapping/fn.foo.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub fn foo() -> impl Debug' +// @count - '//div[@class="item-decl"]/pre[@class="rust"]/br' 0 pub fn foo() -> impl Debug {} From 59ba74cacb87ac89f7f5fcb5233eaccb50dd8349 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 16 Dec 2022 11:12:59 -0700 Subject: [PATCH 036/230] rustdoc: simplify JS search routine by not messing with lev distance Since the sorting function accounts for an `index` field, there's not much reason to also be applying changes to the levenshtein distance. Instead, we can just not treat `lev` as a filter if there's already a non-sentinel value for `index`. This change gives slightly more weight to the index and path part, as search criteria, than it used to. This changes some of the test cases, but not in any obviously-"worse" way, and, in particular, substring matches are a bigger deal than levenshtein distances (we're assuming that a typo is less likely than someone just not typing the entire name). Based on https://github.com/rust-lang/rust/pull/103710#issuecomment-1296894296 --- src/librustdoc/html/static/js/search.js | 114 +++++++++++++----------- 1 file changed, 64 insertions(+), 50 deletions(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 1b8822b0b2b7d..88592fa0c84c1 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -781,7 +781,29 @@ function initSearch(rawSearchIndex) { return a - b; } - // Sort by non levenshtein results and then levenshtein results by the distance + // sort by index of keyword in item name (no literal occurrence goes later) + a = (aaa.index < 0); + b = (bbb.index < 0); + if (a !== b) { + return a - b; + } + + // Sort by distance in the path part, if specified + // (less changes required to match means higher rankings) + a = aaa.path_lev; + b = bbb.path_lev; + if (a !== b) { + return a - b; + } + + // (later literal occurrence, if any, goes later) + a = aaa.index; + b = bbb.index; + if (a !== b) { + return a - b; + } + + // Sort by distance in the name part, the last part of the path // (less changes required to match means higher rankings) a = (aaa.lev); b = (bbb.lev); @@ -810,19 +832,6 @@ function initSearch(rawSearchIndex) { return (a > b ? +1 : -1); } - // sort by index of keyword in item name (no literal occurrence goes later) - a = (aaa.index < 0); - b = (bbb.index < 0); - if (a !== b) { - return a - b; - } - // (later literal occurrence, if any, goes later) - a = aaa.index; - b = bbb.index; - if (a !== b) { - return a - b; - } - // special precedence for primitive and keyword pages if ((aaa.item.ty === TY_PRIMITIVE && bbb.item.ty !== TY_KEYWORD) || (aaa.item.ty === TY_KEYWORD && bbb.item.ty !== TY_PRIMITIVE)) { @@ -1230,15 +1239,19 @@ function initSearch(rawSearchIndex) { * * `id` is the index in both `searchWords` and `searchIndex` arrays for this element. * * `index` is an `integer`` used to sort by the position of the word in the item's name. * * `lev` is the main metric used to sort the search results. + * * `path_lev` is zero if a single-component search query is used, otherwise it's the + * distance computed for everything other than the last path component. * * @param {Results} results * @param {string} fullId * @param {integer} id * @param {integer} index * @param {integer} lev + * @param {integer} path_lev */ - function addIntoResults(results, fullId, id, index, lev) { - if (lev === 0 || (!parsedQuery.literalSearch && lev <= MAX_LEV_DISTANCE)) { + function addIntoResults(results, fullId, id, index, lev, path_lev) { + const inBounds = lev <= MAX_LEV_DISTANCE || index !== -1; + if (lev === 0 || (!parsedQuery.literalSearch && inBounds)) { if (results[fullId] !== undefined) { const result = results[fullId]; if (result.dontValidate || result.lev <= lev) { @@ -1250,6 +1263,7 @@ function initSearch(rawSearchIndex) { index: index, dontValidate: parsedQuery.literalSearch, lev: lev, + path_lev: path_lev, }; } } @@ -1280,68 +1294,68 @@ function initSearch(rawSearchIndex) { if (!row || (filterCrates !== null && row.crate !== filterCrates)) { return; } - let lev, lev_add = 0, index = -1; + let lev, index = -1, path_lev = 0; const fullId = row.id; + const searchWord = searchWords[pos]; const in_args = findArg(row, elem, parsedQuery.typeFilter); const returned = checkReturned(row, elem, parsedQuery.typeFilter); - addIntoResults(results_in_args, fullId, pos, index, in_args); - addIntoResults(results_returned, fullId, pos, index, returned); + // path_lev is 0 because no parent path information is currently stored + // in the search index + addIntoResults(results_in_args, fullId, pos, -1, in_args, 0); + addIntoResults(results_returned, fullId, pos, -1, returned, 0); if (!typePassesFilter(parsedQuery.typeFilter, row.ty)) { return; } - const searchWord = searchWords[pos]; - if (parsedQuery.literalSearch) { - if (searchWord === elem.name) { - addIntoResults(results_others, fullId, pos, -1, 0); - } - return; + const row_index = row.normalizedName.indexOf(elem.pathLast); + const word_index = searchWord.indexOf(elem.pathLast); + + // lower indexes are "better" matches + // rank based on the "best" match + if (row_index === -1) { + index = word_index; + } else if (word_index === -1) { + index = row_index; + } else if (word_index < row_index) { + index = word_index; + } else { + index = row_index; } // No need to check anything else if it's a "pure" generics search. if (elem.name.length === 0) { if (row.type !== null) { lev = checkGenerics(row.type, elem, MAX_LEV_DISTANCE + 1); - addIntoResults(results_others, fullId, pos, index, lev); + // path_lev is 0 because we know it's empty + addIntoResults(results_others, fullId, pos, index, lev, 0); } return; } if (elem.fullPath.length > 1) { - lev = checkPath(elem.pathWithoutLast, row); - if (lev > MAX_LEV_DISTANCE || (parsedQuery.literalSearch && lev !== 0)) { + path_lev = checkPath(elem.pathWithoutLast, row); + if (path_lev > MAX_LEV_DISTANCE) { return; - } else if (lev > 0) { - lev_add = lev / 10; } } - if (searchWord.indexOf(elem.pathLast) > -1 || - row.normalizedName.indexOf(elem.pathLast) > -1 - ) { - index = row.normalizedName.indexOf(elem.pathLast); - } - lev = levenshtein(searchWord, elem.pathLast); - if (lev > 0 && elem.pathLast.length > 2 && searchWord.indexOf(elem.pathLast) > -1) { - if (elem.pathLast.length < 6) { - lev = 1; - } else { - lev = 0; + if (parsedQuery.literalSearch) { + if (searchWord === elem.name) { + addIntoResults(results_others, fullId, pos, index, 0, path_lev); } - } - lev += lev_add; - if (lev > MAX_LEV_DISTANCE) { return; - } else if (index !== -1 && elem.fullPath.length < 2) { - lev -= 1; } - if (lev < 0) { - lev = 0; + + lev = levenshtein(searchWord, elem.pathLast); + + if (index === -1 && lev + path_lev > MAX_LEV_DISTANCE) { + return; } - addIntoResults(results_others, fullId, pos, index, lev); + + addIntoResults(results_others, fullId, pos, index, lev, path_lev); } /** @@ -1386,7 +1400,7 @@ function initSearch(rawSearchIndex) { return; } const lev = Math.round(totalLev / nbLev); - addIntoResults(results, row.id, pos, 0, lev); + addIntoResults(results, row.id, pos, 0, lev, 0); } function innerRunQuery() { From db558b46861ee2f812ee1cc2b03b796f691a246d Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 16 Dec 2022 13:19:38 -0700 Subject: [PATCH 037/230] rustdoc: update search test cases --- tests/rustdoc-js-std/macro-print.js | 2 +- tests/rustdoc-js-std/typed-query.js | 2 +- tests/rustdoc-js-std/vec-new.js | 5 +++-- tests/rustdoc-js/search-short-types.js | 3 +-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/rustdoc-js-std/macro-print.js b/tests/rustdoc-js-std/macro-print.js index 858046e72e9a4..1b4c7b4057020 100644 --- a/tests/rustdoc-js-std/macro-print.js +++ b/tests/rustdoc-js-std/macro-print.js @@ -3,8 +3,8 @@ const QUERY = 'macro:print'; const EXPECTED = { 'others': [ { 'path': 'std', 'name': 'print' }, - { 'path': 'std', 'name': 'eprint' }, { 'path': 'std', 'name': 'println' }, + { 'path': 'std', 'name': 'eprint' }, { 'path': 'std', 'name': 'eprintln' }, ], }; diff --git a/tests/rustdoc-js-std/typed-query.js b/tests/rustdoc-js-std/typed-query.js index 25efbad269540..fd5c5489d79cf 100644 --- a/tests/rustdoc-js-std/typed-query.js +++ b/tests/rustdoc-js-std/typed-query.js @@ -6,8 +6,8 @@ const FILTER_CRATE = 'std'; const EXPECTED = { 'others': [ { 'path': 'std', 'name': 'print' }, - { 'path': 'std', 'name': 'eprint' }, { 'path': 'std', 'name': 'println' }, + { 'path': 'std', 'name': 'eprint' }, { 'path': 'std', 'name': 'eprintln' }, { 'path': 'std::pin', 'name': 'pin' }, { 'path': 'std::future', 'name': 'join' }, diff --git a/tests/rustdoc-js-std/vec-new.js b/tests/rustdoc-js-std/vec-new.js index cd0e8e7b4a9eb..fc44a566af21f 100644 --- a/tests/rustdoc-js-std/vec-new.js +++ b/tests/rustdoc-js-std/vec-new.js @@ -3,7 +3,8 @@ const QUERY = 'Vec::new'; const EXPECTED = { 'others': [ { 'path': 'std::vec::Vec', 'name': 'new' }, - { 'path': 'std::vec::Vec', 'name': 'ne' }, - { 'path': 'alloc::vec::Vec', 'name': 'ne' }, + { 'path': 'alloc::vec::Vec', 'name': 'new' }, + { 'path': 'std::vec::Vec', 'name': 'new_in' }, + { 'path': 'alloc::vec::Vec', 'name': 'new_in' }, ], }; diff --git a/tests/rustdoc-js/search-short-types.js b/tests/rustdoc-js/search-short-types.js index d14672af71fd6..3b2f15a40bf87 100644 --- a/tests/rustdoc-js/search-short-types.js +++ b/tests/rustdoc-js/search-short-types.js @@ -4,7 +4,6 @@ const EXPECTED = { 'others': [ { 'path': 'search_short_types', 'name': 'P' }, { 'path': 'search_short_types::VeryLongTypeName', 'name': 'p' }, - { 'path': 'search_short_types', 'name': 'Ap' }, - { 'path': 'search_short_types::VeryLongTypeName', 'name': 'ap' }, + { 'path': 'search_short_types', 'name': 'Pa' }, ], }; From 39edcfa84e7e715d6ac78f3dfdadfb1046d31b56 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 14 Jan 2023 11:02:14 -0800 Subject: [PATCH 038/230] Add more nbsp to unicode-chars test --- tests/ui/parser/unicode-chars.rs | 8 +++++- tests/ui/parser/unicode-chars.stderr | 39 +++++++++++++++++++++++++--- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/tests/ui/parser/unicode-chars.rs b/tests/ui/parser/unicode-chars.rs index ba35e95c82a49..b989205632155 100644 --- a/tests/ui/parser/unicode-chars.rs +++ b/tests/ui/parser/unicode-chars.rs @@ -2,8 +2,14 @@ fn main() { let y = 0; //~^ ERROR unknown start of token: \u{37e} //~^^ HELP Unicode character ';' (Greek Question Mark) looks like ';' (Semicolon), but it is not -     let x = 0; +     let x = 0; //~^ ERROR unknown start of token: \u{a0} //~^^ NOTE character appears 3 more times //~^^^ HELP Unicode character ' ' (No-Break Space) looks like ' ' (Space), but it is not + //~^^^^ ERROR unknown start of token: \u{a0} + //~^^^^^ HELP Unicode character ' ' (No-Break Space) looks like ' ' (Space), but it is not + //~^^^^^^ ERROR unknown start of token: \u{a0} + //~^^^^^^^ HELP Unicode character ' ' (No-Break Space) looks like ' ' (Space), but it is not + //~^^^^^^^^ ERROR unknown start of token: \u{a0} + //~^^^^^^^^^ HELP Unicode character ' ' (No-Break Space) looks like ' ' (Space), but it is not } diff --git a/tests/ui/parser/unicode-chars.stderr b/tests/ui/parser/unicode-chars.stderr index 6a5b27872e738..93ac5ec14be5b 100644 --- a/tests/ui/parser/unicode-chars.stderr +++ b/tests/ui/parser/unicode-chars.stderr @@ -12,14 +12,47 @@ LL | let y = 0; error: unknown start of token: \u{a0} --> $DIR/unicode-chars.rs:5:5 | -LL |     let x = 0; +LL |     let x = 0; | ^^^^ | = note: character appears 3 more times help: Unicode character ' ' (No-Break Space) looks like ' ' (Space), but it is not | -LL | let x = 0; +LL | let x = 0; | ++++ -error: aborting due to 2 previous errors +error: unknown start of token: \u{a0} + --> $DIR/unicode-chars.rs:5:12 + | +LL |     let x = 0; + | ^ + | +help: Unicode character ' ' (No-Break Space) looks like ' ' (Space), but it is not + | +LL |     let x = 0; + | + + +error: unknown start of token: \u{a0} + --> $DIR/unicode-chars.rs:5:14 + | +LL |     let x = 0; + | ^ + | +help: Unicode character ' ' (No-Break Space) looks like ' ' (Space), but it is not + | +LL |     let x = 0; + | + + +error: unknown start of token: \u{a0} + --> $DIR/unicode-chars.rs:5:16 + | +LL |     let x = 0; + | ^ + | +help: Unicode character ' ' (No-Break Space) looks like ' ' (Space), but it is not + | +LL |     let x = 0; + | + + +error: aborting due to 5 previous errors From dab06ccdab57d160de2e9afea752929ad39ee534 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 14 Jan 2023 10:34:06 -0800 Subject: [PATCH 039/230] Emit only one nbsp error per file --- compiler/rustc_parse/src/lexer/mod.rs | 31 ++++++++++++++++++++---- tests/ui/parser/unicode-chars.rs | 6 ----- tests/ui/parser/unicode-chars.stderr | 35 +-------------------------- 3 files changed, 27 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 8761c23625b21..9fe8d9836ba60 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -52,8 +52,15 @@ pub(crate) fn parse_token_trees<'a>( } let cursor = Cursor::new(src); - let string_reader = - StringReader { sess, start_pos, pos: start_pos, src, cursor, override_span }; + let string_reader = StringReader { + sess, + start_pos, + pos: start_pos, + src, + cursor, + override_span, + nbsp_is_whitespace: false, + }; tokentrees::TokenTreesReader::parse_all_token_trees(string_reader) } @@ -68,6 +75,10 @@ struct StringReader<'a> { /// Cursor for getting lexer tokens. cursor: Cursor<'a>, override_span: Option, + /// When a "unknown start of token: \u{a0}" has already been emitted earlier + /// in this file, it's safe to treat further occurrences of the non-breaking + /// space character as whitespace. + nbsp_is_whitespace: bool, } impl<'a> StringReader<'a> { @@ -239,6 +250,16 @@ impl<'a> StringReader<'a> { } let mut it = self.str_from_to_end(start).chars(); let c = it.next().unwrap(); + if c == '\u{00a0}' { + // If an error has already been reported on non-breaking + // space characters earlier in the file, treat all + // subsequent occurrences as whitespace. + if self.nbsp_is_whitespace { + preceded_by_whitespace = true; + continue; + } + self.nbsp_is_whitespace = true; + } let repeats = it.take_while(|c1| *c1 == c).count(); let mut err = self.struct_err_span_char(start, self.pos + Pos::from_usize(repeats * c.len_utf8()), "unknown start of token", c); @@ -486,7 +507,7 @@ impl<'a> StringReader<'a> { /// Slice of the source text from `start` up to but excluding `self.pos`, /// meaning the slice does not include the character `self.ch`. - fn str_from(&self, start: BytePos) -> &str { + fn str_from(&self, start: BytePos) -> &'a str { self.str_from_to(start, self.pos) } @@ -497,12 +518,12 @@ impl<'a> StringReader<'a> { } /// Slice of the source text spanning from `start` up to but excluding `end`. - fn str_from_to(&self, start: BytePos, end: BytePos) -> &str { + fn str_from_to(&self, start: BytePos, end: BytePos) -> &'a str { &self.src[self.src_index(start)..self.src_index(end)] } /// Slice of the source text spanning from `start` until the end - fn str_from_to_end(&self, start: BytePos) -> &str { + fn str_from_to_end(&self, start: BytePos) -> &'a str { &self.src[self.src_index(start)..] } diff --git a/tests/ui/parser/unicode-chars.rs b/tests/ui/parser/unicode-chars.rs index b989205632155..f0122561f463d 100644 --- a/tests/ui/parser/unicode-chars.rs +++ b/tests/ui/parser/unicode-chars.rs @@ -6,10 +6,4 @@ fn main() { //~^ ERROR unknown start of token: \u{a0} //~^^ NOTE character appears 3 more times //~^^^ HELP Unicode character ' ' (No-Break Space) looks like ' ' (Space), but it is not - //~^^^^ ERROR unknown start of token: \u{a0} - //~^^^^^ HELP Unicode character ' ' (No-Break Space) looks like ' ' (Space), but it is not - //~^^^^^^ ERROR unknown start of token: \u{a0} - //~^^^^^^^ HELP Unicode character ' ' (No-Break Space) looks like ' ' (Space), but it is not - //~^^^^^^^^ ERROR unknown start of token: \u{a0} - //~^^^^^^^^^ HELP Unicode character ' ' (No-Break Space) looks like ' ' (Space), but it is not } diff --git a/tests/ui/parser/unicode-chars.stderr b/tests/ui/parser/unicode-chars.stderr index 93ac5ec14be5b..b1d4a0af71154 100644 --- a/tests/ui/parser/unicode-chars.stderr +++ b/tests/ui/parser/unicode-chars.stderr @@ -21,38 +21,5 @@ help: Unicode character ' ' (No-Break Space) looks like ' ' (Space), but it is LL | let x = 0; | ++++ -error: unknown start of token: \u{a0} - --> $DIR/unicode-chars.rs:5:12 - | -LL |     let x = 0; - | ^ - | -help: Unicode character ' ' (No-Break Space) looks like ' ' (Space), but it is not - | -LL |     let x = 0; - | + - -error: unknown start of token: \u{a0} - --> $DIR/unicode-chars.rs:5:14 - | -LL |     let x = 0; - | ^ - | -help: Unicode character ' ' (No-Break Space) looks like ' ' (Space), but it is not - | -LL |     let x = 0; - | + - -error: unknown start of token: \u{a0} - --> $DIR/unicode-chars.rs:5:16 - | -LL |     let x = 0; - | ^ - | -help: Unicode character ' ' (No-Break Space) looks like ' ' (Space), but it is not - | -LL |     let x = 0; - | + - -error: aborting due to 5 previous errors +error: aborting due to 2 previous errors From e590b934998c85175b85cb13842163a27a221dc7 Mon Sep 17 00:00:00 2001 From: Ezra Shaw Date: Sat, 14 Jan 2023 21:20:20 +1300 Subject: [PATCH 040/230] make error emitted on `impl &Trait` nicer --- compiler/rustc_ast/src/ast.rs | 3 +- compiler/rustc_parse/src/parser/ty.rs | 39 +++++++++-- tests/ui/generics/issue-106694.rs | 24 +++++++ tests/ui/generics/issue-106694.stderr | 93 +++++++++++++++++++++++++++ 4 files changed, 154 insertions(+), 5 deletions(-) create mode 100644 tests/ui/generics/issue-106694.rs create mode 100644 tests/ui/generics/issue-106694.stderr diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 7de594719ddc4..9317579f70dd5 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2032,7 +2032,8 @@ impl Clone for Ty { impl Ty { pub fn peel_refs(&self) -> &Self { let mut final_ty = self; - while let TyKind::Ref(_, MutTy { ty, .. }) = &final_ty.kind { + while let TyKind::Ref(_, MutTy { ty, .. }) | TyKind::Ptr(MutTy { ty, .. }) = &final_ty.kind + { final_ty = ty; } final_ty diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index a6f702e542869..aedebd0fb7062 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -727,11 +727,13 @@ impl<'a> Parser<'a> { let mut bounds = Vec::new(); let mut negative_bounds = Vec::new(); + // In addition to looping while we find generic bounds: + // We continue even if we find a keyword. This is necessary for error recovery on, + // for example, `impl fn()`. The only keyword that can go after generic bounds is + // `where`, so stop if it's it. + // We also continue if we find types (not traits), again for error recovery. while self.can_begin_bound() - // Continue even if we find a keyword. - // This is necessary for error recover on, for example, `impl fn()`. - // - // The only keyword that can go after generic bounds is `where`, so stop if it's it. + || self.token.can_begin_type() || (self.token.is_reserved_ident() && !self.token.is_keyword(kw::Where)) { if self.token.is_keyword(kw::Dyn) { @@ -938,6 +940,35 @@ impl<'a> Parser<'a> { && self.look_ahead(1, |tok| tok.kind == TokenKind::OpenDelim(Delimiter::Parenthesis)) && let Some(path) = self.recover_path_from_fn() { + path + } else if !self.token.is_path_start() && self.token.can_begin_type() && let Ok(ty) = self.parse_ty_no_plus() { + // Instead of finding a path (a trait), we found a type. + let mut err = self.struct_span_err(ty.span, "expected a trait, found type"); + + // If we can recover, try to extract a path from the type. Note + // that we do not use the try operator when parsing the type because + // if it fails then we get a parser error which we don't want (we're trying + // to recover from errors, not make more). + let path = if self.may_recover() + && matches!(ty.kind, TyKind::Ptr(..) | TyKind::Ref(..)) + && let TyKind::Path(_, path) = &ty.peel_refs().kind { + // Just get the indirection part of the type. + let span = ty.span.until(path.span); + + err.span_suggestion_verbose( + span, + "consider removing the indirection", + "", + Applicability::MaybeIncorrect, + ); + + path.clone() + } else { + return Err(err); + }; + + err.emit(); + path } else { self.parse_path(PathStyle::Type)? diff --git a/tests/ui/generics/issue-106694.rs b/tests/ui/generics/issue-106694.rs new file mode 100644 index 0000000000000..c4b02ee81ec8f --- /dev/null +++ b/tests/ui/generics/issue-106694.rs @@ -0,0 +1,24 @@ +trait Trait {} + +fn foo(_: impl &Trait) {} +//~^ ERROR expected a trait, found type + +fn bar(_: T) {} +//~^ ERROR expected a trait, found type + +fn partially_correct_impl(_: impl &*const &Trait + Copy) {} +//~^ ERROR expected a trait, found type + +fn foo_bad(_: impl &BadTrait) {} +//~^ ERROR expected a trait, found type +//~^^ ERROR cannot find trait `BadTrait` in this scope + +fn bar_bad(_: T) {} +//~^ ERROR expected a trait, found type +//~^^ ERROR cannot find trait `BadTrait` in this scope + +fn partially_correct_impl_bad(_: impl &*const &BadTrait + Copy) {} +//~^ ERROR expected a trait, found type +//~^^ ERROR cannot find trait `BadTrait` in this scope + +fn main() {} diff --git a/tests/ui/generics/issue-106694.stderr b/tests/ui/generics/issue-106694.stderr new file mode 100644 index 0000000000000..235b8982a99c6 --- /dev/null +++ b/tests/ui/generics/issue-106694.stderr @@ -0,0 +1,93 @@ +error: expected a trait, found type + --> $DIR/issue-106694.rs:3:16 + | +LL | fn foo(_: impl &Trait) {} + | ^^^^^^ + | +help: consider removing the indirection + | +LL - fn foo(_: impl &Trait) {} +LL + fn foo(_: impl Trait) {} + | + +error: expected a trait, found type + --> $DIR/issue-106694.rs:6:11 + | +LL | fn bar(_: T) {} + | ^^^^^^ + | +help: consider removing the indirection + | +LL - fn bar(_: T) {} +LL + fn bar(_: T) {} + | + +error: expected a trait, found type + --> $DIR/issue-106694.rs:9:35 + | +LL | fn partially_correct_impl(_: impl &*const &Trait + Copy) {} + | ^^^^^^^^^^^^^^ + | +help: consider removing the indirection + | +LL - fn partially_correct_impl(_: impl &*const &Trait + Copy) {} +LL + fn partially_correct_impl(_: impl Trait + Copy) {} + | + +error: expected a trait, found type + --> $DIR/issue-106694.rs:12:20 + | +LL | fn foo_bad(_: impl &BadTrait) {} + | ^^^^^^^^^ + | +help: consider removing the indirection + | +LL - fn foo_bad(_: impl &BadTrait) {} +LL + fn foo_bad(_: impl BadTrait) {} + | + +error: expected a trait, found type + --> $DIR/issue-106694.rs:16:15 + | +LL | fn bar_bad(_: T) {} + | ^^^^^^^^^ + | +help: consider removing the indirection + | +LL - fn bar_bad(_: T) {} +LL + fn bar_bad(_: T) {} + | + +error: expected a trait, found type + --> $DIR/issue-106694.rs:20:39 + | +LL | fn partially_correct_impl_bad(_: impl &*const &BadTrait + Copy) {} + | ^^^^^^^^^^^^^^^^^ + | +help: consider removing the indirection + | +LL - fn partially_correct_impl_bad(_: impl &*const &BadTrait + Copy) {} +LL + fn partially_correct_impl_bad(_: impl BadTrait + Copy) {} + | + +error[E0405]: cannot find trait `BadTrait` in this scope + --> $DIR/issue-106694.rs:12:21 + | +LL | fn foo_bad(_: impl &BadTrait) {} + | ^^^^^^^^ not found in this scope + +error[E0405]: cannot find trait `BadTrait` in this scope + --> $DIR/issue-106694.rs:16:16 + | +LL | fn bar_bad(_: T) {} + | ^^^^^^^^ not found in this scope + +error[E0405]: cannot find trait `BadTrait` in this scope + --> $DIR/issue-106694.rs:20:48 + | +LL | fn partially_correct_impl_bad(_: impl &*const &BadTrait + Copy) {} + | ^^^^^^^^ not found in this scope + +error: aborting due to 9 previous errors + +For more information about this error, try `rustc --explain E0405`. From 38917ee9e91452aca1f433e47931ee35bb0283f4 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 14 Jan 2023 15:31:32 -0800 Subject: [PATCH 041/230] Mention the lack of `windows_mut` in `windows` --- library/core/src/slice/mod.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 2995cf0c6443f..340c6745853df 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -781,6 +781,22 @@ impl [T] { /// let mut iter = slice.windows(4); /// assert!(iter.next().is_none()); /// ``` + /// + /// There's no `windows_mut`, as that existing would let safe code violate the + /// "only one `&mut` at a time to the same thing" rule. However, you can sometimes + /// use [`Cell::as_slice_of_cells`](crate::cell::Cell::as_slice_of_cells) in + /// conjunction with `windows` to accomplish something similar: + /// ``` + /// use std::cell::Cell; + /// + /// let mut array = ['R', 'u', 's', 't', ' ', '2', '0', '1', '5']; + /// let slice = &mut array[..]; + /// let slice_of_cells: &[Cell] = Cell::from_mut(slice).as_slice_of_cells(); + /// for w in slice_of_cells.windows(3) { + /// Cell::swap(&w[0], &w[2]); + /// } + /// assert_eq!(array, ['s', 't', ' ', '2', '0', '1', '5', 'u', 'R']); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn windows(&self, size: usize) -> Windows<'_, T> { From 295f5483fee168b385b03db03dfa9986f05ea706 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Sun, 15 Jan 2023 05:06:33 +0000 Subject: [PATCH 042/230] Fix regression in `unused_braces` with macros --- compiler/rustc_lint/src/unused.rs | 12 ++++++++---- tests/ui/lint/unused_braces.fixed | 4 ++++ tests/ui/lint/unused_braces.rs | 4 ++++ tests/ui/lint/unused_braces.stderr | 14 +++++++++++++- 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index f2ee9ab1a1987..36791915964df 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -1095,17 +1095,21 @@ impl UnusedDelimLint for UnusedBraces { // ``` // - the block has no attribute and was not created inside a macro // - if the block is an `anon_const`, the inner expr must be a literal - // (do not lint `struct A; let _: A<{ 2 + 3 }>;`) - // + // not created by a macro, i.e. do not lint on: + // ``` + // struct A; + // let _: A<{ 2 + 3 }>; + // let _: A<{produces_literal!()}>; + // ``` // FIXME(const_generics): handle paths when #67075 is fixed. if let [stmt] = inner.stmts.as_slice() { if let ast::StmtKind::Expr(ref expr) = stmt.kind { if !Self::is_expr_delims_necessary(expr, followed_by_block, false) && (ctx != UnusedDelimsCtx::AnonConst - || matches!(expr.kind, ast::ExprKind::Lit(_))) + || (matches!(expr.kind, ast::ExprKind::Lit(_)) + && !expr.span.from_expansion())) && !cx.sess().source_map().is_multiline(value.span) && value.attrs.is_empty() - && !expr.span.from_expansion() && !value.span.from_expansion() && !inner.span.from_expansion() { diff --git a/tests/ui/lint/unused_braces.fixed b/tests/ui/lint/unused_braces.fixed index 1a88d985dd86a..e691fb37e6c43 100644 --- a/tests/ui/lint/unused_braces.fixed +++ b/tests/ui/lint/unused_braces.fixed @@ -50,4 +50,8 @@ fn main() { if { return } { } + + // regression test for https://github.com/rust-lang/rust/issues/106899 + return println!("!"); + //~^ WARN unnecessary braces } diff --git a/tests/ui/lint/unused_braces.rs b/tests/ui/lint/unused_braces.rs index 5ca4811fc32d8..0d260d2cbc93f 100644 --- a/tests/ui/lint/unused_braces.rs +++ b/tests/ui/lint/unused_braces.rs @@ -50,4 +50,8 @@ fn main() { if { return } { } + + // regression test for https://github.com/rust-lang/rust/issues/106899 + return { println!("!") }; + //~^ WARN unnecessary braces } diff --git a/tests/ui/lint/unused_braces.stderr b/tests/ui/lint/unused_braces.stderr index 7773f44ea2d38..0b4a1c321805d 100644 --- a/tests/ui/lint/unused_braces.stderr +++ b/tests/ui/lint/unused_braces.stderr @@ -68,5 +68,17 @@ LL - consume({ 7 }); LL + consume(7); | -warning: 5 warnings emitted +warning: unnecessary braces around `return` value + --> $DIR/unused_braces.rs:55:12 + | +LL | return { println!("!") }; + | ^^ ^^ + | +help: remove these braces + | +LL - return { println!("!") }; +LL + return println!("!"); + | + +warning: 6 warnings emitted From 92ced4a12e60811b67ed98c79c77c151581b7e07 Mon Sep 17 00:00:00 2001 From: Ezra Shaw Date: Sun, 15 Jan 2023 15:51:52 +1300 Subject: [PATCH 043/230] suggest `is_empty` for collections when casting to `bool` --- compiler/rustc_hir_typeck/src/cast.rs | 46 ++++++++++++++++- tests/ui/cast/cast-as-bool.rs | 6 ++- tests/ui/cast/cast-as-bool.stderr | 9 +++- tests/ui/cast/issue-106883-is-empty.rs | 27 ++++++++++ tests/ui/cast/issue-106883-is-empty.stderr | 58 ++++++++++++++++++++++ 5 files changed, 142 insertions(+), 4 deletions(-) create mode 100644 tests/ui/cast/issue-106883-is-empty.rs create mode 100644 tests/ui/cast/issue-106883-is-empty.stderr diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 042a50f2fd42e..0a230fca107af 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -31,7 +31,9 @@ use super::FnCtxt; use crate::type_error_struct; -use rustc_errors::{struct_span_err, Applicability, DelayDm, DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::{ + struct_span_err, Applicability, DelayDm, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, +}; use rustc_hir as hir; use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::mir::Mutability; @@ -270,6 +272,9 @@ impl<'a, 'tcx> CastCheck<'tcx> { } )); } + + self.try_suggest_collection_to_bool(fcx, &mut err); + err.emit(); } CastError::NeedViaInt => { @@ -517,6 +522,9 @@ impl<'a, 'tcx> CastCheck<'tcx> { } else { err.span_label(self.span, "invalid cast"); } + + self.try_suggest_collection_to_bool(fcx, &mut err); + err.emit(); } CastError::SizedUnsizedCast => { @@ -1080,4 +1088,40 @@ impl<'a, 'tcx> CastCheck<'tcx> { }, ); } + + /// Attempt to suggest using `.is_empty` when trying to cast from a + /// collection type to a boolean. + fn try_suggest_collection_to_bool(&self, fcx: &FnCtxt<'a, 'tcx>, err: &mut Diagnostic) { + if self.cast_ty.is_bool() { + let derefed = fcx + .autoderef(self.expr_span, self.expr_ty) + .silence_errors() + .find(|t| matches!(t.0.kind(), ty::Str | ty::Slice(..))); + + if let Some((deref_ty, _)) = derefed { + // Give a note about what the expr derefs to. + if deref_ty != self.expr_ty.peel_refs() { + err.span_note( + self.expr_span, + format!( + "this expression `Deref`s to `{}` which implements `is_empty`", + fcx.ty_to_string(deref_ty) + ), + ); + } + + // Create a multipart suggestion: add `!` and `.is_empty()` in + // place of the cast. + let suggestion = vec![ + (self.expr_span.shrink_to_lo(), "!".to_string()), + (self.span.with_lo(self.expr_span.hi()), ".is_empty()".to_string()), + ]; + + err.multipart_suggestion_verbose(format!( + "consider using the `is_empty` method on `{}` to determine if it contains anything", + fcx.ty_to_string(self.expr_ty), + ), suggestion, Applicability::MaybeIncorrect); + } + } + } } diff --git a/tests/ui/cast/cast-as-bool.rs b/tests/ui/cast/cast-as-bool.rs index 1aed218aeb473..fbebc80d91ced 100644 --- a/tests/ui/cast/cast-as-bool.rs +++ b/tests/ui/cast/cast-as-bool.rs @@ -2,8 +2,12 @@ fn main() { let u = 5 as bool; //~ ERROR cannot cast as `bool` //~| HELP compare with zero instead //~| SUGGESTION 5 != 0 + let t = (1 + 2) as bool; //~ ERROR cannot cast as `bool` //~| HELP compare with zero instead //~| SUGGESTION (1 + 2) != 0 - let v = "hello" as bool; //~ ERROR casting `&'static str` as `bool` is invalid + + let v = "hello" as bool; + //~^ ERROR casting `&'static str` as `bool` is invalid + //~| HELP consider using the `is_empty` method on `&'static str` to determine if it contains anything } diff --git a/tests/ui/cast/cast-as-bool.stderr b/tests/ui/cast/cast-as-bool.stderr index 15d94ab69d88c..19ac8f10fec21 100644 --- a/tests/ui/cast/cast-as-bool.stderr +++ b/tests/ui/cast/cast-as-bool.stderr @@ -5,16 +5,21 @@ LL | let u = 5 as bool; | ^^^^^^^^^ help: compare with zero instead: `5 != 0` error[E0054]: cannot cast as `bool` - --> $DIR/cast-as-bool.rs:5:13 + --> $DIR/cast-as-bool.rs:6:13 | LL | let t = (1 + 2) as bool; | ^^^^^^^^^^^^^^^ help: compare with zero instead: `(1 + 2) != 0` error[E0606]: casting `&'static str` as `bool` is invalid - --> $DIR/cast-as-bool.rs:8:13 + --> $DIR/cast-as-bool.rs:10:13 | LL | let v = "hello" as bool; | ^^^^^^^^^^^^^^^ + | +help: consider using the `is_empty` method on `&'static str` to determine if it contains anything + | +LL | let v = !"hello".is_empty(); + | + ~~~~~~~~~~~ error: aborting due to 3 previous errors diff --git a/tests/ui/cast/issue-106883-is-empty.rs b/tests/ui/cast/issue-106883-is-empty.rs new file mode 100644 index 0000000000000..27e0816dd1c6a --- /dev/null +++ b/tests/ui/cast/issue-106883-is-empty.rs @@ -0,0 +1,27 @@ +use std::ops::Deref; + +struct Foo; + +impl Deref for Foo { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + &[] + } +} + +fn main() { + let _ = "foo" as bool; + //~^ ERROR casting `&'static str` as `bool` is invalid [E0606] + + let _ = String::from("foo") as bool; + //~^ ERROR non-primitive cast: `String` as `bool` [E0605] + + let _ = Foo as bool; + //~^ ERROR non-primitive cast: `Foo` as `bool` [E0605] +} + +fn _slice(bar: &[i32]) -> bool { + bar as bool + //~^ ERROR casting `&[i32]` as `bool` is invalid [E0606] +} diff --git a/tests/ui/cast/issue-106883-is-empty.stderr b/tests/ui/cast/issue-106883-is-empty.stderr new file mode 100644 index 0000000000000..7115c7704ca29 --- /dev/null +++ b/tests/ui/cast/issue-106883-is-empty.stderr @@ -0,0 +1,58 @@ +error[E0606]: casting `&'static str` as `bool` is invalid + --> $DIR/issue-106883-is-empty.rs:14:13 + | +LL | let _ = "foo" as bool; + | ^^^^^^^^^^^^^ + | +help: consider using the `is_empty` method on `&'static str` to determine if it contains anything + | +LL | let _ = !"foo".is_empty(); + | + ~~~~~~~~~~~ + +error[E0605]: non-primitive cast: `String` as `bool` + --> $DIR/issue-106883-is-empty.rs:17:13 + | +LL | let _ = String::from("foo") as bool; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object + | +note: this expression `Deref`s to `str` which implements `is_empty` + --> $DIR/issue-106883-is-empty.rs:17:13 + | +LL | let _ = String::from("foo") as bool; + | ^^^^^^^^^^^^^^^^^^^ +help: consider using the `is_empty` method on `String` to determine if it contains anything + | +LL | let _ = !String::from("foo").is_empty(); + | + ~~~~~~~~~~~ + +error[E0605]: non-primitive cast: `Foo` as `bool` + --> $DIR/issue-106883-is-empty.rs:20:13 + | +LL | let _ = Foo as bool; + | ^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object + | +note: this expression `Deref`s to `[u8]` which implements `is_empty` + --> $DIR/issue-106883-is-empty.rs:20:13 + | +LL | let _ = Foo as bool; + | ^^^ +help: consider using the `is_empty` method on `Foo` to determine if it contains anything + | +LL | let _ = !Foo.is_empty(); + | + ~~~~~~~~~~~ + +error[E0606]: casting `&[i32]` as `bool` is invalid + --> $DIR/issue-106883-is-empty.rs:25:5 + | +LL | bar as bool + | ^^^^^^^^^^^ + | +help: consider using the `is_empty` method on `&[i32]` to determine if it contains anything + | +LL | !bar.is_empty() + | + ~~~~~~~~~~~ + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0605, E0606. +For more information about an error, try `rustc --explain E0605`. From 98cfa68f16cb07a3c4bc18daeb071c53904a487f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 14 Jan 2023 22:17:06 +0100 Subject: [PATCH 044/230] Add tidy check to ensure that rustdoc GUI tests start with a small description --- src/tools/tidy/src/lib.rs | 1 + src/tools/tidy/src/main.rs | 1 + src/tools/tidy/src/rustdoc_gui_tests.rs | 33 +++++++++++++++++++++++++ 3 files changed, 35 insertions(+) create mode 100644 src/tools/tidy/src/rustdoc_gui_tests.rs diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 40375f1306d62..97e56720b9852 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -62,6 +62,7 @@ pub mod features; pub mod mir_opt_tests; pub mod pal; pub mod primitive_docs; +pub mod rustdoc_gui_tests; pub mod style; pub mod target_specific_tests; pub mod tests_placement; diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index ea2886a3c2f8f..0b9a1b37e947e 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -80,6 +80,7 @@ fn main() { check!(debug_artifacts, &tests_path); check!(ui_tests, &tests_path); check!(mir_opt_tests, &tests_path, bless); + check!(rustdoc_gui_tests, &tests_path); // Checks that only make sense for the compiler. check!(error_codes, &root_path, &[&compiler_path, &librustdoc_path], verbose); diff --git a/src/tools/tidy/src/rustdoc_gui_tests.rs b/src/tools/tidy/src/rustdoc_gui_tests.rs new file mode 100644 index 0000000000000..feb513df34bf7 --- /dev/null +++ b/src/tools/tidy/src/rustdoc_gui_tests.rs @@ -0,0 +1,33 @@ +//! Tidy check to ensure that rustdoc GUI tests start with a small description. + +use std::path::Path; + +pub fn check(path: &Path, bad: &mut bool) { + crate::walk::walk( + &path.join("rustdoc-gui"), + &mut |p| { + // If there is no extension, it's very likely a folder and we want to go into it. + p.extension().map(|e| e != "goml").unwrap_or(false) + }, + &mut |entry, content| { + for line in content.lines() { + if !line.starts_with("// ") { + tidy_error!( + bad, + "{}: rustdoc-gui tests must start with a small description", + entry.path().display(), + ); + return; + } else if line.starts_with("// ") { + let parts = line[2..].trim(); + // We ignore tidy comments. + if parts.starts_with("// tidy-") { + continue; + } + // All good! + return; + } + } + }, + ); +} From 5376670323d14870be7d90b585735354674aa4cc Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 14 Jan 2023 22:18:56 +0100 Subject: [PATCH 045/230] Add small description to GUI test --- tests/rustdoc-gui/basic-code.goml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/rustdoc-gui/basic-code.goml b/tests/rustdoc-gui/basic-code.goml index 108cf8abcb529..971c2f9480ea2 100644 --- a/tests/rustdoc-gui/basic-code.goml +++ b/tests/rustdoc-gui/basic-code.goml @@ -1,3 +1,5 @@ +// Small test to ensure the "src-line-numbers" element is only present once on +// the page. goto: "file://" + |DOC_PATH| + "/test_docs/index.html" click: ".srclink" wait-for: ".src-line-numbers" From 665d4ea98df9b350cc459816337c9fc839bdf128 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sun, 15 Jan 2023 15:02:02 +0100 Subject: [PATCH 046/230] remove redundant clones --- compiler/rustc_lint/src/internal.rs | 4 ++-- compiler/rustc_lint/src/pass_by_value.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 5eb54cc003427..6cefaea2bc7da 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -187,9 +187,9 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { }, None => cx.emit_spanned_lint(USAGE_OF_TY_TYKIND, path.span, TykindDiag), } - } else if !ty.span.from_expansion() && path.segments.len() > 1 && let Some(t) = is_ty_or_ty_ctxt(cx, &path) { + } else if !ty.span.from_expansion() && path.segments.len() > 1 && let Some(ty) = is_ty_or_ty_ctxt(cx, &path) { cx.emit_spanned_lint(USAGE_OF_QUALIFIED_TY, path.span, TyQualified { - ty: t.clone(), + ty, suggestion: path.span, }); } diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs index 57482a9edba88..392e13f2fa941 100644 --- a/compiler/rustc_lint/src/pass_by_value.rs +++ b/compiler/rustc_lint/src/pass_by_value.rs @@ -32,7 +32,7 @@ impl<'tcx> LateLintPass<'tcx> for PassByValue { cx.emit_spanned_lint( PASS_BY_VALUE, ty.span, - PassByValueDiag { ty: t.clone(), suggestion: ty.span }, + PassByValueDiag { ty: t, suggestion: ty.span }, ); } } From fdd6af14a1006c196c5859904f2096ee4e32de85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sun, 15 Jan 2023 15:23:30 +0100 Subject: [PATCH 047/230] rustdoc: simplify some & ref erences --- src/librustdoc/clean/auto_trait.rs | 16 +++++++--------- src/librustdoc/clean/simplify.rs | 2 +- src/librustdoc/formats/cache.rs | 2 +- src/librustdoc/html/format.rs | 2 +- src/librustdoc/html/render/search_index.rs | 4 ++-- 5 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 4d6f1524732f7..a302750aa1aea 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -402,15 +402,13 @@ where bound_params: Vec::new(), }) }) - .chain( - lifetime_to_bounds.into_iter().filter(|&(_, ref bounds)| !bounds.is_empty()).map( - |(lifetime, bounds)| { - let mut bounds_vec = bounds.into_iter().collect(); - self.sort_where_bounds(&mut bounds_vec); - WherePredicate::RegionPredicate { lifetime, bounds: bounds_vec } - }, - ), - ) + .chain(lifetime_to_bounds.into_iter().filter(|(_, bounds)| !bounds.is_empty()).map( + |(lifetime, bounds)| { + let mut bounds_vec = bounds.into_iter().collect(); + self.sort_where_bounds(&mut bounds_vec); + WherePredicate::RegionPredicate { lifetime, bounds: bounds_vec } + }, + )) .collect() } diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index e96a9bab72620..dbbc25739aa07 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -46,7 +46,7 @@ pub(crate) fn where_clauses(cx: &DocContext<'_>, clauses: Vec) -> ThinVec DocFolder for CacheBuilder<'a, 'tcx> { // for where the type was defined. On the other // hand, `paths` always has the right // information if present. - Some(&(ref fqp, _)) => Some(&fqp[..fqp.len() - 1]), + Some((fqp, _)) => Some(&fqp[..fqp.len() - 1]), None => None, }; ((did, path), true) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 006076baf7257..d3dc4065dfc72 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -962,7 +962,7 @@ fn fmt_type<'cx>( clean::Tuple(ref typs) => { match &typs[..] { &[] => primitive_link(f, PrimitiveType::Unit, "()", cx), - &[ref one] => { + [one] => { if let clean::Generic(name) = one { primitive_link(f, PrimitiveType::Tuple, &format!("({name},)"), cx) } else { diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index c64349f413cee..5b0caac099bc3 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -29,7 +29,7 @@ pub(crate) fn build_index<'tcx>( // Attach all orphan items to the type's definition if the type // has since been learned. for &OrphanImplItem { parent, ref item, ref impl_generics } in &cache.orphan_impl_items { - if let Some(&(ref fqp, _)) = cache.paths.get(&parent) { + if let Some((fqp, _)) = cache.paths.get(&parent) { let desc = item .doc_value() .map_or_else(String::new, |s| short_markdown_summary(&s, &item.link_names(cache))); @@ -573,7 +573,7 @@ fn get_fn_inputs_and_outputs<'tcx>( let decl = &func.decl; let combined_generics; - let (self_, generics) = if let Some(&(ref impl_self, ref impl_generics)) = impl_generics { + let (self_, generics) = if let Some((impl_self, impl_generics)) = impl_generics { match (impl_generics.is_empty(), func.generics.is_empty()) { (true, _) => (Some(impl_self), &func.generics), (_, true) => (Some(impl_self), impl_generics), From 91fd862df011168e7634f79fc2f2c9fb15a7afd3 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 3 Jan 2023 02:49:31 +0000 Subject: [PATCH 048/230] instantiate_own doesn't need to return a pair of vectors --- .../src/check/compare_impl_item.rs | 25 ++++++++++--------- compiler/rustc_middle/src/ty/generics.rs | 12 +++------ compiler/rustc_middle/src/ty/subst.rs | 15 +++++++++++ .../src/traits/project.rs | 4 +-- .../src/traits/select/confirmation.rs | 5 ++-- .../src/traits/vtable.rs | 5 +++- 6 files changed, 39 insertions(+), 27 deletions(-) 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 770d7b6f927e4..c43bfd16ab1e4 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -209,9 +209,11 @@ fn compare_method_predicate_entailment<'tcx>( // // We then register the obligations from the impl_m and check to see // if all constraints hold. - hybrid_preds - .predicates - .extend(trait_m_predicates.instantiate_own(tcx, trait_to_placeholder_substs).predicates); + hybrid_preds.predicates.extend( + trait_m_predicates + .instantiate_own(tcx, trait_to_placeholder_substs) + .map(|(predicate, _)| predicate), + ); // Construct trait parameter environment and then shift it into the placeholder viewpoint. // The key step here is to update the caller_bounds's predicates to be @@ -230,7 +232,7 @@ fn compare_method_predicate_entailment<'tcx>( debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds()); let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_substs); - for (predicate, span) in iter::zip(impl_m_own_bounds.predicates, impl_m_own_bounds.spans) { + for (predicate, span) in impl_m_own_bounds { let normalize_cause = traits::ObligationCause::misc(span, impl_m_hir_id); let predicate = ocx.normalize(&normalize_cause, param_env, predicate); @@ -1828,8 +1830,7 @@ fn compare_type_predicate_entailment<'tcx>( check_region_bounds_on_impl_item(tcx, impl_ty, trait_ty, false)?; let impl_ty_own_bounds = impl_ty_predicates.instantiate_own(tcx, impl_substs); - - if impl_ty_own_bounds.is_empty() { + if impl_ty_own_bounds.len() == 0 { // Nothing to check. return Ok(()); } @@ -1844,9 +1845,11 @@ fn compare_type_predicate_entailment<'tcx>( // associated type in the trait are assumed. let impl_predicates = tcx.predicates_of(impl_ty_predicates.parent.unwrap()); let mut hybrid_preds = impl_predicates.instantiate_identity(tcx); - hybrid_preds - .predicates - .extend(trait_ty_predicates.instantiate_own(tcx, trait_to_impl_substs).predicates); + hybrid_preds.predicates.extend( + trait_ty_predicates + .instantiate_own(tcx, trait_to_impl_substs) + .map(|(predicate, _)| predicate), + ); debug!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds); @@ -1862,9 +1865,7 @@ fn compare_type_predicate_entailment<'tcx>( debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds()); - assert_eq!(impl_ty_own_bounds.predicates.len(), impl_ty_own_bounds.spans.len()); - for (span, predicate) in std::iter::zip(impl_ty_own_bounds.spans, impl_ty_own_bounds.predicates) - { + for (predicate, span) in impl_ty_own_bounds { let cause = ObligationCause::misc(span, impl_ty_hir_id); let predicate = ocx.normalize(&cause, param_env, predicate); diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 8a5e765b9a306..801ca60044568 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -341,15 +341,9 @@ impl<'tcx> GenericPredicates<'tcx> { &self, tcx: TyCtxt<'tcx>, substs: SubstsRef<'tcx>, - ) -> InstantiatedPredicates<'tcx> { - InstantiatedPredicates { - predicates: self - .predicates - .iter() - .map(|(p, _)| EarlyBinder(*p).subst(tcx, substs)) - .collect(), - spans: self.predicates.iter().map(|(_, sp)| *sp).collect(), - } + ) -> impl Iterator, Span)> + DoubleEndedIterator + ExactSizeIterator + { + EarlyBinder(self.predicates).subst_iter_copied(tcx, substs) } #[instrument(level = "debug", skip(self, tcx))] diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 8f764011d0ac3..5dc9e311bf6b1 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -639,6 +639,13 @@ where } } +impl<'tcx, I: IntoIterator> ExactSizeIterator for SubstIter<'_, 'tcx, I> +where + I::IntoIter: ExactSizeIterator, + I::Item: TypeFoldable<'tcx>, +{ +} + impl<'tcx, 's, I: IntoIterator> EarlyBinder where I::Item: Deref, @@ -686,6 +693,14 @@ where } } +impl<'tcx, I: IntoIterator> ExactSizeIterator for SubstIterCopied<'_, 'tcx, I> +where + I::IntoIter: ExactSizeIterator, + I::Item: Deref, + ::Target: Copy + TypeFoldable<'tcx>, +{ +} + pub struct EarlyBinderIter { t: T, } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 81966f3fcb231..15320916fbe09 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -2303,10 +2303,10 @@ fn assoc_ty_own_obligations<'cx, 'tcx>( nested: &mut Vec>, ) { let tcx = selcx.tcx(); - let own = tcx + let predicates = tcx .predicates_of(obligation.predicate.def_id) .instantiate_own(tcx, obligation.predicate.substs); - for (predicate, span) in std::iter::zip(own.predicates, own.spans) { + for (predicate, span) in predicates { let normalized = normalize_with_depth_to( selcx, obligation.param_env, diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index a41d10f104358..d4ac461690c90 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -185,9 +185,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { })?); if let ty::Alias(ty::Projection, ..) = placeholder_self_ty.kind() { - let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs).predicates; - debug!(?predicates, "projection predicates"); - for predicate in predicates { + let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs); + for (predicate, _) in predicates { let normalized = normalize_with_depth_to( self, obligation.param_env, diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index 5ec9c2a24cd44..64daca714c32d 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -261,7 +261,10 @@ fn vtable_entries<'tcx>( // Note that this method could then never be called, so we // do not want to try and codegen it, in that case (see #23435). let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs); - if impossible_predicates(tcx, predicates.predicates) { + if impossible_predicates( + tcx, + predicates.map(|(predicate, _)| predicate).collect(), + ) { debug!("vtable_entries: predicates do not hold"); return VtblEntry::Vacant; } From 9b28edb6d7746f457e79f5ca2c4ade944f653113 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 3 Jan 2023 03:32:59 +0000 Subject: [PATCH 049/230] Make InstantiatedPredicates impl IntoIterator --- .../src/type_check/canonical.rs | 6 +--- .../rustc_hir_analysis/src/check/wfcheck.rs | 20 +++++------ compiler/rustc_hir_typeck/src/callee.rs | 8 ++--- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 3 +- .../rustc_hir_typeck/src/method/confirm.rs | 10 +++--- compiler/rustc_middle/src/ty/mod.rs | 27 ++++++++++++++ .../src/traits/error_reporting/ambiguity.rs | 4 +-- .../src/traits/error_reporting/suggestions.rs | 4 +-- .../rustc_trait_selection/src/traits/mod.rs | 14 ++++---- .../src/traits/project.rs | 36 +++++++++---------- .../rustc_trait_selection/src/traits/wf.rs | 2 +- compiler/rustc_traits/src/type_op.rs | 5 +-- 12 files changed, 74 insertions(+), 65 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index 02222c0a03cb3..11729e2c83f0b 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -107,11 +107,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { instantiated_predicates: ty::InstantiatedPredicates<'tcx>, locations: Locations, ) { - for (predicate, span) in instantiated_predicates - .predicates - .into_iter() - .zip(instantiated_predicates.spans.into_iter()) - { + for (predicate, span) in instantiated_predicates { debug!(?predicate); let category = ConstraintCategory::Predicate(span); let predicate = self.normalize_with_category(predicate, locations, category); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 912e0ec560b49..9af325b77fc94 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -32,7 +32,6 @@ use rustc_trait_selection::traits::{ }; use std::cell::LazyCell; -use std::iter; use std::ops::{ControlFlow, Deref}; pub(super) struct WfCheckingCtxt<'a, 'tcx> { @@ -1480,16 +1479,15 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id debug!(?predicates.predicates); assert_eq!(predicates.predicates.len(), predicates.spans.len()); - let wf_obligations = - iter::zip(&predicates.predicates, &predicates.spans).flat_map(|(&p, &sp)| { - traits::wf::predicate_obligations( - infcx, - wfcx.param_env.without_const(), - wfcx.body_id, - p, - sp, - ) - }); + let wf_obligations = predicates.into_iter().flat_map(|(p, sp)| { + traits::wf::predicate_obligations( + infcx, + wfcx.param_env.without_const(), + wfcx.body_id, + p, + sp, + ) + }); let obligations: Vec<_> = wf_obligations.chain(default_obligations).collect(); wfcx.register_obligations(obligations); diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index f1a4f94cd0151..b617821fbd652 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -375,14 +375,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if self.tcx.has_attr(def_id, sym::rustc_evaluate_where_clauses) { let predicates = self.tcx.predicates_of(def_id); let predicates = predicates.instantiate(self.tcx, subst); - for (predicate, predicate_span) in - predicates.predicates.iter().zip(&predicates.spans) - { + for (predicate, predicate_span) in predicates { let obligation = Obligation::new( self.tcx, ObligationCause::dummy_with_span(callee_expr.span), self.param_env, - *predicate, + predicate, ); let result = self.evaluate_obligation(&obligation); self.tcx @@ -391,7 +389,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { callee_expr.span, &format!("evaluate({:?}) = {:?}", predicate, result), ) - .span_label(*predicate_span, "predicate") + .span_label(predicate_span, "predicate") .emit(); } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index b9e13fd200924..c9609e6943981 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -2140,8 +2140,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // FIXME(compiler-errors): This could be problematic if something has two // fn-like predicates with different args, but callable types really never // do that, so it's OK. - for (predicate, span) in - std::iter::zip(instantiated.predicates, instantiated.spans) + for (predicate, span) in instantiated { if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = predicate.kind().skip_binder() && pred.self_ty().peel_refs() == callee_ty diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 4a33a791e1b7f..372ea30ebd08e 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -19,7 +19,6 @@ use rustc_middle::ty::{InternalSubsts, UserSubsts, UserType}; use rustc_span::{Span, DUMMY_SP}; use rustc_trait_selection::traits; -use std::iter; use std::ops::Deref; struct ConfirmContext<'a, 'tcx> { @@ -101,7 +100,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { let filler_substs = rcvr_substs .extend_to(self.tcx, pick.item.def_id, |def, _| self.tcx.mk_param_from_def(def)); let illegal_sized_bound = self.predicates_require_illegal_sized_bound( - &self.tcx.predicates_of(pick.item.def_id).instantiate(self.tcx, filler_substs), + self.tcx.predicates_of(pick.item.def_id).instantiate(self.tcx, filler_substs), ); // Unify the (adjusted) self type with what the method expects. @@ -565,7 +564,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { fn predicates_require_illegal_sized_bound( &self, - predicates: &ty::InstantiatedPredicates<'tcx>, + predicates: ty::InstantiatedPredicates<'tcx>, ) -> Option { let sized_def_id = self.tcx.lang_items().sized_trait()?; @@ -575,10 +574,11 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) if trait_pred.def_id() == sized_def_id => { - let span = iter::zip(&predicates.predicates, &predicates.spans) + let span = predicates + .iter() .find_map( |(p, span)| { - if *p == obligation.predicate { Some(*span) } else { None } + if p == obligation.predicate { Some(span) } else { None } }, ) .unwrap_or(rustc_span::DUMMY_SP); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index e9bd0e9866fdc..655753a42efd8 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1252,6 +1252,33 @@ impl<'tcx> InstantiatedPredicates<'tcx> { pub fn is_empty(&self) -> bool { self.predicates.is_empty() } + + pub fn iter(&self) -> <&Self as IntoIterator>::IntoIter { + (&self).into_iter() + } +} + +impl<'tcx> IntoIterator for InstantiatedPredicates<'tcx> { + type Item = (Predicate<'tcx>, Span); + + type IntoIter = std::iter::Zip>, std::vec::IntoIter>; + + fn into_iter(self) -> Self::IntoIter { + std::iter::zip(self.predicates, self.spans) + } +} + +impl<'a, 'tcx> IntoIterator for &'a InstantiatedPredicates<'tcx> { + type Item = (Predicate<'tcx>, Span); + + type IntoIter = std::iter::Zip< + std::iter::Copied>>, + std::iter::Copied>, + >; + + fn into_iter(self) -> Self::IntoIter { + std::iter::zip(self.predicates.iter().copied(), self.spans.iter().copied()) + } } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable, Lift)] diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs index df57c0f60fa6d..0419bb3f724f9 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs @@ -82,9 +82,7 @@ pub fn recompute_applicable_impls<'tcx>( let predicates = tcx.predicates_of(obligation.cause.body_id.owner.to_def_id()).instantiate_identity(tcx); - for obligation in - elaborate_predicates_with_span(tcx, std::iter::zip(predicates.predicates, predicates.spans)) - { + for obligation in elaborate_predicates_with_span(tcx, predicates.into_iter()) { let kind = obligation.predicate.kind(); if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = kind.skip_binder() && param_env_candidate_may_apply(kind.rebind(trait_pred)) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 5211f873a1e3b..6e2341a823b9b 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -2070,7 +2070,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Find another predicate whose self-type is equal to the expected self type, // but whose substs don't match. - let other_pred = std::iter::zip(&predicates.predicates, &predicates.spans) + let other_pred = predicates.into_iter() .enumerate() .find(|(other_idx, (pred, _))| match pred.kind().skip_binder() { ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) @@ -2095,7 +2095,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // If we found one, then it's very likely the cause of the error. if let Some((_, (_, other_pred_span))) = other_pred { err.span_note( - *other_pred_span, + other_pred_span, "closure inferred to have a different signature due to this bound", ); } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 13aa067844a92..531aa23d6eac5 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -115,14 +115,12 @@ pub fn predicates_for_generics<'tcx>( param_env: ty::ParamEnv<'tcx>, generic_bounds: ty::InstantiatedPredicates<'tcx>, ) -> impl Iterator> { - std::iter::zip(generic_bounds.predicates, generic_bounds.spans).enumerate().map( - move |(idx, (predicate, span))| Obligation { - cause: cause(idx, span), - recursion_depth: 0, - param_env, - predicate, - }, - ) + generic_bounds.into_iter().enumerate().map(move |(idx, (predicate, span))| Obligation { + cause: cause(idx, span), + recursion_depth: 0, + param_env, + predicate, + }) } /// Determines whether the type `ty` is known to meet `bound` and diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 15320916fbe09..9c655aff0bac4 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -2259,25 +2259,23 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>( tcx.predicates_of(impl_fn_def_id).instantiate(tcx, impl_fn_substs), &mut obligations, ); - obligations.extend(std::iter::zip(predicates.predicates, predicates.spans).map( - |(pred, span)| { - Obligation::with_depth( - tcx, - ObligationCause::new( - obligation.cause.span, - obligation.cause.body_id, - if span.is_dummy() { - super::ItemObligation(impl_fn_def_id) - } else { - super::BindingObligation(impl_fn_def_id, span) - }, - ), - obligation.recursion_depth + 1, - obligation.param_env, - pred, - ) - }, - )); + obligations.extend(predicates.into_iter().map(|(pred, span)| { + Obligation::with_depth( + tcx, + ObligationCause::new( + obligation.cause.span, + obligation.cause.body_id, + if span.is_dummy() { + super::ItemObligation(impl_fn_def_id) + } else { + super::BindingObligation(impl_fn_def_id, span) + }, + ), + obligation.recursion_depth + 1, + obligation.param_env, + pred, + ) + })); let ty = normalize_with_depth_to( selcx, diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index fec4047ff49ba..2cebad64c4373 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -736,7 +736,7 @@ impl<'tcx> WfPredicates<'tcx> { trace!("{:#?}", predicates); debug_assert_eq!(predicates.predicates.len(), origins.len()); - iter::zip(iter::zip(predicates.predicates, predicates.spans), origins.into_iter().rev()) + iter::zip(predicates, origins.into_iter().rev()) .map(|((mut pred, span), origin_def_id)| { let code = if span.is_dummy() { traits::ItemObligation(origin_def_id) diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs index aa5c83ac2e655..f35c5e44882df 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -17,7 +17,6 @@ use rustc_trait_selection::traits::query::type_op::subtype::Subtype; use rustc_trait_selection::traits::query::{Fallible, NoSolution}; use rustc_trait_selection::traits::{Normalized, Obligation, ObligationCause, ObligationCtxt}; use std::fmt; -use std::iter::zip; pub(crate) fn provide(p: &mut Providers) { *p = Providers { @@ -108,9 +107,7 @@ fn relate_mir_and_user_substs<'tcx>( let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs); debug!(?instantiated_predicates); - for (instantiated_predicate, predicate_span) in - zip(instantiated_predicates.predicates, instantiated_predicates.spans) - { + for (instantiated_predicate, predicate_span) in instantiated_predicates { let span = if span == DUMMY_SP { predicate_span } else { span }; let cause = ObligationCause::new( span, From e1533a26f77000b6e22195987ef45d0aae3c710a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 3 Jan 2023 03:38:06 +0000 Subject: [PATCH 050/230] drive-by: assert when iterating through InstantiatedPredicates --- compiler/rustc_middle/src/ty/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 655753a42efd8..bf8f45c50a3c9 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1264,6 +1264,7 @@ impl<'tcx> IntoIterator for InstantiatedPredicates<'tcx> { type IntoIter = std::iter::Zip>, std::vec::IntoIter>; fn into_iter(self) -> Self::IntoIter { + debug_assert_eq!(self.predicates.len(), self.spans.len()); std::iter::zip(self.predicates, self.spans) } } @@ -1277,6 +1278,7 @@ impl<'a, 'tcx> IntoIterator for &'a InstantiatedPredicates<'tcx> { >; fn into_iter(self) -> Self::IntoIter { + debug_assert_eq!(self.predicates.len(), self.spans.len()); std::iter::zip(self.predicates.iter().copied(), self.spans.iter().copied()) } } From 90df86f474e9214fe3337181db8e88b9b785e6fe Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 3 Jan 2023 05:01:17 +0000 Subject: [PATCH 051/230] Remove bound_{explicit,}_item_bounds --- .../src/diagnostics/conflict_errors.rs | 48 ++++++++----------- .../rustc_hir_analysis/src/check/wfcheck.rs | 9 ++-- .../src/infer/error_reporting/note.rs | 5 +- compiler/rustc_middle/src/ty/util.rs | 14 ------ .../src/traits/select/mod.rs | 13 +++-- compiler/rustc_traits/src/chalk/db.rs | 15 +++--- 6 files changed, 40 insertions(+), 64 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 968c1f49b95c0..e512099b93b13 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -673,40 +673,34 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let tcx = self.infcx.tcx; // Find out if the predicates show that the type is a Fn or FnMut - let find_fn_kind_from_did = |predicates: ty::EarlyBinder< - &[(ty::Predicate<'tcx>, Span)], - >, - substs| { - predicates.0.iter().find_map(|(pred, _)| { - let pred = if let Some(substs) = substs { - predicates.rebind(*pred).subst(tcx, substs).kind().skip_binder() - } else { - pred.kind().skip_binder() - }; - if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = pred && pred.self_ty() == ty { - if Some(pred.def_id()) == tcx.lang_items().fn_trait() { - return Some(hir::Mutability::Not); - } else if Some(pred.def_id()) == tcx.lang_items().fn_mut_trait() { - return Some(hir::Mutability::Mut); - } + let find_fn_kind_from_did = |(pred, _): (ty::Predicate<'tcx>, _)| { + if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = pred.kind().skip_binder() + && pred.self_ty() == ty + { + if Some(pred.def_id()) == tcx.lang_items().fn_trait() { + return Some(hir::Mutability::Not); + } else if Some(pred.def_id()) == tcx.lang_items().fn_mut_trait() { + return Some(hir::Mutability::Mut); } - None - }) + } + None }; // If the type is opaque/param/closure, and it is Fn or FnMut, let's suggest (mutably) // borrowing the type, since `&mut F: FnMut` iff `F: FnMut` and similarly for `Fn`. // These types seem reasonably opaque enough that they could be substituted with their // borrowed variants in a function body when we see a move error. - let borrow_level = match ty.kind() { - ty::Param(_) => find_fn_kind_from_did( - tcx.bound_explicit_predicates_of(self.mir_def_id().to_def_id()) - .map_bound(|p| p.predicates), - None, - ), - ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { - find_fn_kind_from_did(tcx.bound_explicit_item_bounds(*def_id), Some(*substs)) - } + let borrow_level = match *ty.kind() { + ty::Param(_) => tcx + .explicit_predicates_of(self.mir_def_id().to_def_id()) + .predicates + .iter() + .copied() + .find_map(find_fn_kind_from_did), + ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => tcx + .bound_explicit_item_bounds(def_id) + .subst_iter_copied(tcx, substs) + .find_map(find_fn_kind_from_did), ty::Closure(_, substs) => match substs.as_closure().kind() { ty::ClosureKind::Fn => Some(hir::Mutability::Not), ty::ClosureKind::FnMut => Some(hir::Mutability::Mut), diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 9af325b77fc94..49dd1eb22f7fe 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1309,7 +1309,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id let infcx = wfcx.infcx; let tcx = wfcx.tcx(); - let predicates = tcx.bound_predicates_of(def_id.to_def_id()); + let predicates = tcx.predicates_of(def_id.to_def_id()); let generics = tcx.generics_of(def_id); let is_our_default = |def: &ty::GenericParamDef| match def.kind { @@ -1410,7 +1410,6 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id // Now we build the substituted predicates. let default_obligations = predicates - .0 .predicates .iter() .flat_map(|&(pred, sp)| { @@ -1441,13 +1440,13 @@ 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 = predicates.rebind(pred).subst(tcx, substs); + let substituted_pred = ty::EarlyBinder(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 { None - } else if predicates.0.predicates.iter().any(|&(p, _)| p == substituted_pred) { + } else if predicates.predicates.iter().any(|&(p, _)| p == substituted_pred) { // Avoid duplication of predicates that contain no parameters, for example. None } else { @@ -1473,7 +1472,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id traits::Obligation::new(tcx, cause, wfcx.param_env, pred) }); - let predicates = predicates.0.instantiate_identity(tcx); + let predicates = predicates.instantiate_identity(tcx); let predicates = wfcx.normalize(span, None, predicates); diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index 021e741ee2f71..b18cbd404d47f 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -330,9 +330,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let Ok(trait_predicates) = self .tcx - .bound_explicit_predicates_of(trait_item_def_id) - .map_bound(|p| p.predicates) - .subst_iter_copied(self.tcx, trait_item_substs) + .explicit_predicates_of(trait_item_def_id) + .instantiate_own(self.tcx, trait_item_substs) .map(|(pred, _)| { if pred.is_suggestable(self.tcx, false) { Ok(pred.to_string()) diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 1286a5253c068..37d3e12a66763 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -666,20 +666,6 @@ impl<'tcx> TyCtxt<'tcx> { ty::EarlyBinder(self.item_bounds(def_id)) } - pub fn bound_predicates_of( - self, - def_id: DefId, - ) -> ty::EarlyBinder> { - ty::EarlyBinder(self.predicates_of(def_id)) - } - - pub fn bound_explicit_predicates_of( - self, - def_id: DefId, - ) -> ty::EarlyBinder> { - ty::EarlyBinder(self.explicit_predicates_of(def_id)) - } - pub fn bound_impl_subject(self, def_id: DefId) -> ty::EarlyBinder> { ty::EarlyBinder(self.impl_subject(def_id)) } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index ba4e668f52ddd..95c269d1b7853 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2558,12 +2558,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // obligation will normalize to `<$0 as Iterator>::Item = $1` and // `$1: Copy`, so we must ensure the obligations are emitted in // that order. - let predicates = tcx.bound_predicates_of(def_id); - debug!(?predicates); - assert_eq!(predicates.0.parent, None); - let mut obligations = Vec::with_capacity(predicates.0.predicates.len()); - for (predicate, span) in predicates.0.predicates { - let span = *span; + let predicates = tcx.predicates_of(def_id); + assert_eq!(predicates.parent, None); + let predicates = predicates.instantiate_own(tcx, substs); + let mut obligations = Vec::with_capacity(predicates.len()); + for (predicate, span) in predicates { let cause = cause.clone().derived_cause(parent_trait_pred, |derived| { ImplDerivedObligation(Box::new(ImplDerivedObligationCause { derived, @@ -2576,7 +2575,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { param_env, cause.clone(), recursion_depth, - predicates.rebind(*predicate).subst(tcx, substs), + predicate, &mut obligations, ); obligations.push(Obligation { cause, recursion_depth, param_env, predicate }); diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index 7c0cae1e7bdc2..f146de3966ba1 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -7,7 +7,7 @@ //! `crate::chalk::lowering` (to lower rustc types into Chalk types). use rustc_middle::traits::ChalkRustInterner as RustInterner; -use rustc_middle::ty::{self, AssocKind, EarlyBinder, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable}; +use rustc_middle::ty::{self, AssocKind, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable}; use rustc_middle::ty::{InternalSubsts, SubstsRef}; use rustc_target::abi::{Integer, IntegerType}; @@ -38,13 +38,12 @@ impl<'tcx> RustIrDatabase<'tcx> { def_id: DefId, bound_vars: SubstsRef<'tcx>, ) -> Vec>> { - let predicates = self.interner.tcx.predicates_defined_on(def_id).predicates; - predicates - .iter() - .map(|(wc, _)| EarlyBinder(*wc).subst(self.interner.tcx, bound_vars)) - .filter_map(|wc| LowerInto::< - Option>> - >::lower_into(wc, self.interner)).collect() + self.interner + .tcx + .predicates_defined_on(def_id) + .instantiate_own(self.interner.tcx, bound_vars) + .filter_map(|(wc, _)| LowerInto::lower_into(wc, self.interner)) + .collect() } fn bounds_for(&self, def_id: DefId, bound_vars: SubstsRef<'tcx>) -> Vec From 566202b97511b27e66312f67faacffb7272d7dbb Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 15 Jan 2023 16:33:08 +0000 Subject: [PATCH 052/230] Only suggest adding type param if path being resolved was a type --- compiler/rustc_resolve/src/late.rs | 2 +- tests/ui/suggestions/constrain-suggest-ice.stderr | 11 +---------- tests/ui/typeck/issue-104513-ice.stderr | 5 ----- 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index ca43762aa214e..6ca7cd3e71349 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -3373,7 +3373,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { sugg.to_string(), Applicability::MaybeIncorrect, )) - } else if res.is_none() { + } else if res.is_none() && matches!(source, PathSource::Type) { this.report_missing_type_error(path) } else { None diff --git a/tests/ui/suggestions/constrain-suggest-ice.stderr b/tests/ui/suggestions/constrain-suggest-ice.stderr index 477eb2786799a..2af7c2f697148 100644 --- a/tests/ui/suggestions/constrain-suggest-ice.stderr +++ b/tests/ui/suggestions/constrain-suggest-ice.stderr @@ -24,16 +24,7 @@ error[E0425]: cannot find value `F` in this scope --> $DIR/constrain-suggest-ice.rs:6:9 | LL | F - | ^ - | -help: a local variable with a similar name exists - | -LL | x - | ~ -help: you might be missing a type parameter - | -LL | struct Bug{ - | +++ + | ^ help: a local variable with a similar name exists: `x` error: generic `Self` types are currently not permitted in anonymous constants --> $DIR/constrain-suggest-ice.rs:3:21 diff --git a/tests/ui/typeck/issue-104513-ice.stderr b/tests/ui/typeck/issue-104513-ice.stderr index 5561673f3c672..42cfe38aed888 100644 --- a/tests/ui/typeck/issue-104513-ice.stderr +++ b/tests/ui/typeck/issue-104513-ice.stderr @@ -3,11 +3,6 @@ error[E0405]: cannot find trait `Oops` in this scope | LL | let _: S = S; | ^^^^ not found in this scope - | -help: you might be missing a type parameter - | -LL | fn f() { - | ++++++ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding --> $DIR/issue-104513-ice.rs:3:14 From 9db013401879a39df86c33552c8c092cf95ea20c Mon Sep 17 00:00:00 2001 From: The 8472 Date: Tue, 3 Jan 2023 02:39:13 +0100 Subject: [PATCH 053/230] replace manual ptr arithmetic with ptr_sub --- library/core/src/slice/iter.rs | 8 +------ library/core/src/slice/iter/macros.rs | 22 +++++-------------- .../issue-45964-bounds-check-slice-pos.rs | 1 + 3 files changed, 8 insertions(+), 23 deletions(-) diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index c3e7f2eb302ca..90ab43d1289f0 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -6,7 +6,7 @@ mod macros; use crate::cmp; use crate::cmp::Ordering; use crate::fmt; -use crate::intrinsics::{assume, exact_div, unchecked_sub}; +use crate::intrinsics::assume; use crate::iter::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce}; use crate::marker::{PhantomData, Send, Sized, Sync}; use crate::mem::{self, SizedTypeProperties}; @@ -35,12 +35,6 @@ impl<'a, T> IntoIterator for &'a mut [T] { } } -// Macro helper functions -#[inline(always)] -fn size_from_ptr(_: *const T) -> usize { - mem::size_of::() -} - /// Immutable slice iterator /// /// This struct is created by the [`iter`] method on [slices]. diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs index 55af4cb61dcc0..0fd57b197aa97 100644 --- a/library/core/src/slice/iter/macros.rs +++ b/library/core/src/slice/iter/macros.rs @@ -9,30 +9,20 @@ macro_rules! is_empty { }; } -// To get rid of some bounds checks (see `position`), we compute the length in a somewhat -// unexpected way. (Tested by `codegen/slice-position-bounds-check`.) macro_rules! len { ($self: ident) => {{ #![allow(unused_unsafe)] // we're sometimes used within an unsafe block let start = $self.ptr; - let size = size_from_ptr(start.as_ptr()); - if size == 0 { - // This _cannot_ use `unchecked_sub` because we depend on wrapping + if T::IS_ZST { + // This _cannot_ use `ptr_sub` because we depend on wrapping // to represent the length of long ZST slice iterators. $self.end.addr().wrapping_sub(start.as_ptr().addr()) } else { - // We know that `start <= end`, so can do better than `offset_from`, - // which needs to deal in signed. By setting appropriate flags here - // we can tell LLVM this, which helps it remove bounds checks. - // SAFETY: By the type invariant, `start <= end` - let diff = unsafe { unchecked_sub($self.end.addr(), start.as_ptr().addr()) }; - // By also telling LLVM that the pointers are apart by an exact - // multiple of the type size, it can optimize `len() == 0` down to - // `start == end` instead of `(end - start) < size`. - // SAFETY: By the type invariant, the pointers are aligned so the - // distance between them must be a multiple of pointee size - unsafe { exact_div(diff, size) } + // To get rid of some bounds checks (see `position`), we use ptr_sub instead of + // offset_from (Tested by `codegen/slice-position-bounds-check`.) + // SAFETY: by the type invariant pointers are aligned and `start <= end` + unsafe { $self.end.sub_ptr(start.as_ptr()) } } }}; } diff --git a/tests/codegen/issue-45964-bounds-check-slice-pos.rs b/tests/codegen/issue-45964-bounds-check-slice-pos.rs index aa59c713b7846..1daa213fc8213 100644 --- a/tests/codegen/issue-45964-bounds-check-slice-pos.rs +++ b/tests/codegen/issue-45964-bounds-check-slice-pos.rs @@ -2,6 +2,7 @@ // prevent optimizing away bounds checks // compile-flags: -O +// ignore-debug: the debug assertions get in the way #![crate_type="rlib"] From 8dbc878a350c51f4e6c75fab3cdec45008a92f9e Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Mon, 16 Jan 2023 01:15:06 +0200 Subject: [PATCH 054/230] Avoid unsafe code in `to_ascii_[lower/upper]case()` --- library/alloc/src/str.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index b28d20cda179e..afbe5cfaf8ef9 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -559,10 +559,9 @@ impl str { #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] pub fn to_ascii_uppercase(&self) -> String { - let mut bytes = self.as_bytes().to_vec(); - bytes.make_ascii_uppercase(); - // make_ascii_uppercase() preserves the UTF-8 invariant. - unsafe { String::from_utf8_unchecked(bytes) } + let mut s = self.to_owned(); + s.make_ascii_uppercase(); + s } /// Returns a copy of this string where each character is mapped to its @@ -592,10 +591,9 @@ impl str { #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] pub fn to_ascii_lowercase(&self) -> String { - let mut bytes = self.as_bytes().to_vec(); - bytes.make_ascii_lowercase(); - // make_ascii_lowercase() preserves the UTF-8 invariant. - unsafe { String::from_utf8_unchecked(bytes) } + let mut s = self.to_owned(); + s.make_ascii_lowercase(); + s } } From d21696ae465db24fc0026eafd03166b9e6b2bdc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Mon, 16 Jan 2023 00:00:00 +0000 Subject: [PATCH 055/230] Remove ineffective run of SimplifyConstCondition There are no constant conditions at this stage. --- compiler/rustc_mir_transform/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 16b8a901f3651..20b7fdcfe6d4d 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -487,7 +487,6 @@ fn run_analysis_to_runtime_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx> fn run_analysis_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let passes: &[&dyn MirPass<'tcx>] = &[ &cleanup_post_borrowck::CleanupPostBorrowck, - &simplify_branches::SimplifyConstCondition::new("initial"), &remove_noop_landing_pads::RemoveNoopLandingPads, &simplify::SimplifyCfg::new("early-opt"), &deref_separator::Derefer, From fcd5ed21b77dd1d72696e43dd70e60b1ad458f55 Mon Sep 17 00:00:00 2001 From: Ezra Shaw Date: Mon, 16 Jan 2023 16:18:56 +1300 Subject: [PATCH 056/230] fix dropping diagnostic without emit --- compiler/rustc_parse/src/parser/ty.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index aedebd0fb7062..1766b0293de52 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -941,7 +941,8 @@ impl<'a> Parser<'a> { && let Some(path) = self.recover_path_from_fn() { path - } else if !self.token.is_path_start() && self.token.can_begin_type() && let Ok(ty) = self.parse_ty_no_plus() { + } else if !self.token.is_path_start() && self.token.can_begin_type() { + let ty = self.parse_ty_no_plus()?; // Instead of finding a path (a trait), we found a type. let mut err = self.struct_span_err(ty.span, "expected a trait, found type"); From ca1178f02237fd84649a30b74052da4ef265371f Mon Sep 17 00:00:00 2001 From: Ezra Shaw Date: Mon, 16 Jan 2023 20:24:01 +1300 Subject: [PATCH 057/230] make `CastError::NeedsDeref` create a `MachineApplicable` suggestion + other misc fixes --- compiler/rustc_hir_typeck/src/cast.rs | 30 +++++++------------ tests/ui/error-codes/E0606.stderr | 10 ++++--- tests/ui/error-festival.stderr | 10 ++++--- tests/ui/mismatched_types/cast-rfc0401.stderr | 10 ++++--- 4 files changed, 29 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 0a230fca107af..b312a3d30af08 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -151,7 +151,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { #[derive(Copy, Clone)] pub enum CastError { - ErrorGuaranteed, + ErrorGuaranteed(ErrorGuaranteed), CastToBool, CastToChar, @@ -176,8 +176,8 @@ pub enum CastError { } impl From for CastError { - fn from(_: ErrorGuaranteed) -> Self { - CastError::ErrorGuaranteed + fn from(err: ErrorGuaranteed) -> Self { + CastError::ErrorGuaranteed(err) } } @@ -225,11 +225,10 @@ impl<'a, 'tcx> CastCheck<'tcx> { fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) { match e { - CastError::ErrorGuaranteed => { + CastError::ErrorGuaranteed(_) => { // an error has already been reported } CastError::NeedDeref => { - let error_span = self.span; let mut err = make_invalid_casting_error( fcx.tcx.sess, self.span, @@ -237,21 +236,14 @@ impl<'a, 'tcx> CastCheck<'tcx> { self.cast_ty, fcx, ); - let cast_ty = fcx.ty_to_string(self.cast_ty); - err.span_label( - error_span, - format!("cannot cast `{}` as `{}`", fcx.ty_to_string(self.expr_ty), cast_ty), + + err.span_suggestion_verbose( + self.expr_span.shrink_to_lo(), + "dereference the expression", + "*", + Applicability::MachineApplicable, ); - if let Ok(snippet) = fcx.sess().source_map().span_to_snippet(self.expr_span) { - err.span_suggestion( - self.expr_span, - "dereference the expression", - format!("*{}", snippet), - Applicability::MaybeIncorrect, - ); - } else { - err.span_help(self.expr_span, "dereference the expression with `*`"); - } + err.emit(); } CastError::NeedViaThinPtr | CastError::NeedViaPtr => { diff --git a/tests/ui/error-codes/E0606.stderr b/tests/ui/error-codes/E0606.stderr index fce24886eb0df..586b1f2fd5472 100644 --- a/tests/ui/error-codes/E0606.stderr +++ b/tests/ui/error-codes/E0606.stderr @@ -2,10 +2,12 @@ error[E0606]: casting `&u8` as `u8` is invalid --> $DIR/E0606.rs:2:5 | LL | &0u8 as u8; - | ----^^^^^^ - | | - | cannot cast `&u8` as `u8` - | help: dereference the expression: `*&0u8` + | ^^^^^^^^^^ + | +help: dereference the expression + | +LL | *&0u8 as u8; + | + error: aborting due to previous error diff --git a/tests/ui/error-festival.stderr b/tests/ui/error-festival.stderr index fe9956b70bdd7..e8ee1d96942f7 100644 --- a/tests/ui/error-festival.stderr +++ b/tests/ui/error-festival.stderr @@ -69,10 +69,12 @@ error[E0606]: casting `&u8` as `u32` is invalid --> $DIR/error-festival.rs:37:18 | LL | let y: u32 = x as u32; - | -^^^^^^^ - | | - | cannot cast `&u8` as `u32` - | help: dereference the expression: `*x` + | ^^^^^^^^ + | +help: dereference the expression + | +LL | let y: u32 = *x as u32; + | + error[E0607]: cannot cast thin pointer `*const u8` to fat pointer `*const [u8]` --> $DIR/error-festival.rs:41:5 diff --git a/tests/ui/mismatched_types/cast-rfc0401.stderr b/tests/ui/mismatched_types/cast-rfc0401.stderr index eab8e8e80c424..2a36a352c7341 100644 --- a/tests/ui/mismatched_types/cast-rfc0401.stderr +++ b/tests/ui/mismatched_types/cast-rfc0401.stderr @@ -243,10 +243,12 @@ error[E0606]: casting `&{float}` as `f32` is invalid --> $DIR/cast-rfc0401.rs:71:30 | LL | vec![0.0].iter().map(|s| s as f32).collect::>(); - | -^^^^^^^ - | | - | cannot cast `&{float}` as `f32` - | help: dereference the expression: `*s` + | ^^^^^^^^ + | +help: dereference the expression + | +LL | vec![0.0].iter().map(|s| *s as f32).collect::>(); + | + error: aborting due to 34 previous errors From 9e9c871a7842bed0ed566d0ee0726658036d1c1e Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 6 Dec 2022 15:07:00 +0000 Subject: [PATCH 058/230] Remove `prepare_outputs` --- compiler/rustc_driver/src/lib.rs | 4 +--- compiler/rustc_interface/src/queries.rs | 28 ++++++++----------------- 2 files changed, 10 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index a62e5dec4b864..c56443512f4d2 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -362,7 +362,7 @@ fn run_compiler( return early_exit(); } - queries.prepare_outputs()?; + queries.global_ctxt()?; if sess.opts.output_types.contains_key(&OutputType::DepInfo) && sess.opts.output_types.len() == 1 @@ -370,8 +370,6 @@ fn run_compiler( return early_exit(); } - queries.global_ctxt()?; - if sess.opts.unstable_opts.no_analysis { return early_exit(); } diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 041bb9eb7a1cb..cb07688e2f508 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -90,7 +90,6 @@ pub struct Queries<'tcx> { register_plugins: Query<(ast::Crate, Lrc)>, expansion: Query<(Lrc, Rc>, Lrc)>, dep_graph: Query, - prepare_outputs: Query, global_ctxt: Query>, ongoing_codegen: Query>, } @@ -109,7 +108,6 @@ impl<'tcx> Queries<'tcx> { register_plugins: Default::default(), expansion: Default::default(), dep_graph: Default::default(), - prepare_outputs: Default::default(), global_ctxt: Default::default(), ongoing_codegen: Default::default(), } @@ -211,32 +209,24 @@ impl<'tcx> Queries<'tcx> { }) } - pub fn prepare_outputs(&self) -> Result> { - self.prepare_outputs.compute(|| { - let expansion = self.expansion()?; - let (krate, boxed_resolver, _) = &*expansion.borrow(); + pub fn global_ctxt(&'tcx self) -> Result>> { + self.global_ctxt.compute(|| { let crate_name = *self.crate_name()?.borrow(); - passes::prepare_outputs( + let (krate, resolver, lint_store) = self.expansion()?.steal(); + + let outputs = passes::prepare_outputs( self.session(), self.compiler, - krate, - &*boxed_resolver, + &krate, + &resolver, crate_name, - ) - }) - } + )?; - pub fn global_ctxt(&'tcx self) -> Result>> { - self.global_ctxt.compute(|| { - let crate_name = *self.crate_name()?.borrow(); - let outputs = self.prepare_outputs()?.steal(); - let dep_graph = self.dep_graph()?.borrow().clone(); - let (krate, resolver, lint_store) = self.expansion()?.steal(); Ok(passes::create_global_ctxt( self.compiler, lint_store, krate, - dep_graph, + self.dep_graph()?.steal(), resolver, outputs, crate_name, From 6b1a789fb69f832d2b3df53b9e42c08c919c7487 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 6 Dec 2022 15:43:52 +0000 Subject: [PATCH 059/230] remove some arguments that can also be fed at the caller side --- compiler/rustc_interface/src/passes.rs | 30 +++---------------------- compiler/rustc_interface/src/queries.rs | 30 +++++++++++++++++++------ 2 files changed, 26 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 50c40206d8026..5dd758c94512f 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -13,7 +13,6 @@ use rustc_ast::{self as ast, visit}; use rustc_borrowck as mir_borrowck; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::parallel; -use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal}; use rustc_errors::{ErrorGuaranteed, PResult}; use rustc_expand::base::{ExtCtxt, LintStoreExpand, ResolverExpand}; @@ -31,7 +30,7 @@ use rustc_plugin_impl as plugin; use rustc_query_impl::{OnDiskCache, Queries as TcxQueries}; use rustc_resolve::{Resolver, ResolverArenas}; use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType}; -use rustc_session::cstore::{MetadataLoader, MetadataLoaderDyn}; +use rustc_session::cstore::{MetadataLoader, MetadataLoaderDyn, Untracked}; use rustc_session::output::filename_for_input; use rustc_session::search_paths::PathKind; use rustc_session::{Limit, Session}; @@ -775,11 +774,8 @@ impl<'tcx> QueryContext<'tcx> { pub fn create_global_ctxt<'tcx>( compiler: &'tcx Compiler, lint_store: Lrc, - krate: Lrc, dep_graph: DepGraph, - resolver: Rc>, - outputs: OutputFilenames, - crate_name: Symbol, + untracked: Untracked, queries: &'tcx OnceCell>, global_ctxt: &'tcx OnceCell>, arena: &'tcx WorkerLocal>, @@ -790,8 +786,6 @@ pub fn create_global_ctxt<'tcx>( // incr. comp. yet. dep_graph.assert_ignored(); - let resolver_outputs = BoxedResolver::to_resolver_outputs(resolver); - let sess = &compiler.session(); let query_result_on_disk_cache = rustc_incremental::load_query_result_cache(sess); @@ -810,12 +804,6 @@ pub fn create_global_ctxt<'tcx>( TcxQueries::new(local_providers, extern_providers, query_result_on_disk_cache) }); - let ty::ResolverOutputs { - global_ctxt: untracked_resolutions, - ast_lowering: untracked_resolver_for_lowering, - untracked, - } = resolver_outputs; - let gcx = sess.time("setup_global_ctxt", || { global_ctxt.get_or_init(move || { TyCtxt::create_global_ctxt( @@ -832,19 +820,7 @@ pub fn create_global_ctxt<'tcx>( }) }); - let mut qcx = QueryContext { gcx }; - qcx.enter(|tcx| { - let feed = tcx.feed_unit_query(); - feed.resolver_for_lowering( - tcx.arena.alloc(Steal::new((untracked_resolver_for_lowering, krate))), - ); - feed.resolutions(tcx.arena.alloc(untracked_resolutions)); - feed.output_filenames(tcx.arena.alloc(std::sync::Arc::new(outputs))); - feed.features_query(sess.features_untracked()); - let feed = tcx.feed_local_crate(); - feed.crate_name(crate_name); - }); - qcx + QueryContext { gcx } } /// Runs the resolution, type-checking, region checking and other diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index cb07688e2f508..6f791c8893ce3 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -13,7 +13,7 @@ use rustc_incremental::DepGraphFuture; use rustc_lint::LintStore; use rustc_middle::arena::Arena; use rustc_middle::dep_graph::DepGraph; -use rustc_middle::ty::{GlobalCtxt, TyCtxt}; +use rustc_middle::ty::{self, GlobalCtxt, TyCtxt}; use rustc_query_impl::Queries as TcxQueries; use rustc_session::config::{self, OutputFilenames, OutputType}; use rustc_session::{output::find_crate_name, Session}; @@ -222,19 +222,35 @@ impl<'tcx> Queries<'tcx> { crate_name, )?; - Ok(passes::create_global_ctxt( + let ty::ResolverOutputs { + untracked, + global_ctxt: untracked_resolutions, + ast_lowering: untracked_resolver_for_lowering, + } = BoxedResolver::to_resolver_outputs(resolver); + + let mut qcx = passes::create_global_ctxt( self.compiler, lint_store, - krate, self.dep_graph()?.steal(), - resolver, - outputs, - crate_name, + untracked, &self.queries, &self.gcx, &self.arena, &self.hir_arena, - )) + ); + + qcx.enter(|tcx| { + let feed = tcx.feed_unit_query(); + feed.resolver_for_lowering( + tcx.arena.alloc(Steal::new((untracked_resolver_for_lowering, krate))), + ); + feed.resolutions(tcx.arena.alloc(untracked_resolutions)); + feed.output_filenames(tcx.arena.alloc(std::sync::Arc::new(outputs))); + feed.features_query(tcx.sess.features_untracked()); + let feed = tcx.feed_local_crate(); + feed.crate_name(crate_name); + }); + Ok(qcx) }) } From f5c601492ee520d2ee4f6c133f7f4dfa7b0c13e2 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 6 Dec 2022 18:56:28 +0000 Subject: [PATCH 060/230] Remove redundant `input_path` field from `Config` --- compiler/rustc_driver/src/lib.rs | 12 +++++------- compiler/rustc_interface/src/interface.rs | 5 +---- compiler/rustc_interface/src/passes.rs | 2 +- compiler/rustc_session/src/config.rs | 18 ++++++++++++++++++ src/librustdoc/core.rs | 2 -- src/librustdoc/doctest.rs | 1 - 6 files changed, 25 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index c56443512f4d2..ec46fc8999a17 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -219,7 +219,6 @@ fn run_compiler( crate_cfg: cfg, crate_check_cfg: check_cfg, input: Input::File(PathBuf::new()), - input_path: None, output_file: ofile, output_dir: odir, file_loader, @@ -237,9 +236,8 @@ fn run_compiler( match make_input(config.opts.error_format, &matches.free) { Err(reported) => return Err(reported), - Ok(Some((input, input_file_path))) => { + Ok(Some(input)) => { config.input = input; - config.input_path = input_file_path; callbacks.config(&mut config); } @@ -437,7 +435,7 @@ fn make_output(matches: &getopts::Matches) -> (Option, Option) fn make_input( error_format: ErrorOutputType, free_matches: &[String], -) -> Result)>, ErrorGuaranteed> { +) -> Result, ErrorGuaranteed> { if free_matches.len() == 1 { let ifile = &free_matches[0]; if ifile == "-" { @@ -459,12 +457,12 @@ fn make_input( let line = isize::from_str_radix(&line, 10) .expect("UNSTABLE_RUSTDOC_TEST_LINE needs to be an number"); let file_name = FileName::doc_test_source_code(PathBuf::from(path), line); - Ok(Some((Input::Str { name: file_name, input: src }, None))) + Ok(Some(Input::Str { name: file_name, input: src })) } else { - Ok(Some((Input::Str { name: FileName::anon_source_code(&src), input: src }, None))) + Ok(Some(Input::Str { name: FileName::anon_source_code(&src), input: src })) } } else { - Ok(Some((Input::File(PathBuf::from(ifile)), Some(PathBuf::from(ifile))))) + Ok(Some(Input::File(PathBuf::from(ifile)))) } } else { Ok(None) diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 7f761b005edd0..22a01db5e7573 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -36,7 +36,6 @@ pub struct Compiler { pub(crate) sess: Lrc, codegen_backend: Lrc>, pub(crate) input: Input, - pub(crate) input_path: Option, pub(crate) output_dir: Option, pub(crate) output_file: Option, pub(crate) temps_dir: Option, @@ -244,7 +243,6 @@ pub struct Config { pub crate_check_cfg: CheckCfg, pub input: Input, - pub input_path: Option, pub output_dir: Option, pub output_file: Option, pub file_loader: Option>, @@ -292,7 +290,7 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se config.crate_cfg, config.crate_check_cfg, config.file_loader, - config.input_path.clone(), + config.input.opt_path(), config.lint_caps, config.make_codegen_backend, registry.clone(), @@ -308,7 +306,6 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se sess: Lrc::new(sess), codegen_backend: Lrc::new(codegen_backend), input: config.input, - input_path: config.input_path, output_dir: config.output_dir, output_file: config.output_file, temps_dir, diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 5dd758c94512f..bba0a50a93fae 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -686,7 +686,7 @@ pub fn prepare_outputs( generated_output_paths(sess, &outputs, compiler.output_file.is_some(), crate_name); // Ensure the source file isn't accidentally overwritten during compilation. - if let Some(ref input_path) = compiler.input_path { + if let Some(ref input_path) = compiler.input.opt_path() { if sess.opts.will_create_output_file() { if output_contains_path(&output_paths, input_path) { let reported = sess.emit_err(InputFileWouldBeOverWritten { path: input_path }); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 55576b4e0d19d..2679164b927e5 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -591,6 +591,24 @@ impl Input { Input::Str { ref name, .. } => name.clone(), } } + + pub fn opt_path(&self) -> Option { + match self { + Input::File(file) => Some(file.clone()), + Input::Str { name, .. } => match name { + FileName::Real(real) => real.local_path().map(|p| p.to_owned()), + FileName::QuoteExpansion(_) => None, + FileName::Anon(_) => None, + FileName::MacroExpansion(_) => None, + FileName::ProcMacroSourceCode(_) => None, + FileName::CfgSpec(_) => None, + FileName::CliCrateAttr(_) => None, + FileName::Custom(_) => None, + FileName::DocTest(path, _) => Some(path.to_owned()), + FileName::InlineAsm(_) => None, + }, + } + } } #[derive(Clone, Hash, Debug, HashStable_Generic)] diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index da0df596c41e3..2153e7d8c9ad9 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -225,7 +225,6 @@ pub(crate) fn create_config( // Add the doc cfg into the doc build. cfgs.push("doc".to_string()); - let cpath = Some(input.clone()); let input = Input::File(input); // By default, rustdoc ignores all lints. @@ -277,7 +276,6 @@ pub(crate) fn create_config( crate_cfg: interface::parse_cfgspecs(cfgs), crate_check_cfg: interface::parse_check_cfg(check_cfgs), input, - input_path: cpath, output_file: None, output_dir: None, file_loader: None, diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index d1b6d470e86ce..c1a652c75f4a1 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -95,7 +95,6 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> { crate_cfg: interface::parse_cfgspecs(cfgs), crate_check_cfg: interface::parse_check_cfg(options.check_cfgs.clone()), input, - input_path: None, output_file: None, output_dir: None, file_loader: None, From 2c5583efbde7987c6de16cb057503f57c0d73d73 Mon Sep 17 00:00:00 2001 From: gftea Date: Sun, 15 Jan 2023 18:42:04 +0100 Subject: [PATCH 061/230] check -Z query-dep-graph is enabled if -Z dump-dep-graph (#106736) --- compiler/rustc_session/src/config.rs | 5 +++++ tests/ui/dep-graph/dep-graph-dump.rs | 6 ++++++ tests/ui/dep-graph/dep-graph-dump.stderr | 2 ++ 3 files changed, 13 insertions(+) create mode 100644 tests/ui/dep-graph/dep-graph-dump.rs create mode 100644 tests/ui/dep-graph/dep-graph-dump.stderr diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 55576b4e0d19d..38aebc81cd6b8 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2459,6 +2459,11 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { let pretty = parse_pretty(&unstable_opts, error_format); + // query-dep-graph is required if dump-dep-graph is given #106736 + if unstable_opts.dump_dep_graph && !unstable_opts.query_dep_graph { + early_error(error_format, "can't dump dependency graph without `-Z query-dep-graph`"); + } + // Try to find a directory containing the Rust `src`, for more details see // the doc comment on the `real_rust_source_base_dir` field. let tmp_buf; diff --git a/tests/ui/dep-graph/dep-graph-dump.rs b/tests/ui/dep-graph/dep-graph-dump.rs new file mode 100644 index 0000000000000..cbc4def0e03aa --- /dev/null +++ b/tests/ui/dep-graph/dep-graph-dump.rs @@ -0,0 +1,6 @@ +// Test dump-dep-graph requires query-dep-graph enabled + +// incremental +// compile-flags: -Z dump-dep-graph + +fn main() {} diff --git a/tests/ui/dep-graph/dep-graph-dump.stderr b/tests/ui/dep-graph/dep-graph-dump.stderr new file mode 100644 index 0000000000000..ea44b8bb07509 --- /dev/null +++ b/tests/ui/dep-graph/dep-graph-dump.stderr @@ -0,0 +1,2 @@ +error: can't dump dependency graph without `-Z query-dep-graph` + From fe96c11aba8ef34de187551572a8943d89ae26ac Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Mon, 16 Jan 2023 21:06:34 +0900 Subject: [PATCH 062/230] fix #104440 --- compiler/rustc_lint/src/context.rs | 47 ++++---- compiler/rustc_lint_defs/src/lib.rs | 2 +- .../rustc_resolve/src/late/diagnostics.rs | 22 +++- tests/ui/single-use-lifetime/issue-104440.rs | 100 ++++++++++++++++++ .../single-use-lifetime/issue-104440.stderr | 28 +++++ 5 files changed, 174 insertions(+), 25 deletions(-) create mode 100644 tests/ui/single-use-lifetime/issue-104440.rs create mode 100644 tests/ui/single-use-lifetime/issue-104440.stderr diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index c9b9a62257148..8046cc21cea58 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -825,21 +825,24 @@ pub trait LintContext: Sized { debug!(?param_span, ?use_span, ?deletion_span); db.span_label(param_span, "this lifetime..."); db.span_label(use_span, "...is used only here"); - let msg = "elide the single-use lifetime"; - let (use_span, replace_lt) = if elide { - let use_span = sess.source_map().span_extend_while( - use_span, - char::is_whitespace, - ).unwrap_or(use_span); - (use_span, String::new()) - } else { - (use_span, "'_".to_owned()) - }; - db.multipart_suggestion( - msg, - vec![(deletion_span, String::new()), (use_span, replace_lt)], - Applicability::MachineApplicable, - ); + if let Some(deletion_span) = deletion_span { + let msg = "elide the single-use lifetime"; + let (use_span, replace_lt) = if elide { + let use_span = sess.source_map().span_extend_while( + use_span, + char::is_whitespace, + ).unwrap_or(use_span); + (use_span, String::new()) + } else { + (use_span, "'_".to_owned()) + }; + debug!(?deletion_span, ?use_span); + db.multipart_suggestion( + msg, + vec![(deletion_span, String::new()), (use_span, replace_lt)], + Applicability::MachineApplicable, + ); + } }, BuiltinLintDiagnostics::SingleUseLifetime { param_span: _, @@ -847,12 +850,14 @@ pub trait LintContext: Sized { deletion_span, } => { debug!(?deletion_span); - db.span_suggestion( - deletion_span, - "elide the unused lifetime", - "", - Applicability::MachineApplicable, - ); + if let Some(deletion_span) = deletion_span { + db.span_suggestion( + deletion_span, + "elide the unused lifetime", + "", + Applicability::MachineApplicable, + ); + } }, BuiltinLintDiagnostics::NamedArgumentUsedPositionally{ position_sp_to_replace, position_sp_for_msg, named_arg_sp, named_arg_name, is_formatting_arg} => { db.span_label(named_arg_sp, "this named argument is referred to by position in formatting string"); diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index f4b4c5168bfd6..45e2467340bab 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -502,7 +502,7 @@ pub enum BuiltinLintDiagnostics { param_span: Span, /// Span of the code that should be removed when eliding this lifetime. /// This span should include leading or trailing comma. - deletion_span: Span, + deletion_span: Option, /// Span of the single use, or None if the lifetime is never used. /// If true, the lifetime will be fully elided. use_span: Option<(Span, bool)>, diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index d92b046d0b9f2..6d448433ee6db 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2188,15 +2188,31 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { let deletion_span = || { if params.len() == 1 { // if sole lifetime, remove the entire `<>` brackets - generics_span + Some(generics_span) } else if param_index == 0 { // if removing within `<>` brackets, we also want to // delete a leading or trailing comma as appropriate - param.span().to(params[param_index + 1].span().shrink_to_lo()) + match ( + param.span().find_ancestor_inside(generics_span), + params[param_index + 1].span().find_ancestor_inside(generics_span), + ) { + (Some(param_span), Some(next_param_span)) => { + Some(param_span.to(next_param_span.shrink_to_lo())) + } + _ => None, + } } else { // if removing within `<>` brackets, we also want to // delete a leading or trailing comma as appropriate - params[param_index - 1].span().shrink_to_hi().to(param.span()) + match ( + param.span().find_ancestor_inside(generics_span), + params[param_index - 1].span().find_ancestor_inside(generics_span), + ) { + (Some(param_span), Some(prev_param_span)) => { + Some(prev_param_span.shrink_to_hi().to(param_span)) + } + _ => None, + } } }; match use_set { diff --git a/tests/ui/single-use-lifetime/issue-104440.rs b/tests/ui/single-use-lifetime/issue-104440.rs new file mode 100644 index 0000000000000..0795e95303a1e --- /dev/null +++ b/tests/ui/single-use-lifetime/issue-104440.rs @@ -0,0 +1,100 @@ +#![feature(decl_macro, rustc_attrs)] +#![deny(single_use_lifetimes)] + +mod type_params { + macro m($T:ident) { + fn f<$T: Clone, T: PartialEq>(t1: $T, t2: T) -> ($T, bool) { + (t1.clone(), t2 == t2) + } + } + + #[rustc_macro_transparency = "semitransparent"] + macro n($T:ident) { + fn g<$T: Clone>(t1: $T, t2: T) -> (T, $T) { + (t1.clone(), t2.clone()) + } + fn h(t1: $T, t2: T) -> (T, $T) { + (t1.clone(), t2.clone()) + } + } + + #[rustc_macro_transparency = "transparent"] + macro p($T:ident) { + fn j<$T: Clone>(t1: $T, t2: T) -> (T, $T) { + (t1.clone(), t2.clone()) + } + fn k(t1: $T, t2: T) -> (T, $T) { + (t1.clone(), t2.clone()) + } + } + + m!(T); + n!(T); + p!(T); +} + +mod lifetime_params { + macro m($a:lifetime) { + fn f<'b, 'c, $a: 'b, 'a: 'c>(t1: &$a(), t2: &'a ()) -> (&'b (), &'c ()) { //~ ERROR lifetime parameter `'a` only used once + (t1, t2) + } + } + + #[rustc_macro_transparency = "semitransparent"] + macro n($a:lifetime) { + fn g<$a>(t1: &$a(), t2: &'a ()) -> (&'a (), &$a ()) { + (t1, t2) + } + fn h<'a>(t1: &$a(), t2: &'a ()) -> (&'a (), &$a ()) { + (t1, t2) + } + } + + #[rustc_macro_transparency = "transparent"] + macro p($a:lifetime) { + fn j<$a>(t1: &$a(), t2: &'a ()) -> (&'a (), &$a ()) { + (t1, t2) + } + fn k<'a>(t1: &$a(), t2: &'a ()) -> (&'a (), &$a ()) { + (t1, t2) + } + } + + m!('a); //~ ERROR lifetime parameter `'a` only used once + n!('a); + p!('a); +} + +mod const_params { + macro m($C:ident) { + fn f(t1: [(); $C], t2: [(); C]) -> ([(); $C], [(); C]) { + (t1, t2) + } + } + + #[rustc_macro_transparency = "semitransparent"] + macro n($C:ident) { + fn g(t1: [(); $C], t2: [(); C]) -> ([(); C], [(); $C]) { + (t1, t2) + } + fn h(t1: [(); $C], t2: [(); C]) -> ([(); C], [(); $C]) { + (t1, t2) + } + } + + #[rustc_macro_transparency = "transparent"] + macro p($C:ident) { + fn j(t1: [(); $C], t2: [(); C]) -> ([(); C], [(); $C]) { + (t1, t2) + } + fn k(t1: [(); $C], t2: [(); C]) -> ([(); C], [(); $C]) { + (t1, t2) + } + } + + m!(C); + n!(C); + p!(C); +} + +fn main() {} diff --git a/tests/ui/single-use-lifetime/issue-104440.stderr b/tests/ui/single-use-lifetime/issue-104440.stderr new file mode 100644 index 0000000000000..54ded31dcbe89 --- /dev/null +++ b/tests/ui/single-use-lifetime/issue-104440.stderr @@ -0,0 +1,28 @@ +error: lifetime parameter `'a` only used once + --> $DIR/issue-104440.rs:63:8 + | +LL | m!('a); + | ^^ + | | + | this lifetime... + | ...is used only here + | +note: the lint level is defined here + --> $DIR/issue-104440.rs:2:9 + | +LL | #![deny(single_use_lifetimes)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: lifetime parameter `'a` only used once + --> $DIR/issue-104440.rs:38:30 + | +LL | fn f<'b, 'c, $a: 'b, 'a: 'c>(t1: &$a(), t2: &'a ()) -> (&'b (), &'c ()) { + | ^^ this lifetime... -- ...is used only here +... +LL | m!('a); + | ------ in this macro invocation + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + From 9d74bb832f2529535a9896ba0ff2797679907415 Mon Sep 17 00:00:00 2001 From: yukang Date: Mon, 16 Jan 2023 20:44:14 +0800 Subject: [PATCH 063/230] comments feedback --- compiler/rustc_lint/src/unused.rs | 52 ++++++++++--------- .../lint/unused/issue-105061-should-lint.rs | 8 ++- .../unused/issue-105061-should-lint.stderr | 16 +++++- 3 files changed, 49 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 65f2644a858af..e40530a6dd67a 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -1009,31 +1009,35 @@ impl EarlyLintPass for UnusedParens { } fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) { - if let ast::TyKind::Array(_, len) = &ty.kind { - self.check_unused_delims_expr( - cx, - &len.value, - UnusedDelimsCtx::ArrayLenExpr, - false, - None, - None, - ); - } - if let ast::TyKind::Paren(r) = &ty.kind { - match &r.kind { - ast::TyKind::TraitObject(..) => {} - ast::TyKind::BareFn(b) - if self.with_self_ty_parens && b.generic_params.len() > 0 => {} - ast::TyKind::ImplTrait(_, bounds) if bounds.len() > 1 => {} - _ => { - let spans = if let Some(r) = r.span.find_ancestor_inside(ty.span) { - Some((ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi()))) - } else { - None - }; - self.emit_unused_delims(cx, ty.span, spans, "type", (false, false)); + match &ty.kind { + ast::TyKind::Array(_, len) => { + self.check_unused_delims_expr( + cx, + &len.value, + UnusedDelimsCtx::ArrayLenExpr, + false, + None, + None, + ); + } + ast::TyKind::Paren(r) => { + match &r.kind { + ast::TyKind::TraitObject(..) => {} + ast::TyKind::BareFn(b) + if self.with_self_ty_parens && b.generic_params.len() > 0 => {} + ast::TyKind::ImplTrait(_, bounds) if bounds.len() > 1 => {} + _ => { + let spans = if let Some(r) = r.span.find_ancestor_inside(ty.span) { + Some((ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi()))) + } else { + None + }; + self.emit_unused_delims(cx, ty.span, spans, "type", (false, false)); + } } + self.with_self_ty_parens = false; } + _ => {} } } @@ -1055,7 +1059,7 @@ impl EarlyLintPass for UnusedParens { } fn exit_where_predicate(&mut self, _: &EarlyContext<'_>, _: &ast::WherePredicate) { - self.with_self_ty_parens = false; + assert!(!self.with_self_ty_parens); } } diff --git a/tests/ui/lint/unused/issue-105061-should-lint.rs b/tests/ui/lint/unused/issue-105061-should-lint.rs index ff47e1734f7b0..7e4e09473493a 100644 --- a/tests/ui/lint/unused/issue-105061-should-lint.rs +++ b/tests/ui/lint/unused/issue-105061-should-lint.rs @@ -6,12 +6,18 @@ struct Inv<'a>(&'a mut &'a ()); trait Trait<'a> {} impl<'b> Trait<'b> for for<'a> fn(Inv<'a>) {} - fn with_bound() where for<'b> (for<'a> fn(Inv<'a>)): Trait<'b>, //~ ERROR unnecessary parentheses around type {} +trait Hello {} +fn with_dyn_bound() +where + (dyn Hello<(for<'b> fn(&'b ()))>): Hello //~ ERROR unnecessary parentheses around type +{} + fn main() { with_bound(); + with_dyn_bound(); } diff --git a/tests/ui/lint/unused/issue-105061-should-lint.stderr b/tests/ui/lint/unused/issue-105061-should-lint.stderr index 60b1af71e0e56..e591f1ffb6b89 100644 --- a/tests/ui/lint/unused/issue-105061-should-lint.stderr +++ b/tests/ui/lint/unused/issue-105061-should-lint.stderr @@ -1,5 +1,5 @@ error: unnecessary parentheses around type - --> $DIR/issue-105061-should-lint.rs:12:13 + --> $DIR/issue-105061-should-lint.rs:11:13 | LL | for<'b> (for<'a> fn(Inv<'a>)): Trait<'b>, | ^ ^ @@ -16,5 +16,17 @@ LL - for<'b> (for<'a> fn(Inv<'a>)): Trait<'b>, LL + for<'b> for<'a> fn(Inv<'a>): Trait<'b>, | -error: aborting due to previous error +error: unnecessary parentheses around type + --> $DIR/issue-105061-should-lint.rs:17:16 + | +LL | (dyn Hello<(for<'b> fn(&'b ()))>): Hello + | ^ ^ + | +help: remove these parentheses + | +LL - (dyn Hello<(for<'b> fn(&'b ()))>): Hello +LL + (dyn Hello fn(&'b ())>): Hello + | + +error: aborting due to 2 previous errors From c1f1f60bcbb7a0f4021e8aa1b6fa7113f2c6d27a Mon Sep 17 00:00:00 2001 From: gftea <1705787+gftea@users.noreply.github.com> Date: Tue, 20 Dec 2022 14:45:19 +0100 Subject: [PATCH 064/230] Update instrument-coverage.md Document the default for LLVM_PROFILE_FILE and add a recemmondation for setting it for older versions of Rust which had a different default. --- src/doc/rustc/src/instrument-coverage.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/doc/rustc/src/instrument-coverage.md b/src/doc/rustc/src/instrument-coverage.md index 38fd5c9699763..da91e25595cc7 100644 --- a/src/doc/rustc/src/instrument-coverage.md +++ b/src/doc/rustc/src/instrument-coverage.md @@ -201,6 +201,8 @@ $ RUSTFLAGS="-C instrument-coverage" \ cargo test --tests ``` +> **Note**: The default for `LLVM_PROFILE_FILE` is `default_%m_%p.profraw`. Versions prior to 1.65 had a default of `default.profraw`, so if using those earlier versions, it is recommended to explicitly set `LLVM_PROFILE_FILE="default_%m_%p.profraw"` to avoid having multiple tests overwrite the `.profraw` files. + Make note of the test binary file paths, displayed after the word "`Running`" in the test output: ```text From 42f75f1e462f90bfe20f458690113c3cb2a26271 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 7 Dec 2022 08:42:21 +0000 Subject: [PATCH 065/230] Group some commonly passed together values into a struct --- compiler/rustc_driver/src/lib.rs | 80 +++++++++-------------- compiler/rustc_driver/src/pretty.rs | 28 ++++---- compiler/rustc_interface/src/interface.rs | 44 +++++-------- compiler/rustc_interface/src/passes.rs | 17 ++--- compiler/rustc_interface/src/queries.rs | 4 +- compiler/rustc_interface/src/util.rs | 21 +++--- src/tools/miri/src/bin/miri.rs | 2 +- 7 files changed, 77 insertions(+), 119 deletions(-) diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index ec46fc8999a17..feb78cb0984e8 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -26,6 +26,7 @@ use rustc_errors::registry::{InvalidErrorCode, Registry}; use rustc_errors::{ErrorGuaranteed, PResult}; use rustc_feature::find_gated_cfg; use rustc_hir::def_id::LOCAL_CRATE; +use rustc_interface::interface::CompilerIO; use rustc_interface::util::{self, collect_crate_types, get_codegen_backend}; use rustc_interface::{interface, Queries}; use rustc_lint::LintStore; @@ -262,10 +263,8 @@ fn run_compiler( let should_stop = print_crate_info( &***compiler.codegen_backend(), compiler.session(), - None, - compiler.output_dir(), - compiler.output_file(), - compiler.temps_dir(), + false, + compiler.io(), ); if should_stop == Compilation::Stop { @@ -288,18 +287,16 @@ fn run_compiler( interface::run_compiler(config, |compiler| { let sess = compiler.session(); - let should_stop = print_crate_info( - &***compiler.codegen_backend(), - sess, - Some(compiler.input()), - compiler.output_dir(), - compiler.output_file(), - compiler.temps_dir(), - ) - .and_then(|| { - list_metadata(sess, &*compiler.codegen_backend().metadata_loader(), compiler.input()) - }) - .and_then(|| try_process_rlink(sess, compiler)); + let should_stop = + print_crate_info(&***compiler.codegen_backend(), sess, true, compiler.io()) + .and_then(|| { + list_metadata( + sess, + &*compiler.codegen_backend().metadata_loader(), + &compiler.io().input, + ) + }) + .and_then(|| try_process_rlink(sess, compiler)); if should_stop == Compilation::Stop { return sess.compile_status(); @@ -315,22 +312,15 @@ fn run_compiler( queries.global_ctxt()?.enter(|tcx| { pretty::print_after_hir_lowering( tcx, - compiler.input(), + compiler.io(), &*expanded_crate, *ppm, - compiler.output_file().as_deref(), ); Ok(()) })?; } else { let krate = queries.parse()?.steal(); - pretty::print_after_parsing( - sess, - compiler.input(), - &krate, - *ppm, - compiler.output_file().as_deref(), - ); + pretty::print_after_parsing(sess, compiler.io(), &krate, *ppm); } trace!("finished pretty-printing"); return early_exit(); @@ -380,9 +370,9 @@ fn run_compiler( save::process_crate( tcx, crate_name, - compiler.input(), + &compiler.io().input, None, - DumpHandler::new(compiler.output_dir().as_deref(), crate_name), + DumpHandler::new(compiler.io().output_dir.as_deref(), crate_name), ) }); } @@ -556,7 +546,7 @@ fn show_content_with_pager(content: &str) { pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Compilation { if sess.opts.unstable_opts.link_only { - if let Input::File(file) = compiler.input() { + if let Input::File(file) = &compiler.io().input { // FIXME: #![crate_type] and #![crate_name] support not implemented yet sess.init_crate_types(collect_crate_types(sess, &[])); let outputs = compiler.build_output_filenames(sess, &[]); @@ -623,10 +613,8 @@ pub fn list_metadata( fn print_crate_info( codegen_backend: &dyn CodegenBackend, sess: &Session, - input: Option<&Input>, - odir: &Option, - ofile: &Option, - temps_dir: &Option, + parse_attrs: bool, + io: &CompilerIO, ) -> Compilation { use rustc_session::config::PrintRequest::*; // NativeStaticLibs and LinkArgs are special - printed during linking @@ -635,18 +623,17 @@ fn print_crate_info( return Compilation::Continue; } - let attrs = match input { - None => None, - Some(input) => { - let result = parse_crate_attrs(sess, input); - match result { - Ok(attrs) => Some(attrs), - Err(mut parse_error) => { - parse_error.emit(); - return Compilation::Stop; - } + let attrs = if parse_attrs { + let result = parse_crate_attrs(sess, &io.input); + match result { + Ok(attrs) => Some(attrs), + Err(mut parse_error) => { + parse_error.emit(); + return Compilation::Stop; } } + } else { + None }; for req in &sess.opts.prints { match *req { @@ -661,14 +648,9 @@ fn print_crate_info( println!("{}", serde_json::to_string_pretty(&sess.target.to_json()).unwrap()); } FileNames | CrateName => { - let input = input.unwrap_or_else(|| { - early_error(ErrorOutputType::default(), "no input file provided") - }); let attrs = attrs.as_ref().unwrap(); - let t_outputs = rustc_interface::util::build_output_filenames( - input, odir, ofile, temps_dir, attrs, sess, - ); - let id = rustc_session::output::find_crate_name(sess, attrs, input); + let t_outputs = rustc_interface::util::build_output_filenames(io, attrs, sess); + let id = rustc_session::output::find_crate_name(sess, attrs, &io.input); if *req == PrintRequest::CrateName { println!("{id}"); continue; diff --git a/compiler/rustc_driver/src/pretty.rs b/compiler/rustc_driver/src/pretty.rs index b2451bc730f79..dd24f0bc98f10 100644 --- a/compiler/rustc_driver/src/pretty.rs +++ b/compiler/rustc_driver/src/pretty.rs @@ -6,6 +6,7 @@ use rustc_ast_pretty::pprust; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir_pretty as pprust_hir; +use rustc_interface::interface::CompilerIO; use rustc_middle::hir::map as hir_map; use rustc_middle::mir::{write_mir_graphviz, write_mir_pretty}; use rustc_middle::ty::{self, TyCtxt}; @@ -16,7 +17,7 @@ use rustc_span::FileName; use std::cell::Cell; use std::fmt::Write; -use std::path::Path; +use std::path::PathBuf; pub use self::PpMode::*; pub use self::PpSourceMode::*; @@ -358,7 +359,7 @@ fn get_source(input: &Input, sess: &Session) -> (String, FileName) { (src, src_name) } -fn write_or_print(out: &str, ofile: Option<&Path>, sess: &Session) { +fn write_or_print(out: &str, ofile: &Option, sess: &Session) { match ofile { None => print!("{out}"), Some(p) => { @@ -372,14 +373,8 @@ fn write_or_print(out: &str, ofile: Option<&Path>, sess: &Session) { } } -pub fn print_after_parsing( - sess: &Session, - input: &Input, - krate: &ast::Crate, - ppm: PpMode, - ofile: Option<&Path>, -) { - let (src, src_name) = get_source(input, sess); +pub fn print_after_parsing(sess: &Session, io: &CompilerIO, krate: &ast::Crate, ppm: PpMode) { + let (src, src_name) = get_source(&io.input, sess); let out = match ppm { Source(s) => { @@ -407,22 +402,21 @@ pub fn print_after_parsing( _ => unreachable!(), }; - write_or_print(&out, ofile, sess); + write_or_print(&out, &io.output_file, sess); } pub fn print_after_hir_lowering<'tcx>( tcx: TyCtxt<'tcx>, - input: &Input, + io: &CompilerIO, krate: &ast::Crate, ppm: PpMode, - ofile: Option<&Path>, ) { if ppm.needs_analysis() { - abort_on_err(print_with_analysis(tcx, ppm, ofile), tcx.sess); + abort_on_err(print_with_analysis(tcx, ppm, &io.output_file), tcx.sess); return; } - let (src, src_name) = get_source(input, tcx.sess); + let (src, src_name) = get_source(&io.input, tcx.sess); let out = match ppm { Source(s) => { @@ -474,7 +468,7 @@ pub fn print_after_hir_lowering<'tcx>( _ => unreachable!(), }; - write_or_print(&out, ofile, tcx.sess); + write_or_print(&out, &io.output_file, tcx.sess); } // In an ideal world, this would be a public function called by the driver after @@ -484,7 +478,7 @@ pub fn print_after_hir_lowering<'tcx>( fn print_with_analysis( tcx: TyCtxt<'_>, ppm: PpMode, - ofile: Option<&Path>, + ofile: &Option, ) -> Result<(), ErrorGuaranteed> { tcx.analysis(())?; let out = match ppm { diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 22a01db5e7573..e3c4f9052cebe 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -35,15 +35,19 @@ pub type Result = result::Result; pub struct Compiler { pub(crate) sess: Lrc, codegen_backend: Lrc>, - pub(crate) input: Input, - pub(crate) output_dir: Option, - pub(crate) output_file: Option, - pub(crate) temps_dir: Option, + pub(crate) io: CompilerIO, pub(crate) register_lints: Option>, pub(crate) override_queries: Option, } +pub struct CompilerIO { + pub input: Input, + pub output_dir: Option, + pub output_file: Option, + pub temps_dir: Option, +} + impl Compiler { pub fn session(&self) -> &Lrc { &self.sess @@ -51,17 +55,8 @@ impl Compiler { pub fn codegen_backend(&self) -> &Lrc> { &self.codegen_backend } - pub fn input(&self) -> &Input { - &self.input - } - pub fn output_dir(&self) -> &Option { - &self.output_dir - } - pub fn output_file(&self) -> &Option { - &self.output_file - } - pub fn temps_dir(&self) -> &Option { - &self.temps_dir + pub fn io(&self) -> &CompilerIO { + &self.io } pub fn register_lints(&self) -> &Option> { &self.register_lints @@ -71,14 +66,7 @@ impl Compiler { sess: &Session, attrs: &[ast::Attribute], ) -> OutputFilenames { - util::build_output_filenames( - &self.input, - &self.output_dir, - &self.output_file, - &self.temps_dir, - attrs, - sess, - ) + util::build_output_filenames(&self.io, attrs, sess) } } @@ -305,10 +293,12 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se let compiler = Compiler { sess: Lrc::new(sess), codegen_backend: Lrc::new(codegen_backend), - input: config.input, - output_dir: config.output_dir, - output_file: config.output_file, - temps_dir, + io: CompilerIO { + input: config.input, + output_dir: config.output_dir, + output_file: config.output_file, + temps_dir, + }, register_lints: config.register_lints, override_queries: config.override_queries, }; diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index bba0a50a93fae..8545cbefa262f 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -673,20 +673,13 @@ pub fn prepare_outputs( let _timer = sess.timer("prepare_outputs"); // FIXME: rustdoc passes &[] instead of &krate.attrs here - let outputs = util::build_output_filenames( - &compiler.input, - &compiler.output_dir, - &compiler.output_file, - &compiler.temps_dir, - &krate.attrs, - sess, - ); + let outputs = util::build_output_filenames(&compiler.io, &krate.attrs, sess); let output_paths = - generated_output_paths(sess, &outputs, compiler.output_file.is_some(), crate_name); + generated_output_paths(sess, &outputs, compiler.io.output_file.is_some(), crate_name); // Ensure the source file isn't accidentally overwritten during compilation. - if let Some(ref input_path) = compiler.input.opt_path() { + if let Some(ref input_path) = compiler.io.input.opt_path() { if sess.opts.will_create_output_file() { if output_contains_path(&output_paths, input_path) { let reported = sess.emit_err(InputFileWouldBeOverWritten { path: input_path }); @@ -700,7 +693,7 @@ pub fn prepare_outputs( } } - if let Some(ref dir) = compiler.temps_dir { + if let Some(ref dir) = compiler.io.temps_dir { if fs::create_dir_all(dir).is_err() { let reported = sess.emit_err(TempsDirError); return Err(reported); @@ -713,7 +706,7 @@ pub fn prepare_outputs( && sess.opts.output_types.len() == 1; if !only_dep_info { - if let Some(ref dir) = compiler.output_dir { + if let Some(ref dir) = compiler.io.output_dir { if fs::create_dir_all(dir).is_err() { let reported = sess.emit_err(OutDirError); return Err(reported); diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 6f791c8893ce3..32348fd72edd3 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -129,7 +129,7 @@ impl<'tcx> Queries<'tcx> { pub fn parse(&self) -> Result> { self.parse.compute(|| { - passes::parse(self.session(), &self.compiler.input) + passes::parse(self.session(), &self.compiler.io.input) .map_err(|mut parse_error| parse_error.emit()) }) } @@ -165,7 +165,7 @@ impl<'tcx> Queries<'tcx> { let parse_result = self.parse()?; let krate = parse_result.borrow(); // parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches. - find_crate_name(self.session(), &krate.attrs, &self.compiler.input) + find_crate_name(self.session(), &krate.attrs, &self.compiler.io.input) }) }) } diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 02a7756c8d453..f19b03c75ebfd 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -8,7 +8,7 @@ use rustc_parse::validate_attr; use rustc_session as session; use rustc_session::config::CheckCfg; use rustc_session::config::{self, CrateType}; -use rustc_session::config::{ErrorOutputType, Input, OutputFilenames}; +use rustc_session::config::{ErrorOutputType, OutputFilenames}; use rustc_session::filesearch::sysroot_candidates; use rustc_session::lint::{self, BuiltinLintDiagnostics, LintBuffer}; use rustc_session::parse::CrateConfig; @@ -25,6 +25,8 @@ use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::OnceLock; use std::thread; +use crate::interface::CompilerIO; + /// Function pointer type that constructs a new CodegenBackend. pub type MakeBackendFn = fn() -> Box; @@ -487,19 +489,16 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec, - ofile: &Option, - temps_dir: &Option, + io: &CompilerIO, attrs: &[ast::Attribute], sess: &Session, ) -> OutputFilenames { - match *ofile { + match io.output_file { None => { // "-" as input file will cause the parser to read from stdin so we // have to make up a name // We want to toss everything after the final '.' - let dirpath = (*odir).as_ref().cloned().unwrap_or_default(); + let dirpath = io.output_dir.clone().unwrap_or_default(); // If a crate name is present, we use it as the link name let stem = sess @@ -507,13 +506,13 @@ pub fn build_output_filenames( .crate_name .clone() .or_else(|| rustc_attr::find_crate_name(sess, attrs).map(|n| n.to_string())) - .unwrap_or_else(|| input.filestem().to_owned()); + .unwrap_or_else(|| io.input.filestem().to_owned()); OutputFilenames::new( dirpath, stem, None, - temps_dir.clone(), + io.temps_dir.clone(), sess.opts.cg.extra_filename.clone(), sess.opts.output_types.clone(), ) @@ -534,7 +533,7 @@ pub fn build_output_filenames( } Some(out_file.clone()) }; - if *odir != None { + if io.output_dir != None { sess.warn("ignoring --out-dir flag due to -o flag"); } @@ -542,7 +541,7 @@ pub fn build_output_filenames( out_file.parent().unwrap_or_else(|| Path::new("")).to_path_buf(), out_file.file_stem().unwrap_or_default().to_str().unwrap().to_string(), ofile, - temps_dir.clone(), + io.temps_dir.clone(), sess.opts.cg.extra_filename.clone(), sess.opts.output_types.clone(), ) diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 6a147de3be2ea..d52c7819c567a 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -75,7 +75,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { let mut config = self.miri_config.clone(); // Add filename to `miri` arguments. - config.args.insert(0, compiler.input().filestem().to_string()); + config.args.insert(0, compiler.io().input.filestem().to_string()); // Adjust working directory for interpretation. if let Some(cwd) = env::var_os("MIRI_CWD") { From 9f5cd0315386e761beae8afd07df94e42a4db154 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 7 Dec 2022 09:24:00 +0000 Subject: [PATCH 066/230] Move compiler input and ouput paths into session --- .../src/debuginfo/mod.rs | 2 +- .../src/debuginfo/metadata.rs | 8 +-- compiler/rustc_driver/src/lib.rs | 56 ++++++------------- compiler/rustc_driver/src/pretty.rs | 39 +++++-------- compiler/rustc_interface/src/interface.rs | 32 ++++------- compiler/rustc_interface/src/passes.rs | 15 +++-- compiler/rustc_interface/src/queries.rs | 16 ++---- compiler/rustc_interface/src/tests.rs | 12 +++- compiler/rustc_interface/src/util.rs | 25 ++++----- compiler/rustc_passes/src/entry.rs | 2 +- .../rustc_save_analysis/src/dump_visitor.rs | 16 +++--- compiler/rustc_session/src/output.rs | 4 +- compiler/rustc_session/src/session.rs | 27 +++++---- src/librustdoc/html/render/mod.rs | 2 +- src/tools/miri/src/bin/miri.rs | 11 ++-- 15 files changed, 113 insertions(+), 154 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs index 2ba012a77b0a9..28fbcb15b2b58 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs @@ -68,7 +68,7 @@ impl DebugContext { .working_dir .to_string_lossy(FileNameDisplayPreference::Remapped) .into_owned(); - let (name, file_info) = match tcx.sess.local_crate_source_file.clone() { + let (name, file_info) = match tcx.sess.local_crate_source_file() { Some(path) => { let name = path.to_string_lossy().into_owned(); (name, None) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 48e3a812e4f20..b6eb5ee183fa3 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -782,10 +782,10 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>( codegen_unit_name: &str, debug_context: &CodegenUnitDebugContext<'ll, 'tcx>, ) -> &'ll DIDescriptor { - let mut name_in_debuginfo = match tcx.sess.local_crate_source_file { - Some(ref path) => path.clone(), - None => PathBuf::from(tcx.crate_name(LOCAL_CRATE).as_str()), - }; + let mut name_in_debuginfo = tcx + .sess + .local_crate_source_file() + .unwrap_or_else(|| PathBuf::from(tcx.crate_name(LOCAL_CRATE).as_str())); // To avoid breaking split DWARF, we need to ensure that each codegen unit // has a unique `DW_AT_name`. This is because there's a remote chance that diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index feb78cb0984e8..66dadf97b1987 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -26,7 +26,6 @@ use rustc_errors::registry::{InvalidErrorCode, Registry}; use rustc_errors::{ErrorGuaranteed, PResult}; use rustc_feature::find_gated_cfg; use rustc_hir::def_id::LOCAL_CRATE; -use rustc_interface::interface::CompilerIO; use rustc_interface::util::{self, collect_crate_types, get_codegen_backend}; use rustc_interface::{interface, Queries}; use rustc_lint::LintStore; @@ -260,12 +259,8 @@ fn run_compiler( describe_lints(compiler.session(), &lint_store, registered_lints); return; } - let should_stop = print_crate_info( - &***compiler.codegen_backend(), - compiler.session(), - false, - compiler.io(), - ); + let should_stop = + print_crate_info(&***compiler.codegen_backend(), compiler.session(), false); if should_stop == Compilation::Stop { return; @@ -287,16 +282,9 @@ fn run_compiler( interface::run_compiler(config, |compiler| { let sess = compiler.session(); - let should_stop = - print_crate_info(&***compiler.codegen_backend(), sess, true, compiler.io()) - .and_then(|| { - list_metadata( - sess, - &*compiler.codegen_backend().metadata_loader(), - &compiler.io().input, - ) - }) - .and_then(|| try_process_rlink(sess, compiler)); + let should_stop = print_crate_info(&***compiler.codegen_backend(), sess, true) + .and_then(|| list_metadata(sess, &*compiler.codegen_backend().metadata_loader())) + .and_then(|| try_process_rlink(sess, compiler)); if should_stop == Compilation::Stop { return sess.compile_status(); @@ -310,17 +298,12 @@ fn run_compiler( if ppm.needs_ast_map() { let expanded_crate = queries.expansion()?.borrow().0.clone(); queries.global_ctxt()?.enter(|tcx| { - pretty::print_after_hir_lowering( - tcx, - compiler.io(), - &*expanded_crate, - *ppm, - ); + pretty::print_after_hir_lowering(tcx, &*expanded_crate, *ppm); Ok(()) })?; } else { let krate = queries.parse()?.steal(); - pretty::print_after_parsing(sess, compiler.io(), &krate, *ppm); + pretty::print_after_parsing(sess, &krate, *ppm); } trace!("finished pretty-printing"); return early_exit(); @@ -370,9 +353,9 @@ fn run_compiler( save::process_crate( tcx, crate_name, - &compiler.io().input, + &sess.io.input, None, - DumpHandler::new(compiler.io().output_dir.as_deref(), crate_name), + DumpHandler::new(sess.io.output_dir.as_deref(), crate_name), ) }); } @@ -546,7 +529,7 @@ fn show_content_with_pager(content: &str) { pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Compilation { if sess.opts.unstable_opts.link_only { - if let Input::File(file) = &compiler.io().input { + if let Input::File(file) = &sess.io.input { // FIXME: #![crate_type] and #![crate_name] support not implemented yet sess.init_crate_types(collect_crate_types(sess, &[])); let outputs = compiler.build_output_filenames(sess, &[]); @@ -587,13 +570,9 @@ pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Comp } } -pub fn list_metadata( - sess: &Session, - metadata_loader: &dyn MetadataLoader, - input: &Input, -) -> Compilation { +pub fn list_metadata(sess: &Session, metadata_loader: &dyn MetadataLoader) -> Compilation { if sess.opts.unstable_opts.ls { - match *input { + match sess.io.input { Input::File(ref ifile) => { let path = &(*ifile); let mut v = Vec::new(); @@ -614,7 +593,6 @@ fn print_crate_info( codegen_backend: &dyn CodegenBackend, sess: &Session, parse_attrs: bool, - io: &CompilerIO, ) -> Compilation { use rustc_session::config::PrintRequest::*; // NativeStaticLibs and LinkArgs are special - printed during linking @@ -624,7 +602,7 @@ fn print_crate_info( } let attrs = if parse_attrs { - let result = parse_crate_attrs(sess, &io.input); + let result = parse_crate_attrs(sess); match result { Ok(attrs) => Some(attrs), Err(mut parse_error) => { @@ -649,8 +627,8 @@ fn print_crate_info( } FileNames | CrateName => { let attrs = attrs.as_ref().unwrap(); - let t_outputs = rustc_interface::util::build_output_filenames(io, attrs, sess); - let id = rustc_session::output::find_crate_name(sess, attrs, &io.input); + let t_outputs = rustc_interface::util::build_output_filenames(attrs, sess); + let id = rustc_session::output::find_crate_name(sess, attrs); if *req == PrintRequest::CrateName { println!("{id}"); continue; @@ -1086,8 +1064,8 @@ pub fn handle_options(args: &[String]) -> Option { Some(matches) } -fn parse_crate_attrs<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::AttrVec> { - match input { +fn parse_crate_attrs<'a>(sess: &'a Session) -> PResult<'a, ast::AttrVec> { + match &sess.io.input { Input::File(ifile) => rustc_parse::parse_crate_attrs_from_file(ifile, &sess.parse_sess), Input::Str { name, input } => rustc_parse::parse_crate_attrs_from_source_str( name.clone(), diff --git a/compiler/rustc_driver/src/pretty.rs b/compiler/rustc_driver/src/pretty.rs index dd24f0bc98f10..ae3ac8625b186 100644 --- a/compiler/rustc_driver/src/pretty.rs +++ b/compiler/rustc_driver/src/pretty.rs @@ -6,18 +6,16 @@ use rustc_ast_pretty::pprust; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir_pretty as pprust_hir; -use rustc_interface::interface::CompilerIO; use rustc_middle::hir::map as hir_map; use rustc_middle::mir::{write_mir_graphviz, write_mir_pretty}; use rustc_middle::ty::{self, TyCtxt}; -use rustc_session::config::{Input, PpAstTreeMode, PpHirMode, PpMode, PpSourceMode}; +use rustc_session::config::{PpAstTreeMode, PpHirMode, PpMode, PpSourceMode}; use rustc_session::Session; use rustc_span::symbol::Ident; use rustc_span::FileName; use std::cell::Cell; use std::fmt::Write; -use std::path::PathBuf; pub use self::PpMode::*; pub use self::PpSourceMode::*; @@ -346,8 +344,8 @@ impl<'tcx> pprust_hir::PpAnn for TypedAnnotation<'tcx> { } } -fn get_source(input: &Input, sess: &Session) -> (String, FileName) { - let src_name = input.source_name(); +fn get_source(sess: &Session) -> (String, FileName) { + let src_name = sess.io.input.source_name(); let src = String::clone( sess.source_map() .get_source_file(&src_name) @@ -359,8 +357,8 @@ fn get_source(input: &Input, sess: &Session) -> (String, FileName) { (src, src_name) } -fn write_or_print(out: &str, ofile: &Option, sess: &Session) { - match ofile { +fn write_or_print(out: &str, sess: &Session) { + match &sess.io.output_file { None => print!("{out}"), Some(p) => { if let Err(e) = std::fs::write(p, out) { @@ -373,8 +371,8 @@ fn write_or_print(out: &str, ofile: &Option, sess: &Session) { } } -pub fn print_after_parsing(sess: &Session, io: &CompilerIO, krate: &ast::Crate, ppm: PpMode) { - let (src, src_name) = get_source(&io.input, sess); +pub fn print_after_parsing(sess: &Session, krate: &ast::Crate, ppm: PpMode) { + let (src, src_name) = get_source(sess); let out = match ppm { Source(s) => { @@ -402,21 +400,16 @@ pub fn print_after_parsing(sess: &Session, io: &CompilerIO, krate: &ast::Crate, _ => unreachable!(), }; - write_or_print(&out, &io.output_file, sess); + write_or_print(&out, sess); } -pub fn print_after_hir_lowering<'tcx>( - tcx: TyCtxt<'tcx>, - io: &CompilerIO, - krate: &ast::Crate, - ppm: PpMode, -) { +pub fn print_after_hir_lowering<'tcx>(tcx: TyCtxt<'tcx>, krate: &ast::Crate, ppm: PpMode) { if ppm.needs_analysis() { - abort_on_err(print_with_analysis(tcx, ppm, &io.output_file), tcx.sess); + abort_on_err(print_with_analysis(tcx, ppm), tcx.sess); return; } - let (src, src_name) = get_source(&io.input, tcx.sess); + let (src, src_name) = get_source(tcx.sess); let out = match ppm { Source(s) => { @@ -468,18 +461,14 @@ pub fn print_after_hir_lowering<'tcx>( _ => unreachable!(), }; - write_or_print(&out, &io.output_file, tcx.sess); + write_or_print(&out, tcx.sess); } // In an ideal world, this would be a public function called by the driver after // analysis is performed. However, we want to call `phase_3_run_analysis_passes` // with a different callback than the standard driver, so that isn't easy. // Instead, we call that function ourselves. -fn print_with_analysis( - tcx: TyCtxt<'_>, - ppm: PpMode, - ofile: &Option, -) -> Result<(), ErrorGuaranteed> { +fn print_with_analysis(tcx: TyCtxt<'_>, ppm: PpMode) -> Result<(), ErrorGuaranteed> { tcx.analysis(())?; let out = match ppm { Mir => { @@ -512,7 +501,7 @@ fn print_with_analysis( _ => unreachable!(), }; - write_or_print(&out, ofile, tcx.sess); + write_or_print(&out, tcx.sess); Ok(()) } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index e3c4f9052cebe..7a5e45ada3f6a 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -14,10 +14,10 @@ use rustc_middle::ty; use rustc_parse::maybe_new_parser_from_source_str; use rustc_query_impl::QueryCtxt; use rustc_session::config::{self, CheckCfg, ErrorOutputType, Input, OutputFilenames}; -use rustc_session::early_error; use rustc_session::lint; use rustc_session::parse::{CrateConfig, ParseSess}; use rustc_session::Session; +use rustc_session::{early_error, CompilerIO}; use rustc_span::source_map::{FileLoader, FileName}; use rustc_span::symbol::sym; use std::path::PathBuf; @@ -35,19 +35,11 @@ pub type Result = result::Result; pub struct Compiler { pub(crate) sess: Lrc, codegen_backend: Lrc>, - pub(crate) io: CompilerIO, pub(crate) register_lints: Option>, pub(crate) override_queries: Option, } -pub struct CompilerIO { - pub input: Input, - pub output_dir: Option, - pub output_file: Option, - pub temps_dir: Option, -} - impl Compiler { pub fn session(&self) -> &Lrc { &self.sess @@ -55,9 +47,6 @@ impl Compiler { pub fn codegen_backend(&self) -> &Lrc> { &self.codegen_backend } - pub fn io(&self) -> &CompilerIO { - &self.io - } pub fn register_lints(&self) -> &Option> { &self.register_lints } @@ -66,7 +55,7 @@ impl Compiler { sess: &Session, attrs: &[ast::Attribute], ) -> OutputFilenames { - util::build_output_filenames(&self.io, attrs, sess) + util::build_output_filenames(attrs, sess) } } @@ -273,12 +262,19 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se crate::callbacks::setup_callbacks(); let registry = &config.registry; + + let temps_dir = config.opts.unstable_opts.temps_dir.as_deref().map(PathBuf::from); let (mut sess, codegen_backend) = util::create_session( config.opts, config.crate_cfg, config.crate_check_cfg, config.file_loader, - config.input.opt_path(), + CompilerIO { + input: config.input, + output_dir: config.output_dir, + output_file: config.output_file, + temps_dir, + }, config.lint_caps, config.make_codegen_backend, registry.clone(), @@ -288,17 +284,9 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se parse_sess_created(&mut sess.parse_sess); } - let temps_dir = sess.opts.unstable_opts.temps_dir.as_deref().map(PathBuf::from); - let compiler = Compiler { sess: Lrc::new(sess), codegen_backend: Lrc::new(codegen_backend), - io: CompilerIO { - input: config.input, - output_dir: config.output_dir, - output_file: config.output_file, - temps_dir, - }, register_lints: config.register_lints, override_queries: config.override_queries, }; diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 8545cbefa262f..2fa846b7e4bfc 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -50,8 +50,8 @@ use std::rc::Rc; use std::sync::LazyLock; use std::{env, fs, iter}; -pub fn parse<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> { - let krate = sess.time("parse_crate", || match input { +pub fn parse<'a>(sess: &'a Session) -> PResult<'a, ast::Crate> { + let krate = sess.time("parse_crate", || match &sess.io.input { Input::File(file) => parse_crate_from_file(file, &sess.parse_sess), Input::Str { input, name } => { parse_crate_from_source_str(name.clone(), input.clone(), &sess.parse_sess) @@ -665,7 +665,6 @@ fn write_out_deps( pub fn prepare_outputs( sess: &Session, - compiler: &Compiler, krate: &ast::Crate, boxed_resolver: &RefCell, crate_name: Symbol, @@ -673,13 +672,13 @@ pub fn prepare_outputs( let _timer = sess.timer("prepare_outputs"); // FIXME: rustdoc passes &[] instead of &krate.attrs here - let outputs = util::build_output_filenames(&compiler.io, &krate.attrs, sess); + let outputs = util::build_output_filenames(&krate.attrs, sess); let output_paths = - generated_output_paths(sess, &outputs, compiler.io.output_file.is_some(), crate_name); + generated_output_paths(sess, &outputs, sess.io.output_file.is_some(), crate_name); // Ensure the source file isn't accidentally overwritten during compilation. - if let Some(ref input_path) = compiler.io.input.opt_path() { + if let Some(ref input_path) = sess.io.input.opt_path() { if sess.opts.will_create_output_file() { if output_contains_path(&output_paths, input_path) { let reported = sess.emit_err(InputFileWouldBeOverWritten { path: input_path }); @@ -693,7 +692,7 @@ pub fn prepare_outputs( } } - if let Some(ref dir) = compiler.io.temps_dir { + if let Some(ref dir) = sess.io.temps_dir { if fs::create_dir_all(dir).is_err() { let reported = sess.emit_err(TempsDirError); return Err(reported); @@ -706,7 +705,7 @@ pub fn prepare_outputs( && sess.opts.output_types.len() == 1; if !only_dep_info { - if let Some(ref dir) = compiler.io.output_dir { + if let Some(ref dir) = sess.io.output_dir { if fs::create_dir_all(dir).is_err() { let reported = sess.emit_err(OutDirError); return Err(reported); diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 32348fd72edd3..dcfb4f43bd018 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -128,10 +128,8 @@ impl<'tcx> Queries<'tcx> { } pub fn parse(&self) -> Result> { - self.parse.compute(|| { - passes::parse(self.session(), &self.compiler.io.input) - .map_err(|mut parse_error| parse_error.emit()) - }) + self.parse + .compute(|| passes::parse(self.session()).map_err(|mut parse_error| parse_error.emit())) } pub fn register_plugins(&self) -> Result)>> { @@ -165,7 +163,7 @@ impl<'tcx> Queries<'tcx> { let parse_result = self.parse()?; let krate = parse_result.borrow(); // parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches. - find_crate_name(self.session(), &krate.attrs, &self.compiler.io.input) + find_crate_name(self.session(), &krate.attrs) }) }) } @@ -214,13 +212,7 @@ impl<'tcx> Queries<'tcx> { let crate_name = *self.crate_name()?.borrow(); let (krate, resolver, lint_store) = self.expansion()?.steal(); - let outputs = passes::prepare_outputs( - self.session(), - self.compiler, - &krate, - &resolver, - crate_name, - )?; + let outputs = passes::prepare_outputs(self.session(), &krate, &resolver, crate_name)?; let ty::ResolverOutputs { untracked, diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 07b28cc86cee1..f94bc4d4c66ac 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -4,6 +4,7 @@ use crate::interface::parse_cfgspecs; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig}; use rustc_session::config::rustc_optgroups; +use rustc_session::config::Input; use rustc_session::config::TraitSolver; use rustc_session::config::{build_configuration, build_session_options, to_crate_config}; use rustc_session::config::{ @@ -17,9 +18,11 @@ use rustc_session::config::{InstrumentCoverage, Passes}; use rustc_session::lint::Level; use rustc_session::search_paths::SearchPath; use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind}; +use rustc_session::CompilerIO; use rustc_session::{build_session, getopts, Session}; use rustc_span::edition::{Edition, DEFAULT_EDITION}; use rustc_span::symbol::sym; +use rustc_span::FileName; use rustc_span::SourceFileHashAlgorithm; use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, RelocModel}; use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel}; @@ -39,7 +42,14 @@ fn build_session_options_and_crate_config(matches: getopts::Matches) -> (Options fn mk_session(matches: getopts::Matches) -> (Session, CfgSpecs) { let registry = registry::Registry::new(&[]); let (sessopts, cfg) = build_session_options_and_crate_config(matches); - let sess = build_session(sessopts, None, None, registry, Default::default(), None, None); + let temps_dir = sessopts.unstable_opts.temps_dir.as_deref().map(PathBuf::from); + let io = CompilerIO { + input: Input::Str { name: FileName::Custom(String::new()), input: String::new() }, + output_dir: None, + output_file: None, + temps_dir, + }; + let sess = build_session(sessopts, io, None, registry, Default::default(), None, None); (sess, cfg) } diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index f19b03c75ebfd..54363e07b971a 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -17,6 +17,7 @@ use rustc_span::edition::Edition; use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::source_map::FileLoader; use rustc_span::symbol::{sym, Symbol}; +use session::CompilerIO; use std::env; use std::env::consts::{DLL_PREFIX, DLL_SUFFIX}; use std::mem; @@ -25,8 +26,6 @@ use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::OnceLock; use std::thread; -use crate::interface::CompilerIO; - /// Function pointer type that constructs a new CodegenBackend. pub type MakeBackendFn = fn() -> Box; @@ -60,7 +59,7 @@ pub fn create_session( cfg: FxHashSet<(String, Option)>, check_cfg: CheckCfg, file_loader: Option>, - input_path: Option, + io: CompilerIO, lint_caps: FxHashMap, make_codegen_backend: Option< Box Box + Send>, @@ -91,7 +90,7 @@ pub fn create_session( let mut sess = session::build_session( sopts, - input_path, + io, bundle, descriptions, lint_caps, @@ -488,17 +487,13 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec OutputFilenames { - match io.output_file { +pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> OutputFilenames { + match sess.io.output_file { None => { // "-" as input file will cause the parser to read from stdin so we // have to make up a name // We want to toss everything after the final '.' - let dirpath = io.output_dir.clone().unwrap_or_default(); + let dirpath = sess.io.output_dir.clone().unwrap_or_default(); // If a crate name is present, we use it as the link name let stem = sess @@ -506,13 +501,13 @@ pub fn build_output_filenames( .crate_name .clone() .or_else(|| rustc_attr::find_crate_name(sess, attrs).map(|n| n.to_string())) - .unwrap_or_else(|| io.input.filestem().to_owned()); + .unwrap_or_else(|| sess.io.input.filestem().to_owned()); OutputFilenames::new( dirpath, stem, None, - io.temps_dir.clone(), + sess.io.temps_dir.clone(), sess.opts.cg.extra_filename.clone(), sess.opts.output_types.clone(), ) @@ -533,7 +528,7 @@ pub fn build_output_filenames( } Some(out_file.clone()) }; - if io.output_dir != None { + if sess.io.output_dir != None { sess.warn("ignoring --out-dir flag due to -o flag"); } @@ -541,7 +536,7 @@ pub fn build_output_filenames( out_file.parent().unwrap_or_else(|| Path::new("")).to_path_buf(), out_file.file_stem().unwrap_or_default().to_str().unwrap().to_string(), ofile, - io.temps_dir.clone(), + sess.io.temps_dir.clone(), sess.opts.cg.extra_filename.clone(), sess.opts.output_types.clone(), ) diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index 5885f45ae45db..b327ba63330ba 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -195,7 +195,7 @@ fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) { // There is no main function. let mut has_filename = true; - let filename = tcx.sess.local_crate_source_file.clone().unwrap_or_else(|| { + let filename = tcx.sess.local_crate_source_file().unwrap_or_else(|| { has_filename = false; Default::default() }); diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs index 9ae07cb005bd4..a5f09de1c401b 100644 --- a/compiler/rustc_save_analysis/src/dump_visitor.rs +++ b/compiler/rustc_save_analysis/src/dump_visitor.rs @@ -112,9 +112,7 @@ impl<'tcx> DumpVisitor<'tcx> { } pub fn dump_crate_info(&mut self, name: Symbol) { - let source_file = self.tcx.sess.local_crate_source_file.as_ref(); - let crate_root = source_file.map(|source_file| { - let source_file = Path::new(source_file); + let crate_root = self.tcx.sess.local_crate_source_file().map(|source_file| { match source_file.file_name() { Some(_) => source_file.parent().unwrap().display(), None => source_file.display(), @@ -157,10 +155,14 @@ impl<'tcx> DumpVisitor<'tcx> { .enumerate() .filter(|(i, _)| !remap_arg_indices.contains(i)) .map(|(_, arg)| match input { - Input::File(ref path) if path == Path::new(&arg) => { - let mapped = &self.tcx.sess.local_crate_source_file; - mapped.as_ref().unwrap().to_string_lossy().into() - } + Input::File(ref path) if path == Path::new(&arg) => self + .tcx + .sess + .local_crate_source_file() + .as_ref() + .unwrap() + .to_string_lossy() + .into(), _ => arg, }); diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs index 8ee3057de625e..2badccbf60344 100644 --- a/compiler/rustc_session/src/output.rs +++ b/compiler/rustc_session/src/output.rs @@ -45,7 +45,7 @@ fn is_writeable(p: &Path) -> bool { } } -pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute], input: &Input) -> Symbol { +pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute]) -> Symbol { let validate = |s: Symbol, span: Option| { validate_crate_name(sess, s, span); s @@ -71,7 +71,7 @@ pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute], input: &Input) if let Some((attr, s)) = attr_crate_name { return validate(s, Some(attr.span)); } - if let Input::File(ref path) = *input { + if let Input::File(ref path) = sess.io.input { if let Some(s) = path.file_stem().and_then(|s| s.to_str()) { if s.starts_with('-') { sess.emit_err(CrateNameInvalid { s }); diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 1b2e8d9dc707b..fe992b915613b 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1,6 +1,7 @@ use crate::cgu_reuse_tracker::CguReuseTracker; use crate::code_stats::CodeStats; pub use crate::code_stats::{DataTypeKind, FieldInfo, SizeKind, VariantInfo}; +use crate::config::Input; use crate::config::{self, CrateType, InstrumentCoverage, OptLevel, OutputType, SwitchWithOptPath}; use crate::errors::{ BranchProtectionRequiresAArch64, CannotEnableCrtStaticLinux, CannotMixAndMatchSanitizers, @@ -137,6 +138,13 @@ pub struct Limits { pub const_eval_limit: Limit, } +pub struct CompilerIO { + pub input: Input, + pub output_dir: Option, + pub output_file: Option, + pub temps_dir: Option, +} + /// Represents the data associated with a compilation /// session for a single crate. pub struct Session { @@ -147,9 +155,8 @@ pub struct Session { pub target_tlib_path: Lrc, pub parse_sess: ParseSess, pub sysroot: PathBuf, - /// The name of the root source file of the crate, in the local file system. - /// `None` means that there is no source file. - pub local_crate_source_file: Option, + /// Input, input file path and output file path to this compilation process. + pub io: CompilerIO, crate_types: OnceCell>, /// The `stable_crate_id` is constructed out of the crate name and all the @@ -228,6 +235,11 @@ impl Session { self.miri_unleashed_features.lock().push((span, feature_gate)); } + pub fn local_crate_source_file(&self) -> Option { + let path = self.io.input.opt_path()?; + Some(self.opts.file_path_mapping().map_prefix(path).0) + } + fn check_miri_unleashed_features(&self) { let unleashed_features = self.miri_unleashed_features.lock(); if !unleashed_features.is_empty() { @@ -1298,7 +1310,7 @@ fn default_emitter( #[allow(rustc::bad_opt_access)] pub fn build_session( sopts: config::Options, - local_crate_source_file: Option, + io: CompilerIO, bundle: Option>, registry: rustc_errors::registry::Registry, driver_lint_caps: FxHashMap, @@ -1391,11 +1403,6 @@ pub fn build_session( Lrc::new(SearchPath::from_sysroot_and_triple(&sysroot, target_triple)) }; - let file_path_mapping = sopts.file_path_mapping(); - - let local_crate_source_file = - local_crate_source_file.map(|path| file_path_mapping.map_prefix(path).0); - let optimization_fuel = Lock::new(OptimizationFuel { remaining: sopts.unstable_opts.fuel.as_ref().map_or(0, |&(_, i)| i), out_of_fuel: false, @@ -1427,7 +1434,7 @@ pub fn build_session( target_tlib_path, parse_sess, sysroot, - local_crate_source_file, + io, crate_types: OnceCell::new(), stable_crate_id: OnceCell::new(), features: OnceCell::new(), diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index f95d8e4303594..4fa33e8907d08 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -2921,7 +2921,7 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite // Look for the example file in the source map if it exists, otherwise return a dummy span let file_span = (|| { let source_map = tcx.sess.source_map(); - let crate_src = tcx.sess.local_crate_source_file.as_ref()?; + let crate_src = tcx.sess.local_crate_source_file()?; let abs_crate_src = crate_src.canonicalize().ok()?; let crate_root = abs_crate_src.parent()?.parent()?; let rel_path = path.strip_prefix(crate_root).ok()?; diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index d52c7819c567a..c0267956aab4a 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -56,12 +56,12 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { fn after_analysis<'tcx>( &mut self, - compiler: &rustc_interface::interface::Compiler, + _: &rustc_interface::interface::Compiler, queries: &'tcx rustc_interface::Queries<'tcx>, ) -> Compilation { - compiler.session().abort_if_errors(); - queries.global_ctxt().unwrap().enter(|tcx| { + tcx.sess.abort_if_errors(); + init_late_loggers(tcx); if !tcx.sess.crate_types().contains(&CrateType::Executable) { tcx.sess.fatal("miri only makes sense on bin crates"); @@ -75,7 +75,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { let mut config = self.miri_config.clone(); // Add filename to `miri` arguments. - config.args.insert(0, compiler.io().input.filestem().to_string()); + config.args.insert(0, tcx.sess.io.input.filestem().to_string()); // Adjust working directory for interpretation. if let Some(cwd) = env::var_os("MIRI_CWD") { @@ -87,10 +87,9 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { i32::try_from(return_code).expect("Return value was too large!"), ); } + tcx.sess.abort_if_errors(); }); - compiler.session().abort_if_errors(); - Compilation::Stop } } From c8a056132144b60f81cd74d062f8f4ba32dfa785 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 7 Dec 2022 12:14:06 +0000 Subject: [PATCH 067/230] Avoid one more call site to `Compiler::expansion` --- compiler/rustc_driver/src/lib.rs | 2 +- compiler/rustc_interface/src/queries.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 66dadf97b1987..98c4383b62ea3 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -328,7 +328,7 @@ fn run_compiler( } } - queries.expansion()?; + queries.global_ctxt()?; if callbacks.after_expansion(compiler, queries) == Compilation::Stop { return early_exit(); } diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index dcfb4f43bd018..d5a49dd75be6a 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -157,7 +157,7 @@ impl<'tcx> Queries<'tcx> { }) } - pub fn crate_name(&self) -> Result> { + fn crate_name(&self) -> Result> { self.crate_name.compute(|| { Ok({ let parse_result = self.parse()?; From e5273a98d301e7ce8214183dff34d25597527d23 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 13 Jan 2023 15:19:25 +0000 Subject: [PATCH 068/230] Fix run-make-fulldeps test --- tests/run-make-fulldeps/issue-19371/foo.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/tests/run-make-fulldeps/issue-19371/foo.rs b/tests/run-make-fulldeps/issue-19371/foo.rs index 7e1b6aeb31558..5bb38fc02af91 100644 --- a/tests/run-make-fulldeps/issue-19371/foo.rs +++ b/tests/run-make-fulldeps/issue-19371/foo.rs @@ -1,12 +1,12 @@ #![feature(rustc_private)] -extern crate rustc_interface; extern crate rustc_driver; +extern crate rustc_interface; extern crate rustc_session; extern crate rustc_span; -use rustc_session::config::{Input, Options, OutputType, OutputTypes}; use rustc_interface::interface; +use rustc_session::config::{Input, Options, OutputType, OutputTypes}; use rustc_span::source_map::FileName; use std::path::PathBuf; @@ -50,7 +50,6 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) { crate_cfg: Default::default(), crate_check_cfg: Default::default(), input, - input_path: None, output_file: Some(output), output_dir: None, file_loader: None, @@ -64,9 +63,7 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) { interface::run_compiler(config, |compiler| { // This runs all the passes prior to linking, too. - let linker = compiler.enter(|queries| { - queries.linker() - }); + let linker = compiler.enter(|queries| queries.linker()); if let Ok(linker) = linker { linker.link(); } From 44ef075aeb308422ac513ddc8f18978d9b92eea4 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 16 Jan 2023 14:04:28 +0000 Subject: [PATCH 069/230] Remove a now-useless function call --- compiler/rustc_driver/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 98c4383b62ea3..f50ad0137b88a 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -333,8 +333,6 @@ fn run_compiler( return early_exit(); } - queries.global_ctxt()?; - if sess.opts.output_types.contains_key(&OutputType::DepInfo) && sess.opts.output_types.len() == 1 { From 13555593672b49b5306990d63d0e61a49e17d9f0 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 16 Jan 2023 14:27:33 +0000 Subject: [PATCH 070/230] Avoid an unnecessary allocation --- .../rustc_save_analysis/src/span_utils.rs | 8 +----- compiler/rustc_session/src/config.rs | 16 +++++------ compiler/rustc_session/src/session.rs | 2 +- compiler/rustc_span/src/source_map.rs | 27 ++++++++++++------- compiler/rustc_span/src/source_map/tests.rs | 2 +- 5 files changed, 28 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_save_analysis/src/span_utils.rs b/compiler/rustc_save_analysis/src/span_utils.rs index 8d6758f40f965..e65d57bb3db3e 100644 --- a/compiler/rustc_save_analysis/src/span_utils.rs +++ b/compiler/rustc_save_analysis/src/span_utils.rs @@ -18,13 +18,7 @@ impl<'a> SpanUtils<'a> { match &file.name { FileName::Real(RealFileName::LocalPath(path)) => { if path.is_absolute() { - self.sess - .source_map() - .path_mapping() - .map_prefix(path.into()) - .0 - .display() - .to_string() + self.sess.source_map().path_mapping().map_prefix(path).0.display().to_string() } else { self.sess .opts diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 2679164b927e5..df6b30bfee9e4 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -592,11 +592,11 @@ impl Input { } } - pub fn opt_path(&self) -> Option { + pub fn opt_path(&self) -> Option<&Path> { match self { - Input::File(file) => Some(file.clone()), + Input::File(file) => Some(file), Input::Str { name, .. } => match name { - FileName::Real(real) => real.local_path().map(|p| p.to_owned()), + FileName::Real(real) => real.local_path(), FileName::QuoteExpansion(_) => None, FileName::Anon(_) => None, FileName::MacroExpansion(_) => None, @@ -604,7 +604,7 @@ impl Input { FileName::CfgSpec(_) => None, FileName::CliCrateAttr(_) => None, FileName::Custom(_) => None, - FileName::DocTest(path, _) => Some(path.to_owned()), + FileName::DocTest(path, _) => Some(path), FileName::InlineAsm(_) => None, }, } @@ -2509,12 +2509,12 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { early_error(error_format, &format!("Current directory is invalid: {e}")); }); - let (path, remapped) = - FilePathMapping::new(remap_path_prefix.clone()).map_prefix(working_dir.clone()); + let remap = FilePathMapping::new(remap_path_prefix.clone()); + let (path, remapped) = remap.map_prefix(&working_dir); let working_dir = if remapped { - RealFileName::Remapped { local_path: Some(working_dir), virtual_name: path } + RealFileName::Remapped { virtual_name: path.into_owned(), local_path: Some(working_dir) } } else { - RealFileName::LocalPath(path) + RealFileName::LocalPath(path.into_owned()) }; Options { diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index fe992b915613b..d4a1e849b2a09 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -237,7 +237,7 @@ impl Session { pub fn local_crate_source_file(&self) -> Option { let path = self.io.input.opt_path()?; - Some(self.opts.file_path_mapping().map_prefix(path).0) + Some(self.opts.file_path_mapping().map_prefix(path).0.into_owned()) } fn check_miri_unleashed_features(&self) { diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index fa09b4faa441f..5bfe247c58d8d 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -1138,7 +1138,8 @@ impl FilePathMapping { /// Applies any path prefix substitution as defined by the mapping. /// The return value is the remapped path and a boolean indicating whether /// the path was affected by the mapping. - pub fn map_prefix(&self, path: PathBuf) -> (PathBuf, bool) { + pub fn map_prefix<'a>(&'a self, path: impl Into>) -> (Cow<'a, Path>, bool) { + let path = path.into(); if path.as_os_str().is_empty() { // Exit early if the path is empty and therefore there's nothing to remap. // This is mostly to reduce spam for `RUSTC_LOG=[remap_path_prefix]`. @@ -1148,7 +1149,10 @@ impl FilePathMapping { return remap_path_prefix(&self.mapping, path); #[instrument(level = "debug", skip(mapping), ret)] - fn remap_path_prefix(mapping: &[(PathBuf, PathBuf)], path: PathBuf) -> (PathBuf, bool) { + fn remap_path_prefix<'a>( + mapping: &'a [(PathBuf, PathBuf)], + path: Cow<'a, Path>, + ) -> (Cow<'a, Path>, bool) { // NOTE: We are iterating over the mapping entries from last to first // because entries specified later on the command line should // take precedence. @@ -1163,9 +1167,9 @@ impl FilePathMapping { // in remapped paths down the line. // So, if we have an exact match, we just return that without a call // to `Path::join()`. - to.clone() + to.into() } else { - to.join(rest) + to.join(rest).into() }; debug!("Match - remapped"); @@ -1183,11 +1187,11 @@ impl FilePathMapping { fn map_filename_prefix(&self, file: &FileName) -> (FileName, bool) { match file { FileName::Real(realfile) if let RealFileName::LocalPath(local_path) = realfile => { - let (mapped_path, mapped) = self.map_prefix(local_path.to_path_buf()); + let (mapped_path, mapped) = self.map_prefix(local_path); let realfile = if mapped { RealFileName::Remapped { local_path: Some(local_path.clone()), - virtual_name: mapped_path, + virtual_name: mapped_path.into_owned(), } } else { realfile.clone() @@ -1228,14 +1232,17 @@ impl FilePathMapping { let (new_path, was_remapped) = self.map_prefix(unmapped_file_path); if was_remapped { // It was remapped, so don't modify further - return RealFileName::Remapped { local_path: None, virtual_name: new_path }; + return RealFileName::Remapped { + local_path: None, + virtual_name: new_path.into_owned(), + }; } if new_path.is_absolute() { // No remapping has applied to this path and it is absolute, // so the working directory cannot influence it either, so // we are done. - return RealFileName::LocalPath(new_path); + return RealFileName::LocalPath(new_path.into_owned()); } debug_assert!(new_path.is_relative()); @@ -1253,12 +1260,12 @@ impl FilePathMapping { RealFileName::Remapped { // Erase the actual path local_path: None, - virtual_name: file_path_abs, + virtual_name: file_path_abs.into_owned(), } } else { // No kind of remapping applied to this path, so // we leave it as it is. - RealFileName::LocalPath(file_path_abs) + RealFileName::LocalPath(file_path_abs.into_owned()) } } RealFileName::Remapped { diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs index 3cab59e8dbe6c..8671267725230 100644 --- a/compiler/rustc_span/src/source_map/tests.rs +++ b/compiler/rustc_span/src/source_map/tests.rs @@ -387,7 +387,7 @@ fn path_prefix_remapping_expand_to_absolute() { let working_directory = path("/foo"); let working_directory = RealFileName::Remapped { local_path: Some(working_directory.clone()), - virtual_name: mapping.map_prefix(working_directory).0, + virtual_name: mapping.map_prefix(working_directory).0.into_owned(), }; assert_eq!(working_directory.remapped_path_if_available(), path("FOO")); From 3a4fdcf86cea75796ed947853ea9544f2d11afff Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 15 Jan 2023 20:59:47 +0000 Subject: [PATCH 071/230] Encode const mir for closures if they're const --- compiler/rustc_metadata/src/rmeta/encoder.rs | 13 ++----------- .../ui/consts/auxiliary/closure-in-foreign-crate.rs | 8 ++++++++ tests/ui/consts/closure-in-foreign-crate.rs | 8 ++++++++ 3 files changed, 18 insertions(+), 11 deletions(-) create mode 100644 tests/ui/consts/auxiliary/closure-in-foreign-crate.rs create mode 100644 tests/ui/consts/closure-in-foreign-crate.rs diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index a8000aa3c8a83..e8ae9712a6330 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -888,8 +888,8 @@ fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) { | DefKind::AssocConst | DefKind::Static(..) | DefKind::Const => (true, false), - // Full-fledged functions - DefKind::AssocFn | DefKind::Fn => { + // Full-fledged functions + closures + DefKind::AssocFn | DefKind::Fn | DefKind::Closure => { let generics = tcx.generics_of(def_id); let needs_inline = (generics.requires_monomorphization(tcx) || tcx.codegen_fn_attrs(def_id).requests_inline()) @@ -900,15 +900,6 @@ fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) { let always_encode_mir = tcx.sess.opts.unstable_opts.always_encode_mir; (is_const_fn, needs_inline || always_encode_mir) } - // Closures can't be const fn. - DefKind::Closure => { - let generics = tcx.generics_of(def_id); - let needs_inline = (generics.requires_monomorphization(tcx) - || tcx.codegen_fn_attrs(def_id).requests_inline()) - && tcx.sess.opts.output_types.should_codegen(); - let always_encode_mir = tcx.sess.opts.unstable_opts.always_encode_mir; - (false, needs_inline || always_encode_mir) - } // Generators require optimized MIR to compute layout. DefKind::Generator => (false, true), // The others don't have MIR. diff --git a/tests/ui/consts/auxiliary/closure-in-foreign-crate.rs b/tests/ui/consts/auxiliary/closure-in-foreign-crate.rs new file mode 100644 index 0000000000000..edc7fa81abb4f --- /dev/null +++ b/tests/ui/consts/auxiliary/closure-in-foreign-crate.rs @@ -0,0 +1,8 @@ +#![crate_type = "lib"] +#![feature(const_closures, const_trait_impl)] +#![allow(incomplete_features)] + +pub const fn test() { + let cl = const || {}; + cl(); +} diff --git a/tests/ui/consts/closure-in-foreign-crate.rs b/tests/ui/consts/closure-in-foreign-crate.rs new file mode 100644 index 0000000000000..fc8f480e706bc --- /dev/null +++ b/tests/ui/consts/closure-in-foreign-crate.rs @@ -0,0 +1,8 @@ +// aux-build:closure-in-foreign-crate.rs +// build-pass + +extern crate closure_in_foreign_crate; + +const _: () = closure_in_foreign_crate::test(); + +fn main() {} From 6b69b5e4607e32d8860c4cd0ebf0132f1998b14d Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 16 Jan 2023 15:15:09 +0000 Subject: [PATCH 072/230] Improve a TAIT error and add an error code plus documentation --- .../src/region_infer/opaque_types.rs | 20 +++---- .../rustc_borrowck/src/session_diagnostics.rs | 13 +++- compiler/rustc_error_codes/src/error_codes.rs | 1 + .../src/error_codes/E0792.md | 60 +++++++++++++++++++ .../locales/en-US/borrowck.ftl | 4 ++ compiler/rustc_middle/src/ty/diagnostics.rs | 2 +- compiler/rustc_middle/src/ty/subst.rs | 7 +++ .../type-alias-impl-trait/bound_reduction2.rs | 2 +- .../bound_reduction2.stderr | 12 ++-- .../generic_nondefining_use.rs | 5 +- .../generic_nondefining_use.stderr | 29 ++++----- .../generic_type_does_not_live_long_enough.rs | 2 +- ...eric_type_does_not_live_long_enough.stderr | 12 ++-- tests/ui/type-alias-impl-trait/issue-60564.rs | 2 +- .../type-alias-impl-trait/issue-60564.stderr | 12 ++-- .../issue-68368-non-defining-use-2.rs | 2 +- .../issue-68368-non-defining-use-2.stderr | 12 ++-- .../issue-68368-non-defining-use.rs | 2 +- .../issue-68368-non-defining-use.stderr | 12 ++-- ...ssue-69136-inner-lifetime-resolve-error.rs | 2 +- ...-69136-inner-lifetime-resolve-error.stderr | 14 ++--- 21 files changed, 145 insertions(+), 82 deletions(-) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0792.md diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index c6e42336ef8ca..9d8812b7eeaac 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -12,6 +12,8 @@ use rustc_span::Span; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; use rustc_trait_selection::traits::ObligationCtxt; +use crate::session_diagnostics::NonGenericOpaqueTypeParam; + use super::RegionInferenceContext; impl<'tcx> RegionInferenceContext<'tcx> { @@ -389,17 +391,13 @@ fn check_opaque_type_parameter_valid( } else { // Prevent `fn foo() -> Foo` from being defining. let opaque_param = opaque_generics.param_at(i, tcx); - tcx.sess - .struct_span_err(span, "non-defining opaque type use in defining scope") - .span_note( - tcx.def_span(opaque_param.def_id), - &format!( - "used non-generic {} `{}` for generic parameter", - opaque_param.kind.descr(), - arg, - ), - ) - .emit(); + let kind = opaque_param.kind.descr(); + tcx.sess.emit_err(NonGenericOpaqueTypeParam { + ty: arg, + kind, + span, + param_span: tcx.def_span(opaque_param.def_id), + }); return false; } } diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs index 577332c0744b8..23acf159240fa 100644 --- a/compiler/rustc_borrowck/src/session_diagnostics.rs +++ b/compiler/rustc_borrowck/src/session_diagnostics.rs @@ -1,6 +1,6 @@ use rustc_errors::{IntoDiagnosticArg, MultiSpan}; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; -use rustc_middle::ty::Ty; +use rustc_middle::ty::{GenericArg, Ty}; use rustc_span::Span; use crate::diagnostics::RegionName; @@ -240,3 +240,14 @@ pub(crate) struct MoveBorrow<'a> { #[label] pub borrow_span: Span, } + +#[derive(Diagnostic)] +#[diag(borrowck_opaque_type_non_generic_param, code = "E0792")] +pub(crate) struct NonGenericOpaqueTypeParam<'a, 'tcx> { + pub ty: GenericArg<'tcx>, + pub kind: &'a str, + #[primary_span] + pub span: Span, + #[label] + pub param_span: Span, +} diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 24258974bb97c..5c77448f908ed 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -508,6 +508,7 @@ E0787: include_str!("./error_codes/E0787.md"), E0788: include_str!("./error_codes/E0788.md"), E0790: include_str!("./error_codes/E0790.md"), E0791: include_str!("./error_codes/E0791.md"), +E0792: include_str!("./error_codes/E0792.md"), ; // E0006, // merged with E0005 // E0008, // cannot bind by-move into a pattern guard diff --git a/compiler/rustc_error_codes/src/error_codes/E0792.md b/compiler/rustc_error_codes/src/error_codes/E0792.md new file mode 100644 index 0000000000000..bad2b5abfe4d7 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0792.md @@ -0,0 +1,60 @@ +A type alias impl trait can only have its hidden type assigned +when used fully generically (and within their defining scope). +This means + +```compile_fail,E0792 +#![feature(type_alias_impl_trait)] + +type Foo = impl std::fmt::Debug; + +fn foo() -> Foo { + 5u32 +} +``` + +is not accepted. If it were accepted, one could create unsound situations like + +```compile_fail,E0792 +#![feature(type_alias_impl_trait)] + +type Foo = impl Default; + +fn foo() -> Foo { + 5u32 +} + +fn main() { + let x = Foo::<&'static mut String>::default(); +} +``` + + +Instead you need to make the function generic: + +``` +#![feature(type_alias_impl_trait)] + +type Foo = impl std::fmt::Debug; + +fn foo() -> Foo { + 5u32 +} +``` + +This means that no matter the generic parameter to `foo`, +the hidden type will always be `u32`. +If you want to link the generic parameter to the hidden type, +you can do that, too: + + +``` +#![feature(type_alias_impl_trait)] + +use std::fmt::Debug; + +type Foo = impl Debug; + +fn foo() -> Foo { + Vec::::new() +} +``` diff --git a/compiler/rustc_error_messages/locales/en-US/borrowck.ftl b/compiler/rustc_error_messages/locales/en-US/borrowck.ftl index 2cd4733220e82..9e4332c428386 100644 --- a/compiler/rustc_error_messages/locales/en-US/borrowck.ftl +++ b/compiler/rustc_error_messages/locales/en-US/borrowck.ftl @@ -120,3 +120,7 @@ borrowck_cannot_move_when_borrowed = [value] value *[other] {$value_place} } occurs here + +borrowck_opaque_type_non_generic_param = + expected generic {$kind} parameter, found `{$ty}` + .label = this generic parameter must be used with a generic {$kind} parameter diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 8c22df7395f10..771b63f59c124 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -17,7 +17,7 @@ use rustc_type_ir::sty::TyKind::*; impl<'tcx> IntoDiagnosticArg for Ty<'tcx> { fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - format!("{}", self).into_diagnostic_arg() + self.to_string().into_diagnostic_arg() } } diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 8f764011d0ac3..75a8dda315765 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -7,6 +7,7 @@ use crate::ty::visit::{TypeVisitable, TypeVisitor}; use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt}; use rustc_data_structures::intern::Interned; +use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg}; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; use rustc_serialize::{self, Decodable, Encodable}; @@ -36,6 +37,12 @@ pub struct GenericArg<'tcx> { marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>, ty::Const<'tcx>)>, } +impl<'tcx> IntoDiagnosticArg for GenericArg<'tcx> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + self.to_string().into_diagnostic_arg() + } +} + const TAG_MASK: usize = 0b11; const TYPE_TAG: usize = 0b00; const REGION_TAG: usize = 0b01; diff --git a/tests/ui/type-alias-impl-trait/bound_reduction2.rs b/tests/ui/type-alias-impl-trait/bound_reduction2.rs index 4d2890b5de583..0bcc9e002ca04 100644 --- a/tests/ui/type-alias-impl-trait/bound_reduction2.rs +++ b/tests/ui/type-alias-impl-trait/bound_reduction2.rs @@ -14,5 +14,5 @@ impl Trait for () {} fn foo_desugared(_: T) -> Foo { () - //~^ ERROR non-defining opaque type use + //~^ ERROR expected generic type parameter, found `::Assoc` } diff --git a/tests/ui/type-alias-impl-trait/bound_reduction2.stderr b/tests/ui/type-alias-impl-trait/bound_reduction2.stderr index c405b1f6af205..3c259bd9e97cc 100644 --- a/tests/ui/type-alias-impl-trait/bound_reduction2.stderr +++ b/tests/ui/type-alias-impl-trait/bound_reduction2.stderr @@ -1,14 +1,12 @@ -error: non-defining opaque type use in defining scope +error[E0792]: expected generic type parameter, found `::Assoc` --> $DIR/bound_reduction2.rs:16:5 | +LL | type Foo = impl Trait; + | - this generic parameter must be used with a generic type parameter +... LL | () | ^^ - | -note: used non-generic type `::Assoc` for generic parameter - --> $DIR/bound_reduction2.rs:9:10 - | -LL | type Foo = impl Trait; - | ^ error: aborting due to previous error +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/type-alias-impl-trait/generic_nondefining_use.rs b/tests/ui/type-alias-impl-trait/generic_nondefining_use.rs index f39741a6a625c..f5045d382aac4 100644 --- a/tests/ui/type-alias-impl-trait/generic_nondefining_use.rs +++ b/tests/ui/type-alias-impl-trait/generic_nondefining_use.rs @@ -10,12 +10,11 @@ type OneLifetime<'a> = impl Debug; type OneConst = impl Debug; - // Not defining uses, because they doesn't define *all* possible generics. fn concrete_ty() -> OneTy { 5u32 - //~^ ERROR non-defining opaque type use in defining scope + //~^ ERROR expected generic type parameter, found `u32` } fn concrete_lifetime() -> OneLifetime<'static> { @@ -25,5 +24,5 @@ fn concrete_lifetime() -> OneLifetime<'static> { fn concrete_const() -> OneConst<{ 123 }> { 7u32 - //~^ ERROR non-defining opaque type use in defining scope + //~^ ERROR expected generic constant parameter, found `123` } diff --git a/tests/ui/type-alias-impl-trait/generic_nondefining_use.stderr b/tests/ui/type-alias-impl-trait/generic_nondefining_use.stderr index e7565525ad338..564648630b161 100644 --- a/tests/ui/type-alias-impl-trait/generic_nondefining_use.stderr +++ b/tests/ui/type-alias-impl-trait/generic_nondefining_use.stderr @@ -1,17 +1,14 @@ -error: non-defining opaque type use in defining scope - --> $DIR/generic_nondefining_use.rs:17:5 +error[E0792]: expected generic type parameter, found `u32` + --> $DIR/generic_nondefining_use.rs:16:5 | +LL | type OneTy = impl Debug; + | - this generic parameter must be used with a generic type parameter +... LL | 5u32 | ^^^^ - | -note: used non-generic type `u32` for generic parameter - --> $DIR/generic_nondefining_use.rs:7:12 - | -LL | type OneTy = impl Debug; - | ^ error: non-defining opaque type use in defining scope - --> $DIR/generic_nondefining_use.rs:22:5 + --> $DIR/generic_nondefining_use.rs:21:5 | LL | type OneLifetime<'a> = impl Debug; | -- cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type @@ -19,17 +16,15 @@ LL | type OneLifetime<'a> = impl Debug; LL | 6u32 | ^^^^ -error: non-defining opaque type use in defining scope - --> $DIR/generic_nondefining_use.rs:27:5 +error[E0792]: expected generic constant parameter, found `123` + --> $DIR/generic_nondefining_use.rs:26:5 | +LL | type OneConst = impl Debug; + | -------------- this generic parameter must be used with a generic constant parameter +... LL | 7u32 | ^^^^ - | -note: used non-generic constant `123` for generic parameter - --> $DIR/generic_nondefining_use.rs:11:15 - | -LL | type OneConst = impl Debug; - | ^^^^^^^^^^^^^^ error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs b/tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs index cb90776472b5d..d3e169a70d3f7 100644 --- a/tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs +++ b/tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs @@ -4,7 +4,7 @@ fn main() { let y = 42; let x = wrong_generic(&y); let z: i32 = x; - //~^ ERROR non-defining opaque type use + //~^ ERROR expected generic type parameter, found `&'static i32 } type WrongGeneric = impl 'static; diff --git a/tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr b/tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr index ba583241a696b..19115fd28662b 100644 --- a/tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr +++ b/tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr @@ -4,17 +4,14 @@ error: at least one trait must be specified LL | type WrongGeneric = impl 'static; | ^^^^^^^^^^^^ -error: non-defining opaque type use in defining scope +error[E0792]: expected generic type parameter, found `&'static i32` --> $DIR/generic_type_does_not_live_long_enough.rs:6:18 | LL | let z: i32 = x; | ^ - | -note: used non-generic type `&'static i32` for generic parameter - --> $DIR/generic_type_does_not_live_long_enough.rs:10:19 - | +... LL | type WrongGeneric = impl 'static; - | ^ + | - this generic parameter must be used with a generic type parameter error[E0310]: the parameter type `T` may not live long enough --> $DIR/generic_type_does_not_live_long_enough.rs:14:5 @@ -29,4 +26,5 @@ LL | fn wrong_generic(t: T) -> WrongGeneric { error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0310`. +Some errors have detailed explanations: E0310, E0792. +For more information about an error, try `rustc --explain E0310`. diff --git a/tests/ui/type-alias-impl-trait/issue-60564.rs b/tests/ui/type-alias-impl-trait/issue-60564.rs index 4fc7679311a2e..c2f4c37080746 100644 --- a/tests/ui/type-alias-impl-trait/issue-60564.rs +++ b/tests/ui/type-alias-impl-trait/issue-60564.rs @@ -18,7 +18,7 @@ where type BitsIter = IterBitsIter; fn iter_bits(self, n: u8) -> Self::BitsIter { (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap()) - //~^ ERROR non-defining opaque type use in defining scope + //~^ ERROR expected generic type parameter, found `u8` } } diff --git a/tests/ui/type-alias-impl-trait/issue-60564.stderr b/tests/ui/type-alias-impl-trait/issue-60564.stderr index bbc93657be32f..f8fdb004d0989 100644 --- a/tests/ui/type-alias-impl-trait/issue-60564.stderr +++ b/tests/ui/type-alias-impl-trait/issue-60564.stderr @@ -1,14 +1,12 @@ -error: non-defining opaque type use in defining scope +error[E0792]: expected generic type parameter, found `u8` --> $DIR/issue-60564.rs:20:9 | +LL | type IterBitsIter = impl std::iter::Iterator; + | - this generic parameter must be used with a generic type parameter +... LL | (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: used non-generic type `u8` for generic parameter - --> $DIR/issue-60564.rs:8:25 - | -LL | type IterBitsIter = impl std::iter::Iterator; - | ^ error: aborting due to previous error +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.rs b/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.rs index 5223fb1c702d6..5e0a82a72868a 100644 --- a/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.rs +++ b/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.rs @@ -7,7 +7,7 @@ trait Trait {} type Alias<'a, U> = impl Trait; fn f<'a>() -> Alias<'a, ()> {} -//~^ ERROR non-defining opaque type use in defining scope +//~^ ERROR expected generic type parameter, found `()` fn main() {} diff --git a/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.stderr b/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.stderr index 7fb9a0c410e83..271743a4010c8 100644 --- a/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.stderr +++ b/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.stderr @@ -1,14 +1,12 @@ -error: non-defining opaque type use in defining scope +error[E0792]: expected generic type parameter, found `()` --> $DIR/issue-68368-non-defining-use-2.rs:9:29 | +LL | type Alias<'a, U> = impl Trait; + | - this generic parameter must be used with a generic type parameter +LL | LL | fn f<'a>() -> Alias<'a, ()> {} | ^^ - | -note: used non-generic type `()` for generic parameter - --> $DIR/issue-68368-non-defining-use-2.rs:7:16 - | -LL | type Alias<'a, U> = impl Trait; - | ^ error: aborting due to previous error +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs b/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs index b50462bf237bb..3b32260c96fe1 100644 --- a/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs +++ b/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs @@ -7,7 +7,7 @@ trait Trait {} type Alias<'a, U> = impl Trait; fn f<'a>() -> Alias<'a, ()> {} -//~^ ERROR non-defining opaque type use in defining scope +//~^ ERROR expected generic type parameter, found `()` fn main() {} diff --git a/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr b/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr index 8059621b61a09..4d9a8d6eef915 100644 --- a/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr +++ b/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr @@ -1,14 +1,12 @@ -error: non-defining opaque type use in defining scope +error[E0792]: expected generic type parameter, found `()` --> $DIR/issue-68368-non-defining-use.rs:9:29 | +LL | type Alias<'a, U> = impl Trait; + | - this generic parameter must be used with a generic type parameter +LL | LL | fn f<'a>() -> Alias<'a, ()> {} | ^^ - | -note: used non-generic type `()` for generic parameter - --> $DIR/issue-68368-non-defining-use.rs:7:16 - | -LL | type Alias<'a, U> = impl Trait; - | ^ error: aborting due to previous error +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs b/tests/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs index 428454bc04844..7657fe2fb1aee 100644 --- a/tests/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs +++ b/tests/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs @@ -18,6 +18,6 @@ type Return = impl WithAssoc; //~^ ERROR use of undeclared lifetime name `'a` fn my_fun() -> Return<()> {} -//~^ ERROR non-defining opaque type use in defining scope +//~^ ERROR expected generic type parameter, found `()` fn main() {} diff --git a/tests/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr b/tests/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr index 7b50c8af26e5f..d1250786d938c 100644 --- a/tests/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr +++ b/tests/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr @@ -14,18 +14,16 @@ help: consider introducing lifetime `'a` here LL | type Return<'a, A> = impl WithAssoc; | +++ -error: non-defining opaque type use in defining scope +error[E0792]: expected generic type parameter, found `()` --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:20:27 | +LL | type Return = impl WithAssoc; + | - this generic parameter must be used with a generic type parameter +... LL | fn my_fun() -> Return<()> {} | ^^ - | -note: used non-generic type `()` for generic parameter - --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:17:13 - | -LL | type Return = impl WithAssoc; - | ^ error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0261`. +Some errors have detailed explanations: E0261, E0792. +For more information about an error, try `rustc --explain E0261`. From db1ddef55e79a4f16dc618f3dfb7c9b458602a59 Mon Sep 17 00:00:00 2001 From: rustbot <47979223+rustbot@users.noreply.github.com> Date: Mon, 16 Jan 2023 12:01:00 -0500 Subject: [PATCH 073/230] Update books --- src/doc/book | 2 +- src/doc/nomicon | 2 +- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- src/doc/rustc-dev-guide | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/doc/book b/src/doc/book index 2bd5d42c99563..2cd1b5593d26d 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 2bd5d42c9956369132228da6409f0e68da56c51a +Subproject commit 2cd1b5593d26dc6a03c20f8619187ad4b2485552 diff --git a/src/doc/nomicon b/src/doc/nomicon index 8ca261268068d..960d610e7f338 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 8ca261268068d80c0969260fff15199bad87b587 +Subproject commit 960d610e7f33889a2577f5f17c26f0d5c82b30df diff --git a/src/doc/reference b/src/doc/reference index 3ae62681ff236..2cb0ed9ba5636 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 3ae62681ff236d5528ef7c8c28ba7c6b2ecc6731 +Subproject commit 2cb0ed9ba56360949f492f9866afe8c293f9f9da diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 8888f9428fe9a..a9fb7d13eadfc 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 8888f9428fe9a48f31de6bd2cef9b9bf80791edc +Subproject commit a9fb7d13eadfcc5f457962731f105b97f9a7474a diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide index b3e2a6e6c8a3a..7352353ae91c4 160000 --- a/src/doc/rustc-dev-guide +++ b/src/doc/rustc-dev-guide @@ -1 +1 @@ -Subproject commit b3e2a6e6c8a3aae5b5d950c63046f23bae07096d +Subproject commit 7352353ae91c48b136d2ca7d03822e1448165e1e From d79207273842c9fd414b9060f74c411d9610b28d Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Fri, 6 Jan 2023 11:40:45 +0000 Subject: [PATCH 074/230] compiletest: Generic support for "no-" versions of boolean directives. --- src/tools/compiletest/src/header.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index c5767a795382e..6b7ae073dbcc6 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -725,6 +725,10 @@ impl Config { && matches!(line.as_bytes().get(directive.len()), None | Some(&b' ') | Some(&b':')) } + fn parse_negative_name_directive(&self, line: &str, directive: &str) -> bool { + line.starts_with("no-") && self.parse_name_directive(&line[3..], directive) + } + pub fn parse_name_value_directive(&self, line: &str, directive: &str) -> Option { let colon = directive.len(); if line.starts_with(directive) && line.as_bytes().get(colon) == Some(&b':') { @@ -754,8 +758,17 @@ impl Config { } fn set_name_directive(&self, line: &str, directive: &str, value: &mut bool) { - if !*value { - *value = self.parse_name_directive(line, directive) + match value { + true => { + if self.parse_negative_name_directive(line, directive) { + *value = false; + } + } + false => { + if self.parse_name_directive(line, directive) { + *value = true; + } + } } } From 10fe7bfc7394b32471f1bad199fd9f8300cd80c2 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Fri, 6 Jan 2023 11:48:03 +0000 Subject: [PATCH 075/230] compiletest: Support running with a remapped base directory. --- src/tools/compiletest/src/header.rs | 6 +++++ src/tools/compiletest/src/runtest.rs | 35 ++++++++++++++++++++++++---- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 6b7ae073dbcc6..fd4b51d637c1a 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -162,6 +162,9 @@ pub struct TestProps { pub stderr_per_bitwidth: bool, // The MIR opt to unit test, if any pub mir_unit_test: Option, + // Whether to tell `rustc` to remap the "src base" directory to a fake + // directory. + pub remap_src_base: bool, } mod directives { @@ -196,6 +199,7 @@ mod directives { pub const INCREMENTAL: &'static str = "incremental"; pub const KNOWN_BUG: &'static str = "known-bug"; pub const MIR_UNIT_TEST: &'static str = "unit-test"; + pub const REMAP_SRC_BASE: &'static str = "remap-src-base"; // This isn't a real directive, just one that is probably mistyped often pub const INCORRECT_COMPILER_FLAGS: &'static str = "compiler-flags"; } @@ -241,6 +245,7 @@ impl TestProps { should_ice: false, stderr_per_bitwidth: false, mir_unit_test: None, + remap_src_base: false, } } @@ -433,6 +438,7 @@ impl TestProps { config.set_name_value_directive(ln, MIR_UNIT_TEST, &mut self.mir_unit_test, |s| { s.trim().to_string() }); + config.set_name_directive(ln, REMAP_SRC_BASE, &mut self.remap_src_base); }); } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index a16ab11e2f978..859c0f1da06c3 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -44,6 +44,8 @@ use debugger::{check_debugger_output, DebuggerCommands}; #[cfg(test)] mod tests; +const FAKE_SRC_BASE: &str = "fake-test-src-base"; + #[cfg(windows)] fn disable_error_reporting R, R>(f: F) -> R { use std::sync::Mutex; @@ -1328,12 +1330,19 @@ impl<'test> TestCx<'test> { return; } + // On Windows, translate all '\' path separators to '/' + let file_name = format!("{}", self.testpaths.file.display()).replace(r"\", "/"); + // On Windows, keep all '\' path separators to match the paths reported in the JSON output // from the compiler - let os_file_name = self.testpaths.file.display().to_string(); - - // on windows, translate all '\' path separators to '/' - let file_name = format!("{}", self.testpaths.file.display()).replace(r"\", "/"); + let diagnostic_file_name = if self.props.remap_src_base { + let mut p = PathBuf::from(FAKE_SRC_BASE); + p.push(&self.testpaths.relative_dir); + p.push(self.testpaths.file.file_name().unwrap()); + p.display().to_string() + } else { + self.testpaths.file.display().to_string() + }; // If the testcase being checked contains at least one expected "help" // message, then we'll ensure that all "help" messages are expected. @@ -1343,7 +1352,7 @@ impl<'test> TestCx<'test> { let expect_note = expected_errors.iter().any(|ee| ee.kind == Some(ErrorKind::Note)); // Parse the JSON output from the compiler and extract out the messages. - let actual_errors = json::parse_output(&os_file_name, &proc_res.stderr, proc_res); + let actual_errors = json::parse_output(&diagnostic_file_name, &proc_res.stderr, proc_res); let mut unexpected = Vec::new(); let mut found = vec![false; expected_errors.len()]; for actual_error in &actual_errors { @@ -1970,6 +1979,14 @@ impl<'test> TestCx<'test> { } } + if self.props.remap_src_base { + rustc.arg(format!( + "--remap-path-prefix={}={}", + self.config.src_base.display(), + FAKE_SRC_BASE, + )); + } + match emit { Emit::None => {} Emit::Metadata if is_rustdoc => {} @@ -3545,6 +3562,14 @@ impl<'test> TestCx<'test> { let parent_dir = self.testpaths.file.parent().unwrap(); normalize_path(parent_dir, "$DIR"); + if self.props.remap_src_base { + let mut remapped_parent_dir = PathBuf::from(FAKE_SRC_BASE); + if self.testpaths.relative_dir != Path::new("") { + remapped_parent_dir.push(&self.testpaths.relative_dir); + } + normalize_path(&remapped_parent_dir, "$DIR"); + } + let source_bases = &[ // Source base on the current filesystem (calculated as parent of `tests/$suite`): Some(self.config.src_base.parent().unwrap().parent().unwrap().into()), From cd1d0bc20cd2c18ec844f6447396dadf90b762e9 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Fri, 6 Jan 2023 11:49:07 +0000 Subject: [PATCH 076/230] ui tests: Remap test base directory by default. --- src/tools/compiletest/src/header.rs | 3 ++ .../ui-fulldeps/mod_dir_path_canonicalized.rs | 1 + tests/ui/errors/auxiliary/remapped_dep.rs | 1 + ...emap-path-prefix-reverse.local-self.stderr | 6 ++-- ...p-path-prefix-reverse.remapped-self.stderr | 6 ++-- tests/ui/errors/remap-path-prefix-reverse.rs | 12 ++----- tests/ui/errors/remap-path-prefix.rs | 1 + tests/ui/errors/remap-path-prefix.stderr | 2 +- tests/ui/proc-macro/expand-expr.rs | 4 ++- tests/ui/proc-macro/expand-expr.stderr | 14 ++++---- .../pretty-print-hack-show.remapped.stderr | 32 +++++++++---------- .../pretty-print-hack-show.remapped.stdout | 16 +++++----- tests/ui/proc-macro/pretty-print-hack-show.rs | 7 ++-- 13 files changed, 52 insertions(+), 53 deletions(-) diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index fd4b51d637c1a..899f068bd3d04 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -278,6 +278,9 @@ impl TestProps { /// `//[foo]`), then the property is ignored unless `cfg` is /// `Some("foo")`. fn load_from(&mut self, testfile: &Path, cfg: Option<&str>, config: &Config) { + // Mode-dependent defaults. + self.remap_src_base = config.mode == Mode::Ui && !config.suite.contains("rustdoc"); + let mut has_edition = false; if !testfile.is_dir() { let file = File::open(testfile).unwrap(); diff --git a/tests/ui-fulldeps/mod_dir_path_canonicalized.rs b/tests/ui-fulldeps/mod_dir_path_canonicalized.rs index ff1be0804151b..bdfd9628c4801 100644 --- a/tests/ui-fulldeps/mod_dir_path_canonicalized.rs +++ b/tests/ui-fulldeps/mod_dir_path_canonicalized.rs @@ -2,6 +2,7 @@ // Testing that a librustc_ast can parse modules with canonicalized base path // ignore-cross-compile // ignore-remote +// no-remap-src-base: Reading `file!()` (expectedly) fails when enabled. #![feature(rustc_private)] diff --git a/tests/ui/errors/auxiliary/remapped_dep.rs b/tests/ui/errors/auxiliary/remapped_dep.rs index ef26f1cd883fb..f9bb7bf89870a 100644 --- a/tests/ui/errors/auxiliary/remapped_dep.rs +++ b/tests/ui/errors/auxiliary/remapped_dep.rs @@ -1,3 +1,4 @@ // compile-flags: --remap-path-prefix={{src-base}}/errors/auxiliary=remapped-aux +// no-remap-src-base: Manually remap, so the remapped path remains in .stderr file. pub struct SomeStruct {} // This line should be show as part of the error. diff --git a/tests/ui/errors/remap-path-prefix-reverse.local-self.stderr b/tests/ui/errors/remap-path-prefix-reverse.local-self.stderr index 2584e3e88a6e5..51e3b776cb2c0 100644 --- a/tests/ui/errors/remap-path-prefix-reverse.local-self.stderr +++ b/tests/ui/errors/remap-path-prefix-reverse.local-self.stderr @@ -1,10 +1,10 @@ error[E0423]: expected value, found struct `remapped_dep::SomeStruct` - --> $DIR/remap-path-prefix-reverse.rs:22:13 + --> $DIR/remap-path-prefix-reverse.rs:16:13 | -LL | let _ = remapped_dep::SomeStruct; +LL | let _ = remapped_dep::SomeStruct; // ~ERROR E0423 | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `remapped_dep::SomeStruct {}` | - ::: remapped-aux/remapped_dep.rs:3:1 + ::: remapped-aux/remapped_dep.rs:4:1 | LL | pub struct SomeStruct {} // This line should be show as part of the error. | --------------------- `remapped_dep::SomeStruct` defined here diff --git a/tests/ui/errors/remap-path-prefix-reverse.remapped-self.stderr b/tests/ui/errors/remap-path-prefix-reverse.remapped-self.stderr index e710183322acc..51e3b776cb2c0 100644 --- a/tests/ui/errors/remap-path-prefix-reverse.remapped-self.stderr +++ b/tests/ui/errors/remap-path-prefix-reverse.remapped-self.stderr @@ -1,10 +1,10 @@ error[E0423]: expected value, found struct `remapped_dep::SomeStruct` - --> remapped/errors/remap-path-prefix-reverse.rs:22:13 + --> $DIR/remap-path-prefix-reverse.rs:16:13 | -LL | let _ = remapped_dep::SomeStruct; +LL | let _ = remapped_dep::SomeStruct; // ~ERROR E0423 | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `remapped_dep::SomeStruct {}` | - ::: remapped-aux/remapped_dep.rs:3:1 + ::: remapped-aux/remapped_dep.rs:4:1 | LL | pub struct SomeStruct {} // This line should be show as part of the error. | --------------------- `remapped_dep::SomeStruct` defined here diff --git a/tests/ui/errors/remap-path-prefix-reverse.rs b/tests/ui/errors/remap-path-prefix-reverse.rs index 635c4164e0f8e..71c80063c320f 100644 --- a/tests/ui/errors/remap-path-prefix-reverse.rs +++ b/tests/ui/errors/remap-path-prefix-reverse.rs @@ -1,15 +1,9 @@ // aux-build:remapped_dep.rs // compile-flags: --remap-path-prefix={{src-base}}/errors/auxiliary=remapped-aux -// The remapped paths are not normalized by compiletest. -// normalize-stderr-test: "\\(errors)" -> "/$1" - // revisions: local-self remapped-self -// [remapped-self]compile-flags: --remap-path-prefix={{src-base}}=remapped - -// The paths from `remapped-self` aren't recognized by compiletest, so we -// cannot use line-specific patterns for the actual error. -// error-pattern: E0423 +// [local-self] no-remap-src-base: The hack should work regardless of remapping. +// [remapped-self] remap-src-base // Verify that the expected source code is shown. // error-pattern: pub struct SomeStruct {} // This line should be show @@ -19,5 +13,5 @@ extern crate remapped_dep; fn main() { // The actual error is irrelevant. The important part it that is should show // a snippet of the dependency's source. - let _ = remapped_dep::SomeStruct; + let _ = remapped_dep::SomeStruct; // ~ERROR E0423 } diff --git a/tests/ui/errors/remap-path-prefix.rs b/tests/ui/errors/remap-path-prefix.rs index 29b9c7be30122..393b8e22f1c1d 100644 --- a/tests/ui/errors/remap-path-prefix.rs +++ b/tests/ui/errors/remap-path-prefix.rs @@ -1,4 +1,5 @@ // compile-flags: --remap-path-prefix={{src-base}}=remapped +// no-remap-src-base: Manually remap, so the remapped path remains in .stderr file. // The remapped paths are not normalized by compiletest. // normalize-stderr-test: "\\(errors)" -> "/$1" diff --git a/tests/ui/errors/remap-path-prefix.stderr b/tests/ui/errors/remap-path-prefix.stderr index 2f421283e6995..62dbd4b8881a3 100644 --- a/tests/ui/errors/remap-path-prefix.stderr +++ b/tests/ui/errors/remap-path-prefix.stderr @@ -1,5 +1,5 @@ error[E0425]: cannot find value `ferris` in this scope - --> remapped/errors/remap-path-prefix.rs:15:5 + --> remapped/errors/remap-path-prefix.rs:16:5 | LL | ferris | ^^^^^^ not found in this scope diff --git a/tests/ui/proc-macro/expand-expr.rs b/tests/ui/proc-macro/expand-expr.rs index 901b3a951023c..700aac41c449a 100644 --- a/tests/ui/proc-macro/expand-expr.rs +++ b/tests/ui/proc-macro/expand-expr.rs @@ -1,4 +1,6 @@ // aux-build:expand-expr.rs +// no-remap-src-base: check_expand_expr_file!() fails when enabled. + #![feature(concat_bytes)] extern crate expand_expr; @@ -8,7 +10,7 @@ use expand_expr::{ // Check builtin macros can be expanded. -expand_expr_is!(11u32, line!()); +expand_expr_is!(13u32, line!()); expand_expr_is!(24u32, column!()); expand_expr_is!("Hello, World!", concat!("Hello, ", "World", "!")); diff --git a/tests/ui/proc-macro/expand-expr.stderr b/tests/ui/proc-macro/expand-expr.stderr index 0004f2fe17f01..df61e9972896b 100644 --- a/tests/ui/proc-macro/expand-expr.stderr +++ b/tests/ui/proc-macro/expand-expr.stderr @@ -1,29 +1,29 @@ error: expected one of `.`, `?`, or an operator, found `;` - --> $DIR/expand-expr.rs:106:27 + --> $DIR/expand-expr.rs:108:27 | LL | expand_expr_fail!("string"; hello); | ^ expected one of `.`, `?`, or an operator error: expected expression, found `$` - --> $DIR/expand-expr.rs:109:19 + --> $DIR/expand-expr.rs:111:19 | LL | expand_expr_fail!($); | ^ expected expression error: expected expression, found `$` - --> $DIR/expand-expr.rs:38:23 + --> $DIR/expand-expr.rs:40:23 | LL | ($($t:tt)*) => { $($t)* }; | ^^^^ expected expression error: expected expression, found `$` - --> $DIR/expand-expr.rs:111:28 + --> $DIR/expand-expr.rs:113:28 | LL | expand_expr_fail!(echo_pm!($)); | ^ expected expression error: macro expansion ignores token `hello` and any following - --> $DIR/expand-expr.rs:115:47 + --> $DIR/expand-expr.rs:117:47 | LL | expand_expr_is!("string", echo_tts!("string"; hello)); | --------------------^^^^^- caused by the macro expansion here @@ -35,7 +35,7 @@ LL | expand_expr_is!("string", echo_tts!("string"; hello);); | + error: macro expansion ignores token `;` and any following - --> $DIR/expand-expr.rs:116:44 + --> $DIR/expand-expr.rs:118:44 | LL | expand_expr_is!("string", echo_pm!("string"; hello)); | -----------------^------- caused by the macro expansion here @@ -47,7 +47,7 @@ LL | expand_expr_is!("string", echo_pm!("string"; hello);); | + error: recursion limit reached while expanding `recursive_expand!` - --> $DIR/expand-expr.rs:124:16 + --> $DIR/expand-expr.rs:126:16 | LL | const _: u32 = recursive_expand!(); | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/proc-macro/pretty-print-hack-show.remapped.stderr b/tests/ui/proc-macro/pretty-print-hack-show.remapped.stderr index ab5013848891e..873054927c962 100644 --- a/tests/ui/proc-macro/pretty-print-hack-show.remapped.stderr +++ b/tests/ui/proc-macro/pretty-print-hack-show.remapped.stderr @@ -1,5 +1,5 @@ error: using an old version of `rental` - --> remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6 + --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6 | LL | enum ProceduralMasqueradeDummyType { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -10,7 +10,7 @@ LL | enum ProceduralMasqueradeDummyType { = note: `#[deny(proc_macro_back_compat)]` on by default error: using an old version of `rental` - --> remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6 + --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6 | LL | enum ProceduralMasqueradeDummyType { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -20,7 +20,7 @@ LL | enum ProceduralMasqueradeDummyType { = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives error: using an old version of `rental` - --> remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6 + --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6 | LL | enum ProceduralMasqueradeDummyType { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -30,7 +30,7 @@ LL | enum ProceduralMasqueradeDummyType { = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives error: using an old version of `rental` - --> remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6 + --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6 | LL | enum ProceduralMasqueradeDummyType { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | enum ProceduralMasqueradeDummyType { = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives error: using an old version of `rental` - --> remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6 + --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6 | LL | enum ProceduralMasqueradeDummyType { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -50,7 +50,7 @@ LL | enum ProceduralMasqueradeDummyType { = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives error: using an old version of `rental` - --> remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6 + --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6 | LL | enum ProceduralMasqueradeDummyType { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -60,7 +60,7 @@ LL | enum ProceduralMasqueradeDummyType { = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives error: using an old version of `rental` - --> remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6 + --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6 | LL | enum ProceduralMasqueradeDummyType { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -70,7 +70,7 @@ LL | enum ProceduralMasqueradeDummyType { = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives error: using an old version of `rental` - --> remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6 + --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6 | LL | enum ProceduralMasqueradeDummyType { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -83,7 +83,7 @@ error: aborting due to 8 previous errors Future incompatibility report: Future breakage diagnostic: error: using an old version of `rental` - --> remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6 + --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6 | LL | enum ProceduralMasqueradeDummyType { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -95,7 +95,7 @@ LL | enum ProceduralMasqueradeDummyType { Future breakage diagnostic: error: using an old version of `rental` - --> remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6 + --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6 | LL | enum ProceduralMasqueradeDummyType { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -107,7 +107,7 @@ LL | enum ProceduralMasqueradeDummyType { Future breakage diagnostic: error: using an old version of `rental` - --> remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6 + --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6 | LL | enum ProceduralMasqueradeDummyType { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -119,7 +119,7 @@ LL | enum ProceduralMasqueradeDummyType { Future breakage diagnostic: error: using an old version of `rental` - --> remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6 + --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6 | LL | enum ProceduralMasqueradeDummyType { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -131,7 +131,7 @@ LL | enum ProceduralMasqueradeDummyType { Future breakage diagnostic: error: using an old version of `rental` - --> remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6 + --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6 | LL | enum ProceduralMasqueradeDummyType { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -143,7 +143,7 @@ LL | enum ProceduralMasqueradeDummyType { Future breakage diagnostic: error: using an old version of `rental` - --> remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6 + --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6 | LL | enum ProceduralMasqueradeDummyType { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -155,7 +155,7 @@ LL | enum ProceduralMasqueradeDummyType { Future breakage diagnostic: error: using an old version of `rental` - --> remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6 + --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6 | LL | enum ProceduralMasqueradeDummyType { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -167,7 +167,7 @@ LL | enum ProceduralMasqueradeDummyType { Future breakage diagnostic: error: using an old version of `rental` - --> remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6 + --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6 | LL | enum ProceduralMasqueradeDummyType { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/proc-macro/pretty-print-hack-show.remapped.stdout b/tests/ui/proc-macro/pretty-print-hack-show.remapped.stdout index 61ca53b28d40d..3d793d2a0145c 100644 --- a/tests/ui/proc-macro/pretty-print-hack-show.remapped.stdout +++ b/tests/ui/proc-macro/pretty-print-hack-show.remapped.stdout @@ -3,21 +3,21 @@ PRINT-DERIVE RE-COLLECTED (DISPLAY): enum ProceduralMasqueradeDummyType { Input PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "enum", - span: remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:1: 4:5 (#0), + span: $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:1: 4:5 (#0), }, Ident { ident: "ProceduralMasqueradeDummyType", - span: remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6: 4:35 (#0), + span: $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6: 4:35 (#0), }, Group { delimiter: Brace, stream: TokenStream [ Ident { ident: "Input", - span: remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:13:5: 13:10 (#0), + span: $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:13:5: 13:10 (#0), }, ], - span: remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:36: 14:2 (#0), + span: $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:36: 14:2 (#0), }, ] PRINT-DERIVE INPUT (DISPLAY): enum ProceduralMasqueradeDummyType { Input, } @@ -25,20 +25,20 @@ PRINT-DERIVE RE-COLLECTED (DISPLAY): enum ProceduralMasqueradeDummyType { Input PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "enum", - span: remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:1: 4:5 (#0), + span: $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:1: 4:5 (#0), }, Ident { ident: "ProceduralMasqueradeDummyType", - span: remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6: 4:35 (#0), + span: $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6: 4:35 (#0), }, Group { delimiter: Brace, stream: TokenStream [ Ident { ident: "Input", - span: remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:13:5: 13:10 (#0), + span: $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:13:5: 13:10 (#0), }, ], - span: remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:36: 14:2 (#0), + span: $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:36: 14:2 (#0), }, ] diff --git a/tests/ui/proc-macro/pretty-print-hack-show.rs b/tests/ui/proc-macro/pretty-print-hack-show.rs index e9ff66ba45a08..24a389c450ea0 100644 --- a/tests/ui/proc-macro/pretty-print-hack-show.rs +++ b/tests/ui/proc-macro/pretty-print-hack-show.rs @@ -1,11 +1,8 @@ // aux-build:test-macros.rs // compile-flags: -Z span-debug // revisions: local remapped -// [remapped]compile-flags: --remap-path-prefix={{src-base}}=remapped - -// The remapped paths are not normalized by compiletest. -// normalize-stdout-test: "\\(proc-macro|pretty-print-hack)" -> "/$1" -// normalize-stderr-test: "\\(proc-macro|pretty-print-hack)" -> "/$1" +// [local] no-remap-src-base: The hack should work regardless of remapping. +// [remapped] remap-src-base #![no_std] // Don't load unnecessary hygiene information from std extern crate std; From 4cc71843da467ac8e432af54ba33e377d770be1c Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 16 Jan 2023 11:46:48 -0800 Subject: [PATCH 077/230] ci: upgrade mingw-check to ubuntu:22.04 --- .../host-x86_64/mingw-check-tidy/Dockerfile | 6 +- .../docker/host-x86_64/mingw-check/Dockerfile | 6 +- .../mingw-check/reuse-requirements.in | 8 - .../mingw-check/reuse-requirements.txt | 197 ++++++------------ 4 files changed, 72 insertions(+), 145 deletions(-) diff --git a/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile b/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile index dc0e591cad6f6..889a586b351d6 100644 --- a/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile @@ -1,8 +1,6 @@ -FROM ubuntu:18.04 -# FIXME: when bumping the version, remove the Python 3.6-specific changes in -# the reuse-requirements.in file, regenerate reuse-requirements.txt and remove -# this comment. +FROM ubuntu:22.04 +ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile index d5bc76eeb23da..4cc5d9f8a0daf 100644 --- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile @@ -1,8 +1,6 @@ -FROM ubuntu:18.04 -# FIXME: when bumping the version, remove the Python 3.6-specific changes in -# the reuse-requirements.in file, regenerate reuse-requirements.txt and remove -# this comment. +FROM ubuntu:22.04 +ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ diff --git a/src/ci/docker/host-x86_64/mingw-check/reuse-requirements.in b/src/ci/docker/host-x86_64/mingw-check/reuse-requirements.in index 4964f40aa39ad..c7b3376e2f1fb 100644 --- a/src/ci/docker/host-x86_64/mingw-check/reuse-requirements.in +++ b/src/ci/docker/host-x86_64/mingw-check/reuse-requirements.in @@ -12,11 +12,3 @@ # reuse - -# Some packages dropped support for Python 3.6, which is the version used in -# this builder (due to Ubuntu 18.04). This should be removed once we bump the -# Ubuntu version of the builder. -jinja2 < 3.1 -markupsafe < 2.1 -requests < 2.28 -setuptools < 59.7 diff --git a/src/ci/docker/host-x86_64/mingw-check/reuse-requirements.txt b/src/ci/docker/host-x86_64/mingw-check/reuse-requirements.txt index 10a5f73879082..b0f598f77ea6f 100644 --- a/src/ci/docker/host-x86_64/mingw-check/reuse-requirements.txt +++ b/src/ci/docker/host-x86_64/mingw-check/reuse-requirements.txt @@ -1,6 +1,6 @@ # -# This file is autogenerated by pip-compile with python 3.10 -# To update, run: +# This file is autogenerated by pip-compile with Python 3.10 +# by the following command: # # pip-compile --allow-unsafe --generate-hashes reuse-requirements.in # @@ -8,138 +8,77 @@ binaryornot==0.4.4 \ --hash=sha256:359501dfc9d40632edc9fac890e19542db1a287bbcfa58175b66658392018061 \ --hash=sha256:b8b71173c917bddcd2c16070412e369c3ed7f0528926f70cac18a6c97fd563e4 # via reuse -boolean-py==3.8 \ - --hash=sha256:cc24e20f985d60cd4a3a5a1c0956dd12611159d32a75081dabd0c9ab981acaa4 \ - --hash=sha256:d75da0fd0354425fa64f6bbc6cec6ae1485d0eec3447b73187ff8cbf9b572e26 +boolean-py==4.0 \ + --hash=sha256:17b9a181630e43dde1851d42bef546d616d5d9b4480357514597e78b203d06e4 \ + --hash=sha256:2876f2051d7d6394a531d82dc6eb407faa0b01a0a0b3083817ccd7323b8d96bd # via # license-expression # reuse -certifi==2022.6.15 \ - --hash=sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d \ - --hash=sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412 - # via requests -chardet==5.0.0 \ - --hash=sha256:0368df2bfd78b5fc20572bb4e9bb7fb53e2c094f60ae9993339e8671d0afb8aa \ - --hash=sha256:d3e64f022d254183001eccc5db4040520c0f23b1a3f33d6413e099eb7f126557 +chardet==5.1.0 \ + --hash=sha256:0d62712b956bc154f85fb0a266e2a3c5913c2967e00348701b32411d6def31e5 \ + --hash=sha256:362777fb014af596ad31334fde1e8c327dfdb076e1960d1694662d46a6917ab9 # via # binaryornot # python-debian -charset-normalizer==2.0.12 \ - --hash=sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597 \ - --hash=sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df - # via requests -idna==3.3 \ - --hash=sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff \ - --hash=sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d - # via requests -jinja2==3.0.3 \ - --hash=sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8 \ - --hash=sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7 - # via - # -r reuse-requirements.in - # reuse -license-expression==21.6.14 \ - --hash=sha256:324246eed8e138b4139fefdc0e9dc4161d5075e3929e56983966d37298dca30e \ - --hash=sha256:9de87a427c9a449eee7913472fb9ed03b63036295547369fdbf95f76a8b924b2 - # via - # -r reuse-requirements.in - # reuse -markupsafe==2.0.1 \ - --hash=sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298 \ - --hash=sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64 \ - --hash=sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b \ - --hash=sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194 \ - --hash=sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567 \ - --hash=sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff \ - --hash=sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724 \ - --hash=sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74 \ - --hash=sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646 \ - --hash=sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35 \ - --hash=sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6 \ - --hash=sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a \ - --hash=sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6 \ - --hash=sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad \ - --hash=sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26 \ - --hash=sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38 \ - --hash=sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac \ - --hash=sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7 \ - --hash=sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6 \ - --hash=sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047 \ - --hash=sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75 \ - --hash=sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f \ - --hash=sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b \ - --hash=sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135 \ - --hash=sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8 \ - --hash=sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a \ - --hash=sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a \ - --hash=sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1 \ - --hash=sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9 \ - --hash=sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864 \ - --hash=sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914 \ - --hash=sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee \ - --hash=sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f \ - --hash=sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18 \ - --hash=sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8 \ - --hash=sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2 \ - --hash=sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d \ - --hash=sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b \ - --hash=sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b \ - --hash=sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86 \ - --hash=sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6 \ - --hash=sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f \ - --hash=sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb \ - --hash=sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833 \ - --hash=sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28 \ - --hash=sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e \ - --hash=sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415 \ - --hash=sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902 \ - --hash=sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f \ - --hash=sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d \ - --hash=sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9 \ - --hash=sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d \ - --hash=sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145 \ - --hash=sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066 \ - --hash=sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c \ - --hash=sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1 \ - --hash=sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a \ - --hash=sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207 \ - --hash=sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f \ - --hash=sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53 \ - --hash=sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd \ - --hash=sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134 \ - --hash=sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85 \ - --hash=sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9 \ - --hash=sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5 \ - --hash=sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94 \ - --hash=sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509 \ - --hash=sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51 \ - --hash=sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872 - # via - # -r reuse-requirements.in - # jinja2 -python-debian==0.1.44 \ - --hash=sha256:11bd6f01c46da57982bdd66dd595e2d240feb32a85de3fd37c452102fd0337ab \ - --hash=sha256:65592fe3b64f6c6c93d94e2d2599db5e0c22831d3bcff07cb7b96d3840b1333e +jinja2==3.1.2 \ + --hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \ + --hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61 # via reuse -requests==2.26.0 \ - --hash=sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24 \ - --hash=sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7 - # via - # -r reuse-requirements.in - # reuse -reuse==1.0.0 \ - --hash=sha256:db3022be2d87f69c8f508b928023de3026f454ce17d01e22f770f7147ac1e8d4 \ - --hash=sha256:e2605e796311c424465d741ea2a1e1ad03bbb90b921d74750119c331ca5af46e +license-expression==30.0.0 \ + --hash=sha256:ad638292aa8493f84354909b517922cb823582c2ce2c4d880e42544a86bea8dd \ + --hash=sha256:e95325110110eb2b7539ee7773b97a0724d5371ec563cc718c8cac0e38cc40cc + # via reuse +markupsafe==2.1.1 \ + --hash=sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003 \ + --hash=sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88 \ + --hash=sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5 \ + --hash=sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7 \ + --hash=sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a \ + --hash=sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603 \ + --hash=sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1 \ + --hash=sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135 \ + --hash=sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247 \ + --hash=sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6 \ + --hash=sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601 \ + --hash=sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77 \ + --hash=sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02 \ + --hash=sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e \ + --hash=sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63 \ + --hash=sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f \ + --hash=sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980 \ + --hash=sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b \ + --hash=sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812 \ + --hash=sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff \ + --hash=sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96 \ + --hash=sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1 \ + --hash=sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925 \ + --hash=sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a \ + --hash=sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6 \ + --hash=sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e \ + --hash=sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f \ + --hash=sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4 \ + --hash=sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f \ + --hash=sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3 \ + --hash=sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c \ + --hash=sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a \ + --hash=sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417 \ + --hash=sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a \ + --hash=sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a \ + --hash=sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37 \ + --hash=sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452 \ + --hash=sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933 \ + --hash=sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a \ + --hash=sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7 + # via jinja2 +python-debian==0.1.49 \ + --hash=sha256:880f3bc52e31599f2a9b432bd7691844286825087fccdcf2f6ffd5cd79a26f9f \ + --hash=sha256:8cf677a30dbcb4be7a99536c17e11308a827a4d22028dc59a67f6c6dd3f0f58c + # via reuse +reuse==1.1.0 \ + --hash=sha256:7a054f6e372ad02d0b1b07368030fc38746b50ed45f5422a81994e7a88b52f1f \ + --hash=sha256:b0f3fb9091ff513af04b555d14a4c529ab05f6a575ab192dd9b68244f1e0721d # via -r reuse-requirements.in -urllib3==1.26.10 \ - --hash=sha256:8298d6d56d39be0e3bc13c1c97d133f9b45d797169a0e11cdd0e0489d786f7ec \ - --hash=sha256:879ba4d1e89654d9769ce13121e0f94310ea32e8d2f8cf587b77c08bbcdb30d6 - # via requests - -# The following packages are considered to be unsafe in a requirements file: -setuptools==59.6.0 \ - --hash=sha256:22c7348c6d2976a52632c67f7ab0cdf40147db7789f9aed18734643fe9cf3373 \ - --hash=sha256:4ce92f1e1f8f01233ee9952c04f6b81d1e02939d6e1b488428154974a4d0783e - # via - # -r reuse-requirements.in - # reuse +setuptools==66.0.0 \ + --hash=sha256:a78d01d1e2c175c474884671dde039962c9d74c7223db7369771fcf6e29ceeab \ + --hash=sha256:bd6eb2d6722568de6d14b87c44a96fac54b2a45ff5e940e639979a3d1792adb6 + # via reuse From fdaac4e48ea276a595a7cdd08f4801763dfbb6cf Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 16 Jan 2023 19:55:20 +0000 Subject: [PATCH 078/230] ConstBlocks are poly if their substs are poly --- compiler/rustc_ty_utils/src/consts.rs | 44 ++++++++++++++++++- .../const-block-is-poly.rs | 11 +++++ .../const-block-is-poly.stderr | 20 +++++++++ 3 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 tests/ui/const-generics/generic_const_exprs/const-block-is-poly.rs create mode 100644 tests/ui/const-generics/generic_const_exprs/const-block-is-poly.stderr diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index a9b4e1420ea0d..a9fbad55dac55 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -302,13 +302,53 @@ impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> { } match expr.kind { - thir::ExprKind::NamedConst { substs, .. } => substs.has_non_region_param(), + thir::ExprKind::NamedConst { substs, .. } + | thir::ExprKind::ConstBlock { substs, .. } => substs.has_non_region_param(), thir::ExprKind::ConstParam { .. } => true, thir::ExprKind::Repeat { value, count } => { self.visit_expr(&self.thir()[value]); count.has_non_region_param() } - _ => false, + thir::ExprKind::Scope { .. } + | thir::ExprKind::Box { .. } + | thir::ExprKind::If { .. } + | thir::ExprKind::Call { .. } + | thir::ExprKind::Deref { .. } + | thir::ExprKind::Binary { .. } + | thir::ExprKind::LogicalOp { .. } + | thir::ExprKind::Unary { .. } + | thir::ExprKind::Cast { .. } + | thir::ExprKind::Use { .. } + | thir::ExprKind::NeverToAny { .. } + | thir::ExprKind::Pointer { .. } + | thir::ExprKind::Loop { .. } + | thir::ExprKind::Let { .. } + | thir::ExprKind::Match { .. } + | thir::ExprKind::Block { .. } + | thir::ExprKind::Assign { .. } + | thir::ExprKind::AssignOp { .. } + | thir::ExprKind::Field { .. } + | thir::ExprKind::Index { .. } + | thir::ExprKind::VarRef { .. } + | thir::ExprKind::UpvarRef { .. } + | thir::ExprKind::Borrow { .. } + | thir::ExprKind::AddressOf { .. } + | thir::ExprKind::Break { .. } + | thir::ExprKind::Continue { .. } + | thir::ExprKind::Return { .. } + | thir::ExprKind::Array { .. } + | thir::ExprKind::Tuple { .. } + | thir::ExprKind::Adt(_) + | thir::ExprKind::PlaceTypeAscription { .. } + | thir::ExprKind::ValueTypeAscription { .. } + | thir::ExprKind::Closure(_) + | thir::ExprKind::Literal { .. } + | thir::ExprKind::NonHirLiteral { .. } + | thir::ExprKind::ZstLiteral { .. } + | thir::ExprKind::StaticRef { .. } + | thir::ExprKind::InlineAsm(_) + | thir::ExprKind::ThreadLocalRef(_) + | thir::ExprKind::Yield { .. } => false, } } fn pat_is_poly(&mut self, pat: &thir::Pat<'tcx>) -> bool { diff --git a/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.rs b/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.rs new file mode 100644 index 0000000000000..7332a8f03c05f --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.rs @@ -0,0 +1,11 @@ +#![feature(inline_const, generic_const_exprs)] +//~^ WARN the feature `generic_const_exprs` is incomplete + +fn foo() { + let _ = [0u8; const { std::mem::size_of::() }]; + //~^ ERROR: overly complex generic constant +} + +fn main() { + foo::(); +} diff --git a/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.stderr b/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.stderr new file mode 100644 index 0000000000000..1513e491b9b99 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.stderr @@ -0,0 +1,20 @@ +warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/const-block-is-poly.rs:1:26 + | +LL | #![feature(inline_const, generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #76560 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: overly complex generic constant + --> $DIR/const-block-is-poly.rs:5:19 + | +LL | let _ = [0u8; const { std::mem::size_of::() }]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ const blocks are not supported in generic constant + | + = help: consider moving this anonymous constant into a `const` function + = note: this operation may be supported in the future + +error: aborting due to previous error; 1 warning emitted + From 9f6fef96571f52b3e4320cfcb906dfdc66eac1c3 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 16 Jan 2023 20:21:29 +0000 Subject: [PATCH 079/230] Properly pluralize 'generic constants' --- .../rustc_error_messages/locales/en-US/ty_utils.ftl | 12 ++++++------ .../array-size-in-generic-struct-param.full.stderr | 2 +- .../generic_const_exprs/const-block-is-poly.stderr | 2 +- .../generic_const_exprs/let-bindings.stderr | 4 ++-- .../generic_const_exprs/unused_expr.stderr | 6 +++--- .../const-generics/issues/issue-67945-2.full.stderr | 2 +- .../const-generics/issues/issue-67945-3.full.stderr | 2 +- .../const-generics/issues/issue-67945-4.full.stderr | 2 +- tests/ui/const-generics/issues/issue-77357.stderr | 2 +- 9 files changed, 17 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/ty_utils.ftl b/compiler/rustc_error_messages/locales/en-US/ty_utils.ftl index 1040ee1c97d81..abe65a0e3fef0 100644 --- a/compiler/rustc_error_messages/locales/en-US/ty_utils.ftl +++ b/compiler/rustc_error_messages/locales/en-US/ty_utils.ftl @@ -10,17 +10,17 @@ ty_utils_address_and_deref_not_supported = dereferencing or taking the address i ty_utils_array_not_supported = array construction is not supported in generic constants -ty_utils_block_not_supported = blocks are not supported in generic constant +ty_utils_block_not_supported = blocks are not supported in generic constants -ty_utils_never_to_any_not_supported = converting nevers to any is not supported in generic constant +ty_utils_never_to_any_not_supported = converting nevers to any is not supported in generic constants ty_utils_tuple_not_supported = tuple construction is not supported in generic constants -ty_utils_index_not_supported = indexing is not supported in generic constant +ty_utils_index_not_supported = indexing is not supported in generic constants -ty_utils_field_not_supported = field access is not supported in generic constant +ty_utils_field_not_supported = field access is not supported in generic constants -ty_utils_const_block_not_supported = const blocks are not supported in generic constant +ty_utils_const_block_not_supported = const blocks are not supported in generic constants ty_utils_adt_not_supported = struct/enum construction is not supported in generic constants @@ -44,4 +44,4 @@ ty_utils_control_flow_not_supported = control flow is not supported in generic c ty_utils_inline_asm_not_supported = assembly is not supported in generic constants -ty_utils_operation_not_supported = unsupported operation in generic constant +ty_utils_operation_not_supported = unsupported operation in generic constants diff --git a/tests/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr b/tests/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr index 041232e869079..1d10dfdf10c6e 100644 --- a/tests/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr +++ b/tests/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr @@ -10,7 +10,7 @@ error: overly complex generic constant --> $DIR/array-size-in-generic-struct-param.rs:19:15 | LL | arr: [u8; CFG.arr_size], - | ^^^^^^^^^^^^ field access is not supported in generic constant + | ^^^^^^^^^^^^ field access is not supported in generic constants | = help: consider moving this anonymous constant into a `const` function = note: this operation may be supported in the future diff --git a/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.stderr b/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.stderr index 1513e491b9b99..f262599084015 100644 --- a/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.stderr +++ b/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.stderr @@ -11,7 +11,7 @@ error: overly complex generic constant --> $DIR/const-block-is-poly.rs:5:19 | LL | let _ = [0u8; const { std::mem::size_of::() }]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ const blocks are not supported in generic constant + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ const blocks are not supported in generic constants | = help: consider moving this anonymous constant into a `const` function = note: this operation may be supported in the future diff --git a/tests/ui/const-generics/generic_const_exprs/let-bindings.stderr b/tests/ui/const-generics/generic_const_exprs/let-bindings.stderr index 5ebb4c3999c36..823a4f8a185bb 100644 --- a/tests/ui/const-generics/generic_const_exprs/let-bindings.stderr +++ b/tests/ui/const-generics/generic_const_exprs/let-bindings.stderr @@ -2,7 +2,7 @@ error: overly complex generic constant --> $DIR/let-bindings.rs:6:68 | LL | fn test() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default { - | ^^^^^^^^^^^^^^^^^^^^ blocks are not supported in generic constant + | ^^^^^^^^^^^^^^^^^^^^ blocks are not supported in generic constants | = help: consider moving this anonymous constant into a `const` function = note: this operation may be supported in the future @@ -11,7 +11,7 @@ error: overly complex generic constant --> $DIR/let-bindings.rs:6:35 | LL | fn test() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default { - | ^^^^^^^^^^^^^^^^^^^^ blocks are not supported in generic constant + | ^^^^^^^^^^^^^^^^^^^^ blocks are not supported in generic constants | = help: consider moving this anonymous constant into a `const` function = note: this operation may be supported in the future diff --git a/tests/ui/const-generics/generic_const_exprs/unused_expr.stderr b/tests/ui/const-generics/generic_const_exprs/unused_expr.stderr index df73acf53de65..265a3b9d23341 100644 --- a/tests/ui/const-generics/generic_const_exprs/unused_expr.stderr +++ b/tests/ui/const-generics/generic_const_exprs/unused_expr.stderr @@ -2,7 +2,7 @@ error: overly complex generic constant --> $DIR/unused_expr.rs:4:34 | LL | fn add() -> [u8; { N + 1; 5 }] { - | ^^^^^^^^^^^^ blocks are not supported in generic constant + | ^^^^^^^^^^^^ blocks are not supported in generic constants | = help: consider moving this anonymous constant into a `const` function = note: this operation may be supported in the future @@ -11,7 +11,7 @@ error: overly complex generic constant --> $DIR/unused_expr.rs:9:34 | LL | fn div() -> [u8; { N / 1; 5 }] { - | ^^^^^^^^^^^^ blocks are not supported in generic constant + | ^^^^^^^^^^^^ blocks are not supported in generic constants | = help: consider moving this anonymous constant into a `const` function = note: this operation may be supported in the future @@ -20,7 +20,7 @@ error: overly complex generic constant --> $DIR/unused_expr.rs:16:38 | LL | fn fn_call() -> [u8; { foo(N); 5 }] { - | ^^^^^^^^^^^^^ blocks are not supported in generic constant + | ^^^^^^^^^^^^^ blocks are not supported in generic constants | = help: consider moving this anonymous constant into a `const` function = note: this operation may be supported in the future diff --git a/tests/ui/const-generics/issues/issue-67945-2.full.stderr b/tests/ui/const-generics/issues/issue-67945-2.full.stderr index cce85772aa4da..47429b7612f94 100644 --- a/tests/ui/const-generics/issues/issue-67945-2.full.stderr +++ b/tests/ui/const-generics/issues/issue-67945-2.full.stderr @@ -8,7 +8,7 @@ LL | | let x: Option> = None; LL | | LL | | 0 LL | | }], - | |_____^ blocks are not supported in generic constant + | |_____^ blocks are not supported in generic constants | = help: consider moving this anonymous constant into a `const` function = note: this operation may be supported in the future diff --git a/tests/ui/const-generics/issues/issue-67945-3.full.stderr b/tests/ui/const-generics/issues/issue-67945-3.full.stderr index d3d9452d316ea..98f9f83976aa7 100644 --- a/tests/ui/const-generics/issues/issue-67945-3.full.stderr +++ b/tests/ui/const-generics/issues/issue-67945-3.full.stderr @@ -7,7 +7,7 @@ LL | | let x: Option = None; LL | | LL | | 0 LL | | }], - | |_____^ blocks are not supported in generic constant + | |_____^ blocks are not supported in generic constants | = help: consider moving this anonymous constant into a `const` function = note: this operation may be supported in the future diff --git a/tests/ui/const-generics/issues/issue-67945-4.full.stderr b/tests/ui/const-generics/issues/issue-67945-4.full.stderr index 9604eb35d02b2..c03d40a7bb832 100644 --- a/tests/ui/const-generics/issues/issue-67945-4.full.stderr +++ b/tests/ui/const-generics/issues/issue-67945-4.full.stderr @@ -7,7 +7,7 @@ LL | | let x: Option> = None; LL | | LL | | 0 LL | | }], - | |_____^ blocks are not supported in generic constant + | |_____^ blocks are not supported in generic constants | = help: consider moving this anonymous constant into a `const` function = note: this operation may be supported in the future diff --git a/tests/ui/const-generics/issues/issue-77357.stderr b/tests/ui/const-generics/issues/issue-77357.stderr index 804c0ae5175a8..68b35a38b0f8a 100644 --- a/tests/ui/const-generics/issues/issue-77357.stderr +++ b/tests/ui/const-generics/issues/issue-77357.stderr @@ -2,7 +2,7 @@ error: overly complex generic constant --> $DIR/issue-77357.rs:6:46 | LL | fn bug<'a, T>() -> &'static dyn MyTrait<[(); { |x: &'a u32| { x }; 4 }]> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ blocks are not supported in generic constant + | ^^^^^^^^^^^^^^^^^^^^^^^^^ blocks are not supported in generic constants | = help: consider moving this anonymous constant into a `const` function = note: this operation may be supported in the future From 7355ab3fe33518bbcaeb04ef0629674b6902293a Mon Sep 17 00:00:00 2001 From: onestacked Date: Mon, 16 Jan 2023 21:26:03 +0100 Subject: [PATCH 080/230] Constify `TypeId` ordering impls --- library/core/src/any.rs | 3 +- tests/ui/const-generics/issues/issue-90318.rs | 4 +-- .../const-generics/issues/issue-90318.stderr | 33 ++++++++----------- tests/ui/consts/const_cmp_type_id.rs | 12 +++++++ tests/ui/consts/issue-73976-monomorphic.rs | 3 +- 5 files changed, 32 insertions(+), 23 deletions(-) create mode 100644 tests/ui/consts/const_cmp_type_id.rs diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 9ca4947ed8f8b..c0fb0d993c3ed 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -662,7 +662,8 @@ impl dyn Any + Send + Sync { /// While `TypeId` implements `Hash`, `PartialOrd`, and `Ord`, it is worth /// noting that the hashes and ordering will vary between Rust releases. Beware /// of relying on them inside of your code! -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +#[derive(Clone, Copy, Debug, Hash, Eq)] +#[derive_const(PartialEq, PartialOrd, Ord)] #[stable(feature = "rust1", since = "1.0.0")] pub struct TypeId { t: u64, diff --git a/tests/ui/const-generics/issues/issue-90318.rs b/tests/ui/const-generics/issues/issue-90318.rs index d6c48e63bb3ce..909997340f36e 100644 --- a/tests/ui/const-generics/issues/issue-90318.rs +++ b/tests/ui/const-generics/issues/issue-90318.rs @@ -12,14 +12,14 @@ impl True for If {} fn consume(_val: T) where If<{ TypeId::of::() != TypeId::of::<()>() }>: True, - //~^ ERROR: can't compare + //~^ overly complex generic constant { } fn test() where If<{ TypeId::of::() != TypeId::of::<()>() }>: True, - //~^ ERROR: can't compare + //~^ overly complex generic constant { } diff --git a/tests/ui/const-generics/issues/issue-90318.stderr b/tests/ui/const-generics/issues/issue-90318.stderr index aba4b5c1a8d8d..f13fd795d7a10 100644 --- a/tests/ui/const-generics/issues/issue-90318.stderr +++ b/tests/ui/const-generics/issues/issue-90318.stderr @@ -1,29 +1,24 @@ -error[E0277]: can't compare `TypeId` with `_` in const contexts - --> $DIR/issue-90318.rs:14:28 +error: overly complex generic constant + --> $DIR/issue-90318.rs:14:8 | LL | If<{ TypeId::of::() != TypeId::of::<()>() }>: True, - | ^^ no implementation for `TypeId == _` + | ^^-----------------^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | borrowing is not supported in generic constants | - = help: the trait `~const PartialEq<_>` is not implemented for `TypeId` -note: the trait `PartialEq<_>` is implemented for `TypeId`, but that implementation is not `const` - --> $DIR/issue-90318.rs:14:28 - | -LL | If<{ TypeId::of::() != TypeId::of::<()>() }>: True, - | ^^ + = help: consider moving this anonymous constant into a `const` function + = note: this operation may be supported in the future -error[E0277]: can't compare `TypeId` with `_` in const contexts - --> $DIR/issue-90318.rs:21:28 +error: overly complex generic constant + --> $DIR/issue-90318.rs:21:8 | LL | If<{ TypeId::of::() != TypeId::of::<()>() }>: True, - | ^^ no implementation for `TypeId == _` + | ^^-----------------^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | borrowing is not supported in generic constants | - = help: the trait `~const PartialEq<_>` is not implemented for `TypeId` -note: the trait `PartialEq<_>` is implemented for `TypeId`, but that implementation is not `const` - --> $DIR/issue-90318.rs:21:28 - | -LL | If<{ TypeId::of::() != TypeId::of::<()>() }>: True, - | ^^ + = help: consider moving this anonymous constant into a `const` function + = note: this operation may be supported in the future error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/const_cmp_type_id.rs b/tests/ui/consts/const_cmp_type_id.rs new file mode 100644 index 0000000000000..f10d1c24f7ded --- /dev/null +++ b/tests/ui/consts/const_cmp_type_id.rs @@ -0,0 +1,12 @@ +// run-pass +#![feature(const_type_id)] +#![feature(const_trait_impl)] + +use std::any::TypeId; + +const fn main() { + assert!(TypeId::of::() == TypeId::of::()); + assert!(TypeId::of::<()>() != TypeId::of::()); + const _A: bool = TypeId::of::() < TypeId::of::(); + // can't assert `_A` because it is not deterministic +} diff --git a/tests/ui/consts/issue-73976-monomorphic.rs b/tests/ui/consts/issue-73976-monomorphic.rs index 7706a97f23b48..addcc1eaab60b 100644 --- a/tests/ui/consts/issue-73976-monomorphic.rs +++ b/tests/ui/consts/issue-73976-monomorphic.rs @@ -7,6 +7,7 @@ #![feature(const_type_id)] #![feature(const_type_name)] +#![feature(const_trait_impl)] use std::any::{self, TypeId}; @@ -17,7 +18,7 @@ impl GetTypeId { } const fn check_type_id() -> bool { - matches!(GetTypeId::::VALUE, GetTypeId::::VALUE) + GetTypeId::::VALUE == GetTypeId::::VALUE } pub struct GetTypeNameLen(T); From 3b0d306b94f78f375931f624f53114c205aef066 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 16 Jan 2023 01:31:21 +0400 Subject: [PATCH 081/230] rustdoc: Fix glob import inlining Filter away names that are not actually imported by the glob, e.g. because they are shadowed by something else --- src/librustdoc/clean/inline.rs | 22 ++++++++++++++++--- src/librustdoc/clean/mod.rs | 3 ++- .../inline_cross/auxiliary/cross-glob.rs | 2 ++ tests/rustdoc/inline_cross/cross-glob.rs | 5 +++++ 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index c6939326144ea..b3b0933123349 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -9,7 +9,7 @@ use rustc_ast as ast; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::Mutability; use rustc_metadata::creader::{CStore, LoadedMacro}; use rustc_middle::ty::{self, TyCtxt}; @@ -162,6 +162,7 @@ pub(crate) fn try_inline( pub(crate) fn try_inline_glob( cx: &mut DocContext<'_>, res: Res, + current_mod: LocalDefId, visited: &mut FxHashSet, inlined_names: &mut FxHashSet<(ItemType, Symbol)>, ) -> Option> { @@ -172,7 +173,16 @@ pub(crate) fn try_inline_glob( match res { Res::Def(DefKind::Mod, did) => { - let mut items = build_module_items(cx, did, visited, inlined_names); + // Use the set of module reexports to filter away names that are not actually + // reexported by the glob, e.g. because they are shadowed by something else. + let reexports = cx + .tcx + .module_reexports(current_mod) + .unwrap_or_default() + .iter() + .filter_map(|child| child.res.opt_def_id()) + .collect(); + let mut items = build_module_items(cx, did, visited, inlined_names, Some(&reexports)); items.drain_filter(|item| { if let Some(name) = item.name { // If an item with the same type and name already exists, @@ -563,7 +573,7 @@ fn build_module( did: DefId, visited: &mut FxHashSet, ) -> clean::Module { - let items = build_module_items(cx, did, visited, &mut FxHashSet::default()); + let items = build_module_items(cx, did, visited, &mut FxHashSet::default(), None); let span = clean::Span::new(cx.tcx.def_span(did)); clean::Module { items, span } @@ -574,6 +584,7 @@ fn build_module_items( did: DefId, visited: &mut FxHashSet, inlined_names: &mut FxHashSet<(ItemType, Symbol)>, + allowed_def_ids: Option<&FxHashSet>, ) -> Vec { let mut items = Vec::new(); @@ -583,6 +594,11 @@ fn build_module_items( for &item in cx.tcx.module_children(did).iter() { if item.vis.is_public() { let res = item.res.expect_non_local(); + if let Some(def_id) = res.opt_def_id() + && let Some(allowed_def_ids) = allowed_def_ids + && !allowed_def_ids.contains(&def_id) { + continue; + } if let Some(def_id) = res.mod_def_id() { // If we're inlining a glob import, it's possible to have // two distinct modules with the same name. We don't want to diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 415e7d5a360d0..20984696b6c01 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2441,7 +2441,8 @@ fn clean_use_statement_inner<'tcx>( let inner = if kind == hir::UseKind::Glob { if !denied { let mut visited = FxHashSet::default(); - if let Some(items) = inline::try_inline_glob(cx, path.res, &mut visited, inlined_names) + if let Some(items) = + inline::try_inline_glob(cx, path.res, current_mod, &mut visited, inlined_names) { return items; } diff --git a/tests/rustdoc/inline_cross/auxiliary/cross-glob.rs b/tests/rustdoc/inline_cross/auxiliary/cross-glob.rs index cde7f68ff0182..48672590a12dd 100644 --- a/tests/rustdoc/inline_cross/auxiliary/cross-glob.rs +++ b/tests/rustdoc/inline_cross/auxiliary/cross-glob.rs @@ -3,3 +3,5 @@ pub struct SomeStruct; pub fn some_fn() {} + +pub enum Shadowed {} diff --git a/tests/rustdoc/inline_cross/cross-glob.rs b/tests/rustdoc/inline_cross/cross-glob.rs index f97da11a90149..7a519d2d25547 100644 --- a/tests/rustdoc/inline_cross/cross-glob.rs +++ b/tests/rustdoc/inline_cross/cross-glob.rs @@ -6,6 +6,11 @@ extern crate inner; // @has cross_glob/struct.SomeStruct.html // @has cross_glob/fn.some_fn.html +// @!has cross_glob/enum.Shadowed.html // @!has cross_glob/index.html '//code' 'pub use inner::*;' #[doc(inline)] pub use inner::*; + +// This type shadows the glob-imported enum `Shadowed`. +// @has cross_glob/type.Shadowed.html +pub type Shadowed = u8; From 1ae1c49c501f8c6baf662e0a8081280bb7a9e79c Mon Sep 17 00:00:00 2001 From: Kyle Matsuda Date: Mon, 16 Jan 2023 11:55:27 -0700 Subject: [PATCH 082/230] document EarlyBinder::subst_identity and skip_binder --- compiler/rustc_middle/src/ty/subst.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 5dc9e311bf6b1..3008c64199a11 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -538,6 +538,9 @@ impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for &'tcx ty::List { /// Similar to [`super::Binder`] except that it tracks early bound generics, i.e. `struct Foo(T)` /// needs `T` substituted immediately. This type primarily exists to avoid forgetting to call /// `subst`. +/// +/// If you don't have anything to `subst`, you may be looking for +/// [`subst_identity`](EarlyBinder::subst_identity) or [`skip_binder`](EarlyBinder::skip_binder). #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[derive(Encodable, Decodable, HashStable)] pub struct EarlyBinder(pub T); @@ -578,6 +581,14 @@ impl EarlyBinder { EarlyBinder(value) } + /// Skips the binder and returns the "bound" value. + /// This can be used to extract data that does not depend on generic parameters + /// (e.g., getting the `DefId` of the inner value or getting the number of + /// arguments of an `FnSig`). Otherwise, consider using + /// [`subst_identity`](EarlyBinder::subst_identity). + /// + /// See also [`Binder::skip_binder`](super::Binder::skip_binder), which is + /// the analogous operation on [`super::Binder`]. pub fn skip_binder(self) -> T { self.0 } @@ -729,6 +740,14 @@ impl<'tcx, T: TypeFoldable<'tcx>> ty::EarlyBinder { self.0.fold_with(&mut folder) } + /// Makes the identity substitution `T0 => T0, ..., TN => TN`. + /// Conceptually, this converts universally bound variables into placeholders + /// when inside of a given item. + /// + /// For example, consider `for fn foo(){ .. }`: + /// - Outside of `foo`, `T` is bound (represented by the presence of `EarlyBinder`). + /// - Inside of the body of `foo`, we treat `T` as a placeholder by calling + /// `subst_identity` to discharge the `EarlyBinder`. pub fn subst_identity(self) -> T { self.0 } From f49126e3d612ec5f7e571a7ccfb3e4447cfa427c Mon Sep 17 00:00:00 2001 From: Jakob Degen Date: Sun, 8 Jan 2023 18:23:13 -0800 Subject: [PATCH 083/230] Document wf constraints on control flow in cleanup blocks Also fixes a bug in dominator computation --- .../src/transform/validate.rs | 62 +++++++++++++++++-- .../src/graph/dominators/mod.rs | 5 +- compiler/rustc_middle/src/mir/syntax.rs | 7 +++ 3 files changed, 68 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 94e1b95a0eb3c..9f429d3a7d984 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -1,6 +1,8 @@ //! Validates the MIR to ensure that invariants are upheld. -use rustc_data_structures::fx::FxHashSet; +use std::collections::hash_map::Entry; + +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_index::bit_set::BitSet; use rustc_infer::traits::Reveal; use rustc_middle::mir::interpret::Scalar; @@ -18,7 +20,7 @@ use rustc_mir_dataflow::storage::always_storage_live_locals; use rustc_mir_dataflow::{Analysis, ResultsCursor}; use rustc_target::abi::{Size, VariantIdx}; -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] enum EdgeKind { Unwind, Normal, @@ -57,7 +59,7 @@ impl<'tcx> MirPass<'tcx> for Validator { .iterate_to_fixpoint() .into_results_cursor(body); - TypeChecker { + let mut checker = TypeChecker { when: &self.when, body, tcx, @@ -67,8 +69,9 @@ impl<'tcx> MirPass<'tcx> for Validator { storage_liveness, place_cache: Vec::new(), value_cache: Vec::new(), - } - .visit_body(body); + }; + checker.visit_body(body); + checker.check_cleanup_control_flow(); } } @@ -134,6 +137,55 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } + fn check_cleanup_control_flow(&self) { + let doms = self.body.basic_blocks.dominators(); + let mut post_contract_node = FxHashMap::default(); + let mut get_post_contract_node = |mut bb| { + if let Some(res) = post_contract_node.get(&bb) { + return *res; + } + let mut dom_path = vec![]; + while self.body.basic_blocks[bb].is_cleanup { + dom_path.push(bb); + bb = doms.immediate_dominator(bb); + } + let root = *dom_path.last().unwrap(); + for bb in dom_path { + post_contract_node.insert(bb, root); + } + root + }; + + let mut parent = FxHashMap::default(); + for (bb, bb_data) in self.body.basic_blocks.iter_enumerated() { + if !bb_data.is_cleanup || !self.reachable_blocks.contains(bb) { + continue; + } + let bb = get_post_contract_node(bb); + for s in bb_data.terminator().successors() { + let s = get_post_contract_node(s); + if s == bb { + continue; + } + match parent.entry(bb) { + Entry::Vacant(e) => { + e.insert(s); + } + Entry::Occupied(e) if s != *e.get() => self.fail( + Location { block: bb, statement_index: 0 }, + format!( + "Cleanup control flow violation: The blocks dominated by {:?} have edges to both {:?} and {:?}", + bb, + s, + *e.get() + ) + ), + Entry::Occupied(_) => (), + } + } + } + } + /// Check if src can be assigned into dest. /// This is not precise, it will accept some incorrect assignments. fn mir_assign_valid_types(&self, src: Ty<'tcx>, dest: Ty<'tcx>) -> bool { diff --git a/compiler/rustc_data_structures/src/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs index ea2a4388b92f0..07b1ace218945 100644 --- a/compiler/rustc_data_structures/src/graph/dominators/mod.rs +++ b/compiler/rustc_data_structures/src/graph/dominators/mod.rs @@ -135,7 +135,10 @@ pub fn dominators(graph: G) -> Dominators { // This loop computes the semi[w] for w. semi[w] = w; for v in graph.predecessors(pre_order_to_real[w]) { - let v = real_to_pre_order[v].unwrap(); + // Reachable vertices may have unreachable predecessors, so ignore any of them + let Some(v) = real_to_pre_order[v] else { + continue + }; // eval returns a vertex x from which semi[x] is minimum among // vertices semi[v] +> x *> v. diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 6b4489026d3d3..0c395cae5665c 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -512,6 +512,13 @@ pub struct CopyNonOverlapping<'tcx> { /// must also be `cleanup`. This is a part of the type system and checked statically, so it is /// still an error to have such an edge in the CFG even if it's known that it won't be taken at /// runtime. +/// 4. The induced subgraph on cleanup blocks must look roughly like an upside down tree. This is +/// necessary to ensure that landing pad information can be correctly codegened. More precisely: +/// +/// Begin with the standard control flow graph `G`. Modify `G` as follows: for any two cleanup +/// vertices `u` and `v` such that `u` dominates `v`, contract `u` and `v` into a single vertex, +/// deleting self edges and duplicate edges in the process. The cleanup blocks of the resulting +/// graph must form an inverted forest. #[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, TypeFoldable, TypeVisitable)] pub enum TerminatorKind<'tcx> { /// Block has one successor; we continue execution there. From ec3d9934103ae33d2116bb5791b38921902c8539 Mon Sep 17 00:00:00 2001 From: Jakob Degen Date: Fri, 13 Jan 2023 08:32:54 -0800 Subject: [PATCH 084/230] Add cycle checking to cleanup control flow validation --- .../src/transform/validate.rs | 65 ++++++++++++++----- compiler/rustc_middle/src/mir/syntax.rs | 11 ++-- 2 files changed, 54 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 9f429d3a7d984..b4f1ab6226714 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -1,9 +1,8 @@ //! Validates the MIR to ensure that invariants are upheld. -use std::collections::hash_map::Entry; - use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_index::bit_set::BitSet; +use rustc_index::vec::IndexVec; use rustc_infer::traits::Reveal; use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::visit::NonUseContext::VarDebugInfo; @@ -140,23 +139,27 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { fn check_cleanup_control_flow(&self) { let doms = self.body.basic_blocks.dominators(); let mut post_contract_node = FxHashMap::default(); + // Reusing the allocation across invocations of the closure + let mut dom_path = vec![]; let mut get_post_contract_node = |mut bb| { - if let Some(res) = post_contract_node.get(&bb) { - return *res; - } - let mut dom_path = vec![]; - while self.body.basic_blocks[bb].is_cleanup { + let root = loop { + if let Some(root) = post_contract_node.get(&bb) { + break *root; + } + let parent = doms.immediate_dominator(bb); dom_path.push(bb); - bb = doms.immediate_dominator(bb); - } - let root = *dom_path.last().unwrap(); - for bb in dom_path { + if !self.body.basic_blocks[parent].is_cleanup { + break bb; + } + bb = parent; + }; + for bb in dom_path.drain(..) { post_contract_node.insert(bb, root); } root }; - let mut parent = FxHashMap::default(); + let mut parent = IndexVec::from_elem(None, &self.body.basic_blocks); for (bb, bb_data) in self.body.basic_blocks.iter_enumerated() { if !bb_data.is_cleanup || !self.reachable_blocks.contains(bb) { continue; @@ -167,23 +170,49 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { if s == bb { continue; } - match parent.entry(bb) { - Entry::Vacant(e) => { - e.insert(s); + let parent = &mut parent[bb]; + match parent { + None => { + *parent = Some(s); } - Entry::Occupied(e) if s != *e.get() => self.fail( + Some(e) if *e == s => (), + Some(e) => self.fail( Location { block: bb, statement_index: 0 }, format!( "Cleanup control flow violation: The blocks dominated by {:?} have edges to both {:?} and {:?}", bb, s, - *e.get() + *e ) ), - Entry::Occupied(_) => (), } } } + + // Check for cycles + let mut stack = FxHashSet::default(); + for i in 0..parent.len() { + let mut bb = BasicBlock::from_usize(i); + stack.clear(); + stack.insert(bb); + loop { + let Some(parent )= parent[bb].take() else { + break + }; + let no_cycle = stack.insert(parent); + if !no_cycle { + self.fail( + Location { block: bb, statement_index: 0 }, + format!( + "Cleanup control flow violation: Cycle involving edge {:?} -> {:?}", + bb, parent, + ), + ); + break; + } + bb = parent; + } + } } /// Check if src can be assigned into dest. diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 0c395cae5665c..52c2b10cbbea9 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -512,13 +512,16 @@ pub struct CopyNonOverlapping<'tcx> { /// must also be `cleanup`. This is a part of the type system and checked statically, so it is /// still an error to have such an edge in the CFG even if it's known that it won't be taken at /// runtime. -/// 4. The induced subgraph on cleanup blocks must look roughly like an upside down tree. This is -/// necessary to ensure that landing pad information can be correctly codegened. More precisely: +/// 4. The control flow between cleanup blocks must look like an upside down tree. Roughly +/// speaking, this means that control flow that looks like a V is allowed, while control flow +/// that looks like a W is not. This is necessary to ensure that landing pad information can be +/// correctly codegened on MSVC. More precisely: /// /// Begin with the standard control flow graph `G`. Modify `G` as follows: for any two cleanup /// vertices `u` and `v` such that `u` dominates `v`, contract `u` and `v` into a single vertex, -/// deleting self edges and duplicate edges in the process. The cleanup blocks of the resulting -/// graph must form an inverted forest. +/// deleting self edges and duplicate edges in the process. Now remove all vertices from `G` +/// that are not cleanup vertices or are not reachable. The resulting graph must be an inverted +/// tree, that is each vertex may have at most one successor and there may be no cycles. #[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, TypeFoldable, TypeVisitable)] pub enum TerminatorKind<'tcx> { /// Block has one successor; we continue execution there. From 4bc963eba67e61507d2069edf10cfec1d7f8ec0a Mon Sep 17 00:00:00 2001 From: Jakob Degen Date: Mon, 16 Jan 2023 15:01:16 -0800 Subject: [PATCH 085/230] Avoid trivial checks on cleanup control flow in MIR validator --- .../rustc_const_eval/src/transform/validate.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index b4f1ab6226714..dd168a9ac3cd3 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -64,6 +64,7 @@ impl<'tcx> MirPass<'tcx> for Validator { tcx, param_env, mir_phase, + unwind_edge_count: 0, reachable_blocks: traversal::reachable_as_bitset(body), storage_liveness, place_cache: Vec::new(), @@ -80,6 +81,7 @@ struct TypeChecker<'a, 'tcx> { tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, mir_phase: MirPhase, + unwind_edge_count: usize, reachable_blocks: BitSet, storage_liveness: ResultsCursor<'a, 'tcx, MaybeStorageLive<'static>>, place_cache: Vec>, @@ -104,7 +106,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); } - fn check_edge(&self, location: Location, bb: BasicBlock, edge_kind: EdgeKind) { + fn check_edge(&mut self, location: Location, bb: BasicBlock, edge_kind: EdgeKind) { if bb == START_BLOCK { self.fail(location, "start block must not have predecessors") } @@ -113,10 +115,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { match (src.is_cleanup, bb.is_cleanup, edge_kind) { // Non-cleanup blocks can jump to non-cleanup blocks along non-unwind edges (false, false, EdgeKind::Normal) - // Non-cleanup blocks can jump to cleanup blocks along unwind edges - | (false, true, EdgeKind::Unwind) // Cleanup blocks can jump to cleanup blocks along non-unwind edges | (true, true, EdgeKind::Normal) => {} + // Non-cleanup blocks can jump to cleanup blocks along unwind edges + (false, true, EdgeKind::Unwind) => { + self.unwind_edge_count += 1; + } // All other jumps are invalid _ => { self.fail( @@ -137,6 +141,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } fn check_cleanup_control_flow(&self) { + if self.unwind_edge_count <= 1 { + return; + } let doms = self.body.basic_blocks.dominators(); let mut post_contract_node = FxHashMap::default(); // Reusing the allocation across invocations of the closure @@ -196,7 +203,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { stack.clear(); stack.insert(bb); loop { - let Some(parent )= parent[bb].take() else { + let Some(parent)= parent[bb].take() else { break }; let no_cycle = stack.insert(parent); From e8ebd43eeb4ff25bec7859589eba36afa26c1ed0 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 16 Jan 2023 22:53:02 +0000 Subject: [PATCH 086/230] Use scope_expr_id from ProbeCtxt --- compiler/rustc_hir_typeck/src/method/probe.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 948a14604d437..a2481431363dd 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -486,7 +486,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { probe_cx.assemble_inherent_candidates(); match scope { ProbeScope::TraitsInScope => { - probe_cx.assemble_extension_candidates_for_traits_in_scope(scope_expr_id) + probe_cx.assemble_extension_candidates_for_traits_in_scope() } ProbeScope::AllTraits => probe_cx.assemble_extension_candidates_for_all_traits(), }; @@ -889,9 +889,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } - fn assemble_extension_candidates_for_traits_in_scope(&mut self, expr_hir_id: hir::HirId) { + fn assemble_extension_candidates_for_traits_in_scope(&mut self) { let mut duplicates = FxHashSet::default(); - let opt_applicable_traits = self.tcx.in_scope_traits(expr_hir_id); + let opt_applicable_traits = self.tcx.in_scope_traits(self.scope_expr_id); if let Some(applicable_traits) = opt_applicable_traits { for trait_candidate in applicable_traits.iter() { let trait_did = trait_candidate.def_id; From b46754762b68126d699ece2b3406cf2617ecc99d Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Thu, 12 Jan 2023 09:40:40 +0900 Subject: [PATCH 087/230] Update cc to 1.0.77 Fixes (without a test) #98746. --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5511d30177559..6b103470f5575 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -551,9 +551,9 @@ version = "0.1.0" [[package]] name = "cc" -version = "1.0.76" +version = "1.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a284da2e6fe2092f2353e51713435363112dfd60030e22add80be333fb928f" +checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4" dependencies = [ "jobserver", ] From 6c763821ba80fa54fcf237b0d422aa16d2a4e6f9 Mon Sep 17 00:00:00 2001 From: jyn Date: Mon, 16 Jan 2023 18:14:44 -0600 Subject: [PATCH 088/230] Don't add A-bootstrap to PRs modifying Cargo.lock Changing Cargo.lock is common even when adding dependencies between existing rustc crates. --- triagebot.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index 22f09396efc6a..94eb25e90cb41 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -185,7 +185,6 @@ trigger_files = [ "src/tools/x", "configure", "Cargo.toml", - "Cargo.lock", "config.toml.example", "src/stage0.json" ] From 716ea5f19cf28c4d2ce6b87ee17ab855ff837385 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 17 Jan 2023 02:35:47 +0000 Subject: [PATCH 089/230] Fix use suggestion span --- compiler/rustc_resolve/src/diagnostics.rs | 16 +++++++++------- tests/ui/extenv/issue-55897.stderr | 2 +- tests/ui/imports/bad-import-with-rename.stderr | 4 ++-- tests/ui/imports/issue-56125.stderr | 8 ++++---- tests/ui/imports/issue-57015.stderr | 2 +- .../not-allowed.stderr | 4 ++-- .../portable-intrinsics-arent-exposed.stderr | 2 +- .../test-attrs/inaccessible-test-modules.stderr | 2 +- tests/ui/unresolved/unresolved-candidates.stderr | 2 +- 9 files changed, 22 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index fb2aebbd18a3d..9277829f2faa3 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -5,10 +5,10 @@ use rustc_ast::visit::{self, Visitor}; use rustc_ast::{self as ast, Crate, ItemKind, ModKind, NodeId, Path, CRATE_NODE_ID}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::struct_span_err; use rustc_errors::{ pluralize, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, }; +use rustc_errors::{struct_span_err, SuggestionStyle}; use rustc_feature::BUILTIN_ATTRIBUTES; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind, PerNS}; @@ -2418,7 +2418,7 @@ fn show_candidates( } if let Some(span) = use_placement_span { - let add_use = match mode { + let (add_use, trailing) = match mode { DiagnosticMode::Pattern => { err.span_suggestions( span, @@ -2428,21 +2428,23 @@ fn show_candidates( ); return; } - DiagnosticMode::Import => "", - DiagnosticMode::Normal => "use ", + DiagnosticMode::Import => ("", ""), + DiagnosticMode::Normal => ("use ", ";\n"), }; for candidate in &mut accessible_path_strings { // produce an additional newline to separate the new use statement // from the directly following item. - let additional_newline = if let FoundUse::Yes = found_use { "" } else { "\n" }; - candidate.0 = format!("{add_use}{}{append};\n{additional_newline}", &candidate.0); + let additional_newline = if let FoundUse::No = found_use && let DiagnosticMode::Normal = mode { "\n" } else { "" }; + candidate.0 = + format!("{add_use}{}{append}{trailing}{additional_newline}", &candidate.0); } - err.span_suggestions( + err.span_suggestions_with_style( span, &msg, accessible_path_strings.into_iter().map(|a| a.0), Applicability::MaybeIncorrect, + SuggestionStyle::ShowAlways, ); if let [first, .., last] = &path[..] { let sp = first.ident.span.until(last.ident.span); diff --git a/tests/ui/extenv/issue-55897.stderr b/tests/ui/extenv/issue-55897.stderr index 63797d4a71bce..92e8a44b55fe5 100644 --- a/tests/ui/extenv/issue-55897.stderr +++ b/tests/ui/extenv/issue-55897.stderr @@ -30,7 +30,7 @@ LL | use env; help: consider importing this module instead | LL | use std::env; - | ~~~~~~~~~ + | ~~~~~~~~ error: cannot determine resolution for the macro `env` --> $DIR/issue-55897.rs:6:22 diff --git a/tests/ui/imports/bad-import-with-rename.stderr b/tests/ui/imports/bad-import-with-rename.stderr index cace2a7a51c8e..f9c5cf920e1f1 100644 --- a/tests/ui/imports/bad-import-with-rename.stderr +++ b/tests/ui/imports/bad-import-with-rename.stderr @@ -7,7 +7,7 @@ LL | use crate::D::B as _; help: consider importing this type alias instead | LL | use A::B as _; - | ~~~~~~~~~~ + | ~~~~~~~~~ error[E0432]: unresolved import `crate::D::B2` --> $DIR/bad-import-with-rename.rs:10:9 @@ -18,7 +18,7 @@ LL | use crate::D::B2; help: consider importing this type alias instead | LL | use A::B2; - | ~~~~~~ + | ~~~~~ error: aborting due to 2 previous errors diff --git a/tests/ui/imports/issue-56125.stderr b/tests/ui/imports/issue-56125.stderr index 059ca96808d9a..3448f3119778a 100644 --- a/tests/ui/imports/issue-56125.stderr +++ b/tests/ui/imports/issue-56125.stderr @@ -7,13 +7,13 @@ LL | use empty::issue_56125; help: consider importing one of these items instead | LL | use crate::m3::last_segment::issue_56125; - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ LL | use crate::m3::non_last_segment::non_last_segment::issue_56125; - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ LL | use issue_56125::issue_56125; - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~~~~~~ LL | use issue_56125::last_segment::issue_56125; - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ and 1 other candidate error[E0659]: `issue_56125` is ambiguous diff --git a/tests/ui/imports/issue-57015.stderr b/tests/ui/imports/issue-57015.stderr index 3b72d57fee41e..5374ba3dc9e6d 100644 --- a/tests/ui/imports/issue-57015.stderr +++ b/tests/ui/imports/issue-57015.stderr @@ -7,7 +7,7 @@ LL | use single_err::something; help: consider importing this module instead | LL | use glob_ok::something; - | ~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~ error: aborting due to previous error diff --git a/tests/ui/rfc-2126-extern-absolute-paths/not-allowed.stderr b/tests/ui/rfc-2126-extern-absolute-paths/not-allowed.stderr index 761089cd3871a..122e8fd350cb2 100644 --- a/tests/ui/rfc-2126-extern-absolute-paths/not-allowed.stderr +++ b/tests/ui/rfc-2126-extern-absolute-paths/not-allowed.stderr @@ -7,9 +7,9 @@ LL | use alloc; help: consider importing one of these items instead | LL | use core::alloc; - | ~~~~~~~~~~~~ -LL | use std::alloc; | ~~~~~~~~~~~ +LL | use std::alloc; + | ~~~~~~~~~~ error: aborting due to previous error diff --git a/tests/ui/simd/portable-intrinsics-arent-exposed.stderr b/tests/ui/simd/portable-intrinsics-arent-exposed.stderr index 8881ede0dbca7..f8b3e6d65afb6 100644 --- a/tests/ui/simd/portable-intrinsics-arent-exposed.stderr +++ b/tests/ui/simd/portable-intrinsics-arent-exposed.stderr @@ -15,7 +15,7 @@ LL | use std::simd::intrinsics; help: consider importing this module instead | LL | use std::intrinsics; - | ~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~ error: aborting due to 2 previous errors diff --git a/tests/ui/test-attrs/inaccessible-test-modules.stderr b/tests/ui/test-attrs/inaccessible-test-modules.stderr index a45c5bd45880f..7635f579d66b9 100644 --- a/tests/ui/test-attrs/inaccessible-test-modules.stderr +++ b/tests/ui/test-attrs/inaccessible-test-modules.stderr @@ -13,7 +13,7 @@ LL | use test as y; help: consider importing this module instead | LL | use test::test as y; - | ~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~ error: aborting due to 2 previous errors diff --git a/tests/ui/unresolved/unresolved-candidates.stderr b/tests/ui/unresolved/unresolved-candidates.stderr index bbd3eec2a5431..ea737c567b960 100644 --- a/tests/ui/unresolved/unresolved-candidates.stderr +++ b/tests/ui/unresolved/unresolved-candidates.stderr @@ -7,7 +7,7 @@ LL | use Trait; help: consider importing this trait instead | LL | use a::Trait; - | ~~~~~~~~~ + | ~~~~~~~~ error[E0405]: cannot find trait `Trait` in this scope --> $DIR/unresolved-candidates.rs:10:10 From 21725774a228771862f5b8b1c971eb77d54ec261 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 17 Jan 2023 03:09:49 +0000 Subject: [PATCH 090/230] note -> help --- compiler/rustc_resolve/src/diagnostics.rs | 2 +- tests/ui/empty/empty-macro-use.stderr | 2 +- tests/ui/hygiene/globs.stderr | 4 ++-- .../hygiene/no_implicit_prelude-2018.stderr | 2 +- tests/ui/imports/bad-import-in-nested.stderr | 6 +++--- tests/ui/macros/issue-88228.rs | 4 ++-- tests/ui/macros/issue-88228.stderr | 4 ++-- tests/ui/macros/macro-use-wrong-name.stderr | 2 +- tests/ui/missing/missing-macro-use.stderr | 2 +- .../proc-macro/derive-helper-shadowing.stderr | 4 ++-- tests/ui/proc-macro/generate-mod.stderr | 20 +++++++++---------- 11 files changed, 26 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 9277829f2faa3..f24e405018b74 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -2465,7 +2465,7 @@ fn show_candidates( msg.push_str(&candidate.0); } - err.note(&msg); + err.help(&msg); } } else if !matches!(mode, DiagnosticMode::Import) { assert!(!inaccessible_path_strings.is_empty()); diff --git a/tests/ui/empty/empty-macro-use.stderr b/tests/ui/empty/empty-macro-use.stderr index 700f6616af40f..e0b3b8685d6eb 100644 --- a/tests/ui/empty/empty-macro-use.stderr +++ b/tests/ui/empty/empty-macro-use.stderr @@ -4,7 +4,7 @@ error: cannot find macro `macro_two` in this scope LL | macro_two!(); | ^^^^^^^^^ | - = note: consider importing this macro: + = help: consider importing this macro: two_macros::macro_two error: aborting due to previous error diff --git a/tests/ui/hygiene/globs.stderr b/tests/ui/hygiene/globs.stderr index 1f2a96a4c411a..c01901be5fe78 100644 --- a/tests/ui/hygiene/globs.stderr +++ b/tests/ui/hygiene/globs.stderr @@ -51,7 +51,7 @@ LL | n!(f); LL | n!(f); | ^ not found in this scope | - = note: consider importing this function: + = help: consider importing this function: foo::f = note: this error originates in the macro `n` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -64,7 +64,7 @@ LL | n!(f); LL | f | ^ not found in this scope | - = note: consider importing this function: + = help: consider importing this function: foo::f = note: this error originates in the macro `n` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/hygiene/no_implicit_prelude-2018.stderr b/tests/ui/hygiene/no_implicit_prelude-2018.stderr index 02ddc391f6e3c..3f31b041b6203 100644 --- a/tests/ui/hygiene/no_implicit_prelude-2018.stderr +++ b/tests/ui/hygiene/no_implicit_prelude-2018.stderr @@ -4,7 +4,7 @@ error: cannot find macro `print` in this scope LL | print!(); | ^^^^^ | - = note: consider importing this macro: + = help: consider importing this macro: std::print error: aborting due to previous error diff --git a/tests/ui/imports/bad-import-in-nested.stderr b/tests/ui/imports/bad-import-in-nested.stderr index 855b1e637e97f..b6b1bc5fccf02 100644 --- a/tests/ui/imports/bad-import-in-nested.stderr +++ b/tests/ui/imports/bad-import-in-nested.stderr @@ -4,7 +4,7 @@ error[E0432]: unresolved import `super::super::C::D::AA` LL | use super::{super::C::D::AA, AA as _}; | ^^^^^^^^^^^^^^^ no `AA` in `C::D` | - = note: consider importing this type alias instead: + = help: consider importing this type alias instead: crate::A::AA error[E0432]: unresolved import `crate::C::AA` @@ -13,7 +13,7 @@ error[E0432]: unresolved import `crate::C::AA` LL | use crate::C::{self, AA}; | ^^ no `AA` in `C` | - = note: consider importing this type alias instead: + = help: consider importing this type alias instead: crate::A::AA error[E0432]: unresolved import `crate::C::BB` @@ -22,7 +22,7 @@ error[E0432]: unresolved import `crate::C::BB` LL | use crate::{A, C::BB}; | ^^^^^ no `BB` in `C` | - = note: consider importing this type alias instead: + = help: consider importing this type alias instead: crate::A::BB error: aborting due to 3 previous errors diff --git a/tests/ui/macros/issue-88228.rs b/tests/ui/macros/issue-88228.rs index cbdef5f0d40a9..60ba2eab7a7bf 100644 --- a/tests/ui/macros/issue-88228.rs +++ b/tests/ui/macros/issue-88228.rs @@ -8,7 +8,7 @@ mod hey { #[derive(Bla)] //~^ ERROR cannot find derive macro `Bla` -//~| NOTE consider importing this derive macro +//~| HELP consider importing this derive macro struct A; #[derive(println)] @@ -19,5 +19,5 @@ struct B; fn main() { bla!(); //~^ ERROR cannot find macro `bla` - //~| NOTE consider importing this macro + //~| HELP consider importing this macro } diff --git a/tests/ui/macros/issue-88228.stderr b/tests/ui/macros/issue-88228.stderr index 62afa67a783c9..fe8a1deaedd77 100644 --- a/tests/ui/macros/issue-88228.stderr +++ b/tests/ui/macros/issue-88228.stderr @@ -4,7 +4,7 @@ error: cannot find macro `bla` in this scope LL | bla!(); | ^^^ | - = note: consider importing this macro: + = help: consider importing this macro: crate::hey::bla error: cannot find derive macro `println` in this scope @@ -21,7 +21,7 @@ error: cannot find derive macro `Bla` in this scope LL | #[derive(Bla)] | ^^^ | - = note: consider importing this derive macro: + = help: consider importing this derive macro: crate::hey::Bla error: aborting due to 3 previous errors diff --git a/tests/ui/macros/macro-use-wrong-name.stderr b/tests/ui/macros/macro-use-wrong-name.stderr index 326001fc15a9a..ca5f0f190e8ba 100644 --- a/tests/ui/macros/macro-use-wrong-name.stderr +++ b/tests/ui/macros/macro-use-wrong-name.stderr @@ -9,7 +9,7 @@ LL | macro_two!(); LL | macro_rules! macro_one { () => ("one") } | ---------------------- similarly named macro `macro_one` defined here | - = note: consider importing this macro: + = help: consider importing this macro: two_macros::macro_two error: aborting due to previous error diff --git a/tests/ui/missing/missing-macro-use.stderr b/tests/ui/missing/missing-macro-use.stderr index ced062269df68..99e291cda0377 100644 --- a/tests/ui/missing/missing-macro-use.stderr +++ b/tests/ui/missing/missing-macro-use.stderr @@ -4,7 +4,7 @@ error: cannot find macro `macro_two` in this scope LL | macro_two!(); | ^^^^^^^^^ | - = note: consider importing this macro: + = help: consider importing this macro: two_macros::macro_two error: aborting due to previous error diff --git a/tests/ui/proc-macro/derive-helper-shadowing.stderr b/tests/ui/proc-macro/derive-helper-shadowing.stderr index 9c52ca4224116..de2c27a878c67 100644 --- a/tests/ui/proc-macro/derive-helper-shadowing.stderr +++ b/tests/ui/proc-macro/derive-helper-shadowing.stderr @@ -16,7 +16,7 @@ error: cannot find attribute `empty_helper` in this scope LL | #[derive(GenHelperUse)] | ^^^^^^^^^^^^ | - = note: consider importing this attribute macro: + = help: consider importing this attribute macro: empty_helper = note: this error originates in the derive macro `GenHelperUse` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -29,7 +29,7 @@ LL | #[empty_helper] LL | gen_helper_use!(); | ----------------- in this macro invocation | - = note: consider importing this attribute macro: + = help: consider importing this attribute macro: crate::empty_helper = note: this error originates in the macro `gen_helper_use` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/proc-macro/generate-mod.stderr b/tests/ui/proc-macro/generate-mod.stderr index 64042ca0ecdea..2c55abf38c399 100644 --- a/tests/ui/proc-macro/generate-mod.stderr +++ b/tests/ui/proc-macro/generate-mod.stderr @@ -4,7 +4,7 @@ error[E0412]: cannot find type `FromOutside` in this scope LL | generate_mod::check!(); | ^^^^^^^^^^^^^^^^^^^^^^ not found in this scope | - = note: consider importing this struct: + = help: consider importing this struct: FromOutside = note: this error originates in the macro `generate_mod::check` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -14,7 +14,7 @@ error[E0412]: cannot find type `Outer` in this scope LL | generate_mod::check!(); | ^^^^^^^^^^^^^^^^^^^^^^ not found in this scope | - = note: consider importing this struct: + = help: consider importing this struct: Outer = note: this error originates in the macro `generate_mod::check` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -24,7 +24,7 @@ error[E0412]: cannot find type `FromOutside` in this scope LL | #[generate_mod::check_attr] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope | - = note: consider importing this struct: + = help: consider importing this struct: FromOutside = note: this error originates in the attribute macro `generate_mod::check_attr` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -34,7 +34,7 @@ error[E0412]: cannot find type `OuterAttr` in this scope LL | #[generate_mod::check_attr] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope | - = note: consider importing this struct: + = help: consider importing this struct: OuterAttr = note: this error originates in the attribute macro `generate_mod::check_attr` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -44,7 +44,7 @@ error[E0412]: cannot find type `FromOutside` in this scope LL | #[derive(generate_mod::CheckDerive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope | - = note: consider importing this struct: + = help: consider importing this struct: FromOutside = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -54,7 +54,7 @@ error[E0412]: cannot find type `OuterDerive` in this scope LL | #[derive(generate_mod::CheckDerive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope | - = note: consider importing this struct: + = help: consider importing this struct: OuterDerive = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -64,7 +64,7 @@ error[E0412]: cannot find type `FromOutside` in this scope LL | #[derive(generate_mod::CheckDerive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope | - = note: consider importing this struct: + = help: consider importing this struct: FromOutside = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -74,7 +74,7 @@ error[E0412]: cannot find type `OuterDerive` in this scope LL | #[derive(generate_mod::CheckDerive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope | - = note: consider importing this struct: + = help: consider importing this struct: OuterDerive = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -84,7 +84,7 @@ error[E0412]: cannot find type `FromOutside` in this scope LL | #[derive(generate_mod::CheckDeriveLint)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope | - = note: consider importing this struct: + = help: consider importing this struct: FromOutside = note: this error originates in the derive macro `generate_mod::CheckDeriveLint` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -94,7 +94,7 @@ error[E0412]: cannot find type `OuterDeriveLint` in this scope LL | #[derive(generate_mod::CheckDeriveLint)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope | - = note: consider importing this struct: + = help: consider importing this struct: OuterDeriveLint = note: this error originates in the derive macro `generate_mod::CheckDeriveLint` (in Nightly builds, run with -Z macro-backtrace for more info) From 645c0fddd2e0446cc0e6eecd8a78de4b5ab5a967 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Fri, 30 Dec 2022 15:55:05 +0100 Subject: [PATCH 091/230] Put `noundef` on all scalars that don't allow uninit Previously, it was only put on scalars with range validity invariants like bool, was uninit was obviously invalid for those. Since then, we have normatively declared all uninit primitives to be undefined behavior and can therefore put `noundef` on them. The remaining concern was the `mem::uninitialized` function, which cause quite a lot of UB in the older parts of the ecosystem. This function now doesn't return uninit values anymore, making users of it safe from this change. The only real sources of UB where people could encounter uninit primitives are `MaybeUninit::uninit().assume_init()`, which has always be clear in the docs about being UB and from heap allocations (like reading from the spare capacity of a vec. This is hopefully rare enough to not break anything. --- compiler/rustc_codegen_llvm/src/builder.rs | 2 +- compiler/rustc_ty_utils/src/abi.rs | 2 +- tests/codegen/abi-sysv64.rs | 2 +- tests/codegen/abi-x86-interrupt.rs | 2 +- tests/codegen/adjustments.rs | 2 +- tests/codegen/box-maybe-uninit-llvm14.rs | 2 +- tests/codegen/box-maybe-uninit.rs | 2 +- tests/codegen/c-variadic.rs | 4 +- tests/codegen/call-llvm-intrinsics.rs | 2 +- tests/codegen/comparison-operators-newtype.rs | 8 +- tests/codegen/enum-match.rs | 6 +- tests/codegen/fastcall-inreg.rs | 12 +- tests/codegen/fewer-names.rs | 4 +- tests/codegen/frame-pointer.rs | 2 +- tests/codegen/function-arguments.rs | 30 ++-- tests/codegen/intrinsics/const_eval_select.rs | 2 +- tests/codegen/intrinsics/mask.rs | 2 +- tests/codegen/issue-32031.rs | 4 +- tests/codegen/issue-58881.rs | 2 +- tests/codegen/loads.rs | 6 +- tests/codegen/naked-functions.rs | 2 +- tests/codegen/pic-relocation-model.rs | 4 +- tests/codegen/pie-relocation-model.rs | 4 +- tests/codegen/refs.rs | 2 +- tests/codegen/repr-transparent.rs | 28 ++-- .../riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs | 18 +-- .../codegen/sanitizer-cfi-emit-type-checks.rs | 2 +- ...mit-kcfi-operand-bundle-itanium-cxx-abi.rs | 6 +- tests/codegen/sanitizer-recover.rs | 10 +- tests/codegen/scalar-pair-bool.rs | 4 +- .../some-abis-do-extend-params-to-32-bits.rs | 148 +++++++++--------- tests/codegen/transmute-scalar.rs | 10 +- tests/codegen/tuple-layout-opt.rs | 12 +- tests/codegen/var-names.rs | 2 +- tests/codegen/zst-offset.rs | 2 +- 35 files changed, 176 insertions(+), 176 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 5bf45a81e4347..5e98deae48aa2 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -501,7 +501,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { layout: TyAndLayout<'tcx>, offset: Size, ) { - if !scalar.is_always_valid(bx) { + if !scalar.is_uninit_valid() { bx.noundef_metadata(load); } diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index dc1dd1bfaf8e7..ce50b6fb43f50 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -220,7 +220,7 @@ fn adjust_for_rust_scalar<'tcx>( } // Scalars which have invalid values cannot be undef. - if !scalar.is_always_valid(&cx) { + if !scalar.is_uninit_valid() { attrs.set(ArgAttribute::NoUndef); } diff --git a/tests/codegen/abi-sysv64.rs b/tests/codegen/abi-sysv64.rs index dfc312279083d..e84c86b9ad04c 100644 --- a/tests/codegen/abi-sysv64.rs +++ b/tests/codegen/abi-sysv64.rs @@ -15,7 +15,7 @@ trait Sized {} trait Copy {} impl Copy for i64 {} -// CHECK: define x86_64_sysvcc i64 @has_sysv64_abi +// CHECK: define x86_64_sysvcc noundef i64 @has_sysv64_abi #[no_mangle] pub extern "sysv64" fn has_sysv64_abi(a: i64) -> i64 { a diff --git a/tests/codegen/abi-x86-interrupt.rs b/tests/codegen/abi-x86-interrupt.rs index d612f603e4fea..94df1cb9f78ba 100644 --- a/tests/codegen/abi-x86-interrupt.rs +++ b/tests/codegen/abi-x86-interrupt.rs @@ -15,7 +15,7 @@ trait Sized {} trait Copy {} impl Copy for i64 {} -// CHECK: define x86_intrcc i64 @has_x86_interrupt_abi +// CHECK: define x86_intrcc noundef i64 @has_x86_interrupt_abi #[no_mangle] pub extern "x86-interrupt" fn has_x86_interrupt_abi(a: i64) -> i64 { a diff --git a/tests/codegen/adjustments.rs b/tests/codegen/adjustments.rs index 39880c9341f4f..d09bdfa09d299 100644 --- a/tests/codegen/adjustments.rs +++ b/tests/codegen/adjustments.rs @@ -3,7 +3,7 @@ #![crate_type = "lib"] // Hack to get the correct size for the length part in slices -// CHECK: @helper([[USIZE:i[0-9]+]] %_1) +// CHECK: @helper([[USIZE:i[0-9]+]] noundef %_1) #[no_mangle] pub fn helper(_: usize) { } diff --git a/tests/codegen/box-maybe-uninit-llvm14.rs b/tests/codegen/box-maybe-uninit-llvm14.rs index 7b5ae894311ef..b0c88f76c436d 100644 --- a/tests/codegen/box-maybe-uninit-llvm14.rs +++ b/tests/codegen/box-maybe-uninit-llvm14.rs @@ -31,4 +31,4 @@ pub fn box_uninitialized2() -> Box> { // Hide the LLVM 15+ `allocalign` attribute in the declaration of __rust_alloc // from the CHECK-NOT above. We don't check the attributes here because we can't rely // on all of them being set until LLVM 15. -// CHECK: declare noalias{{.*}} @__rust_alloc(i{{[0-9]+}}, i{{[0-9]+.*}}) +// CHECK: declare noalias{{.*}} @__rust_alloc(i{{[0-9]+}} noundef, i{{[0-9]+.*}} noundef) diff --git a/tests/codegen/box-maybe-uninit.rs b/tests/codegen/box-maybe-uninit.rs index c82b56a71f5cf..2f88966996ab2 100644 --- a/tests/codegen/box-maybe-uninit.rs +++ b/tests/codegen/box-maybe-uninit.rs @@ -28,6 +28,6 @@ pub fn box_uninitialized2() -> Box> { // Hide the `allocalign` attribute in the declaration of __rust_alloc // from the CHECK-NOT above, and also verify the attributes got set reasonably. -// CHECK: declare noalias ptr @__rust_alloc(i{{[0-9]+}}, i{{[0-9]+}} allocalign) unnamed_addr [[RUST_ALLOC_ATTRS:#[0-9]+]] +// CHECK: declare noalias noundef ptr @__rust_alloc(i{{[0-9]+}} noundef, i{{[0-9]+}} allocalign noundef) unnamed_addr [[RUST_ALLOC_ATTRS:#[0-9]+]] // CHECK-DAG: attributes [[RUST_ALLOC_ATTRS]] = { {{.*}} allockind("alloc,uninitialized,aligned") allocsize(0) uwtable "alloc-family"="__rust_alloc" {{.*}} } diff --git a/tests/codegen/c-variadic.rs b/tests/codegen/c-variadic.rs index a5be56c47be81..1f16550d3b606 100644 --- a/tests/codegen/c-variadic.rs +++ b/tests/codegen/c-variadic.rs @@ -15,7 +15,7 @@ extern "C" { pub unsafe extern "C" fn use_foreign_c_variadic_0() { // Ensure that we correctly call foreign C-variadic functions. - // CHECK: call void (i32, ...) @foreign_c_variadic_0([[PARAM:i32( signext)?]] 0) + // CHECK: call void (i32, ...) @foreign_c_variadic_0([[PARAM:i32 noundef( signext)?]] 0) foreign_c_variadic_0(0); // CHECK: call void (i32, ...) @foreign_c_variadic_0([[PARAM]] 0, [[PARAM]] 42) foreign_c_variadic_0(0, 42i32); @@ -61,7 +61,7 @@ pub unsafe extern "C" fn c_variadic(n: i32, mut ap: ...) -> i32 { // Ensure that we generate the correct `call` signature when calling a Rust // defined C-variadic. pub unsafe fn test_c_variadic_call() { - // CHECK: call [[RET:(signext )?i32]] (i32, ...) @c_variadic([[PARAM]] 0) + // CHECK: call [[RET:noundef( signext)? i32]] (i32, ...) @c_variadic([[PARAM]] 0) c_variadic(0); // CHECK: call [[RET]] (i32, ...) @c_variadic([[PARAM]] 0, [[PARAM]] 42) c_variadic(0, 42i32); diff --git a/tests/codegen/call-llvm-intrinsics.rs b/tests/codegen/call-llvm-intrinsics.rs index 998099c239098..8e0327f84b4ac 100644 --- a/tests/codegen/call-llvm-intrinsics.rs +++ b/tests/codegen/call-llvm-intrinsics.rs @@ -23,7 +23,7 @@ pub fn do_call() { unsafe { // Ensure that we `call` LLVM intrinsics instead of trying to `invoke` them - // CHECK: call float @llvm.sqrt.f32(float 4.000000e+00 + // CHECK: call noundef float @llvm.sqrt.f32(float noundef 4.000000e+00 sqrt(4.0); } } diff --git a/tests/codegen/comparison-operators-newtype.rs b/tests/codegen/comparison-operators-newtype.rs index 5cf6c3ac0a233..683a2bd4fbb5a 100644 --- a/tests/codegen/comparison-operators-newtype.rs +++ b/tests/codegen/comparison-operators-newtype.rs @@ -13,7 +13,7 @@ use std::cmp::Ordering; pub struct Foo(u16); // CHECK-LABEL: @check_lt -// CHECK-SAME: (i16 %[[A:.+]], i16 %[[B:.+]]) +// CHECK-SAME: (i16 noundef %[[A:.+]], i16 noundef %[[B:.+]]) #[no_mangle] pub fn check_lt(a: Foo, b: Foo) -> bool { // CHECK: %[[R:.+]] = icmp ult i16 %[[A]], %[[B]] @@ -22,7 +22,7 @@ pub fn check_lt(a: Foo, b: Foo) -> bool { } // CHECK-LABEL: @check_le -// CHECK-SAME: (i16 %[[A:.+]], i16 %[[B:.+]]) +// CHECK-SAME: (i16 noundef %[[A:.+]], i16 noundef %[[B:.+]]) #[no_mangle] pub fn check_le(a: Foo, b: Foo) -> bool { // CHECK: %[[R:.+]] = icmp ule i16 %[[A]], %[[B]] @@ -31,7 +31,7 @@ pub fn check_le(a: Foo, b: Foo) -> bool { } // CHECK-LABEL: @check_gt -// CHECK-SAME: (i16 %[[A:.+]], i16 %[[B:.+]]) +// CHECK-SAME: (i16 noundef %[[A:.+]], i16 noundef %[[B:.+]]) #[no_mangle] pub fn check_gt(a: Foo, b: Foo) -> bool { // CHECK: %[[R:.+]] = icmp ugt i16 %[[A]], %[[B]] @@ -40,7 +40,7 @@ pub fn check_gt(a: Foo, b: Foo) -> bool { } // CHECK-LABEL: @check_ge -// CHECK-SAME: (i16 %[[A:.+]], i16 %[[B:.+]]) +// CHECK-SAME: (i16 noundef %[[A:.+]], i16 noundef %[[B:.+]]) #[no_mangle] pub fn check_ge(a: Foo, b: Foo) -> bool { // CHECK: %[[R:.+]] = icmp uge i16 %[[A]], %[[B]] diff --git a/tests/codegen/enum-match.rs b/tests/codegen/enum-match.rs index 827eb20154afd..5f8063a27f7ac 100644 --- a/tests/codegen/enum-match.rs +++ b/tests/codegen/enum-match.rs @@ -11,7 +11,7 @@ pub enum Enum0 { B, } -// CHECK: define i8 @match0{{.*}} +// CHECK: define noundef i8 @match0{{.*}} // CHECK-NEXT: start: // CHECK-NEXT: %1 = icmp eq i8 %0, 2 // CHECK-NEXT: %2 = and i8 %0, 1 @@ -32,7 +32,7 @@ pub enum Enum1 { C, } -// CHECK: define i8 @match1{{.*}} +// CHECK: define noundef i8 @match1{{.*}} // CHECK-NEXT: start: // CHECK-NEXT: [[DISCR:%.*]] = {{.*}}call i8 @llvm.usub.sat.i8(i8 %0, i8 1) // CHECK-NEXT: switch i8 [[DISCR]], label {{.*}} [ @@ -88,7 +88,7 @@ pub enum Enum2 { E, } -// CHECK: define i8 @match2{{.*}} +// CHECK: define noundef i8 @match2{{.*}} // CHECK-NEXT: start: // CHECK-NEXT: %1 = add i8 %0, 2 // CHECK-NEXT: %2 = zext i8 %1 to i64 diff --git a/tests/codegen/fastcall-inreg.rs b/tests/codegen/fastcall-inreg.rs index d426ade28dd12..02f5d545910e1 100644 --- a/tests/codegen/fastcall-inreg.rs +++ b/tests/codegen/fastcall-inreg.rs @@ -15,27 +15,27 @@ trait Sized {} trait Copy {} pub mod tests { - // CHECK: @f1(i32 inreg %_1, i32 inreg %_2, i32 %_3) + // CHECK: @f1(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3) #[no_mangle] pub extern "fastcall" fn f1(_: i32, _: i32, _: i32) {} - // CHECK: @f2({{i32\*|ptr}} inreg %_1, {{i32\*|ptr}} inreg %_2, {{i32\*|ptr}} %_3) + // CHECK: @f2({{i32\*|ptr}} inreg noundef %_1, {{i32\*|ptr}} inreg noundef %_2, {{i32\*|ptr}} noundef %_3) #[no_mangle] pub extern "fastcall" fn f2(_: *const i32, _: *const i32, _: *const i32) {} - // CHECK: @f3(float %_1, i32 inreg %_2, i32 inreg %_3, i32 %_4) + // CHECK: @f3(float noundef %_1, i32 inreg noundef %_2, i32 inreg noundef %_3, i32 noundef %_4) #[no_mangle] pub extern "fastcall" fn f3(_: f32, _: i32, _: i32, _: i32) {} - // CHECK: @f4(i32 inreg %_1, float %_2, i32 inreg %_3, i32 %_4) + // CHECK: @f4(i32 inreg noundef %_1, float noundef %_2, i32 inreg noundef %_3, i32 noundef %_4) #[no_mangle] pub extern "fastcall" fn f4(_: i32, _: f32, _: i32, _: i32) {} - // CHECK: @f5(i64 %_1, i32 %_2) + // CHECK: @f5(i64 noundef %_1, i32 noundef %_2) #[no_mangle] pub extern "fastcall" fn f5(_: i64, _: i32) {} - // CHECK: @f6(i1 inreg noundef zeroext %_1, i32 inreg %_2, i32 %_3) + // CHECK: @f6(i1 inreg noundef zeroext %_1, i32 inreg noundef %_2, i32 noundef %_3) #[no_mangle] pub extern "fastcall" fn f6(_: bool, _: i32, _: i32) {} } diff --git a/tests/codegen/fewer-names.rs b/tests/codegen/fewer-names.rs index 7307e0379dfa0..ac8cba06b48f7 100644 --- a/tests/codegen/fewer-names.rs +++ b/tests/codegen/fewer-names.rs @@ -7,11 +7,11 @@ #[no_mangle] pub fn sum(x: u32, y: u32) -> u32 { -// YES-LABEL: define{{.*}}i32 @sum(i32 %0, i32 %1) +// YES-LABEL: define{{.*}}i32 @sum(i32 noundef %0, i32 noundef %1) // YES-NEXT: %3 = add i32 %1, %0 // YES-NEXT: ret i32 %3 -// NO-LABEL: define{{.*}}i32 @sum(i32 %x, i32 %y) +// NO-LABEL: define{{.*}}i32 @sum(i32 noundef %x, i32 noundef %y) // NO-NEXT: start: // NO-NEXT: %z = add i32 %y, %x // NO-NEXT: ret i32 %z diff --git a/tests/codegen/frame-pointer.rs b/tests/codegen/frame-pointer.rs index f7c02d47939fe..da7f2ec80460c 100644 --- a/tests/codegen/frame-pointer.rs +++ b/tests/codegen/frame-pointer.rs @@ -20,7 +20,7 @@ trait Copy { } impl Copy for u32 {} -// CHECK: define i32 @peach{{.*}}[[PEACH_ATTRS:\#[0-9]+]] { +// CHECK: define noundef i32 @peach{{.*}}[[PEACH_ATTRS:\#[0-9]+]] { #[no_mangle] pub fn peach(x: u32) -> u32 { x diff --git a/tests/codegen/function-arguments.rs b/tests/codegen/function-arguments.rs index 0f9e90f6ba779..20519978a0d19 100644 --- a/tests/codegen/function-arguments.rs +++ b/tests/codegen/function-arguments.rs @@ -61,7 +61,7 @@ pub fn maybeuninit_char(x: MaybeUninit) -> MaybeUninit { x } -// CHECK: i64 @int(i64 %x) +// CHECK: noundef i64 @int(i64 noundef %x) #[no_mangle] pub fn int(x: u64) -> u64 { x @@ -73,7 +73,7 @@ pub fn nonzero_int(x: NonZeroU64) -> NonZeroU64 { x } -// CHECK: i64 @option_nonzero_int(i64 %x) +// CHECK: noundef i64 @option_nonzero_int(i64 noundef %x) #[no_mangle] pub fn option_nonzero_int(x: Option) -> Option { x @@ -138,7 +138,7 @@ pub fn indirect_struct(_: S) { pub fn borrowed_struct(_: &S) { } -// CHECK: @raw_struct({{%S\*|ptr}} %_1) +// CHECK: @raw_struct({{%S\*|ptr}} noundef %_1) #[no_mangle] pub fn raw_struct(_: *const S) { } @@ -160,35 +160,35 @@ pub fn struct_return() -> S { } // Hack to get the correct size for the length part in slices -// CHECK: @helper([[USIZE:i[0-9]+]] %_1) +// CHECK: @helper([[USIZE:i[0-9]+]] noundef %_1) #[no_mangle] pub fn helper(_: usize) { } -// CHECK: @slice({{\[0 x i8\]\*|ptr}} noalias noundef nonnull readonly align 1 %_1.0, [[USIZE]] %_1.1) +// CHECK: @slice({{\[0 x i8\]\*|ptr}} noalias noundef nonnull readonly align 1 %_1.0, [[USIZE]] noundef %_1.1) // FIXME #25759 This should also have `nocapture` #[no_mangle] pub fn slice(_: &[u8]) { } -// CHECK: @mutable_slice({{\[0 x i8\]\*|ptr}} noalias noundef nonnull align 1 %_1.0, [[USIZE]] %_1.1) +// CHECK: @mutable_slice({{\[0 x i8\]\*|ptr}} noalias noundef nonnull align 1 %_1.0, [[USIZE]] noundef %_1.1) // FIXME #25759 This should also have `nocapture` #[no_mangle] pub fn mutable_slice(_: &mut [u8]) { } -// CHECK: @unsafe_slice({{\[0 x i16\]\*|ptr}} noundef nonnull align 2 %_1.0, [[USIZE]] %_1.1) +// CHECK: @unsafe_slice({{\[0 x i16\]\*|ptr}} noundef nonnull align 2 %_1.0, [[USIZE]] noundef %_1.1) // unsafe interior means this isn't actually readonly and there may be aliases ... #[no_mangle] pub fn unsafe_slice(_: &[UnsafeInner]) { } -// CHECK: @raw_slice({{\[0 x i8\]\*|ptr}} %_1.0, [[USIZE]] %_1.1) +// CHECK: @raw_slice({{\[0 x i8\]\*|ptr}} noundef %_1.0, [[USIZE]] noundef %_1.1) #[no_mangle] pub fn raw_slice(_: *const [u8]) { } -// CHECK: @str({{\[0 x i8\]\*|ptr}} noalias noundef nonnull readonly align 1 %_1.0, [[USIZE]] %_1.1) +// CHECK: @str({{\[0 x i8\]\*|ptr}} noalias noundef nonnull readonly align 1 %_1.0, [[USIZE]] noundef %_1.1) // FIXME #25759 This should also have `nocapture` #[no_mangle] pub fn str(_: &[u8]) { @@ -197,26 +197,26 @@ pub fn str(_: &[u8]) { // CHECK: @trait_borrow({{\{\}\*|ptr}} noundef nonnull align 1 %_1.0, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}) %_1.1) // FIXME #25759 This should also have `nocapture` #[no_mangle] -pub fn trait_borrow(_: &Drop) { +pub fn trait_borrow(_: &dyn Drop) { } -// CHECK: @trait_raw({{\{\}\*|ptr}} %_1.0, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}) %_1.1) +// CHECK: @trait_raw({{\{\}\*|ptr}} noundef %_1.0, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}) %_1.1) #[no_mangle] -pub fn trait_raw(_: *const Drop) { +pub fn trait_raw(_: *const dyn Drop) { } // CHECK: @trait_box({{\{\}\*|ptr}} noalias noundef nonnull align 1{{( %0)?}}, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}){{( %1)?}}) #[no_mangle] -pub fn trait_box(_: Box) { +pub fn trait_box(_: Box) { } // CHECK: { {{i8\*|ptr}}, {{i8\*|ptr}} } @trait_option({{i8\*|ptr}} noalias noundef align 1 %x.0, {{i8\*|ptr}} %x.1) #[no_mangle] -pub fn trait_option(x: Option>) -> Option> { +pub fn trait_option(x: Option>) -> Option> { x } -// CHECK: { {{\[0 x i16\]\*|ptr}}, [[USIZE]] } @return_slice({{\[0 x i16\]\*|ptr}} noalias noundef nonnull readonly align 2 %x.0, [[USIZE]] %x.1) +// CHECK: { {{\[0 x i16\]\*|ptr}}, [[USIZE]] } @return_slice({{\[0 x i16\]\*|ptr}} noalias noundef nonnull readonly align 2 %x.0, [[USIZE]] noundef %x.1) #[no_mangle] pub fn return_slice(x: &[u16]) -> &[u16] { x diff --git a/tests/codegen/intrinsics/const_eval_select.rs b/tests/codegen/intrinsics/const_eval_select.rs index db8a04763d35d..424157158f6c8 100644 --- a/tests/codegen/intrinsics/const_eval_select.rs +++ b/tests/codegen/intrinsics/const_eval_select.rs @@ -13,6 +13,6 @@ pub fn hi(n: i32) -> i32 { n } #[no_mangle] pub unsafe fn hey() { - // CHECK: call i32 @hi(i32 + // CHECK: call noundef i32 @hi(i32 const_eval_select((42,), foo, hi); } diff --git a/tests/codegen/intrinsics/mask.rs b/tests/codegen/intrinsics/mask.rs index 2e984db1be528..c7a2e4ba06dd2 100644 --- a/tests/codegen/intrinsics/mask.rs +++ b/tests/codegen/intrinsics/mask.rs @@ -2,7 +2,7 @@ #![feature(core_intrinsics)] // CHECK-LABEL: @mask_ptr -// CHECK-SAME: [[WORD:i[0-9]+]] %mask +// CHECK-SAME: [[WORD:i[0-9]+]] noundef %mask #[no_mangle] pub fn mask_ptr(ptr: *const u16, mask: usize) -> *const u16 { // CHECK: call diff --git a/tests/codegen/issue-32031.rs b/tests/codegen/issue-32031.rs index 82ba325572ab4..b181079785cf1 100644 --- a/tests/codegen/issue-32031.rs +++ b/tests/codegen/issue-32031.rs @@ -5,7 +5,7 @@ #[no_mangle] pub struct F32(f32); -// CHECK: define{{.*}}float @add_newtype_f32(float %a, float %b) +// CHECK: define{{.*}}float @add_newtype_f32(float noundef %a, float noundef %b) #[inline(never)] #[no_mangle] pub fn add_newtype_f32(a: F32, b: F32) -> F32 { @@ -15,7 +15,7 @@ pub fn add_newtype_f32(a: F32, b: F32) -> F32 { #[no_mangle] pub struct F64(f64); -// CHECK: define{{.*}}double @add_newtype_f64(double %a, double %b) +// CHECK: define{{.*}}double @add_newtype_f64(double noundef %a, double noundef %b) #[inline(never)] #[no_mangle] pub fn add_newtype_f64(a: F64, b: F64) -> F64 { diff --git a/tests/codegen/issue-58881.rs b/tests/codegen/issue-58881.rs index 0900a33377bcd..9349b78f96205 100644 --- a/tests/codegen/issue-58881.rs +++ b/tests/codegen/issue-58881.rs @@ -16,6 +16,6 @@ struct Bar(u64, u64, u64); // Ensure that emit arguments of the correct type. pub unsafe fn test_call_variadic() { - // CHECK: call void (i32, ...) @variadic_fn(i32 0, i8 {{.*}}, {{%Bar\*|ptr}} {{.*}}) + // CHECK: call void (i32, ...) @variadic_fn(i32 noundef 0, i8 {{.*}}, {{%Bar\*|ptr}} {{.*}}) variadic_fn(0, Foo(0), Bar(0, 0, 0)) } diff --git a/tests/codegen/loads.rs b/tests/codegen/loads.rs index f448306ba1b08..c972819709258 100644 --- a/tests/codegen/loads.rs +++ b/tests/codegen/loads.rs @@ -51,7 +51,7 @@ pub fn load_scalar_pair<'a>(x: &(&'a i32, &'a Align16)) -> (&'a i32, &'a Align16 #[no_mangle] pub fn load_raw_pointer<'a>(x: &*const i32) -> *const i32 { // loaded raw pointer should not have !nonnull, !align, or !noundef metadata - // CHECK: load {{i32\*|ptr}}, {{i32\*\*|ptr}} %x, align [[PTR_ALIGNMENT]]{{$}} + // CHECK: load {{i32\*|ptr}}, {{i32\*\*|ptr}} %x, align [[PTR_ALIGNMENT]], !noundef !2{{$}} *x } @@ -93,7 +93,7 @@ pub fn load_maybeuninit_enum_bool(x: &MaybeUninit) -> MaybeUninit u16 { - // CHECK: load i16, {{i16\*|ptr}} %x, align 2{{$}} + // CHECK: load i16, {{i16\*|ptr}} %x, align 2, !noundef !2{{$}} *x } @@ -107,7 +107,7 @@ pub fn load_nonzero_int(x: &NonZeroU16) -> NonZeroU16 { // CHECK-LABEL: @load_option_nonzero_int #[no_mangle] pub fn load_option_nonzero_int(x: &Option) -> Option { - // CHECK: load i16, {{i16\*|ptr}} %x, align 2{{$}} + // CHECK: load i16, {{i16\*|ptr}} %x, align 2, !noundef !2{{$}} *x } diff --git a/tests/codegen/naked-functions.rs b/tests/codegen/naked-functions.rs index 51c7a0c615d00..725c0a67a0060 100644 --- a/tests/codegen/naked-functions.rs +++ b/tests/codegen/naked-functions.rs @@ -19,7 +19,7 @@ pub unsafe extern "C" fn naked_empty() { } // CHECK: Function Attrs: naked -// CHECK-NEXT: define{{.*}}i{{[0-9]+}} @naked_with_args_and_return(i64 %a, i64 %b) +// CHECK-NEXT: define{{.*}}i{{[0-9]+}} @naked_with_args_and_return(i64 noundef %a, i64 noundef %b) #[no_mangle] #[naked] pub unsafe extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize { diff --git a/tests/codegen/pic-relocation-model.rs b/tests/codegen/pic-relocation-model.rs index 602a08067bae1..7b4f0d9bae5d1 100644 --- a/tests/codegen/pic-relocation-model.rs +++ b/tests/codegen/pic-relocation-model.rs @@ -2,7 +2,7 @@ #![crate_type = "rlib"] -// CHECK: define i8 @call_foreign_fn() +// CHECK: define noundef i8 @call_foreign_fn() #[no_mangle] pub fn call_foreign_fn() -> u8 { unsafe { @@ -13,7 +13,7 @@ pub fn call_foreign_fn() -> u8 { // (Allow but do not require `zeroext` here, because it is not worth effort to // spell out which targets have it and which ones do not; see rust#97800.) -// CHECK: declare{{( zeroext)?}} i8 @foreign_fn() +// CHECK: declare noundef{{( zeroext)?}} i8 @foreign_fn() extern "C" {fn foreign_fn() -> u8;} // CHECK: !{i32 {{[78]}}, !"PIC Level", i32 2} diff --git a/tests/codegen/pie-relocation-model.rs b/tests/codegen/pie-relocation-model.rs index ec44edc066774..a59216c3eee5b 100644 --- a/tests/codegen/pie-relocation-model.rs +++ b/tests/codegen/pie-relocation-model.rs @@ -5,7 +5,7 @@ // With PIE we know local functions cannot be interpositioned, we can mark them // as dso_local. -// CHECK: define dso_local i8 @call_foreign_fn() +// CHECK: define dso_local noundef i8 @call_foreign_fn() #[no_mangle] pub fn call_foreign_fn() -> u8 { unsafe { @@ -15,7 +15,7 @@ pub fn call_foreign_fn() -> u8 { // External functions are still marked as non-dso_local, since we don't know if the symbol // is defined in the binary or in the shared library. -// CHECK: declare zeroext i8 @foreign_fn() +// CHECK: declare noundef zeroext i8 @foreign_fn() extern "C" {fn foreign_fn() -> u8;} // CHECK: !{i32 {{[78]}}, !"PIC Level", i32 2} diff --git a/tests/codegen/refs.rs b/tests/codegen/refs.rs index 0b796754d1d86..579fd901ee66a 100644 --- a/tests/codegen/refs.rs +++ b/tests/codegen/refs.rs @@ -3,7 +3,7 @@ #![crate_type = "lib"] // Hack to get the correct size for the length part in slices -// CHECK: @helper([[USIZE:i[0-9]+]] %_1) +// CHECK: @helper([[USIZE:i[0-9]+]] noundef %_1) #[no_mangle] pub fn helper(_: usize) { } diff --git a/tests/codegen/repr-transparent.rs b/tests/codegen/repr-transparent.rs index 4f2313ce47a97..311cbfbaa0937 100644 --- a/tests/codegen/repr-transparent.rs +++ b/tests/codegen/repr-transparent.rs @@ -18,21 +18,21 @@ pub struct Zst2(()); #[repr(transparent)] pub struct F32(f32); -// CHECK: define{{.*}}float @test_F32(float %_1) +// CHECK: define{{.*}}float @test_F32(float noundef %_1) #[no_mangle] pub extern "C" fn test_F32(_: F32) -> F32 { loop {} } #[repr(transparent)] pub struct Ptr(*mut u8); -// CHECK: define{{.*}}{{i8\*|ptr}} @test_Ptr({{i8\*|ptr}} %_1) +// CHECK: define{{.*}}{{i8\*|ptr}} @test_Ptr({{i8\*|ptr}} noundef %_1) #[no_mangle] pub extern "C" fn test_Ptr(_: Ptr) -> Ptr { loop {} } #[repr(transparent)] pub struct WithZst(u64, Zst1); -// CHECK: define{{.*}}i64 @test_WithZst(i64 %_1) +// CHECK: define{{.*}}i64 @test_WithZst(i64 noundef %_1) #[no_mangle] pub extern "C" fn test_WithZst(_: WithZst) -> WithZst { loop {} } @@ -40,14 +40,14 @@ pub extern "C" fn test_WithZst(_: WithZst) -> WithZst { loop {} } pub struct WithZeroSizedArray(*const f32, [i8; 0]); // Apparently we use i32* when newtype-unwrapping f32 pointers. Whatever. -// CHECK: define{{.*}}{{i32\*|ptr}} @test_WithZeroSizedArray({{i32\*|ptr}} %_1) +// CHECK: define{{.*}}{{i32\*|ptr}} @test_WithZeroSizedArray({{i32\*|ptr}} noundef %_1) #[no_mangle] pub extern "C" fn test_WithZeroSizedArray(_: WithZeroSizedArray) -> WithZeroSizedArray { loop {} } #[repr(transparent)] pub struct Generic(T); -// CHECK: define{{.*}}double @test_Generic(double %_1) +// CHECK: define{{.*}}double @test_Generic(double noundef %_1) #[no_mangle] pub extern "C" fn test_Generic(_: Generic) -> Generic { loop {} } @@ -64,7 +64,7 @@ pub extern "C" fn test_Gpz(_: GenericPlusZst) -> GenericPlusZst { lo #[repr(transparent)] pub struct LifetimePhantom<'a, T: 'a>(*const T, PhantomData<&'a T>); -// CHECK: define{{.*}}{{i16\*|ptr}} @test_LifetimePhantom({{i16\*|ptr}} %_1) +// CHECK: define{{.*}}{{i16\*|ptr}} @test_LifetimePhantom({{i16\*|ptr}} noundef %_1) #[no_mangle] pub extern "C" fn test_LifetimePhantom(_: LifetimePhantom) -> LifetimePhantom { loop {} } @@ -74,28 +74,28 @@ pub struct UnitPhantom { val: T, unit: PhantomData } pub struct Px; -// CHECK: define{{.*}}float @test_UnitPhantom(float %_1) +// CHECK: define{{.*}}float @test_UnitPhantom(float noundef %_1) #[no_mangle] pub extern "C" fn test_UnitPhantom(_: UnitPhantom) -> UnitPhantom { loop {} } #[repr(transparent)] pub struct TwoZsts(Zst1, i8, Zst2); -// CHECK: define{{( dso_local)?}}{{( signext)?}} i8 @test_TwoZsts(i8{{( signext)?}} %_1) +// CHECK: define{{( dso_local)?}} noundef{{( signext)?}} i8 @test_TwoZsts(i8 noundef{{( signext)?}} %_1) #[no_mangle] pub extern "C" fn test_TwoZsts(_: TwoZsts) -> TwoZsts { loop {} } #[repr(transparent)] pub struct Nested1(Zst2, Generic); -// CHECK: define{{.*}}double @test_Nested1(double %_1) +// CHECK: define{{.*}}double @test_Nested1(double noundef %_1) #[no_mangle] pub extern "C" fn test_Nested1(_: Nested1) -> Nested1 { loop {} } #[repr(transparent)] pub struct Nested2(Nested1, Zst1); -// CHECK: define{{.*}}double @test_Nested2(double %_1) +// CHECK: define{{.*}}double @test_Nested2(double noundef %_1) #[no_mangle] pub extern "C" fn test_Nested2(_: Nested2) -> Nested2 { loop {} } @@ -115,7 +115,7 @@ impl Mirror for T { type It = Self; } #[repr(transparent)] pub struct StructWithProjection(::It); -// CHECK: define{{.*}}float @test_Projection(float %_1) +// CHECK: define{{.*}}float @test_Projection(float noundef %_1) #[no_mangle] pub extern "C" fn test_Projection(_: StructWithProjection) -> StructWithProjection { loop {} } @@ -124,7 +124,7 @@ pub enum EnumF32 { Variant(F32) } -// CHECK: define{{.*}}float @test_EnumF32(float %_1) +// CHECK: define{{.*}}float @test_EnumF32(float noundef %_1) #[no_mangle] pub extern "C" fn test_EnumF32(_: EnumF32) -> EnumF32 { loop {} } @@ -133,7 +133,7 @@ pub enum EnumF32WithZsts { Variant(Zst1, F32, Zst2) } -// CHECK: define{{.*}}float @test_EnumF32WithZsts(float %_1) +// CHECK: define{{.*}}float @test_EnumF32WithZsts(float noundef %_1) #[no_mangle] pub extern "C" fn test_EnumF32WithZsts(_: EnumF32WithZsts) -> EnumF32WithZsts { loop {} } @@ -142,7 +142,7 @@ pub union UnionF32 { field: F32, } -// CHECK: define{{.*}}float @test_UnionF32(float %_1) +// CHECK: define{{.*}} float @test_UnionF32(float %_1) #[no_mangle] pub extern "C" fn test_UnionF32(_: UnionF32) -> UnionF32 { loop {} } diff --git a/tests/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs b/tests/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs index 61c4b7b51af7b..045f01985a57f 100644 --- a/tests/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs +++ b/tests/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs @@ -29,25 +29,25 @@ pub extern "C" fn f_scalar_0(a: bool) -> bool { a } -// CHECK: define signext i8 @f_scalar_1(i8 signext %x) +// CHECK: define noundef signext i8 @f_scalar_1(i8 noundef signext %x) #[no_mangle] pub extern "C" fn f_scalar_1(x: i8) -> i8 { x } -// CHECK: define zeroext i8 @f_scalar_2(i8 zeroext %x) +// CHECK: define noundef zeroext i8 @f_scalar_2(i8 noundef zeroext %x) #[no_mangle] pub extern "C" fn f_scalar_2(x: u8) -> u8 { x } -// CHECK: define signext i32 @f_scalar_3(i32 signext %x) +// CHECK: define noundef signext i32 @f_scalar_3(i32 noundef signext %x) #[no_mangle] pub extern "C" fn f_scalar_3(x: i32) -> u32 { x as u32 } -// CHECK: define i64 @f_scalar_4(i64 %x) +// CHECK: define noundef i64 @f_scalar_4(i64 noundef %x) #[no_mangle] pub extern "C" fn f_scalar_4(x: i64) -> i64 { x @@ -132,13 +132,13 @@ pub struct Large { pub extern "C" fn f_agg_large(mut x: Large) { } -// CHECK: define void @f_agg_large_ret({{%Large\*|ptr}} {{.*}}sret{{.*}}, i32 signext %i, i8 signext %j) +// CHECK: define void @f_agg_large_ret({{%Large\*|ptr}} {{.*}}sret{{.*}}, i32 noundef signext %i, i8 noundef signext %j) #[no_mangle] pub extern "C" fn f_agg_large_ret(i: i32, j: i8) -> Large { Large { a: 1, b: 2, c: 3, d: 4 } } -// CHECK: define void @f_scalar_stack_1(i64 %0, [2 x i64] %1, i128 %2, {{%Large\*|ptr}} {{.*}}%d, i8 zeroext %e, i8 signext %f, i8 %g, i8 %h) +// CHECK: define void @f_scalar_stack_1(i64 %0, [2 x i64] %1, i128 %2, {{%Large\*|ptr}} {{.*}}%d, i8 noundef zeroext %e, i8 noundef signext %f, i8 noundef %g, i8 noundef %h) #[no_mangle] pub extern "C" fn f_scalar_stack_1( a: Tiny, @@ -152,7 +152,7 @@ pub extern "C" fn f_scalar_stack_1( ) { } -// CHECK: define void @f_scalar_stack_2({{%Large\*|ptr}} {{.*}}sret{{.*}} %0, i64 %a, i128 %1, i128 %2, i64 %d, i8 zeroext %e, i8 %f, i8 %g) +// CHECK: define void @f_scalar_stack_2({{%Large\*|ptr}} {{.*}}sret{{.*}} %0, i64 noundef %a, i128 %1, i128 %2, i64 noundef %d, i8 noundef zeroext %e, i8 noundef %f, i8 noundef %g) #[no_mangle] pub extern "C" fn f_scalar_stack_2( a: u64, @@ -172,7 +172,7 @@ extern "C" { #[no_mangle] pub unsafe extern "C" fn f_va_caller() { - // CHECK: call signext i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i64 3, double {{.*}}, double {{.*}}, i64 {{.*}}, [2 x i64] {{.*}}, i128 {{.*}}, {{%Large\*|ptr}} {{.*}}) + // CHECK: call noundef signext i32 (i32, ...) @f_va_callee(i32 noundef signext 1, i32 noundef signext 2, i64 noundef 3, double {{.*}}, double {{.*}}, i64 {{.*}}, [2 x i64] {{.*}}, i128 {{.*}}, {{%Large\*|ptr}} {{.*}}) f_va_callee( 1, 2i32, @@ -184,6 +184,6 @@ pub unsafe extern "C" fn f_va_caller() { SmallAligned { a: 11 }, Large { a: 12, b: 13, c: 14, d: 15 }, ); - // CHECK: call signext i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i128 {{.*}}, i32 signext 6, i32 signext 7, i32 8, i32 9) + // CHECK: call noundef signext i32 (i32, ...) @f_va_callee(i32 noundef signext 1, i32 noundef signext 2, i32 noundef signext 3, i32 noundef signext 4, i128 {{.*}}, i32 noundef signext 6, i32 noundef signext 7, i32 noundef 8, i32 noundef 9) f_va_callee(1, 2i32, 3i32, 4i32, SmallAligned { a: 5 }, 6i32, 7i32, 8i32, 9i32); } diff --git a/tests/codegen/sanitizer-cfi-emit-type-checks.rs b/tests/codegen/sanitizer-cfi-emit-type-checks.rs index 8be5186de9e77..82334693d58ed 100644 --- a/tests/codegen/sanitizer-cfi-emit-type-checks.rs +++ b/tests/codegen/sanitizer-cfi-emit-type-checks.rs @@ -11,7 +11,7 @@ pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { // CHECK: [[TT:%.+]] = call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0}}, metadata !"{{[[:print:]]+}}") // CHECK-NEXT: br i1 [[TT]], label %type_test.pass, label %type_test.fail // CHECK: type_test.pass: - // CHECK-NEXT: {{%.+}} = call i32 %f(i32 %arg) + // CHECK-NEXT: {{%.+}} = call noundef i32 %f(i32 noundef %arg) // CHECK-NEXT: br label %bb1 // CHECK: type_test.fail: // CHECK-NEXT: call void @llvm.trap() diff --git a/tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi.rs b/tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi.rs index 8e0d02550ee94..43e520bd6cfd8 100644 --- a/tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi.rs +++ b/tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi.rs @@ -21,21 +21,21 @@ impl Copy for i32 {} pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { // CHECK-LABEL: define{{.*}}foo // CHECK-SAME: {{.*}}!{{|kcfi_type}} ![[TYPE1:[0-9]+]] - // CHECK: call i32 %f(i32 %arg){{.*}}[ "kcfi"(i32 -1666898348) ] + // CHECK: call noundef i32 %f(i32 noundef %arg){{.*}}[ "kcfi"(i32 -1666898348) ] f(arg) } pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 { // CHECK-LABEL: define{{.*}}bar // CHECK-SAME: {{.*}}!{{|kcfi_type}} ![[TYPE2:[0-9]+]] - // CHECK: call i32 %f(i32 %arg1, i32 %arg2){{.*}}[ "kcfi"(i32 -1789026986) ] + // CHECK: call noundef i32 %f(i32 noundef %arg1, i32 noundef %arg2){{.*}}[ "kcfi"(i32 -1789026986) ] f(arg1, arg2) } pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 { // CHECK-LABEL: define{{.*}}baz // CHECK-SAME: {{.*}}!{{|kcfi_type}} ![[TYPE3:[0-9]+]] - // CHECK: call i32 %f(i32 %arg1, i32 %arg2, i32 %arg3){{.*}}[ "kcfi"(i32 1248878270) ] + // CHECK: call noundef i32 %f(i32 noundef %arg1, i32 noundef %arg2, i32 noundef %arg3){{.*}}[ "kcfi"(i32 1248878270) ] f(arg1, arg2, arg3) } diff --git a/tests/codegen/sanitizer-recover.rs b/tests/codegen/sanitizer-recover.rs index 7ce0fa0a20fc2..899c67be6ce56 100644 --- a/tests/codegen/sanitizer-recover.rs +++ b/tests/codegen/sanitizer-recover.rs @@ -16,27 +16,27 @@ // MSAN-RECOVER: @__msan_keep_going = weak_odr {{.*}}constant i32 1 // MSAN-RECOVER-LTO: @__msan_keep_going = weak_odr {{.*}}constant i32 1 -// ASAN-LABEL: define dso_local i32 @penguin( +// ASAN-LABEL: define dso_local noundef i32 @penguin( // ASAN: call void @__asan_report_load4(i64 %0) // ASAN: unreachable // ASAN: } // -// ASAN-RECOVER-LABEL: define dso_local i32 @penguin( +// ASAN-RECOVER-LABEL: define dso_local noundef i32 @penguin( // ASAN-RECOVER: call void @__asan_report_load4_noabort( // ASAN-RECOVER-NOT: unreachable // ASAN: } // -// MSAN-LABEL: define dso_local i32 @penguin( +// MSAN-LABEL: define dso_local noundef i32 @penguin( // MSAN: call void @__msan_warning{{(_with_origin_noreturn\(i32 0\)|_noreturn\(\))}} // MSAN: unreachable // MSAN: } // -// MSAN-RECOVER-LABEL: define dso_local i32 @penguin( +// MSAN-RECOVER-LABEL: define dso_local noundef i32 @penguin( // MSAN-RECOVER: call void @__msan_warning{{(_with_origin\(i32 0\)|\(\))}} // MSAN-RECOVER-NOT: unreachable // MSAN-RECOVER: } // -// MSAN-RECOVER-LTO-LABEL: define dso_local i32 @penguin( +// MSAN-RECOVER-LTO-LABEL: define dso_local noundef i32 @penguin( // MSAN-RECOVER-LTO: call void @__msan_warning{{(_with_origin\(i32 0\)|\(\))}} // MSAN-RECOVER-LTO-NOT: unreachable // MSAN-RECOVER-LTO: } diff --git a/tests/codegen/scalar-pair-bool.rs b/tests/codegen/scalar-pair-bool.rs index 264f28fdb5fee..8e8365b6a673b 100644 --- a/tests/codegen/scalar-pair-bool.rs +++ b/tests/codegen/scalar-pair-bool.rs @@ -8,13 +8,13 @@ pub fn pair_bool_bool(pair: (bool, bool)) -> (bool, bool) { pair } -// CHECK: define{{.*}}{ i8, i32 } @pair_bool_i32(i1 noundef zeroext %pair.0, i32 %pair.1) +// CHECK: define{{.*}}{ i8, i32 } @pair_bool_i32(i1 noundef zeroext %pair.0, i32 noundef %pair.1) #[no_mangle] pub fn pair_bool_i32(pair: (bool, i32)) -> (bool, i32) { pair } -// CHECK: define{{.*}}{ i32, i8 } @pair_i32_bool(i32 %pair.0, i1 noundef zeroext %pair.1) +// CHECK: define{{.*}}{ i32, i8 } @pair_i32_bool(i32 noundef %pair.0, i1 noundef zeroext %pair.1) #[no_mangle] pub fn pair_i32_bool(pair: (i32, bool)) -> (i32, bool) { pair diff --git a/tests/codegen/some-abis-do-extend-params-to-32-bits.rs b/tests/codegen/some-abis-do-extend-params-to-32-bits.rs index 7fc34af3da72a..86acbfba6a0f3 100644 --- a/tests/codegen/some-abis-do-extend-params-to-32-bits.rs +++ b/tests/codegen/some-abis-do-extend-params-to-32-bits.rs @@ -31,85 +31,85 @@ // The patterns in this file are written in the style of a table to make the // uniformities and distinctions more apparent. // -// ZERO/SIGN-EXTENDING TO 32 BITS NON-EXTENDING -// ============================== ======================= -// x86_64: void @c_arg_u8(i8 zeroext %_a) -// i686: void @c_arg_u8(i8 zeroext %_a) -// aarch64-apple: void @c_arg_u8(i8 zeroext %_a) -// aarch64-windows: void @c_arg_u8(i8 %_a) -// aarch64-linux: void @c_arg_u8(i8 %_a) -// arm: void @c_arg_u8(i8 zeroext %_a) -// riscv: void @c_arg_u8(i8 zeroext %_a) +// ZERO/SIGN-EXTENDING TO 32 BITS NON-EXTENDING +// ====================================== =============================== +// x86_64: void @c_arg_u8(i8 noundef zeroext %_a) +// i686: void @c_arg_u8(i8 noundef zeroext %_a) +// aarch64-apple: void @c_arg_u8(i8 noundef zeroext %_a) +// aarch64-windows: void @c_arg_u8(i8 noundef %_a) +// aarch64-linux: void @c_arg_u8(i8 noundef %_a) +// arm: void @c_arg_u8(i8 noundef zeroext %_a) +// riscv: void @c_arg_u8(i8 noundef zeroext %_a) #[no_mangle] pub extern "C" fn c_arg_u8(_a: u8) { } -// x86_64: void @c_arg_u16(i16 zeroext %_a) -// i686: void @c_arg_u16(i16 zeroext %_a) -// aarch64-apple: void @c_arg_u16(i16 zeroext %_a) -// aarch64-windows: void @c_arg_u16(i16 %_a) -// aarch64-linux: void @c_arg_u16(i16 %_a) -// arm: void @c_arg_u16(i16 zeroext %_a) -// riscv: void @c_arg_u16(i16 zeroext %_a) +// x86_64: void @c_arg_u16(i16 noundef zeroext %_a) +// i686: void @c_arg_u16(i16 noundef zeroext %_a) +// aarch64-apple: void @c_arg_u16(i16 noundef zeroext %_a) +// aarch64-windows: void @c_arg_u16(i16 noundef %_a) +// aarch64-linux: void @c_arg_u16(i16 noundef %_a) +// arm: void @c_arg_u16(i16 noundef zeroext %_a) +// riscv: void @c_arg_u16(i16 noundef zeroext %_a) #[no_mangle] pub extern "C" fn c_arg_u16(_a: u16) { } -// x86_64: void @c_arg_u32(i32 %_a) -// i686: void @c_arg_u32(i32 %_a) -// aarch64-apple: void @c_arg_u32(i32 %_a) -// aarch64-windows: void @c_arg_u32(i32 %_a) -// aarch64-linux: void @c_arg_u32(i32 %_a) -// arm: void @c_arg_u32(i32 %_a) -// riscv: void @c_arg_u32(i32 signext %_a) +// x86_64: void @c_arg_u32(i32 noundef %_a) +// i686: void @c_arg_u32(i32 noundef %_a) +// aarch64-apple: void @c_arg_u32(i32 noundef %_a) +// aarch64-windows: void @c_arg_u32(i32 noundef %_a) +// aarch64-linux: void @c_arg_u32(i32 noundef %_a) +// arm: void @c_arg_u32(i32 noundef %_a) +// riscv: void @c_arg_u32(i32 noundef signext %_a) #[no_mangle] pub extern "C" fn c_arg_u32(_a: u32) { } -// x86_64: void @c_arg_u64(i64 %_a) -// i686: void @c_arg_u64(i64 %_a) -// aarch64-apple: void @c_arg_u64(i64 %_a) -// aarch64-windows: void @c_arg_u64(i64 %_a) -// aarch64-linux: void @c_arg_u64(i64 %_a) -// arm: void @c_arg_u64(i64 %_a) -// riscv: void @c_arg_u64(i64 %_a) +// x86_64: void @c_arg_u64(i64 noundef %_a) +// i686: void @c_arg_u64(i64 noundef %_a) +// aarch64-apple: void @c_arg_u64(i64 noundef %_a) +// aarch64-windows: void @c_arg_u64(i64 noundef %_a) +// aarch64-linux: void @c_arg_u64(i64 noundef %_a) +// arm: void @c_arg_u64(i64 noundef %_a) +// riscv: void @c_arg_u64(i64 noundef %_a) #[no_mangle] pub extern "C" fn c_arg_u64(_a: u64) { } -// x86_64: void @c_arg_i8(i8 signext %_a) -// i686: void @c_arg_i8(i8 signext %_a) -// aarch64-apple: void @c_arg_i8(i8 signext %_a) -// aarch64-windows: void @c_arg_i8(i8 %_a) -// aarch64-linux: void @c_arg_i8(i8 %_a) -// arm: void @c_arg_i8(i8 signext %_a) -// riscv: void @c_arg_i8(i8 signext %_a) +// x86_64: void @c_arg_i8(i8 noundef signext %_a) +// i686: void @c_arg_i8(i8 noundef signext %_a) +// aarch64-apple: void @c_arg_i8(i8 noundef signext %_a) +// aarch64-windows: void @c_arg_i8(i8 noundef %_a) +// aarch64-linux: void @c_arg_i8(i8 noundef %_a) +// arm: void @c_arg_i8(i8 noundef signext %_a) +// riscv: void @c_arg_i8(i8 noundef signext %_a) #[no_mangle] pub extern "C" fn c_arg_i8(_a: i8) { } -// x86_64: void @c_arg_i16(i16 signext %_a) -// i686: void @c_arg_i16(i16 signext %_a) -// aarch64-apple: void @c_arg_i16(i16 signext %_a) -// aarch64-windows: void @c_arg_i16(i16 %_a) -// aarch64-linux: void @c_arg_i16(i16 %_a) -// arm: void @c_arg_i16(i16 signext %_a) -// riscv: void @c_arg_i16(i16 signext %_a) +// x86_64: void @c_arg_i16(i16 noundef signext %_a) +// i686: void @c_arg_i16(i16 noundef signext %_a) +// aarch64-apple: void @c_arg_i16(i16 noundef signext %_a) +// aarch64-windows: void @c_arg_i16(i16 noundef %_a) +// aarch64-linux: void @c_arg_i16(i16 noundef %_a) +// arm: void @c_arg_i16(i16 noundef signext %_a) +// riscv: void @c_arg_i16(i16 noundef signext %_a) #[no_mangle] pub extern "C" fn c_arg_i16(_a: i16) { } -// x86_64: void @c_arg_i32(i32 %_a) -// i686: void @c_arg_i32(i32 %_a) -// aarch64-apple: void @c_arg_i32(i32 %_a) -// aarch64-windows: void @c_arg_i32(i32 %_a) -// aarch64-linux: void @c_arg_i32(i32 %_a) -// arm: void @c_arg_i32(i32 %_a) -// riscv: void @c_arg_i32(i32 signext %_a) +// x86_64: void @c_arg_i32(i32 noundef %_a) +// i686: void @c_arg_i32(i32 noundef %_a) +// aarch64-apple: void @c_arg_i32(i32 noundef %_a) +// aarch64-windows: void @c_arg_i32(i32 noundef %_a) +// aarch64-linux: void @c_arg_i32(i32 noundef %_a) +// arm: void @c_arg_i32(i32 noundef %_a) +// riscv: void @c_arg_i32(i32 noundef signext %_a) #[no_mangle] pub extern "C" fn c_arg_i32(_a: i32) { } -// x86_64: void @c_arg_i64(i64 %_a) -// i686: void @c_arg_i64(i64 %_a) -// aarch64-apple: void @c_arg_i64(i64 %_a) -// aarch64-windows: void @c_arg_i64(i64 %_a) -// aarch64-linux: void @c_arg_i64(i64 %_a) -// arm: void @c_arg_i64(i64 %_a) -// riscv: void @c_arg_i64(i64 %_a) +// x86_64: void @c_arg_i64(i64 noundef %_a) +// i686: void @c_arg_i64(i64 noundef %_a) +// aarch64-apple: void @c_arg_i64(i64 noundef %_a) +// aarch64-windows: void @c_arg_i64(i64 noundef %_a) +// aarch64-linux: void @c_arg_i64(i64 noundef %_a) +// arm: void @c_arg_i64(i64 noundef %_a) +// riscv: void @c_arg_i64(i64 noundef %_a) #[no_mangle] pub extern "C" fn c_arg_i64(_a: i64) { } // x86_64: zeroext i8 @c_ret_u8() // i686: zeroext i8 @c_ret_u8() // aarch64-apple: zeroext i8 @c_ret_u8() -// aarch64-windows: i8 @c_ret_u8() -// aarch64-linux: i8 @c_ret_u8() +// aarch64-windows: i8 @c_ret_u8() +// aarch64-linux: i8 @c_ret_u8() // arm: zeroext i8 @c_ret_u8() // riscv: zeroext i8 @c_ret_u8() #[no_mangle] pub extern "C" fn c_ret_u8() -> u8 { 0 } @@ -117,8 +117,8 @@ // x86_64: zeroext i16 @c_ret_u16() // i686: zeroext i16 @c_ret_u16() // aarch64-apple: zeroext i16 @c_ret_u16() -// aarch64-windows: i16 @c_ret_u16() -// aarch64-linux: i16 @c_ret_u16() +// aarch64-windows: i16 @c_ret_u16() +// aarch64-linux: i16 @c_ret_u16() // arm: zeroext i16 @c_ret_u16() // riscv: zeroext i16 @c_ret_u16() #[no_mangle] pub extern "C" fn c_ret_u16() -> u16 { 0 } @@ -126,8 +126,8 @@ // x86_64: i32 @c_ret_u32() // i686: i32 @c_ret_u32() // aarch64-apple: i32 @c_ret_u32() -// aarch64-windows: i32 @c_ret_u32() -// aarch64-linux: i32 @c_ret_u32() +// aarch64-windows: i32 @c_ret_u32() +// aarch64-linux: i32 @c_ret_u32() // arm: i32 @c_ret_u32() // riscv: signext i32 @c_ret_u32() #[no_mangle] pub extern "C" fn c_ret_u32() -> u32 { 0 } @@ -135,8 +135,8 @@ // x86_64: i64 @c_ret_u64() // i686: i64 @c_ret_u64() // aarch64-apple: i64 @c_ret_u64() -// aarch64-windows: i64 @c_ret_u64() -// aarch64-linux: i64 @c_ret_u64() +// aarch64-windows: i64 @c_ret_u64() +// aarch64-linux: i64 @c_ret_u64() // arm: i64 @c_ret_u64() // riscv: i64 @c_ret_u64() #[no_mangle] pub extern "C" fn c_ret_u64() -> u64 { 0 } @@ -144,8 +144,8 @@ // x86_64: signext i8 @c_ret_i8() // i686: signext i8 @c_ret_i8() // aarch64-apple: signext i8 @c_ret_i8() -// aarch64-windows: i8 @c_ret_i8() -// aarch64-linux: i8 @c_ret_i8() +// aarch64-windows: i8 @c_ret_i8() +// aarch64-linux: i8 @c_ret_i8() // arm: signext i8 @c_ret_i8() // riscv: signext i8 @c_ret_i8() #[no_mangle] pub extern "C" fn c_ret_i8() -> i8 { 0 } @@ -153,8 +153,8 @@ // x86_64: signext i16 @c_ret_i16() // i686: signext i16 @c_ret_i16() // aarch64-apple: signext i16 @c_ret_i16() -// aarch64-windows: i16 @c_ret_i16() -// aarch64-linux: i16 @c_ret_i16() +// aarch64-windows: i16 @c_ret_i16() +// aarch64-linux: i16 @c_ret_i16() // arm: signext i16 @c_ret_i16() // riscv: signext i16 @c_ret_i16() #[no_mangle] pub extern "C" fn c_ret_i16() -> i16 { 0 } @@ -162,8 +162,8 @@ // x86_64: i32 @c_ret_i32() // i686: i32 @c_ret_i32() // aarch64-apple: i32 @c_ret_i32() -// aarch64-windows: i32 @c_ret_i32() -// aarch64-linux: i32 @c_ret_i32() +// aarch64-windows: i32 @c_ret_i32() +// aarch64-linux: i32 @c_ret_i32() // arm: i32 @c_ret_i32() // riscv: signext i32 @c_ret_i32() #[no_mangle] pub extern "C" fn c_ret_i32() -> i32 { 0 } @@ -171,8 +171,8 @@ // x86_64: i64 @c_ret_i64() // i686: i64 @c_ret_i64() // aarch64-apple: i64 @c_ret_i64() -// aarch64-windows: i64 @c_ret_i64() -// aarch64-linux: i64 @c_ret_i64() +// aarch64-windows: i64 @c_ret_i64() +// aarch64-linux: i64 @c_ret_i64() // arm: i64 @c_ret_i64() // riscv: i64 @c_ret_i64() #[no_mangle] pub extern "C" fn c_ret_i64() -> i64 { 0 } diff --git a/tests/codegen/transmute-scalar.rs b/tests/codegen/transmute-scalar.rs index a7e5deeffd8e2..260dcbac0fc4f 100644 --- a/tests/codegen/transmute-scalar.rs +++ b/tests/codegen/transmute-scalar.rs @@ -5,7 +5,7 @@ // FIXME(eddyb) all of these tests show memory stores and loads, even after a // scalar `bitcast`, more special-casing is required to remove `alloca` usage. -// CHECK-LABEL: define{{.*}}i32 @f32_to_bits(float %x) +// CHECK-LABEL: define{{.*}}i32 @f32_to_bits(float noundef %x) // CHECK: store i32 %{{.*}}, {{.*}} %0 // CHECK-NEXT: %[[RES:.*]] = load i32, {{.*}} %0 // CHECK: ret i32 %[[RES]] @@ -24,7 +24,7 @@ pub fn bool_to_byte(b: bool) -> u8 { unsafe { std::mem::transmute(b) } } -// CHECK-LABEL: define{{.*}}noundef zeroext i1 @byte_to_bool(i8 %byte) +// CHECK-LABEL: define{{.*}}noundef zeroext i1 @byte_to_bool(i8 noundef %byte) // CHECK: %1 = trunc i8 %byte to i1 // CHECK-NEXT: %2 = zext i1 %1 to i8 // CHECK-NEXT: store i8 %2, {{.*}} %0 @@ -36,7 +36,7 @@ pub unsafe fn byte_to_bool(byte: u8) -> bool { std::mem::transmute(byte) } -// CHECK-LABEL: define{{.*}}{{i8\*|ptr}} @ptr_to_ptr({{i16\*|ptr}} %p) +// CHECK-LABEL: define{{.*}}{{i8\*|ptr}} @ptr_to_ptr({{i16\*|ptr}} noundef %p) // CHECK: store {{i8\*|ptr}} %{{.*}}, {{.*}} %0 // CHECK-NEXT: %[[RES:.*]] = load {{i8\*|ptr}}, {{.*}} %0 // CHECK: ret {{i8\*|ptr}} %[[RES]] @@ -52,7 +52,7 @@ pub fn ptr_to_ptr(p: *mut u16) -> *mut u8 { // Tests below show the non-special-cased behavior (with the possible // future special-cased instructions in the "NOTE(eddyb)" comments). -// CHECK: define{{.*}}[[USIZE:i[0-9]+]] @ptr_to_int({{i16\*|ptr}} %p) +// CHECK: define{{.*}}[[USIZE:i[0-9]+]] @ptr_to_int({{i16\*|ptr}} noundef %p) // NOTE(eddyb) see above, the following two CHECK lines should ideally be this: // %2 = ptrtoint i16* %p to [[USIZE]] @@ -66,7 +66,7 @@ pub fn ptr_to_int(p: *mut u16) -> usize { unsafe { std::mem::transmute(p) } } -// CHECK: define{{.*}}{{i16\*|ptr}} @int_to_ptr([[USIZE]] %i) +// CHECK: define{{.*}}{{i16\*|ptr}} @int_to_ptr([[USIZE]] noundef %i) // NOTE(eddyb) see above, the following two CHECK lines should ideally be this: // %2 = inttoptr [[USIZE]] %i to i16* diff --git a/tests/codegen/tuple-layout-opt.rs b/tests/codegen/tuple-layout-opt.rs index e86c75f3f4826..ad33d6643c296 100644 --- a/tests/codegen/tuple-layout-opt.rs +++ b/tests/codegen/tuple-layout-opt.rs @@ -6,31 +6,31 @@ #![crate_type="lib"] type ScalarZstLast = (u128, ()); -// CHECK: define i128 @test_ScalarZstLast(i128 %_1) +// CHECK: define noundef i128 @test_ScalarZstLast(i128 noundef %_1) #[no_mangle] pub fn test_ScalarZstLast(_: ScalarZstLast) -> ScalarZstLast { loop {} } type ScalarZstFirst = ((), u128); -// CHECK: define i128 @test_ScalarZstFirst(i128 %_1) +// CHECK: define noundef i128 @test_ScalarZstFirst(i128 noundef %_1) #[no_mangle] pub fn test_ScalarZstFirst(_: ScalarZstFirst) -> ScalarZstFirst { loop {} } type ScalarPairZstLast = (u8, u128, ()); -// CHECK: define { i128, i8 } @test_ScalarPairZstLast(i128 %_1.0, i8 %_1.1) +// CHECK: define { i128, i8 } @test_ScalarPairZstLast(i128 noundef %_1.0, i8 noundef %_1.1) #[no_mangle] pub fn test_ScalarPairZstLast(_: ScalarPairZstLast) -> ScalarPairZstLast { loop {} } type ScalarPairZstFirst = ((), u8, u128); -// CHECK: define { i8, i128 } @test_ScalarPairZstFirst(i8 %_1.0, i128 %_1.1) +// CHECK: define { i8, i128 } @test_ScalarPairZstFirst(i8 noundef %_1.0, i128 noundef %_1.1) #[no_mangle] pub fn test_ScalarPairZstFirst(_: ScalarPairZstFirst) -> ScalarPairZstFirst { loop {} } type ScalarPairLotsOfZsts = ((), u8, (), u128, ()); -// CHECK: define { i128, i8 } @test_ScalarPairLotsOfZsts(i128 %_1.0, i8 %_1.1) +// CHECK: define { i128, i8 } @test_ScalarPairLotsOfZsts(i128 noundef %_1.0, i8 noundef %_1.1) #[no_mangle] pub fn test_ScalarPairLotsOfZsts(_: ScalarPairLotsOfZsts) -> ScalarPairLotsOfZsts { loop {} } type ScalarPairLottaNesting = (((), ((), u8, (), u128, ())), ()); -// CHECK: define { i128, i8 } @test_ScalarPairLottaNesting(i128 %_1.0, i8 %_1.1) +// CHECK: define { i128, i8 } @test_ScalarPairLottaNesting(i128 noundef %_1.0, i8 noundef %_1.1) #[no_mangle] pub fn test_ScalarPairLottaNesting(_: ScalarPairLottaNesting) -> ScalarPairLottaNesting { loop {} } diff --git a/tests/codegen/var-names.rs b/tests/codegen/var-names.rs index 8f1b038708e66..d4715efad73c0 100644 --- a/tests/codegen/var-names.rs +++ b/tests/codegen/var-names.rs @@ -2,7 +2,7 @@ #![crate_type = "lib"] -// CHECK-LABEL: define{{.*}}i32 @test(i32 %a, i32 %b) +// CHECK-LABEL: define{{.*}}i32 @test(i32 noundef %a, i32 noundef %b) #[no_mangle] pub fn test(a: u32, b: u32) -> u32 { let c = a + b; diff --git a/tests/codegen/zst-offset.rs b/tests/codegen/zst-offset.rs index 844d5870a846f..27e435e9cf042 100644 --- a/tests/codegen/zst-offset.rs +++ b/tests/codegen/zst-offset.rs @@ -4,7 +4,7 @@ #![feature(repr_simd)] // Hack to get the correct size for the length part in slices -// CHECK: @helper([[USIZE:i[0-9]+]] %_1) +// CHECK: @helper([[USIZE:i[0-9]+]] noundef %_1) #[no_mangle] pub fn helper(_: usize) { } From af23ad93cd3309e90ccb2c49b7a7b2ac913e0d06 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Fri, 30 Dec 2022 21:11:17 +0100 Subject: [PATCH 092/230] Improve comments --- compiler/rustc_ty_utils/src/abi.rs | 6 ------ tests/codegen/loads.rs | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index ce50b6fb43f50..669f84ae1b472 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -219,7 +219,6 @@ fn adjust_for_rust_scalar<'tcx>( return; } - // Scalars which have invalid values cannot be undef. if !scalar.is_uninit_valid() { attrs.set(ArgAttribute::NoUndef); } @@ -246,11 +245,6 @@ fn adjust_for_rust_scalar<'tcx>( PointerKind::SharedMutable | PointerKind::UniqueOwned => Size::ZERO, }; - // `Box`, `&T`, and `&mut T` cannot be undef. - // Note that this only applies to the value of the pointer itself; - // this attribute doesn't make it UB for the pointed-to data to be undef. - attrs.set(ArgAttribute::NoUndef); - // The aliasing rules for `Box` are still not decided, but currently we emit // `noalias` for it. This can be turned off using an unstable flag. // See https://github.com/rust-lang/unsafe-code-guidelines/issues/326 diff --git a/tests/codegen/loads.rs b/tests/codegen/loads.rs index c972819709258..7c3bf07cc811f 100644 --- a/tests/codegen/loads.rs +++ b/tests/codegen/loads.rs @@ -50,7 +50,7 @@ pub fn load_scalar_pair<'a>(x: &(&'a i32, &'a Align16)) -> (&'a i32, &'a Align16 // CHECK-LABEL: @load_raw_pointer #[no_mangle] pub fn load_raw_pointer<'a>(x: &*const i32) -> *const i32 { - // loaded raw pointer should not have !nonnull, !align, or !noundef metadata + // loaded raw pointer should not have !nonnull or !align metadata // CHECK: load {{i32\*|ptr}}, {{i32\*\*|ptr}} %x, align [[PTR_ALIGNMENT]], !noundef !2{{$}} *x } From 3dca58e249703a9e6558f5683b904fcb71d9d879 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Fri, 23 Dec 2022 15:15:21 +0000 Subject: [PATCH 093/230] `rustc_const_eval`: remove `ref` patterns (+some pattern matching imps) --- .../rustc_const_eval/src/const_eval/error.rs | 6 +- .../src/const_eval/eval_queries.rs | 2 +- .../src/const_eval/machine.rs | 2 +- .../rustc_const_eval/src/interpret/cast.rs | 2 +- .../src/interpret/intrinsics.rs | 4 +- .../rustc_const_eval/src/interpret/memory.rs | 2 +- .../rustc_const_eval/src/interpret/operand.rs | 12 +-- .../src/interpret/projection.rs | 4 +- .../rustc_const_eval/src/interpret/step.rs | 50 ++++----- .../src/interpret/terminator.rs | 34 +++--- .../src/interpret/validity.rs | 2 +- .../rustc_const_eval/src/interpret/visitor.rs | 6 +- .../src/transform/check_consts/check.rs | 46 ++++---- .../src/transform/promote_consts.rs | 102 +++++++++--------- 14 files changed, 130 insertions(+), 144 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 13472cc2bfa0a..0579f78153527 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -36,16 +36,16 @@ impl<'tcx> Into> for ConstEvalErrKind { impl fmt::Display for ConstEvalErrKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use self::ConstEvalErrKind::*; - match *self { + match self { ConstAccessesStatic => write!(f, "constant accesses static"), ModifiedGlobal => { write!(f, "modifying a static's initial value from another static's initializer") } - AssertFailure(ref msg) => write!(f, "{:?}", msg), + AssertFailure(msg) => write!(f, "{:?}", msg), Panic { msg, line, col, file } => { write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col) } - Abort(ref msg) => write!(f, "{}", msg), + Abort(msg) => write!(f, "{}", msg), } } } diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 18e01567ca35e..70487f89c252a 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -167,7 +167,7 @@ pub(super) fn op_to_const<'tcx>( } }; match immediate { - Left(ref mplace) => to_const_value(mplace), + Left(mplace) => to_const_value(&mplace), // see comment on `let try_as_immediate` above Right(imm) => match *imm { _ if imm.layout.is_zst() => ConstValue::ZeroSized, diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index e006a62feeabd..d869ca2c3b8d2 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -533,7 +533,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, let eval_to_int = |op| ecx.read_immediate(&ecx.eval_operand(op, None)?).map(|x| x.to_const_int()); let err = match msg { - BoundsCheck { ref len, ref index } => { + BoundsCheck { len, index } => { let len = eval_to_int(len)?; let index = eval_to_int(index)?; BoundsCheck { len, index } diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 986b6d6553001..b2c847d3fd8dd 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -347,7 +347,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let new_vptr = self.get_vtable_ptr(ty, data_b.principal())?; self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest) } - (_, &ty::Dynamic(ref data, _, ty::Dyn)) => { + (_, &ty::Dynamic(data, _, ty::Dyn)) => { // Initial cast from sized to dyn trait let vtable = self.get_vtable_ptr(src_pointee_ty, data.principal())?; let ptr = self.read_scalar(src)?; diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 666fcbd6f8048..cc7b6c91b6074 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -79,9 +79,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>( } sym::variant_count => match tp_ty.kind() { // Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough. - ty::Adt(ref adt, _) => { - ConstValue::from_machine_usize(adt.variants().len() as u64, &tcx) - } + ty::Adt(adt, _) => ConstValue::from_machine_usize(adt.variants().len() as u64, &tcx), ty::Alias(..) | ty::Param(_) | ty::Placeholder(_) | ty::Infer(_) => { throw_inval!(TooGeneric) } diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 5b1ac6b2f65e2..f47f99a166f53 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -863,7 +863,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a, write!(fmt, "{id:?}")?; match self.ecx.memory.alloc_map.get(id) { - Some(&(kind, ref alloc)) => { + Some((kind, alloc)) => { // normal alloc write!(fmt, " ({}, ", kind)?; write_allocation_track_relocs( diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index fcc6f8ea85282..2013de0d3a33d 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -363,11 +363,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { src: &OpTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, Either, ImmTy<'tcx, M::Provenance>>> { Ok(match src.as_mplace_or_imm() { - Left(ref mplace) => { - if let Some(val) = self.read_immediate_from_mplace_raw(mplace)? { + Left(mplace) => { + if let Some(val) = self.read_immediate_from_mplace_raw(&mplace)? { Right(val) } else { - Left(*mplace) + Left(mplace) } } Right(val) => Right(val), @@ -533,11 +533,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { layout: Option>, ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { use rustc_middle::mir::Operand::*; - let op = match *mir_op { + let op = match mir_op { // FIXME: do some more logic on `move` to invalidate the old location - Copy(place) | Move(place) => self.eval_place_to_op(place, layout)?, + &(Copy(place) | Move(place)) => self.eval_place_to_op(place, layout)?, - Constant(ref constant) => { + Constant(constant) => { let c = self.subst_from_current_frame_and_normalize_erasing_regions(constant.literal)?; diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index 291464ab58ae2..2a493b20e5dca 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -87,9 +87,9 @@ where field: usize, ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { let base = match base.as_mplace_or_imm() { - Left(ref mplace) => { + Left(mplace) => { // We can reuse the mplace field computation logic for indirect operands. - let field = self.mplace_field(mplace, field)?; + let field = self.mplace_field(&mplace, field)?; return Ok(field.into()); } Right(value) => value, diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 81b44a49484d0..4bb3100757856 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -111,7 +111,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { M::retag_place_contents(self, *kind, &dest)?; } - Intrinsic(box ref intrinsic) => self.emulate_nondiverging_intrinsic(intrinsic)?, + Intrinsic(box intrinsic) => self.emulate_nondiverging_intrinsic(intrinsic)?, // Statements we do not track. AscribeUserType(..) => {} @@ -151,50 +151,50 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Also see https://github.com/rust-lang/rust/issues/68364. use rustc_middle::mir::Rvalue::*; - match *rvalue { + match rvalue { ThreadLocalRef(did) => { - let ptr = M::thread_local_static_base_pointer(self, did)?; + let ptr = M::thread_local_static_base_pointer(self, *did)?; self.write_pointer(ptr, &dest)?; } - Use(ref operand) => { + Use(operand) => { // Avoid recomputing the layout let op = self.eval_operand(operand, Some(dest.layout))?; self.copy_op(&op, &dest, /*allow_transmute*/ false)?; } - CopyForDeref(ref place) => { + CopyForDeref(place) => { let op = self.eval_place_to_op(*place, Some(dest.layout))?; self.copy_op(&op, &dest, /* allow_transmute*/ false)?; } - BinaryOp(bin_op, box (ref left, ref right)) => { - let layout = binop_left_homogeneous(bin_op).then_some(dest.layout); + BinaryOp(bin_op, box (left, right)) => { + let layout = binop_left_homogeneous(*bin_op).then_some(dest.layout); let left = self.read_immediate(&self.eval_operand(left, layout)?)?; - let layout = binop_right_homogeneous(bin_op).then_some(left.layout); + let layout = binop_right_homogeneous(*bin_op).then_some(left.layout); let right = self.read_immediate(&self.eval_operand(right, layout)?)?; - self.binop_ignore_overflow(bin_op, &left, &right, &dest)?; + self.binop_ignore_overflow(*bin_op, &left, &right, &dest)?; } - CheckedBinaryOp(bin_op, box (ref left, ref right)) => { + CheckedBinaryOp(bin_op, box (left, right)) => { // Due to the extra boolean in the result, we can never reuse the `dest.layout`. let left = self.read_immediate(&self.eval_operand(left, None)?)?; - let layout = binop_right_homogeneous(bin_op).then_some(left.layout); + let layout = binop_right_homogeneous(*bin_op).then_some(left.layout); let right = self.read_immediate(&self.eval_operand(right, layout)?)?; self.binop_with_overflow( - bin_op, /*force_overflow_checks*/ false, &left, &right, &dest, + *bin_op, /*force_overflow_checks*/ false, &left, &right, &dest, )?; } - UnaryOp(un_op, ref operand) => { + UnaryOp(un_op, operand) => { // The operand always has the same type as the result. let val = self.read_immediate(&self.eval_operand(operand, Some(dest.layout))?)?; - let val = self.unary_op(un_op, &val)?; + let val = self.unary_op(*un_op, &val)?; assert_eq!(val.layout, dest.layout, "layout mismatch for result of {:?}", un_op); self.write_immediate(*val, &dest)?; } - Aggregate(box ref kind, ref operands) => { + Aggregate(box kind, operands) => { assert!(matches!(kind, mir::AggregateKind::Array(..))); for (field_index, operand) in operands.iter().enumerate() { @@ -204,7 +204,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } - Repeat(ref operand, _) => { + Repeat(operand, _) => { let src = self.eval_operand(operand, None)?; assert!(src.layout.is_sized()); let dest = self.force_allocation(&dest)?; @@ -241,14 +241,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } Len(place) => { - let src = self.eval_place(place)?; + let src = self.eval_place(*place)?; let op = self.place_to_op(&src)?; let len = op.len(self)?; self.write_scalar(Scalar::from_machine_usize(len, self), &dest)?; } Ref(_, borrow_kind, place) => { - let src = self.eval_place(place)?; + let src = self.eval_place(*place)?; let place = self.force_allocation(&src)?; let val = ImmTy::from_immediate(place.to_ref(self), dest.layout); // A fresh reference was created, make sure it gets retagged. @@ -274,7 +274,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { false }; - let src = self.eval_place(place)?; + let src = self.eval_place(*place)?; let place = self.force_allocation(&src)?; let mut val = ImmTy::from_immediate(place.to_ref(self), dest.layout); if !place_base_raw { @@ -285,7 +285,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } NullaryOp(null_op, ty) => { - let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty)?; + let ty = self.subst_from_current_frame_and_normalize_erasing_regions(*ty)?; let layout = self.layout_of(ty)?; if layout.is_unsized() { // FIXME: This should be a span_bug (#80742) @@ -302,21 +302,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.write_scalar(Scalar::from_machine_usize(val, self), &dest)?; } - ShallowInitBox(ref operand, _) => { + ShallowInitBox(operand, _) => { let src = self.eval_operand(operand, None)?; let v = self.read_immediate(&src)?; self.write_immediate(*v, &dest)?; } - Cast(cast_kind, ref operand, cast_ty) => { + Cast(cast_kind, operand, cast_ty) => { let src = self.eval_operand(operand, None)?; let cast_ty = - self.subst_from_current_frame_and_normalize_erasing_regions(cast_ty)?; - self.cast(&src, cast_kind, cast_ty, &dest)?; + self.subst_from_current_frame_and_normalize_erasing_regions(*cast_ty)?; + self.cast(&src, *cast_kind, cast_ty, &dest)?; } Discriminant(place) => { - let op = self.eval_place_to_op(place, None)?; + let op = self.eval_place_to_op(*place, None)?; let discr_val = self.read_discriminant(&op)?.0; self.write_scalar(discr_val, &dest)?; } diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index 550c7a44c4199..d53a87225421e 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -22,14 +22,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { terminator: &mir::Terminator<'tcx>, ) -> InterpResult<'tcx> { use rustc_middle::mir::TerminatorKind::*; - match terminator.kind { + match &terminator.kind { Return => { self.pop_stack_frame(/* unwinding */ false)? } - Goto { target } => self.go_to_block(target), + Goto { target } => self.go_to_block(*target), - SwitchInt { ref discr, ref targets } => { + SwitchInt { discr, targets } => { let discr = self.read_immediate(&self.eval_operand(discr, None)?)?; trace!("SwitchInt({:?})", *discr); @@ -55,15 +55,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.go_to_block(target_block); } - Call { - ref func, - ref args, - destination, - target, - ref cleanup, - from_hir_call: _, - fn_span: _, - } => { + Call { func, args, destination, target, cleanup, from_hir_call: _, fn_span: _ } => { let old_stack = self.frame_idx(); let old_loc = self.frame().loc; let func = self.eval_operand(func, None)?; @@ -97,14 +89,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ), }; - let destination = self.eval_place(destination)?; + let destination = self.eval_place(*destination)?; self.eval_fn_call( fn_val, (fn_sig.abi, fn_abi), &args, with_caller_location, &destination, - target, + *target, match (cleanup, fn_abi.can_unwind) { (Some(cleanup), true) => StackPopUnwind::Cleanup(*cleanup), (None, true) => StackPopUnwind::Skip, @@ -118,7 +110,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } - Drop { place, target, unwind } => { + &Drop { place, target, unwind } => { let frame = self.frame(); let ty = place.ty(&frame.body.local_decls, *self.tcx).ty; let ty = self.subst_from_frame_and_normalize_erasing_regions(frame, ty)?; @@ -136,12 +128,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.drop_in_place(&place, instance, target, unwind)?; } - Assert { ref cond, expected, ref msg, target, cleanup } => { + Assert { cond, expected, msg, target, cleanup } => { let cond_val = self.read_scalar(&self.eval_operand(cond, None)?)?.to_bool()?; - if expected == cond_val { - self.go_to_block(target); + if *expected == cond_val { + self.go_to_block(*target); } else { - M::assert_panic(self, msg, cleanup)?; + M::assert_panic(self, msg, *cleanup)?; } } @@ -174,8 +166,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { terminator.kind ), - InlineAsm { template, ref operands, options, destination, .. } => { - M::eval_inline_asm(self, template, operands, options)?; + InlineAsm { template, operands, options, destination, .. } => { + M::eval_inline_asm(self, template, operands, *options)?; if options.contains(InlineAsmOptions::NORETURN) { throw_ub_format!("returned from noreturn inline assembly"); } diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index f905d3fb479a0..f976aa983be87 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -419,7 +419,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' ) } // Recursive checking - if let Some(ref mut ref_tracking) = self.ref_tracking { + if let Some(ref_tracking) = self.ref_tracking.as_deref_mut() { // Proceed recursively even for ZST, no reason to skip them! // `!` is a ZST and we want to validate it. if let Ok((alloc_id, _offset, _prov)) = self.ecx.ptr_try_get_alloc_id(place.ptr) { diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs index 1a10851a9f901..2fe411c23c463 100644 --- a/compiler/rustc_const_eval/src/interpret/visitor.rs +++ b/compiler/rustc_const_eval/src/interpret/visitor.rs @@ -481,12 +481,12 @@ macro_rules! make_value_visitor { }; // Visit the fields of this value. - match v.layout().fields { + match &v.layout().fields { FieldsShape::Primitive => {} FieldsShape::Union(fields) => { - self.visit_union(v, fields)?; + self.visit_union(v, *fields)?; } - FieldsShape::Arbitrary { ref offsets, .. } => { + FieldsShape::Arbitrary { offsets, .. } => { // FIXME: We collect in a vec because otherwise there are lifetime // errors: Projecting to a field needs access to `ecx`. let fields: Vec> = 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 d4c75cd55ce1e..79f1737e32b21 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -442,7 +442,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { self.super_rvalue(rvalue, location); - match *rvalue { + match rvalue { Rvalue::ThreadLocalRef(_) => self.check_op(ops::ThreadLocalAccess), Rvalue::Use(_) @@ -451,18 +451,15 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { | Rvalue::Discriminant(..) | Rvalue::Len(_) => {} - Rvalue::Aggregate(ref kind, ..) => { - if let AggregateKind::Generator(def_id, ..) = kind.as_ref() { - if let Some(generator_kind) = self.tcx.generator_kind(def_id.to_def_id()) { - if matches!(generator_kind, hir::GeneratorKind::Async(..)) { - self.check_op(ops::Generator(generator_kind)); - } - } + Rvalue::Aggregate(kind, ..) => { + if let AggregateKind::Generator(def_id, ..) = kind.as_ref() + && let Some(generator_kind @ hir::GeneratorKind::Async(..)) = self.tcx.generator_kind(def_id.to_def_id()) + { + self.check_op(ops::Generator(generator_kind)); } } - Rvalue::Ref(_, kind @ BorrowKind::Mut { .. }, ref place) - | Rvalue::Ref(_, kind @ BorrowKind::Unique, ref place) => { + Rvalue::Ref(_, kind @ (BorrowKind::Mut { .. } | BorrowKind::Unique), place) => { let ty = place.ty(self.body, self.tcx).ty; let is_allowed = match ty.kind() { // Inside a `static mut`, `&mut [...]` is allowed. @@ -491,12 +488,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } } - Rvalue::AddressOf(Mutability::Mut, ref place) => { + Rvalue::AddressOf(Mutability::Mut, place) => { self.check_mut_borrow(place.local, hir::BorrowKind::Raw) } - Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Shallow, ref place) - | Rvalue::AddressOf(Mutability::Not, ref place) => { + Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Shallow, place) + | Rvalue::AddressOf(Mutability::Not, place) => { let borrowed_place_has_mut_interior = qualifs::in_place::( &self.ccx, &mut |local| self.qualifs.has_mut_interior(self.ccx, local, location), @@ -564,7 +561,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {} Rvalue::ShallowInitBox(_, _) => {} - Rvalue::UnaryOp(_, ref operand) => { + Rvalue::UnaryOp(_, operand) => { let ty = operand.ty(self.body, self.tcx); if is_int_bool_or_char(ty) { // Int, bool, and char operations are fine. @@ -575,8 +572,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } } - Rvalue::BinaryOp(op, box (ref lhs, ref rhs)) - | Rvalue::CheckedBinaryOp(op, box (ref lhs, ref rhs)) => { + Rvalue::BinaryOp(op, box (lhs, rhs)) + | Rvalue::CheckedBinaryOp(op, box (lhs, rhs)) => { let lhs_ty = lhs.ty(self.body, self.tcx); let rhs_ty = rhs.ty(self.body, self.tcx); @@ -585,13 +582,16 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } else if lhs_ty.is_fn_ptr() || lhs_ty.is_unsafe_ptr() { assert_eq!(lhs_ty, rhs_ty); assert!( - op == BinOp::Eq - || op == BinOp::Ne - || op == BinOp::Le - || op == BinOp::Lt - || op == BinOp::Ge - || op == BinOp::Gt - || op == BinOp::Offset + matches!( + op, + BinOp::Eq + | BinOp::Ne + | BinOp::Le + | BinOp::Lt + | BinOp::Ge + | BinOp::Gt + | BinOp::Offset + ) ); self.check_op(ops::RawPtrComparison); diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index 04ce701452b90..25f3ac7632fcd 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -133,7 +133,7 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> { } _ => { /* mark as unpromotable below */ } } - } else if let TempState::Defined { ref mut uses, .. } = *temp { + } else if let TempState::Defined { uses, .. } = temp { // We always allow borrows, even mutable ones, as we need // to promote mutable borrows of some ZSTs e.g., `&mut []`. let allowed_use = match context { @@ -748,7 +748,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { if loc.statement_index < num_stmts { let (mut rvalue, source_info) = { let statement = &mut self.source[loc.block].statements[loc.statement_index]; - let StatementKind::Assign(box (_, ref mut rhs)) = statement.kind else { + let StatementKind::Assign(box (_, rhs)) = &mut statement.kind else { span_bug!( statement.source_info.span, "{:?} is not an assignment", @@ -778,9 +778,9 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { self.source[loc.block].terminator().clone() } else { let terminator = self.source[loc.block].terminator_mut(); - let target = match terminator.kind { - TerminatorKind::Call { target: Some(target), .. } => target, - ref kind => { + let target = match &terminator.kind { + TerminatorKind::Call { target: Some(target), .. } => *target, + kind => { span_bug!(terminator.source_info.span, "{:?} not promotable", kind); } }; @@ -814,7 +814,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { ..terminator }; } - ref kind => { + kind => { span_bug!(terminator.source_info.span, "{:?} not promotable", kind); } }; @@ -847,54 +847,50 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { let local_decls = &mut self.source.local_decls; let loc = candidate.location; let statement = &mut blocks[loc.block].statements[loc.statement_index]; - match statement.kind { - StatementKind::Assign(box ( - _, - Rvalue::Ref(ref mut region, borrow_kind, ref mut place), - )) => { - // Use the underlying local for this (necessarily interior) borrow. - let ty = local_decls[place.local].ty; - let span = statement.source_info.span; - - let ref_ty = tcx.mk_ref( - tcx.lifetimes.re_erased, - ty::TypeAndMut { ty, mutbl: borrow_kind.to_mutbl_lossy() }, - ); + let StatementKind::Assign(box (_, Rvalue::Ref(region, borrow_kind, place)))= &mut statement.kind else { + bug!() + }; - *region = tcx.lifetimes.re_erased; - - let mut projection = vec![PlaceElem::Deref]; - projection.extend(place.projection); - place.projection = tcx.intern_place_elems(&projection); - - // Create a temp to hold the promoted reference. - // This is because `*r` requires `r` to be a local, - // otherwise we would use the `promoted` directly. - let mut promoted_ref = LocalDecl::new(ref_ty, span); - promoted_ref.source_info = statement.source_info; - let promoted_ref = local_decls.push(promoted_ref); - assert_eq!(self.temps.push(TempState::Unpromotable), promoted_ref); - - let promoted_ref_statement = Statement { - source_info: statement.source_info, - kind: StatementKind::Assign(Box::new(( - Place::from(promoted_ref), - Rvalue::Use(promoted_operand(ref_ty, span)), - ))), - }; - self.extra_statements.push((loc, promoted_ref_statement)); - - Rvalue::Ref( - tcx.lifetimes.re_erased, - borrow_kind, - Place { - local: mem::replace(&mut place.local, promoted_ref), - projection: List::empty(), - }, - ) - } - _ => bug!(), - } + // Use the underlying local for this (necessarily interior) borrow. + let ty = local_decls[place.local].ty; + let span = statement.source_info.span; + + let ref_ty = tcx.mk_ref( + tcx.lifetimes.re_erased, + ty::TypeAndMut { ty, mutbl: borrow_kind.to_mutbl_lossy() }, + ); + + *region = tcx.lifetimes.re_erased; + + let mut projection = vec![PlaceElem::Deref]; + projection.extend(place.projection); + place.projection = tcx.intern_place_elems(&projection); + + // Create a temp to hold the promoted reference. + // This is because `*r` requires `r` to be a local, + // otherwise we would use the `promoted` directly. + let mut promoted_ref = LocalDecl::new(ref_ty, span); + promoted_ref.source_info = statement.source_info; + let promoted_ref = local_decls.push(promoted_ref); + assert_eq!(self.temps.push(TempState::Unpromotable), promoted_ref); + + let promoted_ref_statement = Statement { + source_info: statement.source_info, + kind: StatementKind::Assign(Box::new(( + Place::from(promoted_ref), + Rvalue::Use(promoted_operand(ref_ty, span)), + ))), + }; + self.extra_statements.push((loc, promoted_ref_statement)); + + Rvalue::Ref( + tcx.lifetimes.re_erased, + *borrow_kind, + Place { + local: mem::replace(&mut place.local, promoted_ref), + projection: List::empty(), + }, + ) }; assert_eq!(self.new_block(), START_BLOCK); From fc6cda860345b734f7c5e39b7801e3fa4cbaaba0 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Fri, 23 Dec 2022 17:12:31 +0000 Subject: [PATCH 094/230] `rustc_data_structures`: remove `ref` patterns and other artifacts of the past --- .../src/graph/implementation/tests.rs | 8 ++++---- .../rustc_data_structures/src/sorted_map.rs | 13 ++++++------- .../src/sorted_map/index_map.rs | 4 ++-- .../src/sorted_map/tests.rs | 2 +- compiler/rustc_data_structures/src/tiny_list.rs | 17 ++++++++--------- .../src/tiny_list/tests.rs | 2 +- 6 files changed, 22 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_data_structures/src/graph/implementation/tests.rs b/compiler/rustc_data_structures/src/graph/implementation/tests.rs index e4e4d0d44baba..dc1ce1747bfa0 100644 --- a/compiler/rustc_data_structures/src/graph/implementation/tests.rs +++ b/compiler/rustc_data_structures/src/graph/implementation/tests.rs @@ -70,8 +70,8 @@ fn test_adjacent_edges( "counter={:?} expected={:?} edge_index={:?} edge={:?}", counter, expected_incoming[counter], edge_index, edge ); - match expected_incoming[counter] { - (ref e, ref n) => { + match &expected_incoming[counter] { + (e, n) => { assert!(e == &edge.data); assert!(n == graph.node_data(edge.source())); assert!(start_index == edge.target); @@ -88,8 +88,8 @@ fn test_adjacent_edges( "counter={:?} expected={:?} edge_index={:?} edge={:?}", counter, expected_outgoing[counter], edge_index, edge ); - match expected_outgoing[counter] { - (ref e, ref n) => { + match &expected_outgoing[counter] { + (e, n) => { assert!(e == &edge.data); assert!(start_index == edge.source); assert!(n == graph.node_data(edge.target)); diff --git a/compiler/rustc_data_structures/src/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs index c63caa06818f2..9409057d4847e 100644 --- a/compiler/rustc_data_structures/src/sorted_map.rs +++ b/compiler/rustc_data_structures/src/sorted_map.rs @@ -1,6 +1,5 @@ use crate::stable_hasher::{HashStable, StableHasher, StableOrd}; use std::borrow::Borrow; -use std::cmp::Ordering; use std::fmt::Debug; use std::mem; use std::ops::{Bound, Index, IndexMut, RangeBounds}; @@ -171,7 +170,7 @@ impl SortedMap { where F: Fn(&mut K), { - self.data.iter_mut().map(|&mut (ref mut k, _)| k).for_each(f); + self.data.iter_mut().map(|(k, _)| k).for_each(f); } /// Inserts a presorted range of elements into the map. If the range can be @@ -232,10 +231,10 @@ impl SortedMap { R: RangeBounds, { let start = match range.start_bound() { - Bound::Included(ref k) => match self.lookup_index_for(k) { + Bound::Included(k) => match self.lookup_index_for(k) { Ok(index) | Err(index) => index, }, - Bound::Excluded(ref k) => match self.lookup_index_for(k) { + Bound::Excluded(k) => match self.lookup_index_for(k) { Ok(index) => index + 1, Err(index) => index, }, @@ -243,11 +242,11 @@ impl SortedMap { }; let end = match range.end_bound() { - Bound::Included(ref k) => match self.lookup_index_for(k) { + Bound::Included(k) => match self.lookup_index_for(k) { Ok(index) => index + 1, Err(index) => index, }, - Bound::Excluded(ref k) => match self.lookup_index_for(k) { + Bound::Excluded(k) => match self.lookup_index_for(k) { Ok(index) | Err(index) => index, }, Bound::Unbounded => self.data.len(), @@ -302,7 +301,7 @@ impl FromIterator<(K, V)> for SortedMap { let mut data: Vec<(K, V)> = iter.into_iter().collect(); data.sort_unstable_by(|(k1, _), (k2, _)| k1.cmp(k2)); - data.dedup_by(|&mut (ref k1, _), &mut (ref k2, _)| k1.cmp(k2) == Ordering::Equal); + data.dedup_by(|(k1, _), (k2, _)| k1 == k2); SortedMap { data } } diff --git a/compiler/rustc_data_structures/src/sorted_map/index_map.rs b/compiler/rustc_data_structures/src/sorted_map/index_map.rs index 7af5c14942adf..814e7c7fb9ba6 100644 --- a/compiler/rustc_data_structures/src/sorted_map/index_map.rs +++ b/compiler/rustc_data_structures/src/sorted_map/index_map.rs @@ -63,13 +63,13 @@ impl SortedIndexMultiMap { /// Returns an iterator over the items in the map in insertion order. #[inline] pub fn iter(&self) -> impl '_ + DoubleEndedIterator { - self.items.iter().map(|(ref k, ref v)| (k, v)) + self.items.iter().map(|(k, v)| (k, v)) } /// Returns an iterator over the items in the map in insertion order along with their indices. #[inline] pub fn iter_enumerated(&self) -> impl '_ + DoubleEndedIterator { - self.items.iter_enumerated().map(|(i, (ref k, ref v))| (i, (k, v))) + self.items.iter_enumerated().map(|(i, (k, v))| (i, (k, v))) } /// Returns the item in the map with the given index. diff --git a/compiler/rustc_data_structures/src/sorted_map/tests.rs b/compiler/rustc_data_structures/src/sorted_map/tests.rs index 1e977d709f1cd..3cc250862df42 100644 --- a/compiler/rustc_data_structures/src/sorted_map/tests.rs +++ b/compiler/rustc_data_structures/src/sorted_map/tests.rs @@ -6,7 +6,7 @@ fn test_sorted_index_multi_map() { let set: SortedIndexMultiMap = entries.iter().copied().collect(); // Insertion order is preserved. - assert!(entries.iter().map(|(ref k, ref v)| (k, v)).eq(set.iter())); + assert!(entries.iter().map(|(k, v)| (k, v)).eq(set.iter())); // Indexing for (i, expect) in entries.iter().enumerate() { diff --git a/compiler/rustc_data_structures/src/tiny_list.rs b/compiler/rustc_data_structures/src/tiny_list.rs index 9b07f86846eb3..11a408f216a14 100644 --- a/compiler/rustc_data_structures/src/tiny_list.rs +++ b/compiler/rustc_data_structures/src/tiny_list.rs @@ -37,9 +37,9 @@ impl TinyList { #[inline] pub fn remove(&mut self, data: &T) -> bool { - self.head = match self.head { - Some(ref mut head) if head.data == *data => head.next.take().map(|x| *x), - Some(ref mut head) => return head.remove_next(data), + self.head = match &mut self.head { + Some(head) if head.data == *data => head.next.take().map(|x| *x), + Some(head) => return head.remove_next(data), None => return false, }; true @@ -48,7 +48,7 @@ impl TinyList { #[inline] pub fn contains(&self, data: &T) -> bool { let mut elem = self.head.as_ref(); - while let Some(ref e) = elem { + while let Some(e) = elem { if &e.data == data { return true; } @@ -65,15 +65,14 @@ struct Element { } impl Element { - fn remove_next(&mut self, data: &T) -> bool { - let mut n = self; + fn remove_next(mut self: &mut Self, data: &T) -> bool { loop { - match n.next { + match self.next { Some(ref mut next) if next.data == *data => { - n.next = next.next.take(); + self.next = next.next.take(); return true; } - Some(ref mut next) => n = next, + Some(ref mut next) => self = next, None => return false, } } diff --git a/compiler/rustc_data_structures/src/tiny_list/tests.rs b/compiler/rustc_data_structures/src/tiny_list/tests.rs index c0334d2e23e55..4b95e62bef02b 100644 --- a/compiler/rustc_data_structures/src/tiny_list/tests.rs +++ b/compiler/rustc_data_structures/src/tiny_list/tests.rs @@ -6,7 +6,7 @@ use test::{black_box, Bencher}; impl TinyList { fn len(&self) -> usize { let (mut elem, mut count) = (self.head.as_ref(), 0); - while let Some(ref e) = elem { + while let Some(e) = elem { count += 1; elem = e.next.as_deref(); } From bddbf38af29dcfe5ebe12efebf465233fbb52398 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Fri, 23 Dec 2022 17:34:23 +0000 Subject: [PATCH 095/230] `rustc_expand`: remove `ref` patterns --- compiler/rustc_expand/src/base.rs | 30 ++++++------- compiler/rustc_expand/src/config.rs | 2 +- compiler/rustc_expand/src/expand.rs | 16 +++---- compiler/rustc_expand/src/mbe/macro_check.rs | 10 ++--- compiler/rustc_expand/src/mbe/macro_rules.rs | 44 +++++++++---------- compiler/rustc_expand/src/mbe/transcribe.rs | 32 +++++++------- compiler/rustc_expand/src/parse/tests.rs | 19 +++----- .../rustc_expand/src/proc_macro_server.rs | 4 +- 8 files changed, 75 insertions(+), 82 deletions(-) diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index ffde8480c0211..951d59246785d 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -63,21 +63,21 @@ pub enum Annotatable { impl Annotatable { pub fn span(&self) -> Span { - match *self { - Annotatable::Item(ref item) => item.span, - Annotatable::TraitItem(ref trait_item) => trait_item.span, - Annotatable::ImplItem(ref impl_item) => impl_item.span, - Annotatable::ForeignItem(ref foreign_item) => foreign_item.span, - Annotatable::Stmt(ref stmt) => stmt.span, - Annotatable::Expr(ref expr) => expr.span, - Annotatable::Arm(ref arm) => arm.span, - Annotatable::ExprField(ref field) => field.span, - Annotatable::PatField(ref fp) => fp.pat.span, - Annotatable::GenericParam(ref gp) => gp.ident.span, - Annotatable::Param(ref p) => p.span, - Annotatable::FieldDef(ref sf) => sf.span, - Annotatable::Variant(ref v) => v.span, - Annotatable::Crate(ref c) => c.spans.inner_span, + match self { + Annotatable::Item(item) => item.span, + Annotatable::TraitItem(trait_item) => trait_item.span, + Annotatable::ImplItem(impl_item) => impl_item.span, + Annotatable::ForeignItem(foreign_item) => foreign_item.span, + Annotatable::Stmt(stmt) => stmt.span, + Annotatable::Expr(expr) => expr.span, + Annotatable::Arm(arm) => arm.span, + Annotatable::ExprField(field) => field.span, + Annotatable::PatField(fp) => fp.pat.span, + Annotatable::GenericParam(gp) => gp.ident.span, + Annotatable::Param(p) => p.span, + Annotatable::FieldDef(sf) => sf.span, + Annotatable::Variant(v) => v.span, + Annotatable::Crate(c) => c.spans.inner_span, } } diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index f4c6f3386ade2..1fcbdfd9be5ce 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -298,7 +298,7 @@ impl<'a> StripUnconfigured<'a> { Some(AttrTokenTree::Delimited(sp, delim, inner)) .into_iter() } - AttrTokenTree::Token(ref token, _) if let TokenKind::Interpolated(ref nt) = token.kind => { + AttrTokenTree::Token(ref token, _) if let TokenKind::Interpolated(nt) = &token.kind => { panic!( "Nonterminal should have been flattened at {:?}: {:?}", token.span, nt diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 5d47c1ed363fb..79d058d9c9736 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -144,12 +144,12 @@ macro_rules! ast_fragments { } pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) { - match *self { - AstFragment::OptExpr(Some(ref expr)) => visitor.visit_expr(expr), + match self { + AstFragment::OptExpr(Some(expr)) => visitor.visit_expr(expr), AstFragment::OptExpr(None) => {} - AstFragment::MethodReceiverExpr(ref expr) => visitor.visit_method_receiver_expr(expr), - $($(AstFragment::$Kind(ref ast) => visitor.$visit_ast(ast),)?)* - $($(AstFragment::$Kind(ref ast) => for ast_elt in &ast[..] { + AstFragment::MethodReceiverExpr(expr) => visitor.visit_method_receiver_expr(expr), + $($(AstFragment::$Kind(ast) => visitor.$visit_ast(ast),)?)* + $($(AstFragment::$Kind(ast) => for ast_elt in &ast[..] { visitor.$visit_ast_elt(ast_elt, $($args)*); })?)* } @@ -592,7 +592,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let expn_id = invoc.expansion_data.id; let parent_def = self.cx.resolver.invocation_parent(expn_id); let span = match &mut invoc.kind { - InvocationKind::Bang { ref mut span, .. } => span, + InvocationKind::Bang { span, .. } => span, InvocationKind::Attr { attr, .. } => &mut attr.span, InvocationKind::Derive { path, .. } => &mut path.span, }; @@ -945,8 +945,8 @@ pub fn ensure_complete_parse<'a>( let def_site_span = parser.token.span.with_ctxt(SyntaxContext::root()); let semi_span = parser.sess.source_map().next_point(span); - let add_semicolon = match parser.sess.source_map().span_to_snippet(semi_span) { - Ok(ref snippet) if &snippet[..] != ";" && kind_name == "expression" => { + let add_semicolon = match &parser.sess.source_map().span_to_snippet(semi_span) { + Ok(snippet) if &snippet[..] != ";" && kind_name == "expression" => { Some(span.shrink_to_hi()) } _ => None, diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs index 0b8847f827df1..5be134f4e664c 100644 --- a/compiler/rustc_expand/src/mbe/macro_check.rs +++ b/compiler/rustc_expand/src/mbe/macro_check.rs @@ -151,9 +151,9 @@ impl<'a, T> Iterator for &'a Stack<'a, T> { // Iterates from top to bottom of the stack. fn next(&mut self) -> Option<&'a T> { - match *self { + match self { Stack::Empty => None, - Stack::Push { ref top, ref prev } => { + Stack::Push { top, prev } => { *self = prev; Some(top) } @@ -437,8 +437,8 @@ fn check_nested_occurrences( // We check that the meta-variable is correctly used. check_occurrences(sess, node_id, tt, macros, binders, ops, valid); } - (NestedMacroState::MacroRulesNotName, &TokenTree::Delimited(_, ref del)) - | (NestedMacroState::MacroName, &TokenTree::Delimited(_, ref del)) + (NestedMacroState::MacroRulesNotName, TokenTree::Delimited(_, del)) + | (NestedMacroState::MacroName, TokenTree::Delimited(_, del)) if del.delim == Delimiter::Brace => { let macro_rules = state == NestedMacroState::MacroRulesNotName; @@ -497,7 +497,7 @@ fn check_nested_occurrences( valid, ); } - (_, ref tt) => { + (_, tt) => { state = NestedMacroState::Empty; check_occurrences(sess, node_id, tt, macros, binders, ops, valid); } diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index c0489f686336b..4ebd75f018560 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -486,11 +486,11 @@ pub fn compile_declarative_macro( let mut valid = true; // Extract the arguments: - let lhses = match argument_map[&MacroRulesNormalizedIdent::new(lhs_nm)] { - MatchedSeq(ref s) => s + let lhses = match &argument_map[&MacroRulesNormalizedIdent::new(lhs_nm)] { + MatchedSeq(s) => s .iter() .map(|m| { - if let MatchedTokenTree(ref tt) = *m { + if let MatchedTokenTree(tt) = m { let tt = mbe::quoted::parse( TokenStream::new(vec![tt.clone()]), true, @@ -510,11 +510,11 @@ pub fn compile_declarative_macro( _ => sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs"), }; - let rhses = match argument_map[&MacroRulesNormalizedIdent::new(rhs_nm)] { - MatchedSeq(ref s) => s + let rhses = match &argument_map[&MacroRulesNormalizedIdent::new(rhs_nm)] { + MatchedSeq(s) => s .iter() .map(|m| { - if let MatchedTokenTree(ref tt) = *m { + if let MatchedTokenTree(tt) = m { return mbe::quoted::parse( TokenStream::new(vec![tt.clone()]), false, @@ -624,21 +624,21 @@ fn check_lhs_nt_follows(sess: &ParseSess, def: &ast::Item, lhs: &mbe::TokenTree) fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool { use mbe::TokenTree; for tt in tts { - match *tt { + match tt { TokenTree::Token(..) | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) | TokenTree::MetaVarExpr(..) => (), - TokenTree::Delimited(_, ref del) => { + TokenTree::Delimited(_, del) => { if !check_lhs_no_empty_seq(sess, &del.tts) { return false; } } - TokenTree::Sequence(span, ref seq) => { + TokenTree::Sequence(span, seq) => { if seq.separator.is_none() - && seq.tts.iter().all(|seq_tt| match *seq_tt { + && seq.tts.iter().all(|seq_tt| match seq_tt { TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis)) => true, - TokenTree::Sequence(_, ref sub_seq) => { + TokenTree::Sequence(_, sub_seq) => { sub_seq.kleene.op == mbe::KleeneOp::ZeroOrMore || sub_seq.kleene.op == mbe::KleeneOp::ZeroOrOne } @@ -736,21 +736,21 @@ impl<'tt> FirstSets<'tt> { fn build_recur<'tt>(sets: &mut FirstSets<'tt>, tts: &'tt [TokenTree]) -> TokenSet<'tt> { let mut first = TokenSet::empty(); for tt in tts.iter().rev() { - match *tt { + match tt { TokenTree::Token(..) | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) | TokenTree::MetaVarExpr(..) => { first.replace_with(TtHandle::TtRef(tt)); } - TokenTree::Delimited(span, ref delimited) => { + TokenTree::Delimited(span, delimited) => { build_recur(sets, &delimited.tts); first.replace_with(TtHandle::from_token_kind( token::OpenDelim(delimited.delim), span.open, )); } - TokenTree::Sequence(sp, ref seq_rep) => { + TokenTree::Sequence(sp, seq_rep) => { let subfirst = build_recur(sets, &seq_rep.tts); match sets.first.entry(sp.entire()) { @@ -804,7 +804,7 @@ impl<'tt> FirstSets<'tt> { let mut first = TokenSet::empty(); for tt in tts.iter() { assert!(first.maybe_empty); - match *tt { + match tt { TokenTree::Token(..) | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) @@ -812,14 +812,14 @@ impl<'tt> FirstSets<'tt> { first.add_one(TtHandle::TtRef(tt)); return first; } - TokenTree::Delimited(span, ref delimited) => { + TokenTree::Delimited(span, delimited) => { first.add_one(TtHandle::from_token_kind( token::OpenDelim(delimited.delim), span.open, )); return first; } - TokenTree::Sequence(sp, ref seq_rep) => { + TokenTree::Sequence(sp, seq_rep) => { let subfirst_owned; let subfirst = match self.first.get(&sp.entire()) { Some(Some(subfirst)) => subfirst, @@ -1041,7 +1041,7 @@ fn check_matcher_core<'tt>( // First, update `last` so that it corresponds to the set // of NT tokens that might end the sequence `... token`. - match *token { + match token { TokenTree::Token(..) | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) @@ -1057,7 +1057,7 @@ fn check_matcher_core<'tt>( suffix_first = build_suffix_first(); } } - TokenTree::Delimited(span, ref d) => { + TokenTree::Delimited(span, d) => { let my_suffix = TokenSet::singleton(TtHandle::from_token_kind( token::CloseDelim(d.delim), span.close, @@ -1070,7 +1070,7 @@ fn check_matcher_core<'tt>( // against SUFFIX continue 'each_token; } - TokenTree::Sequence(_, ref seq_rep) => { + TokenTree::Sequence(_, seq_rep) => { suffix_first = build_suffix_first(); // The trick here: when we check the interior, we want // to include the separator (if any) as a potential @@ -1372,8 +1372,8 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow { } fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String { - match *tt { - mbe::TokenTree::Token(ref token) => pprust::token_to_string(&token).into(), + match tt { + mbe::TokenTree::Token(token) => pprust::token_to_string(&token).into(), mbe::TokenTree::MetaVar(_, name) => format!("${}", name), mbe::TokenTree::MetaVarDecl(_, name, Some(kind)) => format!("${}:{}", name, kind), mbe::TokenTree::MetaVarDecl(_, name, None) => format!("${}:", name), diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index bec6d1a2df7d8..b79835be73a7e 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -47,8 +47,7 @@ impl<'a> Iterator for Frame<'a> { fn next(&mut self) -> Option<&'a mbe::TokenTree> { match self { - Frame::Delimited { tts, ref mut idx, .. } - | Frame::Sequence { tts, ref mut idx, .. } => { + Frame::Delimited { tts, idx, .. } | Frame::Sequence { tts, idx, .. } => { let res = tts.get(*idx); *idx += 1; res @@ -220,13 +219,13 @@ pub(super) fn transcribe<'a>( let ident = MacroRulesNormalizedIdent::new(original_ident); if let Some(cur_matched) = lookup_cur_matched(ident, interp, &repeats) { match cur_matched { - MatchedTokenTree(ref tt) => { + MatchedTokenTree(tt) => { // `tt`s are emitted into the output stream directly as "raw tokens", // without wrapping them into groups. let token = tt.clone(); result.push(token); } - MatchedNonterminal(ref nt) => { + MatchedNonterminal(nt) => { // Other variables are emitted into the output stream as groups with // `Delimiter::Invisible` to maintain parsing priorities. // `Interpolated` is currently used for such groups in rustc parser. @@ -299,12 +298,11 @@ fn lookup_cur_matched<'a>( interpolations: &'a FxHashMap, repeats: &[(usize, usize)], ) -> Option<&'a NamedMatch> { - interpolations.get(&ident).map(|matched| { - let mut matched = matched; + interpolations.get(&ident).map(|mut matched| { for &(idx, _) in repeats { match matched { MatchedTokenTree(_) | MatchedNonterminal(_) => break, - MatchedSeq(ref ads) => matched = ads.get(idx).unwrap(), + MatchedSeq(ads) => matched = ads.get(idx).unwrap(), } } @@ -339,7 +337,7 @@ impl LockstepIterSize { match self { LockstepIterSize::Unconstrained => other, LockstepIterSize::Contradiction(_) => self, - LockstepIterSize::Constraint(l_len, ref l_id) => match other { + LockstepIterSize::Constraint(l_len, l_id) => match other { LockstepIterSize::Unconstrained => self, LockstepIterSize::Contradiction(_) => other, LockstepIterSize::Constraint(r_len, _) if l_len == r_len => self, @@ -378,33 +376,33 @@ fn lockstep_iter_size( repeats: &[(usize, usize)], ) -> LockstepIterSize { use mbe::TokenTree; - match *tree { - TokenTree::Delimited(_, ref delimited) => { + match tree { + TokenTree::Delimited(_, delimited) => { delimited.tts.iter().fold(LockstepIterSize::Unconstrained, |size, tt| { size.with(lockstep_iter_size(tt, interpolations, repeats)) }) } - TokenTree::Sequence(_, ref seq) => { + TokenTree::Sequence(_, seq) => { seq.tts.iter().fold(LockstepIterSize::Unconstrained, |size, tt| { size.with(lockstep_iter_size(tt, interpolations, repeats)) }) } TokenTree::MetaVar(_, name) | TokenTree::MetaVarDecl(_, name, _) => { - let name = MacroRulesNormalizedIdent::new(name); + let name = MacroRulesNormalizedIdent::new(*name); match lookup_cur_matched(name, interpolations, repeats) { Some(matched) => match matched { MatchedTokenTree(_) | MatchedNonterminal(_) => LockstepIterSize::Unconstrained, - MatchedSeq(ref ads) => LockstepIterSize::Constraint(ads.len(), name), + MatchedSeq(ads) => LockstepIterSize::Constraint(ads.len(), name), }, _ => LockstepIterSize::Unconstrained, } } - TokenTree::MetaVarExpr(_, ref expr) => { + TokenTree::MetaVarExpr(_, expr) => { let default_rslt = LockstepIterSize::Unconstrained; let Some(ident) = expr.ident() else { return default_rslt; }; let name = MacroRulesNormalizedIdent::new(ident); match lookup_cur_matched(name, interpolations, repeats) { - Some(MatchedSeq(ref ads)) => { + Some(MatchedSeq(ads)) => { default_rslt.with(LockstepIterSize::Constraint(ads.len(), name)) } _ => default_rslt, @@ -449,7 +447,7 @@ fn count_repetitions<'a>( Some(_) => Err(out_of_bounds_err(cx, declared_lhs_depth, sp.entire(), "count")), } } - MatchedSeq(ref named_matches) => { + MatchedSeq(named_matches) => { let new_declared_lhs_depth = declared_lhs_depth + 1; match depth_opt { None => named_matches @@ -472,7 +470,7 @@ fn count_repetitions<'a>( // before we start counting. `matched` contains the various levels of the // tree as we descend, and its final value is the subtree we are currently at. for &(idx, _) in repeats { - if let MatchedSeq(ref ads) = matched { + if let MatchedSeq(ads) = matched { matched = &ads[idx]; } } diff --git a/compiler/rustc_expand/src/parse/tests.rs b/compiler/rustc_expand/src/parse/tests.rs index e49f112bf20a6..0726d922c84a3 100644 --- a/compiler/rustc_expand/src/parse/tests.rs +++ b/compiler/rustc_expand/src/parse/tests.rs @@ -176,9 +176,9 @@ fn get_spans_of_pat_idents(src: &str) -> Vec { } impl<'a> visit::Visitor<'a> for PatIdentVisitor { fn visit_pat(&mut self, p: &'a ast::Pat) { - match p.kind { - PatKind::Ident(_, ref ident, _) => { - self.spans.push(ident.span.clone()); + match &p.kind { + PatKind::Ident(_, ident, _) => { + self.spans.push(ident.span); } _ => { visit::walk_pat(self, p); @@ -290,10 +290,8 @@ fn ttdelim_span() { ) .unwrap(); - let tts: Vec<_> = match expr.kind { - ast::ExprKind::MacCall(ref mac) => mac.args.tokens.clone().into_trees().collect(), - _ => panic!("not a macro"), - }; + let ast::ExprKind::MacCall(mac) = &expr.kind else { panic!("not a macro") }; + let tts: Vec<_> = mac.args.tokens.clone().into_trees().collect(); let span = tts.iter().rev().next().unwrap().span(); @@ -318,11 +316,8 @@ fn out_of_line_mod() { .unwrap() .unwrap(); - if let ast::ItemKind::Mod(_, ref mod_kind) = item.kind { - assert!(matches!(mod_kind, ast::ModKind::Loaded(items, ..) if items.len() == 2)); - } else { - panic!(); - } + let ast::ItemKind::Mod(_, mod_kind) = &item.kind else { panic!() }; + assert!(matches!(mod_kind, ast::ModKind::Loaded(items, ..) if items.len() == 2)); }); } diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 768bdab8a5419..df59c1132cc1b 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -597,8 +597,8 @@ impl server::SourceFile for Rustc<'_, '_> { } fn path(&mut self, file: &Self::SourceFile) -> String { - match file.name { - FileName::Real(ref name) => name + match &file.name { + FileName::Real(name) => name .local_path() .expect("attempting to get a file path in an imported file in `proc_macro::SourceFile::path`") .to_str() From 360e9784375e9487172448d4700a1b038d845c99 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 9 Jan 2023 15:15:26 +0000 Subject: [PATCH 096/230] Don't call closures immediately, use `try{}` blocks --- .../src/check/compare_impl_item.rs | 68 +++++++------------ .../src/infer/lexical_region_resolve/mod.rs | 22 +++--- compiler/rustc_interface/src/lib.rs | 1 + compiler/rustc_interface/src/passes.rs | 6 +- compiler/rustc_middle/src/traits/chalk.rs | 24 ++++--- .../rustc_mir_build/src/build/custom/mod.rs | 6 +- .../rustc_mir_build/src/build/expr/stmt.rs | 10 +-- .../src/thir/pattern/deconstruct_pat.rs | 34 ++++------ .../src/traits/fulfill.rs | 12 ++-- .../src/traits/query/normalize.rs | 20 +++--- 10 files changed, 88 insertions(+), 115 deletions(-) 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 c43bfd16ab1e4..2133b5ac50b02 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -47,42 +47,22 @@ pub(super) fn compare_impl_method<'tcx>( let impl_m_span = tcx.def_span(impl_m.def_id); - if let Err(_) = compare_self_type(tcx, impl_m, impl_m_span, trait_m, impl_trait_ref) { - return; - } - - if let Err(_) = compare_number_of_generics(tcx, impl_m, trait_m, trait_item_span, false) { - return; - } - - if let Err(_) = compare_generic_param_kinds(tcx, impl_m, trait_m, false) { - return; - } - - if let Err(_) = - compare_number_of_method_arguments(tcx, impl_m, impl_m_span, trait_m, trait_item_span) - { - return; - } - - if let Err(_) = compare_synthetic_generics(tcx, impl_m, trait_m) { - return; - } - - if let Err(_) = compare_asyncness(tcx, impl_m, impl_m_span, trait_m, trait_item_span) { - return; - } - - if let Err(_) = compare_method_predicate_entailment( - tcx, - impl_m, - impl_m_span, - trait_m, - impl_trait_ref, - CheckImpliedWfMode::Check, - ) { - return; - } + let _: Result<_, ErrorGuaranteed> = try { + compare_self_type(tcx, impl_m, impl_m_span, trait_m, impl_trait_ref)?; + compare_number_of_generics(tcx, impl_m, trait_m, trait_item_span, false)?; + compare_generic_param_kinds(tcx, impl_m, trait_m, false)?; + compare_number_of_method_arguments(tcx, impl_m, impl_m_span, trait_m, trait_item_span)?; + compare_synthetic_generics(tcx, impl_m, trait_m)?; + compare_asyncness(tcx, impl_m, impl_m_span, trait_m, trait_item_span)?; + compare_method_predicate_entailment( + tcx, + impl_m, + impl_m_span, + trait_m, + impl_trait_ref, + CheckImpliedWfMode::Check, + )?; + }; } /// This function is best explained by example. Consider a trait: @@ -1493,7 +1473,7 @@ fn compare_synthetic_generics<'tcx>( // explicit generics (true, false) => { err.span_label(impl_span, "expected generic parameter, found `impl Trait`"); - (|| { + let _: Option<_> = try { // try taking the name from the trait impl // FIXME: this is obviously suboptimal since the name can already be used // as another generic argument @@ -1526,14 +1506,13 @@ fn compare_synthetic_generics<'tcx>( ], Applicability::MaybeIncorrect, ); - Some(()) - })(); + }; } // The case where the trait method uses `impl Trait`, but the impl method uses // explicit generics. (false, true) => { err.span_label(impl_span, "expected `impl Trait`, found generic parameter"); - (|| { + let _: Option<_> = try { let impl_m = impl_m.def_id.as_local()?; let impl_m = tcx.hir().expect_impl_item(impl_m); let input_tys = match impl_m.kind { @@ -1573,8 +1552,7 @@ fn compare_synthetic_generics<'tcx>( ], Applicability::MaybeIncorrect, ); - Some(()) - })(); + }; } _ => unreachable!(), } @@ -1799,7 +1777,7 @@ pub(super) fn compare_impl_ty<'tcx>( ) { debug!("compare_impl_type(impl_trait_ref={:?})", impl_trait_ref); - let _: Result<(), ErrorGuaranteed> = (|| { + let _: Result<(), ErrorGuaranteed> = try { compare_number_of_generics(tcx, impl_ty, trait_ty, trait_item_span, false)?; compare_generic_param_kinds(tcx, impl_ty, trait_ty, false)?; @@ -1807,8 +1785,8 @@ pub(super) fn compare_impl_ty<'tcx>( let sp = tcx.def_span(impl_ty.def_id); compare_type_predicate_entailment(tcx, impl_ty, sp, trait_ty, impl_trait_ref)?; - check_type_bounds(tcx, trait_ty, impl_ty, impl_ty_span, impl_trait_ref) - })(); + check_type_bounds(tcx, trait_ty, impl_ty, impl_ty_span, impl_trait_ref)?; + }; } /// The equivalent of [compare_method_predicate_entailment], but for associated types 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 897545046c33f..3c5a3b16ec18a 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -251,7 +251,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { VarValue::Empty(a_universe) => { let b_data = var_values.value_mut(b_vid); - let changed = (|| match *b_data { + let changed = match *b_data { VarValue::Empty(b_universe) => { // Empty regions are ordered according to the universe // they are associated with. @@ -280,20 +280,20 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { }; if lub == cur_region { - return false; + false + } else { + debug!( + "Expanding value of {:?} from {:?} to {:?}", + b_vid, cur_region, lub + ); + + *b_data = VarValue::Value(lub); + true } - - debug!( - "Expanding value of {:?} from {:?} to {:?}", - b_vid, cur_region, lub - ); - - *b_data = VarValue::Value(lub); - true } VarValue::ErrorValue => false, - })(); + }; if changed { changes.push(b_vid); diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index 542b638bbd7a4..82bc4770b6b47 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -3,6 +3,7 @@ #![feature(internal_output_capture)] #![feature(thread_spawn_unchecked)] #![feature(once_cell)] +#![feature(try_blocks)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] #![deny(rustc::untranslatable_diagnostic)] diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 50c40206d8026..9bee49f4ba8b2 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -559,7 +559,7 @@ fn write_out_deps( } let deps_filename = outputs.path(OutputType::DepInfo); - let result = (|| -> io::Result<()> { + let result: io::Result<()> = try { // Build a list of files used to compile the output and // write Makefile-compatible dependency rules let mut files: Vec = sess @@ -646,9 +646,7 @@ fn write_out_deps( writeln!(file)?; } } - - Ok(()) - })(); + }; match result { Ok(_) => { diff --git a/compiler/rustc_middle/src/traits/chalk.rs b/compiler/rustc_middle/src/traits/chalk.rs index dd75b0d9ebc23..fcc8f457a8b78 100644 --- a/compiler/rustc_middle/src/traits/chalk.rs +++ b/compiler/rustc_middle/src/traits/chalk.rs @@ -159,18 +159,20 @@ impl<'tcx> chalk_ir::interner::Interner for RustInterner<'tcx> { } chalk_ir::TyKind::Array(ty, len) => Some(write!(fmt, "[{:?}; {:?}]", ty, len)), chalk_ir::TyKind::Slice(ty) => Some(write!(fmt, "[{:?}]", ty)), - chalk_ir::TyKind::Tuple(len, substs) => Some((|| { - write!(fmt, "(")?; - for (idx, substitution) in substs.interned().iter().enumerate() { - if idx == *len && *len != 1 { - // Don't add a trailing comma if the tuple has more than one element - write!(fmt, "{:?}", substitution)?; - } else { - write!(fmt, "{:?},", substitution)?; + chalk_ir::TyKind::Tuple(len, substs) => Some( + try { + write!(fmt, "(")?; + for (idx, substitution) in substs.interned().iter().enumerate() { + if idx == *len && *len != 1 { + // Don't add a trailing comma if the tuple has more than one element + write!(fmt, "{:?}", substitution)?; + } else { + write!(fmt, "{:?},", substitution)?; + } } - } - write!(fmt, ")") - })()), + write!(fmt, ")")?; + }, + ), _ => None, } } diff --git a/compiler/rustc_mir_build/src/build/custom/mod.rs b/compiler/rustc_mir_build/src/build/custom/mod.rs index 34fefb99e09c2..33fdc1901cd78 100644 --- a/compiler/rustc_mir_build/src/build/custom/mod.rs +++ b/compiler/rustc_mir_build/src/build/custom/mod.rs @@ -86,10 +86,10 @@ pub(super) fn build_custom_mir<'tcx>( block_map: FxHashMap::default(), }; - let res = (|| { + let res: PResult<_> = try { pctxt.parse_args(¶ms)?; - pctxt.parse_body(expr) - })(); + pctxt.parse_body(expr)?; + }; if let Err(err) = res { tcx.sess.diagnostic().span_fatal( err.span, diff --git a/compiler/rustc_mir_build/src/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs index e9f327978aab1..ef502b4fa81e1 100644 --- a/compiler/rustc_mir_build/src/build/expr/stmt.rs +++ b/compiler/rustc_mir_build/src/build/expr/stmt.rs @@ -113,7 +113,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // // it is usually better to focus on `the_value` rather // than the entirety of block(s) surrounding it. - let adjusted_span = (|| { + let adjusted_span = if let ExprKind::Block { block } = expr.kind && let Some(tail_ex) = this.thir[block].expr { @@ -135,10 +135,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { tail_result_is_ignored: true, span: expr.span, }); - return Some(expr.span); - } - None - })(); + Some(expr.span) + } else { + None + }; let temp = unpack!(block = this.as_temp(block, statement_scope, expr, Mutability::Not)); diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 17b3c475f83c7..e754e2465346f 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -141,27 +141,23 @@ impl IntRange { ) -> Option { let ty = value.ty(); if let Some((target_size, bias)) = Self::integral_size_and_signed_bias(tcx, ty) { - let val = (|| { - match value { - mir::ConstantKind::Val(ConstValue::Scalar(scalar), _) => { - // For this specific pattern we can skip a lot of effort and go - // straight to the result, after doing a bit of checking. (We - // could remove this branch and just fall through, which - // is more general but much slower.) - return scalar.to_bits_or_ptr_internal(target_size).unwrap().left(); + let val = + if let mir::ConstantKind::Val(ConstValue::Scalar(scalar), _) = value { + // For this specific pattern we can skip a lot of effort and go + // straight to the result, after doing a bit of checking. (We + // could remove this branch and just fall through, which + // is more general but much slower.) + scalar.to_bits_or_ptr_internal(target_size).unwrap().left()? + } else { + if let mir::ConstantKind::Ty(c) = value + && let ty::ConstKind::Value(_) = c.kind() + { + bug!("encountered ConstValue in mir::ConstantKind::Ty, whereas this is expected to be in ConstantKind::Val"); } - mir::ConstantKind::Ty(c) => match c.kind() { - ty::ConstKind::Value(_) => bug!( - "encountered ConstValue in mir::ConstantKind::Ty, whereas this is expected to be in ConstantKind::Val" - ), - _ => {} - }, - _ => {} - } - // This is a more general form of the previous case. - value.try_eval_bits(tcx, param_env, ty) - })()?; + // This is a more general form of the previous case. + value.try_eval_bits(tcx, param_env, ty)? + }; let val = val ^ bias; Some(IntRange { range: val..=val, bias }) } else { diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 76a755ed9e09d..ea27db7b81f87 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -208,14 +208,12 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { _ => { // This `for` loop was once a call to `all()`, but this lower-level // form was a perf win. See #64545 for details. - (|| { - for &infer_var in &pending_obligation.stalled_on { - if self.selcx.infcx.ty_or_const_infer_var_changed(infer_var) { - return true; - } + for &infer_var in &pending_obligation.stalled_on { + if self.selcx.infcx.ty_or_const_infer_var_changed(infer_var) { + return true; } - false - })() + } + false } } } diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index c6ef13e185b2d..751aec48bd8c3 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -201,7 +201,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { // wait to fold the substs. // Wrap this in a closure so we don't accidentally return from the outer function - let res = (|| match *ty.kind() { + let res = match *ty.kind() { // This is really important. While we *can* handle this, this has // severe performance implications for large opaque types with // late-bound regions. See `issue-88862` benchmark. @@ -210,7 +210,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { { // Only normalize `impl Trait` outside of type inference, usually in codegen. match self.param_env.reveal() { - Reveal::UserFacing => ty.try_super_fold_with(self), + Reveal::UserFacing => ty.try_super_fold_with(self)?, Reveal::All => { let substs = substs.try_fold_with(self)?; @@ -230,7 +230,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { if concrete_ty == ty { bug!( "infinite recursion generic_ty: {:#?}, substs: {:#?}, \ - concrete_ty: {:#?}, ty: {:#?}", + concrete_ty: {:#?}, ty: {:#?}", generic_ty, substs, concrete_ty, @@ -239,7 +239,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { } let folded_ty = ensure_sufficient_stack(|| self.try_fold_ty(concrete_ty)); self.anon_depth -= 1; - folded_ty + folded_ty? } } } @@ -287,9 +287,9 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { // `tcx.normalize_projection_ty` may normalize to a type that still has // unevaluated consts, so keep normalizing here if that's the case. if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) { - Ok(res.try_super_fold_with(self)?) + res.try_super_fold_with(self)? } else { - Ok(res) + res } } @@ -344,14 +344,14 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { // `tcx.normalize_projection_ty` may normalize to a type that still has // unevaluated consts, so keep normalizing here if that's the case. if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) { - Ok(res.try_super_fold_with(self)?) + res.try_super_fold_with(self)? } else { - Ok(res) + res } } - _ => ty.try_super_fold_with(self), - })()?; + _ => ty.try_super_fold_with(self)?, + }; self.cache.insert(ty, res); Ok(res) From d60e772e14a862a1ed3f6a7ee23faadbdd9cf443 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 9 Jan 2023 15:21:08 +0000 Subject: [PATCH 097/230] `rustc_hir_analysis`: some general code improvements --- .../src/check/compare_impl_item.rs | 162 ++++++++---------- .../src/coherence/builtin.rs | 7 +- compiler/rustc_hir_analysis/src/collect.rs | 28 ++- compiler/rustc_hir_analysis/src/lib.rs | 9 +- 4 files changed, 92 insertions(+), 114 deletions(-) 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 2133b5ac50b02..6b47f4f019d35 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -916,16 +916,14 @@ fn report_trait_method_mismatch<'tcx>( // When the `impl` receiver is an arbitrary self type, like `self: Box`, the // span points only at the type `Box, but we want to cover the whole // argument pattern and type. - let span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind { - ImplItemKind::Fn(ref sig, body) => tcx - .hir() - .body_param_names(body) - .zip(sig.decl.inputs.iter()) - .map(|(param, ty)| param.span.to(ty.span)) - .next() - .unwrap_or(impl_err_span), - _ => bug!("{:?} is not a method", impl_m), - }; + let ImplItemKind::Fn(ref sig, body) = tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind else { bug!("{impl_m:?} is not a method") }; + let span = tcx + .hir() + .body_param_names(body) + .zip(sig.decl.inputs.iter()) + .map(|(param, ty)| param.span.to(ty.span)) + .next() + .unwrap_or(impl_err_span); diag.span_suggestion( span, @@ -938,22 +936,21 @@ fn report_trait_method_mismatch<'tcx>( if trait_sig.inputs().len() == *i { // Suggestion to change output type. We do not suggest in `async` functions // to avoid complex logic or incorrect output. - match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind { - ImplItemKind::Fn(ref sig, _) if !sig.header.asyncness.is_async() => { - let msg = "change the output type to match the trait"; - let ap = Applicability::MachineApplicable; - match sig.decl.output { - hir::FnRetTy::DefaultReturn(sp) => { - let sugg = format!("-> {} ", trait_sig.output()); - diag.span_suggestion_verbose(sp, msg, sugg, ap); - } - hir::FnRetTy::Return(hir_ty) => { - let sugg = trait_sig.output(); - diag.span_suggestion(hir_ty.span, msg, sugg, ap); - } - }; - } - _ => {} + if let ImplItemKind::Fn(sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind + && !sig.header.asyncness.is_async() + { + let msg = "change the output type to match the trait"; + let ap = Applicability::MachineApplicable; + match sig.decl.output { + hir::FnRetTy::DefaultReturn(sp) => { + let sugg = format!("-> {} ", trait_sig.output()); + diag.span_suggestion_verbose(sp, msg, sugg, ap); + } + hir::FnRetTy::Return(hir_ty) => { + let sugg = trait_sig.output(); + diag.span_suggestion(hir_ty.span, msg, sugg, ap); + } + }; }; } else if let Some(trait_ty) = trait_sig.inputs().get(*i) { diag.span_suggestion( @@ -1080,25 +1077,18 @@ fn extract_spans_for_error_reporting<'tcx>( trait_m: &ty::AssocItem, ) -> (Span, Option) { let tcx = infcx.tcx; - let mut impl_args = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind { - ImplItemKind::Fn(ref sig, _) => { - sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span())) - } - _ => bug!("{:?} is not a method", impl_m), + let mut impl_args = { + let ImplItemKind::Fn(sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind else { bug!("{:?} is not a method", impl_m) }; + sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span())) }; - let trait_args = - trait_m.def_id.as_local().map(|def_id| match tcx.hir().expect_trait_item(def_id).kind { - TraitItemKind::Fn(ref sig, _) => { - sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span())) - } - _ => bug!("{:?} is not a TraitItemKind::Fn", trait_m), - }); + + let trait_args = trait_m.def_id.as_local().map(|def_id| { + let TraitItemKind::Fn(sig, _) = &tcx.hir().expect_trait_item(def_id).kind else { bug!("{:?} is not a TraitItemKind::Fn", trait_m) }; + sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span())) + }); match terr { - TypeError::ArgumentMutability(i) => { - (impl_args.nth(i).unwrap(), trait_args.and_then(|mut args| args.nth(i))) - } - TypeError::ArgumentSorts(ExpectedFound { .. }, i) => { + TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => { (impl_args.nth(i).unwrap(), trait_args.and_then(|mut args| args.nth(i))) } _ => (cause.span(), tcx.hir().span_if_local(trait_m.def_id)), @@ -1158,8 +1148,7 @@ fn compare_self_type<'tcx>( } else { err.note_trait_signature(trait_m.name, trait_m.signature(tcx)); } - let reported = err.emit(); - return Err(reported); + return Err(err.emit()); } (true, false) => { @@ -1178,8 +1167,8 @@ fn compare_self_type<'tcx>( } else { err.note_trait_signature(trait_m.name, trait_m.signature(tcx)); } - let reported = err.emit(); - return Err(reported); + + return Err(err.emit()); } } @@ -1361,41 +1350,41 @@ fn compare_number_of_method_arguments<'tcx>( let trait_m_fty = tcx.fn_sig(trait_m.def_id); let trait_number_args = trait_m_fty.inputs().skip_binder().len(); let impl_number_args = impl_m_fty.inputs().skip_binder().len(); + if trait_number_args != impl_number_args { - let trait_span = if let Some(def_id) = trait_m.def_id.as_local() { - match tcx.hir().expect_trait_item(def_id).kind { - TraitItemKind::Fn(ref trait_m_sig, _) => { - let pos = if trait_number_args > 0 { trait_number_args - 1 } else { 0 }; - if let Some(arg) = trait_m_sig.decl.inputs.get(pos) { - Some(if pos == 0 { - arg.span - } else { - arg.span.with_lo(trait_m_sig.decl.inputs[0].span.lo()) - }) + let trait_span = trait_m + .def_id + .as_local() + .and_then(|def_id| { + let TraitItemKind::Fn(trait_m_sig, _) = &tcx.hir().expect_trait_item(def_id).kind else { bug!("{:?} is not a method", impl_m) }; + let pos = trait_number_args.saturating_sub(1); + trait_m_sig.decl.inputs.get(pos).map(|arg| { + if pos == 0 { + arg.span } else { - trait_item_span + arg.span.with_lo(trait_m_sig.decl.inputs[0].span.lo()) } - } - _ => bug!("{:?} is not a method", impl_m), - } - } else { - trait_item_span - }; - let impl_span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind { - ImplItemKind::Fn(ref impl_m_sig, _) => { - let pos = if impl_number_args > 0 { impl_number_args - 1 } else { 0 }; - if let Some(arg) = impl_m_sig.decl.inputs.get(pos) { + }) + }) + .or(trait_item_span); + + let impl_span = { + let ImplItemKind::Fn(impl_m_sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind else { bug!("{:?} is not a method", impl_m) }; + let pos = impl_number_args.saturating_sub(1); + impl_m_sig + .decl + .inputs + .get(pos) + .map(|arg| { if pos == 0 { arg.span } else { arg.span.with_lo(impl_m_sig.decl.inputs[0].span.lo()) } - } else { - impl_m_span - } - } - _ => bug!("{:?} is not a method", impl_m), + }) + .unwrap_or(impl_m_span) }; + let mut err = struct_span_err!( tcx.sess, impl_span, @@ -1406,6 +1395,7 @@ fn compare_number_of_method_arguments<'tcx>( tcx.def_path_str(trait_m.def_id), trait_number_args ); + if let Some(trait_span) = trait_span { err.span_label( trait_span, @@ -1417,6 +1407,7 @@ fn compare_number_of_method_arguments<'tcx>( } else { err.note_trait_signature(trait_m.name, trait_m.signature(tcx)); } + err.span_label( impl_span, format!( @@ -1425,8 +1416,8 @@ fn compare_number_of_method_arguments<'tcx>( impl_number_args ), ); - let reported = err.emit(); - return Err(reported); + + return Err(err.emit()); } Ok(()) @@ -1515,10 +1506,9 @@ fn compare_synthetic_generics<'tcx>( let _: Option<_> = try { let impl_m = impl_m.def_id.as_local()?; let impl_m = tcx.hir().expect_impl_item(impl_m); - let input_tys = match impl_m.kind { - hir::ImplItemKind::Fn(ref sig, _) => sig.decl.inputs, - _ => unreachable!(), - }; + let hir::ImplItemKind::Fn(sig, _) = &impl_m.kind else { unreachable!() }; + let input_tys = sig.decl.inputs; + struct Visitor(Option, hir::def_id::LocalDefId); impl<'v> intravisit::Visitor<'v> for Visitor { fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) { @@ -1532,6 +1522,7 @@ fn compare_synthetic_generics<'tcx>( } } } + let mut visitor = Visitor(None, impl_def_id); for ty in input_tys { intravisit::Visitor::visit_ty(&mut visitor, ty); @@ -1556,8 +1547,7 @@ fn compare_synthetic_generics<'tcx>( } _ => unreachable!(), } - let reported = err.emit(); - error_found = Some(reported); + error_found = Some(err.emit()); } } if let Some(reported) = error_found { Err(reported) } else { Ok(()) } @@ -1717,10 +1707,8 @@ pub(super) fn compare_impl_const_raw( ); // Locate the Span containing just the type of the offending impl - match tcx.hir().expect_impl_item(impl_const_item_def).kind { - ImplItemKind::Const(ref ty, _) => cause.span = ty.span, - _ => bug!("{:?} is not a impl const", impl_const_item), - } + let ImplItemKind::Const(ty, _) = tcx.hir().expect_impl_item(impl_const_item_def).kind else { bug!("{impl_const_item:?} is not a impl const") }; + cause.span = ty.span; let mut diag = struct_span_err!( tcx.sess, @@ -1732,10 +1720,8 @@ pub(super) fn compare_impl_const_raw( let trait_c_span = trait_const_item_def.as_local().map(|trait_c_def_id| { // Add a label to the Span containing just the type of the const - match tcx.hir().expect_trait_item(trait_c_def_id).kind { - TraitItemKind::Const(ref ty, _) => ty.span, - _ => bug!("{:?} is not a trait const", trait_const_item), - } + let TraitItemKind::Const(ty, _) = tcx.hir().expect_trait_item(trait_c_def_id).kind else { bug!("{trait_const_item:?} is not a trait const") }; + ty.span }); infcx.err_ctxt().note_type_err( diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 5bdd18fcd637c..3e6dafd2c6f3a 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -54,12 +54,9 @@ fn visit_implementation_of_drop(tcx: TyCtxt<'_>, impl_did: LocalDefId) { _ => {} } - let sp = match tcx.hir().expect_item(impl_did).kind { - ItemKind::Impl(ref impl_) => impl_.self_ty.span, - _ => bug!("expected Drop impl item"), - }; + let ItemKind::Impl(impl_) = tcx.hir().expect_item(impl_did).kind else { bug!("expected Drop impl item") }; - tcx.sess.emit_err(DropImplOnWrongItem { span: sp }); + tcx.sess.emit_err(DropImplOnWrongItem { span: impl_.self_ty.span }); } fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) { diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 35f47dfc1a5e2..093a84160fe39 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1342,21 +1342,19 @@ fn suggest_impl_trait<'tcx>( fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option>> { let icx = ItemCtxt::new(tcx, def_id); let item = tcx.hir().expect_item(def_id.expect_local()); - match item.kind { - hir::ItemKind::Impl(ref impl_) => impl_ - .of_trait - .as_ref() - .map(|ast_trait_ref| { - let selfty = tcx.type_of(def_id); - icx.astconv().instantiate_mono_trait_ref( - ast_trait_ref, - selfty, - check_impl_constness(tcx, impl_.constness, ast_trait_ref), - ) - }) - .map(ty::EarlyBinder), - _ => bug!(), - } + let hir::ItemKind::Impl(impl_) = item.kind else { bug!() }; + impl_ + .of_trait + .as_ref() + .map(|ast_trait_ref| { + let selfty = tcx.type_of(def_id); + icx.astconv().instantiate_mono_trait_ref( + ast_trait_ref, + selfty, + check_impl_constness(tcx, impl_.constness, ast_trait_ref), + ) + }) + .map(ty::EarlyBinder) } fn check_impl_constness( diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index ddc5b76688126..97fff85f424c3 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -114,6 +114,7 @@ use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; use std::iter; +use std::ops::Not; use astconv::AstConv; use bounds::Bounds; @@ -203,12 +204,8 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { } let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); match tcx.hir().find(hir_id) { - Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, ref generics, _), .. })) => { - if !generics.params.is_empty() { - Some(generics.span) - } else { - None - } + Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. })) => { + generics.params.is_empty().not().then(|| generics.span) } _ => { span_bug!(tcx.def_span(def_id), "main has a non-function type"); From 09485eaae12b2f268d8e0c90671d759138d82778 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 9 Jan 2023 16:30:40 +0000 Subject: [PATCH 098/230] `rustc_hir_analysis`: remove `ref` patterns --- .../rustc_hir_analysis/src/astconv/mod.rs | 42 ++++++------- .../rustc_hir_analysis/src/check/check.rs | 14 ++--- .../src/check/compare_impl_item.rs | 3 +- .../src/check/intrinsicck.rs | 8 +-- .../rustc_hir_analysis/src/check/region.rs | 38 ++++++------ .../rustc_hir_analysis/src/check/wfcheck.rs | 12 ++-- .../src/coherence/builtin.rs | 11 ++-- .../src/coherence/inherent_impls.rs | 2 +- .../src/coherence/orphan.rs | 2 +- .../src/coherence/unsafety.rs | 2 +- compiler/rustc_hir_analysis/src/collect.rs | 16 ++--- .../src/collect/generics_of.rs | 24 +++---- .../src/collect/lifetimes.rs | 62 +++++++++---------- .../src/collect/predicates_of.rs | 50 +++++++-------- .../rustc_hir_analysis/src/collect/type_of.rs | 27 ++++---- .../rustc_hir_analysis/src/hir_wf_check.rs | 2 +- compiler/rustc_hir_analysis/src/lib.rs | 6 +- .../wrong_number_of_generic_args.rs | 4 +- .../rustc_hir_analysis/src/variance/solve.rs | 4 +- 19 files changed, 161 insertions(+), 168 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 7ac4f65049042..3953fd8c5a803 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -569,17 +569,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .bindings .iter() .map(|binding| { - let kind = match binding.kind { - hir::TypeBindingKind::Equality { ref term } => match term { - hir::Term::Ty(ref ty) => { + let kind = match &binding.kind { + hir::TypeBindingKind::Equality { term } => match term { + hir::Term::Ty(ty) => { ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty).into()) } - hir::Term::Const(ref c) => { + hir::Term::Const(c) => { let c = Const::from_anon_const(self.tcx(), c.def_id); ConvertedBindingKind::Equality(c.into()) } }, - hir::TypeBindingKind::Constraint { ref bounds } => { + hir::TypeBindingKind::Constraint { bounds } => { ConvertedBindingKind::Constraint(bounds) } }; @@ -1928,7 +1928,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> { let tcx = self.tcx(); let assoc_ident = assoc_segment.ident; - let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = qself.kind { + let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind { path.res } else { Res::Err @@ -1971,8 +1971,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { return; }; let (qself_sugg_span, is_self) = if let hir::TyKind::Path( - hir::QPath::Resolved(_, ref path) - ) = qself.kind { + hir::QPath::Resolved(_, path) + ) = &qself.kind { // If the path segment already has type params, we want to overwrite // them. match &path.segments[..] { @@ -2760,7 +2760,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { "generic `Self` types are currently not permitted in anonymous constants", ); if let Some(hir::Node::Item(&hir::Item { - kind: hir::ItemKind::Impl(ref impl_), + kind: hir::ItemKind::Impl(impl_), .. })) = tcx.hir().get_if_local(def_id) { @@ -2843,12 +2843,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool) -> Ty<'tcx> { let tcx = self.tcx(); - let result_ty = match ast_ty.kind { - hir::TyKind::Slice(ref ty) => tcx.mk_slice(self.ast_ty_to_ty(ty)), - hir::TyKind::Ptr(ref mt) => { + let result_ty = match &ast_ty.kind { + hir::TyKind::Slice(ty) => tcx.mk_slice(self.ast_ty_to_ty(ty)), + hir::TyKind::Ptr(mt) => { tcx.mk_ptr(ty::TypeAndMut { ty: self.ast_ty_to_ty(mt.ty), mutbl: mt.mutbl }) } - hir::TyKind::Ref(ref region, ref mt) => { + hir::TyKind::Ref(region, mt) => { let r = self.ast_region_to_region(region, None); debug!(?r); let t = self.ast_ty_to_ty_inner(mt.ty, true, false); @@ -2868,7 +2868,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { Some(ast_ty), )) } - hir::TyKind::TraitObject(bounds, ref lifetime, repr) => { + hir::TyKind::TraitObject(bounds, lifetime, repr) => { self.maybe_lint_bare_trait(ast_ty, in_path); let repr = match repr { TraitObjectSyntax::Dyn | TraitObjectSyntax::None => ty::Dyn, @@ -2876,30 +2876,30 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }; self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed, repr) } - hir::TyKind::Path(hir::QPath::Resolved(ref maybe_qself, ref path)) => { + hir::TyKind::Path(hir::QPath::Resolved(maybe_qself, path)) => { debug!(?maybe_qself, ?path); let opt_self_ty = maybe_qself.as_ref().map(|qself| self.ast_ty_to_ty(qself)); self.res_to_ty(opt_self_ty, path, false) } hir::TyKind::OpaqueDef(item_id, lifetimes, in_trait) => { - let opaque_ty = tcx.hir().item(item_id); + let opaque_ty = tcx.hir().item(*item_id); let def_id = item_id.owner_id.to_def_id(); match opaque_ty.kind { hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => { - self.impl_trait_ty_to_ty(def_id, lifetimes, origin, in_trait) + self.impl_trait_ty_to_ty(def_id, lifetimes, origin, *in_trait) } ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i), } } - hir::TyKind::Path(hir::QPath::TypeRelative(ref qself, ref segment)) => { + hir::TyKind::Path(hir::QPath::TypeRelative(qself, segment)) => { debug!(?qself, ?segment); let ty = self.ast_ty_to_ty_inner(qself, false, true); self.associated_path_to_ty(ast_ty.hir_id, ast_ty.span, ty, qself, segment, false) .map(|(ty, _, _)| ty) .unwrap_or_else(|_| tcx.ty_error()) } - hir::TyKind::Path(hir::QPath::LangItem(lang_item, span, _)) => { + &hir::TyKind::Path(hir::QPath::LangItem(lang_item, span, _)) => { let def_id = tcx.require_lang_item(lang_item, Some(span)); let (substs, _) = self.create_substs_for_ast_path( span, @@ -2913,7 +2913,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ); EarlyBinder(tcx.at(span).type_of(def_id)).subst(tcx, substs) } - hir::TyKind::Array(ref ty, ref length) => { + hir::TyKind::Array(ty, length) => { let length = match length { &hir::ArrayLen::Infer(_, span) => self.ct_infer(tcx.types.usize, None, span), hir::ArrayLen::Body(constant) => { @@ -2923,7 +2923,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { tcx.mk_ty(ty::Array(self.ast_ty_to_ty(ty), length)) } - hir::TyKind::Typeof(ref e) => { + hir::TyKind::Typeof(e) => { let ty_erased = tcx.type_of(e.def_id); let ty = tcx.fold_regions(ty_erased, |r, _| { if r.is_erased() { tcx.lifetimes.re_static } else { r } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index e58669433e218..d286a25dd598a 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -531,9 +531,7 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { DefKind::Fn => {} // entirely within check_item_body DefKind::Impl => { let it = tcx.hir().item(id); - let hir::ItemKind::Impl(ref impl_) = it.kind else { - return; - }; + let hir::ItemKind::Impl(impl_) = it.kind else { return }; debug!("ItemKind::Impl {} with id {:?}", it.ident, it.owner_id); if let Some(impl_trait_ref) = tcx.impl_trait_ref(it.owner_id) { check_impl_items_against_trait( @@ -548,15 +546,15 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { } DefKind::Trait => { let it = tcx.hir().item(id); - let hir::ItemKind::Trait(_, _, _, _, ref items) = it.kind else { + let hir::ItemKind::Trait(_, _, _, _, items) = it.kind else { return; }; check_on_unimplemented(tcx, it); for item in items.iter() { let item = tcx.hir().trait_item(item.id); - match item.kind { - hir::TraitItemKind::Fn(ref sig, _) => { + match &item.kind { + hir::TraitItemKind::Fn(sig, _) => { let abi = sig.header.abi; fn_maybe_err(tcx, item.ident.span, abi); } @@ -652,8 +650,8 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { } let item = tcx.hir().foreign_item(item.id); - match item.kind { - hir::ForeignItemKind::Fn(ref fn_decl, _, _) => { + match &item.kind { + hir::ForeignItemKind::Fn(fn_decl, _, _) => { require_c_abi_if_c_variadic(tcx, fn_decl, abi, item.span); } hir::ForeignItemKind::Static(..) => { 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 6b47f4f019d35..5f1ee9641ee3d 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -1513,8 +1513,7 @@ fn compare_synthetic_generics<'tcx>( impl<'v> intravisit::Visitor<'v> for Visitor { fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) { intravisit::walk_ty(self, ty); - if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) = - ty.kind + if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = ty.kind && let Res::Def(DefKind::TyParam, def_id) = path.res && def_id == self.1.to_def_id() { diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index 17c4d0d482f2a..82030d82f57a0 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -351,7 +351,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { } match *op { - hir::InlineAsmOperand::In { reg, ref expr } => { + hir::InlineAsmOperand::In { reg, expr } => { self.check_asm_operand_type( idx, reg, @@ -362,7 +362,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { &target_features, ); } - hir::InlineAsmOperand::Out { reg, late: _, ref expr } => { + hir::InlineAsmOperand::Out { reg, late: _, expr } => { if let Some(expr) = expr { self.check_asm_operand_type( idx, @@ -375,7 +375,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { ); } } - hir::InlineAsmOperand::InOut { reg, late: _, ref expr } => { + hir::InlineAsmOperand::InOut { reg, late: _, expr } => { self.check_asm_operand_type( idx, reg, @@ -386,7 +386,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { &target_features, ); } - hir::InlineAsmOperand::SplitInOut { reg, late: _, ref in_expr, ref out_expr } => { + hir::InlineAsmOperand::SplitInOut { reg, late: _, in_expr, out_expr } => { let in_ty = self.check_asm_operand_type( idx, reg, diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index b315ebad4686c..46cd07e4b5122 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -180,7 +180,7 @@ fn resolve_arm<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, arm: &'tcx hir visitor.terminating_scopes.insert(arm.body.hir_id.local_id); - if let Some(hir::Guard::If(ref expr)) = arm.guard { + if let Some(hir::Guard::If(expr)) = arm.guard { visitor.terminating_scopes.insert(expr.hir_id.local_id); } @@ -242,8 +242,8 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h // This ensures fixed size stacks. hir::ExprKind::Binary( source_map::Spanned { node: hir::BinOpKind::And | hir::BinOpKind::Or, .. }, - ref l, - ref r, + l, + r, ) => { // expr is a short circuiting operator (|| or &&). As its // functionality can't be overridden by traits, it always @@ -288,20 +288,20 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h terminating(r.hir_id.local_id); } } - hir::ExprKind::If(_, ref then, Some(ref otherwise)) => { + hir::ExprKind::If(_, then, Some(otherwise)) => { terminating(then.hir_id.local_id); terminating(otherwise.hir_id.local_id); } - hir::ExprKind::If(_, ref then, None) => { + hir::ExprKind::If(_, then, None) => { terminating(then.hir_id.local_id); } - hir::ExprKind::Loop(ref body, _, _, _) => { + hir::ExprKind::Loop(body, _, _, _) => { terminating(body.hir_id.local_id); } - hir::ExprKind::DropTemps(ref expr) => { + hir::ExprKind::DropTemps(expr) => { // `DropTemps(expr)` does not denote a conditional scope. // Rather, we want to achieve the same behavior as `{ let _t = expr; _t }`. terminating(expr.hir_id.local_id); @@ -396,7 +396,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h let body = visitor.tcx.hir().body(body); visitor.visit_body(body); } - hir::ExprKind::AssignOp(_, ref left_expr, ref right_expr) => { + hir::ExprKind::AssignOp(_, left_expr, right_expr) => { debug!( "resolve_expr - enabling pessimistic_yield, was previously {}", prev_pessimistic @@ -447,7 +447,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h } } - hir::ExprKind::If(ref cond, ref then, Some(ref otherwise)) => { + hir::ExprKind::If(cond, then, Some(otherwise)) => { let expr_cx = visitor.cx; visitor.enter_scope(Scope { id: then.hir_id.local_id, data: ScopeData::IfThen }); visitor.cx.var_parent = visitor.cx.parent; @@ -457,7 +457,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h visitor.visit_expr(otherwise); } - hir::ExprKind::If(ref cond, ref then, None) => { + hir::ExprKind::If(cond, then, None) => { let expr_cx = visitor.cx; visitor.enter_scope(Scope { id: then.hir_id.local_id, data: ScopeData::IfThen }); visitor.cx.var_parent = visitor.cx.parent; @@ -641,21 +641,21 @@ fn resolve_local<'tcx>( match pat.kind { PatKind::Binding(hir::BindingAnnotation(hir::ByRef::Yes, _), ..) => true, - PatKind::Struct(_, ref field_pats, _) => { + PatKind::Struct(_, field_pats, _) => { field_pats.iter().any(|fp| is_binding_pat(&fp.pat)) } - PatKind::Slice(ref pats1, ref pats2, ref pats3) => { + PatKind::Slice(pats1, pats2, pats3) => { pats1.iter().any(|p| is_binding_pat(&p)) || pats2.iter().any(|p| is_binding_pat(&p)) || pats3.iter().any(|p| is_binding_pat(&p)) } - PatKind::Or(ref subpats) - | PatKind::TupleStruct(_, ref subpats, _) - | PatKind::Tuple(ref subpats, _) => subpats.iter().any(|p| is_binding_pat(&p)), + PatKind::Or(subpats) + | PatKind::TupleStruct(_, subpats, _) + | PatKind::Tuple(subpats, _) => subpats.iter().any(|p| is_binding_pat(&p)), - PatKind::Box(ref subpat) => is_binding_pat(&subpat), + PatKind::Box(subpat) => is_binding_pat(&subpat), PatKind::Ref(_, _) | PatKind::Binding(hir::BindingAnnotation(hir::ByRef::No, _), ..) @@ -704,11 +704,11 @@ fn resolve_local<'tcx>( record_rvalue_scope_if_borrow_expr(visitor, &subexpr, blk_id); } } - hir::ExprKind::Cast(ref subexpr, _) => { + hir::ExprKind::Cast(subexpr, _) => { record_rvalue_scope_if_borrow_expr(visitor, &subexpr, blk_id) } - hir::ExprKind::Block(ref block, _) => { - if let Some(ref subexpr) = block.expr { + hir::ExprKind::Block(block, _) => { + if let Some(subexpr) = block.expr { record_rvalue_scope_if_borrow_expr(visitor, &subexpr, blk_id); } } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 49dd1eb22f7fe..d51bc7ce340a2 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -178,7 +178,7 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) { // // won't be allowed unless there's an *explicit* implementation of `Send` // for `T` - hir::ItemKind::Impl(ref impl_) => { + hir::ItemKind::Impl(impl_) => { let is_auto = tcx .impl_trait_ref(def_id) .map_or(false, |trait_ref| tcx.trait_is_auto(trait_ref.skip_binder().def_id)); @@ -224,15 +224,15 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) { hir::ItemKind::Const(ty, ..) => { check_item_type(tcx, def_id, ty.span, false); } - hir::ItemKind::Struct(_, ref ast_generics) => { + hir::ItemKind::Struct(_, ast_generics) => { check_type_defn(tcx, item, false); check_variances_for_type_defn(tcx, item, ast_generics); } - hir::ItemKind::Union(_, ref ast_generics) => { + hir::ItemKind::Union(_, ast_generics) => { check_type_defn(tcx, item, true); check_variances_for_type_defn(tcx, item, ast_generics); } - hir::ItemKind::Enum(_, ref ast_generics) => { + hir::ItemKind::Enum(_, ast_generics) => { check_type_defn(tcx, item, true); check_variances_for_type_defn(tcx, item, ast_generics); } @@ -1247,8 +1247,8 @@ fn check_impl<'tcx>( constness: hir::Constness, ) { enter_wf_checking_ctxt(tcx, item.span, item.owner_id.def_id, |wfcx| { - match *ast_trait_ref { - Some(ref ast_trait_ref) => { + match ast_trait_ref { + Some(ast_trait_ref) => { // `#[rustc_reservation_impl]` impls are not real impls and // therefore don't need to be WF (the trait's `Self: Trait` predicate // won't hold). diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 3e6dafd2c6f3a..b28b2af8a1180 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -502,12 +502,11 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn return err_info; } else if diff_fields.len() > 1 { let item = tcx.hir().expect_item(impl_did); - let span = - if let ItemKind::Impl(hir::Impl { of_trait: Some(ref t), .. }) = item.kind { - t.path.span - } else { - tcx.def_span(impl_did) - }; + let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(t), .. }) = &item.kind { + t.path.span + } else { + tcx.def_span(impl_did) + }; struct_span_err!( tcx.sess, diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index 6469f389bf91b..dfb9824094346 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -182,7 +182,7 @@ impl<'tcx> InherentCollect<'tcx> { } let item = self.tcx.hir().item(id); - let hir::ItemKind::Impl(hir::Impl { of_trait: None, self_ty: ty, ref items, .. }) = item.kind else { + let hir::ItemKind::Impl(hir::Impl { of_trait: None, self_ty: ty, items, .. }) = item.kind else { return; }; diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 0aadc9f311b03..12dd3cc6b1fc1 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -40,7 +40,7 @@ fn do_orphan_check_impl<'tcx>( let trait_def_id = trait_ref.def_id; let item = tcx.hir().expect_item(def_id); - let hir::ItemKind::Impl(ref impl_) = item.kind else { + let hir::ItemKind::Impl(impl_) = item.kind else { bug!("{:?} is not an impl: {:?}", def_id, item); }; let sp = tcx.def_span(def_id); diff --git a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs index a485768e37b83..fe6119dce8735 100644 --- a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs +++ b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs @@ -11,7 +11,7 @@ use rustc_span::def_id::LocalDefId; pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { debug_assert!(matches!(tcx.def_kind(def_id), DefKind::Impl)); let item = tcx.hir().expect_item(def_id); - let hir::ItemKind::Impl(ref impl_) = item.kind else { bug!() }; + let hir::ItemKind::Impl(impl_) = item.kind else { bug!() }; if let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) { let trait_ref = trait_ref.subst_identity(); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 093a84160fe39..7e6af7393129e 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -560,7 +560,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { debug!("convert: item {} with id {}", it.ident, it.hir_id()); let def_id = item_id.owner_id.def_id; - match it.kind { + match &it.kind { // These don't define types. hir::ItemKind::ExternCrate(_) | hir::ItemKind::Use(..) @@ -568,7 +568,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { | hir::ItemKind::Mod(_) | hir::ItemKind::GlobalAsm(_) => {} hir::ItemKind::ForeignMod { items, .. } => { - for item in items { + for item in *items { let item = tcx.hir().foreign_item(item.id); tcx.ensure().generics_of(item.owner_id); tcx.ensure().type_of(item.owner_id); @@ -618,7 +618,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { tcx.at(it.span).super_predicates_of(def_id); tcx.ensure().predicates_of(def_id); } - hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => { + hir::ItemKind::Struct(struct_def, _) | hir::ItemKind::Union(struct_def, _) => { tcx.ensure().generics_of(def_id); tcx.ensure().type_of(def_id); tcx.ensure().predicates_of(def_id); @@ -853,14 +853,14 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtDef<'_> { }; let repr = tcx.repr_options_of_def(def_id.to_def_id()); - let (kind, variants) = match item.kind { - ItemKind::Enum(ref def, _) => { + let (kind, variants) = match &item.kind { + ItemKind::Enum(def, _) => { let mut distance_from_explicit = 0; let variants = def .variants .iter() .map(|v| { - let discr = if let Some(ref e) = v.disr_expr { + let discr = if let Some(e) = &v.disr_expr { distance_from_explicit = 0; ty::VariantDiscr::Explicit(e.def_id.to_def_id()) } else { @@ -882,7 +882,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtDef<'_> { (AdtKind::Enum, variants) } - ItemKind::Struct(ref def, _) | ItemKind::Union(ref def, _) => { + ItemKind::Struct(def, _) | ItemKind::Union(def, _) => { let adt_kind = match item.kind { ItemKind::Struct(..) => AdtKind::Struct, _ => AdtKind::Union, @@ -1509,7 +1509,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( for (input, ty) in iter::zip(decl.inputs, fty.inputs().skip_binder()) { check(input, *ty) } - if let hir::FnRetTy::Return(ref ty) = decl.output { + if let hir::FnRetTy::Return(ty) = decl.output { check(ty, fty.output().skip_binder()) } } diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 9a5f447c260f5..014ee9fcc207b 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -110,12 +110,12 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { // expressions' count (i.e. `N` in `[x; N]`), and explicit // `enum` discriminants (i.e. `D` in `enum Foo { Bar = D }`), // as they shouldn't be able to cause query cycle errors. - Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. }) + Node::Expr(Expr { kind: ExprKind::Repeat(_, constant), .. }) if constant.hir_id() == hir_id => { Some(parent_def_id.to_def_id()) } - Node::Variant(Variant { disr_expr: Some(ref constant), .. }) + Node::Variant(Variant { disr_expr: Some(constant), .. }) if constant.hir_id == hir_id => { Some(parent_def_id.to_def_id()) @@ -259,7 +259,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { params.extend(ast_generics.params.iter().filter_map(|param| match param.kind { GenericParamKind::Lifetime { .. } => None, - GenericParamKind::Type { ref default, synthetic, .. } => { + GenericParamKind::Type { default, synthetic, .. } => { if default.is_some() { match allow_defaults { Defaults::Allowed => {} @@ -426,26 +426,22 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option match item.kind { - hir::TraitItemKind::Fn(ref sig, _) => { - has_late_bound_regions(tcx, &item.generics, sig.decl) - } + Node::TraitItem(item) => match &item.kind { + hir::TraitItemKind::Fn(sig, _) => has_late_bound_regions(tcx, &item.generics, sig.decl), _ => None, }, - Node::ImplItem(item) => match item.kind { - hir::ImplItemKind::Fn(ref sig, _) => { - has_late_bound_regions(tcx, &item.generics, sig.decl) - } + Node::ImplItem(item) => match &item.kind { + hir::ImplItemKind::Fn(sig, _) => has_late_bound_regions(tcx, &item.generics, sig.decl), _ => None, }, Node::ForeignItem(item) => match item.kind { - hir::ForeignItemKind::Fn(fn_decl, _, ref generics) => { + hir::ForeignItemKind::Fn(fn_decl, _, generics) => { has_late_bound_regions(tcx, generics, fn_decl) } _ => None, }, - Node::Item(item) => match item.kind { - hir::ItemKind::Fn(ref sig, .., ref generics, _) => { + Node::Item(item) => match &item.kind { + hir::ItemKind::Fn(sig, .., generics, _) => { has_late_bound_regions(tcx, generics, sig.decl) } _ => None, diff --git a/compiler/rustc_hir_analysis/src/collect/lifetimes.rs b/compiler/rustc_hir_analysis/src/collect/lifetimes.rs index 35f10dc873745..30bae50654086 100644 --- a/compiler/rustc_hir_analysis/src/collect/lifetimes.rs +++ b/compiler/rustc_hir_analysis/src/collect/lifetimes.rs @@ -428,7 +428,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { _ => {} } match item.kind { - hir::ItemKind::Fn(_, ref generics, _) => { + hir::ItemKind::Fn(_, generics, _) => { self.visit_early_late(item.hir_id(), generics, |this| { intravisit::walk_item(this, item); }); @@ -508,13 +508,13 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { this.with(scope, |this| intravisit::walk_item(this, item)) }); } - hir::ItemKind::TyAlias(_, ref generics) - | hir::ItemKind::Enum(_, ref generics) - | hir::ItemKind::Struct(_, ref generics) - | hir::ItemKind::Union(_, ref generics) - | hir::ItemKind::Trait(_, _, ref generics, ..) - | hir::ItemKind::TraitAlias(ref generics, ..) - | hir::ItemKind::Impl(hir::Impl { ref generics, .. }) => { + hir::ItemKind::TyAlias(_, generics) + | hir::ItemKind::Enum(_, generics) + | hir::ItemKind::Struct(_, generics) + | hir::ItemKind::Union(_, generics) + | hir::ItemKind::Trait(_, _, generics, ..) + | hir::ItemKind::TraitAlias(generics, ..) + | hir::ItemKind::Impl(&hir::Impl { generics, .. }) => { // These kinds of items have only early-bound lifetime parameters. let lifetimes = generics .params @@ -544,7 +544,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { match item.kind { - hir::ForeignItemKind::Fn(_, _, ref generics) => { + hir::ForeignItemKind::Fn(_, _, generics) => { self.visit_early_late(item.hir_id(), generics, |this| { intravisit::walk_foreign_item(this, item); }) @@ -561,7 +561,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { #[instrument(level = "debug", skip(self))] fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { match ty.kind { - hir::TyKind::BareFn(ref c) => { + hir::TyKind::BareFn(c) => { let (lifetimes, binders): (FxIndexMap, Vec<_>) = c .generic_params .iter() @@ -587,7 +587,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { intravisit::walk_ty(this, ty); }); } - hir::TyKind::TraitObject(bounds, ref lifetime, _) => { + hir::TyKind::TraitObject(bounds, lifetime, _) => { debug!(?bounds, ?lifetime, "TraitObject"); let scope = Scope::TraitRefBoundary { s: self.scope }; self.with(scope, |this| { @@ -617,7 +617,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { LifetimeName::Error => {} } } - hir::TyKind::Ref(ref lifetime_ref, ref mt) => { + hir::TyKind::Ref(lifetime_ref, ref mt) => { self.visit_lifetime(lifetime_ref); let scope = Scope::ObjectLifetimeDefault { lifetime: self.map.defs.get(&lifetime_ref.hir_id).cloned(), @@ -632,7 +632,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { // ^ ^ this gets resolved in the scope of // the opaque_ty generics let opaque_ty = self.tcx.hir().item(item_id); - match opaque_ty.kind { + match &opaque_ty.kind { hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. @@ -655,7 +655,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { origin: hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..), .. }) => {} - ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i), + i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i), }; // Resolve the lifetimes that are applied to the opaque type. @@ -720,7 +720,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { intravisit::walk_trait_item(this, trait_item) }); } - Type(bounds, ref ty) => { + Type(bounds, ty) => { let generics = &trait_item.generics; let lifetimes = generics .params @@ -766,7 +766,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { Fn(..) => self.visit_early_late(impl_item.hir_id(), &impl_item.generics, |this| { intravisit::walk_impl_item(this, impl_item) }), - Type(ref ty) => { + Type(ty) => { let generics = &impl_item.generics; let lifetimes: FxIndexMap = generics .params @@ -817,7 +817,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_path(&mut self, path: &hir::Path<'tcx>, _: hir::HirId) { for (i, segment) in path.segments.iter().enumerate() { let depth = path.segments.len() - i - 1; - if let Some(ref args) = segment.args { + if let Some(args) = segment.args { self.visit_segment_args(path.res, depth, args); } } @@ -833,7 +833,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { ) { let output = match fd.output { hir::FnRetTy::DefaultReturn(_) => None, - hir::FnRetTy::Return(ref ty) => Some(&**ty), + hir::FnRetTy::Return(ty) => Some(ty), }; self.visit_fn_like_elision(&fd.inputs, output, matches!(fk, intravisit::FnKind::Closure)); intravisit::walk_fn_kind(self, fk); @@ -846,13 +846,13 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { for param in generics.params { match param.kind { GenericParamKind::Lifetime { .. } => {} - GenericParamKind::Type { ref default, .. } => { - if let Some(ref ty) = default { - this.visit_ty(&ty); + GenericParamKind::Type { default, .. } => { + if let Some(ty) = default { + this.visit_ty(ty); } } - GenericParamKind::Const { ref ty, default } => { - this.visit_ty(&ty); + GenericParamKind::Const { ty, default } => { + this.visit_ty(ty); if let Some(default) = default { this.visit_body(this.tcx.hir().body(default.body)); } @@ -863,9 +863,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { match predicate { &hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { hir_id, - ref bounded_ty, + bounded_ty, bounds, - ref bound_generic_params, + bound_generic_params, origin, .. }) => { @@ -905,7 +905,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { }) } &hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate { - ref lifetime, + lifetime, bounds, .. }) => { @@ -914,7 +914,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { if lifetime.res != hir::LifetimeName::Static { for bound in bounds { - let hir::GenericBound::Outlives(ref lt) = bound else { + let hir::GenericBound::Outlives(lt) = bound else { continue; }; if lt.res != hir::LifetimeName::Static { @@ -939,8 +939,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } } &hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { - ref lhs_ty, - ref rhs_ty, + lhs_ty, + rhs_ty, .. }) => { this.visit_ty(lhs_ty); @@ -1042,7 +1042,7 @@ fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: DefId) -> ObjectLifeti } for bound in bound.bounds { - if let hir::GenericBound::Outlives(ref lifetime) = *bound { + if let hir::GenericBound::Outlives(lifetime) = bound { set.insert(lifetime.res); } } @@ -1828,7 +1828,7 @@ fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet< } } - hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => { + hir::TyKind::Path(hir::QPath::Resolved(None, path)) => { // consider only the lifetimes on the final // segment; I am not sure it's even currently // valid to have them elsewhere, but even if it diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index a7e6494c15adb..8c2ac30616823 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -85,30 +85,30 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP Node::ImplItem(item) => item.generics, Node::Item(item) => match item.kind { - ItemKind::Impl(ref impl_) => { + ItemKind::Impl(impl_) => { if impl_.defaultness.is_default() { is_default_impl_trait = tcx.impl_trait_ref(def_id).map(|t| ty::Binder::dummy(t.subst_identity())); } - &impl_.generics + impl_.generics } - ItemKind::Fn(.., ref generics, _) - | ItemKind::TyAlias(_, ref generics) - | ItemKind::Enum(_, ref generics) - | ItemKind::Struct(_, ref generics) - | ItemKind::Union(_, ref generics) => *generics, + ItemKind::Fn(.., generics, _) + | ItemKind::TyAlias(_, generics) + | ItemKind::Enum(_, generics) + | ItemKind::Struct(_, generics) + | ItemKind::Union(_, generics) => generics, - ItemKind::Trait(_, _, ref generics, ..) | ItemKind::TraitAlias(ref generics, _) => { + ItemKind::Trait(_, _, generics, ..) | ItemKind::TraitAlias(generics, _) => { is_trait = Some(ty::TraitRef::identity(tcx, def_id)); - *generics + generics } - ItemKind::OpaqueTy(OpaqueTy { ref generics, .. }) => generics, + ItemKind::OpaqueTy(OpaqueTy { generics, .. }) => generics, _ => NO_GENERICS, }, Node::ForeignItem(item) => match item.kind { ForeignItemKind::Static(..) => NO_GENERICS, - ForeignItemKind::Fn(_, _, ref generics) => *generics, + ForeignItemKind::Fn(_, _, generics) => generics, ForeignItemKind::Type => NO_GENERICS, }, @@ -350,7 +350,7 @@ fn const_evaluatable_predicates_of( let node = tcx.hir().get(hir_id); let mut collector = ConstCollector { tcx, preds: FxIndexSet::default() }; - if let hir::Node::Item(item) = node && let hir::ItemKind::Impl(ref impl_) = item.kind { + if let hir::Node::Item(item) = node && let hir::ItemKind::Impl(impl_) = item.kind { if let Some(of_trait) = &impl_.of_trait { debug!("const_evaluatable_predicates_of({:?}): visit impl trait_ref", def_id); collector.visit_trait_ref(of_trait); @@ -511,8 +511,8 @@ pub(super) fn super_predicates_that_define_assoc_type( }; let (generics, bounds) = match item.kind { - hir::ItemKind::Trait(.., ref generics, ref supertraits, _) => (generics, supertraits), - hir::ItemKind::TraitAlias(ref generics, ref supertraits) => (generics, supertraits), + hir::ItemKind::Trait(.., generics, supertraits, _) => (generics, supertraits), + hir::ItemKind::TraitAlias(generics, supertraits) => (generics, supertraits), _ => span_bug!(item.span, "super_predicates invoked on non-trait"), }; @@ -612,18 +612,18 @@ pub(super) fn type_param_predicates( Node::Item(item) => { match item.kind { - ItemKind::Fn(.., ref generics, _) - | ItemKind::Impl(hir::Impl { ref generics, .. }) - | ItemKind::TyAlias(_, ref generics) + ItemKind::Fn(.., generics, _) + | ItemKind::Impl(&hir::Impl { generics, .. }) + | ItemKind::TyAlias(_, generics) | ItemKind::OpaqueTy(OpaqueTy { - ref generics, + generics, origin: hir::OpaqueTyOrigin::TyAlias, .. }) - | ItemKind::Enum(_, ref generics) - | ItemKind::Struct(_, ref generics) - | ItemKind::Union(_, ref generics) => generics, - ItemKind::Trait(_, _, ref generics, ..) => { + | ItemKind::Enum(_, generics) + | ItemKind::Struct(_, generics) + | ItemKind::Union(_, generics) => generics, + ItemKind::Trait(_, _, generics, ..) => { // Implied `Self: Trait` and supertrait bounds. if param_id == item_hir_id { let identity_trait_ref = ty::TraitRef::identity(tcx, item_def_id); @@ -637,7 +637,7 @@ pub(super) fn type_param_predicates( } Node::ForeignItem(item) => match item.kind { - ForeignItemKind::Fn(_, _, ref generics) => generics, + ForeignItemKind::Fn(_, _, generics) => generics, _ => return result, }, @@ -681,8 +681,8 @@ impl<'tcx> ItemCtxt<'tcx> { ast_generics .predicates .iter() - .filter_map(|wp| match *wp { - hir::WherePredicate::BoundPredicate(ref bp) => Some(bp), + .filter_map(|wp| match wp { + hir::WherePredicate::BoundPredicate(bp) => Some(bp), _ => None, }) .flat_map(|bp| { diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 1f9a9f80302e3..5e388a2f2babb 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -379,7 +379,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { ForeignItemKind::Type => tcx.mk_foreign(def_id.to_def_id()), }, - Node::Ctor(&ref def) | Node::Variant(Variant { data: ref def, .. }) => match *def { + Node::Ctor(def) | Node::Variant(Variant { data: def, .. }) => match def { VariantData::Unit(..) | VariantData::Struct(..) => { tcx.type_of(tcx.hir().get_parent_item(hir_id)) } @@ -404,17 +404,17 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { Node::AnonConst(_) => { let parent_node = tcx.hir().get_parent(hir_id); match parent_node { - Node::Ty(&Ty { kind: TyKind::Array(_, ref constant), .. }) - | Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. }) + Node::Ty(Ty { kind: TyKind::Array(_, constant), .. }) + | Node::Expr(Expr { kind: ExprKind::Repeat(_, constant), .. }) if constant.hir_id() == hir_id => { tcx.types.usize } - Node::Ty(&Ty { kind: TyKind::Typeof(ref e), .. }) if e.hir_id == hir_id => { + Node::Ty(Ty { kind: TyKind::Typeof(e), .. }) if e.hir_id == hir_id => { tcx.typeck(def_id).node_type(e.hir_id) } - Node::Expr(&Expr { kind: ExprKind::ConstBlock(ref anon_const), .. }) + Node::Expr(Expr { kind: ExprKind::ConstBlock(anon_const), .. }) if anon_const.hir_id == hir_id => { let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); @@ -434,18 +434,19 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { tcx.typeck(def_id).node_type(hir_id) } - Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => { + Node::Variant(Variant { disr_expr: Some(e), .. }) if e.hir_id == hir_id => { tcx.adt_def(tcx.hir().get_parent_item(hir_id)).repr().discr_type().to_ty(tcx) } Node::TypeBinding( - binding @ &TypeBinding { + TypeBinding { hir_id: binding_id, - kind: TypeBindingKind::Equality { term: Term::Const(ref e) }, + kind: TypeBindingKind::Equality { term: Term::Const(e) }, + ident, .. }, ) if let Node::TraitRef(trait_ref) = - tcx.hir().get_parent(binding_id) + tcx.hir().get_parent(*binding_id) && e.hir_id == hir_id => { let Some(trait_def_id) = trait_ref.trait_def_id() else { @@ -454,7 +455,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { let assoc_items = tcx.associated_items(trait_def_id); let assoc_item = assoc_items.find_by_name_and_kind( tcx, - binding.ident, + *ident, ty::AssocKind::Const, def_id.to_def_id(), ); @@ -470,9 +471,9 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { } Node::TypeBinding( - binding @ &TypeBinding { hir_id: binding_id, gen_args, ref kind, .. }, + TypeBinding { hir_id: binding_id, gen_args, kind, ident, .. }, ) if let Node::TraitRef(trait_ref) = - tcx.hir().get_parent(binding_id) + tcx.hir().get_parent(*binding_id) && let Some((idx, _)) = gen_args.args.iter().enumerate().find(|(_, arg)| { if let GenericArg::Const(ct) = arg { @@ -488,7 +489,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { let assoc_items = tcx.associated_items(trait_def_id); let assoc_item = assoc_items.find_by_name_and_kind( tcx, - binding.ident, + *ident, match kind { // I think `` type bindings requires that `A` is a type TypeBindingKind::Constraint { .. } diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index 2dbfc1bc9a229..17dbb126bd1b0 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -128,7 +128,7 @@ fn diagnostic_hir_wf_check<'tcx>( }, hir::Node::Item(item) => match item.kind { hir::ItemKind::Static(ty, _, _) | hir::ItemKind::Const(ty, _) => vec![ty], - hir::ItemKind::Impl(ref impl_) => match &impl_.of_trait { + hir::ItemKind::Impl(impl_) => match &impl_.of_trait { Some(t) => t .path .segments diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 97fff85f424c3..816061c9fa006 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -219,7 +219,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { } let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); match tcx.hir().find(hir_id) { - Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, ref generics, _), .. })) => { + Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. })) => { Some(generics.where_clause_span) } _ => { @@ -241,7 +241,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { } let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); match tcx.hir().find(hir_id) { - Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(ref fn_sig, _, _), .. })) => { + Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(fn_sig, _, _), .. })) => { Some(fn_sig.decl.output.span()) } _ => { @@ -371,7 +371,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) { match start_t.kind() { ty::FnDef(..) => { if let Some(Node::Item(it)) = tcx.hir().find(start_id) { - if let hir::ItemKind::Fn(ref sig, ref generics, _) = it.kind { + if let hir::ItemKind::Fn(sig, generics, _) = &it.kind { let mut error = false; if !generics.params.is_empty() { struct_span_err!( diff --git a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs index 574b1e8b485af..9133e6540d445 100644 --- a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs @@ -727,8 +727,8 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { if let Some(parent_node) = self.tcx.hir().opt_parent_id(self.path_segment.hir_id) && let Some(parent_node) = self.tcx.hir().find(parent_node) && let hir::Node::Expr(expr) = parent_node { - match expr.kind { - hir::ExprKind::Path(ref qpath) => { + match &expr.kind { + hir::ExprKind::Path(qpath) => { self.suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path( err, qpath, diff --git a/compiler/rustc_hir_analysis/src/variance/solve.rs b/compiler/rustc_hir_analysis/src/variance/solve.rs index 97aca621aa217..f2128451611d1 100644 --- a/compiler/rustc_hir_analysis/src/variance/solve.rs +++ b/compiler/rustc_hir_analysis/src/variance/solve.rs @@ -28,8 +28,8 @@ pub fn solve_constraints<'tcx>( let ConstraintContext { terms_cx, constraints, .. } = constraints_cx; let mut solutions = vec![ty::Bivariant; terms_cx.inferred_terms.len()]; - for &(id, ref variances) in &terms_cx.lang_items { - let InferredIndex(start) = terms_cx.inferred_starts[&id]; + for (id, variances) in &terms_cx.lang_items { + let InferredIndex(start) = terms_cx.inferred_starts[id]; for (i, &variance) in variances.iter().enumerate() { solutions[start + i] = variance; } From 66751ea73e849a9afaacaa15fc1cba0cb9d6e689 Mon Sep 17 00:00:00 2001 From: Waffle Maybe Date: Mon, 9 Jan 2023 20:42:36 +0400 Subject: [PATCH 099/230] tidy rustfmt, pleaaaaase, start supporting rust Co-authored-by: nils <48135649+Nilstrieb@users.noreply.github.com> --- .../src/transform/promote_consts.rs | 2 +- .../rustc_mir_build/src/build/expr/stmt.rs | 2 +- .../src/thir/pattern/deconstruct_pat.rs | 31 +++++++++---------- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index 25f3ac7632fcd..fae6117f8f052 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -847,7 +847,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { let local_decls = &mut self.source.local_decls; let loc = candidate.location; let statement = &mut blocks[loc.block].statements[loc.statement_index]; - let StatementKind::Assign(box (_, Rvalue::Ref(region, borrow_kind, place)))= &mut statement.kind else { + let StatementKind::Assign(box (_, Rvalue::Ref(region, borrow_kind, place))) = &mut statement.kind else { bug!() }; diff --git a/compiler/rustc_mir_build/src/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs index ef502b4fa81e1..72659bbeb3ab5 100644 --- a/compiler/rustc_mir_build/src/build/expr/stmt.rs +++ b/compiler/rustc_mir_build/src/build/expr/stmt.rs @@ -113,7 +113,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // // it is usually better to focus on `the_value` rather // than the entirety of block(s) surrounding it. - let adjusted_span = + let adjusted_span = if let ExprKind::Block { block } = expr.kind && let Some(tail_ex) = this.thir[block].expr { diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index e754e2465346f..aba5429da435f 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -141,23 +141,22 @@ impl IntRange { ) -> Option { let ty = value.ty(); if let Some((target_size, bias)) = Self::integral_size_and_signed_bias(tcx, ty) { - let val = - if let mir::ConstantKind::Val(ConstValue::Scalar(scalar), _) = value { - // For this specific pattern we can skip a lot of effort and go - // straight to the result, after doing a bit of checking. (We - // could remove this branch and just fall through, which - // is more general but much slower.) - scalar.to_bits_or_ptr_internal(target_size).unwrap().left()? - } else { - if let mir::ConstantKind::Ty(c) = value - && let ty::ConstKind::Value(_) = c.kind() - { - bug!("encountered ConstValue in mir::ConstantKind::Ty, whereas this is expected to be in ConstantKind::Val"); - } + let val = if let mir::ConstantKind::Val(ConstValue::Scalar(scalar), _) = value { + // For this specific pattern we can skip a lot of effort and go + // straight to the result, after doing a bit of checking. (We + // could remove this branch and just fall through, which + // is more general but much slower.) + scalar.to_bits_or_ptr_internal(target_size).unwrap().left()? + } else { + if let mir::ConstantKind::Ty(c) = value + && let ty::ConstKind::Value(_) = c.kind() + { + bug!("encountered ConstValue in mir::ConstantKind::Ty, whereas this is expected to be in ConstantKind::Val"); + } - // This is a more general form of the previous case. - value.try_eval_bits(tcx, param_env, ty)? - }; + // This is a more general form of the previous case. + value.try_eval_bits(tcx, param_env, ty)? + }; let val = val ^ bias; Some(IntRange { range: val..=val, bias }) } else { From 98f30e833a2705fcb38d11b19ba75cd5fde723c7 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Thu, 12 Jan 2023 18:50:32 +0000 Subject: [PATCH 100/230] Undo questionable changes --- .../src/const_eval/eval_queries.rs | 2 +- .../rustc_const_eval/src/interpret/operand.rs | 2 +- .../src/interpret/projection.rs | 4 +- .../src/interpret/terminator.rs | 41 ++++++++++--------- 4 files changed, 25 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 70487f89c252a..18e01567ca35e 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -167,7 +167,7 @@ pub(super) fn op_to_const<'tcx>( } }; match immediate { - Left(mplace) => to_const_value(&mplace), + Left(ref mplace) => to_const_value(mplace), // see comment on `let try_as_immediate` above Right(imm) => match *imm { _ if imm.layout.is_zst() => ConstValue::ZeroSized, diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 2013de0d3a33d..261f95da3480f 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -535,7 +535,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { use rustc_middle::mir::Operand::*; let op = match mir_op { // FIXME: do some more logic on `move` to invalidate the old location - &(Copy(place) | Move(place)) => self.eval_place_to_op(place, layout)?, + &Copy(place) | &Move(place) => self.eval_place_to_op(place, layout)?, Constant(constant) => { let c = diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index 2a493b20e5dca..291464ab58ae2 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -87,9 +87,9 @@ where field: usize, ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { let base = match base.as_mplace_or_imm() { - Left(mplace) => { + Left(ref mplace) => { // We can reuse the mplace field computation logic for indirect operands. - let field = self.mplace_field(&mplace, field)?; + let field = self.mplace_field(mplace, field)?; return Ok(field.into()); } Right(value) => value, diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index d53a87225421e..30c6013e7aceb 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -22,20 +22,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { terminator: &mir::Terminator<'tcx>, ) -> InterpResult<'tcx> { use rustc_middle::mir::TerminatorKind::*; - match &terminator.kind { + match terminator.kind { Return => { self.pop_stack_frame(/* unwinding */ false)? } - Goto { target } => self.go_to_block(*target), + Goto { target } => self.go_to_block(target), - SwitchInt { discr, targets } => { + SwitchInt { ref discr, ref targets } => { let discr = self.read_immediate(&self.eval_operand(discr, None)?)?; trace!("SwitchInt({:?})", *discr); // Branch to the `otherwise` case by default, if no match is found. let mut target_block = targets.otherwise(); - for (const_int, target) in targets.iter() { // Compare using MIR BinOp::Eq, to also support pointer values. // (Avoiding `self.binary_op` as that does some redundant layout computation.) @@ -51,22 +50,27 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { break; } } - self.go_to_block(target_block); } - Call { func, args, destination, target, cleanup, from_hir_call: _, fn_span: _ } => { + Call { + ref func, + ref args, + destination, + target, + ref cleanup, + from_hir_call: _, + fn_span: _, + } => { let old_stack = self.frame_idx(); let old_loc = self.frame().loc; let func = self.eval_operand(func, None)?; let args = self.eval_operands(args)?; - let fn_sig_binder = func.layout.ty.fn_sig(*self.tcx); let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig_binder); let extra_args = &args[fn_sig.inputs().len()..]; let extra_args = self.tcx.mk_type_list(extra_args.iter().map(|arg| arg.layout.ty)); - let (fn_val, fn_abi, with_caller_location) = match *func.layout.ty.kind() { ty::FnPtr(_sig) => { let fn_ptr = self.read_pointer(&func)?; @@ -89,14 +93,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ), }; - let destination = self.eval_place(*destination)?; + let destination = self.eval_place(destination)?; self.eval_fn_call( fn_val, (fn_sig.abi, fn_abi), &args, with_caller_location, &destination, - *target, + target, match (cleanup, fn_abi.can_unwind) { (Some(cleanup), true) => StackPopUnwind::Cleanup(*cleanup), (None, true) => StackPopUnwind::Skip, @@ -110,7 +114,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } - &Drop { place, target, unwind } => { + Drop { place, target, unwind } => { let frame = self.frame(); let ty = place.ty(&frame.body.local_decls, *self.tcx).ty; let ty = self.subst_from_frame_and_normalize_erasing_regions(frame, ty)?; @@ -128,19 +132,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.drop_in_place(&place, instance, target, unwind)?; } - Assert { cond, expected, msg, target, cleanup } => { + Assert { ref cond, expected, ref msg, target, cleanup } => { let cond_val = self.read_scalar(&self.eval_operand(cond, None)?)?.to_bool()?; - if *expected == cond_val { - self.go_to_block(*target); + if expected == cond_val { + self.go_to_block(target); } else { - M::assert_panic(self, msg, *cleanup)?; + M::assert_panic(self, msg, cleanup)?; } } Abort => { M::abort(self, "the program aborted execution".to_owned())?; } - // When we encounter Resume, we've finished unwinding // cleanup for the current stack frame. We pop it in order // to continue unwinding the next frame @@ -151,10 +154,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.pop_stack_frame(/* unwinding */ true)?; return Ok(()); } - // It is UB to ever encounter this. Unreachable => throw_ub!(Unreachable), - // These should never occur for MIR we actually run. DropAndReplace { .. } | FalseEdge { .. } @@ -166,8 +167,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { terminator.kind ), - InlineAsm { template, operands, options, destination, .. } => { - M::eval_inline_asm(self, template, operands, *options)?; + InlineAsm { template, ref operands, options, destination, .. } => { + M::eval_inline_asm(self, template, operands, options)?; if options.contains(InlineAsmOptions::NORETURN) { throw_ub_format!("returned from noreturn inline assembly"); } From 8d3c90ae13fa5dbad9e312a7c73b334ac2d8c1d7 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Sat, 14 Jan 2023 06:29:16 +0000 Subject: [PATCH 101/230] Review suggestions --- .../rustc_const_eval/src/interpret/operand.rs | 6 ++-- .../src/check/compare_impl_item.rs | 30 +++++++++---------- .../src/traits/query/normalize.rs | 2 +- 3 files changed, 18 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 261f95da3480f..faf7e1fcb1684 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -363,11 +363,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { src: &OpTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, Either, ImmTy<'tcx, M::Provenance>>> { Ok(match src.as_mplace_or_imm() { - Left(mplace) => { - if let Some(val) = self.read_immediate_from_mplace_raw(&mplace)? { + Left(ref mplace) => { + if let Some(val) = self.read_immediate_from_mplace_raw(mplace)? { Right(val) } else { - Left(mplace) + Left(*mplace) } } Right(val) => Right(val), 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 5f1ee9641ee3d..3e0d33c64b3b3 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -1368,22 +1368,20 @@ fn compare_number_of_method_arguments<'tcx>( }) .or(trait_item_span); - let impl_span = { - let ImplItemKind::Fn(impl_m_sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind else { bug!("{:?} is not a method", impl_m) }; - let pos = impl_number_args.saturating_sub(1); - impl_m_sig - .decl - .inputs - .get(pos) - .map(|arg| { - if pos == 0 { - arg.span - } else { - arg.span.with_lo(impl_m_sig.decl.inputs[0].span.lo()) - } - }) - .unwrap_or(impl_m_span) - }; + let ImplItemKind::Fn(impl_m_sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind else { bug!("{:?} is not a method", impl_m) }; + let pos = impl_number_args.saturating_sub(1); + let impl_span = impl_m_sig + .decl + .inputs + .get(pos) + .map(|arg| { + if pos == 0 { + arg.span + } else { + arg.span.with_lo(impl_m_sig.decl.inputs[0].span.lo()) + } + }) + .unwrap_or(impl_m_span); let mut err = struct_span_err!( tcx.sess, diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 751aec48bd8c3..cea21c4f2816b 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -230,7 +230,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { if concrete_ty == ty { bug!( "infinite recursion generic_ty: {:#?}, substs: {:#?}, \ - concrete_ty: {:#?}, ty: {:#?}", + concrete_ty: {:#?}, ty: {:#?}", generic_ty, substs, concrete_ty, From c21b1f742ec403a24acc39f1c8623e1354da85c7 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Sat, 14 Jan 2023 06:47:49 +0000 Subject: [PATCH 102/230] Self review suggestions - add back accidentally removed new lines - try to deref in patterns, rather than in expressions (maybe this was the reason of perf regression?...) --- .../rustc_const_eval/src/interpret/step.rs | 48 +++++++++---------- .../src/interpret/terminator.rs | 7 +++ .../rustc_const_eval/src/interpret/visitor.rs | 4 +- .../rustc_hir_analysis/src/astconv/mod.rs | 6 +-- 4 files changed, 36 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 4bb3100757856..fad4cb06cd6fe 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -151,50 +151,50 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Also see https://github.com/rust-lang/rust/issues/68364. use rustc_middle::mir::Rvalue::*; - match rvalue { + match *rvalue { ThreadLocalRef(did) => { - let ptr = M::thread_local_static_base_pointer(self, *did)?; + let ptr = M::thread_local_static_base_pointer(self, did)?; self.write_pointer(ptr, &dest)?; } - Use(operand) => { + Use(ref operand) => { // Avoid recomputing the layout let op = self.eval_operand(operand, Some(dest.layout))?; self.copy_op(&op, &dest, /*allow_transmute*/ false)?; } CopyForDeref(place) => { - let op = self.eval_place_to_op(*place, Some(dest.layout))?; + let op = self.eval_place_to_op(place, Some(dest.layout))?; self.copy_op(&op, &dest, /* allow_transmute*/ false)?; } - BinaryOp(bin_op, box (left, right)) => { - let layout = binop_left_homogeneous(*bin_op).then_some(dest.layout); + BinaryOp(bin_op, box (ref left, ref right)) => { + let layout = binop_left_homogeneous(bin_op).then_some(dest.layout); let left = self.read_immediate(&self.eval_operand(left, layout)?)?; - let layout = binop_right_homogeneous(*bin_op).then_some(left.layout); + let layout = binop_right_homogeneous(bin_op).then_some(left.layout); let right = self.read_immediate(&self.eval_operand(right, layout)?)?; - self.binop_ignore_overflow(*bin_op, &left, &right, &dest)?; + self.binop_ignore_overflow(bin_op, &left, &right, &dest)?; } - CheckedBinaryOp(bin_op, box (left, right)) => { + CheckedBinaryOp(bin_op, box (ref left, ref right)) => { // Due to the extra boolean in the result, we can never reuse the `dest.layout`. let left = self.read_immediate(&self.eval_operand(left, None)?)?; - let layout = binop_right_homogeneous(*bin_op).then_some(left.layout); + let layout = binop_right_homogeneous(bin_op).then_some(left.layout); let right = self.read_immediate(&self.eval_operand(right, layout)?)?; self.binop_with_overflow( - *bin_op, /*force_overflow_checks*/ false, &left, &right, &dest, + bin_op, /*force_overflow_checks*/ false, &left, &right, &dest, )?; } - UnaryOp(un_op, operand) => { + UnaryOp(un_op, ref operand) => { // The operand always has the same type as the result. let val = self.read_immediate(&self.eval_operand(operand, Some(dest.layout))?)?; - let val = self.unary_op(*un_op, &val)?; + let val = self.unary_op(un_op, &val)?; assert_eq!(val.layout, dest.layout, "layout mismatch for result of {:?}", un_op); self.write_immediate(*val, &dest)?; } - Aggregate(box kind, operands) => { + Aggregate(box ref kind, ref operands) => { assert!(matches!(kind, mir::AggregateKind::Array(..))); for (field_index, operand) in operands.iter().enumerate() { @@ -204,7 +204,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } - Repeat(operand, _) => { + Repeat(ref operand, _) => { let src = self.eval_operand(operand, None)?; assert!(src.layout.is_sized()); let dest = self.force_allocation(&dest)?; @@ -241,14 +241,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } Len(place) => { - let src = self.eval_place(*place)?; + let src = self.eval_place(place)?; let op = self.place_to_op(&src)?; let len = op.len(self)?; self.write_scalar(Scalar::from_machine_usize(len, self), &dest)?; } Ref(_, borrow_kind, place) => { - let src = self.eval_place(*place)?; + let src = self.eval_place(place)?; let place = self.force_allocation(&src)?; let val = ImmTy::from_immediate(place.to_ref(self), dest.layout); // A fresh reference was created, make sure it gets retagged. @@ -274,7 +274,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { false }; - let src = self.eval_place(*place)?; + let src = self.eval_place(place)?; let place = self.force_allocation(&src)?; let mut val = ImmTy::from_immediate(place.to_ref(self), dest.layout); if !place_base_raw { @@ -285,7 +285,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } NullaryOp(null_op, ty) => { - let ty = self.subst_from_current_frame_and_normalize_erasing_regions(*ty)?; + let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty)?; let layout = self.layout_of(ty)?; if layout.is_unsized() { // FIXME: This should be a span_bug (#80742) @@ -302,21 +302,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.write_scalar(Scalar::from_machine_usize(val, self), &dest)?; } - ShallowInitBox(operand, _) => { + ShallowInitBox(ref operand, _) => { let src = self.eval_operand(operand, None)?; let v = self.read_immediate(&src)?; self.write_immediate(*v, &dest)?; } - Cast(cast_kind, operand, cast_ty) => { + Cast(cast_kind, ref operand, cast_ty) => { let src = self.eval_operand(operand, None)?; let cast_ty = - self.subst_from_current_frame_and_normalize_erasing_regions(*cast_ty)?; - self.cast(&src, *cast_kind, cast_ty, &dest)?; + self.subst_from_current_frame_and_normalize_erasing_regions(cast_ty)?; + self.cast(&src, cast_kind, cast_ty, &dest)?; } Discriminant(place) => { - let op = self.eval_place_to_op(*place, None)?; + let op = self.eval_place_to_op(place, None)?; let discr_val = self.read_discriminant(&op)?.0; self.write_scalar(discr_val, &dest)?; } diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index 30c6013e7aceb..550c7a44c4199 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -35,6 +35,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Branch to the `otherwise` case by default, if no match is found. let mut target_block = targets.otherwise(); + for (const_int, target) in targets.iter() { // Compare using MIR BinOp::Eq, to also support pointer values. // (Avoiding `self.binary_op` as that does some redundant layout computation.) @@ -50,6 +51,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { break; } } + self.go_to_block(target_block); } @@ -66,11 +68,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let old_loc = self.frame().loc; let func = self.eval_operand(func, None)?; let args = self.eval_operands(args)?; + let fn_sig_binder = func.layout.ty.fn_sig(*self.tcx); let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig_binder); let extra_args = &args[fn_sig.inputs().len()..]; let extra_args = self.tcx.mk_type_list(extra_args.iter().map(|arg| arg.layout.ty)); + let (fn_val, fn_abi, with_caller_location) = match *func.layout.ty.kind() { ty::FnPtr(_sig) => { let fn_ptr = self.read_pointer(&func)?; @@ -144,6 +148,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Abort => { M::abort(self, "the program aborted execution".to_owned())?; } + // When we encounter Resume, we've finished unwinding // cleanup for the current stack frame. We pop it in order // to continue unwinding the next frame @@ -154,8 +159,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.pop_stack_frame(/* unwinding */ true)?; return Ok(()); } + // It is UB to ever encounter this. Unreachable => throw_ub!(Unreachable), + // These should never occur for MIR we actually run. DropAndReplace { .. } | FalseEdge { .. } diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs index 2fe411c23c463..f9efc2418dbbc 100644 --- a/compiler/rustc_const_eval/src/interpret/visitor.rs +++ b/compiler/rustc_const_eval/src/interpret/visitor.rs @@ -483,8 +483,8 @@ macro_rules! make_value_visitor { // Visit the fields of this value. match &v.layout().fields { FieldsShape::Primitive => {} - FieldsShape::Union(fields) => { - self.visit_union(v, *fields)?; + &FieldsShape::Union(fields) => { + self.visit_union(v, fields)?; } FieldsShape::Arbitrary { offsets, .. } => { // FIXME: We collect in a vec because otherwise there are lifetime diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 3953fd8c5a803..42c3dbfd9a357 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -2881,13 +2881,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let opt_self_ty = maybe_qself.as_ref().map(|qself| self.ast_ty_to_ty(qself)); self.res_to_ty(opt_self_ty, path, false) } - hir::TyKind::OpaqueDef(item_id, lifetimes, in_trait) => { - let opaque_ty = tcx.hir().item(*item_id); + &hir::TyKind::OpaqueDef(item_id, lifetimes, in_trait) => { + let opaque_ty = tcx.hir().item(item_id); let def_id = item_id.owner_id.to_def_id(); match opaque_ty.kind { hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => { - self.impl_trait_ty_to_ty(def_id, lifetimes, origin, *in_trait) + self.impl_trait_ty_to_ty(def_id, lifetimes, origin, in_trait) } ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i), } From 4a6d9de8285a8e1b830b22bc2e6203304952df69 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Sat, 14 Jan 2023 14:15:40 +0000 Subject: [PATCH 103/230] Untouch back perf sensetive code :sweat_smile: --- compiler/rustc_trait_selection/src/traits/fulfill.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index ea27db7b81f87..76a755ed9e09d 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -208,12 +208,14 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { _ => { // This `for` loop was once a call to `all()`, but this lower-level // form was a perf win. See #64545 for details. - for &infer_var in &pending_obligation.stalled_on { - if self.selcx.infcx.ty_or_const_infer_var_changed(infer_var) { - return true; + (|| { + for &infer_var in &pending_obligation.stalled_on { + if self.selcx.infcx.ty_or_const_infer_var_changed(infer_var) { + return true; + } } - } - false + false + })() } } } From 65d1e8d9b556095dc50dc357e1ec4899afc3e975 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Tue, 17 Jan 2023 11:02:46 +0000 Subject: [PATCH 104/230] Hack compiletest to fix a random CI failure --- src/tools/compiletest/src/read2.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/tools/compiletest/src/read2.rs b/src/tools/compiletest/src/read2.rs index 7640e65174428..a5dc6859732a3 100644 --- a/src/tools/compiletest/src/read2.rs +++ b/src/tools/compiletest/src/read2.rs @@ -110,9 +110,18 @@ impl ProcOutput { fn into_bytes(self) -> Vec { match self { ProcOutput::Full { bytes, .. } => bytes, - ProcOutput::Abbreviated { mut head, skipped, tail } => { + ProcOutput::Abbreviated { mut head, mut skipped, tail } => { + let mut tail = &*tail; + + // Skip over '{' at the start of the tail, so we don't later wrongfully consider this as json. + // See + while tail.get(0) == Some(&b'{') { + tail = &tail[1..]; + skipped += 1; + } + write!(&mut head, "\n\n<<<<<< SKIPPED {} BYTES >>>>>>\n\n", skipped).unwrap(); - head.extend_from_slice(&tail); + head.extend_from_slice(tail); head } } From a6235a2006edf09e6eb30bac04f33eef0d2744d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Mon, 16 Jan 2023 00:00:00 +0000 Subject: [PATCH 105/230] Refactor basic blocks control flow caches --- compiler/rustc_middle/src/mir/basic_blocks.rs | 98 ++++++++++++++----- .../src/mir/graph_cyclic_cache.rs | 63 ------------ compiler/rustc_middle/src/mir/mod.rs | 3 - compiler/rustc_middle/src/mir/predecessors.rs | 78 --------------- .../rustc_middle/src/mir/switch_sources.rs | 78 --------------- compiler/rustc_middle/src/mir/traversal.rs | 50 ---------- 6 files changed, 74 insertions(+), 296 deletions(-) delete mode 100644 compiler/rustc_middle/src/mir/graph_cyclic_cache.rs delete mode 100644 compiler/rustc_middle/src/mir/predecessors.rs delete mode 100644 compiler/rustc_middle/src/mir/switch_sources.rs diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs index 752cbdeae6b25..b3354e6e9d2a2 100644 --- a/compiler/rustc_middle/src/mir/basic_blocks.rs +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -1,38 +1,44 @@ -use crate::mir::graph_cyclic_cache::GraphIsCyclicCache; -use crate::mir::predecessors::{PredecessorCache, Predecessors}; -use crate::mir::switch_sources::{SwitchSourceCache, SwitchSources}; -use crate::mir::traversal::PostorderCache; -use crate::mir::{BasicBlock, BasicBlockData, Successors, START_BLOCK}; +use crate::mir::traversal::Postorder; +use crate::mir::{BasicBlock, BasicBlockData, Successors, Terminator, TerminatorKind, START_BLOCK}; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::graph; use rustc_data_structures::graph::dominators::{dominators, Dominators}; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::sync::OnceCell; use rustc_index::vec::IndexVec; +use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; +use smallvec::SmallVec; #[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)] pub struct BasicBlocks<'tcx> { basic_blocks: IndexVec>, - predecessor_cache: PredecessorCache, - switch_source_cache: SwitchSourceCache, - is_cyclic: GraphIsCyclicCache, - postorder_cache: PostorderCache, + cache: Cache, +} + +// Typically 95%+ of basic blocks have 4 or fewer predecessors. +pub type Predecessors = IndexVec>; + +pub type SwitchSources = FxHashMap<(BasicBlock, BasicBlock), SmallVec<[Option; 1]>>; + +#[derive(Clone, Default, Debug)] +struct Cache { + predecessors: OnceCell, + switch_sources: OnceCell, + is_cyclic: OnceCell, + postorder: OnceCell>, } impl<'tcx> BasicBlocks<'tcx> { #[inline] pub fn new(basic_blocks: IndexVec>) -> Self { - BasicBlocks { - basic_blocks, - predecessor_cache: PredecessorCache::new(), - switch_source_cache: SwitchSourceCache::new(), - is_cyclic: GraphIsCyclicCache::new(), - postorder_cache: PostorderCache::new(), - } + BasicBlocks { basic_blocks, cache: Cache::default() } } /// Returns true if control-flow graph contains a cycle reachable from the `START_BLOCK`. #[inline] pub fn is_cfg_cyclic(&self) -> bool { - self.is_cyclic.is_cyclic(self) + *self.cache.is_cyclic.get_or_init(|| graph::is_cyclic(self)) } #[inline] @@ -43,20 +49,46 @@ impl<'tcx> BasicBlocks<'tcx> { /// Returns predecessors for each basic block. #[inline] pub fn predecessors(&self) -> &Predecessors { - self.predecessor_cache.compute(&self.basic_blocks) + self.cache.predecessors.get_or_init(|| { + let mut preds = IndexVec::from_elem(SmallVec::new(), &self.basic_blocks); + for (bb, data) in self.basic_blocks.iter_enumerated() { + if let Some(term) = &data.terminator { + for succ in term.successors() { + preds[succ].push(bb); + } + } + } + preds + }) } /// Returns basic blocks in a postorder. #[inline] pub fn postorder(&self) -> &[BasicBlock] { - self.postorder_cache.compute(&self.basic_blocks) + self.cache.postorder.get_or_init(|| { + Postorder::new(&self.basic_blocks, START_BLOCK).map(|(bb, _)| bb).collect() + }) } /// `switch_sources()[&(target, switch)]` returns a list of switch /// values that lead to a `target` block from a `switch` block. #[inline] pub fn switch_sources(&self) -> &SwitchSources { - self.switch_source_cache.compute(&self.basic_blocks) + self.cache.switch_sources.get_or_init(|| { + let mut switch_sources: SwitchSources = FxHashMap::default(); + for (bb, data) in self.basic_blocks.iter_enumerated() { + if let Some(Terminator { + kind: TerminatorKind::SwitchInt { targets, .. }, .. + }) = &data.terminator + { + for (value, target) in targets.iter() { + switch_sources.entry((target, bb)).or_default().push(Some(value)); + } + switch_sources.entry((targets.otherwise(), bb)).or_default().push(None); + } + } + switch_sources + }) } /// Returns mutable reference to basic blocks. Invalidates CFG cache. @@ -88,10 +120,7 @@ impl<'tcx> BasicBlocks<'tcx> { /// All other methods that allow you to mutate the basic blocks also call this method /// themselves, thereby avoiding any risk of accidentally cache invalidation. pub fn invalidate_cfg_cache(&mut self) { - self.predecessor_cache.invalidate(); - self.switch_source_cache.invalidate(); - self.is_cyclic.invalidate(); - self.postorder_cache.invalidate(); + self.cache = Cache::default(); } } @@ -145,3 +174,24 @@ impl<'tcx> graph::WithPredecessors for BasicBlocks<'tcx> { self.predecessors()[node].iter().copied() } } + +TrivialTypeTraversalAndLiftImpls! { + Cache, +} + +impl Encodable for Cache { + #[inline] + fn encode(&self, _s: &mut S) {} +} + +impl Decodable for Cache { + #[inline] + fn decode(_: &mut D) -> Self { + Default::default() + } +} + +impl HashStable for Cache { + #[inline] + fn hash_stable(&self, _: &mut CTX, _: &mut StableHasher) {} +} diff --git a/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs b/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs deleted file mode 100644 index f97bf2883b369..0000000000000 --- a/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs +++ /dev/null @@ -1,63 +0,0 @@ -use rustc_data_structures::graph::{ - self, DirectedGraph, WithNumNodes, WithStartNode, WithSuccessors, -}; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::OnceCell; -use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; - -/// Helper type to cache the result of `graph::is_cyclic`. -#[derive(Clone, Debug)] -pub(super) struct GraphIsCyclicCache { - cache: OnceCell, -} - -impl GraphIsCyclicCache { - #[inline] - pub(super) fn new() -> Self { - GraphIsCyclicCache { cache: OnceCell::new() } - } - - pub(super) fn is_cyclic(&self, graph: &G) -> bool - where - G: ?Sized + DirectedGraph + WithStartNode + WithSuccessors + WithNumNodes, - { - *self.cache.get_or_init(|| graph::is_cyclic(graph)) - } - - /// Invalidates the cache. - #[inline] - pub(super) fn invalidate(&mut self) { - // Invalidating the cache requires mutating the MIR, which in turn requires a unique - // reference (`&mut`) to the `mir::Body`. Because of this, we can assume that all - // callers of `invalidate` have a unique reference to the MIR and thus to the - // cache. This means we never need to do synchronization when `invalidate` is called, - // we can simply reinitialize the `OnceCell`. - self.cache = OnceCell::new(); - } -} - -impl Encodable for GraphIsCyclicCache { - #[inline] - fn encode(&self, s: &mut S) { - Encodable::encode(&(), s); - } -} - -impl Decodable for GraphIsCyclicCache { - #[inline] - fn decode(d: &mut D) -> Self { - let () = Decodable::decode(d); - Self::new() - } -} - -impl HashStable for GraphIsCyclicCache { - #[inline] - fn hash_stable(&self, _: &mut CTX, _: &mut StableHasher) { - // do nothing - } -} - -TrivialTypeTraversalAndLiftImpls! { - GraphIsCyclicCache, -} diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 14bdff4568f5e..0424d949cc00c 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -47,18 +47,15 @@ mod basic_blocks; pub mod coverage; mod generic_graph; pub mod generic_graphviz; -mod graph_cyclic_cache; pub mod graphviz; pub mod interpret; pub mod mono; pub mod patch; -mod predecessors; pub mod pretty; mod query; pub mod spanview; mod syntax; pub use syntax::*; -mod switch_sources; pub mod tcx; pub mod terminator; pub use terminator::*; diff --git a/compiler/rustc_middle/src/mir/predecessors.rs b/compiler/rustc_middle/src/mir/predecessors.rs deleted file mode 100644 index 5f1fadaf3bc4c..0000000000000 --- a/compiler/rustc_middle/src/mir/predecessors.rs +++ /dev/null @@ -1,78 +0,0 @@ -//! Lazily compute the reverse control-flow graph for the MIR. - -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::OnceCell; -use rustc_index::vec::IndexVec; -use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; -use smallvec::SmallVec; - -use crate::mir::{BasicBlock, BasicBlockData}; - -// Typically 95%+ of basic blocks have 4 or fewer predecessors. -pub type Predecessors = IndexVec>; - -#[derive(Clone, Debug)] -pub(super) struct PredecessorCache { - cache: OnceCell, -} - -impl PredecessorCache { - #[inline] - pub(super) fn new() -> Self { - PredecessorCache { cache: OnceCell::new() } - } - - /// Invalidates the predecessor cache. - #[inline] - pub(super) fn invalidate(&mut self) { - // Invalidating the predecessor cache requires mutating the MIR, which in turn requires a - // unique reference (`&mut`) to the `mir::Body`. Because of this, we can assume that all - // callers of `invalidate` have a unique reference to the MIR and thus to the predecessor - // cache. This means we never need to do synchronization when `invalidate` is called, we can - // simply reinitialize the `OnceCell`. - self.cache = OnceCell::new(); - } - - /// Returns the predecessor graph for this MIR. - #[inline] - pub(super) fn compute( - &self, - basic_blocks: &IndexVec>, - ) -> &Predecessors { - self.cache.get_or_init(|| { - let mut preds = IndexVec::from_elem(SmallVec::new(), basic_blocks); - for (bb, data) in basic_blocks.iter_enumerated() { - if let Some(term) = &data.terminator { - for succ in term.successors() { - preds[succ].push(bb); - } - } - } - - preds - }) - } -} - -impl Encodable for PredecessorCache { - #[inline] - fn encode(&self, _s: &mut S) {} -} - -impl Decodable for PredecessorCache { - #[inline] - fn decode(_: &mut D) -> Self { - Self::new() - } -} - -impl HashStable for PredecessorCache { - #[inline] - fn hash_stable(&self, _: &mut CTX, _: &mut StableHasher) { - // do nothing - } -} - -TrivialTypeTraversalAndLiftImpls! { - PredecessorCache, -} diff --git a/compiler/rustc_middle/src/mir/switch_sources.rs b/compiler/rustc_middle/src/mir/switch_sources.rs deleted file mode 100644 index b91c0c25782f4..0000000000000 --- a/compiler/rustc_middle/src/mir/switch_sources.rs +++ /dev/null @@ -1,78 +0,0 @@ -//! Lazily compute the inverse of each `SwitchInt`'s switch targets. Modeled after -//! `Predecessors`/`PredecessorCache`. - -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::OnceCell; -use rustc_index::vec::IndexVec; -use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; -use smallvec::SmallVec; - -use crate::mir::{BasicBlock, BasicBlockData, Terminator, TerminatorKind}; - -pub type SwitchSources = FxHashMap<(BasicBlock, BasicBlock), SmallVec<[Option; 1]>>; - -#[derive(Clone, Debug)] -pub(super) struct SwitchSourceCache { - cache: OnceCell, -} - -impl SwitchSourceCache { - #[inline] - pub(super) fn new() -> Self { - SwitchSourceCache { cache: OnceCell::new() } - } - - /// Invalidates the switch source cache. - #[inline] - pub(super) fn invalidate(&mut self) { - self.cache = OnceCell::new(); - } - - /// Returns the switch sources for this MIR. - #[inline] - pub(super) fn compute( - &self, - basic_blocks: &IndexVec>, - ) -> &SwitchSources { - self.cache.get_or_init(|| { - let mut switch_sources: SwitchSources = FxHashMap::default(); - for (bb, data) in basic_blocks.iter_enumerated() { - if let Some(Terminator { - kind: TerminatorKind::SwitchInt { targets, .. }, .. - }) = &data.terminator - { - for (value, target) in targets.iter() { - switch_sources.entry((target, bb)).or_default().push(Some(value)); - } - switch_sources.entry((targets.otherwise(), bb)).or_default().push(None); - } - } - - switch_sources - }) - } -} - -impl Encodable for SwitchSourceCache { - #[inline] - fn encode(&self, _s: &mut S) {} -} - -impl Decodable for SwitchSourceCache { - #[inline] - fn decode(_: &mut D) -> Self { - Self::new() - } -} - -impl HashStable for SwitchSourceCache { - #[inline] - fn hash_stable(&self, _: &mut CTX, _: &mut StableHasher) { - // do nothing - } -} - -TrivialTypeTraversalAndLiftImpls! { - SwitchSourceCache, -} diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs index 0b461d1ce41c5..f37222cb29758 100644 --- a/compiler/rustc_middle/src/mir/traversal.rs +++ b/compiler/rustc_middle/src/mir/traversal.rs @@ -1,7 +1,4 @@ -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::OnceCell; use rustc_index::bit_set::BitSet; -use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use super::*; @@ -339,50 +336,3 @@ pub fn reverse_postorder<'a, 'tcx>(body: &'a Body<'tcx>) -> ReversePostorderIter let len = blocks.len(); ReversePostorderIter { body, blocks, idx: len } } - -#[derive(Clone, Debug)] -pub(super) struct PostorderCache { - cache: OnceCell>, -} - -impl PostorderCache { - #[inline] - pub(super) fn new() -> Self { - PostorderCache { cache: OnceCell::new() } - } - - /// Invalidates the postorder cache. - #[inline] - pub(super) fn invalidate(&mut self) { - self.cache = OnceCell::new(); - } - - /// Returns the `&[BasicBlocks]` represents the postorder graph for this MIR. - #[inline] - pub(super) fn compute(&self, body: &IndexVec>) -> &[BasicBlock] { - self.cache.get_or_init(|| Postorder::new(body, START_BLOCK).map(|(bb, _)| bb).collect()) - } -} - -impl Encodable for PostorderCache { - #[inline] - fn encode(&self, _s: &mut S) {} -} - -impl Decodable for PostorderCache { - #[inline] - fn decode(_: &mut D) -> Self { - Self::new() - } -} - -impl HashStable for PostorderCache { - #[inline] - fn hash_stable(&self, _: &mut CTX, _: &mut StableHasher) { - // do nothing - } -} - -TrivialTypeTraversalAndLiftImpls! { - PostorderCache, -} From b7cb77fed9436918e80424a929f8b586d4795a6c Mon Sep 17 00:00:00 2001 From: nils <48135649+Nilstrieb@users.noreply.github.com> Date: Tue, 17 Jan 2023 14:00:21 +0100 Subject: [PATCH 106/230] Document how to get the type of a default associated type --- compiler/rustc_middle/src/ty/assoc.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index 55ee5bd2f810d..9fce0f3108662 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -37,6 +37,11 @@ impl AssocItem { Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap()) } + /// Gets the defaultness of the associated item. + /// To get the default associated type, use the [`type_of`] query on the + /// [`DefId`] of the type. + /// + /// [`type_of`]: crate::ty::TyCtxt::type_of pub fn defaultness(&self, tcx: TyCtxt<'_>) -> hir::Defaultness { tcx.impl_defaultness(self.def_id) } From cb00bc035be9fb3f8ce31f92de95a5eec5e2877c Mon Sep 17 00:00:00 2001 From: nils <48135649+Nilstrieb@users.noreply.github.com> Date: Tue, 17 Jan 2023 14:06:12 +0100 Subject: [PATCH 107/230] Hide `_use_mk_alias_ty_instead` in `::fmt` --- compiler/rustc_middle/src/ty/structural_impls.rs | 11 ++++++++++- compiler/rustc_middle/src/ty/sty.rs | 2 +- tests/ui/chalkify/bugs/async.stderr | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 8f64eb3e4baf6..1e43e8bf30d84 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -7,7 +7,7 @@ use crate::mir::{Field, ProjectionKind}; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer}; use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; -use crate::ty::{self, InferConst, Lift, Term, TermKind, Ty, TyCtxt}; +use crate::ty::{self, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt}; use rustc_data_structures::functor::IdFunctor; use rustc_hir::def::Namespace; use rustc_index::vec::{Idx, IndexVec}; @@ -180,6 +180,15 @@ impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> { } } +impl<'tcx> fmt::Debug for AliasTy<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("AliasTy") + .field("substs", &self.substs) + .field("def_id", &self.def_id) + .finish() + } +} + /////////////////////////////////////////////////////////////////////////// // Atomic structs // diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index e49e7e86da085..3f9e588358494 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1226,7 +1226,7 @@ impl<'tcx> FallibleTypeFolder<'tcx> for SkipBindersAt<'tcx> { /// For a projection, this would be `>::N`. /// /// For an opaque type, there is no explicit syntax. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct AliasTy<'tcx> { /// The parameters of the associated or opaque item. diff --git a/tests/ui/chalkify/bugs/async.stderr b/tests/ui/chalkify/bugs/async.stderr index d1508cb17001b..8043f1e5a0582 100644 --- a/tests/ui/chalkify/bugs/async.stderr +++ b/tests/ui/chalkify/bugs/async.stderr @@ -37,7 +37,7 @@ LL | async fn foo(x: u32) -> u32 { = help: the trait `Future` is not implemented for `[async fn body@$DIR/async.rs:23:29: 25:2]` = note: [async fn body@$DIR/async.rs:23:29: 25:2] must be a future or must implement `IntoFuture` to be awaited -error: internal compiler error: projection clauses should be implied from elsewhere. obligation: `Obligation(predicate=Binder(ProjectionPredicate(AliasTy { substs: [[async fn body@$DIR/async.rs:23:29: 25:2]], def_id: ...), _use_mk_alias_ty_instead: () }, Term::Ty(u32)), []), depth=0)` +error: internal compiler error: projection clauses should be implied from elsewhere. obligation: `Obligation(predicate=Binder(ProjectionPredicate(AliasTy { substs: [[async fn body@$DIR/async.rs:23:29: 25:2]], def_id: ...) }, Term::Ty(u32)), []), depth=0)` --> $DIR/async.rs:23:25 | LL | async fn foo(x: u32) -> u32 { From f1255380ac1cb7be1b6b0ac0eda5b1274b29eff6 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Fri, 30 Dec 2022 21:11:30 +0100 Subject: [PATCH 108/230] Add more codegen tests --- tests/codegen/abi-sysv64.rs | 4 +- tests/codegen/abi-x86-interrupt.rs | 4 +- tests/codegen/adjustments.rs | 4 +- tests/codegen/c-variadic.rs | 6 +- tests/codegen/call-llvm-intrinsics.rs | 4 +- tests/codegen/dllimports/main.rs | 10 +- tests/codegen/frame-pointer.rs | 4 +- tests/codegen/function-arguments.rs | 28 +++- tests/codegen/intrinsics/const_eval_select.rs | 4 +- tests/codegen/intrinsics/mask.rs | 5 +- tests/codegen/issue-32031.rs | 6 +- tests/codegen/issue-58881.rs | 4 +- tests/codegen/iter-repeat-n-trivial-drop.rs | 2 +- tests/codegen/loads.rs | 6 +- tests/codegen/naked-functions.rs | 4 +- tests/codegen/pic-relocation-model.rs | 6 +- tests/codegen/pie-relocation-model.rs | 6 +- tests/codegen/refs.rs | 4 +- .../codegen/sanitizer-cfi-emit-type-checks.rs | 4 +- ...mit-kcfi-operand-bundle-itanium-cxx-abi.rs | 8 +- tests/codegen/sanitizer-recover.rs | 8 +- .../some-abis-do-extend-params-to-32-bits.rs | 150 +++++++++--------- tests/codegen/static-relocation-model-msvc.rs | 4 +- tests/codegen/tuple-layout-opt.rs | 14 +- tests/codegen/vec-calloc.rs | 2 +- tests/codegen/zst-offset.rs | 4 +- 26 files changed, 166 insertions(+), 139 deletions(-) diff --git a/tests/codegen/abi-sysv64.rs b/tests/codegen/abi-sysv64.rs index e84c86b9ad04c..3c2d4e719d423 100644 --- a/tests/codegen/abi-sysv64.rs +++ b/tests/codegen/abi-sysv64.rs @@ -3,7 +3,7 @@ // of the sysv64 abi. // // needs-llvm-components: x86 -// compile-flags: -C no-prepopulate-passes --target=x86_64-unknown-linux-gnu +// compile-flags: -C no-prepopulate-passes --target=x86_64-unknown-linux-gnu -Copt-level=0 #![crate_type = "lib"] #![no_core] @@ -15,7 +15,7 @@ trait Sized {} trait Copy {} impl Copy for i64 {} -// CHECK: define x86_64_sysvcc noundef i64 @has_sysv64_abi +// CHECK: define x86_64_sysvcc i64 @has_sysv64_abi #[no_mangle] pub extern "sysv64" fn has_sysv64_abi(a: i64) -> i64 { a diff --git a/tests/codegen/abi-x86-interrupt.rs b/tests/codegen/abi-x86-interrupt.rs index 94df1cb9f78ba..928ad5a9bbd63 100644 --- a/tests/codegen/abi-x86-interrupt.rs +++ b/tests/codegen/abi-x86-interrupt.rs @@ -3,7 +3,7 @@ // of the x86-interrupt abi. // needs-llvm-components: x86 -// compile-flags: -C no-prepopulate-passes --target=x86_64-unknown-linux-gnu +// compile-flags: -C no-prepopulate-passes --target=x86_64-unknown-linux-gnu -Copt-level=0 #![crate_type = "lib"] #![no_core] @@ -15,7 +15,7 @@ trait Sized {} trait Copy {} impl Copy for i64 {} -// CHECK: define x86_intrcc noundef i64 @has_x86_interrupt_abi +// CHECK: define x86_intrcc i64 @has_x86_interrupt_abi #[no_mangle] pub extern "x86-interrupt" fn has_x86_interrupt_abi(a: i64) -> i64 { a diff --git a/tests/codegen/adjustments.rs b/tests/codegen/adjustments.rs index d09bdfa09d299..6d22475175270 100644 --- a/tests/codegen/adjustments.rs +++ b/tests/codegen/adjustments.rs @@ -1,9 +1,9 @@ -// compile-flags: -C no-prepopulate-passes +// compile-flags: -C no-prepopulate-passes -Copt-level=0 #![crate_type = "lib"] // Hack to get the correct size for the length part in slices -// CHECK: @helper([[USIZE:i[0-9]+]] noundef %_1) +// CHECK: @helper([[USIZE:i[0-9]+]] %_1) #[no_mangle] pub fn helper(_: usize) { } diff --git a/tests/codegen/c-variadic.rs b/tests/codegen/c-variadic.rs index 1f16550d3b606..cab32652210d0 100644 --- a/tests/codegen/c-variadic.rs +++ b/tests/codegen/c-variadic.rs @@ -1,5 +1,5 @@ // ignore-wasm32-bare compiled with panic=abort by default -// compile-flags: -C no-prepopulate-passes +// compile-flags: -C no-prepopulate-passes -Copt-level=0 // #![crate_type = "lib"] @@ -15,7 +15,7 @@ extern "C" { pub unsafe extern "C" fn use_foreign_c_variadic_0() { // Ensure that we correctly call foreign C-variadic functions. - // CHECK: call void (i32, ...) @foreign_c_variadic_0([[PARAM:i32 noundef( signext)?]] 0) + // CHECK: call void (i32, ...) @foreign_c_variadic_0([[PARAM:i32( signext)?]] 0) foreign_c_variadic_0(0); // CHECK: call void (i32, ...) @foreign_c_variadic_0([[PARAM]] 0, [[PARAM]] 42) foreign_c_variadic_0(0, 42i32); @@ -61,7 +61,7 @@ pub unsafe extern "C" fn c_variadic(n: i32, mut ap: ...) -> i32 { // Ensure that we generate the correct `call` signature when calling a Rust // defined C-variadic. pub unsafe fn test_c_variadic_call() { - // CHECK: call [[RET:noundef( signext)? i32]] (i32, ...) @c_variadic([[PARAM]] 0) + // CHECK: call [[RET:(signext )?i32]] (i32, ...) @c_variadic([[PARAM]] 0) c_variadic(0); // CHECK: call [[RET]] (i32, ...) @c_variadic([[PARAM]] 0, [[PARAM]] 42) c_variadic(0, 42i32); diff --git a/tests/codegen/call-llvm-intrinsics.rs b/tests/codegen/call-llvm-intrinsics.rs index 8e0327f84b4ac..cb8abae198ee6 100644 --- a/tests/codegen/call-llvm-intrinsics.rs +++ b/tests/codegen/call-llvm-intrinsics.rs @@ -1,4 +1,4 @@ -// compile-flags: -C no-prepopulate-passes +// compile-flags: -C no-prepopulate-passes -Copt-level=0 // ignore-riscv64 @@ -23,7 +23,7 @@ pub fn do_call() { unsafe { // Ensure that we `call` LLVM intrinsics instead of trying to `invoke` them - // CHECK: call noundef float @llvm.sqrt.f32(float noundef 4.000000e+00 + // CHECK: call float @llvm.sqrt.f32(float 4.000000e+00 sqrt(4.0); } } diff --git a/tests/codegen/dllimports/main.rs b/tests/codegen/dllimports/main.rs index ab599992ffd79..383940e95906d 100644 --- a/tests/codegen/dllimports/main.rs +++ b/tests/codegen/dllimports/main.rs @@ -1,4 +1,4 @@ -// This test is for *-windows-msvc only. + // This test is for *-windows-msvc only. // only-windows // ignore-gnu @@ -15,10 +15,10 @@ extern crate wrapper; // CHECK: @static_global1 = external local_unnamed_addr global i32 // CHECK: @static_global2 = external local_unnamed_addr global i32 -// CHECK: declare dllimport i32 @dylib_func1(i32) -// CHECK: declare dllimport i32 @dylib_func2(i32) -// CHECK: declare i32 @static_func1(i32) -// CHECK: declare i32 @static_func2(i32) +// CHECK: declare dllimport noundef i32 @dylib_func1(i32 noundef) +// CHECK: declare dllimport noundef i32 @dylib_func2(i32 noundef) +// CHECK: declare noundef i32 @static_func1(i32 noundef) +// CHECK: declare noundef i32 @static_func2(i32 noundef) #[link(name = "dummy", kind="dylib")] extern "C" { diff --git a/tests/codegen/frame-pointer.rs b/tests/codegen/frame-pointer.rs index da7f2ec80460c..d8933262e528e 100644 --- a/tests/codegen/frame-pointer.rs +++ b/tests/codegen/frame-pointer.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-type=rlib +// compile-flags: --crate-type=rlib -Copt-level=0 // revisions: aarch64-apple aarch64-linux force x64-apple x64-linux // [aarch64-apple] needs-llvm-components: aarch64 // [aarch64-apple] compile-flags: --target=aarch64-apple-darwin @@ -20,7 +20,7 @@ trait Copy { } impl Copy for u32 {} -// CHECK: define noundef i32 @peach{{.*}}[[PEACH_ATTRS:\#[0-9]+]] { +// CHECK: define i32 @peach{{.*}}[[PEACH_ATTRS:\#[0-9]+]] { #[no_mangle] pub fn peach(x: u32) -> u32 { x diff --git a/tests/codegen/function-arguments.rs b/tests/codegen/function-arguments.rs index 20519978a0d19..1f979d7b90a70 100644 --- a/tests/codegen/function-arguments.rs +++ b/tests/codegen/function-arguments.rs @@ -1,11 +1,11 @@ // compile-flags: -O -C no-prepopulate-passes #![crate_type = "lib"] -#![feature(rustc_attrs)] use std::mem::MaybeUninit; use std::num::NonZeroU64; use std::marker::PhantomPinned; +use std::ptr::NonNull; pub struct S { _field: [i32; 8], @@ -138,11 +138,27 @@ pub fn indirect_struct(_: S) { pub fn borrowed_struct(_: &S) { } +// CHECK: @option_borrow({{i32\*|ptr}} noalias noundef readonly align 4 dereferenceable_or_null(4) %x) +#[no_mangle] +pub fn option_borrow(x: Option<&i32>) { +} + +// CHECK: @option_borrow_mut({{i32\*|ptr}} noalias noundef align 4 dereferenceable_or_null(4) %x) +#[no_mangle] +pub fn option_borrow_mut(x: Option<&mut i32>) { +} + // CHECK: @raw_struct({{%S\*|ptr}} noundef %_1) #[no_mangle] pub fn raw_struct(_: *const S) { } +// CHECK: @raw_option_nonnull_struct({{i32\*|ptr}} noundef %_1) +#[no_mangle] +pub fn raw_option_nonnull_struct(_: Option>) { +} + + // `Box` can get deallocated during execution of the function, so it should // not get `dereferenceable`. // CHECK: noundef nonnull align 4 {{i32\*|ptr}} @_box({{i32\*|ptr}} noalias noundef nonnull align 4 %x) @@ -200,6 +216,16 @@ pub fn str(_: &[u8]) { pub fn trait_borrow(_: &dyn Drop) { } +// CHECK: @option_trait_borrow({{i8\*|ptr}} noundef align 1 %x.0, {{i8\*|ptr}} %x.1) +#[no_mangle] +pub fn option_trait_borrow(x: Option<&dyn Drop>) { +} + +// CHECK: @option_trait_borrow_mut({{i8\*|ptr}} noundef align 1 %x.0, {{i8\*|ptr}} %x.1) +#[no_mangle] +pub fn option_trait_borrow_mut(x: Option<&mut dyn Drop>) { +} + // CHECK: @trait_raw({{\{\}\*|ptr}} noundef %_1.0, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}) %_1.1) #[no_mangle] pub fn trait_raw(_: *const dyn Drop) { diff --git a/tests/codegen/intrinsics/const_eval_select.rs b/tests/codegen/intrinsics/const_eval_select.rs index 424157158f6c8..f3877dc6b96a6 100644 --- a/tests/codegen/intrinsics/const_eval_select.rs +++ b/tests/codegen/intrinsics/const_eval_select.rs @@ -1,4 +1,4 @@ -// compile-flags: -C no-prepopulate-passes +// compile-flags: -C no-prepopulate-passes -Copt-level=0 #![crate_type = "lib"] #![feature(const_eval_select)] @@ -13,6 +13,6 @@ pub fn hi(n: i32) -> i32 { n } #[no_mangle] pub unsafe fn hey() { - // CHECK: call noundef i32 @hi(i32 + // CHECK: call i32 @hi(i32 const_eval_select((42,), foo, hi); } diff --git a/tests/codegen/intrinsics/mask.rs b/tests/codegen/intrinsics/mask.rs index c7a2e4ba06dd2..8f93da2e5da43 100644 --- a/tests/codegen/intrinsics/mask.rs +++ b/tests/codegen/intrinsics/mask.rs @@ -1,11 +1,12 @@ +// compile-flags: -Copt-level=0 #![crate_type = "lib"] #![feature(core_intrinsics)] // CHECK-LABEL: @mask_ptr -// CHECK-SAME: [[WORD:i[0-9]+]] noundef %mask +// CHECK-SAME: [[WORD:i[0-9]+]] %mask #[no_mangle] pub fn mask_ptr(ptr: *const u16, mask: usize) -> *const u16 { // CHECK: call - // CHECK-SAME: @llvm.ptrmask.{{p0|p0i8}}.[[WORD]]({{ptr|i8\*}} {{%ptr|%0}}, [[WORD]] %mask) + // CHECK-SAME: @llvm.ptrmask.{{p0|p0i8}}.[[WORD]]({{ptr|i8\*}} {{%ptr|%1}}, [[WORD]] %mask) core::intrinsics::ptr_mask(ptr, mask) } diff --git a/tests/codegen/issue-32031.rs b/tests/codegen/issue-32031.rs index b181079785cf1..abef92c19b610 100644 --- a/tests/codegen/issue-32031.rs +++ b/tests/codegen/issue-32031.rs @@ -1,11 +1,11 @@ -// compile-flags: -C no-prepopulate-passes +// compile-flags: -C no-prepopulate-passes -Copt-level=0 #![crate_type = "lib"] #[no_mangle] pub struct F32(f32); -// CHECK: define{{.*}}float @add_newtype_f32(float noundef %a, float noundef %b) +// CHECK: define{{.*}}float @add_newtype_f32(float %a, float %b) #[inline(never)] #[no_mangle] pub fn add_newtype_f32(a: F32, b: F32) -> F32 { @@ -15,7 +15,7 @@ pub fn add_newtype_f32(a: F32, b: F32) -> F32 { #[no_mangle] pub struct F64(f64); -// CHECK: define{{.*}}double @add_newtype_f64(double noundef %a, double noundef %b) +// CHECK: define{{.*}}double @add_newtype_f64(double %a, double %b) #[inline(never)] #[no_mangle] pub fn add_newtype_f64(a: F64, b: F64) -> F64 { diff --git a/tests/codegen/issue-58881.rs b/tests/codegen/issue-58881.rs index 9349b78f96205..00f8953d94952 100644 --- a/tests/codegen/issue-58881.rs +++ b/tests/codegen/issue-58881.rs @@ -1,4 +1,4 @@ -// compile-flags: -C no-prepopulate-passes +// compile-flags: -C no-prepopulate-passes -Copt-level=0 // // only-x86_64 // ignore-windows @@ -16,6 +16,6 @@ struct Bar(u64, u64, u64); // Ensure that emit arguments of the correct type. pub unsafe fn test_call_variadic() { - // CHECK: call void (i32, ...) @variadic_fn(i32 noundef 0, i8 {{.*}}, {{%Bar\*|ptr}} {{.*}}) + // CHECK: call void (i32, ...) @variadic_fn(i32 0, i8 {{.*}}, {{%Bar\*|ptr}} {{.*}}) variadic_fn(0, Foo(0), Bar(0, 0, 0)) } diff --git a/tests/codegen/iter-repeat-n-trivial-drop.rs b/tests/codegen/iter-repeat-n-trivial-drop.rs index 20e1d9b4d5988..24059f190acf6 100644 --- a/tests/codegen/iter-repeat-n-trivial-drop.rs +++ b/tests/codegen/iter-repeat-n-trivial-drop.rs @@ -46,7 +46,7 @@ pub fn iter_repeat_n_next(it: &mut std::iter::RepeatN) -> Option Vec { - // CHECK: %[[ADDR:.+]] = tail call dereferenceable_or_null(1234) ptr @__rust_alloc(i64 1234, i64 1) + // CHECK: %[[ADDR:.+]] = tail call noundef dereferenceable_or_null(1234) ptr @__rust_alloc(i64 noundef 1234, i64 noundef 1) // CHECK: tail call void @llvm.memset.p0.i64(ptr noundef nonnull align 1 dereferenceable(1234) %[[ADDR]], i8 42, i64 1234, let n = 1234_usize; diff --git a/tests/codegen/loads.rs b/tests/codegen/loads.rs index 7c3bf07cc811f..f29a26596bfd5 100644 --- a/tests/codegen/loads.rs +++ b/tests/codegen/loads.rs @@ -51,7 +51,7 @@ pub fn load_scalar_pair<'a>(x: &(&'a i32, &'a Align16)) -> (&'a i32, &'a Align16 #[no_mangle] pub fn load_raw_pointer<'a>(x: &*const i32) -> *const i32 { // loaded raw pointer should not have !nonnull or !align metadata - // CHECK: load {{i32\*|ptr}}, {{i32\*\*|ptr}} %x, align [[PTR_ALIGNMENT]], !noundef !2{{$}} + // CHECK: load {{i32\*|ptr}}, {{i32\*\*|ptr}} %x, align [[PTR_ALIGNMENT]], !noundef ![[NOUNDEF:[0-9]+]]{{$}} *x } @@ -93,7 +93,7 @@ pub fn load_maybeuninit_enum_bool(x: &MaybeUninit) -> MaybeUninit u16 { - // CHECK: load i16, {{i16\*|ptr}} %x, align 2, !noundef !2{{$}} + // CHECK: load i16, {{i16\*|ptr}} %x, align 2, !noundef ![[NOUNDEF]]{{$}} *x } @@ -107,7 +107,7 @@ pub fn load_nonzero_int(x: &NonZeroU16) -> NonZeroU16 { // CHECK-LABEL: @load_option_nonzero_int #[no_mangle] pub fn load_option_nonzero_int(x: &Option) -> Option { - // CHECK: load i16, {{i16\*|ptr}} %x, align 2, !noundef !2{{$}} + // CHECK: load i16, {{i16\*|ptr}} %x, align 2, !noundef ![[NOUNDEF]]{{$}} *x } diff --git a/tests/codegen/naked-functions.rs b/tests/codegen/naked-functions.rs index 725c0a67a0060..e05bbc26e830c 100644 --- a/tests/codegen/naked-functions.rs +++ b/tests/codegen/naked-functions.rs @@ -1,4 +1,4 @@ -// compile-flags: -C no-prepopulate-passes +// compile-flags: -C no-prepopulate-passes -Copt-level=0 // needs-asm-support // only-x86_64 @@ -19,7 +19,7 @@ pub unsafe extern "C" fn naked_empty() { } // CHECK: Function Attrs: naked -// CHECK-NEXT: define{{.*}}i{{[0-9]+}} @naked_with_args_and_return(i64 noundef %a, i64 noundef %b) +// CHECK-NEXT: define{{.*}}i{{[0-9]+}} @naked_with_args_and_return(i64 %a, i64 %b) #[no_mangle] #[naked] pub unsafe extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize { diff --git a/tests/codegen/pic-relocation-model.rs b/tests/codegen/pic-relocation-model.rs index 7b4f0d9bae5d1..518e949ffe343 100644 --- a/tests/codegen/pic-relocation-model.rs +++ b/tests/codegen/pic-relocation-model.rs @@ -1,8 +1,8 @@ -// compile-flags: -C relocation-model=pic +// compile-flags: -C relocation-model=pic -Copt-level=0 #![crate_type = "rlib"] -// CHECK: define noundef i8 @call_foreign_fn() +// CHECK: define i8 @call_foreign_fn() #[no_mangle] pub fn call_foreign_fn() -> u8 { unsafe { @@ -13,7 +13,7 @@ pub fn call_foreign_fn() -> u8 { // (Allow but do not require `zeroext` here, because it is not worth effort to // spell out which targets have it and which ones do not; see rust#97800.) -// CHECK: declare noundef{{( zeroext)?}} i8 @foreign_fn() +// CHECK: declare{{( zeroext)?}} i8 @foreign_fn() extern "C" {fn foreign_fn() -> u8;} // CHECK: !{i32 {{[78]}}, !"PIC Level", i32 2} diff --git a/tests/codegen/pie-relocation-model.rs b/tests/codegen/pie-relocation-model.rs index a59216c3eee5b..941cca922bd32 100644 --- a/tests/codegen/pie-relocation-model.rs +++ b/tests/codegen/pie-relocation-model.rs @@ -1,11 +1,11 @@ -// compile-flags: -C relocation-model=pie +// compile-flags: -C relocation-model=pie -Copt-level=0 // only-x86_64-unknown-linux-gnu #![crate_type = "rlib"] // With PIE we know local functions cannot be interpositioned, we can mark them // as dso_local. -// CHECK: define dso_local noundef i8 @call_foreign_fn() +// CHECK: define dso_local i8 @call_foreign_fn() #[no_mangle] pub fn call_foreign_fn() -> u8 { unsafe { @@ -15,7 +15,7 @@ pub fn call_foreign_fn() -> u8 { // External functions are still marked as non-dso_local, since we don't know if the symbol // is defined in the binary or in the shared library. -// CHECK: declare noundef zeroext i8 @foreign_fn() +// CHECK: declare zeroext i8 @foreign_fn() extern "C" {fn foreign_fn() -> u8;} // CHECK: !{i32 {{[78]}}, !"PIC Level", i32 2} diff --git a/tests/codegen/refs.rs b/tests/codegen/refs.rs index 579fd901ee66a..a528976671110 100644 --- a/tests/codegen/refs.rs +++ b/tests/codegen/refs.rs @@ -1,9 +1,9 @@ -// compile-flags: -C no-prepopulate-passes -Zmir-opt-level=0 +// compile-flags: -C no-prepopulate-passes -Zmir-opt-level=0 -Copt-level=0 #![crate_type = "lib"] // Hack to get the correct size for the length part in slices -// CHECK: @helper([[USIZE:i[0-9]+]] noundef %_1) +// CHECK: @helper([[USIZE:i[0-9]+]] %_1) #[no_mangle] pub fn helper(_: usize) { } diff --git a/tests/codegen/sanitizer-cfi-emit-type-checks.rs b/tests/codegen/sanitizer-cfi-emit-type-checks.rs index 82334693d58ed..597b867ebad14 100644 --- a/tests/codegen/sanitizer-cfi-emit-type-checks.rs +++ b/tests/codegen/sanitizer-cfi-emit-type-checks.rs @@ -1,7 +1,7 @@ // Verifies that pointer type membership tests for indirect calls are emitted. // // needs-sanitizer-cfi -// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi +// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0 #![crate_type="lib"] @@ -11,7 +11,7 @@ pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { // CHECK: [[TT:%.+]] = call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0}}, metadata !"{{[[:print:]]+}}") // CHECK-NEXT: br i1 [[TT]], label %type_test.pass, label %type_test.fail // CHECK: type_test.pass: - // CHECK-NEXT: {{%.+}} = call noundef i32 %f(i32 noundef %arg) + // CHECK-NEXT: {{%.+}} = call i32 %f(i32 %arg) // CHECK-NEXT: br label %bb1 // CHECK: type_test.fail: // CHECK-NEXT: call void @llvm.trap() diff --git a/tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi.rs b/tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi.rs index 43e520bd6cfd8..2537df80a90b4 100644 --- a/tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi.rs +++ b/tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi.rs @@ -5,7 +5,7 @@ // [aarch64] needs-llvm-components: aarch64 // [x86_64] compile-flags: --target x86_64-unknown-none // [x86_64] needs-llvm-components: -// compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi +// compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Copt-level=0 #![crate_type="lib"] #![feature(no_core, lang_items)] @@ -21,21 +21,21 @@ impl Copy for i32 {} pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { // CHECK-LABEL: define{{.*}}foo // CHECK-SAME: {{.*}}!{{|kcfi_type}} ![[TYPE1:[0-9]+]] - // CHECK: call noundef i32 %f(i32 noundef %arg){{.*}}[ "kcfi"(i32 -1666898348) ] + // CHECK: call i32 %f(i32 %arg){{.*}}[ "kcfi"(i32 -1666898348) ] f(arg) } pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 { // CHECK-LABEL: define{{.*}}bar // CHECK-SAME: {{.*}}!{{|kcfi_type}} ![[TYPE2:[0-9]+]] - // CHECK: call noundef i32 %f(i32 noundef %arg1, i32 noundef %arg2){{.*}}[ "kcfi"(i32 -1789026986) ] + // CHECK: call i32 %f(i32 %arg1, i32 %arg2){{.*}}[ "kcfi"(i32 -1789026986) ] f(arg1, arg2) } pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 { // CHECK-LABEL: define{{.*}}baz // CHECK-SAME: {{.*}}!{{|kcfi_type}} ![[TYPE3:[0-9]+]] - // CHECK: call noundef i32 %f(i32 noundef %arg1, i32 noundef %arg2, i32 noundef %arg3){{.*}}[ "kcfi"(i32 1248878270) ] + // CHECK: call i32 %f(i32 %arg1, i32 %arg2, i32 %arg3){{.*}}[ "kcfi"(i32 1248878270) ] f(arg1, arg2, arg3) } diff --git a/tests/codegen/sanitizer-recover.rs b/tests/codegen/sanitizer-recover.rs index 899c67be6ce56..7b00fcf8e1bd7 100644 --- a/tests/codegen/sanitizer-recover.rs +++ b/tests/codegen/sanitizer-recover.rs @@ -6,8 +6,8 @@ // revisions:ASAN ASAN-RECOVER MSAN MSAN-RECOVER MSAN-RECOVER-LTO // no-prefer-dynamic // -//[ASAN] compile-flags: -Zsanitizer=address -//[ASAN-RECOVER] compile-flags: -Zsanitizer=address -Zsanitizer-recover=address +//[ASAN] compile-flags: -Zsanitizer=address -Copt-level=0 +//[ASAN-RECOVER] compile-flags: -Zsanitizer=address -Zsanitizer-recover=address -Copt-level=0 //[MSAN] compile-flags: -Zsanitizer=memory //[MSAN-RECOVER] compile-flags: -Zsanitizer=memory -Zsanitizer-recover=memory //[MSAN-RECOVER-LTO] compile-flags: -Zsanitizer=memory -Zsanitizer-recover=memory -C lto=fat @@ -16,12 +16,12 @@ // MSAN-RECOVER: @__msan_keep_going = weak_odr {{.*}}constant i32 1 // MSAN-RECOVER-LTO: @__msan_keep_going = weak_odr {{.*}}constant i32 1 -// ASAN-LABEL: define dso_local noundef i32 @penguin( +// ASAN-LABEL: define dso_local i32 @penguin( // ASAN: call void @__asan_report_load4(i64 %0) // ASAN: unreachable // ASAN: } // -// ASAN-RECOVER-LABEL: define dso_local noundef i32 @penguin( +// ASAN-RECOVER-LABEL: define dso_local i32 @penguin( // ASAN-RECOVER: call void @__asan_report_load4_noabort( // ASAN-RECOVER-NOT: unreachable // ASAN: } diff --git a/tests/codegen/some-abis-do-extend-params-to-32-bits.rs b/tests/codegen/some-abis-do-extend-params-to-32-bits.rs index 86acbfba6a0f3..9f2d9d06524f0 100644 --- a/tests/codegen/some-abis-do-extend-params-to-32-bits.rs +++ b/tests/codegen/some-abis-do-extend-params-to-32-bits.rs @@ -1,4 +1,4 @@ -// compile-flags: -Cno-prepopulate-passes +// compile-flags: -Cno-prepopulate-passes -Copt-level=0 // revisions:x86_64 i686 aarch64-apple aarch64-windows aarch64-linux arm riscv @@ -31,85 +31,85 @@ // The patterns in this file are written in the style of a table to make the // uniformities and distinctions more apparent. // -// ZERO/SIGN-EXTENDING TO 32 BITS NON-EXTENDING -// ====================================== =============================== -// x86_64: void @c_arg_u8(i8 noundef zeroext %_a) -// i686: void @c_arg_u8(i8 noundef zeroext %_a) -// aarch64-apple: void @c_arg_u8(i8 noundef zeroext %_a) -// aarch64-windows: void @c_arg_u8(i8 noundef %_a) -// aarch64-linux: void @c_arg_u8(i8 noundef %_a) -// arm: void @c_arg_u8(i8 noundef zeroext %_a) -// riscv: void @c_arg_u8(i8 noundef zeroext %_a) +// ZERO/SIGN-EXTENDING TO 32 BITS NON-EXTENDING +// ============================== ======================= +// x86_64: void @c_arg_u8(i8 zeroext %_a) +// i686: void @c_arg_u8(i8 zeroext %_a) +// aarch64-apple: void @c_arg_u8(i8 zeroext %_a) +// aarch64-windows: void @c_arg_u8(i8 %_a) +// aarch64-linux: void @c_arg_u8(i8 %_a) +// arm: void @c_arg_u8(i8 zeroext %_a) +// riscv: void @c_arg_u8(i8 zeroext %_a) #[no_mangle] pub extern "C" fn c_arg_u8(_a: u8) { } -// x86_64: void @c_arg_u16(i16 noundef zeroext %_a) -// i686: void @c_arg_u16(i16 noundef zeroext %_a) -// aarch64-apple: void @c_arg_u16(i16 noundef zeroext %_a) -// aarch64-windows: void @c_arg_u16(i16 noundef %_a) -// aarch64-linux: void @c_arg_u16(i16 noundef %_a) -// arm: void @c_arg_u16(i16 noundef zeroext %_a) -// riscv: void @c_arg_u16(i16 noundef zeroext %_a) +// x86_64: void @c_arg_u16(i16 zeroext %_a) +// i686: void @c_arg_u16(i16 zeroext %_a) +// aarch64-apple: void @c_arg_u16(i16 zeroext %_a) +// aarch64-windows: void @c_arg_u16(i16 %_a) +// aarch64-linux: void @c_arg_u16(i16 %_a) +// arm: void @c_arg_u16(i16 zeroext %_a) +// riscv: void @c_arg_u16(i16 zeroext %_a) #[no_mangle] pub extern "C" fn c_arg_u16(_a: u16) { } -// x86_64: void @c_arg_u32(i32 noundef %_a) -// i686: void @c_arg_u32(i32 noundef %_a) -// aarch64-apple: void @c_arg_u32(i32 noundef %_a) -// aarch64-windows: void @c_arg_u32(i32 noundef %_a) -// aarch64-linux: void @c_arg_u32(i32 noundef %_a) -// arm: void @c_arg_u32(i32 noundef %_a) -// riscv: void @c_arg_u32(i32 noundef signext %_a) +// x86_64: void @c_arg_u32(i32 %_a) +// i686: void @c_arg_u32(i32 %_a) +// aarch64-apple: void @c_arg_u32(i32 %_a) +// aarch64-windows: void @c_arg_u32(i32 %_a) +// aarch64-linux: void @c_arg_u32(i32 %_a) +// arm: void @c_arg_u32(i32 %_a) +// riscv: void @c_arg_u32(i32 signext %_a) #[no_mangle] pub extern "C" fn c_arg_u32(_a: u32) { } -// x86_64: void @c_arg_u64(i64 noundef %_a) -// i686: void @c_arg_u64(i64 noundef %_a) -// aarch64-apple: void @c_arg_u64(i64 noundef %_a) -// aarch64-windows: void @c_arg_u64(i64 noundef %_a) -// aarch64-linux: void @c_arg_u64(i64 noundef %_a) -// arm: void @c_arg_u64(i64 noundef %_a) -// riscv: void @c_arg_u64(i64 noundef %_a) +// x86_64: void @c_arg_u64(i64 %_a) +// i686: void @c_arg_u64(i64 %_a) +// aarch64-apple: void @c_arg_u64(i64 %_a) +// aarch64-windows: void @c_arg_u64(i64 %_a) +// aarch64-linux: void @c_arg_u64(i64 %_a) +// arm: void @c_arg_u64(i64 %_a) +// riscv: void @c_arg_u64(i64 %_a) #[no_mangle] pub extern "C" fn c_arg_u64(_a: u64) { } -// x86_64: void @c_arg_i8(i8 noundef signext %_a) -// i686: void @c_arg_i8(i8 noundef signext %_a) -// aarch64-apple: void @c_arg_i8(i8 noundef signext %_a) -// aarch64-windows: void @c_arg_i8(i8 noundef %_a) -// aarch64-linux: void @c_arg_i8(i8 noundef %_a) -// arm: void @c_arg_i8(i8 noundef signext %_a) -// riscv: void @c_arg_i8(i8 noundef signext %_a) +// x86_64: void @c_arg_i8(i8 signext %_a) +// i686: void @c_arg_i8(i8 signext %_a) +// aarch64-apple: void @c_arg_i8(i8 signext %_a) +// aarch64-windows: void @c_arg_i8(i8 %_a) +// aarch64-linux: void @c_arg_i8(i8 %_a) +// arm: void @c_arg_i8(i8 signext %_a) +// riscv: void @c_arg_i8(i8 signext %_a) #[no_mangle] pub extern "C" fn c_arg_i8(_a: i8) { } -// x86_64: void @c_arg_i16(i16 noundef signext %_a) -// i686: void @c_arg_i16(i16 noundef signext %_a) -// aarch64-apple: void @c_arg_i16(i16 noundef signext %_a) -// aarch64-windows: void @c_arg_i16(i16 noundef %_a) -// aarch64-linux: void @c_arg_i16(i16 noundef %_a) -// arm: void @c_arg_i16(i16 noundef signext %_a) -// riscv: void @c_arg_i16(i16 noundef signext %_a) +// x86_64: void @c_arg_i16(i16 signext %_a) +// i686: void @c_arg_i16(i16 signext %_a) +// aarch64-apple: void @c_arg_i16(i16 signext %_a) +// aarch64-windows: void @c_arg_i16(i16 %_a) +// aarch64-linux: void @c_arg_i16(i16 %_a) +// arm: void @c_arg_i16(i16 signext %_a) +// riscv: void @c_arg_i16(i16 signext %_a) #[no_mangle] pub extern "C" fn c_arg_i16(_a: i16) { } -// x86_64: void @c_arg_i32(i32 noundef %_a) -// i686: void @c_arg_i32(i32 noundef %_a) -// aarch64-apple: void @c_arg_i32(i32 noundef %_a) -// aarch64-windows: void @c_arg_i32(i32 noundef %_a) -// aarch64-linux: void @c_arg_i32(i32 noundef %_a) -// arm: void @c_arg_i32(i32 noundef %_a) -// riscv: void @c_arg_i32(i32 noundef signext %_a) +// x86_64: void @c_arg_i32(i32 %_a) +// i686: void @c_arg_i32(i32 %_a) +// aarch64-apple: void @c_arg_i32(i32 %_a) +// aarch64-windows: void @c_arg_i32(i32 %_a) +// aarch64-linux: void @c_arg_i32(i32 %_a) +// arm: void @c_arg_i32(i32 %_a) +// riscv: void @c_arg_i32(i32 signext %_a) #[no_mangle] pub extern "C" fn c_arg_i32(_a: i32) { } -// x86_64: void @c_arg_i64(i64 noundef %_a) -// i686: void @c_arg_i64(i64 noundef %_a) -// aarch64-apple: void @c_arg_i64(i64 noundef %_a) -// aarch64-windows: void @c_arg_i64(i64 noundef %_a) -// aarch64-linux: void @c_arg_i64(i64 noundef %_a) -// arm: void @c_arg_i64(i64 noundef %_a) -// riscv: void @c_arg_i64(i64 noundef %_a) +// x86_64: void @c_arg_i64(i64 %_a) +// i686: void @c_arg_i64(i64 %_a) +// aarch64-apple: void @c_arg_i64(i64 %_a) +// aarch64-windows: void @c_arg_i64(i64 %_a) +// aarch64-linux: void @c_arg_i64(i64 %_a) +// arm: void @c_arg_i64(i64 %_a) +// riscv: void @c_arg_i64(i64 %_a) #[no_mangle] pub extern "C" fn c_arg_i64(_a: i64) { } // x86_64: zeroext i8 @c_ret_u8() // i686: zeroext i8 @c_ret_u8() // aarch64-apple: zeroext i8 @c_ret_u8() -// aarch64-windows: i8 @c_ret_u8() -// aarch64-linux: i8 @c_ret_u8() +// aarch64-windows: i8 @c_ret_u8() +// aarch64-linux: i8 @c_ret_u8() // arm: zeroext i8 @c_ret_u8() // riscv: zeroext i8 @c_ret_u8() #[no_mangle] pub extern "C" fn c_ret_u8() -> u8 { 0 } @@ -117,8 +117,8 @@ // x86_64: zeroext i16 @c_ret_u16() // i686: zeroext i16 @c_ret_u16() // aarch64-apple: zeroext i16 @c_ret_u16() -// aarch64-windows: i16 @c_ret_u16() -// aarch64-linux: i16 @c_ret_u16() +// aarch64-windows: i16 @c_ret_u16() +// aarch64-linux: i16 @c_ret_u16() // arm: zeroext i16 @c_ret_u16() // riscv: zeroext i16 @c_ret_u16() #[no_mangle] pub extern "C" fn c_ret_u16() -> u16 { 0 } @@ -126,8 +126,8 @@ // x86_64: i32 @c_ret_u32() // i686: i32 @c_ret_u32() // aarch64-apple: i32 @c_ret_u32() -// aarch64-windows: i32 @c_ret_u32() -// aarch64-linux: i32 @c_ret_u32() +// aarch64-windows: i32 @c_ret_u32() +// aarch64-linux: i32 @c_ret_u32() // arm: i32 @c_ret_u32() // riscv: signext i32 @c_ret_u32() #[no_mangle] pub extern "C" fn c_ret_u32() -> u32 { 0 } @@ -135,8 +135,8 @@ // x86_64: i64 @c_ret_u64() // i686: i64 @c_ret_u64() // aarch64-apple: i64 @c_ret_u64() -// aarch64-windows: i64 @c_ret_u64() -// aarch64-linux: i64 @c_ret_u64() +// aarch64-windows: i64 @c_ret_u64() +// aarch64-linux: i64 @c_ret_u64() // arm: i64 @c_ret_u64() // riscv: i64 @c_ret_u64() #[no_mangle] pub extern "C" fn c_ret_u64() -> u64 { 0 } @@ -144,8 +144,8 @@ // x86_64: signext i8 @c_ret_i8() // i686: signext i8 @c_ret_i8() // aarch64-apple: signext i8 @c_ret_i8() -// aarch64-windows: i8 @c_ret_i8() -// aarch64-linux: i8 @c_ret_i8() +// aarch64-windows: i8 @c_ret_i8() +// aarch64-linux: i8 @c_ret_i8() // arm: signext i8 @c_ret_i8() // riscv: signext i8 @c_ret_i8() #[no_mangle] pub extern "C" fn c_ret_i8() -> i8 { 0 } @@ -153,8 +153,8 @@ // x86_64: signext i16 @c_ret_i16() // i686: signext i16 @c_ret_i16() // aarch64-apple: signext i16 @c_ret_i16() -// aarch64-windows: i16 @c_ret_i16() -// aarch64-linux: i16 @c_ret_i16() +// aarch64-windows: i16 @c_ret_i16() +// aarch64-linux: i16 @c_ret_i16() // arm: signext i16 @c_ret_i16() // riscv: signext i16 @c_ret_i16() #[no_mangle] pub extern "C" fn c_ret_i16() -> i16 { 0 } @@ -162,8 +162,8 @@ // x86_64: i32 @c_ret_i32() // i686: i32 @c_ret_i32() // aarch64-apple: i32 @c_ret_i32() -// aarch64-windows: i32 @c_ret_i32() -// aarch64-linux: i32 @c_ret_i32() +// aarch64-windows: i32 @c_ret_i32() +// aarch64-linux: i32 @c_ret_i32() // arm: i32 @c_ret_i32() // riscv: signext i32 @c_ret_i32() #[no_mangle] pub extern "C" fn c_ret_i32() -> i32 { 0 } @@ -171,8 +171,8 @@ // x86_64: i64 @c_ret_i64() // i686: i64 @c_ret_i64() // aarch64-apple: i64 @c_ret_i64() -// aarch64-windows: i64 @c_ret_i64() -// aarch64-linux: i64 @c_ret_i64() +// aarch64-windows: i64 @c_ret_i64() +// aarch64-linux: i64 @c_ret_i64() // arm: i64 @c_ret_i64() // riscv: i64 @c_ret_i64() #[no_mangle] pub extern "C" fn c_ret_i64() -> i64 { 0 } diff --git a/tests/codegen/static-relocation-model-msvc.rs b/tests/codegen/static-relocation-model-msvc.rs index b2afc7deb679a..735ef7081c956 100644 --- a/tests/codegen/static-relocation-model-msvc.rs +++ b/tests/codegen/static-relocation-model-msvc.rs @@ -15,8 +15,8 @@ extern crate extern_decl; // it to be marked `dso_local` as well, given the static relocation model. // // CHECK: @extern_static = external dso_local local_unnamed_addr global i8 -// CHECK: define dso_local i8 @access_extern() {{.*}} -// CHECK: declare dso_local i8 @extern_fn() {{.*}} +// CHECK: define dso_local noundef i8 @access_extern() {{.*}} +// CHECK: declare dso_local noundef i8 @extern_fn() {{.*}} #[no_mangle] pub fn access_extern() -> u8 { diff --git a/tests/codegen/tuple-layout-opt.rs b/tests/codegen/tuple-layout-opt.rs index ad33d6643c296..35f760851451e 100644 --- a/tests/codegen/tuple-layout-opt.rs +++ b/tests/codegen/tuple-layout-opt.rs @@ -1,36 +1,36 @@ // ignore-emscripten -// compile-flags: -C no-prepopulate-passes +// compile-flags: -C no-prepopulate-passes -Copt-level=0 // Test that tuples get optimized layout, in particular with a ZST in the last field (#63244) #![crate_type="lib"] type ScalarZstLast = (u128, ()); -// CHECK: define noundef i128 @test_ScalarZstLast(i128 noundef %_1) +// CHECK: define i128 @test_ScalarZstLast(i128 %_1) #[no_mangle] pub fn test_ScalarZstLast(_: ScalarZstLast) -> ScalarZstLast { loop {} } type ScalarZstFirst = ((), u128); -// CHECK: define noundef i128 @test_ScalarZstFirst(i128 noundef %_1) +// CHECK: define i128 @test_ScalarZstFirst(i128 %_1) #[no_mangle] pub fn test_ScalarZstFirst(_: ScalarZstFirst) -> ScalarZstFirst { loop {} } type ScalarPairZstLast = (u8, u128, ()); -// CHECK: define { i128, i8 } @test_ScalarPairZstLast(i128 noundef %_1.0, i8 noundef %_1.1) +// CHECK: define { i128, i8 } @test_ScalarPairZstLast(i128 %_1.0, i8 %_1.1) #[no_mangle] pub fn test_ScalarPairZstLast(_: ScalarPairZstLast) -> ScalarPairZstLast { loop {} } type ScalarPairZstFirst = ((), u8, u128); -// CHECK: define { i8, i128 } @test_ScalarPairZstFirst(i8 noundef %_1.0, i128 noundef %_1.1) +// CHECK: define { i8, i128 } @test_ScalarPairZstFirst(i8 %_1.0, i128 %_1.1) #[no_mangle] pub fn test_ScalarPairZstFirst(_: ScalarPairZstFirst) -> ScalarPairZstFirst { loop {} } type ScalarPairLotsOfZsts = ((), u8, (), u128, ()); -// CHECK: define { i128, i8 } @test_ScalarPairLotsOfZsts(i128 noundef %_1.0, i8 noundef %_1.1) +// CHECK: define { i128, i8 } @test_ScalarPairLotsOfZsts(i128 %_1.0, i8 %_1.1) #[no_mangle] pub fn test_ScalarPairLotsOfZsts(_: ScalarPairLotsOfZsts) -> ScalarPairLotsOfZsts { loop {} } type ScalarPairLottaNesting = (((), ((), u8, (), u128, ())), ()); -// CHECK: define { i128, i8 } @test_ScalarPairLottaNesting(i128 noundef %_1.0, i8 noundef %_1.1) +// CHECK: define { i128, i8 } @test_ScalarPairLottaNesting(i128 %_1.0, i8 %_1.1) #[no_mangle] pub fn test_ScalarPairLottaNesting(_: ScalarPairLottaNesting) -> ScalarPairLottaNesting { loop {} } diff --git a/tests/codegen/vec-calloc.rs b/tests/codegen/vec-calloc.rs index ae6e448f172f7..442cdd41dc66f 100644 --- a/tests/codegen/vec-calloc.rs +++ b/tests/codegen/vec-calloc.rs @@ -162,6 +162,6 @@ pub fn vec_option_bool(n: usize) -> Vec> { } // Ensure that __rust_alloc_zeroed gets the right attributes for LLVM to optimize it away. -// CHECK: declare noalias ptr @__rust_alloc_zeroed(i64, i64 allocalign) unnamed_addr [[RUST_ALLOC_ZEROED_ATTRS:#[0-9]+]] +// CHECK: declare noalias noundef ptr @__rust_alloc_zeroed(i64 noundef, i64 allocalign noundef) unnamed_addr [[RUST_ALLOC_ZEROED_ATTRS:#[0-9]+]] // CHECK-DAG: attributes [[RUST_ALLOC_ZEROED_ATTRS]] = { {{.*}} allockind("alloc,zeroed,aligned") allocsize(0) uwtable "alloc-family"="__rust_alloc" {{.*}} } diff --git a/tests/codegen/zst-offset.rs b/tests/codegen/zst-offset.rs index 27e435e9cf042..cef4b9bdaaf0a 100644 --- a/tests/codegen/zst-offset.rs +++ b/tests/codegen/zst-offset.rs @@ -1,10 +1,10 @@ -// compile-flags: -C no-prepopulate-passes +// compile-flags: -C no-prepopulate-passes -Copt-level=0 #![crate_type = "lib"] #![feature(repr_simd)] // Hack to get the correct size for the length part in slices -// CHECK: @helper([[USIZE:i[0-9]+]] noundef %_1) +// CHECK: @helper([[USIZE:i[0-9]+]] %_1) #[no_mangle] pub fn helper(_: usize) { } From 85eeaa99652973a779ac8d1ed4394d1b150527f1 Mon Sep 17 00:00:00 2001 From: Kyle Matsuda Date: Mon, 16 Jan 2023 14:50:11 -0700 Subject: [PATCH 109/230] change usages of item_bounds query to bound_item_bounds --- src/tools/clippy/clippy_utils/src/ty.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index c8d56a3be5cf3..9525c78312b45 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -648,7 +648,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs), Some(id))), ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => { - sig_from_bounds(cx, ty, cx.tcx.item_bounds(def_id), cx.tcx.opt_parent(def_id)) + sig_from_bounds(cx, ty, cx.tcx.bound_item_bounds(def_id).subst_identity(), cx.tcx.opt_parent(def_id)) }, ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)), ty::Dynamic(bounds, _, _) => { From fc942eed7fc0c8f08ff223a72a3583b93aadea99 Mon Sep 17 00:00:00 2001 From: Kyle Matsuda Date: Mon, 16 Jan 2023 15:07:23 -0700 Subject: [PATCH 110/230] change item_bounds query to return EarlyBinder; remove bound_item_bounds query --- compiler/rustc_hir_analysis/src/collect/item_bounds.rs | 10 +++++++--- compiler/rustc_infer/src/infer/outlives/verify.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/ty/util.rs | 7 ------- .../src/traits/error_reporting/suggestions.rs | 2 +- compiler/rustc_trait_selection/src/traits/project.rs | 2 +- .../src/traits/select/confirmation.rs | 5 ++--- .../rustc_trait_selection/src/traits/select/mod.rs | 2 +- src/tools/clippy/clippy_utils/src/ty.rs | 2 +- 9 files changed, 15 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 62eef710ba48f..8d479f1c3e335 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -99,12 +99,16 @@ pub(super) fn explicit_item_bounds( } } -pub(super) fn item_bounds(tcx: TyCtxt<'_>, def_id: DefId) -> &'_ ty::List> { - tcx.mk_predicates( +pub(super) fn item_bounds( + tcx: TyCtxt<'_>, + def_id: DefId, +) -> ty::EarlyBinder<&'_ ty::List>> { + let bounds = tcx.mk_predicates( util::elaborate_predicates( tcx, tcx.explicit_item_bounds(def_id).iter().map(|&(bound, _span)| bound), ) .map(|obligation| obligation.predicate), - ) + ); + ty::EarlyBinder(bounds) } diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index 66bbf47c3b6e6..56695a87b7c05 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -298,7 +298,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { substs: SubstsRef<'tcx>, ) -> impl Iterator> { let tcx = self.tcx; - let bounds = tcx.bound_item_bounds(def_id); + let bounds = tcx.item_bounds(def_id); trace!("{:#?}", bounds.0); bounds .subst_iter(tcx, substs) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index b3acf815e0c10..0ec6f481af1ff 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -272,7 +272,7 @@ rustc_queries! { /// ``` /// /// Bounds from the parent (e.g. with nested impl trait) are not included. - query item_bounds(key: DefId) -> &'tcx ty::List> { + query item_bounds(key: DefId) -> ty::EarlyBinder<&'tcx ty::List>> { desc { |tcx| "elaborating item bounds for `{}`", tcx.def_path_str(key) } } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 37d3e12a66763..d0d1dcc584f1b 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -659,13 +659,6 @@ impl<'tcx> TyCtxt<'tcx> { ty::EarlyBinder(self.explicit_item_bounds(def_id)) } - pub fn bound_item_bounds( - self, - def_id: DefId, - ) -> ty::EarlyBinder<&'tcx ty::List>> { - ty::EarlyBinder(self.item_bounds(def_id)) - } - pub fn bound_impl_subject(self, def_id: DefId) -> ty::EarlyBinder> { ty::EarlyBinder(self.impl_subject(def_id)) } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 6e2341a823b9b..b9652c25e2be2 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1123,7 +1123,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs().map_bound(|inputs| &inputs[1..]))) } ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { - self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| { + self.tcx.item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| { if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder() && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output() // args tuple will always be substs[1] diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 9c655aff0bac4..39f52ca63becf 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1375,7 +1375,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( // Check whether the self-type is itself a projection. // If so, extract what we know from the trait and try to come up with a good answer. let bounds = match *obligation.predicate.self_ty().kind() { - ty::Alias(_, ref data) => tcx.bound_item_bounds(data.def_id).subst(tcx, data.substs), + ty::Alias(_, ref data) => tcx.item_bounds(data.def_id).subst(tcx, data.substs), ty::Infer(ty::TyVar(_)) => { // If the self-type is an inference variable, then it MAY wind up // being a projected type, so induce an ambiguity. diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index d4ac461690c90..3731658525e39 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -160,8 +160,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { _ => bug!("projection candidate for unexpected type: {:?}", placeholder_self_ty), }; - let candidate_predicate = - tcx.bound_item_bounds(def_id).map_bound(|i| i[idx]).subst(tcx, substs); + let candidate_predicate = tcx.item_bounds(def_id).map_bound(|i| i[idx]).subst(tcx, substs); let candidate = candidate_predicate .to_opt_poly_trait_pred() .expect("projection candidate is not a trait predicate") @@ -510,7 +509,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // This maybe belongs in wf, but that can't (doesn't) handle // higher-ranked things. // Prevent, e.g., `dyn Iterator`. - for bound in self.tcx().bound_item_bounds(assoc_type).transpose_iter() { + for bound in self.tcx().item_bounds(assoc_type).transpose_iter() { let subst_bound = if defs.count() == 0 { bound.subst(tcx, trait_predicate.trait_ref.substs) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 95c269d1b7853..a8aff8d4f24b3 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1604,7 +1604,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); } }; - let bounds = tcx.bound_item_bounds(def_id).subst(tcx, substs); + let bounds = tcx.item_bounds(def_id).subst(tcx, substs); // The bounds returned by `item_bounds` may contain duplicates after // normalization, so try to deduplicate when possible to avoid diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 9525c78312b45..1d2a469ca6ca5 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -648,7 +648,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs), Some(id))), ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => { - sig_from_bounds(cx, ty, cx.tcx.bound_item_bounds(def_id).subst_identity(), cx.tcx.opt_parent(def_id)) + sig_from_bounds(cx, ty, cx.tcx.item_bounds(def_id).subst_identity(), cx.tcx.opt_parent(def_id)) }, ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)), ty::Dynamic(bounds, _, _) => { From f193effcaf421da090a463a49968b7bac849db2f Mon Sep 17 00:00:00 2001 From: Kyle Matsuda Date: Tue, 17 Jan 2023 08:54:07 -0700 Subject: [PATCH 111/230] fix missing subst in clippy utils --- src/tools/clippy/clippy_utils/src/ty.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 1d2a469ca6ca5..99fba4fe741a1 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -647,8 +647,8 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs), Some(id))), - ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => { - sig_from_bounds(cx, ty, cx.tcx.item_bounds(def_id).subst_identity(), cx.tcx.opt_parent(def_id)) + ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { + sig_from_bounds(cx, ty, cx.tcx.item_bounds(def_id).subst(cx.tcx, substs), cx.tcx.opt_parent(def_id)) }, ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)), ty::Dynamic(bounds, _, _) => { From d1478a5600f43637751215802d5df4541e9a005c Mon Sep 17 00:00:00 2001 From: Yiming Lei Date: Thu, 12 Jan 2023 12:28:07 -0800 Subject: [PATCH 112/230] delay E0512 as a bug by checking the references_error fix #106695 --- compiler/rustc_hir_typeck/src/intrinsicck.rs | 10 ++++++++++ tests/ui/type-alias-impl-trait/issue-53092-2.rs | 1 - .../type-alias-impl-trait/issue-53092-2.stderr | 17 ++++------------- .../no_inferrable_concrete_type.rs | 1 - .../no_inferrable_concrete_type.stderr | 12 +----------- 5 files changed, 15 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs index c2dc14024655a..3c873024c924f 100644 --- a/compiler/rustc_hir_typeck/src/intrinsicck.rs +++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs @@ -105,6 +105,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { err.note(&format!("source type: `{}` ({})", from, skeleton_string(from, sk_from))) .note(&format!("target type: `{}` ({})", to, skeleton_string(to, sk_to))); + let mut should_delay_as_bug = false; + if let Err(LayoutError::Unknown(bad_from)) = sk_from && bad_from.references_error() { + should_delay_as_bug = true; + } + if let Err(LayoutError::Unknown(bad_to)) = sk_to && bad_to.references_error() { + should_delay_as_bug = true; + } + if should_delay_as_bug { + err.delay_as_bug(); + } } err.emit(); } diff --git a/tests/ui/type-alias-impl-trait/issue-53092-2.rs b/tests/ui/type-alias-impl-trait/issue-53092-2.rs index 438ac35fdea51..057930f0c1ce7 100644 --- a/tests/ui/type-alias-impl-trait/issue-53092-2.rs +++ b/tests/ui/type-alias-impl-trait/issue-53092-2.rs @@ -4,7 +4,6 @@ type Bug = impl Fn(T) -> U + Copy; //~ ERROR cycle detected const CONST_BUG: Bug = unsafe { std::mem::transmute(|_: u8| ()) }; -//~^ ERROR: cannot transmute fn make_bug>() -> Bug { |x| x.into() //~ ERROR the trait bound `U: From` is not satisfied diff --git a/tests/ui/type-alias-impl-trait/issue-53092-2.stderr b/tests/ui/type-alias-impl-trait/issue-53092-2.stderr index 1b89d55711dbd..2565a28b49354 100644 --- a/tests/ui/type-alias-impl-trait/issue-53092-2.stderr +++ b/tests/ui/type-alias-impl-trait/issue-53092-2.stderr @@ -24,23 +24,14 @@ LL | | CONST_BUG(0); LL | | } | |_^ -error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/issue-53092-2.rs:6:41 - | -LL | const CONST_BUG: Bug = unsafe { std::mem::transmute(|_: u8| ()) }; - | ^^^^^^^^^^^^^^^^^^^ - | - = note: source type: `[closure@$DIR/issue-53092-2.rs:6:61: 6:68]` (0 bits) - = note: target type: `Bug` (size can vary because of [type error]) - error[E0277]: the trait bound `U: From` is not satisfied - --> $DIR/issue-53092-2.rs:10:5 + --> $DIR/issue-53092-2.rs:9:5 | LL | |x| x.into() | ^^^^^^^^^^^^ the trait `From` is not implemented for `U` | note: required by a bound in `make_bug` - --> $DIR/issue-53092-2.rs:9:19 + --> $DIR/issue-53092-2.rs:8:19 | LL | fn make_bug>() -> Bug { | ^^^^^^^ required by this bound in `make_bug` @@ -49,7 +40,7 @@ help: consider restricting type parameter `U` LL | type Bug> = impl Fn(T) -> U + Copy; | +++++++++++++++++++++++ -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0277, E0391, E0512. +Some errors have detailed explanations: E0277, E0391. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/type-alias-impl-trait/no_inferrable_concrete_type.rs b/tests/ui/type-alias-impl-trait/no_inferrable_concrete_type.rs index 46621362e4f73..0f0a02e97d82d 100644 --- a/tests/ui/type-alias-impl-trait/no_inferrable_concrete_type.rs +++ b/tests/ui/type-alias-impl-trait/no_inferrable_concrete_type.rs @@ -15,5 +15,4 @@ mod foo { fn main() { let _: foo::Foo = std::mem::transmute(0u8); - //~^ ERROR cannot transmute between types of different sizes, or dependently-sized types } diff --git a/tests/ui/type-alias-impl-trait/no_inferrable_concrete_type.stderr b/tests/ui/type-alias-impl-trait/no_inferrable_concrete_type.stderr index 337708b876524..f3e8ae9c7dbae 100644 --- a/tests/ui/type-alias-impl-trait/no_inferrable_concrete_type.stderr +++ b/tests/ui/type-alias-impl-trait/no_inferrable_concrete_type.stderr @@ -6,15 +6,5 @@ LL | pub type Foo = impl Copy; | = note: `Foo` must be used in combination with a concrete type within the same module -error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/no_inferrable_concrete_type.rs:17:23 - | -LL | let _: foo::Foo = std::mem::transmute(0u8); - | ^^^^^^^^^^^^^^^^^^^ - | - = note: source type: `u8` (8 bits) - = note: target type: `Foo` (size can vary because of [type error]) - -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0512`. From 148e4f73dcc4bab82d0ad1689d2900e908133614 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 14 Jan 2023 04:46:23 +0000 Subject: [PATCH 113/230] new trait solver: only consider goal changed if response is not identity --- compiler/rustc_middle/src/infer/canonical.rs | 16 ++++++++++++++++ compiler/rustc_trait_selection/src/solve/mod.rs | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 614cf1a0051da..7f3567c08be77 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -68,6 +68,22 @@ pub struct CanonicalVarValues<'tcx> { pub var_values: IndexVec>, } +impl CanonicalVarValues<'_> { + pub fn is_identity(&self) -> bool { + self.var_values.iter_enumerated().all(|(bv, arg)| match arg.unpack() { + ty::GenericArgKind::Lifetime(r) => { + matches!(*r, ty::ReLateBound(ty::INNERMOST, br) if br.var == bv) + } + ty::GenericArgKind::Type(ty) => { + matches!(*ty.kind(), ty::Bound(ty::INNERMOST, bt) if bt.var == bv) + } + ty::GenericArgKind::Const(ct) => { + matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if bc == bv) + } + }) + } +} + /// When we canonicalize a value to form a query, we wind up replacing /// various parts of it with canonical variables. This struct stores /// those replaced bits to remember for when we process the query diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 042ba96b379e0..80775b7aaf2c0 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -178,7 +178,7 @@ impl<'tcx> EvalCtxt<'tcx> { let canonical_goal = infcx.canonicalize_query(goal, &mut orig_values); let canonical_response = self.evaluate_canonical_goal(canonical_goal)?; Ok(( - true, // FIXME: check whether `var_values` are an identity substitution. + !canonical_response.value.var_values.is_identity(), instantiate_canonical_query_response(infcx, &orig_values, canonical_response), )) } From be9c363066088f0a560d181a19ee852e95da6c23 Mon Sep 17 00:00:00 2001 From: joboet Date: Tue, 17 Jan 2023 18:55:44 +0100 Subject: [PATCH 114/230] refactor[alloc]: remove unused box syntax feature --- library/alloc/tests/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index d6d2b055b2395..2a93a242d5174 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -1,7 +1,6 @@ #![feature(allocator_api)] #![feature(alloc_layout_extra)] #![feature(assert_matches)] -#![feature(box_syntax)] #![feature(btree_drain_filter)] #![feature(cow_is_borrowed)] #![feature(const_box)] From 273c6c3913e4d32c3321a3c92fb2ce32c1db9cb8 Mon Sep 17 00:00:00 2001 From: Markus Everling Date: Tue, 17 Jan 2023 19:38:37 +0100 Subject: [PATCH 115/230] Add heapsort fallback in `select_nth_unstable` --- library/core/src/slice/sort.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs index 4d2fcd917849c..3ac01d1727513 100644 --- a/library/core/src/slice/sort.rs +++ b/library/core/src/slice/sort.rs @@ -831,6 +831,15 @@ fn partition_at_index_loop<'a, T, F>( ) where F: FnMut(&T, &T) -> bool, { + // Limit the amount of iterations and fall back to heapsort, similarly to `slice::sort_unstable`. + // This lowers the worst case running time from O(n^2) to O(n log n). + // FIXME: Investigate whether it would be better to use something like Median of Medians + // or Fast Deterministic Selection to guarantee O(n) worst case. + let mut limit = usize::BITS - v.len().leading_zeros(); + + // True if the last partitioning was reasonably balanced. + let mut was_balanced = true; + loop { // For slices of up to this length it's probably faster to simply sort them. const MAX_INSERTION: usize = 10; @@ -839,6 +848,18 @@ fn partition_at_index_loop<'a, T, F>( return; } + if limit == 0 { + heapsort(v, is_less); + return; + } + + // If the last partitioning was imbalanced, try breaking patterns in the slice by shuffling + // some elements around. Hopefully we'll choose a better pivot this time. + if !was_balanced { + break_patterns(v); + limit -= 1; + } + // Choose a pivot let (pivot, _) = choose_pivot(v, is_less); @@ -863,6 +884,7 @@ fn partition_at_index_loop<'a, T, F>( } let (mid, _) = partition(v, pivot, is_less); + was_balanced = cmp::min(mid, v.len() - mid) >= v.len() / 8; // Split the slice into `left`, `pivot`, and `right`. let (left, right) = v.split_at_mut(mid); From 54089e6390e4dd179f35438bd46099fb09854427 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 17 Jan 2023 11:49:36 -0700 Subject: [PATCH 116/230] rustdoc: instead of `.setting-name { width: 100% }`, use default div CSS --- src/librustdoc/html/static/css/settings.css | 4 ---- src/librustdoc/html/static/js/settings.js | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/librustdoc/html/static/css/settings.css b/src/librustdoc/html/static/css/settings.css index 91419093147d7..3fa478751737f 100644 --- a/src/librustdoc/html/static/css/settings.css +++ b/src/librustdoc/html/static/css/settings.css @@ -33,10 +33,6 @@ padding-bottom: 1px; } -.radio-line .setting-name { - width: 100%; -} - .radio-line .choice { margin-top: 0.1em; margin-bottom: 0.1em; diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js index 9ed8f63610ff6..84df1b7d3911a 100644 --- a/src/librustdoc/html/static/js/settings.js +++ b/src/librustdoc/html/static/js/settings.js @@ -135,7 +135,7 @@ // This is a select setting. output += `\
- ${setting_name} +
${setting_name}
`; onEach(setting["options"], option => { const checked = option === setting["default"] ? " checked" : ""; From 1216cc7f1c7762bd82afeeb6ec22121f57980e80 Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Tue, 17 Jan 2023 19:35:19 +0100 Subject: [PATCH 117/230] bump failing assembly & codegen tests from LLVM 14 to LLVM 15 --- tests/assembly/is_aligned.rs | 2 +- tests/codegen/issue-96497-slice-size-nowrap.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/assembly/is_aligned.rs b/tests/assembly/is_aligned.rs index 04b5de8342370..620a3da94636e 100644 --- a/tests/assembly/is_aligned.rs +++ b/tests/assembly/is_aligned.rs @@ -1,5 +1,5 @@ // assembly-output: emit-asm -// min-llvm-version: 14.0 +// min-llvm-version: 15.0 // only-x86_64 // revisions: opt-speed opt-size // [opt-speed] compile-flags: -Copt-level=1 diff --git a/tests/codegen/issue-96497-slice-size-nowrap.rs b/tests/codegen/issue-96497-slice-size-nowrap.rs index a5dbef9346027..0413ed6b26f36 100644 --- a/tests/codegen/issue-96497-slice-size-nowrap.rs +++ b/tests/codegen/issue-96497-slice-size-nowrap.rs @@ -3,7 +3,7 @@ // in some situations, see https://github.com/rust-lang/rust/issues/96497#issuecomment-1112865218 // compile-flags: -O -// min-llvm-version: 14.0 +// min-llvm-version: 15.0 #![crate_type="lib"] From a242a2c6ade769b4986dff36c8d62cb22db59f75 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 17 Jan 2023 12:09:38 -0700 Subject: [PATCH 118/230] rustdoc: add test cases for settings radio button layout --- tests/rustdoc-gui/settings.goml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/rustdoc-gui/settings.goml b/tests/rustdoc-gui/settings.goml index f236dc3e0fe76..72de41e41bae1 100644 --- a/tests/rustdoc-gui/settings.goml +++ b/tests/rustdoc-gui/settings.goml @@ -105,6 +105,33 @@ assert-css: ( "box-shadow": "rgb(33, 150, 243) 0px 0px 1px 1px", }, ) +// Now we check the setting-name for radio buttons is on a different line than the label. +compare-elements-position-near: ( + "#theme .setting-name", + "#theme .choices", + {"x": 1} +) +compare-elements-position-near-false: ( + "#theme .setting-name", + "#theme .choices", + {"y": 1} +) +// Now we check that the label positions are all on the same line. +compare-elements-position-near: ( + "#theme .choices #theme-light", + "#theme .choices #theme-dark", + {"y": 1} +) +compare-elements-position-near: ( + "#theme .choices #theme-dark", + "#theme .choices #theme-ayu", + {"y": 1} +) +compare-elements-position-near: ( + "#theme .choices #theme-ayu", + "#theme .choices #theme-system-preference", + {"y": 1} +) // First we check the "default" display for toggles. assert-css: ( From aadd58ef7a78c3eabc75c73db6b166debdd7f1d2 Mon Sep 17 00:00:00 2001 From: yanchen4791 Date: Wed, 11 Jan 2023 00:19:40 -0800 Subject: [PATCH 119/230] Add 'static lifetime suggestion when GAT implied 'static requirement from HRTB --- .../src/diagnostics/region_errors.rs | 117 +++++++++++++++++- .../rustc_borrowck/src/region_infer/mod.rs | 8 ++ compiler/rustc_middle/src/ty/sty.rs | 7 ++ .../collectivity-regression.stderr | 10 ++ tests/ui/lifetimes/issue-105507.fixed | 43 +++++++ tests/ui/lifetimes/issue-105507.rs | 43 +++++++ tests/ui/lifetimes/issue-105507.stderr | 34 +++++ 7 files changed, 258 insertions(+), 4 deletions(-) create mode 100644 tests/ui/lifetimes/issue-105507.fixed create mode 100644 tests/ui/lifetimes/issue-105507.rs create mode 100644 tests/ui/lifetimes/issue-105507.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index f3050a6ef3f07..187861ba127bd 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -5,8 +5,13 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; +use rustc_hir::def::Res::Def; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; +use rustc_hir::GenericBound::Trait; +use rustc_hir::QPath::Resolved; +use rustc_hir::WherePredicate::BoundPredicate; +use rustc_hir::{PolyTraitRef, TyKind, WhereBoundPredicate}; use rustc_infer::infer::{ error_reporting::nice_region_error::{ self, find_anon_type, find_param_with_region, suggest_adding_lifetime_params, @@ -186,6 +191,101 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { false } + // For generic associated types (GATs) which implied 'static requirement + // from higher-ranked trait bounds (HRTB). Try to locate span of the trait + // and the span which bounded to the trait for adding 'static lifetime suggestion + fn suggest_static_lifetime_for_gat_from_hrtb( + &self, + diag: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, + lower_bound: RegionVid, + ) { + let mut suggestions = vec![]; + let hir = self.infcx.tcx.hir(); + + // find generic associated types in the given region 'lower_bound' + let gat_id_and_generics = self + .regioncx + .placeholders_contained_in(lower_bound) + .map(|placeholder| { + if let Some(id) = placeholder.name.get_id() + && let Some(placeholder_id) = id.as_local() + && let gat_hir_id = hir.local_def_id_to_hir_id(placeholder_id) + && let Some(generics_impl) = hir.get_parent(gat_hir_id).generics() + { + Some((gat_hir_id, generics_impl)) + } else { + None + } + }) + .collect::>(); + debug!(?gat_id_and_generics); + + // find higher-ranked trait bounds bounded to the generic associated types + let mut hrtb_bounds = vec![]; + gat_id_and_generics.iter().flatten().for_each(|(gat_hir_id, generics)| { + for pred in generics.predicates { + let BoundPredicate( + WhereBoundPredicate { + bound_generic_params, + bounds, + .. + }) = pred else { continue; }; + if bound_generic_params + .iter() + .rfind(|bgp| hir.local_def_id_to_hir_id(bgp.def_id) == *gat_hir_id) + .is_some() + { + for bound in *bounds { + hrtb_bounds.push(bound); + } + } + } + }); + debug!(?hrtb_bounds); + + hrtb_bounds.iter().for_each(|bound| { + let Trait(PolyTraitRef { trait_ref, span: trait_span, .. }, _) = bound else { return; }; + diag.span_note( + *trait_span, + format!("due to current limitations in the borrow checker, this implies a `'static` lifetime") + ); + let Some(generics_fn) = hir.get_generics(self.body.source.def_id().expect_local()) else { return; }; + let Def(_, trait_res_defid) = trait_ref.path.res else { return; }; + debug!(?generics_fn); + generics_fn.predicates.iter().for_each(|predicate| { + let BoundPredicate( + WhereBoundPredicate { + span: bounded_span, + bounded_ty, + bounds, + .. + } + ) = predicate else { return; }; + bounds.iter().for_each(|bd| { + if let Trait(PolyTraitRef { trait_ref: tr_ref, .. }, _) = bd + && let Def(_, res_defid) = tr_ref.path.res + && res_defid == trait_res_defid // trait id matches + && let TyKind::Path(Resolved(_, path)) = bounded_ty.kind + && let Def(_, defid) = path.res + && generics_fn.params + .iter() + .rfind(|param| param.def_id.to_def_id() == defid) + .is_some() { + suggestions.push((bounded_span.shrink_to_hi(), format!(" + 'static"))); + } + }); + }); + }); + if suggestions.len() > 0 { + suggestions.dedup(); + diag.multipart_suggestion_verbose( + format!("consider restricting the type parameter to the `'static` lifetime"), + suggestions, + Applicability::MaybeIncorrect, + ); + } + } + /// Produces nice borrowck error diagnostics for all the errors collected in `nll_errors`. pub(crate) fn report_region_errors(&mut self, nll_errors: RegionErrors<'tcx>) { // Iterate through all the errors, producing a diagnostic for each one. The diagnostics are @@ -223,12 +323,21 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // to report it; we could probably handle it by // iterating over the universal regions and reporting // an error that multiple bounds are required. - self.buffer_error(self.infcx.tcx.sess.create_err( - GenericDoesNotLiveLongEnough { + let mut diag = + self.infcx.tcx.sess.create_err(GenericDoesNotLiveLongEnough { kind: type_test.generic_kind.to_string(), span: type_test_span, - }, - )); + }); + + // Add notes and suggestions for the case of 'static lifetime + // implied but not specified when a generic associated types + // are from higher-ranked trait bounds + self.suggest_static_lifetime_for_gat_from_hrtb( + &mut diag, + type_test.lower_bound, + ); + + self.buffer_error(diag); } } diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 308f6e19a73e8..7eae52bca5896 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -527,6 +527,14 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.scc_values.region_value_str(scc) } + pub(crate) fn placeholders_contained_in<'a>( + &'a self, + r: RegionVid, + ) -> impl Iterator + 'a { + let scc = self.constraint_sccs.scc(r.to_region_vid()); + self.scc_values.placeholders_contained_in(scc) + } + /// Returns access to the value of `r` for debugging purposes. pub(crate) fn region_universe(&self, r: RegionVid) -> ty::UniverseIndex { let scc = self.constraint_sccs.scc(r.to_region_vid()); diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index e49e7e86da085..ce2f03679e042 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -100,6 +100,13 @@ impl BoundRegionKind { None } + + pub fn get_id(&self) -> Option { + match *self { + BoundRegionKind::BrNamed(id, _) => return Some(id), + _ => None, + } + } } pub trait Article { diff --git a/tests/ui/generic-associated-types/collectivity-regression.stderr b/tests/ui/generic-associated-types/collectivity-regression.stderr index 1dbe1e2cb2245..a085096e1f8c5 100644 --- a/tests/ui/generic-associated-types/collectivity-regression.stderr +++ b/tests/ui/generic-associated-types/collectivity-regression.stderr @@ -9,6 +9,16 @@ LL | | // probably should work. LL | | let _x = x; LL | | }; | |_____^ + | +note: due to current limitations in the borrow checker, this implies a `'static` lifetime + --> $DIR/collectivity-regression.rs:11:16 + | +LL | for<'a> T: Get = ()>, + | ^^^^^^^^^^^^^^^^^^^ +help: consider restricting the type parameter to the `'static` lifetime + | +LL | for<'a> T: Get = ()> + 'static, + | +++++++++ error: aborting due to previous error diff --git a/tests/ui/lifetimes/issue-105507.fixed b/tests/ui/lifetimes/issue-105507.fixed new file mode 100644 index 0000000000000..277ce8a77e974 --- /dev/null +++ b/tests/ui/lifetimes/issue-105507.fixed @@ -0,0 +1,43 @@ +// run-rustfix +// +#![allow(warnings)] +struct Wrapper<'a, T: ?Sized>(&'a T); + +trait Project { + type Projected<'a> where Self: 'a; + fn project(this: Wrapper<'_, Self>) -> Self::Projected<'_>; +} +trait MyTrait {} +trait ProjectedMyTrait {} + +impl Project for Option { + type Projected<'a> = Option> where T: 'a; + fn project(this: Wrapper<'_, Self>) -> Self::Projected<'_> { + this.0.as_ref().map(Wrapper) + } +} + +impl MyTrait for Option> {} + +impl MyTrait for Wrapper<'_, T> {} + +impl ProjectedMyTrait for T + where + T: Project, + for<'a> T::Projected<'a>: MyTrait, + //~^ NOTE due to current limitations in the borrow checker, this implies a `'static` lifetime + //~| NOTE due to current limitations in the borrow checker, this implies a `'static` lifetime +{} + +fn require_trait(_: T) {} + +fn foo(wrap: Wrapper<'_, Option>, wrap1: Wrapper<'_, Option>) { + //~^ HELP consider restricting the type parameter to the `'static` lifetime + //~| HELP consider restricting the type parameter to the `'static` lifetime + require_trait(wrap); + //~^ ERROR `T` does not live long enough + require_trait(wrap1); + //~^ ERROR `U` does not live long enough +} + +fn main() {} diff --git a/tests/ui/lifetimes/issue-105507.rs b/tests/ui/lifetimes/issue-105507.rs new file mode 100644 index 0000000000000..f46c6b6f21e86 --- /dev/null +++ b/tests/ui/lifetimes/issue-105507.rs @@ -0,0 +1,43 @@ +// run-rustfix +// +#![allow(warnings)] +struct Wrapper<'a, T: ?Sized>(&'a T); + +trait Project { + type Projected<'a> where Self: 'a; + fn project(this: Wrapper<'_, Self>) -> Self::Projected<'_>; +} +trait MyTrait {} +trait ProjectedMyTrait {} + +impl Project for Option { + type Projected<'a> = Option> where T: 'a; + fn project(this: Wrapper<'_, Self>) -> Self::Projected<'_> { + this.0.as_ref().map(Wrapper) + } +} + +impl MyTrait for Option> {} + +impl MyTrait for Wrapper<'_, T> {} + +impl ProjectedMyTrait for T + where + T: Project, + for<'a> T::Projected<'a>: MyTrait, + //~^ NOTE due to current limitations in the borrow checker, this implies a `'static` lifetime + //~| NOTE due to current limitations in the borrow checker, this implies a `'static` lifetime +{} + +fn require_trait(_: T) {} + +fn foo(wrap: Wrapper<'_, Option>, wrap1: Wrapper<'_, Option>) { + //~^ HELP consider restricting the type parameter to the `'static` lifetime + //~| HELP consider restricting the type parameter to the `'static` lifetime + require_trait(wrap); + //~^ ERROR `T` does not live long enough + require_trait(wrap1); + //~^ ERROR `U` does not live long enough +} + +fn main() {} diff --git a/tests/ui/lifetimes/issue-105507.stderr b/tests/ui/lifetimes/issue-105507.stderr new file mode 100644 index 0000000000000..44d3a7eb9a420 --- /dev/null +++ b/tests/ui/lifetimes/issue-105507.stderr @@ -0,0 +1,34 @@ +error: `T` does not live long enough + --> $DIR/issue-105507.rs:37:5 + | +LL | require_trait(wrap); + | ^^^^^^^^^^^^^^^^^^^ + | +note: due to current limitations in the borrow checker, this implies a `'static` lifetime + --> $DIR/issue-105507.rs:27:35 + | +LL | for<'a> T::Projected<'a>: MyTrait, + | ^^^^^^^ +help: consider restricting the type parameter to the `'static` lifetime + | +LL | fn foo(wrap: Wrapper<'_, Option>, wrap1: Wrapper<'_, Option>) { + | +++++++++ +++++++++ + +error: `U` does not live long enough + --> $DIR/issue-105507.rs:39:5 + | +LL | require_trait(wrap1); + | ^^^^^^^^^^^^^^^^^^^^ + | +note: due to current limitations in the borrow checker, this implies a `'static` lifetime + --> $DIR/issue-105507.rs:27:35 + | +LL | for<'a> T::Projected<'a>: MyTrait, + | ^^^^^^^ +help: consider restricting the type parameter to the `'static` lifetime + | +LL | fn foo(wrap: Wrapper<'_, Option>, wrap1: Wrapper<'_, Option>) { + | +++++++++ +++++++++ + +error: aborting due to 2 previous errors + From 7fe68571fa22d6504b3c14303cc4389cd5a92a24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Tue, 17 Jan 2023 00:00:00 +0000 Subject: [PATCH 120/230] Lazy dominator tree construction in borrowck Motivated by the observation that sometimes constructed dominator tree was never queried. --- .../src/diagnostics/conflict_errors.rs | 4 ++-- compiler/rustc_borrowck/src/lib.rs | 16 ++++++++++------ .../src/graph/dominators/mod.rs | 4 ---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index e512099b93b13..e5a36259fa495 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -2193,7 +2193,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let mut back_edge_stack = Vec::new(); predecessor_locations(self.body, location).for_each(|predecessor| { - if location.dominates(predecessor, &self.dominators) { + if location.dominates(predecessor, self.dominators()) { back_edge_stack.push(predecessor) } else { stack.push(predecessor); @@ -2305,7 +2305,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let mut has_predecessor = false; predecessor_locations(self.body, location).for_each(|predecessor| { - if location.dominates(predecessor, &self.dominators) { + if location.dominates(predecessor, self.dominators()) { back_edge_stack.push(predecessor) } else { stack.push(predecessor); diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 278ffed07477b..f2685241724d7 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -5,6 +5,7 @@ #![feature(let_chains)] #![feature(min_specialization)] #![feature(never_type)] +#![feature(once_cell)] #![feature(rustc_attrs)] #![feature(stmt_expr_attributes)] #![feature(trusted_step)] @@ -39,6 +40,7 @@ use rustc_span::{Span, Symbol}; use either::Either; use smallvec::SmallVec; +use std::cell::OnceCell; use std::cell::RefCell; use std::collections::BTreeMap; use std::rc::Rc; @@ -333,7 +335,7 @@ fn do_mir_borrowck<'tcx>( used_mut: Default::default(), used_mut_upvars: SmallVec::new(), borrow_set: Rc::clone(&borrow_set), - dominators: Dominators::dummy(), // not used + dominators: Default::default(), upvars: Vec::new(), local_names: IndexVec::from_elem(None, &promoted_body.local_decls), region_names: RefCell::default(), @@ -346,8 +348,6 @@ fn do_mir_borrowck<'tcx>( }; } - let dominators = body.basic_blocks.dominators(); - let mut mbcx = MirBorrowckCtxt { infcx, param_env, @@ -364,7 +364,7 @@ fn do_mir_borrowck<'tcx>( used_mut: Default::default(), used_mut_upvars: SmallVec::new(), borrow_set: Rc::clone(&borrow_set), - dominators, + dominators: Default::default(), upvars, local_names, region_names: RefCell::default(), @@ -534,7 +534,7 @@ struct MirBorrowckCtxt<'cx, 'tcx> { borrow_set: Rc>, /// Dominators for MIR - dominators: Dominators, + dominators: OnceCell>, /// Information about upvars not necessarily preserved in types or MIR upvars: Vec>, @@ -1051,7 +1051,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { (Read(kind), BorrowKind::Unique | BorrowKind::Mut { .. }) => { // Reading from mere reservations of mutable-borrows is OK. - if !is_active(&this.dominators, borrow, location) { + if !is_active(this.dominators(), borrow, location) { assert!(allow_two_phase_borrow(borrow.kind)); return Control::Continue; } @@ -2219,6 +2219,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn is_upvar_field_projection(&self, place_ref: PlaceRef<'tcx>) -> Option { path_utils::is_upvar_field_projection(self.infcx.tcx, &self.upvars, place_ref, self.body()) } + + fn dominators(&self) -> &Dominators { + self.dominators.get_or_init(|| self.body.basic_blocks.dominators()) + } } mod error { diff --git a/compiler/rustc_data_structures/src/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs index ea2a4388b92f0..434291e837424 100644 --- a/compiler/rustc_data_structures/src/graph/dominators/mod.rs +++ b/compiler/rustc_data_structures/src/graph/dominators/mod.rs @@ -268,10 +268,6 @@ pub struct Dominators { } impl Dominators { - pub fn dummy() -> Self { - Self { post_order_rank: IndexVec::new(), immediate_dominators: IndexVec::new() } - } - pub fn is_reachable(&self, node: Node) -> bool { self.immediate_dominators[node].is_some() } From 47014b1bb968be08923a670b1ebfe4deb4256601 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Mon, 16 Jan 2023 21:39:36 +0100 Subject: [PATCH 121/230] Don't do pointer arithmetic on pointers to deallocated memory vec::Splice can invalidate the slice::Iter inside vec::Drain. So we replace them with dangling pointers which, unlike ones to deallocated memory, are allowed. --- library/alloc/src/vec/drain.rs | 6 +++--- library/alloc/src/vec/splice.rs | 6 ++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/library/alloc/src/vec/drain.rs b/library/alloc/src/vec/drain.rs index 541f99bcfaba4..2b1a787cc5499 100644 --- a/library/alloc/src/vec/drain.rs +++ b/library/alloc/src/vec/drain.rs @@ -223,9 +223,9 @@ impl Drop for Drain<'_, T, A> { } // as_slice() must only be called when iter.len() is > 0 because - // vec::Splice modifies vec::Drain fields and may grow the vec which would invalidate - // the iterator's internal pointers. Creating a reference to deallocated memory - // is invalid even when it is zero-length + // it also gets touched by vec::Splice which may turn it into a dangling pointer + // which would make it and the vec pointer point to different allocations which would + // lead to invalid pointer arithmetic below. let drop_ptr = iter.as_slice().as_ptr(); unsafe { diff --git a/library/alloc/src/vec/splice.rs b/library/alloc/src/vec/splice.rs index bad765c7f51fa..1861147fe72fb 100644 --- a/library/alloc/src/vec/splice.rs +++ b/library/alloc/src/vec/splice.rs @@ -54,6 +54,12 @@ impl ExactSizeIterator for Splice<'_, I, A> {} impl Drop for Splice<'_, I, A> { fn drop(&mut self) { self.drain.by_ref().for_each(drop); + // At this point draining is done and the only remaining tasks are splicing + // and moving things into the final place. + // Which means we can replace the slice::Iter with pointers that won't point to deallocated + // memory, so that Drain::drop is still allowed to call iter.len(), otherwise it would break + // the ptr.sub_ptr contract. + self.drain.iter = (&[]).iter(); unsafe { if self.drain.tail_len == 0 { From 2d54b7ceb2a5c078f019fd2eacf70d59ea37555b Mon Sep 17 00:00:00 2001 From: The 8472 Date: Tue, 17 Jan 2023 20:30:47 +0100 Subject: [PATCH 122/230] add miri regression test --- src/tools/miri/tests/pass/vec.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/tools/miri/tests/pass/vec.rs b/src/tools/miri/tests/pass/vec.rs index 3a6655e2ba69f..30a28bc5803dd 100644 --- a/src/tools/miri/tests/pass/vec.rs +++ b/src/tools/miri/tests/pass/vec.rs @@ -162,6 +162,11 @@ fn reverse() { assert!(v[0].0 == 49); } +fn miri_issue_2759() { + let mut input = "1".to_string(); + input.replace_range(0..0, "0"); +} + fn main() { assert_eq!(vec_reallocate().len(), 5); @@ -191,4 +196,5 @@ fn main() { swap(); swap_remove(); reverse(); + miri_issue_2759(); } From 335e904ad56f138b50e52e18617e09478c18082d Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Tue, 17 Jan 2023 22:25:17 +0000 Subject: [PATCH 123/230] Update cargo 9 commits in 1cd6d3803dfb0b342272862a8590f5dfc9f72573..a5d47a72595dd6fbe7d4e4f6ec20dc5fe724edd1 2023-01-12 18:40:36 +0000 to 2023-01-16 18:51:50 +0000 - Add network container tests (rust-lang/cargo#11583) - Show progress of crates.io index update even `net.git-fetch-with-cli` option enabled (rust-lang/cargo#11579) - `cargo metadata` supports artifact dependencies (rust-lang/cargo#11550) - fix(docs): add required "inherits" option to example profile (rust-lang/cargo#11504) - add documentation that SSH markers aren't supported (rust-lang/cargo#11586) - Fix typo (rust-lang/cargo#11585) - Enable source_config_env test on Windows (rust-lang/cargo#11582) - Support `codegen-backend` and `rustflags` in profiles in config file (rust-lang/cargo#11562) - ci: reflect to clap updates (rust-lang/cargo#11578) --- Cargo.lock | 20 ++++++++++---------- src/tools/cargo | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5511d30177559..39fba4fa73197 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -351,7 +351,7 @@ dependencies = [ "cargo-test-macro", "cargo-test-support", "cargo-util", - "clap 4.0.32", + "clap 4.1.1", "crates-io", "curl", "curl-sys", @@ -655,12 +655,12 @@ dependencies = [ [[package]] name = "clap" -version = "4.0.32" +version = "4.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7db700bc935f9e43e88d00b0850dae18a63773cfbec6d8e070fccf7fef89a39" +checksum = "4ec7a4128863c188deefe750ac1d1dfe66c236909f845af04beed823638dc1b2" dependencies = [ "bitflags", - "clap_derive 4.0.21", + "clap_derive 4.1.0", "clap_lex 0.3.0", "is-terminal", "once_cell", @@ -675,7 +675,7 @@ version = "4.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10861370d2ba66b0f5989f83ebf35db6421713fd92351790e7fdd6c36774c56b" dependencies = [ - "clap 4.0.32", + "clap 4.1.1", ] [[package]] @@ -693,9 +693,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.0.21" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014" +checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8" dependencies = [ "heck", "proc-macro-error", @@ -2294,7 +2294,7 @@ name = "jsondoclint" version = "0.1.0" dependencies = [ "anyhow", - "clap 4.0.32", + "clap 4.1.1", "fs-err", "rustdoc-json-types", "serde", @@ -2557,7 +2557,7 @@ dependencies = [ "ammonia", "anyhow", "chrono", - "clap 4.0.32", + "clap 4.1.1", "clap_complete", "elasticlunr-rs", "env_logger 0.10.0", @@ -3528,7 +3528,7 @@ dependencies = [ name = "rustbook" version = "0.1.0" dependencies = [ - "clap 4.0.32", + "clap 4.1.1", "env_logger 0.7.1", "mdbook", ] diff --git a/src/tools/cargo b/src/tools/cargo index 1cd6d3803dfb0..a5d47a72595dd 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 1cd6d3803dfb0b342272862a8590f5dfc9f72573 +Subproject commit a5d47a72595dd6fbe7d4e4f6ec20dc5fe724edd1 From b73cdf1b29d25d3c6d0cc4f8a7744b08930e86ee Mon Sep 17 00:00:00 2001 From: Ezra Shaw Date: Wed, 18 Jan 2023 13:14:56 +1300 Subject: [PATCH 124/230] special case removing `&` suggestion --- compiler/rustc_hir/src/hir.rs | 8 ++++++++ compiler/rustc_hir_typeck/src/cast.rs | 24 ++++++++++++++++++------ tests/ui/error-codes/E0606.rs | 3 ++- tests/ui/error-codes/E0606.stderr | 22 +++++++++++++++++----- 4 files changed, 45 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 60f5b79de1033..5e59475a7bdfc 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1787,6 +1787,14 @@ impl Expr<'_> { expr } + pub fn peel_borrows(&self) -> &Self { + let mut expr = self; + while let ExprKind::AddrOf(.., inner) = &expr.kind { + expr = inner; + } + expr + } + pub fn can_have_side_effects(&self) -> bool { match self.peel_drop_temps().kind { ExprKind::Path(_) | ExprKind::Lit(_) => false, diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index b312a3d30af08..712f9b87aed0a 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -31,6 +31,7 @@ use super::FnCtxt; use crate::type_error_struct; +use hir::ExprKind; use rustc_errors::{ struct_span_err, Applicability, DelayDm, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, }; @@ -237,12 +238,23 @@ impl<'a, 'tcx> CastCheck<'tcx> { fcx, ); - err.span_suggestion_verbose( - self.expr_span.shrink_to_lo(), - "dereference the expression", - "*", - Applicability::MachineApplicable, - ); + if matches!(self.expr.kind, ExprKind::AddrOf(..)) { + // get just the borrow part of the expression + let span = self.expr_span.with_hi(self.expr.peel_borrows().span.lo()); + err.span_suggestion_verbose( + span, + "remove the unneeded borrow", + "", + Applicability::MachineApplicable, + ); + } else { + err.span_suggestion_verbose( + self.expr_span.shrink_to_lo(), + "dereference the expression", + "*", + Applicability::MachineApplicable, + ); + } err.emit(); } diff --git a/tests/ui/error-codes/E0606.rs b/tests/ui/error-codes/E0606.rs index cb0d8cfc31e23..6f6c6513846cf 100644 --- a/tests/ui/error-codes/E0606.rs +++ b/tests/ui/error-codes/E0606.rs @@ -1,3 +1,4 @@ fn main() { - &0u8 as u8; //~ ERROR E0606 + let x = &(&0u8 as u8); //~ ERROR E0606 + x as u8; //~ casting `&u8` as `u8` is invalid [E0606] } diff --git a/tests/ui/error-codes/E0606.stderr b/tests/ui/error-codes/E0606.stderr index 586b1f2fd5472..2492eb299cc55 100644 --- a/tests/ui/error-codes/E0606.stderr +++ b/tests/ui/error-codes/E0606.stderr @@ -1,14 +1,26 @@ error[E0606]: casting `&u8` as `u8` is invalid - --> $DIR/E0606.rs:2:5 + --> $DIR/E0606.rs:2:14 | -LL | &0u8 as u8; - | ^^^^^^^^^^ +LL | let x = &(&0u8 as u8); + | ^^^^^^^^^^^^ + | +help: remove the unneeded borrow + | +LL - let x = &(&0u8 as u8); +LL + let x = &(0u8 as u8); + | + +error[E0606]: casting `&u8` as `u8` is invalid + --> $DIR/E0606.rs:3:5 + | +LL | x as u8; + | ^^^^^^^ | help: dereference the expression | -LL | *&0u8 as u8; +LL | *x as u8; | + -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0606`. From 6d7e2135f15eeb9a586ef97bb6a7744e5a936777 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 17 Jan 2023 17:22:05 -0700 Subject: [PATCH 125/230] rustdoc: remove function `handleClick` that's only used once --- src/librustdoc/html/static/js/main.js | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index f52229d809536..4d604a214964b 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -803,15 +803,10 @@ function loadCss(cssUrl) { } }); - function handleClick(id, f) { - const elem = document.getElementById(id); - if (elem) { - elem.addEventListener("click", f); - } + const mainElem = document.getElementById(MAIN_ID); + if (mainElem) { + mainElem.addEventListener("click", hideSidebar); } - handleClick(MAIN_ID, () => { - hideSidebar(); - }); onEachLazy(document.querySelectorAll("a[href^='#']"), el => { // For clicks on internal links ( tags with a hash property), we expand the section we're From 708b529f314cc5b126adc2c131dc0d0231db41dc Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 17 Jan 2023 17:54:58 -0700 Subject: [PATCH 126/230] rustdoc: stop using deprecated `window.event` when there's an `ev` param --- src/librustdoc/html/static/js/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 4d604a214964b..9ceeeb5ae8fd8 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -940,7 +940,7 @@ function loadCss(cssUrl) { return; } if (!this.NOTABLE_FORCE_VISIBLE && - !elemIsInParent(event.relatedTarget, window.CURRENT_NOTABLE_ELEMENT)) { + !elemIsInParent(ev.relatedTarget, window.CURRENT_NOTABLE_ELEMENT)) { hideNotable(true); } }; From f6d8abfcbfe2e2600f52bef27d8677febf72767a Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 17 Jan 2023 18:15:54 -0800 Subject: [PATCH 127/230] Re-enable building rust-analyzer on riscv64 It was disabled in #75103 due to an LLVM bug, but followup comments have confirmed that it builds fine on Fedora with LLVM 15. --- src/bootstrap/dist.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 68215790bed17..2e4f753965ded 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -1130,12 +1130,6 @@ impl Step for RustAnalyzer { let compiler = self.compiler; let target = self.target; - if target.contains("riscv64") { - // riscv64 currently has an LLVM bug that makes rust-analyzer unable - // to build. See #74813 for details. - return None; - } - let rust_analyzer = builder .ensure(tool::RustAnalyzer { compiler, target }) .expect("rust-analyzer always builds"); From 4ca5368a122e06e33fd8fb5f3e2c4b63492273f1 Mon Sep 17 00:00:00 2001 From: Boxy Date: Sat, 14 Jan 2023 18:32:17 +0000 Subject: [PATCH 128/230] defer array len printing to const arg printing --- compiler/rustc_middle/src/ty/print/pretty.rs | 24 ++++--------------- ...ram-type-depends-on-const-param.min.stderr | 4 ++-- ...const-param-type-depends-on-const-param.rs | 4 ++-- .../dont-evaluate-array-len-on-err-1.stderr | 4 ++-- .../issue-62504.min.stderr | 2 +- ...-default_trait_method_normalization.stderr | 6 ++--- .../issues/issue-62878.min.stderr | 2 +- tests/ui/const-generics/issues/issue-62878.rs | 2 +- .../issues/issue-71169.min.stderr | 2 +- tests/ui/const-generics/issues/issue-71169.rs | 2 +- .../issues/issue-73491.min.stderr | 2 +- tests/ui/const-generics/issues/issue-73491.rs | 2 +- .../issues/issue-74101.min.stderr | 4 ++-- tests/ui/const-generics/issues/issue-74101.rs | 4 ++-- .../issues/issue-75047.min.stderr | 2 +- tests/ui/const-generics/issues/issue-75047.rs | 2 +- .../ui/const-generics/nested-type.min.stderr | 12 +++++++++- tests/ui/consts/const-size_of-cycle.stderr | 4 ++-- tests/ui/consts/issue-44415.stderr | 4 ++-- tests/ui/consts/too_generic_eval_ice.rs | 2 +- tests/ui/consts/too_generic_eval_ice.stderr | 6 ++--- ...uginfo-type-name-layout-ice-94961-1.stderr | 2 +- ...uginfo-type-name-layout-ice-94961-2.stderr | 2 +- tests/ui/inference/issue-83606.rs | 2 +- tests/ui/inference/issue-83606.stderr | 4 ++-- tests/ui/limits/issue-15919-64.stderr | 2 +- tests/ui/limits/issue-55878.stderr | 4 ++-- ...ssue-69485-var-size-diffs-too-large.stderr | 2 +- tests/ui/limits/issue-75158-64.stderr | 2 +- tests/ui/symbol-names/impl2.rs | 7 +++--- tests/ui/symbol-names/impl2.stderr | 2 +- 31 files changed, 59 insertions(+), 66 deletions(-) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 42fc78a4715f4..eba3016aca82c 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -854,24 +854,7 @@ pub trait PrettyPrinter<'tcx>: } p!("]"); } - ty::Array(ty, sz) => { - p!("[", print(ty), "; "); - if self.should_print_verbose() { - p!(write("{:?}", sz)); - } else if let ty::ConstKind::Unevaluated(..) = sz.kind() { - // Do not try to evaluate unevaluated constants. If we are const evaluating an - // array length anon const, rustc will (with debug assertions) print the - // constant's path. Which will end up here again. - p!("_"); - } else if let Some(n) = sz.kind().try_to_bits(self.tcx().data_layout.pointer_size) { - p!(write("{}", n)); - } else if let ty::ConstKind::Param(param) = sz.kind() { - p!(print(param)); - } else { - p!("_"); - } - p!("]") - } + ty::Array(ty, sz) => p!("[", print(ty), "; ", print(sz), "]"), ty::Slice(ty) => p!("[", print(ty), "]"), } @@ -1303,10 +1286,10 @@ pub trait PrettyPrinter<'tcx>: match ct.kind() { ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) => { match self.tcx().def_kind(def.did) { - DefKind::Static(..) | DefKind::Const | DefKind::AssocConst => { + DefKind::Const | DefKind::AssocConst => { p!(print_value_path(def.did, substs)) } - _ => { + DefKind::AnonConst => { if def.is_local() { let span = self.tcx().def_span(def.did); if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) { @@ -1318,6 +1301,7 @@ pub trait PrettyPrinter<'tcx>: print_underscore!() } } + defkind => bug!("`{:?}` has unexpcted defkind {:?}", ct, defkind), } } ty::ConstKind::Infer(infer_ct) => { diff --git a/tests/ui/const-generics/const-param-type-depends-on-const-param.min.stderr b/tests/ui/const-generics/const-param-type-depends-on-const-param.min.stderr index a7b78b80ca5ea..24aa405211f4c 100644 --- a/tests/ui/const-generics/const-param-type-depends-on-const-param.min.stderr +++ b/tests/ui/const-generics/const-param-type-depends-on-const-param.min.stderr @@ -10,7 +10,7 @@ error[E0770]: the type of const parameters must not depend on other generic para LL | pub struct SelfDependent; | ^ the type must not depend on the parameter `N` -error: `[u8; _]` is forbidden as the type of a const generic parameter +error: `[u8; N]` is forbidden as the type of a const generic parameter --> $DIR/const-param-type-depends-on-const-param.rs:11:47 | LL | pub struct Dependent([(); N]); @@ -19,7 +19,7 @@ LL | pub struct Dependent([(); N]); = note: the only supported types are integers, `bool` and `char` = help: more complex types are supported with `#![feature(adt_const_params)]` -error: `[u8; _]` is forbidden as the type of a const generic parameter +error: `[u8; N]` is forbidden as the type of a const generic parameter --> $DIR/const-param-type-depends-on-const-param.rs:15:35 | LL | pub struct SelfDependent; diff --git a/tests/ui/const-generics/const-param-type-depends-on-const-param.rs b/tests/ui/const-generics/const-param-type-depends-on-const-param.rs index 9d50f9a47ff6e..64b2acb036292 100644 --- a/tests/ui/const-generics/const-param-type-depends-on-const-param.rs +++ b/tests/ui/const-generics/const-param-type-depends-on-const-param.rs @@ -10,10 +10,10 @@ pub struct Dependent([(); N]); //~^ ERROR: the type of const parameters must not depend on other generic parameters -//[min]~^^ ERROR `[u8; _]` is forbidden +//[min]~^^ ERROR `[u8; N]` is forbidden pub struct SelfDependent; //~^ ERROR: the type of const parameters must not depend on other generic parameters -//[min]~^^ ERROR `[u8; _]` is forbidden +//[min]~^^ ERROR `[u8; N]` is forbidden fn main() {} diff --git a/tests/ui/const-generics/dont-evaluate-array-len-on-err-1.stderr b/tests/ui/const-generics/dont-evaluate-array-len-on-err-1.stderr index 68ce61bd4a374..d8eebeb0d2115 100644 --- a/tests/ui/const-generics/dont-evaluate-array-len-on-err-1.stderr +++ b/tests/ui/const-generics/dont-evaluate-array-len-on-err-1.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `[Adt; _]: Foo` is not satisfied +error[E0277]: the trait bound `[Adt; std::mem::size_of::()]: Foo` is not satisfied --> $DIR/dont-evaluate-array-len-on-err-1.rs:15:9 | LL | <[Adt; std::mem::size_of::()] as Foo>::bar() - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `[Adt; _]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `[Adt; std::mem::size_of::()]` error: aborting due to previous error diff --git a/tests/ui/const-generics/generic_const_exprs/issue-62504.min.stderr b/tests/ui/const-generics/generic_const_exprs/issue-62504.min.stderr index 9bea4105d58b0..65822856e1d7c 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-62504.min.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-62504.min.stderr @@ -15,7 +15,7 @@ LL | ArrayHolder([0; Self::SIZE]) | arguments to this struct are incorrect | = note: expected array `[u32; X]` - found array `[u32; _]` + found array `[u32; Self::SIZE]` note: tuple struct defined here --> $DIR/issue-62504.rs:14:8 | diff --git a/tests/ui/const-generics/generic_const_exprs/issue-79518-default_trait_method_normalization.stderr b/tests/ui/const-generics/generic_const_exprs/issue-79518-default_trait_method_normalization.stderr index 029528c3a8172..9baf9790e19b3 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-79518-default_trait_method_normalization.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-79518-default_trait_method_normalization.stderr @@ -2,13 +2,13 @@ error[E0308]: mismatched types --> $DIR/issue-79518-default_trait_method_normalization.rs:16:32 | LL | Self::AssocInstance == [(); std::mem::size_of::()]; - | ------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found array `[(); _]` + | ------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found array `[(); std::mem::size_of::()]` | | | expected because this is `::Assoc` | = note: expected associated type `::Assoc` - found array `[(); _]` - = help: consider constraining the associated type `::Assoc` to `[(); _]` or calling a method that returns `::Assoc` + found array `[(); std::mem::size_of::()]` + = help: consider constraining the associated type `::Assoc` to `[(); std::mem::size_of::()]` or calling a method that returns `::Assoc` = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html error: aborting due to previous error diff --git a/tests/ui/const-generics/issues/issue-62878.min.stderr b/tests/ui/const-generics/issues/issue-62878.min.stderr index af029a6516bc6..5a721720d78b5 100644 --- a/tests/ui/const-generics/issues/issue-62878.min.stderr +++ b/tests/ui/const-generics/issues/issue-62878.min.stderr @@ -4,7 +4,7 @@ error[E0770]: the type of const parameters must not depend on other generic para LL | fn foo() {} | ^ the type must not depend on the parameter `N` -error: `[u8; _]` is forbidden as the type of a const generic parameter +error: `[u8; N]` is forbidden as the type of a const generic parameter --> $DIR/issue-62878.rs:5:33 | LL | fn foo() {} diff --git a/tests/ui/const-generics/issues/issue-62878.rs b/tests/ui/const-generics/issues/issue-62878.rs index 578ce765b2fb8..4c08a484ef47b 100644 --- a/tests/ui/const-generics/issues/issue-62878.rs +++ b/tests/ui/const-generics/issues/issue-62878.rs @@ -4,7 +4,7 @@ fn foo() {} //~^ ERROR the type of const parameters must not -//[min]~| ERROR `[u8; _]` is forbidden as the type of a const generic parameter +//[min]~| ERROR `[u8; N]` is forbidden as the type of a const generic parameter fn main() { foo::<_, { [1] }>(); diff --git a/tests/ui/const-generics/issues/issue-71169.min.stderr b/tests/ui/const-generics/issues/issue-71169.min.stderr index 87ed2d4f8da8c..998b16a79e638 100644 --- a/tests/ui/const-generics/issues/issue-71169.min.stderr +++ b/tests/ui/const-generics/issues/issue-71169.min.stderr @@ -4,7 +4,7 @@ error[E0770]: the type of const parameters must not depend on other generic para LL | fn foo() {} | ^^^ the type must not depend on the parameter `LEN` -error: `[u8; _]` is forbidden as the type of a const generic parameter +error: `[u8; LEN]` is forbidden as the type of a const generic parameter --> $DIR/issue-71169.rs:5:38 | LL | fn foo() {} diff --git a/tests/ui/const-generics/issues/issue-71169.rs b/tests/ui/const-generics/issues/issue-71169.rs index 617149a841893..e4ec6b0737613 100644 --- a/tests/ui/const-generics/issues/issue-71169.rs +++ b/tests/ui/const-generics/issues/issue-71169.rs @@ -4,7 +4,7 @@ fn foo() {} //~^ ERROR the type of const parameters must not -//[min]~^^ ERROR `[u8; _]` is forbidden as the type of a const generic parameter +//[min]~^^ ERROR `[u8; LEN]` is forbidden as the type of a const generic parameter fn main() { const DATA: [u8; 4] = *b"ABCD"; foo::<4, DATA>(); diff --git a/tests/ui/const-generics/issues/issue-73491.min.stderr b/tests/ui/const-generics/issues/issue-73491.min.stderr index f2b58e59f731f..f03354fc472c0 100644 --- a/tests/ui/const-generics/issues/issue-73491.min.stderr +++ b/tests/ui/const-generics/issues/issue-73491.min.stderr @@ -1,4 +1,4 @@ -error: `[u32; _]` is forbidden as the type of a const generic parameter +error: `[u32; LEN]` is forbidden as the type of a const generic parameter --> $DIR/issue-73491.rs:8:19 | LL | fn hoge() {} diff --git a/tests/ui/const-generics/issues/issue-73491.rs b/tests/ui/const-generics/issues/issue-73491.rs index f15c1f2d45521..482dbb04daae9 100644 --- a/tests/ui/const-generics/issues/issue-73491.rs +++ b/tests/ui/const-generics/issues/issue-73491.rs @@ -6,6 +6,6 @@ const LEN: usize = 1024; fn hoge() {} -//[min]~^ ERROR `[u32; _]` is forbidden as the type of a const generic parameter +//[min]~^ ERROR `[u32; LEN]` is forbidden as the type of a const generic parameter fn main() {} diff --git a/tests/ui/const-generics/issues/issue-74101.min.stderr b/tests/ui/const-generics/issues/issue-74101.min.stderr index 82ffb23324044..134c248347d3c 100644 --- a/tests/ui/const-generics/issues/issue-74101.min.stderr +++ b/tests/ui/const-generics/issues/issue-74101.min.stderr @@ -1,4 +1,4 @@ -error: `[u8; _]` is forbidden as the type of a const generic parameter +error: `[u8; 1 + 2]` is forbidden as the type of a const generic parameter --> $DIR/issue-74101.rs:6:18 | LL | fn test() {} @@ -7,7 +7,7 @@ LL | fn test() {} = note: the only supported types are integers, `bool` and `char` = help: more complex types are supported with `#![feature(adt_const_params)]` -error: `[u8; _]` is forbidden as the type of a const generic parameter +error: `[u8; 1 + 2]` is forbidden as the type of a const generic parameter --> $DIR/issue-74101.rs:9:21 | LL | struct Foo; diff --git a/tests/ui/const-generics/issues/issue-74101.rs b/tests/ui/const-generics/issues/issue-74101.rs index 6b606b9460fe2..4c9b2d3c634da 100644 --- a/tests/ui/const-generics/issues/issue-74101.rs +++ b/tests/ui/const-generics/issues/issue-74101.rs @@ -4,9 +4,9 @@ #![cfg_attr(full, allow(incomplete_features))] fn test() {} -//[min]~^ ERROR `[u8; _]` is forbidden as the type of a const generic parameter +//[min]~^ ERROR `[u8; 1 + 2]` is forbidden as the type of a const generic parameter struct Foo; -//[min]~^ ERROR `[u8; _]` is forbidden as the type of a const generic parameter +//[min]~^ ERROR `[u8; 1 + 2]` is forbidden as the type of a const generic parameter fn main() {} diff --git a/tests/ui/const-generics/issues/issue-75047.min.stderr b/tests/ui/const-generics/issues/issue-75047.min.stderr index 7798ae7962983..46af19ef39540 100644 --- a/tests/ui/const-generics/issues/issue-75047.min.stderr +++ b/tests/ui/const-generics/issues/issue-75047.min.stderr @@ -1,4 +1,4 @@ -error: `[u8; _]` is forbidden as the type of a const generic parameter +error: `[u8; Bar::::value()]` is forbidden as the type of a const generic parameter --> $DIR/issue-75047.rs:14:21 | LL | struct Foo::value()]>; diff --git a/tests/ui/const-generics/issues/issue-75047.rs b/tests/ui/const-generics/issues/issue-75047.rs index ee3dcf9ecec50..7b6fb92bca96e 100644 --- a/tests/ui/const-generics/issues/issue-75047.rs +++ b/tests/ui/const-generics/issues/issue-75047.rs @@ -12,6 +12,6 @@ impl Bar { } struct Foo::value()]>; -//[min]~^ ERROR `[u8; _]` is forbidden as the type of a const generic parameter +//[min]~^ ERROR `[u8; Bar::::value()]` is forbidden as the type of a const generic parameter fn main() {} diff --git a/tests/ui/const-generics/nested-type.min.stderr b/tests/ui/const-generics/nested-type.min.stderr index 276ebf31ff8b8..cff02b0d445c8 100644 --- a/tests/ui/const-generics/nested-type.min.stderr +++ b/tests/ui/const-generics/nested-type.min.stderr @@ -1,4 +1,14 @@ -error: `[u8; _]` is forbidden as the type of a const generic parameter +error: `[u8; { + struct Foo; + + impl Foo { + fn value() -> usize { + N + } + } + + Foo::<17>::value() + }]` is forbidden as the type of a const generic parameter --> $DIR/nested-type.rs:6:21 | LL | struct Foo()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires computing layout of `Foo`... - = note: ...which requires computing layout of `[u8; _]`... - = note: ...which requires normalizing `[u8; _]`... + = note: ...which requires computing layout of `[u8; std::mem::size_of::()]`... + = note: ...which requires normalizing `[u8; std::mem::size_of::()]`... = note: ...which again requires evaluating type-level constant, completing the cycle note: cycle used when checking that `Foo` is well-formed --> $DIR/const-size_of-cycle.rs:3:1 diff --git a/tests/ui/consts/issue-44415.stderr b/tests/ui/consts/issue-44415.stderr index 57f94f8c6ab52..ec64b956dfe2b 100644 --- a/tests/ui/consts/issue-44415.stderr +++ b/tests/ui/consts/issue-44415.stderr @@ -15,8 +15,8 @@ note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`.. LL | bytes: [u8; unsafe { intrinsics::size_of::() }], | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires computing layout of `Foo`... - = note: ...which requires computing layout of `[u8; _]`... - = note: ...which requires normalizing `[u8; _]`... + = note: ...which requires computing layout of `[u8; unsafe { intrinsics::size_of::() }]`... + = note: ...which requires normalizing `[u8; unsafe { intrinsics::size_of::() }]`... = note: ...which again requires evaluating type-level constant, completing the cycle note: cycle used when checking that `Foo` is well-formed --> $DIR/issue-44415.rs:5:1 diff --git a/tests/ui/consts/too_generic_eval_ice.rs b/tests/ui/consts/too_generic_eval_ice.rs index af494e3734914..8b3f4b714e1bd 100644 --- a/tests/ui/consts/too_generic_eval_ice.rs +++ b/tests/ui/consts/too_generic_eval_ice.rs @@ -7,7 +7,7 @@ impl Foo { [5; Self::HOST_SIZE] == [6; 0] //~^ ERROR constant expression depends on a generic parameter //~| ERROR constant expression depends on a generic parameter - //~| ERROR can't compare `[{integer}; _]` with `[{integer}; 0]` + //~| ERROR can't compare `[{integer}; Self::HOST_SIZE]` with `[{integer}; 0]` } } diff --git a/tests/ui/consts/too_generic_eval_ice.stderr b/tests/ui/consts/too_generic_eval_ice.stderr index 8de61fcfb7330..5af82a3e34bf5 100644 --- a/tests/ui/consts/too_generic_eval_ice.stderr +++ b/tests/ui/consts/too_generic_eval_ice.stderr @@ -14,13 +14,13 @@ LL | [5; Self::HOST_SIZE] == [6; 0] | = note: this may fail depending on what value the parameter takes -error[E0277]: can't compare `[{integer}; _]` with `[{integer}; 0]` +error[E0277]: can't compare `[{integer}; Self::HOST_SIZE]` with `[{integer}; 0]` --> $DIR/too_generic_eval_ice.rs:7:30 | LL | [5; Self::HOST_SIZE] == [6; 0] - | ^^ no implementation for `[{integer}; _] == [{integer}; 0]` + | ^^ no implementation for `[{integer}; Self::HOST_SIZE] == [{integer}; 0]` | - = help: the trait `PartialEq<[{integer}; 0]>` is not implemented for `[{integer}; _]` + = help: the trait `PartialEq<[{integer}; 0]>` is not implemented for `[{integer}; Self::HOST_SIZE]` = help: the following other types implement trait `PartialEq`: <&[B] as PartialEq<[A; N]>> <&[T] as PartialEq>> diff --git a/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-1.stderr b/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-1.stderr index 851dca84c3dc0..d5991bcf5693d 100644 --- a/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-1.stderr +++ b/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-1.stderr @@ -1,4 +1,4 @@ -error: values of the type `[u8; SIZE]` are too big for the current architecture +error: values of the type `[u8; usize::MAX]` are too big for the current architecture error: aborting due to previous error diff --git a/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-2.stderr b/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-2.stderr index 851dca84c3dc0..d5991bcf5693d 100644 --- a/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-2.stderr +++ b/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-2.stderr @@ -1,4 +1,4 @@ -error: values of the type `[u8; SIZE]` are too big for the current architecture +error: values of the type `[u8; usize::MAX]` are too big for the current architecture error: aborting due to previous error diff --git a/tests/ui/inference/issue-83606.rs b/tests/ui/inference/issue-83606.rs index eaaef3463ddc9..c387046e91008 100644 --- a/tests/ui/inference/issue-83606.rs +++ b/tests/ui/inference/issue-83606.rs @@ -6,5 +6,5 @@ fn foo(_: impl std::fmt::Display) -> [usize; N] { fn main() { let _ = foo("foo"); - //~^ ERROR: type annotations needed for `[usize; _]` + //~^ ERROR: type annotations needed for `[usize; N]` } diff --git a/tests/ui/inference/issue-83606.stderr b/tests/ui/inference/issue-83606.stderr index f5c84f960641a..f2ee8692e38a6 100644 --- a/tests/ui/inference/issue-83606.stderr +++ b/tests/ui/inference/issue-83606.stderr @@ -1,4 +1,4 @@ -error[E0282]: type annotations needed for `[usize; _]` +error[E0282]: type annotations needed for `[usize; N]` --> $DIR/issue-83606.rs:8:9 | LL | let _ = foo("foo"); @@ -6,7 +6,7 @@ LL | let _ = foo("foo"); | help: consider giving this pattern a type, where the the value of const parameter `N` is specified | -LL | let _: [usize; _] = foo("foo"); +LL | let _: [usize; N] = foo("foo"); | ++++++++++++ error: aborting due to previous error diff --git a/tests/ui/limits/issue-15919-64.stderr b/tests/ui/limits/issue-15919-64.stderr index 193b823035c09..3399d644ede3a 100644 --- a/tests/ui/limits/issue-15919-64.stderr +++ b/tests/ui/limits/issue-15919-64.stderr @@ -1,4 +1,4 @@ -error: values of the type `[usize; 18446744073709551615]` are too big for the current architecture +error: values of the type `[usize; usize::MAX]` are too big for the current architecture --> $DIR/issue-15919-64.rs:9:9 | LL | let x = [0usize; 0xffff_ffff_ffff_ffff]; diff --git a/tests/ui/limits/issue-55878.stderr b/tests/ui/limits/issue-55878.stderr index f455dcb06f79d..99f1fdf755aa2 100644 --- a/tests/ui/limits/issue-55878.stderr +++ b/tests/ui/limits/issue-55878.stderr @@ -1,7 +1,7 @@ -error[E0080]: values of the type `[u8; SIZE]` are too big for the current architecture +error[E0080]: values of the type `[u8; usize::MAX]` are too big for the current architecture --> $SRC_DIR/core/src/mem/mod.rs:LL:COL | -note: inside `std::mem::size_of::<[u8; SIZE]>` +note: inside `std::mem::size_of::<[u8; usize::MAX]>` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL note: inside `main` --> $DIR/issue-55878.rs:7:26 diff --git a/tests/ui/limits/issue-69485-var-size-diffs-too-large.stderr b/tests/ui/limits/issue-69485-var-size-diffs-too-large.stderr index f7923bd47439f..44b2be269494a 100644 --- a/tests/ui/limits/issue-69485-var-size-diffs-too-large.stderr +++ b/tests/ui/limits/issue-69485-var-size-diffs-too-large.stderr @@ -1,4 +1,4 @@ -error: values of the type `[u8; 18446744073709551615]` are too big for the current architecture +error: values of the type `[u8; usize::MAX]` are too big for the current architecture --> $DIR/issue-69485-var-size-diffs-too-large.rs:6:5 | LL | Bug::V([0; !0]); diff --git a/tests/ui/limits/issue-75158-64.stderr b/tests/ui/limits/issue-75158-64.stderr index dc11d05615427..d5991bcf5693d 100644 --- a/tests/ui/limits/issue-75158-64.stderr +++ b/tests/ui/limits/issue-75158-64.stderr @@ -1,4 +1,4 @@ -error: values of the type `[u8; 18446744073709551615]` are too big for the current architecture +error: values of the type `[u8; usize::MAX]` are too big for the current architecture error: aborting due to previous error diff --git a/tests/ui/symbol-names/impl2.rs b/tests/ui/symbol-names/impl2.rs index 08add29cb9cd5..81aba403d0ba2 100644 --- a/tests/ui/symbol-names/impl2.rs +++ b/tests/ui/symbol-names/impl2.rs @@ -8,9 +8,8 @@ trait Foo { } impl Foo for [u8; 1 + 2] { - #[rustc_def_path] //~ ERROR def-path(<[u8; _] as Foo>::baz) - fn baz() { } + #[rustc_def_path] //~ ERROR def-path(<[u8; 1 + 2] as Foo>::baz) + fn baz() {} } -fn main() { -} +fn main() {} diff --git a/tests/ui/symbol-names/impl2.stderr b/tests/ui/symbol-names/impl2.stderr index 9833003160223..0c3205e0108e6 100644 --- a/tests/ui/symbol-names/impl2.stderr +++ b/tests/ui/symbol-names/impl2.stderr @@ -1,4 +1,4 @@ -error: def-path(<[u8; _] as Foo>::baz) +error: def-path(<[u8; 1 + 2] as Foo>::baz) --> $DIR/impl2.rs:11:5 | LL | #[rustc_def_path] From 88f81a0de122843afc122468823f1ed6f0b8f2c8 Mon Sep 17 00:00:00 2001 From: Boxy Date: Sat, 14 Jan 2023 19:01:31 +0000 Subject: [PATCH 129/230] test for non local anon const printing --- .../auxiliary/anon_const_non_local.rs | 8 ++++++++ .../non_local_anon_const_diagnostics.rs | 16 ++++++++++++++++ .../non_local_anon_const_diagnostics.stderr | 12 ++++++++++++ 3 files changed, 36 insertions(+) create mode 100644 tests/ui/const-generics/generic_const_exprs/auxiliary/anon_const_non_local.rs create mode 100644 tests/ui/const-generics/generic_const_exprs/non_local_anon_const_diagnostics.rs create mode 100644 tests/ui/const-generics/generic_const_exprs/non_local_anon_const_diagnostics.stderr diff --git a/tests/ui/const-generics/generic_const_exprs/auxiliary/anon_const_non_local.rs b/tests/ui/const-generics/generic_const_exprs/auxiliary/anon_const_non_local.rs new file mode 100644 index 0000000000000..97be074933d9b --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/auxiliary/anon_const_non_local.rs @@ -0,0 +1,8 @@ +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +pub struct Foo; + +pub fn foo() -> Foo<{ N + 1 }> { + Foo +} diff --git a/tests/ui/const-generics/generic_const_exprs/non_local_anon_const_diagnostics.rs b/tests/ui/const-generics/generic_const_exprs/non_local_anon_const_diagnostics.rs new file mode 100644 index 0000000000000..1254b4435f738 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/non_local_anon_const_diagnostics.rs @@ -0,0 +1,16 @@ +// aux-build:anon_const_non_local.rs + +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +extern crate anon_const_non_local; + +fn bar() +where + [(); M + 1]:, +{ + let _: anon_const_non_local::Foo<2> = anon_const_non_local::foo::(); + //~^ ERROR: mismatched types +} + +fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/non_local_anon_const_diagnostics.stderr b/tests/ui/const-generics/generic_const_exprs/non_local_anon_const_diagnostics.stderr new file mode 100644 index 0000000000000..c18281beb0502 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/non_local_anon_const_diagnostics.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/non_local_anon_const_diagnostics.rs:12:43 + | +LL | let _: anon_const_non_local::Foo<2> = anon_const_non_local::foo::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2`, found `_` + | + = note: expected constant `2` + found constant `_` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. From a2a50f96f3532347a0ad61f2d6bfed4c64de4e54 Mon Sep 17 00:00:00 2001 From: Boxy Date: Sat, 14 Jan 2023 19:03:50 +0000 Subject: [PATCH 130/230] actually print out non local anon consts --- compiler/rustc_middle/src/ty/print/pretty.rs | 6 +++--- .../non_local_anon_const_diagnostics.stderr | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index eba3016aca82c..df37b2b4628b5 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1295,10 +1295,10 @@ pub trait PrettyPrinter<'tcx>: if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) { p!(write("{}", snip)) } else { - print_underscore!() + p!(print_value_path(def.did, substs)) } } else { - print_underscore!() + p!(print_value_path(def.did, substs)) } } defkind => bug!("`{:?}` has unexpcted defkind {:?}", ct, defkind), @@ -1323,7 +1323,7 @@ pub trait PrettyPrinter<'tcx>: ty::ConstKind::Placeholder(placeholder) => p!(write("Placeholder({:?})", placeholder)), // FIXME(generic_const_exprs): // write out some legible representation of an abstract const? - ty::ConstKind::Expr(_) => p!("[Const Expr]"), + ty::ConstKind::Expr(_) => p!("[const expr]"), ty::ConstKind::Error(_) => p!("[const error]"), }; Ok(self) diff --git a/tests/ui/const-generics/generic_const_exprs/non_local_anon_const_diagnostics.stderr b/tests/ui/const-generics/generic_const_exprs/non_local_anon_const_diagnostics.stderr index c18281beb0502..c1a846acf8862 100644 --- a/tests/ui/const-generics/generic_const_exprs/non_local_anon_const_diagnostics.stderr +++ b/tests/ui/const-generics/generic_const_exprs/non_local_anon_const_diagnostics.stderr @@ -2,10 +2,10 @@ error[E0308]: mismatched types --> $DIR/non_local_anon_const_diagnostics.rs:12:43 | LL | let _: anon_const_non_local::Foo<2> = anon_const_non_local::foo::(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2`, found `_` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2`, found `foo::::{constant#0}` | = note: expected constant `2` - found constant `_` + found constant `foo::::{constant#0}` error: aborting due to previous error From 1171fe5c455e63a1617d56f7dba2b7901182a1eb Mon Sep 17 00:00:00 2001 From: Boxy Date: Wed, 18 Jan 2023 04:45:35 +0000 Subject: [PATCH 131/230] i am free --- compiler/rustc_middle/src/ty/print/pretty.rs | 19 +++++++++++-------- ...egion_subtyping_basic.main.nll.0.32bit.mir | 2 +- ...egion_subtyping_basic.main.nll.0.64bit.mir | 2 +- .../non_local_anon_const_diagnostics.stderr | 4 ++-- tests/ui/limits/issue-15919-32.stderr | 2 +- tests/ui/limits/issue-17913.rs | 2 +- tests/ui/limits/issue-17913.stderr | 2 +- 7 files changed, 18 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index df37b2b4628b5..aed7051bb993d 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1290,15 +1290,18 @@ pub trait PrettyPrinter<'tcx>: p!(print_value_path(def.did, substs)) } DefKind::AnonConst => { - if def.is_local() { - let span = self.tcx().def_span(def.did); - if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) { - p!(write("{}", snip)) - } else { - p!(print_value_path(def.did, substs)) - } + if def.is_local() + && let span = self.tcx().def_span(def.did) + && let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) + { + p!(write("{}", snip)) } else { - p!(print_value_path(def.did, substs)) + // Do not call `print_value_path` as if a parent of this anon const is an impl it will + // attempt to print out the impl trait ref i.e. `::{constant#0}`. This would + // cause printing to enter an infinite recursion if the anon const is in the self type i.e. + // `impl Default for [T; 32 - 1 - 1 - 1] {` + // where we would try to print `<[T; /* print `constant#0` again */] as Default>::{constant#0}` + p!(write("{}::{}", self.tcx().crate_name(def.did.krate), self.tcx().def_path(def.did).to_string_no_crate_verbose())) } } defkind => bug!("`{:?}` has unexpcted defkind {:?}", ct, defkind), diff --git a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir index 8e6564a38b0bb..798e45df8ca76 100644 --- a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir +++ b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir @@ -22,7 +22,7 @@ | fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/region_subtyping_basic.rs:+0:11: +0:11 - let mut _1: [usize; Const { ty: usize, kind: Value(Leaf(0x00000003)) }]; // in scope 0 at $DIR/region_subtyping_basic.rs:+1:9: +1:14 + let mut _1: [usize; Const(Value(Leaf(0x00000003)): usize)]; // in scope 0 at $DIR/region_subtyping_basic.rs:+1:9: +1:14 let _3: usize; // in scope 0 at $DIR/region_subtyping_basic.rs:+2:16: +2:17 let mut _4: usize; // in scope 0 at $DIR/region_subtyping_basic.rs:+2:14: +2:18 let mut _5: bool; // in scope 0 at $DIR/region_subtyping_basic.rs:+2:14: +2:18 diff --git a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir index 74d44c6741a92..4767bfc76ed9d 100644 --- a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir +++ b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir @@ -22,7 +22,7 @@ | fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/region_subtyping_basic.rs:+0:11: +0:11 - let mut _1: [usize; Const { ty: usize, kind: Value(Leaf(0x0000000000000003)) }]; // in scope 0 at $DIR/region_subtyping_basic.rs:+1:9: +1:14 + let mut _1: [usize; Const(Value(Leaf(0x0000000000000003)): usize)]; // in scope 0 at $DIR/region_subtyping_basic.rs:+1:9: +1:14 let _3: usize; // in scope 0 at $DIR/region_subtyping_basic.rs:+2:16: +2:17 let mut _4: usize; // in scope 0 at $DIR/region_subtyping_basic.rs:+2:14: +2:18 let mut _5: bool; // in scope 0 at $DIR/region_subtyping_basic.rs:+2:14: +2:18 diff --git a/tests/ui/const-generics/generic_const_exprs/non_local_anon_const_diagnostics.stderr b/tests/ui/const-generics/generic_const_exprs/non_local_anon_const_diagnostics.stderr index c1a846acf8862..3926c830adb7a 100644 --- a/tests/ui/const-generics/generic_const_exprs/non_local_anon_const_diagnostics.stderr +++ b/tests/ui/const-generics/generic_const_exprs/non_local_anon_const_diagnostics.stderr @@ -2,10 +2,10 @@ error[E0308]: mismatched types --> $DIR/non_local_anon_const_diagnostics.rs:12:43 | LL | let _: anon_const_non_local::Foo<2> = anon_const_non_local::foo::(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2`, found `foo::::{constant#0}` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2`, found `anon_const_non_local::::foo::{constant#0}` | = note: expected constant `2` - found constant `foo::::{constant#0}` + found constant `anon_const_non_local::::foo::{constant#0}` error: aborting due to previous error diff --git a/tests/ui/limits/issue-15919-32.stderr b/tests/ui/limits/issue-15919-32.stderr index 133637f9a058b..0d79fc0c77069 100644 --- a/tests/ui/limits/issue-15919-32.stderr +++ b/tests/ui/limits/issue-15919-32.stderr @@ -1,4 +1,4 @@ -error: values of the type `[usize; 4294967295]` are too big for the current architecture +error: values of the type `[usize; usize::MAX]` are too big for the current architecture --> $DIR/issue-15919-32.rs:9:9 | LL | let x = [0usize; 0xffff_ffff]; diff --git a/tests/ui/limits/issue-17913.rs b/tests/ui/limits/issue-17913.rs index 8d4cbe2018461..56cf5d831bd7e 100644 --- a/tests/ui/limits/issue-17913.rs +++ b/tests/ui/limits/issue-17913.rs @@ -1,5 +1,5 @@ // build-fail -// normalize-stderr-test "\[&usize; \d+\]" -> "[&usize; N]" +// normalize-stderr-test "\[&usize; \d+\]" -> "[&usize; usize::MAX]" // error-pattern: too big for the current architecture // FIXME https://github.com/rust-lang/rust/issues/59774 diff --git a/tests/ui/limits/issue-17913.stderr b/tests/ui/limits/issue-17913.stderr index 9a6431d447004..684db53a91909 100644 --- a/tests/ui/limits/issue-17913.stderr +++ b/tests/ui/limits/issue-17913.stderr @@ -1,4 +1,4 @@ -error: values of the type `[&usize; N]` are too big for the current architecture +error: values of the type `[&usize; usize::MAX]` are too big for the current architecture error: aborting due to previous error From b738b0616093dbe6ce14bd640d44cf4252981d56 Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 11 Jan 2023 13:39:02 +0100 Subject: [PATCH 132/230] update cache --- Cargo.lock | 1 + compiler/rustc_trait_selection/Cargo.toml | 1 + compiler/rustc_trait_selection/src/lib.rs | 1 + .../rustc_trait_selection/src/solve/cache.rs | 200 ++++++++---------- 4 files changed, 91 insertions(+), 112 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 39fba4fa73197..b3afaaa35c0a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4783,6 +4783,7 @@ dependencies = [ "rustc_middle", "rustc_parse_format", "rustc_query_system", + "rustc_serialize", "rustc_session", "rustc_span", "rustc_target", diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index 67613e1a4ebc0..90d879976c260 100644 --- a/compiler/rustc_trait_selection/Cargo.toml +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -19,6 +19,7 @@ rustc_infer = { path = "../rustc_infer" } rustc_lint_defs = { path = "../rustc_lint_defs" } rustc_macros = { path = "../rustc_macros" } rustc_query_system = { path = "../rustc_query_system" } +rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index 081ac966c6961..6fa0941036390 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -21,6 +21,7 @@ #![feature(never_type)] #![feature(result_option_inspect)] #![feature(type_alias_impl_trait)] +#![feature(min_specialization)] #![recursion_limit = "512"] // For rustdoc #[macro_use] diff --git a/compiler/rustc_trait_selection/src/solve/cache.rs b/compiler/rustc_trait_selection/src/solve/cache.rs index f1ee73a5b853f..9ac629980eb72 100644 --- a/compiler/rustc_trait_selection/src/solve/cache.rs +++ b/compiler/rustc_trait_selection/src/solve/cache.rs @@ -11,22 +11,37 @@ use super::overflow::OverflowData; use super::{CanonicalGoal, Certainty, MaybeCause, Response}; use super::{EvalCtxt, QueryResult}; - use rustc_data_structures::fx::FxHashMap; +use rustc_index::vec::IndexVec; use rustc_infer::infer::canonical::{Canonical, CanonicalVarKind, CanonicalVarValues}; use rustc_middle::ty::{self, TyCtxt}; -use std::{cmp::Ordering, collections::hash_map::Entry}; +use std::collections::hash_map::Entry; + +rustc_index::newtype_index! { + pub struct StackDepth {} +} +rustc_index::newtype_index! { + pub struct EntryIndex {} +} #[derive(Debug, Clone)] struct ProvisionalEntry<'tcx> { // In case we have a coinductive cycle, this is the // the currently least restrictive result of this goal. response: QueryResult<'tcx>, - // The lowest element on the stack on which this result - // relies on. Starts out as just being the depth at which - // we've proven this obligation, but gets lowered to the - // depth of another goal if we rely on it in a cycle. - depth: usize, + // In case of a cycle, the depth of lowest stack entry involved + // in that cycle. This is monotonically decreasing in the stack as all + // elements between the current stack element in the lowest stack entry + // involved have to also be involved in that cycle. + // + // We can only move entries to the global cache once we're complete done + // with the cycle. If this entry has not been involved in a cycle, + // this is just its own depth. + depth: StackDepth, + + // The goal for this entry. Should always be equal to the corresponding goal + // in the lookup table. + goal: CanonicalGoal<'tcx>, } struct StackElem<'tcx> { @@ -34,61 +49,22 @@ struct StackElem<'tcx> { has_been_used: bool, } -/// The cache used for goals which are currently in progress or which depend -/// on in progress results. -/// -/// Once we're done with a goal we can store it in the global trait solver -/// cache of the `TyCtxt`. For goals which we're currently proving, or which -/// have only been proven via a coinductive cycle using a goal still on our stack -/// we have to use this separate data structure. -/// -/// The current data structure is not perfect, so there may still be room for -/// improvement here. We have the following requirements: -/// -/// ## Is there is a provisional entry for the given goal: -/// -/// ```ignore (for syntax highlighting) -/// self.entries.get(goal) -/// ``` -/// -/// ## Get all goals on the stack involved in a cycle: -/// -/// ```ignore (for syntax highlighting) -/// let entry = self.entries.get(goal).unwrap(); -/// let involved_goals = self.stack.iter().skip(entry.depth); -/// ``` -/// -/// ## Capping the depth of all entries -/// -/// Needed whenever we encounter a cycle. The current implementation always -/// iterates over all entries instead of only the ones with a larger depth. -/// Changing this may result in notable performance improvements. -/// -/// ```ignore (for syntax highlighting) -/// let cycle_depth = self.entries.get(goal).unwrap().depth; -/// for e in &mut self.entries { -/// e.depth = e.depth.min(cycle_depth); -/// } -/// ``` -/// -/// ## Checking whether we have to rerun the current goal -/// -/// A goal has to be rerun if its provisional result was used in a cycle -/// and that result is different from its final result. We update -/// [StackElem::has_been_used] for the deepest stack element involved in a cycle. -/// -/// ## Moving all finished goals into the global cache -/// -/// If `stack_elem.has_been_used` is true, iterate over all entries, moving the ones -/// with equal depth. If not, simply move this single entry. pub(super) struct ProvisionalCache<'tcx> { - stack: Vec>, - entries: FxHashMap, ProvisionalEntry<'tcx>>, + stack: IndexVec>, + entries: IndexVec>, + // FIXME: This is only used to quickly check whether a given goal + // is in the cache. We should experiment with using something like + // `SsoHashSet` here because in most cases there are only a few entries. + lookup_table: FxHashMap, EntryIndex>, } impl<'tcx> ProvisionalCache<'tcx> { pub(super) fn empty() -> ProvisionalCache<'tcx> { - ProvisionalCache { stack: Vec::new(), entries: Default::default() } + ProvisionalCache { + stack: Default::default(), + entries: Default::default(), + lookup_table: Default::default(), + } } pub(super) fn current_depth(&self) -> usize { @@ -108,18 +84,17 @@ impl<'tcx> EvalCtxt<'tcx> { // Look at the provisional cache to check for cycles. let cache = &mut self.provisional_cache; - match cache.entries.entry(goal) { + match cache.lookup_table.entry(goal) { // No entry, simply push this goal on the stack after dealing with overflow. Entry::Vacant(v) => { if self.overflow_data.has_overflow(cache.stack.len()) { return Err(self.deal_with_overflow(goal)); } - v.insert(ProvisionalEntry { - response: response_no_constraints(self.tcx, goal, Certainty::Yes), - depth: cache.stack.len(), - }); - cache.stack.push(StackElem { goal, has_been_used: false }); + let depth = cache.stack.push(StackElem { goal, has_been_used: false }); + let response = response_no_constraints(self.tcx, goal, Certainty::Yes); + let entry_index = cache.entries.push(ProvisionalEntry { response, depth, goal }); + v.insert(entry_index); Ok(()) } // We have a nested goal which relies on a goal `root` deeper in the stack. @@ -131,11 +106,12 @@ impl<'tcx> EvalCtxt<'tcx> { // // Finally we can return either the provisional response for that goal if we have a // coinductive cycle or an ambiguous result if the cycle is inductive. - Entry::Occupied(entry) => { - // FIXME: `ProvisionalEntry` should be `Copy`. - let entry = entry.get().clone(); + Entry::Occupied(entry_index) => { + let entry_index = *entry_index.get(); + // FIXME `ProvisionalEntry` should be `Copy`. + let entry = cache.entries.get(entry_index).unwrap().clone(); cache.stack[entry.depth].has_been_used = true; - for provisional_entry in cache.entries.values_mut() { + for provisional_entry in cache.entries.iter_mut().skip(entry_index.index()) { provisional_entry.depth = provisional_entry.depth.min(entry.depth); } @@ -143,9 +119,9 @@ impl<'tcx> EvalCtxt<'tcx> { // We can also depend on goals which aren't part of the stack but coinductively // depend on the stack themselves. We already checked whether all the goals // between these goals and their root on the stack. This means that as long as - // each goal in a cycle is checked for coinductivity by itself simply checking + // each goal in a cycle is checked for coinductivity by itself, simply checking // the stack is enough. - if cache.stack[entry.depth..] + if cache.stack.raw[entry.depth.index()..] .iter() .all(|g| g.goal.value.predicate.is_coinductive(self.tcx)) { @@ -154,7 +130,7 @@ impl<'tcx> EvalCtxt<'tcx> { Err(response_no_constraints( self.tcx, goal, - Certainty::Maybe(MaybeCause::Ambiguity), + Certainty::Maybe(MaybeCause::Overflow), )) } } @@ -182,49 +158,49 @@ impl<'tcx> EvalCtxt<'tcx> { let StackElem { goal, has_been_used } = cache.stack.pop().unwrap(); assert_eq!(goal, actual_goal); - let provisional_entry = cache.entries.get_mut(&goal).unwrap(); - // Check whether the current stack entry is the root of a cycle. - // - // If so, we either move all participants of that cycle to the global cache - // or, in case the provisional response used in the cycle is not equal to the - // final response, have to recompute the goal after updating the provisional - // response to the final response of this iteration. - if has_been_used { - if provisional_entry.response == response { - // We simply drop all entries according to an immutable condition, so - // query instability is not a concern here. - #[allow(rustc::potential_query_instability)] - cache.entries.retain(|goal, entry| match entry.depth.cmp(&cache.stack.len()) { - Ordering::Less => true, - Ordering::Equal => { - Self::try_move_finished_goal_to_global_cache( - self.tcx, - &mut self.overflow_data, - &cache.stack, - // FIXME: these should be `Copy` :( - goal.clone(), - entry.response.clone(), - ); - false - } - Ordering::Greater => bug!("entry with greater depth than the current leaf"), - }); + let provisional_entry_index = *cache.lookup_table.get(&goal).unwrap(); + let provisional_entry = &mut cache.entries[provisional_entry_index]; + // Was the current goal the root of a cycle and was the provisional response + // different from the final one. + if has_been_used && provisional_entry.response != response { + // If so, update the provisional reponse for this goal... + provisional_entry.response = response; + // ...remove all entries whose result depends on this goal + // from the provisional cache... + // + // That's not completely correct, as a nested goal can also + // depend on a goal which is lower in the stack so it doesn't + // actually depend on the current goal. This should be fairly + // rare and is hopefully not relevant for performance. + #[allow(rustc::potential_query_instability)] + cache.lookup_table.retain(|_key, index| *index <= provisional_entry_index); + cache.entries.truncate(provisional_entry_index.index() + 1); - true - } else { - provisional_entry.response = response; - cache.stack.push(StackElem { goal, has_been_used: false }); - false - } + // ...and finally push our goal back on the stack and reevaluate it. + cache.stack.push(StackElem { goal, has_been_used: false }); + false } else { - Self::try_move_finished_goal_to_global_cache( - self.tcx, - &mut self.overflow_data, - &cache.stack, - goal, - response, - ); - cache.entries.remove(&goal); + // If not, we're done with this goal. + // + // Check whether that this goal doesn't depend on a goal deeper on the stack + // and if so, move it and all nested goals to the global cache. + // + // Note that if any nested goal were to depend on something deeper on the stack, + // this would have also updated the depth of this goal. + if provisional_entry.depth == cache.stack.next_index() { + for (i, entry) in cache.entries.drain_enumerated(provisional_entry_index.index()..) + { + let actual_index = cache.lookup_table.remove(&entry.goal); + debug_assert_eq!(Some(i), actual_index); + Self::try_move_finished_goal_to_global_cache( + self.tcx, + &mut self.overflow_data, + &cache.stack, + entry.goal, + entry.response, + ); + } + } true } } @@ -232,7 +208,7 @@ impl<'tcx> EvalCtxt<'tcx> { fn try_move_finished_goal_to_global_cache( tcx: TyCtxt<'tcx>, overflow_data: &mut OverflowData, - stack: &[StackElem<'tcx>], + stack: &IndexVec>, goal: CanonicalGoal<'tcx>, response: QueryResult<'tcx>, ) { From bf7dbff9210497ca3db0b19b5ca0c6daed47e64e Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 17 Jan 2023 10:21:30 +0100 Subject: [PATCH 133/230] instantiate canonical vars eagerly --- compiler/rustc_middle/src/ty/sty.rs | 11 - .../src/solve/assembly.rs | 78 ++--- .../rustc_trait_selection/src/solve/cache.rs | 267 ------------------ .../src/solve/fulfill.rs | 26 +- .../src/solve/infcx_ext.rs | 37 --- .../rustc_trait_selection/src/solve/mod.rs | 212 ++++++++------ .../src/solve/project_goals.rs | 36 +-- .../src/solve/search_graph/cache.rs | 115 ++++++++ .../src/solve/search_graph/mod.rs | 172 +++++++++++ .../src/solve/{ => search_graph}/overflow.rs | 29 +- .../src/solve/trait_goals.rs | 22 +- 11 files changed, 509 insertions(+), 496 deletions(-) delete mode 100644 compiler/rustc_trait_selection/src/solve/cache.rs create mode 100644 compiler/rustc_trait_selection/src/solve/search_graph/cache.rs create mode 100644 compiler/rustc_trait_selection/src/solve/search_graph/mod.rs rename compiler/rustc_trait_selection/src/solve/{ => search_graph}/overflow.rs (74%) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 3f8252aefdc39..4166f79c96c82 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1106,17 +1106,6 @@ impl<'tcx, T> Binder<'tcx, T> { if self.0.has_escaping_bound_vars() { None } else { Some(self.skip_binder()) } } - pub fn no_bound_vars_ignoring_escaping(self, tcx: TyCtxt<'tcx>) -> Option - where - T: TypeFoldable<'tcx>, - { - if !self.0.has_escaping_bound_vars() { - Some(self.skip_binder()) - } else { - self.0.try_fold_with(&mut SkipBindersAt { index: ty::INNERMOST, tcx }).ok() - } - } - /// Splits the contents into two things that share the same binder /// level as the original, returning two distinct binders. /// diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs index ba68da0686fea..da6bb844a0fbe 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -1,20 +1,11 @@ //! Code shared by trait and projection goals for candidate assembly. use super::infcx_ext::InferCtxtExt; -use super::{ - instantiate_canonical_query_response, CanonicalGoal, CanonicalResponse, Certainty, EvalCtxt, - Goal, -}; +use super::{CanonicalResponse, Certainty, EvalCtxt, Goal}; use rustc_hir::def_id::DefId; -use rustc_infer::infer::TyCtxtInferExt; -use rustc_infer::infer::{ - canonical::{CanonicalVarValues, OriginalQueryValues}, - InferCtxt, -}; use rustc_infer::traits::query::NoSolution; use rustc_middle::ty::TypeFoldable; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::DUMMY_SP; use std::fmt::Debug; /// A candidate is a possible way to prove a goal. @@ -40,7 +31,7 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy { fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId; fn consider_impl_candidate( - acx: &mut AssemblyCtxt<'_, 'tcx, Self>, + acx: &mut AssemblyCtxt<'_, '_, 'tcx, Self>, goal: Goal<'tcx, Self>, impl_def_id: DefId, ); @@ -49,21 +40,17 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy { /// An abstraction which correctly deals with the canonical results for candidates. /// /// It also deduplicates the behavior between trait and projection predicates. -pub(super) struct AssemblyCtxt<'a, 'tcx, G: GoalKind<'tcx>> { - pub(super) cx: &'a mut EvalCtxt<'tcx>, - pub(super) infcx: &'a InferCtxt<'tcx>, - var_values: CanonicalVarValues<'tcx>, +pub(super) struct AssemblyCtxt<'a, 'b, 'tcx, G: GoalKind<'tcx>> { + pub(super) cx: &'a mut EvalCtxt<'b, 'tcx>, candidates: Vec>, } -impl<'a, 'tcx, G: GoalKind<'tcx>> AssemblyCtxt<'a, 'tcx, G> { +impl<'a, 'b, 'tcx, G: GoalKind<'tcx>> AssemblyCtxt<'a, 'b, 'tcx, G> { pub(super) fn assemble_and_evaluate_candidates( - cx: &'a mut EvalCtxt<'tcx>, - goal: CanonicalGoal<'tcx, G>, + cx: &'a mut EvalCtxt<'b, 'tcx>, + goal: Goal<'tcx, G>, ) -> Vec> { - let (ref infcx, goal, var_values) = - cx.tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &goal); - let mut acx = AssemblyCtxt { cx, infcx, var_values, candidates: Vec::new() }; + let mut acx = AssemblyCtxt { cx, candidates: Vec::new() }; acx.assemble_candidates_after_normalizing_self_ty(goal); @@ -77,7 +64,7 @@ impl<'a, 'tcx, G: GoalKind<'tcx>> AssemblyCtxt<'a, 'tcx, G> { source: G::CandidateSource, certainty: Certainty, ) { - match self.infcx.make_canonical_response(self.var_values.clone(), certainty) { + match self.cx.make_canonical_response(certainty) { Ok(result) => self.candidates.push(Candidate { source, result }), Err(NoSolution) => debug!(?source, ?certainty, "failed leakcheck"), } @@ -89,13 +76,14 @@ impl<'a, 'tcx, G: GoalKind<'tcx>> AssemblyCtxt<'a, 'tcx, G> { /// self type to the list of candidates in case that succeeds. Note that we can't just eagerly return in /// this case as projections as self types add ` fn assemble_candidates_after_normalizing_self_ty(&mut self, goal: Goal<'tcx, G>) { - let tcx = self.cx.tcx; + let tcx = self.cx.tcx(); + let infcx = self.cx.infcx; // FIXME: We also have to normalize opaque types, not sure where to best fit that in. let &ty::Alias(ty::Projection, projection_ty) = goal.predicate.self_ty().kind() else { return }; - self.infcx.probe(|_| { - let normalized_ty = self.infcx.next_ty_infer(); + infcx.probe(|_| { + let normalized_ty = infcx.next_ty_infer(); let normalizes_to_goal = goal.with( tcx, ty::Binder::dummy(ty::ProjectionPredicate { @@ -103,43 +91,31 @@ impl<'a, 'tcx, G: GoalKind<'tcx>> AssemblyCtxt<'a, 'tcx, G> { term: normalized_ty.into(), }), ); - let normalization_certainty = - match self.cx.evaluate_goal(&self.infcx, normalizes_to_goal) { - Ok((_, certainty)) => certainty, - Err(NoSolution) => return, - }; + let normalization_certainty = match self.cx.evaluate_goal(normalizes_to_goal) { + Ok((_, certainty)) => certainty, + Err(NoSolution) => return, + }; // NOTE: Alternatively we could call `evaluate_goal` here and only have a `Normalized` candidate. // This doesn't work as long as we use `CandidateSource` in both winnowing and to resolve associated items. let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty)); - let mut orig_values = OriginalQueryValues::default(); - let goal = self.infcx.canonicalize_query(goal, &mut orig_values); let normalized_candidates = AssemblyCtxt::assemble_and_evaluate_candidates(self.cx, goal); - - // Map each candidate from being canonical wrt the current inference context to being - // canonical wrt the caller. - for Candidate { source, result } in normalized_candidates { - self.infcx.probe(|_| { - let candidate_certainty = - instantiate_canonical_query_response(&self.infcx, &orig_values, result); - - // FIXME: This is a bit scary if the `normalizes_to_goal` overflows. - // - // If we have an ambiguous candidate it hides that normalization - // caused an overflow which may cause issues. - self.try_insert_candidate( - source, - normalization_certainty.unify_and(candidate_certainty), - ) - }) + for mut normalized_candidate in normalized_candidates { + normalized_candidate.result = + normalized_candidate.result.unchecked_map(|mut response| { + response.certainty = response.certainty.unify_and(normalization_certainty); + response + }); + self.candidates.push(normalized_candidate); } }) } fn assemble_impl_candidates(&mut self, goal: Goal<'tcx, G>) { - self.cx.tcx.for_each_relevant_impl( - goal.predicate.trait_def_id(self.cx.tcx), + let tcx = self.cx.tcx(); + tcx.for_each_relevant_impl( + goal.predicate.trait_def_id(tcx), goal.predicate.self_ty(), |impl_def_id| G::consider_impl_candidate(self, goal, impl_def_id), ); diff --git a/compiler/rustc_trait_selection/src/solve/cache.rs b/compiler/rustc_trait_selection/src/solve/cache.rs deleted file mode 100644 index 9ac629980eb72..0000000000000 --- a/compiler/rustc_trait_selection/src/solve/cache.rs +++ /dev/null @@ -1,267 +0,0 @@ -//! This module both handles the global cache which stores "finished" goals, -//! and the provisional cache which contains partially computed goals. -//! -//! The provisional cache is necessary when dealing with coinductive cycles. -//! -//! For more information about the provisional cache and coinduction in general, -//! check out the relevant section of the rustc-dev-guide. -//! -//! FIXME(@lcnr): Write that section, feel free to ping me if you need help here -//! before then or if I still haven't done that before January 2023. -use super::overflow::OverflowData; -use super::{CanonicalGoal, Certainty, MaybeCause, Response}; -use super::{EvalCtxt, QueryResult}; -use rustc_data_structures::fx::FxHashMap; -use rustc_index::vec::IndexVec; -use rustc_infer::infer::canonical::{Canonical, CanonicalVarKind, CanonicalVarValues}; -use rustc_middle::ty::{self, TyCtxt}; -use std::collections::hash_map::Entry; - -rustc_index::newtype_index! { - pub struct StackDepth {} -} -rustc_index::newtype_index! { - pub struct EntryIndex {} -} - -#[derive(Debug, Clone)] -struct ProvisionalEntry<'tcx> { - // In case we have a coinductive cycle, this is the - // the currently least restrictive result of this goal. - response: QueryResult<'tcx>, - // In case of a cycle, the depth of lowest stack entry involved - // in that cycle. This is monotonically decreasing in the stack as all - // elements between the current stack element in the lowest stack entry - // involved have to also be involved in that cycle. - // - // We can only move entries to the global cache once we're complete done - // with the cycle. If this entry has not been involved in a cycle, - // this is just its own depth. - depth: StackDepth, - - // The goal for this entry. Should always be equal to the corresponding goal - // in the lookup table. - goal: CanonicalGoal<'tcx>, -} - -struct StackElem<'tcx> { - goal: CanonicalGoal<'tcx>, - has_been_used: bool, -} - -pub(super) struct ProvisionalCache<'tcx> { - stack: IndexVec>, - entries: IndexVec>, - // FIXME: This is only used to quickly check whether a given goal - // is in the cache. We should experiment with using something like - // `SsoHashSet` here because in most cases there are only a few entries. - lookup_table: FxHashMap, EntryIndex>, -} - -impl<'tcx> ProvisionalCache<'tcx> { - pub(super) fn empty() -> ProvisionalCache<'tcx> { - ProvisionalCache { - stack: Default::default(), - entries: Default::default(), - lookup_table: Default::default(), - } - } - - pub(super) fn current_depth(&self) -> usize { - self.stack.len() - } -} - -impl<'tcx> EvalCtxt<'tcx> { - /// Tries putting the new goal on the stack, returning an error if it is already cached. - /// - /// This correctly updates the provisional cache if there is a cycle. - pub(super) fn try_push_stack( - &mut self, - goal: CanonicalGoal<'tcx>, - ) -> Result<(), QueryResult<'tcx>> { - // FIXME: start by checking the global cache - - // Look at the provisional cache to check for cycles. - let cache = &mut self.provisional_cache; - match cache.lookup_table.entry(goal) { - // No entry, simply push this goal on the stack after dealing with overflow. - Entry::Vacant(v) => { - if self.overflow_data.has_overflow(cache.stack.len()) { - return Err(self.deal_with_overflow(goal)); - } - - let depth = cache.stack.push(StackElem { goal, has_been_used: false }); - let response = response_no_constraints(self.tcx, goal, Certainty::Yes); - let entry_index = cache.entries.push(ProvisionalEntry { response, depth, goal }); - v.insert(entry_index); - Ok(()) - } - // We have a nested goal which relies on a goal `root` deeper in the stack. - // - // We first store that we may have to rerun `evaluate_goal` for `root` in case the - // provisional response is not equal to the final response. We also update the depth - // of all goals which recursively depend on our current goal to depend on `root` - // instead. - // - // Finally we can return either the provisional response for that goal if we have a - // coinductive cycle or an ambiguous result if the cycle is inductive. - Entry::Occupied(entry_index) => { - let entry_index = *entry_index.get(); - // FIXME `ProvisionalEntry` should be `Copy`. - let entry = cache.entries.get(entry_index).unwrap().clone(); - cache.stack[entry.depth].has_been_used = true; - for provisional_entry in cache.entries.iter_mut().skip(entry_index.index()) { - provisional_entry.depth = provisional_entry.depth.min(entry.depth); - } - - // NOTE: The goals on the stack aren't the only goals involved in this cycle. - // We can also depend on goals which aren't part of the stack but coinductively - // depend on the stack themselves. We already checked whether all the goals - // between these goals and their root on the stack. This means that as long as - // each goal in a cycle is checked for coinductivity by itself, simply checking - // the stack is enough. - if cache.stack.raw[entry.depth.index()..] - .iter() - .all(|g| g.goal.value.predicate.is_coinductive(self.tcx)) - { - Err(entry.response) - } else { - Err(response_no_constraints( - self.tcx, - goal, - Certainty::Maybe(MaybeCause::Overflow), - )) - } - } - } - } - - /// We cannot simply store the result of [EvalCtxt::compute_goal] as we have to deal with - /// coinductive cycles. - /// - /// When we encounter a coinductive cycle, we have to prove the final result of that cycle - /// while we are still computing that result. Because of this we continously recompute the - /// cycle until the result of the previous iteration is equal to the final result, at which - /// point we are done. - /// - /// This function returns `true` if we were able to finalize the goal and `false` if it has - /// updated the provisional cache and we have to recompute the current goal. - /// - /// FIXME: Refer to the rustc-dev-guide entry once it exists. - pub(super) fn try_finalize_goal( - &mut self, - actual_goal: CanonicalGoal<'tcx>, - response: QueryResult<'tcx>, - ) -> bool { - let cache = &mut self.provisional_cache; - let StackElem { goal, has_been_used } = cache.stack.pop().unwrap(); - assert_eq!(goal, actual_goal); - - let provisional_entry_index = *cache.lookup_table.get(&goal).unwrap(); - let provisional_entry = &mut cache.entries[provisional_entry_index]; - // Was the current goal the root of a cycle and was the provisional response - // different from the final one. - if has_been_used && provisional_entry.response != response { - // If so, update the provisional reponse for this goal... - provisional_entry.response = response; - // ...remove all entries whose result depends on this goal - // from the provisional cache... - // - // That's not completely correct, as a nested goal can also - // depend on a goal which is lower in the stack so it doesn't - // actually depend on the current goal. This should be fairly - // rare and is hopefully not relevant for performance. - #[allow(rustc::potential_query_instability)] - cache.lookup_table.retain(|_key, index| *index <= provisional_entry_index); - cache.entries.truncate(provisional_entry_index.index() + 1); - - // ...and finally push our goal back on the stack and reevaluate it. - cache.stack.push(StackElem { goal, has_been_used: false }); - false - } else { - // If not, we're done with this goal. - // - // Check whether that this goal doesn't depend on a goal deeper on the stack - // and if so, move it and all nested goals to the global cache. - // - // Note that if any nested goal were to depend on something deeper on the stack, - // this would have also updated the depth of this goal. - if provisional_entry.depth == cache.stack.next_index() { - for (i, entry) in cache.entries.drain_enumerated(provisional_entry_index.index()..) - { - let actual_index = cache.lookup_table.remove(&entry.goal); - debug_assert_eq!(Some(i), actual_index); - Self::try_move_finished_goal_to_global_cache( - self.tcx, - &mut self.overflow_data, - &cache.stack, - entry.goal, - entry.response, - ); - } - } - true - } - } - - fn try_move_finished_goal_to_global_cache( - tcx: TyCtxt<'tcx>, - overflow_data: &mut OverflowData, - stack: &IndexVec>, - goal: CanonicalGoal<'tcx>, - response: QueryResult<'tcx>, - ) { - // We move goals to the global cache if we either did not hit an overflow or if it's - // the root goal as that will now always hit the same overflow limit. - // - // NOTE: We cannot move any non-root goals to the global cache even if their final result - // isn't impacted by the overflow as that goal still has unstable query dependencies - // because it didn't go its full depth. - // - // FIXME(@lcnr): We could still cache subtrees which are not impacted by overflow though. - // Tracking that info correctly isn't trivial, so I haven't implemented it for now. - let should_cache_globally = !overflow_data.did_overflow() || stack.is_empty(); - if should_cache_globally { - // FIXME: move the provisional entry to the global cache. - let _ = (tcx, goal, response); - } - } -} - -pub(super) fn response_no_constraints<'tcx>( - tcx: TyCtxt<'tcx>, - goal: Canonical<'tcx, impl Sized>, - certainty: Certainty, -) -> QueryResult<'tcx> { - let var_values = goal - .variables - .iter() - .enumerate() - .map(|(i, info)| match info.kind { - CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => { - tcx.mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_usize(i).into())).into() - } - CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => { - let br = ty::BoundRegion { - var: ty::BoundVar::from_usize(i), - kind: ty::BrAnon(i as u32, None), - }; - tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into() - } - CanonicalVarKind::Const(_, ty) | CanonicalVarKind::PlaceholderConst(_, ty) => tcx - .mk_const(ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_usize(i)), ty) - .into(), - }) - .collect(); - - Ok(Canonical { - max_universe: goal.max_universe, - variables: goal.variables, - value: Response { - var_values: CanonicalVarValues { var_values }, - external_constraints: Default::default(), - certainty, - }, - }) -} diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index dfc2b5ed32947..3146f468f7d81 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -2,7 +2,7 @@ use std::mem; use rustc_data_structures::fx::FxHashMap; use rustc_infer::{ - infer::InferCtxt, + infer::{canonical::OriginalQueryValues, InferCtxt}, traits::{ query::NoSolution, FulfillmentError, FulfillmentErrorCode, PredicateObligation, SelectionError, TraitEngine, @@ -67,10 +67,26 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { let mut has_changed = false; for obligation in mem::take(&mut self.obligations) { - let mut cx = EvalCtxt::new(infcx.tcx); - let (changed, certainty) = match cx.evaluate_goal(infcx, obligation.clone().into()) - { - Ok(result) => result, + let goal = obligation.clone().into(); + + // FIXME: Add a better API for that '^^ + let mut orig_values = OriginalQueryValues::default(); + let canonical_goal = infcx.canonicalize_query(goal, &mut orig_values); + let (changed, certainty) = match EvalCtxt::evaluate_canonical_goal( + infcx.tcx, + &mut super::search_graph::SearchGraph::new(infcx.tcx), + canonical_goal, + ) { + Ok(canonical_response) => { + ( + true, // FIXME: check whether `var_values` are an identity substitution. + super::instantiate_canonical_query_response( + infcx, + &orig_values, + canonical_response, + ), + ) + } Err(NoSolution) => { errors.push(FulfillmentError { obligation: obligation.clone(), diff --git a/compiler/rustc_trait_selection/src/solve/infcx_ext.rs b/compiler/rustc_trait_selection/src/solve/infcx_ext.rs index 436f4eea6625b..8a8c3091d549f 100644 --- a/compiler/rustc_trait_selection/src/solve/infcx_ext.rs +++ b/compiler/rustc_trait_selection/src/solve/infcx_ext.rs @@ -1,23 +1,11 @@ -use rustc_infer::infer::canonical::CanonicalVarValues; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::InferCtxt; -use rustc_infer::traits::query::NoSolution; use rustc_middle::ty::Ty; use rustc_span::DUMMY_SP; -use crate::solve::ExternalConstraints; - -use super::{Certainty, QueryResult, Response}; - /// Methods used inside of the canonical queries of the solver. pub(super) trait InferCtxtExt<'tcx> { fn next_ty_infer(&self) -> Ty<'tcx>; - - fn make_canonical_response( - &self, - var_values: CanonicalVarValues<'tcx>, - certainty: Certainty, - ) -> QueryResult<'tcx>; } impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { @@ -27,29 +15,4 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { span: DUMMY_SP, }) } - - fn make_canonical_response( - &self, - var_values: CanonicalVarValues<'tcx>, - certainty: Certainty, - ) -> QueryResult<'tcx> { - let external_constraints = take_external_constraints(self)?; - - Ok(self.canonicalize_response(Response { var_values, external_constraints, certainty })) - } -} - -#[instrument(level = "debug", skip(infcx), ret)] -fn take_external_constraints<'tcx>( - infcx: &InferCtxt<'tcx>, -) -> Result, NoSolution> { - let region_obligations = infcx.take_registered_region_obligations(); - let opaque_types = infcx.take_opaque_types_for_query_response(); - Ok(ExternalConstraints { - // FIXME: Now that's definitely wrong :) - // - // Should also do the leak check here I think - regions: drop(region_obligations), - opaque_types, - }) } diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 80775b7aaf2c0..0e629664b2b1a 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -19,27 +19,23 @@ use std::mem; +use rustc_infer::infer::canonical::{Canonical, CanonicalVarKind, CanonicalVarValues}; use rustc_infer::infer::canonical::{OriginalQueryValues, QueryRegionConstraints, QueryResponse}; use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt}; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::Obligation; use rustc_middle::infer::canonical::Certainty as OldCertainty; -use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{RegionOutlivesPredicate, ToPredicate, TypeOutlivesPredicate}; use rustc_span::DUMMY_SP; use crate::traits::ObligationCause; -use self::cache::response_no_constraints; -use self::infcx_ext::InferCtxtExt; - mod assembly; -mod cache; mod fulfill; mod infcx_ext; -mod overflow; mod project_goals; +mod search_graph; mod trait_goals; pub use fulfill::FulfillmentCtxt; @@ -146,45 +142,25 @@ pub trait TyCtxtExt<'tcx> { impl<'tcx> TyCtxtExt<'tcx> for TyCtxt<'tcx> { fn evaluate_goal(self, goal: CanonicalGoal<'tcx>) -> QueryResult<'tcx> { - let mut cx = EvalCtxt::new(self); - cx.evaluate_canonical_goal(goal) + let mut search_graph = search_graph::SearchGraph::new(self); + EvalCtxt::evaluate_canonical_goal(self, &mut search_graph, goal) } } -struct EvalCtxt<'tcx> { - tcx: TyCtxt<'tcx>, +struct EvalCtxt<'a, 'tcx> { + infcx: &'a InferCtxt<'tcx>, + var_values: CanonicalVarValues<'tcx>, - provisional_cache: cache::ProvisionalCache<'tcx>, - overflow_data: overflow::OverflowData, + search_graph: &'a mut search_graph::SearchGraph<'tcx>, } -impl<'tcx> EvalCtxt<'tcx> { - fn new(tcx: TyCtxt<'tcx>) -> EvalCtxt<'tcx> { - EvalCtxt { - tcx, - provisional_cache: cache::ProvisionalCache::empty(), - overflow_data: overflow::OverflowData::new(tcx), - } - } - - /// Recursively evaluates `goal`, returning whether any inference vars have - /// been constrained and the certainty of the result. - fn evaluate_goal( - &mut self, - infcx: &InferCtxt<'tcx>, - goal: Goal<'tcx, ty::Predicate<'tcx>>, - ) -> Result<(bool, Certainty), NoSolution> { - let mut orig_values = OriginalQueryValues::default(); - let canonical_goal = infcx.canonicalize_query(goal, &mut orig_values); - let canonical_response = self.evaluate_canonical_goal(canonical_goal)?; - Ok(( - !canonical_response.value.var_values.is_identity(), - instantiate_canonical_query_response(infcx, &orig_values, canonical_response), - )) - } - - fn evaluate_canonical_goal(&mut self, goal: CanonicalGoal<'tcx>) -> QueryResult<'tcx> { - match self.try_push_stack(goal) { +impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { + fn evaluate_canonical_goal( + tcx: TyCtxt<'tcx>, + search_graph: &'a mut search_graph::SearchGraph<'tcx>, + canonical_goal: CanonicalGoal<'tcx>, + ) -> QueryResult<'tcx> { + match search_graph.try_push_stack(tcx, canonical_goal) { Ok(()) => {} // Our goal is already on the stack, eager return. Err(response) => return response, @@ -195,41 +171,65 @@ impl<'tcx> EvalCtxt<'tcx> { // // FIXME: Similar to `evaluate_all`, this has to check for overflow. loop { - let result = self.compute_goal(goal); + let (ref infcx, goal, var_values) = + tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical_goal); + let mut ecx = EvalCtxt { infcx, var_values, search_graph }; + let result = ecx.compute_goal(goal); // FIXME: `Response` should be `Copy` - if self.try_finalize_goal(goal, result.clone()) { + if search_graph.try_finalize_goal(tcx, canonical_goal, result.clone()) { return result; } } } - fn compute_goal(&mut self, canonical_goal: CanonicalGoal<'tcx>) -> QueryResult<'tcx> { - // WARNING: We're looking at a canonical value without instantiating it here. - // - // We have to be incredibly careful to not change the order of bound variables or - // remove any. As we go from `Goal<'tcx, Predicate>` to `Goal` with the variants - // of `PredicateKind` this is the case and it is and faster than instantiating and - // recanonicalizing. - let Goal { param_env, predicate } = canonical_goal.value; + fn tcx(&self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + + fn make_canonical_response(&self, certainty: Certainty) -> QueryResult<'tcx> { + let external_constraints = take_external_constraints(self.infcx)?; + + Ok(self.infcx.canonicalize_response(Response { + var_values: self.var_values.clone(), + external_constraints, + certainty, + })) + } + + /// Recursively evaluates `goal`, returning whether any inference vars have + /// been constrained and the certainty of the result. + fn evaluate_goal( + &mut self, + goal: Goal<'tcx, ty::Predicate<'tcx>>, + ) -> Result<(bool, Certainty), NoSolution> { + let mut orig_values = OriginalQueryValues::default(); + let canonical_goal = self.infcx.canonicalize_query(goal, &mut orig_values); + let canonical_response = + EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?; + Ok(( + !canonical_response.value.var_values.is_identity(), + instantiate_canonical_query_response(self.infcx, &orig_values, canonical_response), + )) + } - if let Some(kind) = predicate.kind().no_bound_vars_ignoring_escaping(self.tcx) { + fn compute_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) -> QueryResult<'tcx> { + let Goal { param_env, predicate } = goal; + let kind = predicate.kind(); + if let Some(kind) = kind.no_bound_vars() { match kind { - ty::PredicateKind::Clause(ty::Clause::Trait(predicate)) => self.compute_trait_goal( - canonical_goal.unchecked_rebind(Goal { param_env, predicate }), - ), - ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) => self - .compute_projection_goal( - canonical_goal.unchecked_rebind(Goal { param_env, predicate }), - ), - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(predicate)) => self - .compute_type_outlives_goal( - canonical_goal.unchecked_rebind(Goal { param_env, predicate }), - ), - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(predicate)) => self - .compute_region_outlives_goal( - canonical_goal.unchecked_rebind(Goal { param_env, predicate }), - ), + ty::PredicateKind::Clause(ty::Clause::Trait(predicate)) => { + self.compute_trait_goal(Goal { param_env, predicate }) + } + ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) => { + self.compute_projection_goal(Goal { param_env, predicate }) + } + ty::PredicateKind::Clause(ty::Clause::TypeOutlives(predicate)) => { + self.compute_type_outlives_goal(Goal { param_env, predicate }) + } + ty::PredicateKind::Clause(ty::Clause::RegionOutlives(predicate)) => { + self.compute_region_outlives_goal(Goal { param_env, predicate }) + } // FIXME: implement these predicates :) ty::PredicateKind::WellFormed(_) | ty::PredicateKind::ObjectSafe(_) @@ -239,49 +239,41 @@ impl<'tcx> EvalCtxt<'tcx> { | ty::PredicateKind::ConstEvaluatable(_) | ty::PredicateKind::ConstEquate(_, _) | ty::PredicateKind::TypeWellFormedFromEnv(_) - | ty::PredicateKind::Ambiguous => { - // FIXME - response_no_constraints(self.tcx, canonical_goal, Certainty::Yes) - } + | ty::PredicateKind::Ambiguous => self.make_canonical_response(Certainty::Yes), } } else { - let (infcx, goal, var_values) = - self.tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical_goal); - let kind = infcx.replace_bound_vars_with_placeholders(goal.predicate.kind()); - let goal = goal.with(self.tcx, ty::Binder::dummy(kind)); - let (_, certainty) = self.evaluate_goal(&infcx, goal)?; - infcx.make_canonical_response(var_values, certainty) + let kind = self.infcx.replace_bound_vars_with_placeholders(kind); + let goal = goal.with(self.tcx(), ty::Binder::dummy(kind)); + let (_, certainty) = self.evaluate_goal(goal)?; + self.make_canonical_response(certainty) } } fn compute_type_outlives_goal( &mut self, - goal: CanonicalGoal<'tcx, TypeOutlivesPredicate<'tcx>>, + _goal: Goal<'tcx, TypeOutlivesPredicate<'tcx>>, ) -> QueryResult<'tcx> { - // FIXME - response_no_constraints(self.tcx, goal, Certainty::Yes) + self.make_canonical_response(Certainty::Yes) } fn compute_region_outlives_goal( &mut self, - goal: CanonicalGoal<'tcx, RegionOutlivesPredicate<'tcx>>, + _goal: Goal<'tcx, RegionOutlivesPredicate<'tcx>>, ) -> QueryResult<'tcx> { - // FIXME - response_no_constraints(self.tcx, goal, Certainty::Yes) + self.make_canonical_response(Certainty::Yes) } } -impl<'tcx> EvalCtxt<'tcx> { +impl<'tcx> EvalCtxt<'_, 'tcx> { fn evaluate_all( &mut self, - infcx: &InferCtxt<'tcx>, mut goals: Vec>>, ) -> Result { let mut new_goals = Vec::new(); self.repeat_while_none(|this| { let mut has_changed = Err(Certainty::Yes); for goal in goals.drain(..) { - let (changed, certainty) = match this.evaluate_goal(infcx, goal) { + let (changed, certainty) = match this.evaluate_goal(goal) { Ok(result) => result, Err(NoSolution) => return Some(Err(NoSolution)), }; @@ -310,6 +302,21 @@ impl<'tcx> EvalCtxt<'tcx> { } } +#[instrument(level = "debug", skip(infcx), ret)] +fn take_external_constraints<'tcx>( + infcx: &InferCtxt<'tcx>, +) -> Result, NoSolution> { + let region_obligations = infcx.take_registered_region_obligations(); + let opaque_types = infcx.take_opaque_types_for_query_response(); + Ok(ExternalConstraints { + // FIXME: Now that's definitely wrong :) + // + // Should also do the leak check here I think + regions: drop(region_obligations), + opaque_types, + }) +} + fn instantiate_canonical_query_response<'tcx>( infcx: &InferCtxt<'tcx>, original_values: &OriginalQueryValues<'tcx>, @@ -334,3 +341,40 @@ fn instantiate_canonical_query_response<'tcx>( assert!(obligations.is_empty()); value } + +pub(super) fn response_no_constraints<'tcx>( + tcx: TyCtxt<'tcx>, + goal: Canonical<'tcx, impl Sized>, + certainty: Certainty, +) -> QueryResult<'tcx> { + let var_values = goal + .variables + .iter() + .enumerate() + .map(|(i, info)| match info.kind { + CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => { + tcx.mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_usize(i).into())).into() + } + CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => { + let br = ty::BoundRegion { + var: ty::BoundVar::from_usize(i), + kind: ty::BrAnon(i as u32, None), + }; + tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into() + } + CanonicalVarKind::Const(_, ty) | CanonicalVarKind::PlaceholderConst(_, ty) => tcx + .mk_const(ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_usize(i)), ty) + .into(), + }) + .collect(); + + Ok(Canonical { + max_universe: goal.max_universe, + variables: goal.variables, + value: Response { + var_values: CanonicalVarValues { var_values }, + external_constraints: Default::default(), + certainty, + }, + }) +} diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index d2f2e78f555ae..1120dfb809862 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -1,7 +1,7 @@ use crate::traits::{specialization_graph, translate_substs}; use super::assembly::{self, AssemblyCtxt}; -use super::{CanonicalGoal, EvalCtxt, Goal, QueryResult}; +use super::{EvalCtxt, Goal, QueryResult}; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; @@ -26,10 +26,10 @@ pub(super) enum CandidateSource { type Candidate<'tcx> = assembly::Candidate<'tcx, ProjectionPredicate<'tcx>>; -impl<'tcx> EvalCtxt<'tcx> { +impl<'tcx> EvalCtxt<'_, 'tcx> { pub(super) fn compute_projection_goal( &mut self, - goal: CanonicalGoal<'tcx, ProjectionPredicate<'tcx>>, + goal: Goal<'tcx, ProjectionPredicate<'tcx>>, ) -> QueryResult<'tcx> { let candidates = AssemblyCtxt::assemble_and_evaluate_candidates(self, goal); self.merge_project_candidates(candidates) @@ -104,11 +104,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { } fn consider_impl_candidate( - acx: &mut AssemblyCtxt<'_, 'tcx, ProjectionPredicate<'tcx>>, + acx: &mut AssemblyCtxt<'_, '_, 'tcx, ProjectionPredicate<'tcx>>, goal: Goal<'tcx, ProjectionPredicate<'tcx>>, impl_def_id: DefId, ) { - let tcx = acx.cx.tcx; + let tcx = acx.cx.tcx(); + let infcx = acx.cx.infcx; + let goal_trait_ref = goal.predicate.projection_ty.trait_ref(tcx); let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsPlaceholder }; @@ -118,12 +120,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { return; } - acx.infcx.probe(|_| { - let impl_substs = acx.infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id); + infcx.probe(|_| { + let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id); let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs); - let Ok(InferOk { obligations, .. }) = acx - .infcx + let Ok(InferOk { obligations, .. }) = infcx .at(&ObligationCause::dummy(), goal.param_env) .define_opaque_types(false) .eq(goal_trait_ref, impl_trait_ref) @@ -138,11 +139,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { .into_iter() .map(|pred| goal.with(tcx, pred)); - let nested_goals = obligations.into_iter().map(|o| o.into()).chain(where_clause_bounds).collect(); - let Ok(trait_ref_certainty) = acx.cx.evaluate_all(acx.infcx, nested_goals) else { return }; + let nested_goals = + obligations.into_iter().map(|o| o.into()).chain(where_clause_bounds).collect(); + let Ok(trait_ref_certainty) = acx.cx.evaluate_all(nested_goals) else { return }; let Some(assoc_def) = fetch_eligible_assoc_item_def( - acx.infcx, + infcx, goal.param_env, goal_trait_ref, goal.predicate.def_id(), @@ -174,7 +176,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { impl_substs, ); let substs = translate_substs( - acx.infcx, + infcx, goal.param_env, impl_def_id, impl_substs_with_gat, @@ -185,7 +187,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { let is_const = matches!(tcx.def_kind(assoc_def.item.def_id), DefKind::AssocConst); let ty = tcx.bound_type_of(assoc_def.item.def_id); let term: ty::EarlyBinder> = if is_const { - let identity_substs = ty::InternalSubsts::identity_for_item(tcx, assoc_def.item.def_id); + let identity_substs = + ty::InternalSubsts::identity_for_item(tcx, assoc_def.item.def_id); let did = ty::WithOptConstParam::unknown(assoc_def.item.def_id); let kind = ty::ConstKind::Unevaluated(ty::UnevaluatedConst::new(did, identity_substs)); @@ -194,8 +197,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ty.map_bound(|ty| ty.into()) }; - let Ok(InferOk { obligations, .. }) = acx - .infcx + let Ok(InferOk { obligations, .. }) = infcx .at(&ObligationCause::dummy(), goal.param_env) .define_opaque_types(false) .eq(goal.predicate.term, term.subst(tcx, substs)) @@ -205,7 +207,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { }; let nested_goals = obligations.into_iter().map(|o| o.into()).collect(); - let Ok(rhs_certainty) = acx.cx.evaluate_all(acx.infcx, nested_goals) else { return }; + let Ok(rhs_certainty) = acx.cx.evaluate_all(nested_goals) else { return }; let certainty = trait_ref_certainty.unify_and(rhs_certainty); acx.try_insert_candidate(CandidateSource::Impl(impl_def_id), certainty); diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/cache.rs b/compiler/rustc_trait_selection/src/solve/search_graph/cache.rs new file mode 100644 index 0000000000000..435e46f211a04 --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/search_graph/cache.rs @@ -0,0 +1,115 @@ +//! This module both handles the global cache which stores "finished" goals, +//! and the provisional cache which contains partially computed goals. +//! +//! The provisional cache is necessary when dealing with coinductive cycles. +//! +//! For more information about the provisional cache and coinduction in general, +//! check out the relevant section of the rustc-dev-guide. +//! +//! FIXME(@lcnr): Write that section, feel free to ping me if you need help here +//! before then or if I still haven't done that before January 2023. +use super::overflow::OverflowData; +use super::StackDepth; +use crate::solve::{CanonicalGoal, QueryResult}; +use rustc_data_structures::fx::FxHashMap; +use rustc_index::vec::IndexVec; +use rustc_middle::ty::TyCtxt; + +rustc_index::newtype_index! { + pub struct EntryIndex {} +} + +#[derive(Debug, Clone)] +pub(super) struct ProvisionalEntry<'tcx> { + // In case we have a coinductive cycle, this is the + // the currently least restrictive result of this goal. + pub(super) response: QueryResult<'tcx>, + // In case of a cycle, the position of deepest stack entry involved + // in that cycle. This is monotonically decreasing in the stack as all + // elements between the current stack element in the deepest stack entry + // involved have to also be involved in that cycle. + // + // We can only move entries to the global cache once we're complete done + // with the cycle. If this entry has not been involved in a cycle, + // this is just its own depth. + pub(super) depth: StackDepth, + + // The goal for this entry. Should always be equal to the corresponding goal + // in the lookup table. + pub(super) goal: CanonicalGoal<'tcx>, +} + +pub(super) struct ProvisionalCache<'tcx> { + pub(super) entries: IndexVec>, + // FIXME: This is only used to quickly check whether a given goal + // is in the cache. We should experiment with using something like + // `SsoHashSet` here because in most cases there are only a few entries. + pub(super) lookup_table: FxHashMap, EntryIndex>, +} + +impl<'tcx> ProvisionalCache<'tcx> { + pub(super) fn empty() -> ProvisionalCache<'tcx> { + ProvisionalCache { entries: Default::default(), lookup_table: Default::default() } + } + + /// Adds a dependency from the current leaf to `target` in the cache + /// to prevent us from moving any goals which depend on the current leaf + /// to the global cache while we're still computing `target`. + pub(super) fn add_dependency_of_leaf_on(&mut self, target: EntryIndex) { + let depth = self.entries[target].depth; + for provisional_entry in &mut self.entries.raw[target.index()..] { + // The depth of `target` is the position of the deepest goal in the stack + // on which `target` depends. That goal is the `root` of this cycle. + // + // Any entry which was added after `target` is either on the stack itself + // at which point its depth is definitely at least as high as the depth of + // `root`. If it's not on the stack itself it has to depend on a goal + // between `root` and `leaf`. If it were to depend on a goal deeper in the + // stack than `root`, then `root` would also depend on that goal, at which + // point `root` wouldn't be the root anymore. + debug_assert!(provisional_entry.depth >= depth); + provisional_entry.depth = depth; + } + + // We only update entries which were added after `target` as no other + // entry should have a higher depth. + // + // Any entry which previously had a higher depth than target has to + // be between `target` and `root`. Because of this we would have updated + // its depth when calling `add_dependency_of_leaf_on(root)` for `target`. + if cfg!(debug_assertions) { + self.entries.iter().all(|e| e.depth <= depth); + } + } + + pub(super) fn depth(&self, entry_index: EntryIndex) -> StackDepth { + self.entries[entry_index].depth + } + + pub(super) fn provisional_result(&self, entry_index: EntryIndex) -> QueryResult<'tcx> { + self.entries[entry_index].response.clone() + } +} + +pub(super) fn try_move_finished_goal_to_global_cache<'tcx>( + tcx: TyCtxt<'tcx>, + overflow_data: &mut OverflowData, + stack: &IndexVec>, + goal: CanonicalGoal<'tcx>, + response: QueryResult<'tcx>, +) { + // We move goals to the global cache if we either did not hit an overflow or if it's + // the root goal as that will now always hit the same overflow limit. + // + // NOTE: We cannot move any non-root goals to the global cache even if their final result + // isn't impacted by the overflow as that goal still has unstable query dependencies + // because it didn't go its full depth. + // + // FIXME(@lcnr): We could still cache subtrees which are not impacted by overflow though. + // Tracking that info correctly isn't trivial, so I haven't implemented it for now. + let should_cache_globally = !overflow_data.did_overflow() || stack.is_empty(); + if should_cache_globally { + // FIXME: move the provisional entry to the global cache. + let _ = (tcx, goal, response); + } +} diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs new file mode 100644 index 0000000000000..8d2a3a9cd818e --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs @@ -0,0 +1,172 @@ +mod cache; +mod overflow; + +use self::cache::ProvisionalEntry; +use super::{CanonicalGoal, Certainty, MaybeCause, QueryResult}; +use cache::ProvisionalCache; +use overflow::OverflowData; +use rustc_index::vec::IndexVec; +use rustc_middle::ty::TyCtxt; +use std::collections::hash_map::Entry; + +rustc_index::newtype_index! { + pub struct StackDepth {} +} + +struct StackElem<'tcx> { + goal: CanonicalGoal<'tcx>, + has_been_used: bool, +} + +pub(super) struct SearchGraph<'tcx> { + /// The stack of goals currently being computed. + /// + /// An element is *deeper* in the stack if its index is *lower*. + stack: IndexVec>, + overflow_data: OverflowData, + provisional_cache: ProvisionalCache<'tcx>, +} + +impl<'tcx> SearchGraph<'tcx> { + pub(super) fn new(tcx: TyCtxt<'tcx>) -> SearchGraph<'tcx> { + Self { + stack: Default::default(), + overflow_data: OverflowData::new(tcx), + provisional_cache: ProvisionalCache::empty(), + } + } + + /// Tries putting the new goal on the stack, returning an error if it is already cached. + /// + /// This correctly updates the provisional cache if there is a cycle. + pub(super) fn try_push_stack( + &mut self, + tcx: TyCtxt<'tcx>, + goal: CanonicalGoal<'tcx>, + ) -> Result<(), QueryResult<'tcx>> { + // FIXME: start by checking the global cache + + // Look at the provisional cache to check for cycles. + let cache = &mut self.provisional_cache; + match cache.lookup_table.entry(goal) { + // No entry, simply push this goal on the stack after dealing with overflow. + Entry::Vacant(v) => { + if self.overflow_data.has_overflow(self.stack.len()) { + return Err(self.deal_with_overflow(tcx, goal)); + } + + let depth = self.stack.push(StackElem { goal, has_been_used: false }); + let response = super::response_no_constraints(tcx, goal, Certainty::Yes); + let entry_index = cache.entries.push(ProvisionalEntry { response, depth, goal }); + v.insert(entry_index); + Ok(()) + } + // We have a nested goal which relies on a goal `root` deeper in the stack. + // + // We first store that we may have to rerun `evaluate_goal` for `root` in case the + // provisional response is not equal to the final response. We also update the depth + // of all goals which recursively depend on our current goal to depend on `root` + // instead. + // + // Finally we can return either the provisional response for that goal if we have a + // coinductive cycle or an ambiguous result if the cycle is inductive. + Entry::Occupied(entry_index) => { + let entry_index = *entry_index.get(); + + cache.add_dependency_of_leaf_on(entry_index); + let stack_depth = cache.depth(entry_index); + + self.stack[stack_depth].has_been_used = true; + // NOTE: The goals on the stack aren't the only goals involved in this cycle. + // We can also depend on goals which aren't part of the stack but coinductively + // depend on the stack themselves. We already checked whether all the goals + // between these goals and their root on the stack. This means that as long as + // each goal in a cycle is checked for coinductivity by itself, simply checking + // the stack is enough. + if self.stack.raw[stack_depth.index()..] + .iter() + .all(|g| g.goal.value.predicate.is_coinductive(tcx)) + { + Err(cache.provisional_result(entry_index)) + } else { + Err(super::response_no_constraints( + tcx, + goal, + Certainty::Maybe(MaybeCause::Overflow), + )) + } + } + } + } + + /// We cannot simply store the result of [EvalCtxt::compute_goal] as we have to deal with + /// coinductive cycles. + /// + /// When we encounter a coinductive cycle, we have to prove the final result of that cycle + /// while we are still computing that result. Because of this we continously recompute the + /// cycle until the result of the previous iteration is equal to the final result, at which + /// point we are done. + /// + /// This function returns `true` if we were able to finalize the goal and `false` if it has + /// updated the provisional cache and we have to recompute the current goal. + /// + /// FIXME: Refer to the rustc-dev-guide entry once it exists. + pub(super) fn try_finalize_goal( + &mut self, + tcx: TyCtxt<'tcx>, + actual_goal: CanonicalGoal<'tcx>, + response: QueryResult<'tcx>, + ) -> bool { + let StackElem { goal, has_been_used } = self.stack.pop().unwrap(); + assert_eq!(goal, actual_goal); + + let cache = &mut self.provisional_cache; + let provisional_entry_index = *cache.lookup_table.get(&goal).unwrap(); + let provisional_entry = &mut cache.entries[provisional_entry_index]; + let depth = provisional_entry.depth; + // Was the current goal the root of a cycle and was the provisional response + // different from the final one. + if has_been_used && provisional_entry.response != response { + // If so, update the provisional reponse for this goal... + provisional_entry.response = response; + // ...remove all entries whose result depends on this goal + // from the provisional cache... + // + // That's not completely correct, as a nested goal can also + // depend on a goal which is lower in the stack so it doesn't + // actually depend on the current goal. This should be fairly + // rare and is hopefully not relevant for performance. + #[allow(rustc::potential_query_instability)] + cache.lookup_table.retain(|_key, index| *index <= provisional_entry_index); + cache.entries.truncate(provisional_entry_index.index() + 1); + + // ...and finally push our goal back on the stack and reevaluate it. + self.stack.push(StackElem { goal, has_been_used: false }); + false + } else { + // If not, we're done with this goal. + // + // Check whether that this goal doesn't depend on a goal deeper on the stack + // and if so, move it and all nested goals to the global cache. + // + // Note that if any nested goal were to depend on something deeper on the stack, + // this would have also updated the depth of the current goal. + if depth == self.stack.next_index() { + for (i, entry) in cache.entries.drain_enumerated(provisional_entry_index.index()..) + { + let actual_index = cache.lookup_table.remove(&entry.goal); + debug_assert_eq!(Some(i), actual_index); + debug_assert!(entry.depth == depth); + cache::try_move_finished_goal_to_global_cache( + tcx, + &mut self.overflow_data, + &self.stack, + entry.goal, + entry.response, + ); + } + } + true + } + } +} diff --git a/compiler/rustc_trait_selection/src/solve/overflow.rs b/compiler/rustc_trait_selection/src/solve/search_graph/overflow.rs similarity index 74% rename from compiler/rustc_trait_selection/src/solve/overflow.rs rename to compiler/rustc_trait_selection/src/solve/search_graph/overflow.rs index 8bbb9f63e7868..1dd3894c91adc 100644 --- a/compiler/rustc_trait_selection/src/solve/overflow.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph/overflow.rs @@ -3,8 +3,8 @@ use rustc_infer::traits::query::NoSolution; use rustc_middle::ty::TyCtxt; use rustc_session::Limit; -use super::cache::response_no_constraints; -use super::{Certainty, EvalCtxt, MaybeCause, QueryResult}; +use super::SearchGraph; +use crate::solve::{response_no_constraints, Certainty, EvalCtxt, MaybeCause, QueryResult}; /// When detecting a solver overflow, we return ambiguity. Overflow can be /// *hidden* by either a fatal error in an **AND** or a trivial success in an **OR**. @@ -50,32 +50,35 @@ impl OverflowData { } } -impl<'tcx> EvalCtxt<'tcx> { - pub(super) fn deal_with_overflow( +impl<'tcx> SearchGraph<'tcx> { + pub fn deal_with_overflow( &mut self, + tcx: TyCtxt<'tcx>, goal: Canonical<'tcx, impl Sized>, ) -> QueryResult<'tcx> { self.overflow_data.deal_with_overflow(); - response_no_constraints(self.tcx, goal, Certainty::Maybe(MaybeCause::Overflow)) + response_no_constraints(tcx, goal, Certainty::Maybe(MaybeCause::Overflow)) } +} +impl<'tcx> EvalCtxt<'_, 'tcx> { /// A `while`-loop which tracks overflow. - pub(super) fn repeat_while_none( + pub fn repeat_while_none( &mut self, mut loop_body: impl FnMut(&mut Self) -> Option>, ) -> Result { - let start_depth = self.overflow_data.additional_depth; - let depth = self.provisional_cache.current_depth(); - while !self.overflow_data.has_overflow(depth) { + let start_depth = self.search_graph.overflow_data.additional_depth; + let depth = self.search_graph.stack.len(); + while !self.search_graph.overflow_data.has_overflow(depth) { if let Some(result) = loop_body(self) { - self.overflow_data.additional_depth = start_depth; + self.search_graph.overflow_data.additional_depth = start_depth; return result; } - self.overflow_data.additional_depth += 1; + self.search_graph.overflow_data.additional_depth += 1; } - self.overflow_data.additional_depth = start_depth; - self.overflow_data.deal_with_overflow(); + self.search_graph.overflow_data.additional_depth = start_depth; + self.search_graph.overflow_data.deal_with_overflow(); Ok(Certainty::Maybe(MaybeCause::Overflow)) } } diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index a43fef5cdb0c8..cc68cfeea1d07 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -3,7 +3,7 @@ use std::iter; use super::assembly::{self, AssemblyCtxt}; -use super::{CanonicalGoal, EvalCtxt, Goal, QueryResult}; +use super::{EvalCtxt, Goal, QueryResult}; use rustc_hir::def_id::DefId; use rustc_infer::infer::InferOk; use rustc_infer::traits::query::NoSolution; @@ -67,11 +67,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_impl_candidate( - acx: &mut AssemblyCtxt<'_, 'tcx, Self>, + acx: &mut AssemblyCtxt<'_, '_, 'tcx, Self>, goal: Goal<'tcx, TraitPredicate<'tcx>>, impl_def_id: DefId, ) { - let tcx = acx.cx.tcx; + let tcx = acx.cx.tcx(); + let infcx = acx.cx.infcx; let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsPlaceholder }; @@ -81,12 +82,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { return; } - acx.infcx.probe(|_| { - let impl_substs = acx.infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id); + infcx.probe(|_| { + let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id); let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs); - let Ok(InferOk { obligations, .. }) = acx - .infcx + let Ok(InferOk { obligations, .. }) = infcx .at(&ObligationCause::dummy(), goal.param_env) .define_opaque_types(false) .eq(goal.predicate.trait_ref, impl_trait_ref) @@ -104,16 +104,16 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { let nested_goals = obligations.into_iter().map(|o| o.into()).chain(where_clause_bounds).collect(); - let Ok(certainty) = acx.cx.evaluate_all(acx.infcx, nested_goals) else { return }; + let Ok(certainty) = acx.cx.evaluate_all(nested_goals) else { return }; acx.try_insert_candidate(CandidateSource::Impl(impl_def_id), certainty); }) } } -impl<'tcx> EvalCtxt<'tcx> { +impl<'tcx> EvalCtxt<'_, 'tcx> { pub(super) fn compute_trait_goal( &mut self, - goal: CanonicalGoal<'tcx, TraitPredicate<'tcx>>, + goal: Goal<'tcx, TraitPredicate<'tcx>>, ) -> QueryResult<'tcx> { let candidates = AssemblyCtxt::assemble_and_evaluate_candidates(self, goal); self.merge_trait_candidates_discard_reservation_impls(candidates) @@ -176,7 +176,7 @@ impl<'tcx> EvalCtxt<'tcx> { fn discard_reservation_impl(&self, candidate: Candidate<'tcx>) -> Candidate<'tcx> { if let CandidateSource::Impl(def_id) = candidate.source { - if let ty::ImplPolarity::Reservation = self.tcx.impl_polarity(def_id) { + if let ty::ImplPolarity::Reservation = self.tcx().impl_polarity(def_id) { debug!("Selected reservation impl"); // FIXME: reduce candidate to ambiguous // FIXME: replace `var_values` with identity, yeet external constraints. From 660c28391c79bd12e116724a8877a2148630dee5 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 17 Jan 2023 11:47:47 +0100 Subject: [PATCH 134/230] remove assembly context and impl a bit more --- compiler/rustc_middle/src/infer/canonical.rs | 6 + .../src/solve/assembly.rs | 254 ++++++++++++++---- .../src/solve/fulfill.rs | 27 +- .../rustc_trait_selection/src/solve/mod.rs | 21 +- .../src/solve/project_goals.rs | 74 ++--- .../src/solve/search_graph/cache.rs | 4 + .../src/solve/search_graph/mod.rs | 6 + .../src/solve/trait_goals.rs | 88 +++--- 8 files changed, 317 insertions(+), 163 deletions(-) diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 7f3567c08be77..43583b5723e69 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -339,6 +339,12 @@ TrivialTypeTraversalAndLiftImpls! { } impl<'tcx> CanonicalVarValues<'tcx> { + /// Creates dummy var values which should not be used in a + /// canonical response. + pub fn dummy() -> CanonicalVarValues<'tcx> { + CanonicalVarValues { var_values: Default::default() } + } + #[inline] pub fn len(&self) -> usize { self.var_values.len() diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs index da6bb844a0fbe..cd6e4d2bccd5c 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -12,18 +12,73 @@ use std::fmt::Debug; /// /// It consists of both the `source`, which describes how that goal would be proven, /// and the `result` when using the given `source`. -/// -/// For the list of possible candidates, please look at the documentation of -/// [super::trait_goals::CandidateSource] and [super::project_goals::CandidateSource]. #[derive(Debug, Clone)] -pub(super) struct Candidate<'tcx, G: GoalKind<'tcx>> { - pub(super) source: G::CandidateSource, +pub(super) struct Candidate<'tcx> { + pub(super) source: CandidateSource, pub(super) result: CanonicalResponse<'tcx>, } -pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy { - type CandidateSource: Debug + Copy; +/// Possible ways the given goal can be proven. +#[derive(Debug, Clone, Copy)] +pub(super) enum CandidateSource { + /// A user written impl. + /// + /// ## Examples + /// + /// ```rust + /// fn main() { + /// let x: Vec = Vec::new(); + /// // This uses the impl from the standard library to prove `Vec: Clone`. + /// let y = x.clone(); + /// } + /// ``` + Impl(DefId), + /// A builtin impl generated by the compiler. When adding a new special + /// trait, try to use actual impls whenever possible. Builtin impls should + /// only be used in cases where the impl cannot be manually be written. + /// + /// Notable examples are auto traits, `Sized`, and `DiscriminantKind`. + /// For a list of all traits with builtin impls, check out the + /// [`EvalCtxt::assemble_builtin_impl_candidates`] method. Not + BuiltinImpl, + /// An assumption from the environment. + /// + /// More precicely we've used the `n-th` assumption in the `param_env`. + /// + /// ## Examples + /// + /// ```rust + /// fn is_clone(x: T) -> (T, T) { + /// // This uses the assumption `T: Clone` from the `where`-bounds + /// // to prove `T: Clone`. + /// (x.clone(), x) + /// } + /// ``` + ParamEnv(usize), + /// If the self type is an alias type, e.g. an opaque type or a projection, + /// we know the bounds on that alias to hold even without knowing its concrete + /// underlying type. + /// + /// More precisely this candidate is using the `n-th` bound in the `item_bounds` of + /// the self type. + /// + /// ## Examples + /// + /// ```rust + /// trait Trait { + /// type Assoc: Clone; + /// } + /// + /// fn foo(x: ::Assoc) { + /// // We prove `::Assoc` by looking at the bounds on `Assoc` in + /// // in the trait definition. + /// let _y = x.clone(); + /// } + /// ``` + AliasBound(usize), +} +pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy { fn self_ty(self) -> Ty<'tcx>; fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self; @@ -31,43 +86,40 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy { fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId; fn consider_impl_candidate( - acx: &mut AssemblyCtxt<'_, '_, 'tcx, Self>, + ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, impl_def_id: DefId, - ); -} + ) -> Result; -/// An abstraction which correctly deals with the canonical results for candidates. -/// -/// It also deduplicates the behavior between trait and projection predicates. -pub(super) struct AssemblyCtxt<'a, 'b, 'tcx, G: GoalKind<'tcx>> { - pub(super) cx: &'a mut EvalCtxt<'b, 'tcx>, - candidates: Vec>, -} + fn consider_builtin_sized_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> Result; -impl<'a, 'b, 'tcx, G: GoalKind<'tcx>> AssemblyCtxt<'a, 'b, 'tcx, G> { - pub(super) fn assemble_and_evaluate_candidates( - cx: &'a mut EvalCtxt<'b, 'tcx>, + fn consider_assumption( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + assumption: ty::Predicate<'tcx>, + ) -> Result; +} +impl<'tcx> EvalCtxt<'_, 'tcx> { + pub(super) fn assemble_and_evaluate_candidates>( + &mut self, goal: Goal<'tcx, G>, - ) -> Vec> { - let mut acx = AssemblyCtxt { cx, candidates: Vec::new() }; + ) -> Vec> { + let mut candidates = Vec::new(); - acx.assemble_candidates_after_normalizing_self_ty(goal); + self.assemble_candidates_after_normalizing_self_ty(goal, &mut candidates); - acx.assemble_impl_candidates(goal); + self.assemble_impl_candidates(goal, &mut candidates); - acx.candidates - } + self.assemble_builtin_impl_candidates(goal, &mut candidates); - pub(super) fn try_insert_candidate( - &mut self, - source: G::CandidateSource, - certainty: Certainty, - ) { - match self.cx.make_canonical_response(certainty) { - Ok(result) => self.candidates.push(Candidate { source, result }), - Err(NoSolution) => debug!(?source, ?certainty, "failed leakcheck"), - } + self.assemble_param_env_candidates(goal, &mut candidates); + + self.assemble_alias_bound_candidates(goal, &mut candidates); + + candidates } /// If the self type of a goal is a projection, computing the relevant candidates is difficult. @@ -75,15 +127,18 @@ impl<'a, 'b, 'tcx, G: GoalKind<'tcx>> AssemblyCtxt<'a, 'b, 'tcx, G> { /// To deal with this, we first try to normalize the self type and add the candidates for the normalized /// self type to the list of candidates in case that succeeds. Note that we can't just eagerly return in /// this case as projections as self types add ` - fn assemble_candidates_after_normalizing_self_ty(&mut self, goal: Goal<'tcx, G>) { - let tcx = self.cx.tcx(); - let infcx = self.cx.infcx; + fn assemble_candidates_after_normalizing_self_ty>( + &mut self, + goal: Goal<'tcx, G>, + candidates: &mut Vec>, + ) { + let tcx = self.tcx(); // FIXME: We also have to normalize opaque types, not sure where to best fit that in. let &ty::Alias(ty::Projection, projection_ty) = goal.predicate.self_ty().kind() else { return }; - infcx.probe(|_| { - let normalized_ty = infcx.next_ty_infer(); + self.infcx.probe(|_| { + let normalized_ty = self.infcx.next_ty_infer(); let normalizes_to_goal = goal.with( tcx, ty::Binder::dummy(ty::ProjectionPredicate { @@ -91,33 +146,136 @@ impl<'a, 'b, 'tcx, G: GoalKind<'tcx>> AssemblyCtxt<'a, 'b, 'tcx, G> { term: normalized_ty.into(), }), ); - let normalization_certainty = match self.cx.evaluate_goal(normalizes_to_goal) { + let normalization_certainty = match self.evaluate_goal(normalizes_to_goal) { Ok((_, certainty)) => certainty, Err(NoSolution) => return, }; // NOTE: Alternatively we could call `evaluate_goal` here and only have a `Normalized` candidate. - // This doesn't work as long as we use `CandidateSource` in both winnowing and to resolve associated items. + // This doesn't work as long as we use `CandidateSource` in winnowing. let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty)); - let normalized_candidates = - AssemblyCtxt::assemble_and_evaluate_candidates(self.cx, goal); + // FIXME: This is broken if we care about the `usize` of `AliasBound` because the self type + // could be normalized to yet another projection with different item bounds. + let normalized_candidates = self.assemble_and_evaluate_candidates(goal); for mut normalized_candidate in normalized_candidates { normalized_candidate.result = normalized_candidate.result.unchecked_map(|mut response| { + // FIXME: This currently hides overflow in the normalization step of the self type + // which is probably wrong. Maybe `unify_and` should actually keep overflow as + // we treat it as non-fatal anyways. response.certainty = response.certainty.unify_and(normalization_certainty); response }); - self.candidates.push(normalized_candidate); + candidates.push(normalized_candidate); } }) } - fn assemble_impl_candidates(&mut self, goal: Goal<'tcx, G>) { - let tcx = self.cx.tcx(); + fn assemble_impl_candidates>( + &mut self, + goal: Goal<'tcx, G>, + candidates: &mut Vec>, + ) { + let tcx = self.tcx(); tcx.for_each_relevant_impl( goal.predicate.trait_def_id(tcx), goal.predicate.self_ty(), - |impl_def_id| G::consider_impl_candidate(self, goal, impl_def_id), + |impl_def_id| match G::consider_impl_candidate(self, goal, impl_def_id) + .and_then(|certainty| self.make_canonical_response(certainty)) + { + Ok(result) => candidates + .push(Candidate { source: CandidateSource::Impl(impl_def_id), result }), + Err(NoSolution) => (), + }, ); } + + fn assemble_builtin_impl_candidates>( + &mut self, + goal: Goal<'tcx, G>, + candidates: &mut Vec>, + ) { + let lang_items = self.tcx().lang_items(); + let trait_def_id = goal.predicate.trait_def_id(self.tcx()); + let result = if lang_items.sized_trait() == Some(trait_def_id) { + G::consider_builtin_sized_candidate(self, goal) + } else { + Err(NoSolution) + }; + + match result.and_then(|certainty| self.make_canonical_response(certainty)) { + Ok(result) => { + candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result }) + } + Err(NoSolution) => (), + } + } + + fn assemble_param_env_candidates>( + &mut self, + goal: Goal<'tcx, G>, + candidates: &mut Vec>, + ) { + for (i, assumption) in goal.param_env.caller_bounds().iter().enumerate() { + match G::consider_assumption(self, goal, assumption) + .and_then(|certainty| self.make_canonical_response(certainty)) + { + Ok(result) => { + candidates.push(Candidate { source: CandidateSource::ParamEnv(i), result }) + } + Err(NoSolution) => (), + } + } + } + + fn assemble_alias_bound_candidates>( + &mut self, + goal: Goal<'tcx, G>, + candidates: &mut Vec>, + ) { + let alias_ty = match goal.predicate.self_ty().kind() { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(_, _) + | ty::Foreign(_) + | ty::Str + | ty::Array(_, _) + | ty::Slice(_) + | ty::RawPtr(_) + | ty::Ref(_, _, _) + | ty::FnDef(_, _) + | ty::FnPtr(_) + | ty::Dynamic(..) + | ty::Closure(..) + | ty::Generator(..) + | ty::GeneratorWitness(_) + | ty::Never + | ty::Tuple(_) + | ty::Param(_) + | ty::Placeholder(..) + | ty::Infer(_) + | ty::Error(_) => return, + ty::Bound(..) => bug!("unexpected bound type: {goal:?}"), + ty::Alias(_, alias_ty) => alias_ty, + }; + + for (i, (assumption, _)) in self + .tcx() + .bound_explicit_item_bounds(alias_ty.def_id) + .subst_iter_copied(self.tcx(), alias_ty.substs) + .enumerate() + { + match G::consider_assumption(self, goal, assumption) + .and_then(|certainty| self.make_canonical_response(certainty)) + { + Ok(result) => { + candidates.push(Candidate { source: CandidateSource::AliasBound(i), result }) + } + Err(NoSolution) => (), + } + } + } } diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 3146f468f7d81..b086c0684d28d 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -2,7 +2,7 @@ use std::mem; use rustc_data_structures::fx::FxHashMap; use rustc_infer::{ - infer::{canonical::OriginalQueryValues, InferCtxt}, + infer::InferCtxt, traits::{ query::NoSolution, FulfillmentError, FulfillmentErrorCode, PredicateObligation, SelectionError, TraitEngine, @@ -10,7 +10,7 @@ use rustc_infer::{ }; use rustc_middle::ty; -use super::{Certainty, EvalCtxt}; +use super::{search_graph, Certainty, EvalCtxt}; /// A trait engine using the new trait solver. /// @@ -68,25 +68,10 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { let mut has_changed = false; for obligation in mem::take(&mut self.obligations) { let goal = obligation.clone().into(); - - // FIXME: Add a better API for that '^^ - let mut orig_values = OriginalQueryValues::default(); - let canonical_goal = infcx.canonicalize_query(goal, &mut orig_values); - let (changed, certainty) = match EvalCtxt::evaluate_canonical_goal( - infcx.tcx, - &mut super::search_graph::SearchGraph::new(infcx.tcx), - canonical_goal, - ) { - Ok(canonical_response) => { - ( - true, // FIXME: check whether `var_values` are an identity substitution. - super::instantiate_canonical_query_response( - infcx, - &orig_values, - canonical_response, - ), - ) - } + let search_graph = &mut search_graph::SearchGraph::new(infcx.tcx); + let mut ecx = EvalCtxt::new_outside_solver(infcx, search_graph); + let (changed, certainty) = match ecx.evaluate_goal(goal) { + Ok(result) => result, Err(NoSolution) => { errors.push(FulfillmentError { obligation: obligation.clone(), diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 0e629664b2b1a..579cd6a2d59cd 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -155,6 +155,23 @@ struct EvalCtxt<'a, 'tcx> { } impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + + /// Creates a new evaluation context outside of the trait solver. + /// + /// With this solver making a canonical response doesn't make much sense. + /// The `search_graph` for this solver has to be completely empty. + fn new_outside_solver( + infcx: &'a InferCtxt<'tcx>, + search_graph: &'a mut search_graph::SearchGraph<'tcx>, + ) -> EvalCtxt<'a, 'tcx> { + assert!(search_graph.is_empty()); + EvalCtxt { infcx, var_values: CanonicalVarValues::dummy(), search_graph } + } + + #[instrument(level = "debug", skip(tcx, search_graph), ret)] fn evaluate_canonical_goal( tcx: TyCtxt<'tcx>, search_graph: &'a mut search_graph::SearchGraph<'tcx>, @@ -183,10 +200,6 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { } } - fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - fn make_canonical_response(&self, certainty: Certainty) -> QueryResult<'tcx> { let external_constraints = take_external_constraints(self.infcx)?; diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 1120dfb809862..92c5d4e53f530 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -1,7 +1,7 @@ use crate::traits::{specialization_graph, translate_substs}; -use super::assembly::{self, AssemblyCtxt}; -use super::{EvalCtxt, Goal, QueryResult}; +use super::assembly::{self, Candidate, CandidateSource}; +use super::{Certainty, EvalCtxt, Goal, QueryResult}; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; @@ -16,22 +16,12 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::DUMMY_SP; use std::iter; -#[allow(dead_code)] // FIXME: implement and use all variants. -#[derive(Debug, Clone, Copy)] -pub(super) enum CandidateSource { - Impl(DefId), - ParamEnv(usize), - Builtin, -} - -type Candidate<'tcx> = assembly::Candidate<'tcx, ProjectionPredicate<'tcx>>; - impl<'tcx> EvalCtxt<'_, 'tcx> { pub(super) fn compute_projection_goal( &mut self, goal: Goal<'tcx, ProjectionPredicate<'tcx>>, ) -> QueryResult<'tcx> { - let candidates = AssemblyCtxt::assemble_and_evaluate_candidates(self, goal); + let candidates = self.assemble_and_evaluate_candidates(goal); self.merge_project_candidates(candidates) } @@ -83,14 +73,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { match (candidate.source, other.source) { (CandidateSource::Impl(_), _) | (CandidateSource::ParamEnv(_), _) - | (CandidateSource::Builtin, _) => unimplemented!(), + | (CandidateSource::BuiltinImpl, _) + | (CandidateSource::AliasBound(_), _) => unimplemented!(), } } } impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { - type CandidateSource = CandidateSource; - fn self_ty(self) -> Ty<'tcx> { self.self_ty() } @@ -104,12 +93,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { } fn consider_impl_candidate( - acx: &mut AssemblyCtxt<'_, '_, 'tcx, ProjectionPredicate<'tcx>>, + ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, ProjectionPredicate<'tcx>>, impl_def_id: DefId, - ) { - let tcx = acx.cx.tcx(); - let infcx = acx.cx.infcx; + ) -> Result { + let tcx = ecx.tcx(); let goal_trait_ref = goal.predicate.projection_ty.trait_ref(tcx); let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); @@ -117,20 +105,20 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { if iter::zip(goal_trait_ref.substs, impl_trait_ref.skip_binder().substs) .any(|(goal, imp)| !drcx.generic_args_may_unify(goal, imp)) { - return; + return Err(NoSolution); } - infcx.probe(|_| { - let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id); + ecx.infcx.probe(|_| { + let impl_substs = ecx.infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id); let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs); - let Ok(InferOk { obligations, .. }) = infcx + let Ok(InferOk { obligations, .. }) = ecx.infcx .at(&ObligationCause::dummy(), goal.param_env) .define_opaque_types(false) .eq(goal_trait_ref, impl_trait_ref) .map_err(|e| debug!("failed to equate trait refs: {e:?}")) else { - return + return Err(NoSolution) }; let where_clause_bounds = tcx .predicates_of(impl_def_id) @@ -141,16 +129,16 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { let nested_goals = obligations.into_iter().map(|o| o.into()).chain(where_clause_bounds).collect(); - let Ok(trait_ref_certainty) = acx.cx.evaluate_all(nested_goals) else { return }; + let trait_ref_certainty = ecx.evaluate_all(nested_goals)?; let Some(assoc_def) = fetch_eligible_assoc_item_def( - infcx, + ecx.infcx, goal.param_env, goal_trait_ref, goal.predicate.def_id(), impl_def_id ) else { - return + return Err(NoSolution); }; if !assoc_def.item.defaultness(tcx).has_value() { @@ -176,7 +164,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { impl_substs, ); let substs = translate_substs( - infcx, + ecx.infcx, goal.param_env, impl_def_id, impl_substs_with_gat, @@ -197,22 +185,40 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ty.map_bound(|ty| ty.into()) }; - let Ok(InferOk { obligations, .. }) = infcx + let Ok(InferOk { obligations, .. }) = ecx.infcx .at(&ObligationCause::dummy(), goal.param_env) .define_opaque_types(false) .eq(goal.predicate.term, term.subst(tcx, substs)) .map_err(|e| debug!("failed to equate trait refs: {e:?}")) else { - return + return Err(NoSolution); }; let nested_goals = obligations.into_iter().map(|o| o.into()).collect(); - let Ok(rhs_certainty) = acx.cx.evaluate_all(nested_goals) else { return }; + let rhs_certainty = ecx.evaluate_all(nested_goals)?; - let certainty = trait_ref_certainty.unify_and(rhs_certainty); - acx.try_insert_candidate(CandidateSource::Impl(impl_def_id), certainty); + Ok(trait_ref_certainty.unify_and(rhs_certainty)) }) } + + fn consider_builtin_sized_candidate( + _ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> Result { + bug!("`Sized` does not have an associated type: {:?}", goal); + } + + fn consider_assumption( + _ecx: &mut EvalCtxt<'_, 'tcx>, + _goal: Goal<'tcx, Self>, + assumption: ty::Predicate<'tcx>, + ) -> Result { + if let Some(_poly_projection_pred) = assumption.to_opt_poly_projection_pred() { + unimplemented!() + } else { + Err(NoSolution) + } + } } /// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code. diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/cache.rs b/compiler/rustc_trait_selection/src/solve/search_graph/cache.rs index 435e46f211a04..cb00fe6bf14af 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph/cache.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph/cache.rs @@ -52,6 +52,10 @@ impl<'tcx> ProvisionalCache<'tcx> { ProvisionalCache { entries: Default::default(), lookup_table: Default::default() } } + pub(super) fn is_empty(&self) -> bool { + self.entries.is_empty() && self.lookup_table.is_empty() + } + /// Adds a dependency from the current leaf to `target` in the cache /// to prevent us from moving any goals which depend on the current leaf /// to the global cache while we're still computing `target`. diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs index 8d2a3a9cd818e..4f48389410bfa 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs @@ -36,6 +36,12 @@ impl<'tcx> SearchGraph<'tcx> { } } + pub(super) fn is_empty(&self) -> bool { + self.stack.is_empty() + && self.provisional_cache.is_empty() + && !self.overflow_data.did_overflow() + } + /// Tries putting the new goal on the stack, returning an error if it is already cached. /// /// This correctly updates the provisional cache if there is a cycle. diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index cc68cfeea1d07..3c8314aa565ee 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -2,8 +2,8 @@ use std::iter; -use super::assembly::{self, AssemblyCtxt}; -use super::{EvalCtxt, Goal, QueryResult}; +use super::assembly::{self, Candidate, CandidateSource}; +use super::{Certainty, EvalCtxt, Goal, QueryResult}; use rustc_hir::def_id::DefId; use rustc_infer::infer::InferOk; use rustc_infer::traits::query::NoSolution; @@ -13,47 +13,7 @@ use rustc_middle::ty::TraitPredicate; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::DUMMY_SP; -#[allow(dead_code)] // FIXME: implement and use all variants. -#[derive(Debug, Clone, Copy)] -pub(super) enum CandidateSource { - /// Some user-defined impl with the given `DefId`. - Impl(DefId), - /// The n-th caller bound in the `param_env` of our goal. - /// - /// This is pretty much always a bound from the `where`-clauses of the - /// currently checked item. - ParamEnv(usize), - /// A bound on the `self_ty` in case it is a projection or an opaque type. - /// - /// # Examples - /// - /// ```ignore (for syntax highlighting) - /// trait Trait { - /// type Assoc: OtherTrait; - /// } - /// ``` - /// - /// We know that `::Assoc: OtherTrait` holds by looking at - /// the bounds on `Trait::Assoc`. - AliasBound(usize), - /// A builtin implementation for some specific traits, used in cases - /// where we cannot rely an ordinary library implementations. - /// - /// The most notable examples are `Sized`, `Copy` and `Clone`. This is also - /// used for the `DiscriminantKind` and `Pointee` trait, both of which have - /// an associated type. - Builtin, - /// An automatic impl for an auto trait, e.g. `Send`. These impls recursively look - /// at the constituent types of the `self_ty` to check whether the auto trait - /// is implemented for those. - AutoImpl, -} - -type Candidate<'tcx> = assembly::Candidate<'tcx, TraitPredicate<'tcx>>; - impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { - type CandidateSource = CandidateSource; - fn self_ty(self) -> Ty<'tcx> { self.self_ty() } @@ -67,32 +27,31 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_impl_candidate( - acx: &mut AssemblyCtxt<'_, '_, 'tcx, Self>, + ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, TraitPredicate<'tcx>>, impl_def_id: DefId, - ) { - let tcx = acx.cx.tcx(); - let infcx = acx.cx.infcx; + ) -> Result { + let tcx = ecx.tcx(); let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsPlaceholder }; if iter::zip(goal.predicate.trait_ref.substs, impl_trait_ref.skip_binder().substs) .any(|(goal, imp)| !drcx.generic_args_may_unify(goal, imp)) { - return; + return Err(NoSolution); } - infcx.probe(|_| { - let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id); + ecx.infcx.probe(|_| { + let impl_substs = ecx.infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id); let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs); - let Ok(InferOk { obligations, .. }) = infcx + let Ok(InferOk { obligations, .. }) = ecx.infcx .at(&ObligationCause::dummy(), goal.param_env) .define_opaque_types(false) .eq(goal.predicate.trait_ref, impl_trait_ref) .map_err(|e| debug!("failed to equate trait refs: {e:?}")) else { - return + return Err(NoSolution); }; let where_clause_bounds = tcx .predicates_of(impl_def_id) @@ -104,10 +63,28 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { let nested_goals = obligations.into_iter().map(|o| o.into()).chain(where_clause_bounds).collect(); - let Ok(certainty) = acx.cx.evaluate_all(nested_goals) else { return }; - acx.try_insert_candidate(CandidateSource::Impl(impl_def_id), certainty); + ecx.evaluate_all(nested_goals) }) } + + fn consider_builtin_sized_candidate( + _ecx: &mut EvalCtxt<'_, 'tcx>, + _goal: Goal<'tcx, Self>, + ) -> Result { + unimplemented!(); + } + + fn consider_assumption( + _ecx: &mut EvalCtxt<'_, 'tcx>, + _goal: Goal<'tcx, Self>, + assumption: ty::Predicate<'tcx>, + ) -> Result { + if let Some(_poly_trait_pred) = assumption.to_opt_poly_trait_pred() { + unimplemented!() + } else { + Err(NoSolution) + } + } } impl<'tcx> EvalCtxt<'_, 'tcx> { @@ -115,7 +92,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { &mut self, goal: Goal<'tcx, TraitPredicate<'tcx>>, ) -> QueryResult<'tcx> { - let candidates = AssemblyCtxt::assemble_and_evaluate_candidates(self, goal); + let candidates = self.assemble_and_evaluate_candidates(goal); self.merge_trait_candidates_discard_reservation_impls(candidates) } @@ -169,8 +146,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { (CandidateSource::Impl(_), _) | (CandidateSource::ParamEnv(_), _) | (CandidateSource::AliasBound(_), _) - | (CandidateSource::Builtin, _) - | (CandidateSource::AutoImpl, _) => unimplemented!(), + | (CandidateSource::BuiltinImpl, _) => unimplemented!(), } } From 9a757d6ee4229bd7e022a2f3f26946cf05fddbcf Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 17 Jan 2023 12:26:28 +0100 Subject: [PATCH 135/230] add `eq` to `InferCtxtExt` --- .../src/solve/infcx_ext.rs | 40 ++++++++++++++++++- .../src/solve/project_goals.rs | 29 ++++---------- .../src/solve/trait_goals.rs | 18 ++------- 3 files changed, 49 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/infcx_ext.rs b/compiler/rustc_trait_selection/src/solve/infcx_ext.rs index 8a8c3091d549f..f92d64631340a 100644 --- a/compiler/rustc_trait_selection/src/solve/infcx_ext.rs +++ b/compiler/rustc_trait_selection/src/solve/infcx_ext.rs @@ -1,11 +1,28 @@ +use rustc_infer::infer::at::ToTrace; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_infer::infer::InferCtxt; -use rustc_middle::ty::Ty; +use rustc_infer::infer::{InferCtxt, InferOk}; +use rustc_infer::traits::query::NoSolution; +use rustc_infer::traits::ObligationCause; +use rustc_middle::ty::{self, Ty}; use rustc_span::DUMMY_SP; +use super::Goal; + /// Methods used inside of the canonical queries of the solver. +/// +/// Most notably these do not care about diagnostics information. +/// If you find this while looking for methods to use outside of the +/// solver, you may look at the implementation of these method for +/// help. pub(super) trait InferCtxtExt<'tcx> { fn next_ty_infer(&self) -> Ty<'tcx>; + + fn eq>( + &self, + param_env: ty::ParamEnv<'tcx>, + lhs: T, + rhs: T, + ) -> Result>>, NoSolution>; } impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { @@ -15,4 +32,23 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { span: DUMMY_SP, }) } + + #[instrument(level = "debug", skip(self, param_env), ret)] + fn eq>( + &self, + param_env: ty::ParamEnv<'tcx>, + lhs: T, + rhs: T, + ) -> Result>>, NoSolution> { + self.at(&ObligationCause::dummy(), param_env) + .define_opaque_types(false) + .eq(lhs, rhs) + .map(|InferOk { value: (), obligations }| { + obligations.into_iter().map(|o| o.into()).collect() + }) + .map_err(|e| { + debug!(?e, "failed to equate"); + NoSolution + }) + } } diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 92c5d4e53f530..cf07926f85a27 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -1,14 +1,15 @@ use crate::traits::{specialization_graph, translate_substs}; use super::assembly::{self, Candidate, CandidateSource}; +use super::infcx_ext::InferCtxtExt; use super::{Certainty, EvalCtxt, Goal, QueryResult}; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; -use rustc_infer::infer::{InferCtxt, InferOk}; +use rustc_infer::infer::InferCtxt; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::specialization_graph::LeafDef; -use rustc_infer::traits::{ObligationCause, Reveal}; +use rustc_infer::traits::Reveal; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::ProjectionPredicate; use rustc_middle::ty::TypeVisitable; @@ -112,14 +113,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { let impl_substs = ecx.infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id); let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs); - let Ok(InferOk { obligations, .. }) = ecx.infcx - .at(&ObligationCause::dummy(), goal.param_env) - .define_opaque_types(false) - .eq(goal_trait_ref, impl_trait_ref) - .map_err(|e| debug!("failed to equate trait refs: {e:?}")) - else { - return Err(NoSolution) - }; + let mut nested_goals = ecx.infcx.eq(goal.param_env, goal_trait_ref, impl_trait_ref)?; let where_clause_bounds = tcx .predicates_of(impl_def_id) .instantiate(tcx, impl_substs) @@ -127,8 +121,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { .into_iter() .map(|pred| goal.with(tcx, pred)); - let nested_goals = - obligations.into_iter().map(|o| o.into()).chain(where_clause_bounds).collect(); + nested_goals.extend(where_clause_bounds); let trait_ref_certainty = ecx.evaluate_all(nested_goals)?; let Some(assoc_def) = fetch_eligible_assoc_item_def( @@ -185,16 +178,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ty.map_bound(|ty| ty.into()) }; - let Ok(InferOk { obligations, .. }) = ecx.infcx - .at(&ObligationCause::dummy(), goal.param_env) - .define_opaque_types(false) - .eq(goal.predicate.term, term.subst(tcx, substs)) - .map_err(|e| debug!("failed to equate trait refs: {e:?}")) - else { - return Err(NoSolution); - }; - - let nested_goals = obligations.into_iter().map(|o| o.into()).collect(); + let nested_goals = + ecx.infcx.eq(goal.param_env, goal.predicate.term, term.subst(tcx, substs))?; let rhs_certainty = ecx.evaluate_all(nested_goals)?; Ok(trait_ref_certainty.unify_and(rhs_certainty)) diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 3c8314aa565ee..bbe175d5cc853 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -3,11 +3,10 @@ use std::iter; use super::assembly::{self, Candidate, CandidateSource}; +use super::infcx_ext::InferCtxtExt; use super::{Certainty, EvalCtxt, Goal, QueryResult}; use rustc_hir::def_id::DefId; -use rustc_infer::infer::InferOk; use rustc_infer::traits::query::NoSolution; -use rustc_infer::traits::ObligationCause; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::TraitPredicate; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -45,24 +44,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { let impl_substs = ecx.infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id); let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs); - let Ok(InferOk { obligations, .. }) = ecx.infcx - .at(&ObligationCause::dummy(), goal.param_env) - .define_opaque_types(false) - .eq(goal.predicate.trait_ref, impl_trait_ref) - .map_err(|e| debug!("failed to equate trait refs: {e:?}")) - else { - return Err(NoSolution); - }; + let mut nested_goals = + ecx.infcx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?; let where_clause_bounds = tcx .predicates_of(impl_def_id) .instantiate(tcx, impl_substs) .predicates .into_iter() .map(|pred| goal.with(tcx, pred)); - - let nested_goals = - obligations.into_iter().map(|o| o.into()).chain(where_clause_bounds).collect(); - + nested_goals.extend(where_clause_bounds); ecx.evaluate_all(nested_goals) }) } From 31ac29d9899c063fdee7a78988990f2b037bef7b Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 17 Jan 2023 13:41:12 +0100 Subject: [PATCH 136/230] update project to emulate a projection cache --- .../src/solve/infcx_ext.rs | 8 ++ .../src/solve/project_goals.rs | 128 ++++++++++++++++-- .../src/solve/search_graph/mod.rs | 2 +- 3 files changed, 124 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/infcx_ext.rs b/compiler/rustc_trait_selection/src/solve/infcx_ext.rs index f92d64631340a..9b7feb5053787 100644 --- a/compiler/rustc_trait_selection/src/solve/infcx_ext.rs +++ b/compiler/rustc_trait_selection/src/solve/infcx_ext.rs @@ -3,6 +3,7 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi use rustc_infer::infer::{InferCtxt, InferOk}; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::ObligationCause; +use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_middle::ty::{self, Ty}; use rustc_span::DUMMY_SP; @@ -16,6 +17,7 @@ use super::Goal; /// help. pub(super) trait InferCtxtExt<'tcx> { fn next_ty_infer(&self) -> Ty<'tcx>; + fn next_const_infer(&self, ty: Ty<'tcx>) -> ty::Const<'tcx>; fn eq>( &self, @@ -32,6 +34,12 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { span: DUMMY_SP, }) } + fn next_const_infer(&self, ty: Ty<'tcx>) -> ty::Const<'tcx> { + self.next_const_var( + ty, + ConstVariableOrigin { kind: ConstVariableOriginKind::MiscVariable, span: DUMMY_SP }, + ) + } #[instrument(level = "debug", skip(self, param_env), ret)] fn eq>( diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index cf07926f85a27..435f2877fb329 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -2,7 +2,7 @@ use crate::traits::{specialization_graph, translate_substs}; use super::assembly::{self, Candidate, CandidateSource}; use super::infcx_ext::InferCtxtExt; -use super::{Certainty, EvalCtxt, Goal, QueryResult}; +use super::{Certainty, EvalCtxt, Goal, MaybeCause, QueryResult}; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; @@ -11,19 +11,112 @@ use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::specialization_graph::LeafDef; use rustc_infer::traits::Reveal; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; -use rustc_middle::ty::ProjectionPredicate; use rustc_middle::ty::TypeVisitable; use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{ProjectionPredicate, TypeSuperVisitable, TypeVisitor}; use rustc_span::DUMMY_SP; use std::iter; +use std::ops::ControlFlow; impl<'tcx> EvalCtxt<'_, 'tcx> { pub(super) fn compute_projection_goal( &mut self, goal: Goal<'tcx, ProjectionPredicate<'tcx>>, ) -> QueryResult<'tcx> { - let candidates = self.assemble_and_evaluate_candidates(goal); - self.merge_project_candidates(candidates) + // To only compute normalization ones for each projection we only + // normalize if the expected term is an unconstrained inference variable. + // + // E.g. for `::Assoc = u32` we recursively compute the goal + // `exists ::Assoc = U` and then take the resulting type for + // `U` and equate it with `u32`. This means that we don't need a separate + // projection cache in the solver. + if self.term_is_fully_unconstrained(goal) { + let candidates = self.assemble_and_evaluate_candidates(goal); + self.merge_project_candidates(candidates) + } else { + let predicate = goal.predicate; + let unconstrained_rhs = match predicate.term.unpack() { + ty::TermKind::Ty(_) => self.infcx.next_ty_infer().into(), + ty::TermKind::Const(ct) => self.infcx.next_const_infer(ct.ty()).into(), + }; + let unconstrained_predicate = ty::Clause::Projection(ProjectionPredicate { + projection_ty: goal.predicate.projection_ty, + term: unconstrained_rhs, + }); + let (_has_changed, normalize_certainty) = + self.evaluate_goal(goal.with(self.tcx(), unconstrained_predicate))?; + + let nested_eq_goals = + self.infcx.eq(goal.param_env, unconstrained_rhs, predicate.term)?; + let eval_certainty = self.evaluate_all(nested_eq_goals)?; + self.make_canonical_response(normalize_certainty.unify_and(eval_certainty)) + } + } + + /// Is the projection predicate is of the form `exists ::Assoc = T`. + /// + /// This is the case if the `term` is an inference variable in the innermost universe + /// and does not occur in any other part of the predicate. + fn term_is_fully_unconstrained(&self, goal: Goal<'tcx, ProjectionPredicate<'tcx>>) -> bool { + let infcx = self.infcx; + let term_is_infer = match goal.predicate.term.unpack() { + ty::TermKind::Ty(ty) => { + if let &ty::Infer(ty::TyVar(vid)) = ty.kind() { + match infcx.probe_ty_var(vid) { + Ok(value) => bug!("resolved var in query: {goal:?} {value:?}"), + Err(universe) => universe == infcx.universe(), + } + } else { + false + } + } + ty::TermKind::Const(ct) => { + if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() { + match self.infcx.probe_const_var(vid) { + Ok(value) => bug!("resolved var in query: {goal:?} {value:?}"), + Err(universe) => universe == infcx.universe(), + } + } else { + false + } + } + }; + + struct ContainsTerm<'tcx> { + term: ty::Term<'tcx>, + } + impl<'tcx> TypeVisitor<'tcx> for ContainsTerm<'tcx> { + type BreakTy = (); + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { + if t.needs_infer() { + if ty::Term::from(t) == self.term { + ControlFlow::BREAK + } else { + t.super_visit_with(self) + } + } else { + ControlFlow::CONTINUE + } + } + + fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow { + if c.needs_infer() { + if ty::Term::from(c) == self.term { + ControlFlow::BREAK + } else { + c.super_visit_with(self) + } + } else { + ControlFlow::CONTINUE + } + } + } + + let mut visitor = ContainsTerm { term: goal.predicate.term }; + + term_is_infer + && goal.predicate.projection_ty.visit_with(&mut visitor).is_continue() + && goal.param_env.visit_with(&mut visitor).is_continue() } fn merge_project_candidates( @@ -124,14 +217,18 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { nested_goals.extend(where_clause_bounds); let trait_ref_certainty = ecx.evaluate_all(nested_goals)?; + // In case the associated item is hidden due to specialization, we have to + // return ambiguity this would otherwise be incomplete, resulting in + // unsoundness during coherence (#105782). let Some(assoc_def) = fetch_eligible_assoc_item_def( ecx.infcx, goal.param_env, goal_trait_ref, goal.predicate.def_id(), impl_def_id - ) else { - return Err(NoSolution); + )? else { + let certainty = Certainty::Maybe(MaybeCause::Ambiguity); + return Ok(trait_ref_certainty.unify_and(certainty)); }; if !assoc_def.item.defaultness(tcx).has_value() { @@ -178,9 +275,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ty.map_bound(|ty| ty.into()) }; - let nested_goals = - ecx.infcx.eq(goal.param_env, goal.predicate.term, term.subst(tcx, substs))?; - let rhs_certainty = ecx.evaluate_all(nested_goals)?; + // The term of our goal should be fully unconstrained, so this should never fail. + // + // It can however be ambiguous when the resolved type is a projection. + let nested_goals = ecx + .infcx + .eq(goal.param_env, goal.predicate.term, term.subst(tcx, substs)) + .expect("failed to unify with unconstrained term"); + let rhs_certainty = + ecx.evaluate_all(nested_goals).expect("failed to unify with unconstrained term"); Ok(trait_ref_certainty.unify_and(rhs_certainty)) }) @@ -217,10 +320,9 @@ fn fetch_eligible_assoc_item_def<'tcx>( goal_trait_ref: ty::TraitRef<'tcx>, trait_assoc_def_id: DefId, impl_def_id: DefId, -) -> Option { +) -> Result, NoSolution> { let node_item = specialization_graph::assoc_def(infcx.tcx, impl_def_id, trait_assoc_def_id) - .map_err(|ErrorGuaranteed { .. }| ()) - .ok()?; + .map_err(|ErrorGuaranteed { .. }| NoSolution)?; let eligible = if node_item.is_final() { // Non-specializable items are always projectable. @@ -239,5 +341,5 @@ fn fetch_eligible_assoc_item_def<'tcx>( } }; - if eligible { Some(node_item) } else { None } + if eligible { Ok(Some(node_item)) } else { Ok(None) } } diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs index 4f48389410bfa..0030e9aa3e514 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs @@ -105,7 +105,7 @@ impl<'tcx> SearchGraph<'tcx> { } } - /// We cannot simply store the result of [EvalCtxt::compute_goal] as we have to deal with + /// We cannot simply store the result of [super::EvalCtxt::compute_goal] as we have to deal with /// coinductive cycles. /// /// When we encounter a coinductive cycle, we have to prove the final result of that cycle From 415aa663a2cafd07d934dd683db6ab88e65f6c30 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 17 Jan 2023 16:00:00 +0100 Subject: [PATCH 137/230] add note about indirect cycles --- .../rustc_trait_selection/src/solve/search_graph/cache.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/cache.rs b/compiler/rustc_trait_selection/src/solve/search_graph/cache.rs index cb00fe6bf14af..730a8e6125887 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph/cache.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph/cache.rs @@ -59,6 +59,10 @@ impl<'tcx> ProvisionalCache<'tcx> { /// Adds a dependency from the current leaf to `target` in the cache /// to prevent us from moving any goals which depend on the current leaf /// to the global cache while we're still computing `target`. + /// + /// Its important to note that `target` may already be part of a different cycle. + /// In this case we have to ensure that we also depend on all other goals + /// in the existing cycle in addition to the potentially direct cycle with `target`. pub(super) fn add_dependency_of_leaf_on(&mut self, target: EntryIndex) { let depth = self.entries[target].depth; for provisional_entry in &mut self.entries.raw[target.index()..] { From 369f9aa0990bd90b5f193ce149e74170f276c0e4 Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 18 Jan 2023 08:08:58 +0100 Subject: [PATCH 138/230] add comment --- compiler/rustc_trait_selection/src/solve/project_goals.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 435f2877fb329..0658836fb9cd3 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -82,6 +82,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } }; + // Guard against `>::Assoc = ?0>`. struct ContainsTerm<'tcx> { term: ty::Term<'tcx>, } From 925dc37313853f15dc21e42dc869b024fe488ef3 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Tue, 17 Jan 2023 23:17:13 -0800 Subject: [PATCH 139/230] Stop using `BREAK` & `CONTINUE` in compiler Switching them to `Break(())` and `Continue(())` instead. libs-api would like to remove these constants, so stop using them in compiler to make the removal PR later smaller. --- .../src/const_eval/machine.rs | 8 ++--- .../rustc_const_eval/src/interpret/util.rs | 4 +-- .../src/graph/iterate/mod.rs | 8 ++--- .../rustc_hir_analysis/src/check/check.rs | 6 ++-- .../rustc_hir_analysis/src/check/wfcheck.rs | 2 +- .../src/coherence/orphan.rs | 6 ++-- .../src/constrained_generic_params.rs | 4 +-- .../rustc_hir_analysis/src/variance/mod.rs | 2 +- compiler/rustc_hir_typeck/src/closure.rs | 2 +- .../nice_region_error/static_impl_trait.rs | 2 +- .../rustc_infer/src/infer/nll_relate/mod.rs | 4 +-- .../rustc_infer/src/infer/opaque_types.rs | 10 +++--- compiler/rustc_infer/src/infer/resolve.rs | 4 +-- compiler/rustc_lint/src/types.rs | 2 +- compiler/rustc_macros/src/type_visitable.rs | 2 +- compiler/rustc_middle/src/macros.rs | 8 ++--- .../rustc_middle/src/mir/type_visitable.rs | 2 +- compiler/rustc_middle/src/ty/print/pretty.rs | 2 +- .../rustc_middle/src/ty/structural_impls.rs | 8 ++--- compiler/rustc_middle/src/ty/sty.rs | 2 +- compiler/rustc_middle/src/ty/visit.rs | 32 +++++++++---------- compiler/rustc_mir_build/src/lints.rs | 6 ++-- .../rustc_monomorphize/src/polymorphize.rs | 14 ++++---- compiler/rustc_privacy/src/lib.rs | 28 +++++++++------- .../src/traits/coherence.rs | 8 ++--- .../src/traits/const_evaluatable.rs | 2 +- .../src/traits/error_reporting/mod.rs | 2 +- .../rustc_trait_selection/src/traits/mod.rs | 6 ++-- .../src/traits/object_safety.rs | 8 ++--- .../src/traits/query/normalize.rs | 6 ++-- .../src/traits/structural_match.rs | 16 +++++----- 31 files changed, 110 insertions(+), 106 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 4f7c1fc96f13f..ca6b01d8a8a7a 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -225,7 +225,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> { /// `align_offset(ptr, target_align)` needs special handling in const eval, because the pointer /// may not have an address. /// - /// If `ptr` does have a known address, then we return `CONTINUE` and the function call should + /// If `ptr` does have a known address, then we return `Continue(())` and the function call should /// proceed as normal. /// /// If `ptr` doesn't have an address, but its underlying allocation's alignment is at most @@ -273,18 +273,18 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> { ret, StackPopUnwind::NotAllowed, )?; - Ok(ControlFlow::BREAK) + Ok(ControlFlow::Break(())) } else { // Not alignable in const, return `usize::MAX`. let usize_max = Scalar::from_machine_usize(self.machine_usize_max(), self); self.write_scalar(usize_max, dest)?; self.return_to_block(ret)?; - Ok(ControlFlow::BREAK) + Ok(ControlFlow::Break(())) } } Err(_addr) => { // The pointer has an address, continue with function call. - Ok(ControlFlow::CONTINUE) + Ok(ControlFlow::Continue(())) } } } diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index a61d3ab40a5ca..cabc65e2c077e 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -26,7 +26,7 @@ where fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { if !ty.needs_subst() { - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } match *ty.kind() { @@ -48,7 +48,7 @@ where return subst.visit_with(self); } } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } _ => ty.super_visit_with(self), } diff --git a/compiler/rustc_data_structures/src/graph/iterate/mod.rs b/compiler/rustc_data_structures/src/graph/iterate/mod.rs index 57007611a76c3..8a9af300c066e 100644 --- a/compiler/rustc_data_structures/src/graph/iterate/mod.rs +++ b/compiler/rustc_data_structures/src/graph/iterate/mod.rs @@ -317,12 +317,12 @@ where _node: G::Node, _prior_status: Option, ) -> ControlFlow { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } /// Called after all nodes reachable from this one have been examined. fn node_settled(&mut self, _node: G::Node) -> ControlFlow { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } /// Behave as if no edges exist from `source` to `target`. @@ -346,8 +346,8 @@ where prior_status: Option, ) -> ControlFlow { match prior_status { - Some(NodeStatus::Visited) => ControlFlow::BREAK, - _ => ControlFlow::CONTINUE, + Some(NodeStatus::Visited) => ControlFlow::Break(()), + _ => ControlFlow::Continue(()), } } } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index e58669433e218..d5e4b4cb9e728 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -267,7 +267,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { debug!(?t, "root_visit_ty"); if t == self.opaque_identity_ty { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } else { t.visit_with(&mut ConstrainOpaqueTypeRegionVisitor { tcx: self.tcx, @@ -282,7 +282,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( if self.references_parent_regions { ControlFlow::Break(t) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } @@ -1439,7 +1439,7 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> E match *t.kind() { ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => { self.0.push(def); - ControlFlow::CONTINUE + ControlFlow::Continue(()) } _ => t.super_visit_with(self), } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 49dd1eb22f7fe..8739228e207b0 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1428,7 +1428,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id } fn visit_region(&mut self, _: ty::Region<'tcx>) -> ControlFlow { - ControlFlow::BREAK + ControlFlow::Break(()) } fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow { diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 0aadc9f311b03..0d070f3d118e0 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -416,13 +416,13 @@ fn fast_reject_auto_impl<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, self_ty: if t != self.self_ty_root { for impl_def_id in tcx.non_blanket_impls_for_ty(self.trait_def_id, t) { match tcx.impl_polarity(impl_def_id) { - ImplPolarity::Negative => return ControlFlow::BREAK, + ImplPolarity::Negative => return ControlFlow::Break(()), ImplPolarity::Reservation => {} // FIXME(@lcnr): That's probably not good enough, idk // // We might just want to take the rustdoc code and somehow avoid // explicit impls for `Self`. - ImplPolarity::Positive => return ControlFlow::CONTINUE, + ImplPolarity::Positive => return ControlFlow::Continue(()), } } } @@ -440,7 +440,7 @@ fn fast_reject_auto_impl<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, self_ty: } } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } _ => t.super_visit_with(self), } diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs index 95c971c0d7845..56cc1d8fadc00 100644 --- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs +++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs @@ -61,7 +61,7 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { match *t.kind() { ty::Alias(ty::Projection, ..) if !self.include_nonconstraining => { // projections are not injective - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } ty::Param(data) => { self.parameters.push(Parameter::from(data)); @@ -76,7 +76,7 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { if let ty::ReEarlyBound(data) = *r { self.parameters.push(Parameter::from(data)); } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow { diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index 24008f8881433..079070be27983 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -92,7 +92,7 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc a.visit_with(self)?; } } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } else { substs.visit_with(self) } diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 26e8dd654c13f..12a2abfa76a92 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -236,7 +236,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { if t == self.expected_ty { - ControlFlow::BREAK + ControlFlow::Break(()) } else { t.super_visit_with(self) } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index fb0f09198ccc1..49ad3ce50b8f5 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -543,7 +543,7 @@ impl<'tcx> TypeVisitor<'tcx> for TraitObjectVisitor { if let Some(def_id) = preds.principal_def_id() { self.0.insert(def_id); } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } _ => t.super_visit_with(self), } diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 985cb6463a064..f235cb5ab4503 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -849,7 +849,7 @@ impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> { t.super_visit_with(self); self.target_index.shift_out(1); - ControlFlow::CONTINUE + ControlFlow::Continue(()) } fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { @@ -863,7 +863,7 @@ impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> { _ => {} } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 6b54ee9576f67..e22ba9785e1fd 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -440,16 +440,16 @@ where t: &ty::Binder<'tcx, T>, ) -> ControlFlow { t.super_visit_with(self); - ControlFlow::CONTINUE + ControlFlow::Continue(()) } fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { match *r { // ignore bound regions, keep visiting - ty::ReLateBound(_, _) => ControlFlow::CONTINUE, + ty::ReLateBound(_, _) => ControlFlow::Continue(()), _ => { (self.op)(r); - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } @@ -457,7 +457,7 @@ where fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { // We're only interested in types involving regions if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) { - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } match ty.kind() { @@ -507,7 +507,7 @@ where } } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 8671f8d45a917..65b90aa3d79d3 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -147,7 +147,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeOrConstFinder<'a, 'tcx> { } else if !t.has_non_region_infer() { // All const/type variables in inference types must already be resolved, // no need to visit the contents. - ControlFlow::CONTINUE + ControlFlow::Continue(()) } else { // Otherwise, keep visiting. t.super_visit_with(self) @@ -178,7 +178,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeOrConstFinder<'a, 'tcx> { } else if !ct.has_non_region_infer() { // All const/type variables in inference types must already be resolved, // no need to visit the contents. - ControlFlow::CONTINUE + ControlFlow::Continue(()) } else { // Otherwise, keep visiting. ct.super_visit_with(self) diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index f2ab44ac97c83..be47a3e238c1c 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1147,7 +1147,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { if !ty.has_opaque_types() { - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } if let ty::Alias(ty::Opaque, ..) = ty.kind() { diff --git a/compiler/rustc_macros/src/type_visitable.rs b/compiler/rustc_macros/src/type_visitable.rs index 14e6aa6e0c17b..1f95661ce9d5f 100644 --- a/compiler/rustc_macros/src/type_visitable.rs +++ b/compiler/rustc_macros/src/type_visitable.rs @@ -26,7 +26,7 @@ pub fn type_visitable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2: __visitor: &mut __V ) -> ::std::ops::ControlFlow<__V::BreakTy> { match *self { #body_visit } - ::std::ops::ControlFlow::CONTINUE + ::std::ops::ControlFlow::Continue(()) } }, ) diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs index 5ca4d260179ce..250f3d0797eb5 100644 --- a/compiler/rustc_middle/src/macros.rs +++ b/compiler/rustc_middle/src/macros.rs @@ -93,7 +93,7 @@ macro_rules! TrivialTypeTraversalImpls { _: &mut F) -> ::std::ops::ControlFlow { - ::std::ops::ControlFlow::CONTINUE + ::std::ops::ControlFlow::Continue(()) } } )+ @@ -219,7 +219,7 @@ macro_rules! EnumTypeTraversalImpl { $($crate::ty::visit::TypeVisitable::visit_with( $variant_arg, $visitor )?;)* - ::std::ops::ControlFlow::CONTINUE + ::std::ops::ControlFlow::Continue(()) } $($output)* ) @@ -237,7 +237,7 @@ macro_rules! EnumTypeTraversalImpl { $($crate::ty::visit::TypeVisitable::visit_with( $variant_arg, $visitor )?;)* - ::std::ops::ControlFlow::CONTINUE + ::std::ops::ControlFlow::Continue(()) } $($output)* ) @@ -251,7 +251,7 @@ macro_rules! EnumTypeTraversalImpl { @VisitVariants($this, $visitor) input($($input)*) output( - $variant => { ::std::ops::ControlFlow::CONTINUE } + $variant => { ::std::ops::ControlFlow::Continue(()) } $($output)* ) ) diff --git a/compiler/rustc_middle/src/mir/type_visitable.rs b/compiler/rustc_middle/src/mir/type_visitable.rs index e7cd497b206a9..d44c6809bd830 100644 --- a/compiler/rustc_middle/src/mir/type_visitable.rs +++ b/compiler/rustc_middle/src/mir/type_visitable.rs @@ -4,6 +4,6 @@ use super::*; impl<'tcx, R: Idx, C: Idx> TypeVisitable<'tcx> for BitMatrix { fn visit_with>(&self, _: &mut V) -> ControlFlow { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 42fc78a4715f4..a483945ccf262 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2481,7 +2481,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { if not_previously_inserted { ty.super_visit_with(self) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 81ec18684fd85..7d4d35b7fdf94 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -367,7 +367,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::AdtDef<'tcx> { impl<'tcx> TypeVisitable<'tcx> for ty::AdtDef<'tcx> { fn visit_with>(&self, _visitor: &mut V) -> ControlFlow { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -714,7 +714,7 @@ impl<'tcx> TypeSuperVisitable<'tcx> for Ty<'tcx> { | ty::Placeholder(..) | ty::Param(..) | ty::Never - | ty::Foreign(..) => ControlFlow::CONTINUE, + | ty::Foreign(..) => ControlFlow::Continue(()), } } } @@ -742,7 +742,7 @@ impl<'tcx> TypeSuperFoldable<'tcx> for ty::Region<'tcx> { impl<'tcx> TypeSuperVisitable<'tcx> for ty::Region<'tcx> { fn super_visit_with>(&self, _visitor: &mut V) -> ControlFlow { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -844,7 +844,7 @@ impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> { impl<'tcx> TypeVisitable<'tcx> for InferConst<'tcx> { fn visit_with>(&self, _visitor: &mut V) -> ControlFlow { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 3f8252aefdc39..8720ee26b4273 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2015,7 +2015,7 @@ impl<'tcx> Ty<'tcx> { type BreakTy = (); fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { - if self.0 == t { ControlFlow::BREAK } else { t.super_visit_with(self) } + if self.0 == t { ControlFlow::Break(()) } else { t.super_visit_with(self) } } } diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index ca44555813138..bee3cc4d7cb9b 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -294,13 +294,13 @@ impl<'tcx> TyCtxt<'tcx> { fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { match *r { ty::ReLateBound(debruijn, _) if debruijn < self.outer_index => { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } _ => { if (self.callback)(r) { - ControlFlow::BREAK + ControlFlow::Break(()) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } @@ -311,7 +311,7 @@ impl<'tcx> TyCtxt<'tcx> { if ty.flags().intersects(TypeFlags::HAS_FREE_REGIONS) { ty.super_visit_with(self) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } @@ -394,7 +394,7 @@ impl<'tcx> TypeVisitor<'tcx> for ValidateBoundVars<'tcx> { if t.outer_exclusive_binder() < self.binder_index || !self.visited.insert((self.binder_index, t)) { - return ControlFlow::BREAK; + return ControlFlow::Break(()); } match *t.kind() { ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => { @@ -512,7 +512,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { if t.outer_exclusive_binder() > self.outer_index { ControlFlow::Break(FoundEscapingVars) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -524,7 +524,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { if r.bound_at_or_above_binder(self.outer_index) { ControlFlow::Break(FoundEscapingVars) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -547,7 +547,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { if predicate.outer_exclusive_binder() > self.outer_index { ControlFlow::Break(FoundEscapingVars) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } @@ -575,7 +575,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { if flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -585,7 +585,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { if flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -596,7 +596,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { if flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -605,7 +605,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { if predicate.flags().intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } @@ -653,7 +653,7 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { // in the normalized form if self.just_constrained { if let ty::Alias(..) = t.kind() { - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } } @@ -666,7 +666,7 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { // in the normalized form if self.just_constrained { if let ty::ConstKind::Unevaluated(..) = c.kind() { - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } } @@ -679,7 +679,7 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { self.regions.insert(br.kind); } } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -726,6 +726,6 @@ impl<'tcx> TypeVisitor<'tcx> for MaxUniverse { ); } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs index fac4997fcbf6d..f67f24b43c4d7 100644 --- a/compiler/rustc_mir_build/src/lints.rs +++ b/compiler/rustc_mir_build/src/lints.rs @@ -118,7 +118,7 @@ impl<'mir, 'tcx> TriColorVisitor> for Search<'mir, 'tcx> { // A diverging InlineAsm is treated as non-recursing TerminatorKind::InlineAsm { destination, .. } => { if destination.is_some() { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } else { ControlFlow::Break(NonRecursive) } @@ -132,7 +132,7 @@ impl<'mir, 'tcx> TriColorVisitor> for Search<'mir, 'tcx> { | TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseUnwind { .. } | TerminatorKind::Goto { .. } - | TerminatorKind::SwitchInt { .. } => ControlFlow::CONTINUE, + | TerminatorKind::SwitchInt { .. } => ControlFlow::Continue(()), } } @@ -145,7 +145,7 @@ impl<'mir, 'tcx> TriColorVisitor> for Search<'mir, 'tcx> { } } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } fn ignore_edge(&mut self, bb: BasicBlock, target: BasicBlock) -> bool { diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index c8fc69eb856ab..cf13d4584a124 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -300,20 +300,20 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { #[instrument(level = "debug", skip(self))] fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow { if !c.has_non_region_param() { - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } match c.kind() { ty::ConstKind::Param(param) => { debug!(?param); self.unused_parameters.mark_used(param.index); - ControlFlow::CONTINUE + ControlFlow::Continue(()) } ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) if matches!(self.tcx.def_kind(def.did), DefKind::AnonConst) => { self.visit_child_body(def.did, substs); - ControlFlow::CONTINUE + ControlFlow::Continue(()) } _ => c.super_visit_with(self), } @@ -322,7 +322,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { #[instrument(level = "debug", skip(self))] fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { if !ty.has_non_region_param() { - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } match *ty.kind() { @@ -330,18 +330,18 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { debug!(?def_id); // Avoid cycle errors with generators. if def_id == self.def_id { - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } // Consider any generic parameters used by any closures/generators as used in the // parent. self.visit_child_body(def_id, substs); - ControlFlow::CONTINUE + ControlFlow::Continue(()) } ty::Param(param) => { debug!(?param); self.unused_parameters.mark_used(param.index); - ControlFlow::CONTINUE + ControlFlow::Continue(()) } _ => ty.super_visit_with(self), } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index fb55bb4afaac3..1c492c53de7e1 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -112,7 +112,11 @@ where fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow { let TraitRef { def_id, substs, .. } = trait_ref; self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref.print_only_trait_path())?; - if self.def_id_visitor.shallow() { ControlFlow::CONTINUE } else { substs.visit_with(self) } + if self.def_id_visitor.shallow() { + ControlFlow::Continue(()) + } else { + substs.visit_with(self) + } } fn visit_projection_ty(&mut self, projection: ty::AliasTy<'tcx>) -> ControlFlow { @@ -131,7 +135,7 @@ where }; self.visit_trait(trait_ref)?; if self.def_id_visitor.shallow() { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } else { assoc_substs.iter().try_for_each(|subst| subst.visit_with(self)) } @@ -155,7 +159,7 @@ where ty, _region, ))) => ty.visit_with(self), - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) => ControlFlow::CONTINUE, + ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) => ControlFlow::Continue(()), ty::PredicateKind::ConstEvaluatable(ct) => ct.visit_with(self), ty::PredicateKind::WellFormed(arg) => arg.visit_with(self), _ => bug!("unexpected predicate: {:?}", predicate), @@ -189,7 +193,7 @@ where | ty::Generator(def_id, ..) => { self.def_id_visitor.visit_def_id(def_id, "type", &ty)?; if self.def_id_visitor.shallow() { - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } // Default type visitor doesn't visit signatures of fn types. // Something like `fn() -> Priv {my_func}` is considered a private type even if @@ -214,7 +218,7 @@ where // as visible/reachable even if both `Type` and `Trait` are private. // Ideally, associated types should be substituted in the same way as // free type aliases, but this isn't done yet. - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } // This will also visit substs if necessary, so we don't need to recurse. return self.visit_projection_ty(proj); @@ -274,7 +278,7 @@ where } if self.def_id_visitor.shallow() { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } else { ty.super_visit_with(self) } @@ -319,7 +323,7 @@ impl<'a, 'tcx, VL: VisibilityLike> DefIdVisitor<'tcx> for FindMin<'a, 'tcx, VL> if let Some(def_id) = def_id.as_local() { self.min = VL::new_min(self, def_id); } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -881,7 +885,7 @@ impl<'tcx> DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> self.ev.update(def_id, self.level); } } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -1368,9 +1372,9 @@ impl<'tcx> DefIdVisitor<'tcx> for TypePrivacyVisitor<'tcx> { descr: &dyn fmt::Display, ) -> ControlFlow { if self.check_def_id(def_id, kind, descr) { - ControlFlow::BREAK + ControlFlow::Break(()) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } @@ -1865,9 +1869,9 @@ impl<'tcx> DefIdVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'tcx> { descr: &dyn fmt::Display, ) -> ControlFlow { if self.check_def_id(def_id, kind, descr) { - ControlFlow::BREAK + ControlFlow::Break(()) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 0edae34190c30..5f649852d0bbd 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -614,12 +614,12 @@ impl<'tcx> OrphanChecker<'tcx> { fn found_non_local_ty(&mut self, t: Ty<'tcx>) -> ControlFlow> { self.non_local_tys.push((t, self.in_self_ty)); - ControlFlow::CONTINUE + ControlFlow::Continue(()) } fn found_param_ty(&mut self, t: Ty<'tcx>) -> ControlFlow> { if self.search_first_local_ty { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } else { ControlFlow::Break(OrphanCheckEarlyExit::ParamTy(t)) } @@ -641,7 +641,7 @@ enum OrphanCheckEarlyExit<'tcx> { impl<'tcx> TypeVisitor<'tcx> for OrphanChecker<'tcx> { type BreakTy = OrphanCheckEarlyExit<'tcx>; fn visit_region(&mut self, _r: ty::Region<'tcx>) -> ControlFlow { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { @@ -756,6 +756,6 @@ impl<'tcx> TypeVisitor<'tcx> for OrphanChecker<'tcx> { /// parameters, allowing uncovered const parameters in impls seems more useful /// than allowing `impl Trait for i32` to compile. fn visit_const(&mut self, _c: ty::Const<'tcx>) -> ControlFlow { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 71fb6058cd2c5..f779d9dd8d935 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -198,7 +198,7 @@ fn satisfied_from_param_env<'tcx>( // If we start allowing directly writing `ConstKind::Expr` without an intermediate anon const // this will be incorrect. It might be worth investigating making `predicates_of` elaborate // all of the `ConstEvaluatable` bounds rather than having a visitor here. - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 32b0f65176c18..434f75de02bff 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -2932,7 +2932,7 @@ impl<'tcx> ty::TypeVisitor<'tcx> for HasNumericInferVisitor { if matches!(ty.kind(), ty::Infer(ty::FloatVar(_) | ty::IntVar(_))) { ControlFlow::Break(()) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 531aa23d6eac5..f036a311d464c 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -493,7 +493,7 @@ fn is_impossible_method(tcx: TyCtxt<'_>, (impl_def_id, trait_item_def_id): (DefI && let param_def_id = self.generics.type_param(param, self.tcx).def_id && self.tcx.parent(param_def_id) == self.trait_item_def_id { - return ControlFlow::BREAK; + return ControlFlow::Break(()); } t.super_visit_with(self) } @@ -502,7 +502,7 @@ fn is_impossible_method(tcx: TyCtxt<'_>, (impl_def_id, trait_item_def_id): (DefI && let param_def_id = self.generics.region_param(¶m, self.tcx).def_id && self.tcx.parent(param_def_id) == self.trait_item_def_id { - return ControlFlow::BREAK; + return ControlFlow::Break(()); } r.super_visit_with(self) } @@ -511,7 +511,7 @@ fn is_impossible_method(tcx: TyCtxt<'_>, (impl_def_id, trait_item_def_id): (DefI && let param_def_id = self.generics.const_param(¶m, self.tcx).def_id && self.tcx.parent(param_def_id) == self.trait_item_def_id { - return ControlFlow::BREAK; + return ControlFlow::Break(()); } ct.super_visit_with(self) } diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 9a0e3d298eda1..c9121212cd8f1 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -783,16 +783,16 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>( match t.kind() { ty::Param(_) => { if t == self.tcx.types.self_param { - ControlFlow::BREAK + ControlFlow::Break(()) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } ty::Alias(ty::Projection, ref data) if self.tcx.def_kind(data.def_id) == DefKind::ImplTraitPlaceholder => { // We'll deny these later in their own pass - ControlFlow::CONTINUE + ControlFlow::Continue(()) } ty::Alias(ty::Projection, ref data) => { // This is a projected type `::X`. @@ -820,7 +820,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>( .contains(&data.trait_ref(self.tcx).def_id); if is_supertrait_of_current_trait { - ControlFlow::CONTINUE // do not walk contained types, do not report error, do collect $200 + ControlFlow::Continue(()) // do not walk contained types, do not report error, do collect $200 } else { t.super_visit_with(self) // DO walk contained types, POSSIBLY reporting an error } diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index c6ef13e185b2d..1531c50760d53 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -133,7 +133,7 @@ impl<'tcx> TypeVisitor<'tcx> for MaxEscapingBoundVarVisitor { .escaping .max(t.outer_exclusive_binder().as_usize() - self.outer_index.as_usize()); } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } #[inline] @@ -145,7 +145,7 @@ impl<'tcx> TypeVisitor<'tcx> for MaxEscapingBoundVarVisitor { } _ => {} } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow { @@ -153,7 +153,7 @@ impl<'tcx> TypeVisitor<'tcx> for MaxEscapingBoundVarVisitor { ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => { self.escaping = self.escaping.max(debruijn.as_usize() - self.outer_index.as_usize()); - ControlFlow::CONTINUE + ControlFlow::Continue(()) } _ => ct.super_visit_with(self), } diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs index 892a7afd799c7..f398fb06c187a 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -107,25 +107,25 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { ty::FnDef(..) => { // Types of formals and return in `fn(_) -> _` are also irrelevant; // so we do not recur into them via `super_visit_with` - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } ty::Array(_, n) if { n.try_eval_usize(self.tcx, ty::ParamEnv::reveal_all()) == Some(0) } => { // rust-lang/rust#62336: ignore type of contents // for empty array. - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Str | ty::Never => { // These primitive types are always structural match. // // `Never` is kind of special here, but as it is not inhabitable, this should be fine. - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } ty::FnPtr(..) => { if !self.adt_const_param { - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } else { return ControlFlow::Break(ty); } @@ -147,7 +147,7 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { // Even though `NonStructural` does not implement `PartialEq`, // structural equality on `T` does not recur into the raw // pointer. Therefore, one can still use `C` in a pattern. - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } else { return ControlFlow::Break(ty); } @@ -155,7 +155,7 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { ty::Float(_) => { if !self.adt_const_param { - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } else { return ControlFlow::Break(ty); } @@ -172,13 +172,13 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { self.tcx.sess.delay_span_bug(self.span, "ty::Error in structural-match check"); // We still want to check other types after encountering an error, // as this may still emit relevant errors. - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } }; if !self.seen.insert(adt_def.did()) { debug!("Search already seen adt_def: {:?}", adt_def); - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } if !self.type_marked_structural(ty) { From 708861e5b77d2600da523dc817bc831f7d7d7733 Mon Sep 17 00:00:00 2001 From: Ezra Shaw Date: Mon, 16 Jan 2023 23:30:50 +1300 Subject: [PATCH 140/230] remove error code from `#[rustc_variance]` and document its remains --- .../src/error_codes/E0208.md | 45 +++++++++++++++++++ .../rustc_hir_analysis/src/variance/test.rs | 5 +-- src/tools/tidy/src/error_codes.rs | 3 +- tests/ui/error-codes/E0208.rs | 8 ++++ tests/ui/error-codes/E0208.stderr | 8 ++++ .../variance-associated-consts.stderr | 3 +- .../variance/variance-associated-types.stderr | 5 +-- .../ui/variance/variance-object-types.stderr | 3 +- .../variance/variance-regions-direct.stderr | 15 +++---- .../variance/variance-regions-indirect.stderr | 11 +++-- .../ui/variance/variance-trait-bounds.stderr | 9 ++-- .../variance-trait-object-bound.stderr | 3 +- .../ui/variance/variance-types-bounds.stderr | 11 +++-- tests/ui/variance/variance-types.stderr | 13 +++--- 14 files changed, 96 insertions(+), 46 deletions(-) create mode 100644 tests/ui/error-codes/E0208.rs create mode 100644 tests/ui/error-codes/E0208.stderr diff --git a/compiler/rustc_error_codes/src/error_codes/E0208.md b/compiler/rustc_error_codes/src/error_codes/E0208.md index 7edd93e56a945..1ae01106f2014 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0208.md +++ b/compiler/rustc_error_codes/src/error_codes/E0208.md @@ -1 +1,46 @@ #### This error code is internal to the compiler and will not be emitted with normal Rust code. +#### Note: this error code is no longer emitted by the compiler. + +This error code shows the variance of a type's generic parameters. + +Erroneous code example: + +```compile_fail +// NOTE: this feature is perma-unstable and should *only* be used for +// testing purposes. +#![feature(rustc_attrs)] + +#[rustc_variance] +struct Foo<'a, T> { // error: deliberate error to display type's variance + t: &'a mut T, +} +``` + +which produces the following error: + +```text +error: [-, o] + --> :4:1 + | +4 | struct Foo<'a, T> { + | ^^^^^^^^^^^^^^^^^ +``` + +*Note that while `#[rustc_variance]` still exists and is used within the* +*compiler, it no longer is marked as `E0208` and instead has no error code.* + +This error is deliberately triggered with the `#[rustc_variance]` attribute +(`#![feature(rustc_attrs)]` must be enabled) and helps to show you the variance +of the type's generic parameters. You can read more about variance and +subtyping in [this section of the Rustnomicon]. For a more in depth look at +variance (including a more complete list of common variances) see +[this section of the Reference]. For information on how variance is implemented +in the compiler, see [this section of `rustc-dev-guide`]. + +This error can be easily fixed by removing the `#[rustc_variance]` attribute, +the compiler's suggestion to comment it out can be applied automatically with +`rustfix`. + +[this section of the Rustnomicon]: https://doc.rust-lang.org/nomicon/subtyping.html +[this section of the Reference]: https://doc.rust-lang.org/reference/subtyping.html#variance +[this section of `rustc-dev-guide`]: https://rustc-dev-guide.rust-lang.org/variance.html diff --git a/compiler/rustc_hir_analysis/src/variance/test.rs b/compiler/rustc_hir_analysis/src/variance/test.rs index 83ed3e44b3d73..5feeb92d33782 100644 --- a/compiler/rustc_hir_analysis/src/variance/test.rs +++ b/compiler/rustc_hir_analysis/src/variance/test.rs @@ -1,4 +1,3 @@ -use rustc_errors::struct_span_err; use rustc_middle::ty::TyCtxt; use rustc_span::symbol::sym; @@ -8,8 +7,8 @@ pub fn test_variance(tcx: TyCtxt<'_>) { for id in tcx.hir().items() { if tcx.has_attr(id.owner_id.to_def_id(), sym::rustc_variance) { let variances_of = tcx.variances_of(id.owner_id); - struct_span_err!(tcx.sess, tcx.def_span(id.owner_id), E0208, "{:?}", variances_of) - .emit(); + + tcx.sess.struct_span_err(tcx.def_span(id.owner_id), format!("{variances_of:?}")).emit(); } } } diff --git a/src/tools/tidy/src/error_codes.rs b/src/tools/tidy/src/error_codes.rs index bc9fd35ecde37..5b84b51a035d4 100644 --- a/src/tools/tidy/src/error_codes.rs +++ b/src/tools/tidy/src/error_codes.rs @@ -27,8 +27,7 @@ const ERROR_DOCS_PATH: &str = "compiler/rustc_error_codes/src/error_codes/"; const ERROR_TESTS_PATH: &str = "tests/ui/error-codes/"; // Error codes that (for some reason) can't have a doctest in their explanation. Error codes are still expected to provide a code example, even if untested. -const IGNORE_DOCTEST_CHECK: &[&str] = - &["E0208", "E0464", "E0570", "E0601", "E0602", "E0640", "E0717"]; +const IGNORE_DOCTEST_CHECK: &[&str] = &["E0464", "E0570", "E0601", "E0602", "E0640", "E0717"]; // Error codes that don't yet have a UI test. This list will eventually be removed. const IGNORE_UI_TEST_CHECK: &[&str] = diff --git a/tests/ui/error-codes/E0208.rs b/tests/ui/error-codes/E0208.rs new file mode 100644 index 0000000000000..c67d42889d69b --- /dev/null +++ b/tests/ui/error-codes/E0208.rs @@ -0,0 +1,8 @@ +#![feature(rustc_attrs)] + +#[rustc_variance] +struct Foo<'a, T> { //~ ERROR [-, o] + t: &'a mut T, +} + +fn main() {} diff --git a/tests/ui/error-codes/E0208.stderr b/tests/ui/error-codes/E0208.stderr new file mode 100644 index 0000000000000..dbbb41e79500c --- /dev/null +++ b/tests/ui/error-codes/E0208.stderr @@ -0,0 +1,8 @@ +error: [-, o] + --> $DIR/E0208.rs:4:1 + | +LL | struct Foo<'a, T> { + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/variance/variance-associated-consts.stderr b/tests/ui/variance/variance-associated-consts.stderr index f9732d02cb285..4df2d8da3d680 100644 --- a/tests/ui/variance/variance-associated-consts.stderr +++ b/tests/ui/variance/variance-associated-consts.stderr @@ -1,4 +1,4 @@ -error[E0208]: [o] +error: [o] --> $DIR/variance-associated-consts.rs:13:1 | LL | struct Foo { @@ -6,4 +6,3 @@ LL | struct Foo { error: aborting due to previous error -For more information about this error, try `rustc --explain E0208`. diff --git a/tests/ui/variance/variance-associated-types.stderr b/tests/ui/variance/variance-associated-types.stderr index 5ce62884e1d83..51f17c7c22887 100644 --- a/tests/ui/variance/variance-associated-types.stderr +++ b/tests/ui/variance/variance-associated-types.stderr @@ -1,10 +1,10 @@ -error[E0208]: [-, +] +error: [-, +] --> $DIR/variance-associated-types.rs:13:1 | LL | struct Foo<'a, T : Trait<'a>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0208]: [o, o] +error: [o, o] --> $DIR/variance-associated-types.rs:18:1 | LL | struct Bar<'a, T : Trait<'a>> { @@ -12,4 +12,3 @@ LL | struct Bar<'a, T : Trait<'a>> { error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0208`. diff --git a/tests/ui/variance/variance-object-types.stderr b/tests/ui/variance/variance-object-types.stderr index 1c3c1a6d1f223..55a760425ee59 100644 --- a/tests/ui/variance/variance-object-types.stderr +++ b/tests/ui/variance/variance-object-types.stderr @@ -1,4 +1,4 @@ -error[E0208]: [o] +error: [o] --> $DIR/variance-object-types.rs:7:1 | LL | struct Foo<'a> { @@ -6,4 +6,3 @@ LL | struct Foo<'a> { error: aborting due to previous error -For more information about this error, try `rustc --explain E0208`. diff --git a/tests/ui/variance/variance-regions-direct.stderr b/tests/ui/variance/variance-regions-direct.stderr index 27d69b6e82575..eda02e9b03bb8 100644 --- a/tests/ui/variance/variance-regions-direct.stderr +++ b/tests/ui/variance/variance-regions-direct.stderr @@ -1,40 +1,40 @@ -error[E0208]: [-, -, -] +error: [-, -, -] --> $DIR/variance-regions-direct.rs:9:1 | LL | struct Test2<'a, 'b, 'c> { | ^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0208]: [+, +, +] +error: [+, +, +] --> $DIR/variance-regions-direct.rs:18:1 | LL | struct Test3<'a, 'b, 'c> { | ^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0208]: [-, o] +error: [-, o] --> $DIR/variance-regions-direct.rs:27:1 | LL | struct Test4<'a, 'b:'a> { | ^^^^^^^^^^^^^^^^^^^^^^^ -error[E0208]: [+, o] +error: [+, o] --> $DIR/variance-regions-direct.rs:35:1 | LL | struct Test5<'a, 'b:'a> { | ^^^^^^^^^^^^^^^^^^^^^^^ -error[E0208]: [-, o] +error: [-, o] --> $DIR/variance-regions-direct.rs:45:1 | LL | struct Test6<'a, 'b:'a> { | ^^^^^^^^^^^^^^^^^^^^^^^ -error[E0208]: [*] +error: [*] --> $DIR/variance-regions-direct.rs:52:1 | LL | struct Test7<'a> { | ^^^^^^^^^^^^^^^^ -error[E0208]: [+, -, o] +error: [+, -, o] --> $DIR/variance-regions-direct.rs:59:1 | LL | enum Test8<'a, 'b, 'c:'b> { @@ -42,4 +42,3 @@ LL | enum Test8<'a, 'b, 'c:'b> { error: aborting due to 7 previous errors -For more information about this error, try `rustc --explain E0208`. diff --git a/tests/ui/variance/variance-regions-indirect.stderr b/tests/ui/variance/variance-regions-indirect.stderr index 535e97db3fb10..fa2f4d507f3d5 100644 --- a/tests/ui/variance/variance-regions-indirect.stderr +++ b/tests/ui/variance/variance-regions-indirect.stderr @@ -1,28 +1,28 @@ -error[E0208]: [+, -, o, *] +error: [+, -, o, *] --> $DIR/variance-regions-indirect.rs:8:1 | LL | enum Base<'a, 'b, 'c:'b, 'd> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0208]: [*, o, -, +] +error: [*, o, -, +] --> $DIR/variance-regions-indirect.rs:15:1 | LL | struct Derived1<'w, 'x:'y, 'y, 'z> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0208]: [o, o, *] +error: [o, o, *] --> $DIR/variance-regions-indirect.rs:20:1 | LL | struct Derived2<'a, 'b:'a, 'c> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0208]: [o, -, *] +error: [o, -, *] --> $DIR/variance-regions-indirect.rs:25:1 | LL | struct Derived3<'a:'b, 'b, 'c> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0208]: [+, -, o] +error: [+, -, o] --> $DIR/variance-regions-indirect.rs:30:1 | LL | struct Derived4<'a, 'b, 'c:'b> { @@ -30,4 +30,3 @@ LL | struct Derived4<'a, 'b, 'c:'b> { error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0208`. diff --git a/tests/ui/variance/variance-trait-bounds.stderr b/tests/ui/variance/variance-trait-bounds.stderr index 3f6ca62a64069..5a73e541c3a17 100644 --- a/tests/ui/variance/variance-trait-bounds.stderr +++ b/tests/ui/variance/variance-trait-bounds.stderr @@ -1,22 +1,22 @@ -error[E0208]: [+, +] +error: [+, +] --> $DIR/variance-trait-bounds.rs:16:1 | LL | struct TestStruct> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0208]: [*, +] +error: [*, +] --> $DIR/variance-trait-bounds.rs:21:1 | LL | enum TestEnum> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0208]: [*, +] +error: [*, +] --> $DIR/variance-trait-bounds.rs:26:1 | LL | struct TestContraStruct> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0208]: [*, +] +error: [*, +] --> $DIR/variance-trait-bounds.rs:31:1 | LL | struct TestBox+Setter> { @@ -24,4 +24,3 @@ LL | struct TestBox+Setter> { error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0208`. diff --git a/tests/ui/variance/variance-trait-object-bound.stderr b/tests/ui/variance/variance-trait-object-bound.stderr index 9a2c924b96a95..7c46b553f4394 100644 --- a/tests/ui/variance/variance-trait-object-bound.stderr +++ b/tests/ui/variance/variance-trait-object-bound.stderr @@ -1,4 +1,4 @@ -error[E0208]: [-] +error: [-] --> $DIR/variance-trait-object-bound.rs:14:1 | LL | struct TOption<'a> { @@ -6,4 +6,3 @@ LL | struct TOption<'a> { error: aborting due to previous error -For more information about this error, try `rustc --explain E0208`. diff --git a/tests/ui/variance/variance-types-bounds.stderr b/tests/ui/variance/variance-types-bounds.stderr index 523763b8a07b4..bb81644347693 100644 --- a/tests/ui/variance/variance-types-bounds.stderr +++ b/tests/ui/variance/variance-types-bounds.stderr @@ -1,28 +1,28 @@ -error[E0208]: [+, +] +error: [+, +] --> $DIR/variance-types-bounds.rs:7:1 | LL | struct TestImm { | ^^^^^^^^^^^^^^^^^^^^ -error[E0208]: [+, o] +error: [+, o] --> $DIR/variance-types-bounds.rs:13:1 | LL | struct TestMut { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0208]: [+, o] +error: [+, o] --> $DIR/variance-types-bounds.rs:19:1 | LL | struct TestIndirect { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0208]: [o, o] +error: [o, o] --> $DIR/variance-types-bounds.rs:24:1 | LL | struct TestIndirect2 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0208]: [o, o] +error: [o, o] --> $DIR/variance-types-bounds.rs:38:1 | LL | struct TestObject { @@ -30,4 +30,3 @@ LL | struct TestObject { error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0208`. diff --git a/tests/ui/variance/variance-types.stderr b/tests/ui/variance/variance-types.stderr index 5a5aaecffc5eb..9f7f1d9b0e332 100644 --- a/tests/ui/variance/variance-types.stderr +++ b/tests/ui/variance/variance-types.stderr @@ -1,34 +1,34 @@ -error[E0208]: [-, o, o] +error: [-, o, o] --> $DIR/variance-types.rs:10:1 | LL | struct InvariantMut<'a,A:'a,B:'a> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0208]: [o] +error: [o] --> $DIR/variance-types.rs:15:1 | LL | struct InvariantCell { | ^^^^^^^^^^^^^^^^^^^^^^^ -error[E0208]: [o] +error: [o] --> $DIR/variance-types.rs:20:1 | LL | struct InvariantIndirect { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0208]: [+] +error: [+] --> $DIR/variance-types.rs:25:1 | LL | struct Covariant { | ^^^^^^^^^^^^^^^^^^^ -error[E0208]: [-] +error: [-] --> $DIR/variance-types.rs:30:1 | LL | struct Contravariant { | ^^^^^^^^^^^^^^^^^^^^^^^ -error[E0208]: [+, -, o] +error: [+, -, o] --> $DIR/variance-types.rs:35:1 | LL | enum Enum { @@ -36,4 +36,3 @@ LL | enum Enum { error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0208`. From f46f9231a8058bcbfc2c1442f86c072f5bd92ddc Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 18 Jan 2023 12:09:15 +0100 Subject: [PATCH 141/230] Remove extra removal from test path --- src/tools/compiletest/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 2aea30870ff5e..3092c656cd729 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -775,7 +775,7 @@ fn make_test_name( ) -> test::TestName { // Print the name of the file, relative to the repository root. // `src_base` looks like `/path/to/rust/tests/ui` - let root_directory = config.src_base.parent().unwrap().parent().unwrap().parent().unwrap(); + let root_directory = config.src_base.parent().unwrap().parent().unwrap(); let path = testpaths.file.strip_prefix(root_directory).unwrap(); let debugger = match config.debugger { Some(d) => format!("-{}", d), From 5a685a10ec9a8fb6d236f91ab11298c2cf0740c6 Mon Sep 17 00:00:00 2001 From: Albert Larsan Date: Wed, 18 Jan 2023 14:08:41 +0100 Subject: [PATCH 142/230] Correct typo --- compiler/rustc_trait_selection/src/solve/project_goals.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 0658836fb9cd3..a2aad049998af 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -23,7 +23,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { &mut self, goal: Goal<'tcx, ProjectionPredicate<'tcx>>, ) -> QueryResult<'tcx> { - // To only compute normalization ones for each projection we only + // To only compute normalization once for each projection we only // normalize if the expected term is an unconstrained inference variable. // // E.g. for `::Assoc = u32` we recursively compute the goal From b84b1da2dbacdfd7e33428540062380b56bfd8de Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 17 Jan 2023 19:29:52 +0000 Subject: [PATCH 143/230] Canonicalize trait solver response inside probe --- .../src/solve/assembly.rs | 22 +++++++------------ .../rustc_trait_selection/src/solve/mod.rs | 7 ++++++ .../src/solve/project_goals.rs | 10 ++++----- .../src/solve/trait_goals.rs | 10 ++++----- 4 files changed, 25 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs index cd6e4d2bccd5c..c8611294449e9 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -1,7 +1,7 @@ //! Code shared by trait and projection goals for candidate assembly. use super::infcx_ext::InferCtxtExt; -use super::{CanonicalResponse, Certainty, EvalCtxt, Goal}; +use super::{CanonicalResponse, EvalCtxt, Goal, QueryResult}; use rustc_hir::def_id::DefId; use rustc_infer::traits::query::NoSolution; use rustc_middle::ty::TypeFoldable; @@ -89,18 +89,18 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, impl_def_id: DefId, - ) -> Result; + ) -> QueryResult<'tcx>; fn consider_builtin_sized_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> Result; + ) -> QueryResult<'tcx>; fn consider_assumption( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, assumption: ty::Predicate<'tcx>, - ) -> Result; + ) -> QueryResult<'tcx>; } impl<'tcx> EvalCtxt<'_, 'tcx> { pub(super) fn assemble_and_evaluate_candidates>( @@ -180,9 +180,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { tcx.for_each_relevant_impl( goal.predicate.trait_def_id(tcx), goal.predicate.self_ty(), - |impl_def_id| match G::consider_impl_candidate(self, goal, impl_def_id) - .and_then(|certainty| self.make_canonical_response(certainty)) - { + |impl_def_id| match G::consider_impl_candidate(self, goal, impl_def_id) { Ok(result) => candidates .push(Candidate { source: CandidateSource::Impl(impl_def_id), result }), Err(NoSolution) => (), @@ -203,7 +201,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { Err(NoSolution) }; - match result.and_then(|certainty| self.make_canonical_response(certainty)) { + match result { Ok(result) => { candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result }) } @@ -217,9 +215,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { candidates: &mut Vec>, ) { for (i, assumption) in goal.param_env.caller_bounds().iter().enumerate() { - match G::consider_assumption(self, goal, assumption) - .and_then(|certainty| self.make_canonical_response(certainty)) - { + match G::consider_assumption(self, goal, assumption) { Ok(result) => { candidates.push(Candidate { source: CandidateSource::ParamEnv(i), result }) } @@ -268,9 +264,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { .subst_iter_copied(self.tcx(), alias_ty.substs) .enumerate() { - match G::consider_assumption(self, goal, assumption) - .and_then(|certainty| self.make_canonical_response(certainty)) - { + match G::consider_assumption(self, goal, assumption) { Ok(result) => { candidates.push(Candidate { source: CandidateSource::AliasBound(i), result }) } diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 579cd6a2d59cd..32eb84635b536 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -313,6 +313,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } }) } + + fn evaluate_all_and_make_canonical_response( + &mut self, + goals: Vec>>, + ) -> QueryResult<'tcx> { + self.evaluate_all(goals).and_then(|certainty| self.make_canonical_response(certainty)) + } } #[instrument(level = "debug", skip(infcx), ret)] diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 0658836fb9cd3..1d85d31705ad4 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -191,7 +191,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, ProjectionPredicate<'tcx>>, impl_def_id: DefId, - ) -> Result { + ) -> QueryResult<'tcx> { let tcx = ecx.tcx(); let goal_trait_ref = goal.predicate.projection_ty.trait_ref(tcx); @@ -229,7 +229,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { impl_def_id )? else { let certainty = Certainty::Maybe(MaybeCause::Ambiguity); - return Ok(trait_ref_certainty.unify_and(certainty)); + return ecx.make_canonical_response(trait_ref_certainty.unify_and(certainty)); }; if !assoc_def.item.defaultness(tcx).has_value() { @@ -286,14 +286,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { let rhs_certainty = ecx.evaluate_all(nested_goals).expect("failed to unify with unconstrained term"); - Ok(trait_ref_certainty.unify_and(rhs_certainty)) + ecx.make_canonical_response(trait_ref_certainty.unify_and(rhs_certainty)) }) } fn consider_builtin_sized_candidate( _ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> Result { + ) -> QueryResult<'tcx> { bug!("`Sized` does not have an associated type: {:?}", goal); } @@ -301,7 +301,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { _ecx: &mut EvalCtxt<'_, 'tcx>, _goal: Goal<'tcx, Self>, assumption: ty::Predicate<'tcx>, - ) -> Result { + ) -> QueryResult<'tcx> { if let Some(_poly_projection_pred) = assumption.to_opt_poly_projection_pred() { unimplemented!() } else { diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index bbe175d5cc853..111758c77d99c 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -4,7 +4,7 @@ use std::iter; use super::assembly::{self, Candidate, CandidateSource}; use super::infcx_ext::InferCtxtExt; -use super::{Certainty, EvalCtxt, Goal, QueryResult}; +use super::{EvalCtxt, Goal, QueryResult}; use rustc_hir::def_id::DefId; use rustc_infer::traits::query::NoSolution; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; @@ -29,7 +29,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, TraitPredicate<'tcx>>, impl_def_id: DefId, - ) -> Result { + ) -> QueryResult<'tcx> { let tcx = ecx.tcx(); let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); @@ -53,14 +53,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { .into_iter() .map(|pred| goal.with(tcx, pred)); nested_goals.extend(where_clause_bounds); - ecx.evaluate_all(nested_goals) + ecx.evaluate_all_and_make_canonical_response(nested_goals) }) } fn consider_builtin_sized_candidate( _ecx: &mut EvalCtxt<'_, 'tcx>, _goal: Goal<'tcx, Self>, - ) -> Result { + ) -> QueryResult<'tcx> { unimplemented!(); } @@ -68,7 +68,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { _ecx: &mut EvalCtxt<'_, 'tcx>, _goal: Goal<'tcx, Self>, assumption: ty::Predicate<'tcx>, - ) -> Result { + ) -> QueryResult<'tcx> { if let Some(_poly_trait_pred) = assumption.to_opt_poly_trait_pred() { unimplemented!() } else { From f99b273d577914ee0c9073e2e6144aee17354717 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 17 Jan 2023 19:50:50 +0000 Subject: [PATCH 144/230] implement consider_assumption --- .../src/solve/infcx_ext.rs | 26 ++++++++++++++ .../src/solve/project_goals.rs | 35 ++++++++++++++++--- .../src/solve/trait_goals.rs | 19 +++++++--- 3 files changed, 70 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/infcx_ext.rs b/compiler/rustc_trait_selection/src/solve/infcx_ext.rs index 9b7feb5053787..47e6c93016a0e 100644 --- a/compiler/rustc_trait_selection/src/solve/infcx_ext.rs +++ b/compiler/rustc_trait_selection/src/solve/infcx_ext.rs @@ -25,6 +25,13 @@ pub(super) trait InferCtxtExt<'tcx> { lhs: T, rhs: T, ) -> Result>>, NoSolution>; + + fn sup>( + &self, + param_env: ty::ParamEnv<'tcx>, + lhs: T, + rhs: T, + ) -> Result>>, NoSolution>; } impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { @@ -59,4 +66,23 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { NoSolution }) } + + #[instrument(level = "debug", skip(self, param_env), ret)] + fn sup>( + &self, + param_env: ty::ParamEnv<'tcx>, + lhs: T, + rhs: T, + ) -> Result>>, NoSolution> { + self.at(&ObligationCause::dummy(), param_env) + .define_opaque_types(false) + .sup(lhs, rhs) + .map(|InferOk { value: (), obligations }| { + obligations.into_iter().map(|o| o.into()).collect() + }) + .map_err(|e| { + debug!(?e, "failed to sup"); + NoSolution + }) + } } diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 1d85d31705ad4..9ebcb4e4657d8 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -6,7 +6,7 @@ use super::{Certainty, EvalCtxt, Goal, MaybeCause, QueryResult}; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; -use rustc_infer::infer::InferCtxt; +use rustc_infer::infer::{InferCtxt, LateBoundRegionConversionTime}; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::specialization_graph::LeafDef; use rustc_infer::traits::Reveal; @@ -298,12 +298,37 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { } fn consider_assumption( - _ecx: &mut EvalCtxt<'_, 'tcx>, - _goal: Goal<'tcx, Self>, + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, assumption: ty::Predicate<'tcx>, ) -> QueryResult<'tcx> { - if let Some(_poly_projection_pred) = assumption.to_opt_poly_projection_pred() { - unimplemented!() + if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred() { + ecx.infcx.probe(|_| { + let assumption_projection_pred = ecx.infcx.replace_bound_vars_with_fresh_vars( + DUMMY_SP, + LateBoundRegionConversionTime::HigherRankedType, + poly_projection_pred, + ); + let nested_goals = ecx.infcx.sup( + goal.param_env, + goal.predicate.projection_ty, + assumption_projection_pred.projection_ty, + )?; + let subst_certainty = ecx.evaluate_all(nested_goals)?; + + // The term of our goal should be fully unconstrained, so this should never fail. + // + // It can however be ambiguous when the resolved type is a projection. + let nested_goals = ecx + .infcx + .eq(goal.param_env, goal.predicate.term, assumption_projection_pred.term) + .expect("failed to unify with unconstrained term"); + let rhs_certainty = ecx + .evaluate_all(nested_goals) + .expect("failed to unify with unconstrained term"); + + ecx.make_canonical_response(subst_certainty.unify_and(rhs_certainty)) + }) } else { Err(NoSolution) } diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 111758c77d99c..362424b0d1431 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -6,10 +6,11 @@ use super::assembly::{self, Candidate, CandidateSource}; use super::infcx_ext::InferCtxtExt; use super::{EvalCtxt, Goal, QueryResult}; use rustc_hir::def_id::DefId; +use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_infer::traits::query::NoSolution; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; -use rustc_middle::ty::TraitPredicate; use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{ToPolyTraitRef, TraitPredicate}; use rustc_span::DUMMY_SP; impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { @@ -65,12 +66,20 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_assumption( - _ecx: &mut EvalCtxt<'_, 'tcx>, - _goal: Goal<'tcx, Self>, + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, assumption: ty::Predicate<'tcx>, ) -> QueryResult<'tcx> { - if let Some(_poly_trait_pred) = assumption.to_opt_poly_trait_pred() { - unimplemented!() + if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred() { + // FIXME: Constness and polarity + ecx.infcx.probe(|_| { + let nested_goals = ecx.infcx.sup( + goal.param_env, + ty::Binder::dummy(goal.predicate.trait_ref), + poly_trait_pred.to_poly_trait_ref(), + )?; + ecx.evaluate_all_and_make_canonical_response(nested_goals) + }) } else { Err(NoSolution) } From 3d87a8e84850e2f5edc0f87ab2f4d3c2b67a48ac Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 17 Jan 2023 18:19:11 +0000 Subject: [PATCH 145/230] Assemble object bound candidates --- .../src/solve/assembly.rs | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs index c8611294449e9..0a82c14e226fd 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -4,6 +4,7 @@ use super::infcx_ext::InferCtxtExt; use super::{CanonicalResponse, EvalCtxt, Goal, QueryResult}; use rustc_hir::def_id::DefId; use rustc_infer::traits::query::NoSolution; +use rustc_infer::traits::util::elaborate_predicates; use rustc_middle::ty::TypeFoldable; use rustc_middle::ty::{self, Ty, TyCtxt}; use std::fmt::Debug; @@ -119,6 +120,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { self.assemble_alias_bound_candidates(goal, &mut candidates); + self.assemble_object_bound_candidates(goal, &mut candidates); + candidates } @@ -272,4 +275,53 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } } + + fn assemble_object_bound_candidates>( + &mut self, + goal: Goal<'tcx, G>, + candidates: &mut Vec>, + ) { + let self_ty = goal.predicate.self_ty(); + let bounds = match *self_ty.kind() { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(_, _) + | ty::Foreign(_) + | ty::Str + | ty::Array(_, _) + | ty::Slice(_) + | ty::RawPtr(_) + | ty::Ref(_, _, _) + | ty::FnDef(_, _) + | ty::FnPtr(_) + | ty::Alias(..) + | ty::Closure(..) + | ty::Generator(..) + | ty::GeneratorWitness(_) + | ty::Never + | ty::Tuple(_) + | ty::Param(_) + | ty::Placeholder(..) + | ty::Infer(_) + | ty::Error(_) => return, + ty::Bound(..) => bug!("unexpected bound type: {goal:?}"), + ty::Dynamic(bounds, ..) => bounds, + }; + + let tcx = self.tcx(); + for assumption in + elaborate_predicates(tcx, bounds.iter().map(|bound| bound.with_self_ty(tcx, self_ty))) + { + match G::consider_assumption(self, goal, assumption.predicate) + { + Ok(result) => { + candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result }) + } + Err(NoSolution) => (), + } + } + } } From 0368adb262c27e4cc88158c95dabc9dfe8e18e4f Mon Sep 17 00:00:00 2001 From: yukang Date: Wed, 18 Jan 2023 17:23:50 +0800 Subject: [PATCH 146/230] Fix #107090, fix missing arguments for fluent --- .../locales/en-US/infer.ftl | 26 +++++++++---------- compiler/rustc_infer/src/errors/mod.rs | 2 ++ .../nice_region_error/static_impl_trait.rs | 5 +++- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl index cc38d71b484a4..164d6d26d230d 100644 --- a/compiler/rustc_error_messages/locales/en-US/infer.ftl +++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl @@ -268,28 +268,28 @@ infer_but_calling_introduces = {$has_param_name -> [true] `{$param_name}` *[false] `fn` parameter } has {$lifetime_kind -> - [named] lifetime `{$lifetime}` - *[anon] an anonymous lifetime `'_` -} but calling `{assoc_item}` introduces an implicit `'static` lifetime requirement + [true] lifetime `{$lifetime}` + *[false] an anonymous lifetime `'_` +} but calling `{$assoc_item}` introduces an implicit `'static` lifetime requirement .label1 = {$has_lifetime -> - [named] lifetime `{$lifetime}` - *[anon] an anonymous lifetime `'_` + [true] lifetime `{$lifetime}` + *[false] an anonymous lifetime `'_` } .label2 = ...is used and required to live as long as `'static` here because of an implicit lifetime bound on the {$has_impl_path -> - [named] `impl` of `{$impl_path}` - *[anon] inherent `impl` + [true] `impl` of `{$impl_path}` + *[false] inherent `impl` } infer_but_needs_to_satisfy = {$has_param_name -> [true] `{$param_name}` *[false] `fn` parameter } has {$has_lifetime -> - [named] lifetime `{$lifetime}` - *[anon] an anonymous lifetime `'_` + [true] lifetime `{$lifetime}` + *[false] an anonymous lifetime `'_` } but it needs to satisfy a `'static` lifetime requirement .influencer = this data with {$has_lifetime -> - [named] lifetime `{$lifetime}` - *[anon] an anonymous lifetime `'_` + [true] lifetime `{$lifetime}` + *[false] an anonymous lifetime `'_` }... .require = {$spans_empty -> *[true] ...is used and required to live as long as `'static` here @@ -302,8 +302,8 @@ infer_more_targeted = {$has_param_name -> [true] `{$param_name}` *[false] `fn` parameter } has {$has_lifetime -> - [named] lifetime `{$lifetime}` - *[anon] an anonymous lifetime `'_` + [true] lifetime `{$lifetime}` + *[false] an anonymous lifetime `'_` } but calling `{$ident}` introduces an implicit `'static` lifetime requirement infer_ril_introduced_here = `'static` requirement introduced here diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 033a1842edb25..8bf3a160abbb4 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -927,6 +927,8 @@ pub struct ButNeedsToSatisfy { #[subdiagnostic] pub req_introduces_loc: Option, + pub has_param_name: bool, + pub param_name: String, pub spans_empty: bool, pub has_lifetime: bool, pub lifetime: String, diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index 49ad3ce50b8f5..6a463583dfb0f 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -98,6 +98,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let sp = var_origin.span(); let return_sp = sub_origin.span(); let param = self.find_param_with_region(*sup_r, *sub_r)?; + let simple_ident = param.param.pat.simple_ident(); let lifetime_name = if sup_r.has_name() { sup_r.to_string() } else { "'_".to_owned() }; let (mention_influencer, influencer_point) = @@ -187,7 +188,9 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { req_introduces_loc: subdiag, has_lifetime: sup_r.has_name(), - lifetime: sup_r.to_string(), + lifetime: lifetime_name.clone(), + has_param_name: simple_ident.is_some(), + param_name: simple_ident.map(|x| x.to_string()).unwrap_or_default(), spans_empty, bound, }; From 81efdab3f8871ecbef2a504c34ef90ecd3989cf4 Mon Sep 17 00:00:00 2001 From: yukang Date: Wed, 18 Jan 2023 17:28:19 +0800 Subject: [PATCH 147/230] add tests for 107090 --- tests/ui/inference/issue-107090.rs | 31 +++++ tests/ui/inference/issue-107090.stderr | 173 +++++++++++++++++++++++++ 2 files changed, 204 insertions(+) create mode 100644 tests/ui/inference/issue-107090.rs create mode 100644 tests/ui/inference/issue-107090.stderr diff --git a/tests/ui/inference/issue-107090.rs b/tests/ui/inference/issue-107090.rs new file mode 100644 index 0000000000000..9426445656f23 --- /dev/null +++ b/tests/ui/inference/issue-107090.rs @@ -0,0 +1,31 @@ +use std::marker::PhantomData; +struct Foo<'a, 'b, T>(PhantomData<(&'a (), &'b (), T)>) +where + Foo<'short, 'out, T>: Convert<'a, 'b>; + //~^ ERROR mismatched types + //~^^ ERROR mismatched types + //~^^^ ERROR use of undeclared lifetime name + //~| ERROR use of undeclared lifetime name `'out` + +trait Convert<'a, 'b>: Sized { + fn cast(&'a self) -> &'b Self; +} +impl<'long: 'short, 'short, T> Convert<'long, 'b> for Foo<'short, 'out, T> { + //~^ ERROR use of undeclared lifetime name + //~^^ ERROR use of undeclared lifetime name `'out` + //~| ERROR cannot infer an appropriate lifetime for lifetime parameter + fn cast(&'long self) -> &'short Foo<'short, 'out, T> { + //~^ ERROR use of undeclared lifetime name + //~| ERROR cannot infer an appropriate lifetime for lifetime parameter + self + } +} + +fn badboi<'in_, 'out, T>(x: Foo<'in_, 'out, T>, sadness: &'in_ Foo<'short, 'out, T>) -> &'out T { + //~^ ERROR use of undeclared lifetime name + //~^^ ERROR incompatible lifetime on type + //~| ERROR `x` has lifetime `'in_` but it needs to satisfy a `'static` lifetime requirement + sadness.cast() +} + +fn main() {} diff --git a/tests/ui/inference/issue-107090.stderr b/tests/ui/inference/issue-107090.stderr new file mode 100644 index 0000000000000..33cb39014acfa --- /dev/null +++ b/tests/ui/inference/issue-107090.stderr @@ -0,0 +1,173 @@ +error[E0261]: use of undeclared lifetime name `'short` + --> $DIR/issue-107090.rs:4:9 + | +LL | Foo<'short, 'out, T>: Convert<'a, 'b>; + | ^^^^^^ undeclared lifetime + | + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the bound lifetime-generic with a new `'short` lifetime + | +LL | for<'short> Foo<'short, 'out, T>: Convert<'a, 'b>; + | +++++++++++ +help: consider introducing lifetime `'short` here + | +LL | struct Foo<'short, 'a, 'b, T>(PhantomData<(&'a (), &'b (), T)>) + | +++++++ + +error[E0261]: use of undeclared lifetime name `'out` + --> $DIR/issue-107090.rs:4:17 + | +LL | Foo<'short, 'out, T>: Convert<'a, 'b>; + | ^^^^ undeclared lifetime + | +help: consider making the bound lifetime-generic with a new `'out` lifetime + | +LL | for<'out> Foo<'short, 'out, T>: Convert<'a, 'b>; + | +++++++++ +help: consider introducing lifetime `'out` here + | +LL | struct Foo<'out, 'a, 'b, T>(PhantomData<(&'a (), &'b (), T)>) + | +++++ + +error[E0261]: use of undeclared lifetime name `'b` + --> $DIR/issue-107090.rs:13:47 + | +LL | impl<'long: 'short, 'short, T> Convert<'long, 'b> for Foo<'short, 'out, T> { + | - ^^ undeclared lifetime + | | + | help: consider introducing lifetime `'b` here: `'b,` + +error[E0261]: use of undeclared lifetime name `'out` + --> $DIR/issue-107090.rs:13:67 + | +LL | impl<'long: 'short, 'short, T> Convert<'long, 'b> for Foo<'short, 'out, T> { + | - help: consider introducing lifetime `'out` here: `'out,` ^^^^ undeclared lifetime + +error[E0261]: use of undeclared lifetime name `'out` + --> $DIR/issue-107090.rs:17:49 + | +LL | fn cast(&'long self) -> &'short Foo<'short, 'out, T> { + | ^^^^ undeclared lifetime + | +help: consider introducing lifetime `'out` here + | +LL | fn cast<'out>(&'long self) -> &'short Foo<'short, 'out, T> { + | ++++++ +help: consider introducing lifetime `'out` here + | +LL | impl<'out, 'long: 'short, 'short, T> Convert<'long, 'b> for Foo<'short, 'out, T> { + | +++++ + +error[E0261]: use of undeclared lifetime name `'short` + --> $DIR/issue-107090.rs:24:68 + | +LL | fn badboi<'in_, 'out, T>(x: Foo<'in_, 'out, T>, sadness: &'in_ Foo<'short, 'out, T>) -> &'out T { + | - ^^^^^^ undeclared lifetime + | | + | help: consider introducing lifetime `'short` here: `'short,` + +error[E0308]: mismatched types + --> $DIR/issue-107090.rs:4:27 + | +LL | Foo<'short, 'out, T>: Convert<'a, 'b>; + | ^^^^^^^^^^^^^^^ lifetime mismatch + | + = note: expected trait `Convert<'static, 'static>` + found trait `Convert<'a, 'b>` +note: the lifetime `'a` as defined here... + --> $DIR/issue-107090.rs:2:12 + | +LL | struct Foo<'a, 'b, T>(PhantomData<(&'a (), &'b (), T)>) + | ^^ + = note: ...does not necessarily outlive the static lifetime + +error[E0308]: mismatched types + --> $DIR/issue-107090.rs:4:27 + | +LL | Foo<'short, 'out, T>: Convert<'a, 'b>; + | ^^^^^^^^^^^^^^^ lifetime mismatch + | + = note: expected trait `Convert<'static, 'static>` + found trait `Convert<'a, 'b>` +note: the lifetime `'b` as defined here... + --> $DIR/issue-107090.rs:2:16 + | +LL | struct Foo<'a, 'b, T>(PhantomData<(&'a (), &'b (), T)>) + | ^^ + = note: ...does not necessarily outlive the static lifetime + +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'long` due to conflicting requirements + --> $DIR/issue-107090.rs:13:55 + | +LL | impl<'long: 'short, 'short, T> Convert<'long, 'b> for Foo<'short, 'out, T> { + | ^^^^^^^^^^^^^^^^^^^^ + | +note: first, the lifetime cannot outlive the lifetime `'short` as defined here... + --> $DIR/issue-107090.rs:13:21 + | +LL | impl<'long: 'short, 'short, T> Convert<'long, 'b> for Foo<'short, 'out, T> { + | ^^^^^^ + = note: ...but the lifetime must also be valid for the static lifetime... +note: ...so that the types are compatible + --> $DIR/issue-107090.rs:13:55 + | +LL | impl<'long: 'short, 'short, T> Convert<'long, 'b> for Foo<'short, 'out, T> { + | ^^^^^^^^^^^^^^^^^^^^ + = note: expected `Convert<'short, 'static>` + found `Convert<'_, 'static>` + +error: incompatible lifetime on type + --> $DIR/issue-107090.rs:24:29 + | +LL | fn badboi<'in_, 'out, T>(x: Foo<'in_, 'out, T>, sadness: &'in_ Foo<'short, 'out, T>) -> &'out T { + | ^^^^^^^^^^^^^^^^^^ + | +note: because this has an unmet lifetime requirement + --> $DIR/issue-107090.rs:4:27 + | +LL | Foo<'short, 'out, T>: Convert<'a, 'b>; + | ^^^^^^^^^^^^^^^ introduces a `'static` lifetime requirement +note: the lifetime `'out` as defined here... + --> $DIR/issue-107090.rs:24:17 + | +LL | fn badboi<'in_, 'out, T>(x: Foo<'in_, 'out, T>, sadness: &'in_ Foo<'short, 'out, T>) -> &'out T { + | ^^^^ +note: ...does not necessarily outlive the static lifetime introduced by the compatible `impl` + --> $DIR/issue-107090.rs:13:1 + | +LL | impl<'long: 'short, 'short, T> Convert<'long, 'b> for Foo<'short, 'out, T> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0759]: `x` has lifetime `'in_` but it needs to satisfy a `'static` lifetime requirement + --> $DIR/issue-107090.rs:24:29 + | +LL | fn badboi<'in_, 'out, T>(x: Foo<'in_, 'out, T>, sadness: &'in_ Foo<'short, 'out, T>) -> &'out T { + | ^^^^^^^^^^^^^^^^^^ + | | + | this data with lifetime `'in_`... + | ...is used and required to live as long as `'static` here + +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'long` due to conflicting requirements + --> $DIR/issue-107090.rs:17:13 + | +LL | fn cast(&'long self) -> &'short Foo<'short, 'out, T> { + | ^^^^^^^^^^^ + | +note: first, the lifetime cannot outlive the lifetime `'short` as defined here... + --> $DIR/issue-107090.rs:13:21 + | +LL | impl<'long: 'short, 'short, T> Convert<'long, 'b> for Foo<'short, 'out, T> { + | ^^^^^^ + = note: ...but the lifetime must also be valid for the static lifetime... +note: ...so that the types are compatible + --> $DIR/issue-107090.rs:17:13 + | +LL | fn cast(&'long self) -> &'short Foo<'short, 'out, T> { + | ^^^^^^^^^^^ + = note: expected `Convert<'short, 'static>` + found `Convert<'_, 'static>` + +error: aborting due to 12 previous errors + +Some errors have detailed explanations: E0261, E0308, E0495, E0759. +For more information about an error, try `rustc --explain E0261`. From 45aa5c0f90124e926662f2c2c2d9efca065e0397 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 17 Jan 2023 20:16:30 +0000 Subject: [PATCH 148/230] Auto and alias traits --- compiler/rustc_middle/src/ty/mod.rs | 5 + .../src/solve/assembly.rs | 25 +++- .../src/solve/project_goals.rs | 28 +++- .../src/solve/trait_goals.rs | 132 ++++++++++++++++-- 4 files changed, 169 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index e68f27cc0fd5d..db7dd2e5e75d7 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2382,6 +2382,11 @@ impl<'tcx> TyCtxt<'tcx> { self.trait_def(trait_def_id).has_auto_impl } + /// Returns `true` if this is a trait alias. + pub fn trait_is_alias(self, trait_def_id: DefId) -> bool { + self.def_kind(trait_def_id) == DefKind::TraitAlias + } + pub fn trait_is_coinductive(self, trait_def_id: DefId) -> bool { self.trait_is_auto(trait_def_id) || self.lang_items().sized_trait() == Some(trait_def_id) } diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs index 0a82c14e226fd..0759c42338249 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -92,15 +92,25 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy { impl_def_id: DefId, ) -> QueryResult<'tcx>; - fn consider_builtin_sized_candidate( + fn consider_assumption( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, + assumption: ty::Predicate<'tcx>, ) -> QueryResult<'tcx>; - fn consider_assumption( + fn consider_auto_trait_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx>; + + fn consider_trait_alias_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx>; + + fn consider_builtin_sized_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - assumption: ty::Predicate<'tcx>, ) -> QueryResult<'tcx>; } impl<'tcx> EvalCtxt<'_, 'tcx> { @@ -198,7 +208,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ) { let lang_items = self.tcx().lang_items(); let trait_def_id = goal.predicate.trait_def_id(self.tcx()); - let result = if lang_items.sized_trait() == Some(trait_def_id) { + let result = if self.tcx().trait_is_auto(trait_def_id) { + G::consider_auto_trait_candidate(self, goal) + } else if self.tcx().trait_is_alias(trait_def_id) { + G::consider_trait_alias_candidate(self, goal) + } else if lang_items.sized_trait() == Some(trait_def_id) { G::consider_builtin_sized_candidate(self, goal) } else { Err(NoSolution) @@ -315,8 +329,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { for assumption in elaborate_predicates(tcx, bounds.iter().map(|bound| bound.with_self_ty(tcx, self_ty))) { - match G::consider_assumption(self, goal, assumption.predicate) - { + match G::consider_assumption(self, goal, assumption.predicate) { Ok(result) => { candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result }) } diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 9ebcb4e4657d8..3c74de09802d5 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -290,13 +290,6 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { }) } - fn consider_builtin_sized_candidate( - _ecx: &mut EvalCtxt<'_, 'tcx>, - goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { - bug!("`Sized` does not have an associated type: {:?}", goal); - } - fn consider_assumption( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, @@ -333,6 +326,27 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { Err(NoSolution) } } + + fn consider_auto_trait_candidate( + _ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + bug!("auto traits do not have associated types: {:?}", goal); + } + + fn consider_trait_alias_candidate( + _ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + bug!("trait aliases do not have associated types: {:?}", goal); + } + + fn consider_builtin_sized_candidate( + _ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + bug!("`Sized` does not have an associated type: {:?}", goal); + } } /// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code. diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 362424b0d1431..1f18de2e7a9e0 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -6,7 +6,7 @@ use super::assembly::{self, Candidate, CandidateSource}; use super::infcx_ext::InferCtxtExt; use super::{EvalCtxt, Goal, QueryResult}; use rustc_hir::def_id::DefId; -use rustc_infer::infer::LateBoundRegionConversionTime; +use rustc_infer::infer::InferCtxt; use rustc_infer::traits::query::NoSolution; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -58,13 +58,6 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { }) } - fn consider_builtin_sized_candidate( - _ecx: &mut EvalCtxt<'_, 'tcx>, - _goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { - unimplemented!(); - } - fn consider_assumption( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, @@ -84,9 +77,61 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { Err(NoSolution) } } + + fn consider_auto_trait_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + ecx.infcx.probe(|_| { + let constituent_tys = + instantiate_constituent_tys_for_auto_trait(ecx.infcx, goal.predicate.self_ty())?; + ecx.evaluate_goal_for_constituent_tys_and_make_canonical_response(goal, constituent_tys) + }) + } + + fn consider_trait_alias_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + let tcx = ecx.tcx(); + + ecx.infcx.probe(|_| { + let nested_obligations = tcx + .predicates_of(goal.predicate.def_id()) + .instantiate(tcx, goal.predicate.trait_ref.substs); + ecx.evaluate_all_and_make_canonical_response( + nested_obligations.predicates.into_iter().map(|p| goal.with(tcx, p)).collect(), + ) + }) + } + + fn consider_builtin_sized_candidate( + _ecx: &mut EvalCtxt<'_, 'tcx>, + _goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + unimplemented!(); + } } impl<'tcx> EvalCtxt<'_, 'tcx> { + fn evaluate_goal_for_constituent_tys_and_make_canonical_response( + &mut self, + goal: Goal<'tcx, TraitPredicate<'tcx>>, + constituent_tys: Vec>, + ) -> QueryResult<'tcx> { + self.evaluate_all_and_make_canonical_response( + constituent_tys + .into_iter() + .map(|ty| { + goal.with( + self.tcx(), + ty::Binder::dummy(goal.predicate.with_self_ty(self.tcx(), ty)), + ) + }) + .collect(), + ) + } + pub(super) fn compute_trait_goal( &mut self, goal: Goal<'tcx, TraitPredicate<'tcx>>, @@ -162,3 +207,74 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { candidate } } + +// Calculates the constituent types of a type for `auto trait` purposes. +// +// For types with an "existential" binder, i.e. generator witnesses, we also +// instantiate the binder with placeholders eagerly. +fn instantiate_constituent_tys_for_auto_trait<'tcx>( + infcx: &InferCtxt<'tcx>, + ty: Ty<'tcx>, +) -> Result>, NoSolution> { + let tcx = infcx.tcx; + match *ty.kind() { + ty::Uint(_) + | ty::Int(_) + | ty::Bool + | ty::Float(_) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::Str + | ty::Error(_) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Never + | ty::Char => Ok(vec![]), + + ty::Placeholder(..) + | ty::Dynamic(..) + | ty::Param(..) + | ty::Foreign(..) + | ty::Alias(ty::Projection, ..) + | ty::Bound(..) + | ty::Infer(ty::TyVar(_)) => { + // FIXME: Do we need to mark anything as ambiguous here? Yeah? + Err(NoSolution) + } + + ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), + + ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => { + Ok(vec![element_ty]) + } + + ty::Array(element_ty, _) | ty::Slice(element_ty) => Ok(vec![element_ty]), + + ty::Tuple(ref tys) => { + // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet + Ok(tys.iter().collect()) + } + + ty::Closure(_, ref substs) => Ok(vec![substs.as_closure().tupled_upvars_ty()]), + + ty::Generator(_, ref substs, _) => { + let generator_substs = substs.as_generator(); + Ok(vec![generator_substs.tupled_upvars_ty(), generator_substs.witness()]) + } + + ty::GeneratorWitness(types) => { + Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec()) + } + + // For `PhantomData`, we pass `T`. + ty::Adt(def, substs) if def.is_phantom_data() => Ok(vec![substs.type_at(0)]), + + ty::Adt(def, substs) => Ok(def.all_fields().map(|f| f.ty(tcx, substs)).collect()), + + ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { + // We can resolve the `impl Trait` to its concrete type, + // which enforces a DAG between the functions requiring + // the auto trait bounds in question. + Ok(vec![tcx.bound_type_of(def_id).subst(tcx, substs)]) + } + } +} From 685c32fd858acf107108abd6d35782532a0064e2 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 17 Jan 2023 20:24:58 +0000 Subject: [PATCH 149/230] Sized, Copy/Clone --- .../src/solve/assembly.rs | 10 ++ .../src/solve/project_goals.rs | 7 + .../src/solve/trait_goals.rs | 137 +++++++++++++++++- 3 files changed, 151 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs index 0759c42338249..2336fb53aec28 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -112,7 +112,13 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; + + fn consider_builtin_copy_clone_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx>; } + impl<'tcx> EvalCtxt<'_, 'tcx> { pub(super) fn assemble_and_evaluate_candidates>( &mut self, @@ -214,6 +220,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { G::consider_trait_alias_candidate(self, goal) } else if lang_items.sized_trait() == Some(trait_def_id) { G::consider_builtin_sized_candidate(self, goal) + } else if lang_items.copy_trait() == Some(trait_def_id) + || lang_items.clone_trait() == Some(trait_def_id) + { + G::consider_builtin_copy_clone_candidate(self, goal) } else { Err(NoSolution) }; diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 3c74de09802d5..5c1f3f02e93a8 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -347,6 +347,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ) -> QueryResult<'tcx> { bug!("`Sized` does not have an associated type: {:?}", goal); } + + fn consider_builtin_copy_clone_candidate( + _ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + bug!("`Copy`/`Clone` does not have an associated type: {:?}", goal); + } } /// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code. diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 1f18de2e7a9e0..4d94265dc07f5 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -6,6 +6,7 @@ use super::assembly::{self, Candidate, CandidateSource}; use super::infcx_ext::InferCtxtExt; use super::{EvalCtxt, Goal, QueryResult}; use rustc_hir::def_id::DefId; +use rustc_hir::{Movability, Mutability}; use rustc_infer::infer::InferCtxt; use rustc_infer::traits::query::NoSolution; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; @@ -106,10 +107,27 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_builtin_sized_candidate( - _ecx: &mut EvalCtxt<'_, 'tcx>, - _goal: Goal<'tcx, Self>, + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { - unimplemented!(); + ecx.infcx.probe(|_| { + let constituent_tys = + instantiate_constituent_tys_for_sized_trait(ecx.infcx, goal.predicate.self_ty())?; + ecx.evaluate_goal_for_constituent_tys_and_make_canonical_response(goal, constituent_tys) + }) + } + + fn consider_builtin_copy_clone_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + ecx.infcx.probe(|_| { + let constituent_tys = instantiate_constituent_tys_for_copy_clone_trait( + ecx.infcx, + goal.predicate.self_ty(), + )?; + ecx.evaluate_goal_for_constituent_tys_and_make_canonical_response(goal, constituent_tys) + }) } } @@ -278,3 +296,116 @@ fn instantiate_constituent_tys_for_auto_trait<'tcx>( } } } + +fn instantiate_constituent_tys_for_sized_trait<'tcx>( + infcx: &InferCtxt<'tcx>, + ty: Ty<'tcx>, +) -> Result>, NoSolution> { + match *ty.kind() { + ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Uint(_) + | ty::Int(_) + | ty::Bool + | ty::Float(_) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::RawPtr(..) + | ty::Char + | ty::Ref(..) + | ty::Generator(..) + | ty::GeneratorWitness(..) + | ty::Array(..) + | ty::Closure(..) + | ty::Never + | ty::Dynamic(_, _, ty::DynStar) + | ty::Error(_) => Ok(vec![]), + + ty::Str + | ty::Slice(_) + | ty::Dynamic(..) + | ty::Foreign(..) + | ty::Alias(..) + | ty::Param(_) => Err(NoSolution), + + ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"), + + ty::Placeholder(..) + | ty::Bound(..) + | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), + + ty::Tuple(tys) => Ok(tys.to_vec()), + + ty::Adt(def, substs) => { + let sized_crit = def.sized_constraint(infcx.tcx); + Ok(sized_crit + .0 + .iter() + .map(|ty| sized_crit.rebind(*ty).subst(infcx.tcx, substs)) + .collect()) + } + } +} + +fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( + infcx: &InferCtxt<'tcx>, + ty: Ty<'tcx>, +) -> Result>, NoSolution> { + match *ty.kind() { + ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::Error(_) => Ok(vec![]), + + // Implementations are provided in core + ty::Uint(_) + | ty::Int(_) + | ty::Bool + | ty::Float(_) + | ty::Char + | ty::RawPtr(..) + | ty::Never + | ty::Ref(_, _, Mutability::Not) + | ty::Array(..) => Err(NoSolution), + + ty::Dynamic(..) + | ty::Str + | ty::Slice(_) + | ty::Generator(_, _, Movability::Static) + | ty::Foreign(..) + | ty::Ref(_, _, Mutability::Mut) + | ty::Adt(_, _) + | ty::Alias(_, _) + | ty::Param(_) => Err(NoSolution), + + ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"), + + ty::Placeholder(..) + | ty::Bound(..) + | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), + + ty::Tuple(tys) => Ok(tys.to_vec()), + + ty::Closure(_, substs) => match *substs.as_closure().tupled_upvars_ty().kind() { + ty::Tuple(tys) => Ok(tys.to_vec()), + ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"), + _ => bug!(), + }, + + ty::Generator(_, substs, Movability::Movable) => { + if infcx.tcx.features().generator_clone { + let generator = substs.as_generator(); + match *generator.tupled_upvars_ty().kind() { + ty::Tuple(tys) => Ok(tys.iter().chain([generator.witness()]).collect()), + ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"), + _ => bug!(), + } + } else { + Err(NoSolution) + } + } + + ty::GeneratorWitness(types) => { + Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec()) + } + } +} From 34127c50803cc0a3c68f1f15480399e19d3813af Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 18 Jan 2023 14:40:16 +0000 Subject: [PATCH 150/230] no subtyping in the new trait solver --- .../src/solve/infcx_ext.rs | 36 +++++++------------ .../src/solve/project_goals.rs | 11 +++--- .../src/solve/trait_goals.rs | 10 +++--- 3 files changed, 23 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/infcx_ext.rs b/compiler/rustc_trait_selection/src/solve/infcx_ext.rs index 47e6c93016a0e..42f597c781d25 100644 --- a/compiler/rustc_trait_selection/src/solve/infcx_ext.rs +++ b/compiler/rustc_trait_selection/src/solve/infcx_ext.rs @@ -1,10 +1,10 @@ use rustc_infer::infer::at::ToTrace; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_infer::infer::{InferCtxt, InferOk}; +use rustc_infer::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime}; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::ObligationCause; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, Ty, TypeFoldable}; use rustc_span::DUMMY_SP; use super::Goal; @@ -26,12 +26,10 @@ pub(super) trait InferCtxtExt<'tcx> { rhs: T, ) -> Result>>, NoSolution>; - fn sup>( + fn instantiate_bound_vars_with_infer + Copy>( &self, - param_env: ty::ParamEnv<'tcx>, - lhs: T, - rhs: T, - ) -> Result>>, NoSolution>; + value: ty::Binder<'tcx, T>, + ) -> T; } impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { @@ -67,22 +65,14 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { }) } - #[instrument(level = "debug", skip(self, param_env), ret)] - fn sup>( + fn instantiate_bound_vars_with_infer + Copy>( &self, - param_env: ty::ParamEnv<'tcx>, - lhs: T, - rhs: T, - ) -> Result>>, NoSolution> { - self.at(&ObligationCause::dummy(), param_env) - .define_opaque_types(false) - .sup(lhs, rhs) - .map(|InferOk { value: (), obligations }| { - obligations.into_iter().map(|o| o.into()).collect() - }) - .map_err(|e| { - debug!(?e, "failed to sup"); - NoSolution - }) + value: ty::Binder<'tcx, T>, + ) -> T { + self.replace_bound_vars_with_fresh_vars( + DUMMY_SP, + LateBoundRegionConversionTime::HigherRankedType, + value, + ) } } diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 5c1f3f02e93a8..00c7edf0ef8a3 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -6,7 +6,7 @@ use super::{Certainty, EvalCtxt, Goal, MaybeCause, QueryResult}; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; -use rustc_infer::infer::{InferCtxt, LateBoundRegionConversionTime}; +use rustc_infer::infer::InferCtxt; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::specialization_graph::LeafDef; use rustc_infer::traits::Reveal; @@ -297,12 +297,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ) -> QueryResult<'tcx> { if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred() { ecx.infcx.probe(|_| { - let assumption_projection_pred = ecx.infcx.replace_bound_vars_with_fresh_vars( - DUMMY_SP, - LateBoundRegionConversionTime::HigherRankedType, - poly_projection_pred, - ); - let nested_goals = ecx.infcx.sup( + let assumption_projection_pred = + ecx.infcx.instantiate_bound_vars_with_infer(poly_projection_pred); + let nested_goals = ecx.infcx.eq( goal.param_env, goal.predicate.projection_ty, assumption_projection_pred.projection_ty, diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 4d94265dc07f5..d89759f4dd487 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -10,8 +10,8 @@ use rustc_hir::{Movability, Mutability}; use rustc_infer::infer::InferCtxt; use rustc_infer::traits::query::NoSolution; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; +use rustc_middle::ty::TraitPredicate; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_middle::ty::{ToPolyTraitRef, TraitPredicate}; use rustc_span::DUMMY_SP; impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { @@ -67,10 +67,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred() { // FIXME: Constness and polarity ecx.infcx.probe(|_| { - let nested_goals = ecx.infcx.sup( + let assumption_trait_pred = + ecx.infcx.instantiate_bound_vars_with_infer(poly_trait_pred); + let nested_goals = ecx.infcx.eq( goal.param_env, - ty::Binder::dummy(goal.predicate.trait_ref), - poly_trait_pred.to_poly_trait_ref(), + goal.predicate.trait_ref, + assumption_trait_pred.trait_ref, )?; ecx.evaluate_all_and_make_canonical_response(nested_goals) }) From f672436f04938da11c74664f6665f28018f0a390 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 18 Jan 2023 14:56:44 +0000 Subject: [PATCH 151/230] Handle structural traits more gracefully --- .../src/solve/trait_goals.rs | 248 +++--------------- .../solve/trait_goals/structural_traits.rs | 179 +++++++++++++ 2 files changed, 212 insertions(+), 215 deletions(-) create mode 100644 compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index d89759f4dd487..1ebcfd03c14ea 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -6,7 +6,6 @@ use super::assembly::{self, Candidate, CandidateSource}; use super::infcx_ext::InferCtxtExt; use super::{EvalCtxt, Goal, QueryResult}; use rustc_hir::def_id::DefId; -use rustc_hir::{Movability, Mutability}; use rustc_infer::infer::InferCtxt; use rustc_infer::traits::query::NoSolution; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; @@ -14,6 +13,8 @@ use rustc_middle::ty::TraitPredicate; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::DUMMY_SP; +mod structural_traits; + impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn self_ty(self) -> Ty<'tcx> { self.self_ty() @@ -85,11 +86,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { - ecx.infcx.probe(|_| { - let constituent_tys = - instantiate_constituent_tys_for_auto_trait(ecx.infcx, goal.predicate.self_ty())?; - ecx.evaluate_goal_for_constituent_tys_and_make_canonical_response(goal, constituent_tys) - }) + ecx.probe_and_evaluate_goal_for_constituent_tys( + goal, + structural_traits::instantiate_constituent_tys_for_auto_trait, + ) } fn consider_trait_alias_candidate( @@ -112,44 +112,46 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { - ecx.infcx.probe(|_| { - let constituent_tys = - instantiate_constituent_tys_for_sized_trait(ecx.infcx, goal.predicate.self_ty())?; - ecx.evaluate_goal_for_constituent_tys_and_make_canonical_response(goal, constituent_tys) - }) + ecx.probe_and_evaluate_goal_for_constituent_tys( + goal, + structural_traits::instantiate_constituent_tys_for_sized_trait, + ) } fn consider_builtin_copy_clone_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { - ecx.infcx.probe(|_| { - let constituent_tys = instantiate_constituent_tys_for_copy_clone_trait( - ecx.infcx, - goal.predicate.self_ty(), - )?; - ecx.evaluate_goal_for_constituent_tys_and_make_canonical_response(goal, constituent_tys) - }) + ecx.probe_and_evaluate_goal_for_constituent_tys( + goal, + structural_traits::instantiate_constituent_tys_for_copy_clone_trait, + ) } } impl<'tcx> EvalCtxt<'_, 'tcx> { - fn evaluate_goal_for_constituent_tys_and_make_canonical_response( + /// Convenience function for traits that are structural, i.e. that only + /// have nested subgoals that only change the self type. Unlike other + /// evaluate-like helpers, this does a probe, so it doesn't need to be + /// wrapped in one. + fn probe_and_evaluate_goal_for_constituent_tys( &mut self, goal: Goal<'tcx, TraitPredicate<'tcx>>, - constituent_tys: Vec>, + constituent_tys: impl Fn(&InferCtxt<'tcx>, Ty<'tcx>) -> Result>, NoSolution>, ) -> QueryResult<'tcx> { - self.evaluate_all_and_make_canonical_response( - constituent_tys - .into_iter() - .map(|ty| { - goal.with( - self.tcx(), - ty::Binder::dummy(goal.predicate.with_self_ty(self.tcx(), ty)), - ) - }) - .collect(), - ) + self.infcx.probe(|_| { + self.evaluate_all_and_make_canonical_response( + constituent_tys(self.infcx, goal.predicate.self_ty())? + .into_iter() + .map(|ty| { + goal.with( + self.tcx(), + ty::Binder::dummy(goal.predicate.with_self_ty(self.tcx(), ty)), + ) + }) + .collect(), + ) + }) } pub(super) fn compute_trait_goal( @@ -227,187 +229,3 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { candidate } } - -// Calculates the constituent types of a type for `auto trait` purposes. -// -// For types with an "existential" binder, i.e. generator witnesses, we also -// instantiate the binder with placeholders eagerly. -fn instantiate_constituent_tys_for_auto_trait<'tcx>( - infcx: &InferCtxt<'tcx>, - ty: Ty<'tcx>, -) -> Result>, NoSolution> { - let tcx = infcx.tcx; - match *ty.kind() { - ty::Uint(_) - | ty::Int(_) - | ty::Bool - | ty::Float(_) - | ty::FnDef(..) - | ty::FnPtr(_) - | ty::Str - | ty::Error(_) - | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) - | ty::Never - | ty::Char => Ok(vec![]), - - ty::Placeholder(..) - | ty::Dynamic(..) - | ty::Param(..) - | ty::Foreign(..) - | ty::Alias(ty::Projection, ..) - | ty::Bound(..) - | ty::Infer(ty::TyVar(_)) => { - // FIXME: Do we need to mark anything as ambiguous here? Yeah? - Err(NoSolution) - } - - ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), - - ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => { - Ok(vec![element_ty]) - } - - ty::Array(element_ty, _) | ty::Slice(element_ty) => Ok(vec![element_ty]), - - ty::Tuple(ref tys) => { - // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet - Ok(tys.iter().collect()) - } - - ty::Closure(_, ref substs) => Ok(vec![substs.as_closure().tupled_upvars_ty()]), - - ty::Generator(_, ref substs, _) => { - let generator_substs = substs.as_generator(); - Ok(vec![generator_substs.tupled_upvars_ty(), generator_substs.witness()]) - } - - ty::GeneratorWitness(types) => { - Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec()) - } - - // For `PhantomData`, we pass `T`. - ty::Adt(def, substs) if def.is_phantom_data() => Ok(vec![substs.type_at(0)]), - - ty::Adt(def, substs) => Ok(def.all_fields().map(|f| f.ty(tcx, substs)).collect()), - - ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { - // We can resolve the `impl Trait` to its concrete type, - // which enforces a DAG between the functions requiring - // the auto trait bounds in question. - Ok(vec![tcx.bound_type_of(def_id).subst(tcx, substs)]) - } - } -} - -fn instantiate_constituent_tys_for_sized_trait<'tcx>( - infcx: &InferCtxt<'tcx>, - ty: Ty<'tcx>, -) -> Result>, NoSolution> { - match *ty.kind() { - ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) - | ty::Uint(_) - | ty::Int(_) - | ty::Bool - | ty::Float(_) - | ty::FnDef(..) - | ty::FnPtr(_) - | ty::RawPtr(..) - | ty::Char - | ty::Ref(..) - | ty::Generator(..) - | ty::GeneratorWitness(..) - | ty::Array(..) - | ty::Closure(..) - | ty::Never - | ty::Dynamic(_, _, ty::DynStar) - | ty::Error(_) => Ok(vec![]), - - ty::Str - | ty::Slice(_) - | ty::Dynamic(..) - | ty::Foreign(..) - | ty::Alias(..) - | ty::Param(_) => Err(NoSolution), - - ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"), - - ty::Placeholder(..) - | ty::Bound(..) - | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), - - ty::Tuple(tys) => Ok(tys.to_vec()), - - ty::Adt(def, substs) => { - let sized_crit = def.sized_constraint(infcx.tcx); - Ok(sized_crit - .0 - .iter() - .map(|ty| sized_crit.rebind(*ty).subst(infcx.tcx, substs)) - .collect()) - } - } -} - -fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( - infcx: &InferCtxt<'tcx>, - ty: Ty<'tcx>, -) -> Result>, NoSolution> { - match *ty.kind() { - ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) - | ty::FnDef(..) - | ty::FnPtr(_) - | ty::Error(_) => Ok(vec![]), - - // Implementations are provided in core - ty::Uint(_) - | ty::Int(_) - | ty::Bool - | ty::Float(_) - | ty::Char - | ty::RawPtr(..) - | ty::Never - | ty::Ref(_, _, Mutability::Not) - | ty::Array(..) => Err(NoSolution), - - ty::Dynamic(..) - | ty::Str - | ty::Slice(_) - | ty::Generator(_, _, Movability::Static) - | ty::Foreign(..) - | ty::Ref(_, _, Mutability::Mut) - | ty::Adt(_, _) - | ty::Alias(_, _) - | ty::Param(_) => Err(NoSolution), - - ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"), - - ty::Placeholder(..) - | ty::Bound(..) - | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), - - ty::Tuple(tys) => Ok(tys.to_vec()), - - ty::Closure(_, substs) => match *substs.as_closure().tupled_upvars_ty().kind() { - ty::Tuple(tys) => Ok(tys.to_vec()), - ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"), - _ => bug!(), - }, - - ty::Generator(_, substs, Movability::Movable) => { - if infcx.tcx.features().generator_clone { - let generator = substs.as_generator(); - match *generator.tupled_upvars_ty().kind() { - ty::Tuple(tys) => Ok(tys.iter().chain([generator.witness()]).collect()), - ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"), - _ => bug!(), - } - } else { - Err(NoSolution) - } - } - - ty::GeneratorWitness(types) => { - Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec()) - } - } -} diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs new file mode 100644 index 0000000000000..bbc0c77253278 --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs @@ -0,0 +1,179 @@ +use rustc_hir::{Movability, Mutability}; +use rustc_infer::{infer::InferCtxt, traits::query::NoSolution}; +use rustc_middle::ty::{self, Ty}; + +// Calculates the constituent types of a type for `auto trait` purposes. +// +// For types with an "existential" binder, i.e. generator witnesses, we also +// instantiate the binder with placeholders eagerly. +pub(super) fn instantiate_constituent_tys_for_auto_trait<'tcx>( + infcx: &InferCtxt<'tcx>, + ty: Ty<'tcx>, +) -> Result>, NoSolution> { + let tcx = infcx.tcx; + match *ty.kind() { + ty::Uint(_) + | ty::Int(_) + | ty::Bool + | ty::Float(_) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::Str + | ty::Error(_) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Never + | ty::Char => Ok(vec![]), + + ty::Placeholder(..) + | ty::Dynamic(..) + | ty::Param(..) + | ty::Foreign(..) + | ty::Alias(ty::Projection, ..) + | ty::Bound(..) + | ty::Infer(ty::TyVar(_)) => { + // FIXME: Do we need to mark anything as ambiguous here? Yeah? + Err(NoSolution) + } + + ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), + + ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => { + Ok(vec![element_ty]) + } + + ty::Array(element_ty, _) | ty::Slice(element_ty) => Ok(vec![element_ty]), + + ty::Tuple(ref tys) => { + // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet + Ok(tys.iter().collect()) + } + + ty::Closure(_, ref substs) => Ok(vec![substs.as_closure().tupled_upvars_ty()]), + + ty::Generator(_, ref substs, _) => { + let generator_substs = substs.as_generator(); + Ok(vec![generator_substs.tupled_upvars_ty(), generator_substs.witness()]) + } + + ty::GeneratorWitness(types) => { + Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec()) + } + + // For `PhantomData`, we pass `T`. + ty::Adt(def, substs) if def.is_phantom_data() => Ok(vec![substs.type_at(0)]), + + ty::Adt(def, substs) => Ok(def.all_fields().map(|f| f.ty(tcx, substs)).collect()), + + ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { + // We can resolve the `impl Trait` to its concrete type, + // which enforces a DAG between the functions requiring + // the auto trait bounds in question. + Ok(vec![tcx.bound_type_of(def_id).subst(tcx, substs)]) + } + } +} + +pub(super) fn instantiate_constituent_tys_for_sized_trait<'tcx>( + infcx: &InferCtxt<'tcx>, + ty: Ty<'tcx>, +) -> Result>, NoSolution> { + match *ty.kind() { + ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Uint(_) + | ty::Int(_) + | ty::Bool + | ty::Float(_) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::RawPtr(..) + | ty::Char + | ty::Ref(..) + | ty::Generator(..) + | ty::GeneratorWitness(..) + | ty::Array(..) + | ty::Closure(..) + | ty::Never + | ty::Dynamic(_, _, ty::DynStar) + | ty::Error(_) => Ok(vec![]), + + ty::Str + | ty::Slice(_) + | ty::Dynamic(..) + | ty::Foreign(..) + | ty::Alias(..) + | ty::Param(_) => Err(NoSolution), + + ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"), + + ty::Placeholder(..) + | ty::Bound(..) + | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), + + ty::Tuple(tys) => Ok(tys.to_vec()), + + ty::Adt(def, substs) => { + let sized_crit = def.sized_constraint(infcx.tcx); + Ok(sized_crit + .0 + .iter() + .map(|ty| sized_crit.rebind(*ty).subst(infcx.tcx, substs)) + .collect()) + } + } +} + +pub(super) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( + infcx: &InferCtxt<'tcx>, + ty: Ty<'tcx>, +) -> Result>, NoSolution> { + match *ty.kind() { + ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::Error(_) => Ok(vec![]), + + // Implementations are provided in core + ty::Uint(_) + | ty::Int(_) + | ty::Bool + | ty::Float(_) + | ty::Char + | ty::RawPtr(..) + | ty::Never + | ty::Ref(_, _, Mutability::Not) + | ty::Array(..) => Err(NoSolution), + + ty::Dynamic(..) + | ty::Str + | ty::Slice(_) + | ty::Generator(_, _, Movability::Static) + | ty::Foreign(..) + | ty::Ref(_, _, Mutability::Mut) + | ty::Adt(_, _) + | ty::Alias(_, _) + | ty::Param(_) => Err(NoSolution), + + ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"), + + ty::Placeholder(..) + | ty::Bound(..) + | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), + + ty::Tuple(tys) => Ok(tys.to_vec()), + + ty::Closure(_, substs) => Ok(vec![substs.as_closure().tupled_upvars_ty()]), + + ty::Generator(_, substs, Movability::Movable) => { + if infcx.tcx.features().generator_clone { + let generator = substs.as_generator(); + Ok(vec![generator.tupled_upvars_ty(), generator.witness()]) + } else { + Err(NoSolution) + } + } + + ty::GeneratorWitness(types) => { + Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec()) + } + } +} From b94a29a25ff9ca4a8edfc0b6c7d1d309dc03d5cd Mon Sep 17 00:00:00 2001 From: clubby789 Date: Tue, 17 Jan 2023 15:42:53 +0000 Subject: [PATCH 152/230] Implement `alloc::vec::IsZero` for `Option<$NUM>` types --- library/alloc/src/lib.rs | 1 + library/alloc/src/vec/is_zero.rs | 17 +++++++++++++++++ tests/codegen/vec-calloc.rs | 17 +++++++++++++++++ 3 files changed, 35 insertions(+) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index afc3a3dc6a8c6..ca75c3895f41f 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -106,6 +106,7 @@ #![feature(const_size_of_val)] #![feature(const_align_of_val)] #![feature(const_ptr_read)] +#![feature(const_maybe_uninit_zeroed)] #![feature(const_maybe_uninit_write)] #![feature(const_maybe_uninit_as_mut_ptr)] #![feature(const_refs_to_cell)] diff --git a/library/alloc/src/vec/is_zero.rs b/library/alloc/src/vec/is_zero.rs index 26120270c0cb0..2b6be14de792d 100644 --- a/library/alloc/src/vec/is_zero.rs +++ b/library/alloc/src/vec/is_zero.rs @@ -147,6 +147,23 @@ impl_is_zero_option_of_nonzero!( NonZeroIsize, ); +macro_rules! impl_is_zero_option_of_num { + ($($t:ty,)+) => {$( + unsafe impl IsZero for Option<$t> { + #[inline] + fn is_zero(&self) -> bool { + const { + let none: Self = unsafe { core::mem::MaybeUninit::zeroed().assume_init() }; + assert!(none.is_none()); + } + self.is_none() + } + } + )+}; +} + +impl_is_zero_option_of_num!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize,); + unsafe impl IsZero for Wrapping { #[inline] fn is_zero(&self) -> bool { diff --git a/tests/codegen/vec-calloc.rs b/tests/codegen/vec-calloc.rs index ae6e448f172f7..9cc5bd4fd1a99 100644 --- a/tests/codegen/vec-calloc.rs +++ b/tests/codegen/vec-calloc.rs @@ -161,6 +161,23 @@ pub fn vec_option_bool(n: usize) -> Vec> { vec![Some(false); n] } +// CHECK-LABEL: @vec_option_i32 +#[no_mangle] +pub fn vec_option_i32(n: usize) -> Vec> { + // CHECK-NOT: call {{.*}}alloc::vec::from_elem + // CHECK-NOT: call {{.*}}reserve + // CHECK-NOT: call {{.*}}__rust_alloc( + + // CHECK: call {{.*}}__rust_alloc_zeroed( + + // CHECK-NOT: call {{.*}}alloc::vec::from_elem + // CHECK-NOT: call {{.*}}reserve + // CHECK-NOT: call {{.*}}__rust_alloc( + + // CHECK: ret void + vec![None; n] +} + // Ensure that __rust_alloc_zeroed gets the right attributes for LLVM to optimize it away. // CHECK: declare noalias ptr @__rust_alloc_zeroed(i64, i64 allocalign) unnamed_addr [[RUST_ALLOC_ZEROED_ATTRS:#[0-9]+]] From 50e9f2e6e87911659b6ae63230a5797f4cdf28e1 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Wed, 18 Jan 2023 15:48:53 +0000 Subject: [PATCH 153/230] Update `IsZero` documentation --- library/alloc/src/vec/is_zero.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/alloc/src/vec/is_zero.rs b/library/alloc/src/vec/is_zero.rs index 2b6be14de792d..cb9adf05c25b0 100644 --- a/library/alloc/src/vec/is_zero.rs +++ b/library/alloc/src/vec/is_zero.rs @@ -4,7 +4,8 @@ use crate::boxed::Box; #[rustc_specialization_trait] pub(super) unsafe trait IsZero { - /// Whether this value's representation is all zeros + /// Whether this value's representation is all zeros, + /// or can be represented with all zeroes. fn is_zero(&self) -> bool; } From b8c5821ad8bd4ae9da7b157d9189e2bc1bfe788e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Wed, 18 Jan 2023 00:00:00 +0000 Subject: [PATCH 154/230] Fix Dominators::rank_partial_cmp to match documentation The only use site is also updated accordingly and there is no change in end-to-end behaviour. --- .../rustc_data_structures/src/graph/dominators/mod.rs | 2 +- compiler/rustc_mir_transform/src/coverage/spans.rs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_data_structures/src/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs index 07b1ace218945..fb2a22e94a527 100644 --- a/compiler/rustc_data_structures/src/graph/dominators/mod.rs +++ b/compiler/rustc_data_structures/src/graph/dominators/mod.rs @@ -299,7 +299,7 @@ impl Dominators { /// of two unrelated nodes will also be consistent, but otherwise the order has no /// meaning.) This method cannot be used to determine if either Node dominates the other. pub fn rank_partial_cmp(&self, lhs: Node, rhs: Node) -> Option { - self.post_order_rank[lhs].partial_cmp(&self.post_order_rank[rhs]) + self.post_order_rank[rhs].partial_cmp(&self.post_order_rank[lhs]) } } diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index 9f842c929dc24..c54348404536a 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -341,11 +341,11 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { if a.is_in_same_bcb(b) { Some(Ordering::Equal) } else { - // Sort equal spans by dominator relationship, in reverse order (so - // dominators always come after the dominated equal spans). When later - // comparing two spans in order, the first will either dominate the second, - // or they will have no dominator relationship. - self.basic_coverage_blocks.dominators().rank_partial_cmp(b.bcb, a.bcb) + // Sort equal spans by dominator relationship (so dominators always come + // before the dominated equal spans). When later comparing two spans in + // order, the first will either dominate the second, or they will have no + // dominator relationship. + self.basic_coverage_blocks.dominators().rank_partial_cmp(a.bcb, b.bcb) } } else { // Sort hi() in reverse order so shorter spans are attempted after longer spans. From 7d57685682778900cb3b8d57605a143d402b8d0c Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Wed, 18 Jan 2023 10:22:21 -0800 Subject: [PATCH 155/230] Also remove `#![feature(control_flow_enum)]` where possible --- compiler/rustc_const_eval/src/lib.rs | 1 - compiler/rustc_data_structures/src/lib.rs | 1 - compiler/rustc_mir_build/src/lib.rs | 1 - compiler/rustc_monomorphize/src/lib.rs | 1 - compiler/rustc_privacy/src/lib.rs | 1 - compiler/rustc_transmute/src/lib.rs | 2 +- compiler/rustc_ty_utils/src/lib.rs | 1 - 7 files changed, 1 insertion(+), 7 deletions(-) diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 46e7b09a55e10..57b91df2d0708 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -6,7 +6,6 @@ Rust MIR: a lowered representation of Rust. #![feature(assert_matches)] #![feature(box_patterns)] -#![feature(control_flow_enum)] #![feature(decl_macro)] #![feature(exact_size_is_empty)] #![feature(let_chains)] diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 3a2000233c5d1..954e84c303b83 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -11,7 +11,6 @@ #![feature(associated_type_bounds)] #![feature(auto_traits)] #![feature(cell_leak)] -#![feature(control_flow_enum)] #![feature(extend_one)] #![feature(hash_raw_entry)] #![feature(hasher_prefixfree_extras)] diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index fb7ae6f1d2424..a428180a4fa82 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -5,7 +5,6 @@ #![feature(assert_matches)] #![feature(associated_type_bounds)] #![feature(box_patterns)] -#![feature(control_flow_enum)] #![feature(if_let_guard)] #![feature(let_chains)] #![feature(min_specialization)] diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index b616ed35d99d7..f88155e4fc792 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -1,5 +1,4 @@ #![feature(array_windows)] -#![feature(control_flow_enum)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] #![deny(rustc::untranslatable_diagnostic)] diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 1c492c53de7e1..9a5d3cceb914e 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1,6 +1,5 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(associated_type_defaults)] -#![feature(control_flow_enum)] #![feature(rustc_private)] #![feature(try_blocks)] #![feature(let_chains)] diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index 384d03106b1e8..b3b9a67b26e3d 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(alloc_layout_extra, control_flow_enum, decl_macro, iterator_try_reduce, never_type)] +#![feature(alloc_layout_extra, decl_macro, iterator_try_reduce, never_type)] #![allow(dead_code, unused_variables)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index 7ad5cbc01ccf2..0853de601b040 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -6,7 +6,6 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(let_chains)] -#![feature(control_flow_enum)] #![feature(never_type)] #![feature(box_patterns)] #![recursion_limit = "256"] From deb05758c8d7e13599617f322be8c03b22d1d724 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 18 Jan 2023 11:41:34 -0700 Subject: [PATCH 156/230] rustdoc: put focus on the help link when opening it from keyboard This prevents some strange blur-event-related bugs with the "?" command by ensuring that the focus remains in the same spot when the settings area closes. --- src/librustdoc/html/static/js/main.js | 3 +++ tests/rustdoc-gui/settings.goml | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 9ceeeb5ae8fd8..6cb670d32a660 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -1082,6 +1082,9 @@ function loadCss(cssUrl) { * Show the help popup menu. */ function showHelp() { + // Prevent `blur` events from being dispatched as a result of closing + // other modals. + getHelpButton().querySelector("a").focus(); const menu = getHelpMenu(true); if (menu.style.display === "none") { window.hideAllModals(); diff --git a/tests/rustdoc-gui/settings.goml b/tests/rustdoc-gui/settings.goml index 72de41e41bae1..2114e2cc4c23d 100644 --- a/tests/rustdoc-gui/settings.goml +++ b/tests/rustdoc-gui/settings.goml @@ -203,6 +203,15 @@ press-key: "?" wait-for-css: ("#help-button .popover", {"display": "block"}) assert-css: ("#settings-menu .popover", {"display": "none"}) +// Now switch back to the settings popover, and make sure the keyboard +// shortcut works when a check box is selected. +click: "#settings-menu > a" +wait-for-css: ("#settings-menu .popover", {"display": "block"}) +focus: "#auto-hide-large-items" +press-key: "?" +wait-for-css: ("#settings-menu .popover", {"display": "none"}) +wait-for-css: ("#help-button .popover", {"display": "block"}) + // Now we go to the settings page to check that the CSS is loaded as expected. goto: "file://" + |DOC_PATH| + "/settings.html" wait-for: "#settings" From bb5fb53b30fd2216639ae85ab44ec4445e004556 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 18 Jan 2023 11:52:31 -0700 Subject: [PATCH 157/230] rustdoc: fix "?" keyboard command when radio button is focused This extends the special case with checkbox settings to also cover radios. --- src/librustdoc/html/static/js/main.js | 3 ++- tests/rustdoc-gui/settings.goml | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 6cb670d32a660..604ab147f6a16 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -390,7 +390,8 @@ function loadCss(cssUrl) { } if (document.activeElement.tagName === "INPUT" && - document.activeElement.type !== "checkbox") { + document.activeElement.type !== "checkbox" && + document.activeElement.type !== "radio") { switch (getVirtualKey(ev)) { case "Escape": handleEscape(ev); diff --git a/tests/rustdoc-gui/settings.goml b/tests/rustdoc-gui/settings.goml index 2114e2cc4c23d..4c72ed51a4979 100644 --- a/tests/rustdoc-gui/settings.goml +++ b/tests/rustdoc-gui/settings.goml @@ -212,6 +212,16 @@ press-key: "?" wait-for-css: ("#settings-menu .popover", {"display": "none"}) wait-for-css: ("#help-button .popover", {"display": "block"}) +// Now switch back to the settings popover, and make sure the keyboard +// shortcut works when a check box is selected. +click: "#settings-menu > a" +wait-for-css: ("#settings-menu .popover", {"display": "block"}) +wait-for-css: ("#help-button .popover", {"display": "none"}) +focus: "#theme-system-preference" +press-key: "?" +wait-for-css: ("#settings-menu .popover", {"display": "none"}) +wait-for-css: ("#help-button .popover", {"display": "block"}) + // Now we go to the settings page to check that the CSS is loaded as expected. goto: "file://" + |DOC_PATH| + "/settings.html" wait-for: "#settings" From a8086cf9dfbe733f1172dfba816c8e65d3f35e76 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Wed, 18 Jan 2023 19:47:22 +0100 Subject: [PATCH 158/230] Revert "Improve heuristics whether `format_args` string is a source literal" This reverts commit e6c02aad9345925cfed74f86b414c4d0715d381b. Keeps the code improvements from the PR and the test (as a known-bug). --- compiler/rustc_parse_format/src/lib.rs | 37 +------------------ .../fmt/auxiliary/format-string-proc-macro.rs | 12 ++++++ tests/ui/fmt/indoc-issue-106408.rs | 9 +++++ .../ui/fmt/respanned-literal-issue-106191.rs | 9 ++++- .../fmt/respanned-literal-issue-106191.stderr | 21 +---------- 5 files changed, 32 insertions(+), 56 deletions(-) create mode 100644 tests/ui/fmt/indoc-issue-106408.rs diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 1eb227503f242..7b016cadac320 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -20,7 +20,6 @@ pub use Flag::*; pub use Piece::*; pub use Position::*; -use rustc_lexer::unescape; use std::iter; use std::str; use std::string; @@ -314,11 +313,12 @@ impl<'a> Parser<'a> { append_newline: bool, mode: ParseMode, ) -> Parser<'a> { - let input_string_kind = find_width_map_from_snippet(s, snippet, style); + let input_string_kind = find_width_map_from_snippet(snippet, style); let (width_map, is_literal) = match input_string_kind { InputStringKind::Literal { width_mappings } => (width_mappings, true), InputStringKind::NotALiteral => (Vec::new(), false), }; + Parser { mode, input: s, @@ -856,7 +856,6 @@ impl<'a> Parser<'a> { /// written code (code snippet) and the `InternedString` that gets processed in the `Parser` /// in order to properly synthesise the intra-string `Span`s for error diagnostics. fn find_width_map_from_snippet( - input: &str, snippet: Option, str_style: Option, ) -> InputStringKind { @@ -869,27 +868,8 @@ fn find_width_map_from_snippet( return InputStringKind::Literal { width_mappings: Vec::new() }; } - // Strip quotes. let snippet = &snippet[1..snippet.len() - 1]; - // Macros like `println` add a newline at the end. That technically doens't make them "literals" anymore, but it's fine - // since we will never need to point our spans there, so we lie about it here by ignoring it. - // Since there might actually be newlines in the source code, we need to normalize away all trailing newlines. - // If we only trimmed it off the input, `format!("\n")` would cause a mismatch as here we they actually match up. - // Alternatively, we could just count the trailing newlines and only trim one from the input if they don't match up. - let input_no_nl = input.trim_end_matches('\n'); - let Ok(unescaped) = unescape_string(snippet) else { - return InputStringKind::NotALiteral; - }; - - let unescaped_no_nl = unescaped.trim_end_matches('\n'); - - if unescaped_no_nl != input_no_nl { - // The source string that we're pointing at isn't our input, so spans pointing at it will be incorrect. - // This can for example happen with proc macros that respan generated literals. - return InputStringKind::NotALiteral; - } - let mut s = snippet.char_indices(); let mut width_mappings = vec![]; while let Some((pos, c)) = s.next() { @@ -972,19 +952,6 @@ fn find_width_map_from_snippet( InputStringKind::Literal { width_mappings } } -fn unescape_string(string: &str) -> Result { - let mut buf = string::String::new(); - let mut error = Ok(()); - unescape::unescape_literal(string, unescape::Mode::Str, &mut |_, unescaped_char| { - match unescaped_char { - Ok(c) => buf.push(c), - Err(err) => error = Err(err), - } - }); - - error.map(|_| buf) -} - // Assert a reasonable size for `Piece` #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] rustc_data_structures::static_assert_size!(Piece<'_>, 16); diff --git a/tests/ui/fmt/auxiliary/format-string-proc-macro.rs b/tests/ui/fmt/auxiliary/format-string-proc-macro.rs index 539c8fb27b3b0..1b7ef93f41d57 100644 --- a/tests/ui/fmt/auxiliary/format-string-proc-macro.rs +++ b/tests/ui/fmt/auxiliary/format-string-proc-macro.rs @@ -28,6 +28,7 @@ pub fn err_with_input_span(input: TokenStream) -> TokenStream { TokenStream::from(TokenTree::Literal(lit)) } + #[proc_macro] pub fn respan_to_invalid_format_literal(input: TokenStream) -> TokenStream { let mut s = Literal::string("{"); @@ -38,3 +39,14 @@ pub fn respan_to_invalid_format_literal(input: TokenStream) -> TokenStream { TokenTree::from(Group::new(Delimiter::Parenthesis, TokenTree::from(s).into())), ]) } + +#[proc_macro] +pub fn capture_a_with_prepended_space_preserve_span(input: TokenStream) -> TokenStream { + let mut s = Literal::string(" {a}"); + s.set_span(input.into_iter().next().unwrap().span()); + TokenStream::from_iter([ + TokenTree::from(Ident::new("format", Span::call_site())), + TokenTree::from(Punct::new('!', Spacing::Alone)), + TokenTree::from(Group::new(Delimiter::Parenthesis, TokenTree::from(s).into())), + ]) +} diff --git a/tests/ui/fmt/indoc-issue-106408.rs b/tests/ui/fmt/indoc-issue-106408.rs new file mode 100644 index 0000000000000..e4e3093b59009 --- /dev/null +++ b/tests/ui/fmt/indoc-issue-106408.rs @@ -0,0 +1,9 @@ +// aux-build:format-string-proc-macro.rs +// check-pass + +extern crate format_string_proc_macro; + +fn main() { + let a = 0; + format_string_proc_macro::capture_a_with_prepended_space_preserve_span!("{a}"); +} diff --git a/tests/ui/fmt/respanned-literal-issue-106191.rs b/tests/ui/fmt/respanned-literal-issue-106191.rs index 44642a10fc076..bb741c0ef93fa 100644 --- a/tests/ui/fmt/respanned-literal-issue-106191.rs +++ b/tests/ui/fmt/respanned-literal-issue-106191.rs @@ -1,10 +1,15 @@ // aux-build:format-string-proc-macro.rs +// check-fail +// known-bug: #106191 +// unset-rustc-env:RUST_BACKTRACE +// had to be reverted +// error-pattern:internal compiler error +// failure-status:101 +// dont-check-compiler-stderr extern crate format_string_proc_macro; fn main() { format_string_proc_macro::respan_to_invalid_format_literal!("¡"); - //~^ ERROR invalid format string: expected `'}'` but string was terminated format_args!(r#concat!("¡ {")); - //~^ ERROR invalid format string: expected `'}'` but string was terminated } diff --git a/tests/ui/fmt/respanned-literal-issue-106191.stderr b/tests/ui/fmt/respanned-literal-issue-106191.stderr index 73a3af65a3849..16717f42253d6 100644 --- a/tests/ui/fmt/respanned-literal-issue-106191.stderr +++ b/tests/ui/fmt/respanned-literal-issue-106191.stderr @@ -1,19 +1,2 @@ -error: invalid format string: expected `'}'` but string was terminated - --> $DIR/respanned-literal-issue-106191.rs:6:65 - | -LL | format_string_proc_macro::respan_to_invalid_format_literal!("¡"); - | ^^^ expected `'}'` in format string - | - = note: if you intended to print `{`, you can escape it using `{{` - -error: invalid format string: expected `'}'` but string was terminated - --> $DIR/respanned-literal-issue-106191.rs:8:18 - | -LL | format_args!(r#concat!("¡ {")); - | ^^^^^^^^^^^^^^^^^^^^^^^ expected `'}'` in format string - | - = note: if you intended to print `{`, you can escape it using `{{` - = note: this error originates in the macro `concat` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to 2 previous errors - + query stack during panic: +end of query stack From 9ee4df0e9cbe474a0f357ed00dd479a2dae65e23 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 18 Jan 2023 12:39:13 -0700 Subject: [PATCH 159/230] rustdoc: remove redundant rule `#settings .setting-line` Since the current version of settings.js always nests things below a div with ID `settings`, this rule always overrode the one above. --- src/librustdoc/html/static/css/settings.css | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/librustdoc/html/static/css/settings.css b/src/librustdoc/html/static/css/settings.css index 3fa478751737f..7211ffb779568 100644 --- a/src/librustdoc/html/static/css/settings.css +++ b/src/librustdoc/html/static/css/settings.css @@ -1,5 +1,5 @@ .setting-line { - margin: 0.6em 0 0.6em 0.3em; + margin: 1.2em 0.6em; position: relative; } @@ -55,10 +55,6 @@ cursor: pointer; } -#settings .setting-line { - margin: 1.2em 0.6em; -} - .setting-line .radio-line input:checked { box-shadow: inset 0 0 0 3px var(--main-background-color); background-color: var(--settings-input-color); From 34d595dda16cbcc7a14aea17db8c5328867ed94d Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 18 Jan 2023 12:48:24 -0700 Subject: [PATCH 160/230] rustdoc: add test case for setting-line margin on settings.html --- tests/rustdoc-gui/settings.goml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/rustdoc-gui/settings.goml b/tests/rustdoc-gui/settings.goml index 72de41e41bae1..951ff4e30d2e3 100644 --- a/tests/rustdoc-gui/settings.goml +++ b/tests/rustdoc-gui/settings.goml @@ -8,6 +8,10 @@ assert-false: "#settings" click: "#settings-menu" wait-for: "#settings" assert-css: ("#settings", {"display": "block"}) + +// Store the line margin to compare with the settings.html later. +store-css: (setting_line_margin, ".setting-line", "margin") + // Let's close it by clicking on the same button. click: "#settings-menu" wait-for-css: ("#settings", {"display": "none"}) @@ -211,6 +215,9 @@ assert-css: (".setting-line", {"position": "relative"}) assert-attribute-false: ("#settings", {"class": "popover"}, CONTAINS) compare-elements-position: (".sub form", "#settings", ("x")) +// Check that setting-line has the same margin in this mode as in the popover. +assert-css: (".setting-line", {"margin": |setting_line_margin|}) + // We now check the display with JS disabled. assert-false: "noscript section" javascript: false From ae9e66bafbe83b3c32b6c08027a667961cfdc8fe Mon Sep 17 00:00:00 2001 From: David Carlier Date: Wed, 18 Jan 2023 23:06:59 +0000 Subject: [PATCH 161/230] signal update string representation for haiku. --- library/std/src/sys/unix/process/process_unix.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index c2c4aa1c9dfce..3bc17b7754d85 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -746,6 +746,8 @@ fn signal_string(signal: i32) -> &'static str { libc::SIGWINCH => " (SIGWINCH)", #[cfg(not(target_os = "haiku"))] libc::SIGIO => " (SIGIO)", + #[cfg(target_os = "haiku")] + libc::SIGPOLL => " (SIGPOLL)", libc::SIGSYS => " (SIGSYS)", // For information on Linux signals, run `man 7 signal` #[cfg(all( From 3520bba13690e843704e77bd2ada89131b81051e Mon Sep 17 00:00:00 2001 From: clubby789 Date: Thu, 19 Jan 2023 02:24:51 +0000 Subject: [PATCH 162/230] Use strings for homoglyph replacements --- .../rustc_parse/src/lexer/unicode_chars.rs | 640 +++++++++--------- 1 file changed, 320 insertions(+), 320 deletions(-) diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs index 65479b341d7a8..2332216f09bf9 100644 --- a/compiler/rustc_parse/src/lexer/unicode_chars.rs +++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs @@ -7,329 +7,329 @@ use rustc_errors::{Applicability, Diagnostic}; use rustc_span::{symbol::kw, BytePos, Pos, Span}; #[rustfmt::skip] // for line breaks -pub(crate) const UNICODE_ARRAY: &[(char, &str, char)] = &[ - ('
', "Line Separator", ' '), - ('
', "Paragraph Separator", ' '), - (' ', "Ogham Space mark", ' '), - (' ', "En Quad", ' '), - (' ', "Em Quad", ' '), - (' ', "En Space", ' '), - (' ', "Em Space", ' '), - (' ', "Three-Per-Em Space", ' '), - (' ', "Four-Per-Em Space", ' '), - (' ', "Six-Per-Em Space", ' '), - (' ', "Punctuation Space", ' '), - (' ', "Thin Space", ' '), - (' ', "Hair Space", ' '), - (' ', "Medium Mathematical Space", ' '), - (' ', "No-Break Space", ' '), - (' ', "Figure Space", ' '), - (' ', "Narrow No-Break Space", ' '), - (' ', "Ideographic Space", ' '), - - ('ߺ', "Nko Lajanyalan", '_'), - ('﹍', "Dashed Low Line", '_'), - ('﹎', "Centreline Low Line", '_'), - ('﹏', "Wavy Low Line", '_'), - ('_', "Fullwidth Low Line", '_'), - - ('‐', "Hyphen", '-'), - ('‑', "Non-Breaking Hyphen", '-'), - ('‒', "Figure Dash", '-'), - ('–', "En Dash", '-'), - ('—', "Em Dash", '-'), - ('﹘', "Small Em Dash", '-'), - ('۔', "Arabic Full Stop", '-'), - ('⁃', "Hyphen Bullet", '-'), - ('˗', "Modifier Letter Minus Sign", '-'), - ('−', "Minus Sign", '-'), - ('➖', "Heavy Minus Sign", '-'), - ('Ⲻ', "Coptic Letter Dialect-P Ni", '-'), - ('ー', "Katakana-Hiragana Prolonged Sound Mark", '-'), - ('-', "Fullwidth Hyphen-Minus", '-'), - ('―', "Horizontal Bar", '-'), - ('─', "Box Drawings Light Horizontal", '-'), - ('━', "Box Drawings Heavy Horizontal", '-'), - ('㇐', "CJK Stroke H", '-'), - ('ꟷ', "Latin Epigraphic Letter Sideways I", '-'), - ('ᅳ', "Hangul Jungseong Eu", '-'), - ('ㅡ', "Hangul Letter Eu", '-'), - ('一', "CJK Unified Ideograph-4E00", '-'), - ('⼀', "Kangxi Radical One", '-'), - - ('؍', "Arabic Date Separator", ','), - ('٫', "Arabic Decimal Separator", ','), - ('‚', "Single Low-9 Quotation Mark", ','), - ('¸', "Cedilla", ','), - ('ꓹ', "Lisu Letter Tone Na Po", ','), - (',', "Fullwidth Comma", ','), - - (';', "Greek Question Mark", ';'), - (';', "Fullwidth Semicolon", ';'), - ('︔', "Presentation Form For Vertical Semicolon", ';'), - - ('ः', "Devanagari Sign Visarga", ':'), - ('ઃ', "Gujarati Sign Visarga", ':'), - (':', "Fullwidth Colon", ':'), - ('։', "Armenian Full Stop", ':'), - ('܃', "Syriac Supralinear Colon", ':'), - ('܄', "Syriac Sublinear Colon", ':'), - ('᛬', "Runic Multiple Punctuation", ':'), - ('︰', "Presentation Form For Vertical Two Dot Leader", ':'), - ('᠃', "Mongolian Full Stop", ':'), - ('᠉', "Mongolian Manchu Full Stop", ':'), - ('⁚', "Two Dot Punctuation", ':'), - ('׃', "Hebrew Punctuation Sof Pasuq", ':'), - ('˸', "Modifier Letter Raised Colon", ':'), - ('꞉', "Modifier Letter Colon", ':'), - ('∶', "Ratio", ':'), - ('ː', "Modifier Letter Triangular Colon", ':'), - ('ꓽ', "Lisu Letter Tone Mya Jeu", ':'), - ('︓', "Presentation Form For Vertical Colon", ':'), - - ('!', "Fullwidth Exclamation Mark", '!'), - ('ǃ', "Latin Letter Retroflex Click", '!'), - ('ⵑ', "Tifinagh Letter Tuareg Yang", '!'), - ('︕', "Presentation Form For Vertical Exclamation Mark", '!'), - - ('ʔ', "Latin Letter Glottal Stop", '?'), - ('Ɂ', "Latin Capital Letter Glottal Stop", '?'), - ('ॽ', "Devanagari Letter Glottal Stop", '?'), - ('Ꭾ', "Cherokee Letter He", '?'), - ('ꛫ', "Bamum Letter Ntuu", '?'), - ('?', "Fullwidth Question Mark", '?'), - ('︖', "Presentation Form For Vertical Question Mark", '?'), - - ('𝅭', "Musical Symbol Combining Augmentation Dot", '.'), - ('․', "One Dot Leader", '.'), - ('܁', "Syriac Supralinear Full Stop", '.'), - ('܂', "Syriac Sublinear Full Stop", '.'), - ('꘎', "Vai Full Stop", '.'), - ('𐩐', "Kharoshthi Punctuation Dot", '.'), - ('٠', "Arabic-Indic Digit Zero", '.'), - ('۰', "Extended Arabic-Indic Digit Zero", '.'), - ('ꓸ', "Lisu Letter Tone Mya Ti", '.'), - ('·', "Middle Dot", '.'), - ('・', "Katakana Middle Dot", '.'), - ('・', "Halfwidth Katakana Middle Dot", '.'), - ('᛫', "Runic Single Punctuation", '.'), - ('·', "Greek Ano Teleia", '.'), - ('⸱', "Word Separator Middle Dot", '.'), - ('𐄁', "Aegean Word Separator Dot", '.'), - ('•', "Bullet", '.'), - ('‧', "Hyphenation Point", '.'), - ('∙', "Bullet Operator", '.'), - ('⋅', "Dot Operator", '.'), - ('ꞏ', "Latin Letter Sinological Dot", '.'), - ('ᐧ', "Canadian Syllabics Final Middle Dot", '.'), - ('ᐧ', "Canadian Syllabics Final Middle Dot", '.'), - ('.', "Fullwidth Full Stop", '.'), - ('。', "Ideographic Full Stop", '.'), - ('︒', "Presentation Form For Vertical Ideographic Full Stop", '.'), - - ('՝', "Armenian Comma", '\''), - (''', "Fullwidth Apostrophe", '\''), - ('‘', "Left Single Quotation Mark", '\''), - ('’', "Right Single Quotation Mark", '\''), - ('‛', "Single High-Reversed-9 Quotation Mark", '\''), - ('′', "Prime", '\''), - ('‵', "Reversed Prime", '\''), - ('՚', "Armenian Apostrophe", '\''), - ('׳', "Hebrew Punctuation Geresh", '\''), - ('`', "Grave Accent", '\''), - ('`', "Greek Varia", '\''), - ('`', "Fullwidth Grave Accent", '\''), - ('´', "Acute Accent", '\''), - ('΄', "Greek Tonos", '\''), - ('´', "Greek Oxia", '\''), - ('᾽', "Greek Koronis", '\''), - ('᾿', "Greek Psili", '\''), - ('῾', "Greek Dasia", '\''), - ('ʹ', "Modifier Letter Prime", '\''), - ('ʹ', "Greek Numeral Sign", '\''), - ('ˈ', "Modifier Letter Vertical Line", '\''), - ('ˊ', "Modifier Letter Acute Accent", '\''), - ('ˋ', "Modifier Letter Grave Accent", '\''), - ('˴', "Modifier Letter Middle Grave Accent", '\''), - ('ʻ', "Modifier Letter Turned Comma", '\''), - ('ʽ', "Modifier Letter Reversed Comma", '\''), - ('ʼ', "Modifier Letter Apostrophe", '\''), - ('ʾ', "Modifier Letter Right Half Ring", '\''), - ('ꞌ', "Latin Small Letter Saltillo", '\''), - ('י', "Hebrew Letter Yod", '\''), - ('ߴ', "Nko High Tone Apostrophe", '\''), - ('ߵ', "Nko Low Tone Apostrophe", '\''), - ('ᑊ', "Canadian Syllabics West-Cree P", '\''), - ('ᛌ', "Runic Letter Short-Twig-Sol S", '\''), - ('𖽑', "Miao Sign Aspiration", '\''), - ('𖽒', "Miao Sign Reformed Voicing", '\''), - - ('᳓', "Vedic Sign Nihshvasa", '"'), - ('"', "Fullwidth Quotation Mark", '"'), - ('“', "Left Double Quotation Mark", '"'), - ('”', "Right Double Quotation Mark", '"'), - ('‟', "Double High-Reversed-9 Quotation Mark", '"'), - ('″', "Double Prime", '"'), - ('‶', "Reversed Double Prime", '"'), - ('〃', "Ditto Mark", '"'), - ('״', "Hebrew Punctuation Gershayim", '"'), - ('˝', "Double Acute Accent", '"'), - ('ʺ', "Modifier Letter Double Prime", '"'), - ('˶', "Modifier Letter Middle Double Acute Accent", '"'), - ('˵', "Modifier Letter Middle Double Grave Accent", '"'), - ('ˮ', "Modifier Letter Double Apostrophe", '"'), - ('ײ', "Hebrew Ligature Yiddish Double Yod", '"'), - ('❞', "Heavy Double Comma Quotation Mark Ornament", '"'), - ('❝', "Heavy Double Turned Comma Quotation Mark Ornament", '"'), - - ('(', "Fullwidth Left Parenthesis", '('), - ('❨', "Medium Left Parenthesis Ornament", '('), - ('﴾', "Ornate Left Parenthesis", '('), - - (')', "Fullwidth Right Parenthesis", ')'), - ('❩', "Medium Right Parenthesis Ornament", ')'), - ('﴿', "Ornate Right Parenthesis", ')'), - - ('[', "Fullwidth Left Square Bracket", '['), - ('❲', "Light Left Tortoise Shell Bracket Ornament", '['), - ('「', "Left Corner Bracket", '['), - ('『', "Left White Corner Bracket", '['), - ('【', "Left Black Lenticular Bracket", '['), - ('〔', "Left Tortoise Shell Bracket", '['), - ('〖', "Left White Lenticular Bracket", '['), - ('〘', "Left White Tortoise Shell Bracket", '['), - ('〚', "Left White Square Bracket", '['), - - (']', "Fullwidth Right Square Bracket", ']'), - ('❳', "Light Right Tortoise Shell Bracket Ornament", ']'), - ('」', "Right Corner Bracket", ']'), - ('』', "Right White Corner Bracket", ']'), - ('】', "Right Black Lenticular Bracket", ']'), - ('〕', "Right Tortoise Shell Bracket", ']'), - ('〗', "Right White Lenticular Bracket", ']'), - ('〙', "Right White Tortoise Shell Bracket", ']'), - ('〛', "Right White Square Bracket", ']'), - - ('❴', "Medium Left Curly Bracket Ornament", '{'), - ('𝄔', "Musical Symbol Brace", '{'), - ('{', "Fullwidth Left Curly Bracket", '{'), - - ('❵', "Medium Right Curly Bracket Ornament", '}'), - ('}', "Fullwidth Right Curly Bracket", '}'), - - ('⁎', "Low Asterisk", '*'), - ('٭', "Arabic Five Pointed Star", '*'), - ('∗', "Asterisk Operator", '*'), - ('𐌟', "Old Italic Letter Ess", '*'), - ('*', "Fullwidth Asterisk", '*'), - - ('᜵', "Philippine Single Punctuation", '/'), - ('⁁', "Caret Insertion Point", '/'), - ('∕', "Division Slash", '/'), - ('⁄', "Fraction Slash", '/'), - ('╱', "Box Drawings Light Diagonal Upper Right To Lower Left", '/'), - ('⟋', "Mathematical Rising Diagonal", '/'), - ('⧸', "Big Solidus", '/'), - ('𝈺', "Greek Instrumental Notation Symbol-47", '/'), - ('㇓', "CJK Stroke Sp", '/'), - ('〳', "Vertical Kana Repeat Mark Upper Half", '/'), - ('Ⳇ', "Coptic Capital Letter Old Coptic Esh", '/'), - ('ノ', "Katakana Letter No", '/'), - ('丿', "CJK Unified Ideograph-4E3F", '/'), - ('⼃', "Kangxi Radical Slash", '/'), - ('/', "Fullwidth Solidus", '/'), - - ('\', "Fullwidth Reverse Solidus", '\\'), - ('﹨', "Small Reverse Solidus", '\\'), - ('∖', "Set Minus", '\\'), - ('⟍', "Mathematical Falling Diagonal", '\\'), - ('⧵', "Reverse Solidus Operator", '\\'), - ('⧹', "Big Reverse Solidus", '\\'), - ('⧹', "Greek Vocal Notation Symbol-16", '\\'), - ('⧹', "Greek Instrumental Symbol-48", '\\'), - ('㇔', "CJK Stroke D", '\\'), - ('丶', "CJK Unified Ideograph-4E36", '\\'), - ('⼂', "Kangxi Radical Dot", '\\'), - ('、', "Ideographic Comma", '\\'), - ('ヽ', "Katakana Iteration Mark", '\\'), - - ('ꝸ', "Latin Small Letter Um", '&'), - ('&', "Fullwidth Ampersand", '&'), - - ('᛭', "Runic Cross Punctuation", '+'), - ('➕', "Heavy Plus Sign", '+'), - ('𐊛', "Lycian Letter H", '+'), - ('﬩', "Hebrew Letter Alternative Plus Sign", '+'), - ('+', "Fullwidth Plus Sign", '+'), - - ('‹', "Single Left-Pointing Angle Quotation Mark", '<'), - ('❮', "Heavy Left-Pointing Angle Quotation Mark Ornament", '<'), - ('˂', "Modifier Letter Left Arrowhead", '<'), - ('𝈶', "Greek Instrumental Symbol-40", '<'), - ('ᐸ', "Canadian Syllabics Pa", '<'), - ('ᚲ', "Runic Letter Kauna", '<'), - ('❬', "Medium Left-Pointing Angle Bracket Ornament", '<'), - ('⟨', "Mathematical Left Angle Bracket", '<'), - ('〈', "Left-Pointing Angle Bracket", '<'), - ('〈', "Left Angle Bracket", '<'), - ('㇛', "CJK Stroke Pd", '<'), - ('く', "Hiragana Letter Ku", '<'), - ('𡿨', "CJK Unified Ideograph-21FE8", '<'), - ('《', "Left Double Angle Bracket", '<'), - ('<', "Fullwidth Less-Than Sign", '<'), - - ('᐀', "Canadian Syllabics Hyphen", '='), - ('⹀', "Double Hyphen", '='), - ('゠', "Katakana-Hiragana Double Hyphen", '='), - ('꓿', "Lisu Punctuation Full Stop", '='), - ('=', "Fullwidth Equals Sign", '='), - - ('›', "Single Right-Pointing Angle Quotation Mark", '>'), - ('❯', "Heavy Right-Pointing Angle Quotation Mark Ornament", '>'), - ('˃', "Modifier Letter Right Arrowhead", '>'), - ('𝈷', "Greek Instrumental Symbol-42", '>'), - ('ᐳ', "Canadian Syllabics Po", '>'), - ('𖼿', "Miao Letter Archaic Zza", '>'), - ('❭', "Medium Right-Pointing Angle Bracket Ornament", '>'), - ('⟩', "Mathematical Right Angle Bracket", '>'), - ('〉', "Right-Pointing Angle Bracket", '>'), - ('〉', "Right Angle Bracket", '>'), - ('》', "Right Double Angle Bracket", '>'), - ('>', "Fullwidth Greater-Than Sign", '>'), +pub(crate) const UNICODE_ARRAY: &[(char, &str, &str)] = &[ + ('
', "Line Separator", " "), + ('
', "Paragraph Separator", " "), + (' ', "Ogham Space mark", " "), + (' ', "En Quad", " "), + (' ', "Em Quad", " "), + (' ', "En Space", " "), + (' ', "Em Space", " "), + (' ', "Three-Per-Em Space", " "), + (' ', "Four-Per-Em Space", " "), + (' ', "Six-Per-Em Space", " "), + (' ', "Punctuation Space", " "), + (' ', "Thin Space", " "), + (' ', "Hair Space", " "), + (' ', "Medium Mathematical Space", " "), + (' ', "No-Break Space", " "), + (' ', "Figure Space", " "), + (' ', "Narrow No-Break Space", " "), + (' ', "Ideographic Space", " "), + + ('ߺ', "Nko Lajanyalan", "_"), + ('﹍', "Dashed Low Line", "_"), + ('﹎', "Centreline Low Line", "_"), + ('﹏', "Wavy Low Line", "_"), + ('_', "Fullwidth Low Line", "_"), + + ('‐', "Hyphen", "-"), + ('‑', "Non-Breaking Hyphen", "-"), + ('‒', "Figure Dash", "-"), + ('–', "En Dash", "-"), + ('—', "Em Dash", "-"), + ('﹘', "Small Em Dash", "-"), + ('۔', "Arabic Full Stop", "-"), + ('⁃', "Hyphen Bullet", "-"), + ('˗', "Modifier Letter Minus Sign", "-"), + ('−', "Minus Sign", "-"), + ('➖', "Heavy Minus Sign", "-"), + ('Ⲻ', "Coptic Letter Dialect-P Ni", "-"), + ('ー', "Katakana-Hiragana Prolonged Sound Mark", "-"), + ('-', "Fullwidth Hyphen-Minus", "-"), + ('―', "Horizontal Bar", "-"), + ('─', "Box Drawings Light Horizontal", "-"), + ('━', "Box Drawings Heavy Horizontal", "-"), + ('㇐', "CJK Stroke H", "-"), + ('ꟷ', "Latin Epigraphic Letter Sideways I", "-"), + ('ᅳ', "Hangul Jungseong Eu", "-"), + ('ㅡ', "Hangul Letter Eu", "-"), + ('一', "CJK Unified Ideograph-4E00", "-"), + ('⼀', "Kangxi Radical One", "-"), + + ('؍', "Arabic Date Separator", ","), + ('٫', "Arabic Decimal Separator", ","), + ('‚', "Single Low-9 Quotation Mark", ","), + ('¸', "Cedilla", ","), + ('ꓹ', "Lisu Letter Tone Na Po", ","), + (',', "Fullwidth Comma", ","), + + (';', "Greek Question Mark", ";"), + (';', "Fullwidth Semicolon", ";"), + ('︔', "Presentation Form For Vertical Semicolon", ";"), + + ('ः', "Devanagari Sign Visarga", ":"), + ('ઃ', "Gujarati Sign Visarga", ":"), + (':', "Fullwidth Colon", ":"), + ('։', "Armenian Full Stop", ":"), + ('܃', "Syriac Supralinear Colon", ":"), + ('܄', "Syriac Sublinear Colon", ":"), + ('᛬', "Runic Multiple Punctuation", ":"), + ('︰', "Presentation Form For Vertical Two Dot Leader", ":"), + ('᠃', "Mongolian Full Stop", ":"), + ('᠉', "Mongolian Manchu Full Stop", ":"), + ('⁚', "Two Dot Punctuation", ":"), + ('׃', "Hebrew Punctuation Sof Pasuq", ":"), + ('˸', "Modifier Letter Raised Colon", ":"), + ('꞉', "Modifier Letter Colon", ":"), + ('∶', "Ratio", ":"), + ('ː', "Modifier Letter Triangular Colon", ":"), + ('ꓽ', "Lisu Letter Tone Mya Jeu", ":"), + ('︓', "Presentation Form For Vertical Colon", ":"), + + ('!', "Fullwidth Exclamation Mark", "!"), + ('ǃ', "Latin Letter Retroflex Click", "!"), + ('ⵑ', "Tifinagh Letter Tuareg Yang", "!"), + ('︕', "Presentation Form For Vertical Exclamation Mark", "!"), + + ('ʔ', "Latin Letter Glottal Stop", "?"), + ('Ɂ', "Latin Capital Letter Glottal Stop", "?"), + ('ॽ', "Devanagari Letter Glottal Stop", "?"), + ('Ꭾ', "Cherokee Letter He", "?"), + ('ꛫ', "Bamum Letter Ntuu", "?"), + ('?', "Fullwidth Question Mark", "?"), + ('︖', "Presentation Form For Vertical Question Mark", "?"), + + ('𝅭', "Musical Symbol Combining Augmentation Dot", "."), + ('․', "One Dot Leader", "."), + ('܁', "Syriac Supralinear Full Stop", "."), + ('܂', "Syriac Sublinear Full Stop", "."), + ('꘎', "Vai Full Stop", "."), + ('𐩐', "Kharoshthi Punctuation Dot", "."), + ('٠', "Arabic-Indic Digit Zero", "."), + ('۰', "Extended Arabic-Indic Digit Zero", "."), + ('ꓸ', "Lisu Letter Tone Mya Ti", "."), + ('·', "Middle Dot", "."), + ('・', "Katakana Middle Dot", "."), + ('・', "Halfwidth Katakana Middle Dot", "."), + ('᛫', "Runic Single Punctuation", "."), + ('·', "Greek Ano Teleia", "."), + ('⸱', "Word Separator Middle Dot", "."), + ('𐄁', "Aegean Word Separator Dot", "."), + ('•', "Bullet", "."), + ('‧', "Hyphenation Point", "."), + ('∙', "Bullet Operator", "."), + ('⋅', "Dot Operator", "."), + ('ꞏ', "Latin Letter Sinological Dot", "."), + ('ᐧ', "Canadian Syllabics Final Middle Dot", "."), + ('ᐧ', "Canadian Syllabics Final Middle Dot", "."), + ('.', "Fullwidth Full Stop", "."), + ('。', "Ideographic Full Stop", "."), + ('︒', "Presentation Form For Vertical Ideographic Full Stop", "."), + + ('՝', "Armenian Comma", "\'"), + (''', "Fullwidth Apostrophe", "\'"), + ('‘', "Left Single Quotation Mark", "\'"), + ('’', "Right Single Quotation Mark", "\'"), + ('‛', "Single High-Reversed-9 Quotation Mark", "\'"), + ('′', "Prime", "\'"), + ('‵', "Reversed Prime", "\'"), + ('՚', "Armenian Apostrophe", "\'"), + ('׳', "Hebrew Punctuation Geresh", "\'"), + ('`', "Grave Accent", "\'"), + ('`', "Greek Varia", "\'"), + ('`', "Fullwidth Grave Accent", "\'"), + ('´', "Acute Accent", "\'"), + ('΄', "Greek Tonos", "\'"), + ('´', "Greek Oxia", "\'"), + ('᾽', "Greek Koronis", "\'"), + ('᾿', "Greek Psili", "\'"), + ('῾', "Greek Dasia", "\'"), + ('ʹ', "Modifier Letter Prime", "\'"), + ('ʹ', "Greek Numeral Sign", "\'"), + ('ˈ', "Modifier Letter Vertical Line", "\'"), + ('ˊ', "Modifier Letter Acute Accent", "\'"), + ('ˋ', "Modifier Letter Grave Accent", "\'"), + ('˴', "Modifier Letter Middle Grave Accent", "\'"), + ('ʻ', "Modifier Letter Turned Comma", "\'"), + ('ʽ', "Modifier Letter Reversed Comma", "\'"), + ('ʼ', "Modifier Letter Apostrophe", "\'"), + ('ʾ', "Modifier Letter Right Half Ring", "\'"), + ('ꞌ', "Latin Small Letter Saltillo", "\'"), + ('י', "Hebrew Letter Yod", "\'"), + ('ߴ', "Nko High Tone Apostrophe", "\'"), + ('ߵ', "Nko Low Tone Apostrophe", "\'"), + ('ᑊ', "Canadian Syllabics West-Cree P", "\'"), + ('ᛌ', "Runic Letter Short-Twig-Sol S", "\'"), + ('𖽑', "Miao Sign Aspiration", "\'"), + ('𖽒', "Miao Sign Reformed Voicing", "\'"), + + ('᳓', "Vedic Sign Nihshvasa", "\""), + ('"', "Fullwidth Quotation Mark", "\""), + ('“', "Left Double Quotation Mark", "\""), + ('”', "Right Double Quotation Mark", "\""), + ('‟', "Double High-Reversed-9 Quotation Mark", "\""), + ('″', "Double Prime", "\""), + ('‶', "Reversed Double Prime", "\""), + ('〃', "Ditto Mark", "\""), + ('״', "Hebrew Punctuation Gershayim", "\""), + ('˝', "Double Acute Accent", "\""), + ('ʺ', "Modifier Letter Double Prime", "\""), + ('˶', "Modifier Letter Middle Double Acute Accent", "\""), + ('˵', "Modifier Letter Middle Double Grave Accent", "\""), + ('ˮ', "Modifier Letter Double Apostrophe", "\""), + ('ײ', "Hebrew Ligature Yiddish Double Yod", "\""), + ('❞', "Heavy Double Comma Quotation Mark Ornament", "\""), + ('❝', "Heavy Double Turned Comma Quotation Mark Ornament", "\""), + + ('(', "Fullwidth Left Parenthesis", "("), + ('❨', "Medium Left Parenthesis Ornament", "("), + ('﴾', "Ornate Left Parenthesis", "("), + + (')', "Fullwidth Right Parenthesis", ")"), + ('❩', "Medium Right Parenthesis Ornament", ")"), + ('﴿', "Ornate Right Parenthesis", ")"), + + ('[', "Fullwidth Left Square Bracket", "["), + ('❲', "Light Left Tortoise Shell Bracket Ornament", "["), + ('「', "Left Corner Bracket", "["), + ('『', "Left White Corner Bracket", "["), + ('【', "Left Black Lenticular Bracket", "["), + ('〔', "Left Tortoise Shell Bracket", "["), + ('〖', "Left White Lenticular Bracket", "["), + ('〘', "Left White Tortoise Shell Bracket", "["), + ('〚', "Left White Square Bracket", "["), + + (']', "Fullwidth Right Square Bracket", "]"), + ('❳', "Light Right Tortoise Shell Bracket Ornament", "]"), + ('」', "Right Corner Bracket", "]"), + ('』', "Right White Corner Bracket", "]"), + ('】', "Right Black Lenticular Bracket", "]"), + ('〕', "Right Tortoise Shell Bracket", "]"), + ('〗', "Right White Lenticular Bracket", "]"), + ('〙', "Right White Tortoise Shell Bracket", "]"), + ('〛', "Right White Square Bracket", "]"), + + ('❴', "Medium Left Curly Bracket Ornament", "{"), + ('𝄔', "Musical Symbol Brace", "{"), + ('{', "Fullwidth Left Curly Bracket", "{"), + + ('❵', "Medium Right Curly Bracket Ornament", "}"), + ('}', "Fullwidth Right Curly Bracket", "}"), + + ('⁎', "Low Asterisk", "*"), + ('٭', "Arabic Five Pointed Star", "*"), + ('∗', "Asterisk Operator", "*"), + ('𐌟', "Old Italic Letter Ess", "*"), + ('*', "Fullwidth Asterisk", "*"), + + ('᜵', "Philippine Single Punctuation", "/"), + ('⁁', "Caret Insertion Point", "/"), + ('∕', "Division Slash", "/"), + ('⁄', "Fraction Slash", "/"), + ('╱', "Box Drawings Light Diagonal Upper Right To Lower Left", "/"), + ('⟋', "Mathematical Rising Diagonal", "/"), + ('⧸', "Big Solidus", "/"), + ('𝈺', "Greek Instrumental Notation Symbol-47", "/"), + ('㇓', "CJK Stroke Sp", "/"), + ('〳', "Vertical Kana Repeat Mark Upper Half", "/"), + ('Ⳇ', "Coptic Capital Letter Old Coptic Esh", "/"), + ('ノ', "Katakana Letter No", "/"), + ('丿', "CJK Unified Ideograph-4E3F", "/"), + ('⼃', "Kangxi Radical Slash", "/"), + ('/', "Fullwidth Solidus", "/"), + + ('\', "Fullwidth Reverse Solidus", "\\"), + ('﹨', "Small Reverse Solidus", "\\"), + ('∖', "Set Minus", "\\"), + ('⟍', "Mathematical Falling Diagonal", "\\"), + ('⧵', "Reverse Solidus Operator", "\\"), + ('⧹', "Big Reverse Solidus", "\\"), + ('⧹', "Greek Vocal Notation Symbol-16", "\\"), + ('⧹', "Greek Instrumental Symbol-48", "\\"), + ('㇔', "CJK Stroke D", "\\"), + ('丶', "CJK Unified Ideograph-4E36", "\\"), + ('⼂', "Kangxi Radical Dot", "\\"), + ('、', "Ideographic Comma", "\\"), + ('ヽ', "Katakana Iteration Mark", "\\"), + + ('ꝸ', "Latin Small Letter Um", "&"), + ('&', "Fullwidth Ampersand", "&"), + + ('᛭', "Runic Cross Punctuation", "+"), + ('➕', "Heavy Plus Sign", "+"), + ('𐊛', "Lycian Letter H", "+"), + ('﬩', "Hebrew Letter Alternative Plus Sign", "+"), + ('+', "Fullwidth Plus Sign", "+"), + + ('‹', "Single Left-Pointing Angle Quotation Mark", "<"), + ('❮', "Heavy Left-Pointing Angle Quotation Mark Ornament", "<"), + ('˂', "Modifier Letter Left Arrowhead", "<"), + ('𝈶', "Greek Instrumental Symbol-40", "<"), + ('ᐸ', "Canadian Syllabics Pa", "<"), + ('ᚲ', "Runic Letter Kauna", "<"), + ('❬', "Medium Left-Pointing Angle Bracket Ornament", "<"), + ('⟨', "Mathematical Left Angle Bracket", "<"), + ('〈', "Left-Pointing Angle Bracket", "<"), + ('〈', "Left Angle Bracket", "<"), + ('㇛', "CJK Stroke Pd", "<"), + ('く', "Hiragana Letter Ku", "<"), + ('𡿨', "CJK Unified Ideograph-21FE8", "<"), + ('《', "Left Double Angle Bracket", "<"), + ('<', "Fullwidth Less-Than Sign", "<"), + + ('᐀', "Canadian Syllabics Hyphen", "="), + ('⹀', "Double Hyphen", "="), + ('゠', "Katakana-Hiragana Double Hyphen", "="), + ('꓿', "Lisu Punctuation Full Stop", "="), + ('=', "Fullwidth Equals Sign", "="), + + ('›', "Single Right-Pointing Angle Quotation Mark", ">"), + ('❯', "Heavy Right-Pointing Angle Quotation Mark Ornament", ">"), + ('˃', "Modifier Letter Right Arrowhead", ">"), + ('𝈷', "Greek Instrumental Symbol-42", ">"), + ('ᐳ', "Canadian Syllabics Po", ">"), + ('𖼿', "Miao Letter Archaic Zza", ">"), + ('❭', "Medium Right-Pointing Angle Bracket Ornament", ">"), + ('⟩', "Mathematical Right Angle Bracket", ">"), + ('〉', "Right-Pointing Angle Bracket", ">"), + ('〉', "Right Angle Bracket", ">"), + ('》', "Right Double Angle Bracket", ">"), + ('>', "Fullwidth Greater-Than Sign", ">"), ]; // FIXME: the lexer could be used to turn the ASCII version of unicode homoglyphs, instead of // keeping the substitution token in this table. Ideally, this should be inside `rustc_lexer`. // However, we should first remove compound tokens like `<<` from `rustc_lexer`, and then add // fancier error recovery to it, as there will be less overall work to do this way. -const ASCII_ARRAY: &[(char, &str, Option)] = &[ - (' ', "Space", None), - ('_', "Underscore", Some(token::Ident(kw::Underscore, false))), - ('-', "Minus/Hyphen", Some(token::BinOp(token::Minus))), - (',', "Comma", Some(token::Comma)), - (';', "Semicolon", Some(token::Semi)), - (':', "Colon", Some(token::Colon)), - ('!', "Exclamation Mark", Some(token::Not)), - ('?', "Question Mark", Some(token::Question)), - ('.', "Period", Some(token::Dot)), - ('(', "Left Parenthesis", Some(token::OpenDelim(Delimiter::Parenthesis))), - (')', "Right Parenthesis", Some(token::CloseDelim(Delimiter::Parenthesis))), - ('[', "Left Square Bracket", Some(token::OpenDelim(Delimiter::Bracket))), - (']', "Right Square Bracket", Some(token::CloseDelim(Delimiter::Bracket))), - ('{', "Left Curly Brace", Some(token::OpenDelim(Delimiter::Brace))), - ('}', "Right Curly Brace", Some(token::CloseDelim(Delimiter::Brace))), - ('*', "Asterisk", Some(token::BinOp(token::Star))), - ('/', "Slash", Some(token::BinOp(token::Slash))), - ('\\', "Backslash", None), - ('&', "Ampersand", Some(token::BinOp(token::And))), - ('+', "Plus Sign", Some(token::BinOp(token::Plus))), - ('<', "Less-Than Sign", Some(token::Lt)), - ('=', "Equals Sign", Some(token::Eq)), - ('>', "Greater-Than Sign", Some(token::Gt)), +const ASCII_ARRAY: &[(&str, &str, Option)] = &[ + (" ", "Space", None), + ("_", "Underscore", Some(token::Ident(kw::Underscore, false))), + ("-", "Minus/Hyphen", Some(token::BinOp(token::Minus))), + (",", "Comma", Some(token::Comma)), + (";", "Semicolon", Some(token::Semi)), + (":", "Colon", Some(token::Colon)), + ("!", "Exclamation Mark", Some(token::Not)), + ("?", "Question Mark", Some(token::Question)), + (".", "Period", Some(token::Dot)), + ("(", "Left Parenthesis", Some(token::OpenDelim(Delimiter::Parenthesis))), + (")", "Right Parenthesis", Some(token::CloseDelim(Delimiter::Parenthesis))), + ("[", "Left Square Bracket", Some(token::OpenDelim(Delimiter::Bracket))), + ("]", "Right Square Bracket", Some(token::CloseDelim(Delimiter::Bracket))), + ("{", "Left Curly Brace", Some(token::OpenDelim(Delimiter::Brace))), + ("}", "Right Curly Brace", Some(token::CloseDelim(Delimiter::Brace))), + ("*", "Asterisk", Some(token::BinOp(token::Star))), + ("/", "Slash", Some(token::BinOp(token::Slash))), + ("\\", "Backslash", None), + ("&", "Ampersand", Some(token::BinOp(token::And))), + ("+", "Plus Sign", Some(token::BinOp(token::Plus))), + ("<", "Less-Than Sign", Some(token::Lt)), + ("=", "Equals Sign", Some(token::Eq)), + (">", "Greater-Than Sign", Some(token::Gt)), // FIXME: Literals are already lexed by this point, so we can't recover gracefully just by // spitting the correct token out. - ('\'', "Single Quote", None), - ('"', "Quotation Mark", None), + ("\'", "Single Quote", None), + ("\"", "Quotation Mark", None), ]; pub(super) fn check_for_substitution<'a>( @@ -339,11 +339,11 @@ pub(super) fn check_for_substitution<'a>( err: &mut Diagnostic, count: usize, ) -> Option { - let &(_u_char, u_name, ascii_char) = UNICODE_ARRAY.iter().find(|&&(c, _, _)| c == ch)?; + let &(_, u_name, ascii_str) = UNICODE_ARRAY.iter().find(|&&(c, _, _)| c == ch)?; let span = Span::with_root_ctxt(pos, pos + Pos::from_usize(ch.len_utf8() * count)); - let Some((_ascii_char, ascii_name, token)) = ASCII_ARRAY.iter().find(|&&(c, _, _)| c == ascii_char) else { + let Some((_, ascii_name, token)) = ASCII_ARRAY.iter().find(|&&(s, _, _)| s == ascii_str) else { let msg = format!("substitution character not found for '{}'", ch); reader.sess.span_diagnostic.span_bug_no_panic(span, &msg); return None; @@ -354,7 +354,7 @@ pub(super) fn check_for_substitution<'a>( let msg = format!( "Unicode characters '“' (Left Double Quotation Mark) and \ '”' (Right Double Quotation Mark) look like '{}' ({}), but are not", - ascii_char, ascii_name + ascii_str, ascii_name ); err.span_suggestion( Span::with_root_ctxt( @@ -368,12 +368,12 @@ pub(super) fn check_for_substitution<'a>( } else { let msg = format!( "Unicode character '{}' ({}) looks like '{}' ({}), but it is not", - ch, u_name, ascii_char, ascii_name + ch, u_name, ascii_str, ascii_name ); err.span_suggestion( span, &msg, - ascii_char.to_string().repeat(count), + ascii_str.to_string().repeat(count), Applicability::MaybeIncorrect, ); } From 1487aa9f9d7edbe660272f7adb5e57ef31deab9d Mon Sep 17 00:00:00 2001 From: clubby789 Date: Thu, 19 Jan 2023 02:25:24 +0000 Subject: [PATCH 163/230] Add double-equals homoglyph --- compiler/rustc_parse/src/lexer/unicode_chars.rs | 2 ++ tests/ui/parser/unicode-chars.rs | 3 +++ tests/ui/parser/unicode-chars.stderr | 13 ++++++++++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs index 2332216f09bf9..34d003ccfa7b4 100644 --- a/compiler/rustc_parse/src/lexer/unicode_chars.rs +++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs @@ -296,6 +296,7 @@ pub(crate) const UNICODE_ARRAY: &[(char, &str, &str)] = &[ ('〉', "Right Angle Bracket", ">"), ('》', "Right Double Angle Bracket", ">"), ('>', "Fullwidth Greater-Than Sign", ">"), + ('⩵', "Two Consecutive Equals Signs", "==") ]; // FIXME: the lexer could be used to turn the ASCII version of unicode homoglyphs, instead of @@ -325,6 +326,7 @@ const ASCII_ARRAY: &[(&str, &str, Option)] = &[ ("+", "Plus Sign", Some(token::BinOp(token::Plus))), ("<", "Less-Than Sign", Some(token::Lt)), ("=", "Equals Sign", Some(token::Eq)), + ("==", "Double Equals Sign", Some(token::EqEq)), (">", "Greater-Than Sign", Some(token::Gt)), // FIXME: Literals are already lexed by this point, so we can't recover gracefully just by // spitting the correct token out. diff --git a/tests/ui/parser/unicode-chars.rs b/tests/ui/parser/unicode-chars.rs index f0122561f463d..cd25c7566897a 100644 --- a/tests/ui/parser/unicode-chars.rs +++ b/tests/ui/parser/unicode-chars.rs @@ -6,4 +6,7 @@ fn main() { //~^ ERROR unknown start of token: \u{a0} //~^^ NOTE character appears 3 more times //~^^^ HELP Unicode character ' ' (No-Break Space) looks like ' ' (Space), but it is not + let _ = 1 ⩵ 2; + //~^ ERROR unknown start of token + //~^^ HELP Unicode character '⩵' (Two Consecutive Equals Signs) looks like '==' (Double Equals Sign), but it is not } diff --git a/tests/ui/parser/unicode-chars.stderr b/tests/ui/parser/unicode-chars.stderr index b1d4a0af71154..086de5ec0997e 100644 --- a/tests/ui/parser/unicode-chars.stderr +++ b/tests/ui/parser/unicode-chars.stderr @@ -21,5 +21,16 @@ help: Unicode character ' ' (No-Break Space) looks like ' ' (Space), but it is LL | let x = 0; | ++++ -error: aborting due to 2 previous errors +error: unknown start of token: \u{2a75} + --> $DIR/unicode-chars.rs:9:15 + | +LL | let _ = 1 ⩵ 2; + | ^ + | +help: Unicode character '⩵' (Two Consecutive Equals Signs) looks like '==' (Double Equals Sign), but it is not + | +LL | let _ = 1 == 2; + | ~~ + +error: aborting due to 3 previous errors From 96931a787abaac7d720fc415780037fc63bee98d Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Tue, 20 Dec 2022 15:15:29 +0100 Subject: [PATCH 164/230] Transform async ResumeTy in generator transform - Eliminates all the `get_context` calls that async lowering created. - Replace all `Local` `ResumeTy` types with `&mut Context<'_>`. The `Local`s that have their types replaced are: - The `resume` argument itself. - The argument to `get_context`. - The yielded value of a `yield`. The `ResumeTy` hides a `&mut Context<'_>` behind an unsafe raw pointer, and the `get_context` function is being used to convert that back to a `&mut Context<'_>`. Ideally the async lowering would not use the `ResumeTy`/`get_context` indirection, but rather directly use `&mut Context<'_>`, however that would currently lead to higher-kinded lifetime errors. See . The async lowering step and the type / lifetime inference / checking are still using the `ResumeTy` indirection for the time being, and that indirection is removed here. After this transform, the generator body only knows about `&mut Context<'_>`. --- compiler/rustc_hir/src/lang_items.rs | 1 + compiler/rustc_middle/src/ty/context.rs | 9 + compiler/rustc_mir_transform/src/generator.rs | 118 +++++- compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_ty_utils/src/abi.rs | 34 +- library/core/src/future/mod.rs | 4 + library/core/src/task/wake.rs | 1 + ...await.a-{closure#0}.generator_resume.0.mir | 41 +++ ...await.b-{closure#0}.generator_resume.0.mir | 337 ++++++++++++++++++ tests/mir-opt/building/async_await.rs | 17 + 10 files changed, 549 insertions(+), 14 deletions(-) create mode 100644 tests/mir-opt/building/async_await.a-{closure#0}.generator_resume.0.mir create mode 100644 tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir create mode 100644 tests/mir-opt/building/async_await.rs diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 3474fab34f00b..54fa5702fbca4 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -291,6 +291,7 @@ language_item_table! { IdentityFuture, sym::identity_future, identity_future_fn, Target::Fn, GenericRequirement::None; GetContext, sym::get_context, get_context_fn, Target::Fn, GenericRequirement::None; + Context, sym::Context, context, Target::Struct, GenericRequirement::None; FuturePoll, sym::poll, future_poll_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; FromFrom, sym::from, from_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 0c66443555fa4..ce04d8d21f4cd 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1952,6 +1952,15 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_ty(GeneratorWitness(types)) } + /// Creates a `&mut Context<'_>` [`Ty`] with erased lifetimes. + pub fn mk_task_context(self) -> Ty<'tcx> { + let context_did = self.require_lang_item(LangItem::Context, None); + let context_adt_ref = self.adt_def(context_did); + let context_substs = self.intern_substs(&[self.lifetimes.re_erased.into()]); + let context_ty = self.mk_adt(context_adt_ref, context_substs); + self.mk_mut_ref(self.lifetimes.re_erased, context_ty) + } + #[inline] pub fn mk_ty_var(self, v: TyVid) -> Ty<'tcx> { self.mk_ty_infer(TyVar(v)) diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index c097af6161159..39c61a34afcbd 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -460,6 +460,104 @@ fn replace_local<'tcx>( new_local } +/// Transforms the `body` of the generator applying the following transforms: +/// +/// - Eliminates all the `get_context` calls that async lowering created. +/// - Replace all `Local` `ResumeTy` types with `&mut Context<'_>` (`context_mut_ref`). +/// +/// The `Local`s that have their types replaced are: +/// - The `resume` argument itself. +/// - The argument to `get_context`. +/// - The yielded value of a `yield`. +/// +/// The `ResumeTy` hides a `&mut Context<'_>` behind an unsafe raw pointer, and the +/// `get_context` function is being used to convert that back to a `&mut Context<'_>`. +/// +/// Ideally the async lowering would not use the `ResumeTy`/`get_context` indirection, +/// but rather directly use `&mut Context<'_>`, however that would currently +/// lead to higher-kinded lifetime errors. +/// See . +/// +/// The async lowering step and the type / lifetime inference / checking are +/// still using the `ResumeTy` indirection for the time being, and that indirection +/// is removed here. After this transform, the generator body only knows about `&mut Context<'_>`. +fn transform_async_context<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let context_mut_ref = tcx.mk_task_context(); + + // replace the type of the `resume` argument + replace_resume_ty_local(tcx, body, Local::new(2), context_mut_ref); + + let get_context_def_id = tcx.require_lang_item(LangItem::GetContext, None); + + for bb in BasicBlock::new(0)..body.basic_blocks.next_index() { + let bb_data = &body[bb]; + if bb_data.is_cleanup { + continue; + } + + match &bb_data.terminator().kind { + TerminatorKind::Call { func, .. } => { + let func_ty = func.ty(body, tcx); + if let ty::FnDef(def_id, _) = *func_ty.kind() { + if def_id == get_context_def_id { + let local = eliminate_get_context_call(&mut body[bb]); + replace_resume_ty_local(tcx, body, local, context_mut_ref); + } + } else { + continue; + } + } + TerminatorKind::Yield { resume_arg, .. } => { + replace_resume_ty_local(tcx, body, resume_arg.local, context_mut_ref); + } + _ => {} + } + } +} + +fn eliminate_get_context_call<'tcx>(bb_data: &mut BasicBlockData<'tcx>) -> Local { + let terminator = bb_data.terminator.take().unwrap(); + if let TerminatorKind::Call { mut args, destination, target, .. } = terminator.kind { + let arg = args.pop().unwrap(); + let local = arg.place().unwrap().local; + + let arg = Rvalue::Use(arg); + let assign = Statement { + source_info: terminator.source_info, + kind: StatementKind::Assign(Box::new((destination, arg))), + }; + bb_data.statements.push(assign); + bb_data.terminator = Some(Terminator { + source_info: terminator.source_info, + kind: TerminatorKind::Goto { target: target.unwrap() }, + }); + local + } else { + bug!(); + } +} + +#[cfg_attr(not(debug_assertions), allow(unused))] +fn replace_resume_ty_local<'tcx>( + tcx: TyCtxt<'tcx>, + body: &mut Body<'tcx>, + local: Local, + context_mut_ref: Ty<'tcx>, +) { + let local_ty = std::mem::replace(&mut body.local_decls[local].ty, context_mut_ref); + // We have to replace the `ResumeTy` that is used for type and borrow checking + // with `&mut Context<'_>` in MIR. + #[cfg(debug_assertions)] + { + if let ty::Adt(resume_ty_adt, _) = local_ty.kind() { + let expected_adt = tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, None)); + assert_eq!(*resume_ty_adt, expected_adt); + } else { + panic!("expected `ResumeTy`, found `{:?}`", local_ty); + }; + } +} + struct LivenessInfo { /// Which locals are live across any suspension point. saved_locals: GeneratorSavedLocals, @@ -1283,13 +1381,13 @@ impl<'tcx> MirPass<'tcx> for StateTransform { } }; - let is_async_kind = body.generator_kind().unwrap() != GeneratorKind::Gen; + let is_async_kind = matches!(body.generator_kind(), Some(GeneratorKind::Async(_))); let (state_adt_ref, state_substs) = if is_async_kind { // Compute Poll - let state_did = tcx.require_lang_item(LangItem::Poll, None); - let state_adt_ref = tcx.adt_def(state_did); - let state_substs = tcx.intern_substs(&[body.return_ty().into()]); - (state_adt_ref, state_substs) + let poll_did = tcx.require_lang_item(LangItem::Poll, None); + let poll_adt_ref = tcx.adt_def(poll_did); + let poll_substs = tcx.intern_substs(&[body.return_ty().into()]); + (poll_adt_ref, poll_substs) } else { // Compute GeneratorState let state_did = tcx.require_lang_item(LangItem::GeneratorState, None); @@ -1303,13 +1401,19 @@ impl<'tcx> MirPass<'tcx> for StateTransform { // RETURN_PLACE then is a fresh unused local with type ret_ty. let new_ret_local = replace_local(RETURN_PLACE, ret_ty, body, tcx); + // Replace all occurrences of `ResumeTy` with `&mut Context<'_>` within async bodies. + if is_async_kind { + transform_async_context(tcx, body); + } + // We also replace the resume argument and insert an `Assign`. // This is needed because the resume argument `_2` might be live across a `yield`, in which // case there is no `Assign` to it that the transform can turn into a store to the generator // state. After the yield the slot in the generator state would then be uninitialized. let resume_local = Local::new(2); - let new_resume_local = - replace_local(resume_local, body.local_decls[resume_local].ty, body, tcx); + let resume_ty = + if is_async_kind { tcx.mk_task_context() } else { body.local_decls[resume_local].ty }; + let new_resume_local = replace_local(resume_local, resume_ty, body, tcx); // When first entering the generator, move the resume argument into its new local. let source_info = SourceInfo::outermost(body.span); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 706002f79b1fb..7597b8d126a9c 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -164,6 +164,7 @@ symbols! { Capture, Center, Clone, + Context, Continue, Copy, Count, diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 669f84ae1b472..91a505a72fae7 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -108,21 +108,41 @@ fn fn_sig_for_fn_abi<'tcx>( // `Generator::resume(...) -> GeneratorState` function in case we // have an ordinary generator, or the `Future::poll(...) -> Poll` // function in case this is a special generator backing an async construct. - let ret_ty = if tcx.generator_is_async(did) { - let state_did = tcx.require_lang_item(LangItem::Poll, None); - let state_adt_ref = tcx.adt_def(state_did); - let state_substs = tcx.intern_substs(&[sig.return_ty.into()]); - tcx.mk_adt(state_adt_ref, state_substs) + let (resume_ty, ret_ty) = if tcx.generator_is_async(did) { + // The signature should be `Future::poll(_, &mut Context<'_>) -> Poll` + let poll_did = tcx.require_lang_item(LangItem::Poll, None); + let poll_adt_ref = tcx.adt_def(poll_did); + let poll_substs = tcx.intern_substs(&[sig.return_ty.into()]); + let ret_ty = tcx.mk_adt(poll_adt_ref, poll_substs); + + // We have to replace the `ResumeTy` that is used for type and borrow checking + // with `&mut Context<'_>` which is used in codegen. + #[cfg(debug_assertions)] + { + if let ty::Adt(resume_ty_adt, _) = sig.resume_ty.kind() { + let expected_adt = + tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, None)); + assert_eq!(*resume_ty_adt, expected_adt); + } else { + panic!("expected `ResumeTy`, found `{:?}`", sig.resume_ty); + }; + } + let context_mut_ref = tcx.mk_task_context(); + + (context_mut_ref, ret_ty) } else { + // The signature should be `Generator::resume(_, Resume) -> GeneratorState` let state_did = tcx.require_lang_item(LangItem::GeneratorState, None); let state_adt_ref = tcx.adt_def(state_did); let state_substs = tcx.intern_substs(&[sig.yield_ty.into(), sig.return_ty.into()]); - tcx.mk_adt(state_adt_ref, state_substs) + let ret_ty = tcx.mk_adt(state_adt_ref, state_substs); + + (sig.resume_ty, ret_ty) }; ty::Binder::bind_with_vars( tcx.mk_fn_sig( - [env_ty, sig.resume_ty].iter(), + [env_ty, resume_ty].iter(), &ret_ty, false, hir::Unsafety::Normal, diff --git a/library/core/src/future/mod.rs b/library/core/src/future/mod.rs index 5bfe001de46e3..c4fb362094664 100644 --- a/library/core/src/future/mod.rs +++ b/library/core/src/future/mod.rs @@ -112,6 +112,10 @@ pub unsafe fn get_context<'a, 'b>(cx: ResumeTy) -> &'a mut Context<'b> { unsafe { &mut *cx.0.as_ptr().cast() } } +// FIXME(swatinem): This fn is currently needed to work around shortcomings +// in type and lifetime inference. +// See the comment at the bottom of `LoweringContext::make_async_expr` and +// . #[doc(hidden)] #[unstable(feature = "gen_future", issue = "50547")] #[inline] diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index a4425fd234a4e..89adfccd90135 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs @@ -174,6 +174,7 @@ impl RawWakerVTable { /// Currently, `Context` only serves to provide access to a [`&Waker`](Waker) /// which can be used to wake the current task. #[stable(feature = "futures_api", since = "1.36.0")] +#[cfg_attr(not(bootstrap), lang = "Context")] pub struct Context<'a> { waker: &'a Waker, // Ensure we future-proof against variance changes by forcing diff --git a/tests/mir-opt/building/async_await.a-{closure#0}.generator_resume.0.mir b/tests/mir-opt/building/async_await.a-{closure#0}.generator_resume.0.mir new file mode 100644 index 0000000000000..2a7f90fe9476a --- /dev/null +++ b/tests/mir-opt/building/async_await.a-{closure#0}.generator_resume.0.mir @@ -0,0 +1,41 @@ +// MIR for `a::{closure#0}` 0 generator_resume +/* generator_layout = GeneratorLayout { + field_tys: {}, + variant_fields: { + Unresumed(0): [], + Returned (1): [], + Panicked (2): [], + }, + storage_conflicts: BitMatrix(0x0) {}, +} */ + +fn a::{closure#0}(_1: Pin<&mut [async fn body@$DIR/async_await.rs:11:14: 11:16]>, _2: &mut Context<'_>) -> Poll<()> { + debug _task_context => _4; // in scope 0 at $DIR/async_await.rs:+0:14: +0:16 + let mut _0: std::task::Poll<()>; // return place in scope 0 at $DIR/async_await.rs:+0:14: +0:16 + let mut _3: (); // in scope 0 at $DIR/async_await.rs:+0:14: +0:16 + let mut _4: &mut std::task::Context<'_>; // in scope 0 at $DIR/async_await.rs:+0:14: +0:16 + let mut _5: u32; // in scope 0 at $DIR/async_await.rs:+0:14: +0:16 + + bb0: { + _5 = discriminant((*(_1.0: &mut [async fn body@$DIR/async_await.rs:11:14: 11:16]))); // scope 0 at $DIR/async_await.rs:+0:14: +0:16 + switchInt(move _5) -> [0: bb1, 1: bb2, otherwise: bb3]; // scope 0 at $DIR/async_await.rs:+0:14: +0:16 + } + + bb1: { + _4 = move _2; // scope 0 at $DIR/async_await.rs:+0:14: +0:16 + _3 = const (); // scope 0 at $DIR/async_await.rs:+0:14: +0:16 + Deinit(_0); // scope 0 at $DIR/async_await.rs:+0:16: +0:16 + ((_0 as Ready).0: ()) = move _3; // scope 0 at $DIR/async_await.rs:+0:16: +0:16 + discriminant(_0) = 0; // scope 0 at $DIR/async_await.rs:+0:16: +0:16 + discriminant((*(_1.0: &mut [async fn body@$DIR/async_await.rs:11:14: 11:16]))) = 1; // scope 0 at $DIR/async_await.rs:+0:16: +0:16 + return; // scope 0 at $DIR/async_await.rs:+0:16: +0:16 + } + + bb2: { + assert(const false, "`async fn` resumed after completion") -> bb2; // scope 0 at $DIR/async_await.rs:+0:14: +0:16 + } + + bb3: { + unreachable; // scope 0 at $DIR/async_await.rs:+0:14: +0:16 + } +} diff --git a/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir b/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir new file mode 100644 index 0000000000000..05edc4797d4e5 --- /dev/null +++ b/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir @@ -0,0 +1,337 @@ +// MIR for `b::{closure#0}` 0 generator_resume +/* generator_layout = GeneratorLayout { + field_tys: { + _0: impl std::future::Future, + _1: impl std::future::Future, + }, + variant_fields: { + Unresumed(0): [], + Returned (1): [], + Panicked (2): [], + Suspend0 (3): [_0], + Suspend1 (4): [_1], + }, + storage_conflicts: BitMatrix(2x2) { + (_0, _0), + (_1, _1), + }, +} */ + +fn b::{closure#0}(_1: Pin<&mut [async fn body@$DIR/async_await.rs:14:18: 17:2]>, _2: &mut Context<'_>) -> Poll<()> { + debug _task_context => _38; // in scope 0 at $DIR/async_await.rs:+0:18: +3:2 + let mut _0: std::task::Poll<()>; // return place in scope 0 at $DIR/async_await.rs:+0:18: +3:2 + let _3: (); // in scope 0 at $DIR/async_await.rs:+1:5: +1:14 + let mut _4: impl std::future::Future; // in scope 0 at $DIR/async_await.rs:+1:8: +1:14 + let mut _5: impl std::future::Future; // in scope 0 at $DIR/async_await.rs:+1:5: +1:8 + let mut _6: impl std::future::Future; // in scope 0 at $DIR/async_await.rs:+1:8: +1:14 + let mut _7: (); // in scope 0 at $DIR/async_await.rs:+0:18: +3:2 + let _8: (); // in scope 0 at $DIR/async_await.rs:+1:8: +1:14 + let mut _9: std::task::Poll<()>; // in scope 0 at $DIR/async_await.rs:+1:8: +1:14 + let mut _10: std::pin::Pin<&mut impl std::future::Future>; // in scope 0 at $DIR/async_await.rs:+1:8: +1:14 + let mut _11: &mut impl std::future::Future; // in scope 0 at $DIR/async_await.rs:+1:8: +1:14 + let mut _12: &mut impl std::future::Future; // in scope 0 at $DIR/async_await.rs:+1:8: +1:14 + let mut _13: &mut std::task::Context<'_>; // in scope 0 at $DIR/async_await.rs:+1:5: +1:14 + let mut _14: &mut std::task::Context<'_>; // in scope 0 at $DIR/async_await.rs:+1:5: +1:14 + let mut _15: &mut std::task::Context<'_>; // in scope 0 at $DIR/async_await.rs:+1:8: +1:14 + let mut _16: isize; // in scope 0 at $DIR/async_await.rs:+1:8: +1:14 + let mut _18: !; // in scope 0 at $DIR/async_await.rs:+1:5: +1:14 + let mut _19: &mut std::task::Context<'_>; // in scope 0 at $DIR/async_await.rs:+1:8: +1:14 + let mut _20: (); // in scope 0 at $DIR/async_await.rs:+1:8: +1:14 + let mut _21: impl std::future::Future; // in scope 0 at $DIR/async_await.rs:+2:8: +2:14 + let mut _22: impl std::future::Future; // in scope 0 at $DIR/async_await.rs:+2:5: +2:8 + let mut _23: impl std::future::Future; // in scope 0 at $DIR/async_await.rs:+2:8: +2:14 + let _24: (); // in scope 0 at $DIR/async_await.rs:+2:8: +2:14 + let mut _25: std::task::Poll<()>; // in scope 0 at $DIR/async_await.rs:+2:8: +2:14 + let mut _26: std::pin::Pin<&mut impl std::future::Future>; // in scope 0 at $DIR/async_await.rs:+2:8: +2:14 + let mut _27: &mut impl std::future::Future; // in scope 0 at $DIR/async_await.rs:+2:8: +2:14 + let mut _28: &mut impl std::future::Future; // in scope 0 at $DIR/async_await.rs:+2:8: +2:14 + let mut _29: &mut std::task::Context<'_>; // in scope 0 at $DIR/async_await.rs:+2:5: +2:14 + let mut _30: &mut std::task::Context<'_>; // in scope 0 at $DIR/async_await.rs:+2:5: +2:14 + let mut _31: &mut std::task::Context<'_>; // in scope 0 at $DIR/async_await.rs:+2:8: +2:14 + let mut _32: isize; // in scope 0 at $DIR/async_await.rs:+2:8: +2:14 + let mut _34: !; // in scope 0 at $DIR/async_await.rs:+2:5: +2:14 + let mut _35: &mut std::task::Context<'_>; // in scope 0 at $DIR/async_await.rs:+2:8: +2:14 + let mut _36: (); // in scope 0 at $DIR/async_await.rs:+2:8: +2:14 + let mut _37: (); // in scope 0 at $DIR/async_await.rs:+0:18: +3:2 + let mut _38: &mut std::task::Context<'_>; // in scope 0 at $DIR/async_await.rs:+0:18: +3:2 + let mut _39: u32; // in scope 0 at $DIR/async_await.rs:+0:18: +3:2 + scope 1 { + debug __awaitee => (((*(_1.0: &mut [async fn body@$DIR/async_await.rs:14:18: 17:2])) as variant#3).0: impl std::future::Future); // in scope 1 at $DIR/async_await.rs:+1:8: +1:14 + let _17: (); // in scope 1 at $DIR/async_await.rs:+1:5: +1:14 + scope 2 { + } + scope 3 { + debug result => _17; // in scope 3 at $DIR/async_await.rs:+1:5: +1:14 + } + } + scope 4 { + debug __awaitee => (((*(_1.0: &mut [async fn body@$DIR/async_await.rs:14:18: 17:2])) as variant#4).0: impl std::future::Future); // in scope 4 at $DIR/async_await.rs:+2:8: +2:14 + let _33: (); // in scope 4 at $DIR/async_await.rs:+2:5: +2:14 + scope 5 { + } + scope 6 { + debug result => _33; // in scope 6 at $DIR/async_await.rs:+2:5: +2:14 + } + } + + bb0: { + _39 = discriminant((*(_1.0: &mut [async fn body@$DIR/async_await.rs:14:18: 17:2]))); // scope 0 at $DIR/async_await.rs:+0:18: +3:2 + switchInt(move _39) -> [0: bb1, 1: bb29, 3: bb27, 4: bb28, otherwise: bb30]; // scope 0 at $DIR/async_await.rs:+0:18: +3:2 + } + + bb1: { + _38 = move _2; // scope 0 at $DIR/async_await.rs:+0:18: +3:2 + StorageLive(_3); // scope 0 at $DIR/async_await.rs:+1:5: +1:14 + StorageLive(_4); // scope 0 at $DIR/async_await.rs:+1:8: +1:14 + StorageLive(_5); // scope 0 at $DIR/async_await.rs:+1:5: +1:8 + _5 = a() -> bb2; // scope 0 at $DIR/async_await.rs:+1:5: +1:8 + // mir::Constant + // + span: $DIR/async_await.rs:15:5: 15:6 + // + literal: Const { ty: fn() -> impl Future {a}, val: Value() } + } + + bb2: { + _4 = as IntoFuture>::into_future(move _5) -> bb3; // scope 0 at $DIR/async_await.rs:+1:8: +1:14 + // mir::Constant + // + span: $DIR/async_await.rs:15:8: 15:14 + // + literal: Const { ty: fn(impl Future) -> as IntoFuture>::IntoFuture { as IntoFuture>::into_future}, val: Value() } + } + + bb3: { + StorageDead(_5); // scope 0 at $DIR/async_await.rs:+1:13: +1:14 + nop; // scope 0 at $DIR/async_await.rs:+1:8: +1:14 + (((*(_1.0: &mut [async fn body@$DIR/async_await.rs:14:18: 17:2])) as variant#3).0: impl std::future::Future) = move _4; // scope 0 at $DIR/async_await.rs:+1:8: +1:14 + goto -> bb4; // scope 1 at $DIR/async_await.rs:+1:8: +1:14 + } + + bb4: { + StorageLive(_8); // scope 1 at $DIR/async_await.rs:+1:8: +1:14 + StorageLive(_9); // scope 1 at $DIR/async_await.rs:+1:8: +1:14 + StorageLive(_10); // scope 2 at $DIR/async_await.rs:+1:8: +1:14 + StorageLive(_11); // scope 2 at $DIR/async_await.rs:+1:8: +1:14 + StorageLive(_12); // scope 2 at $DIR/async_await.rs:+1:8: +1:14 + _12 = &mut (((*(_1.0: &mut [async fn body@$DIR/async_await.rs:14:18: 17:2])) as variant#3).0: impl std::future::Future); // scope 2 at $DIR/async_await.rs:+1:8: +1:14 + _11 = &mut (*_12); // scope 2 at $DIR/async_await.rs:+1:8: +1:14 + _10 = Pin::<&mut impl Future>::new_unchecked(move _11) -> bb5; // scope 2 at $DIR/async_await.rs:+1:8: +1:14 + // mir::Constant + // + span: $DIR/async_await.rs:15:8: 15:14 + // + literal: Const { ty: unsafe fn(&mut impl Future) -> Pin<&mut impl Future> {Pin::<&mut impl Future>::new_unchecked}, val: Value() } + } + + bb5: { + StorageDead(_11); // scope 2 at $DIR/async_await.rs:+1:13: +1:14 + StorageLive(_13); // scope 2 at $DIR/async_await.rs:+1:5: +1:14 + StorageLive(_14); // scope 2 at $DIR/async_await.rs:+1:5: +1:14 + StorageLive(_15); // scope 2 at $DIR/async_await.rs:+1:8: +1:14 + _15 = _38; // scope 2 at $DIR/async_await.rs:+1:8: +1:14 + _14 = move _15; // scope 2 at $DIR/async_await.rs:+1:5: +1:14 + goto -> bb6; // scope 2 at $DIR/async_await.rs:+1:5: +1:14 + } + + bb6: { + _13 = &mut (*_14); // scope 2 at $DIR/async_await.rs:+1:5: +1:14 + StorageDead(_15); // scope 2 at $DIR/async_await.rs:+1:13: +1:14 + _9 = as Future>::poll(move _10, move _13) -> bb7; // scope 2 at $DIR/async_await.rs:+1:8: +1:14 + // mir::Constant + // + span: $DIR/async_await.rs:15:8: 15:14 + // + literal: Const { ty: for<'a, 'b, 'c> fn(Pin<&'a mut impl Future>, &'b mut Context<'c>) -> Poll< as Future>::Output> { as Future>::poll}, val: Value() } + } + + bb7: { + StorageDead(_13); // scope 2 at $DIR/async_await.rs:+1:13: +1:14 + StorageDead(_10); // scope 2 at $DIR/async_await.rs:+1:13: +1:14 + _16 = discriminant(_9); // scope 1 at $DIR/async_await.rs:+1:8: +1:14 + switchInt(move _16) -> [0: bb10, 1: bb8, otherwise: bb9]; // scope 1 at $DIR/async_await.rs:+1:8: +1:14 + } + + bb8: { + _8 = const (); // scope 1 at $DIR/async_await.rs:+1:8: +1:14 + StorageDead(_14); // scope 1 at $DIR/async_await.rs:+1:13: +1:14 + StorageDead(_12); // scope 1 at $DIR/async_await.rs:+1:13: +1:14 + StorageDead(_9); // scope 1 at $DIR/async_await.rs:+1:13: +1:14 + StorageDead(_8); // scope 1 at $DIR/async_await.rs:+1:13: +1:14 + StorageLive(_19); // scope 1 at $DIR/async_await.rs:+1:8: +1:14 + StorageLive(_20); // scope 1 at $DIR/async_await.rs:+1:8: +1:14 + _20 = (); // scope 1 at $DIR/async_await.rs:+1:8: +1:14 + Deinit(_0); // scope 1 at $DIR/async_await.rs:+1:8: +1:14 + discriminant(_0) = 1; // scope 1 at $DIR/async_await.rs:+1:8: +1:14 + discriminant((*(_1.0: &mut [async fn body@$DIR/async_await.rs:14:18: 17:2]))) = 3; // scope 1 at $DIR/async_await.rs:+1:8: +1:14 + return; // scope 1 at $DIR/async_await.rs:+1:8: +1:14 + } + + bb9: { + unreachable; // scope 1 at $DIR/async_await.rs:+1:8: +1:14 + } + + bb10: { + StorageLive(_17); // scope 1 at $DIR/async_await.rs:+1:5: +1:14 + _17 = ((_9 as Ready).0: ()); // scope 1 at $DIR/async_await.rs:+1:5: +1:14 + _3 = _17; // scope 3 at $DIR/async_await.rs:+1:5: +1:14 + StorageDead(_17); // scope 1 at $DIR/async_await.rs:+1:13: +1:14 + StorageDead(_14); // scope 1 at $DIR/async_await.rs:+1:13: +1:14 + StorageDead(_12); // scope 1 at $DIR/async_await.rs:+1:13: +1:14 + StorageDead(_9); // scope 1 at $DIR/async_await.rs:+1:13: +1:14 + StorageDead(_8); // scope 1 at $DIR/async_await.rs:+1:13: +1:14 + goto -> bb12; // scope 0 at $DIR/async_await.rs:+1:13: +1:14 + } + + bb11: { + StorageDead(_20); // scope 1 at $DIR/async_await.rs:+1:13: +1:14 + _38 = move _19; // scope 1 at $DIR/async_await.rs:+1:8: +1:14 + StorageDead(_19); // scope 1 at $DIR/async_await.rs:+1:13: +1:14 + _7 = const (); // scope 1 at $DIR/async_await.rs:+1:8: +1:14 + goto -> bb4; // scope 1 at $DIR/async_await.rs:+1:8: +1:14 + } + + bb12: { + nop; // scope 0 at $DIR/async_await.rs:+1:13: +1:14 + goto -> bb13; // scope 0 at $DIR/async_await.rs:+1:14: +1:15 + } + + bb13: { + StorageDead(_4); // scope 0 at $DIR/async_await.rs:+1:14: +1:15 + StorageDead(_3); // scope 0 at $DIR/async_await.rs:+1:14: +1:15 + StorageLive(_21); // scope 0 at $DIR/async_await.rs:+2:8: +2:14 + StorageLive(_22); // scope 0 at $DIR/async_await.rs:+2:5: +2:8 + _22 = a() -> bb14; // scope 0 at $DIR/async_await.rs:+2:5: +2:8 + // mir::Constant + // + span: $DIR/async_await.rs:16:5: 16:6 + // + literal: Const { ty: fn() -> impl Future {a}, val: Value() } + } + + bb14: { + _21 = as IntoFuture>::into_future(move _22) -> bb15; // scope 0 at $DIR/async_await.rs:+2:8: +2:14 + // mir::Constant + // + span: $DIR/async_await.rs:16:8: 16:14 + // + literal: Const { ty: fn(impl Future) -> as IntoFuture>::IntoFuture { as IntoFuture>::into_future}, val: Value() } + } + + bb15: { + StorageDead(_22); // scope 0 at $DIR/async_await.rs:+2:13: +2:14 + nop; // scope 0 at $DIR/async_await.rs:+2:8: +2:14 + (((*(_1.0: &mut [async fn body@$DIR/async_await.rs:14:18: 17:2])) as variant#4).0: impl std::future::Future) = move _21; // scope 0 at $DIR/async_await.rs:+2:8: +2:14 + goto -> bb16; // scope 4 at $DIR/async_await.rs:+2:8: +2:14 + } + + bb16: { + StorageLive(_24); // scope 4 at $DIR/async_await.rs:+2:8: +2:14 + StorageLive(_25); // scope 4 at $DIR/async_await.rs:+2:8: +2:14 + StorageLive(_26); // scope 5 at $DIR/async_await.rs:+2:8: +2:14 + StorageLive(_27); // scope 5 at $DIR/async_await.rs:+2:8: +2:14 + StorageLive(_28); // scope 5 at $DIR/async_await.rs:+2:8: +2:14 + _28 = &mut (((*(_1.0: &mut [async fn body@$DIR/async_await.rs:14:18: 17:2])) as variant#4).0: impl std::future::Future); // scope 5 at $DIR/async_await.rs:+2:8: +2:14 + _27 = &mut (*_28); // scope 5 at $DIR/async_await.rs:+2:8: +2:14 + _26 = Pin::<&mut impl Future>::new_unchecked(move _27) -> bb17; // scope 5 at $DIR/async_await.rs:+2:8: +2:14 + // mir::Constant + // + span: $DIR/async_await.rs:16:8: 16:14 + // + literal: Const { ty: unsafe fn(&mut impl Future) -> Pin<&mut impl Future> {Pin::<&mut impl Future>::new_unchecked}, val: Value() } + } + + bb17: { + StorageDead(_27); // scope 5 at $DIR/async_await.rs:+2:13: +2:14 + StorageLive(_29); // scope 5 at $DIR/async_await.rs:+2:5: +2:14 + StorageLive(_30); // scope 5 at $DIR/async_await.rs:+2:5: +2:14 + StorageLive(_31); // scope 5 at $DIR/async_await.rs:+2:8: +2:14 + _31 = _38; // scope 5 at $DIR/async_await.rs:+2:8: +2:14 + _30 = move _31; // scope 5 at $DIR/async_await.rs:+2:5: +2:14 + goto -> bb18; // scope 5 at $DIR/async_await.rs:+2:5: +2:14 + } + + bb18: { + _29 = &mut (*_30); // scope 5 at $DIR/async_await.rs:+2:5: +2:14 + StorageDead(_31); // scope 5 at $DIR/async_await.rs:+2:13: +2:14 + _25 = as Future>::poll(move _26, move _29) -> bb19; // scope 5 at $DIR/async_await.rs:+2:8: +2:14 + // mir::Constant + // + span: $DIR/async_await.rs:16:8: 16:14 + // + literal: Const { ty: for<'a, 'b, 'c> fn(Pin<&'a mut impl Future>, &'b mut Context<'c>) -> Poll< as Future>::Output> { as Future>::poll}, val: Value() } + } + + bb19: { + StorageDead(_29); // scope 5 at $DIR/async_await.rs:+2:13: +2:14 + StorageDead(_26); // scope 5 at $DIR/async_await.rs:+2:13: +2:14 + _32 = discriminant(_25); // scope 4 at $DIR/async_await.rs:+2:8: +2:14 + switchInt(move _32) -> [0: bb22, 1: bb20, otherwise: bb21]; // scope 4 at $DIR/async_await.rs:+2:8: +2:14 + } + + bb20: { + _24 = const (); // scope 4 at $DIR/async_await.rs:+2:8: +2:14 + StorageDead(_30); // scope 4 at $DIR/async_await.rs:+2:13: +2:14 + StorageDead(_28); // scope 4 at $DIR/async_await.rs:+2:13: +2:14 + StorageDead(_25); // scope 4 at $DIR/async_await.rs:+2:13: +2:14 + StorageDead(_24); // scope 4 at $DIR/async_await.rs:+2:13: +2:14 + StorageLive(_35); // scope 4 at $DIR/async_await.rs:+2:8: +2:14 + StorageLive(_36); // scope 4 at $DIR/async_await.rs:+2:8: +2:14 + _36 = (); // scope 4 at $DIR/async_await.rs:+2:8: +2:14 + Deinit(_0); // scope 4 at $DIR/async_await.rs:+2:8: +2:14 + discriminant(_0) = 1; // scope 4 at $DIR/async_await.rs:+2:8: +2:14 + discriminant((*(_1.0: &mut [async fn body@$DIR/async_await.rs:14:18: 17:2]))) = 4; // scope 4 at $DIR/async_await.rs:+2:8: +2:14 + return; // scope 4 at $DIR/async_await.rs:+2:8: +2:14 + } + + bb21: { + unreachable; // scope 4 at $DIR/async_await.rs:+2:8: +2:14 + } + + bb22: { + StorageLive(_33); // scope 4 at $DIR/async_await.rs:+2:5: +2:14 + _33 = ((_25 as Ready).0: ()); // scope 4 at $DIR/async_await.rs:+2:5: +2:14 + _37 = _33; // scope 6 at $DIR/async_await.rs:+2:5: +2:14 + StorageDead(_33); // scope 4 at $DIR/async_await.rs:+2:13: +2:14 + StorageDead(_30); // scope 4 at $DIR/async_await.rs:+2:13: +2:14 + StorageDead(_28); // scope 4 at $DIR/async_await.rs:+2:13: +2:14 + StorageDead(_25); // scope 4 at $DIR/async_await.rs:+2:13: +2:14 + StorageDead(_24); // scope 4 at $DIR/async_await.rs:+2:13: +2:14 + goto -> bb24; // scope 0 at $DIR/async_await.rs:+2:13: +2:14 + } + + bb23: { + StorageDead(_36); // scope 4 at $DIR/async_await.rs:+2:13: +2:14 + _38 = move _35; // scope 4 at $DIR/async_await.rs:+2:8: +2:14 + StorageDead(_35); // scope 4 at $DIR/async_await.rs:+2:13: +2:14 + _7 = const (); // scope 4 at $DIR/async_await.rs:+2:8: +2:14 + goto -> bb16; // scope 4 at $DIR/async_await.rs:+2:8: +2:14 + } + + bb24: { + nop; // scope 0 at $DIR/async_await.rs:+2:13: +2:14 + goto -> bb25; // scope 0 at $DIR/async_await.rs:+3:1: +3:2 + } + + bb25: { + StorageDead(_21); // scope 0 at $DIR/async_await.rs:+3:1: +3:2 + goto -> bb26; // scope 0 at $DIR/async_await.rs:+3:1: +3:2 + } + + bb26: { + Deinit(_0); // scope 0 at $DIR/async_await.rs:+3:2: +3:2 + ((_0 as Ready).0: ()) = move _37; // scope 0 at $DIR/async_await.rs:+3:2: +3:2 + discriminant(_0) = 0; // scope 0 at $DIR/async_await.rs:+3:2: +3:2 + discriminant((*(_1.0: &mut [async fn body@$DIR/async_await.rs:14:18: 17:2]))) = 1; // scope 0 at $DIR/async_await.rs:+3:2: +3:2 + return; // scope 0 at $DIR/async_await.rs:+3:2: +3:2 + } + + bb27: { + StorageLive(_3); // scope 0 at $DIR/async_await.rs:+0:18: +3:2 + StorageLive(_4); // scope 0 at $DIR/async_await.rs:+0:18: +3:2 + StorageLive(_19); // scope 0 at $DIR/async_await.rs:+0:18: +3:2 + StorageLive(_20); // scope 0 at $DIR/async_await.rs:+0:18: +3:2 + _19 = move _2; // scope 0 at $DIR/async_await.rs:+0:18: +3:2 + goto -> bb11; // scope 0 at $DIR/async_await.rs:+0:18: +3:2 + } + + bb28: { + StorageLive(_21); // scope 0 at $DIR/async_await.rs:+0:18: +3:2 + StorageLive(_35); // scope 0 at $DIR/async_await.rs:+0:18: +3:2 + StorageLive(_36); // scope 0 at $DIR/async_await.rs:+0:18: +3:2 + _35 = move _2; // scope 0 at $DIR/async_await.rs:+0:18: +3:2 + goto -> bb23; // scope 0 at $DIR/async_await.rs:+0:18: +3:2 + } + + bb29: { + assert(const false, "`async fn` resumed after completion") -> bb29; // scope 0 at $DIR/async_await.rs:+0:18: +3:2 + } + + bb30: { + unreachable; // scope 0 at $DIR/async_await.rs:+0:18: +3:2 + } +} diff --git a/tests/mir-opt/building/async_await.rs b/tests/mir-opt/building/async_await.rs new file mode 100644 index 0000000000000..0b991e3b8f8cc --- /dev/null +++ b/tests/mir-opt/building/async_await.rs @@ -0,0 +1,17 @@ +// This test makes sure that the generator MIR pass eliminates all calls to +// `get_context`, and that the MIR argument type for an async fn and all locals +// related to `yield` are `&mut Context`, and its return type is `Poll`. + +// edition:2018 +// compile-flags: -C panic=abort + +#![crate_type = "lib"] + +// EMIT_MIR async_await.a-{closure#0}.generator_resume.0.mir +async fn a() {} + +// EMIT_MIR async_await.b-{closure#0}.generator_resume.0.mir +pub async fn b() { + a().await; + a().await +} From fa7d17dbb570d1674781c590849ea22ebc882418 Mon Sep 17 00:00:00 2001 From: Albert Larsan <74931857+albertlarsan68@users.noreply.github.com> Date: Thu, 19 Jan 2023 08:15:57 +0000 Subject: [PATCH 165/230] Create new bootstrap team --- triagebot.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index bfbbae6857fa8..16a3132151374 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -175,7 +175,7 @@ exclude_labels = [ "T-*", ] -[autolabel."A-bootstrap"] +[autolabel."T-bootstrap"] trigger_files = [ "x.py", "x", @@ -493,6 +493,8 @@ libs = [ ] bootstrap = [ "@Mark-Simulacrum", + "@albertlarsan68", + "@ozkanonur", ] infra-ci = [ "@Mark-Simulacrum", From 8a1de57a4aaf4ff13d20fdbc162064f237bb7679 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 2 Dec 2022 16:27:25 +0100 Subject: [PATCH 166/230] Use UnordSet instead of FxHashSet in define_id_collections!(). --- .../src/coverageinfo/mapgen.rs | 8 +++--- compiler/rustc_codegen_ssa/src/base.rs | 15 ++++++----- compiler/rustc_data_structures/src/fx.rs | 2 +- compiler/rustc_data_structures/src/unord.rs | 26 ++++++++++++++++--- compiler/rustc_hir_typeck/src/writeback.rs | 14 +++++++--- src/tools/clippy/clippy_lints/src/len_zero.rs | 2 +- 6 files changed, 49 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 393bf30e9f834..22c61248b7d53 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -8,7 +8,7 @@ use rustc_codegen_ssa::coverageinfo::map::{Counter, CounterExpression}; use rustc_codegen_ssa::traits::{ConstMethods, CoverageInfoMethods}; use rustc_data_structures::fx::FxIndexSet; use rustc_hir::def::DefKind; -use rustc_hir::def_id::DefIdSet; +use rustc_hir::def_id::DefId; use rustc_llvm::RustString; use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; @@ -291,7 +291,7 @@ fn add_unused_functions(cx: &CodegenCx<'_, '_>) { let ignore_unused_generics = tcx.sess.instrument_coverage_except_unused_generics(); - let eligible_def_ids: DefIdSet = tcx + let eligible_def_ids: Vec = tcx .mir_keys(()) .iter() .filter_map(|local_def_id| { @@ -317,7 +317,9 @@ fn add_unused_functions(cx: &CodegenCx<'_, '_>) { let codegenned_def_ids = tcx.codegened_and_inlined_items(()); - for &non_codegenned_def_id in eligible_def_ids.difference(codegenned_def_ids) { + for non_codegenned_def_id in + eligible_def_ids.into_iter().filter(|id| !codegenned_def_ids.contains(id)) + { let codegen_fn_attrs = tcx.codegen_fn_attrs(non_codegenned_def_id); // If a function is marked `#[no_coverage]`, then skip generating a diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index f7312f6fcdafd..32d3cfe6fc650 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -964,16 +964,19 @@ pub fn provide(providers: &mut Providers) { }; let (defids, _) = tcx.collect_and_partition_mono_items(cratenum); - for id in &*defids { + + let any_for_speed = defids.items().any(|id| { let CodegenFnAttrs { optimize, .. } = tcx.codegen_fn_attrs(*id); match optimize { - attr::OptimizeAttr::None => continue, - attr::OptimizeAttr::Size => continue, - attr::OptimizeAttr::Speed => { - return for_speed; - } + attr::OptimizeAttr::None | attr::OptimizeAttr::Size => false, + attr::OptimizeAttr::Speed => true, } + }); + + if any_for_speed { + return for_speed; } + tcx.sess.opts.optimize }; } diff --git a/compiler/rustc_data_structures/src/fx.rs b/compiler/rustc_data_structures/src/fx.rs index 0d0c51b681946..11f9def34aac5 100644 --- a/compiler/rustc_data_structures/src/fx.rs +++ b/compiler/rustc_data_structures/src/fx.rs @@ -12,7 +12,7 @@ pub type IndexEntry<'a, K, V> = indexmap::map::Entry<'a, K, V>; macro_rules! define_id_collections { ($map_name:ident, $set_name:ident, $entry_name:ident, $key:ty) => { pub type $map_name = $crate::fx::FxHashMap<$key, T>; - pub type $set_name = $crate::fx::FxHashSet<$key>; + pub type $set_name = $crate::unord::UnordSet<$key>; pub type $entry_name<'a, T> = $crate::fx::StdEntry<'a, $key, T>; }; } diff --git a/compiler/rustc_data_structures/src/unord.rs b/compiler/rustc_data_structures/src/unord.rs index 14257e4d5c60b..cfd7ee097a35f 100644 --- a/compiler/rustc_data_structures/src/unord.rs +++ b/compiler/rustc_data_structures/src/unord.rs @@ -38,17 +38,17 @@ impl> UnordItems { } #[inline] - pub fn all bool>(mut self, f: F) -> bool { + pub fn all bool>(mut self, f: F) -> bool { self.0.all(f) } #[inline] - pub fn any bool>(mut self, f: F) -> bool { + pub fn any bool>(mut self, f: F) -> bool { self.0.any(f) } #[inline] - pub fn filter bool>(self, f: F) -> UnordItems> { + pub fn filter bool>(self, f: F) -> UnordItems> { UnordItems(self.0.filter(f)) } @@ -96,6 +96,15 @@ impl> UnordItems { pub fn count(self) -> usize { self.0.count() } + + #[inline] + pub fn flat_map(self, f: F) -> UnordItems> + where + U: IntoIterator, + F: Fn(T) -> U, + { + UnordItems(self.0.flat_map(f)) + } } impl<'a, T: Clone + 'a, I: Iterator> UnordItems<&'a T, I> { @@ -193,6 +202,11 @@ impl UnordSet { pub fn extend>(&mut self, items: UnordItems) { self.inner.extend(items.0) } + + #[inline] + pub fn clear(&mut self) { + self.inner.clear(); + } } impl Extend for UnordSet { @@ -201,6 +215,12 @@ impl Extend for UnordSet { } } +impl FromIterator for UnordSet { + fn from_iter>(iter: T) -> Self { + UnordSet { inner: FxHashSet::from_iter(iter) } + } +} + impl> HashStable for UnordSet { #[inline] fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) { diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 30ef7f3ba2927..b8c1bcc5a283e 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -19,6 +19,7 @@ use rustc_middle::ty::TypeckResults; use rustc_middle::ty::{self, ClosureSizeProfileData, Ty, TyCtxt}; use rustc_span::symbol::sym; use rustc_span::Span; +use smallvec::SmallVec; use std::mem; use std::ops::ControlFlow; @@ -458,12 +459,17 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { fn visit_coercion_casts(&mut self) { let fcx_typeck_results = self.fcx.typeck_results.borrow(); - let fcx_coercion_casts = fcx_typeck_results.coercion_casts(); + assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); - for local_id in fcx_coercion_casts { - self.typeck_results.set_coercion_cast(*local_id); - } + self.tcx().with_stable_hashing_context(|hcx| { + let fcx_coercion_casts: SmallVec<[_; 32]> = + fcx_typeck_results.coercion_casts().items().cloned().into_sorted_small_vec(&hcx); + + for local_id in fcx_coercion_casts { + self.typeck_results.set_coercion_cast(local_id); + } + }); } fn visit_user_provided_tys(&mut self) { diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index 9eba46756299c..3c70c9cf19a51 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -219,7 +219,7 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items let is_empty = sym!(is_empty); let is_empty_method_found = current_and_super_traits - .iter() + .items() .flat_map(|&i| cx.tcx.associated_items(i).filter_by_name_unhygienic(is_empty)) .any(|i| { i.kind == ty::AssocKind::Fn From c3d25731207e466fc20b00124a5aadd435d3b885 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 17 Jan 2023 12:05:01 +0100 Subject: [PATCH 167/230] Use UnordMap instead of FxHashMap in define_id_collections!(). --- .../src/back/symbol_export.rs | 14 ++- compiler/rustc_data_structures/src/fx.rs | 2 +- compiler/rustc_data_structures/src/unord.rs | 110 +++++++++++++++++- .../rustc_hir_analysis/src/variance/solve.rs | 15 +-- compiler/rustc_hir_typeck/src/writeback.rs | 88 ++++++++------ compiler/rustc_lint_defs/src/lib.rs | 5 +- .../src/rmeta/decoder/cstore_impl.rs | 7 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 7 +- compiler/rustc_middle/src/ty/mod.rs | 4 +- .../rustc_middle/src/ty/typeck_results.rs | 37 ++++-- compiler/rustc_resolve/src/check_unused.rs | 10 +- .../clippy/clippy_lints/src/inherent_impl.rs | 26 ++--- .../src/loops/while_immutable_condition.rs | 2 +- .../clippy_lints/src/missing_trait_methods.rs | 26 +++-- .../clippy_lints/src/pass_by_ref_or_value.rs | 4 +- 15 files changed, 254 insertions(+), 103 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 8cb7d74b90d4b..b442483346d6c 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -173,11 +173,15 @@ fn exported_symbols_provider_local( return &[]; } - let mut symbols: Vec<_> = tcx - .reachable_non_generics(LOCAL_CRATE) - .iter() - .map(|(&def_id, &info)| (ExportedSymbol::NonGeneric(def_id), info)) - .collect(); + // FIXME: Sorting this is unnecessary since we are sorting later anyway. + // Can we skip the later sorting? + let mut symbols: Vec<_> = tcx.with_stable_hashing_context(|hcx| { + tcx.reachable_non_generics(LOCAL_CRATE) + .to_sorted(&hcx) + .into_iter() + .map(|(&def_id, &info)| (ExportedSymbol::NonGeneric(def_id), info)) + .collect() + }); if tcx.entry_fn(()).is_some() { let exported_symbol = diff --git a/compiler/rustc_data_structures/src/fx.rs b/compiler/rustc_data_structures/src/fx.rs index 11f9def34aac5..9fce0e1e65cc9 100644 --- a/compiler/rustc_data_structures/src/fx.rs +++ b/compiler/rustc_data_structures/src/fx.rs @@ -11,7 +11,7 @@ pub type IndexEntry<'a, K, V> = indexmap::map::Entry<'a, K, V>; #[macro_export] macro_rules! define_id_collections { ($map_name:ident, $set_name:ident, $entry_name:ident, $key:ty) => { - pub type $map_name = $crate::fx::FxHashMap<$key, T>; + pub type $map_name = $crate::unord::UnordMap<$key, T>; pub type $set_name = $crate::unord::UnordSet<$key>; pub type $entry_name<'a, T> = $crate::fx::StdEntry<'a, $key, T>; }; diff --git a/compiler/rustc_data_structures/src/unord.rs b/compiler/rustc_data_structures/src/unord.rs index cfd7ee097a35f..1e71629a7c4e0 100644 --- a/compiler/rustc_data_structures/src/unord.rs +++ b/compiler/rustc_data_structures/src/unord.rs @@ -6,8 +6,10 @@ use rustc_hash::{FxHashMap, FxHashSet}; use smallvec::SmallVec; use std::{ borrow::Borrow, + collections::hash_map::Entry, hash::Hash, iter::{Product, Sum}, + ops::Index, }; use crate::{ @@ -187,7 +189,16 @@ impl UnordSet { } #[inline] - pub fn items(&self) -> UnordItems<&V, impl Iterator> { + pub fn remove(&mut self, k: &Q) -> bool + where + V: Borrow, + Q: Hash + Eq, + { + self.inner.remove(k) + } + + #[inline] + pub fn items<'a>(&'a self) -> UnordItems<&'a V, impl Iterator> { UnordItems(self.inner.iter()) } @@ -254,6 +265,18 @@ impl Extend<(K, V)> for UnordMap { } } +impl FromIterator<(K, V)> for UnordMap { + fn from_iter>(iter: T) -> Self { + UnordMap { inner: FxHashMap::from_iter(iter) } + } +} + +impl> From> for UnordMap { + fn from(items: UnordItems<(K, V), I>) -> Self { + UnordMap { inner: FxHashMap::from_iter(items.0) } + } +} + impl UnordMap { #[inline] pub fn len(&self) -> usize { @@ -275,7 +298,44 @@ impl UnordMap { } #[inline] - pub fn items(&self) -> UnordItems<(&K, &V), impl Iterator> { + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } + + #[inline] + pub fn entry(&mut self, key: K) -> Entry<'_, K, V> { + self.inner.entry(key) + } + + #[inline] + pub fn get(&self, k: &Q) -> Option<&V> + where + K: Borrow, + Q: Hash + Eq, + { + self.inner.get(k) + } + + #[inline] + pub fn get_mut(&mut self, k: &Q) -> Option<&mut V> + where + K: Borrow, + Q: Hash + Eq, + { + self.inner.get_mut(k) + } + + #[inline] + pub fn remove(&mut self, k: &Q) -> Option + where + K: Borrow, + Q: Hash + Eq, + { + self.inner.remove(k) + } + + #[inline] + pub fn items<'a>(&'a self) -> UnordItems<(&'a K, &'a V), impl Iterator> { UnordItems(self.inner.iter()) } @@ -290,6 +350,46 @@ impl UnordMap { pub fn extend>(&mut self, items: UnordItems<(K, V), I>) { self.inner.extend(items.0) } + + pub fn to_sorted(&self, hcx: &HCX) -> Vec<(&K, &V)> + where + K: ToStableHashKey, + { + let mut items: Vec<(&K, &V)> = self.inner.iter().collect(); + items.sort_by_cached_key(|(k, _)| k.to_stable_hash_key(hcx)); + items + } + + pub fn into_sorted(self, hcx: &HCX) -> Vec<(K, V)> + where + K: ToStableHashKey, + { + let mut items: Vec<(K, V)> = self.inner.into_iter().collect(); + items.sort_by_cached_key(|(k, _)| k.to_stable_hash_key(hcx)); + items + } + + pub fn values_sorted(&self, hcx: &HCX) -> impl Iterator + where + K: ToStableHashKey, + { + let mut items: Vec<(&K, &V)> = self.inner.iter().collect(); + items.sort_by_cached_key(|(k, _)| k.to_stable_hash_key(hcx)); + items.into_iter().map(|(_, v)| v) + } +} + +impl Index<&Q> for UnordMap +where + K: Eq + Hash + Borrow, + Q: Eq + Hash, +{ + type Output = V; + + #[inline] + fn index(&self, key: &Q) -> &V { + &self.inner[key] + } } impl, V: HashStable> HashStable for UnordMap { @@ -354,6 +454,12 @@ impl Extend for UnordBag { } } +impl> From> for UnordBag { + fn from(value: UnordItems) -> Self { + UnordBag { inner: Vec::from_iter(value.0) } + } +} + impl> HashStable for UnordBag { #[inline] fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) { diff --git a/compiler/rustc_hir_analysis/src/variance/solve.rs b/compiler/rustc_hir_analysis/src/variance/solve.rs index c9b59d35704b2..2d283532bdfc3 100644 --- a/compiler/rustc_hir_analysis/src/variance/solve.rs +++ b/compiler/rustc_hir_analysis/src/variance/solve.rs @@ -5,8 +5,7 @@ //! optimal solution to the constraints. The final variance for each //! inferred is then written into the `variance_map` in the tcx. -use rustc_data_structures::fx::FxHashMap; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::DefIdMap; use rustc_middle::ty; use super::constraints::*; @@ -89,14 +88,12 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> { } } - fn create_map(&self) -> FxHashMap { + fn create_map(&self) -> DefIdMap<&'tcx [ty::Variance]> { let tcx = self.terms_cx.tcx; let solutions = &self.solutions; - self.terms_cx - .inferred_starts - .iter() - .map(|(&def_id, &InferredIndex(start))| { + DefIdMap::from(self.terms_cx.inferred_starts.items().map( + |(&def_id, &InferredIndex(start))| { let generics = tcx.generics_of(def_id); let count = generics.count(); @@ -115,8 +112,8 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> { } (def_id.to_def_id(), &*variances) - }) - .collect() + }, + )) } fn evaluate(&self, term: VarianceTermPtr<'a>) -> ty::Variance { diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index b8c1bcc5a283e..6e6b63beca2a7 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -449,8 +449,11 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); let common_hir_owner = fcx_typeck_results.hir_owner; - for (id, origin) in fcx_typeck_results.closure_kind_origins().iter() { - let hir_id = hir::HirId { owner: common_hir_owner, local_id: *id }; + let fcx_closure_kind_origins = + fcx_typeck_results.closure_kind_origins().items_in_stable_order(self.tcx()); + + for (&local_id, origin) in fcx_closure_kind_origins { + let hir_id = hir::HirId { owner: common_hir_owner, local_id }; let place_span = origin.0; let place = self.resolve(origin.1.clone(), &place_span); self.typeck_results.closure_kind_origins_mut().insert(hir_id, (place_span, place)); @@ -477,22 +480,15 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); let common_hir_owner = fcx_typeck_results.hir_owner; - let mut errors_buffer = Vec::new(); - for (&local_id, c_ty) in fcx_typeck_results.user_provided_types().iter() { - let hir_id = hir::HirId { owner: common_hir_owner, local_id }; - - if cfg!(debug_assertions) && c_ty.needs_infer() { - span_bug!( - hir_id.to_span(self.fcx.tcx), - "writeback: `{:?}` has inference variables", - c_ty - ); - }; + if self.rustc_dump_user_substs { + let sorted_user_provided_types = + fcx_typeck_results.user_provided_types().items_in_stable_order(self.tcx()); - self.typeck_results.user_provided_types_mut().insert(hir_id, *c_ty); + let mut errors_buffer = Vec::new(); + for (&local_id, c_ty) in sorted_user_provided_types { + let hir_id = hir::HirId { owner: common_hir_owner, local_id }; - if let ty::UserType::TypeOf(_, user_substs) = c_ty.value { - if self.rustc_dump_user_substs { + if let ty::UserType::TypeOf(_, user_substs) = c_ty.value { // This is a unit-testing mechanism. let span = self.tcx().hir().span(hir_id); // We need to buffer the errors in order to guarantee a consistent @@ -504,31 +500,49 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { err.buffer(&mut errors_buffer); } } - } - if !errors_buffer.is_empty() { - errors_buffer.sort_by_key(|diag| diag.span.primary_span()); - for mut diag in errors_buffer { - self.tcx().sess.diagnostic().emit_diagnostic(&mut diag); + if !errors_buffer.is_empty() { + errors_buffer.sort_by_key(|diag| diag.span.primary_span()); + for mut diag in errors_buffer { + self.tcx().sess.diagnostic().emit_diagnostic(&mut diag); + } } } + + self.typeck_results.user_provided_types_mut().extend( + fcx_typeck_results.user_provided_types().items().map(|(local_id, c_ty)| { + let hir_id = hir::HirId { owner: common_hir_owner, local_id }; + + if cfg!(debug_assertions) && c_ty.needs_infer() { + span_bug!( + hir_id.to_span(self.fcx.tcx), + "writeback: `{:?}` has inference variables", + c_ty + ); + }; + + (hir_id, *c_ty) + }), + ); } fn visit_user_provided_sigs(&mut self) { let fcx_typeck_results = self.fcx.typeck_results.borrow(); assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); - for (&def_id, c_sig) in fcx_typeck_results.user_provided_sigs.iter() { - if cfg!(debug_assertions) && c_sig.needs_infer() { - span_bug!( - self.fcx.tcx.def_span(def_id), - "writeback: `{:?}` has inference variables", - c_sig - ); - }; - - self.typeck_results.user_provided_sigs.insert(def_id, *c_sig); - } + self.typeck_results.user_provided_sigs.extend( + fcx_typeck_results.user_provided_sigs.items().map(|(&def_id, c_sig)| { + if cfg!(debug_assertions) && c_sig.needs_infer() { + span_bug!( + self.fcx.tcx.def_span(def_id), + "writeback: `{:?}` has inference variables", + c_sig + ); + }; + + (def_id, *c_sig) + }), + ); } fn visit_generator_interior_types(&mut self) { @@ -647,7 +661,10 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); let common_hir_owner = fcx_typeck_results.hir_owner; - for (&local_id, &fn_sig) in fcx_typeck_results.liberated_fn_sigs().iter() { + let fcx_liberated_fn_sigs = + fcx_typeck_results.liberated_fn_sigs().items_in_stable_order(self.tcx()); + + for (&local_id, &fn_sig) in fcx_liberated_fn_sigs { let hir_id = hir::HirId { owner: common_hir_owner, local_id }; let fn_sig = self.resolve(fn_sig, &hir_id); self.typeck_results.liberated_fn_sigs_mut().insert(hir_id, fn_sig); @@ -659,7 +676,10 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); let common_hir_owner = fcx_typeck_results.hir_owner; - for (&local_id, ftys) in fcx_typeck_results.fru_field_types().iter() { + let fcx_fru_field_types = + fcx_typeck_results.fru_field_types().items_in_stable_order(self.tcx()); + + for (&local_id, ftys) in fcx_fru_field_types { let hir_id = hir::HirId { owner: common_hir_owner, local_id }; let ftys = self.resolve(ftys.clone(), &hir_id); self.typeck_results.fru_field_types_mut().insert(hir_id, ftys); diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index f4b4c5168bfd6..9aca485e502e6 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -6,8 +6,9 @@ extern crate rustc_macros; pub use self::Level::*; -use rustc_ast::node_id::{NodeId, NodeMap}; +use rustc_ast::node_id::NodeId; use rustc_ast::{AttrId, Attribute}; +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; use rustc_error_messages::{DiagnosticMessage, MultiSpan}; use rustc_hir::HashStableContext; @@ -544,7 +545,7 @@ pub struct BufferedEarlyLint { #[derive(Default)] pub struct LintBuffer { - pub map: NodeMap>, + pub map: FxIndexMap>, } impl LintBuffer { diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index cb451931dfe17..78997961d173d 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -382,7 +382,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { // keys from the former. // This is a rudimentary check that does not catch all cases, // just the easiest. - let mut fallback_map: DefIdMap = Default::default(); + let mut fallback_map: Vec<(DefId, DefId)> = Default::default(); // Issue 46112: We want the map to prefer the shortest // paths when reporting the path to an item. Therefore we @@ -412,12 +412,12 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { if let Some(def_id) = child.res.opt_def_id() { if child.ident.name == kw::Underscore { - fallback_map.insert(def_id, parent); + fallback_map.push((def_id, parent)); return; } if ty::util::is_doc_hidden(tcx, parent) { - fallback_map.insert(def_id, parent); + fallback_map.push((def_id, parent)); return; } @@ -451,6 +451,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { // Fill in any missing entries with the less preferable path. // If this path re-exports the child as `_`, we still use this // path in a diagnostic that suggests importing `::*`. + for (child, parent) in fallback_map { visible_parent_map.entry(child).or_insert(parent); } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index a3d44fa890dd1..c3292681cc6ab 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1187,8 +1187,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.trait_impl_trait_tys[def_id] <- table); } } - let inherent_impls = tcx.crate_inherent_impls(()); - for (def_id, implementations) in inherent_impls.inherent_impls.iter() { + let inherent_impls = tcx.with_stable_hashing_context(|hcx| { + tcx.crate_inherent_impls(()).inherent_impls.to_sorted(&hcx) + }); + + for (def_id, implementations) in inherent_impls { if implementations.is_empty() { continue; } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index d681df14af10a..7dfcd1bb5074d 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -38,7 +38,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::tagged_ptr::CopyTaggedPtr; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, LifetimeRes, Res}; -use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap}; +use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap}; use rustc_hir::Node; use rustc_index::vec::IndexVec; use rustc_macros::HashStable; @@ -436,7 +436,7 @@ pub struct CrateVariancesMap<'tcx> { /// For each item with generics, maps to a vector of the variance /// of its generics. If an item has no generics, it will have no /// entry. - pub variances: FxHashMap, + pub variances: DefIdMap<&'tcx [ty::Variance]>, } // Contains information needed to resolve types and (in the future) look up diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 18281b5175c44..0eaa47178c05d 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -6,7 +6,12 @@ use crate::{ GenericArgKind, InternalSubsts, SubstsRef, Ty, UserSubsts, }, }; -use rustc_data_structures::{fx::FxHashMap, sync::Lrc, unord::UnordSet, vec_map::VecMap}; +use rustc_data_structures::{ + fx::FxHashMap, + sync::Lrc, + unord::{UnordItems, UnordSet}, + vec_map::VecMap, +}; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::{ @@ -20,13 +25,9 @@ use rustc_macros::HashStable; use rustc_middle::mir::FakeReadCause; use rustc_session::Session; use rustc_span::Span; -use std::{ - collections::hash_map::{self, Entry}, - hash::Hash, - iter, -}; +use std::{collections::hash_map::Entry, hash::Hash, iter}; -use super::RvalueScopes; +use super::{RvalueScopes, TyCtxt}; #[derive(TyEncodable, TyDecodable, Debug, HashStable)] pub struct TypeckResults<'tcx> { @@ -567,8 +568,16 @@ impl<'a, V> LocalTableInContext<'a, V> { self.data.get(&id.local_id) } - pub fn iter(&self) -> hash_map::Iter<'_, hir::ItemLocalId, V> { - self.data.iter() + pub fn items( + &'a self, + ) -> UnordItems<(hir::ItemLocalId, &'a V), impl Iterator> + { + self.data.items().map(|(id, value)| (*id, value)) + } + + #[allow(rustc::pass_by_value)] + pub fn items_in_stable_order(&self, tcx: TyCtxt<'_>) -> Vec<(&'a ItemLocalId, &'a V)> { + tcx.with_stable_hashing_context(|hcx| self.data.to_sorted(&hcx)) } } @@ -605,6 +614,16 @@ impl<'a, V> LocalTableInContextMut<'a, V> { validate_hir_id_for_typeck_results(self.hir_owner, id); self.data.remove(&id.local_id) } + + pub fn extend( + &mut self, + items: UnordItems<(hir::HirId, V), impl Iterator>, + ) { + self.data.extend(items.map(|(id, value)| { + validate_hir_id_for_typeck_results(self.hir_owner, id); + (id.local_id, value) + })) + } } rustc_index::newtype_index! { diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 32fb5e18276ab..eae4c9992eb08 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -28,9 +28,9 @@ use crate::module_to_string; use crate::Resolver; use rustc_ast as ast; -use rustc_ast::node_id::NodeMap; use rustc_ast::visit::{self, Visitor}; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::unord::UnordSet; use rustc_errors::{pluralize, MultiSpan}; use rustc_session::lint::builtin::{MACRO_USE_EXTERN_CRATE, UNUSED_IMPORTS}; use rustc_session::lint::BuiltinLintDiagnostics; @@ -40,7 +40,7 @@ struct UnusedImport<'a> { use_tree: &'a ast::UseTree, use_tree_id: ast::NodeId, item_span: Span, - unused: FxHashSet, + unused: UnordSet, } impl<'a> UnusedImport<'a> { @@ -52,7 +52,7 @@ impl<'a> UnusedImport<'a> { struct UnusedImportCheckVisitor<'a, 'b> { r: &'a mut Resolver<'b>, /// All the (so far) unused imports, grouped path list - unused_imports: NodeMap>, + unused_imports: FxIndexMap>, base_use_tree: Option<&'a ast::UseTree>, base_id: ast::NodeId, item_span: Span, @@ -89,7 +89,7 @@ impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> { use_tree, use_tree_id, item_span, - unused: FxHashSet::default(), + unused: Default::default(), }) } } diff --git a/src/tools/clippy/clippy_lints/src/inherent_impl.rs b/src/tools/clippy/clippy_lints/src/inherent_impl.rs index c5abcc462545c..81b37ce5dfc2d 100644 --- a/src/tools/clippy/clippy_lints/src/inherent_impl.rs +++ b/src/tools/clippy/clippy_lints/src/inherent_impl.rs @@ -52,21 +52,19 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl { // List of spans to lint. (lint_span, first_span) let mut lint_spans = Vec::new(); - for (_, impl_ids) in cx + let inherent_impls = cx .tcx - .crate_inherent_impls(()) - .inherent_impls - .iter() - .filter(|(&id, impls)| { - impls.len() > 1 - // Check for `#[allow]` on the type definition - && !is_lint_allowed( - cx, - MULTIPLE_INHERENT_IMPL, - cx.tcx.hir().local_def_id_to_hir_id(id), - ) - }) - { + .with_stable_hashing_context(|hcx| cx.tcx.crate_inherent_impls(()).inherent_impls.to_sorted(&hcx)); + + for (_, impl_ids) in inherent_impls.into_iter().filter(|(&id, impls)| { + impls.len() > 1 + // Check for `#[allow]` on the type definition + && !is_lint_allowed( + cx, + MULTIPLE_INHERENT_IMPL, + cx.tcx.hir().local_def_id_to_hir_id(id), + ) + }) { for impl_id in impl_ids.iter().map(|id| id.expect_local()) { match type_map.entry(cx.tcx.type_of(impl_id)) { Entry::Vacant(e) => { diff --git a/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs b/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs index a63422d2a36ac..d1a1f773f87b3 100644 --- a/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs +++ b/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs @@ -35,7 +35,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, expr: &' } else { return; }; - let mutable_static_in_cond = var_visitor.def_ids.iter().any(|(_, v)| *v); + let mutable_static_in_cond = var_visitor.def_ids.items().any(|(_, v)| *v); let mut has_break_or_return_visitor = HasBreakOrReturnVisitor { has_break_or_return: false, diff --git a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs index 68af8a672f6ae..1c61c6e551c35 100644 --- a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs +++ b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs @@ -80,19 +80,21 @@ impl<'tcx> LateLintPass<'tcx> for MissingTraitMethods { } } - for assoc in provided.values() { - let source_map = cx.tcx.sess.source_map(); - let definition_span = source_map.guess_head_span(cx.tcx.def_span(assoc.def_id)); + cx.tcx.with_stable_hashing_context(|hcx| { + for assoc in provided.values_sorted(&hcx) { + let source_map = cx.tcx.sess.source_map(); + let definition_span = source_map.guess_head_span(cx.tcx.def_span(assoc.def_id)); - span_lint_and_help( - cx, - MISSING_TRAIT_METHODS, - source_map.guess_head_span(item.span), - &format!("missing trait method provided by default: `{}`", assoc.name), - Some(definition_span), - "implement the method", - ); - } + span_lint_and_help( + cx, + MISSING_TRAIT_METHODS, + source_map.guess_head_span(item.span), + &format!("missing trait method provided by default: `{}`", assoc.name), + Some(definition_span), + "implement the method", + ); + } + }) } } } diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs index 870a1c7d88d53..2d21aaa4f7fdb 100644 --- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs +++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs @@ -190,10 +190,10 @@ impl<'tcx> PassByRefOrValue { // Don't lint if an unsafe pointer is created. // TODO: Limit the check only to unsafe pointers to the argument (or part of the argument) // which escape the current function. - if typeck.node_types().iter().any(|(_, &ty)| ty.is_unsafe_ptr()) + if typeck.node_types().items().any(|(_, &ty)| ty.is_unsafe_ptr()) || typeck .adjustments() - .iter() + .items() .flat_map(|(_, a)| a) .any(|a| matches!(a.kind, Adjust::Pointer(PointerCast::UnsafeFnPointer))) { From 72ee14ce3960ca02ba4f4a19b84bf9c27ec6de9d Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 18 Jan 2023 10:47:31 +0100 Subject: [PATCH 168/230] Allow for more efficient sorting when exporting Unord collections. --- .../src/back/symbol_export.rs | 2 +- compiler/rustc_data_structures/src/unord.rs | 87 +++++++++++++++++-- compiler/rustc_hir_typeck/src/writeback.rs | 31 +++---- compiler/rustc_metadata/src/rmeta/encoder.rs | 2 +- .../rustc_middle/src/ty/typeck_results.rs | 7 +- .../clippy/clippy_lints/src/inherent_impl.rs | 2 +- .../clippy_lints/src/missing_trait_methods.rs | 2 +- 7 files changed, 99 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index b442483346d6c..57a99e74c21ad 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -177,7 +177,7 @@ fn exported_symbols_provider_local( // Can we skip the later sorting? let mut symbols: Vec<_> = tcx.with_stable_hashing_context(|hcx| { tcx.reachable_non_generics(LOCAL_CRATE) - .to_sorted(&hcx) + .to_sorted(&hcx, true) .into_iter() .map(|(&def_id, &info)| (ExportedSymbol::NonGeneric(def_id), info)) .collect() diff --git a/compiler/rustc_data_structures/src/unord.rs b/compiler/rustc_data_structures/src/unord.rs index 1e71629a7c4e0..d29b49872741c 100644 --- a/compiler/rustc_data_structures/src/unord.rs +++ b/compiler/rustc_data_structures/src/unord.rs @@ -14,7 +14,7 @@ use std::{ use crate::{ fingerprint::Fingerprint, - stable_hasher::{HashStable, StableHasher, ToStableHashKey}, + stable_hasher::{HashStable, StableHasher, StableOrd, ToStableHashKey}, }; /// `UnordItems` is the order-less version of `Iterator`. It only contains methods @@ -158,6 +158,7 @@ pub struct UnordSet { } impl Default for UnordSet { + #[inline] fn default() -> Self { Self { inner: FxHashSet::default() } } @@ -207,6 +208,46 @@ impl UnordSet { UnordItems(self.inner.into_iter()) } + #[inline] + pub fn to_sorted(&self, hcx: &HCX, cache_sort_key: bool) -> Vec<&V> + where + V: ToStableHashKey, + { + let mut items: Vec<&V> = self.inner.iter().collect(); + if cache_sort_key { + items.sort_by_cached_key(|k| k.to_stable_hash_key(hcx)); + } else { + items.sort_unstable_by_key(|k| k.to_stable_hash_key(hcx)); + } + + items + } + + #[inline] + pub fn to_sorted_stable_ord(&self) -> Vec + where + V: Ord + StableOrd + Copy, + { + let mut items: Vec = self.inner.iter().copied().collect(); + items.sort_unstable(); + items + } + + #[inline] + pub fn into_sorted(self, hcx: &HCX, cache_sort_key: bool) -> Vec + where + V: ToStableHashKey, + { + let mut items: Vec = self.inner.into_iter().collect(); + if cache_sort_key { + items.sort_by_cached_key(|k| k.to_stable_hash_key(hcx)); + } else { + items.sort_unstable_by_key(|k| k.to_stable_hash_key(hcx)); + } + + items + } + // We can safely extend this UnordSet from a set of unordered values because that // won't expose the internal ordering anywhere. #[inline] @@ -221,12 +262,14 @@ impl UnordSet { } impl Extend for UnordSet { + #[inline] fn extend>(&mut self, iter: T) { self.inner.extend(iter) } } impl FromIterator for UnordSet { + #[inline] fn from_iter>(iter: T) -> Self { UnordSet { inner: FxHashSet::from_iter(iter) } } @@ -254,24 +297,28 @@ pub struct UnordMap { } impl Default for UnordMap { + #[inline] fn default() -> Self { Self { inner: FxHashMap::default() } } } impl Extend<(K, V)> for UnordMap { + #[inline] fn extend>(&mut self, iter: T) { self.inner.extend(iter) } } impl FromIterator<(K, V)> for UnordMap { + #[inline] fn from_iter>(iter: T) -> Self { UnordMap { inner: FxHashMap::from_iter(iter) } } } impl> From> for UnordMap { + #[inline] fn from(items: UnordItems<(K, V), I>) -> Self { UnordMap { inner: FxHashMap::from_iter(items.0) } } @@ -351,30 +398,56 @@ impl UnordMap { self.inner.extend(items.0) } - pub fn to_sorted(&self, hcx: &HCX) -> Vec<(&K, &V)> + #[inline] + pub fn to_sorted(&self, hcx: &HCX, cache_sort_key: bool) -> Vec<(&K, &V)> where K: ToStableHashKey, { let mut items: Vec<(&K, &V)> = self.inner.iter().collect(); - items.sort_by_cached_key(|(k, _)| k.to_stable_hash_key(hcx)); + if cache_sort_key { + items.sort_by_cached_key(|(k, _)| k.to_stable_hash_key(hcx)); + } else { + items.sort_unstable_by_key(|(k, _)| k.to_stable_hash_key(hcx)); + } + items } - pub fn into_sorted(self, hcx: &HCX) -> Vec<(K, V)> + #[inline] + pub fn to_sorted_stable_ord(&self) -> Vec<(K, &V)> + where + K: Ord + StableOrd + Copy, + { + let mut items: Vec<(K, &V)> = self.inner.iter().map(|(&k, v)| (k, v)).collect(); + items.sort_unstable_by_key(|&(k, _)| k); + items + } + + #[inline] + pub fn into_sorted(self, hcx: &HCX, cache_sort_key: bool) -> Vec<(K, V)> where K: ToStableHashKey, { let mut items: Vec<(K, V)> = self.inner.into_iter().collect(); - items.sort_by_cached_key(|(k, _)| k.to_stable_hash_key(hcx)); + if cache_sort_key { + items.sort_by_cached_key(|(k, _)| k.to_stable_hash_key(hcx)); + } else { + items.sort_unstable_by_key(|(k, _)| k.to_stable_hash_key(hcx)); + } items } - pub fn values_sorted(&self, hcx: &HCX) -> impl Iterator + #[inline] + pub fn values_sorted(&self, hcx: &HCX, cache_sort_key: bool) -> impl Iterator where K: ToStableHashKey, { let mut items: Vec<(&K, &V)> = self.inner.iter().collect(); - items.sort_by_cached_key(|(k, _)| k.to_stable_hash_key(hcx)); + if cache_sort_key { + items.sort_by_cached_key(|(k, _)| k.to_stable_hash_key(hcx)); + } else { + items.sort_unstable_by_key(|(k, _)| k.to_stable_hash_key(hcx)); + } items.into_iter().map(|(_, v)| v) } } diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 6e6b63beca2a7..250f4cd3f65fb 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -19,7 +19,6 @@ use rustc_middle::ty::TypeckResults; use rustc_middle::ty::{self, ClosureSizeProfileData, Ty, TyCtxt}; use rustc_span::symbol::sym; use rustc_span::Span; -use smallvec::SmallVec; use std::mem; use std::ops::ControlFlow; @@ -450,9 +449,9 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { let common_hir_owner = fcx_typeck_results.hir_owner; let fcx_closure_kind_origins = - fcx_typeck_results.closure_kind_origins().items_in_stable_order(self.tcx()); + fcx_typeck_results.closure_kind_origins().items_in_stable_order(); - for (&local_id, origin) in fcx_closure_kind_origins { + for (local_id, origin) in fcx_closure_kind_origins { let hir_id = hir::HirId { owner: common_hir_owner, local_id }; let place_span = origin.0; let place = self.resolve(origin.1.clone(), &place_span); @@ -465,14 +464,10 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); - self.tcx().with_stable_hashing_context(|hcx| { - let fcx_coercion_casts: SmallVec<[_; 32]> = - fcx_typeck_results.coercion_casts().items().cloned().into_sorted_small_vec(&hcx); - - for local_id in fcx_coercion_casts { - self.typeck_results.set_coercion_cast(local_id); - } - }); + let fcx_coercion_casts = fcx_typeck_results.coercion_casts().to_sorted_stable_ord(); + for local_id in fcx_coercion_casts { + self.typeck_results.set_coercion_cast(local_id); + } } fn visit_user_provided_tys(&mut self) { @@ -482,10 +477,10 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { if self.rustc_dump_user_substs { let sorted_user_provided_types = - fcx_typeck_results.user_provided_types().items_in_stable_order(self.tcx()); + fcx_typeck_results.user_provided_types().items_in_stable_order(); let mut errors_buffer = Vec::new(); - for (&local_id, c_ty) in sorted_user_provided_types { + for (local_id, c_ty) in sorted_user_provided_types { let hir_id = hir::HirId { owner: common_hir_owner, local_id }; if let ty::UserType::TypeOf(_, user_substs) = c_ty.value { @@ -661,10 +656,9 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); let common_hir_owner = fcx_typeck_results.hir_owner; - let fcx_liberated_fn_sigs = - fcx_typeck_results.liberated_fn_sigs().items_in_stable_order(self.tcx()); + let fcx_liberated_fn_sigs = fcx_typeck_results.liberated_fn_sigs().items_in_stable_order(); - for (&local_id, &fn_sig) in fcx_liberated_fn_sigs { + for (local_id, &fn_sig) in fcx_liberated_fn_sigs { let hir_id = hir::HirId { owner: common_hir_owner, local_id }; let fn_sig = self.resolve(fn_sig, &hir_id); self.typeck_results.liberated_fn_sigs_mut().insert(hir_id, fn_sig); @@ -676,10 +670,9 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); let common_hir_owner = fcx_typeck_results.hir_owner; - let fcx_fru_field_types = - fcx_typeck_results.fru_field_types().items_in_stable_order(self.tcx()); + let fcx_fru_field_types = fcx_typeck_results.fru_field_types().items_in_stable_order(); - for (&local_id, ftys) in fcx_fru_field_types { + for (local_id, ftys) in fcx_fru_field_types { let hir_id = hir::HirId { owner: common_hir_owner, local_id }; let ftys = self.resolve(ftys.clone(), &hir_id); self.typeck_results.fru_field_types_mut().insert(hir_id, ftys); diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index c3292681cc6ab..5b6f327c5c2c0 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1188,7 +1188,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } let inherent_impls = tcx.with_stable_hashing_context(|hcx| { - tcx.crate_inherent_impls(()).inherent_impls.to_sorted(&hcx) + tcx.crate_inherent_impls(()).inherent_impls.to_sorted(&hcx, true) }); for (def_id, implementations) in inherent_impls { diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 0eaa47178c05d..2902c6dc556e4 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -27,7 +27,7 @@ use rustc_session::Session; use rustc_span::Span; use std::{collections::hash_map::Entry, hash::Hash, iter}; -use super::{RvalueScopes, TyCtxt}; +use super::RvalueScopes; #[derive(TyEncodable, TyDecodable, Debug, HashStable)] pub struct TypeckResults<'tcx> { @@ -575,9 +575,8 @@ impl<'a, V> LocalTableInContext<'a, V> { self.data.items().map(|(id, value)| (*id, value)) } - #[allow(rustc::pass_by_value)] - pub fn items_in_stable_order(&self, tcx: TyCtxt<'_>) -> Vec<(&'a ItemLocalId, &'a V)> { - tcx.with_stable_hashing_context(|hcx| self.data.to_sorted(&hcx)) + pub fn items_in_stable_order(&self) -> Vec<(ItemLocalId, &'a V)> { + self.data.to_sorted_stable_ord() } } diff --git a/src/tools/clippy/clippy_lints/src/inherent_impl.rs b/src/tools/clippy/clippy_lints/src/inherent_impl.rs index 81b37ce5dfc2d..e9b2e31a769ad 100644 --- a/src/tools/clippy/clippy_lints/src/inherent_impl.rs +++ b/src/tools/clippy/clippy_lints/src/inherent_impl.rs @@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl { let inherent_impls = cx .tcx - .with_stable_hashing_context(|hcx| cx.tcx.crate_inherent_impls(()).inherent_impls.to_sorted(&hcx)); + .with_stable_hashing_context(|hcx| cx.tcx.crate_inherent_impls(()).inherent_impls.to_sorted(&hcx, true)); for (_, impl_ids) in inherent_impls.into_iter().filter(|(&id, impls)| { impls.len() > 1 diff --git a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs index 1c61c6e551c35..3371b4cce32c1 100644 --- a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs +++ b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs @@ -81,7 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingTraitMethods { } cx.tcx.with_stable_hashing_context(|hcx| { - for assoc in provided.values_sorted(&hcx) { + for assoc in provided.values_sorted(&hcx, true) { let source_map = cx.tcx.sess.source_map(); let definition_span = source_map.guess_head_span(cx.tcx.def_span(assoc.def_id)); From d6f565b1577084da6623ef861a54438ba7d0db5b Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Fri, 13 Jan 2023 00:04:28 +0000 Subject: [PATCH 169/230] Move `unchecked_duration_subtraction` to pedantic --- src/tools/clippy/clippy_lints/src/instant_subtraction.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs index dd1b23e7d9d29..9f6e89405713c 100644 --- a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs +++ b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs @@ -61,7 +61,7 @@ declare_clippy_lint! { /// [`Instant::now()`]: std::time::Instant::now; #[clippy::version = "1.65.0"] pub UNCHECKED_DURATION_SUBTRACTION, - suspicious, + pedantic, "finds unchecked subtraction of a 'Duration' from an 'Instant'" } From ca3d55e32d762ca0acb0676aac70848c559c7f06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Thu, 19 Jan 2023 00:00:00 +0000 Subject: [PATCH 170/230] Custom MIR: Support storage statements --- .../src/build/custom/parse/instruction.rs | 6 ++++++ library/core/src/intrinsics/mir.rs | 2 ++ tests/mir-opt/building/custom/simple_assign.rs | 2 ++ .../custom/simple_assign.simple.built.after.mir | 12 +++++++----- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index dca4906c07de5..0bca02589bce1 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -12,6 +12,12 @@ use super::{parse_by_kind, PResult, ParseCtxt}; impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { pub fn parse_statement(&self, expr_id: ExprId) -> PResult> { parse_by_kind!(self, expr_id, _, "statement", + @call("mir_storage_live", args) => { + Ok(StatementKind::StorageLive(self.parse_local(args[0])?)) + }, + @call("mir_storage_dead", args) => { + Ok(StatementKind::StorageDead(self.parse_local(args[0])?)) + }, @call("mir_retag", args) => { Ok(StatementKind::Retag(RetagKind::Default, Box::new(self.parse_place(args[0])?))) }, diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs index 399d54f18c5b3..e3157b66902eb 100644 --- a/library/core/src/intrinsics/mir.rs +++ b/library/core/src/intrinsics/mir.rs @@ -259,6 +259,8 @@ define!("mir_unreachable", fn Unreachable() -> BasicBlock); define!("mir_drop", fn Drop(place: T, goto: BasicBlock)); define!("mir_drop_and_replace", fn DropAndReplace(place: T, value: T, goto: BasicBlock)); define!("mir_call", fn Call(place: T, goto: BasicBlock, call: T)); +define!("mir_storage_live", fn StorageLive(local: T)); +define!("mir_storage_dead", fn StorageDead(local: T)); define!("mir_retag", fn Retag(place: T)); define!("mir_move", fn Move(place: T) -> T); define!("mir_static", fn Static(s: T) -> &'static T); diff --git a/tests/mir-opt/building/custom/simple_assign.rs b/tests/mir-opt/building/custom/simple_assign.rs index ec6dbe1d0526b..db041aab239e3 100644 --- a/tests/mir-opt/building/custom/simple_assign.rs +++ b/tests/mir-opt/building/custom/simple_assign.rs @@ -11,12 +11,14 @@ pub fn simple(x: i32) -> i32 { let temp2: _; { + StorageLive(temp1); temp1 = x; Goto(exit) } exit = { temp2 = Move(temp1); + StorageDead(temp1); RET = temp2; Return() } diff --git a/tests/mir-opt/building/custom/simple_assign.simple.built.after.mir b/tests/mir-opt/building/custom/simple_assign.simple.built.after.mir index d7560fde69c95..743016708c583 100644 --- a/tests/mir-opt/building/custom/simple_assign.simple.built.after.mir +++ b/tests/mir-opt/building/custom/simple_assign.simple.built.after.mir @@ -6,13 +6,15 @@ fn simple(_1: i32) -> i32 { let mut _3: i32; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL bb0: { - _2 = _1; // scope 0 at $DIR/simple_assign.rs:+6:13: +6:22 - goto -> bb1; // scope 0 at $DIR/simple_assign.rs:+7:13: +7:23 + StorageLive(_2); // scope 0 at $DIR/simple_assign.rs:+6:13: +6:31 + _2 = _1; // scope 0 at $DIR/simple_assign.rs:+7:13: +7:22 + goto -> bb1; // scope 0 at $DIR/simple_assign.rs:+8:13: +8:23 } bb1: { - _3 = move _2; // scope 0 at $DIR/simple_assign.rs:+11:13: +11:32 - _0 = _3; // scope 0 at $DIR/simple_assign.rs:+12:13: +12:24 - return; // scope 0 at $DIR/simple_assign.rs:+13:13: +13:21 + _3 = move _2; // scope 0 at $DIR/simple_assign.rs:+12:13: +12:32 + StorageDead(_2); // scope 0 at $DIR/simple_assign.rs:+13:13: +13:31 + _0 = _3; // scope 0 at $DIR/simple_assign.rs:+14:13: +14:24 + return; // scope 0 at $DIR/simple_assign.rs:+15:13: +15:21 } } From 42f1f54a5e15616f23d22d09cbdd510ee3d5f789 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 17 Jan 2023 09:39:35 +0000 Subject: [PATCH 171/230] Don't treat closures from other crates as local --- .../src/traits/coherence.rs | 42 +++++++++---------- .../ui/coherence/coherence-with-generator.rs | 8 +++- ... => coherence-with-generator.stock.stderr} | 2 +- .../ui/type-alias-impl-trait/issue-104817.rs | 19 +++++++++ .../issue-104817.stock.stderr | 11 +++++ 5 files changed, 58 insertions(+), 24 deletions(-) rename tests/ui/coherence/{coherence-with-generator.stderr => coherence-with-generator.stock.stderr} (91%) create mode 100644 tests/ui/type-alias-impl-trait/issue-104817.rs create mode 100644 tests/ui/type-alias-impl-trait/issue-104817.stock.stderr diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 0edae34190c30..c8d56db2aa732 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -401,12 +401,12 @@ fn resolve_negative_obligation<'tcx>( infcx.resolve_regions(&outlives_env).is_empty() } +#[instrument(level = "debug", skip(tcx), ret)] pub fn trait_ref_is_knowable<'tcx>( tcx: TyCtxt<'tcx>, trait_ref: ty::TraitRef<'tcx>, ) -> Result<(), Conflict> { - debug!("trait_ref_is_knowable(trait_ref={:?})", trait_ref); - if orphan_check_trait_ref(tcx, trait_ref, InCrate::Remote).is_ok() { + if orphan_check_trait_ref(trait_ref, InCrate::Remote).is_ok() { // A downstream or cousin crate is allowed to implement some // substitution of this trait-ref. return Err(Conflict::Downstream); @@ -429,11 +429,9 @@ pub fn trait_ref_is_knowable<'tcx>( // and if we are an intermediate owner, then we don't care // about future-compatibility, which means that we're OK if // we are an owner. - if orphan_check_trait_ref(tcx, trait_ref, InCrate::Local).is_ok() { - debug!("trait_ref_is_knowable: orphan check passed"); + if orphan_check_trait_ref(trait_ref, InCrate::Local).is_ok() { Ok(()) } else { - debug!("trait_ref_is_knowable: nonlocal, nonfundamental, unowned"); Err(Conflict::Upstream) } } @@ -445,6 +443,7 @@ pub fn trait_ref_is_local_or_fundamental<'tcx>( trait_ref.def_id.krate == LOCAL_CRATE || tcx.has_attr(trait_ref.def_id, sym::fundamental) } +#[derive(Debug)] pub enum OrphanCheckErr<'tcx> { NonLocalInputType(Vec<(Ty<'tcx>, bool /* Is this the first input type? */)>), UncoveredTy(Ty<'tcx>, Option>), @@ -456,13 +455,12 @@ pub enum OrphanCheckErr<'tcx> { /// /// 1. All type parameters in `Self` must be "covered" by some local type constructor. /// 2. Some local type must appear in `Self`. +#[instrument(level = "debug", skip(tcx), ret)] pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanCheckErr<'_>> { - debug!("orphan_check({:?})", impl_def_id); - // We only except this routine to be invoked on implementations // of a trait, not inherent implementations. let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity(); - debug!("orphan_check: trait_ref={:?}", trait_ref); + debug!(?trait_ref); // If the *trait* is local to the crate, ok. if trait_ref.def_id.is_local() { @@ -470,7 +468,7 @@ pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanChe return Ok(()); } - orphan_check_trait_ref(tcx, trait_ref, InCrate::Local) + orphan_check_trait_ref(trait_ref, InCrate::Local) } /// Checks whether a trait-ref is potentially implementable by a crate. @@ -559,13 +557,11 @@ pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanChe /// /// Note that this function is never called for types that have both type /// parameters and inference variables. +#[instrument(level = "trace", ret)] fn orphan_check_trait_ref<'tcx>( - tcx: TyCtxt<'tcx>, trait_ref: ty::TraitRef<'tcx>, in_crate: InCrate, ) -> Result<(), OrphanCheckErr<'tcx>> { - debug!("orphan_check_trait_ref(trait_ref={:?}, in_crate={:?})", trait_ref, in_crate); - if trait_ref.needs_infer() && trait_ref.needs_subst() { bug!( "can't orphan check a trait ref with both params and inference variables {:?}", @@ -573,7 +569,7 @@ fn orphan_check_trait_ref<'tcx>( ); } - let mut checker = OrphanChecker::new(tcx, in_crate); + let mut checker = OrphanChecker::new(in_crate); match trait_ref.visit_with(&mut checker) { ControlFlow::Continue(()) => Err(OrphanCheckErr::NonLocalInputType(checker.non_local_tys)), ControlFlow::Break(OrphanCheckEarlyExit::ParamTy(ty)) => { @@ -592,7 +588,6 @@ fn orphan_check_trait_ref<'tcx>( } struct OrphanChecker<'tcx> { - tcx: TyCtxt<'tcx>, in_crate: InCrate, in_self_ty: bool, /// Ignore orphan check failures and exclusively search for the first @@ -602,9 +597,8 @@ struct OrphanChecker<'tcx> { } impl<'tcx> OrphanChecker<'tcx> { - fn new(tcx: TyCtxt<'tcx>, in_crate: InCrate) -> Self { + fn new(in_crate: InCrate) -> Self { OrphanChecker { - tcx, in_crate, in_self_ty: true, search_first_local_ty: false, @@ -697,13 +691,17 @@ impl<'tcx> TypeVisitor<'tcx> for OrphanChecker<'tcx> { } } ty::Error(_) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)), - ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) => { - self.tcx.sess.delay_span_bug( - DUMMY_SP, - format!("ty_is_local invoked on closure or generator: {:?}", ty), - ); - ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)) + ty::Closure(did, ..) | ty::Generator(did, ..) => { + if self.def_id_is_local(did) { + ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)) + } else { + self.found_non_local_ty(ty) + } } + // This should only be created when checking whether we have to check whether some + // auto trait impl applies. There will never be multiple impls, so we can just + // act as if it were a local type here. + ty::GeneratorWitness(_) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)), ty::Alias(ty::Opaque, ..) => { // This merits some explanation. // Normally, opaque types are not involved when performing diff --git a/tests/ui/coherence/coherence-with-generator.rs b/tests/ui/coherence/coherence-with-generator.rs index 70665ba06f954..5eb8dc2a4687f 100644 --- a/tests/ui/coherence/coherence-with-generator.rs +++ b/tests/ui/coherence/coherence-with-generator.rs @@ -1,5 +1,11 @@ // Test that encountering closures during coherence does not cause issues. #![feature(type_alias_impl_trait, generators)] +#![cfg_attr(specialized, feature(specialization))] +#![allow(incomplete_features)] + +// revisions: stock specialized +// [specialized]check-pass + type OpaqueGenerator = impl Sized; fn defining_use() -> OpaqueGenerator { || { @@ -13,6 +19,6 @@ struct Wrapper(T); trait Trait {} impl Trait for Wrapper {} impl Trait for Wrapper {} -//~^ ERROR conflicting implementations of trait `Trait` for type `Wrapper` +//[stock]~^ ERROR conflicting implementations of trait `Trait` for type `Wrapper` fn main() {} diff --git a/tests/ui/coherence/coherence-with-generator.stderr b/tests/ui/coherence/coherence-with-generator.stock.stderr similarity index 91% rename from tests/ui/coherence/coherence-with-generator.stderr rename to tests/ui/coherence/coherence-with-generator.stock.stderr index 6d3be2e16c657..478ac4912646d 100644 --- a/tests/ui/coherence/coherence-with-generator.stderr +++ b/tests/ui/coherence/coherence-with-generator.stock.stderr @@ -1,5 +1,5 @@ error[E0119]: conflicting implementations of trait `Trait` for type `Wrapper` - --> $DIR/coherence-with-generator.rs:15:1 + --> $DIR/coherence-with-generator.rs:21:1 | LL | impl Trait for Wrapper {} | --------------------------------------- first implementation here diff --git a/tests/ui/type-alias-impl-trait/issue-104817.rs b/tests/ui/type-alias-impl-trait/issue-104817.rs new file mode 100644 index 0000000000000..0d3bace4db1f4 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/issue-104817.rs @@ -0,0 +1,19 @@ +#![feature(type_alias_impl_trait)] +#![cfg_attr(specialized, feature(specialization))] +#![allow(incomplete_features)] + +// revisions: stock specialized +// [specialized]check-pass + +trait OpaqueTrait {} +impl OpaqueTrait for T {} +type OpaqueType = impl OpaqueTrait; +fn mk_opaque() -> OpaqueType { + || 0 +} +trait AnotherTrait {} +impl AnotherTrait for T {} +impl AnotherTrait for OpaqueType {} +//[stock]~^ conflicting implementations of trait `AnotherTrait` for type `OpaqueType` + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/issue-104817.stock.stderr b/tests/ui/type-alias-impl-trait/issue-104817.stock.stderr new file mode 100644 index 0000000000000..47bae8bd12b6b --- /dev/null +++ b/tests/ui/type-alias-impl-trait/issue-104817.stock.stderr @@ -0,0 +1,11 @@ +error[E0119]: conflicting implementations of trait `AnotherTrait` for type `OpaqueType` + --> $DIR/issue-104817.rs:16:1 + | +LL | impl AnotherTrait for T {} + | -------------------------------- first implementation here +LL | impl AnotherTrait for OpaqueType {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `OpaqueType` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. From a7a842027cfdd7ede4d44349d4c15a6b71935fa0 Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Sun, 15 Jan 2023 19:38:31 +0300 Subject: [PATCH 172/230] even more unify Projection/Opaque in outlives code --- .../src/type_check/free_region_relations.rs | 4 +- .../rustc_hir_analysis/src/outlives/utils.rs | 6 +- .../src/infer/error_reporting/mod.rs | 11 +-- .../src/infer/outlives/components.rs | 23 ++---- .../rustc_infer/src/infer/outlives/env.rs | 4 +- .../src/infer/outlives/obligations.rs | 81 +++++-------------- .../rustc_infer/src/infer/outlives/verify.rs | 62 ++++++-------- .../src/infer/region_constraints/mod.rs | 14 +--- compiler/rustc_infer/src/traits/util.rs | 9 ++- compiler/rustc_middle/src/traits/query.rs | 2 +- compiler/rustc_middle/src/ty/sty.rs | 19 ++++- .../src/implied_outlives_bounds.rs | 6 +- 12 files changed, 90 insertions(+), 151 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index 9cf4d8cdf7db4..82ff862479e81 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -359,9 +359,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { .insert(ty::OutlivesPredicate(GenericKind::Param(param_b), r_a)); } - OutlivesBound::RegionSubAlias(r_a, kind, alias_b) => { + OutlivesBound::RegionSubAlias(r_a, alias_b) => { self.region_bound_pairs - .insert(ty::OutlivesPredicate(GenericKind::Alias(kind, alias_b), r_a)); + .insert(ty::OutlivesPredicate(GenericKind::Alias(alias_b), r_a)); } } } diff --git a/compiler/rustc_hir_analysis/src/outlives/utils.rs b/compiler/rustc_hir_analysis/src/outlives/utils.rs index 3f691beec3116..9459c5f54abbf 100644 --- a/compiler/rustc_hir_analysis/src/outlives/utils.rs +++ b/compiler/rustc_hir_analysis/src/outlives/utils.rs @@ -80,7 +80,7 @@ pub(crate) fn insert_outlives_predicate<'tcx>( .or_insert(span); } - Component::Alias(kind, alias) => { + Component::Alias(alias_ty) => { // This would either arise from something like: // // ``` @@ -99,13 +99,13 @@ pub(crate) fn insert_outlives_predicate<'tcx>( // // Here we want to add an explicit `where ::Item: 'a` // or `Opaque: 'a` depending on the alias kind. - let ty: Ty<'tcx> = tcx.mk_ty(ty::Alias(kind, alias)); + let ty = alias_ty.to_ty(tcx); required_predicates .entry(ty::OutlivesPredicate(ty.into(), outlived_region)) .or_insert(span); } - Component::EscapingProjection(_) => { + Component::EscapingAlias(_) => { // As above, but the projection involves // late-bound regions. Therefore, the WF // requirement is not checked in type definition diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 9c38eb6163f56..28fd03b878b2b 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2272,13 +2272,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let labeled_user_string = match bound_kind { GenericKind::Param(ref p) => format!("the parameter type `{}`", p), - GenericKind::Alias(ty::Projection, ref p) => format!("the associated type `{}`", p), - GenericKind::Alias(ty::Opaque, ref p) => { - format!( - "the opaque type `{}`", - self.tcx.def_path_str_with_substs(p.def_id, p.substs) - ) - } + GenericKind::Alias(ref p) => match p.kind(self.tcx) { + ty::AliasKind::Projection => format!("the associated type `{}`", p), + ty::AliasKind::Opaque => format!("the opaque type `{}`", p), + }, }; if let Some(SubregionOrigin::CompareImplItemObligation { diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs index 37907d289a84e..3d86279b03cc6 100644 --- a/compiler/rustc_infer/src/infer/outlives/components.rs +++ b/compiler/rustc_infer/src/infer/outlives/components.rs @@ -22,7 +22,7 @@ pub enum Component<'tcx> { // is not in a position to judge which is the best technique, so // we just product the projection as a component and leave it to // the consumer to decide (but see `EscapingProjection` below). - Alias(ty::AliasKind, ty::AliasTy<'tcx>), + Alias(ty::AliasTy<'tcx>), // In the case where a projection has escaping regions -- meaning // regions bound within the type itself -- we always use @@ -44,7 +44,7 @@ pub enum Component<'tcx> { // projection, so that implied bounds code can avoid relying on // them. This gives us room to improve the regionck reasoning in // the future without breaking backwards compat. - EscapingProjection(Vec>), + EscapingAlias(Vec>), } /// Push onto `out` all the things that must outlive `'a` for the condition @@ -120,17 +120,6 @@ fn compute_components<'tcx>( out.push(Component::Param(p)); } - // Ignore lifetimes found in opaque types. Opaque types can - // have lifetimes in their substs which their hidden type doesn't - // actually use. If we inferred that an opaque type is outlived by - // its parameter lifetimes, then we could prove that any lifetime - // outlives any other lifetime, which is unsound. - // See https://github.com/rust-lang/rust/issues/84305 for - // more details. - ty::Alias(ty::Opaque, data) => { - out.push(Component::Alias(ty::Opaque, data)); - }, - // For projections, we prefer to generate an obligation like // `>::Foo: 'a`, because this gives the // regionck more ways to prove that it holds. However, @@ -139,15 +128,15 @@ fn compute_components<'tcx>( // trait-ref. Therefore, if we see any higher-ranked regions, // we simply fallback to the most restrictive rule, which // requires that `Pi: 'a` for all `i`. - ty::Alias(ty::Projection, data) => { - if !data.has_escaping_bound_vars() { + ty::Alias(_, alias_ty) => { + if !alias_ty.has_escaping_bound_vars() { // best case: no escaping regions, so push the // projection and skip the subtree (thus generating no // constraints for Pi). This defers the choice between // the rules OutlivesProjectionEnv, // OutlivesProjectionTraitDef, and // OutlivesProjectionComponents to regionck. - out.push(Component::Alias(ty::Projection, data)); + out.push(Component::Alias(alias_ty)); } else { // fallback case: hard code // OutlivesProjectionComponents. Continue walking @@ -155,7 +144,7 @@ fn compute_components<'tcx>( let mut subcomponents = smallvec![]; let mut subvisited = SsoHashSet::new(); compute_components_recursive(tcx, ty.into(), &mut subcomponents, &mut subvisited); - out.push(Component::EscapingProjection(subcomponents.into_iter().collect())); + out.push(Component::EscapingAlias(subcomponents.into_iter().collect())); } } diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs index 52c3d97f24111..24e3c34dd94fc 100644 --- a/compiler/rustc_infer/src/infer/outlives/env.rs +++ b/compiler/rustc_infer/src/infer/outlives/env.rs @@ -138,9 +138,9 @@ impl<'tcx> OutlivesEnvironmentBuilder<'tcx> { self.region_bound_pairs .insert(ty::OutlivesPredicate(GenericKind::Param(param_b), r_a)); } - OutlivesBound::RegionSubAlias(r_a, kind, projection_b) => { + OutlivesBound::RegionSubAlias(r_a, alias_b) => { self.region_bound_pairs - .insert(ty::OutlivesPredicate(GenericKind::Alias(kind, projection_b), r_a)); + .insert(ty::OutlivesPredicate(GenericKind::Alias(alias_b), r_a)); } OutlivesBound::RegionSubRegion(r_a, r_b) => { if let (ReEarlyBound(_) | ReFree(_), ReVar(vid_b)) = (r_a.kind(), r_b.kind()) { diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 77de335e7f547..0194549a8868d 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -67,7 +67,6 @@ use crate::infer::{ }; use crate::traits::{ObligationCause, ObligationCauseCode}; use rustc_data_structures::undo_log::UndoLogs; -use rustc_hir::def_id::DefId; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, Region, SubstsRef, Ty, TyCtxt, TypeVisitable}; @@ -266,10 +265,8 @@ where Component::Param(param_ty) => { self.param_ty_must_outlive(origin, region, *param_ty); } - Component::Alias(kind, data) => { - self.alias_must_outlive(*kind, *data, origin, region) - } - Component::EscapingProjection(subcomponents) => { + Component::Alias(alias_ty) => self.alias_ty_must_outlive(origin, region, *alias_ty), + Component::EscapingAlias(subcomponents) => { self.components_must_outlive(origin, &subcomponents, region, category); } Component::UnresolvedInferenceVariable(v) => { @@ -285,61 +282,26 @@ where } } + #[instrument(level = "debug", skip(self))] fn param_ty_must_outlive( &mut self, origin: infer::SubregionOrigin<'tcx>, region: ty::Region<'tcx>, param_ty: ty::ParamTy, ) { - debug!( - "param_ty_must_outlive(region={:?}, param_ty={:?}, origin={:?})", - region, param_ty, origin - ); - - let generic = GenericKind::Param(param_ty); let verify_bound = self.verify_bound.param_bound(param_ty); - self.delegate.push_verify(origin, generic, region, verify_bound); + self.delegate.push_verify(origin, GenericKind::Param(param_ty), region, verify_bound); } #[instrument(level = "debug", skip(self))] - fn alias_must_outlive( + fn alias_ty_must_outlive( &mut self, - kind: ty::AliasKind, - data: ty::AliasTy<'tcx>, origin: infer::SubregionOrigin<'tcx>, region: ty::Region<'tcx>, - ) { - self.generic_must_outlive( - origin, - region, - GenericKind::Alias(kind, data), - data.def_id, - data.substs, - kind == ty::Opaque, - |ty| match *ty.kind() { - ty::Alias(filter_kind, ty::AliasTy { def_id, substs, .. }) - if kind == filter_kind => - { - (def_id, substs) - } - _ => bug!("expected only projection types from env, not {:?}", ty), - }, - ); - } - - #[instrument(level = "debug", skip(self, filter))] - fn generic_must_outlive( - &mut self, - origin: infer::SubregionOrigin<'tcx>, - region: ty::Region<'tcx>, - generic: GenericKind<'tcx>, - def_id: DefId, - substs: SubstsRef<'tcx>, - is_opaque: bool, - filter: impl Fn(Ty<'tcx>) -> (DefId, SubstsRef<'tcx>), + alias_ty: ty::AliasTy<'tcx>, ) { // An optimization for a common case with opaque types. - if substs.is_empty() { + if alias_ty.substs.is_empty() { return; } @@ -361,14 +323,14 @@ where // These are guaranteed to apply, no matter the inference // results. let trait_bounds: Vec<_> = - self.verify_bound.declared_region_bounds(def_id, substs).collect(); + self.verify_bound.declared_bounds_from_definition(alias_ty).collect(); debug!(?trait_bounds); // Compute the bounds we can derive from the environment. This // is an "approximate" match -- in some cases, these bounds // may not apply. - let mut approx_env_bounds = self.verify_bound.approx_declared_bounds_from_env(generic); + let mut approx_env_bounds = self.verify_bound.approx_declared_bounds_from_env(alias_ty); debug!(?approx_env_bounds); // Remove outlives bounds that we get from the environment but @@ -383,8 +345,8 @@ where // If the declaration is `trait Trait<'b> { type Item: 'b; }`, then `projection_declared_bounds_from_trait` // will be invoked with `['b => ^1]` and so we will get `^1` returned. let bound = bound_outlives.skip_binder(); - let (def_id, substs) = filter(bound.0); - self.verify_bound.declared_region_bounds(def_id, substs).all(|r| r != bound.1) + let ty::Alias(_, alias_ty) = bound.0.kind() else { bug!("expected AliasTy") }; + self.verify_bound.declared_bounds_from_definition(*alias_ty).all(|r| r != bound.1) }); // If declared bounds list is empty, the only applicable rule is @@ -401,12 +363,12 @@ where // the problem is to add `T: 'r`, which isn't true. So, if there are no // inference variables, we use a verify constraint instead of adding // edges, which winds up enforcing the same condition. - let needs_infer = substs.needs_infer(); - if approx_env_bounds.is_empty() && trait_bounds.is_empty() && (needs_infer || is_opaque) { + if approx_env_bounds.is_empty() + && trait_bounds.is_empty() + && (alias_ty.needs_infer() || alias_ty.kind(self.tcx) == ty::Opaque) + { debug!("no declared bounds"); - - self.substs_must_outlive(substs, origin, region); - + self.substs_must_outlive(alias_ty.substs, origin, region); return; } @@ -447,14 +409,9 @@ where // projection outlive; in some cases, this may add insufficient // edges into the inference graph, leading to inference failures // even though a satisfactory solution exists. - let verify_bound = self.verify_bound.projection_opaque_bounds( - generic, - def_id, - substs, - &mut Default::default(), - ); - debug!("projection_must_outlive: pushing {:?}", verify_bound); - self.delegate.push_verify(origin, generic, region, verify_bound); + let verify_bound = self.verify_bound.alias_bound(alias_ty, &mut Default::default()); + debug!("alias_must_outlive: pushing {:?}", verify_bound); + self.delegate.push_verify(origin, GenericKind::Alias(alias_ty), region, verify_bound); } fn substs_must_outlive( diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index 56695a87b7c05..94de9bc2d0228 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -1,11 +1,10 @@ use crate::infer::outlives::components::{compute_components_recursive, Component}; use crate::infer::outlives::env::RegionBoundPairs; use crate::infer::region_constraints::VerifyIfEq; -use crate::infer::{GenericKind, VerifyBound}; +use crate::infer::VerifyBound; use rustc_data_structures::sso::SsoHashSet; -use rustc_hir::def_id::DefId; use rustc_middle::ty::GenericArg; -use rustc_middle::ty::{self, OutlivesPredicate, SubstsRef, Ty, TyCtxt}; +use rustc_middle::ty::{self, OutlivesPredicate, Ty, TyCtxt}; use smallvec::smallvec; @@ -94,29 +93,26 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { /// this list. pub fn approx_declared_bounds_from_env( &self, - generic: GenericKind<'tcx>, + alias_ty: ty::AliasTy<'tcx>, ) -> Vec, ty::Region<'tcx>>>> { - let projection_ty = generic.to_ty(self.tcx); - let erased_projection_ty = self.tcx.erase_regions(projection_ty); - self.declared_generic_bounds_from_env_for_erased_ty(erased_projection_ty) + let erased_alias_ty = self.tcx.erase_regions(alias_ty.to_ty(self.tcx)); + self.declared_generic_bounds_from_env_for_erased_ty(erased_alias_ty) } #[instrument(level = "debug", skip(self, visited))] - pub fn projection_opaque_bounds( + pub fn alias_bound( &self, - generic: GenericKind<'tcx>, - def_id: DefId, - substs: SubstsRef<'tcx>, + alias_ty: ty::AliasTy<'tcx>, visited: &mut SsoHashSet>, ) -> VerifyBound<'tcx> { - let generic_ty = generic.to_ty(self.tcx); + let alias_ty_as_ty = alias_ty.to_ty(self.tcx); // Search the env for where clauses like `P: 'a`. - let projection_opaque_bounds = self - .approx_declared_bounds_from_env(generic) + let env_bounds = self + .approx_declared_bounds_from_env(alias_ty) .into_iter() .map(|binder| { - if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars() && ty == generic_ty { + if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars() && ty == alias_ty_as_ty { // Micro-optimize if this is an exact match (this // occurs often when there are no region variables // involved). @@ -126,19 +122,19 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { VerifyBound::IfEq(verify_if_eq_b) } }); - // Extend with bounds that we can find from the trait. - let trait_bounds = - self.declared_region_bounds(def_id, substs).map(|r| VerifyBound::OutlivedBy(r)); + + // Extend with bounds that we can find from the definition. + let definition_bounds = + self.declared_bounds_from_definition(alias_ty).map(|r| VerifyBound::OutlivedBy(r)); // see the extensive comment in projection_must_outlive let recursive_bound = { let mut components = smallvec![]; - compute_components_recursive(self.tcx, generic_ty.into(), &mut components, visited); + compute_components_recursive(self.tcx, alias_ty_as_ty.into(), &mut components, visited); self.bound_from_components(&components, visited) }; - VerifyBound::AnyBound(projection_opaque_bounds.chain(trait_bounds).collect()) - .or(recursive_bound) + VerifyBound::AnyBound(env_bounds.chain(definition_bounds).collect()).or(recursive_bound) } fn bound_from_components( @@ -149,10 +145,8 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { let mut bounds = components .iter() .map(|component| self.bound_from_single_component(component, visited)) - .filter(|bound| { - // Remove bounds that must hold, since they are not interesting. - !bound.must_hold() - }); + // Remove bounds that must hold, since they are not interesting. + .filter(|bound| !bound.must_hold()); match (bounds.next(), bounds.next()) { (Some(first), None) => first, @@ -170,13 +164,8 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { match *component { Component::Region(lt) => VerifyBound::OutlivedBy(lt), Component::Param(param_ty) => self.param_bound(param_ty), - Component::Alias(kind, data) => self.projection_opaque_bounds( - GenericKind::Alias(kind, data), - data.def_id, - data.substs, - visited, - ), - Component::EscapingProjection(ref components) => { + Component::Alias(alias_ty) => self.alias_bound(alias_ty, visited), + Component::EscapingAlias(ref components) => { self.bound_from_components(components, visited) } Component::UnresolvedInferenceVariable(v) => { @@ -292,16 +281,15 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { /// /// This is for simplicity, and because we are not really smart /// enough to cope with such bounds anywhere. - pub fn declared_region_bounds( + pub fn declared_bounds_from_definition( &self, - def_id: DefId, - substs: SubstsRef<'tcx>, + alias_ty: ty::AliasTy<'tcx>, ) -> impl Iterator> { let tcx = self.tcx; - let bounds = tcx.item_bounds(def_id); + let bounds = tcx.item_bounds(alias_ty.def_id); trace!("{:#?}", bounds.0); bounds - .subst_iter(tcx, substs) + .subst_iter(tcx, alias_ty.substs) .filter_map(|p| p.to_opt_type_outlives()) .filter_map(|p| p.no_bound_vars()) .map(|OutlivesPredicate(_, r)| r) diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index fda5ffe784678..0428481b7ff02 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -167,7 +167,7 @@ pub struct Verify<'tcx> { #[derive(Copy, Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)] pub enum GenericKind<'tcx> { Param(ty::ParamTy), - Alias(ty::AliasKind, ty::AliasTy<'tcx>), + Alias(ty::AliasTy<'tcx>), } /// Describes the things that some `GenericKind` value `G` is known to @@ -746,10 +746,7 @@ impl<'tcx> fmt::Debug for GenericKind<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { GenericKind::Param(ref p) => write!(f, "{:?}", p), - GenericKind::Alias(ty::Projection, ref p) => write!(f, "{:?}", p), - GenericKind::Alias(ty::Opaque, ref p) => ty::tls::with(|tcx| { - write!(f, "{}", tcx.def_path_str_with_substs(p.def_id, tcx.lift(p.substs).unwrap())) - }), + GenericKind::Alias(ref p) => write!(f, "{:?}", p), } } } @@ -758,10 +755,7 @@ impl<'tcx> fmt::Display for GenericKind<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { GenericKind::Param(ref p) => write!(f, "{}", p), - GenericKind::Alias(ty::Projection, ref p) => write!(f, "{}", p), - GenericKind::Alias(ty::Opaque, ref p) => ty::tls::with(|tcx| { - write!(f, "{}", tcx.def_path_str_with_substs(p.def_id, tcx.lift(p.substs).unwrap())) - }), + GenericKind::Alias(ref p) => write!(f, "{}", p), } } } @@ -770,7 +764,7 @@ impl<'tcx> GenericKind<'tcx> { pub fn to_ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { match *self { GenericKind::Param(ref p) => p.to_ty(tcx), - GenericKind::Alias(kind, data) => tcx.mk_ty(ty::Alias(kind, data)), + GenericKind::Alias(ref p) => p.to_ty(tcx), } } } diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 4ada7b22d084c..cd5bde2a79130 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -261,14 +261,15 @@ impl<'tcx> Elaborator<'tcx> { Component::UnresolvedInferenceVariable(_) => None, - Component::Alias(kind, data) => { - let ty = tcx.mk_ty(ty::Alias(kind, data)); + Component::Alias(alias_ty) => { + // We might end up here if we have `Foo<::Assoc>: 'a`. + // With this, we can deduce that `::Assoc: 'a`. Some(ty::PredicateKind::Clause(ty::Clause::TypeOutlives( - ty::OutlivesPredicate(ty, r_min), + ty::OutlivesPredicate(alias_ty.to_ty(tcx), r_min), ))) } - Component::EscapingProjection(_) => { + Component::EscapingAlias(_) => { // We might be able to do more here, but we don't // want to deal with escaping vars right now. None diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index 2a68315fefc56..615154a55e586 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -213,5 +213,5 @@ pub struct NormalizationResult<'tcx> { pub enum OutlivesBound<'tcx> { RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>), RegionSubParam(ty::Region<'tcx>, ty::ParamTy), - RegionSubAlias(ty::Region<'tcx>, ty::AliasKind, ty::AliasTy<'tcx>), + RegionSubAlias(ty::Region<'tcx>, ty::AliasTy<'tcx>), } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index a128e9025fd69..6a7b23e40a779 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1245,11 +1245,26 @@ pub struct AliasTy<'tcx> { /// aka. `tcx.parent(def_id)`. pub def_id: DefId, - /// This field exists to prevent the creation of `ProjectionTy` without using + /// This field exists to prevent the creation of `AliasTy` without using /// [TyCtxt::mk_alias_ty]. pub(super) _use_mk_alias_ty_instead: (), } +impl<'tcx> AliasTy<'tcx> { + pub fn kind(self, tcx: TyCtxt<'tcx>) -> ty::AliasKind { + match tcx.def_kind(self.def_id) { + DefKind::AssocTy | DefKind::ImplTraitPlaceholder => ty::Projection, + DefKind::OpaqueTy => ty::Opaque, + kind => bug!("unexpected DefKind in AliasTy: {kind:?}"), + } + } + + pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + tcx.mk_ty(ty::Alias(self.kind(tcx), self)) + } +} + +/// The following methods work only with associated type projections. impl<'tcx> AliasTy<'tcx> { pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId { match tcx.def_kind(self.def_id) { @@ -1257,7 +1272,7 @@ impl<'tcx> AliasTy<'tcx> { DefKind::ImplTraitPlaceholder => { tcx.parent(tcx.impl_trait_in_trait_parent(self.def_id)) } - kind => bug!("unexpected DefKind in ProjectionTy: {kind:?}"), + kind => bug!("expected a projection AliasTy; found {kind:?}"), } } diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index d457a4a2beaf5..7d2d8433c932d 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -154,10 +154,8 @@ fn implied_bounds_from_components<'tcx>( match component { Component::Region(r) => Some(OutlivesBound::RegionSubRegion(sub_region, r)), Component::Param(p) => Some(OutlivesBound::RegionSubParam(sub_region, p)), - Component::Alias(kind, p) => { - Some(OutlivesBound::RegionSubAlias(sub_region, kind, p)) - } - Component::EscapingProjection(_) => + Component::Alias(p) => Some(OutlivesBound::RegionSubAlias(sub_region, p)), + Component::EscapingAlias(_) => // If the projection has escaping regions, don't // try to infer any implied bounds even for its // free components. This is conservative, because From e40567b2cf50c4694c75b1ac34aff6108e529700 Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Mon, 16 Jan 2023 01:35:51 +0300 Subject: [PATCH 173/230] add test for ICE fix --- .../outlives-bound-var.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 tests/ui/type-alias-impl-trait/outlives-bound-var.rs diff --git a/tests/ui/type-alias-impl-trait/outlives-bound-var.rs b/tests/ui/type-alias-impl-trait/outlives-bound-var.rs new file mode 100644 index 0000000000000..b8fac45b76db7 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/outlives-bound-var.rs @@ -0,0 +1,18 @@ +// Here we process outlive obligations involving +// opaque types with bound vars in substs. +// This was an ICE. +// +// check-pass +#![feature(type_alias_impl_trait)] + +type Ty<'a> = impl Sized + 'a; +fn define<'a>() -> Ty<'a> {} + +// Ty<'^0>: 'static +fn test1(_: &'static fn(Ty<'_>)) {} + +fn test2() { + None::<&fn(Ty<'_>)>; +} + +fn main() { } From cc5af33d64a6c80a7a54e0f0071ebcffc00ca4f0 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Thu, 19 Jan 2023 13:52:15 +0100 Subject: [PATCH 174/230] Autoderive ExternBlockSuggestion --- .../rustc_ast_passes/src/ast_validation.rs | 15 +++---- compiler/rustc_ast_passes/src/errors.rs | 42 ++++++++----------- .../locales/en-US/ast_passes.ftl | 3 +- 3 files changed, 27 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 55ea12d25ea2c..902b4b1a1ecfe 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1100,16 +1100,17 @@ impl<'a> Visitor<'a> for AstValidator<'a> { replace_span: self.ending_semi_or_hi(item.span), extern_block_suggestion: match sig.header.ext { Extern::None => None, - Extern::Implicit(start_span) => Some(ExternBlockSuggestion { + Extern::Implicit(start_span) => Some(ExternBlockSuggestion::Implicit { start_span, end_span: item.span.shrink_to_hi(), - abi: None, - }), - Extern::Explicit(abi, start_span) => Some(ExternBlockSuggestion { - start_span, - end_span: item.span.shrink_to_hi(), - abi: Some(abi.symbol_unescaped), }), + Extern::Explicit(abi, start_span) => { + Some(ExternBlockSuggestion::Explicit { + start_span, + end_span: item.span.shrink_to_hi(), + abi: abi.symbol_unescaped, + }) + } }, }); } diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 59f582f10d989..09e262452b11d 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -1,6 +1,5 @@ //! Errors emitted by ast_passes. -use rustc_errors::{fluent, AddToDiagnostic, Applicability, Diagnostic, SubdiagnosticMessage}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; @@ -207,28 +206,21 @@ pub struct FnWithoutBody { pub extern_block_suggestion: Option, } -pub struct ExternBlockSuggestion { - pub start_span: Span, - pub end_span: Span, - pub abi: Option, -} - -impl AddToDiagnostic for ExternBlockSuggestion { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { - let start_suggestion = if let Some(abi) = self.abi { - format!("extern \"{}\" {{", abi) - } else { - "extern {".to_owned() - }; - let end_suggestion = " }".to_owned(); - - diag.multipart_suggestion( - fluent::extern_block_suggestion, - vec![(self.start_span, start_suggestion), (self.end_span, end_suggestion)], - Applicability::MaybeIncorrect, - ); - } +#[derive(Subdiagnostic)] +pub enum ExternBlockSuggestion { + #[multipart_suggestion(ast_passes_extern_block_suggestion, applicability = "maybe-incorrect")] + Implicit { + #[suggestion_part(code = "extern {{")] + start_span: Span, + #[suggestion_part(code = " }}")] + end_span: Span, + }, + #[multipart_suggestion(ast_passes_extern_block_suggestion, applicability = "maybe-incorrect")] + Explicit { + #[suggestion_part(code = "extern \"{abi}\" {{")] + start_span: Span, + #[suggestion_part(code = " }}")] + end_span: Span, + abi: Symbol, + }, } diff --git a/compiler/rustc_error_messages/locales/en-US/ast_passes.ftl b/compiler/rustc_error_messages/locales/en-US/ast_passes.ftl index e5cd1142b20c8..5f28839f136d6 100644 --- a/compiler/rustc_error_messages/locales/en-US/ast_passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/ast_passes.ftl @@ -88,4 +88,5 @@ ast_passes_ty_alias_without_body = ast_passes_fn_without_body = free function without a body .suggestion = provide a definition for the function - .extern_block_suggestion = if you meant to declare an externally defined function, use an `extern` block + +ast_passes_extern_block_suggestion = if you meant to declare an externally defined function, use an `extern` block From be02a4a23d714834248de96a7a9df81228ae0122 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Thu, 19 Jan 2023 14:18:36 +0000 Subject: [PATCH 175/230] Update cargo 3 commits in a5d47a72595dd6fbe7d4e4f6ec20dc5fe724edd1..50eb688c2bbea5de5a2e8496230a7428798089d1 2023-01-16 18:51:50 +0000 to 2023-01-19 10:09:05 +0000 - Normalize git deps when doing `cargo vendor` for resolving deps inherited from a workspace (rust-lang/cargo#11414) - Ignore `workspace.default-members` when running `cargo install` on root package of a non-virtual workspace (rust-lang/cargo#11067) - Corrected documentation of how to cache binaries installed with `cargo install` in CI workflows (rust-lang/cargo#11592) --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index a5d47a72595dd..50eb688c2bbea 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit a5d47a72595dd6fbe7d4e4f6ec20dc5fe724edd1 +Subproject commit 50eb688c2bbea5de5a2e8496230a7428798089d1 From 8657cb8efe934501f4ac316bbde0ac4daa1f0d0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrik=20K=C3=A5rlin?= Date: Thu, 19 Jan 2023 15:39:05 +0100 Subject: [PATCH 176/230] Added UI test case for issue #106419 --- ...issue-106419-struct-with-multiple-const-params.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/ui/const-generics/issue-106419-struct-with-multiple-const-params.rs diff --git a/tests/ui/const-generics/issue-106419-struct-with-multiple-const-params.rs b/tests/ui/const-generics/issue-106419-struct-with-multiple-const-params.rs new file mode 100644 index 0000000000000..8363e5af4b61c --- /dev/null +++ b/tests/ui/const-generics/issue-106419-struct-with-multiple-const-params.rs @@ -0,0 +1,12 @@ +// check-pass +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +#[derive(Clone)] +struct Bar +where + [(); A as usize]:, + [(); B as usize]:, +{} + +fn main() {} From 280f69d8585b676b0441cdb476634882ebe1b983 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 19 Jan 2023 15:24:00 +0000 Subject: [PATCH 177/230] Fix IndexVec::drain_enumerated --- compiler/rustc_index/src/vec.rs | 7 ++++++- .../src/solve/trait_goals/structural_traits.rs | 15 +++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index c18a911b2fbcd..68cdc6d7711d4 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -207,7 +207,12 @@ impl IndexVec { &'a mut self, range: R, ) -> impl Iterator + 'a { - self.raw.drain(range).enumerate().map(|(n, t)| (I::new(n), t)) + let begin = match range.start_bound() { + std::ops::Bound::Included(i) => *i, + std::ops::Bound::Excluded(i) => i.checked_add(1).unwrap(), + std::ops::Bound::Unbounded => 0, + }; + self.raw.drain(range).enumerate().map(move |(n, t)| (I::new(begin + n), t)) } #[inline] diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs index bbc0c77253278..2c75d0907b739 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs @@ -30,10 +30,7 @@ pub(super) fn instantiate_constituent_tys_for_auto_trait<'tcx>( | ty::Foreign(..) | ty::Alias(ty::Projection, ..) | ty::Bound(..) - | ty::Infer(ty::TyVar(_)) => { - // FIXME: Do we need to mark anything as ambiguous here? Yeah? - Err(NoSolution) - } + | ty::Infer(ty::TyVar(_)) => Err(NoSolution), ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), @@ -101,9 +98,8 @@ pub(super) fn instantiate_constituent_tys_for_sized_trait<'tcx>( | ty::Dynamic(..) | ty::Foreign(..) | ty::Alias(..) - | ty::Param(_) => Err(NoSolution), - - ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"), + | ty::Param(_) + | ty::Infer(ty::TyVar(_)) => Err(NoSolution), ty::Placeholder(..) | ty::Bound(..) @@ -151,9 +147,8 @@ pub(super) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( | ty::Ref(_, _, Mutability::Mut) | ty::Adt(_, _) | ty::Alias(_, _) - | ty::Param(_) => Err(NoSolution), - - ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"), + | ty::Param(_) + | ty::Infer(ty::TyVar(_)) => Err(NoSolution), ty::Placeholder(..) | ty::Bound(..) From c9c8e294d2b6fc7c83641476f4986a7bf5e84817 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 19 Jan 2023 03:26:54 +0000 Subject: [PATCH 178/230] HACK: self ty ambiguity hack --- compiler/rustc_trait_selection/src/solve/assembly.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs index 2336fb53aec28..2c92e7eb9ad3f 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -1,7 +1,7 @@ //! Code shared by trait and projection goals for candidate assembly. use super::infcx_ext::InferCtxtExt; -use super::{CanonicalResponse, EvalCtxt, Goal, QueryResult}; +use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, MaybeCause, QueryResult}; use rustc_hir::def_id::DefId; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::util::elaborate_predicates; @@ -124,6 +124,16 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { &mut self, goal: Goal<'tcx, G>, ) -> Vec> { + // HACK: `_: Trait` is ambiguous, because it may be satisfied via a builtin rule, + // object bound, alias bound, etc. We are unable to determine this until we can at + // least structually resolve the type one layer. + if goal.predicate.self_ty().is_ty_var() { + return vec![Candidate { + source: CandidateSource::BuiltinImpl, + result: self.make_canonical_response(Certainty::Maybe(MaybeCause::Ambiguity)).unwrap(), + }]; + } + let mut candidates = Vec::new(); self.assemble_candidates_after_normalizing_self_ty(goal, &mut candidates); From 97cf1713d19d01666bf4613fae51eacce3974640 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Sat, 14 Jan 2023 21:16:25 +0000 Subject: [PATCH 179/230] Add enum for fieldless unification --- .../src/deriving/clone.rs | 6 +- .../src/deriving/cmp/eq.rs | 2 +- .../src/deriving/cmp/ord.rs | 2 +- .../src/deriving/cmp/partial_eq.rs | 2 +- .../src/deriving/cmp/partial_ord.rs | 2 +- .../src/deriving/debug.rs | 9 +- .../src/deriving/decodable.rs | 2 +- .../src/deriving/default.rs | 2 +- .../src/deriving/encodable.rs | 2 +- .../src/deriving/generic/mod.rs | 90 +++++++++++++------ .../rustc_builtin_macros/src/deriving/hash.rs | 2 +- 11 files changed, 78 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index d59b3b8c86d35..bc7e8b6a22314 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -82,7 +82,7 @@ pub fn expand_deriving_clone( nonself_args: Vec::new(), ret_ty: Self_, attributes: attrs, - unify_fieldless_variants: false, + fieldless_variants_strategy: FieldlessVariantsStrategy::Default, combine_substructure: substructure, }], associated_types: Vec::new(), @@ -177,7 +177,9 @@ fn cs_clone( all_fields = af; vdata = &variant.data; } - EnumTag(..) => cx.span_bug(trait_span, &format!("enum tags in `derive({})`", name,)), + EnumTag(..) | AllFieldlessEnum(..) => { + cx.span_bug(trait_span, &format!("enum tags in `derive({})`", name,)) + } StaticEnum(..) | StaticStruct(..) => { cx.span_bug(trait_span, &format!("associated function in `derive({})`", name)) } diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs index f861d47ed408e..3e994f037ad7a 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs @@ -36,7 +36,7 @@ pub fn expand_deriving_eq( nonself_args: vec![], ret_ty: Unit, attributes: attrs, - unify_fieldless_variants: true, + fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, combine_substructure: combine_substructure(Box::new(|a, b, c| { cs_total_eq_assert(a, b, c) })), diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs index 96d18c7afb924..a926fca4e65f8 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs @@ -29,7 +29,7 @@ pub fn expand_deriving_ord( nonself_args: vec![(self_ref(), sym::other)], ret_ty: Path(path_std!(cmp::Ordering)), attributes: attrs, - unify_fieldless_variants: true, + fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, combine_substructure: combine_substructure(Box::new(|a, b, c| cs_cmp(a, b, c))), }], associated_types: Vec::new(), diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs index 7f95551fc483a..9051fe0b28abe 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -76,7 +76,7 @@ pub fn expand_deriving_partial_eq( nonself_args: vec![(self_ref(), sym::other)], ret_ty: Path(path_local!(bool)), attributes: attrs, - unify_fieldless_variants: true, + fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, combine_substructure: combine_substructure(Box::new(|a, b, c| cs_eq(a, b, c))), }]; diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs index 5c4e5b7f81675..c9dc89212622d 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -28,7 +28,7 @@ pub fn expand_deriving_partial_ord( nonself_args: vec![(self_ref(), sym::other)], ret_ty, attributes: attrs, - unify_fieldless_variants: true, + fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, combine_substructure: combine_substructure(Box::new(|cx, span, substr| { cs_partial_cmp(cx, span, substr) })), diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index 5b1b7e6804c86..a586964d0c321 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -31,7 +31,7 @@ pub fn expand_deriving_debug( nonself_args: vec![(fmtr, sym::f)], ret_ty: Path(path_std!(fmt::Result)), attributes: ast::AttrVec::new(), - unify_fieldless_variants: false, + fieldless_variants_strategy: FieldlessVariantsStrategy::Default, combine_substructure: combine_substructure(Box::new(|a, b, c| { show_substructure(a, b, c) })), @@ -43,16 +43,17 @@ pub fn expand_deriving_debug( } fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr { + // We want to make sure we have the ctxt set so that we can use unstable methods + let span = cx.with_def_site_ctxt(span); + let (ident, vdata, fields) = match substr.fields { Struct(vdata, fields) => (substr.type_ident, *vdata, fields), EnumMatching(_, _, v, fields) => (v.ident, &v.data, fields), - EnumTag(..) | StaticStruct(..) | StaticEnum(..) => { + AllFieldlessEnum(..) | EnumTag(..) | StaticStruct(..) | StaticEnum(..) => { cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`") } }; - // We want to make sure we have the ctxt set so that we can use unstable methods - let span = cx.with_def_site_ctxt(span); let name = cx.expr_str(span, ident.name); let fmt = substr.nonselflike_args[0].clone(); diff --git a/compiler/rustc_builtin_macros/src/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs index 62af02c2bb4b2..5f9519dad1b25 100644 --- a/compiler/rustc_builtin_macros/src/deriving/decodable.rs +++ b/compiler/rustc_builtin_macros/src/deriving/decodable.rs @@ -49,7 +49,7 @@ pub fn expand_deriving_rustc_decodable( PathKind::Std, )), attributes: ast::AttrVec::new(), - unify_fieldless_variants: false, + fieldless_variants_strategy: FieldlessVariantsStrategy::Default, combine_substructure: combine_substructure(Box::new(|a, b, c| { decodable_substructure(a, b, c, krate) })), diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index eb66c4a69a69b..18270747296b8 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -34,7 +34,7 @@ pub fn expand_deriving_default( nonself_args: Vec::new(), ret_ty: Self_, attributes: attrs, - unify_fieldless_variants: false, + fieldless_variants_strategy: FieldlessVariantsStrategy::Default, combine_substructure: combine_substructure(Box::new(|cx, trait_span, substr| { match substr.fields { StaticStruct(_, fields) => { diff --git a/compiler/rustc_builtin_macros/src/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs index 68bc0ff2ec0b4..2afeed927ac2c 100644 --- a/compiler/rustc_builtin_macros/src/deriving/encodable.rs +++ b/compiler/rustc_builtin_macros/src/deriving/encodable.rs @@ -133,7 +133,7 @@ pub fn expand_deriving_rustc_encodable( PathKind::Std, )), attributes: AttrVec::new(), - unify_fieldless_variants: false, + fieldless_variants_strategy: FieldlessVariantsStrategy::Default, combine_substructure: combine_substructure(Box::new(|a, b, c| { encodable_substructure(a, b, c, krate) })), diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index beac591bfc879..17b7ac0eba120 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -222,14 +222,27 @@ pub struct MethodDef<'a> { pub attributes: ast::AttrVec, - /// Can we combine fieldless variants for enums into a single match arm? - /// If true, indicates that the trait operation uses the enum tag in some - /// way. - pub unify_fieldless_variants: bool, + pub fieldless_variants_strategy: FieldlessVariantsStrategy, pub combine_substructure: RefCell>, } +/// How to handle fieldless enum variants. +#[derive(PartialEq)] +pub enum FieldlessVariantsStrategy { + /// Combine fieldless variants into a single match arm. + /// This assumes that relevant information has been handled + /// by looking at the enum's discriminant. + Unify, + /// Don't do anything special about fieldless variants. They are + /// handled like any other variant. + Default, + /// If all variants of the enum are fieldless, expand the special + /// `AllFieldLessEnum` substructure, so that the entire enum can be handled + /// at once. + SpecializeIfAllVariantsFieldless, +} + /// All the data about the data structure/method being derived upon. pub struct Substructure<'a> { /// ident of self @@ -264,9 +277,14 @@ pub enum StaticFields { /// A summary of the possible sets of fields. pub enum SubstructureFields<'a> { - /// A non-static method with `Self` is a struct. + /// A non-static method where `Self` is a struct. Struct(&'a ast::VariantData, Vec), + /// A non-static method handling the entire enum at once + /// (after it has been determined that none of the enum + /// variants has any fields). + AllFieldlessEnum(&'a ast::EnumDef), + /// Matching variants of the enum: variant index, variant count, ast::Variant, /// fields: the field name is only non-`None` in the case of a struct /// variant. @@ -1086,8 +1104,8 @@ impl<'a> MethodDef<'a> { /// ``` /// Creates a tag check combined with a match for a tuple of all /// `selflike_args`, with an arm for each variant with fields, possibly an - /// arm for each fieldless variant (if `!unify_fieldless_variants` is not - /// true), and possibly a default arm. + /// arm for each fieldless variant (if `unify_fieldless_variants` is not + /// `Unify`), and possibly a default arm. fn expand_enum_method_body<'b>( &self, cx: &mut ExtCtxt<'_>, @@ -1101,7 +1119,8 @@ impl<'a> MethodDef<'a> { let variants = &enum_def.variants; // Traits that unify fieldless variants always use the tag(s). - let uses_tags = self.unify_fieldless_variants; + let unify_fieldless_variants = + self.fieldless_variants_strategy == FieldlessVariantsStrategy::Unify; // There is no sensible code to be generated for *any* deriving on a // zero-variant enum. So we just generate a failing expression. @@ -1161,23 +1180,35 @@ impl<'a> MethodDef<'a> { // match is necessary. let all_fieldless = variants.iter().all(|v| v.data.fields().is_empty()); if all_fieldless { - if uses_tags && variants.len() > 1 { - // If the type is fieldless and the trait uses the tag and - // there are multiple variants, we need just an operation on - // the tag(s). - let (tag_field, mut tag_let_stmts) = get_tag_pieces(cx); - let mut tag_check = self.call_substructure_method( - cx, - trait_, - type_ident, - nonselflike_args, - &EnumTag(tag_field, None), - ); - tag_let_stmts.append(&mut tag_check.0); - return BlockOrExpr(tag_let_stmts, tag_check.1); - } - - if variants.len() == 1 { + if variants.len() > 1 { + match self.fieldless_variants_strategy { + FieldlessVariantsStrategy::Unify => { + // If the type is fieldless and the trait uses the tag and + // there are multiple variants, we need just an operation on + // the tag(s). + let (tag_field, mut tag_let_stmts) = get_tag_pieces(cx); + let mut tag_check = self.call_substructure_method( + cx, + trait_, + type_ident, + nonselflike_args, + &EnumTag(tag_field, None), + ); + tag_let_stmts.append(&mut tag_check.0); + return BlockOrExpr(tag_let_stmts, tag_check.1); + } + FieldlessVariantsStrategy::SpecializeIfAllVariantsFieldless => { + return self.call_substructure_method( + cx, + trait_, + type_ident, + nonselflike_args, + &AllFieldlessEnum(enum_def), + ); + } + FieldlessVariantsStrategy::Default => (), + } + } else if variants.len() == 1 { // If there is a single variant, we don't need an operation on // the tag(s). Just use the most degenerate result. return self.call_substructure_method( @@ -1187,7 +1218,7 @@ impl<'a> MethodDef<'a> { nonselflike_args, &EnumMatching(0, 1, &variants[0], Vec::new()), ); - }; + } } // These arms are of the form: @@ -1198,7 +1229,7 @@ impl<'a> MethodDef<'a> { let mut match_arms: Vec = variants .iter() .enumerate() - .filter(|&(_, v)| !(self.unify_fieldless_variants && v.data.fields().is_empty())) + .filter(|&(_, v)| !(unify_fieldless_variants && v.data.fields().is_empty())) .map(|(index, variant)| { // A single arm has form (&VariantK, &VariantK, ...) => BodyK // (see "Final wrinkle" note below for why.) @@ -1249,7 +1280,7 @@ impl<'a> MethodDef<'a> { // Add a default arm to the match, if necessary. let first_fieldless = variants.iter().find(|v| v.data.fields().is_empty()); let default = match first_fieldless { - Some(v) if self.unify_fieldless_variants => { + Some(v) if unify_fieldless_variants => { // We need a default case that handles all the fieldless // variants. The index and actual variant aren't meaningful in // this case, so just use dummy values. @@ -1296,7 +1327,7 @@ impl<'a> MethodDef<'a> { // If the trait uses the tag and there are multiple variants, we need // to add a tag check operation before the match. Otherwise, the match // is enough. - if uses_tags && variants.len() > 1 { + if unify_fieldless_variants && variants.len() > 1 { let (tag_field, mut tag_let_stmts) = get_tag_pieces(cx); // Combine a tag check with the match. @@ -1580,5 +1611,6 @@ where } } StaticEnum(..) | StaticStruct(..) => cx.span_bug(trait_span, "static function in `derive`"), + AllFieldlessEnum(..) => cx.span_bug(trait_span, "fieldless enum in `derive`"), } } diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs index c136bb7141ab9..f8570d8f86a08 100644 --- a/compiler/rustc_builtin_macros/src/deriving/hash.rs +++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs @@ -33,7 +33,7 @@ pub fn expand_deriving_hash( nonself_args: vec![(Ref(Box::new(Path(arg)), Mutability::Mut), sym::state)], ret_ty: Unit, attributes: AttrVec::new(), - unify_fieldless_variants: true, + fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, combine_substructure: combine_substructure(Box::new(|a, b, c| { hash_substructure(a, b, c) })), From 200f466d1a3cd1530752842b6895c73fc61b0cb6 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 18 Jan 2023 18:03:06 +0000 Subject: [PATCH 180/230] Encode whether foreign opaques are TAITs or not --- compiler/rustc_hir_analysis/src/astconv/mod.rs | 2 +- compiler/rustc_hir_analysis/src/collect.rs | 11 +++++++++++ .../rustc_metadata/src/rmeta/decoder/cstore_impl.rs | 1 + compiler/rustc_metadata/src/rmeta/encoder.rs | 1 + compiler/rustc_metadata/src/rmeta/mod.rs | 1 + compiler/rustc_middle/src/query/mod.rs | 6 ++++++ compiler/rustc_middle/src/ty/parameterized.rs | 1 + compiler/rustc_trait_selection/src/traits/wf.rs | 2 +- 8 files changed, 23 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 9031c04849dfe..ce72b78f42f93 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -2602,7 +2602,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { match path.res { Res::Def(DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder, did) => { // Check for desugared `impl Trait`. - assert!(ty::is_impl_trait_defn(tcx, did).is_none()); + assert!(tcx.is_type_alias_impl_trait(did)); let item_segment = path.segments.split_last().unwrap(); self.prohibit_generics(item_segment.1.iter(), |err| { err.note("`impl Trait` types can't have type parameters"); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 35f47dfc1a5e2..9be37dbe8c6b5 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -76,6 +76,7 @@ pub fn provide(providers: &mut Providers) { is_foreign_item, generator_kind, collect_mod_item_types, + is_type_alias_impl_trait, ..*providers }; } @@ -1537,3 +1538,13 @@ fn generator_kind(tcx: TyCtxt<'_>, def_id: DefId) -> Option _ => bug!("generator_kind applied to non-local def-id {:?}", def_id), } } + +fn is_type_alias_impl_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { + match tcx.hir().get_if_local(def_id) { + Some(Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(opaque), .. })) => { + matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias) + } + Some(_) => bug!("tried getting opaque_ty_origin for non-opaque: {:?}", def_id), + _ => bug!("tried getting opaque_ty_origin for non-local def-id {:?}", def_id), + } +} diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index cb451931dfe17..c00a95607aadc 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -223,6 +223,7 @@ provide! { tcx, def_id, other, cdata, generator_kind => { table } trait_def => { table } deduced_param_attrs => { table } + is_type_alias_impl_trait => { table } collect_return_position_impl_trait_in_trait_tys => { Ok(cdata .root diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index a3d44fa890dd1..69adefe432c62 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1514,6 +1514,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } hir::ItemKind::OpaqueTy(..) => { self.encode_explicit_item_bounds(def_id); + record!(self.tables.is_type_alias_impl_trait[def_id] <- self.tcx.is_type_alias_impl_trait(def_id)); } hir::ItemKind::Enum(..) => { let adt_def = self.tcx.adt_def(def_id); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 5b7b096b4edf1..5e2b7938bd510 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -404,6 +404,7 @@ define_tables! { proc_macro: Table, module_reexports: Table>, deduced_param_attrs: Table>, + is_type_alias_impl_trait: Table>, trait_impl_trait_tys: Table>>>, } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 0ec6f481af1ff..6bbf7fa3914e6 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -177,6 +177,12 @@ rustc_queries! { separate_provide_extern } + query is_type_alias_impl_trait(key: DefId) -> bool + { + desc { "determine whether the opaque is a type-alias impl trait" } + separate_provide_extern + } + query analysis(key: ()) -> Result<(), ErrorGuaranteed> { eval_always desc { "running analysis passes on this crate" } diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index e32a7ee1c3545..24f3d1acff188 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -52,6 +52,7 @@ trivially_parameterized_over_tcx! { usize, (), u32, + bool, std::string::String, crate::metadata::ModChild, crate::middle::codegen_fn_attrs::CodegenFnAttrs, diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index b47a70b4e7b96..12d4cb4fc6920 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -654,7 +654,7 @@ impl<'tcx> WfPredicates<'tcx> { // All of the requirements on type parameters // have already been checked for `impl Trait` in // return position. We do need to check type-alias-impl-trait though. - if ty::is_impl_trait_defn(self.tcx, def_id).is_none() { + if self.tcx.is_type_alias_impl_trait(def_id) { let obligations = self.nominal_obligations(def_id, substs); self.out.extend(obligations); } From 9793abc2092ab37e406a07b8e35bfaf5a9e26fe6 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 18 Jan 2023 18:11:19 +0000 Subject: [PATCH 181/230] Add test --- tests/ui/async-await/auxiliary/issue-107036.rs | 12 ++++++++++++ tests/ui/async-await/issue-107036.rs | 14 ++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 tests/ui/async-await/auxiliary/issue-107036.rs create mode 100644 tests/ui/async-await/issue-107036.rs diff --git a/tests/ui/async-await/auxiliary/issue-107036.rs b/tests/ui/async-await/auxiliary/issue-107036.rs new file mode 100644 index 0000000000000..c3f6141b28403 --- /dev/null +++ b/tests/ui/async-await/auxiliary/issue-107036.rs @@ -0,0 +1,12 @@ +// edition:2021 + +pub trait T {} +impl T for () {} + +pub struct S {} + +impl S { + pub async fn f<'a>(&self) -> impl T + 'a { + () + } +} diff --git a/tests/ui/async-await/issue-107036.rs b/tests/ui/async-await/issue-107036.rs new file mode 100644 index 0000000000000..6a22de2c94354 --- /dev/null +++ b/tests/ui/async-await/issue-107036.rs @@ -0,0 +1,14 @@ +// aux-build:issue-107036.rs +// edition:2021 +// check-pass + +extern crate issue_107036; +use issue_107036::S; + +async fn f() { + S{}.f().await; +} + +fn main() { + let _ = f(); +} From 95a824c02c3f9a50bb4fa49e7af7d3a5a2faf51e Mon Sep 17 00:00:00 2001 From: clubby789 Date: Thu, 19 Jan 2023 15:52:29 +0000 Subject: [PATCH 182/230] Special case `derive(Debug)` for fieldless enums --- .../src/deriving/debug.rs | 51 ++++++++++++++++++- tests/ui/deriving/deriving-all-codegen.stdout | 11 ++-- 2 files changed, 55 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index a586964d0c321..e0f487e864898 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -2,6 +2,7 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use crate::deriving::path_std; +use ast::EnumDef; use rustc_ast::{self as ast, MetaItem}; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::{sym, Ident, Symbol}; @@ -31,7 +32,8 @@ pub fn expand_deriving_debug( nonself_args: vec![(fmtr, sym::f)], ret_ty: Path(path_std!(fmt::Result)), attributes: ast::AttrVec::new(), - fieldless_variants_strategy: FieldlessVariantsStrategy::Default, + fieldless_variants_strategy: + FieldlessVariantsStrategy::SpecializeIfAllVariantsFieldless, combine_substructure: combine_substructure(Box::new(|a, b, c| { show_substructure(a, b, c) })), @@ -49,7 +51,8 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_> let (ident, vdata, fields) = match substr.fields { Struct(vdata, fields) => (substr.type_ident, *vdata, fields), EnumMatching(_, _, v, fields) => (v.ident, &v.data, fields), - AllFieldlessEnum(..) | EnumTag(..) | StaticStruct(..) | StaticEnum(..) => { + AllFieldlessEnum(enum_def) => return show_fieldless_enum(cx, span, enum_def, substr), + EnumTag(..) | StaticStruct(..) | StaticEnum(..) => { cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`") } }; @@ -174,3 +177,47 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_> BlockOrExpr::new_mixed(stmts, Some(expr)) } } + +/// Special case for enums with no fields. Builds: +/// ```text +/// impl ::core::fmt::Debug for A { +/// fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { +/// ::core::fmt::Formatter::write_str(f, +/// match self { +/// A::A => "A", +/// A::B() => "B", +/// A::C {} => "C", +/// }) +/// } +/// } +/// ``` +fn show_fieldless_enum( + cx: &mut ExtCtxt<'_>, + span: Span, + def: &EnumDef, + substr: &Substructure<'_>, +) -> BlockOrExpr { + let fmt = substr.nonselflike_args[0].clone(); + let arms = def + .variants + .iter() + .map(|v| { + let variant_path = cx.path(span, vec![substr.type_ident, v.ident]); + let pat = match &v.data { + ast::VariantData::Tuple(fields, _) => { + debug_assert!(fields.is_empty()); + cx.pat_tuple_struct(span, variant_path, vec![]) + } + ast::VariantData::Struct(fields, _) => { + debug_assert!(fields.is_empty()); + cx.pat_struct(span, variant_path, vec![]) + } + ast::VariantData::Unit(_) => cx.pat_path(span, variant_path), + }; + cx.arm(span, pat, cx.expr_str(span, v.ident.name)) + }) + .collect::>(); + let name = cx.expr_match(span, cx.expr_self(span), arms); + let fn_path_write_str = cx.std_path(&[sym::fmt, sym::Formatter, sym::write_str]); + BlockOrExpr::new_expr(cx.expr_call_global(span, fn_path_write_str, vec![fmt, name])) +} diff --git a/tests/ui/deriving/deriving-all-codegen.stdout b/tests/ui/deriving/deriving-all-codegen.stdout index a63cbd4ca7ede..e6ee11a783b88 100644 --- a/tests/ui/deriving/deriving-all-codegen.stdout +++ b/tests/ui/deriving/deriving-all-codegen.stdout @@ -731,11 +731,12 @@ impl ::core::marker::Copy for Fieldless { } #[automatically_derived] impl ::core::fmt::Debug for Fieldless { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - match self { - Fieldless::A => ::core::fmt::Formatter::write_str(f, "A"), - Fieldless::B => ::core::fmt::Formatter::write_str(f, "B"), - Fieldless::C => ::core::fmt::Formatter::write_str(f, "C"), - } + ::core::fmt::Formatter::write_str(f, + match self { + Fieldless::A => "A", + Fieldless::B => "B", + Fieldless::C => "C", + }) } } #[automatically_derived] From 7e0b1f11154bc5e9af996b821b2c28680c3f46c8 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 19 Jan 2023 16:09:10 +0000 Subject: [PATCH 183/230] Conditionally encode boolean --- .../rustc_metadata/src/rmeta/decoder/cstore_impl.rs | 10 +++++++++- compiler/rustc_metadata/src/rmeta/encoder.rs | 6 ++++-- compiler/rustc_metadata/src/rmeta/mod.rs | 3 ++- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index c00a95607aadc..0d924f27c21a6 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -223,7 +223,15 @@ provide! { tcx, def_id, other, cdata, generator_kind => { table } trait_def => { table } deduced_param_attrs => { table } - is_type_alias_impl_trait => { table } + is_type_alias_impl_trait => { + debug_assert_eq!(tcx.def_kind(def_id), DefKind::OpaqueTy); + cdata + .root + .tables + .is_type_alias_impl_trait + .get(cdata, def_id.index) + .is_some() + } collect_return_position_impl_trait_in_trait_tys => { Ok(cdata .root diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 69adefe432c62..ab2ad79b876d4 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1512,9 +1512,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { hir::ItemKind::Mod(ref m) => { return self.encode_info_for_mod(item.owner_id.def_id, m); } - hir::ItemKind::OpaqueTy(..) => { + hir::ItemKind::OpaqueTy(ref opaque) => { self.encode_explicit_item_bounds(def_id); - record!(self.tables.is_type_alias_impl_trait[def_id] <- self.tcx.is_type_alias_impl_trait(def_id)); + if matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias) { + self.tables.is_type_alias_impl_trait.set(def_id.index, ()); + } } hir::ItemKind::Enum(..) => { let adt_def = self.tcx.adt_def(def_id); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 5e2b7938bd510..5066dbbb90f3a 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -404,7 +404,8 @@ define_tables! { proc_macro: Table, module_reexports: Table>, deduced_param_attrs: Table>, - is_type_alias_impl_trait: Table>, + // Slot is full when opaque is TAIT. + is_type_alias_impl_trait: Table, trait_impl_trait_tys: Table>>>, } From aee75f25cbfb187f74d2b8453b0d902ad6ced391 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 19 Jan 2023 15:32:20 +0000 Subject: [PATCH 184/230] Assert goal is fully normalized during assemble --- compiler/rustc_trait_selection/src/solve/assembly.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs index 2c92e7eb9ad3f..45bce34b1edd8 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -79,7 +79,7 @@ pub(super) enum CandidateSource { AliasBound(usize), } -pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy { +pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy + Eq { fn self_ty(self) -> Ty<'tcx>; fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self; @@ -124,6 +124,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { &mut self, goal: Goal<'tcx, G>, ) -> Vec> { + debug_assert_eq!(goal, self.infcx.resolve_vars_if_possible(goal)); + // HACK: `_: Trait` is ambiguous, because it may be satisfied via a builtin rule, // object bound, alias bound, etc. We are unable to determine this until we can at // least structually resolve the type one layer. @@ -179,6 +181,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { Ok((_, certainty)) => certainty, Err(NoSolution) => return, }; + let normalized_ty = self.infcx.resolve_vars_if_possible(normalized_ty); // NOTE: Alternatively we could call `evaluate_goal` here and only have a `Normalized` candidate. // This doesn't work as long as we use `CandidateSource` in winnowing. From f53f5b4463a28b44d036342f0a849390495f6a9b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 19 Jan 2023 04:50:14 +0000 Subject: [PATCH 185/230] swap Ambiguity and Unimplemented in new trait engine --- compiler/rustc_trait_selection/src/solve/fulfill.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index b086c0684d28d..a6240666ed43a 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -52,7 +52,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { .drain(..) .map(|obligation| FulfillmentError { obligation: obligation.clone(), - code: FulfillmentErrorCode::CodeSelectionError(SelectionError::Unimplemented), + code: FulfillmentErrorCode::CodeAmbiguity, root_obligation: obligation, }) .collect() @@ -75,7 +75,9 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { Err(NoSolution) => { errors.push(FulfillmentError { obligation: obligation.clone(), - code: FulfillmentErrorCode::CodeAmbiguity, + code: FulfillmentErrorCode::CodeSelectionError( + SelectionError::Unimplemented, + ), root_obligation: obligation, }); continue; From 69890b2df447e7d3febff1a0f8974f3fcf694128 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 18 Jan 2023 23:21:12 +0000 Subject: [PATCH 186/230] trait solver: PointerSized --- .../src/solve/assembly.rs | 7 +++++ .../src/solve/project_goals.rs | 7 +++++ .../src/solve/trait_goals.rs | 27 +++++++++++++++++-- tests/ui/traits/new-solver/pointer-sized.rs | 12 +++++++++ .../ui/traits/new-solver/pointer-sized.stderr | 24 +++++++++++++++++ 5 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 tests/ui/traits/new-solver/pointer-sized.rs create mode 100644 tests/ui/traits/new-solver/pointer-sized.stderr diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs index 45bce34b1edd8..52155aa0f1894 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -117,6 +117,11 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy + Eq { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; + + fn consider_builtin_pointer_sized_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx>; } impl<'tcx> EvalCtxt<'_, 'tcx> { @@ -237,6 +242,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { || lang_items.clone_trait() == Some(trait_def_id) { G::consider_builtin_copy_clone_candidate(self, goal) + } else if lang_items.pointer_sized() == Some(trait_def_id) { + G::consider_builtin_pointer_sized_candidate(self, goal) } else { Err(NoSolution) }; diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index ffc1c70e0cb81..3f3d32efe7f53 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -351,6 +351,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ) -> QueryResult<'tcx> { bug!("`Copy`/`Clone` does not have an associated type: {:?}", goal); } + + fn consider_builtin_pointer_sized_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + bug!("`PointerSized` does not have an associated type: {:?}", goal); + } } /// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code. diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 1ebcfd03c14ea..f68a296922aae 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -4,13 +4,13 @@ use std::iter; use super::assembly::{self, Candidate, CandidateSource}; use super::infcx_ext::InferCtxtExt; -use super::{EvalCtxt, Goal, QueryResult}; +use super::{Certainty, EvalCtxt, Goal, QueryResult}; use rustc_hir::def_id::DefId; use rustc_infer::infer::InferCtxt; use rustc_infer::traits::query::NoSolution; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; -use rustc_middle::ty::TraitPredicate; use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{TraitPredicate, TypeVisitable}; use rustc_span::DUMMY_SP; mod structural_traits; @@ -127,6 +127,29 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { structural_traits::instantiate_constituent_tys_for_copy_clone_trait, ) } + + fn consider_builtin_pointer_sized_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + if goal.predicate.self_ty().has_non_region_infer() { + return ecx.make_canonical_response(Certainty::Maybe(MaybeCause::Ambiguity)); + } + + let tcx = ecx.tcx(); + let self_ty = tcx.erase_regions(goal.predicate.self_ty()); + + if let Ok(layout) = tcx.layout_of(goal.param_env.and(self_ty)) + && let usize_layout = tcx.layout_of(ty::ParamEnv::empty().and(tcx.types.usize)).unwrap().layout + && layout.layout.size() == usize_layout.size() + && layout.layout.align().abi == usize_layout.align().abi + { + // FIXME: We could make this faster by making a no-constraints response + ecx.make_canonical_response(Certainty::Yes) + } else { + Err(NoSolution) + } + } } impl<'tcx> EvalCtxt<'_, 'tcx> { diff --git a/tests/ui/traits/new-solver/pointer-sized.rs b/tests/ui/traits/new-solver/pointer-sized.rs new file mode 100644 index 0000000000000..15681cd132ec6 --- /dev/null +++ b/tests/ui/traits/new-solver/pointer-sized.rs @@ -0,0 +1,12 @@ +#![feature(pointer_sized_trait)] + +use std::marker::PointerSized; + +fn require_pointer_sized(_: impl PointerSized) {} + +fn main() { + require_pointer_sized(1usize); + require_pointer_sized(1u16); + //~^ ERROR `u16` needs to be a pointer-sized type + require_pointer_sized(&1i16); +} diff --git a/tests/ui/traits/new-solver/pointer-sized.stderr b/tests/ui/traits/new-solver/pointer-sized.stderr new file mode 100644 index 0000000000000..b250b1331bbf9 --- /dev/null +++ b/tests/ui/traits/new-solver/pointer-sized.stderr @@ -0,0 +1,24 @@ +error[E0277]: `u16` needs to be a pointer-sized type + --> $DIR/pointer-sized.rs:9:27 + | +LL | require_pointer_sized(1u16); + | --------------------- ^^^^ the trait `PointerSized` is not implemented for `u16` + | | + | required by a bound introduced by this call + | + = note: the trait bound `u16: PointerSized` is not satisfied +note: required by a bound in `require_pointer_sized` + --> $DIR/pointer-sized.rs:5:34 + | +LL | fn require_pointer_sized(_: impl PointerSized) {} + | ^^^^^^^^^^^^ required by this bound in `require_pointer_sized` +help: consider borrowing here + | +LL | require_pointer_sized(&1u16); + | + +LL | require_pointer_sized(&mut 1u16); + | ++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From ed6aebbfecb56ae9ec2702572b70d6e350433de2 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 19 Jan 2023 01:20:34 +0000 Subject: [PATCH 187/230] trait solver: Implement Fn traits and tuple trait --- .../src/solve/assembly.rs | 19 ++++++- .../src/solve/project_goals.rs | 38 +++++++++++++- .../src/solve/trait_goals.rs | 41 +++++++++++++-- .../solve/trait_goals/structural_traits.rs | 51 ++++++++++++++++++- .../ui/traits/new-solver/fn-trait-closure.rs | 15 ++++++ tests/ui/traits/new-solver/fn-trait.rs | 13 +++++ 6 files changed, 170 insertions(+), 7 deletions(-) create mode 100644 tests/ui/traits/new-solver/fn-trait-closure.rs create mode 100644 tests/ui/traits/new-solver/fn-trait.rs diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs index 52155aa0f1894..31c1bc9ecc062 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -122,6 +122,17 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy + Eq { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; + + fn consider_builtin_fn_trait_candidates( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + kind: ty::ClosureKind, + ) -> QueryResult<'tcx>; + + fn consider_builtin_tuple_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx>; } impl<'tcx> EvalCtxt<'_, 'tcx> { @@ -137,7 +148,9 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { if goal.predicate.self_ty().is_ty_var() { return vec![Candidate { source: CandidateSource::BuiltinImpl, - result: self.make_canonical_response(Certainty::Maybe(MaybeCause::Ambiguity)).unwrap(), + result: self + .make_canonical_response(Certainty::Maybe(MaybeCause::Ambiguity)) + .unwrap(), }]; } @@ -244,6 +257,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { G::consider_builtin_copy_clone_candidate(self, goal) } else if lang_items.pointer_sized() == Some(trait_def_id) { G::consider_builtin_pointer_sized_candidate(self, goal) + } else if let Some(kind) = self.tcx().fn_trait_kind_from_def_id(trait_def_id) { + G::consider_builtin_fn_trait_candidates(self, goal, kind) + } else if lang_items.tuple_trait() == Some(trait_def_id) { + G::consider_builtin_tuple_candidate(self, goal) } else { Err(NoSolution) }; diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 3f3d32efe7f53..e39fa05339286 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -2,6 +2,7 @@ use crate::traits::{specialization_graph, translate_substs}; use super::assembly::{self, Candidate, CandidateSource}; use super::infcx_ext::InferCtxtExt; +use super::trait_goals::structural_traits; use super::{Certainty, EvalCtxt, Goal, MaybeCause, QueryResult}; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::DefKind; @@ -11,9 +12,9 @@ use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::specialization_graph::LeafDef; use rustc_infer::traits::Reveal; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; -use rustc_middle::ty::TypeVisitable; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{ProjectionPredicate, TypeSuperVisitable, TypeVisitor}; +use rustc_middle::ty::{ToPredicate, TypeVisitable}; use rustc_span::DUMMY_SP; use std::iter; use std::ops::ControlFlow; @@ -353,11 +354,44 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { } fn consider_builtin_pointer_sized_candidate( - ecx: &mut EvalCtxt<'_, 'tcx>, + _ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { bug!("`PointerSized` does not have an associated type: {:?}", goal); } + + fn consider_builtin_fn_trait_candidates( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + goal_kind: ty::ClosureKind, + ) -> QueryResult<'tcx> { + if let Some(tupled_inputs_and_output) = + structural_traits::extract_tupled_inputs_and_output_from_callable( + ecx.tcx(), + goal.predicate.self_ty(), + goal_kind, + )? + { + let pred = tupled_inputs_and_output + .map_bound(|(inputs, output)| ty::ProjectionPredicate { + projection_ty: ecx + .tcx() + .mk_alias_ty(goal.predicate.def_id(), [goal.predicate.self_ty(), inputs]), + term: output.into(), + }) + .to_predicate(ecx.tcx()); + Self::consider_assumption(ecx, goal, pred) + } else { + ecx.make_canonical_response(Certainty::Maybe(MaybeCause::Ambiguity)) + } + } + + fn consider_builtin_tuple_candidate( + _ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + bug!("`Tuple` does not have an associated type: {:?}", goal); + } } /// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code. diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index f68a296922aae..9985d7181bb7d 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -4,16 +4,16 @@ use std::iter; use super::assembly::{self, Candidate, CandidateSource}; use super::infcx_ext::InferCtxtExt; -use super::{Certainty, EvalCtxt, Goal, QueryResult}; +use super::{Certainty, EvalCtxt, Goal, MaybeCause, QueryResult}; use rustc_hir::def_id::DefId; use rustc_infer::infer::InferCtxt; use rustc_infer::traits::query::NoSolution; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt}; use rustc_middle::ty::{TraitPredicate, TypeVisitable}; use rustc_span::DUMMY_SP; -mod structural_traits; +pub mod structural_traits; impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn self_ty(self) -> Ty<'tcx> { @@ -150,6 +150,41 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { Err(NoSolution) } } + + fn consider_builtin_fn_trait_candidates( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + goal_kind: ty::ClosureKind, + ) -> QueryResult<'tcx> { + if let Some(tupled_inputs_and_output) = + structural_traits::extract_tupled_inputs_and_output_from_callable( + ecx.tcx(), + goal.predicate.self_ty(), + goal_kind, + )? + { + let pred = tupled_inputs_and_output + .map_bound(|(inputs, _)| { + ecx.tcx() + .mk_trait_ref(goal.predicate.def_id(), [goal.predicate.self_ty(), inputs]) + }) + .to_predicate(ecx.tcx()); + Self::consider_assumption(ecx, goal, pred) + } else { + ecx.make_canonical_response(Certainty::Maybe(MaybeCause::Ambiguity)) + } + } + + fn consider_builtin_tuple_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + if let ty::Tuple(..) = goal.predicate.self_ty().kind() { + ecx.make_canonical_response(Certainty::Yes) + } else { + Err(NoSolution) + } + } } impl<'tcx> EvalCtxt<'_, 'tcx> { diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs index 2c75d0907b739..a11cd13cb0856 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs @@ -1,6 +1,6 @@ use rustc_hir::{Movability, Mutability}; use rustc_infer::{infer::InferCtxt, traits::query::NoSolution}; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, Ty, TyCtxt}; // Calculates the constituent types of a type for `auto trait` purposes. // @@ -172,3 +172,52 @@ pub(super) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( } } } + +pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>( + tcx: TyCtxt<'tcx>, + self_ty: Ty<'tcx>, + goal_kind: ty::ClosureKind, +) -> Result, Ty<'tcx>)>>, NoSolution> { + match *self_ty.kind() { + ty::FnDef(def_id, substs) => Ok(Some( + tcx.bound_fn_sig(def_id) + .subst(tcx, substs) + .map_bound(|sig| (tcx.mk_tup(sig.inputs().iter()), sig.output())), + )), + ty::FnPtr(sig) => { + Ok(Some(sig.map_bound(|sig| (tcx.mk_tup(sig.inputs().iter()), sig.output())))) + } + ty::Closure(_, substs) => { + let closure_substs = substs.as_closure(); + match closure_substs.kind_ty().to_opt_closure_kind() { + Some(closure_kind) if closure_kind.extends(goal_kind) => {} + None => return Ok(None), + _ => return Err(NoSolution), + } + Ok(Some(closure_substs.sig().map_bound(|sig| (sig.inputs()[0], sig.output())))) + } + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(_, _) + | ty::Foreign(_) + | ty::Str + | ty::Array(_, _) + | ty::Slice(_) + | ty::RawPtr(_) + | ty::Ref(_, _, _) + | ty::Dynamic(_, _, _) + | ty::Generator(_, _, _) + | ty::GeneratorWitness(_) + | ty::Never + | ty::Tuple(_) + | ty::Alias(_, _) + | ty::Param(_) + | ty::Placeholder(_) + | ty::Bound(_, _) + | ty::Infer(_) + | ty::Error(_) => Err(NoSolution), + } +} diff --git a/tests/ui/traits/new-solver/fn-trait-closure.rs b/tests/ui/traits/new-solver/fn-trait-closure.rs new file mode 100644 index 0000000000000..c0ecf1c91fb38 --- /dev/null +++ b/tests/ui/traits/new-solver/fn-trait-closure.rs @@ -0,0 +1,15 @@ +// compile-flags: -Ztrait-solver=next +// known-bug: unknown +// failure-status: 101 +// dont-check-compiler-stderr + +// This test will fail until we fix `FulfillmentCtxt::relationships`. That's +// because we create a type variable for closure upvar types, which is not +// constrained until after we try to do fallback on diverging type variables. +// Thus, we will call that function, which is unimplemented. + +fn require_fn(_: impl Fn() -> i32) {} + +fn main() { + require_fn(|| -> i32 { 1i32 }); +} diff --git a/tests/ui/traits/new-solver/fn-trait.rs b/tests/ui/traits/new-solver/fn-trait.rs new file mode 100644 index 0000000000000..d566ead105c86 --- /dev/null +++ b/tests/ui/traits/new-solver/fn-trait.rs @@ -0,0 +1,13 @@ +// compile-flags: -Ztrait-solver=next +// check-pass + +fn require_fn(_: impl Fn() -> i32) {} + +fn f() -> i32 { + 1i32 +} + +fn main() { + require_fn(f); + require_fn(f as fn() -> i32); +} From 97ae79ac9d8090dcbf0242865cda171d00ea116a Mon Sep 17 00:00:00 2001 From: bohan Date: Mon, 16 Jan 2023 15:09:05 +0800 Subject: [PATCH 188/230] add raw identifier for keyword in suggestion --- compiler/rustc_middle/src/ty/print/pretty.rs | 2 +- ...4-raw-ident-suggestion.edition2015.stderr} | 10 +++---- ...34-raw-ident-suggestion.edition2018.stderr | 28 +++++++++++++++++++ .../issue-65634-raw-ident-suggestion.rs | 3 ++ 4 files changed, 37 insertions(+), 6 deletions(-) rename tests/ui/issues/{issue-65634-raw-ident-suggestion.stderr => issue-65634-raw-ident-suggestion.edition2015.stderr} (80%) create mode 100644 tests/ui/issues/issue-65634-raw-ident-suggestion.edition2018.stderr diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 5576e53e6a74d..ae7c20fff0c34 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -393,7 +393,7 @@ pub trait PrettyPrinter<'tcx>: match self.tcx().trimmed_def_paths(()).get(&def_id) { None => Ok((self, false)), Some(symbol) => { - self.write_str(symbol.as_str())?; + write!(self, "{}", Ident::with_dummy_span(*symbol))?; Ok((self, true)) } } diff --git a/tests/ui/issues/issue-65634-raw-ident-suggestion.stderr b/tests/ui/issues/issue-65634-raw-ident-suggestion.edition2015.stderr similarity index 80% rename from tests/ui/issues/issue-65634-raw-ident-suggestion.stderr rename to tests/ui/issues/issue-65634-raw-ident-suggestion.edition2015.stderr index 68ccf5cab5b6b..d0cb16995af68 100644 --- a/tests/ui/issues/issue-65634-raw-ident-suggestion.stderr +++ b/tests/ui/issues/issue-65634-raw-ident-suggestion.edition2015.stderr @@ -1,16 +1,16 @@ error[E0034]: multiple applicable items in scope - --> $DIR/issue-65634-raw-ident-suggestion.rs:21:13 + --> $DIR/issue-65634-raw-ident-suggestion.rs:24:13 | LL | r#fn {}.r#struct(); | ^^^^^^^^ multiple `r#struct` found | -note: candidate #1 is defined in an impl of the trait `async` for the type `fn` - --> $DIR/issue-65634-raw-ident-suggestion.rs:4:5 +note: candidate #1 is defined in an impl of the trait `async` for the type `r#fn` + --> $DIR/issue-65634-raw-ident-suggestion.rs:7:5 | LL | fn r#struct(&self) { | ^^^^^^^^^^^^^^^^^^ -note: candidate #2 is defined in an impl of the trait `await` for the type `fn` - --> $DIR/issue-65634-raw-ident-suggestion.rs:10:5 +note: candidate #2 is defined in an impl of the trait `await` for the type `r#fn` + --> $DIR/issue-65634-raw-ident-suggestion.rs:13:5 | LL | fn r#struct(&self) { | ^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/issues/issue-65634-raw-ident-suggestion.edition2018.stderr b/tests/ui/issues/issue-65634-raw-ident-suggestion.edition2018.stderr new file mode 100644 index 0000000000000..a75c1c413636e --- /dev/null +++ b/tests/ui/issues/issue-65634-raw-ident-suggestion.edition2018.stderr @@ -0,0 +1,28 @@ +error[E0034]: multiple applicable items in scope + --> $DIR/issue-65634-raw-ident-suggestion.rs:24:13 + | +LL | r#fn {}.r#struct(); + | ^^^^^^^^ multiple `r#struct` found + | +note: candidate #1 is defined in an impl of the trait `r#async` for the type `r#fn` + --> $DIR/issue-65634-raw-ident-suggestion.rs:7:5 + | +LL | fn r#struct(&self) { + | ^^^^^^^^^^^^^^^^^^ +note: candidate #2 is defined in an impl of the trait `r#await` for the type `r#fn` + --> $DIR/issue-65634-raw-ident-suggestion.rs:13:5 + | +LL | fn r#struct(&self) { + | ^^^^^^^^^^^^^^^^^^ +help: disambiguate the associated function for candidate #1 + | +LL | r#async::r#struct(&r#fn {}); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +help: disambiguate the associated function for candidate #2 + | +LL | r#await::r#struct(&r#fn {}); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0034`. diff --git a/tests/ui/issues/issue-65634-raw-ident-suggestion.rs b/tests/ui/issues/issue-65634-raw-ident-suggestion.rs index b928510258b2f..03dd0340c9d69 100644 --- a/tests/ui/issues/issue-65634-raw-ident-suggestion.rs +++ b/tests/ui/issues/issue-65634-raw-ident-suggestion.rs @@ -1,3 +1,6 @@ +// revisions: edition2015 edition2018 +//[edition2018]edition:2018 + #![allow(non_camel_case_types)] trait r#async { From f219771961c94f218d23bfab66aa678c48840fc4 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 19 Jan 2023 17:37:59 +0100 Subject: [PATCH 189/230] Clean up and document unord collections a bit. --- compiler/rustc_data_structures/src/unord.rs | 104 +++++++++++++------- 1 file changed, 66 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_data_structures/src/unord.rs b/compiler/rustc_data_structures/src/unord.rs index d29b49872741c..f35f18e51cb4e 100644 --- a/compiler/rustc_data_structures/src/unord.rs +++ b/compiler/rustc_data_structures/src/unord.rs @@ -208,21 +208,24 @@ impl UnordSet { UnordItems(self.inner.into_iter()) } + /// Returns the items of this set in stable sort order (as defined by `ToStableHashKey`). + /// + /// The `cache_sort_key` parameter controls if [slice::sort_by_cached_key] or + /// [slice::sort_unstable_by_key] will be used for sorting the vec. Use + /// `cache_sort_key` when the [ToStableHashKey::to_stable_hash_key] implementation + /// for `V` is expensive (e.g. a `DefId -> DefPathHash` lookup). #[inline] pub fn to_sorted(&self, hcx: &HCX, cache_sort_key: bool) -> Vec<&V> where V: ToStableHashKey, { - let mut items: Vec<&V> = self.inner.iter().collect(); - if cache_sort_key { - items.sort_by_cached_key(|k| k.to_stable_hash_key(hcx)); - } else { - items.sort_unstable_by_key(|k| k.to_stable_hash_key(hcx)); - } - - items + to_sorted_vec(hcx, self.inner.iter(), cache_sort_key, |&x| x) } + /// Returns the items of this set in stable sort order (as defined by + /// `StableOrd`). This method is much more efficient than + /// `into_sorted` because it does not need to transform keys to their + /// `ToStableHashKey` equivalent. #[inline] pub fn to_sorted_stable_ord(&self) -> Vec where @@ -233,19 +236,18 @@ impl UnordSet { items } + /// Returns the items of this set in stable sort order (as defined by `ToStableHashKey`). + /// + /// The `cache_sort_key` parameter controls if [slice::sort_by_cached_key] or + /// [slice::sort_unstable_by_key] will be used for sorting the vec. Use + /// `cache_sort_key` when the [ToStableHashKey::to_stable_hash_key] implementation + /// for `V` is expensive (e.g. a `DefId -> DefPathHash` lookup). #[inline] pub fn into_sorted(self, hcx: &HCX, cache_sort_key: bool) -> Vec where V: ToStableHashKey, { - let mut items: Vec = self.inner.into_iter().collect(); - if cache_sort_key { - items.sort_by_cached_key(|k| k.to_stable_hash_key(hcx)); - } else { - items.sort_unstable_by_key(|k| k.to_stable_hash_key(hcx)); - } - - items + to_sorted_vec(hcx, self.inner.into_iter(), cache_sort_key, |x| x) } // We can safely extend this UnordSet from a set of unordered values because that @@ -398,21 +400,23 @@ impl UnordMap { self.inner.extend(items.0) } + /// Returns the entries of this map in stable sort order (as defined by `ToStableHashKey`). + /// + /// The `cache_sort_key` parameter controls if [slice::sort_by_cached_key] or + /// [slice::sort_unstable_by_key] will be used for sorting the vec. Use + /// `cache_sort_key` when the [ToStableHashKey::to_stable_hash_key] implementation + /// for `K` is expensive (e.g. a `DefId -> DefPathHash` lookup). #[inline] pub fn to_sorted(&self, hcx: &HCX, cache_sort_key: bool) -> Vec<(&K, &V)> where K: ToStableHashKey, { - let mut items: Vec<(&K, &V)> = self.inner.iter().collect(); - if cache_sort_key { - items.sort_by_cached_key(|(k, _)| k.to_stable_hash_key(hcx)); - } else { - items.sort_unstable_by_key(|(k, _)| k.to_stable_hash_key(hcx)); - } - - items + to_sorted_vec(hcx, self.inner.iter(), cache_sort_key, |&(k, _)| k) } + /// Returns the entries of this map in stable sort order (as defined by `StableOrd`). + /// This method can be much more efficient than `into_sorted` because it does not need + /// to transform keys to their `ToStableHashKey` equivalent. #[inline] pub fn to_sorted_stable_ord(&self) -> Vec<(K, &V)> where @@ -423,32 +427,35 @@ impl UnordMap { items } + /// Returns the entries of this map in stable sort order (as defined by `ToStableHashKey`). + /// + /// The `cache_sort_key` parameter controls if [slice::sort_by_cached_key] or + /// [slice::sort_unstable_by_key] will be used for sorting the vec. Use + /// `cache_sort_key` when the [ToStableHashKey::to_stable_hash_key] implementation + /// for `K` is expensive (e.g. a `DefId -> DefPathHash` lookup). #[inline] pub fn into_sorted(self, hcx: &HCX, cache_sort_key: bool) -> Vec<(K, V)> where K: ToStableHashKey, { - let mut items: Vec<(K, V)> = self.inner.into_iter().collect(); - if cache_sort_key { - items.sort_by_cached_key(|(k, _)| k.to_stable_hash_key(hcx)); - } else { - items.sort_unstable_by_key(|(k, _)| k.to_stable_hash_key(hcx)); - } - items + to_sorted_vec(hcx, self.inner.into_iter(), cache_sort_key, |(k, _)| k) } + /// Returns the values of this map in stable sort order (as defined by K's + /// `ToStableHashKey` implementation). + /// + /// The `cache_sort_key` parameter controls if [slice::sort_by_cached_key] or + /// [slice::sort_unstable_by_key] will be used for sorting the vec. Use + /// `cache_sort_key` when the [ToStableHashKey::to_stable_hash_key] implementation + /// for `K` is expensive (e.g. a `DefId -> DefPathHash` lookup). #[inline] pub fn values_sorted(&self, hcx: &HCX, cache_sort_key: bool) -> impl Iterator where K: ToStableHashKey, { - let mut items: Vec<(&K, &V)> = self.inner.iter().collect(); - if cache_sort_key { - items.sort_by_cached_key(|(k, _)| k.to_stable_hash_key(hcx)); - } else { - items.sort_unstable_by_key(|(k, _)| k.to_stable_hash_key(hcx)); - } - items.into_iter().map(|(_, v)| v) + to_sorted_vec(hcx, self.inner.iter(), cache_sort_key, |&(k, _)| k) + .into_iter() + .map(|(_, v)| v) } } @@ -540,6 +547,27 @@ impl> HashStable for UnordBag { } } +#[inline] +fn to_sorted_vec( + hcx: &HCX, + iter: I, + cache_sort_key: bool, + extract_key: fn(&T) -> &K, +) -> Vec +where + I: Iterator, + K: ToStableHashKey, +{ + let mut items: Vec = iter.collect(); + if cache_sort_key { + items.sort_by_cached_key(|x| extract_key(x).to_stable_hash_key(hcx)); + } else { + items.sort_unstable_by_key(|x| extract_key(x).to_stable_hash_key(hcx)); + } + + items +} + fn hash_iter_order_independent< HCX, T: HashStable, From 5feeca01563155c2836342e028f81dab51289dc0 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 19 Jan 2023 20:25:46 +0100 Subject: [PATCH 190/230] Revert "Improve code" This reverts commit a954d6334d000225ae38f65f5f9e9c182e6764ae. --- src/librustdoc/visit_ast.rs | 183 ++++++++++++++++++------------------ 1 file changed, 93 insertions(+), 90 deletions(-) diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 7db470359672f..bcbdafd4b005b 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -8,6 +8,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{walk_item, Visitor}; use rustc_hir::Node; use rustc_hir::CRATE_HIR_ID; +use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE}; @@ -67,6 +68,7 @@ pub(crate) struct RustdocVisitor<'a, 'tcx> { inside_public_path: bool, exact_paths: FxHashMap>, modules: Vec>, + map: Map<'tcx>, } impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { @@ -79,6 +81,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { hir::CRATE_HIR_ID, cx.tcx.hir().root_module().spans.inner_span, ); + let map = cx.tcx.hir(); RustdocVisitor { cx, @@ -87,6 +90,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { inside_public_path: true, exact_paths: FxHashMap::default(), modules: vec![om], + map, } } @@ -95,95 +99,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { self.exact_paths.entry(did).or_insert_with(|| def_id_to_path(tcx, did)); } - pub(crate) fn visit(mut self) -> Module<'tcx> { - let root_module = self.cx.tcx.hir().root_module(); - self.visit_mod_contents(CRATE_HIR_ID, root_module); - - let mut top_level_module = self.modules.pop().unwrap(); - - // `#[macro_export] macro_rules!` items are reexported at the top level of the - // crate, regardless of where they're defined. We want to document the - // top level rexport of the macro, not its original definition, since - // the rexport defines the path that a user will actually see. Accordingly, - // we add the rexport as an item here, and then skip over the original - // definition in `visit_item()` below. - // - // We also skip `#[macro_export] macro_rules!` that have already been inserted, - // it can happen if within the same module a `#[macro_export] macro_rules!` - // is declared but also a reexport of itself producing two exports of the same - // macro in the same module. - let mut inserted = FxHashSet::default(); - for export in self.cx.tcx.module_reexports(CRATE_DEF_ID).unwrap_or(&[]) { - if let Res::Def(DefKind::Macro(_), def_id) = export.res && - let Some(local_def_id) = def_id.as_local() && - self.cx.tcx.has_attr(def_id, sym::macro_export) && - inserted.insert(def_id) - { - let item = self.cx.tcx.hir().expect_item(local_def_id); - top_level_module.items.push((item, None, None)); - } - } - - self.cx.cache.hidden_cfg = self - .cx - .tcx - .hir() - .attrs(CRATE_HIR_ID) - .iter() - .filter(|attr| attr.has_name(sym::doc)) - .flat_map(|attr| attr.meta_item_list().into_iter().flatten()) - .filter(|attr| attr.has_name(sym::cfg_hide)) - .flat_map(|attr| { - attr.meta_item_list() - .unwrap_or(&[]) - .iter() - .filter_map(|attr| { - Cfg::parse(attr.meta_item()?) - .map_err(|e| self.cx.sess().diagnostic().span_err(e.span, e.msg)) - .ok() - }) - .collect::>() - }) - .chain( - [Cfg::Cfg(sym::test, None), Cfg::Cfg(sym::doc, None), Cfg::Cfg(sym::doctest, None)] - .into_iter(), - ) - .collect(); - - self.cx.cache.exact_paths = self.exact_paths; - top_level_module - } - - /// This method will go through the given module items in two passes: - /// 1. The items which are not glob imports/reexports. - /// 2. The glob imports/reexports. - fn visit_mod_contents(&mut self, id: hir::HirId, m: &'tcx hir::Mod<'tcx>) { - debug!("Going through module {:?}", m); - let def_id = self.cx.tcx.hir().local_def_id(id).to_def_id(); - // Keep track of if there were any private modules in the path. - let orig_inside_public_path = self.inside_public_path; - self.inside_public_path &= self.cx.tcx.visibility(def_id).is_public(); - - // Reimplementation of `walk_mod` because we need to do it in two passes (explanations in - // the second loop): - for &i in m.item_ids { - let item = self.cx.tcx.hir().item(i); - if !matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) { - self.visit_item(item); - } - } - for &i in m.item_ids { - let item = self.cx.tcx.hir().item(i); - // To match the way import precedence works, visit glob imports last. - // Later passes in rustdoc will de-duplicate by name and kind, so if glob- - // imported items appear last, then they'll be the ones that get discarded. - if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) { - self.visit_item(item); - } - } - self.inside_public_path = orig_inside_public_path; - } - /// Tries to resolve the target of a `pub use` statement and inlines the /// target if it is defined locally and would not be documented otherwise, /// or when it is specifically requested with `please_inline`. @@ -408,6 +323,65 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } } + pub(crate) fn visit(mut self) -> Module<'tcx> { + let root_module = self.cx.tcx.hir().root_module(); + self.visit_mod_contents(CRATE_HIR_ID, root_module); + + let mut top_level_module = self.modules.pop().unwrap(); + + // `#[macro_export] macro_rules!` items are reexported at the top level of the + // crate, regardless of where they're defined. We want to document the + // top level rexport of the macro, not its original definition, since + // the rexport defines the path that a user will actually see. Accordingly, + // we add the rexport as an item here, and then skip over the original + // definition in `visit_item()` below. + // + // We also skip `#[macro_export] macro_rules!` that have already been inserted, + // it can happen if within the same module a `#[macro_export] macro_rules!` + // is declared but also a reexport of itself producing two exports of the same + // macro in the same module. + let mut inserted = FxHashSet::default(); + for export in self.cx.tcx.module_reexports(CRATE_DEF_ID).unwrap_or(&[]) { + if let Res::Def(DefKind::Macro(_), def_id) = export.res && + let Some(local_def_id) = def_id.as_local() && + self.cx.tcx.has_attr(def_id, sym::macro_export) && + inserted.insert(def_id) + { + let item = self.cx.tcx.hir().expect_item(local_def_id); + top_level_module.items.push((item, None, None)); + } + } + + self.cx.cache.hidden_cfg = self + .cx + .tcx + .hir() + .attrs(CRATE_HIR_ID) + .iter() + .filter(|attr| attr.has_name(sym::doc)) + .flat_map(|attr| attr.meta_item_list().into_iter().flatten()) + .filter(|attr| attr.has_name(sym::cfg_hide)) + .flat_map(|attr| { + attr.meta_item_list() + .unwrap_or(&[]) + .iter() + .filter_map(|attr| { + Cfg::parse(attr.meta_item()?) + .map_err(|e| self.cx.sess().diagnostic().span_err(e.span, e.msg)) + .ok() + }) + .collect::>() + }) + .chain( + [Cfg::Cfg(sym::test, None), Cfg::Cfg(sym::doc, None), Cfg::Cfg(sym::doctest, None)] + .into_iter(), + ) + .collect(); + + self.cx.cache.exact_paths = self.exact_paths; + top_level_module + } + /// This method will create a new module and push it onto the "modules stack" then call /// `visit_mod_contents`. Once done, it'll remove it from the "modules stack" and instead /// add into the list of modules of the current module. @@ -419,6 +393,35 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let last = self.modules.pop().unwrap(); self.modules.last_mut().unwrap().mods.push(last); } + + /// This method will go through the given module items in two passes: + /// 1. The items which are not glob imports/reexports. + /// 2. The glob imports/reexports. + fn visit_mod_contents(&mut self, id: hir::HirId, m: &'tcx hir::Mod<'tcx>) { + debug!("Going through module {:?}", m); + let def_id = self.cx.tcx.hir().local_def_id(id).to_def_id(); + // Keep track of if there were any private modules in the path. + let orig_inside_public_path = self.inside_public_path; + self.inside_public_path &= self.cx.tcx.visibility(def_id).is_public(); + + // Reimplementation of `walk_mod`: + for &i in m.item_ids { + let item = self.cx.tcx.hir().item(i); + if !matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) { + self.visit_item(item); + } + } + for &i in m.item_ids { + let item = self.cx.tcx.hir().item(i); + // To match the way import precedence works, visit glob imports last. + // Later passes in rustdoc will de-duplicate by name and kind, so if glob- + // imported items appear last, then they'll be the ones that get discarded. + if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) { + self.visit_item(item); + } + } + self.inside_public_path = orig_inside_public_path; + } } // We need to implement this visitor so it'll go everywhere and retrieve items we're interested in @@ -427,7 +430,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RustdocVisitor<'a, 'tcx> { type NestedFilter = nested_filter::All; fn nested_visit_map(&mut self) -> Self::Map { - self.cx.tcx.hir() + self.map } fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) { From 286a632e725826bb13f6710f188f4ed1af0d50cf Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 19 Jan 2023 20:25:53 +0100 Subject: [PATCH 191/230] Revert "Speed up execution a bit by removing some walks" This reverts commit a9d582f51f547583380f2f2894ae0c799b609a86. --- src/librustdoc/visit_ast.rs | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index bcbdafd4b005b..c5aaae7a908ca 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -250,6 +250,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { res, ident, is_glob, + om, please_inline, ) { continue; @@ -445,26 +446,6 @@ impl<'a, 'tcx> Visitor<'tcx> for RustdocVisitor<'a, 'tcx> { } fn visit_mod(&mut self, _: &hir::Mod<'tcx>, _: Span, _: hir::HirId) { - // Handled in `visit_item_inner` - } - - fn visit_use(&mut self, _: &hir::UsePath<'tcx>, _: hir::HirId) { - // Handled in `visit_item_inner` - } - - fn visit_path(&mut self, _: &hir::Path<'tcx>, _: hir::HirId) { - // Handled in `visit_item_inner` - } - - fn visit_label(&mut self, _: &rustc_ast::Label) { - // Unneeded. - } - - fn visit_infer(&mut self, _: &hir::InferArg) { - // Unneeded. - } - - fn visit_lifetime(&mut self, _: &hir::Lifetime) { - // Unneeded. + // handled in `visit_item_inner` } } From 8b80bc1bf4719270a9b4bf8f4cc682bb18a574c7 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 19 Jan 2023 20:26:01 +0100 Subject: [PATCH 192/230] Revert "Improve code readability" This reverts commit eb93d1bedeab64c6f5d661df6a309a5b8a9273ca. --- src/librustdoc/html/render/write_shared.rs | 2 +- src/librustdoc/visit_ast.rs | 36 +++++++++------------- 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index ca3e9916487aa..bc8badad38eb0 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -138,7 +138,7 @@ pub(super) fn write_shared( Ok((ret, krates)) } - /// Read a file and return all lines that match the "{crate}":{data},\ format, + /// Read a file and return all lines that match the "{crate}":{data},\ format, /// and return a tuple `(Vec, Vec)`. /// /// This forms the payload of files that look like this: diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index c5aaae7a908ca..a8fc85a3ee1d8 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -187,16 +187,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { ret } - #[inline] - fn add_to_current_mod( - &mut self, - item: &'tcx hir::Item<'_>, - renamed: Option, - parent_id: Option, - ) { - self.modules.last_mut().unwrap().items.push((item, renamed, parent_id)) - } - fn visit_item_inner( &mut self, item: &'tcx hir::Item<'_>, @@ -257,7 +247,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } } - self.add_to_current_mod(item, renamed, parent_id); + self.modules.last_mut().unwrap().items.push((item, renamed, parent_id)); } } hir::ItemKind::Macro(ref macro_def, _) => { @@ -277,7 +267,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let nonexported = !self.cx.tcx.has_attr(def_id, sym::macro_export); if is_macro_2_0 || nonexported || self.inlining { - self.add_to_current_mod(item, renamed, None); + self.modules.last_mut().unwrap().items.push((item, renamed, None)); } } hir::ItemKind::Mod(ref m) => { @@ -293,20 +283,20 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { | hir::ItemKind::Static(..) | hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) => { - self.add_to_current_mod(item, renamed, parent_id); + self.modules.last_mut().unwrap().items.push((item, renamed, parent_id)) } hir::ItemKind::Const(..) => { // Underscore constants do not correspond to a nameable item and // so are never useful in documentation. if name != kw::Underscore { - self.add_to_current_mod(item, renamed, parent_id); + self.modules.last_mut().unwrap().items.push((item, renamed, parent_id)); } } hir::ItemKind::Impl(impl_) => { // Don't duplicate impls when inlining or if it's implementing a trait, we'll pick // them up regardless of where they're located. if !self.inlining && impl_.of_trait.is_none() { - self.add_to_current_mod(item, None, None); + self.modules.last_mut().unwrap().items.push((item, None, None)); } } } @@ -343,13 +333,15 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { // macro in the same module. let mut inserted = FxHashSet::default(); for export in self.cx.tcx.module_reexports(CRATE_DEF_ID).unwrap_or(&[]) { - if let Res::Def(DefKind::Macro(_), def_id) = export.res && - let Some(local_def_id) = def_id.as_local() && - self.cx.tcx.has_attr(def_id, sym::macro_export) && - inserted.insert(def_id) - { - let item = self.cx.tcx.hir().expect_item(local_def_id); - top_level_module.items.push((item, None, None)); + if let Res::Def(DefKind::Macro(_), def_id) = export.res { + if let Some(local_def_id) = def_id.as_local() { + if self.cx.tcx.has_attr(def_id, sym::macro_export) { + if inserted.insert(def_id) { + let item = self.cx.tcx.hir().expect_item(local_def_id); + top_level_module.items.push((item, None, None)); + } + } + } } } From 69de8fbbebaede4b8cb89fb75d1c7a14bd4a2642 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 19 Jan 2023 20:27:00 +0100 Subject: [PATCH 193/230] Revert "Update newly failing UI tests" This reverts commit 9c46173895430c63066731440e00faf0ab2195dd. --- .../infinite-recursive-type-impl-trait-return.rs | 4 +++- ...inite-recursive-type-impl-trait-return.stderr | 16 ---------------- .../infinite-recursive-type-impl-trait.rs | 5 ++++- .../infinite-recursive-type-impl-trait.stderr | 16 ---------------- 4 files changed, 7 insertions(+), 34 deletions(-) delete mode 100644 tests/rustdoc-ui/infinite-recursive-type-impl-trait-return.stderr delete mode 100644 tests/rustdoc-ui/infinite-recursive-type-impl-trait.stderr diff --git a/tests/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs b/tests/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs index 939da186fbcdb..4b1e04234c870 100644 --- a/tests/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs +++ b/tests/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs @@ -1,10 +1,12 @@ +// check-pass // normalize-stderr-test: "`.*`" -> "`DEF_ID`" // normalize-stdout-test: "`.*`" -> "`DEF_ID`" // edition:2018 pub async fn f() -> impl std::fmt::Debug { + // rustdoc doesn't care that this is infinitely sized #[derive(Debug)] - enum E { //~ ERROR + enum E { This(E), Unit, } diff --git a/tests/rustdoc-ui/infinite-recursive-type-impl-trait-return.stderr b/tests/rustdoc-ui/infinite-recursive-type-impl-trait-return.stderr deleted file mode 100644 index aff7402bc91c6..0000000000000 --- a/tests/rustdoc-ui/infinite-recursive-type-impl-trait-return.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0072]: recursive type `DEF_ID` has infinite size - --> $DIR/infinite-recursive-type-impl-trait-return.rs:7:5 - | -LL | enum E { - | ^^^^^^ -LL | This(E), - | - recursive without indirection - | -help: insert some indirection (e.g., a `DEF_ID`) to break the cycle - | -LL | This(Box), - | ++++ + - -error: aborting due to previous error - -For more information about this error, try `DEF_ID`. diff --git a/tests/rustdoc-ui/infinite-recursive-type-impl-trait.rs b/tests/rustdoc-ui/infinite-recursive-type-impl-trait.rs index ac51725749867..ac79582fb3f0d 100644 --- a/tests/rustdoc-ui/infinite-recursive-type-impl-trait.rs +++ b/tests/rustdoc-ui/infinite-recursive-type-impl-trait.rs @@ -1,5 +1,8 @@ +// check-pass + fn f() -> impl Sized { - enum E { //~ ERROR + // rustdoc doesn't care that this is infinitely sized + enum E { V(E), } unimplemented!() diff --git a/tests/rustdoc-ui/infinite-recursive-type-impl-trait.stderr b/tests/rustdoc-ui/infinite-recursive-type-impl-trait.stderr deleted file mode 100644 index a61577bd14afc..0000000000000 --- a/tests/rustdoc-ui/infinite-recursive-type-impl-trait.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0072]: recursive type `f::E` has infinite size - --> $DIR/infinite-recursive-type-impl-trait.rs:2:5 - | -LL | enum E { - | ^^^^^^ -LL | V(E), - | - recursive without indirection - | -help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle - | -LL | V(Box), - | ++++ + - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0072`. From 13239a9b8e75f871e004a8167f67c7ed399dde01 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 19 Jan 2023 20:27:37 +0100 Subject: [PATCH 194/230] Revert "Add regression test for impl blocks in const expr" This reverts commit 9cce0bc583ee2cff88935ce0e08d8ec1eb1239a8. --- tests/rustdoc/impl-in-const-block.rs | 43 ---------------------------- 1 file changed, 43 deletions(-) delete mode 100644 tests/rustdoc/impl-in-const-block.rs diff --git a/tests/rustdoc/impl-in-const-block.rs b/tests/rustdoc/impl-in-const-block.rs deleted file mode 100644 index b44e713524668..0000000000000 --- a/tests/rustdoc/impl-in-const-block.rs +++ /dev/null @@ -1,43 +0,0 @@ -// Regression test for #83026. -// The goal of this test is to ensure that impl blocks inside -// const expressions are documented as well. - -#![crate_name = "foo"] - -// @has 'foo/struct.A.html' -// @has - '//*[@id="method.new"]/*[@class="code-header"]' 'pub fn new() -> A' -// @has - '//*[@id="method.bar"]/*[@class="code-header"]' 'pub fn bar(&self)' -// @has - '//*[@id="method.woo"]/*[@class="code-header"]' 'pub fn woo(&self)' -// @has - '//*[@id="method.yoo"]/*[@class="code-header"]' 'pub fn yoo()' -// @has - '//*[@id="method.yuu"]/*[@class="code-header"]' 'pub fn yuu()' -pub struct A; - -const _: () = { - impl A { - const FOO: () = { - impl A { - pub fn woo(&self) {} - } - }; - - pub fn new() -> A { - A - } - } -}; -pub const X: () = { - impl A { - pub fn bar(&self) {} - } -}; - -fn foo() { - impl A { - pub fn yoo() {} - } - const _: () = { - impl A { - pub fn yuu() {} - } - }; -} From a22cd9cdfad00d28b7116a8ddae91f7fada7473f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 19 Jan 2023 20:28:17 +0100 Subject: [PATCH 195/230] Revert "Fix missing const expression items visit" This reverts commit cdfc5051b1286938f56160243c28538f79dce6b1. --- src/librustdoc/visit_ast.rs | 273 +++++++++++++++--------------------- 1 file changed, 115 insertions(+), 158 deletions(-) diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index a8fc85a3ee1d8..22068ebe041c7 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -5,11 +5,8 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::intravisit::{walk_item, Visitor}; use rustc_hir::Node; use rustc_hir::CRATE_HIR_ID; -use rustc_middle::hir::map::Map; -use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE}; use rustc_span::symbol::{kw, sym, Symbol}; @@ -60,6 +57,9 @@ pub(crate) fn inherits_doc_hidden(tcx: TyCtxt<'_>, mut node: hir::HirId) -> bool false } +// Also, is there some reason that this doesn't use the 'visit' +// framework from syntax?. + pub(crate) struct RustdocVisitor<'a, 'tcx> { cx: &'a mut core::DocContext<'tcx>, view_item_stack: FxHashSet, @@ -67,8 +67,6 @@ pub(crate) struct RustdocVisitor<'a, 'tcx> { /// Are the current module and all of its parents public? inside_public_path: bool, exact_paths: FxHashMap>, - modules: Vec>, - map: Map<'tcx>, } impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { @@ -76,21 +74,12 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { // If the root is re-exported, terminate all recursion. let mut stack = FxHashSet::default(); stack.insert(hir::CRATE_HIR_ID); - let om = Module::new( - cx.tcx.crate_name(LOCAL_CRATE), - hir::CRATE_HIR_ID, - cx.tcx.hir().root_module().spans.inner_span, - ); - let map = cx.tcx.hir(); - RustdocVisitor { cx, view_item_stack: stack, inlining: false, inside_public_path: true, exact_paths: FxHashMap::default(), - modules: vec![om], - map, } } @@ -99,6 +88,101 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { self.exact_paths.entry(did).or_insert_with(|| def_id_to_path(tcx, did)); } + pub(crate) fn visit(mut self) -> Module<'tcx> { + let mut top_level_module = self.visit_mod_contents( + hir::CRATE_HIR_ID, + self.cx.tcx.hir().root_module(), + self.cx.tcx.crate_name(LOCAL_CRATE), + None, + ); + + // `#[macro_export] macro_rules!` items are reexported at the top level of the + // crate, regardless of where they're defined. We want to document the + // top level rexport of the macro, not its original definition, since + // the rexport defines the path that a user will actually see. Accordingly, + // we add the rexport as an item here, and then skip over the original + // definition in `visit_item()` below. + // + // We also skip `#[macro_export] macro_rules!` that have already been inserted, + // it can happen if within the same module a `#[macro_export] macro_rules!` + // is declared but also a reexport of itself producing two exports of the same + // macro in the same module. + let mut inserted = FxHashSet::default(); + for export in self.cx.tcx.module_reexports(CRATE_DEF_ID).unwrap_or(&[]) { + if let Res::Def(DefKind::Macro(_), def_id) = export.res { + if let Some(local_def_id) = def_id.as_local() { + if self.cx.tcx.has_attr(def_id, sym::macro_export) { + if inserted.insert(def_id) { + let item = self.cx.tcx.hir().expect_item(local_def_id); + top_level_module.items.push((item, None, None)); + } + } + } + } + } + + self.cx.cache.hidden_cfg = self + .cx + .tcx + .hir() + .attrs(CRATE_HIR_ID) + .iter() + .filter(|attr| attr.has_name(sym::doc)) + .flat_map(|attr| attr.meta_item_list().into_iter().flatten()) + .filter(|attr| attr.has_name(sym::cfg_hide)) + .flat_map(|attr| { + attr.meta_item_list() + .unwrap_or(&[]) + .iter() + .filter_map(|attr| { + Cfg::parse(attr.meta_item()?) + .map_err(|e| self.cx.sess().diagnostic().span_err(e.span, e.msg)) + .ok() + }) + .collect::>() + }) + .chain( + [Cfg::Cfg(sym::test, None), Cfg::Cfg(sym::doc, None), Cfg::Cfg(sym::doctest, None)] + .into_iter(), + ) + .collect(); + + self.cx.cache.exact_paths = self.exact_paths; + top_level_module + } + + fn visit_mod_contents( + &mut self, + id: hir::HirId, + m: &'tcx hir::Mod<'tcx>, + name: Symbol, + parent_id: Option, + ) -> Module<'tcx> { + let mut om = Module::new(name, id, m.spans.inner_span); + let def_id = self.cx.tcx.hir().local_def_id(id).to_def_id(); + // Keep track of if there were any private modules in the path. + let orig_inside_public_path = self.inside_public_path; + self.inside_public_path &= self.cx.tcx.visibility(def_id).is_public(); + for &i in m.item_ids { + let item = self.cx.tcx.hir().item(i); + if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) { + continue; + } + self.visit_item(item, None, &mut om, parent_id); + } + for &i in m.item_ids { + let item = self.cx.tcx.hir().item(i); + // To match the way import precedence works, visit glob imports last. + // Later passes in rustdoc will de-duplicate by name and kind, so if glob- + // imported items appear last, then they'll be the ones that get discarded. + if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) { + self.visit_item(item, None, &mut om, parent_id); + } + } + self.inside_public_path = orig_inside_public_path; + om + } + /// Tries to resolve the target of a `pub use` statement and inlines the /// target if it is defined locally and would not be documented otherwise, /// or when it is specifically requested with `please_inline`. @@ -114,6 +198,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { res: Res, renamed: Option, glob: bool, + om: &mut Module<'tcx>, please_inline: bool, ) -> bool { debug!("maybe_inline_local res: {:?}", res); @@ -164,20 +249,20 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let prev = mem::replace(&mut self.inlining, true); for &i in m.item_ids { let i = self.cx.tcx.hir().item(i); - self.visit_item_inner(i, None, Some(id)); + self.visit_item(i, None, om, Some(id)); } self.inlining = prev; true } Node::Item(it) if !glob => { let prev = mem::replace(&mut self.inlining, true); - self.visit_item_inner(it, renamed, Some(id)); + self.visit_item(it, renamed, om, Some(id)); self.inlining = prev; true } Node::ForeignItem(it) if !glob => { let prev = mem::replace(&mut self.inlining, true); - self.visit_foreign_item_inner(it, renamed); + self.visit_foreign_item(it, renamed, om); self.inlining = prev; true } @@ -187,12 +272,13 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { ret } - fn visit_item_inner( + fn visit_item( &mut self, item: &'tcx hir::Item<'_>, renamed: Option, + om: &mut Module<'tcx>, parent_id: Option, - ) -> bool { + ) { debug!("visiting item {:?}", item); let name = renamed.unwrap_or(item.ident.name); @@ -207,7 +293,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { hir::ItemKind::ForeignMod { items, .. } => { for item in items { let item = self.cx.tcx.hir().foreign_item(item.id); - self.visit_foreign_item_inner(item, None); + self.visit_foreign_item(item, None, om); } } // If we're inlining, skip private items or item reexported as "_". @@ -247,7 +333,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } } - self.modules.last_mut().unwrap().items.push((item, renamed, parent_id)); + om.items.push((item, renamed, parent_id)) } } hir::ItemKind::Macro(ref macro_def, _) => { @@ -267,11 +353,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let nonexported = !self.cx.tcx.has_attr(def_id, sym::macro_export); if is_macro_2_0 || nonexported || self.inlining { - self.modules.last_mut().unwrap().items.push((item, renamed, None)); + om.items.push((item, renamed, None)); } } hir::ItemKind::Mod(ref m) => { - self.enter_mod(item.hir_id(), m, name); + om.mods.push(self.visit_mod_contents(item.hir_id(), m, name, parent_id)); } hir::ItemKind::Fn(..) | hir::ItemKind::ExternCrate(..) @@ -282,162 +368,33 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { | hir::ItemKind::OpaqueTy(..) | hir::ItemKind::Static(..) | hir::ItemKind::Trait(..) - | hir::ItemKind::TraitAlias(..) => { - self.modules.last_mut().unwrap().items.push((item, renamed, parent_id)) - } + | hir::ItemKind::TraitAlias(..) => om.items.push((item, renamed, parent_id)), hir::ItemKind::Const(..) => { // Underscore constants do not correspond to a nameable item and // so are never useful in documentation. if name != kw::Underscore { - self.modules.last_mut().unwrap().items.push((item, renamed, parent_id)); + om.items.push((item, renamed, parent_id)); } } hir::ItemKind::Impl(impl_) => { // Don't duplicate impls when inlining or if it's implementing a trait, we'll pick // them up regardless of where they're located. if !self.inlining && impl_.of_trait.is_none() { - self.modules.last_mut().unwrap().items.push((item, None, None)); + om.items.push((item, None, None)); } } } - true } - fn visit_foreign_item_inner( + fn visit_foreign_item( &mut self, item: &'tcx hir::ForeignItem<'_>, renamed: Option, + om: &mut Module<'tcx>, ) { // If inlining we only want to include public functions. if !self.inlining || self.cx.tcx.visibility(item.owner_id).is_public() { - self.modules.last_mut().unwrap().foreigns.push((item, renamed)); + om.foreigns.push((item, renamed)); } } - - pub(crate) fn visit(mut self) -> Module<'tcx> { - let root_module = self.cx.tcx.hir().root_module(); - self.visit_mod_contents(CRATE_HIR_ID, root_module); - - let mut top_level_module = self.modules.pop().unwrap(); - - // `#[macro_export] macro_rules!` items are reexported at the top level of the - // crate, regardless of where they're defined. We want to document the - // top level rexport of the macro, not its original definition, since - // the rexport defines the path that a user will actually see. Accordingly, - // we add the rexport as an item here, and then skip over the original - // definition in `visit_item()` below. - // - // We also skip `#[macro_export] macro_rules!` that have already been inserted, - // it can happen if within the same module a `#[macro_export] macro_rules!` - // is declared but also a reexport of itself producing two exports of the same - // macro in the same module. - let mut inserted = FxHashSet::default(); - for export in self.cx.tcx.module_reexports(CRATE_DEF_ID).unwrap_or(&[]) { - if let Res::Def(DefKind::Macro(_), def_id) = export.res { - if let Some(local_def_id) = def_id.as_local() { - if self.cx.tcx.has_attr(def_id, sym::macro_export) { - if inserted.insert(def_id) { - let item = self.cx.tcx.hir().expect_item(local_def_id); - top_level_module.items.push((item, None, None)); - } - } - } - } - } - - self.cx.cache.hidden_cfg = self - .cx - .tcx - .hir() - .attrs(CRATE_HIR_ID) - .iter() - .filter(|attr| attr.has_name(sym::doc)) - .flat_map(|attr| attr.meta_item_list().into_iter().flatten()) - .filter(|attr| attr.has_name(sym::cfg_hide)) - .flat_map(|attr| { - attr.meta_item_list() - .unwrap_or(&[]) - .iter() - .filter_map(|attr| { - Cfg::parse(attr.meta_item()?) - .map_err(|e| self.cx.sess().diagnostic().span_err(e.span, e.msg)) - .ok() - }) - .collect::>() - }) - .chain( - [Cfg::Cfg(sym::test, None), Cfg::Cfg(sym::doc, None), Cfg::Cfg(sym::doctest, None)] - .into_iter(), - ) - .collect(); - - self.cx.cache.exact_paths = self.exact_paths; - top_level_module - } - - /// This method will create a new module and push it onto the "modules stack" then call - /// `visit_mod_contents`. Once done, it'll remove it from the "modules stack" and instead - /// add into the list of modules of the current module. - fn enter_mod(&mut self, id: hir::HirId, m: &'tcx hir::Mod<'tcx>, name: Symbol) { - self.modules.push(Module::new(name, id, m.spans.inner_span)); - - self.visit_mod_contents(id, m); - - let last = self.modules.pop().unwrap(); - self.modules.last_mut().unwrap().mods.push(last); - } - - /// This method will go through the given module items in two passes: - /// 1. The items which are not glob imports/reexports. - /// 2. The glob imports/reexports. - fn visit_mod_contents(&mut self, id: hir::HirId, m: &'tcx hir::Mod<'tcx>) { - debug!("Going through module {:?}", m); - let def_id = self.cx.tcx.hir().local_def_id(id).to_def_id(); - // Keep track of if there were any private modules in the path. - let orig_inside_public_path = self.inside_public_path; - self.inside_public_path &= self.cx.tcx.visibility(def_id).is_public(); - - // Reimplementation of `walk_mod`: - for &i in m.item_ids { - let item = self.cx.tcx.hir().item(i); - if !matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) { - self.visit_item(item); - } - } - for &i in m.item_ids { - let item = self.cx.tcx.hir().item(i); - // To match the way import precedence works, visit glob imports last. - // Later passes in rustdoc will de-duplicate by name and kind, so if glob- - // imported items appear last, then they'll be the ones that get discarded. - if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) { - self.visit_item(item); - } - } - self.inside_public_path = orig_inside_public_path; - } -} - -// We need to implement this visitor so it'll go everywhere and retrieve items we're interested in -// such as impl blocks in const blocks. -impl<'a, 'tcx> Visitor<'tcx> for RustdocVisitor<'a, 'tcx> { - type NestedFilter = nested_filter::All; - - fn nested_visit_map(&mut self) -> Self::Map { - self.map - } - - fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) { - let parent_id = if self.modules.len() > 1 { - Some(self.modules[self.modules.len() - 2].id) - } else { - None - }; - if self.visit_item_inner(i, None, parent_id) { - walk_item(self, i); - } - } - - fn visit_mod(&mut self, _: &hir::Mod<'tcx>, _: Span, _: hir::HirId) { - // handled in `visit_item_inner` - } } From 33e11a3b2e2f2ee68fb2cb72e20f84c50c4c15cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 14 Jan 2023 23:53:56 +0000 Subject: [PATCH 196/230] Tweak "borrow closure argument" suggestion Fix #45727. --- .../src/traits/error_reporting/mod.rs | 1 + .../src/traits/error_reporting/suggestions.rs | 33 +++++++--- .../anonymous-higher-ranked-lifetime.stderr | 62 +++++++++++-------- tests/ui/closures/multiple-fn-bounds.stderr | 10 +-- ...losure-arg-type-mismatch-issue-45727.fixed | 5 ++ .../closure-arg-type-mismatch-issue-45727.rs | 5 ++ ...osure-arg-type-mismatch-issue-45727.stderr | 38 ++++++++++++ .../closure-arg-type-mismatch.stderr | 10 +-- .../ui/mismatched_types/issue-36053-2.stderr | 10 +-- 9 files changed, 127 insertions(+), 47 deletions(-) create mode 100644 tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.fixed create mode 100644 tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs create mode 100644 tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.stderr diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 434f75de02bff..52971486c553e 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1350,6 +1350,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { expected_trait_ref, obligation.cause.code(), found_node, + obligation.param_env, ) } else { let (closure_span, closure_arg_span, found) = found_did diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 195bbe92f8b3a..39e50b2accf17 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -283,6 +283,7 @@ pub trait TypeErrCtxtExt<'tcx> { expected: ty::PolyTraitRef<'tcx>, cause: &ObligationCauseCode<'tcx>, found_node: Option>, + param_env: ty::ParamEnv<'tcx>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>; fn note_conflicting_closure_bounds( @@ -1978,6 +1979,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { expected: ty::PolyTraitRef<'tcx>, cause: &ObligationCauseCode<'tcx>, found_node: Option>, + param_env: ty::ParamEnv<'tcx>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { pub(crate) fn build_fn_sig_ty<'tcx>( infcx: &InferCtxt<'tcx>, @@ -2040,7 +2042,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.note_conflicting_closure_bounds(cause, &mut err); if let Some(found_node) = found_node { - hint_missing_borrow(span, found, expected, found_node, &mut err); + hint_missing_borrow(self, param_env, span, found, expected, found_node, &mut err); } err @@ -3747,6 +3749,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { /// Add a hint to add a missing borrow or remove an unnecessary one. fn hint_missing_borrow<'tcx>( + infcx: &InferCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, span: Span, found: Ty<'tcx>, expected: Ty<'tcx>, @@ -3769,7 +3773,7 @@ fn hint_missing_borrow<'tcx>( // This could be a variant constructor, for example. let Some(fn_decl) = found_node.fn_decl() else { return; }; - let arg_spans = fn_decl.inputs.iter().map(|ty| ty.span); + let args = fn_decl.inputs.iter().map(|ty| ty); fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) { let mut refs = 0; @@ -3785,21 +3789,34 @@ fn hint_missing_borrow<'tcx>( let mut to_borrow = Vec::new(); let mut remove_borrow = Vec::new(); - for ((found_arg, expected_arg), arg_span) in found_args.zip(expected_args).zip(arg_spans) { + for ((found_arg, expected_arg), arg) in found_args.zip(expected_args).zip(args) { let (found_ty, found_refs) = get_deref_type_and_refs(*found_arg); let (expected_ty, expected_refs) = get_deref_type_and_refs(*expected_arg); - if found_ty == expected_ty { + if infcx.can_eq(param_env, found_ty, expected_ty).is_ok() { if found_refs < expected_refs { - to_borrow.push((arg_span, expected_arg.to_string())); + to_borrow.push((arg.span.shrink_to_lo(), "&".repeat(expected_refs - found_refs))); } else if found_refs > expected_refs { - remove_borrow.push((arg_span, expected_arg.to_string())); + let mut span = arg.span.shrink_to_lo(); + let mut left = found_refs - expected_refs; + let mut ty = arg; + while let hir::TyKind::Ref(_, mut_ty) = &ty.kind && left > 0 { + span = span.with_hi(mut_ty.ty.span.lo()); + ty = mut_ty.ty; + left -= 1; + } + let sugg = if left == 0 { + (span, String::new()) + } else { + (arg.span, expected_arg.to_string()) + }; + remove_borrow.push(sugg); } } } if !to_borrow.is_empty() { - err.multipart_suggestion( + err.multipart_suggestion_verbose( "consider borrowing the argument", to_borrow, Applicability::MaybeIncorrect, @@ -3807,7 +3824,7 @@ fn hint_missing_borrow<'tcx>( } if !remove_borrow.is_empty() { - err.multipart_suggestion( + err.multipart_suggestion_verbose( "do not borrow the argument", remove_borrow, Applicability::MaybeIncorrect, diff --git a/tests/ui/anonymous-higher-ranked-lifetime.stderr b/tests/ui/anonymous-higher-ranked-lifetime.stderr index afb7f8fea92a1..c023d1b159056 100644 --- a/tests/ui/anonymous-higher-ranked-lifetime.stderr +++ b/tests/ui/anonymous-higher-ranked-lifetime.stderr @@ -16,7 +16,7 @@ LL | fn f1(_: F) where F: Fn(&(), &()) {} help: consider borrowing the argument | LL | f1(|_: &(), _: &()| {}); - | ~~~ ~~~ + | + + error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:3:5 @@ -35,8 +35,8 @@ LL | fn f2(_: F) where F: for<'a> Fn(&'a (), &()) {} | ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `f2` help: consider borrowing the argument | -LL | f2(|_: &'a (), _: &()| {}); - | ~~~~~~ ~~~ +LL | f2(|_: &(), _: &()| {}); + | + + error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:4:5 @@ -56,7 +56,7 @@ LL | fn f3<'a, F>(_: F) where F: Fn(&'a (), &()) {} help: consider borrowing the argument | LL | f3(|_: &(), _: &()| {}); - | ~~~ ~~~ + | + + error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:5:5 @@ -75,8 +75,8 @@ LL | fn f4(_: F) where F: for<'r> Fn(&(), &'r ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `f4` help: consider borrowing the argument | -LL | f4(|_: &(), _: &'r ()| {}); - | ~~~ ~~~~~~ +LL | f4(|_: &(), _: &()| {}); + | + + error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:6:5 @@ -95,17 +95,15 @@ LL | fn f5(_: F) where F: for<'r> Fn(&'r (), &'r ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `f5` help: consider borrowing the argument | -LL | f5(|_: &'r (), _: &'r ()| {}); - | ~~~~~~ ~~~~~~ +LL | f5(|_: &(), _: &()| {}); + | + + error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:7:5 | LL | g1(|_: (), _: ()| {}); - | ^^ -------------- - | | | | - | | | help: consider borrowing the argument: `&()` - | | found signature defined here + | ^^ -------------- found signature defined here + | | | expected due to this | = note: expected closure signature `for<'a> fn(&'a (), Box<(dyn for<'a> Fn(&'a ()) + 'static)>) -> _` @@ -115,15 +113,17 @@ note: required by a bound in `g1` | LL | fn g1(_: F) where F: Fn(&(), Box) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `g1` +help: consider borrowing the argument + | +LL | g1(|_: &(), _: ()| {}); + | + error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:8:5 | LL | g2(|_: (), _: ()| {}); - | ^^ -------------- - | | | | - | | | help: consider borrowing the argument: `&()` - | | found signature defined here + | ^^ -------------- found signature defined here + | | | expected due to this | = note: expected closure signature `for<'a> fn(&'a (), for<'a> fn(&'a ())) -> _` @@ -133,15 +133,17 @@ note: required by a bound in `g2` | LL | fn g2(_: F) where F: Fn(&(), fn(&())) {} | ^^^^^^^^^^^^^^^^ required by this bound in `g2` +help: consider borrowing the argument + | +LL | g2(|_: &(), _: ()| {}); + | + error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:9:5 | LL | g3(|_: (), _: ()| {}); - | ^^ -------------- - | | | | - | | | help: consider borrowing the argument: `&'s ()` - | | found signature defined here + | ^^ -------------- found signature defined here + | | | expected due to this | = note: expected closure signature `for<'s> fn(&'s (), Box<(dyn for<'a> Fn(&'a ()) + 'static)>) -> _` @@ -151,15 +153,17 @@ note: required by a bound in `g3` | LL | fn g3(_: F) where F: for<'s> Fn(&'s (), Box) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `g3` +help: consider borrowing the argument + | +LL | g3(|_: &(), _: ()| {}); + | + error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:10:5 | LL | g4(|_: (), _: ()| {}); - | ^^ -------------- - | | | | - | | | help: consider borrowing the argument: `&()` - | | found signature defined here + | ^^ -------------- found signature defined here + | | | expected due to this | = note: expected closure signature `for<'a> fn(&'a (), for<'r> fn(&'r ())) -> _` @@ -169,6 +173,10 @@ note: required by a bound in `g4` | LL | fn g4(_: F) where F: Fn(&(), for<'r> fn(&'r ())) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `g4` +help: consider borrowing the argument + | +LL | g4(|_: &(), _: ()| {}); + | + error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:11:5 @@ -188,7 +196,7 @@ LL | fn h1(_: F) where F: Fn(&(), Box, &(), fn(&(), &())) {} help: consider borrowing the argument | LL | h1(|_: &(), _: (), _: &(), _: ()| {}); - | ~~~ ~~~ + | + + error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:12:5 @@ -207,8 +215,8 @@ LL | fn h2(_: F) where F: for<'t0> Fn(&(), Box, &'t0 (), fn(&(), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `h2` help: consider borrowing the argument | -LL | h2(|_: &(), _: (), _: &'t0 (), _: ()| {}); - | ~~~ ~~~~~~~ +LL | h2(|_: &(), _: (), _: &(), _: ()| {}); + | + + error: aborting due to 11 previous errors diff --git a/tests/ui/closures/multiple-fn-bounds.stderr b/tests/ui/closures/multiple-fn-bounds.stderr index da26302c9d8a4..32a1edb0024c0 100644 --- a/tests/ui/closures/multiple-fn-bounds.stderr +++ b/tests/ui/closures/multiple-fn-bounds.stderr @@ -2,10 +2,8 @@ error[E0631]: type mismatch in closure arguments --> $DIR/multiple-fn-bounds.rs:10:5 | LL | foo(move |x| v); - | ^^^ -------- - | | | | - | | | help: do not borrow the argument: `char` - | | found signature defined here + | ^^^ -------- found signature defined here + | | | expected due to this | = note: expected closure signature `fn(char) -> _` @@ -20,6 +18,10 @@ note: required by a bound in `foo` | LL | fn foo bool + Fn(char) -> bool>(f: F) { | ^^^^^^^^^^^^^^^^ required by this bound in `foo` +help: do not borrow the argument + | +LL | foo(move |char| v); + | ~~~~ error: aborting due to previous error diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.fixed b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.fixed new file mode 100644 index 0000000000000..6315fcca2b8b0 --- /dev/null +++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.fixed @@ -0,0 +1,5 @@ +// run-rustfix +fn main() { + let _ = (-10..=10).find(|x: &i32| x.signum() == 0); //~ ERROR type mismatch in closure arguments + let _ = (-10..=10).find(|x: &i32| x.signum() == 0); //~ ERROR type mismatch in closure arguments +} diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs new file mode 100644 index 0000000000000..c12c5362efcfe --- /dev/null +++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs @@ -0,0 +1,5 @@ +// run-rustfix +fn main() { + let _ = (-10..=10).find(|x: i32| x.signum() == 0); //~ ERROR type mismatch in closure arguments + let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0); //~ ERROR type mismatch in closure arguments +} diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.stderr b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.stderr new file mode 100644 index 0000000000000..fb8af4bb7dd29 --- /dev/null +++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.stderr @@ -0,0 +1,38 @@ +error[E0631]: type mismatch in closure arguments + --> $DIR/closure-arg-type-mismatch-issue-45727.rs:3:24 + | +LL | let _ = (-10..=10).find(|x: i32| x.signum() == 0); + | ^^^^ -------- found signature defined here + | | + | expected due to this + | + = note: expected closure signature `for<'a> fn(&'a {integer}) -> _` + found closure signature `fn(i32) -> _` +note: required by a bound in `find` + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL +help: consider borrowing the argument + | +LL | let _ = (-10..=10).find(|x: &i32| x.signum() == 0); + | + + +error[E0631]: type mismatch in closure arguments + --> $DIR/closure-arg-type-mismatch-issue-45727.rs:4:24 + | +LL | let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0); + | ^^^^ ----------- found signature defined here + | | + | expected due to this + | + = note: expected closure signature `for<'a> fn(&'a {integer}) -> _` + found closure signature `for<'a, 'b, 'c> fn(&'a &'b &'c i32) -> _` +note: required by a bound in `find` + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL +help: do not borrow the argument + | +LL - let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0); +LL + let _ = (-10..=10).find(|x: &i32| x.signum() == 0); + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0631`. diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch.stderr b/tests/ui/mismatched_types/closure-arg-type-mismatch.stderr index fab9b7edc0cc5..811ff0533f012 100644 --- a/tests/ui/mismatched_types/closure-arg-type-mismatch.stderr +++ b/tests/ui/mismatched_types/closure-arg-type-mismatch.stderr @@ -2,16 +2,18 @@ error[E0631]: type mismatch in closure arguments --> $DIR/closure-arg-type-mismatch.rs:3:14 | LL | a.iter().map(|_: (u32, u32)| 45); - | ^^^ --------------- - | | | | - | | | help: consider borrowing the argument: `&(u32, u32)` - | | found signature defined here + | ^^^ --------------- found signature defined here + | | | expected due to this | = note: expected closure signature `fn(&(u32, u32)) -> _` found closure signature `fn((u32, u32)) -> _` note: required by a bound in `map` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL +help: consider borrowing the argument + | +LL | a.iter().map(|_: &(u32, u32)| 45); + | + error[E0631]: type mismatch in closure arguments --> $DIR/closure-arg-type-mismatch.rs:4:14 diff --git a/tests/ui/mismatched_types/issue-36053-2.stderr b/tests/ui/mismatched_types/issue-36053-2.stderr index 72fb0e4d77431..a6764a1dc6d31 100644 --- a/tests/ui/mismatched_types/issue-36053-2.stderr +++ b/tests/ui/mismatched_types/issue-36053-2.stderr @@ -2,16 +2,18 @@ error[E0631]: type mismatch in closure arguments --> $DIR/issue-36053-2.rs:7:32 | LL | once::<&str>("str").fuse().filter(|a: &str| true).count(); - | ^^^^^^ --------- - | | | | - | | | help: consider borrowing the argument: `&&str` - | | found signature defined here + | ^^^^^^ --------- found signature defined here + | | | expected due to this | = note: expected closure signature `for<'a> fn(&'a &str) -> _` found closure signature `for<'a> fn(&'a str) -> _` note: required by a bound in `filter` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL +help: consider borrowing the argument + | +LL | once::<&str>("str").fuse().filter(|a: &&str| true).count(); + | + error[E0599]: the method `count` exists for struct `Filter>, [closure@issue-36053-2.rs:7:39]>`, but its trait bounds were not satisfied --> $DIR/issue-36053-2.rs:7:55 From 3eecdd10a2e145c1744592784de41a0d6e7c30a2 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 11 Jan 2023 19:42:27 +0000 Subject: [PATCH 197/230] Fix known-bug, silence ICE stderr --- tests/ui/chalkify/bugs/async.rs | 6 ++--- .../ui/const-generics/issues/issue-85031-2.rs | 3 +-- .../issues/issue-85031-2.stderr | 1 - .../bugs/hrtb-implied-1.rs | 3 +-- .../bugs/hrtb-implied-1.stderr | 2 +- .../bugs/hrtb-implied-2.rs | 3 +-- .../bugs/issue-100013.rs | 6 +---- .../bugs/issue-100013.stderr | 24 ++++++++----------- .../bugs/issue-91762.rs | 3 +-- 9 files changed, 19 insertions(+), 32 deletions(-) diff --git a/tests/ui/chalkify/bugs/async.rs b/tests/ui/chalkify/bugs/async.rs index 1c69b07e3d4af..3169e4781ee2e 100644 --- a/tests/ui/chalkify/bugs/async.rs +++ b/tests/ui/chalkify/bugs/async.rs @@ -1,7 +1,7 @@ -// check-fail -// known-bug +// edition:2021 +// known-bug: unknown // unset-rustc-env:RUST_BACKTRACE -// compile-flags:-Z trait-solver=chalk --edition=2021 +// compile-flags:-Z trait-solver=chalk // error-pattern:internal compiler error // failure-status:101 // normalize-stderr-test "DefId([^)]*)" -> "..." diff --git a/tests/ui/const-generics/issues/issue-85031-2.rs b/tests/ui/const-generics/issues/issue-85031-2.rs index 4908fb29692cc..50dd66da6dbb4 100644 --- a/tests/ui/const-generics/issues/issue-85031-2.rs +++ b/tests/ui/const-generics/issues/issue-85031-2.rs @@ -1,5 +1,5 @@ // check-pass -// known-bug +// known-bug: unknown // This should not compile, as the compiler should not know // `A - 0` is satisfied `?x - 0` if `?x` is inferred to `A`. @@ -10,7 +10,6 @@ pub struct Ref<'a>(&'a i32); impl<'a> Ref<'a> { pub fn foo() -> [(); A - 0] { - //~^ WARN function cannot Self::foo() } } diff --git a/tests/ui/const-generics/issues/issue-85031-2.stderr b/tests/ui/const-generics/issues/issue-85031-2.stderr index fc69057687520..896e1c7ea8dd6 100644 --- a/tests/ui/const-generics/issues/issue-85031-2.stderr +++ b/tests/ui/const-generics/issues/issue-85031-2.stderr @@ -3,7 +3,6 @@ warning: function cannot return without recursing | LL | pub fn foo() -> [(); A - 0] { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing -LL | LL | Self::foo() | ----------- recursive call site | diff --git a/tests/ui/generic-associated-types/bugs/hrtb-implied-1.rs b/tests/ui/generic-associated-types/bugs/hrtb-implied-1.rs index 719d1bd5a4c7d..5101de19d3cb6 100644 --- a/tests/ui/generic-associated-types/bugs/hrtb-implied-1.rs +++ b/tests/ui/generic-associated-types/bugs/hrtb-implied-1.rs @@ -1,5 +1,5 @@ // check-fail -// known-bug +// known-bug: unknown // This gives us problems because `for<'a> I::Item<'a>: Debug` should mean "for // all 'a where I::Item<'a> is WF", but really means "for all 'a possible" @@ -29,7 +29,6 @@ where fn main() { let slice = &mut (); - //~^ temporary value dropped while borrowed let windows = WindowsMut { slice }; print_items::>(windows); } diff --git a/tests/ui/generic-associated-types/bugs/hrtb-implied-1.stderr b/tests/ui/generic-associated-types/bugs/hrtb-implied-1.stderr index 1c9abc4e837c5..362aeae23614f 100644 --- a/tests/ui/generic-associated-types/bugs/hrtb-implied-1.stderr +++ b/tests/ui/generic-associated-types/bugs/hrtb-implied-1.stderr @@ -3,7 +3,7 @@ error[E0716]: temporary value dropped while borrowed | LL | let slice = &mut (); | ^^ creates a temporary value which is freed while still in use -... +LL | let windows = WindowsMut { slice }; LL | print_items::>(windows); | -------------------------------------- argument requires that borrow lasts for `'static` LL | } diff --git a/tests/ui/generic-associated-types/bugs/hrtb-implied-2.rs b/tests/ui/generic-associated-types/bugs/hrtb-implied-2.rs index 8e6c5348e71ca..3174227a7a1e1 100644 --- a/tests/ui/generic-associated-types/bugs/hrtb-implied-2.rs +++ b/tests/ui/generic-associated-types/bugs/hrtb-implied-2.rs @@ -1,5 +1,5 @@ // check-fail -// known-bug +// known-bug: unknown // This gives us problems because `for<'a> I::Item<'a>: Debug` should mean "for // all 'a where I::Item<'a> is WF", but really means "for all 'a possible" @@ -16,7 +16,6 @@ where { let mut iter2 = Eat(iter, f); let _next = iter2.next(); - //~^ borrowed data escapes true } impl LendingIterator for &mut I { diff --git a/tests/ui/generic-associated-types/bugs/issue-100013.rs b/tests/ui/generic-associated-types/bugs/issue-100013.rs index fc4e47a3ba188..973c548d785ed 100644 --- a/tests/ui/generic-associated-types/bugs/issue-100013.rs +++ b/tests/ui/generic-associated-types/bugs/issue-100013.rs @@ -1,5 +1,5 @@ // check-fail -// known-bug +// known-bug: unknown // edition: 2021 // We really should accept this, but we need implied bounds between the regions @@ -13,7 +13,6 @@ pub trait FutureIterator { fn call() -> impl Send { async { // a generator checked for autotrait impl `Send` - //~^ lifetime bound not satisfied let x = None::>; // a type referencing GAT async {}.await; // a yield point } @@ -21,16 +20,13 @@ fn call() -> impl Send { fn call2<'a, 'b, I: FutureIterator>() -> impl Send { async { // a generator checked for autotrait impl `Send` - //~^ lifetime bound not satisfied let x = None::>; // a type referencing GAT - //~^ lifetime may not live long enough async {}.await; // a yield point } } fn call3<'a: 'b, 'b, I: FutureIterator>() -> impl Send { async { // a generator checked for autotrait impl `Send` - //~^ lifetime bound not satisfied let x = None::>; // a type referencing GAT async {}.await; // a yield point } diff --git a/tests/ui/generic-associated-types/bugs/issue-100013.stderr b/tests/ui/generic-associated-types/bugs/issue-100013.stderr index 72ae288dcab64..9db124a81e487 100644 --- a/tests/ui/generic-associated-types/bugs/issue-100013.stderr +++ b/tests/ui/generic-associated-types/bugs/issue-100013.stderr @@ -2,77 +2,73 @@ error: lifetime bound not satisfied --> $DIR/issue-100013.rs:15:5 | LL | / async { // a generator checked for autotrait impl `Send` -LL | | LL | | let x = None::>; // a type referencing GAT LL | | async {}.await; // a yield point LL | | } | |_____^ | note: the lifetime defined here... - --> $DIR/issue-100013.rs:17:38 + --> $DIR/issue-100013.rs:16:38 | LL | let x = None::>; // a type referencing GAT | ^^ note: ...must outlive the lifetime defined here - --> $DIR/issue-100013.rs:17:34 + --> $DIR/issue-100013.rs:16:34 | LL | let x = None::>; // a type referencing GAT | ^^ = note: this is a known limitation that will be removed in the future (see issue #100013 for more information) error: lifetime bound not satisfied - --> $DIR/issue-100013.rs:23:5 + --> $DIR/issue-100013.rs:22:5 | LL | / async { // a generator checked for autotrait impl `Send` -LL | | LL | | let x = None::>; // a type referencing GAT -LL | | LL | | async {}.await; // a yield point LL | | } | |_____^ | note: the lifetime defined here... - --> $DIR/issue-100013.rs:22:14 + --> $DIR/issue-100013.rs:21:14 | LL | fn call2<'a, 'b, I: FutureIterator>() -> impl Send { | ^^ note: ...must outlive the lifetime defined here - --> $DIR/issue-100013.rs:22:10 + --> $DIR/issue-100013.rs:21:10 | LL | fn call2<'a, 'b, I: FutureIterator>() -> impl Send { | ^^ = note: this is a known limitation that will be removed in the future (see issue #100013 for more information) error: lifetime may not live long enough - --> $DIR/issue-100013.rs:25:17 + --> $DIR/issue-100013.rs:23:17 | LL | fn call2<'a, 'b, I: FutureIterator>() -> impl Send { | -- -- lifetime `'b` defined here | | | lifetime `'a` defined here -... +LL | async { // a generator checked for autotrait impl `Send` LL | let x = None::>; // a type referencing GAT | ^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'b` | = help: consider adding the following bound: `'a: 'b` error: lifetime bound not satisfied - --> $DIR/issue-100013.rs:32:5 + --> $DIR/issue-100013.rs:29:5 | LL | / async { // a generator checked for autotrait impl `Send` -LL | | LL | | let x = None::>; // a type referencing GAT LL | | async {}.await; // a yield point LL | | } | |_____^ | note: the lifetime defined here... - --> $DIR/issue-100013.rs:31:18 + --> $DIR/issue-100013.rs:28:18 | LL | fn call3<'a: 'b, 'b, I: FutureIterator>() -> impl Send { | ^^ note: ...must outlive the lifetime defined here - --> $DIR/issue-100013.rs:31:10 + --> $DIR/issue-100013.rs:28:10 | LL | fn call3<'a: 'b, 'b, I: FutureIterator>() -> impl Send { | ^^ diff --git a/tests/ui/generic-associated-types/bugs/issue-91762.rs b/tests/ui/generic-associated-types/bugs/issue-91762.rs index dec668bec10ed..8f2cc45509ffc 100644 --- a/tests/ui/generic-associated-types/bugs/issue-91762.rs +++ b/tests/ui/generic-associated-types/bugs/issue-91762.rs @@ -1,5 +1,5 @@ // check-fail -// known-bug +// known-bug: unknown // We almost certainly want this to pass, but // it's particularly difficult currently, because we need a way of specifying @@ -22,7 +22,6 @@ pub trait FunctorExt: Sized { arg = self; ret = ::fmap(arg); - //~^ type annotations needed } } From a3d5be6631f9d7cef7aeabb5fb9694aacc37f969 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 11 Jan 2023 19:44:49 +0000 Subject: [PATCH 198/230] Make bare known-bug an error --- src/tools/compiletest/src/header.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index c5767a795382e..c49ecb104a74a 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -426,10 +426,15 @@ impl TestProps { self.known_bug = true; } else { panic!( - "Invalid known-bug value: {known_bug}\nIt requires comma-separated issue references (`#000` or `chalk#000`) or `unknown`." + "Invalid known-bug value: {known_bug}\nIt requires comma-separated issue references (`#000` or `chalk#000`) or `known-bug: unknown`." ); } + } else if config.parse_name_directive(ln, KNOWN_BUG) { + panic!( + "Invalid known-bug attribute, requires comma-separated issue references (`#000` or `chalk#000`) or `known-bug: unknown`." + ); } + config.set_name_value_directive(ln, MIR_UNIT_TEST, &mut self.mir_unit_test, |s| { s.trim().to_string() }); From f3cde8e9da7948295c5b770664786d03fa4979c5 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Thu, 19 Jan 2023 23:13:01 +0000 Subject: [PATCH 199/230] Fix broken format strings in `infer.ftl` --- .../rustc_error_messages/locales/en-US/infer.ftl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl index ae0091b03736f..cc38d71b484a4 100644 --- a/compiler/rustc_error_messages/locales/en-US/infer.ftl +++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl @@ -193,7 +193,7 @@ infer_actual_impl_expl_expected_signature_any = {$leading_ellipsis -> infer_actual_impl_expl_expected_signature_some = {$leading_ellipsis -> [true] ... *[false] {""} -}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{lifetime_1}`... +}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{$lifetime_1}`... infer_actual_impl_expl_expected_signature_nothing = {$leading_ellipsis -> [true] ... *[false] {""} @@ -209,7 +209,7 @@ infer_actual_impl_expl_expected_passive_any = {$leading_ellipsis -> infer_actual_impl_expl_expected_passive_some = {$leading_ellipsis -> [true] ... *[false] {""} -}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for some specific lifetime `'{lifetime_1}`... +}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for some specific lifetime `'{$lifetime_1}`... infer_actual_impl_expl_expected_passive_nothing = {$leading_ellipsis -> [true] ... *[false] {""} @@ -225,7 +225,7 @@ infer_actual_impl_expl_expected_other_any = {$leading_ellipsis -> infer_actual_impl_expl_expected_other_some = {$leading_ellipsis -> [true] ... *[false] {""} -}`{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{lifetime_1}`... +}`{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{$lifetime_1}`... infer_actual_impl_expl_expected_other_nothing = {$leading_ellipsis -> [true] ... *[false] {""} @@ -268,11 +268,11 @@ infer_but_calling_introduces = {$has_param_name -> [true] `{$param_name}` *[false] `fn` parameter } has {$lifetime_kind -> - [named] lifetime `{lifetime}` + [named] lifetime `{$lifetime}` *[anon] an anonymous lifetime `'_` } but calling `{assoc_item}` introduces an implicit `'static` lifetime requirement .label1 = {$has_lifetime -> - [named] lifetime `{lifetime}` + [named] lifetime `{$lifetime}` *[anon] an anonymous lifetime `'_` } .label2 = ...is used and required to live as long as `'static` here because of an implicit lifetime bound on the {$has_impl_path -> @@ -284,11 +284,11 @@ infer_but_needs_to_satisfy = {$has_param_name -> [true] `{$param_name}` *[false] `fn` parameter } has {$has_lifetime -> - [named] lifetime `{lifetime}` + [named] lifetime `{$lifetime}` *[anon] an anonymous lifetime `'_` } but it needs to satisfy a `'static` lifetime requirement .influencer = this data with {$has_lifetime -> - [named] lifetime `{lifetime}` + [named] lifetime `{$lifetime}` *[anon] an anonymous lifetime `'_` }... .require = {$spans_empty -> @@ -302,7 +302,7 @@ infer_more_targeted = {$has_param_name -> [true] `{$param_name}` *[false] `fn` parameter } has {$has_lifetime -> - [named] lifetime `{lifetime}` + [named] lifetime `{$lifetime}` *[anon] an anonymous lifetime `'_` } but calling `{$ident}` introduces an implicit `'static` lifetime requirement From 05889fc52e8d18f96df659660eff9cd5e9ff3f08 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 19 Jan 2023 16:30:05 -0700 Subject: [PATCH 200/230] rustdoc: remove redundant CSS selector `.sidebar .current` Since the current sidebar item is already a link, it doesn't do anything. --- src/librustdoc/html/static/css/rustdoc.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index a08b8d89db67d..a93f60da2adf2 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -497,7 +497,7 @@ ul.block, .block li { padding-left: 24px; } -.sidebar a, .sidebar .current { +.sidebar a { color: var(--sidebar-link-color); } .sidebar .current, From 734f375019ecceaf4adad2423b0035f070dda354 Mon Sep 17 00:00:00 2001 From: --global <39689890+timrobertsdev@users.noreply.github.com> Date: Tue, 8 Nov 2022 10:24:06 -0500 Subject: [PATCH 201/230] Change `bindings_with_variant_name` to deny-by-default --- compiler/rustc_lint_defs/src/builtin.rs | 2 +- tests/ui/issues/issue-19100.fixed | 5 ++-- tests/ui/issues/issue-19100.rs | 5 ++-- tests/ui/issues/issue-19100.stderr | 12 ++++---- tests/ui/lint/issue-30302.rs | 2 +- tests/ui/lint/issue-30302.stderr | 6 ++-- tests/ui/lint/lint-uppercase-variables.rs | 6 ++-- tests/ui/lint/lint-uppercase-variables.stderr | 10 +++---- tests/ui/pattern/issue-14221.rs | 4 +-- tests/ui/pattern/issue-14221.stderr | 8 +++--- ...67776-match-same-name-enum-variant-refs.rs | 16 +++++------ ...6-match-same-name-enum-variant-refs.stderr | 28 +++++++++---------- tests/ui/suggestions/issue-88730.rs | 3 +- tests/ui/suggestions/issue-88730.stderr | 10 ++----- 14 files changed, 54 insertions(+), 63 deletions(-) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 6cdf50970836a..0748dd94c457c 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -743,7 +743,7 @@ declare_lint! { /// [identifier pattern]: https://doc.rust-lang.org/reference/patterns.html#identifier-patterns /// [path pattern]: https://doc.rust-lang.org/reference/patterns.html#path-patterns pub BINDINGS_WITH_VARIANT_NAME, - Warn, + Deny, "detects pattern bindings with the same name as one of the matched variants" } diff --git a/tests/ui/issues/issue-19100.fixed b/tests/ui/issues/issue-19100.fixed index 6dc8f7ddbc972..029855de2dea0 100644 --- a/tests/ui/issues/issue-19100.fixed +++ b/tests/ui/issues/issue-19100.fixed @@ -1,4 +1,3 @@ -// run-pass // run-rustfix #![allow(non_snake_case)] @@ -16,11 +15,11 @@ impl Foo { match self { & Foo::Bar if true -//~^ WARN pattern binding `Bar` is named the same as one of the variants of the type `Foo` +//~^ ERROR pattern binding `Bar` is named the same as one of the variants of the type `Foo` => println!("bar"), & Foo::Baz if false -//~^ WARN pattern binding `Baz` is named the same as one of the variants of the type `Foo` +//~^ ERROR pattern binding `Baz` is named the same as one of the variants of the type `Foo` => println!("baz"), _ => () } diff --git a/tests/ui/issues/issue-19100.rs b/tests/ui/issues/issue-19100.rs index cfdc7c9e75488..bd9e4ea5b601b 100644 --- a/tests/ui/issues/issue-19100.rs +++ b/tests/ui/issues/issue-19100.rs @@ -1,4 +1,3 @@ -// run-pass // run-rustfix #![allow(non_snake_case)] @@ -16,11 +15,11 @@ impl Foo { match self { & Bar if true -//~^ WARN pattern binding `Bar` is named the same as one of the variants of the type `Foo` +//~^ ERROR pattern binding `Bar` is named the same as one of the variants of the type `Foo` => println!("bar"), & Baz if false -//~^ WARN pattern binding `Baz` is named the same as one of the variants of the type `Foo` +//~^ ERROR pattern binding `Baz` is named the same as one of the variants of the type `Foo` => println!("baz"), _ => () } diff --git a/tests/ui/issues/issue-19100.stderr b/tests/ui/issues/issue-19100.stderr index 293430691ddcf..ebbf083b7dea8 100644 --- a/tests/ui/issues/issue-19100.stderr +++ b/tests/ui/issues/issue-19100.stderr @@ -1,17 +1,17 @@ -warning[E0170]: pattern binding `Bar` is named the same as one of the variants of the type `Foo` - --> $DIR/issue-19100.rs:18:1 +error[E0170]: pattern binding `Bar` is named the same as one of the variants of the type `Foo` + --> $DIR/issue-19100.rs:17:1 | LL | Bar if true | ^^^ help: to match on the variant, qualify the path: `Foo::Bar` | - = note: `#[warn(bindings_with_variant_name)]` on by default + = note: `#[deny(bindings_with_variant_name)]` on by default -warning[E0170]: pattern binding `Baz` is named the same as one of the variants of the type `Foo` - --> $DIR/issue-19100.rs:22:1 +error[E0170]: pattern binding `Baz` is named the same as one of the variants of the type `Foo` + --> $DIR/issue-19100.rs:21:1 | LL | Baz if false | ^^^ help: to match on the variant, qualify the path: `Foo::Baz` -warning: 2 warnings emitted +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0170`. diff --git a/tests/ui/lint/issue-30302.rs b/tests/ui/lint/issue-30302.rs index c37d4f29d10e3..5eccb8cd5d8d2 100644 --- a/tests/ui/lint/issue-30302.rs +++ b/tests/ui/lint/issue-30302.rs @@ -11,7 +11,7 @@ enum Stack { fn is_empty(s: Stack) -> bool { match s { Nil => true, -//~^ WARN pattern binding `Nil` is named the same as one of the variants of the type `Stack` +//~^ ERROR pattern binding `Nil` is named the same as one of the variants of the type `Stack` _ => false //~^ ERROR unreachable pattern } diff --git a/tests/ui/lint/issue-30302.stderr b/tests/ui/lint/issue-30302.stderr index 849ff1ebd9236..baf6c0d7a59d8 100644 --- a/tests/ui/lint/issue-30302.stderr +++ b/tests/ui/lint/issue-30302.stderr @@ -1,10 +1,10 @@ -warning[E0170]: pattern binding `Nil` is named the same as one of the variants of the type `Stack` +error[E0170]: pattern binding `Nil` is named the same as one of the variants of the type `Stack` --> $DIR/issue-30302.rs:13:9 | LL | Nil => true, | ^^^ help: to match on the variant, qualify the path: `Stack::Nil` | - = note: `#[warn(bindings_with_variant_name)]` on by default + = note: `#[deny(bindings_with_variant_name)]` on by default error: unreachable pattern --> $DIR/issue-30302.rs:15:9 @@ -21,6 +21,6 @@ note: the lint level is defined here LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error; 1 warning emitted +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0170`. diff --git a/tests/ui/lint/lint-uppercase-variables.rs b/tests/ui/lint/lint-uppercase-variables.rs index d4e88aa264361..59dba536f24b6 100644 --- a/tests/ui/lint/lint-uppercase-variables.rs +++ b/tests/ui/lint/lint-uppercase-variables.rs @@ -21,18 +21,18 @@ fn main() { match foo::Foo::Foo { Foo => {} //~^ ERROR variable `Foo` should have a snake case name - //~^^ WARN `Foo` is named the same as one of the variants of the type `foo::Foo` + //~^^ ERROR `Foo` is named the same as one of the variants of the type `foo::Foo` //~^^^ WARN unused variable: `Foo` } let Foo = foo::Foo::Foo; //~^ ERROR variable `Foo` should have a snake case name - //~^^ WARN `Foo` is named the same as one of the variants of the type `foo::Foo` + //~^^ ERROR `Foo` is named the same as one of the variants of the type `foo::Foo` //~^^^ WARN unused variable: `Foo` fn in_param(Foo: foo::Foo) {} //~^ ERROR variable `Foo` should have a snake case name - //~^^ WARN `Foo` is named the same as one of the variants of the type `foo::Foo` + //~^^ ERROR `Foo` is named the same as one of the variants of the type `foo::Foo` //~^^^ WARN unused variable: `Foo` test(1); diff --git a/tests/ui/lint/lint-uppercase-variables.stderr b/tests/ui/lint/lint-uppercase-variables.stderr index d476d856e24c5..42ec9364bc6e6 100644 --- a/tests/ui/lint/lint-uppercase-variables.stderr +++ b/tests/ui/lint/lint-uppercase-variables.stderr @@ -1,18 +1,18 @@ -warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo` +error[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo` --> $DIR/lint-uppercase-variables.rs:22:9 | LL | Foo => {} | ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo` | - = note: `#[warn(bindings_with_variant_name)]` on by default + = note: `#[deny(bindings_with_variant_name)]` on by default -warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo` +error[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo` --> $DIR/lint-uppercase-variables.rs:28:9 | LL | let Foo = foo::Foo::Foo; | ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo` -warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo` +error[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo` --> $DIR/lint-uppercase-variables.rs:33:17 | LL | fn in_param(Foo: foo::Foo) {} @@ -85,6 +85,6 @@ error: variable `Foo` should have a snake case name LL | fn in_param(Foo: foo::Foo) {} | ^^^ help: convert the identifier to snake case (notice the capitalization): `foo` -error: aborting due to 6 previous errors; 6 warnings emitted +error: aborting due to 9 previous errors; 3 warnings emitted For more information about this error, try `rustc --explain E0170`. diff --git a/tests/ui/pattern/issue-14221.rs b/tests/ui/pattern/issue-14221.rs index 282c411136922..13427d2c9b208 100644 --- a/tests/ui/pattern/issue-14221.rs +++ b/tests/ui/pattern/issue-14221.rs @@ -11,9 +11,9 @@ pub mod b { pub fn key(e: ::E) -> &'static str { match e { A => "A", -//~^ WARN pattern binding `A` is named the same as one of the variants of the type `E` +//~^ ERROR pattern binding `A` is named the same as one of the variants of the type `E` B => "B", //~ ERROR: unreachable pattern -//~^ WARN pattern binding `B` is named the same as one of the variants of the type `E` +//~^ ERROR pattern binding `B` is named the same as one of the variants of the type `E` } } } diff --git a/tests/ui/pattern/issue-14221.stderr b/tests/ui/pattern/issue-14221.stderr index fc8ae1ed7b5b0..7ea51b5f804c0 100644 --- a/tests/ui/pattern/issue-14221.stderr +++ b/tests/ui/pattern/issue-14221.stderr @@ -1,12 +1,12 @@ -warning[E0170]: pattern binding `A` is named the same as one of the variants of the type `E` +error[E0170]: pattern binding `A` is named the same as one of the variants of the type `E` --> $DIR/issue-14221.rs:13:13 | LL | A => "A", | ^ help: to match on the variant, qualify the path: `E::A` | - = note: `#[warn(bindings_with_variant_name)]` on by default + = note: `#[deny(bindings_with_variant_name)]` on by default -warning[E0170]: pattern binding `B` is named the same as one of the variants of the type `E` +error[E0170]: pattern binding `B` is named the same as one of the variants of the type `E` --> $DIR/issue-14221.rs:15:13 | LL | B => "B", @@ -27,6 +27,6 @@ note: the lint level is defined here LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error; 2 warnings emitted +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0170`. diff --git a/tests/ui/pattern/issue-67776-match-same-name-enum-variant-refs.rs b/tests/ui/pattern/issue-67776-match-same-name-enum-variant-refs.rs index 6fd5768a5a26d..05d097eaf14e4 100644 --- a/tests/ui/pattern/issue-67776-match-same-name-enum-variant-refs.rs +++ b/tests/ui/pattern/issue-67776-match-same-name-enum-variant-refs.rs @@ -1,7 +1,5 @@ // Test for issue #67776: binding named the same as enum variant -// should report a warning even when matching against a reference type - -// check-pass +// should report an error even when matching against a reference type #![allow(unused_variables)] #![allow(non_snake_case)] @@ -15,27 +13,27 @@ enum Foo { fn fn1(e: Foo) { match e { Bar => {}, - //~^ WARNING named the same as one of the variants of the type `Foo` + //~^ ERROR named the same as one of the variants of the type `Foo` Baz => {}, - //~^ WARNING named the same as one of the variants of the type `Foo` + //~^ ERROR named the same as one of the variants of the type `Foo` } } fn fn2(e: &Foo) { match e { Bar => {}, - //~^ WARNING named the same as one of the variants of the type `Foo` + //~^ ERROR named the same as one of the variants of the type `Foo` Baz => {}, - //~^ WARNING named the same as one of the variants of the type `Foo` + //~^ ERROR named the same as one of the variants of the type `Foo` } } fn fn3(e: &mut &&mut Foo) { match e { Bar => {}, - //~^ WARNING named the same as one of the variants of the type `Foo` + //~^ ERROR named the same as one of the variants of the type `Foo` Baz => {}, - //~^ WARNING named the same as one of the variants of the type `Foo` + //~^ ERROR named the same as one of the variants of the type `Foo` } } diff --git a/tests/ui/pattern/issue-67776-match-same-name-enum-variant-refs.stderr b/tests/ui/pattern/issue-67776-match-same-name-enum-variant-refs.stderr index 6f3613b63c9aa..da580c7accb97 100644 --- a/tests/ui/pattern/issue-67776-match-same-name-enum-variant-refs.stderr +++ b/tests/ui/pattern/issue-67776-match-same-name-enum-variant-refs.stderr @@ -1,41 +1,41 @@ -warning[E0170]: pattern binding `Bar` is named the same as one of the variants of the type `Foo` - --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:17:9 +error[E0170]: pattern binding `Bar` is named the same as one of the variants of the type `Foo` + --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:15:9 | LL | Bar => {}, | ^^^ help: to match on the variant, qualify the path: `Foo::Bar` | - = note: `#[warn(bindings_with_variant_name)]` on by default + = note: `#[deny(bindings_with_variant_name)]` on by default -warning[E0170]: pattern binding `Baz` is named the same as one of the variants of the type `Foo` - --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:19:9 +error[E0170]: pattern binding `Baz` is named the same as one of the variants of the type `Foo` + --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:17:9 | LL | Baz => {}, | ^^^ help: to match on the variant, qualify the path: `Foo::Baz` -warning[E0170]: pattern binding `Bar` is named the same as one of the variants of the type `Foo` - --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:26:9 +error[E0170]: pattern binding `Bar` is named the same as one of the variants of the type `Foo` + --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:24:9 | LL | Bar => {}, | ^^^ help: to match on the variant, qualify the path: `Foo::Bar` -warning[E0170]: pattern binding `Baz` is named the same as one of the variants of the type `Foo` - --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:28:9 +error[E0170]: pattern binding `Baz` is named the same as one of the variants of the type `Foo` + --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:26:9 | LL | Baz => {}, | ^^^ help: to match on the variant, qualify the path: `Foo::Baz` -warning[E0170]: pattern binding `Bar` is named the same as one of the variants of the type `Foo` - --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:35:9 +error[E0170]: pattern binding `Bar` is named the same as one of the variants of the type `Foo` + --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:33:9 | LL | Bar => {}, | ^^^ help: to match on the variant, qualify the path: `Foo::Bar` -warning[E0170]: pattern binding `Baz` is named the same as one of the variants of the type `Foo` - --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:37:9 +error[E0170]: pattern binding `Baz` is named the same as one of the variants of the type `Foo` + --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:35:9 | LL | Baz => {}, | ^^^ help: to match on the variant, qualify the path: `Foo::Baz` -warning: 6 warnings emitted +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0170`. diff --git a/tests/ui/suggestions/issue-88730.rs b/tests/ui/suggestions/issue-88730.rs index e63210a3e987e..d161ed284f6d9 100644 --- a/tests/ui/suggestions/issue-88730.rs +++ b/tests/ui/suggestions/issue-88730.rs @@ -1,9 +1,8 @@ #![allow(unused, nonstandard_style)] -#![deny(bindings_with_variant_name)] // If an enum has two different variants, // then it cannot be matched upon in a function argument. -// It still gets a warning, but no suggestions. +// It still gets an error, but no suggestions. enum Foo { C, D, diff --git a/tests/ui/suggestions/issue-88730.stderr b/tests/ui/suggestions/issue-88730.stderr index eb22b0ea5c83d..0bd1b7ba4bacf 100644 --- a/tests/ui/suggestions/issue-88730.stderr +++ b/tests/ui/suggestions/issue-88730.stderr @@ -1,17 +1,13 @@ error[E0170]: pattern binding `C` is named the same as one of the variants of the type `Foo` - --> $DIR/issue-88730.rs:12:8 + --> $DIR/issue-88730.rs:11:8 | LL | fn foo(C: Foo) {} | ^ | -note: the lint level is defined here - --> $DIR/issue-88730.rs:2:9 - | -LL | #![deny(bindings_with_variant_name)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[deny(bindings_with_variant_name)]` on by default error[E0170]: pattern binding `C` is named the same as one of the variants of the type `Foo` - --> $DIR/issue-88730.rs:15:9 + --> $DIR/issue-88730.rs:14:9 | LL | let C = Foo::D; | ^ From 1cbce729c74c3c3b50dabdb776e41cc5c23f5601 Mon Sep 17 00:00:00 2001 From: --global <39689890+timrobertsdev@users.noreply.github.com> Date: Tue, 8 Nov 2022 11:01:03 -0500 Subject: [PATCH 202/230] Add `compile_fail` to doctest for `bindings_with_variant_name` --- compiler/rustc_lint_defs/src/builtin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 0748dd94c457c..1ac97849ec611 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -708,7 +708,7 @@ declare_lint! { /// /// ### Example /// - /// ```rust + /// ```rust,compile_fail /// pub enum Enum { /// Foo, /// Bar, From 1adb4d6e5f5d242459655a6ef071669422ce0019 Mon Sep 17 00:00:00 2001 From: Ikko Eltociear Ashimine Date: Fri, 20 Jan 2023 17:56:29 +0900 Subject: [PATCH 203/230] Fix typo in opaque_types.rs paramters -> parameters --- compiler/rustc_infer/src/infer/opaque_types.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index e22ba9785e1fd..c54c66eab2799 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -479,7 +479,7 @@ where } ty::Alias(ty::Opaque, ty::AliasTy { def_id, ref substs, .. }) => { - // Skip lifetime paramters that are not captures. + // Skip lifetime parameters that are not captures. let variances = self.tcx.variances_of(*def_id); for (v, s) in std::iter::zip(variances, substs.iter()) { @@ -492,7 +492,7 @@ where ty::Alias(ty::Projection, proj) if self.tcx.def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder => { - // Skip lifetime paramters that are not captures. + // Skip lifetime parameters that are not captures. let variances = self.tcx.variances_of(proj.def_id); for (v, s) in std::iter::zip(variances, proj.substs.iter()) { From ec3da87582a318ddb35d451bdba6d50591ea55ce Mon Sep 17 00:00:00 2001 From: Valdemar Erk Date: Fri, 20 Jan 2023 11:16:38 +0100 Subject: [PATCH 204/230] Add note about absolute paths to Path::join --- library/std/src/path.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/std/src/path.rs b/library/std/src/path.rs index c3593264e520b..500a09ad08abc 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -2531,6 +2531,8 @@ impl Path { /// Creates an owned [`PathBuf`] with `path` adjoined to `self`. /// + /// If `path` is absolute, it replaces the current path. + /// /// See [`PathBuf::push`] for more details on what it means to adjoin a path. /// /// # Examples From d8f8adfe3df3cdc882db8ba7dfb9d7fcc8533b82 Mon Sep 17 00:00:00 2001 From: Valdemar Erk Date: Fri, 20 Jan 2023 12:03:43 +0100 Subject: [PATCH 205/230] add example of joining with a absolute path --- library/std/src/path.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 500a09ad08abc..2f53cf8393691 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -2541,6 +2541,7 @@ impl Path { /// use std::path::{Path, PathBuf}; /// /// assert_eq!(Path::new("/etc").join("passwd"), PathBuf::from("/etc/passwd")); + /// assert_eq!(Path::new("/etc").join("/bin/sh"), PathBuf::from("/bin/sh")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[must_use] From 3f4fdce0de69c42de4f9b8ec64ee23644cfd1185 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 20 Jan 2023 07:48:59 -0800 Subject: [PATCH 206/230] Pull in more LLVM commits --- src/llvm-project | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm-project b/src/llvm-project index 6c0bab9ef2d4c..477e7285b12f8 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 6c0bab9ef2d4c692e91e9f61e2d27514346d49f3 +Subproject commit 477e7285b12f876ad105188cfcfc8adda7dc29aa From ea4620a7102a20880a4284523bade2a2a536b1b2 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Fri, 20 Jan 2023 15:52:56 +0000 Subject: [PATCH 207/230] Update cargo 3 commits in 50eb688c2bbea5de5a2e8496230a7428798089d1..985d561f0bb9b76ec043a2b12511790ec7a2b954 2023-01-19 10:09:05 +0000 to 2023-01-20 14:39:28 +0000 - Stabilize sparse-registry (rust-lang/cargo#11224) - Wrapper type for data that should never be logged (rust-lang/cargo#11545) - Add semver rule for lints (rust-lang/cargo#11596) --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 50eb688c2bbea..985d561f0bb9b 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 50eb688c2bbea5de5a2e8496230a7428798089d1 +Subproject commit 985d561f0bb9b76ec043a2b12511790ec7a2b954 From 540ca2ff2acf5539868b1f1c156f6c895fdc9ffc Mon Sep 17 00:00:00 2001 From: DebugSteven Date: Wed, 4 Jan 2023 21:57:20 -0700 Subject: [PATCH 208/230] run cargo install to check for x installation and version --- Cargo.lock | 1 + src/tools/tidy/Cargo.toml | 1 + src/tools/tidy/src/lib.rs | 1 + src/tools/tidy/src/main.rs | 2 + src/tools/tidy/src/x_version.rs | 68 +++++++++++++++++++++++++++++++++ 5 files changed, 73 insertions(+) create mode 100644 src/tools/tidy/src/x_version.rs diff --git a/Cargo.lock b/Cargo.lock index 5511d30177559..f6a5fb14d53b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5607,6 +5607,7 @@ dependencies = [ "lazy_static", "miropt-test-tools", "regex", + "semver", "termcolor", "walkdir", ] diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml index 19812fc6f55b6..cdf1dd366046c 100644 --- a/src/tools/tidy/Cargo.toml +++ b/src/tools/tidy/Cargo.toml @@ -12,6 +12,7 @@ miropt-test-tools = { path = "../miropt-test-tools" } lazy_static = "1" walkdir = "2" ignore = "0.4.18" +semver = "1.0" termcolor = "1.1.3" [[bin]] diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 97e56720b9852..35000320d1abf 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -70,3 +70,4 @@ pub mod ui_tests; pub mod unit_tests; pub mod unstable_book; pub mod walk; +pub mod x_version; diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 0b9a1b37e947e..4c446b72a4495 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -114,6 +114,8 @@ fn main() { check!(alphabetical, &compiler_path); check!(alphabetical, &library_path); + check!(x_version, &root_path, &cargo); + let collected = { drain_handles(&mut handles); diff --git a/src/tools/tidy/src/x_version.rs b/src/tools/tidy/src/x_version.rs new file mode 100644 index 0000000000000..c470d502a6548 --- /dev/null +++ b/src/tools/tidy/src/x_version.rs @@ -0,0 +1,68 @@ +use semver::Version; +use std::path::Path; +use std::process::{Command, Stdio}; + +pub fn check(root: &Path, cargo: &Path, bad: &mut bool) { + let cargo_list = Command::new(cargo).args(["install", "--list"]).stdout(Stdio::piped()).spawn(); + + let child = match cargo_list { + Ok(child) => child, + Err(e) => return tidy_error!(bad, "failed to run `cargo`: {}", e), + }; + + let cargo_list = child.wait_with_output().unwrap(); + + if cargo_list.status.success() { + let exe_list = String::from_utf8_lossy(&cargo_list.stdout); + let exe_list = exe_list.lines(); + + let mut installed: Option = None; + + for line in exe_list { + let mut iter = line.split_whitespace(); + if iter.next() == Some("x") { + if let Some(version) = iter.next() { + // Check this is the rust-lang/rust x tool installation since it should be + // installed at a path containing `src/tools/x`. + if let Some(path) = iter.next() { + if path.contains(&"src/tools/x") { + let version = version.strip_prefix("v").unwrap(); + installed = Some(Version::parse(version).unwrap()); + break; + } + }; + } + } else { + continue; + } + } + // Unwrap the some if x is installed, otherwise return because it's fine if x isn't installed. + let installed = if let Some(i) = installed { i } else { return }; + + if let Some(expected) = get_x_wrapper_version(root, cargo) { + if installed < expected { + return println!( + "Current version of x is {installed}, but the latest version is {expected}\nConsider updating to the newer version of x by running `cargo install --path src/tools/x`" + ); + } + } else { + return tidy_error!( + bad, + "Unable to parse the latest version of `x` at `src/tools/x/Cargo.toml`" + ); + } + } else { + return tidy_error!(bad, "failed to check version of `x`: {}", cargo_list.status); + } +} + +// Parse latest version out of `x` Cargo.toml +fn get_x_wrapper_version(root: &Path, cargo: &Path) -> Option { + let mut cmd = cargo_metadata::MetadataCommand::new(); + cmd.cargo_path(cargo) + .manifest_path(root.join("src/tools/x/Cargo.toml")) + .no_deps() + .features(cargo_metadata::CargoOpt::AllFeatures); + let mut metadata = t!(cmd.exec()); + metadata.packages.pop().map(|x| x.version) +} From a641b929ad35e262ed6d0e0e275b291da26a588a Mon Sep 17 00:00:00 2001 From: DebugSteven Date: Thu, 19 Jan 2023 13:56:15 -0700 Subject: [PATCH 209/230] remove leading comma when there are no args in check macro expansion --- src/tools/tidy/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 0b9a1b37e947e..17cba0f6ccd4e 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -60,7 +60,7 @@ fn main() { let handle = s.spawn(|| { let mut flag = false; - $p::check($($args),* , &mut flag); + $p::check($($args, )* &mut flag); if (flag) { bad.store(true, Ordering::Relaxed); } From 492d928e44c73c5e804dbf174e53ea2229f61315 Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Fri, 20 Jan 2023 18:34:24 +0100 Subject: [PATCH 210/230] Enable sanitizers for s390x-linux Include sanitizers supported by LLVM on s390x (asan, lsan, msan, tsan) in the target definition, as well as in the compiletest supported list. Build sanitizer runtime for the target. Enable sanitizers in the CI. --- .../rustc_target/src/spec/s390x_unknown_linux_gnu.rs | 4 +++- .../rustc_target/src/spec/s390x_unknown_linux_musl.rs | 4 +++- src/bootstrap/native.rs | 6 ++++++ src/ci/docker/host-x86_64/dist-s390x-linux/Dockerfile | 2 +- src/tools/compiletest/src/util.rs | 11 +++++++++-- 5 files changed, 22 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs index cda88de0ea406..f2c722b9a89da 100644 --- a/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs @@ -1,5 +1,5 @@ use crate::abi::Endian; -use crate::spec::{StackProbeType, Target}; +use crate::spec::{SanitizerSet, StackProbeType, Target}; pub fn target() -> Target { let mut base = super::linux_gnu_base::opts(); @@ -13,6 +13,8 @@ pub fn target() -> Target { base.max_atomic_width = Some(64); base.min_global_align = Some(16); base.stack_probes = StackProbeType::Inline; + base.supported_sanitizers = + SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::MEMORY | SanitizerSet::THREAD; Target { llvm_target: "s390x-unknown-linux-gnu".into(), diff --git a/compiler/rustc_target/src/spec/s390x_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/s390x_unknown_linux_musl.rs index 91e63aee5e490..8fe9d023c527e 100644 --- a/compiler/rustc_target/src/spec/s390x_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/s390x_unknown_linux_musl.rs @@ -1,5 +1,5 @@ use crate::abi::Endian; -use crate::spec::{StackProbeType, Target}; +use crate::spec::{SanitizerSet, StackProbeType, Target}; pub fn target() -> Target { let mut base = super::linux_musl_base::opts(); @@ -14,6 +14,8 @@ pub fn target() -> Target { base.min_global_align = Some(16); base.static_position_independent_executables = true; base.stack_probes = StackProbeType::Inline; + base.supported_sanitizers = + SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::MEMORY | SanitizerSet::THREAD; Target { llvm_target: "s390x-unknown-linux-musl".into(), diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index e0d1504c9c780..cb5706ca0a651 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -1105,6 +1105,12 @@ fn supported_sanitizers( "x86_64-unknown-linux-musl" => { common_libs("linux", "x86_64", &["asan", "lsan", "msan", "tsan"]) } + "s390x-unknown-linux-gnu" => { + common_libs("linux", "s390x", &["asan", "lsan", "msan", "tsan"]) + } + "s390x-unknown-linux-musl" => { + common_libs("linux", "s390x", &["asan", "lsan", "msan", "tsan"]) + } _ => Vec::new(), } } diff --git a/src/ci/docker/host-x86_64/dist-s390x-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-s390x-linux/Dockerfile index 43a449b3a1926..adb98d7ebb545 100644 --- a/src/ci/docker/host-x86_64/dist-s390x-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-s390x-linux/Dockerfile @@ -28,5 +28,5 @@ ENV \ ENV HOSTS=s390x-unknown-linux-gnu -ENV RUST_CONFIGURE_ARGS --enable-extended --enable-lld --enable-profiler --disable-docs +ENV RUST_CONFIGURE_ARGS --enable-extended --enable-lld --enable-sanitizers --enable-profiler --disable-docs ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index 6c63b760ff6a9..ff7e8df987816 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -23,6 +23,7 @@ pub const ASAN_SUPPORTED_TARGETS: &[&str] = &[ "x86_64-linux-android", "x86_64-unknown-freebsd", "x86_64-unknown-linux-gnu", + "s390x-unknown-linux-gnu", ]; // FIXME(rcvalle): More targets are likely supported. @@ -50,10 +51,15 @@ pub const LSAN_SUPPORTED_TARGETS: &[&str] = &[ "aarch64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu", + "s390x-unknown-linux-gnu", ]; -pub const MSAN_SUPPORTED_TARGETS: &[&str] = - &["aarch64-unknown-linux-gnu", "x86_64-unknown-freebsd", "x86_64-unknown-linux-gnu"]; +pub const MSAN_SUPPORTED_TARGETS: &[&str] = &[ + "aarch64-unknown-linux-gnu", + "x86_64-unknown-freebsd", + "x86_64-unknown-linux-gnu", + "s390x-unknown-linux-gnu", +]; pub const TSAN_SUPPORTED_TARGETS: &[&str] = &[ "aarch64-apple-darwin", @@ -61,6 +67,7 @@ pub const TSAN_SUPPORTED_TARGETS: &[&str] = &[ "x86_64-apple-darwin", "x86_64-unknown-freebsd", "x86_64-unknown-linux-gnu", + "s390x-unknown-linux-gnu", ]; pub const HWASAN_SUPPORTED_TARGETS: &[&str] = From 112d85c1ec8d5294ece4850bec306df4a2ed6dab Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 20 Jan 2023 14:28:16 -0700 Subject: [PATCH 211/230] rustdoc: use CSS inline layout for radio line instead of flexbox This uses less code to lay them out the same way. --- src/librustdoc/html/static/css/settings.css | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/librustdoc/html/static/css/settings.css b/src/librustdoc/html/static/css/settings.css index 7211ffb779568..4e9803fe2366d 100644 --- a/src/librustdoc/html/static/css/settings.css +++ b/src/librustdoc/html/static/css/settings.css @@ -3,11 +3,6 @@ position: relative; } -.setting-line .choices { - display: flex; - flex-wrap: wrap; -} - .setting-line .radio-line input, .setting-line .settings-toggle input { margin-right: 0.3em; @@ -38,7 +33,7 @@ margin-bottom: 0.1em; min-width: 3.8em; padding: 0.3em; - display: flex; + display: inline-flex; align-items: center; cursor: pointer; } From e9d8d238ef76c7991b316bbfbd9f857d84bd39cf Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sat, 12 Nov 2022 21:46:05 -0700 Subject: [PATCH 212/230] diagnostics: suggest changing `s@self::{macro}@::macro` for exported Fixes #99695 --- compiler/rustc_resolve/src/diagnostics.rs | 30 ++++++++++++++++++++++- tests/ui/imports/issue-99695.fixed | 17 +++++++++++++ tests/ui/imports/issue-99695.rs | 16 ++++++++++++ tests/ui/imports/issue-99695.stderr | 16 ++++++++++++ 4 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 tests/ui/imports/issue-99695.fixed create mode 100644 tests/ui/imports/issue-99695.rs create mode 100644 tests/ui/imports/issue-99695.stderr diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index f24e405018b74..2a5cc288380f4 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -2125,9 +2125,31 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let source_map = self.r.session.source_map(); + // Make sure this is actually crate-relative. + let use_and_crate = import.use_span.with_hi(after_crate_name.lo()); + let is_definitely_crate = + source_map.span_to_snippet(use_and_crate).map_or(false, |s| { + let mut s = s.trim(); + debug!("check_for_module_export_macro: s={s:?}",); + s = s + .split_whitespace() + .rev() + .next() + .expect("split_whitespace always yields at least once"); + debug!("check_for_module_export_macro: s={s:?}",); + if s.ends_with("::") { + s = &s[..s.len() - 2]; + } else { + return false; + } + s = s.trim(); + debug!("check_for_module_export_macro: s={s:?}",); + s != "self" && s != "super" + }); + // Add the import to the start, with a `{` if required. let start_point = source_map.start_point(after_crate_name); - if let Ok(start_snippet) = source_map.span_to_snippet(start_point) { + if is_definitely_crate && let Ok(start_snippet) = source_map.span_to_snippet(start_point) { corrections.push(( start_point, if has_nested { @@ -2139,6 +2161,12 @@ impl<'a, 'b> ImportResolver<'a, 'b> { format!("{{{}, {}", import_snippet, start_snippet) }, )); + } else { + // If the root import is module-relative, add the import separately + corrections.push(( + source_map.start_point(import.use_span).shrink_to_lo(), + format!("use {module_name}::{import_snippet};\n"), + )); } // Add a `};` to the end if nested, matching the `{` added at the start. diff --git a/tests/ui/imports/issue-99695.fixed b/tests/ui/imports/issue-99695.fixed new file mode 100644 index 0000000000000..6bf228b23aad2 --- /dev/null +++ b/tests/ui/imports/issue-99695.fixed @@ -0,0 +1,17 @@ +// run-rustfix +#![allow(unused, nonstandard_style)] +mod m { + #[macro_export] + macro_rules! nu { + {} => {}; + } + + pub struct other_item; + + use ::nu; +pub use self::{other_item as _}; + //~^ ERROR unresolved import `self::nu` [E0432] + //~| HELP a macro with this name exists at the root of the crate +} + +fn main() {} diff --git a/tests/ui/imports/issue-99695.rs b/tests/ui/imports/issue-99695.rs new file mode 100644 index 0000000000000..f7199f1497ab0 --- /dev/null +++ b/tests/ui/imports/issue-99695.rs @@ -0,0 +1,16 @@ +// run-rustfix +#![allow(unused, nonstandard_style)] +mod m { + #[macro_export] + macro_rules! nu { + {} => {}; + } + + pub struct other_item; + + pub use self::{nu, other_item as _}; + //~^ ERROR unresolved import `self::nu` [E0432] + //~| HELP a macro with this name exists at the root of the crate +} + +fn main() {} diff --git a/tests/ui/imports/issue-99695.stderr b/tests/ui/imports/issue-99695.stderr new file mode 100644 index 0000000000000..0ef762e1c8230 --- /dev/null +++ b/tests/ui/imports/issue-99695.stderr @@ -0,0 +1,16 @@ +error[E0432]: unresolved import `self::nu` + --> $DIR/issue-99695.rs:11:20 + | +LL | pub use self::{nu, other_item as _}; + | ^^ no `nu` in `m` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL ~ use ::nu; +LL ~ pub use self::{other_item as _}; + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0432`. From e237690a28f0d38ab478616fe4b247fb6eb8013f Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sat, 12 Nov 2022 22:08:07 -0700 Subject: [PATCH 213/230] diagnostics: add `};` only if `{` was added too --- compiler/rustc_resolve/src/diagnostics.rs | 10 +++++----- tests/ui/imports/issue-99695-b.fixed | 20 ++++++++++++++++++++ tests/ui/imports/issue-99695-b.rs | 19 +++++++++++++++++++ tests/ui/imports/issue-99695-b.stderr | 16 ++++++++++++++++ 4 files changed, 60 insertions(+), 5 deletions(-) create mode 100644 tests/ui/imports/issue-99695-b.fixed create mode 100644 tests/ui/imports/issue-99695-b.rs create mode 100644 tests/ui/imports/issue-99695-b.stderr diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 2a5cc288380f4..af4d7a8eafff3 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -2161,6 +2161,11 @@ impl<'a, 'b> ImportResolver<'a, 'b> { format!("{{{}, {}", import_snippet, start_snippet) }, )); + + // Add a `};` to the end if nested, matching the `{` added at the start. + if !has_nested { + corrections.push((source_map.end_point(after_crate_name), "};".to_string())); + } } else { // If the root import is module-relative, add the import separately corrections.push(( @@ -2168,11 +2173,6 @@ impl<'a, 'b> ImportResolver<'a, 'b> { format!("use {module_name}::{import_snippet};\n"), )); } - - // Add a `};` to the end if nested, matching the `{` added at the start. - if !has_nested { - corrections.push((source_map.end_point(after_crate_name), "};".to_string())); - } } let suggestion = Some(( diff --git a/tests/ui/imports/issue-99695-b.fixed b/tests/ui/imports/issue-99695-b.fixed new file mode 100644 index 0000000000000..0e60c73b67a44 --- /dev/null +++ b/tests/ui/imports/issue-99695-b.fixed @@ -0,0 +1,20 @@ +// run-rustfix +#![allow(unused, nonstandard_style)] +mod m { + + mod p { + #[macro_export] + macro_rules! nu { + {} => {}; + } + + pub struct other_item; + } + + use ::nu; +pub use self::p::{other_item as _}; + //~^ ERROR unresolved import `self::p::nu` [E0432] + //~| HELP a macro with this name exists at the root of the crate +} + +fn main() {} diff --git a/tests/ui/imports/issue-99695-b.rs b/tests/ui/imports/issue-99695-b.rs new file mode 100644 index 0000000000000..031443a1f5df8 --- /dev/null +++ b/tests/ui/imports/issue-99695-b.rs @@ -0,0 +1,19 @@ +// run-rustfix +#![allow(unused, nonstandard_style)] +mod m { + + mod p { + #[macro_export] + macro_rules! nu { + {} => {}; + } + + pub struct other_item; + } + + pub use self::p::{nu, other_item as _}; + //~^ ERROR unresolved import `self::p::nu` [E0432] + //~| HELP a macro with this name exists at the root of the crate +} + +fn main() {} diff --git a/tests/ui/imports/issue-99695-b.stderr b/tests/ui/imports/issue-99695-b.stderr new file mode 100644 index 0000000000000..b6f5c726a5ca9 --- /dev/null +++ b/tests/ui/imports/issue-99695-b.stderr @@ -0,0 +1,16 @@ +error[E0432]: unresolved import `self::p::nu` + --> $DIR/issue-99695-b.rs:14:23 + | +LL | pub use self::p::{nu, other_item as _}; + | ^^ no `nu` in `m::p` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL ~ use ::nu; +LL ~ pub use self::p::{other_item as _}; + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0432`. From dca160a06a85cfe6d961a586543112e772e55b13 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 6 Dec 2022 08:42:30 -0700 Subject: [PATCH 214/230] diagnostics: use `module_path` to check crate import instead of strings --- compiler/rustc_resolve/src/diagnostics.rs | 24 ++++------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index af4d7a8eafff3..0b60952ae3c08 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -2126,26 +2126,10 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let source_map = self.r.session.source_map(); // Make sure this is actually crate-relative. - let use_and_crate = import.use_span.with_hi(after_crate_name.lo()); - let is_definitely_crate = - source_map.span_to_snippet(use_and_crate).map_or(false, |s| { - let mut s = s.trim(); - debug!("check_for_module_export_macro: s={s:?}",); - s = s - .split_whitespace() - .rev() - .next() - .expect("split_whitespace always yields at least once"); - debug!("check_for_module_export_macro: s={s:?}",); - if s.ends_with("::") { - s = &s[..s.len() - 2]; - } else { - return false; - } - s = s.trim(); - debug!("check_for_module_export_macro: s={s:?}",); - s != "self" && s != "super" - }); + let is_definitely_crate = import + .module_path + .first() + .map_or(false, |f| f.ident.name != kw::SelfLower && f.ident.name != kw::Super); // Add the import to the start, with a `{` if required. let start_point = source_map.start_point(after_crate_name); From c07a722847497233e6590d62a3d63946409385c3 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 6 Dec 2022 08:44:48 -0700 Subject: [PATCH 215/230] diagnostics: remvoe unnecessary use of `source_map.start_point` --- compiler/rustc_resolve/src/diagnostics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 0b60952ae3c08..8d104aa5cc592 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -2153,7 +2153,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } else { // If the root import is module-relative, add the import separately corrections.push(( - source_map.start_point(import.use_span).shrink_to_lo(), + import.use_span.shrink_to_lo(), format!("use {module_name}::{import_snippet};\n"), )); } From 5fa1347331aff7d5d9248ba43bdd7c75262b101c Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 20 Jan 2023 17:13:55 -0500 Subject: [PATCH 216/230] Revert "Make PROC_MACRO_DERIVE_RESOLUTION_FALLBACK a hard error" This reverts commit 7d82cadd97acc66993b69304c5a1a04ef7d1fa36. I am doing this to buy us some time with respect to issue #106337 w.r.t. the 1.67 release. --- compiler/rustc_lint_defs/src/builtin.rs | 68 ++++++++++++ compiler/rustc_resolve/src/diagnostics.rs | 2 +- compiler/rustc_resolve/src/ident.rs | 75 +++++++++++-- compiler/rustc_resolve/src/lib.rs | 6 +- tests/ui/proc-macro/generate-mod.rs | 7 +- tests/ui/proc-macro/generate-mod.stderr | 129 ++++++++++++++++------ 6 files changed, 238 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 6cdf50970836a..fe92d2810a1f1 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -2023,6 +2023,73 @@ declare_lint! { }; } +declare_lint! { + /// The `proc_macro_derive_resolution_fallback` lint detects proc macro + /// derives using inaccessible names from parent modules. + /// + /// ### Example + /// + /// ```rust,ignore (proc-macro) + /// // foo.rs + /// #![crate_type = "proc-macro"] + /// + /// extern crate proc_macro; + /// + /// use proc_macro::*; + /// + /// #[proc_macro_derive(Foo)] + /// pub fn foo1(a: TokenStream) -> TokenStream { + /// drop(a); + /// "mod __bar { static mut BAR: Option = None; }".parse().unwrap() + /// } + /// ``` + /// + /// ```rust,ignore (needs-dependency) + /// // bar.rs + /// #[macro_use] + /// extern crate foo; + /// + /// struct Something; + /// + /// #[derive(Foo)] + /// struct Another; + /// + /// fn main() {} + /// ``` + /// + /// This will produce: + /// + /// ```text + /// warning: cannot find type `Something` in this scope + /// --> src/main.rs:8:10 + /// | + /// 8 | #[derive(Foo)] + /// | ^^^ names from parent modules are not accessible without an explicit import + /// | + /// = note: `#[warn(proc_macro_derive_resolution_fallback)]` on by default + /// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + /// = note: for more information, see issue #50504 + /// ``` + /// + /// ### Explanation + /// + /// If a proc-macro generates a module, the compiler unintentionally + /// allowed items in that module to refer to items in the crate root + /// without importing them. This is a [future-incompatible] lint to + /// transition this to a hard error in the future. See [issue #50504] for + /// more details. + /// + /// [issue #50504]: https://github.com/rust-lang/rust/issues/50504 + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, + Deny, + "detects proc macro derives using inaccessible names from parent modules", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #83583 ", + reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow, + }; +} + declare_lint! { /// The `macro_use_extern_crate` lint detects the use of the /// [`macro_use` attribute]. @@ -3261,6 +3328,7 @@ declare_lint_pass! { UNSTABLE_NAME_COLLISIONS, IRREFUTABLE_LET_PATTERNS, WHERE_CLAUSES_OBJECT_SAFETY, + PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, MACRO_USE_EXTERN_CRATE, MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS, ILL_FORMED_ATTRIBUTE_INPUT, diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index f24e405018b74..e264601c8f94e 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1033,7 +1033,7 @@ impl<'a> Resolver<'a> { let root_module = this.resolve_crate_root(root_ident); this.add_module_candidates(root_module, &mut suggestions, filter_fn, None); } - Scope::Module(module) => { + Scope::Module(module, _) => { this.add_module_candidates(module, &mut suggestions, filter_fn, None); } Scope::MacroUsePrelude => { diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index e41fe325b811c..a84652a315dc2 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1,9 +1,11 @@ -use rustc_ast as ast; +use rustc_ast::{self as ast, NodeId}; use rustc_feature::is_builtin_attr_name; use rustc_hir::def::{DefKind, Namespace, NonMacroAttrKind, PartialRes, PerNS}; use rustc_hir::PrimTy; use rustc_middle::bug; use rustc_middle::ty; +use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK; +use rustc_session::lint::BuiltinLintDiagnostics; use rustc_span::def_id::LocalDefId; use rustc_span::edition::Edition; use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext}; @@ -99,7 +101,7 @@ impl<'a> Resolver<'a> { }; let mut scope = match ns { _ if is_absolute_path => Scope::CrateRoot, - TypeNS | ValueNS => Scope::Module(module), + TypeNS | ValueNS => Scope::Module(module, None), MacroNS => Scope::DeriveHelpers(parent_scope.expansion), }; let mut ctxt = ctxt.normalize_to_macros_2_0(); @@ -163,7 +165,7 @@ impl<'a> Resolver<'a> { MacroRulesScope::Invocation(invoc_id) => { Scope::MacroRules(self.invocation_parent_scopes[&invoc_id].macro_rules) } - MacroRulesScope::Empty => Scope::Module(module), + MacroRulesScope::Empty => Scope::Module(module, None), }, Scope::CrateRoot => match ns { TypeNS => { @@ -172,10 +174,16 @@ impl<'a> Resolver<'a> { } ValueNS | MacroNS => break, }, - Scope::Module(module) => { + Scope::Module(module, prev_lint_id) => { use_prelude = !module.no_implicit_prelude; - match self.hygienic_lexical_parent(module, &mut ctxt) { - Some(parent_module) => Scope::Module(parent_module), + let derive_fallback_lint_id = match scope_set { + ScopeSet::Late(.., lint_id) => lint_id, + _ => None, + }; + match self.hygienic_lexical_parent(module, &mut ctxt, derive_fallback_lint_id) { + Some((parent_module, lint_id)) => { + Scope::Module(parent_module, lint_id.or(prev_lint_id)) + } None => { ctxt.adjust(ExpnId::root()); match ns { @@ -207,13 +215,45 @@ impl<'a> Resolver<'a> { &mut self, module: Module<'a>, ctxt: &mut SyntaxContext, - ) -> Option> { + derive_fallback_lint_id: Option, + ) -> Option<(Module<'a>, Option)> { if !module.expansion.outer_expn_is_descendant_of(*ctxt) { - return Some(self.expn_def_scope(ctxt.remove_mark())); + return Some((self.expn_def_scope(ctxt.remove_mark()), None)); } if let ModuleKind::Block = module.kind { - return Some(module.parent.unwrap().nearest_item_scope()); + return Some((module.parent.unwrap().nearest_item_scope(), None)); + } + + // We need to support the next case under a deprecation warning + // ``` + // struct MyStruct; + // ---- begin: this comes from a proc macro derive + // mod implementation_details { + // // Note that `MyStruct` is not in scope here. + // impl SomeTrait for MyStruct { ... } + // } + // ---- end + // ``` + // So we have to fall back to the module's parent during lexical resolution in this case. + if derive_fallback_lint_id.is_some() { + if let Some(parent) = module.parent { + // Inner module is inside the macro, parent module is outside of the macro. + if module.expansion != parent.expansion + && module.expansion.is_descendant_of(parent.expansion) + { + // The macro is a proc macro derive + if let Some(def_id) = module.expansion.expn_data().macro_def_id { + let ext = self.get_macro_by_def_id(def_id).ext; + if ext.builtin_name.is_none() + && ext.macro_kind() == MacroKind::Derive + && parent.expansion.outer_expn_is_descendant_of(*ctxt) + { + return Some((parent, derive_fallback_lint_id)); + } + } + } + } } None @@ -470,7 +510,7 @@ impl<'a> Resolver<'a> { Err((Determinacy::Determined, _)) => Err(Determinacy::Determined), } } - Scope::Module(module) => { + Scope::Module(module, derive_fallback_lint_id) => { let adjusted_parent_scope = &ParentScope { module, ..*parent_scope }; let binding = this.resolve_ident_in_module_unadjusted_ext( ModuleOrUniformRoot::Module(module), @@ -483,6 +523,21 @@ impl<'a> Resolver<'a> { ); match binding { Ok(binding) => { + if let Some(lint_id) = derive_fallback_lint_id { + this.lint_buffer.buffer_lint_with_diagnostic( + PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, + lint_id, + orig_ident.span, + &format!( + "cannot find {} `{}` in this scope", + ns.descr(), + ident + ), + BuiltinLintDiagnostics::ProcMacroDeriveResolutionFallback( + orig_ident.span, + ), + ); + } let misc_flags = if ptr::eq(module, this.graph_root) { Flags::MISC_SUGGEST_CRATE } else if module.is_normal() { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index f950e4a9bee65..1b181b714005b 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -105,7 +105,9 @@ enum Scope<'a> { DeriveHelpersCompat, MacroRules(MacroRulesScopeRef<'a>), CrateRoot, - Module(Module<'a>), + // The node ID is for reporting the `PROC_MACRO_DERIVE_RESOLUTION_FALLBACK` + // lint if it should be reported. + Module(Module<'a>, Option), MacroUsePrelude, BuiltinAttrs, ExternPrelude, @@ -1591,7 +1593,7 @@ impl<'a> Resolver<'a> { self.visit_scopes(ScopeSet::All(TypeNS, false), parent_scope, ctxt, |this, scope, _, _| { match scope { - Scope::Module(module) => { + Scope::Module(module, _) => { this.traits_in_module(module, assoc_item, &mut found_traits); } Scope::StdLibPrelude => { diff --git a/tests/ui/proc-macro/generate-mod.rs b/tests/ui/proc-macro/generate-mod.rs index 9eea630c310ec..471f317edf964 100644 --- a/tests/ui/proc-macro/generate-mod.rs +++ b/tests/ui/proc-macro/generate-mod.rs @@ -15,16 +15,19 @@ struct S; #[derive(generate_mod::CheckDerive)] //~ ERROR cannot find type `FromOutside` in this scope //~| ERROR cannot find type `OuterDerive` in this scope + //~| WARN this was previously accepted + //~| WARN this was previously accepted struct Z; fn inner_block() { #[derive(generate_mod::CheckDerive)] //~ ERROR cannot find type `FromOutside` in this scope //~| ERROR cannot find type `OuterDerive` in this scope + //~| WARN this was previously accepted + //~| WARN this was previously accepted struct InnerZ; } -#[derive(generate_mod::CheckDeriveLint)] //~ ERROR cannot find type `OuterDeriveLint` in this scope - //~| ERROR cannot find type `FromOutside` in this scope +#[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed struct W; fn main() {} diff --git a/tests/ui/proc-macro/generate-mod.stderr b/tests/ui/proc-macro/generate-mod.stderr index 2c55abf38c399..db629b5b5e239 100644 --- a/tests/ui/proc-macro/generate-mod.stderr +++ b/tests/ui/proc-macro/generate-mod.stderr @@ -38,66 +38,127 @@ LL | #[generate_mod::check_attr] OuterAttr = note: this error originates in the attribute macro `generate_mod::check_attr` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0412]: cannot find type `FromOutside` in this scope +error: cannot find type `FromOutside` in this scope --> $DIR/generate-mod.rs:16:10 | LL | #[derive(generate_mod::CheckDerive)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope + | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import | - = help: consider importing this struct: - FromOutside + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #83583 + = note: `#[deny(proc_macro_derive_resolution_fallback)]` on by default = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0412]: cannot find type `OuterDerive` in this scope +error: cannot find type `OuterDerive` in this scope --> $DIR/generate-mod.rs:16:10 | LL | #[derive(generate_mod::CheckDerive)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope + | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import | - = help: consider importing this struct: - OuterDerive + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #83583 = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0412]: cannot find type `FromOutside` in this scope - --> $DIR/generate-mod.rs:21:14 +error: cannot find type `FromOutside` in this scope + --> $DIR/generate-mod.rs:23:14 | LL | #[derive(generate_mod::CheckDerive)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope + | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import | - = help: consider importing this struct: - FromOutside + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #83583 = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0412]: cannot find type `OuterDerive` in this scope - --> $DIR/generate-mod.rs:21:14 +error: cannot find type `OuterDerive` in this scope + --> $DIR/generate-mod.rs:23:14 | LL | #[derive(generate_mod::CheckDerive)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope + | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import | - = help: consider importing this struct: - OuterDerive + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #83583 = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0412]: cannot find type `FromOutside` in this scope - --> $DIR/generate-mod.rs:26:10 +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0412`. +Future incompatibility report: Future breakage diagnostic: +error: cannot find type `FromOutside` in this scope + --> $DIR/generate-mod.rs:16:10 | -LL | #[derive(generate_mod::CheckDeriveLint)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope +LL | #[derive(generate_mod::CheckDerive)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import | - = help: consider importing this struct: - FromOutside - = note: this error originates in the derive macro `generate_mod::CheckDeriveLint` (in Nightly builds, run with -Z macro-backtrace for more info) + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #83583 + = note: `#[deny(proc_macro_derive_resolution_fallback)]` on by default + = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0412]: cannot find type `OuterDeriveLint` in this scope - --> $DIR/generate-mod.rs:26:10 +Future breakage diagnostic: +error: cannot find type `OuterDerive` in this scope + --> $DIR/generate-mod.rs:16:10 | -LL | #[derive(generate_mod::CheckDeriveLint)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope +LL | #[derive(generate_mod::CheckDerive)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import | - = help: consider importing this struct: - OuterDeriveLint - = note: this error originates in the derive macro `generate_mod::CheckDeriveLint` (in Nightly builds, run with -Z macro-backtrace for more info) + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #83583 + = note: `#[deny(proc_macro_derive_resolution_fallback)]` on by default + = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 10 previous errors +Future breakage diagnostic: +error: cannot find type `FromOutside` in this scope + --> $DIR/generate-mod.rs:23:14 + | +LL | #[derive(generate_mod::CheckDerive)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #83583 + = note: `#[deny(proc_macro_derive_resolution_fallback)]` on by default + = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) + +Future breakage diagnostic: +error: cannot find type `OuterDerive` in this scope + --> $DIR/generate-mod.rs:23:14 + | +LL | #[derive(generate_mod::CheckDerive)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #83583 + = note: `#[deny(proc_macro_derive_resolution_fallback)]` on by default + = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) + +Future breakage diagnostic: +warning: cannot find type `FromOutside` in this scope + --> $DIR/generate-mod.rs:30:10 + | +LL | #[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #83583 +note: the lint level is defined here + --> $DIR/generate-mod.rs:30:10 + | +LL | #[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this warning originates in the derive macro `generate_mod::CheckDeriveLint` (in Nightly builds, run with -Z macro-backtrace for more info) + +Future breakage diagnostic: +warning: cannot find type `OuterDeriveLint` in this scope + --> $DIR/generate-mod.rs:30:10 + | +LL | #[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #83583 +note: the lint level is defined here + --> $DIR/generate-mod.rs:30:10 + | +LL | #[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this warning originates in the derive macro `generate_mod::CheckDeriveLint` (in Nightly builds, run with -Z macro-backtrace for more info) -For more information about this error, try `rustc --explain E0412`. From 67978a7e97d713e725bcc7829f1bf1c9d289ae6c Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Fri, 20 Jan 2023 18:06:54 -0500 Subject: [PATCH 217/230] Bump to 1.69.0 --- src/version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version b/src/version index ee2f4ca913048..49349856550b6 100644 --- a/src/version +++ b/src/version @@ -1 +1 @@ -1.68.0 +1.69.0 From 6f1795a9faff958fecaea56d1edf3a85fa05a1a3 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Sat, 21 Jan 2023 00:17:15 +0100 Subject: [PATCH 218/230] update git2 dependency --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b3afaaa35c0a2..289e1e0005b03 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1799,9 +1799,9 @@ dependencies = [ [[package]] name = "git2" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be36bc9e0546df253c0cc41fd0af34f5e92845ad8509462ec76672fac6997f5b" +checksum = "ccf7f68c2995f392c49fffb4f95ae2c873297830eb25c6bc4c114ce8f4562acc" dependencies = [ "bitflags", "libc", @@ -2365,9 +2365,9 @@ dependencies = [ [[package]] name = "libgit2-sys" -version = "0.14.1+1.5.0" +version = "0.14.2+1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a07fb2692bc3593bda59de45a502bb3071659f2c515e28c71e728306b038e17" +checksum = "7f3d95f6b51075fe9810a7ae22c7095f12b98005ab364d8544797a825ce946a4" dependencies = [ "cc", "libc", From 8742fd9c8592a846d487e8a1cdab8235859c4bc8 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 8 Jan 2023 00:29:30 +0000 Subject: [PATCH 219/230] Label closure captures/generator locals that make opaque types recursive --- .../rustc_hir_analysis/src/check/check.rs | 59 +++++++++++++++++-- tests/ui/impl-trait/recursive-generator.rs | 23 ++++++++ .../ui/impl-trait/recursive-generator.stderr | 19 ++++++ .../recursive-impl-trait-type-indirect.stderr | 4 ++ 4 files changed, 99 insertions(+), 6 deletions(-) create mode 100644 tests/ui/impl-trait/recursive-generator.rs create mode 100644 tests/ui/impl-trait/recursive-generator.stderr diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index aa75132444a5a..abc1c2d7b8d17 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1391,11 +1391,15 @@ fn async_opaque_type_cycle_error(tcx: TyCtxt<'_>, span: Span) -> ErrorGuaranteed /// /// If all the return expressions evaluate to `!`, then we explain that the error will go away /// after changing it. This can happen when a user uses `panic!()` or similar as a placeholder. -fn opaque_type_cycle_error(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> ErrorGuaranteed { +fn opaque_type_cycle_error( + tcx: TyCtxt<'_>, + opaque_def_id: LocalDefId, + span: Span, +) -> ErrorGuaranteed { let mut err = struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type"); let mut label = false; - if let Some((def_id, visitor)) = get_owner_return_paths(tcx, def_id) { + if let Some((def_id, visitor)) = get_owner_return_paths(tcx, opaque_def_id) { let typeck_results = tcx.typeck(def_id); if visitor .returns @@ -1431,21 +1435,30 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> E .filter_map(|e| typeck_results.node_type_opt(e.hir_id).map(|t| (e.span, t))) .filter(|(_, ty)| !matches!(ty.kind(), ty::Never)) { - struct OpaqueTypeCollector(Vec); + #[derive(Default)] + struct OpaqueTypeCollector { + opaques: Vec, + closures: Vec, + } impl<'tcx> ty::visit::TypeVisitor<'tcx> for OpaqueTypeCollector { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { match *t.kind() { ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => { - self.0.push(def); + self.opaques.push(def); ControlFlow::Continue(()) } + ty::Closure(def_id, ..) | ty::Generator(def_id, ..) => { + self.closures.push(def_id); + t.super_visit_with(self) + } _ => t.super_visit_with(self), } } } - let mut visitor = OpaqueTypeCollector(vec![]); + + let mut visitor = OpaqueTypeCollector::default(); ty.visit_with(&mut visitor); - for def_id in visitor.0 { + for def_id in visitor.opaques { let ty_span = tcx.def_span(def_id); if !seen.contains(&ty_span) { err.span_label(ty_span, &format!("returning this opaque type `{ty}`")); @@ -1453,6 +1466,40 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> E } err.span_label(sp, &format!("returning here with type `{ty}`")); } + + for closure_def_id in visitor.closures { + let Some(closure_local_did) = closure_def_id.as_local() else { continue; }; + let typeck_results = tcx.typeck(closure_local_did); + + let mut label_match = |ty: Ty<'_>, span| { + for arg in ty.walk() { + if let ty::GenericArgKind::Type(ty) = arg.unpack() + && let ty::Alias(ty::Opaque, ty::AliasTy { def_id: captured_def_id, .. }) = *ty.kind() + && captured_def_id == opaque_def_id.to_def_id() + { + err.span_label( + span, + format!( + "{} captures itself here", + tcx.def_kind(closure_def_id).descr(closure_def_id) + ), + ); + } + } + }; + + // Label any closure upvars that capture the opaque + for capture in typeck_results.closure_min_captures_flattened(closure_local_did) + { + label_match(capture.place.ty(), capture.get_path_span(tcx)); + } + // Label any generator locals that capture the opaque + for interior_ty in + typeck_results.generator_interior_types.as_ref().skip_binder() + { + label_match(interior_ty.ty, interior_ty.span); + } + } } } } diff --git a/tests/ui/impl-trait/recursive-generator.rs b/tests/ui/impl-trait/recursive-generator.rs new file mode 100644 index 0000000000000..e876f0fb43f65 --- /dev/null +++ b/tests/ui/impl-trait/recursive-generator.rs @@ -0,0 +1,23 @@ +#![feature(generators, generator_trait)] + +use std::ops::{Generator, GeneratorState}; + +fn foo() -> impl Generator { + //~^ ERROR cannot resolve opaque type + //~| NOTE recursive opaque type + //~| NOTE in this expansion of desugaring of + || { + //~^ NOTE returning here + let mut gen = Box::pin(foo()); + //~^ NOTE generator captures itself here + let mut r = gen.as_mut().resume(()); + while let GeneratorState::Yielded(v) = r { + yield v; + r = gen.as_mut().resume(()); + } + } +} + +fn main() { + foo(); +} diff --git a/tests/ui/impl-trait/recursive-generator.stderr b/tests/ui/impl-trait/recursive-generator.stderr new file mode 100644 index 0000000000000..e23fd4b4a85e5 --- /dev/null +++ b/tests/ui/impl-trait/recursive-generator.stderr @@ -0,0 +1,19 @@ +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-generator.rs:5:13 + | +LL | fn foo() -> impl Generator { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive opaque type +... +LL | / || { +LL | | +LL | | let mut gen = Box::pin(foo()); + | | ------- generator captures itself here +LL | | +... | +LL | | } +LL | | } + | |_____- returning here with type `[generator@$DIR/recursive-generator.rs:9:5: 9:7]` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0720`. diff --git a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr index 2e34d3d4275ad..ebb231ae14f0d 100644 --- a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr +++ b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr @@ -53,6 +53,7 @@ LL | fn closure_capture() -> impl Sized { ... LL | / move || { LL | | x; + | | - closure captures itself here LL | | } | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:35:5: 35:12]` @@ -64,6 +65,7 @@ LL | fn closure_ref_capture() -> impl Sized { ... LL | / move || { LL | | &x; + | | - closure captures itself here LL | | } | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:43:5: 43:12]` @@ -94,6 +96,7 @@ LL | fn generator_capture() -> impl Sized { LL | / move || { LL | | yield; LL | | x; + | | - generator captures itself here LL | | } | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:61:5: 61:12]` @@ -114,6 +117,7 @@ LL | fn generator_hold() -> impl Sized { LL | LL | / move || { LL | | let x = generator_hold(); + | | - generator captures itself here LL | | yield; LL | | x; LL | | } From 397e4b13f9441afb6e1e4d78708dd5f99aefe685 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 21 Jan 2023 12:15:42 +0100 Subject: [PATCH 220/230] Migrate scraped-examples top and bottom "borders" to CSS variables --- src/librustdoc/html/static/css/rustdoc.css | 6 ++++++ src/librustdoc/html/static/css/themes/ayu.css | 9 ++------- src/librustdoc/html/static/css/themes/dark.css | 9 ++------- src/librustdoc/html/static/css/themes/light.css | 9 ++------- 4 files changed, 12 insertions(+), 21 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index a08b8d89db67d..8ff8ea088be91 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1907,9 +1907,15 @@ in storage.js } .scraped-example:not(.expanded) .code-wrapper:before { top: 0; + background: linear-gradient(to bottom, + var(--scrape-example-code-wrapper-background-start), + var(--scrape-example-code-wrapper-background-end)); } .scraped-example:not(.expanded) .code-wrapper:after { bottom: 0; + background: linear-gradient(to top, + var(--scrape-example-code-wrapper-background-start), + var(--scrape-example-code-wrapper-background-end)); } .scraped-example .code-wrapper .example-wrap { diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css index 979e7e0f999ed..ed779bf6166ee 100644 --- a/src/librustdoc/html/static/css/themes/ayu.css +++ b/src/librustdoc/html/static/css/themes/ayu.css @@ -97,6 +97,8 @@ Original by Dempfi (https://github.com/dempfi/ayu) --scrape-example-help-color: #eee; --scrape-example-help-hover-border-color: #fff; --scrape-example-help-hover-color: #fff; + --scrape-example-code-wrapper-background-start: rgba(15, 20, 25, 1); + --scrape-example-code-wrapper-background-end: rgba(15, 20, 25, 0); } h1, h2, h3, h4 { @@ -203,10 +205,3 @@ above the `@media (max-width: 700px)` rules due to a bug in the css checker */ #source-sidebar div.files > a.selected { color: #ffb44c; } - -.scraped-example:not(.expanded) .code-wrapper::before { - background: linear-gradient(to bottom, rgba(15, 20, 25, 1), rgba(15, 20, 25, 0)); -} -.scraped-example:not(.expanded) .code-wrapper::after { - background: linear-gradient(to top, rgba(15, 20, 25, 1), rgba(15, 20, 25, 0)); -} diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css index fb15863b027ca..3766f0daa42ff 100644 --- a/src/librustdoc/html/static/css/themes/dark.css +++ b/src/librustdoc/html/static/css/themes/dark.css @@ -92,6 +92,8 @@ --scrape-example-help-color: #eee; --scrape-example-help-hover-border-color: #fff; --scrape-example-help-hover-color: #fff; + --scrape-example-code-wrapper-background-start: rgba(53, 53, 53, 1); + --scrape-example-code-wrapper-background-end: rgba(53, 53, 53, 0); } #search-tabs > button:not(.selected) { @@ -103,10 +105,3 @@ border-top-color: #0089ff; background-color: #353535; } - -.scraped-example:not(.expanded) .code-wrapper::before { - background: linear-gradient(to bottom, rgba(53, 53, 53, 1), rgba(53, 53, 53, 0)); -} -.scraped-example:not(.expanded) .code-wrapper::after { - background: linear-gradient(to top, rgba(53, 53, 53, 1), rgba(53, 53, 53, 0)); -} diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css index 053fa78d1dc58..8a7f6abcf8d8e 100644 --- a/src/librustdoc/html/static/css/themes/light.css +++ b/src/librustdoc/html/static/css/themes/light.css @@ -89,6 +89,8 @@ --scrape-example-help-color: #333; --scrape-example-help-hover-border-color: #000; --scrape-example-help-hover-color: #000; + --scrape-example-code-wrapper-background-start: rgba(255, 255, 255, 1); + --scrape-example-code-wrapper-background-end: rgba(255, 255, 255, 0); } #search-tabs > button:not(.selected) { @@ -100,10 +102,3 @@ background-color: #ffffff; border-top-color: #0089ff; } - -.scraped-example:not(.expanded) .code-wrapper::before { - background: linear-gradient(to bottom, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0)); -} -.scraped-example:not(.expanded) .code-wrapper::after { - background: linear-gradient(to top, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0)); -} From 372ad130d595d50a8c79c836fcadc3b39d14859c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 21 Jan 2023 12:16:02 +0100 Subject: [PATCH 221/230] Extend rustdoc GUI test for scraped examples top and bottom "borders" --- tests/rustdoc-gui/scrape-examples-color.goml | 36 ++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/rustdoc-gui/scrape-examples-color.goml b/tests/rustdoc-gui/scrape-examples-color.goml index 40f31b2771b25..67c58826efc26 100644 --- a/tests/rustdoc-gui/scrape-examples-color.goml +++ b/tests/rustdoc-gui/scrape-examples-color.goml @@ -58,3 +58,39 @@ call-function: ("check-colors", { "help_hover_border": "rgb(0, 0, 0)", "help_hover_color": "rgb(0, 0, 0)", }) + +// Now testing the top and bottom background in case there is only one scraped examples. +goto: "file://" + |DOC_PATH| + "/scrape_examples/fn.test.html" + +define-function: ( + "check-background", + (theme, background_color_start, background_color_end), + block { + local-storage: { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false", } + reload: + assert-css: (".scraped-example:not(.expanded) .code-wrapper::before", { + "background-image": "linear-gradient(" + |background_color_start| + ", " + + |background_color_end| + ")", + }) + assert-css: (".scraped-example:not(.expanded) .code-wrapper::after", { + "background-image": "linear-gradient(to top, " + |background_color_start| + ", " + + |background_color_end| + ")", + }) + }, +) + +call-function: ("check-background", { + "theme": "ayu", + "background_color_start": "rgb(15, 20, 25)", + "background_color_end": "rgba(15, 20, 25, 0)", +}) +call-function: ("check-background", { + "theme": "dark", + "background_color_start": "rgb(53, 53, 53)", + "background_color_end": "rgba(53, 53, 53, 0)", +}) +call-function: ("check-background", { + "theme": "light", + "background_color_start": "rgb(255, 255, 255)", + "background_color_end": "rgba(255, 255, 255, 0)", +}) From 248988923195a17b14b740a4f550d87d33477916 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 20 Jan 2023 02:05:57 +0000 Subject: [PATCH 222/230] Add compare-mode-next-solver --- src/tools/compiletest/src/common.rs | 3 +++ src/tools/compiletest/src/header.rs | 1 + src/tools/compiletest/src/runtest.rs | 3 +++ 3 files changed, 7 insertions(+) diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index a5f5eb447da6c..3676f69b100db 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -123,6 +123,7 @@ pub enum FailMode { pub enum CompareMode { Polonius, Chalk, + NextSolver, SplitDwarf, SplitDwarfSingle, } @@ -132,6 +133,7 @@ impl CompareMode { match *self { CompareMode::Polonius => "polonius", CompareMode::Chalk => "chalk", + CompareMode::NextSolver => "next-solver", CompareMode::SplitDwarf => "split-dwarf", CompareMode::SplitDwarfSingle => "split-dwarf-single", } @@ -141,6 +143,7 @@ impl CompareMode { match s.as_str() { "polonius" => CompareMode::Polonius, "chalk" => CompareMode::Chalk, + "next-solver" => CompareMode::NextSolver, "split-dwarf" => CompareMode::SplitDwarf, "split-dwarf-single" => CompareMode::SplitDwarfSingle, x => panic!("unknown --compare-mode option: {}", x), diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index c49ecb104a74a..9d99231e4c7b9 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -701,6 +701,7 @@ impl Config { match self.compare_mode { Some(CompareMode::Polonius) => name == "compare-mode-polonius", Some(CompareMode::Chalk) => name == "compare-mode-chalk", + Some(CompareMode::NextSolver) => name == "compare-mode-next-solver", Some(CompareMode::SplitDwarf) => name == "compare-mode-split-dwarf", Some(CompareMode::SplitDwarfSingle) => name == "compare-mode-split-dwarf-single", None => false, diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index a16ab11e2f978..a181cdf2da60a 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2013,6 +2013,9 @@ impl<'test> TestCx<'test> { Some(CompareMode::Chalk) => { rustc.args(&["-Ztrait-solver=chalk"]); } + Some(CompareMode::NextSolver) => { + rustc.args(&["-Ztrait-solver=next"]); + } Some(CompareMode::SplitDwarf) if self.config.target.contains("windows") => { rustc.args(&["-Csplit-debuginfo=unpacked", "-Zunstable-options"]); } From d6a411c086e61926aa52022b1df3a4a94e934906 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 20 Jan 2023 03:05:06 +0000 Subject: [PATCH 223/230] Implement some more predicates --- .../rustc_trait_selection/src/solve/mod.rs | 64 +++++++++++++++++-- 1 file changed, 57 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 32eb84635b536..e89d3df04db0b 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -26,7 +26,9 @@ use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::Obligation; use rustc_middle::infer::canonical::Certainty as OldCertainty; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_middle::ty::{RegionOutlivesPredicate, ToPredicate, TypeOutlivesPredicate}; +use rustc_middle::ty::{ + RegionOutlivesPredicate, SubtypePredicate, ToPredicate, TypeOutlivesPredicate, +}; use rustc_span::DUMMY_SP; use crate::traits::ObligationCause; @@ -243,16 +245,34 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { ty::PredicateKind::Clause(ty::Clause::RegionOutlives(predicate)) => { self.compute_region_outlives_goal(Goal { param_env, predicate }) } + ty::PredicateKind::Subtype(predicate) => { + self.compute_subtype_goal(Goal { param_env, predicate }) + } + ty::PredicateKind::Coerce(predicate) => self.compute_subtype_goal(Goal { + param_env, + predicate: SubtypePredicate { + a_is_expected: true, + a: predicate.a, + b: predicate.b, + }, + }), + ty::PredicateKind::ClosureKind(_, substs, kind) => self.compute_closure_kind_goal( + substs.as_closure().kind_ty().to_opt_closure_kind(), + kind, + ), + ty::PredicateKind::Ambiguous => { + self.make_canonical_response(Certainty::Maybe(MaybeCause::Ambiguity)) + } // FIXME: implement these predicates :) ty::PredicateKind::WellFormed(_) | ty::PredicateKind::ObjectSafe(_) - | ty::PredicateKind::ClosureKind(_, _, _) - | ty::PredicateKind::Subtype(_) - | ty::PredicateKind::Coerce(_) | ty::PredicateKind::ConstEvaluatable(_) - | ty::PredicateKind::ConstEquate(_, _) - | ty::PredicateKind::TypeWellFormedFromEnv(_) - | ty::PredicateKind::Ambiguous => self.make_canonical_response(Certainty::Yes), + | ty::PredicateKind::ConstEquate(_, _) => { + self.make_canonical_response(Certainty::Yes) + } + ty::PredicateKind::TypeWellFormedFromEnv(..) => { + bug!("TypeWellFormedFromEnv is only used for Chalk") + } } } else { let kind = self.infcx.replace_bound_vars_with_placeholders(kind); @@ -275,6 +295,36 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { ) -> QueryResult<'tcx> { self.make_canonical_response(Certainty::Yes) } + + fn compute_subtype_goal( + &mut self, + goal: Goal<'tcx, SubtypePredicate<'tcx>>, + ) -> QueryResult<'tcx> { + self.infcx.probe(|_| { + let InferOk { value: (), obligations } = self + .infcx + .at(&ObligationCause::dummy(), goal.param_env) + .sub(goal.predicate.a, goal.predicate.b)?; + self.evaluate_all_and_make_canonical_response( + obligations.into_iter().map(|pred| pred.into()).collect(), + ) + }) + } + + fn compute_closure_kind_goal( + &mut self, + found_kind: Option, + expected_kind: ty::ClosureKind, + ) -> QueryResult<'tcx> { + let Some(found_kind) = found_kind else { + return self.make_canonical_response(Certainty::Maybe(MaybeCause::Ambiguity)); + }; + if found_kind.extends(expected_kind) { + self.make_canonical_response(Certainty::Yes) + } else { + Err(NoSolution) + } + } } impl<'tcx> EvalCtxt<'_, 'tcx> { From 444cbcd729e4b55602fedcaef7fe902316d8ab49 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 20 Jan 2023 18:38:33 +0000 Subject: [PATCH 224/230] Address goal nits --- .../src/solve/assembly.rs | 6 +- .../rustc_trait_selection/src/solve/mod.rs | 73 ++++++++++++------- .../src/solve/project_goals.rs | 7 +- .../src/solve/trait_goals.rs | 6 +- 4 files changed, 54 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs index 31c1bc9ecc062..cdb72d49834f0 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -1,7 +1,7 @@ //! Code shared by trait and projection goals for candidate assembly. use super::infcx_ext::InferCtxtExt; -use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, MaybeCause, QueryResult}; +use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, QueryResult}; use rustc_hir::def_id::DefId; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::util::elaborate_predicates; @@ -148,9 +148,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { if goal.predicate.self_ty().is_ty_var() { return vec![Candidate { source: CandidateSource::BuiltinImpl, - result: self - .make_canonical_response(Certainty::Maybe(MaybeCause::Ambiguity)) - .unwrap(), + result: self.make_canonical_response(Certainty::AMBIGUOUS).unwrap(), }]; } diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index e89d3df04db0b..da2a1a19957e1 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -19,6 +19,7 @@ use std::mem; +use rustc_hir::def_id::DefId; use rustc_infer::infer::canonical::{Canonical, CanonicalVarKind, CanonicalVarValues}; use rustc_infer::infer::canonical::{OriginalQueryValues, QueryRegionConstraints, QueryResponse}; use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt}; @@ -27,7 +28,7 @@ use rustc_infer::traits::Obligation; use rustc_middle::infer::canonical::Certainty as OldCertainty; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{ - RegionOutlivesPredicate, SubtypePredicate, ToPredicate, TypeOutlivesPredicate, + CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, ToPredicate, TypeOutlivesPredicate, }; use rustc_span::DUMMY_SP; @@ -89,6 +90,8 @@ pub enum Certainty { } impl Certainty { + pub const AMBIGUOUS: Certainty = Certainty::Maybe(MaybeCause::Ambiguity); + /// When proving multiple goals using **AND**, e.g. nested obligations for an impl, /// use this function to unify the certainty of these goals pub fn unify_and(self, other: Certainty) -> Certainty { @@ -248,21 +251,15 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { ty::PredicateKind::Subtype(predicate) => { self.compute_subtype_goal(Goal { param_env, predicate }) } - ty::PredicateKind::Coerce(predicate) => self.compute_subtype_goal(Goal { - param_env, - predicate: SubtypePredicate { - a_is_expected: true, - a: predicate.a, - b: predicate.b, - }, - }), - ty::PredicateKind::ClosureKind(_, substs, kind) => self.compute_closure_kind_goal( - substs.as_closure().kind_ty().to_opt_closure_kind(), - kind, - ), - ty::PredicateKind::Ambiguous => { - self.make_canonical_response(Certainty::Maybe(MaybeCause::Ambiguity)) + ty::PredicateKind::Coerce(predicate) => { + self.compute_coerce_goal(Goal { param_env, predicate }) } + ty::PredicateKind::ClosureKind(def_id, substs, kind) => self + .compute_closure_kind_goal(Goal { + param_env, + predicate: (def_id, substs, kind), + }), + ty::PredicateKind::Ambiguous => self.make_canonical_response(Certainty::AMBIGUOUS), // FIXME: implement these predicates :) ty::PredicateKind::WellFormed(_) | ty::PredicateKind::ObjectSafe(_) @@ -296,28 +293,50 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { self.make_canonical_response(Certainty::Yes) } + fn compute_coerce_goal( + &mut self, + goal: Goal<'tcx, CoercePredicate<'tcx>>, + ) -> QueryResult<'tcx> { + self.compute_subtype_goal(Goal { + param_env: goal.param_env, + predicate: SubtypePredicate { + a_is_expected: false, + a: goal.predicate.a, + b: goal.predicate.b, + }, + }) + } + fn compute_subtype_goal( &mut self, goal: Goal<'tcx, SubtypePredicate<'tcx>>, ) -> QueryResult<'tcx> { - self.infcx.probe(|_| { - let InferOk { value: (), obligations } = self - .infcx - .at(&ObligationCause::dummy(), goal.param_env) - .sub(goal.predicate.a, goal.predicate.b)?; - self.evaluate_all_and_make_canonical_response( - obligations.into_iter().map(|pred| pred.into()).collect(), - ) - }) + if goal.predicate.a.is_ty_var() && goal.predicate.b.is_ty_var() { + // FIXME: Do we want to register a subtype relation between these vars? + // That won't actually reflect in the query response, so it seems moot. + self.make_canonical_response(Certainty::AMBIGUOUS) + } else { + self.infcx.probe(|_| { + let InferOk { value: (), obligations } = self + .infcx + .at(&ObligationCause::dummy(), goal.param_env) + .sub(goal.predicate.a, goal.predicate.b)?; + self.evaluate_all_and_make_canonical_response( + obligations.into_iter().map(|pred| pred.into()).collect(), + ) + }) + } } fn compute_closure_kind_goal( &mut self, - found_kind: Option, - expected_kind: ty::ClosureKind, + goal: Goal<'tcx, (DefId, ty::SubstsRef<'tcx>, ty::ClosureKind)>, ) -> QueryResult<'tcx> { + let (_, substs, expected_kind) = goal.predicate; + let found_kind = substs.as_closure().kind_ty().to_opt_closure_kind(); + let Some(found_kind) = found_kind else { - return self.make_canonical_response(Certainty::Maybe(MaybeCause::Ambiguity)); + return self.make_canonical_response(Certainty::AMBIGUOUS); }; if found_kind.extends(expected_kind) { self.make_canonical_response(Certainty::Yes) diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index e39fa05339286..32e15f03998b3 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -3,7 +3,7 @@ use crate::traits::{specialization_graph, translate_substs}; use super::assembly::{self, Candidate, CandidateSource}; use super::infcx_ext::InferCtxtExt; use super::trait_goals::structural_traits; -use super::{Certainty, EvalCtxt, Goal, MaybeCause, QueryResult}; +use super::{Certainty, EvalCtxt, Goal, QueryResult}; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; @@ -229,8 +229,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { goal.predicate.def_id(), impl_def_id )? else { - let certainty = Certainty::Maybe(MaybeCause::Ambiguity); - return ecx.make_canonical_response(trait_ref_certainty.unify_and(certainty)); + return ecx.make_canonical_response(trait_ref_certainty.unify_and(Certainty::AMBIGUOUS)); }; if !assoc_def.item.defaultness(tcx).has_value() { @@ -382,7 +381,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { .to_predicate(ecx.tcx()); Self::consider_assumption(ecx, goal, pred) } else { - ecx.make_canonical_response(Certainty::Maybe(MaybeCause::Ambiguity)) + ecx.make_canonical_response(Certainty::AMBIGUOUS) } } diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 9985d7181bb7d..4b6d673c999c9 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -4,7 +4,7 @@ use std::iter; use super::assembly::{self, Candidate, CandidateSource}; use super::infcx_ext::InferCtxtExt; -use super::{Certainty, EvalCtxt, Goal, MaybeCause, QueryResult}; +use super::{Certainty, EvalCtxt, Goal, QueryResult}; use rustc_hir::def_id::DefId; use rustc_infer::infer::InferCtxt; use rustc_infer::traits::query::NoSolution; @@ -133,7 +133,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { if goal.predicate.self_ty().has_non_region_infer() { - return ecx.make_canonical_response(Certainty::Maybe(MaybeCause::Ambiguity)); + return ecx.make_canonical_response(Certainty::AMBIGUOUS); } let tcx = ecx.tcx(); @@ -171,7 +171,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { .to_predicate(ecx.tcx()); Self::consider_assumption(ecx, goal, pred) } else { - ecx.make_canonical_response(Certainty::Maybe(MaybeCause::Ambiguity)) + ecx.make_canonical_response(Certainty::AMBIGUOUS) } } From dc8876196b7d0a219a02f479abb5876b71270eeb Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 22 Oct 2022 17:28:08 -0500 Subject: [PATCH 225/230] Add `SEMICOLON_IN_EXPRESSIONS_FROM_MACROS` to future-incompat report --- compiler/rustc_lint_defs/src/builtin.rs | 1 + ...emicolon-in-expressions-from-macros.stderr | 137 ++++++++++++++++++ ...emicolon-in-expressions-from-macros.stderr | 15 ++ .../macros/issue-84195-lint-anon-const.stderr | 19 +++ .../ui/macros/lint-trailing-macro-call.stderr | 17 +++ tests/ui/macros/macro-context.stderr | 15 ++ .../macros/macro-in-expression-context.stderr | 17 +++ 7 files changed, 221 insertions(+) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 1ac97849ec611..357b00b1a9958 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -2948,6 +2948,7 @@ declare_lint! { "trailing semicolon in macro body used as expression", @future_incompatible = FutureIncompatibleInfo { reference: "issue #79813 ", + reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow, }; } diff --git a/tests/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.stderr b/tests/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.stderr index 49608c20524d3..c60120061643d 100644 --- a/tests/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.stderr +++ b/tests/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.stderr @@ -46,3 +46,140 @@ LL | let _ = #[allow(semicolon_in_expressions_from_macros)] foo!(allow_does_ warning: 3 warnings emitted +Future incompatibility report: Future breakage diagnostic: +warning: trailing semicolon in macro used in expression position + --> $DIR/semicolon-in-expressions-from-macros.rs:9:13 + | +LL | true; + | ^ +... +LL | foo!(first) + | ----------- in this macro invocation + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79813 + = note: macro invocations at the end of a block are treated as expressions + = note: to ignore the value produced by the macro, add a semicolon after the invocation of `foo` +note: the lint level is defined here + --> $DIR/semicolon-in-expressions-from-macros.rs:24:13 + | +LL | #[allow(semicolon_in_expressions_from_macros)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +Future breakage diagnostic: +warning: trailing semicolon in macro used in expression position + --> $DIR/semicolon-in-expressions-from-macros.rs:9:13 + | +LL | true; + | ^ +... +LL | let _ = foo!(second); + | ------------ in this macro invocation + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79813 +note: the lint level is defined here + --> $DIR/semicolon-in-expressions-from-macros.rs:29:13 + | +LL | #[allow(semicolon_in_expressions_from_macros)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +Future breakage diagnostic: +warning: trailing semicolon in macro used in expression position + --> $DIR/semicolon-in-expressions-from-macros.rs:9:13 + | +LL | true; + | ^ +... +LL | let _ = foo!(third); + | ----------- in this macro invocation + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79813 +note: the lint level is defined here + --> $DIR/semicolon-in-expressions-from-macros.rs:32:13 + | +LL | #[allow(semicolon_in_expressions_from_macros)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +Future breakage diagnostic: +warning: trailing semicolon in macro used in expression position + --> $DIR/semicolon-in-expressions-from-macros.rs:9:13 + | +LL | true; + | ^ +... +LL | let _ = foo!(fourth); + | ------------ in this macro invocation + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79813 +note: the lint level is defined here + --> $DIR/semicolon-in-expressions-from-macros.rs:37:13 + | +LL | #[allow(semicolon_in_expressions_from_macros)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +Future breakage diagnostic: +warning: trailing semicolon in macro used in expression position + --> $DIR/semicolon-in-expressions-from-macros.rs:9:13 + | +LL | true; + | ^ +... +LL | foo!(warn_in_block) + | ------------------- in this macro invocation + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79813 + = note: macro invocations at the end of a block are treated as expressions + = note: to ignore the value produced by the macro, add a semicolon after the invocation of `foo` +note: the lint level is defined here + --> $DIR/semicolon-in-expressions-from-macros.rs:4:9 + | +LL | #![warn(semicolon_in_expressions_from_macros)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +Future breakage diagnostic: +warning: trailing semicolon in macro used in expression position + --> $DIR/semicolon-in-expressions-from-macros.rs:9:13 + | +LL | true; + | ^ +... +LL | let _ = foo!(warn_in_expr); + | ------------------ in this macro invocation + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79813 +note: the lint level is defined here + --> $DIR/semicolon-in-expressions-from-macros.rs:4:9 + | +LL | #![warn(semicolon_in_expressions_from_macros)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +Future breakage diagnostic: +warning: trailing semicolon in macro used in expression position + --> $DIR/semicolon-in-expressions-from-macros.rs:9:13 + | +LL | true; + | ^ +... +LL | let _ = #[allow(semicolon_in_expressions_from_macros)] foo!(allow_does_not_work); + | ------------------------- in this macro invocation + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79813 +note: the lint level is defined here + --> $DIR/semicolon-in-expressions-from-macros.rs:4:9 + | +LL | #![warn(semicolon_in_expressions_from_macros)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + diff --git a/tests/ui/lint/semicolon-in-expressions-from-macros/warn-semicolon-in-expressions-from-macros.stderr b/tests/ui/lint/semicolon-in-expressions-from-macros/warn-semicolon-in-expressions-from-macros.stderr index 16c152eb23c2d..0fec4996f1a0a 100644 --- a/tests/ui/lint/semicolon-in-expressions-from-macros/warn-semicolon-in-expressions-from-macros.stderr +++ b/tests/ui/lint/semicolon-in-expressions-from-macros/warn-semicolon-in-expressions-from-macros.stderr @@ -14,3 +14,18 @@ LL | _ => foo!() warning: 1 warning emitted +Future incompatibility report: Future breakage diagnostic: +warning: trailing semicolon in macro used in expression position + --> $DIR/warn-semicolon-in-expressions-from-macros.rs:6:13 + | +LL | true; + | ^ +... +LL | _ => foo!() + | ------ in this macro invocation + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79813 + = note: `#[warn(semicolon_in_expressions_from_macros)]` on by default + = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + diff --git a/tests/ui/macros/issue-84195-lint-anon-const.stderr b/tests/ui/macros/issue-84195-lint-anon-const.stderr index 306c08b13573e..29ccd17e06999 100644 --- a/tests/ui/macros/issue-84195-lint-anon-const.stderr +++ b/tests/ui/macros/issue-84195-lint-anon-const.stderr @@ -18,3 +18,22 @@ LL | #![deny(semicolon_in_expressions_from_macros)] error: aborting due to previous error +Future incompatibility report: Future breakage diagnostic: +error: trailing semicolon in macro used in expression position + --> $DIR/issue-84195-lint-anon-const.rs:8:14 + | +LL | () => { 0; }; + | ^ +... +LL | let val: [u8; len!()] = []; + | ------ in this macro invocation + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79813 +note: the lint level is defined here + --> $DIR/issue-84195-lint-anon-const.rs:5:9 + | +LL | #![deny(semicolon_in_expressions_from_macros)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `len` (in Nightly builds, run with -Z macro-backtrace for more info) + diff --git a/tests/ui/macros/lint-trailing-macro-call.stderr b/tests/ui/macros/lint-trailing-macro-call.stderr index 6ab121f7c06c6..13cecc3a31d23 100644 --- a/tests/ui/macros/lint-trailing-macro-call.stderr +++ b/tests/ui/macros/lint-trailing-macro-call.stderr @@ -16,3 +16,20 @@ LL | expand_it!() warning: 1 warning emitted +Future incompatibility report: Future breakage diagnostic: +warning: trailing semicolon in macro used in expression position + --> $DIR/lint-trailing-macro-call.rs:9:25 + | +LL | #[cfg(FALSE)] 25; + | ^ +... +LL | expand_it!() + | ------------ in this macro invocation + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79813 + = note: macro invocations at the end of a block are treated as expressions + = note: to ignore the value produced by the macro, add a semicolon after the invocation of `expand_it` + = note: `#[warn(semicolon_in_expressions_from_macros)]` on by default + = note: this warning originates in the macro `expand_it` (in Nightly builds, run with -Z macro-backtrace for more info) + diff --git a/tests/ui/macros/macro-context.stderr b/tests/ui/macros/macro-context.stderr index f597c398b7c17..7785f41594627 100644 --- a/tests/ui/macros/macro-context.stderr +++ b/tests/ui/macros/macro-context.stderr @@ -82,3 +82,18 @@ error: aborting due to 6 previous errors; 1 warning emitted Some errors have detailed explanations: E0412, E0425. For more information about an error, try `rustc --explain E0412`. +Future incompatibility report: Future breakage diagnostic: +warning: trailing semicolon in macro used in expression position + --> $DIR/macro-context.rs:3:15 + | +LL | () => ( i ; typeof ); + | ^ +... +LL | let i = m!(); + | ---- in this macro invocation + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79813 + = note: `#[warn(semicolon_in_expressions_from_macros)]` on by default + = note: this warning originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + diff --git a/tests/ui/macros/macro-in-expression-context.stderr b/tests/ui/macros/macro-in-expression-context.stderr index 36aba8aa08a0b..3f492b141a5f5 100644 --- a/tests/ui/macros/macro-in-expression-context.stderr +++ b/tests/ui/macros/macro-in-expression-context.stderr @@ -31,3 +31,20 @@ LL | foo!() error: aborting due to previous error; 1 warning emitted +Future incompatibility report: Future breakage diagnostic: +warning: trailing semicolon in macro used in expression position + --> $DIR/macro-in-expression-context.rs:5:29 + | +LL | assert_eq!("A", "A"); + | ^ +... +LL | foo!() + | ------ in this macro invocation + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79813 + = note: macro invocations at the end of a block are treated as expressions + = note: to ignore the value produced by the macro, add a semicolon after the invocation of `foo` + = note: `#[warn(semicolon_in_expressions_from_macros)]` on by default + = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + From e54028b68eb2dc0adc52aa3be4d1f521065ab4a9 Mon Sep 17 00:00:00 2001 From: Albert Larsan <74931857+albertlarsan68@users.noreply.github.com> Date: Sat, 21 Jan 2023 20:52:20 +0000 Subject: [PATCH 226/230] Add myself to .mailmap --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index 022cdd0fd50c1..42c86a827693a 100644 --- a/.mailmap +++ b/.mailmap @@ -15,6 +15,7 @@ Adrien Tétar Ahmed Charles Alan Egerton Alan Stoate +Albert Larsan Albert Larsan <74931857+albertlarsan68@users.noreply.github.com> Alessandro Decina Alex Burka Alex Burka Alex Hansen From 68803926e0f32b74c30ecb40a4a1c5e9221bb18b Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 22 Jan 2023 01:33:53 +0400 Subject: [PATCH 227/230] rustdoc: Use `DefId(Map,Set)` instead of `FxHash(Map,Set)` Not all uses are converted, a few cases iterating through maps/sets and requiring nontrivial changes are kept. --- src/librustdoc/clean/inline.rs | 16 ++++++---------- src/librustdoc/clean/mod.rs | 10 +++++----- src/librustdoc/core.rs | 12 ++++-------- src/librustdoc/formats/cache.rs | 10 +++++----- src/librustdoc/html/render/context.rs | 8 ++++---- src/librustdoc/html/render/mod.rs | 12 ++++++------ src/librustdoc/json/import_finder.rs | 10 +++++----- src/librustdoc/json/mod.rs | 6 +++--- src/librustdoc/passes/collect_trait_impls.rs | 12 ++++++------ src/librustdoc/visit_ast.rs | 15 +++++++-------- src/librustdoc/visit_lib.rs | 9 ++++----- 11 files changed, 55 insertions(+), 65 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index b3b0933123349..da300b89a4e9b 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -9,7 +9,7 @@ use rustc_ast as ast; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::{DefId, DefIdSet, LocalDefId}; use rustc_hir::Mutability; use rustc_metadata::creader::{CStore, LoadedMacro}; use rustc_middle::ty::{self, TyCtxt}; @@ -45,7 +45,7 @@ pub(crate) fn try_inline( res: Res, name: Symbol, attrs: Option<&[ast::Attribute]>, - visited: &mut FxHashSet, + visited: &mut DefIdSet, ) -> Option> { let did = res.opt_def_id()?; if did.is_local() { @@ -163,7 +163,7 @@ pub(crate) fn try_inline_glob( cx: &mut DocContext<'_>, res: Res, current_mod: LocalDefId, - visited: &mut FxHashSet, + visited: &mut DefIdSet, inlined_names: &mut FxHashSet<(ItemType, Symbol)>, ) -> Option> { let did = res.opt_def_id()?; @@ -568,11 +568,7 @@ pub(crate) fn build_impl( )); } -fn build_module( - cx: &mut DocContext<'_>, - did: DefId, - visited: &mut FxHashSet, -) -> clean::Module { +fn build_module(cx: &mut DocContext<'_>, did: DefId, visited: &mut DefIdSet) -> clean::Module { let items = build_module_items(cx, did, visited, &mut FxHashSet::default(), None); let span = clean::Span::new(cx.tcx.def_span(did)); @@ -582,9 +578,9 @@ fn build_module( fn build_module_items( cx: &mut DocContext<'_>, did: DefId, - visited: &mut FxHashSet, + visited: &mut DefIdSet, inlined_names: &mut FxHashSet<(ItemType, Symbol)>, - allowed_def_ids: Option<&FxHashSet>, + allowed_def_ids: Option<&DefIdSet>, ) -> Vec { let mut items = Vec::new(); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 20984696b6c01..34a7068e5da53 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -15,7 +15,7 @@ use rustc_attr as attr; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet, IndexEntry}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; -use rustc_hir::def_id::{DefId, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LOCAL_CRATE}; use rustc_hir::PredicateOrigin; use rustc_hir_analysis::hir_ty_to_ty; use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData}; @@ -1528,7 +1528,7 @@ fn maybe_expand_private_type_alias<'tcx>( let hir::ItemKind::TyAlias(ty, generics) = alias else { return None }; let provided_params = &path.segments.last().expect("segments were empty"); - let mut substs = FxHashMap::default(); + let mut substs = DefIdMap::default(); let generic_args = provided_params.args(); let mut indices: hir::GenericParamCount = Default::default(); @@ -2321,7 +2321,7 @@ fn clean_extern_crate<'tcx>( let krate_owner_def_id = krate.owner_id.to_def_id(); if please_inline { - let mut visited = FxHashSet::default(); + let mut visited = DefIdSet::default(); let res = Res::Def(DefKind::Mod, crate_def_id); @@ -2440,7 +2440,7 @@ fn clean_use_statement_inner<'tcx>( let path = clean_path(path, cx); let inner = if kind == hir::UseKind::Glob { if !denied { - let mut visited = FxHashSet::default(); + let mut visited = DefIdSet::default(); if let Some(items) = inline::try_inline_glob(cx, path.res, current_mod, &mut visited, inlined_names) { @@ -2459,7 +2459,7 @@ fn clean_use_statement_inner<'tcx>( } } if !denied { - let mut visited = FxHashSet::default(); + let mut visited = DefIdSet::default(); let import_def_id = import.owner_id.to_def_id(); if let Some(mut items) = inline::try_inline( diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 2153e7d8c9ad9..10b606f425ea4 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -6,7 +6,7 @@ use rustc_errors::emitter::{Emitter, EmitterWriter}; use rustc_errors::json::JsonEmitter; use rustc_feature::UnstableFeatures; use rustc_hir::def::{Namespace, Res}; -use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; +use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{HirId, Path, TraitCandidate}; use rustc_interface::interface; @@ -60,11 +60,11 @@ pub(crate) struct DocContext<'tcx> { pub(crate) external_traits: Rc>>, /// Used while populating `external_traits` to ensure we don't process the same trait twice at /// the same time. - pub(crate) active_extern_traits: FxHashSet, + pub(crate) active_extern_traits: DefIdSet, // The current set of parameter substitutions, // for expanding type aliases at the HIR level: /// Table `DefId` of type, lifetime, or const parameter -> substituted type, lifetime, or const - pub(crate) substs: FxHashMap, + pub(crate) substs: DefIdMap, /// Table synthetic type parameter for `impl Trait` in argument position -> bounds pub(crate) impl_trait_bounds: FxHashMap>, /// Auto-trait or blanket impls processed so far, as `(self_ty, trait_def_id)`. @@ -108,11 +108,7 @@ impl<'tcx> DocContext<'tcx> { /// Call the closure with the given parameters set as /// the substitutions for a type alias' RHS. - pub(crate) fn enter_alias( - &mut self, - substs: FxHashMap, - f: F, - ) -> R + pub(crate) fn enter_alias(&mut self, substs: DefIdMap, f: F) -> R where F: FnOnce(&mut Self) -> R, { diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 1c78c5b8d280b..24752cddb337c 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -1,7 +1,7 @@ use std::mem; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_hir::def_id::{CrateNum, DefId}; +use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet}; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::Symbol; @@ -33,7 +33,7 @@ pub(crate) struct Cache { /// /// The values of the map are a list of implementations and documentation /// found on that implementation. - pub(crate) impls: FxHashMap>, + pub(crate) impls: DefIdMap>, /// Maintains a mapping of local crate `DefId`s to the fully qualified name /// and "short type description" of that node. This is used when generating @@ -56,7 +56,7 @@ pub(crate) struct Cache { /// to the path used if the corresponding type is inlined. By /// doing this, we can detect duplicate impls on a trait page, and only display /// the impl for the inlined type. - pub(crate) exact_paths: FxHashMap>, + pub(crate) exact_paths: DefIdMap>, /// This map contains information about all known traits of this crate. /// Implementations of a crate should inherit the documentation of the @@ -127,7 +127,7 @@ pub(crate) struct Cache { struct CacheBuilder<'a, 'tcx> { cache: &'a mut Cache, /// This field is used to prevent duplicated impl blocks. - impl_ids: FxHashMap>, + impl_ids: DefIdMap, tcx: TyCtxt<'tcx>, } @@ -173,7 +173,7 @@ impl Cache { let (krate, mut impl_ids) = { let mut cache_builder = - CacheBuilder { tcx, cache: &mut cx.cache, impl_ids: FxHashMap::default() }; + CacheBuilder { tcx, cache: &mut cx.cache, impl_ids: Default::default() }; krate = cache_builder.fold_crate(krate); (krate, cache_builder.impl_ids) }; diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 5cefe9475e775..15258a467a228 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -6,7 +6,7 @@ use std::rc::Rc; use std::sync::mpsc::{channel, Receiver}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_hir::def_id::{DefId, LOCAL_CRATE}; +use rustc_hir::def_id::{DefIdMap, LOCAL_CRATE}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_span::edition::Edition; @@ -56,7 +56,7 @@ pub(crate) struct Context<'tcx> { pub(super) render_redirect_pages: bool, /// Tracks section IDs for `Deref` targets so they match in both the main /// body and the sidebar. - pub(super) deref_id_map: FxHashMap, + pub(super) deref_id_map: DefIdMap, /// The map used to ensure all generated 'id=' attributes are unique. pub(super) id_map: IdMap, /// Shared mutable state. @@ -544,7 +544,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { dst, render_redirect_pages: false, id_map, - deref_id_map: FxHashMap::default(), + deref_id_map: Default::default(), shared: Rc::new(scx), include_sources, types_with_notable_traits: FxHashSet::default(), @@ -572,7 +572,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { current: self.current.clone(), dst: self.dst.clone(), render_redirect_pages: self.render_redirect_pages, - deref_id_map: FxHashMap::default(), + deref_id_map: Default::default(), id_map: IdMap::new(), shared: Rc::clone(&self.shared), include_sources: self.include_sources, diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 4fa33e8907d08..d644293d3ef12 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -50,7 +50,7 @@ use rustc_ast_pretty::pprust; use rustc_attr::{ConstStability, Deprecation, StabilityLevel}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def::CtorKind; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_hir::Mutability; use rustc_middle::middle::stability; use rustc_middle::ty; @@ -1115,7 +1115,7 @@ fn render_assoc_items( it: DefId, what: AssocItemRender<'_>, ) { - let mut derefs = FxHashSet::default(); + let mut derefs = DefIdSet::default(); derefs.insert(it); render_assoc_items_inner(w, cx, containing_item, it, what, &mut derefs) } @@ -1126,7 +1126,7 @@ fn render_assoc_items_inner( containing_item: &clean::Item, it: DefId, what: AssocItemRender<'_>, - derefs: &mut FxHashSet, + derefs: &mut DefIdSet, ) { info!("Documenting associated items of {:?}", containing_item.name); let shared = Rc::clone(&cx.shared); @@ -1215,7 +1215,7 @@ fn render_deref_methods( impl_: &Impl, container_item: &clean::Item, deref_mut: bool, - derefs: &mut FxHashSet, + derefs: &mut DefIdSet, ) { let cache = cx.cache(); let deref_type = impl_.inner_impl().trait_.as_ref().unwrap(); @@ -2175,7 +2175,7 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) { if let Some(impl_) = v.iter().find(|i| i.trait_did() == cx.tcx().lang_items().deref_trait()) { - let mut derefs = FxHashSet::default(); + let mut derefs = DefIdSet::default(); derefs.insert(did); sidebar_deref_methods(cx, out, impl_, v, &mut derefs, &mut used_links); } @@ -2195,7 +2195,7 @@ fn sidebar_deref_methods( out: &mut Buffer, impl_: &Impl, v: &[Impl], - derefs: &mut FxHashSet, + derefs: &mut DefIdSet, used_links: &mut FxHashSet, ) { let c = cx.cache(); diff --git a/src/librustdoc/json/import_finder.rs b/src/librustdoc/json/import_finder.rs index c5c687df74fd8..982370aa21c43 100644 --- a/src/librustdoc/json/import_finder.rs +++ b/src/librustdoc/json/import_finder.rs @@ -1,5 +1,4 @@ -use rustc_data_structures::fx::FxHashSet; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::DefIdSet; use crate::{ clean::{self, Import, ImportSource, Item}, @@ -14,14 +13,15 @@ use crate::{ /// See [#100973](https://github.com/rust-lang/rust/issues/100973) and /// [#101103](https://github.com/rust-lang/rust/issues/101103) for times when /// this information is needed. -pub(crate) fn get_imports(krate: clean::Crate) -> (clean::Crate, FxHashSet) { - let mut finder = ImportFinder { imported: FxHashSet::default() }; +pub(crate) fn get_imports(krate: clean::Crate) -> (clean::Crate, DefIdSet) { + let mut finder = ImportFinder::default(); let krate = finder.fold_crate(krate); (krate, finder.imported) } +#[derive(Default)] struct ImportFinder { - imported: FxHashSet, + imported: DefIdSet, } impl DocFolder for ImportFinder { diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 1196f944faad2..5adc0d2a40e41 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -13,8 +13,8 @@ use std::io::{BufWriter, Write}; use std::path::PathBuf; use std::rc::Rc; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_hir::def_id::DefId; +use rustc_data_structures::fx::FxHashMap; +use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_span::def_id::LOCAL_CRATE; @@ -40,7 +40,7 @@ pub(crate) struct JsonRenderer<'tcx> { /// The directory where the blob will be written to. out_path: PathBuf, cache: Rc, - imported_items: FxHashSet, + imported_items: DefIdSet, } impl<'tcx> JsonRenderer<'tcx> { diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 79db3c6c3e786..7d15a207d0652 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -7,8 +7,8 @@ use crate::core::DocContext; use crate::formats::cache::Cache; use crate::visit::DocVisitor; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_hir::def_id::{DefId, LOCAL_CRATE}; +use rustc_data_structures::fx::FxHashSet; +use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LOCAL_CRATE}; use rustc_middle::ty::{self, DefIdTree}; use rustc_span::symbol::sym; @@ -126,14 +126,14 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> }); let mut cleaner = BadImplStripper { prims, items: crate_items, cache: &cx.cache }; - let mut type_did_to_deref_target: FxHashMap = FxHashMap::default(); + let mut type_did_to_deref_target: DefIdMap<&Type> = DefIdMap::default(); // Follow all `Deref` targets of included items and recursively add them as valid fn add_deref_target( cx: &DocContext<'_>, - map: &FxHashMap, + map: &DefIdMap<&Type>, cleaner: &mut BadImplStripper<'_>, - targets: &mut FxHashSet, + targets: &mut DefIdSet, type_did: DefId, ) { if let Some(target) = map.get(&type_did) { @@ -177,7 +177,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> // `Deref` target type and the impl for type positions, this map of types is keyed by // `DefId` and for convenience uses a special cleaner that accepts `DefId`s directly. if cleaner.keep_impl_with_def_id(for_did.into()) { - let mut targets = FxHashSet::default(); + let mut targets = DefIdSet::default(); targets.insert(for_did); add_deref_target( cx, diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 22068ebe041c7..00ea6ca4152c8 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -1,12 +1,11 @@ //! The Rust AST Visitor. Extracts useful information and massages it into a form //! usable for `clean`. -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::DefId; -use rustc_hir::Node; -use rustc_hir::CRATE_HIR_ID; +use rustc_hir::def_id::{DefId, DefIdMap}; +use rustc_hir::{HirIdSet, Node, CRATE_HIR_ID}; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE}; use rustc_span::symbol::{kw, sym, Symbol}; @@ -62,24 +61,24 @@ pub(crate) fn inherits_doc_hidden(tcx: TyCtxt<'_>, mut node: hir::HirId) -> bool pub(crate) struct RustdocVisitor<'a, 'tcx> { cx: &'a mut core::DocContext<'tcx>, - view_item_stack: FxHashSet, + view_item_stack: HirIdSet, inlining: bool, /// Are the current module and all of its parents public? inside_public_path: bool, - exact_paths: FxHashMap>, + exact_paths: DefIdMap>, } impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { pub(crate) fn new(cx: &'a mut core::DocContext<'tcx>) -> RustdocVisitor<'a, 'tcx> { // If the root is re-exported, terminate all recursion. - let mut stack = FxHashSet::default(); + let mut stack = HirIdSet::default(); stack.insert(hir::CRATE_HIR_ID); RustdocVisitor { cx, view_item_stack: stack, inlining: false, inside_public_path: true, - exact_paths: FxHashMap::default(), + exact_paths: Default::default(), } } diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs index e490559b0e92a..fd4f9254107ca 100644 --- a/src/librustdoc/visit_lib.rs +++ b/src/librustdoc/visit_lib.rs @@ -1,14 +1,13 @@ use crate::core::DocContext; -use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::DefKind; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_middle::ty::TyCtxt; // FIXME: this may not be exhaustive, but is sufficient for rustdocs current uses #[derive(Default)] pub(crate) struct RustdocEffectiveVisibilities { - extern_public: FxHashSet, + extern_public: DefIdSet, } macro_rules! define_method { @@ -43,9 +42,9 @@ pub(crate) fn lib_embargo_visit_item(cx: &mut DocContext<'_>, def_id: DefId) { struct LibEmbargoVisitor<'a, 'tcx> { tcx: TyCtxt<'tcx>, // Effective visibilities for reachable nodes - extern_public: &'a mut FxHashSet, + extern_public: &'a mut DefIdSet, // Keeps track of already visited modules, in case a module re-exports its parent - visited_mods: FxHashSet, + visited_mods: DefIdSet, } impl LibEmbargoVisitor<'_, '_> { From 734a91358b2628dae64ff8f99a96d63707c40241 Mon Sep 17 00:00:00 2001 From: Nikolai Vazquez Date: Sat, 21 Jan 2023 22:00:25 -0500 Subject: [PATCH 228/230] Remove unnecessary `&format!` These were likely from before the `PartialEq` impl for `&String`. --- library/core/src/fmt/mod.rs | 60 +++++++++---------- library/core/tests/num/dec2flt/mod.rs | 2 +- .../core_simd/examples/spectral_norm.rs | 2 +- library/std/src/io/error/tests.rs | 2 +- library/std/src/net/ip_addr/tests.rs | 8 +-- library/std/src/net/socket_addr/tests.rs | 8 +-- 6 files changed, 41 insertions(+), 41 deletions(-) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index fa5073e3304d7..2a7ec544f9e2e 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -1355,11 +1355,11 @@ impl<'a> Formatter<'a> { /// } /// } /// - /// assert_eq!(&format!("{}", Foo::new(2)), "2"); - /// assert_eq!(&format!("{}", Foo::new(-1)), "-1"); - /// assert_eq!(&format!("{}", Foo::new(0)), "0"); - /// assert_eq!(&format!("{:#}", Foo::new(-1)), "-Foo 1"); - /// assert_eq!(&format!("{:0>#8}", Foo::new(-1)), "00-Foo 1"); + /// assert_eq!(format!("{}", Foo::new(2)), "2"); + /// assert_eq!(format!("{}", Foo::new(-1)), "-1"); + /// assert_eq!(format!("{}", Foo::new(0)), "0"); + /// assert_eq!(format!("{:#}", Foo::new(-1)), "-Foo 1"); + /// assert_eq!(format!("{:0>#8}", Foo::new(-1)), "00-Foo 1"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn pad_integral(&mut self, is_nonnegative: bool, prefix: &str, buf: &str) -> Result { @@ -1452,8 +1452,8 @@ impl<'a> Formatter<'a> { /// } /// } /// - /// assert_eq!(&format!("{Foo:<4}"), "Foo "); - /// assert_eq!(&format!("{Foo:0>4}"), "0Foo"); + /// assert_eq!(format!("{Foo:<4}"), "Foo "); + /// assert_eq!(format!("{Foo:0>4}"), "0Foo"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn pad(&mut self, s: &str) -> Result { @@ -1636,8 +1636,8 @@ impl<'a> Formatter<'a> { /// } /// } /// - /// assert_eq!(&format!("{Foo}"), "Foo"); - /// assert_eq!(&format!("{Foo:0>8}"), "Foo"); + /// assert_eq!(format!("{Foo}"), "Foo"); + /// assert_eq!(format!("{Foo:0>8}"), "Foo"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn write_str(&mut self, data: &str) -> Result { @@ -1659,8 +1659,8 @@ impl<'a> Formatter<'a> { /// } /// } /// - /// assert_eq!(&format!("{}", Foo(-1)), "Foo -1"); - /// assert_eq!(&format!("{:0>8}", Foo(2)), "Foo 2"); + /// assert_eq!(format!("{}", Foo(-1)), "Foo -1"); + /// assert_eq!(format!("{:0>8}", Foo(2)), "Foo 2"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn write_fmt(&mut self, fmt: Arguments<'_>) -> Result { @@ -1703,8 +1703,8 @@ impl<'a> Formatter<'a> { /// } /// /// // We set alignment to the right with ">". - /// assert_eq!(&format!("{Foo:G>3}"), "GGG"); - /// assert_eq!(&format!("{Foo:t>6}"), "tttttt"); + /// assert_eq!(format!("{Foo:G>3}"), "GGG"); + /// assert_eq!(format!("{Foo:t>6}"), "tttttt"); /// ``` #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] @@ -1738,10 +1738,10 @@ impl<'a> Formatter<'a> { /// } /// } /// - /// assert_eq!(&format!("{Foo:<}"), "left"); - /// assert_eq!(&format!("{Foo:>}"), "right"); - /// assert_eq!(&format!("{Foo:^}"), "center"); - /// assert_eq!(&format!("{Foo}"), "into the void"); + /// assert_eq!(format!("{Foo:<}"), "left"); + /// assert_eq!(format!("{Foo:>}"), "right"); + /// assert_eq!(format!("{Foo:^}"), "center"); + /// assert_eq!(format!("{Foo}"), "into the void"); /// ``` #[must_use] #[stable(feature = "fmt_flags_align", since = "1.28.0")] @@ -1767,7 +1767,7 @@ impl<'a> Formatter<'a> { /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { /// if let Some(width) = formatter.width() { /// // If we received a width, we use it - /// write!(formatter, "{:width$}", &format!("Foo({})", self.0), width = width) + /// write!(formatter, "{:width$}", format!("Foo({})", self.0), width = width) /// } else { /// // Otherwise we do nothing special /// write!(formatter, "Foo({})", self.0) @@ -1775,8 +1775,8 @@ impl<'a> Formatter<'a> { /// } /// } /// - /// assert_eq!(&format!("{:10}", Foo(23)), "Foo(23) "); - /// assert_eq!(&format!("{}", Foo(23)), "Foo(23)"); + /// assert_eq!(format!("{:10}", Foo(23)), "Foo(23) "); + /// assert_eq!(format!("{}", Foo(23)), "Foo(23)"); /// ``` #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] @@ -1806,8 +1806,8 @@ impl<'a> Formatter<'a> { /// } /// } /// - /// assert_eq!(&format!("{:.4}", Foo(23.2)), "Foo(23.2000)"); - /// assert_eq!(&format!("{}", Foo(23.2)), "Foo(23.20)"); + /// assert_eq!(format!("{:.4}", Foo(23.2)), "Foo(23.2000)"); + /// assert_eq!(format!("{}", Foo(23.2)), "Foo(23.20)"); /// ``` #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] @@ -1837,9 +1837,9 @@ impl<'a> Formatter<'a> { /// } /// } /// - /// assert_eq!(&format!("{:+}", Foo(23)), "Foo(+23)"); - /// assert_eq!(&format!("{:+}", Foo(-23)), "Foo(-23)"); - /// assert_eq!(&format!("{}", Foo(23)), "Foo(23)"); + /// assert_eq!(format!("{:+}", Foo(23)), "Foo(+23)"); + /// assert_eq!(format!("{:+}", Foo(-23)), "Foo(-23)"); + /// assert_eq!(format!("{}", Foo(23)), "Foo(23)"); /// ``` #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] @@ -1867,8 +1867,8 @@ impl<'a> Formatter<'a> { /// } /// } /// - /// assert_eq!(&format!("{:-}", Foo(23)), "-Foo(23)"); - /// assert_eq!(&format!("{}", Foo(23)), "Foo(23)"); + /// assert_eq!(format!("{:-}", Foo(23)), "-Foo(23)"); + /// assert_eq!(format!("{}", Foo(23)), "Foo(23)"); /// ``` #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] @@ -1895,8 +1895,8 @@ impl<'a> Formatter<'a> { /// } /// } /// - /// assert_eq!(&format!("{:#}", Foo(23)), "Foo(23)"); - /// assert_eq!(&format!("{}", Foo(23)), "23"); + /// assert_eq!(format!("{:#}", Foo(23)), "Foo(23)"); + /// assert_eq!(format!("{}", Foo(23)), "23"); /// ``` #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] @@ -1922,7 +1922,7 @@ impl<'a> Formatter<'a> { /// } /// } /// - /// assert_eq!(&format!("{:04}", Foo(23)), "23"); + /// assert_eq!(format!("{:04}", Foo(23)), "23"); /// ``` #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] diff --git a/library/core/tests/num/dec2flt/mod.rs b/library/core/tests/num/dec2flt/mod.rs index c4e105cba600d..a2b9bb551e677 100644 --- a/library/core/tests/num/dec2flt/mod.rs +++ b/library/core/tests/num/dec2flt/mod.rs @@ -15,7 +15,7 @@ macro_rules! test_literal { for input in inputs { assert_eq!(input.parse(), Ok(x64)); assert_eq!(input.parse(), Ok(x32)); - let neg_input = &format!("-{input}"); + let neg_input = format!("-{input}"); assert_eq!(neg_input.parse(), Ok(-x64)); assert_eq!(neg_input.parse(), Ok(-x32)); } diff --git a/library/portable-simd/crates/core_simd/examples/spectral_norm.rs b/library/portable-simd/crates/core_simd/examples/spectral_norm.rs index 012182e090b9f..d576bd0ccee03 100644 --- a/library/portable-simd/crates/core_simd/examples/spectral_norm.rs +++ b/library/portable-simd/crates/core_simd/examples/spectral_norm.rs @@ -69,7 +69,7 @@ fn dot(x: &[f64], y: &[f64]) -> f64 { #[cfg(test)] #[test] fn test() { - assert_eq!(&format!("{:.9}", spectral_norm(100)), "1.274219991"); + assert_eq!(format!("{:.9}", spectral_norm(100)), "1.274219991"); } fn main() { diff --git a/library/std/src/io/error/tests.rs b/library/std/src/io/error/tests.rs index 16c634e9afd50..9aea62a5b940c 100644 --- a/library/std/src/io/error/tests.rs +++ b/library/std/src/io/error/tests.rs @@ -190,5 +190,5 @@ fn test_std_io_error_downcast() { let io_error = io_error.downcast::().unwrap_err(); assert_eq!(SIMPLE_MESSAGE.kind, io_error.kind()); - assert_eq!(SIMPLE_MESSAGE.message, &*format!("{io_error}")); + assert_eq!(SIMPLE_MESSAGE.message, format!("{io_error}")); } diff --git a/library/std/src/net/ip_addr/tests.rs b/library/std/src/net/ip_addr/tests.rs index 7c3430b2b217c..0eb59d45de727 100644 --- a/library/std/src/net/ip_addr/tests.rs +++ b/library/std/src/net/ip_addr/tests.rs @@ -125,8 +125,8 @@ fn ipv4_addr_to_string() { assert_eq!(Ipv4Addr::new(127, 127, 127, 127).to_string(), "127.127.127.127"); // Test padding - assert_eq!(&format!("{:16}", Ipv4Addr::new(1, 1, 1, 1)), "1.1.1.1 "); - assert_eq!(&format!("{:>16}", Ipv4Addr::new(1, 1, 1, 1)), " 1.1.1.1"); + assert_eq!(format!("{:16}", Ipv4Addr::new(1, 1, 1, 1)), "1.1.1.1 "); + assert_eq!(format!("{:>16}", Ipv4Addr::new(1, 1, 1, 1)), " 1.1.1.1"); } #[test] @@ -148,8 +148,8 @@ fn ipv6_addr_to_string() { "1111:2222:3333:4444:5555:6666:7777:8888" ); // padding - assert_eq!(&format!("{:20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), "1:2:3:4:5:6:7:8 "); - assert_eq!(&format!("{:>20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), " 1:2:3:4:5:6:7:8"); + assert_eq!(format!("{:20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), "1:2:3:4:5:6:7:8 "); + assert_eq!(format!("{:>20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), " 1:2:3:4:5:6:7:8"); // reduce a single run of zeros assert_eq!( diff --git a/library/std/src/net/socket_addr/tests.rs b/library/std/src/net/socket_addr/tests.rs index 15211f81981ba..dfc6dabbed1ed 100644 --- a/library/std/src/net/socket_addr/tests.rs +++ b/library/std/src/net/socket_addr/tests.rs @@ -64,11 +64,11 @@ fn ipv4_socket_addr_to_string() { // Test padding. assert_eq!( - &format!("{:16}", SocketAddrV4::new(Ipv4Addr::new(1, 1, 1, 1), 53)), + format!("{:16}", SocketAddrV4::new(Ipv4Addr::new(1, 1, 1, 1), 53)), "1.1.1.1:53 " ); assert_eq!( - &format!("{:>16}", SocketAddrV4::new(Ipv4Addr::new(1, 1, 1, 1), 53)), + format!("{:>16}", SocketAddrV4::new(Ipv4Addr::new(1, 1, 1, 1), 53)), " 1.1.1.1:53" ); } @@ -111,11 +111,11 @@ fn ipv6_socket_addr_to_string() { // Test padding. assert_eq!( - &format!("{:22}", SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9, 0, 0)), + format!("{:22}", SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9, 0, 0)), "[1:2:3:4:5:6:7:8]:9 " ); assert_eq!( - &format!("{:>22}", SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9, 0, 0)), + format!("{:>22}", SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9, 0, 0)), " [1:2:3:4:5:6:7:8]:9" ); } From 002dbbeafa39d0375ba45d2e9f7bc2d4ae248c59 Mon Sep 17 00:00:00 2001 From: Lenko Donchev Date: Thu, 12 Jan 2023 01:21:21 -0600 Subject: [PATCH 229/230] Print why a test was ignored if it's the only test specified. --- src/tools/compiletest/src/header.rs | 82 +++++++++++++++++++---------- 1 file changed, 54 insertions(+), 28 deletions(-) diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index dc30e4bb1bef7..45fd87bea9bb5 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -926,7 +926,7 @@ pub fn make_test_description( cfg: Option<&str>, ) -> test::TestDesc { let mut ignore = false; - let ignore_message = None; + let mut ignore_message = None; let mut should_fail = false; let rustc_has_profiler_support = env::var_os("RUSTC_PROFILER_SUPPORT").is_some(); @@ -966,41 +966,67 @@ pub fn make_test_description( if revision.is_some() && revision != cfg { return; } + macro_rules! reason { + ($e:expr) => { + ignore |= match $e { + true => { + ignore_message = Some(stringify!($e)); + true + } + false => ignore, + } + }; + } ignore = match config.parse_cfg_name_directive(ln, "ignore") { - ParsedNameDirective::Match => true, + ParsedNameDirective::Match => { + ignore_message = Some("cfg -> ignore => Match"); + true + } ParsedNameDirective::NoMatch => ignore, }; + if config.has_cfg_prefix(ln, "only") { ignore = match config.parse_cfg_name_directive(ln, "only") { ParsedNameDirective::Match => ignore, - ParsedNameDirective::NoMatch => true, + ParsedNameDirective::NoMatch => { + ignore_message = Some("cfg -> only => NoMatch"); + true + } }; } - ignore |= ignore_llvm(config, ln); - ignore |= - config.run_clang_based_tests_with.is_none() && config.parse_needs_matching_clang(ln); - ignore |= !has_asm_support && config.parse_name_directive(ln, "needs-asm-support"); - ignore |= !rustc_has_profiler_support && config.parse_needs_profiler_support(ln); - ignore |= !config.run_enabled() && config.parse_name_directive(ln, "needs-run-enabled"); - ignore |= !rustc_has_sanitizer_support - && config.parse_name_directive(ln, "needs-sanitizer-support"); - ignore |= !has_asan && config.parse_name_directive(ln, "needs-sanitizer-address"); - ignore |= !has_cfi && config.parse_name_directive(ln, "needs-sanitizer-cfi"); - ignore |= !has_kcfi && config.parse_name_directive(ln, "needs-sanitizer-kcfi"); - ignore |= !has_lsan && config.parse_name_directive(ln, "needs-sanitizer-leak"); - ignore |= !has_msan && config.parse_name_directive(ln, "needs-sanitizer-memory"); - ignore |= !has_tsan && config.parse_name_directive(ln, "needs-sanitizer-thread"); - ignore |= !has_hwasan && config.parse_name_directive(ln, "needs-sanitizer-hwaddress"); - ignore |= !has_memtag && config.parse_name_directive(ln, "needs-sanitizer-memtag"); - ignore |= !has_shadow_call_stack - && config.parse_name_directive(ln, "needs-sanitizer-shadow-call-stack"); - ignore |= !config.can_unwind() && config.parse_name_directive(ln, "needs-unwind"); - ignore |= config.target == "wasm32-unknown-unknown" - && config.parse_name_directive(ln, directives::CHECK_RUN_RESULTS); - ignore |= config.debugger == Some(Debugger::Cdb) && ignore_cdb(config, ln); - ignore |= config.debugger == Some(Debugger::Gdb) && ignore_gdb(config, ln); - ignore |= config.debugger == Some(Debugger::Lldb) && ignore_lldb(config, ln); - ignore |= !has_rust_lld && config.parse_name_directive(ln, "needs-rust-lld"); + + reason!(ignore_llvm(config, ln)); + reason!( + config.run_clang_based_tests_with.is_none() && config.parse_needs_matching_clang(ln) + ); + reason!(!has_asm_support && config.parse_name_directive(ln, "needs-asm-support")); + reason!(!rustc_has_profiler_support && config.parse_needs_profiler_support(ln)); + reason!(!config.run_enabled() && config.parse_name_directive(ln, "needs-run-enabled")); + reason!( + !rustc_has_sanitizer_support + && config.parse_name_directive(ln, "needs-sanitizer-support") + ); + reason!(!has_asan && config.parse_name_directive(ln, "needs-sanitizer-address")); + reason!(!has_cfi && config.parse_name_directive(ln, "needs-sanitizer-cfi")); + reason!(!has_kcfi && config.parse_name_directive(ln, "needs-sanitizer-kcfi")); + reason!(!has_lsan && config.parse_name_directive(ln, "needs-sanitizer-leak")); + reason!(!has_msan && config.parse_name_directive(ln, "needs-sanitizer-memory")); + reason!(!has_tsan && config.parse_name_directive(ln, "needs-sanitizer-thread")); + reason!(!has_hwasan && config.parse_name_directive(ln, "needs-sanitizer-hwaddress")); + reason!(!has_memtag && config.parse_name_directive(ln, "needs-sanitizer-memtag")); + reason!( + !has_shadow_call_stack + && config.parse_name_directive(ln, "needs-sanitizer-shadow-call-stack") + ); + reason!(!config.can_unwind() && config.parse_name_directive(ln, "needs-unwind")); + reason!( + config.target == "wasm32-unknown-unknown" + && config.parse_name_directive(ln, directives::CHECK_RUN_RESULTS) + ); + reason!(config.debugger == Some(Debugger::Cdb) && ignore_cdb(config, ln)); + reason!(config.debugger == Some(Debugger::Gdb) && ignore_gdb(config, ln)); + reason!(config.debugger == Some(Debugger::Lldb) && ignore_lldb(config, ln)); + reason!(!has_rust_lld && config.parse_name_directive(ln, "needs-rust-lld")); should_fail |= config.parse_name_directive(ln, "should-fail"); }); From cb7770736c15488ec816d24ed41928d513f56b4c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 22 Jan 2023 20:39:33 -0500 Subject: [PATCH 230/230] 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 c0dbb2e644c11..7a5e8b789da33 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -9e75dddf609c0201d03f9792e850f95d6a283d11 +a5fa99eed20a46a88c0c85eed6552a94b6656634