From a20866254c6864e49814d6abd47a37fd01bcff0a Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Thu, 12 Oct 2023 15:35:03 -0700 Subject: [PATCH 01/21] References refer to allocated objects --- library/core/src/primitive_docs.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 380a21b376bde..e73d5f990cbac 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1389,6 +1389,18 @@ mod prim_usize {} /// work on references as well as they do on owned values! The implementations described here are /// meant for generic contexts, where the final type `T` is a type parameter or otherwise not /// locally known. +/// +/// # Safety +/// +/// For all types, `T: ?Sized`, and for all `t: &T` or `t: &mut T`, unsafe code may assume that +/// the following properties hold. It is undefined behavior to produce a `t: &T` or `t: &mut T` +/// which violates any of these properties. +/// +/// * `t` is aligned to `align_of_val(t)` +/// * `t` refers to a valid instance of `T` +/// * `t` refers to a single [allocated object] +/// +/// [allocated object]: ptr#allocated-object #[stable(feature = "rust1", since = "1.0.0")] mod prim_ref {} From 4f0192a756f756db6bd1c25a8dbe6e89f0086661 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Thu, 12 Oct 2023 18:55:45 -0700 Subject: [PATCH 02/21] Update primitive_docs.rs --- library/core/src/primitive_docs.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index e73d5f990cbac..04ae8c223f2cb 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1397,7 +1397,6 @@ mod prim_usize {} /// which violates any of these properties. /// /// * `t` is aligned to `align_of_val(t)` -/// * `t` refers to a valid instance of `T` /// * `t` refers to a single [allocated object] /// /// [allocated object]: ptr#allocated-object From 39660c4a77d3dda7f5d57a8d91faa946fff5192b Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Fri, 13 Oct 2023 09:47:39 -0700 Subject: [PATCH 03/21] Update library/core/src/primitive_docs.rs Co-authored-by: Ralf Jung --- library/core/src/primitive_docs.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 04ae8c223f2cb..cde49aeb687f0 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1397,7 +1397,11 @@ mod prim_usize {} /// which violates any of these properties. /// /// * `t` is aligned to `align_of_val(t)` -/// * `t` refers to a single [allocated object] +/// * `t` is dereferenceable for `size_of_val(t)` many bytes +/// +/// Being "dereferenceable" for N bytes means that the memory range beginning +/// at the address `t` points to and ending N bytes later is all contained within a +/// single [allocated object]. /// /// [allocated object]: ptr#allocated-object #[stable(feature = "rust1", since = "1.0.0")] From 55487e235b106088ced4e5b4710fa8f9674baaf9 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Fri, 13 Oct 2023 09:49:23 -0700 Subject: [PATCH 04/21] Update primitive_docs.rs --- library/core/src/primitive_docs.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index cde49aeb687f0..19ff41697d9fc 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1399,9 +1399,8 @@ mod prim_usize {} /// * `t` is aligned to `align_of_val(t)` /// * `t` is dereferenceable for `size_of_val(t)` many bytes /// -/// Being "dereferenceable" for N bytes means that the memory range beginning -/// at the address `t` points to and ending N bytes later is all contained within a -/// single [allocated object]. +/// If `t` points at address `a`, being "dereferenceable" for N bytes means that the memory range +/// `[a, a + N)` is all contained within a single [allocated object]. /// /// [allocated object]: ptr#allocated-object #[stable(feature = "rust1", since = "1.0.0")] From 1a0309afb62b01002c1ac2466a6af0dc69594596 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Fri, 3 Nov 2023 06:41:23 -0700 Subject: [PATCH 05/21] Update primitive_docs.rs --- library/core/src/primitive_docs.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 19ff41697d9fc..939342c4d9760 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1393,8 +1393,9 @@ mod prim_usize {} /// # Safety /// /// For all types, `T: ?Sized`, and for all `t: &T` or `t: &mut T`, unsafe code may assume that -/// the following properties hold. It is undefined behavior to produce a `t: &T` or `t: &mut T` -/// which violates any of these properties. +/// the following properties hold. Rust programmers must assume that, unless explicitly stated +/// otherwise, any Rust code they did not author themselves may rely on these properties, and that +/// violating them may cause that code to exhibit undefined behavior. /// /// * `t` is aligned to `align_of_val(t)` /// * `t` is dereferenceable for `size_of_val(t)` many bytes From ab938b9acbf1d5849198cba19e14959d8ad2871f Mon Sep 17 00:00:00 2001 From: Frank Steffahn Date: Tue, 23 Jan 2024 11:29:11 +0100 Subject: [PATCH 06/21] Improve documentation for [A]Rc::into_inner General improvements, and also aims to better encourage the reader to actually check out Arc::try_unwrap. --- library/alloc/src/rc.rs | 7 +++++-- library/alloc/src/sync.rs | 10 +++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index f986df058467b..197d3a6e55ef6 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -938,8 +938,11 @@ impl Rc { /// it is guaranteed that exactly one of the calls returns the inner value. /// This means in particular that the inner value is not dropped. /// - /// This is equivalent to `Rc::try_unwrap(this).ok()`. (Note that these are not equivalent for - /// [`Arc`](crate::sync::Arc), due to race conditions that do not apply to `Rc`.) + /// [`Rc::try_unwrap`] is conceptually similar to `Rc::into_inner`. + /// And while they are meant for different use-cases, `Rc::into_inner(this)` + /// is in fact equivalent to [Rc::try_unwrap]\(this).[ok][Result::ok](). + /// (Note that the same kind of equivalence does **not** hold true for + /// [`Arc`](crate::sync::Arc), due to race conditions that do not apply to `Rc`!) #[inline] #[stable(feature = "rc_into_inner", since = "1.70.0")] pub fn into_inner(this: Self) -> Option { diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index dc82c9c411110..4784a5db17ab5 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -983,9 +983,13 @@ impl Arc { /// it is guaranteed that exactly one of the calls returns the inner value. /// This means in particular that the inner value is not dropped. /// - /// The similar expression `Arc::try_unwrap(this).ok()` does not - /// offer such a guarantee. See the last example below - /// and the documentation of [`Arc::try_unwrap`]. + /// [`Arc::try_unwrap`] is conceptually similar to `Arc::into_inner`, but it + /// is meant for different use-cases. If used as a direct replacement + /// for `Arc::into_inner` anyway, such as with the expression + /// [Arc::try_unwrap]\(this).[ok][Result::ok](), then it does + /// **not** give the same guarantee as described in the previous paragraph. + /// For more information, see the examples below and read the documentation + /// of [`Arc::try_unwrap`]. /// /// # Examples /// From c2c6e333356f53338e6eecd710faf663217a0074 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Thu, 25 Jan 2024 06:59:51 -0800 Subject: [PATCH 07/21] Update primitive_docs.rs --- library/core/src/primitive_docs.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 939342c4d9760..fca2d3979ab47 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1403,6 +1403,10 @@ mod prim_usize {} /// If `t` points at address `a`, being "dereferenceable" for N bytes means that the memory range /// `[a, a + N)` is all contained within a single [allocated object]. /// +/// Note that the precise validity invariants for reference types are a work in progress. In the +/// future, new guarantees may be added. However, the guarantees documented in this section will +/// never be removed. +/// /// [allocated object]: ptr#allocated-object #[stable(feature = "rust1", since = "1.0.0")] mod prim_ref {} From 3269513eb0189946c40a67d98724b40321e6e9f3 Mon Sep 17 00:00:00 2001 From: "HTGAzureX1212." <39023054+HTGAzureX1212@users.noreply.github.com> Date: Fri, 26 Jan 2024 20:15:30 +0800 Subject: [PATCH 08/21] fix issue 120040 --- library/std/src/sys/pal/windows/fs.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index 4248454368644..06a08ea22ebee 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -1068,6 +1068,27 @@ pub fn readdir(p: &Path) -> io::Result { unsafe { let mut wfd = mem::zeroed(); let find_handle = c::FindFirstFileW(path.as_ptr(), &mut wfd); + + // The status `ERROR_FILE_NOT_FOUND` is returned by the `FindFirstFileW` function + // if no matching files can be found, but not necessarily that the path to find the + // files in does not exist. + // + // Hence, a check for whether the path to search in exists is added when the last + // os error returned by Windows is `ERROR_FILE_NOT_FOUND` to handle this scenario. + // If that is the case, an empty `ReadDir` iterator is returned as it returns `None` + // in the initial `.next()` invocation because `ERROR_NO_MORE_FILES` would have been + // returned by the `FindNextFileW` function. + // + // See issue #120040: https://github.com/rust-lang/rust/issues/120040. + let last_error = Error::last_os_error(); + if last_error.raw_os_error().unwrap() == c::ERROR_FILE_NOT_FOUND && p.exists() { + return Ok(ReadDir { + handle: FindNextFileHandle(file_handle), + root: Arc::new(root), + first: None, + }); + } + if find_handle != c::INVALID_HANDLE_VALUE { Ok(ReadDir { handle: FindNextFileHandle(find_handle), From 8f89e57e9f7fe4a2fccf57161aea39a4e48b6a75 Mon Sep 17 00:00:00 2001 From: "HTGAzureX1212." <39023054+HTGAzureX1212@users.noreply.github.com> Date: Fri, 26 Jan 2024 20:27:20 +0800 Subject: [PATCH 09/21] remove redundant call to Error::last_os_error --- library/std/src/sys/pal/windows/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index 06a08ea22ebee..b5976b87be210 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -1096,7 +1096,7 @@ pub fn readdir(p: &Path) -> io::Result { first: Some(wfd), }) } else { - Err(Error::last_os_error()) + Err(last_error) } } } From 2241d1618960a2d192b2874e925fa51afeb8a83b Mon Sep 17 00:00:00 2001 From: "HTGAzureX1212." <39023054+HTGAzureX1212@users.noreply.github.com> Date: Fri, 26 Jan 2024 20:34:13 +0800 Subject: [PATCH 10/21] fix --- library/std/src/sys/pal/windows/fs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index b5976b87be210..38835db7649de 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -1081,9 +1081,9 @@ pub fn readdir(p: &Path) -> io::Result { // // See issue #120040: https://github.com/rust-lang/rust/issues/120040. let last_error = Error::last_os_error(); - if last_error.raw_os_error().unwrap() == c::ERROR_FILE_NOT_FOUND && p.exists() { + if last_error.raw_os_error().unwrap() == c::ERROR_FILE_NOT_FOUND as i32 && p.exists() { return Ok(ReadDir { - handle: FindNextFileHandle(file_handle), + handle: FindNextFileHandle(find_handle), root: Arc::new(root), first: None, }); From e26f213050f451ec3e9c6a3132bc0d5be5123737 Mon Sep 17 00:00:00 2001 From: "HTGAzureX1212." <39023054+HTGAzureX1212@users.noreply.github.com> Date: Sat, 27 Jan 2024 12:28:28 +0800 Subject: [PATCH 11/21] make modifications as per reviews --- library/std/src/sys/pal/windows/fs.rs | 46 +++++++++++++++------------ 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index 38835db7649de..1a8151479f390 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -1069,26 +1069,6 @@ pub fn readdir(p: &Path) -> io::Result { let mut wfd = mem::zeroed(); let find_handle = c::FindFirstFileW(path.as_ptr(), &mut wfd); - // The status `ERROR_FILE_NOT_FOUND` is returned by the `FindFirstFileW` function - // if no matching files can be found, but not necessarily that the path to find the - // files in does not exist. - // - // Hence, a check for whether the path to search in exists is added when the last - // os error returned by Windows is `ERROR_FILE_NOT_FOUND` to handle this scenario. - // If that is the case, an empty `ReadDir` iterator is returned as it returns `None` - // in the initial `.next()` invocation because `ERROR_NO_MORE_FILES` would have been - // returned by the `FindNextFileW` function. - // - // See issue #120040: https://github.com/rust-lang/rust/issues/120040. - let last_error = Error::last_os_error(); - if last_error.raw_os_error().unwrap() == c::ERROR_FILE_NOT_FOUND as i32 && p.exists() { - return Ok(ReadDir { - handle: FindNextFileHandle(find_handle), - root: Arc::new(root), - first: None, - }); - } - if find_handle != c::INVALID_HANDLE_VALUE { Ok(ReadDir { handle: FindNextFileHandle(find_handle), @@ -1096,7 +1076,31 @@ pub fn readdir(p: &Path) -> io::Result { first: Some(wfd), }) } else { - Err(last_error) + // The status `ERROR_FILE_NOT_FOUND` is returned by the `FindFirstFileW` function + // if no matching files can be found, but not necessarily that the path to find the + // files in does not exist. + // + // Hence, a check for whether the path to search in exists is added when the last + // os error returned by Windows is `ERROR_FILE_NOT_FOUND` to handle this scenario. + // If that is the case, an empty `ReadDir` iterator is returned as it returns `None` + // in the initial `.next()` invocation because `ERROR_NO_MORE_FILES` would have been + // returned by the `FindNextFileW` function. + // + // See issue #120040: https://github.com/rust-lang/rust/issues/120040. + let last_error = api::get_last_error(); + if last_error.code == c::ERROR_FILE_NOT_FOUND { + return Ok(ReadDir { + handle: FindNextFileHandle(find_handle), + root: Arc::new(root), + first: None, + }); + } + + // Just return the error constructed from the raw OS error if the above is not the case. + // + // Note: `ERROR_PATH_NOT_FOUND` would have been returned by the `FindFirstFileW` function + // when the path to search in does not exist in the first place. + Err(Error::from_raw_os_error(last_error.code as i32)); } } } From 018bf305cdcc2d478998642bc2d9a5613ec902f3 Mon Sep 17 00:00:00 2001 From: "HTGAzureX1212." <39023054+HTGAzureX1212@users.noreply.github.com> Date: Sat, 27 Jan 2024 12:43:38 +0800 Subject: [PATCH 12/21] add extra check for invalid handle in ReadDir::next --- library/std/src/sys/pal/windows/fs.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index 1a8151479f390..2bdd3d96fa48c 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -112,6 +112,13 @@ impl fmt::Debug for ReadDir { impl Iterator for ReadDir { type Item = io::Result; fn next(&mut self) -> Option> { + if self.handle.0 == c::INVALID_HANDLE_VALUE { + // This iterator was initialized with an `INVALID_HANDLE_VALUE` as its handle. + // Simply return `None` because this is only the case when `FindFirstFileW` in + // the construction of this iterator returns `ERROR_FILE_NOT_FOUND` which means + // no matchhing files can be found. + return None; + } if let Some(first) = self.first.take() { if let Some(e) = DirEntry::new(&self.root, &first) { return Some(Ok(e)); @@ -1100,7 +1107,7 @@ pub fn readdir(p: &Path) -> io::Result { // // Note: `ERROR_PATH_NOT_FOUND` would have been returned by the `FindFirstFileW` function // when the path to search in does not exist in the first place. - Err(Error::from_raw_os_error(last_error.code as i32)); + Err(Error::from_raw_os_error(last_error.code as i32)) } } } From f5c78955c88ac37b7422bef6ee9ec993c0a5dad2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Sat, 27 Jan 2024 14:18:33 +0200 Subject: [PATCH 13/21] Stop using derivative in rustc_pattern_analysis --- Cargo.lock | 1 - compiler/rustc_pattern_analysis/Cargo.toml | 1 - .../rustc_pattern_analysis/src/constructor.rs | 98 ++++++++++++++++++- compiler/rustc_pattern_analysis/src/lib.rs | 20 +++- compiler/rustc_pattern_analysis/src/pat.rs | 31 +++++- compiler/rustc_pattern_analysis/src/rustc.rs | 8 +- .../rustc_pattern_analysis/src/usefulness.rs | 58 ++++++++--- 7 files changed, 191 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 28068684362e4..587489a94b20e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4342,7 +4342,6 @@ dependencies = [ name = "rustc_pattern_analysis" version = "0.0.0" dependencies = [ - "derivative", "rustc-hash", "rustc_apfloat", "rustc_arena", diff --git a/compiler/rustc_pattern_analysis/Cargo.toml b/compiler/rustc_pattern_analysis/Cargo.toml index 1d0e1cb7e6a57..b9bdcb41929dc 100644 --- a/compiler/rustc_pattern_analysis/Cargo.toml +++ b/compiler/rustc_pattern_analysis/Cargo.toml @@ -5,7 +5,6 @@ edition = "2021" [dependencies] # tidy-alphabetical-start -derivative = "2.2.0" rustc-hash = "1.1.0" rustc_apfloat = "0.2.0" rustc_arena = { path = "../rustc_arena", optional = true } diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs index e94a0373c79ff..4996015f86345 100644 --- a/compiler/rustc_pattern_analysis/src/constructor.rs +++ b/compiler/rustc_pattern_analysis/src/constructor.rs @@ -151,6 +151,7 @@ use std::cmp::{self, max, min, Ordering}; use std::fmt; use std::iter::once; +use std::mem; use smallvec::SmallVec; @@ -648,8 +649,6 @@ impl OpaqueId { /// `specialize_constructor` returns the list of fields corresponding to a pattern, given a /// constructor. `Constructor::apply` reconstructs the pattern from a pair of `Constructor` and /// `Fields`. -#[derive(derivative::Derivative)] -#[derivative(Debug(bound = ""), Clone(bound = ""), PartialEq(bound = ""))] pub enum Constructor { /// Tuples and structs. Struct, @@ -692,6 +691,101 @@ pub enum Constructor { Missing, } +impl Clone for Constructor { + fn clone(&self) -> Self { + match self { + Constructor::Struct => Constructor::Struct, + Constructor::Variant(idx) => Constructor::Variant(idx.clone()), + Constructor::Ref => Constructor::Ref, + Constructor::Slice(slice) => Constructor::Slice(slice.clone()), + Constructor::UnionField => Constructor::UnionField, + Constructor::Bool(b) => Constructor::Bool(b.clone()), + Constructor::IntRange(range) => Constructor::IntRange(range.clone()), + Constructor::F32Range(lo, hi, end) => { + Constructor::F32Range(lo.clone(), hi.clone(), end.clone()) + } + Constructor::F64Range(lo, hi, end) => { + Constructor::F64Range(lo.clone(), hi.clone(), end.clone()) + } + Constructor::Str(value) => Constructor::Str(value.clone()), + Constructor::Opaque(inner) => Constructor::Opaque(inner.clone()), + Constructor::Or => Constructor::Or, + Constructor::Wildcard => Constructor::Wildcard, + Constructor::NonExhaustive => Constructor::NonExhaustive, + Constructor::Hidden => Constructor::Hidden, + Constructor::Missing => Constructor::Missing, + } + } +} + +impl fmt::Debug for Constructor { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Constructor::Struct => f.debug_tuple("Struct").finish(), + Constructor::Variant(idx) => f.debug_tuple("Variant").field(idx).finish(), + Constructor::Ref => f.debug_tuple("Ref").finish(), + Constructor::Slice(slice) => f.debug_tuple("Slice").field(slice).finish(), + Constructor::UnionField => f.debug_tuple("UnionField").finish(), + Constructor::Bool(b) => f.debug_tuple("Bool").field(b).finish(), + Constructor::IntRange(range) => f.debug_tuple("IntRange").field(range).finish(), + Constructor::F32Range(lo, hi, end) => { + f.debug_tuple("F32Range").field(lo).field(hi).field(end).finish() + } + Constructor::F64Range(lo, hi, end) => { + f.debug_tuple("F64Range").field(lo).field(hi).field(end).finish() + } + Constructor::Str(value) => f.debug_tuple("Str").field(value).finish(), + Constructor::Opaque(inner) => f.debug_tuple("Opaque").field(inner).finish(), + Constructor::Or => f.debug_tuple("Or").finish(), + Constructor::Wildcard => f.debug_tuple("Wildcard").finish(), + Constructor::NonExhaustive => f.debug_tuple("NonExhaustive").finish(), + Constructor::Hidden => f.debug_tuple("Hidden").finish(), + Constructor::Missing => f.debug_tuple("Missing").finish(), + } + } +} + +impl PartialEq for Constructor { + fn eq(&self, other: &Self) -> bool { + (mem::discriminant(self) == mem::discriminant(other)) + && match (self, other) { + (Constructor::Struct, Constructor::Struct) => true, + (Constructor::Variant(self_variant), Constructor::Variant(other_variant)) => { + self_variant == other_variant + } + (Constructor::Ref, Constructor::Ref) => true, + (Constructor::Slice(self_slice), Constructor::Slice(other_slice)) => { + self_slice == other_slice + } + (Constructor::UnionField, Constructor::UnionField) => true, + (Constructor::Bool(self_b), Constructor::Bool(other_b)) => self_b == other_b, + (Constructor::IntRange(self_range), Constructor::IntRange(other_range)) => { + self_range == other_range + } + ( + Constructor::F32Range(self_lo, self_hi, self_end), + Constructor::F32Range(other_lo, other_hi, other_end), + ) => self_lo == other_lo && self_hi == other_hi && self_end == other_end, + ( + Constructor::F64Range(self_lo, self_hi, self_end), + Constructor::F64Range(other_lo, other_hi, other_end), + ) => self_lo == other_lo && self_hi == other_hi && self_end == other_end, + (Constructor::Str(self_value), Constructor::Str(other_value)) => { + self_value == other_value + } + (Constructor::Opaque(self_inner), Constructor::Opaque(other_inner)) => { + self_inner == other_inner + } + (Constructor::Or, Constructor::Or) => true, + (Constructor::Wildcard, Constructor::Wildcard) => true, + (Constructor::NonExhaustive, Constructor::NonExhaustive) => true, + (Constructor::Hidden, Constructor::Hidden) => true, + (Constructor::Missing, Constructor::Missing) => true, + _ => unreachable!(), + } + } +} + impl Constructor { pub(crate) fn is_non_exhaustive(&self) -> bool { matches!(self, NonExhaustive) diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs index 6374874165fc1..a53d7a0d8096a 100644 --- a/compiler/rustc_pattern_analysis/src/lib.rs +++ b/compiler/rustc_pattern_analysis/src/lib.rs @@ -136,23 +136,35 @@ pub trait TypeCx: Sized + fmt::Debug { } /// Context that provides information global to a match. -#[derive(derivative::Derivative)] -#[derivative(Clone(bound = ""), Copy(bound = ""))] pub struct MatchCtxt<'a, Cx: TypeCx> { /// The context for type information. pub tycx: &'a Cx, } +impl<'a, Cx: TypeCx> Clone for MatchCtxt<'a, Cx> { + fn clone(&self) -> Self { + Self { tycx: self.tycx } + } +} + +impl<'a, Cx: TypeCx> Copy for MatchCtxt<'a, Cx> {} + /// The arm of a match expression. #[derive(Debug)] -#[derive(derivative::Derivative)] -#[derivative(Clone(bound = ""), Copy(bound = ""))] pub struct MatchArm<'p, Cx: TypeCx> { pub pat: &'p DeconstructedPat<'p, Cx>, pub has_guard: bool, pub arm_data: Cx::ArmData, } +impl<'p, Cx: TypeCx> Clone for MatchArm<'p, Cx> { + fn clone(&self) -> Self { + Self { pat: self.pat, has_guard: self.has_guard, arm_data: self.arm_data } + } +} + +impl<'p, Cx: TypeCx> Copy for MatchArm<'p, Cx> {} + /// The entrypoint for this crate. Computes whether a match is exhaustive and which of its arms are /// useful, and runs some lints. #[cfg(feature = "rustc")] diff --git a/compiler/rustc_pattern_analysis/src/pat.rs b/compiler/rustc_pattern_analysis/src/pat.rs index 1cc3107455645..d476766d466f2 100644 --- a/compiler/rustc_pattern_analysis/src/pat.rs +++ b/compiler/rustc_pattern_analysis/src/pat.rs @@ -218,8 +218,6 @@ impl<'p, Cx: TypeCx> fmt::Debug for DeconstructedPat<'p, Cx> { /// algorithm. Do not use `Wild` to represent a wildcard pattern comping from user input. /// /// This is morally `Option<&'p DeconstructedPat>` where `None` is interpreted as a wildcard. -#[derive(derivative::Derivative)] -#[derivative(Clone(bound = ""), Copy(bound = ""))] pub(crate) enum PatOrWild<'p, Cx: TypeCx> { /// A non-user-provided wildcard, created during specialization. Wild, @@ -227,6 +225,17 @@ pub(crate) enum PatOrWild<'p, Cx: TypeCx> { Pat(&'p DeconstructedPat<'p, Cx>), } +impl<'p, Cx: TypeCx> Clone for PatOrWild<'p, Cx> { + fn clone(&self) -> Self { + match self { + PatOrWild::Wild => PatOrWild::Wild, + PatOrWild::Pat(pat) => PatOrWild::Pat(pat), + } + } +} + +impl<'p, Cx: TypeCx> Copy for PatOrWild<'p, Cx> {} + impl<'p, Cx: TypeCx> PatOrWild<'p, Cx> { pub(crate) fn as_pat(&self) -> Option<&'p DeconstructedPat<'p, Cx>> { match self { @@ -289,14 +298,28 @@ impl<'p, Cx: TypeCx> fmt::Debug for PatOrWild<'p, Cx> { /// Same idea as `DeconstructedPat`, except this is a fictitious pattern built up for diagnostics /// purposes. As such they don't use interning and can be cloned. -#[derive(derivative::Derivative)] -#[derivative(Debug(bound = ""), Clone(bound = ""))] pub struct WitnessPat { ctor: Constructor, pub(crate) fields: Vec>, ty: Cx::Ty, } +impl Clone for WitnessPat { + fn clone(&self) -> Self { + Self { ctor: self.ctor.clone(), fields: self.fields.clone(), ty: self.ty.clone() } + } +} + +impl fmt::Debug for WitnessPat { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("WitnessPat") + .field("ctor", &self.ctor) + .field("fields", &self.fields) + .field("ty", &self.ty) + .finish() + } +} + impl WitnessPat { pub(crate) fn new(ctor: Constructor, fields: Vec, ty: Cx::Ty) -> Self { Self { ctor, fields, ty } diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index ef90d24b0bf1e..223d6cefc83fe 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -46,11 +46,15 @@ pub type WitnessPat<'p, 'tcx> = crate::pat::WitnessPat`. #[repr(transparent)] -#[derive(derivative::Derivative)] #[derive(Clone, Copy)] -#[derivative(Debug = "transparent")] pub struct RevealedTy<'tcx>(Ty<'tcx>); +impl<'tcx> fmt::Debug for RevealedTy<'tcx> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(fmt) + } +} + impl<'tcx> std::ops::Deref for RevealedTy<'tcx> { type Target = Ty<'tcx>; fn deref(&self) -> &Self::Target { diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index a627bdeef81e3..b15de1c0ca9d7 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -731,16 +731,26 @@ pub fn ensure_sufficient_stack(f: impl FnOnce() -> R) -> R { } /// Context that provides information local to a place under investigation. -#[derive(derivative::Derivative)] -#[derivative(Debug(bound = ""), Clone(bound = ""), Copy(bound = ""))] pub(crate) struct PlaceCtxt<'a, Cx: TypeCx> { - #[derivative(Debug = "ignore")] pub(crate) mcx: MatchCtxt<'a, Cx>, /// Type of the place under investigation. - #[derivative(Clone(clone_with = "Clone::clone"))] // See rust-derivative#90 pub(crate) ty: &'a Cx::Ty, } +impl<'a, Cx: TypeCx> Clone for PlaceCtxt<'a, Cx> { + fn clone(&self) -> Self { + Self { mcx: self.mcx, ty: self.ty } + } +} + +impl<'a, Cx: TypeCx> Copy for PlaceCtxt<'a, Cx> {} + +impl<'a, Cx: TypeCx> fmt::Debug for PlaceCtxt<'a, Cx> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("PlaceCtxt").field("ty", self.ty).finish() + } +} + impl<'a, Cx: TypeCx> PlaceCtxt<'a, Cx> { /// A `PlaceCtxt` when code other than `is_useful` needs one. #[cfg_attr(not(feature = "rustc"), allow(dead_code))] @@ -813,8 +823,6 @@ impl fmt::Display for ValidityConstraint { // The three lifetimes are: // - 'p coming from the input // - Cx global compilation context -#[derive(derivative::Derivative)] -#[derivative(Clone(bound = ""))] struct PatStack<'p, Cx: TypeCx> { // Rows of len 1 are very common, which is why `SmallVec[_; 2]` works well. pats: SmallVec<[PatOrWild<'p, Cx>; 2]>, @@ -824,6 +832,12 @@ struct PatStack<'p, Cx: TypeCx> { relevant: bool, } +impl<'p, Cx: TypeCx> Clone for PatStack<'p, Cx> { + fn clone(&self) -> Self { + Self { pats: self.pats.clone(), relevant: self.relevant } + } +} + impl<'p, Cx: TypeCx> PatStack<'p, Cx> { fn from_pattern(pat: &'p DeconstructedPat<'p, Cx>) -> Self { PatStack { pats: smallvec![PatOrWild::Pat(pat)], relevant: true } @@ -1184,10 +1198,20 @@ impl<'p, Cx: TypeCx> fmt::Debug for Matrix<'p, Cx> { /// The final `Pair(Some(_), true)` is then the resulting witness. /// /// See the top of the file for more detailed explanations and examples. -#[derive(derivative::Derivative)] -#[derivative(Debug(bound = ""), Clone(bound = ""))] struct WitnessStack(Vec>); +impl Clone for WitnessStack { + fn clone(&self) -> Self { + Self(self.0.clone()) + } +} + +impl fmt::Debug for WitnessStack { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple("WitnessStack").field(&self.0).finish() + } +} + impl WitnessStack { /// Asserts that the witness contains a single pattern, and returns it. fn single_pattern(self) -> WitnessPat { @@ -1232,18 +1256,28 @@ impl WitnessStack { /// /// Just as the `Matrix` starts with a single column, by the end of the algorithm, this has a single /// column, which contains the patterns that are missing for the match to be exhaustive. -#[derive(derivative::Derivative)] -#[derivative(Debug(bound = ""), Clone(bound = ""))] struct WitnessMatrix(Vec>); +impl Clone for WitnessMatrix { + fn clone(&self) -> Self { + Self(self.0.clone()) + } +} + +impl fmt::Debug for WitnessMatrix { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple("WitnessMatrix").field(&self.0).finish() + } +} + impl WitnessMatrix { /// New matrix with no witnesses. fn empty() -> Self { - WitnessMatrix(vec![]) + WitnessMatrix(Vec::new()) } /// New matrix with one `()` witness, i.e. with no columns. fn unit_witness() -> Self { - WitnessMatrix(vec![WitnessStack(vec![])]) + WitnessMatrix(vec![WitnessStack(Vec::new())]) } /// Whether this has any witnesses. From b867c7c707be0070beac663a03eb6a797f076f68 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Sat, 27 Jan 2024 08:47:14 -0800 Subject: [PATCH 14/21] Update primitive_docs.rs --- library/core/src/primitive_docs.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index fca2d3979ab47..e9c30ce9a23f5 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1392,10 +1392,8 @@ mod prim_usize {} /// /// # Safety /// -/// For all types, `T: ?Sized`, and for all `t: &T` or `t: &mut T`, unsafe code may assume that -/// the following properties hold. Rust programmers must assume that, unless explicitly stated -/// otherwise, any Rust code they did not author themselves may rely on these properties, and that -/// violating them may cause that code to exhibit undefined behavior. +/// For all types, `T: ?Sized`, and for all `t: &T` or `t: &mut T`, when such values cross an API +/// boundary, the following invariants must generally be upheld: /// /// * `t` is aligned to `align_of_val(t)` /// * `t` is dereferenceable for `size_of_val(t)` many bytes @@ -1403,9 +1401,16 @@ mod prim_usize {} /// If `t` points at address `a`, being "dereferenceable" for N bytes means that the memory range /// `[a, a + N)` is all contained within a single [allocated object]. /// -/// Note that the precise validity invariants for reference types are a work in progress. In the -/// future, new guarantees may be added. However, the guarantees documented in this section will -/// never be removed. +/// For instance, this means that unsafe code in a safe function may assume these invariants are +/// ensured of arguments passed by the caller, and it may assume that these invariants are ensured +/// of return values from any safe functions it calls. In most cases, the inverse is also true: +/// unsafe code must not violate these invariants when passing arguments to safe functions or +/// returning values from safe functions; such violations may result in undefined behavior. Where +/// exceptions to this latter requirement exist, they will be called out explicitly in documentation. +/// +/// It is not decided yet whether unsafe code may violate these invariants temporarily on internal +/// data. As a consequence, unsafe code which violates these invariants temporarily on internal data +/// may become unsound in future versions of Rust depending on how this question is decided. /// /// [allocated object]: ptr#allocated-object #[stable(feature = "rust1", since = "1.0.0")] From 5f8030dcc9eaa68975279134d76c4a1eb941081b Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 27 Jan 2024 17:46:50 +0300 Subject: [PATCH 15/21] hir: Remove unnecessary `HirId` from `hir::Let` It has 1-to-1 correspondence to its expression id. Also remove mostly useless `visit_let_expr`. --- compiler/rustc_ast_lowering/src/expr.rs | 1 - compiler/rustc_hir/src/hir.rs | 1 - compiler/rustc_hir/src/intravisit.rs | 18 ++++++------------ compiler/rustc_hir_typeck/src/expr.rs | 6 +++--- compiler/rustc_hir_typeck/src/gather_locals.rs | 14 ++++++++------ compiler/rustc_passes/src/hir_stats.rs | 5 ----- 6 files changed, 17 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index cc172b376573f..0ad4a59c17eb1 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -153,7 +153,6 @@ impl<'hir> LoweringContext<'_, 'hir> { } ExprKind::Let(pat, scrutinee, span, is_recovered) => { hir::ExprKind::Let(self.arena.alloc(hir::Let { - hir_id: self.next_id(), span: self.lower_span(*span), pat: self.lower_pat(pat), ty: None, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 23881cfd7dfd3..e34ea73952f5a 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1273,7 +1273,6 @@ pub struct Arm<'hir> { /// desugaring to if-let. Only let-else supports the type annotation at present. #[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct Let<'hir> { - pub hir_id: HirId, pub span: Span, pub pat: &'hir Pat<'hir>, pub ty: Option<&'hir Ty<'hir>>, diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 116de6fb04d99..38ec325630b38 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -341,9 +341,6 @@ pub trait Visitor<'v>: Sized { fn visit_expr(&mut self, ex: &'v Expr<'v>) { walk_expr(self, ex) } - fn visit_let_expr(&mut self, lex: &'v Let<'v>) { - walk_let_expr(self, lex) - } fn visit_expr_field(&mut self, field: &'v ExprField<'v>) { walk_expr_field(self, field) } @@ -729,7 +726,12 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) ExprKind::DropTemps(ref subexpression) => { visitor.visit_expr(subexpression); } - ExprKind::Let(ref let_expr) => visitor.visit_let_expr(let_expr), + ExprKind::Let(Let { span: _, pat, ty, init, is_recovered: _ }) => { + // match the visit order in walk_local + visitor.visit_expr(init); + visitor.visit_pat(pat); + walk_list!(visitor, visit_ty, ty); + } ExprKind::If(ref cond, ref then, ref else_opt) => { visitor.visit_expr(cond); visitor.visit_expr(then); @@ -806,14 +808,6 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) } } -pub fn walk_let_expr<'v, V: Visitor<'v>>(visitor: &mut V, let_expr: &'v Let<'v>) { - // match the visit order in walk_local - visitor.visit_expr(let_expr.init); - visitor.visit_id(let_expr.hir_id); - visitor.visit_pat(let_expr.pat); - walk_list!(visitor, visit_ty, let_expr.ty); -} - pub fn walk_expr_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v ExprField<'v>) { visitor.visit_id(field.hir_id); visitor.visit_ident(field.ident); diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 3bc259c17b774..3bc4032558885 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -320,7 +320,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } ExprKind::Ret(ref expr_opt) => self.check_expr_return(expr_opt.as_deref(), expr), ExprKind::Become(call) => self.check_expr_become(call, expr), - ExprKind::Let(let_expr) => self.check_expr_let(let_expr), + ExprKind::Let(let_expr) => self.check_expr_let(let_expr, expr.hir_id), ExprKind::Loop(body, _, source, _) => { self.check_expr_loop(body, source, expected, expr) } @@ -1259,12 +1259,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - pub(super) fn check_expr_let(&self, let_expr: &'tcx hir::Let<'tcx>) -> Ty<'tcx> { + pub(super) fn check_expr_let(&self, let_expr: &'tcx hir::Let<'tcx>, hir_id: HirId) -> Ty<'tcx> { // for let statements, this is done in check_stmt let init = let_expr.init; self.warn_if_unreachable(init.hir_id, init.span, "block in `let` expression"); // otherwise check exactly as a let statement - self.check_decl(let_expr.into()); + self.check_decl((let_expr, hir_id).into()); // but return a bool, for this is a boolean expression if let Some(error_guaranteed) = let_expr.is_recovered { self.set_tainted_by_errors(error_guaranteed); diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs index 52dc1e8591656..f9af357f0e79e 100644 --- a/compiler/rustc_hir_typeck/src/gather_locals.rs +++ b/compiler/rustc_hir_typeck/src/gather_locals.rs @@ -48,9 +48,9 @@ impl<'a> From<&'a hir::Local<'a>> for Declaration<'a> { } } -impl<'a> From<&'a hir::Let<'a>> for Declaration<'a> { - fn from(let_expr: &'a hir::Let<'a>) -> Self { - let hir::Let { hir_id, pat, ty, span, init, is_recovered: _ } = *let_expr; +impl<'a> From<(&'a hir::Let<'a>, hir::HirId)> for Declaration<'a> { + fn from((let_expr, hir_id): (&'a hir::Let<'a>, hir::HirId)) -> Self { + let hir::Let { pat, ty, span, init, is_recovered: _ } = *let_expr; Declaration { hir_id, pat, ty, span, init: Some(init), origin: DeclOrigin::LetExpr } } } @@ -125,9 +125,11 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { intravisit::walk_local(self, local) } - fn visit_let_expr(&mut self, let_expr: &'tcx hir::Let<'tcx>) { - self.declare(let_expr.into()); - intravisit::walk_let_expr(self, let_expr); + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { + if let hir::ExprKind::Let(let_expr) = expr.kind { + self.declare((let_expr, expr.hir_id).into()); + } + intravisit::walk_expr(self, expr) } fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index 528a52f42255e..e94d8c4c932f9 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -328,11 +328,6 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { hir_visit::walk_expr(self, e) } - fn visit_let_expr(&mut self, lex: &'v hir::Let<'v>) { - self.record("Let", Id::Node(lex.hir_id), lex); - hir_visit::walk_let_expr(self, lex) - } - fn visit_expr_field(&mut self, f: &'v hir::ExprField<'v>) { self.record("ExprField", Id::Node(f.hir_id), f); hir_visit::walk_expr_field(self, f) From b2b5b91bfbe5b39d17be3a14108fe7823627e0d8 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 27 Jan 2024 18:59:20 +0300 Subject: [PATCH 16/21] hir: Use `InferArg` in `ArrayLen::Infer` --- compiler/rustc_ast_lowering/src/lib.rs | 5 ++++- compiler/rustc_hir/src/hir.rs | 8 +++++--- compiler/rustc_hir/src/intravisit.rs | 2 +- compiler/rustc_hir_analysis/src/astconv/mod.rs | 2 +- compiler/rustc_hir_analysis/src/collect.rs | 4 ++-- compiler/rustc_hir_pretty/src/lib.rs | 2 +- compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs | 2 +- src/librustdoc/clean/mod.rs | 2 +- 8 files changed, 16 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index ee1f5d5bd7a3f..3621844efc8d2 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2305,7 +2305,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { match c.value.kind { ExprKind::Underscore => { if self.tcx.features().generic_arg_infer { - hir::ArrayLen::Infer(self.lower_node_id(c.id), self.lower_span(c.value.span)) + hir::ArrayLen::Infer(hir::InferArg { + hir_id: self.lower_node_id(c.id), + span: self.lower_span(c.value.span), + }) } else { feature_err( &self.tcx.sess, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index e34ea73952f5a..681e228a0f2ff 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1531,14 +1531,16 @@ pub type Lit = Spanned; #[derive(Copy, Clone, Debug, HashStable_Generic)] pub enum ArrayLen { - Infer(HirId, Span), + Infer(InferArg), Body(AnonConst), } impl ArrayLen { pub fn hir_id(&self) -> HirId { match self { - &ArrayLen::Infer(hir_id, _) | &ArrayLen::Body(AnonConst { hir_id, .. }) => hir_id, + ArrayLen::Infer(InferArg { hir_id, .. }) | ArrayLen::Body(AnonConst { hir_id, .. }) => { + *hir_id + } } } } @@ -2423,7 +2425,7 @@ impl<'hir> Ty<'hir> { TyKind::Infer => true, TyKind::Slice(ty) => ty.is_suggestable_infer_ty(), TyKind::Array(ty, length) => { - ty.is_suggestable_infer_ty() || matches!(length, ArrayLen::Infer(_, _)) + ty.is_suggestable_infer_ty() || matches!(length, ArrayLen::Infer(..)) } TyKind::Tup(tys) => tys.iter().any(Self::is_suggestable_infer_ty), TyKind::Ptr(mut_ty) | TyKind::Ref(_, mut_ty) => mut_ty.ty.is_suggestable_infer_ty(), diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 38ec325630b38..27c834d848fc4 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -669,7 +669,7 @@ pub fn walk_pat_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v PatField<' pub fn walk_array_len<'v, V: Visitor<'v>>(visitor: &mut V, len: &'v ArrayLen) { match len { - &ArrayLen::Infer(hir_id, _span) => visitor.visit_id(hir_id), + ArrayLen::Infer(InferArg { hir_id, span: _ }) => visitor.visit_id(*hir_id), ArrayLen::Body(c) => visitor.visit_anon_const(c), } } diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 7c97c2a1a6ff2..3ba63c659c776 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -2529,7 +2529,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } hir::TyKind::Array(ty, length) => { let length = match length { - &hir::ArrayLen::Infer(_, span) => self.ct_infer(tcx.types.usize, None, span), + hir::ArrayLen::Infer(inf) => self.ct_infer(tcx.types.usize, None, inf.span), hir::ArrayLen::Body(constant) => { ty::Const::from_anon_const(tcx, constant.def_id) } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index d8ce2307995c5..8d862d5eb715f 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -146,8 +146,8 @@ impl<'v> Visitor<'v> for HirPlaceholderCollector { } } fn visit_array_length(&mut self, length: &'v hir::ArrayLen) { - if let &hir::ArrayLen::Infer(_, span) = length { - self.0.push(span); + if let hir::ArrayLen::Infer(inf) = length { + self.0.push(inf.span); } intravisit::walk_array_len(self, length) } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index e76303bc6dfa1..9d0c5cb0f32b0 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -956,7 +956,7 @@ impl<'a> State<'a> { fn print_array_length(&mut self, len: &hir::ArrayLen) { match len { - hir::ArrayLen::Infer(_, _) => self.word("_"), + hir::ArrayLen::Infer(..) => self.word("_"), hir::ArrayLen::Body(ct) => self.print_anon_const(ct), } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index c6b9197d0e986..e99489ee3c03c 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -405,7 +405,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn array_length_to_const(&self, length: &hir::ArrayLen) -> ty::Const<'tcx> { match length { - &hir::ArrayLen::Infer(_, span) => self.ct_infer(self.tcx.types.usize, None, span), + hir::ArrayLen::Infer(inf) => self.ct_infer(self.tcx.types.usize, None, inf.span), hir::ArrayLen::Body(anon_const) => { let span = self.tcx.def_span(anon_const.def_id); let c = ty::Const::from_anon_const(self.tcx, anon_const.def_id); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 8706abda97963..bc3c455f3980b 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1835,7 +1835,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T TyKind::Slice(ty) => Slice(Box::new(clean_ty(ty, cx))), TyKind::Array(ty, ref length) => { let length = match length { - hir::ArrayLen::Infer(_, _) => "_".to_string(), + hir::ArrayLen::Infer(..) => "_".to_string(), hir::ArrayLen::Body(anon_const) => { // NOTE(min_const_generics): We can't use `const_eval_poly` for constants // as we currently do not supply the parent generics to anonymous constants From 6f014a81b2466c2abdae4c06ff81fae7e1bc006c Mon Sep 17 00:00:00 2001 From: Lieselotte <52315535+she3py@users.noreply.github.com> Date: Sun, 28 Jan 2024 16:12:21 +0100 Subject: [PATCH 17/21] Handle methodcalls & operators in patterns --- compiler/rustc_parse/messages.ftl | 14 ++ compiler/rustc_parse/src/errors.rs | 12 ++ compiler/rustc_parse/src/parser/expr.rs | 13 ++ compiler/rustc_parse/src/parser/mod.rs | 1 + compiler/rustc_parse/src/parser/pat.rs | 155 ++++++++++++++++-- .../range_pat_interactions1.rs | 8 +- .../range_pat_interactions1.stderr | 73 ++++++++- .../range_pat_interactions2.rs | 8 +- .../range_pat_interactions2.stderr | 75 ++++++++- tests/ui/parser/issues/issue-24197.rs | 2 +- tests/ui/parser/issues/issue-24197.stderr | 6 +- tests/ui/parser/issues/issue-24375.rs | 2 +- tests/ui/parser/issues/issue-24375.stderr | 6 +- tests/ui/parser/pat-lt-bracket-5.rs | 4 +- tests/ui/parser/pat-lt-bracket-5.stderr | 15 +- tests/ui/parser/pat-lt-bracket-6.rs | 3 +- tests/ui/parser/pat-lt-bracket-6.stderr | 30 +++- tests/ui/parser/pat-ranges-3.rs | 6 +- tests/ui/parser/pat-ranges-3.stderr | 14 +- tests/ui/parser/pat-ranges-4.rs | 6 - tests/ui/parser/pat-ranges-4.stderr | 8 - tests/ui/parser/pat-recover-exprs.rs | 28 ++++ tests/ui/parser/pat-recover-exprs.stderr | 76 +++++++++ tests/ui/parser/pat-recover-methodcalls.rs | 37 +++++ .../ui/parser/pat-recover-methodcalls.stderr | 35 ++++ tests/ui/parser/pat-recover-ranges.rs | 16 ++ tests/ui/parser/pat-recover-ranges.stderr | 84 +++++++++- tests/ui/parser/pat-recover-wildcards.rs | 61 +++++++ tests/ui/parser/pat-recover-wildcards.stderr | 77 +++++++++ 29 files changed, 809 insertions(+), 66 deletions(-) delete mode 100644 tests/ui/parser/pat-ranges-4.rs delete mode 100644 tests/ui/parser/pat-ranges-4.stderr create mode 100644 tests/ui/parser/pat-recover-exprs.rs create mode 100644 tests/ui/parser/pat-recover-exprs.stderr create mode 100644 tests/ui/parser/pat-recover-methodcalls.rs create mode 100644 tests/ui/parser/pat-recover-methodcalls.stderr create mode 100644 tests/ui/parser/pat-recover-wildcards.rs create mode 100644 tests/ui/parser/pat-recover-wildcards.stderr diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index f904e0c44ea92..aac8c0b310320 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -772,6 +772,20 @@ parse_unexpected_const_param_declaration = unexpected `const` parameter declarat parse_unexpected_default_value_for_lifetime_in_generic_parameters = unexpected default lifetime parameter .label = lifetime parameters cannot have default values +parse_unexpected_expr_in_pat = + expected {$is_bound -> + [true] a pattern range bound + *[false] a pattern + }, found {$is_method_call -> + [true] a method call + *[false] an expression + } + + .label = {$is_method_call -> + [true] method calls + *[false] arbitrary expressions + } are not allowed in patterns + parse_unexpected_if_with_if = unexpected `if` in the condition expression .suggestion = remove the `if` diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 40852048293a9..fa91b64d5310d 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2415,6 +2415,18 @@ pub(crate) struct ExpectedCommaAfterPatternField { pub span: Span, } +#[derive(Diagnostic)] +#[diag(parse_unexpected_expr_in_pat)] +pub(crate) struct UnexpectedExpressionInPattern { + #[primary_span] + #[label] + pub span: Span, + /// Was a `RangePatternBound` expected? + pub is_bound: bool, + /// Was the unexpected expression a `MethodCallExpression`? + pub is_method_call: bool, +} + #[derive(Diagnostic)] #[diag(parse_unexpected_paren_in_range_pat)] pub(crate) struct UnexpectedParenInRangePat { diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index b789b65797bad..c395decab129e 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -444,6 +444,19 @@ impl<'a> Parser<'a> { ) if self.restrictions.contains(Restrictions::CONST_EXPR) => { return None; } + // When recovering patterns as expressions, stop parsing when encountering an assignment `=`, an alternative `|`, or a range `..`. + ( + Some( + AssocOp::Assign + | AssocOp::AssignOp(_) + | AssocOp::BitOr + | AssocOp::DotDot + | AssocOp::DotDotEq, + ), + _, + ) if self.restrictions.contains(Restrictions::IS_PAT) => { + return None; + } (Some(op), _) => (op, self.token.span), (None, Some((Ident { name: sym::and, span }, false))) if self.may_recover() => { self.dcx().emit_err(errors::InvalidLogicalOperator { diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index ff2fb6271a8df..623407eb38003 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -53,6 +53,7 @@ bitflags::bitflags! { const CONST_EXPR = 1 << 2; const ALLOW_LET = 1 << 3; const IN_IF_GUARD = 1 << 4; + const IS_PAT = 1 << 5; } } diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 7918e03750ce3..d04921dde54b7 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -1,4 +1,4 @@ -use super::{ForceCollect, Parser, PathStyle, TrailingToken}; +use super::{ForceCollect, Parser, PathStyle, Restrictions, TrailingToken}; use crate::errors::{ self, AmbiguousRangePattern, DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed, DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt, @@ -6,14 +6,14 @@ use crate::errors::{ InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern, PatternOnWrongSideOfAt, RefMutOrderIncorrect, RemoveLet, RepeatedMutInPattern, SwitchRefBoxOrder, TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg, - TrailingVertNotAllowed, UnexpectedLifetimeInPattern, UnexpectedParenInRangePat, - UnexpectedParenInRangePatSugg, UnexpectedVertVertBeforeFunctionParam, - UnexpectedVertVertInPattern, + TrailingVertNotAllowed, UnexpectedExpressionInPattern, UnexpectedLifetimeInPattern, + UnexpectedParenInRangePat, UnexpectedParenInRangePatSugg, + UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern, }; use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor}; use rustc_ast::ptr::P; -use rustc_ast::token::{self, Delimiter}; +use rustc_ast::token::{self, BinOpToken, Delimiter, Token}; use rustc_ast::{ self as ast, AttrVec, BindingAnnotation, ByRef, Expr, ExprKind, MacCall, Mutability, Pat, PatField, PatFieldsRest, PatKind, Path, QSelf, RangeEnd, RangeSyntax, @@ -23,7 +23,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder, PResult}; use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::Span; +use rustc_span::{ErrorGuaranteed, Span}; use thin_vec::{thin_vec, ThinVec}; #[derive(PartialEq, Copy, Clone)] @@ -336,6 +336,95 @@ impl<'a> Parser<'a> { } } + /// Ensures that the last parsed pattern (or pattern range bound) is not followed by a method call or an operator. + /// + /// `is_end_bound` indicates whether the last parsed thing was the end bound of a range pattern (see [`parse_pat_range_end`](Self::parse_pat_range_end)) + /// in order to say "expected a pattern range bound" instead of "expected a pattern"; + /// ```text + /// 0..=1 + 2 + /// ^^^^^ + /// ``` + /// Only the end bound is spanned, and this function have no idea if there were a `..=` before `pat_span`, hence the parameter. + #[must_use = "the pattern must be discarded as `PatKind::Err` if this function returns Some"] + fn maybe_recover_trailing_expr( + &mut self, + pat_span: Span, + is_end_bound: bool, + ) -> Option { + if self.prev_token.is_keyword(kw::Underscore) || !self.may_recover() { + // Don't recover anything after an `_` or if recovery is disabled. + return None; + } + + // Check for `.hello()`, but allow `.Hello()` to be recovered as `, Hello()` in `parse_seq_to_before_tokens()`. + let has_trailing_method = self.check_noexpect(&token::Dot) + && self.look_ahead(1, |tok| { + tok.ident() + .and_then(|(ident, _)| ident.name.as_str().chars().next()) + .is_some_and(char::is_lowercase) + }) + && self.look_ahead(2, |tok| tok.kind == token::OpenDelim(Delimiter::Parenthesis)); + + // Check for operators. + // `|` is excluded as it is used in pattern alternatives and lambdas, + // `?` is included for error propagation, + // `[` is included for indexing operations, + // `[]` is excluded as `a[]` isn't an expression and should be recovered as `a, []` (cf. `tests/ui/parser/pat-lt-bracket-7.rs`) + let has_trailing_operator = matches!(self.token.kind, token::BinOp(op) if op != BinOpToken::Or) + || self.token.kind == token::Question + || (self.token.kind == token::OpenDelim(Delimiter::Bracket) + && self.look_ahead(1, |tok| tok.kind != token::CloseDelim(Delimiter::Bracket))); + + if !has_trailing_method && !has_trailing_operator { + // Nothing to recover here. + return None; + } + + // Let's try to parse an expression to emit a better diagnostic. + let mut snapshot = self.create_snapshot_for_diagnostic(); + snapshot.restrictions.insert(Restrictions::IS_PAT); + + // Parse `?`, `.f`, `(arg0, arg1, ...)` or `[expr]` until they've all been eaten. + if let Ok(expr) = snapshot + .parse_expr_dot_or_call_with( + self.mk_expr_err(pat_span), // equivalent to transforming the parsed pattern into an `Expr` + pat_span, + AttrVec::new(), + ) + .map_err(|err| err.cancel()) + { + let non_assoc_span = expr.span; + + // Parse an associative expression such as `+ expr`, `% expr`, ... + // Assignements, ranges and `|` are disabled by [`Restrictions::IS_PAT`]. + if let Ok(expr) = + snapshot.parse_expr_assoc_with(0, expr.into()).map_err(|err| err.cancel()) + { + // We got a valid expression. + self.restore_snapshot(snapshot); + self.restrictions.remove(Restrictions::IS_PAT); + + let is_bound = is_end_bound + // is_start_bound: either `..` or `)..` + || self.token.is_range_separator() + || self.token.kind == token::CloseDelim(Delimiter::Parenthesis) + && self.look_ahead(1, Token::is_range_separator); + + // Check that `parse_expr_assoc_with` didn't eat a rhs. + let is_method_call = has_trailing_method && non_assoc_span == expr.span; + + return Some(self.dcx().emit_err(UnexpectedExpressionInPattern { + span: expr.span, + is_bound, + is_method_call, + })); + } + } + + // We got a trailing method/operator, but we couldn't parse an expression. + None + } + /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are /// allowed). fn parse_pat_with_range_pat( @@ -441,7 +530,10 @@ impl<'a> Parser<'a> { } else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) { self.parse_pat_tuple_struct(qself, path)? } else { - PatKind::Path(qself, path) + match self.maybe_recover_trailing_expr(span, false) { + Some(guar) => PatKind::Err(guar), + None => PatKind::Path(qself, path), + } } } else if matches!(self.token.kind, token::Lifetime(_)) // In pattern position, we're totally fine with using "next token isn't colon" @@ -470,10 +562,17 @@ impl<'a> Parser<'a> { } else { // Try to parse everything else as literal with optional minus match self.parse_literal_maybe_minus() { - Ok(begin) => match self.parse_range_end() { - Some(form) => self.parse_pat_range_begin_with(begin, form)?, - None => PatKind::Lit(begin), - }, + Ok(begin) => { + let begin = match self.maybe_recover_trailing_expr(begin.span, false) { + Some(_) => self.mk_expr_err(begin.span), + None => begin, + }; + + match self.parse_range_end() { + Some(form) => self.parse_pat_range_begin_with(begin, form)?, + None => PatKind::Lit(begin), + } + } Err(err) => return self.fatal_unexpected_non_pat(err, expected), } }; @@ -615,6 +714,21 @@ impl<'a> Parser<'a> { self.parse_pat_range_begin_with(begin.clone(), form)? } + // recover ranges with parentheses around the `(start)..` + PatKind::Err(_) + if self.may_recover() + && let Some(form) = self.parse_range_end() => + { + self.dcx().emit_err(UnexpectedParenInRangePat { + span: vec![open_paren, close_paren], + sugg: UnexpectedParenInRangePatSugg { + start_span: open_paren, + end_span: close_paren, + }, + }); + + self.parse_pat_range_begin_with(self.mk_expr(pat.span, ExprKind::Err), form)? + } // (pat) with optional parentheses _ => PatKind::Paren(pat), @@ -853,6 +967,8 @@ impl<'a> Parser<'a> { self.parse_literal_maybe_minus() }?; + let recovered = self.maybe_recover_trailing_expr(bound.span, true); + // recover trailing `)` if let Some(open_paren) = open_paren { self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; @@ -866,7 +982,10 @@ impl<'a> Parser<'a> { }); } - Ok(bound) + Ok(match recovered { + Some(_) => self.mk_expr_err(bound.span), + None => bound, + }) } /// Is this the start of a pattern beginning with a path? @@ -929,7 +1048,17 @@ impl<'a> Parser<'a> { .create_err(EnumPatternInsteadOfIdentifier { span: self.prev_token.span })); } - Ok(PatKind::Ident(binding_annotation, ident, sub)) + // Check for method calls after the `ident`, + // but not `ident @ subpat` as `subpat` was already checked and `ident` continues with `@`. + + let pat = if sub.is_none() + && let Some(guar) = self.maybe_recover_trailing_expr(ident.span, false) + { + PatKind::Err(guar) + } else { + PatKind::Ident(binding_annotation, ident, sub) + }; + Ok(pat) } /// Parse a struct ("record") pattern (e.g. `Foo { ... }` or `Foo::Bar { ... }`). diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions1.rs b/tests/ui/half-open-range-patterns/range_pat_interactions1.rs index 55353999b6788..0c050c550c4ce 100644 --- a/tests/ui/half-open-range-patterns/range_pat_interactions1.rs +++ b/tests/ui/half-open-range-patterns/range_pat_interactions1.rs @@ -17,12 +17,18 @@ fn main() { } match x as i32 { 0..5+1 => errors_only.push(x), - //~^ error: expected one of `=>`, `if`, or `|`, found `+` + //~^ error: expected a pattern range bound, found an expression + //~| error: exclusive range pattern syntax is experimental 1 | -3..0 => first_or.push(x), + //~^ error: exclusive range pattern syntax is experimental y @ (0..5 | 6) => or_two.push(y), + //~^ error: exclusive range pattern syntax is experimental y @ 0..const { 5 + 1 } => assert_eq!(y, 5), + //~^ error: exclusive range pattern syntax is experimental + //~| error: inline-const in pattern position is experimental y @ -5.. => range_from.push(y), y @ ..-7 => assert_eq!(y, -8), + //~^ error: exclusive range pattern syntax is experimental y => bottom.push(y), } } diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr b/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr index cf3bde9705b6b..cc481f7a79e13 100644 --- a/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr +++ b/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr @@ -1,8 +1,8 @@ -error: expected one of `=>`, `if`, or `|`, found `+` - --> $DIR/range_pat_interactions1.rs:19:17 +error: expected a pattern range bound, found an expression + --> $DIR/range_pat_interactions1.rs:19:16 | LL | 0..5+1 => errors_only.push(x), - | ^ expected one of `=>`, `if`, or `|` + | ^^^ arbitrary expressions are not allowed in patterns error[E0408]: variable `n` is not bound in all patterns --> $DIR/range_pat_interactions1.rs:10:25 @@ -12,6 +12,16 @@ LL | if let n @ 2..3|4 = x { | | | variable not in all patterns +error[E0658]: inline-const in pattern position is experimental + --> $DIR/range_pat_interactions1.rs:26:20 + | +LL | y @ 0..const { 5 + 1 } => assert_eq!(y, 5), + | ^^^^^ + | + = note: see issue #76001 for more information + = help: add `#![feature(inline_const_pat)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error[E0658]: exclusive range pattern syntax is experimental --> $DIR/range_pat_interactions1.rs:10:20 | @@ -34,7 +44,62 @@ LL | } else if let 2..3 | 4 = x { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = help: use an inclusive range pattern, like N..=M -error: aborting due to 4 previous errors +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/range_pat_interactions1.rs:19:13 + | +LL | 0..5+1 => errors_only.push(x), + | ^^^^^^ + | + = note: see issue #37854 for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M + +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/range_pat_interactions1.rs:22:17 + | +LL | 1 | -3..0 => first_or.push(x), + | ^^^^^ + | + = note: see issue #37854 for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M + +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/range_pat_interactions1.rs:24:18 + | +LL | y @ (0..5 | 6) => or_two.push(y), + | ^^^^ + | + = note: see issue #37854 for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M + +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/range_pat_interactions1.rs:26:17 + | +LL | y @ 0..const { 5 + 1 } => assert_eq!(y, 5), + | ^^^^^^^^^^^^^^^^^^ + | + = note: see issue #37854 for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M + +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/range_pat_interactions1.rs:30:17 + | +LL | y @ ..-7 => assert_eq!(y, -8), + | ^^^^ + | + = note: see issue #37854 for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M + +error: aborting due to 10 previous errors Some errors have detailed explanations: E0408, E0658. For more information about an error, try `rustc --explain E0408`. diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions2.rs b/tests/ui/half-open-range-patterns/range_pat_interactions2.rs index 0e96cfe785857..068104c4b1b8c 100644 --- a/tests/ui/half-open-range-patterns/range_pat_interactions2.rs +++ b/tests/ui/half-open-range-patterns/range_pat_interactions2.rs @@ -8,12 +8,18 @@ fn main() { for x in -9 + 1..=(9 - 2) { match x as i32 { 0..=(5+1) => errors_only.push(x), - //~^ error: expected `)`, found `+` + //~^ error: expected a pattern range bound, found an expression + //~| error: range pattern bounds cannot have parentheses 1 | -3..0 => first_or.push(x), + //~^ error: exclusive range pattern syntax is experimental y @ (0..5 | 6) => or_two.push(y), + //~^ error: exclusive range pattern syntax is experimental y @ 0..const { 5 + 1 } => assert_eq!(y, 5), + //~^ error: inline-const in pattern position is experimental + //~| error: exclusive range pattern syntax is experimental y @ -5.. => range_from.push(y), y @ ..-7 => assert_eq!(y, -8), + //~^ error: exclusive range pattern syntax is experimental y => bottom.push(y), } } diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr b/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr index a54f29a3b3263..8f21a6149fb89 100644 --- a/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr +++ b/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr @@ -1,8 +1,75 @@ -error: expected `)`, found `+` - --> $DIR/range_pat_interactions2.rs:10:19 +error: expected a pattern range bound, found an expression + --> $DIR/range_pat_interactions2.rs:10:18 | LL | 0..=(5+1) => errors_only.push(x), - | ^ expected `)` + | ^^^ arbitrary expressions are not allowed in patterns -error: aborting due to 1 previous error +error: range pattern bounds cannot have parentheses + --> $DIR/range_pat_interactions2.rs:10:17 + | +LL | 0..=(5+1) => errors_only.push(x), + | ^ ^ + | +help: remove these parentheses + | +LL - 0..=(5+1) => errors_only.push(x), +LL + 0..=5+1 => errors_only.push(x), + | + +error[E0658]: inline-const in pattern position is experimental + --> $DIR/range_pat_interactions2.rs:17:20 + | +LL | y @ 0..const { 5 + 1 } => assert_eq!(y, 5), + | ^^^^^ + | + = note: see issue #76001 for more information + = help: add `#![feature(inline_const_pat)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/range_pat_interactions2.rs:13:17 + | +LL | 1 | -3..0 => first_or.push(x), + | ^^^^^ + | + = note: see issue #37854 for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M + +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/range_pat_interactions2.rs:15:18 + | +LL | y @ (0..5 | 6) => or_two.push(y), + | ^^^^ + | + = note: see issue #37854 for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M + +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/range_pat_interactions2.rs:17:17 + | +LL | y @ 0..const { 5 + 1 } => assert_eq!(y, 5), + | ^^^^^^^^^^^^^^^^^^ + | + = note: see issue #37854 for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M + +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/range_pat_interactions2.rs:21:17 + | +LL | y @ ..-7 => assert_eq!(y, -8), + | ^^^^ + | + = note: see issue #37854 for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M + +error: aborting due to 7 previous errors +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/parser/issues/issue-24197.rs b/tests/ui/parser/issues/issue-24197.rs index aaf5137461fa6..9bba16e5596ff 100644 --- a/tests/ui/parser/issues/issue-24197.rs +++ b/tests/ui/parser/issues/issue-24197.rs @@ -1,3 +1,3 @@ fn main() { - let buf[0] = 0; //~ ERROR expected one of `:`, `;`, `=`, `@`, or `|`, found `[` + let buf[0] = 0; //~ error: expected a pattern, found an expression } diff --git a/tests/ui/parser/issues/issue-24197.stderr b/tests/ui/parser/issues/issue-24197.stderr index 3ef707f3953cf..7ebbf4ac370d7 100644 --- a/tests/ui/parser/issues/issue-24197.stderr +++ b/tests/ui/parser/issues/issue-24197.stderr @@ -1,8 +1,8 @@ -error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[` - --> $DIR/issue-24197.rs:2:12 +error: expected a pattern, found an expression + --> $DIR/issue-24197.rs:2:9 | LL | let buf[0] = 0; - | ^ expected one of `:`, `;`, `=`, `@`, or `|` + | ^^^^^^ arbitrary expressions are not allowed in patterns error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-24375.rs b/tests/ui/parser/issues/issue-24375.rs index 1d128d33e4f49..a5e256b7f1554 100644 --- a/tests/ui/parser/issues/issue-24375.rs +++ b/tests/ui/parser/issues/issue-24375.rs @@ -3,7 +3,7 @@ static tmp : [&'static str; 2] = ["hello", "he"]; fn main() { let z = "hello"; match z { - tmp[0] => {} //~ ERROR expected one of `=>`, `@`, `if`, or `|`, found `[` + tmp[0] => {} //~ error: expected a pattern, found an expression _ => {} } } diff --git a/tests/ui/parser/issues/issue-24375.stderr b/tests/ui/parser/issues/issue-24375.stderr index bb1e19e9e6d8d..e6ef07d13fd8d 100644 --- a/tests/ui/parser/issues/issue-24375.stderr +++ b/tests/ui/parser/issues/issue-24375.stderr @@ -1,8 +1,8 @@ -error: expected one of `=>`, `@`, `if`, or `|`, found `[` - --> $DIR/issue-24375.rs:6:12 +error: expected a pattern, found an expression + --> $DIR/issue-24375.rs:6:9 | LL | tmp[0] => {} - | ^ expected one of `=>`, `@`, `if`, or `|` + | ^^^^^^ arbitrary expressions are not allowed in patterns error: aborting due to 1 previous error diff --git a/tests/ui/parser/pat-lt-bracket-5.rs b/tests/ui/parser/pat-lt-bracket-5.rs index aaece1f6bd9cb..6d784494d56a3 100644 --- a/tests/ui/parser/pat-lt-bracket-5.rs +++ b/tests/ui/parser/pat-lt-bracket-5.rs @@ -1,3 +1,5 @@ fn main() { - let v[0] = v[1]; //~ ERROR expected one of `:`, `;`, `=`, `@`, or `|`, found `[` + let v[0] = v[1]; + //~^ error: expected a pattern, found an expression + //~| error: cannot find value `v` in this scope } diff --git a/tests/ui/parser/pat-lt-bracket-5.stderr b/tests/ui/parser/pat-lt-bracket-5.stderr index e556e6c0206fb..18cf2df028216 100644 --- a/tests/ui/parser/pat-lt-bracket-5.stderr +++ b/tests/ui/parser/pat-lt-bracket-5.stderr @@ -1,8 +1,15 @@ -error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[` - --> $DIR/pat-lt-bracket-5.rs:2:10 +error: expected a pattern, found an expression + --> $DIR/pat-lt-bracket-5.rs:2:9 | LL | let v[0] = v[1]; - | ^ expected one of `:`, `;`, `=`, `@`, or `|` + | ^^^^ arbitrary expressions are not allowed in patterns -error: aborting due to 1 previous error +error[E0425]: cannot find value `v` in this scope + --> $DIR/pat-lt-bracket-5.rs:2:16 + | +LL | let v[0] = v[1]; + | ^ not found in this scope + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/parser/pat-lt-bracket-6.rs b/tests/ui/parser/pat-lt-bracket-6.rs index 7becffa9fe2f7..496525ed5370c 100644 --- a/tests/ui/parser/pat-lt-bracket-6.rs +++ b/tests/ui/parser/pat-lt-bracket-6.rs @@ -3,7 +3,8 @@ fn main() { let x = Test(&0, []); let Test(&desc[..]) = x; - //~^ ERROR: expected one of `)`, `,`, `@`, or `|`, found `[` + //~^ error: expected a pattern, found an expression + //~| error: this pattern has 1 field, but the corresponding tuple struct has 2 fields } const RECOVERY_WITNESS: () = 0; //~ ERROR mismatched types diff --git a/tests/ui/parser/pat-lt-bracket-6.stderr b/tests/ui/parser/pat-lt-bracket-6.stderr index 035d0dbfe06d6..10c638a63e44c 100644 --- a/tests/ui/parser/pat-lt-bracket-6.stderr +++ b/tests/ui/parser/pat-lt-bracket-6.stderr @@ -1,18 +1,30 @@ -error: expected one of `)`, `,`, `@`, or `|`, found `[` - --> $DIR/pat-lt-bracket-6.rs:5:19 +error: expected a pattern, found an expression + --> $DIR/pat-lt-bracket-6.rs:5:15 | LL | let Test(&desc[..]) = x; - | ^ - | | - | expected one of `)`, `,`, `@`, or `|` - | help: missing `,` + | ^^^^^^^^ arbitrary expressions are not allowed in patterns error[E0308]: mismatched types - --> $DIR/pat-lt-bracket-6.rs:9:30 + --> $DIR/pat-lt-bracket-6.rs:10:30 | LL | const RECOVERY_WITNESS: () = 0; | ^ expected `()`, found integer -error: aborting due to 2 previous errors +error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 2 fields + --> $DIR/pat-lt-bracket-6.rs:5:14 + | +LL | struct Test(&'static u8, [u8; 0]); + | ----------- ------- tuple struct has 2 fields +... +LL | let Test(&desc[..]) = x; + | ^^^^^^^^^ expected 2 fields, found 1 + | +help: use `_` to explicitly ignore each field + | +LL | let Test(&desc[..], _) = x; + | +++ + +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0023, E0308. +For more information about an error, try `rustc --explain E0023`. diff --git a/tests/ui/parser/pat-ranges-3.rs b/tests/ui/parser/pat-ranges-3.rs index 8976dcf0d90f9..419768a2a2022 100644 --- a/tests/ui/parser/pat-ranges-3.rs +++ b/tests/ui/parser/pat-ranges-3.rs @@ -1,5 +1,9 @@ // Parsing of range patterns fn main() { - let 10 ..= 10 + 3 = 12; //~ expected one of `:`, `;`, `=`, or `|`, found `+` + let 10 ..= 10 + 3 = 12; + //~^ error: expected a pattern range bound, found an expression + + let 10 - 3 ..= 10 = 8; + //~^ error: expected a pattern range bound, found an expression } diff --git a/tests/ui/parser/pat-ranges-3.stderr b/tests/ui/parser/pat-ranges-3.stderr index 611b35a650280..5e1f35d1b6f9a 100644 --- a/tests/ui/parser/pat-ranges-3.stderr +++ b/tests/ui/parser/pat-ranges-3.stderr @@ -1,8 +1,14 @@ -error: expected one of `:`, `;`, `=`, or `|`, found `+` - --> $DIR/pat-ranges-3.rs:4:19 +error: expected a pattern range bound, found an expression + --> $DIR/pat-ranges-3.rs:4:16 | LL | let 10 ..= 10 + 3 = 12; - | ^ expected one of `:`, `;`, `=`, or `|` + | ^^^^^^ arbitrary expressions are not allowed in patterns -error: aborting due to 1 previous error +error: expected a pattern range bound, found an expression + --> $DIR/pat-ranges-3.rs:7:9 + | +LL | let 10 - 3 ..= 10 = 8; + | ^^^^^^ arbitrary expressions are not allowed in patterns + +error: aborting due to 2 previous errors diff --git a/tests/ui/parser/pat-ranges-4.rs b/tests/ui/parser/pat-ranges-4.rs deleted file mode 100644 index 61188976b028c..0000000000000 --- a/tests/ui/parser/pat-ranges-4.rs +++ /dev/null @@ -1,6 +0,0 @@ -// Parsing of range patterns - -fn main() { - let 10 - 3 ..= 10 = 8; - //~^ error: expected one of `...`, `..=`, `..`, `:`, `;`, `=`, or `|`, found `-` -} diff --git a/tests/ui/parser/pat-ranges-4.stderr b/tests/ui/parser/pat-ranges-4.stderr deleted file mode 100644 index c30160291d608..0000000000000 --- a/tests/ui/parser/pat-ranges-4.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: expected one of `...`, `..=`, `..`, `:`, `;`, `=`, or `|`, found `-` - --> $DIR/pat-ranges-4.rs:4:12 - | -LL | let 10 - 3 ..= 10 = 8; - | ^ expected one of 7 possible tokens - -error: aborting due to 1 previous error - diff --git a/tests/ui/parser/pat-recover-exprs.rs b/tests/ui/parser/pat-recover-exprs.rs new file mode 100644 index 0000000000000..ecd471467e380 --- /dev/null +++ b/tests/ui/parser/pat-recover-exprs.rs @@ -0,0 +1,28 @@ +fn main() { + match u8::MAX { + u8::MAX.abs() => (), + //~^ error: expected a pattern, found a method call + x.sqrt() @ .. => (), + //~^ error: expected a pattern, found a method call + //~| error: left-hand side of `@` must be a binding + z @ w @ v.u() => (), + //~^ error: expected a pattern, found a method call + y.ilog(3) => (), + //~^ error: expected a pattern, found a method call + n + 1 => (), + //~^ error: expected a pattern, found an expression + ("".f() + 14 * 8) => (), + //~^ error: expected a pattern, found an expression + 0 | ((1) | 2) | 3 => (), + f?() => (), + //~^ error: expected a pattern, found an expression + (_ + 1) => (), + //~^ error: expected one of `)`, `,`, or `|`, found `+` + } + + let 1 + 1 = 2; + //~^ error: expected a pattern, found an expression + + let b = matches!(x, (x * x | x.f()) | x[0]); + //~^ error: expected one of `)`, `,`, `@`, or `|`, found `*` +} diff --git a/tests/ui/parser/pat-recover-exprs.stderr b/tests/ui/parser/pat-recover-exprs.stderr new file mode 100644 index 0000000000000..787fd03b0c30d --- /dev/null +++ b/tests/ui/parser/pat-recover-exprs.stderr @@ -0,0 +1,76 @@ +error: expected a pattern, found a method call + --> $DIR/pat-recover-exprs.rs:3:9 + | +LL | u8::MAX.abs() => (), + | ^^^^^^^^^^^^^ method calls are not allowed in patterns + +error: expected a pattern, found a method call + --> $DIR/pat-recover-exprs.rs:5:9 + | +LL | x.sqrt() @ .. => (), + | ^^^^^^^^ method calls are not allowed in patterns + +error: left-hand side of `@` must be a binding + --> $DIR/pat-recover-exprs.rs:5:9 + | +LL | x.sqrt() @ .. => (), + | --------^^^-- + | | | + | | also a pattern + | interpreted as a pattern, not a binding + | + = note: bindings are `x`, `mut x`, `ref x`, and `ref mut x` + +error: expected a pattern, found a method call + --> $DIR/pat-recover-exprs.rs:8:17 + | +LL | z @ w @ v.u() => (), + | ^^^^^ method calls are not allowed in patterns + +error: expected a pattern, found a method call + --> $DIR/pat-recover-exprs.rs:10:9 + | +LL | y.ilog(3) => (), + | ^^^^^^^^^ method calls are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/pat-recover-exprs.rs:12:9 + | +LL | n + 1 => (), + | ^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/pat-recover-exprs.rs:14:10 + | +LL | ("".f() + 14 * 8) => (), + | ^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/pat-recover-exprs.rs:17:9 + | +LL | f?() => (), + | ^^^^ arbitrary expressions are not allowed in patterns + +error: expected one of `)`, `,`, or `|`, found `+` + --> $DIR/pat-recover-exprs.rs:19:12 + | +LL | (_ + 1) => (), + | ^ expected one of `)`, `,`, or `|` + +error: expected a pattern, found an expression + --> $DIR/pat-recover-exprs.rs:23:9 + | +LL | let 1 + 1 = 2; + | ^^^^^ arbitrary expressions are not allowed in patterns + +error: expected one of `)`, `,`, `@`, or `|`, found `*` + --> $DIR/pat-recover-exprs.rs:26:28 + | +LL | let b = matches!(x, (x * x | x.f()) | x[0]); + | ^ expected one of `)`, `,`, `@`, or `|` + --> $SRC_DIR/core/src/macros/mod.rs:LL:COL + | + = note: while parsing argument for this `pat` macro fragment + +error: aborting due to 11 previous errors + diff --git a/tests/ui/parser/pat-recover-methodcalls.rs b/tests/ui/parser/pat-recover-methodcalls.rs new file mode 100644 index 0000000000000..54104e9a53559 --- /dev/null +++ b/tests/ui/parser/pat-recover-methodcalls.rs @@ -0,0 +1,37 @@ +struct Foo(String); +struct Bar { baz: String } + +fn foo(foo: Foo) -> bool { + match foo { + Foo("hi".to_owned()) => true, + //~^ error: expected a pattern, found a method call + _ => false + } +} + +fn bar(bar: Bar) -> bool { + match bar { + Bar { baz: "hi".to_owned() } => true, + //~^ error: expected a pattern, found a method call + _ => false + } +} + +fn baz() { // issue #90121 + let foo = vec!["foo".to_string()]; + + match foo.as_slice() { + &["foo".to_string()] => {} + //~^ error: expected a pattern, found a method call + _ => {} + }; +} + +fn main() { + if let (-1.some(4)) = (0, Some(4)) {} + //~^ error: expected a pattern, found a method call + + if let (-1.Some(4)) = (0, Some(4)) {} + //~^ error: expected one of `)`, `,`, `...`, `..=`, `..`, or `|`, found `.` + //~| help: missing `,` +} diff --git a/tests/ui/parser/pat-recover-methodcalls.stderr b/tests/ui/parser/pat-recover-methodcalls.stderr new file mode 100644 index 0000000000000..1f9ae81dc0c55 --- /dev/null +++ b/tests/ui/parser/pat-recover-methodcalls.stderr @@ -0,0 +1,35 @@ +error: expected a pattern, found a method call + --> $DIR/pat-recover-methodcalls.rs:6:13 + | +LL | Foo("hi".to_owned()) => true, + | ^^^^^^^^^^^^^^^ method calls are not allowed in patterns + +error: expected a pattern, found a method call + --> $DIR/pat-recover-methodcalls.rs:14:20 + | +LL | Bar { baz: "hi".to_owned() } => true, + | ^^^^^^^^^^^^^^^ method calls are not allowed in patterns + +error: expected a pattern, found a method call + --> $DIR/pat-recover-methodcalls.rs:24:11 + | +LL | &["foo".to_string()] => {} + | ^^^^^^^^^^^^^^^^^ method calls are not allowed in patterns + +error: expected a pattern, found a method call + --> $DIR/pat-recover-methodcalls.rs:31:13 + | +LL | if let (-1.some(4)) = (0, Some(4)) {} + | ^^^^^^^^^^ method calls are not allowed in patterns + +error: expected one of `)`, `,`, `...`, `..=`, `..`, or `|`, found `.` + --> $DIR/pat-recover-methodcalls.rs:34:15 + | +LL | if let (-1.Some(4)) = (0, Some(4)) {} + | ^ + | | + | expected one of `)`, `,`, `...`, `..=`, `..`, or `|` + | help: missing `,` + +error: aborting due to 5 previous errors + diff --git a/tests/ui/parser/pat-recover-ranges.rs b/tests/ui/parser/pat-recover-ranges.rs index 65a6fc6fe21f3..7d77e950d905a 100644 --- a/tests/ui/parser/pat-recover-ranges.rs +++ b/tests/ui/parser/pat-recover-ranges.rs @@ -8,6 +8,22 @@ fn main() { (0)..=(-4) => (), //~^ error: range pattern bounds cannot have parentheses //~| error: range pattern bounds cannot have parentheses + ..=1 + 2 => (), + //~^ error: expected a pattern range bound, found an expression + (4).. => (), + //~^ error: range pattern bounds cannot have parentheses + (-4 + 0).. => (), + //~^ error: expected a pattern range bound, found an expression + //~| error: range pattern bounds cannot have parentheses + (1 + 4)...1 * 2 => (), + //~^ error: expected a pattern range bound, found an expression + //~| error: expected a pattern range bound, found an expression + //~| error: range pattern bounds cannot have parentheses + //~| warning: `...` range patterns are deprecated + //~| warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + 0.x()..="y".z() => (), + //~^ error: expected a pattern range bound, found a method call + //~| error: expected a pattern range bound, found a method call }; } diff --git a/tests/ui/parser/pat-recover-ranges.stderr b/tests/ui/parser/pat-recover-ranges.stderr index 0d722b5aa95c8..a7d62bd7f8ad2 100644 --- a/tests/ui/parser/pat-recover-ranges.stderr +++ b/tests/ui/parser/pat-recover-ranges.stderr @@ -46,5 +46,87 @@ LL - (0)..=(-4) => (), LL + (0)..=-4 => (), | -error: aborting due to 4 previous errors +error: expected a pattern range bound, found an expression + --> $DIR/pat-recover-ranges.rs:11:12 + | +LL | ..=1 + 2 => (), + | ^^^^^ arbitrary expressions are not allowed in patterns + +error: range pattern bounds cannot have parentheses + --> $DIR/pat-recover-ranges.rs:13:9 + | +LL | (4).. => (), + | ^ ^ + | +help: remove these parentheses + | +LL - (4).. => (), +LL + 4.. => (), + | + +error: expected a pattern range bound, found an expression + --> $DIR/pat-recover-ranges.rs:15:10 + | +LL | (-4 + 0).. => (), + | ^^^^^^ arbitrary expressions are not allowed in patterns + +error: range pattern bounds cannot have parentheses + --> $DIR/pat-recover-ranges.rs:15:9 + | +LL | (-4 + 0).. => (), + | ^ ^ + | +help: remove these parentheses + | +LL - (-4 + 0).. => (), +LL + -4 + 0.. => (), + | + +error: expected a pattern range bound, found an expression + --> $DIR/pat-recover-ranges.rs:18:10 + | +LL | (1 + 4)...1 * 2 => (), + | ^^^^^ arbitrary expressions are not allowed in patterns + +error: range pattern bounds cannot have parentheses + --> $DIR/pat-recover-ranges.rs:18:9 + | +LL | (1 + 4)...1 * 2 => (), + | ^ ^ + | +help: remove these parentheses + | +LL - (1 + 4)...1 * 2 => (), +LL + 1 + 4...1 * 2 => (), + | + +error: expected a pattern range bound, found an expression + --> $DIR/pat-recover-ranges.rs:18:19 + | +LL | (1 + 4)...1 * 2 => (), + | ^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern range bound, found a method call + --> $DIR/pat-recover-ranges.rs:24:9 + | +LL | 0.x()..="y".z() => (), + | ^^^^^ method calls are not allowed in patterns + +error: expected a pattern range bound, found a method call + --> $DIR/pat-recover-ranges.rs:24:17 + | +LL | 0.x()..="y".z() => (), + | ^^^^^^^ method calls are not allowed in patterns + +warning: `...` range patterns are deprecated + --> $DIR/pat-recover-ranges.rs:18:16 + | +LL | (1 + 4)...1 * 2 => (), + | ^^^ help: use `..=` for an inclusive range + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see + = note: `#[warn(ellipsis_inclusive_range_patterns)]` on by default + +error: aborting due to 13 previous errors; 1 warning emitted diff --git a/tests/ui/parser/pat-recover-wildcards.rs b/tests/ui/parser/pat-recover-wildcards.rs new file mode 100644 index 0000000000000..f506e2223d608 --- /dev/null +++ b/tests/ui/parser/pat-recover-wildcards.rs @@ -0,0 +1,61 @@ +// check that we can't do funny things with wildcards. + +fn a() { + match 1 { + _ + 1 => () //~ error: expected one of `=>`, `if`, or `|`, found `+` + } +} + +fn b() { + match 2 { + (_ % 4) => () //~ error: expected one of `)`, `,`, or `|`, found `%` + } +} + +fn c() { + match 3 { + _.x() => () //~ error: expected one of `=>`, `if`, or `|`, found `.` + } +} + +fn d() { + match 4 { + _..=4 => () //~ error: expected one of `=>`, `if`, or `|`, found `..=` + } +} + +fn e() { + match 5 { + .._ => () //~ error: expected one of `=>`, `if`, or `|`, found reserved identifier `_` + } +} + +fn f() { + match 6 { + 0..._ => () + //~^ error: inclusive range with no end + //~| error: expected one of `=>`, `if`, or `|`, found reserved identifier `_` + } +} + +fn g() { + match 7 { + (_ * 0)..5 => () //~ error: expected one of `)`, `,`, or `|`, found `*` + } +} + +fn h() { + match 8 { + ..(_) => () //~ error: expected one of `=>`, `if`, or `|`, found `(` + } +} + +fn i() { + match 9 { + 4..=(2 + _) => () + //~^ error: expected a pattern range bound, found an expression + //~| error: range pattern bounds cannot have parentheses + } +} + +fn main() {} diff --git a/tests/ui/parser/pat-recover-wildcards.stderr b/tests/ui/parser/pat-recover-wildcards.stderr new file mode 100644 index 0000000000000..2b0c9bbc5be86 --- /dev/null +++ b/tests/ui/parser/pat-recover-wildcards.stderr @@ -0,0 +1,77 @@ +error: expected one of `=>`, `if`, or `|`, found `+` + --> $DIR/pat-recover-wildcards.rs:5:11 + | +LL | _ + 1 => () + | ^ expected one of `=>`, `if`, or `|` + +error: expected one of `)`, `,`, or `|`, found `%` + --> $DIR/pat-recover-wildcards.rs:11:12 + | +LL | (_ % 4) => () + | ^ expected one of `)`, `,`, or `|` + +error: expected one of `=>`, `if`, or `|`, found `.` + --> $DIR/pat-recover-wildcards.rs:17:10 + | +LL | _.x() => () + | ^ expected one of `=>`, `if`, or `|` + +error: expected one of `=>`, `if`, or `|`, found `..=` + --> $DIR/pat-recover-wildcards.rs:23:10 + | +LL | _..=4 => () + | ^^^ expected one of `=>`, `if`, or `|` + +error: expected one of `=>`, `if`, or `|`, found reserved identifier `_` + --> $DIR/pat-recover-wildcards.rs:29:11 + | +LL | .._ => () + | ^ expected one of `=>`, `if`, or `|` + +error[E0586]: inclusive range with no end + --> $DIR/pat-recover-wildcards.rs:35:10 + | +LL | 0..._ => () + | ^^^ help: use `..` instead + | + = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) + +error: expected one of `=>`, `if`, or `|`, found reserved identifier `_` + --> $DIR/pat-recover-wildcards.rs:35:13 + | +LL | 0..._ => () + | ^ expected one of `=>`, `if`, or `|` + +error: expected one of `)`, `,`, or `|`, found `*` + --> $DIR/pat-recover-wildcards.rs:43:12 + | +LL | (_ * 0)..5 => () + | ^ expected one of `)`, `,`, or `|` + +error: expected one of `=>`, `if`, or `|`, found `(` + --> $DIR/pat-recover-wildcards.rs:49:11 + | +LL | ..(_) => () + | ^ expected one of `=>`, `if`, or `|` + +error: expected a pattern range bound, found an expression + --> $DIR/pat-recover-wildcards.rs:55:14 + | +LL | 4..=(2 + _) => () + | ^^^^^ arbitrary expressions are not allowed in patterns + +error: range pattern bounds cannot have parentheses + --> $DIR/pat-recover-wildcards.rs:55:13 + | +LL | 4..=(2 + _) => () + | ^ ^ + | +help: remove these parentheses + | +LL - 4..=(2 + _) => () +LL + 4..=2 + _ => () + | + +error: aborting due to 11 previous errors + +For more information about this error, try `rustc --explain E0586`. From 67558055e39ee44be32ad4eb77052b1cd2ee3158 Mon Sep 17 00:00:00 2001 From: Matthew Woodcraft Date: Sun, 28 Jan 2024 19:30:00 +0000 Subject: [PATCH 18/21] normalize_newlines(): fix incorrect comment --- compiler/rustc_span/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 65702f76fdac7..ea6766ea583be 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -2105,7 +2105,7 @@ fn remove_bom(src: &mut String, normalized_pos: &mut Vec) { /// Replaces `\r\n` with `\n` in-place in `src`. /// -/// Returns error if there's a lone `\r` in the string. +/// Leaves any occurrences of lone `\r` unchanged. fn normalize_newlines(src: &mut String, normalized_pos: &mut Vec) { if !src.as_bytes().contains(&b'\r') { return; From d3bf8b717b81a57fcf8d6196743a8359f7d50800 Mon Sep 17 00:00:00 2001 From: r0cky Date: Sun, 28 Jan 2024 22:03:33 +0800 Subject: [PATCH 19/21] Clean dead code --- library/std/src/sys/pal/wasi/net.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/library/std/src/sys/pal/wasi/net.rs b/library/std/src/sys/pal/wasi/net.rs index 2239880ffbef4..2098d05db0bc7 100644 --- a/library/std/src/sys/pal/wasi/net.rs +++ b/library/std/src/sys/pal/wasi/net.rs @@ -538,7 +538,4 @@ pub mod netc { pub sin6_flowinfo: u32, pub sin6_scope_id: u32, } - - #[derive(Copy, Clone)] - pub struct sockaddr {} } From 83fa46fe5bcf8324aaa0614212080486623d672b Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 26 Jan 2024 13:23:55 +0000 Subject: [PATCH 20/21] Borrow check inline const patterns Add type annotations to MIR so that borrowck can pass constraints from inline constants in patterns to the containing function. --- compiler/rustc_borrowck/src/type_check/mod.rs | 64 ++++++++++++++++--- .../src/build/matches/simplify.rs | 37 ++++++++++- .../const-match-pat-lifetime-err.rs | 25 ++++++-- .../const-match-pat-lifetime-err.stderr | 28 ++++++++ 4 files changed, 139 insertions(+), 15 deletions(-) create mode 100644 tests/ui/inline-const/const-match-pat-lifetime-err.stderr diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index cf28e62177fb4..488dfc64cf6f0 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1099,10 +1099,17 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { #[instrument(skip(self), level = "debug")] fn check_user_type_annotations(&mut self) { debug!(?self.user_type_annotations); + let tcx = self.tcx(); for user_annotation in self.user_type_annotations { let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation; let annotation = self.instantiate_canonical_with_fresh_inference_vars(span, user_ty); - self.ascribe_user_type(inferred_ty, annotation, span); + if let ty::UserType::TypeOf(def, args) = annotation + && let DefKind::InlineConst = tcx.def_kind(def) + { + self.check_inline_const(inferred_ty, def.expect_local(), args, span); + } else { + self.ascribe_user_type(inferred_ty, annotation, span); + } } } @@ -1195,6 +1202,36 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Ok(()) } + fn check_inline_const( + &mut self, + inferred_ty: Ty<'tcx>, + def_id: LocalDefId, + args: UserArgs<'tcx>, + span: Span, + ) { + assert!(args.user_self_ty.is_none()); + let tcx = self.tcx(); + let const_ty = tcx.type_of(def_id).instantiate(tcx, args.args); + if let Err(terr) = + self.eq_types(const_ty, inferred_ty, Locations::All(span), ConstraintCategory::Boring) + { + span_bug!( + span, + "bad inline const pattern: ({:?} = {:?}) {:?}", + const_ty, + inferred_ty, + terr + ); + } + let args = self.infcx.resolve_vars_if_possible(args.args); + let predicates = self.prove_closure_bounds(tcx, def_id, args, Locations::All(span)); + self.normalize_and_prove_instantiated_predicates( + def_id.to_def_id(), + predicates, + Locations::All(span), + ); + } + fn tcx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } @@ -1851,7 +1888,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let def_id = uv.def; if tcx.def_kind(def_id) == DefKind::InlineConst { let def_id = def_id.expect_local(); - let predicates = self.prove_closure_bounds(tcx, def_id, uv.args, location); + let predicates = self.prove_closure_bounds( + tcx, + def_id, + uv.args, + location.to_locations(), + ); self.normalize_and_prove_instantiated_predicates( def_id.to_def_id(), predicates, @@ -2654,9 +2696,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // desugaring. A closure gets desugared to a struct, and // these extra requirements are basically like where // clauses on the struct. - AggregateKind::Closure(def_id, args) | AggregateKind::Coroutine(def_id, args) => { - (def_id, self.prove_closure_bounds(tcx, def_id.expect_local(), args, location)) - } + AggregateKind::Closure(def_id, args) | AggregateKind::Coroutine(def_id, args) => ( + def_id, + self.prove_closure_bounds( + tcx, + def_id.expect_local(), + args, + location.to_locations(), + ), + ), AggregateKind::Array(_) | AggregateKind::Tuple => { (CRATE_DEF_ID.to_def_id(), ty::InstantiatedPredicates::empty()) @@ -2675,7 +2723,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { tcx: TyCtxt<'tcx>, def_id: LocalDefId, args: GenericArgsRef<'tcx>, - location: Location, + locations: Locations, ) -> ty::InstantiatedPredicates<'tcx> { if let Some(closure_requirements) = &tcx.mir_borrowck(def_id).closure_requirements { constraint_conversion::ConstraintConversion::new( @@ -2684,7 +2732,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.region_bound_pairs, self.implicit_region_bound, self.param_env, - location.to_locations(), + locations, DUMMY_SP, // irrelevant; will be overridden. ConstraintCategory::Boring, // same as above. self.borrowck_context.constraints, @@ -2710,7 +2758,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { if let Err(_) = self.eq_args( typeck_root_args, parent_args, - location.to_locations(), + locations, ConstraintCategory::BoringNoLocation, ) { span_mirbug!( diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index a7f6f4873e383..065c93e86a866 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -15,7 +15,9 @@ use crate::build::expr::as_place::PlaceBuilder; use crate::build::matches::{Ascription, Binding, Candidate, MatchPair}; use crate::build::Builder; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::thir::{self, *}; +use rustc_middle::ty; use std::mem; @@ -149,7 +151,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ref subpattern, ascription: thir::Ascription { ref annotation, variance }, } => { - // Apply the type ascription to the value at `match_pair.place`, which is the + // Apply the type ascription to the value at `match_pair.place` if let Some(source) = match_pair.place.try_to_place(self) { candidate.ascriptions.push(Ascription { annotation: annotation.clone(), @@ -205,7 +207,38 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Err(match_pair) } - PatKind::InlineConstant { subpattern: ref pattern, def: _ } => { + PatKind::InlineConstant { subpattern: ref pattern, def } => { + // Apply a type ascription for the inline constant to the value at `match_pair.place` + if let Some(source) = match_pair.place.try_to_place(self) { + let span = match_pair.pattern.span; + let parent_id = self.tcx.typeck_root_def_id(self.def_id.to_def_id()); + let args = ty::InlineConstArgs::new( + self.tcx, + ty::InlineConstArgsParts { + parent_args: ty::GenericArgs::identity_for_item(self.tcx, parent_id), + ty: self.infcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span, + }), + }, + ) + .args; + let user_ty = + self.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf( + def.to_def_id(), + ty::UserArgs { args, user_self_ty: None }, + )); + let annotation = ty::CanonicalUserTypeAnnotation { + inferred_ty: pattern.ty, + span, + user_ty: Box::new(user_ty), + }; + candidate.ascriptions.push(Ascription { + annotation, + source, + variance: ty::Contravariant, + }); + } candidate.match_pairs.push(MatchPair::new(match_pair.place, pattern, self)); Ok(()) diff --git a/tests/ui/inline-const/const-match-pat-lifetime-err.rs b/tests/ui/inline-const/const-match-pat-lifetime-err.rs index 366ad26bb2716..ce91e5233bccd 100644 --- a/tests/ui/inline-const/const-match-pat-lifetime-err.rs +++ b/tests/ui/inline-const/const-match-pat-lifetime-err.rs @@ -1,5 +1,3 @@ -// ignore-test (This is currently broken) - #![allow(incomplete_features)] #![feature(const_mut_refs)] #![feature(inline_const_pat)] @@ -9,6 +7,9 @@ use std::marker::PhantomData; #[derive(PartialEq, Eq)] pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>); +#[derive(PartialEq, Eq)] +pub struct CovariantRef<'a, T: ?Sized>(&'a T); + impl<'a, T: ?Sized> InvariantRef<'a, T> { pub const fn new(r: &'a T) -> Self { InvariantRef(r, PhantomData) @@ -19,16 +20,30 @@ impl<'a> InvariantRef<'a, ()> { pub const NEW: Self = InvariantRef::new(&()); } +impl<'a> CovariantRef<'a, ()> { + pub const NEW: Self = CovariantRef(&()); +} + fn match_invariant_ref<'a>() { let y = (); match InvariantRef::new(&y) { - //~^ ERROR `y` does not live long enough [E0597] - // FIXME(nbdd0121): This should give the same error as `InvariantRef::<'a>::NEW` (without - // const block) + //~^ ERROR `y` does not live long enough [E0597] const { InvariantRef::<'a>::NEW } => (), } } +fn match_covariant_ref<'a>() { + // Unclear if we should error here (should we be able to subtype the type of + // `y.0`), but using the associated const directly in the pattern also + // errors. + let y: (CovariantRef<'static, _>,) = (CovariantRef(&()),); + //~^ ERROR lifetime may not live long enough + match y.0 { + const { CovariantRef::<'a>::NEW } => (), + } +} + fn main() { match_invariant_ref(); + match_covariant_ref(); } diff --git a/tests/ui/inline-const/const-match-pat-lifetime-err.stderr b/tests/ui/inline-const/const-match-pat-lifetime-err.stderr new file mode 100644 index 0000000000000..c5760f1027ef2 --- /dev/null +++ b/tests/ui/inline-const/const-match-pat-lifetime-err.stderr @@ -0,0 +1,28 @@ +error[E0597]: `y` does not live long enough + --> $DIR/const-match-pat-lifetime-err.rs:29:29 + | +LL | fn match_invariant_ref<'a>() { + | -- lifetime `'a` defined here +LL | let y = (); + | - binding `y` declared here +LL | match InvariantRef::new(&y) { + | ^^ borrowed value does not live long enough +LL | +LL | const { InvariantRef::<'a>::NEW } => (), + | --------------------------------- type annotation requires that `y` is borrowed for `'a` +LL | } +LL | } + | - `y` dropped here while still borrowed + +error: lifetime may not live long enough + --> $DIR/const-match-pat-lifetime-err.rs:39:12 + | +LL | fn match_covariant_ref<'a>() { + | -- lifetime `'a` defined here +... +LL | let y: (CovariantRef<'static, _>,) = (CovariantRef(&()),); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0597`. From 44824e0bcedcbd3e5a43c1cf51c26ee20a585637 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 26 Jan 2024 13:24:23 +0000 Subject: [PATCH 21/21] Enable tests for unsafe blocks in inline const patterns --- tests/ui/inline-const/pat-unsafe-err.rs | 2 -- tests/ui/inline-const/pat-unsafe-err.stderr | 19 +++++++++++++++++++ tests/ui/inline-const/pat-unsafe.rs | 1 - tests/ui/inline-const/pat-unsafe.stderr | 20 ++++++++++++++++++++ 4 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 tests/ui/inline-const/pat-unsafe-err.stderr create mode 100644 tests/ui/inline-const/pat-unsafe.stderr diff --git a/tests/ui/inline-const/pat-unsafe-err.rs b/tests/ui/inline-const/pat-unsafe-err.rs index 0db18dd3260d0..7680c82efb5c5 100644 --- a/tests/ui/inline-const/pat-unsafe-err.rs +++ b/tests/ui/inline-const/pat-unsafe-err.rs @@ -1,5 +1,3 @@ -// ignore-test This is currently broken - #![allow(incomplete_features)] #![feature(inline_const_pat)] diff --git a/tests/ui/inline-const/pat-unsafe-err.stderr b/tests/ui/inline-const/pat-unsafe-err.stderr new file mode 100644 index 0000000000000..9b995d6ccf27e --- /dev/null +++ b/tests/ui/inline-const/pat-unsafe-err.stderr @@ -0,0 +1,19 @@ +error[E0133]: call to unsafe function `require_unsafe` is unsafe and requires unsafe function or block + --> $DIR/pat-unsafe-err.rs:11:13 + | +LL | require_unsafe(); + | ^^^^^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error[E0133]: call to unsafe function `require_unsafe` is unsafe and requires unsafe function or block + --> $DIR/pat-unsafe-err.rs:18:13 + | +LL | require_unsafe() + | ^^^^^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/inline-const/pat-unsafe.rs b/tests/ui/inline-const/pat-unsafe.rs index cfef9ad6a563e..f7073ef40eb09 100644 --- a/tests/ui/inline-const/pat-unsafe.rs +++ b/tests/ui/inline-const/pat-unsafe.rs @@ -1,5 +1,4 @@ // check-pass -// ignore-test This is currently broken #![allow(incomplete_features)] #![warn(unused_unsafe)] diff --git a/tests/ui/inline-const/pat-unsafe.stderr b/tests/ui/inline-const/pat-unsafe.stderr new file mode 100644 index 0000000000000..84dc10c490258 --- /dev/null +++ b/tests/ui/inline-const/pat-unsafe.stderr @@ -0,0 +1,20 @@ +warning: unnecessary `unsafe` block + --> $DIR/pat-unsafe.rs:16:17 + | +LL | unsafe {} + | ^^^^^^ unnecessary `unsafe` block + | +note: the lint level is defined here + --> $DIR/pat-unsafe.rs:4:9 + | +LL | #![warn(unused_unsafe)] + | ^^^^^^^^^^^^^ + +warning: unnecessary `unsafe` block + --> $DIR/pat-unsafe.rs:23:17 + | +LL | unsafe {} + | ^^^^^^ unnecessary `unsafe` block + +warning: 2 warnings emitted +