From 40466672b5988e8bdbbcf089c788003e3c81b1b3 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 19 Aug 2021 20:12:13 -0700 Subject: [PATCH 01/18] Stabilize std::os::unix::fs::chroot --- library/std/src/os/unix/fs.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs index e4ce788f741..6cf37f23c57 100644 --- a/library/std/src/os/unix/fs.rs +++ b/library/std/src/os/unix/fs.rs @@ -934,7 +934,6 @@ impl DirBuilderExt for fs::DirBuilder { /// # Examples /// /// ```no_run -/// #![feature(unix_chroot)] /// use std::os::unix::fs; /// /// fn main() -> std::io::Result<()> { @@ -944,7 +943,7 @@ impl DirBuilderExt for fs::DirBuilder { /// Ok(()) /// } /// ``` -#[unstable(feature = "unix_chroot", issue = "84715")] +#[stable(feature = "unix_chroot", since = "1.56.0")] #[cfg(not(any(target_os = "fuchsia", target_os = "vxworks")))] pub fn chroot>(dir: P) -> io::Result<()> { sys::fs::chroot(dir.as_ref()) From b99038f4780d918224cd1aed6da2f9d6b42e7481 Mon Sep 17 00:00:00 2001 From: ibraheemdev Date: Mon, 30 Aug 2021 16:13:56 -0400 Subject: [PATCH 02/18] use `unwrap_unchecked` where possible --- library/alloc/src/collections/linked_list.rs | 2 +- library/core/src/array/mod.rs | 7 ++----- library/core/src/option.rs | 7 ++----- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index 7aa24ff4afa..77f09a2377a 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -300,7 +300,7 @@ impl LinkedList { let tail = self.tail.take(); let len = mem::replace(&mut self.len, 0); if let Some(head) = head { - let tail = tail.unwrap_or_else(|| unsafe { core::hint::unreachable_unchecked() }); + let tail = unsafe { tail.unwrap_unchecked() }; Some((head, tail, len)) } else { None diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 3c638e655dc..70cccd31b92 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -459,11 +459,8 @@ where debug_assert!(N <= iter.size_hint().1.unwrap_or(usize::MAX)); debug_assert!(N <= iter.size_hint().0); - match collect_into_array(iter) { - Some(array) => array, - // SAFETY: covered by the function contract. - None => unsafe { crate::hint::unreachable_unchecked() }, - } + // SAFETY: covered by the function contract. + unsafe { collect_into_array(iter).unwrap_unchecked() } } /// Pulls `N` items from `iter` and returns them as an array. If the iterator diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 47865240f6a..9d5e03dd0de 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -1198,11 +1198,8 @@ impl Option { pub fn insert(&mut self, value: T) -> &mut T { *self = Some(value); - match self { - Some(v) => v, - // SAFETY: the code above just filled the option - None => unsafe { hint::unreachable_unchecked() }, - } + // SAFETY: the code above just filled the option + unsafe { self.as_mut().unwrap_unchecked() } } /// Inserts `value` into the option if it is [`None`], then From 422ad3bec2a9b41345cf1dd95a4ce4b4d9f159d8 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 30 Aug 2021 23:41:48 +0200 Subject: [PATCH 03/18] Upgrade array_into_iter lint to include Deref-to-array types. --- compiler/rustc_lint/src/array_into_iter.rs | 52 ++++++++++++---------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs index 21fad5f9af6..2e20f376766 100644 --- a/compiler/rustc_lint/src/array_into_iter.rs +++ b/compiler/rustc_lint/src/array_into_iter.rs @@ -74,39 +74,45 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter { _ => return, }; - // As this is a method call expression, we have at least one - // argument. + // As this is a method call expression, we have at least one argument. let receiver_arg = &args[0]; + let receiver_ty = cx.typeck_results().expr_ty(receiver_arg); + let adjustments = cx.typeck_results().expr_adjustments(receiver_arg); - // Peel all `Box<_>` layers. We have to special case `Box` here as - // `Box` is the only thing that values can be moved out of via - // method call. `Box::new([1]).into_iter()` should trigger this - // lint. - let mut recv_ty = cx.typeck_results().expr_ty(receiver_arg); - let mut num_box_derefs = 0; - while recv_ty.is_box() { - num_box_derefs += 1; - recv_ty = recv_ty.boxed_ty(); + let target = match adjustments.last() { + Some(Adjustment { kind: Adjust::Borrow(_), target }) => target, + _ => return, + }; + + let types = + std::iter::once(receiver_ty).chain(adjustments.iter().map(|adj| adj.target)); + + let mut found_array = false; + + for ty in types { + match ty.kind() { + // If we run into a &[T; N] or &[T] first, there's nothing to warn about. + // It'll resolve to the reference version. + ty::Ref(_, inner_ty, _) if inner_ty.is_array() => return, + ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Slice(..)) => return, + // Found an actual array type without matching a &[T; N] first. + // This is the problematic case. + ty::Array(..) => { + found_array = true; + break; + } + _ => {} + } } - // Make sure we found an array after peeling the boxes. - if !matches!(recv_ty.kind(), ty::Array(..)) { + if !found_array { return; } - // Make sure that there is an autoref coercion at the expected - // position. The first `num_box_derefs` adjustments are the derefs - // of the box. - match cx.typeck_results().expr_adjustments(receiver_arg).get(num_box_derefs) { - Some(Adjustment { kind: Adjust::Borrow(_), .. }) => {} - _ => return, - } - // Emit lint diagnostic. - let target = match *cx.typeck_results().expr_ty_adjusted(receiver_arg).kind() { + let target = match *target.kind() { ty::Ref(_, inner_ty, _) if inner_ty.is_array() => "[T; N]", ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Slice(..)) => "[T]", - // We know the original first argument type is an array type, // we know that the first adjustment was an autoref coercion // and we know that `IntoIterator` is the trait involved. The From 90080f47032b5b2d578b0940ee615a428680e884 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 30 Aug 2021 23:42:13 +0200 Subject: [PATCH 04/18] Don't give invalid suggestions in array_into_iter. --- compiler/rustc_lint/src/array_into_iter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs index 2e20f376766..5ac42c50c72 100644 --- a/compiler/rustc_lint/src/array_into_iter.rs +++ b/compiler/rustc_lint/src/array_into_iter.rs @@ -141,7 +141,7 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter { String::new(), Applicability::MaybeIncorrect, ); - } else { + } else if receiver_ty.is_array() { diag.multipart_suggestion( "or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value", vec![ From 96d4666f23f71683965ded5844e78b3f4346406c Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 30 Aug 2021 23:42:48 +0200 Subject: [PATCH 05/18] Update tests for array_into_iter lint upgrade. --- .../ui/iterators/into-iter-on-arrays-2018.rs | 5 +- .../iterators/into-iter-on-arrays-2018.stderr | 32 +++++--- .../iterators/into-iter-on-arrays-lint.stderr | 80 ++----------------- 3 files changed, 33 insertions(+), 84 deletions(-) diff --git a/src/test/ui/iterators/into-iter-on-arrays-2018.rs b/src/test/ui/iterators/into-iter-on-arrays-2018.rs index e56c2956a69..60995170a51 100644 --- a/src/test/ui/iterators/into-iter-on-arrays-2018.rs +++ b/src/test/ui/iterators/into-iter-on-arrays-2018.rs @@ -19,9 +19,12 @@ fn main() { //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter` //~| WARNING this changes meaning - // The `array_into_iter` lint doesn't cover other wrappers that deref to an array. let _: Iter<'_, i32> = Rc::new(array).into_iter(); + //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter` + //~| WARNING this changes meaning let _: Iter<'_, i32> = Array(array).into_iter(); + //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter` + //~| WARNING this changes meaning // But you can always use the trait method explicitly as an array. let _: IntoIter = IntoIterator::into_iter(array); diff --git a/src/test/ui/iterators/into-iter-on-arrays-2018.stderr b/src/test/ui/iterators/into-iter-on-arrays-2018.stderr index e9780d9b165..bc08fdcafa0 100644 --- a/src/test/ui/iterators/into-iter-on-arrays-2018.stderr +++ b/src/test/ui/iterators/into-iter-on-arrays-2018.stderr @@ -20,21 +20,31 @@ warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (du --> $DIR/into-iter-on-arrays-2018.rs:18:44 | LL | let _: Iter<'_, i32> = Box::new(array).into_iter(); - | ^^^^^^^^^ + | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` | = warning: this changes meaning in Rust 2021 = note: for more information, see -help: use `.iter()` instead of `.into_iter()` to avoid ambiguity - | -LL | let _: Iter<'_, i32> = Box::new(array).iter(); - | ~~~~ -help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value - | -LL | let _: Iter<'_, i32> = IntoIterator::into_iter(Box::new(array)); - | ++++++++++++++++++++++++ ~ warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. - --> $DIR/into-iter-on-arrays-2018.rs:29:24 + --> $DIR/into-iter-on-arrays-2018.rs:22:43 + | +LL | let _: Iter<'_, i32> = Rc::new(array).into_iter(); + | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` + | + = warning: this changes meaning in Rust 2021 + = note: for more information, see + +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. + --> $DIR/into-iter-on-arrays-2018.rs:25:41 + | +LL | let _: Iter<'_, i32> = Array(array).into_iter(); + | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` + | + = warning: this changes meaning in Rust 2021 + = note: for more information, see + +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. + --> $DIR/into-iter-on-arrays-2018.rs:32:24 | LL | for _ in [1, 2, 3].into_iter() {} | ^^^^^^^^^ @@ -51,5 +61,5 @@ LL - for _ in [1, 2, 3].into_iter() {} LL + for _ in [1, 2, 3] {} | -warning: 3 warnings emitted +warning: 5 warnings emitted diff --git a/src/test/ui/iterators/into-iter-on-arrays-lint.stderr b/src/test/ui/iterators/into-iter-on-arrays-lint.stderr index 138becc4ffe..2df1a06df20 100644 --- a/src/test/ui/iterators/into-iter-on-arrays-lint.stderr +++ b/src/test/ui/iterators/into-iter-on-arrays-lint.stderr @@ -71,137 +71,73 @@ warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (du --> $DIR/into-iter-on-arrays-lint.rs:23:21 | LL | Box::new(small).into_iter(); - | ^^^^^^^^^ + | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` | = warning: this changes meaning in Rust 2021 = note: for more information, see -help: use `.iter()` instead of `.into_iter()` to avoid ambiguity - | -LL | Box::new(small).iter(); - | ~~~~ -help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value - | -LL | IntoIterator::into_iter(Box::new(small)); - | ++++++++++++++++++++++++ ~ warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. --> $DIR/into-iter-on-arrays-lint.rs:26:22 | LL | Box::new([1, 2]).into_iter(); - | ^^^^^^^^^ + | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` | = warning: this changes meaning in Rust 2021 = note: for more information, see -help: use `.iter()` instead of `.into_iter()` to avoid ambiguity - | -LL | Box::new([1, 2]).iter(); - | ~~~~ -help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value - | -LL | IntoIterator::into_iter(Box::new([1, 2])); - | ++++++++++++++++++++++++ ~ warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. --> $DIR/into-iter-on-arrays-lint.rs:29:19 | LL | Box::new(big).into_iter(); - | ^^^^^^^^^ + | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` | = warning: this changes meaning in Rust 2021 = note: for more information, see -help: use `.iter()` instead of `.into_iter()` to avoid ambiguity - | -LL | Box::new(big).iter(); - | ~~~~ -help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value - | -LL | IntoIterator::into_iter(Box::new(big)); - | ++++++++++++++++++++++++ ~ warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. --> $DIR/into-iter-on-arrays-lint.rs:32:25 | LL | Box::new([0u8; 33]).into_iter(); - | ^^^^^^^^^ + | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` | = warning: this changes meaning in Rust 2021 = note: for more information, see -help: use `.iter()` instead of `.into_iter()` to avoid ambiguity - | -LL | Box::new([0u8; 33]).iter(); - | ~~~~ -help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value - | -LL | IntoIterator::into_iter(Box::new([0u8; 33])); - | ++++++++++++++++++++++++ ~ warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. --> $DIR/into-iter-on-arrays-lint.rs:36:31 | LL | Box::new(Box::new(small)).into_iter(); - | ^^^^^^^^^ + | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` | = warning: this changes meaning in Rust 2021 = note: for more information, see -help: use `.iter()` instead of `.into_iter()` to avoid ambiguity - | -LL | Box::new(Box::new(small)).iter(); - | ~~~~ -help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value - | -LL | IntoIterator::into_iter(Box::new(Box::new(small))); - | ++++++++++++++++++++++++ ~ warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. --> $DIR/into-iter-on-arrays-lint.rs:39:32 | LL | Box::new(Box::new([1, 2])).into_iter(); - | ^^^^^^^^^ + | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` | = warning: this changes meaning in Rust 2021 = note: for more information, see -help: use `.iter()` instead of `.into_iter()` to avoid ambiguity - | -LL | Box::new(Box::new([1, 2])).iter(); - | ~~~~ -help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value - | -LL | IntoIterator::into_iter(Box::new(Box::new([1, 2]))); - | ++++++++++++++++++++++++ ~ warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. --> $DIR/into-iter-on-arrays-lint.rs:42:29 | LL | Box::new(Box::new(big)).into_iter(); - | ^^^^^^^^^ + | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` | = warning: this changes meaning in Rust 2021 = note: for more information, see -help: use `.iter()` instead of `.into_iter()` to avoid ambiguity - | -LL | Box::new(Box::new(big)).iter(); - | ~~~~ -help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value - | -LL | IntoIterator::into_iter(Box::new(Box::new(big))); - | ++++++++++++++++++++++++ ~ warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. --> $DIR/into-iter-on-arrays-lint.rs:45:35 | LL | Box::new(Box::new([0u8; 33])).into_iter(); - | ^^^^^^^^^ + | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` | = warning: this changes meaning in Rust 2021 = note: for more information, see -help: use `.iter()` instead of `.into_iter()` to avoid ambiguity - | -LL | Box::new(Box::new([0u8; 33])).iter(); - | ~~~~ -help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value - | -LL | IntoIterator::into_iter(Box::new(Box::new([0u8; 33]))); - | ++++++++++++++++++++++++ ~ warning: 12 warnings emitted From 99a3d646734c3aa7ff2564637e52e041e311c288 Mon Sep 17 00:00:00 2001 From: Paul Trojahn Date: Tue, 31 Aug 2021 15:53:50 +0200 Subject: [PATCH 06/18] Remove single use variables --- compiler/rustc_middle/src/mir/mod.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index b66995afc6d..d0a144a2d98 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -412,8 +412,7 @@ impl<'tcx> Body<'tcx> { /// Returns an iterator over all function arguments. #[inline] pub fn args_iter(&self) -> impl Iterator + ExactSizeIterator { - let arg_count = self.arg_count; - (1..arg_count + 1).map(Local::new) + (1..self.arg_count + 1).map(Local::new) } /// Returns an iterator over all user-defined variables and compiler-generated temporaries (all @@ -422,9 +421,7 @@ impl<'tcx> Body<'tcx> { pub fn vars_and_temps_iter( &self, ) -> impl DoubleEndedIterator + ExactSizeIterator { - let arg_count = self.arg_count; - let local_count = self.local_decls.len(); - (arg_count + 1..local_count).map(Local::new) + (self.arg_count + 1..self.local_decls.len()).map(Local::new) } /// Changes a statement to a nop. This is both faster than deleting instructions and avoids From ffc43b84682b9378a03b4cf5b166b2049625f7a4 Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Tue, 31 Aug 2021 11:18:30 -0400 Subject: [PATCH 07/18] add safety annotation to `LinkedList::detach_all_nodes` Co-authored-by: kennytm --- library/alloc/src/collections/linked_list.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index 77f09a2377a..9d45c5082db 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -300,6 +300,9 @@ impl LinkedList { let tail = self.tail.take(); let len = mem::replace(&mut self.len, 0); if let Some(head) = head { + // SAFETY: In a LinkedList, either both the head and tail are None because + // the list is empty, or both head and tail are Some because the list is populated. + // Since we have verified the head is Some, we are sure the tail is Some too. let tail = unsafe { tail.unwrap_unchecked() }; Some((head, tail, len)) } else { From 7189c854139b84d4356285c13d19b04b64e32272 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 31 Aug 2021 22:17:51 +0200 Subject: [PATCH 08/18] Improve closure dummy capture suggestion in macros. --- compiler/rustc_typeck/src/check/upvar.rs | 35 ++++++++++++++++++------ 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index a25d0f80644..702f69a9fcf 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -47,7 +47,7 @@ use rustc_middle::ty::{ }; use rustc_session::lint; use rustc_span::sym; -use rustc_span::{BytePos, MultiSpan, Pos, Span, Symbol, DUMMY_SP}; +use rustc_span::{BytePos, MultiSpan, Pos, Span, Symbol}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_data_structures::stable_map::FxHashMap; @@ -680,15 +680,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { migrated_variables_concat ); - // If the body was entirely expanded from a macro - // invocation, i.e. the body is not contained inside the - // closure span, then we walk up the expansion until we - // find the span before the expansion. - let closure_body_span = self.tcx.hir().span(body_id.hir_id) - .find_ancestor_inside(closure_span) - .unwrap_or(DUMMY_SP); + let mut closure_body_span = { + // If the body was entirely expanded from a macro + // invocation, i.e. the body is not contained inside the + // closure span, then we walk up the expansion until we + // find the span before the expansion. + let s = self.tcx.hir().span(body_id.hir_id); + s.find_ancestor_inside(closure_span).unwrap_or(s) + }; + + if let Ok(mut s) = self.tcx.sess.source_map().span_to_snippet(closure_body_span) { + if s.starts_with('$') { + // Looks like a macro fragment. Try to find the real block. + if let Some(hir::Node::Expr(&hir::Expr { + kind: hir::ExprKind::Block(block, ..), .. + })) = self.tcx.hir().find(body_id.hir_id) { + // If the body is a block (with `{..}`), we use the span of that block. + // E.g. with a `|| $body` expanded from a `m!({ .. })`, we use `{ .. }`, and not `$body`. + // Since we know it's a block, we know we can insert the `let _ = ..` without + // breaking the macro syntax. + if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(block.span) { + closure_body_span = block.span; + s = snippet; + } + } + } - if let Ok(s) = self.tcx.sess.source_map().span_to_snippet(closure_body_span) { let mut lines = s.lines(); let line1 = lines.next().unwrap_or_default(); From 7d18052b1bfc31a96c2482e8919ba824c0e4100c Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 31 Aug 2021 22:18:10 +0200 Subject: [PATCH 09/18] Add test for closure migration where body is a block fragment. --- .../closure-body-macro-fragment.fixed | 25 +++++++++++++ .../migrations/closure-body-macro-fragment.rs | 24 ++++++++++++ .../closure-body-macro-fragment.stderr | 37 +++++++++++++++++++ 3 files changed, 86 insertions(+) create mode 100644 src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.fixed create mode 100644 src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.fixed new file mode 100644 index 00000000000..f91454aa211 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.fixed @@ -0,0 +1,25 @@ +// run-rustfix +// edition:2018 +// check-pass +#![warn(rust_2021_compatibility)] + +macro_rules! m { + (@ $body:expr) => {{ + let f = || $body; + //~^ WARNING: drop order + f(); + }}; + ($body:block) => {{ + m!(@ $body); + }}; +} + +fn main() { + let a = (1.to_string(), 2.to_string()); + m!({ + let _ = &a; + //~^ HELP: add a dummy + let x = a.0; + println!("{}", x); + }); +} diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.rs b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.rs new file mode 100644 index 00000000000..5a1026d0433 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.rs @@ -0,0 +1,24 @@ +// run-rustfix +// edition:2018 +// check-pass +#![warn(rust_2021_compatibility)] + +macro_rules! m { + (@ $body:expr) => {{ + let f = || $body; + //~^ WARNING: drop order + f(); + }}; + ($body:block) => {{ + m!(@ $body); + }}; +} + +fn main() { + let a = (1.to_string(), 2.to_string()); + m!({ + //~^ HELP: add a dummy + let x = a.0; + println!("{}", x); + }); +} diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr new file mode 100644 index 00000000000..e6e5598f6d2 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr @@ -0,0 +1,37 @@ +warning: changes to closure capture in Rust 2021 will affect drop order + --> $DIR/closure-body-macro-fragment.rs:8:17 + | +LL | let f = || $body; + | _________________^ +LL | | +LL | | f(); +LL | | }}; + | | - in Rust 2018, `a` is dropped here, but in Rust 2021, only `a.0` will be dropped here as part of the closure +LL | | ($body:block) => {{ +LL | | m!(@ $body); + | |__________________^ +... +LL | / m!({ +LL | | +LL | | let x = a.0; + | | --- in Rust 2018, this closure captures all of `a`, but in Rust 2021, it will only capture `a.0` +LL | | println!("{}", x); +LL | | }); + | |_______- in this macro invocation + | +note: the lint level is defined here + --> $DIR/closure-body-macro-fragment.rs:4:9 + | +LL | #![warn(rust_2021_compatibility)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(rust_2021_incompatible_closure_captures)]` implied by `#[warn(rust_2021_compatibility)]` + = note: for more information, see + = note: this warning originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) +help: add a dummy let to cause `a` to be fully captured + | +LL ~ m!({ +LL + let _ = &a; + | + +warning: 1 warning emitted + From 6c9e708f4be04a5da9267171602be135789b12b8 Mon Sep 17 00:00:00 2001 From: klensy Date: Wed, 1 Sep 2021 15:35:58 +0300 Subject: [PATCH 10/18] `fmt::Formatter::pad`: don't call chars().count() more than one time --- library/core/src/fmt/mod.rs | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 1d75ac3d254..18539fc9588 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -1421,16 +1421,21 @@ impl<'a> Formatter<'a> { // If we're under the maximum length, and there's no minimum length // requirements, then we can just emit the string None => self.buf.write_str(s), - // If we're under the maximum width, check if we're over the minimum - // width, if so it's as easy as just emitting the string. - Some(width) if s.chars().count() >= width => self.buf.write_str(s), - // If we're under both the maximum and the minimum width, then fill - // up the minimum width with the specified string + some alignment. Some(width) => { - let align = rt::v1::Alignment::Left; - let post_padding = self.padding(width - s.chars().count(), align)?; - self.buf.write_str(s)?; - post_padding.write(self.buf) + let chars_count = s.chars().count(); + // If we're under the maximum width, check if we're over the minimum + // width, if so it's as easy as just emitting the string. + if chars_count >= width { + self.buf.write_str(s) + } + // If we're under both the maximum and the minimum width, then fill + // up the minimum width with the specified string + some alignment. + else { + let align = rt::v1::Alignment::Left; + let post_padding = self.padding(width - chars_count, align)?; + self.buf.write_str(s)?; + post_padding.write(self.buf) + } } } } From f5f489b945f2fe67474a1a49c5b19cffebc2e7bb Mon Sep 17 00:00:00 2001 From: klensy Date: Wed, 1 Sep 2021 15:52:29 +0300 Subject: [PATCH 11/18] fix clippy lints --- library/core/src/fmt/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 18539fc9588..aff789f2afa 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -402,7 +402,7 @@ impl<'a> Arguments<'a> { if self.args.is_empty() { pieces_length - } else if self.pieces[0] == "" && pieces_length < 16 { + } else if !self.pieces.is_empty() && self.pieces[0].is_empty() && pieces_length < 16 { // If the format string starts with an argument, // don't preallocate anything, unless length // of pieces is significant. @@ -1163,7 +1163,7 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result { } // SAFETY: arg and args.args come from the same Arguments, // which guarantees the indexes are always within bounds. - unsafe { run(&mut formatter, arg, &args.args) }?; + unsafe { run(&mut formatter, arg, args.args) }?; idx += 1; } } @@ -1409,7 +1409,7 @@ impl<'a> Formatter<'a> { // we know that it can't panic. Use `get` + `unwrap_or` to avoid // `unsafe` and otherwise don't emit any panic-related code // here. - s.get(..i).unwrap_or(&s) + s.get(..i).unwrap_or(s) } else { &s } From a5fd955b9531e6cd6e8394ccf3a1f804ad227881 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Wed, 1 Sep 2021 18:33:34 +0200 Subject: [PATCH 12/18] add regression test for issue 83190 --- src/test/ui/issues/issue-83190.rs | 49 +++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 src/test/ui/issues/issue-83190.rs diff --git a/src/test/ui/issues/issue-83190.rs b/src/test/ui/issues/issue-83190.rs new file mode 100644 index 00000000000..da931c3edaf --- /dev/null +++ b/src/test/ui/issues/issue-83190.rs @@ -0,0 +1,49 @@ +// check-pass + +// Regression test for issue #83190, triggering an ICE in borrowck. + +pub trait Any {} +impl Any for T {} + +pub trait StreamOnce { + type Range; +} + +pub trait Parser: Sized { + type Output; + type PartialState; + fn map(self) -> Map { + todo!() + } +} + +pub struct Map

(P); +impl> Parser for Map

{ + type Output = (); + type PartialState = P::PartialState; +} + +struct TakeWhile1(Input); +impl Parser for TakeWhile1 { + type Output = I::Range; + type PartialState = (); +} +impl TakeWhile1 { + fn new() -> Self { + todo!() + } +} + +impl> Parser for (A,) { + type Output = (); + type PartialState = Map; +} + +pub fn metric_stream_parser<'a, I>() -> impl Parser +where + I: StreamOnce, +{ + (TakeWhile1::new(),).map() +} + +fn main() {} From 4553a4baf2b365541c2322462a31eb5e5f43f3b5 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Wed, 1 Sep 2021 11:07:33 -0700 Subject: [PATCH 13/18] Remove redundant `Span` in `QueryJobInfo` Previously, `QueryJobInfo` was composed of two parts: a `QueryInfo` and a `QueryJob`. However, both `QueryInfo` and `QueryJob` have a `span` field, which seem to be the same. So, the `span` was recorded twice. Now, `QueryJobInfo` is composed of a `QueryStackFrame` (the other field of `QueryInfo`) and a `QueryJob`. So, now, the `span` is only recorded once. --- compiler/rustc_query_system/src/query/job.rs | 15 ++++++--------- compiler/rustc_query_system/src/query/plumbing.rs | 4 ++-- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index 63a8f062475..c3fdf4fc228 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -61,7 +61,7 @@ where } fn query(self, map: &QueryMap) -> QueryStackFrame { - map.get(&self).unwrap().info.query.clone() + map.get(&self).unwrap().query.clone() } #[cfg(parallel_compiler)] @@ -81,7 +81,7 @@ where } pub struct QueryJobInfo { - pub info: QueryInfo, + pub query: QueryStackFrame, pub job: QueryJob, } @@ -155,7 +155,7 @@ where while let Some(job) = current_job { let info = query_map.get(&job).unwrap(); - cycle.push(info.info.clone()); + cycle.push(QueryInfo { span: info.job.span, query: info.query.clone() }); if job == *self { cycle.reverse(); @@ -170,7 +170,7 @@ where .job .parent .as_ref() - .map(|parent| (info.info.span, parent.query(&query_map))); + .map(|parent| (info.job.span, parent.query(&query_map))); return CycleError { usage, cycle }; } @@ -649,13 +649,10 @@ pub fn print_query_stack( }; let mut diag = Diagnostic::new( Level::FailureNote, - &format!( - "#{} [{}] {}", - i, query_info.info.query.name, query_info.info.query.description - ), + &format!("#{} [{}] {}", i, query_info.query.name, query_info.query.description), ); diag.span = - tcx.dep_context().sess().source_map().guess_head_span(query_info.info.span).into(); + tcx.dep_context().sess().source_map().guess_head_span(query_info.job.span).into(); handler.force_print_diagnostic(diag); current_query = query_info.job.parent; diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index a7511846cad..3f22de6fba4 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -130,8 +130,8 @@ where for (k, v) in shard.active.iter() { if let QueryResult::Started(ref job) = *v { let id = QueryJobId::new(job.id, shard_id, kind); - let info = QueryInfo { span: job.span, query: make_query(tcx, k.clone()) }; - jobs.insert(id, QueryJobInfo { info, job: job.clone() }); + let query = make_query(tcx, k.clone()); + jobs.insert(id, QueryJobInfo { query, job: job.clone() }); } } } From 50983ba6df8effdeae993b2d4ed5eefe8c863bbf Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Wed, 1 Sep 2021 14:59:07 -0700 Subject: [PATCH 14/18] rustdoc: Don't panic on ambiguous inherent associated types Instead, return `Type::Infer` since compilation should fail anyway. That's how rustdoc handles `hir::TyKind::Err`s, so this just extends that behavior to `ty::Err`s when analyzing associated types. For some reason, the error is printed twice with rustdoc (though only once with rustc). I'm not sure why that is, but it's better than panicking. This commit also makes rustdoc fail early in the non-projection, non-error case, instead of returning a `Res::Err` that would likely cause rustdoc to panic later on. This change is originally from #88379. --- src/librustdoc/clean/mod.rs | 10 ++++++---- .../rustdoc-ui/ambiguous-inherent-assoc-ty.rs | 17 +++++++++++++++++ .../ambiguous-inherent-assoc-ty.stderr | 15 +++++++++++++++ 3 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.rs create mode 100644 src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.stderr diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b566239423e..d59c6bfdd36 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1311,10 +1311,11 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type { } hir::QPath::TypeRelative(ref qself, ref segment) => { let ty = hir_ty_to_ty(cx.tcx, hir_ty); - let res = if let ty::Projection(proj) = ty.kind() { - Res::Def(DefKind::Trait, proj.trait_ref(cx.tcx).def_id) - } else { - Res::Err + let res = match ty.kind() { + ty::Projection(proj) => Res::Def(DefKind::Trait, proj.trait_ref(cx.tcx).def_id), + // Rustdoc handles `ty::Error`s by turning them into `Type::Infer`s. + ty::Error(_) => return Type::Infer, + _ => bug!("clean: expected associated type, found `{:?}`", ty), }; let trait_path = hir::Path { span, res, segments: &[] }.clean(cx); Type::QPath { @@ -1379,6 +1380,7 @@ impl Clean for hir::Ty<'_> { DynTrait(bounds, lifetime) } TyKind::BareFn(ref barefn) => BareFunction(Box::new(barefn.clean(cx))), + // Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s. TyKind::Infer | TyKind::Err => Infer, TyKind::Typeof(..) => panic!("unimplemented type {:?}", self.kind), } diff --git a/src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.rs b/src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.rs new file mode 100644 index 00000000000..3ad56aebc21 --- /dev/null +++ b/src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.rs @@ -0,0 +1,17 @@ +// This test ensures that rustdoc does not panic on inherented associated types +// that are referred to without fully-qualified syntax. + +#![feature(inherent_associated_types)] +#![allow(incomplete_features)] + +pub struct Struct; + +impl Struct { + pub type AssocTy = usize; + pub const AssocConst: Self::AssocTy = 42; + //~^ ERROR ambiguous associated type + //~| HELP use fully-qualified syntax + // FIXME: for some reason, the error is shown twice with rustdoc but only once with rustc + //~| ERROR ambiguous associated type + //~| HELP use fully-qualified syntax +} diff --git a/src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.stderr b/src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.stderr new file mode 100644 index 00000000000..b963b722f66 --- /dev/null +++ b/src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.stderr @@ -0,0 +1,15 @@ +error[E0223]: ambiguous associated type + --> $DIR/ambiguous-inherent-assoc-ty.rs:11:27 + | +LL | pub const AssocConst: Self::AssocTy = 42; + | ^^^^^^^^^^^^^ help: use fully-qualified syntax: `::AssocTy` + +error[E0223]: ambiguous associated type + --> $DIR/ambiguous-inherent-assoc-ty.rs:11:27 + | +LL | pub const AssocConst: Self::AssocTy = 42; + | ^^^^^^^^^^^^^ help: use fully-qualified syntax: `::AssocTy` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0223`. From 727a4fc7e3f836938dfeb4a2ab237cfca612222d Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Thu, 2 Sep 2021 01:28:47 -0400 Subject: [PATCH 15/18] Implement #88581 --- library/core/src/num/int_macros.rs | 167 ++++++++++++++++++++++++++ library/core/src/num/uint_macros.rs | 104 ++++++++++++++++ library/core/tests/lib.rs | 1 + library/core/tests/num/int_macros.rs | 49 ++++++++ library/core/tests/num/uint_macros.rs | 25 ++++ 5 files changed, 346 insertions(+) diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 0bc646995c7..6fb5936db6c 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -1746,6 +1746,173 @@ macro_rules! int_impl { } } + /// Calculates the quotient of `self` and `rhs`, rounding the result towards negative infinity. + /// + /// # Panics + /// + /// This function will panic if `rhs` is 0 or the division results in overflow. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(int_roundings)] + #[doc = concat!("let a: ", stringify!($SelfT)," = 8;")] + /// let b = 3; + /// + /// assert_eq!(a.div_floor(b), 2); + /// assert_eq!(a.div_floor(-b), -3); + /// assert_eq!((-a).div_floor(b), -3); + /// assert_eq!((-a).div_floor(-b), 2); + /// ``` + #[unstable(feature = "int_roundings", issue = "88581")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[rustc_inherit_overflow_checks] + pub const fn div_floor(self, rhs: Self) -> Self { + let d = self / rhs; + let r = self % rhs; + if (r > 0 && rhs < 0) || (r < 0 && rhs > 0) { + d - 1 + } else { + d + } + } + + /// Calculates the quotient of `self` and `rhs`, rounding the result towards positive infinity. + /// + /// # Panics + /// + /// This function will panic if `rhs` is 0 or the division results in overflow. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(int_roundings)] + #[doc = concat!("let a: ", stringify!($SelfT)," = 8;")] + /// let b = 3; + /// + /// assert_eq!(a.div_ceil(b), 3); + /// assert_eq!(a.div_ceil(-b), -2); + /// assert_eq!((-a).div_ceil(b), -2); + /// assert_eq!((-a).div_ceil(-b), 3); + /// ``` + #[unstable(feature = "int_roundings", issue = "88581")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[rustc_inherit_overflow_checks] + pub const fn div_ceil(self, rhs: Self) -> Self { + let d = self / rhs; + let r = self % rhs; + if (r > 0 && rhs > 0) || (r < 0 && rhs < 0) { + d + 1 + } else { + d + } + } + + /// If `rhs` is positive, calculates the smallest value greater than or + /// equal to `self` that is a multiple of `rhs`. If `rhs` is negative, + /// calculates the largest value less than or equal to `self` that is a + /// multiple of `rhs`. + /// + /// # Panics + /// + /// This function will panic if `rhs` is 0 or the operation results in overflow. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(int_roundings)] + #[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".next_multiple_of(8), 16);")] + #[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".next_multiple_of(8), 24);")] + #[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".next_multiple_of(-8), 16);")] + #[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".next_multiple_of(-8), 16);")] + #[doc = concat!("assert_eq!((-16_", stringify!($SelfT), ").next_multiple_of(8), -16);")] + #[doc = concat!("assert_eq!((-23_", stringify!($SelfT), ").next_multiple_of(8), -16);")] + #[doc = concat!("assert_eq!((-16_", stringify!($SelfT), ").next_multiple_of(-8), -16);")] + #[doc = concat!("assert_eq!((-23_", stringify!($SelfT), ").next_multiple_of(-8), -24);")] + /// ``` + #[unstable(feature = "int_roundings", issue = "88581")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[rustc_inherit_overflow_checks] + pub const fn next_multiple_of(self, rhs: Self) -> Self { + // This would otherwise fail when calculating `r` when self == T::MIN. + if rhs == -1 { + return self; + } + + let r = self % rhs; + let m = if (r > 0 && rhs < 0) || (r < 0 && rhs > 0) { + r + rhs + } else { + r + }; + + if m == 0 { + self + } else { + self + (rhs - m) + } + } + + /// If `rhs` is positive, calculates the smallest value greater than or + /// equal to `self` that is a multiple of `rhs`. If `rhs` is negative, + /// calculates the largest value less than or equal to `self` that is a + /// multiple of `rhs`. Returns `None` if `rhs` is zero or the operation + /// would result in overflow. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(int_roundings)] + #[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".checked_next_multiple_of(8), Some(16));")] + #[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".checked_next_multiple_of(8), Some(24));")] + #[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".checked_next_multiple_of(-8), Some(16));")] + #[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".checked_next_multiple_of(-8), Some(16));")] + #[doc = concat!("assert_eq!((-16_", stringify!($SelfT), ").checked_next_multiple_of(8), Some(-16));")] + #[doc = concat!("assert_eq!((-23_", stringify!($SelfT), ").checked_next_multiple_of(8), Some(-16));")] + #[doc = concat!("assert_eq!((-16_", stringify!($SelfT), ").checked_next_multiple_of(-8), Some(-16));")] + #[doc = concat!("assert_eq!((-23_", stringify!($SelfT), ").checked_next_multiple_of(-8), Some(-24));")] + #[doc = concat!("assert_eq!(1_", stringify!($SelfT), ".checked_next_multiple_of(0), None);")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.checked_next_multiple_of(2), None);")] + /// ``` + #[unstable(feature = "int_roundings", issue = "88581")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[rustc_inherit_overflow_checks] + pub const fn checked_next_multiple_of(self, rhs: Self) -> Option { + // This would otherwise fail when calculating `r` when self == T::MIN. + if rhs == -1 { + return Some(self); + } + + let r = try_opt!(self.checked_rem(rhs)); + let m = if (r > 0 && rhs < 0) || (r < 0 && rhs > 0) { + try_opt!(r.checked_add(rhs)) + } else { + r + }; + + if m == 0 { + Some(self) + } else { + self.checked_add(try_opt!(rhs.checked_sub(m))) + } + } + /// Returns the logarithm of the number with respect to an arbitrary base. /// /// This method might not be optimized owing to implementation details; diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index ae113a47e95..f88d3ff8aac 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -1758,6 +1758,110 @@ macro_rules! uint_impl { self % rhs } + /// Calculates the quotient of `self` and `rhs`, rounding the result towards negative infinity. + /// + /// This is the same as performing `self / rhs` for all unsigned integers. + /// + /// # Panics + /// + /// This function will panic if `rhs` is 0. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(int_roundings)] + #[doc = concat!("assert_eq!(7_", stringify!($SelfT), ".div_floor(4), 1);")] + /// ``` + #[unstable(feature = "int_roundings", issue = "88581")] + #[inline(always)] + #[rustc_inherit_overflow_checks] + pub const fn div_floor(self, rhs: Self) -> Self { + self / rhs + } + + /// Calculates the quotient of `self` and `rhs`, rounding the result towards positive infinity. + /// + /// # Panics + /// + /// This function will panic if `rhs` is 0. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(int_roundings)] + #[doc = concat!("assert_eq!(7_", stringify!($SelfT), ".div_ceil(4), 2);")] + /// ``` + #[unstable(feature = "int_roundings", issue = "88581")] + #[inline] + #[rustc_inherit_overflow_checks] + pub const fn div_ceil(self, rhs: Self) -> Self { + let d = self / rhs; + let r = self % rhs; + if r > 0 && rhs > 0 { + d + 1 + } else { + d + } + } + + /// Calculates the smallest value greater than or equal to `self` that + /// is a multiple of `rhs`. + /// + /// # Panics + /// + /// This function will panic if `rhs` is 0 or the operation results in overflow. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(int_roundings)] + #[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".next_multiple_of(8), 16);")] + #[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".next_multiple_of(8), 24);")] + /// ``` + #[unstable(feature = "int_roundings", issue = "88581")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[rustc_inherit_overflow_checks] + pub const fn next_multiple_of(self, rhs: Self) -> Self { + match self % rhs { + 0 => self, + r => self + (rhs - r) + } + } + + /// Calculates the smallest value greater than or equal to `self` that + /// is a multiple of `rhs`. If `rhs` is negative, + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(int_roundings)] + #[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".checked_next_multiple_of(8), Some(16));")] + #[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".checked_next_multiple_of(8), Some(24));")] + #[doc = concat!("assert_eq!(1_", stringify!($SelfT), ".checked_next_multiple_of(0), None);")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.checked_next_multiple_of(2), None);")] + /// ``` + #[unstable(feature = "int_roundings", issue = "88581")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[rustc_inherit_overflow_checks] + pub const fn checked_next_multiple_of(self, rhs: Self) -> Option { + match try_opt!(self.checked_rem(rhs)) { + 0 => Some(self), + r => self.checked_add(try_opt!(rhs.checked_sub(r))) + } + } + /// Returns `true` if and only if `self == 2^k` for some `k`. /// /// # Examples diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 13f483f19b7..1cf6e1d9176 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -65,6 +65,7 @@ #![feature(unsized_tuple_coercion)] #![feature(const_option)] #![feature(integer_atomics)] +#![feature(int_roundings)] #![feature(slice_group_by)] #![feature(trusted_random_access)] #![feature(unsize)] diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs index 90c47656784..d2d655ea2c7 100644 --- a/library/core/tests/num/int_macros.rs +++ b/library/core/tests/num/int_macros.rs @@ -289,6 +289,55 @@ macro_rules! int_module { assert_eq!(r.saturating_pow(3), -8 as $T); assert_eq!(r.saturating_pow(0), 1 as $T); } + + #[test] + fn test_div_floor() { + let a: $T = 8; + let b = 3; + assert_eq!(a.div_floor(b), 2); + assert_eq!(a.div_floor(-b), -3); + assert_eq!((-a).div_floor(b), -3); + assert_eq!((-a).div_floor(-b), 2); + } + + #[test] + fn test_div_ceil() { + let a: $T = 8; + let b = 3; + assert_eq!(a.div_ceil(b), 3); + assert_eq!(a.div_ceil(-b), -2); + assert_eq!((-a).div_ceil(b), -2); + assert_eq!((-a).div_ceil(-b), 3); + } + + #[test] + fn test_next_multiple_of() { + assert_eq!((16 as $T).next_multiple_of(8), 16); + assert_eq!((23 as $T).next_multiple_of(8), 24); + assert_eq!((16 as $T).next_multiple_of(-8), 16); + assert_eq!((23 as $T).next_multiple_of(-8), 16); + assert_eq!((-16 as $T).next_multiple_of(8), -16); + assert_eq!((-23 as $T).next_multiple_of(8), -16); + assert_eq!((-16 as $T).next_multiple_of(-8), -16); + assert_eq!((-23 as $T).next_multiple_of(-8), -24); + assert_eq!(MIN.next_multiple_of(-1), MIN); + } + + #[test] + fn test_checked_next_multiple_of() { + assert_eq!((16 as $T).checked_next_multiple_of(8), Some(16)); + assert_eq!((23 as $T).checked_next_multiple_of(8), Some(24)); + assert_eq!((16 as $T).checked_next_multiple_of(-8), Some(16)); + assert_eq!((23 as $T).checked_next_multiple_of(-8), Some(16)); + assert_eq!((-16 as $T).checked_next_multiple_of(8), Some(-16)); + assert_eq!((-23 as $T).checked_next_multiple_of(8), Some(-16)); + assert_eq!((-16 as $T).checked_next_multiple_of(-8), Some(-16)); + assert_eq!((-23 as $T).checked_next_multiple_of(-8), Some(-24)); + assert_eq!((1 as $T).checked_next_multiple_of(0), None); + assert_eq!(MAX.checked_next_multiple_of(2), None); + assert_eq!(MIN.checked_next_multiple_of(-3), None); + assert_eq!(MIN.checked_next_multiple_of(-1), Some(MIN)); + } } }; } diff --git a/library/core/tests/num/uint_macros.rs b/library/core/tests/num/uint_macros.rs index 445f8fb350e..49f8f1f13fa 100644 --- a/library/core/tests/num/uint_macros.rs +++ b/library/core/tests/num/uint_macros.rs @@ -205,6 +205,31 @@ macro_rules! uint_module { assert_eq!(r.overflowing_pow(2), (1 as $T, true)); assert_eq!(r.saturating_pow(2), MAX); } + + #[test] + fn test_div_floor() { + assert_eq!((8 as $T).div_floor(3), 2); + } + + #[test] + fn test_div_ceil() { + assert_eq!((8 as $T).div_ceil(3), 3); + } + + #[test] + fn test_next_multiple_of() { + assert_eq!((16 as $T).next_multiple_of(8), 16); + assert_eq!((23 as $T).next_multiple_of(8), 24); + assert_eq!(MAX.next_multiple_of(1), MAX); + } + + #[test] + fn test_checked_next_multiple_of() { + assert_eq!((16 as $T).checked_next_multiple_of(8), Some(16)); + assert_eq!((23 as $T).checked_next_multiple_of(8), Some(24)); + assert_eq!((1 as $T).checked_next_multiple_of(0), None); + assert_eq!(MAX.checked_next_multiple_of(2), None); + } } }; } From a079ae2599305d6a218e52a384f1cb1077f5ffb1 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Thu, 2 Sep 2021 14:59:14 +0200 Subject: [PATCH 16/18] Correct doc comments inside `use_expr_visitor.rs` --- compiler/rustc_typeck/src/expr_use_visitor.rs | 78 +++++++++---------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index 3d483e322a8..ba70006fe96 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -21,29 +21,26 @@ use std::iter; use crate::mem_categorization as mc; -/////////////////////////////////////////////////////////////////////////// -// The Delegate trait - /// This trait defines the callbacks you can expect to receive when /// employing the ExprUseVisitor. pub trait Delegate<'tcx> { - // The value found at `place` is moved, depending - // on `mode`. Where `diag_expr_id` is the id used for diagnostics for `place`. - // - // Use of a `Copy` type in a ByValue context is considered a use - // by `ImmBorrow` and `borrow` is called instead. This is because - // a shared borrow is the "minimum access" that would be needed - // to perform a copy. - // - // - // The parameter `diag_expr_id` indicates the HIR id that ought to be used for - // diagnostics. Around pattern matching such as `let pat = expr`, the diagnostic - // id will be the id of the expression `expr` but the place itself will have - // the id of the binding in the pattern `pat`. + /// The value found at `place` is moved, depending + /// on `mode`. Where `diag_expr_id` is the id used for diagnostics for `place`. + /// + /// Use of a `Copy` type in a ByValue context is considered a use + /// by `ImmBorrow` and `borrow` is called instead. This is because + /// a shared borrow is the "minimum access" that would be needed + /// to perform a copy. + /// + /// + /// The parameter `diag_expr_id` indicates the HIR id that ought to be used for + /// diagnostics. Around pattern matching such as `let pat = expr`, the diagnostic + /// id will be the id of the expression `expr` but the place itself will have + /// the id of the binding in the pattern `pat`. fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId); - // The value found at `place` is being borrowed with kind `bk`. - // `diag_expr_id` is the id used for diagnostics (see `consume` for more details). + /// The value found at `place` is being borrowed with kind `bk`. + /// `diag_expr_id` is the id used for diagnostics (see `consume` for more details). fn borrow( &mut self, place_with_id: &PlaceWithHirId<'tcx>, @@ -51,44 +48,47 @@ pub trait Delegate<'tcx> { bk: ty::BorrowKind, ); - // The path at `assignee_place` is being assigned to. - // `diag_expr_id` is the id used for diagnostics (see `consume` for more details). + /// The path at `assignee_place` is being assigned to. + /// `diag_expr_id` is the id used for diagnostics (see `consume` for more details). fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId); - // The `place` should be a fake read because of specified `cause`. + /// The `place` should be a fake read because of specified `cause`. fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause, diag_expr_id: hir::HirId); } #[derive(Copy, Clone, PartialEq, Debug)] enum ConsumeMode { - Copy, // reference to x where x has a type that copies - Move, // reference to x where x has a type that moves + /// reference to x where x has a type that copies + Copy, + /// reference to x where x has a type that moves + Move, } #[derive(Copy, Clone, PartialEq, Debug)] pub enum MutateMode { Init, - JustWrite, // x = y - WriteAndRead, // x += y + /// Example: `x = y` + JustWrite, + /// Example: `x += y` + WriteAndRead, } -/////////////////////////////////////////////////////////////////////////// -// The ExprUseVisitor type -// -// This is the code that actually walks the tree. +/// The ExprUseVisitor type +/// +/// This is the code that actually walks the tree. pub struct ExprUseVisitor<'a, 'tcx> { mc: mc::MemCategorizationContext<'a, 'tcx>, body_owner: LocalDefId, delegate: &'a mut dyn Delegate<'tcx>, } -// If the MC results in an error, it's because the type check -// failed (or will fail, when the error is uncovered and reported -// during writeback). In this case, we just ignore this part of the -// code. -// -// Note that this macro appears similar to try!(), but, unlike try!(), -// it does not propagate the error. +/// If the MC results in an error, it's because the type check +/// failed (or will fail, when the error is uncovered and reported +/// during writeback). In this case, we just ignore this part of the +/// code. +/// +/// Note that this macro appears similar to try!(), but, unlike try!(), +/// it does not propagate the error. macro_rules! return_if_err { ($inp: expr) => { match $inp { @@ -537,9 +537,9 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { self.walk_expr(with_expr); } - // Invoke the appropriate delegate calls for anything that gets - // consumed or borrowed as part of the automatic adjustment - // process. + /// Invoke the appropriate delegate calls for anything that gets + /// consumed or borrowed as part of the automatic adjustment + /// process. fn walk_adjustment(&mut self, expr: &hir::Expr<'_>) { let adjustments = self.mc.typeck_results.expr_adjustments(expr); let mut place_with_id = return_if_err!(self.mc.cat_expr_unadjusted(expr)); From b5f680e7484dd96b1417c0219c5616ef2cd82d9d Mon Sep 17 00:00:00 2001 From: b-naber Date: Thu, 2 Sep 2021 12:22:23 +0200 Subject: [PATCH 17/18] do not resolve instances for trait fn ids --- .../src/transform/check_consts/check.rs | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_mir/src/transform/check_consts/check.rs b/compiler/rustc_mir/src/transform/check_consts/check.rs index 2b748062cdf..0c381276823 100644 --- a/compiler/rustc_mir/src/transform/check_consts/check.rs +++ b/compiler/rustc_mir/src/transform/check_consts/check.rs @@ -9,7 +9,7 @@ use rustc_infer::traits::{ImplSource, Obligation, ObligationCause}; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::cast::CastTy; -use rustc_middle::ty::subst::GenericArgKind; +use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt}; use rustc_middle::ty::{Binder, TraitPredicate, TraitRef}; use rustc_span::{sym, Span, Symbol}; @@ -793,7 +793,7 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> { let fn_ty = func.ty(body, tcx); - let (mut callee, substs) = match *fn_ty.kind() { + let (mut callee, mut substs) = match *fn_ty.kind() { ty::FnDef(def_id, substs) => (def_id, substs), ty::FnPtr(_) => { @@ -846,29 +846,31 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> { .iter() .find(|did| tcx.item_name(**did) == callee_name) { + // using internal substs is ok here, since this is only + // used for the `resolve` call below + substs = InternalSubsts::identity_for_item(tcx, did); callee = did; } } - _ => { - if !tcx.is_const_fn_raw(callee) { - // At this point, it is only legal when the caller is marked with - // #[default_method_body_is_const], and the callee is in the same - // trait. - let callee_trait = tcx.trait_of_item(callee); - if callee_trait.is_some() { - if tcx.has_attr(caller, sym::default_method_body_is_const) { - if tcx.trait_of_item(caller) == callee_trait { - nonconst_call_permission = true; - } + _ if !tcx.is_const_fn_raw(callee) => { + // At this point, it is only legal when the caller is marked with + // #[default_method_body_is_const], and the callee is in the same + // trait. + let callee_trait = tcx.trait_of_item(callee); + if callee_trait.is_some() { + if tcx.has_attr(caller, sym::default_method_body_is_const) { + if tcx.trait_of_item(caller) == callee_trait { + nonconst_call_permission = true; } } + } - if !nonconst_call_permission { - self.check_op(ops::FnCallNonConst); - return; - } + if !nonconst_call_permission { + self.check_op(ops::FnCallNonConst); + return; } } + _ => {} } // Resolve a trait method call to its concrete implementation, which may be in a From f825d6c6ccb5bc1eab9dfda96d3189f7092eb867 Mon Sep 17 00:00:00 2001 From: b-naber Date: Thu, 2 Sep 2021 16:29:04 +0200 Subject: [PATCH 18/18] add test --- .../const_trait_fn-issue-88433.rs | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/test/ui/const-generics/const_trait_fn-issue-88433.rs diff --git a/src/test/ui/const-generics/const_trait_fn-issue-88433.rs b/src/test/ui/const-generics/const_trait_fn-issue-88433.rs new file mode 100644 index 00000000000..8724fa69825 --- /dev/null +++ b/src/test/ui/const-generics/const_trait_fn-issue-88433.rs @@ -0,0 +1,26 @@ +// build-pass + +#![feature(const_trait_impl)] + +trait Func { + type Output; + + fn call_once(self, arg: T) -> Self::Output; +} + + +struct Closure; + +impl const Func<&usize> for Closure { + type Output = usize; + + fn call_once(self, arg: &usize) -> Self::Output { + *arg + } +} + +enum Bug { + V(T), +} + +fn main() {}