From 54d35e71a6a0053641e5813f74fbcf1c7379503a Mon Sep 17 00:00:00 2001 From: Yiming Lei Date: Fri, 8 Jul 2022 12:42:29 -0700 Subject: [PATCH 01/13] =?UTF-8?q?distinguish=20the=20method=20and=20associ?= =?UTF-8?q?ated=20function=20diagnostic=20information=20Methods=20are=20de?= =?UTF-8?q?fined=20within=20the=20context=20of=20a=20struct=20and=20their?= =?UTF-8?q?=20first=20parameter=20is=20always=20self=20Associated=20functi?= =?UTF-8?q?ons=20don=E2=80=99t=20take=20self=20as=20a=20parameter=20=09mod?= =?UTF-8?q?ified:=20=20=20compiler/rustc=5Ftypeck/src/check/method/suggest?= =?UTF-8?q?.rs=20=09modified:=20=20=20src/test/ui/auto-ref-slice-plus-ref.?= =?UTF-8?q?stderr=20=09modified:=20=20=20src/test/ui/block-result/issue-35?= =?UTF-8?q?63.stderr=20=09modified:=20=20=20src/test/ui/issues/issue-28344?= =?UTF-8?q?.stderr=20=09modified:=20=20=20src/test/ui/suggestions/dont-sug?= =?UTF-8?q?gest-pin-array-dot-set.stderr=20=09modified:=20=20=20src/test/u?= =?UTF-8?q?i/suggestions/suggest-methods.stderr=20=09modified:=20=20=20src?= =?UTF-8?q?/test/ui/traits/trait-upcasting/subtrait-method.stderr?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rustc_typeck/src/check/method/suggest.rs | 33 +++++++++++++------ src/test/ui/auto-ref-slice-plus-ref.stderr | 2 +- src/test/ui/block-result/issue-3563.stderr | 2 +- src/test/ui/issues/issue-28344.stderr | 4 +-- .../dont-suggest-pin-array-dot-set.stderr | 2 +- .../ui/suggestions/suggest-methods.stderr | 8 ++--- .../trait-upcasting/subtrait-method.stderr | 10 +++--- 7 files changed, 37 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 4e1a105fc71cc..4b91049355804 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -1035,16 +1035,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // that had unsatisfied trait bounds if unsatisfied_predicates.is_empty() { let def_kind = lev_candidate.kind.as_def_kind(); - err.span_suggestion( - span, - &format!( - "there is {} {} with a similar name", - def_kind.article(), - def_kind.descr(lev_candidate.def_id), - ), - lev_candidate.name, - Applicability::MaybeIncorrect, - ); + // Methods are defined within the context of a struct and their first parameter is always self, + // which represents the instance of the struct the method is being called on + // Associated functions don’t take self as a parameter and + // they are not methods because they don’t have an instance of the struct to work with. + if def_kind == DefKind::AssocFn && lev_candidate.fn_has_self_parameter { + err.span_suggestion( + span, + &format!("there is a method with a similar name",), + lev_candidate.name, + Applicability::MaybeIncorrect, + ); + } else { + err.span_suggestion( + span, + &format!( + "there is {} {} with a similar name", + def_kind.article(), + def_kind.descr(lev_candidate.def_id), + ), + lev_candidate.name, + Applicability::MaybeIncorrect, + ); + } } } diff --git a/src/test/ui/auto-ref-slice-plus-ref.stderr b/src/test/ui/auto-ref-slice-plus-ref.stderr index eb8447ff0f3e7..e2883050720d6 100644 --- a/src/test/ui/auto-ref-slice-plus-ref.stderr +++ b/src/test/ui/auto-ref-slice-plus-ref.stderr @@ -2,7 +2,7 @@ error[E0599]: no method named `test_mut` found for struct `Vec<{integer}>` in th --> $DIR/auto-ref-slice-plus-ref.rs:7:7 | LL | a.test_mut(); - | ^^^^^^^^ help: there is an associated function with a similar name: `get_mut` + | ^^^^^^^^ help: there is a method with a similar name: `get_mut` | = help: items from traits can only be used if the trait is implemented and in scope note: `MyIter` defines an item `test_mut`, perhaps you need to implement it diff --git a/src/test/ui/block-result/issue-3563.stderr b/src/test/ui/block-result/issue-3563.stderr index 5255e48bee13b..be551f6e889fc 100644 --- a/src/test/ui/block-result/issue-3563.stderr +++ b/src/test/ui/block-result/issue-3563.stderr @@ -2,7 +2,7 @@ error[E0599]: no method named `b` found for reference `&Self` in the current sco --> $DIR/issue-3563.rs:3:17 | LL | || self.b() - | ^ help: there is an associated function with a similar name: `a` + | ^ help: there is a method with a similar name: `a` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-28344.stderr b/src/test/ui/issues/issue-28344.stderr index b1d1c01b27a3c..85a8698afc5a7 100644 --- a/src/test/ui/issues/issue-28344.stderr +++ b/src/test/ui/issues/issue-28344.stderr @@ -25,7 +25,7 @@ LL | let x: u8 = BitXor::bitor(0 as u8, 0 as u8); | ^^^^^ | | | function or associated item not found in `dyn BitXor<_>` - | help: there is an associated function with a similar name: `bitxor` + | help: there is a method with a similar name: `bitxor` warning: trait objects without an explicit `dyn` are deprecated --> $DIR/issue-28344.rs:10:13 @@ -53,7 +53,7 @@ LL | let g = BitXor::bitor; | ^^^^^ | | | function or associated item not found in `dyn BitXor<_>` - | help: there is an associated function with a similar name: `bitxor` + | help: there is a method with a similar name: `bitxor` error: aborting due to 4 previous errors; 2 warnings emitted diff --git a/src/test/ui/suggestions/dont-suggest-pin-array-dot-set.stderr b/src/test/ui/suggestions/dont-suggest-pin-array-dot-set.stderr index 677aa031bf7d6..c66da3ea6d976 100644 --- a/src/test/ui/suggestions/dont-suggest-pin-array-dot-set.stderr +++ b/src/test/ui/suggestions/dont-suggest-pin-array-dot-set.stderr @@ -2,7 +2,7 @@ error[E0599]: no method named `set` found for array `[u8; 1]` in the current sco --> $DIR/dont-suggest-pin-array-dot-set.rs:14:7 | LL | a.set(0, 3); - | ^^^ help: there is an associated function with a similar name: `get` + | ^^^ help: there is a method with a similar name: `get` error: aborting due to previous error diff --git a/src/test/ui/suggestions/suggest-methods.stderr b/src/test/ui/suggestions/suggest-methods.stderr index dd9010e32955e..4277b23fdc127 100644 --- a/src/test/ui/suggestions/suggest-methods.stderr +++ b/src/test/ui/suggestions/suggest-methods.stderr @@ -5,25 +5,25 @@ LL | struct Foo; | --- method `bat` not found for this struct ... LL | f.bat(1.0); - | ^^^ help: there is an associated function with a similar name: `bar` + | ^^^ help: there is a method with a similar name: `bar` error[E0599]: no method named `is_emtpy` found for struct `String` in the current scope --> $DIR/suggest-methods.rs:21:15 | LL | let _ = s.is_emtpy(); - | ^^^^^^^^ help: there is an associated function with a similar name: `is_empty` + | ^^^^^^^^ help: there is a method with a similar name: `is_empty` error[E0599]: no method named `count_eos` found for type `u32` in the current scope --> $DIR/suggest-methods.rs:25:19 | LL | let _ = 63u32.count_eos(); - | ^^^^^^^^^ help: there is an associated function with a similar name: `count_zeros` + | ^^^^^^^^^ help: there is a method with a similar name: `count_zeros` error[E0599]: no method named `count_o` found for type `u32` in the current scope --> $DIR/suggest-methods.rs:28:19 | LL | let _ = 63u32.count_o(); - | ^^^^^^^ help: there is an associated function with a similar name: `count_ones` + | ^^^^^^^ help: there is a method with a similar name: `count_ones` error: aborting due to 4 previous errors diff --git a/src/test/ui/traits/trait-upcasting/subtrait-method.stderr b/src/test/ui/traits/trait-upcasting/subtrait-method.stderr index 8c69011800b47..af7a410f6d92c 100644 --- a/src/test/ui/traits/trait-upcasting/subtrait-method.stderr +++ b/src/test/ui/traits/trait-upcasting/subtrait-method.stderr @@ -2,7 +2,7 @@ error[E0599]: no method named `c` found for reference `&dyn Bar` in the current --> $DIR/subtrait-method.rs:56:9 | LL | bar.c(); - | ^ help: there is an associated function with a similar name: `a` + | ^ help: there is a method with a similar name: `a` | = help: items from traits can only be used if the trait is implemented and in scope note: `Baz` defines an item `c`, perhaps you need to implement it @@ -15,7 +15,7 @@ error[E0599]: no method named `b` found for reference `&dyn Foo` in the current --> $DIR/subtrait-method.rs:60:9 | LL | foo.b(); - | ^ help: there is an associated function with a similar name: `a` + | ^ help: there is a method with a similar name: `a` | = help: items from traits can only be used if the trait is implemented and in scope note: `Bar` defines an item `b`, perhaps you need to implement it @@ -28,7 +28,7 @@ error[E0599]: no method named `c` found for reference `&dyn Foo` in the current --> $DIR/subtrait-method.rs:62:9 | LL | foo.c(); - | ^ help: there is an associated function with a similar name: `a` + | ^ help: there is a method with a similar name: `a` | = help: items from traits can only be used if the trait is implemented and in scope note: `Baz` defines an item `c`, perhaps you need to implement it @@ -41,7 +41,7 @@ error[E0599]: no method named `b` found for reference `&dyn Foo` in the current --> $DIR/subtrait-method.rs:66:9 | LL | foo.b(); - | ^ help: there is an associated function with a similar name: `a` + | ^ help: there is a method with a similar name: `a` | = help: items from traits can only be used if the trait is implemented and in scope note: `Bar` defines an item `b`, perhaps you need to implement it @@ -54,7 +54,7 @@ error[E0599]: no method named `c` found for reference `&dyn Foo` in the current --> $DIR/subtrait-method.rs:68:9 | LL | foo.c(); - | ^ help: there is an associated function with a similar name: `a` + | ^ help: there is a method with a similar name: `a` | = help: items from traits can only be used if the trait is implemented and in scope note: `Baz` defines an item `c`, perhaps you need to implement it From 97c963d0812c347eaa02b7194f96c4bc01ab9698 Mon Sep 17 00:00:00 2001 From: Trevor Spiteri Date: Tue, 2 Aug 2022 22:22:16 +0200 Subject: [PATCH 02/13] make slice::{split_at,split_at_unchecked} const functions --- library/core/src/lib.rs | 1 + library/core/src/slice/mod.rs | 13 +++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 24742bb49b9a5..3a03edfb6465b 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -137,6 +137,7 @@ #![feature(const_size_of_val)] #![feature(const_slice_from_raw_parts_mut)] #![feature(const_slice_ptr_len)] +#![feature(const_slice_split_at_not_mut)] #![feature(const_str_from_utf8_unchecked_mut)] #![feature(const_swap)] #![feature(const_trait_impl)] diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index e6ca6ef82673e..2336ad9cae303 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1538,13 +1538,14 @@ impl [T] { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_slice_split_at_not_mut", issue = "none")] #[inline] #[track_caller] #[must_use] - pub fn split_at(&self, mid: usize) -> (&[T], &[T]) { + pub const fn split_at(&self, mid: usize) -> (&[T], &[T]) { assert!(mid <= self.len()); // SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which - // fulfills the requirements of `from_raw_parts_mut`. + // fulfills the requirements of `split_at_unchecked`. unsafe { self.split_at_unchecked(mid) } } @@ -1623,11 +1624,15 @@ impl [T] { /// } /// ``` #[unstable(feature = "slice_split_at_unchecked", reason = "new API", issue = "76014")] + #[rustc_const_unstable(feature = "const_slice_split_at_not_mut", issue = "none")] #[inline] #[must_use] - pub unsafe fn split_at_unchecked(&self, mid: usize) -> (&[T], &[T]) { + pub const unsafe fn split_at_unchecked(&self, mid: usize) -> (&[T], &[T]) { + let len = self.len(); + let ptr = self.as_ptr(); + // SAFETY: Caller has to check that `0 <= mid <= self.len()` - unsafe { (self.get_unchecked(..mid), self.get_unchecked(mid..)) } + unsafe { (from_raw_parts(ptr, mid), from_raw_parts(ptr.add(mid), len - mid)) } } /// Divides one mutable slice into two at an index, without doing bounds checking. From 83f081fc01f3173ef17a04da3cde313fa06d8502 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 15 Aug 2022 11:11:56 -0700 Subject: [PATCH 03/13] Remove unstable Result::into_ok_or_err --- ...0024-core-Disable-portable-simd-test.patch | 1 - compiler/rustc_transmute/src/layout/tree.rs | 13 +++---- compiler/rustc_transmute/src/lib.rs | 9 +---- library/core/src/result.rs | 34 ------------------- library/core/tests/lib.rs | 1 - library/core/tests/result.rs | 9 ----- 6 files changed, 8 insertions(+), 59 deletions(-) diff --git a/compiler/rustc_codegen_gcc/patches/0024-core-Disable-portable-simd-test.patch b/compiler/rustc_codegen_gcc/patches/0024-core-Disable-portable-simd-test.patch index d5fa1cec061dd..c59a40df03988 100644 --- a/compiler/rustc_codegen_gcc/patches/0024-core-Disable-portable-simd-test.patch +++ b/compiler/rustc_codegen_gcc/patches/0024-core-Disable-portable-simd-test.patch @@ -14,7 +14,6 @@ index 06c7be0..359e2e7 100644 @@ -75,7 +75,6 @@ #![feature(never_type)] #![feature(unwrap_infallible)] - #![feature(result_into_ok_or_err)] -#![feature(portable_simd)] #![feature(ptr_metadata)] #![feature(once_cell)] diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index 70b3ba02b05b5..402d2c95f5fbb 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -86,17 +86,18 @@ where F: Fn(D) -> bool, { match self { - Self::Seq(elts) => elts - .into_iter() - .map(|elt| elt.prune(f)) - .try_fold(Tree::unit(), |elts, elt| { + Self::Seq(elts) => match elts.into_iter().map(|elt| elt.prune(f)).try_fold( + Tree::unit(), + |elts, elt| { if elt == Tree::uninhabited() { Err(Tree::uninhabited()) } else { Ok(elts.then(elt)) } - }) - .into_ok_or_err(), + }, + ) { + Err(node) | Ok(node) => node, + }, Self::Alt(alts) => alts .into_iter() .map(|alt| alt.prune(f)) diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index cfc7c752a6bd6..01c50fb7cc80e 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -1,11 +1,4 @@ -#![feature( - alloc_layout_extra, - control_flow_enum, - decl_macro, - iterator_try_reduce, - never_type, - result_into_ok_or_err -)] +#![feature(alloc_layout_extra, control_flow_enum, decl_macro, iterator_try_reduce, never_type)] #![allow(dead_code, unused_variables)] #[macro_use] diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 45b052c824d31..6d583e28404d6 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1771,40 +1771,6 @@ impl Result, E> { } } -impl Result { - /// Returns the [`Ok`] value if `self` is `Ok`, and the [`Err`] value if - /// `self` is `Err`. - /// - /// In other words, this function returns the value (the `T`) of a - /// `Result`, regardless of whether or not that result is `Ok` or - /// `Err`. - /// - /// This can be useful in conjunction with APIs such as - /// [`Atomic*::compare_exchange`], or [`slice::binary_search`], but only in - /// cases where you don't care if the result was `Ok` or not. - /// - /// [`Atomic*::compare_exchange`]: crate::sync::atomic::AtomicBool::compare_exchange - /// - /// # Examples - /// - /// ``` - /// #![feature(result_into_ok_or_err)] - /// let ok: Result = Ok(3); - /// let err: Result = Err(4); - /// - /// assert_eq!(ok.into_ok_or_err(), 3); - /// assert_eq!(err.into_ok_or_err(), 4); - /// ``` - #[inline] - #[unstable(feature = "result_into_ok_or_err", reason = "newly added", issue = "82223")] - pub const fn into_ok_or_err(self) -> T { - match self { - Ok(v) => v, - Err(v) => v, - } - } -} - // This is a separate function to reduce the code size of the methods #[cfg(not(feature = "panic_immediate_abort"))] #[inline(never)] diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 09f1500f564cf..fe875c05aad55 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -75,7 +75,6 @@ #![feature(const_pin)] #![feature(never_type)] #![feature(unwrap_infallible)] -#![feature(result_into_ok_or_err)] #![feature(pointer_byte_offsets)] #![feature(portable_simd)] #![feature(ptr_metadata)] diff --git a/library/core/tests/result.rs b/library/core/tests/result.rs index 103e8cc3a96fa..50926da3ce799 100644 --- a/library/core/tests/result.rs +++ b/library/core/tests/result.rs @@ -95,15 +95,6 @@ fn test_unwrap_or() { assert_eq!(ok_err.unwrap_or(50), 50); } -#[test] -fn test_ok_or_err() { - let ok: Result = Ok(100); - let err: Result = Err(200); - - assert_eq!(ok.into_ok_or_err(), 100); - assert_eq!(err.into_ok_or_err(), 200); -} - #[test] fn test_unwrap_or_else() { fn handler(msg: &'static str) -> isize { From 39809c5f68e5618dc4183cfa95499df70357e617 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 15 Aug 2022 16:21:39 -0700 Subject: [PATCH 04/13] Replace a try_fold in rustc_transmute to use ControlFlow instead of Result --- compiler/rustc_transmute/src/layout/tree.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index 402d2c95f5fbb..93cab7ca53395 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -1,4 +1,5 @@ use super::{Byte, Def, Ref}; +use std::ops::ControlFlow; #[cfg(test)] mod tests; @@ -90,13 +91,13 @@ where Tree::unit(), |elts, elt| { if elt == Tree::uninhabited() { - Err(Tree::uninhabited()) + ControlFlow::Break(Tree::uninhabited()) } else { - Ok(elts.then(elt)) + ControlFlow::Continue(elts.then(elt)) } }, ) { - Err(node) | Ok(node) => node, + ControlFlow::Break(node) | ControlFlow::Continue(node) => node, }, Self::Alt(alts) => alts .into_iter() From 289d7cca1dff4b142b1c208fd1dd5eb2ce0a628f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Wed, 24 Aug 2022 00:53:09 +0200 Subject: [PATCH 05/13] Reduce code size of `assert_matches_failed` --- library/core/src/panicking.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 7a575a88e52e1..d4afe0f5326a3 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -190,11 +190,11 @@ pub fn assert_matches_failed( right: &str, args: Option>, ) -> ! { - // Use the Display implementation to display the pattern. + // The pattern is a string so it can be displayed directly. struct Pattern<'a>(&'a str); impl fmt::Debug for Pattern<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self.0, f) + f.write_str(self.0) } } assert_failed_inner(AssertKind::Match, &left, &Pattern(right), args); From b997af95fce1f1295f3b90ae33c575b6ded4f914 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 25 Aug 2022 09:41:48 +1000 Subject: [PATCH 06/13] Handle `Err` in `ast::LitKind::to_token_lit`. Fixes #100948. --- compiler/rustc_ast/src/util/literal.rs | 4 +++- src/test/ui/unpretty/bad-literal.rs | 8 ++++++++ src/test/ui/unpretty/bad-literal.stderr | 10 ++++++++++ src/test/ui/unpretty/bad-literal.stdout | 11 +++++++++++ 4 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/unpretty/bad-literal.rs create mode 100644 src/test/ui/unpretty/bad-literal.stderr create mode 100644 src/test/ui/unpretty/bad-literal.stdout diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index 6a02a3b56f616..69a78d165ef58 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -199,7 +199,9 @@ impl LitKind { let symbol = if value { kw::True } else { kw::False }; (token::Bool, symbol, None) } - LitKind::Err => unreachable!(), + // This only shows up in places like `-Zunpretty=hir` output, so we + // don't bother to produce something useful. + LitKind::Err => (token::Err, Symbol::intern(""), None), }; token::Lit::new(kind, symbol, suffix) diff --git a/src/test/ui/unpretty/bad-literal.rs b/src/test/ui/unpretty/bad-literal.rs new file mode 100644 index 0000000000000..6dcc0da30cc2c --- /dev/null +++ b/src/test/ui/unpretty/bad-literal.rs @@ -0,0 +1,8 @@ +// compile-flags: -Zunpretty=hir +// check-fail + +// In #100948 this caused an ICE with -Zunpretty=hir. +fn main() { + 1u; + //~^ ERROR invalid suffix `u` for number literal +} diff --git a/src/test/ui/unpretty/bad-literal.stderr b/src/test/ui/unpretty/bad-literal.stderr new file mode 100644 index 0000000000000..f3fcb4a4e921d --- /dev/null +++ b/src/test/ui/unpretty/bad-literal.stderr @@ -0,0 +1,10 @@ +error: invalid suffix `u` for number literal + --> $DIR/bad-literal.rs:6:5 + | +LL | 1u; + | ^^ invalid suffix `u` + | + = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) + +error: aborting due to previous error + diff --git a/src/test/ui/unpretty/bad-literal.stdout b/src/test/ui/unpretty/bad-literal.stdout new file mode 100644 index 0000000000000..8df9332703316 --- /dev/null +++ b/src/test/ui/unpretty/bad-literal.stdout @@ -0,0 +1,11 @@ +#[prelude_import] +use ::std::prelude::rust_2015::*; +#[macro_use] +extern crate std; +// compile-flags: -Zunpretty=hir +// check-fail + +// In #100948 this caused an ICE with -Zunpretty=hir. +fn main() { + ; + } From 31d892a942bd490b3478ceb6624c387b75690279 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Mon, 1 Aug 2022 00:00:00 +0000 Subject: [PATCH 07/13] Fix liveness analysis for yield terminators A resume place is evaluated and assigned to only after a yield terminator resumes. Ensure that locals used when evaluating the resume place are live across the yield. --- .../rustc_mir_dataflow/src/impls/liveness.rs | 93 ++++++++++++------- 1 file changed, 61 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index 21132eb991fd5..8f81b71e3e200 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -23,12 +23,6 @@ use crate::{Analysis, AnalysisDomain, Backward, CallReturnPlaces, GenKill, GenKi /// [liveness]: https://en.wikipedia.org/wiki/Live_variable_analysis pub struct MaybeLiveLocals; -impl MaybeLiveLocals { - fn transfer_function<'a, T>(&self, trans: &'a mut T) -> TransferFunction<'a, T> { - TransferFunction(trans) - } -} - impl<'tcx> AnalysisDomain<'tcx> for MaybeLiveLocals { type Domain = ChunkedBitSet; type Direction = Backward; @@ -54,7 +48,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals { statement: &mir::Statement<'tcx>, location: Location, ) { - self.transfer_function(trans).visit_statement(statement, location); + TransferFunction(trans).visit_statement(statement, location); } fn terminator_effect( @@ -63,7 +57,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals { terminator: &mir::Terminator<'tcx>, location: Location, ) { - self.transfer_function(trans).visit_terminator(terminator, location); + TransferFunction(trans).visit_terminator(terminator, location); } fn call_return_effect( @@ -85,9 +79,11 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals { _resume_block: mir::BasicBlock, resume_place: mir::Place<'tcx>, ) { - if let Some(local) = resume_place.as_local() { - trans.kill(local); - } + YieldResumeEffect(trans).visit_place( + &resume_place, + PlaceContext::MutatingUse(MutatingUseContext::Yield), + Location::START, + ) } } @@ -98,23 +94,58 @@ where T: GenKill, { fn visit_place(&mut self, place: &mir::Place<'tcx>, context: PlaceContext, location: Location) { - let local = place.local; + if let PlaceContext::MutatingUse(MutatingUseContext::Yield) = context { + // The resume place is evaluated and assigned to only after generator resumes, so its + // effect is handled separately in `yield_resume_effect`. + return; + } + + match DefUse::for_place(*place, context) { + Some(DefUse::Def) => { + if let PlaceContext::MutatingUse( + MutatingUseContext::Call | MutatingUseContext::AsmOutput, + ) = context + { + // For the associated terminators, this is only a `Def` when the terminator returns + // "successfully." As such, we handle this case separately in `call_return_effect` + // above. However, if the place looks like `*_5`, this is still unconditionally a use of + // `_5`. + } else { + self.0.kill(place.local); + } + } + Some(DefUse::Use) => self.0.gen(place.local), + None => {} + } - // We purposefully do not call `super_place` here to avoid calling `visit_local` for this - // place with one of the `Projection` variants of `PlaceContext`. self.visit_projection(place.as_ref(), context, location); + } - match DefUse::for_place(*place, context) { + fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) { + match DefUse::for_place(local.into(), context) { Some(DefUse::Def) => self.0.kill(local), Some(DefUse::Use) => self.0.gen(local), None => {} } } +} + +struct YieldResumeEffect<'a, T>(&'a mut T); + +impl<'tcx, T> Visitor<'tcx> for YieldResumeEffect<'_, T> +where + T: GenKill, +{ + fn visit_place(&mut self, place: &mir::Place<'tcx>, context: PlaceContext, location: Location) { + match DefUse::for_place(*place, context) { + Some(DefUse::Def) => self.0.kill(place.local), + Some(DefUse::Use) => self.0.gen(place.local), + None => {} + } + self.visit_projection(place.as_ref(), context, location); + } fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) { - // Because we do not call `super_place` above, `visit_local` is only called for locals that - // do not appear as part of a `Place` in the MIR. This handles cases like the implicit use - // of the return place in a `Return` terminator or the index in an `Index` projection. match DefUse::for_place(local.into(), context) { Some(DefUse::Def) => self.0.kill(local), Some(DefUse::Use) => self.0.gen(local), @@ -134,7 +165,13 @@ impl DefUse { match context { PlaceContext::NonUse(_) => None, - PlaceContext::MutatingUse(MutatingUseContext::Store | MutatingUseContext::Deinit) => { + PlaceContext::MutatingUse( + MutatingUseContext::Call + | MutatingUseContext::Yield + | MutatingUseContext::AsmOutput + | MutatingUseContext::Store + | MutatingUseContext::Deinit, + ) => { if place.is_indirect() { // Treat derefs as a use of the base local. `*p = 4` is not a def of `p` but a // use. @@ -152,16 +189,6 @@ impl DefUse { place.is_indirect().then_some(DefUse::Use) } - // For the associated terminators, this is only a `Def` when the terminator returns - // "successfully." As such, we handle this case separately in `call_return_effect` - // above. However, if the place looks like `*_5`, this is still unconditionally a use of - // `_5`. - PlaceContext::MutatingUse( - MutatingUseContext::Call - | MutatingUseContext::Yield - | MutatingUseContext::AsmOutput, - ) => place.is_indirect().then_some(DefUse::Use), - // All other contexts are uses... PlaceContext::MutatingUse( MutatingUseContext::AddressOf @@ -290,8 +317,10 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> { _resume_block: mir::BasicBlock, resume_place: mir::Place<'tcx>, ) { - if let Some(local) = resume_place.as_local() { - trans.remove(local); - } + YieldResumeEffect(trans).visit_place( + &resume_place, + PlaceContext::MutatingUse(MutatingUseContext::Yield), + Location::START, + ) } } From 4462b4af52e753e79de737857ff620fd267fb58f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Mon, 1 Aug 2022 00:00:00 +0000 Subject: [PATCH 08/13] Elaborate all box dereferences in `ElaborateBoxDerefs` so that it is the only pass responsible for elaboration, instead of splitting this responsibility between the `StateTransform` and `ElaborateBoxDerefs`. --- .../src/elaborate_box_derefs.rs | 23 +---- compiler/rustc_mir_transform/src/generator.rs | 88 ++----------------- 2 files changed, 9 insertions(+), 102 deletions(-) diff --git a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs index e04094153dfc0..294af2455d069 100644 --- a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs +++ b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs @@ -107,27 +107,8 @@ impl<'tcx> MirPass<'tcx> for ElaborateBoxDerefs { let mut visitor = ElaborateBoxDerefVisitor { tcx, unique_did, nonnull_did, local_decls, patch }; - for (block, BasicBlockData { statements, terminator, .. }) in - body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() - { - let mut index = 0; - for statement in statements { - let location = Location { block, statement_index: index }; - visitor.visit_statement(statement, location); - index += 1; - } - - let location = Location { block, statement_index: index }; - match terminator { - // yielding into a box is handled when lowering generators - Some(Terminator { kind: TerminatorKind::Yield { value, .. }, .. }) => { - visitor.visit_operand(value, location); - } - Some(terminator) => { - visitor.visit_terminator(terminator, location); - } - None => {} - } + for (block, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() { + visitor.visit_basic_block_data(block, data); } visitor.patch.apply(body); diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index 91ecf3879229d..5b0d9900c0fb5 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -1182,8 +1182,6 @@ fn create_cases<'tcx>( transform: &TransformVisitor<'tcx>, operation: Operation, ) -> Vec<(usize, BasicBlock)> { - let tcx = transform.tcx; - let source_info = SourceInfo::outermost(body.span); transform @@ -1216,85 +1214,13 @@ fn create_cases<'tcx>( if operation == Operation::Resume { // Move the resume argument to the destination place of the `Yield` terminator let resume_arg = Local::new(2); // 0 = return, 1 = self - - // handle `box yield` properly - let box_place = if let [projection @ .., ProjectionElem::Deref] = - &**point.resume_arg.projection - { - let box_place = - Place::from(point.resume_arg.local).project_deeper(projection, tcx); - - let box_ty = box_place.ty(&body.local_decls, tcx).ty; - - if box_ty.is_box() { Some((box_place, box_ty)) } else { None } - } else { - None - }; - - if let Some((box_place, box_ty)) = box_place { - let unique_did = box_ty - .ty_adt_def() - .expect("expected Box to be an Adt") - .non_enum_variant() - .fields[0] - .did; - - let Some(nonnull_def) = tcx.type_of(unique_did).ty_adt_def() else { - span_bug!(tcx.def_span(unique_did), "expected Box to contain Unique") - }; - - let nonnull_did = nonnull_def.non_enum_variant().fields[0].did; - - let (unique_ty, nonnull_ty, ptr_ty) = - crate::elaborate_box_derefs::build_ptr_tys( - tcx, - box_ty.boxed_ty(), - unique_did, - nonnull_did, - ); - - let ptr_local = body.local_decls.push(LocalDecl::new(ptr_ty, body.span)); - - statements.push(Statement { - source_info, - kind: StatementKind::StorageLive(ptr_local), - }); - - statements.push(Statement { - source_info, - kind: StatementKind::Assign(Box::new(( - Place::from(ptr_local), - Rvalue::Use(Operand::Copy(box_place.project_deeper( - &crate::elaborate_box_derefs::build_projection( - unique_ty, nonnull_ty, ptr_ty, - ), - tcx, - ))), - ))), - }); - - statements.push(Statement { - source_info, - kind: StatementKind::Assign(Box::new(( - Place::from(ptr_local) - .project_deeper(&[ProjectionElem::Deref], tcx), - Rvalue::Use(Operand::Move(resume_arg.into())), - ))), - }); - - statements.push(Statement { - source_info, - kind: StatementKind::StorageDead(ptr_local), - }); - } else { - statements.push(Statement { - source_info, - kind: StatementKind::Assign(Box::new(( - point.resume_arg, - Rvalue::Use(Operand::Move(resume_arg.into())), - ))), - }); - } + statements.push(Statement { + source_info, + kind: StatementKind::Assign(Box::new(( + point.resume_arg, + Rvalue::Use(Operand::Move(resume_arg.into())), + ))), + }); } // Then jump to the real target From 58eabb291d4e4e307e00869f5a253c5061482141 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Thu, 25 Aug 2022 00:00:00 +0000 Subject: [PATCH 09/13] Add method that applies DefUse effect --- .../rustc_mir_dataflow/src/impls/liveness.rs | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index 8f81b71e3e200..483c1e274aa78 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -122,11 +122,7 @@ where } fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) { - match DefUse::for_place(local.into(), context) { - Some(DefUse::Def) => self.0.kill(local), - Some(DefUse::Use) => self.0.gen(local), - None => {} - } + DefUse::apply(self.0, local.into(), context); } } @@ -137,20 +133,12 @@ where T: GenKill, { fn visit_place(&mut self, place: &mir::Place<'tcx>, context: PlaceContext, location: Location) { - match DefUse::for_place(*place, context) { - Some(DefUse::Def) => self.0.kill(place.local), - Some(DefUse::Use) => self.0.gen(place.local), - None => {} - } + DefUse::apply(self.0, *place, context); self.visit_projection(place.as_ref(), context, location); } fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) { - match DefUse::for_place(local.into(), context) { - Some(DefUse::Def) => self.0.kill(local), - Some(DefUse::Use) => self.0.gen(local), - None => {} - } + DefUse::apply(self.0, local.into(), context); } } @@ -161,6 +149,14 @@ enum DefUse { } impl DefUse { + fn apply<'tcx>(trans: &mut impl GenKill, place: Place<'tcx>, context: PlaceContext) { + match DefUse::for_place(place, context) { + Some(DefUse::Def) => trans.kill(place.local), + Some(DefUse::Use) => trans.gen(place.local), + None => {} + } + } + fn for_place<'tcx>(place: Place<'tcx>, context: PlaceContext) -> Option { match context { PlaceContext::NonUse(_) => None, From 4394ea8b8230b21973ee0f7a58dbce7c531ef0c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Thu, 25 Aug 2022 00:00:00 +0000 Subject: [PATCH 10/13] Inline trivial `From for Place<'_>` impl --- compiler/rustc_middle/src/mir/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 7ab71f9009d04..9da9b4e91f647 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1531,6 +1531,7 @@ impl<'tcx> Place<'tcx> { } impl From for Place<'_> { + #[inline] fn from(local: Local) -> Self { Place { local, projection: List::empty() } } From bc3d7199e1dcb650ef17c7a5370665641819545d Mon Sep 17 00:00:00 2001 From: Trevor Spiteri Date: Thu, 25 Aug 2022 12:54:30 +0200 Subject: [PATCH 11/13] review --- library/core/src/lib.rs | 2 +- library/core/src/slice/mod.rs | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 3a03edfb6465b..4a4c33e36d37e 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -137,7 +137,6 @@ #![feature(const_size_of_val)] #![feature(const_slice_from_raw_parts_mut)] #![feature(const_slice_ptr_len)] -#![feature(const_slice_split_at_not_mut)] #![feature(const_str_from_utf8_unchecked_mut)] #![feature(const_swap)] #![feature(const_trait_impl)] @@ -150,6 +149,7 @@ #![feature(maybe_uninit_uninit_array)] #![feature(ptr_metadata)] #![feature(slice_ptr_get)] +#![feature(slice_split_at_unchecked)] #![feature(str_internals)] #![feature(utf16_extra)] #![feature(utf16_extra_const)] diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 2336ad9cae303..5bbbd7cf5126c 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1624,10 +1624,14 @@ impl [T] { /// } /// ``` #[unstable(feature = "slice_split_at_unchecked", reason = "new API", issue = "76014")] - #[rustc_const_unstable(feature = "const_slice_split_at_not_mut", issue = "none")] + #[rustc_const_unstable(feature = "slice_split_at_unchecked", issue = "76014")] #[inline] #[must_use] pub const unsafe fn split_at_unchecked(&self, mid: usize) -> (&[T], &[T]) { + // HACK: the const function `from_raw_parts` is used to make this + // function const; previously the implementation used + // `(self.get_unchecked(..mid), self.get_unchecked(mid..))` + let len = self.len(); let ptr = self.as_ptr(); From 45cc8cb3b9cf94e5e9dfa34f2e0ce7cc69f95d9a Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 25 Aug 2022 11:43:36 -0700 Subject: [PATCH 12/13] rustdoc: remove unused CSS for `.multi-column` As a sanity check, [this tool] can be used to run a CSS query across an HTML tree to detect if a selector ever matches (I use compiler-docs and std docs). This isn't good enough, because I also need to account for JavaScript, but this class is never mentioned in any of the JS files, either. According to [blame], this class was added when rustdoc was first written, and, as far as I can tell, was never actually used. [this tool]: https://gitlab.com/notriddle/html-scanner [blame]: https://github.com/rust-lang/rust/blame/4d45b0745ab227feb9000bc15713ade4b99241ea/src/librustdoc/html/static/css/rustdoc.css#L753-L761 --- src/librustdoc/html/static/css/rustdoc.css | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index b1fa5e7d86de6..6d8315340c973 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -754,16 +754,6 @@ pre, .rustdoc.source .example-wrap { padding: 0; } -.content .multi-column { - -moz-column-count: 5; - -moz-column-gap: 2.5em; - -webkit-column-count: 5; - -webkit-column-gap: 2.5em; - column-count: 5; - column-gap: 2.5em; -} -.content .multi-column li { width: 100%; display: inline-block; } - .content > .methods > .method { font-size: 1rem; position: relative; From 258d3672f0a99a766705e11890bcd59079edcc7e Mon Sep 17 00:00:00 2001 From: Ellen Arteca Date: Thu, 25 Aug 2022 20:19:18 +0000 Subject: [PATCH 13/13] Adding support for rustc_serialize encode and decode for Box and Vec that use a custom allocator --- compiler/rustc_serialize/src/lib.rs | 1 + compiler/rustc_serialize/src/serialize.rs | 26 +++++++++++++---------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs index 079d44bac685b..91f4cfaf5acaa 100644 --- a/compiler/rustc_serialize/src/lib.rs +++ b/compiler/rustc_serialize/src/lib.rs @@ -16,6 +16,7 @@ Core encoding and decoding interfaces. #![feature(maybe_uninit_slice)] #![feature(let_else)] #![feature(new_uninit)] +#![feature(allocator_api)] #![cfg_attr(test, feature(test))] #![allow(rustc::internal)] #![deny(rustc::untranslatable_diagnostic)] diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs index 9bd5550038fc6..751b209f11a3a 100644 --- a/compiler/rustc_serialize/src/serialize.rs +++ b/compiler/rustc_serialize/src/serialize.rs @@ -4,6 +4,7 @@ Core encoding and decoding interfaces. */ +use std::alloc::Allocator; use std::borrow::Cow; use std::cell::{Cell, RefCell}; use std::marker::PhantomData; @@ -229,9 +230,9 @@ impl Decodable for PhantomData { } } -impl> Decodable for Box<[T]> { - fn decode(d: &mut D) -> Box<[T]> { - let v: Vec = Decodable::decode(d); +impl> Decodable for Box<[T], A> { + fn decode(d: &mut D) -> Box<[T], A> { + let v: Vec = Decodable::decode(d); v.into_boxed_slice() } } @@ -264,12 +265,13 @@ impl> Encodable for Vec { } } -impl> Decodable for Vec { - default fn decode(d: &mut D) -> Vec { +impl, A: Allocator + Default> Decodable for Vec { + default fn decode(d: &mut D) -> Vec { let len = d.read_usize(); + let allocator = A::default(); // SAFETY: we set the capacity in advance, only write elements, and // only set the length at the end once the writing has succeeded. - let mut vec = Vec::with_capacity(len); + let mut vec = Vec::with_capacity_in(len, allocator); unsafe { let ptr: *mut T = vec.as_mut_ptr(); for i in 0..len { @@ -457,13 +459,15 @@ impl> Decodable for Arc { } } -impl> Encodable for Box { +impl, A: Allocator + Default> Encodable for Box { fn encode(&self, s: &mut S) { - (**self).encode(s); + (**self).encode(s) } } -impl> Decodable for Box { - fn decode(d: &mut D) -> Box { - Box::new(Decodable::decode(d)) + +impl> Decodable for Box { + fn decode(d: &mut D) -> Box { + let allocator = A::default(); + Box::new_in(Decodable::decode(d), allocator) } }