From: Dylan DPC Date: Wed, 26 Aug 2020 23:14:13 +0000 (+0200) Subject: Rollup merge of #75837 - GuillaumeGomez:fix-font-color-help-button, r=Cldfire X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=88c68cae4f6d2e12d54ff436eea36595454ccda8;hp=5041aeef3d4155ac28245419193280491552fd35;p=rust.git Rollup merge of #75837 - GuillaumeGomez:fix-font-color-help-button, r=Cldfire Fix font color for help button in ayu and dark themes A nice before/after: ![Screenshot from 2020-08-23 14-47-07](https://user-images.githubusercontent.com/3050060/90979230-0dd07400-e554-11ea-85f7-046dfca65e8e.png) ![Screenshot from 2020-08-23 14-47-03](https://user-images.githubusercontent.com/3050060/90979233-145eeb80-e554-11ea-8e63-1864c3f2699b.png) For the ayu theme, the change is very "light", the font color was already close to white, so I unified the color with the pictures of the other buttons: ![Screenshot from 2020-08-23 15-20-45](https://user-images.githubusercontent.com/3050060/90979281-5e47d180-e554-11ea-9993-8595057481ab.png) ![Screenshot from 2020-08-23 15-20-50](https://user-images.githubusercontent.com/3050060/90979279-5daf3b00-e554-11ea-8d39-beb57091aba7.png) --- diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a19cca9071f..f6f181612c9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -364,9 +364,6 @@ jobs: - name: x86_64-gnu-distcheck os: ubuntu-latest-xl env: {} - - name: x86_64-gnu-full-bootstrap - os: ubuntu-latest-xl - env: {} - name: x86_64-gnu-llvm-8 env: RUST_BACKTRACE: 1 diff --git a/.gitmodules b/.gitmodules index a327aaa8d5a..8f4d3768c21 100644 --- a/.gitmodules +++ b/.gitmodules @@ -37,7 +37,7 @@ [submodule "src/llvm-project"] path = src/llvm-project url = https://github.com/rust-lang/llvm-project.git - branch = rustc/10.0-2020-05-05 + branch = rustc/11.0-2020-08-20 [submodule "src/doc/embedded-book"] path = src/doc/embedded-book url = https://github.com/rust-embedded/book.git diff --git a/.mailmap b/.mailmap index 15ca403456a..cc7b2a677ba 100644 --- a/.mailmap +++ b/.mailmap @@ -176,8 +176,8 @@ Mark Sinclair =Mark Sinclair <=125axel125@gmail.com> Markus Westerlind Markus Martin Hafskjold Thoresen Matej Lach Matej Ľach -Mateusz Mikuła -Mateusz Mikuła +Mateusz Mikuła +Mateusz Mikuła Matt Brubeck Matthew Auld Matthew Kraai diff --git a/Cargo.lock b/Cargo.lock index f8fa2971b49..1bbae2cbd80 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -403,6 +403,17 @@ dependencies = [ "serde_json", ] +[[package]] +name = "cargo_metadata" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89fec17b16f1ac67908af82e47d0a90a7afd0e1827b181cd77504323d3263d35" +dependencies = [ + "semver 0.10.0", + "serde", + "serde_json", +] + [[package]] name = "cargotest2" version = "0.1.0" @@ -997,6 +1008,16 @@ dependencies = [ "yaml-rust 0.4.4", ] +[[package]] +name = "expect-test" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e383741ea1982866572109d1a8c807bd36aad91fca701489fdca56ef92b3b8" +dependencies = [ + "difference", + "once_cell", +] + [[package]] name = "failure" version = "0.1.8" @@ -3642,6 +3663,7 @@ dependencies = [ name = "rustc_lexer" version = "0.1.0" dependencies = [ + "expect-test", "unicode-xid", ] @@ -4680,7 +4702,7 @@ dependencies = [ name = "tidy" version = "0.1.0" dependencies = [ - "cargo_metadata 0.9.1", + "cargo_metadata 0.11.1", "lazy_static", "regex", "walkdir", diff --git a/library/alloc/benches/vec.rs b/library/alloc/benches/vec.rs index a3da9e80cd0..4e71eec03e5 100644 --- a/library/alloc/benches/vec.rs +++ b/library/alloc/benches/vec.rs @@ -213,7 +213,7 @@ fn bench_extend_1000_1000(b: &mut Bencher) { do_bench_extend(b, 1000, 1000) } -fn do_bench_push_all(b: &mut Bencher, dst_len: usize, src_len: usize) { +fn do_bench_extend_from_slice(b: &mut Bencher, dst_len: usize, src_len: usize) { let dst: Vec<_> = FromIterator::from_iter(0..dst_len); let src: Vec<_> = FromIterator::from_iter(dst_len..dst_len + src_len); @@ -228,87 +228,38 @@ fn do_bench_push_all(b: &mut Bencher, dst_len: usize, src_len: usize) { } #[bench] -fn bench_push_all_0000_0000(b: &mut Bencher) { - do_bench_push_all(b, 0, 0) +fn bench_extend_from_slice_0000_0000(b: &mut Bencher) { + do_bench_extend_from_slice(b, 0, 0) } #[bench] -fn bench_push_all_0000_0010(b: &mut Bencher) { - do_bench_push_all(b, 0, 10) +fn bench_extend_from_slice_0000_0010(b: &mut Bencher) { + do_bench_extend_from_slice(b, 0, 10) } #[bench] -fn bench_push_all_0000_0100(b: &mut Bencher) { - do_bench_push_all(b, 0, 100) +fn bench_extend_from_slice_0000_0100(b: &mut Bencher) { + do_bench_extend_from_slice(b, 0, 100) } #[bench] -fn bench_push_all_0000_1000(b: &mut Bencher) { - do_bench_push_all(b, 0, 1000) +fn bench_extend_from_slice_0000_1000(b: &mut Bencher) { + do_bench_extend_from_slice(b, 0, 1000) } #[bench] -fn bench_push_all_0010_0010(b: &mut Bencher) { - do_bench_push_all(b, 10, 10) +fn bench_extend_from_slice_0010_0010(b: &mut Bencher) { + do_bench_extend_from_slice(b, 10, 10) } #[bench] -fn bench_push_all_0100_0100(b: &mut Bencher) { - do_bench_push_all(b, 100, 100) +fn bench_extend_from_slice_0100_0100(b: &mut Bencher) { + do_bench_extend_from_slice(b, 100, 100) } #[bench] -fn bench_push_all_1000_1000(b: &mut Bencher) { - do_bench_push_all(b, 1000, 1000) -} - -fn do_bench_push_all_move(b: &mut Bencher, dst_len: usize, src_len: usize) { - let dst: Vec<_> = FromIterator::from_iter(0..dst_len); - let src: Vec<_> = FromIterator::from_iter(dst_len..dst_len + src_len); - - b.bytes = src_len as u64; - - b.iter(|| { - let mut dst = dst.clone(); - dst.extend(src.clone()); - assert_eq!(dst.len(), dst_len + src_len); - assert!(dst.iter().enumerate().all(|(i, x)| i == *x)); - }); -} - -#[bench] -fn bench_push_all_move_0000_0000(b: &mut Bencher) { - do_bench_push_all_move(b, 0, 0) -} - -#[bench] -fn bench_push_all_move_0000_0010(b: &mut Bencher) { - do_bench_push_all_move(b, 0, 10) -} - -#[bench] -fn bench_push_all_move_0000_0100(b: &mut Bencher) { - do_bench_push_all_move(b, 0, 100) -} - -#[bench] -fn bench_push_all_move_0000_1000(b: &mut Bencher) { - do_bench_push_all_move(b, 0, 1000) -} - -#[bench] -fn bench_push_all_move_0010_0010(b: &mut Bencher) { - do_bench_push_all_move(b, 10, 10) -} - -#[bench] -fn bench_push_all_move_0100_0100(b: &mut Bencher) { - do_bench_push_all_move(b, 100, 100) -} - -#[bench] -fn bench_push_all_move_1000_1000(b: &mut Bencher) { - do_bench_push_all_move(b, 1000, 1000) +fn bench_extend_from_slice_1000_1000(b: &mut Bencher) { + do_bench_extend_from_slice(b, 1000, 1000) } fn do_bench_clone(b: &mut Bencher, src_len: usize) { diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index fa5eb1823f1..5f09f8def4d 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -3,7 +3,7 @@ #![stable(feature = "alloc_module", since = "1.28.0")] use core::intrinsics::{self, min_align_of_val, size_of_val}; -use core::ptr::{NonNull, Unique}; +use core::ptr::{self, NonNull, Unique}; #[stable(feature = "alloc_module", since = "1.28.0")] #[doc(inline)] @@ -36,8 +36,6 @@ /// /// Note: while this type is unstable, the functionality it provides can be /// accessed through the [free functions in `alloc`](index.html#functions). -/// -/// [`AllocRef`]: trait.AllocRef.html #[unstable(feature = "allocator_api", issue = "32838")] #[derive(Copy, Clone, Default, Debug)] pub struct Global; @@ -55,10 +53,6 @@ /// /// See [`GlobalAlloc::alloc`]. /// -/// [`Global`]: struct.Global.html -/// [`AllocRef`]: trait.AllocRef.html -/// [`GlobalAlloc::alloc`]: trait.GlobalAlloc.html#tymethod.alloc -/// /// # Examples /// /// ``` @@ -92,10 +86,6 @@ pub unsafe fn alloc(layout: Layout) -> *mut u8 { /// # Safety /// /// See [`GlobalAlloc::dealloc`]. -/// -/// [`Global`]: struct.Global.html -/// [`AllocRef`]: trait.AllocRef.html -/// [`GlobalAlloc::dealloc`]: trait.GlobalAlloc.html#tymethod.dealloc #[stable(feature = "global_alloc", since = "1.28.0")] #[inline] pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) { @@ -114,10 +104,6 @@ pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) { /// # Safety /// /// See [`GlobalAlloc::realloc`]. -/// -/// [`Global`]: struct.Global.html -/// [`AllocRef`]: trait.AllocRef.html -/// [`GlobalAlloc::realloc`]: trait.GlobalAlloc.html#method.realloc #[stable(feature = "global_alloc", since = "1.28.0")] #[inline] pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { @@ -137,10 +123,6 @@ pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 /// /// See [`GlobalAlloc::alloc_zeroed`]. /// -/// [`Global`]: struct.Global.html -/// [`AllocRef`]: trait.AllocRef.html -/// [`GlobalAlloc::alloc_zeroed`]: trait.GlobalAlloc.html#method.alloc_zeroed -/// /// # Examples /// /// ``` @@ -180,36 +162,45 @@ fn alloc_impl(&mut self, layout: Layout, zeroed: bool) -> Result, unsafe fn grow_impl( &mut self, ptr: NonNull, - layout: Layout, - new_size: usize, + old_layout: Layout, + new_layout: Layout, zeroed: bool, ) -> Result, AllocErr> { debug_assert!( - new_size >= layout.size(), - "`new_size` must be greater than or equal to `layout.size()`" + new_layout.size() >= old_layout.size(), + "`new_layout.size()` must be greater than or equal to `old_layout.size()`" ); - match layout.size() { - // SAFETY: the caller must ensure that the `new_size` does not overflow. - // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid for a Layout. - 0 => unsafe { - let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); - self.alloc_impl(new_layout, zeroed) - }, + match old_layout.size() { + 0 => self.alloc_impl(new_layout, zeroed), // SAFETY: `new_size` is non-zero as `old_size` is greater than or equal to `new_size` // as required by safety conditions. Other conditions must be upheld by the caller - old_size => unsafe { - // `realloc` probably checks for `new_size >= size` or something similar. - intrinsics::assume(new_size >= layout.size()); + old_size if old_layout.align() == new_layout.align() => unsafe { + let new_size = new_layout.size(); - let raw_ptr = realloc(ptr.as_ptr(), layout, new_size); + // `realloc` probably checks for `new_size >= old_layout.size()` or something similar. + intrinsics::assume(new_size >= old_layout.size()); + + let raw_ptr = realloc(ptr.as_ptr(), old_layout, new_size); let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?; if zeroed { raw_ptr.add(old_size).write_bytes(0, new_size - old_size); } Ok(NonNull::slice_from_raw_parts(ptr, new_size)) }, + + // SAFETY: because `new_layout.size()` must be greater than or equal to `old_size`, + // both the old and new memory allocation are valid for reads and writes for `old_size` + // bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap + // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract + // for `dealloc` must be upheld by the caller. + old_size => unsafe { + let new_ptr = self.alloc_impl(new_layout, zeroed)?; + ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_size); + self.dealloc(ptr, old_layout); + Ok(new_ptr) + }, } } } @@ -239,52 +230,64 @@ unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { unsafe fn grow( &mut self, ptr: NonNull, - layout: Layout, - new_size: usize, + old_layout: Layout, + new_layout: Layout, ) -> Result, AllocErr> { // SAFETY: all conditions must be upheld by the caller - unsafe { self.grow_impl(ptr, layout, new_size, false) } + unsafe { self.grow_impl(ptr, old_layout, new_layout, false) } } #[inline] unsafe fn grow_zeroed( &mut self, ptr: NonNull, - layout: Layout, - new_size: usize, + old_layout: Layout, + new_layout: Layout, ) -> Result, AllocErr> { // SAFETY: all conditions must be upheld by the caller - unsafe { self.grow_impl(ptr, layout, new_size, true) } + unsafe { self.grow_impl(ptr, old_layout, new_layout, true) } } #[inline] unsafe fn shrink( &mut self, ptr: NonNull, - layout: Layout, - new_size: usize, + old_layout: Layout, + new_layout: Layout, ) -> Result, AllocErr> { debug_assert!( - new_size <= layout.size(), - "`new_size` must be smaller than or equal to `layout.size()`" + new_layout.size() <= old_layout.size(), + "`new_layout.size()` must be smaller than or equal to `old_layout.size()`" ); - match new_size { + match new_layout.size() { // SAFETY: conditions must be upheld by the caller 0 => unsafe { - self.dealloc(ptr, layout); - Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)) + self.dealloc(ptr, old_layout); + Ok(NonNull::slice_from_raw_parts(new_layout.dangling(), 0)) }, // SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller - new_size => unsafe { - // `realloc` probably checks for `new_size <= size` or something similar. - intrinsics::assume(new_size <= layout.size()); + new_size if old_layout.align() == new_layout.align() => unsafe { + // `realloc` probably checks for `new_size <= old_layout.size()` or something similar. + intrinsics::assume(new_size <= old_layout.size()); - let raw_ptr = realloc(ptr.as_ptr(), layout, new_size); + let raw_ptr = realloc(ptr.as_ptr(), old_layout, new_size); let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?; Ok(NonNull::slice_from_raw_parts(ptr, new_size)) }, + + // SAFETY: because `new_size` must be smaller than or equal to `old_layout.size()`, + // both the old and new memory allocation are valid for reads and writes for `new_size` + // bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap + // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract + // for `dealloc` must be upheld by the caller. + new_size => unsafe { + let new_ptr = self.alloc(new_layout)?; + ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), new_size); + self.dealloc(ptr, old_layout); + Ok(new_ptr) + }, } } } @@ -297,7 +300,7 @@ unsafe fn shrink( unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { let layout = unsafe { Layout::from_size_align_unchecked(size, align) }; match Global.alloc(layout) { - Ok(ptr) => ptr.as_non_null_ptr().as_ptr(), + Ok(ptr) => ptr.as_mut_ptr(), Err(_) => handle_alloc_error(layout), } } diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 5e304beff78..05211e2037b 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -118,14 +118,13 @@ //! described in [rust-lang/unsafe-code-guidelines#198][ucg#198]. //! //! [ucg#198]: https://github.com/rust-lang/unsafe-code-guidelines/issues/198 -//! [dereferencing]: ../../std/ops/trait.Deref.html -//! [`Box`]: struct.Box.html -//! [`Box`]: struct.Box.html -//! [`Box::::from_raw(value)`]: struct.Box.html#method.from_raw -//! [`Box::::into_raw`]: struct.Box.html#method.into_raw -//! [`Global`]: ../alloc/struct.Global.html -//! [`Layout`]: ../alloc/struct.Layout.html -//! [`Layout::for_value(&*value)`]: ../alloc/struct.Layout.html#method.for_value +//! [dereferencing]: core::ops::Deref +//! [`Box`]: Box +//! [`Box::::from_raw(value)`]: Box::from_raw +//! [`Box::::into_raw`]: Box::into_raw +//! [`Global`]: crate::alloc::Global +//! [`Layout`]: crate::alloc::Layout +//! [`Layout::for_value(&*value)`]: crate::alloc::Layout::for_value #![stable(feature = "rust1", since = "1.0.0")] @@ -240,7 +239,6 @@ pub fn pin(x: T) -> Pin> { /// Converts a `Box` into a `Box<[T]>` /// /// This conversion does not allocate on the heap and happens in place. - /// #[unstable(feature = "box_into_boxed_slice", issue = "71582")] pub fn into_boxed_slice(boxed: Box) -> Box<[T]> { // *mut T and *mut [T; 1] have the same size and alignment @@ -273,6 +271,29 @@ impl Box<[T]> { pub fn new_uninit_slice(len: usize) -> Box<[mem::MaybeUninit]> { unsafe { RawVec::with_capacity(len).into_box(len) } } + + /// Constructs a new boxed slice with uninitialized contents, with the memory + /// being filled with `0` bytes. + /// + /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and incorrect usage + /// of this method. + /// + /// # Examples + /// + /// ``` + /// #![feature(new_uninit)] + /// + /// let values = Box::<[u32]>::new_zeroed_slice(3); + /// let values = unsafe { values.assume_init() }; + /// + /// assert_eq!(*values, [0, 0, 0]) + /// ``` + /// + /// [zeroed]: ../../std/mem/union.MaybeUninit.html#method.zeroed + #[unstable(feature = "new_uninit", issue = "63291")] + pub fn new_zeroed_slice(len: usize) -> Box<[mem::MaybeUninit]> { + unsafe { RawVec::with_capacity_zeroed(len).into_box(len) } + } } impl Box> { @@ -386,9 +407,8 @@ impl Box { /// } /// ``` /// - /// [memory layout]: index.html#memory-layout - /// [`Layout`]: ../alloc/struct.Layout.html - /// [`Box::into_raw`]: struct.Box.html#method.into_raw + /// [memory layout]: self#memory-layout + /// [`Layout`]: crate::Layout #[stable(feature = "box_raw", since = "1.4.0")] #[inline] pub unsafe fn from_raw(raw: *mut T) -> Self { @@ -433,8 +453,7 @@ pub unsafe fn from_raw(raw: *mut T) -> Self { /// } /// ``` /// - /// [memory layout]: index.html#memory-layout - /// [`Box::from_raw`]: struct.Box.html#method.from_raw + /// [memory layout]: self#memory-layout #[stable(feature = "box_raw", since = "1.4.0")] #[inline] pub fn into_raw(b: Box) -> *mut T { @@ -478,8 +497,6 @@ pub fn into_unique(b: Box) -> Unique { /// to call it as `Box::leak(b)` instead of `b.leak()`. This /// is so that there is no conflict with a method on the inner type. /// - /// [`Box::from_raw`]: struct.Box.html#method.from_raw - /// /// # Examples /// /// Simple usage: diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs index 8398cfa3bd3..477a598ff5b 100644 --- a/library/alloc/src/collections/binary_heap.rs +++ b/library/alloc/src/collections/binary_heap.rs @@ -12,9 +12,9 @@ //! to solve the [shortest path problem][sssp] on a [directed graph][dir_graph]. //! It shows how to use [`BinaryHeap`] with custom types. //! -//! [dijkstra]: http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm -//! [sssp]: http://en.wikipedia.org/wiki/Shortest_path_problem -//! [dir_graph]: http://en.wikipedia.org/wiki/Directed_graph +//! [dijkstra]: https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm +//! [sssp]: https://en.wikipedia.org/wiki/Shortest_path_problem +//! [dir_graph]: https://en.wikipedia.org/wiki/Directed_graph //! [`BinaryHeap`]: struct.BinaryHeap.html //! //! ``` diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index 02a746f0e24..5390b57a1d9 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -7,8 +7,8 @@ //! array-based containers are generally faster, //! more memory efficient, and make better use of CPU cache. //! -//! [`Vec`]: ../../vec/struct.Vec.html -//! [`VecDeque`]: ../vec_deque/struct.VecDeque.html +//! [`Vec`]: crate::vec::Vec +//! [`VecDeque`]: super::vec_deque::VecDeque #![stable(feature = "rust1", since = "1.0.0")] @@ -50,11 +50,8 @@ struct Node { /// An iterator over the elements of a `LinkedList`. /// -/// This `struct` is created by the [`iter`] method on [`LinkedList`]. See its +/// This `struct` is created by [`LinkedList::iter()`]. See its /// documentation for more. -/// -/// [`iter`]: struct.LinkedList.html#method.iter -/// [`LinkedList`]: struct.LinkedList.html #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, T: 'a> { head: Option>>, @@ -80,11 +77,8 @@ fn clone(&self) -> Self { /// A mutable iterator over the elements of a `LinkedList`. /// -/// This `struct` is created by the [`iter_mut`] method on [`LinkedList`]. See its +/// This `struct` is created by [`LinkedList::iter_mut()`]. See its /// documentation for more. -/// -/// [`iter_mut`]: struct.LinkedList.html#method.iter_mut -/// [`LinkedList`]: struct.LinkedList.html #[stable(feature = "rust1", since = "1.0.0")] pub struct IterMut<'a, T: 'a> { // We do *not* exclusively own the entire list here, references to node's `element` @@ -109,7 +103,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// (provided by the `IntoIterator` trait). See its documentation for more. /// /// [`into_iter`]: struct.LinkedList.html#method.into_iter -/// [`LinkedList`]: struct.LinkedList.html #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs index a0b151a4496..a886e17f5a9 100644 --- a/library/alloc/src/fmt.rs +++ b/library/alloc/src/fmt.rs @@ -501,31 +501,23 @@ //! it would internally pass around this structure until it has been determined //! where output should go to. //! -//! [`usize`]: ../../std/primitive.usize.html -//! [`isize`]: ../../std/primitive.isize.html -//! [`i8`]: ../../std/primitive.i8.html -//! [`Display`]: trait.Display.html -//! [`Binary`]: trait.Binary.html -//! [`fmt::Result`]: type.Result.html -//! [`Result`]: ../../std/result/enum.Result.html -//! [`std::fmt::Error`]: struct.Error.html -//! [`Formatter`]: struct.Formatter.html -//! [`write!`]: ../../std/macro.write.html -//! [`Debug`]: trait.Debug.html -//! [`format!`]: ../../std/macro.format.html -//! [`to_string`]: ../../std/string/trait.ToString.html -//! [`writeln!`]: ../../std/macro.writeln.html +//! [`fmt::Result`]: Result +//! [`Result`]: core::result::Result +//! [`std::fmt::Error`]: Error +//! [`write!`]: core::write +//! [`write`]: core::write +//! [`format!`]: crate::format +//! [`to_string`]: crate::string::ToString +//! [`writeln!`]: core::writeln //! [`write_fmt`]: ../../std/io/trait.Write.html#method.write_fmt //! [`std::io::Write`]: ../../std/io/trait.Write.html //! [`print!`]: ../../std/macro.print.html //! [`println!`]: ../../std/macro.println.html //! [`eprint!`]: ../../std/macro.eprint.html //! [`eprintln!`]: ../../std/macro.eprintln.html -//! [`write!`]: ../../std/macro.write.html -//! [`format_args!`]: ../../std/macro.format_args.html -//! [`fmt::Arguments`]: struct.Arguments.html -//! [`write`]: fn.write.html -//! [`format`]: fn.format.html +//! [`format_args!`]: core::format_args +//! [`fmt::Arguments`]: Arguments +//! [`format`]: crate::format #![stable(feature = "rust1", since = "1.0.0")] @@ -576,9 +568,8 @@ /// assert_eq!(s, "Hello, world!"); /// ``` /// -/// [`Arguments`]: struct.Arguments.html -/// [`format_args!`]: ../../std/macro.format_args.html -/// [`format!`]: ../../std/macro.format.html +/// [`format_args!`]: core::format_args +/// [`format!`]: crate::format #[stable(feature = "rust1", since = "1.0.0")] pub fn format(args: Arguments<'_>) -> string::String { let capacity = args.estimated_capacity(); diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 2d25941a524..755a21934f0 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -50,11 +50,11 @@ //! The [`alloc`](alloc/index.html) module defines the low-level interface to the //! default global allocator. It is not compatible with the libc allocator API. //! -//! [`Arc`]: sync/index.html -//! [`Box`]: boxed/index.html -//! [`Cell`]: ../core/cell/index.html -//! [`Rc`]: rc/index.html -//! [`RefCell`]: ../core/cell/index.html +//! [`Arc`]: sync +//! [`Box`]: boxed +//! [`Cell`]: core::cell +//! [`Rc`]: rc +//! [`RefCell`]: core::cell #![allow(unused_attributes)] #![stable(feature = "alloc", since = "1.36.0")] @@ -113,7 +113,6 @@ #![feature(or_patterns)] #![feature(pattern)] #![feature(ptr_internals)] -#![feature(ptr_offset_from)] #![feature(raw_ref_op)] #![feature(rustc_attrs)] #![feature(receiver_trait)] @@ -136,7 +135,6 @@ #![feature(alloc_layout_extra)] #![feature(try_trait)] #![feature(associated_type_bounds)] - // Allow testing this library #[cfg(test)] diff --git a/library/alloc/src/macros.rs b/library/alloc/src/macros.rs index e163a166b49..2f744618d69 100644 --- a/library/alloc/src/macros.rs +++ b/library/alloc/src/macros.rs @@ -29,8 +29,7 @@ /// to the same boxed integer value, not five references pointing to independently /// boxed integers. /// -/// [`Vec`]: ../std/vec/struct.Vec.html -/// [`Clone`]: ../std/clone/trait.Clone.html +/// [`Vec`]: crate::vec::Vec #[cfg(not(test))] #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] @@ -81,11 +80,11 @@ macro_rules! vec { /// To convert a single value to a string, use the [`to_string`] method. This /// will use the [`Display`] formatting trait. /// -/// [fmt]: ../std/fmt/index.html +/// [fmt]: core::fmt /// [`print!`]: ../std/macro.print.html -/// [`write!`]: ../std/macro.write.html -/// [`to_string`]: ../std/string/trait.ToString.html -/// [`Display`]: ../std/fmt/trait.Display.html +/// [`write!`]: core::write +/// [`to_string`]: crate::string::ToString +/// [`Display`]: core::fmt::Display /// /// # Panics /// diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index 247b636c808..05382d0b559 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -3,6 +3,7 @@ use core::alloc::LayoutErr; use core::cmp; +use core::intrinsics; use core::mem::{self, ManuallyDrop, MaybeUninit}; use core::ops::Drop; use core::ptr::{NonNull, Unique}; @@ -465,8 +466,9 @@ fn shrink(&mut self, amount: usize) -> Result<(), TryReserveError> { let new_size = amount * mem::size_of::(); let ptr = unsafe { - self.alloc.shrink(ptr, layout, new_size).map_err(|_| TryReserveError::AllocError { - layout: Layout::from_size_align_unchecked(new_size, layout.align()), + let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); + self.alloc.shrink(ptr, layout, new_layout).map_err(|_| TryReserveError::AllocError { + layout: new_layout, non_exhaustive: (), })? }; @@ -494,13 +496,16 @@ fn finish_grow( let memory = if let Some((ptr, old_layout)) = current_memory { debug_assert_eq!(old_layout.align(), new_layout.align()); - unsafe { alloc.grow(ptr, old_layout, new_layout.size()) } + unsafe { + // The allocator checks for alignment equality + intrinsics::assume(old_layout.align() == new_layout.align()); + alloc.grow(ptr, old_layout, new_layout) + } } else { alloc.alloc(new_layout) - } - .map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })?; + }; - Ok(memory) + memory.map_err(|_| AllocError { layout: new_layout, non_exhaustive: () }) } unsafe impl<#[may_dangle] T, A: AllocRef> Drop for RawVec { diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index d0a47ccea0a..1046397f4be 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -214,18 +214,15 @@ //! } //! ``` //! -//! [`Rc`]: struct.Rc.html -//! [`Weak`]: struct.Weak.html -//! [clone]: ../../std/clone/trait.Clone.html#tymethod.clone -//! [`Cell`]: ../../std/cell/struct.Cell.html -//! [`RefCell`]: ../../std/cell/struct.RefCell.html -//! [send]: ../../std/marker/trait.Send.html +//! [clone]: Clone::clone +//! [`Cell`]: core::cell::Cell +//! [`RefCell`]: core::cell::RefCell +//! [send]: core::marker::Send //! [arc]: ../../std/sync/struct.Arc.html -//! [`Deref`]: ../../std/ops/trait.Deref.html -//! [downgrade]: struct.Rc.html#method.downgrade -//! [upgrade]: struct.Weak.html#method.upgrade -//! [`None`]: ../../std/option/enum.Option.html#variant.None -//! [mutability]: ../../std/cell/index.html#introducing-mutability-inside-of-something-immutable +//! [`Deref`]: core::ops::Deref +//! [downgrade]: Rc::downgrade +//! [upgrade]: Weak::upgrade +//! [mutability]: core::cell#introducing-mutability-inside-of-something-immutable #![stable(feature = "rust1", since = "1.0.0")] @@ -250,7 +247,7 @@ use core::ptr::{self, NonNull}; use core::slice::from_raw_parts_mut; -use crate::alloc::{box_free, handle_alloc_error, AllocRef, Global, Layout}; +use crate::alloc::{box_free, handle_alloc_error, AllocErr, AllocRef, Global, Layout}; use crate::borrow::{Cow, ToOwned}; use crate::string::String; use crate::vec::Vec; @@ -352,9 +349,11 @@ pub fn new(value: T) -> Rc { #[unstable(feature = "new_uninit", issue = "63291")] pub fn new_uninit() -> Rc> { unsafe { - Rc::from_ptr(Rc::allocate_for_layout(Layout::new::(), |mem| { - mem as *mut RcBox> - })) + Rc::from_ptr(Rc::allocate_for_layout( + Layout::new::(), + |layout| Global.alloc(layout), + |mem| mem as *mut RcBox>, + )) } } @@ -381,9 +380,11 @@ pub fn new_uninit() -> Rc> { #[unstable(feature = "new_uninit", issue = "63291")] pub fn new_zeroed() -> Rc> { unsafe { - let mut uninit = Self::new_uninit(); - ptr::write_bytes::(Rc::get_mut_unchecked(&mut uninit).as_mut_ptr(), 0, 1); - uninit + Rc::from_ptr(Rc::allocate_for_layout( + Layout::new::(), + |layout| Global.alloc_zeroed(layout), + |mem| mem as *mut RcBox>, + )) } } @@ -396,13 +397,11 @@ pub fn pin(value: T) -> Pin> { /// Returns the inner value, if the `Rc` has exactly one strong reference. /// - /// Otherwise, an [`Err`][result] is returned with the same `Rc` that was + /// Otherwise, an [`Err`] is returned with the same `Rc` that was /// passed in. /// /// This will succeed even if there are outstanding weak references. /// - /// [result]: ../../std/result/enum.Result.html - /// /// # Examples /// /// ``` @@ -465,6 +464,40 @@ impl Rc<[T]> { pub fn new_uninit_slice(len: usize) -> Rc<[mem::MaybeUninit]> { unsafe { Rc::from_ptr(Rc::allocate_for_slice(len)) } } + + /// Constructs a new reference-counted slice with uninitialized contents, with the memory being + /// filled with `0` bytes. + /// + /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and + /// incorrect usage of this method. + /// + /// # Examples + /// + /// ``` + /// #![feature(new_uninit)] + /// + /// use std::rc::Rc; + /// + /// let values = Rc::<[u32]>::new_zeroed_slice(3); + /// let values = unsafe { values.assume_init() }; + /// + /// assert_eq!(*values, [0, 0, 0]) + /// ``` + /// + /// [zeroed]: ../../std/mem/union.MaybeUninit.html#method.zeroed + #[unstable(feature = "new_uninit", issue = "63291")] + pub fn new_zeroed_slice(len: usize) -> Rc<[mem::MaybeUninit]> { + unsafe { + Rc::from_ptr(Rc::allocate_for_layout( + Layout::array::(len).unwrap(), + |layout| Global.alloc_zeroed(layout), + |mem| { + ptr::slice_from_raw_parts_mut(mem as *mut T, len) + as *mut RcBox<[mem::MaybeUninit]> + }, + )) + } + } } impl Rc> { @@ -553,7 +586,7 @@ impl Rc { /// To avoid a memory leak the pointer must be converted back to an `Rc` using /// [`Rc::from_raw`][from_raw]. /// - /// [from_raw]: struct.Rc.html#method.from_raw + /// [from_raw]: Rc::from_raw /// /// # Examples /// @@ -613,8 +646,8 @@ pub fn as_ptr(this: &Self) -> *const T { /// This function is unsafe because improper use may lead to memory unsafety, /// even if the returned `Rc` is never accessed. /// - /// [into_raw]: struct.Rc.html#method.into_raw - /// [transmute]: ../../std/mem/fn.transmute.html + /// [into_raw]: Rc::into_raw + /// [transmute]: core::mem::transmute /// /// # Examples /// @@ -645,9 +678,7 @@ pub unsafe fn from_raw(ptr: *const T) -> Self { unsafe { Self::from_ptr(rc_ptr) } } - /// Creates a new [`Weak`][weak] pointer to this allocation. - /// - /// [weak]: struct.Weak.html + /// Creates a new [`Weak`] pointer to this allocation. /// /// # Examples /// @@ -666,9 +697,7 @@ pub fn downgrade(this: &Self) -> Weak { Weak { ptr: this.ptr } } - /// Gets the number of [`Weak`][weak] pointers to this allocation. - /// - /// [weak]: struct.Weak.html + /// Gets the number of [`Weak`] pointers to this allocation. /// /// # Examples /// @@ -704,17 +733,15 @@ pub fn strong_count(this: &Self) -> usize { this.strong() } - /// Returns `true` if there are no other `Rc` or [`Weak`][weak] pointers to + /// Returns `true` if there are no other `Rc` or [`Weak`] pointers to /// this allocation. - /// - /// [weak]: struct.Weak.html #[inline] fn is_unique(this: &Self) -> bool { Rc::weak_count(this) == 0 && Rc::strong_count(this) == 1 } /// Returns a mutable reference into the given `Rc`, if there are - /// no other `Rc` or [`Weak`][weak] pointers to the same allocation. + /// no other `Rc` or [`Weak`] pointers to the same allocation. /// /// Returns [`None`] otherwise, because it is not safe to /// mutate a shared value. @@ -722,10 +749,8 @@ fn is_unique(this: &Self) -> bool { /// See also [`make_mut`][make_mut], which will [`clone`][clone] /// the inner value when there are other pointers. /// - /// [weak]: struct.Weak.html - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// [make_mut]: struct.Rc.html#method.make_mut - /// [clone]: ../../std/clone/trait.Clone.html#tymethod.clone + /// [make_mut]: Rc::make_mut + /// [clone]: Clone::clone /// /// # Examples /// @@ -750,7 +775,7 @@ pub fn get_mut(this: &mut Self) -> Option<&mut T> { /// /// See also [`get_mut`], which is safe and does appropriate checks. /// - /// [`get_mut`]: struct.Rc.html#method.get_mut + /// [`get_mut`]: Rc::get_mut /// /// # Safety /// @@ -796,7 +821,7 @@ pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T { /// assert!(!Rc::ptr_eq(&five, &other_five)); /// ``` /// - /// [`ptr::eq`]: ../../std/ptr/fn.eq.html + /// [`ptr::eq`]: core::ptr::eq pub fn ptr_eq(this: &Self, other: &Self) -> bool { this.ptr.as_ptr() == other.ptr.as_ptr() } @@ -814,9 +839,8 @@ impl Rc { /// /// See also [`get_mut`], which will fail rather than cloning. /// - /// [`Weak`]: struct.Weak.html - /// [`clone`]: ../../std/clone/trait.Clone.html#tymethod.clone - /// [`get_mut`]: struct.Rc.html#method.get_mut + /// [`clone`]: Clone::clone + /// [`get_mut`]: Rc::get_mut /// /// # Examples /// @@ -919,6 +943,7 @@ impl Rc { /// and must return back a (potentially fat)-pointer for the `RcBox`. unsafe fn allocate_for_layout( value_layout: Layout, + allocate: impl FnOnce(Layout) -> Result, AllocErr>, mem_to_rcbox: impl FnOnce(*mut u8) -> *mut RcBox, ) -> *mut RcBox { // Calculate layout using the given value layout. @@ -928,7 +953,7 @@ unsafe fn allocate_for_layout( let layout = Layout::new::>().extend(value_layout).unwrap().0.pad_to_align(); // Allocate for the layout. - let ptr = Global.alloc(layout).unwrap_or_else(|_| handle_alloc_error(layout)); + let ptr = allocate(layout).unwrap_or_else(|_| handle_alloc_error(layout)); // Initialize the RcBox let inner = mem_to_rcbox(ptr.as_non_null_ptr().as_ptr()); @@ -946,9 +971,11 @@ unsafe fn allocate_for_layout( unsafe fn allocate_for_ptr(ptr: *const T) -> *mut RcBox { // Allocate for the `RcBox` using the given value. unsafe { - Self::allocate_for_layout(Layout::for_value(&*ptr), |mem| { - set_data_ptr(ptr as *mut T, mem) as *mut RcBox - }) + Self::allocate_for_layout( + Layout::for_value(&*ptr), + |layout| Global.alloc(layout), + |mem| set_data_ptr(ptr as *mut T, mem) as *mut RcBox, + ) } } @@ -979,9 +1006,11 @@ impl Rc<[T]> { /// Allocates an `RcBox<[T]>` with the given length. unsafe fn allocate_for_slice(len: usize) -> *mut RcBox<[T]> { unsafe { - Self::allocate_for_layout(Layout::array::(len).unwrap(), |mem| { - ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut RcBox<[T]> - }) + Self::allocate_for_layout( + Layout::array::(len).unwrap(), + |layout| Global.alloc(layout), + |mem| ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut RcBox<[T]>, + ) } } } @@ -1117,8 +1146,6 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc { /// drop(foo); // Doesn't print anything /// drop(foo2); // Prints "dropped!" /// ``` - /// - /// [`Weak`]: ../../std/rc/struct.Weak.html fn drop(&mut self) { unsafe { self.dec_strong(); @@ -1600,11 +1627,7 @@ fn to_rc_slice(self) -> Rc<[T]> { /// /// The typical way to obtain a `Weak` pointer is to call [`Rc::downgrade`]. /// -/// [`Rc`]: struct.Rc.html -/// [`Rc::downgrade`]: struct.Rc.html#method.downgrade -/// [`upgrade`]: struct.Weak.html#method.upgrade -/// [`Option`]: ../../std/option/enum.Option.html -/// [`None`]: ../../std/option/enum.Option.html#variant.None +/// [`upgrade`]: Weak::upgrade #[stable(feature = "rc_weak", since = "1.4.0")] pub struct Weak { // This is a `NonNull` to allow optimizing the size of this type in enums, @@ -1631,8 +1654,7 @@ impl Weak { /// Constructs a new `Weak`, without allocating any memory. /// Calling [`upgrade`] on the return value always gives [`None`]. /// - /// [`upgrade`]: #method.upgrade - /// [`None`]: ../../std/option/enum.Option.html + /// [`upgrade`]: Weak::upgrade /// /// # Examples /// @@ -1671,7 +1693,7 @@ pub fn new() -> Weak { /// // assert_eq!("hello", unsafe { &*weak.as_ptr() }); /// ``` /// - /// [`null`]: ../../std/ptr/fn.null.html + /// [`null`]: core::ptr::null #[stable(feature = "rc_as_ptr", since = "1.45.0")] pub fn as_ptr(&self) -> *const T { let ptr: *mut RcBox = NonNull::as_ptr(self.ptr); @@ -1713,8 +1735,8 @@ pub fn as_ptr(&self) -> *const T { /// assert_eq!(0, Rc::weak_count(&strong)); /// ``` /// - /// [`from_raw`]: struct.Weak.html#method.from_raw - /// [`as_ptr`]: struct.Weak.html#method.as_ptr + /// [`from_raw`]: Weak::from_raw + /// [`as_ptr`]: Weak::as_ptr #[stable(feature = "weak_into_raw", since = "1.45.0")] pub fn into_raw(self) -> *const T { let result = self.as_ptr(); @@ -1761,12 +1783,9 @@ pub fn into_raw(self) -> *const T { /// assert!(unsafe { Weak::from_raw(raw_2) }.upgrade().is_none()); /// ``` /// - /// [`into_raw`]: struct.Weak.html#method.into_raw - /// [`upgrade`]: struct.Weak.html#method.upgrade - /// [`Rc`]: struct.Rc.html - /// [`Weak`]: struct.Weak.html - /// [`new`]: struct.Weak.html#method.new - /// [`forget`]: ../../std/mem/fn.forget.html + /// [`into_raw`]: Weak::into_raw + /// [`upgrade`]: Weak::upgrade + /// [`new`]: Weak::new #[stable(feature = "weak_into_raw", since = "1.45.0")] pub unsafe fn from_raw(ptr: *const T) -> Self { if ptr.is_null() { @@ -1794,9 +1813,6 @@ impl Weak { /// /// Returns [`None`] if the inner value has since been dropped. /// - /// [`Rc`]: struct.Rc.html - /// [`None`]: ../../std/option/enum.Option.html - /// /// # Examples /// /// ``` @@ -1829,8 +1845,6 @@ pub fn upgrade(&self) -> Option> { /// Gets the number of strong (`Rc`) pointers pointing to this allocation. /// /// If `self` was created using [`Weak::new`], this will return 0. - /// - /// [`Weak::new`]: #method.new #[stable(feature = "weak_counts", since = "1.41.0")] pub fn strong_count(&self) -> usize { if let Some(inner) = self.inner() { inner.strong() } else { 0 } @@ -1899,7 +1913,7 @@ fn inner(&self) -> Option<&RcBox> { /// assert!(!first.ptr_eq(&third)); /// ``` /// - /// [`ptr::eq`]: ../../std/ptr/fn.eq.html + /// [`ptr::eq`]: core::ptr::eq #[inline] #[stable(feature = "weak_ptr_eq", since = "1.39.0")] pub fn ptr_eq(&self, other: &Self) -> bool { @@ -1981,8 +1995,8 @@ impl Default for Weak { /// Constructs a new `Weak`, allocating memory for `T` without initializing /// it. Calling [`upgrade`] on the return value always gives [`None`]. /// - /// [`None`]: ../../std/option/enum.Option.html - /// [`upgrade`]: ../../std/rc/struct.Weak.html#method.upgrade + /// [`None`]: Option + /// [`upgrade`]: Weak::upgrade /// /// # Examples /// @@ -2090,7 +2104,7 @@ fn as_ref(&self) -> &T { #[stable(feature = "pin", since = "1.33.0")] impl Unpin for Rc {} -/// Get the offset within an `ArcInner` for +/// Get the offset within an `RcBox` for /// a payload of type described by a pointer. /// /// # Safety diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index b791c775548..8ea2c6dc859 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -70,11 +70,7 @@ //! * Further methods that return iterators are [`.split`], [`.splitn`], //! [`.chunks`], [`.windows`] and more. //! -//! [`Clone`]: ../../std/clone/trait.Clone.html -//! [`Eq`]: ../../std/cmp/trait.Eq.html -//! [`Ord`]: ../../std/cmp/trait.Ord.html -//! [`Iter`]: struct.Iter.html -//! [`Hash`]: ../../std/hash/trait.Hash.html +//! [`Hash`]: core::hash::Hash //! [`.iter`]: ../../std/primitive.slice.html#method.iter //! [`.iter_mut`]: ../../std/primitive.slice.html#method.iter_mut //! [`.split`]: ../../std/primitive.slice.html#method.split @@ -560,7 +556,7 @@ impl [u8] { /// /// To uppercase the value in-place, use [`make_ascii_uppercase`]. /// - /// [`make_ascii_uppercase`]: #method.make_ascii_uppercase + /// [`make_ascii_uppercase`]: u8::make_ascii_uppercase #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] pub fn to_ascii_uppercase(&self) -> Vec { @@ -577,7 +573,7 @@ pub fn to_ascii_uppercase(&self) -> Vec { /// /// To lowercase the value in-place, use [`make_ascii_lowercase`]. /// - /// [`make_ascii_lowercase`]: #method.make_ascii_lowercase + /// [`make_ascii_lowercase`]: u8::make_ascii_lowercase #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] pub fn to_ascii_lowercase(&self) -> Vec { diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index d7d7b6bd157..05690e19d23 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -268,8 +268,8 @@ /// /// Here, there's no need to allocate more memory inside the loop. /// -/// [`str`]: type@str -/// [`&str`]: type@str +/// [`str`]: prim@str +/// [`&str`]: prim@str /// [`Deref`]: core::ops::Deref /// [`as_str()`]: String::as_str #[derive(PartialOrd, Eq, Ord)] @@ -296,7 +296,7 @@ pub struct String { /// /// [`Utf8Error`]: core::str::Utf8Error /// [`std::str`]: core::str -/// [`&str`]: str +/// [`&str`]: prim@str /// [`utf8_error`]: Self::utf8_error /// /// # Examples @@ -472,7 +472,7 @@ pub fn from_str(_: &str) -> String { /// /// [`from_utf8_unchecked`]: String::from_utf8_unchecked /// [`Vec`]: crate::vec::Vec - /// [`&str`]: str + /// [`&str`]: prim@str /// [`into_bytes`]: String::into_bytes #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -1576,6 +1576,8 @@ pub fn replace_range(&mut self, range: R, replace_with: &str) /// /// This will drop any excess capacity. /// + /// [`str`]: prim@str + /// /// # Examples /// /// Basic usage: @@ -1644,7 +1646,7 @@ pub fn into_bytes(self) -> Vec { /// on using it. /// /// [`std::str`]: core::str - /// [`&str`]: str + /// [`&str`]: prim@str /// /// # Examples /// diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index b3763303137..73d2fe74826 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -2,9 +2,7 @@ //! Thread-safe reference-counting pointers. //! -//! See the [`Arc`][arc] documentation for more details. -//! -//! [arc]: struct.Arc.html +//! See the [`Arc`][Arc] documentation for more details. use core::any::Any; use core::borrow; @@ -23,7 +21,7 @@ use core::sync::atomic; use core::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst}; -use crate::alloc::{box_free, handle_alloc_error, AllocRef, Global, Layout}; +use crate::alloc::{box_free, handle_alloc_error, AllocErr, AllocRef, Global, Layout}; use crate::borrow::{Cow, ToOwned}; use crate::boxed::Box; use crate::rc::is_dangling; @@ -100,21 +98,21 @@ macro_rules! acquire { /// ## Breaking cycles with `Weak` /// /// The [`downgrade`][downgrade] method can be used to create a non-owning -/// [`Weak`][weak] pointer. A [`Weak`][weak] pointer can be [`upgrade`][upgrade]d +/// [`Weak`] pointer. A [`Weak`] pointer can be [`upgrade`][upgrade]d /// to an `Arc`, but this will return [`None`] if the value stored in the allocation has /// already been dropped. In other words, `Weak` pointers do not keep the value /// inside the allocation alive; however, they *do* keep the allocation /// (the backing store for the value) alive. /// /// A cycle between `Arc` pointers will never be deallocated. For this reason, -/// [`Weak`][weak] is used to break cycles. For example, a tree could have -/// strong `Arc` pointers from parent nodes to children, and [`Weak`][weak] +/// [`Weak`] is used to break cycles. For example, a tree could have +/// strong `Arc` pointers from parent nodes to children, and [`Weak`] /// pointers from children back to their parents. /// /// # Cloning references /// /// Creating a new reference from an existing reference counted pointer is done using the -/// `Clone` trait implemented for [`Arc`][arc] and [`Weak`][weak]. +/// `Clone` trait implemented for [`Arc`][Arc] and [`Weak`][Weak]. /// /// ``` /// use std::sync::Arc; @@ -139,23 +137,20 @@ macro_rules! acquire { /// Arc::downgrade(&my_arc); /// ``` /// -/// [`Weak`][weak] does not auto-dereference to `T`, because the inner value may have +/// [`Weak`][Weak] does not auto-dereference to `T`, because the inner value may have /// already been dropped. /// -/// [arc]: struct.Arc.html -/// [weak]: struct.Weak.html -/// [`Rc`]: ../../std/rc/struct.Rc.html -/// [clone]: ../../std/clone/trait.Clone.html#tymethod.clone +/// [`Rc`]: crate::rc::Rc +/// [clone]: Clone::clone /// [mutex]: ../../std/sync/struct.Mutex.html /// [rwlock]: ../../std/sync/struct.RwLock.html -/// [atomic]: ../../std/sync/atomic/index.html -/// [`Send`]: ../../std/marker/trait.Send.html -/// [`Sync`]: ../../std/marker/trait.Sync.html -/// [deref]: ../../std/ops/trait.Deref.html -/// [downgrade]: struct.Arc.html#method.downgrade -/// [upgrade]: struct.Weak.html#method.upgrade -/// [`None`]: ../../std/option/enum.Option.html#variant.None -/// [`RefCell`]: ../../std/cell/struct.RefCell.html +/// [atomic]: core::sync::atomic +/// [`Send`]: core::marker::Send +/// [`Sync`]: core::marker::Sync +/// [deref]: core::ops::Deref +/// [downgrade]: Arc::downgrade +/// [upgrade]: Weak::upgrade +/// [`RefCell`]: core::cell::RefCell /// [`std::sync`]: ../../std/sync/index.html /// [`Arc::clone(&from)`]: #method.clone /// @@ -184,7 +179,7 @@ macro_rules! acquire { /// /// Sharing a mutable [`AtomicUsize`]: /// -/// [`AtomicUsize`]: ../../std/sync/atomic/struct.AtomicUsize.html +/// [`AtomicUsize`]: core::sync::atomic::AtomicUsize /// /// ```no_run /// use std::sync::Arc; @@ -254,11 +249,7 @@ unsafe fn from_ptr(ptr: *mut ArcInner) -> Self { /// /// The typical way to obtain a `Weak` pointer is to call [`Arc::downgrade`]. /// -/// [`Arc`]: struct.Arc.html -/// [`Arc::downgrade`]: struct.Arc.html#method.downgrade -/// [`upgrade`]: struct.Weak.html#method.upgrade -/// [`Option`]: ../../std/option/enum.Option.html -/// [`None`]: ../../std/option/enum.Option.html#variant.None +/// [`upgrade`]: Weak::upgrade #[stable(feature = "arc_weak", since = "1.4.0")] pub struct Weak { // This is a `NonNull` to allow optimizing the size of this type in enums, @@ -328,6 +319,79 @@ pub fn new(data: T) -> Arc { Self::from_inner(Box::leak(x).into()) } + /// Constructs a new `Arc` using a weak reference to itself. Attempting + /// to upgrade the weak reference before this function returns will result + /// in a `None` value. However, the weak reference may be cloned freely and + /// stored for use at a later time. + /// + /// # Examples + /// ``` + /// #![feature(arc_new_cyclic)] + /// #![allow(dead_code)] + /// + /// use std::sync::{Arc, Weak}; + /// + /// struct Foo { + /// me: Weak, + /// } + /// + /// let foo = Arc::new_cyclic(|me| Foo { + /// me: me.clone(), + /// }); + /// ``` + #[inline] + #[unstable(feature = "arc_new_cyclic", issue = "75861")] + pub fn new_cyclic(data_fn: impl FnOnce(&Weak) -> T) -> Arc { + // Construct the inner in the "uninitialized" state with a single + // weak reference. + let uninit_ptr: NonNull<_> = Box::leak(box ArcInner { + strong: atomic::AtomicUsize::new(0), + weak: atomic::AtomicUsize::new(1), + data: mem::MaybeUninit::::uninit(), + }) + .into(); + let init_ptr: NonNull> = uninit_ptr.cast(); + + let weak = Weak { ptr: init_ptr }; + + // It's important we don't give up ownership of the weak pointer, or + // else the memory might be freed by the time `data_fn` returns. If + // we really wanted to pass ownership, we could create an additional + // weak pointer for ourselves, but this would result in additional + // updates to the weak reference count which might not be necessary + // otherwise. + let data = data_fn(&weak); + + // Now we can properly initialize the inner value and turn our weak + // reference into a strong reference. + unsafe { + let inner = init_ptr.as_ptr(); + ptr::write(&raw mut (*inner).data, data); + + // The above write to the data field must be visible to any threads which + // observe a non-zero strong count. Therefore we need at least "Release" ordering + // in order to synchronize with the `compare_exchange_weak` in `Weak::upgrade`. + // + // "Acquire" ordering is not required. When considering the possible behaviours + // of `data_fn` we only need to look at what it could do with a reference to a + // non-upgradeable `Weak`: + // - It can *clone* the `Weak`, increasing the weak reference count. + // - It can drop those clones, decreasing the weak reference count (but never to zero). + // + // These side effects do not impact us in any way, and no other side effects are + // possible with safe code alone. + let prev_value = (*inner).strong.fetch_add(1, Release); + debug_assert_eq!(prev_value, 0, "No prior strong references should exist"); + } + + let strong = Arc::from_inner(init_ptr); + + // Strong references should collectively own a shared weak reference, + // so don't run the destructor for our old weak reference. + mem::forget(weak); + strong + } + /// Constructs a new `Arc` with uninitialized contents. /// /// # Examples @@ -352,9 +416,11 @@ pub fn new(data: T) -> Arc { #[unstable(feature = "new_uninit", issue = "63291")] pub fn new_uninit() -> Arc> { unsafe { - Arc::from_ptr(Arc::allocate_for_layout(Layout::new::(), |mem| { - mem as *mut ArcInner> - })) + Arc::from_ptr(Arc::allocate_for_layout( + Layout::new::(), + |layout| Global.alloc(layout), + |mem| mem as *mut ArcInner>, + )) } } @@ -381,9 +447,11 @@ pub fn new_uninit() -> Arc> { #[unstable(feature = "new_uninit", issue = "63291")] pub fn new_zeroed() -> Arc> { unsafe { - let mut uninit = Self::new_uninit(); - ptr::write_bytes::(Arc::get_mut_unchecked(&mut uninit).as_mut_ptr(), 0, 1); - uninit + Arc::from_ptr(Arc::allocate_for_layout( + Layout::new::(), + |layout| Global.alloc_zeroed(layout), + |mem| mem as *mut ArcInner>, + )) } } @@ -396,13 +464,11 @@ pub fn pin(data: T) -> Pin> { /// Returns the inner value, if the `Arc` has exactly one strong reference. /// - /// Otherwise, an [`Err`][result] is returned with the same `Arc` that was + /// Otherwise, an [`Err`] is returned with the same `Arc` that was /// passed in. /// /// This will succeed even if there are outstanding weak references. /// - /// [result]: ../../std/result/enum.Result.html - /// /// # Examples /// /// ``` @@ -437,7 +503,7 @@ pub fn try_unwrap(this: Self) -> Result { } impl Arc<[T]> { - /// Constructs a new reference-counted slice with uninitialized contents. + /// Constructs a new atomically reference-counted slice with uninitialized contents. /// /// # Examples /// @@ -464,6 +530,40 @@ impl Arc<[T]> { pub fn new_uninit_slice(len: usize) -> Arc<[mem::MaybeUninit]> { unsafe { Arc::from_ptr(Arc::allocate_for_slice(len)) } } + + /// Constructs a new atomically reference-counted slice with uninitialized contents, with the memory being + /// filled with `0` bytes. + /// + /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and + /// incorrect usage of this method. + /// + /// # Examples + /// + /// ``` + /// #![feature(new_uninit)] + /// + /// use std::sync::Arc; + /// + /// let values = Arc::<[u32]>::new_zeroed_slice(3); + /// let values = unsafe { values.assume_init() }; + /// + /// assert_eq!(*values, [0, 0, 0]) + /// ``` + /// + /// [zeroed]: ../../std/mem/union.MaybeUninit.html#method.zeroed + #[unstable(feature = "new_uninit", issue = "63291")] + pub fn new_zeroed_slice(len: usize) -> Arc<[mem::MaybeUninit]> { + unsafe { + Arc::from_ptr(Arc::allocate_for_layout( + Layout::array::(len).unwrap(), + |layout| Global.alloc_zeroed(layout), + |mem| { + ptr::slice_from_raw_parts_mut(mem as *mut T, len) + as *mut ArcInner<[mem::MaybeUninit]> + }, + )) + } + } } impl Arc> { @@ -550,9 +650,7 @@ impl Arc { /// Consumes the `Arc`, returning the wrapped pointer. /// /// To avoid a memory leak the pointer must be converted back to an `Arc` using - /// [`Arc::from_raw`][from_raw]. - /// - /// [from_raw]: struct.Arc.html#method.from_raw + /// [`Arc::from_raw`]. /// /// # Examples /// @@ -612,8 +710,8 @@ pub fn as_ptr(this: &Self) -> *const T { /// This function is unsafe because improper use may lead to memory unsafety, /// even if the returned `Arc` is never accessed. /// - /// [into_raw]: struct.Arc.html#method.into_raw - /// [transmute]: ../../std/mem/fn.transmute.html + /// [into_raw]: Arc::into_raw + /// [transmute]: core::mem::transmute /// /// # Examples /// @@ -646,9 +744,7 @@ pub unsafe fn from_raw(ptr: *const T) -> Self { } } - /// Creates a new [`Weak`][weak] pointer to this allocation. - /// - /// [weak]: struct.Weak.html + /// Creates a new [`Weak`] pointer to this allocation. /// /// # Examples /// @@ -690,9 +786,7 @@ pub fn downgrade(this: &Self) -> Weak { } } - /// Gets the number of [`Weak`][weak] pointers to this allocation. - /// - /// [weak]: struct.Weak.html + /// Gets the number of [`Weak`] pointers to this allocation. /// /// # Safety /// @@ -861,7 +955,7 @@ unsafe fn drop_slow(&mut self) { /// assert!(!Arc::ptr_eq(&five, &other_five)); /// ``` /// - /// [`ptr::eq`]: ../../std/ptr/fn.eq.html + /// [`ptr::eq`]: core::ptr::eq pub fn ptr_eq(this: &Self, other: &Self) -> bool { this.ptr.as_ptr() == other.ptr.as_ptr() } @@ -875,6 +969,7 @@ impl Arc { /// and must return back a (potentially fat)-pointer for the `ArcInner`. unsafe fn allocate_for_layout( value_layout: Layout, + allocate: impl FnOnce(Layout) -> Result, AllocErr>, mem_to_arcinner: impl FnOnce(*mut u8) -> *mut ArcInner, ) -> *mut ArcInner { // Calculate layout using the given value layout. @@ -883,7 +978,7 @@ unsafe fn allocate_for_layout( // reference (see #54908). let layout = Layout::new::>().extend(value_layout).unwrap().0.pad_to_align(); - let ptr = Global.alloc(layout).unwrap_or_else(|_| handle_alloc_error(layout)); + let ptr = allocate(layout).unwrap_or_else(|_| handle_alloc_error(layout)); // Initialize the ArcInner let inner = mem_to_arcinner(ptr.as_non_null_ptr().as_ptr()); @@ -901,9 +996,11 @@ unsafe fn allocate_for_layout( unsafe fn allocate_for_ptr(ptr: *const T) -> *mut ArcInner { // Allocate for the `ArcInner` using the given value. unsafe { - Self::allocate_for_layout(Layout::for_value(&*ptr), |mem| { - set_data_ptr(ptr as *mut T, mem) as *mut ArcInner - }) + Self::allocate_for_layout( + Layout::for_value(&*ptr), + |layout| Global.alloc(layout), + |mem| set_data_ptr(ptr as *mut T, mem) as *mut ArcInner, + ) } } @@ -934,9 +1031,11 @@ impl Arc<[T]> { /// Allocates an `ArcInner<[T]>` with the given length. unsafe fn allocate_for_slice(len: usize) -> *mut ArcInner<[T]> { unsafe { - Self::allocate_for_layout(Layout::array::(len).unwrap(), |mem| { - ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut ArcInner<[T]> - }) + Self::allocate_for_layout( + Layout::array::(len).unwrap(), + |layout| Global.alloc(layout), + |mem| ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut ArcInner<[T]>, + ) } } } @@ -1098,7 +1197,7 @@ impl Receiver for Arc {} impl Arc { /// Makes a mutable reference into the given `Arc`. /// - /// If there are other `Arc` or [`Weak`][weak] pointers to the same allocation, + /// If there are other `Arc` or [`Weak`] pointers to the same allocation, /// then `make_mut` will create a new allocation and invoke [`clone`][clone] on the inner value /// to ensure unique ownership. This is also referred to as clone-on-write. /// @@ -1107,10 +1206,9 @@ impl Arc { /// /// See also [`get_mut`][get_mut], which will fail rather than cloning. /// - /// [weak]: struct.Weak.html - /// [clone]: ../../std/clone/trait.Clone.html#tymethod.clone - /// [get_mut]: struct.Arc.html#method.get_mut - /// [`Rc::make_mut`]: ../rc/struct.Rc.html#method.make_mut + /// [clone]: Clone::clone + /// [get_mut]: Arc::get_mut + /// [`Rc::make_mut`]: super::rc::Rc::make_mut /// /// # Examples /// @@ -1184,18 +1282,16 @@ pub fn make_mut(this: &mut Self) -> &mut T { impl Arc { /// Returns a mutable reference into the given `Arc`, if there are - /// no other `Arc` or [`Weak`][weak] pointers to the same allocation. + /// no other `Arc` or [`Weak`] pointers to the same allocation. /// - /// Returns [`None`][option] otherwise, because it is not safe to + /// Returns [`None`] otherwise, because it is not safe to /// mutate a shared value. /// /// See also [`make_mut`][make_mut], which will [`clone`][clone] /// the inner value when there are other pointers. /// - /// [weak]: struct.Weak.html - /// [option]: ../../std/option/enum.Option.html - /// [make_mut]: struct.Arc.html#method.make_mut - /// [clone]: ../../std/clone/trait.Clone.html#tymethod.clone + /// [make_mut]: Arc::make_mut + /// [clone]: Clone::clone /// /// # Examples /// @@ -1229,7 +1325,7 @@ pub fn get_mut(this: &mut Self) -> Option<&mut T> { /// /// See also [`get_mut`], which is safe and does appropriate checks. /// - /// [`get_mut`]: struct.Arc.html#method.get_mut + /// [`get_mut`]: Arc::get_mut /// /// # Safety /// @@ -1315,8 +1411,6 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Arc { /// drop(foo); // Doesn't print anything /// drop(foo2); // Prints "dropped!" /// ``` - /// - /// [`Weak`]: ../../std/sync/struct.Weak.html #[inline] fn drop(&mut self) { // Because `fetch_sub` is already atomic, we do not need to synchronize @@ -1401,8 +1495,7 @@ impl Weak { /// Constructs a new `Weak`, without allocating any memory. /// Calling [`upgrade`] on the return value always gives [`None`]. /// - /// [`upgrade`]: struct.Weak.html#method.upgrade - /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`upgrade`]: Weak::upgrade /// /// # Examples /// @@ -1441,7 +1534,7 @@ pub fn new() -> Weak { /// // assert_eq!("hello", unsafe { &*weak.as_ptr() }); /// ``` /// - /// [`null`]: ../../std/ptr/fn.null.html + /// [`null`]: core::ptr::null #[stable(feature = "weak_into_raw", since = "1.45.0")] pub fn as_ptr(&self) -> *const T { let ptr: *mut ArcInner = NonNull::as_ptr(self.ptr); @@ -1483,8 +1576,8 @@ pub fn as_ptr(&self) -> *const T { /// assert_eq!(0, Arc::weak_count(&strong)); /// ``` /// - /// [`from_raw`]: struct.Weak.html#method.from_raw - /// [`as_ptr`]: struct.Weak.html#method.as_ptr + /// [`from_raw`]: Weak::from_raw + /// [`as_ptr`]: Weak::as_ptr #[stable(feature = "weak_into_raw", since = "1.45.0")] pub fn into_raw(self) -> *const T { let result = self.as_ptr(); @@ -1530,12 +1623,10 @@ pub fn into_raw(self) -> *const T { /// assert!(unsafe { Weak::from_raw(raw_2) }.upgrade().is_none()); /// ``` /// - /// [`new`]: struct.Weak.html#method.new - /// [`into_raw`]: struct.Weak.html#method.into_raw - /// [`upgrade`]: struct.Weak.html#method.upgrade - /// [`Weak`]: struct.Weak.html - /// [`Arc`]: struct.Arc.html - /// [`forget`]: ../../std/mem/fn.forget.html + /// [`new`]: Weak::new + /// [`into_raw`]: Weak::into_raw + /// [`upgrade`]: Weak::upgrade + /// [`forget`]: std::mem::forget #[stable(feature = "weak_into_raw", since = "1.45.0")] pub unsafe fn from_raw(ptr: *const T) -> Self { if ptr.is_null() { @@ -1565,9 +1656,6 @@ impl Weak { /// /// Returns [`None`] if the inner value has since been dropped. /// - /// [`Arc`]: struct.Arc.html - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// /// # Examples /// /// ``` @@ -1589,7 +1677,8 @@ impl Weak { #[stable(feature = "arc_weak", since = "1.4.0")] pub fn upgrade(&self) -> Option> { // We use a CAS loop to increment the strong count instead of a - // fetch_add because once the count hits 0 it must never be above 0. + // fetch_add as this function should never take the reference count + // from zero to one. let inner = self.inner()?; // Relaxed load because any write of 0 that we can observe @@ -1608,8 +1697,11 @@ pub fn upgrade(&self) -> Option> { abort(); } - // Relaxed is valid for the same reason it is on Arc's Clone impl - match inner.strong.compare_exchange_weak(n, n + 1, Relaxed, Relaxed) { + // Relaxed is fine for the failure case because we don't have any expectations about the new state. + // Acquire is necessary for the success case to synchronise with `Arc::new_cyclic`, when the inner + // value can be initialized after `Weak` references have already been created. In that case, we + // expect to observe the fully initialized value. + match inner.strong.compare_exchange_weak(n, n + 1, Acquire, Relaxed) { Ok(_) => return Some(Arc::from_inner(self.ptr)), // null checked above Err(old) => n = old, } @@ -1619,8 +1711,6 @@ pub fn upgrade(&self) -> Option> { /// Gets the number of strong (`Arc`) pointers pointing to this allocation. /// /// If `self` was created using [`Weak::new`], this will return 0. - /// - /// [`Weak::new`]: #method.new #[stable(feature = "weak_counts", since = "1.41.0")] pub fn strong_count(&self) -> usize { if let Some(inner) = self.inner() { inner.strong.load(SeqCst) } else { 0 } @@ -1637,8 +1727,6 @@ pub fn strong_count(&self) -> usize { /// Due to implementation details, the returned value can be off by 1 in /// either direction when other threads are manipulating any `Arc`s or /// `Weak`s pointing to the same allocation. - /// - /// [`Weak::new`]: #method.new #[stable(feature = "weak_counts", since = "1.41.0")] pub fn weak_count(&self) -> usize { self.inner() @@ -1716,7 +1804,7 @@ fn inner(&self) -> Option> { /// assert!(!first.ptr_eq(&third)); /// ``` /// - /// [`ptr::eq`]: ../../std/ptr/fn.eq.html + /// [`ptr::eq`]: core::ptr::eq #[inline] #[stable(feature = "weak_ptr_eq", since = "1.39.0")] pub fn ptr_eq(&self, other: &Self) -> bool { @@ -1765,8 +1853,7 @@ impl Default for Weak { /// Calling [`upgrade`] on the return value always /// gives [`None`]. /// - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// [`upgrade`]: ../../std/sync/struct.Weak.html#method.upgrade + /// [`upgrade`]: Weak::upgrade /// /// # Examples /// diff --git a/library/alloc/src/sync/tests.rs b/library/alloc/src/sync/tests.rs index 6f08cd7f123..d2517171606 100644 --- a/library/alloc/src/sync/tests.rs +++ b/library/alloc/src/sync/tests.rs @@ -492,3 +492,70 @@ fn test_array_from_slice() { let a: Result, _> = r.clone().try_into(); assert!(a.is_err()); } + +#[test] +fn test_arc_cyclic_with_zero_refs() { + struct ZeroRefs { + inner: Weak, + } + let zero_refs = Arc::new_cyclic(|inner| { + assert_eq!(inner.strong_count(), 0); + assert!(inner.upgrade().is_none()); + ZeroRefs { inner: Weak::new() } + }); + + assert_eq!(Arc::strong_count(&zero_refs), 1); + assert_eq!(Arc::weak_count(&zero_refs), 0); + assert_eq!(zero_refs.inner.strong_count(), 0); + assert_eq!(zero_refs.inner.weak_count(), 0); +} + +#[test] +fn test_arc_new_cyclic_one_ref() { + struct OneRef { + inner: Weak, + } + let one_ref = Arc::new_cyclic(|inner| { + assert_eq!(inner.strong_count(), 0); + assert!(inner.upgrade().is_none()); + OneRef { inner: inner.clone() } + }); + + assert_eq!(Arc::strong_count(&one_ref), 1); + assert_eq!(Arc::weak_count(&one_ref), 1); + + let one_ref2 = Weak::upgrade(&one_ref.inner).unwrap(); + assert!(Arc::ptr_eq(&one_ref, &one_ref2)); + + assert_eq!(Arc::strong_count(&one_ref), 2); + assert_eq!(Arc::weak_count(&one_ref), 1); +} + +#[test] +fn test_arc_cyclic_two_refs() { + struct TwoRefs { + inner1: Weak, + inner2: Weak, + } + let two_refs = Arc::new_cyclic(|inner| { + assert_eq!(inner.strong_count(), 0); + assert!(inner.upgrade().is_none()); + + let inner1 = inner.clone(); + let inner2 = inner1.clone(); + + TwoRefs { inner1, inner2 } + }); + + assert_eq!(Arc::strong_count(&two_refs), 1); + assert_eq!(Arc::weak_count(&two_refs), 2); + + let two_refs1 = Weak::upgrade(&two_refs.inner1).unwrap(); + assert!(Arc::ptr_eq(&two_refs, &two_refs1)); + + let two_refs2 = Weak::upgrade(&two_refs.inner2).unwrap(); + assert!(Arc::ptr_eq(&two_refs, &two_refs2)); + + assert_eq!(Arc::strong_count(&two_refs), 3); + assert_eq!(Arc::weak_count(&two_refs), 2); +} diff --git a/library/alloc/src/task.rs b/library/alloc/src/task.rs index 252e04a4105..5edc5796056 100644 --- a/library/alloc/src/task.rs +++ b/library/alloc/src/task.rs @@ -13,11 +13,9 @@ /// /// This trait is a memory-safe and ergonomic alternative to constructing a /// [`RawWaker`]. It supports the common executor design in which the data used -/// to wake up a task is stored in an [`Arc`][arc]. Some executors (especially +/// to wake up a task is stored in an [`Arc`]. Some executors (especially /// those for embedded systems) cannot use this API, which is why [`RawWaker`] /// exists as an alternative for those systems. -/// -/// [arc]: ../../std/sync/struct.Arc.html #[unstable(feature = "wake_trait", issue = "69912")] pub trait Wake { /// Wake this task. diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index 80f7ff4893e..058a06e1326 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -50,12 +50,9 @@ //! v[1] = v[1] + 5; //! ``` //! -//! [`Vec`]: ../../std/vec/struct.Vec.html -//! [`new`]: ../../std/vec/struct.Vec.html#method.new -//! [`push`]: ../../std/vec/struct.Vec.html#method.push -//! [`Index`]: ../../std/ops/trait.Index.html -//! [`IndexMut`]: ../../std/ops/trait.IndexMut.html -//! [`vec!`]: ../../std/macro.vec.html +//! [`Vec`]: Vec +//! [`new`]: Vec::new +//! [`push`]: Vec::push #![stable(feature = "rust1", since = "1.0.0")] @@ -278,22 +275,18 @@ /// `Vec` does not currently guarantee the order in which elements are dropped. /// The order has changed in the past and may change again. /// -/// [`vec!`]: ../../std/macro.vec.html /// [`get`]: ../../std/vec/struct.Vec.html#method.get /// [`get_mut`]: ../../std/vec/struct.Vec.html#method.get_mut -/// [`Index`]: ../../std/ops/trait.Index.html -/// [`String`]: ../../std/string/struct.String.html -/// [`&str`]: ../../std/primitive.str.html -/// [`Vec::with_capacity`]: ../../std/vec/struct.Vec.html#method.with_capacity -/// [`Vec::new`]: ../../std/vec/struct.Vec.html#method.new -/// [`shrink_to_fit`]: ../../std/vec/struct.Vec.html#method.shrink_to_fit -/// [`capacity`]: ../../std/vec/struct.Vec.html#method.capacity -/// [`mem::size_of::`]: ../../std/mem/fn.size_of.html -/// [`len`]: ../../std/vec/struct.Vec.html#method.len -/// [`push`]: ../../std/vec/struct.Vec.html#method.push -/// [`insert`]: ../../std/vec/struct.Vec.html#method.insert -/// [`reserve`]: ../../std/vec/struct.Vec.html#method.reserve -/// [owned slice]: ../../std/boxed/struct.Box.html +/// [`String`]: crate::string::String +/// [`&str`]: type@str +/// [`shrink_to_fit`]: Vec::shrink_to_fit +/// [`capacity`]: Vec::capacity +/// [`mem::size_of::`]: core::mem::size_of +/// [`len`]: Vec::len +/// [`push`]: Vec::push +/// [`insert`]: Vec::insert +/// [`reserve`]: Vec::reserve +/// [owned slice]: Box #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "vec_type")] pub struct Vec { @@ -375,7 +368,7 @@ pub fn with_capacity(capacity: usize) -> Vec { /// into a `Vec` with the [`from_raw_parts`] function, allowing /// the destructor to perform the cleanup. /// - /// [`from_raw_parts`]: #method.from_raw_parts + /// [`from_raw_parts`]: Vec::from_raw_parts /// /// # Examples /// @@ -430,8 +423,8 @@ pub fn into_raw_parts(self) -> (*mut T, usize, usize) { /// that nothing else uses the pointer after calling this /// function. /// - /// [`String`]: ../../std/string/struct.String.html - /// [`dealloc`]: ../../alloc/alloc/trait.GlobalAlloc.html#tymethod.dealloc + /// [`String`]: crate::string::String + /// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc /// /// # Examples /// @@ -661,7 +654,7 @@ pub fn shrink_to(&mut self, min_capacity: usize) { /// /// Note that this will drop any excess capacity. /// - /// [owned slice]: ../../std/boxed/struct.Box.html + /// [owned slice]: Box /// /// # Examples /// @@ -732,8 +725,8 @@ pub fn into_boxed_slice(mut self) -> Box<[T]> { /// assert_eq!(vec, []); /// ``` /// - /// [`clear`]: #method.clear - /// [`drain`]: #method.drain + /// [`clear`]: Vec::clear + /// [`drain`]: Vec::drain #[stable(feature = "rust1", since = "1.0.0")] pub fn truncate(&mut self, len: usize) { // This is safe because: @@ -812,7 +805,7 @@ pub fn as_mut_slice(&mut self) -> &mut [T] { /// } /// ``` /// - /// [`as_mut_ptr`]: #method.as_mut_ptr + /// [`as_mut_ptr`]: Vec::as_mut_ptr #[stable(feature = "vec_as_ptr", since = "1.37.0")] #[inline] pub fn as_ptr(&self) -> *const T { @@ -868,17 +861,17 @@ pub fn as_mut_ptr(&mut self) -> *mut T { /// is done using one of the safe operations instead, such as /// [`truncate`], [`resize`], [`extend`], or [`clear`]. /// - /// [`truncate`]: #method.truncate - /// [`resize`]: #method.resize - /// [`extend`]: ../../std/iter/trait.Extend.html#tymethod.extend - /// [`clear`]: #method.clear + /// [`truncate`]: Vec::truncate + /// [`resize`]: Vec::resize + /// [`extend`]: Extend::extend + /// [`clear`]: Vec::clear /// /// # Safety /// /// - `new_len` must be less than or equal to [`capacity()`]. /// - The elements at `old_len..new_len` must be initialized. /// - /// [`capacity()`]: #method.capacity + /// [`capacity()`]: Vec::capacity /// /// # Examples /// @@ -1217,8 +1210,6 @@ pub fn push(&mut self, value: T) { /// Removes the last element from a vector and returns it, or [`None`] if it /// is empty. /// - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// /// # Examples /// /// ``` @@ -1482,8 +1473,7 @@ fn assert_failed(at: usize, len: usize) -> ! { /// assert_eq!(vec, [2, 4, 8, 16]); /// ``` /// - /// [`resize`]: #method.resize - /// [`Clone`]: ../../std/clone/trait.Clone.html + /// [`resize`]: Vec::resize #[stable(feature = "vec_resize_with", since = "1.33.0")] pub fn resize_with(&mut self, new_len: usize, f: F) where @@ -1534,7 +1524,7 @@ pub fn leak<'a>(self) -> &'a mut [T] /// reading from a file) before marking the data as initialized using the /// [`set_len`] method. /// - /// [`set_len`]: #method.set_len + /// [`set_len`]: Vec::set_len /// /// # Examples /// @@ -1593,9 +1583,7 @@ impl Vec { /// assert_eq!(vec, [1, 2]); /// ``` /// - /// [`Clone`]: ../../std/clone/trait.Clone.html - /// [`Default`]: ../../std/default/trait.Default.html - /// [`resize_with`]: #method.resize_with + /// [`resize_with`]: Vec::resize_with #[stable(feature = "vec_resize", since = "1.5.0")] pub fn resize(&mut self, new_len: usize, value: T) { let len = self.len(); @@ -1657,10 +1645,7 @@ impl Vec { /// assert_eq!(vec, [1, 2]); /// ``` /// - /// [`resize`]: #method.resize - /// [`Default::default()`]: ../../std/default/trait.Default.html#tymethod.default - /// [`Default`]: ../../std/default/trait.Default.html - /// [`Clone`]: ../../std/clone/trait.Clone.html + /// [`resize`]: Vec::resize #[unstable(feature = "vec_resize_default", issue = "41758")] #[rustc_deprecated( reason = "This is moving towards being removed in favor \ @@ -2341,7 +2326,6 @@ pub fn splice(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoI /// Note that `drain_filter` also lets you mutate every element in the filter closure, /// regardless of whether you choose to keep or remove it. /// - /// /// # Examples /// /// Splitting an array into evens and odds, reusing the original allocation: diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index 7129f0f2402..a5ddf7619b6 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -85,7 +85,7 @@ pub const fn from_size_align(size: usize, align: usize) -> Result NonNull { /// will *still* have size 16. /// /// Returns an error if the combination of `self.size()` and the given - /// `align` violates the conditions listed in - /// [`Layout::from_size_align`](#method.from_size_align). + /// `align` violates the conditions listed in [`Layout::from_size_align`]. #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")] #[inline] pub fn align_to(&self, align: usize) -> Result { diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index ad4f8bf1397..c1fda2fce64 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -147,9 +147,8 @@ fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { /// Attempts to extend the memory block. /// /// Returns a new [`NonNull<[u8]>`] containing a pointer and the actual size of the allocated - /// memory. The pointer is suitable for holding data described by a new layout with `layout`’s - /// alignment and a size given by `new_size`. To accomplish this, the allocator may extend the - /// allocation referenced by `ptr` to fit the new layout. + /// memory. The pointer is suitable for holding data described by `new_layout`. To accomplish + /// this, the allocator may extend the allocation referenced by `ptr` to fit the new layout. /// /// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been /// transferred to this allocator. The memory may or may not have been freed, and should be @@ -163,11 +162,9 @@ fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { /// /// # Safety /// - /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator, - /// * `layout` must [*fit*] that block of memory (The `new_size` argument need not fit it.), - /// * `new_size` must be greater than or equal to `layout.size()`, and - /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`, must not overflow - /// (i.e., the rounded value must be less than or equal to `usize::MAX`). + /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator. + /// * `old_layout` must [*fit*] that block of memory (The `new_layout` argument need not fit it.). + /// * `new_layout.size()` must be greater than or equal to `old_layout.size()`. /// /// [*currently allocated*]: #currently-allocated-memory /// [*fit*]: #memory-fitting @@ -188,28 +185,24 @@ fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { unsafe fn grow( &mut self, ptr: NonNull, - layout: Layout, - new_size: usize, + old_layout: Layout, + new_layout: Layout, ) -> Result, AllocErr> { - let size = layout.size(); debug_assert!( - new_size >= size, - "`new_size` must be greater than or equal to `layout.size()`" + new_layout.size() >= old_layout.size(), + "`new_layout.size()` must be greater than or equal to `old_layout.size()`" ); - // SAFETY: the caller must ensure that the `new_size` does not overflow. - // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid for a Layout. - let new_layout = unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) }; let new_ptr = self.alloc(new_layout)?; - // SAFETY: because `new_size` must be greater than or equal to `size`, both the old and new - // memory allocation are valid for reads and writes for `size` bytes. Also, because the old - // allocation wasn't yet deallocated, it cannot overlap `new_ptr`. Thus, the call to - // `copy_nonoverlapping` is safe. - // The safety contract for `dealloc` must be upheld by the caller. + // SAFETY: because `new_layout.size()` must be greater than or equal to + // `old_layout.size()`, both the old and new memory allocation are valid for reads and + // writes for `old_layout.size()` bytes. Also, because the old allocation wasn't yet + // deallocated, it cannot overlap `new_ptr`. Thus, the call to `copy_nonoverlapping` is + // safe. The safety contract for `dealloc` must be upheld by the caller. unsafe { - ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), size); - self.dealloc(ptr, layout); + ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_layout.size()); + self.dealloc(ptr, old_layout); } Ok(new_ptr) @@ -220,21 +213,19 @@ unsafe fn grow( /// /// The memory block will contain the following contents after a successful call to /// `grow_zeroed`: - /// * Bytes `0..layout.size()` are preserved from the original allocation. - /// * Bytes `layout.size()..old_size` will either be preserved or zeroed, depending on the - /// allocator implementation. `old_size` refers to the size of the memory block prior to - /// the `grow_zeroed` call, which may be larger than the size that was originally requested - /// when it was allocated. + /// * Bytes `0..old_layout.size()` are preserved from the original allocation. + /// * Bytes `old_layout.size()..old_size` will either be preserved or zeroed, depending on + /// the allocator implementation. `old_size` refers to the size of the memory block prior + /// to the `grow_zeroed` call, which may be larger than the size that was originally + /// requested when it was allocated. /// * Bytes `old_size..new_size` are zeroed. `new_size` refers to the size of the memory - /// block returned by the `grow` call. + /// block returned by the `grow_zeroed` call. /// /// # Safety /// - /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator, - /// * `layout` must [*fit*] that block of memory (The `new_size` argument need not fit it.), - /// * `new_size` must be greater than or equal to `layout.size()`, and - /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`, must not overflow - /// (i.e., the rounded value must be less than or equal to `usize::MAX`). + /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator. + /// * `old_layout` must [*fit*] that block of memory (The `new_layout` argument need not fit it.). + /// * `new_layout.size()` must be greater than or equal to `old_layout.size()`. /// /// [*currently allocated*]: #currently-allocated-memory /// [*fit*]: #memory-fitting @@ -255,28 +246,24 @@ unsafe fn grow( unsafe fn grow_zeroed( &mut self, ptr: NonNull, - layout: Layout, - new_size: usize, + old_layout: Layout, + new_layout: Layout, ) -> Result, AllocErr> { - let size = layout.size(); debug_assert!( - new_size >= size, - "`new_size` must be greater than or equal to `layout.size()`" + new_layout.size() >= old_layout.size(), + "`new_layout.size()` must be greater than or equal to `old_layout.size()`" ); - // SAFETY: the caller must ensure that the `new_size` does not overflow. - // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid for a Layout. - let new_layout = unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) }; let new_ptr = self.alloc_zeroed(new_layout)?; - // SAFETY: because `new_size` must be greater than or equal to `size`, both the old and new - // memory allocation are valid for reads and writes for `size` bytes. Also, because the old - // allocation wasn't yet deallocated, it cannot overlap `new_ptr`. Thus, the call to - // `copy_nonoverlapping` is safe. - // The safety contract for `dealloc` must be upheld by the caller. + // SAFETY: because `new_layout.size()` must be greater than or equal to + // `old_layout.size()`, both the old and new memory allocation are valid for reads and + // writes for `old_layout.size()` bytes. Also, because the old allocation wasn't yet + // deallocated, it cannot overlap `new_ptr`. Thus, the call to `copy_nonoverlapping` is + // safe. The safety contract for `dealloc` must be upheld by the caller. unsafe { - ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), size); - self.dealloc(ptr, layout); + ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_layout.size()); + self.dealloc(ptr, old_layout); } Ok(new_ptr) @@ -285,9 +272,8 @@ unsafe fn grow_zeroed( /// Attempts to shrink the memory block. /// /// Returns a new [`NonNull<[u8]>`] containing a pointer and the actual size of the allocated - /// memory. The pointer is suitable for holding data described by a new layout with `layout`’s - /// alignment and a size given by `new_size`. To accomplish this, the allocator may shrink the - /// allocation referenced by `ptr` to fit the new layout. + /// memory. The pointer is suitable for holding data described by `new_layout`. To accomplish + /// this, the allocator may shrink the allocation referenced by `ptr` to fit the new layout. /// /// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been /// transferred to this allocator. The memory may or may not have been freed, and should be @@ -301,9 +287,9 @@ unsafe fn grow_zeroed( /// /// # Safety /// - /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator, - /// * `layout` must [*fit*] that block of memory (The `new_size` argument need not fit it.), and - /// * `new_size` must be smaller than or equal to `layout.size()`. + /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator. + /// * `old_layout` must [*fit*] that block of memory (The `new_layout` argument need not fit it.). + /// * `new_layout.size()` must be smaller than or equal to `old_layout.size()`. /// /// [*currently allocated*]: #currently-allocated-memory /// [*fit*]: #memory-fitting @@ -324,28 +310,24 @@ unsafe fn grow_zeroed( unsafe fn shrink( &mut self, ptr: NonNull, - layout: Layout, - new_size: usize, + old_layout: Layout, + new_layout: Layout, ) -> Result, AllocErr> { - let size = layout.size(); debug_assert!( - new_size <= size, - "`new_size` must be smaller than or equal to `layout.size()`" + new_layout.size() <= old_layout.size(), + "`new_layout.size()` must be smaller than or equal to `old_layout.size()`" ); - // SAFETY: the caller must ensure that the `new_size` does not overflow. - // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid for a Layout. - let new_layout = unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) }; let new_ptr = self.alloc(new_layout)?; - // SAFETY: because `new_size` must be lower than or equal to `size`, both the old and new - // memory allocation are valid for reads and writes for `new_size` bytes. Also, because the - // old allocation wasn't yet deallocated, it cannot overlap `new_ptr`. Thus, the call to - // `copy_nonoverlapping` is safe. - // The safety contract for `dealloc` must be upheld by the caller. + // SAFETY: because `new_layout.size()` must be lower than or equal to + // `old_layout.size()`, both the old and new memory allocation are valid for reads and + // writes for `new_layout.size()` bytes. Also, because the old allocation wasn't yet + // deallocated, it cannot overlap `new_ptr`. Thus, the call to `copy_nonoverlapping` is + // safe. The safety contract for `dealloc` must be upheld by the caller. unsafe { - ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), size); - self.dealloc(ptr, layout); + ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), new_layout.size()); + self.dealloc(ptr, old_layout); } Ok(new_ptr) @@ -385,32 +367,32 @@ unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { unsafe fn grow( &mut self, ptr: NonNull, - layout: Layout, - new_size: usize, + old_layout: Layout, + new_layout: Layout, ) -> Result, AllocErr> { // SAFETY: the safety contract must be upheld by the caller - unsafe { (**self).grow(ptr, layout, new_size) } + unsafe { (**self).grow(ptr, old_layout, new_layout) } } #[inline] unsafe fn grow_zeroed( &mut self, ptr: NonNull, - layout: Layout, - new_size: usize, + old_layout: Layout, + new_layout: Layout, ) -> Result, AllocErr> { // SAFETY: the safety contract must be upheld by the caller - unsafe { (**self).grow_zeroed(ptr, layout, new_size) } + unsafe { (**self).grow_zeroed(ptr, old_layout, new_layout) } } #[inline] unsafe fn shrink( &mut self, ptr: NonNull, - layout: Layout, - new_size: usize, + old_layout: Layout, + new_layout: Layout, ) -> Result, AllocErr> { // SAFETY: the safety contract must be upheld by the caller - unsafe { (**self).shrink(ptr, layout, new_size) } + unsafe { (**self).shrink(ptr, old_layout, new_layout) } } } diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 6b28ab7d755..88795d8429d 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -32,9 +32,6 @@ /// Note that the traits [`AsRef`] and [`AsMut`] provide similar methods for types that /// may not be fixed-size arrays. Implementors should prefer those traits /// instead. -/// -/// [`AsRef`]: ../convert/trait.AsRef.html -/// [`AsMut`]: ../convert/trait.AsMut.html #[unstable(feature = "fixed_size_array", issue = "27778")] pub unsafe trait FixedSizeArray { /// Converts the array to immutable slice diff --git a/library/core/src/char/mod.rs b/library/core/src/char/mod.rs index 1b4e906e4e4..7a68de5e6af 100644 --- a/library/core/src/char/mod.rs +++ b/library/core/src/char/mod.rs @@ -94,7 +94,6 @@ /// Point], but only ones within a certain range. `MAX` is the highest valid /// code point that's a valid [Unicode Scalar Value]. /// -/// [`char`]: ../../std/primitive.char.html /// [Unicode Scalar Value]: http://www.unicode.org/glossary/#unicode_scalar_value /// [Code Point]: http://www.unicode.org/glossary/#code_point #[stable(feature = "rust1", since = "1.0.0")] @@ -114,8 +113,7 @@ /// This `struct` is created by the [`escape_unicode`] method on [`char`]. See /// its documentation for more. /// -/// [`escape_unicode`]: ../../std/primitive.char.html#method.escape_unicode -/// [`char`]: ../../std/primitive.char.html +/// [`escape_unicode`]: char::escape_unicode #[derive(Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct EscapeUnicode { @@ -236,8 +234,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// This `struct` is created by the [`escape_default`] method on [`char`]. See /// its documentation for more. /// -/// [`escape_default`]: ../../std/primitive.char.html#method.escape_default -/// [`char`]: ../../std/primitive.char.html +/// [`escape_default`]: char::escape_default #[derive(Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct EscapeDefault { @@ -345,8 +342,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// This `struct` is created by the [`escape_debug`] method on [`char`]. See its /// documentation for more. /// -/// [`escape_debug`]: ../../std/primitive.char.html#method.escape_debug -/// [`char`]: ../../std/primitive.char.html +/// [`escape_debug`]: char::escape_debug #[stable(feature = "char_escape_debug", since = "1.20.0")] #[derive(Clone, Debug)] pub struct EscapeDebug(EscapeDefault); @@ -380,8 +376,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// This `struct` is created by the [`to_lowercase`] method on [`char`]. See /// its documentation for more. /// -/// [`to_lowercase`]: ../../std/primitive.char.html#method.to_lowercase -/// [`char`]: ../../std/primitive.char.html +/// [`to_lowercase`]: char::to_lowercase #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug, Clone)] pub struct ToLowercase(CaseMappingIter); @@ -408,8 +403,7 @@ impl ExactSizeIterator for ToLowercase {} /// This `struct` is created by the [`to_uppercase`] method on [`char`]. See /// its documentation for more. /// -/// [`to_uppercase`]: ../../std/primitive.char.html#method.to_uppercase -/// [`char`]: ../../std/primitive.char.html +/// [`to_uppercase`]: char::to_uppercase #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug, Clone)] pub struct ToUppercase(CaseMappingIter); diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index e775ded60f5..3953c73319f 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -25,7 +25,7 @@ use self::Ordering::*; /// Trait for equality comparisons which are [partial equivalence -/// relations](http://en.wikipedia.org/wiki/Partial_equivalence_relation). +/// relations](https://en.wikipedia.org/wiki/Partial_equivalence_relation). /// /// This trait allows for partial equality, for types that do not have a full /// equivalence relation. For example, in floating point numbers `NaN != NaN`, @@ -505,7 +505,7 @@ fn cmp(&self, other: &Reverse) -> Ordering { /// /// This trait can be used with `#[derive]`. When `derive`d on structs, it will produce a /// lexicographic ordering based on the top-to-bottom declaration order of the struct's members. -/// When `derive`d on enums, variants are ordered by their top-to-bottom declaration order. +/// When `derive`d on enums, variants are ordered by their top-to-bottom discriminant order. /// /// ## How can I implement `Ord`? /// @@ -694,7 +694,7 @@ fn partial_cmp(&self, other: &Ordering) -> Option { /// /// This trait can be used with `#[derive]`. When `derive`d on structs, it will produce a /// lexicographic ordering based on the top-to-bottom declaration order of the struct's members. -/// When `derive`d on enums, variants are ordered by their top-to-bottom declaration order. +/// When `derive`d on enums, variants are ordered by their top-to-bottom discriminant order. /// /// ## How can I implement `PartialOrd`? /// diff --git a/library/core/src/ffi.rs b/library/core/src/ffi.rs index e9689af39d5..4525ba78ba0 100644 --- a/library/core/src/ffi.rs +++ b/library/core/src/ffi.rs @@ -281,8 +281,6 @@ fn deref_mut(&mut self) -> &mut VaListImpl<'f> { // improving this. mod sealed_trait { /// Trait which permits the allowed types to be used with [VaList::arg]. - /// - /// [VaList::arg]: ../struct.VaList.html#method.arg #[unstable( feature = "c_variadic", reason = "the `c_variadic` feature has not been properly tested on \ diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 638e83c3b93..52f73c03e02 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -117,8 +117,6 @@ pub trait Write { /// /// This function will return an instance of [`Error`] on error. /// - /// [`Error`]: struct.Error.html - /// /// # Examples /// /// ``` @@ -146,9 +144,6 @@ pub trait Write { /// /// This function will return an instance of [`Error`] on error. /// - /// [`char`]: ../../std/primitive.char.html - /// [`Error`]: struct.Error.html - /// /// # Examples /// /// ``` @@ -218,9 +213,6 @@ fn write_fmt(&mut self, args: Arguments<'_>) -> Result { /// To interact with a `Formatter`, you'll call various methods to change the /// various options related to formatting. For examples, please see the /// documentation of the methods defined on `Formatter` below. -/// -/// [`Debug`]: trait.Debug.html -/// [`Display`]: trait.Display.html #[allow(missing_debug_implementations)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Formatter<'a> { @@ -378,7 +370,7 @@ pub fn estimated_capacity(&self) -> usize { /// /// The [`format_args!`] macro will safely create an instance of this structure. /// The macro validates the format string at compile-time so usage of the -/// [`write`] and [`format`] functions can be safely performed. +/// [`write()`] and [`format()`] functions can be safely performed. /// /// You can use the `Arguments<'a>` that [`format_args!`] returns in `Debug` /// and `Display` contexts as seen below. The example also shows that `Debug` @@ -392,9 +384,7 @@ pub fn estimated_capacity(&self) -> usize { /// assert_eq!(display, debug); /// ``` /// -/// [`format_args!`]: ../../std/macro.format_args.html -/// [`format`]: ../../std/fmt/fn.format.html -/// [`write`]: ../../std/fmt/fn.write.html +/// [`format()`]: ../../std/fmt/fn.format.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Copy, Clone)] pub struct Arguments<'a> { @@ -472,9 +462,7 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> Result { /// /// When used with the alternate format specifier `#?`, the output is pretty-printed. /// -/// For more information on formatters, see [the module-level documentation][module]. -/// -/// [module]: ../../std/fmt/index.html +/// For more information on formatters, see [the module-level documentation][self]. /// /// This trait can be used with `#[derive]` if all fields implement `Debug`. When /// `derive`d for structs, it will use the name of the `struct`, then `{`, then a @@ -535,8 +523,7 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> Result { /// `Debug` implementations using either `derive` or the debug builder API /// on [`Formatter`] support pretty-printing using the alternate flag: `{:#?}`. /// -/// [`debug_struct`]: ../../std/fmt/struct.Formatter.html#method.debug_struct -/// [`Formatter`]: ../../std/fmt/struct.Formatter.html +/// [`debug_struct`]: Formatter::debug_struct /// /// Pretty-printing with `#?`: /// @@ -618,14 +605,10 @@ pub(crate) mod macros { /// Format trait for an empty format, `{}`. /// -/// `Display` is similar to [`Debug`][debug], but `Display` is for user-facing +/// `Display` is similar to [`Debug`], but `Display` is for user-facing /// output, and so cannot be derived. /// -/// [debug]: trait.Debug.html -/// -/// For more information on formatters, see [the module-level documentation][module]. -/// -/// [module]: ../../std/fmt/index.html +/// For more information on formatters, see [the module-level documentation][self]. /// /// # Examples /// @@ -697,9 +680,7 @@ pub trait Display { /// /// The alternate flag, `#`, adds a `0o` in front of the output. /// -/// For more information on formatters, see [the module-level documentation][module]. -/// -/// [module]: ../../std/fmt/index.html +/// For more information on formatters, see [the module-level documentation][self]. /// /// # Examples /// @@ -751,7 +732,7 @@ pub trait Octal { /// /// The alternate flag, `#`, adds a `0b` in front of the output. /// -/// For more information on formatters, see [the module-level documentation][module]. +/// For more information on formatters, see [the module-level documentation][self]. /// /// # Examples /// @@ -790,12 +771,6 @@ pub trait Octal { /// "l as binary is: 0b000000000000000000000001101011" /// ); /// ``` -/// -/// [module]: ../../std/fmt/index.html -/// [`i8`]: ../../std/primitive.i8.html -/// [`i128`]: ../../std/primitive.i128.html -/// [`isize`]: ../../std/primitive.isize.html -/// [`i32`]: ../../std/primitive.i32.html #[stable(feature = "rust1", since = "1.0.0")] pub trait Binary { /// Formats the value using the given formatter. @@ -813,9 +788,7 @@ pub trait Binary { /// /// The alternate flag, `#`, adds a `0x` in front of the output. /// -/// For more information on formatters, see [the module-level documentation][module]. -/// -/// [module]: ../../std/fmt/index.html +/// For more information on formatters, see [the module-level documentation][self]. /// /// # Examples /// @@ -868,9 +841,7 @@ pub trait LowerHex { /// /// The alternate flag, `#`, adds a `0x` in front of the output. /// -/// For more information on formatters, see [the module-level documentation][module]. -/// -/// [module]: ../../std/fmt/index.html +/// For more information on formatters, see [the module-level documentation][self]. /// /// # Examples /// @@ -918,9 +889,7 @@ pub trait UpperHex { /// The `Pointer` trait should format its output as a memory location. This is commonly presented /// as hexadecimal. /// -/// For more information on formatters, see [the module-level documentation][module]. -/// -/// [module]: ../../std/fmt/index.html +/// For more information on formatters, see [the module-level documentation][self]. /// /// # Examples /// @@ -967,9 +936,7 @@ pub trait Pointer { /// /// The `LowerExp` trait should format its output in scientific notation with a lower-case `e`. /// -/// For more information on formatters, see [the module-level documentation][module]. -/// -/// [module]: ../../std/fmt/index.html +/// For more information on formatters, see [the module-level documentation][self]. /// /// # Examples /// @@ -1018,9 +985,7 @@ pub trait LowerExp { /// /// The `UpperExp` trait should format its output in scientific notation with an upper-case `E`. /// -/// For more information on formatters, see [the module-level documentation][module]. -/// -/// [module]: ../../std/fmt/index.html +/// For more information on formatters, see [the module-level documentation][self]. /// /// # Examples /// @@ -1812,8 +1777,7 @@ fn debug_upper_hex(&self) -> bool { /// Creates a [`DebugStruct`] builder designed to assist with creation of /// [`fmt::Debug`] implementations for structs. /// - /// [`DebugStruct`]: ../../std/fmt/struct.DebugStruct.html - /// [`fmt::Debug`]: ../../std/fmt/trait.Debug.html + /// [`fmt::Debug`]: self::Debug /// /// # Examples /// diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 1399d0c020f..25951e2f582 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -57,6 +57,11 @@ use crate::marker::DiscriminantKind; use crate::mem; +// These imports are used for simplifying intra-doc links +#[allow(unused_imports)] +#[cfg(all(target_has_atomic = "8", target_has_atomic = "32", target_has_atomic = "ptr"))] +use crate::sync::atomic::{self, AtomicBool, AtomicI32, AtomicIsize, AtomicU32, Ordering}; + #[stable(feature = "drop_in_place", since = "1.8.0")] #[rustc_deprecated( reason = "no longer an intrinsic - use `ptr::drop_in_place` directly", @@ -71,710 +76,510 @@ /// Stores a value if the current value is the same as the `old` value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `compare_exchange` method by passing - /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) - /// as both the `success` and `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`][compare_exchange]. - /// - /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange + /// [`atomic`] types via the `compare_exchange` method by passing + /// [`Ordering::SeqCst`] as both the `success` and `failure` parameters. + /// For example, [`AtomicBool::compare_exchange`]. pub fn atomic_cxchg(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `compare_exchange` method by passing - /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) - /// as both the `success` and `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`][compare_exchange]. - /// - /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange + /// [`atomic`] types via the `compare_exchange` method by passing + /// [`Ordering::Acquire`] as both the `success` and `failure` parameters. + /// For example, [`AtomicBool::compare_exchange`]. pub fn atomic_cxchg_acq(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `compare_exchange` method by passing - /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html) - /// as the `success` and - /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) - /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`][compare_exchange]. - /// - /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange + /// [`atomic`] types via the `compare_exchange` method by passing + /// [`Ordering::Release`] as the `success` and [`Ordering::Relaxed`] as the + /// `failure` parameters. For example, [`AtomicBool::compare_exchange`]. pub fn atomic_cxchg_rel(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `compare_exchange` method by passing - /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html) - /// as the `success` and - /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) - /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`][compare_exchange]. - /// - /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange + /// [`atomic`] types via the `compare_exchange` method by passing + /// [`Ordering::AcqRel`] as the `success` and [`Ordering::Acquire`] as the + /// `failure` parameters. For example, [`AtomicBool::compare_exchange`]. pub fn atomic_cxchg_acqrel(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `compare_exchange` method by passing - /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) - /// as both the `success` and `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`][compare_exchange]. - /// - /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange + /// [`atomic`] types via the `compare_exchange` method by passing + /// [`Ordering::Relaxed`] as both the `success` and `failure` parameters. + /// For example, [`AtomicBool::compare_exchange`]. pub fn atomic_cxchg_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `compare_exchange` method by passing - /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) - /// as the `success` and - /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) - /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`][compare_exchange]. - /// - /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange + /// [`atomic`] types via the `compare_exchange` method by passing + /// [`Ordering::SeqCst`] as the `success` and [`Ordering::Relaxed`] as the + /// `failure` parameters. For example, [`AtomicBool::compare_exchange`]. pub fn atomic_cxchg_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `compare_exchange` method by passing - /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) - /// as the `success` and - /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) - /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`][compare_exchange]. - /// - /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange + /// [`atomic`] types via the `compare_exchange` method by passing + /// [`Ordering::SeqCst`] as the `success` and [`Ordering::Acquire`] as the + /// `failure` parameters. For example, [`AtomicBool::compare_exchange`]. pub fn atomic_cxchg_failacq(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `compare_exchange` method by passing - /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) - /// as the `success` and - /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) - /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`][compare_exchange]. - /// - /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange + /// [`atomic`] types via the `compare_exchange` method by passing + /// [`Ordering::Acquire`] as the `success` and [`Ordering::Relaxed`] as the + /// `failure` parameters. For example, [`AtomicBool::compare_exchange`]. pub fn atomic_cxchg_acq_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `compare_exchange` method by passing - /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html) - /// as the `success` and - /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) - /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`][compare_exchange]. - /// - /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange + /// [`atomic`] types via the `compare_exchange` method by passing + /// [`Ordering::AcqRel`] as the `success` and [`Ordering::Relaxed`] as the + /// `failure` parameters. For example, [`AtomicBool::compare_exchange`]. pub fn atomic_cxchg_acqrel_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing - /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) - /// as both the `success` and `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`][cew]. - /// - /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak + /// [`atomic`] types via the `compare_exchange_weak` method by passing + /// [`Ordering::SeqCst`] as both the `success` and `failure` parameters. + /// For example, [`AtomicBool::compare_exchange_weak`]. pub fn atomic_cxchgweak(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing - /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) - /// as both the `success` and `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`][cew]. - /// - /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak + /// [`atomic`] types via the `compare_exchange_weak` method by passing + /// [`Ordering::Acquire`] as both the `success` and `failure` parameters. + /// For example, [`AtomicBool::compare_exchange_weak`]. pub fn atomic_cxchgweak_acq(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing - /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html) - /// as the `success` and - /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) - /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`][cew]. - /// - /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak + /// [`atomic`] types via the `compare_exchange_weak` method by passing + /// [`Ordering::Release`] as the `success` and [`Ordering::Relaxed`] as the + /// `failure` parameters. For example, [`AtomicBool::compare_exchange_weak`]. pub fn atomic_cxchgweak_rel(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing - /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html) - /// as the `success` and - /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) - /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`][cew]. - /// - /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak + /// [`atomic`] types via the `compare_exchange_weak` method by passing + /// [`Ordering::AcqRel`] as the `success` and [`Ordering::Acquire`] as the + /// `failure` parameters. For example, [`AtomicBool::compare_exchange_weak`]. pub fn atomic_cxchgweak_acqrel(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing - /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) - /// as both the `success` and `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`][cew]. - /// - /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak + /// [`atomic`] types via the `compare_exchange_weak` method by passing + /// [`Ordering::Relaxed`] as both the `success` and `failure` parameters. + /// For example, [`AtomicBool::compare_exchange_weak`]. pub fn atomic_cxchgweak_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing - /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) - /// as the `success` and - /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) - /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`][cew]. - /// - /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak + /// [`atomic`] types via the `compare_exchange_weak` method by passing + /// [`Ordering::SeqCst`] as the `success` and [`Ordering::Relaxed`] as the + /// `failure` parameters. For example, [`AtomicBool::compare_exchange_weak`]. pub fn atomic_cxchgweak_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing - /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) - /// as the `success` and - /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) - /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`][cew]. - /// - /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak + /// [`atomic`] types via the `compare_exchange_weak` method by passing + /// [`Ordering::SeqCst`] as the `success` and [`Ordering::Acquire`] as the + /// `failure` parameters. For example, [`AtomicBool::compare_exchange_weak`]. pub fn atomic_cxchgweak_failacq(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing - /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) - /// as the `success` and - /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) - /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`][cew]. - /// - /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak + /// [`atomic`] types via the `compare_exchange_weak` method by passing + /// [`Ordering::Acquire`] as the `success` and [`Ordering::Relaxed`] as the + /// `failure` parameters. For example, [`AtomicBool::compare_exchange_weak`]. pub fn atomic_cxchgweak_acq_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing - /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html) - /// as the `success` and - /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) - /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`][cew]. - /// - /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak + /// [`atomic`] types via the `compare_exchange_weak` method by passing + /// [`Ordering::AcqRel`] as the `success` and [`Ordering::Relaxed`] as the + /// `failure` parameters. For example, [`AtomicBool::compare_exchange_weak`]. pub fn atomic_cxchgweak_acqrel_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Loads the current value of the pointer. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `load` method by passing - /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicBool::load`](../../std/sync/atomic/struct.AtomicBool.html#method.load). + /// [`atomic`] types via the `load` method by passing + /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::load`]. pub fn atomic_load(src: *const T) -> T; /// Loads the current value of the pointer. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `load` method by passing - /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicBool::load`](../../std/sync/atomic/struct.AtomicBool.html#method.load). + /// [`atomic`] types via the `load` method by passing + /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::load`]. pub fn atomic_load_acq(src: *const T) -> T; /// Loads the current value of the pointer. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `load` method by passing - /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicBool::load`](../../std/sync/atomic/struct.AtomicBool.html#method.load). + /// [`atomic`] types via the `load` method by passing + /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::load`]. pub fn atomic_load_relaxed(src: *const T) -> T; pub fn atomic_load_unordered(src: *const T) -> T; /// Stores the value at the specified memory location. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `store` method by passing - /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicBool::store`](../../std/sync/atomic/struct.AtomicBool.html#method.store). + /// [`atomic`] types via the `store` method by passing + /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::store`]. pub fn atomic_store(dst: *mut T, val: T); /// Stores the value at the specified memory location. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `store` method by passing - /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicBool::store`](../../std/sync/atomic/struct.AtomicBool.html#method.store). + /// [`atomic`] types via the `store` method by passing + /// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::store`]. pub fn atomic_store_rel(dst: *mut T, val: T); /// Stores the value at the specified memory location. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `store` method by passing - /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicBool::store`](../../std/sync/atomic/struct.AtomicBool.html#method.store). + /// [`atomic`] types via the `store` method by passing + /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::store`]. pub fn atomic_store_relaxed(dst: *mut T, val: T); pub fn atomic_store_unordered(dst: *mut T, val: T); /// Stores the value at the specified memory location, returning the old value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `swap` method by passing - /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicBool::swap`](../../std/sync/atomic/struct.AtomicBool.html#method.swap). + /// [`atomic`] types via the `swap` method by passing + /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::swap`]. pub fn atomic_xchg(dst: *mut T, src: T) -> T; /// Stores the value at the specified memory location, returning the old value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `swap` method by passing - /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicBool::swap`](../../std/sync/atomic/struct.AtomicBool.html#method.swap). + /// [`atomic`] types via the `swap` method by passing + /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::swap`]. pub fn atomic_xchg_acq(dst: *mut T, src: T) -> T; /// Stores the value at the specified memory location, returning the old value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `swap` method by passing - /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicBool::swap`](../../std/sync/atomic/struct.AtomicBool.html#method.swap). + /// [`atomic`] types via the `swap` method by passing + /// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::swap`]. pub fn atomic_xchg_rel(dst: *mut T, src: T) -> T; /// Stores the value at the specified memory location, returning the old value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `swap` method by passing - /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicBool::swap`](../../std/sync/atomic/struct.AtomicBool.html#method.swap). + /// [`atomic`] types via the `swap` method by passing + /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicBool::swap`]. pub fn atomic_xchg_acqrel(dst: *mut T, src: T) -> T; /// Stores the value at the specified memory location, returning the old value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `swap` method by passing - /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicBool::swap`](../../std/sync/atomic/struct.AtomicBool.html#method.swap). + /// [`atomic`] types via the `swap` method by passing + /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::swap`]. pub fn atomic_xchg_relaxed(dst: *mut T, src: T) -> T; /// Adds to the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `fetch_add` method by passing - /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicIsize::fetch_add`](../../std/sync/atomic/struct.AtomicIsize.html#method.fetch_add). + /// [`atomic`] types via the `fetch_add` method by passing + /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicIsize::fetch_add`]. pub fn atomic_xadd(dst: *mut T, src: T) -> T; /// Adds to the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `fetch_add` method by passing - /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicIsize::fetch_add`](../../std/sync/atomic/struct.AtomicIsize.html#method.fetch_add). + /// [`atomic`] types via the `fetch_add` method by passing + /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicIsize::fetch_add`]. pub fn atomic_xadd_acq(dst: *mut T, src: T) -> T; /// Adds to the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `fetch_add` method by passing - /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicIsize::fetch_add`](../../std/sync/atomic/struct.AtomicIsize.html#method.fetch_add). + /// [`atomic`] types via the `fetch_add` method by passing + /// [`Ordering::Release`] as the `order`. For example, [`AtomicIsize::fetch_add`]. pub fn atomic_xadd_rel(dst: *mut T, src: T) -> T; /// Adds to the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `fetch_add` method by passing - /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicIsize::fetch_add`](../../std/sync/atomic/struct.AtomicIsize.html#method.fetch_add). + /// [`atomic`] types via the `fetch_add` method by passing + /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicIsize::fetch_add`]. pub fn atomic_xadd_acqrel(dst: *mut T, src: T) -> T; /// Adds to the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `fetch_add` method by passing - /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicIsize::fetch_add`](../../std/sync/atomic/struct.AtomicIsize.html#method.fetch_add). + /// [`atomic`] types via the `fetch_add` method by passing + /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicIsize::fetch_add`]. pub fn atomic_xadd_relaxed(dst: *mut T, src: T) -> T; /// Subtract from the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `fetch_sub` method by passing - /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicIsize::fetch_sub`](../../std/sync/atomic/struct.AtomicIsize.html#method.fetch_sub). + /// [`atomic`] types via the `fetch_sub` method by passing + /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicIsize::fetch_sub`]. pub fn atomic_xsub(dst: *mut T, src: T) -> T; /// Subtract from the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `fetch_sub` method by passing - /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicIsize::fetch_sub`](../../std/sync/atomic/struct.AtomicIsize.html#method.fetch_sub). + /// [`atomic`] types via the `fetch_sub` method by passing + /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicIsize::fetch_sub`]. pub fn atomic_xsub_acq(dst: *mut T, src: T) -> T; /// Subtract from the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `fetch_sub` method by passing - /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicIsize::fetch_sub`](../../std/sync/atomic/struct.AtomicIsize.html#method.fetch_sub). + /// [`atomic`] types via the `fetch_sub` method by passing + /// [`Ordering::Release`] as the `order`. For example, [`AtomicIsize::fetch_sub`]. pub fn atomic_xsub_rel(dst: *mut T, src: T) -> T; /// Subtract from the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `fetch_sub` method by passing - /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicIsize::fetch_sub`](../../std/sync/atomic/struct.AtomicIsize.html#method.fetch_sub). + /// [`atomic`] types via the `fetch_sub` method by passing + /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicIsize::fetch_sub`]. pub fn atomic_xsub_acqrel(dst: *mut T, src: T) -> T; /// Subtract from the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `fetch_sub` method by passing - /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicIsize::fetch_sub`](../../std/sync/atomic/struct.AtomicIsize.html#method.fetch_sub). + /// [`atomic`] types via the `fetch_sub` method by passing + /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicIsize::fetch_sub`]. pub fn atomic_xsub_relaxed(dst: *mut T, src: T) -> T; /// Bitwise and with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `fetch_and` method by passing - /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicBool::fetch_and`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_and). + /// [`atomic`] types via the `fetch_and` method by passing + /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::fetch_and`]. pub fn atomic_and(dst: *mut T, src: T) -> T; /// Bitwise and with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `fetch_and` method by passing - /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicBool::fetch_and`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_and). + /// [`atomic`] types via the `fetch_and` method by passing + /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::fetch_and`]. pub fn atomic_and_acq(dst: *mut T, src: T) -> T; /// Bitwise and with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `fetch_and` method by passing - /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicBool::fetch_and`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_and). + /// [`atomic`] types via the `fetch_and` method by passing + /// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::fetch_and`]. pub fn atomic_and_rel(dst: *mut T, src: T) -> T; /// Bitwise and with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `fetch_and` method by passing - /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicBool::fetch_and`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_and). + /// [`atomic`] types via the `fetch_and` method by passing + /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicBool::fetch_and`]. pub fn atomic_and_acqrel(dst: *mut T, src: T) -> T; /// Bitwise and with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `fetch_and` method by passing - /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicBool::fetch_and`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_and). + /// [`atomic`] types via the `fetch_and` method by passing + /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::fetch_and`]. pub fn atomic_and_relaxed(dst: *mut T, src: T) -> T; /// Bitwise nand with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic::AtomicBool` type via the `fetch_nand` method by passing - /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicBool::fetch_nand`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_nand). + /// [`AtomicBool`] type via the `fetch_nand` method by passing + /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::fetch_nand`]. pub fn atomic_nand(dst: *mut T, src: T) -> T; /// Bitwise nand with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic::AtomicBool` type via the `fetch_nand` method by passing - /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicBool::fetch_nand`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_nand). + /// [`AtomicBool`] type via the `fetch_nand` method by passing + /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::fetch_nand`]. pub fn atomic_nand_acq(dst: *mut T, src: T) -> T; /// Bitwise nand with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic::AtomicBool` type via the `fetch_nand` method by passing - /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicBool::fetch_nand`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_nand). + /// [`AtomicBool`] type via the `fetch_nand` method by passing + /// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::fetch_nand`]. pub fn atomic_nand_rel(dst: *mut T, src: T) -> T; /// Bitwise nand with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic::AtomicBool` type via the `fetch_nand` method by passing - /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicBool::fetch_nand`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_nand). + /// [`AtomicBool`] type via the `fetch_nand` method by passing + /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicBool::fetch_nand`]. pub fn atomic_nand_acqrel(dst: *mut T, src: T) -> T; /// Bitwise nand with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic::AtomicBool` type via the `fetch_nand` method by passing - /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicBool::fetch_nand`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_nand). + /// [`AtomicBool`] type via the `fetch_nand` method by passing + /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::fetch_nand`]. pub fn atomic_nand_relaxed(dst: *mut T, src: T) -> T; /// Bitwise or with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `fetch_or` method by passing - /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicBool::fetch_or`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_or). + /// [`atomic`] types via the `fetch_or` method by passing + /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::fetch_or`]. pub fn atomic_or(dst: *mut T, src: T) -> T; /// Bitwise or with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `fetch_or` method by passing - /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicBool::fetch_or`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_or). + /// [`atomic`] types via the `fetch_or` method by passing + /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::fetch_or`]. pub fn atomic_or_acq(dst: *mut T, src: T) -> T; /// Bitwise or with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `fetch_or` method by passing - /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicBool::fetch_or`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_or). + /// [`atomic`] types via the `fetch_or` method by passing + /// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::fetch_or`]. pub fn atomic_or_rel(dst: *mut T, src: T) -> T; /// Bitwise or with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `fetch_or` method by passing - /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicBool::fetch_or`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_or). + /// [`atomic`] types via the `fetch_or` method by passing + /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicBool::fetch_or`]. pub fn atomic_or_acqrel(dst: *mut T, src: T) -> T; /// Bitwise or with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `fetch_or` method by passing - /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicBool::fetch_or`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_or). + /// [`atomic`] types via the `fetch_or` method by passing + /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::fetch_or`]. pub fn atomic_or_relaxed(dst: *mut T, src: T) -> T; /// Bitwise xor with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `fetch_xor` method by passing - /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicBool::fetch_xor`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_xor). + /// [`atomic`] types via the `fetch_xor` method by passing + /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::fetch_xor`]. pub fn atomic_xor(dst: *mut T, src: T) -> T; /// Bitwise xor with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `fetch_xor` method by passing - /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicBool::fetch_xor`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_xor). + /// [`atomic`] types via the `fetch_xor` method by passing + /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::fetch_xor`]. pub fn atomic_xor_acq(dst: *mut T, src: T) -> T; /// Bitwise xor with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `fetch_xor` method by passing - /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicBool::fetch_xor`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_xor). + /// [`atomic`] types via the `fetch_xor` method by passing + /// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::fetch_xor`]. pub fn atomic_xor_rel(dst: *mut T, src: T) -> T; /// Bitwise xor with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `fetch_xor` method by passing - /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicBool::fetch_xor`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_xor). + /// [`atomic`] types via the `fetch_xor` method by passing + /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicBool::fetch_xor`]. pub fn atomic_xor_acqrel(dst: *mut T, src: T) -> T; /// Bitwise xor with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` types via the `fetch_xor` method by passing - /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) - /// as the `order`. For example, - /// [`AtomicBool::fetch_xor`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_xor). + /// [`atomic`] types via the `fetch_xor` method by passing + /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::fetch_xor`]. pub fn atomic_xor_relaxed(dst: *mut T, src: T) -> T; /// Maximum with the current value using a signed comparison. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` signed integer types via the `fetch_max` method by passing - /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html#variant.SeqCst) - /// as the `order`. For example, - /// [`AtomicI32::fetch_max`](../../std/sync/atomic/struct.AtomicI32.html#method.fetch_max). + /// [`atomic`] signed integer types via the `fetch_max` method by passing + /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicI32::fetch_max`]. pub fn atomic_max(dst: *mut T, src: T) -> T; /// Maximum with the current value using a signed comparison. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` signed integer types via the `fetch_max` method by passing - /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html#variant.Acquire) - /// as the `order`. For example, - /// [`AtomicI32::fetch_max`](../../std/sync/atomic/struct.AtomicI32.html#method.fetch_max). + /// [`atomic`] signed integer types via the `fetch_max` method by passing + /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicI32::fetch_max`]. pub fn atomic_max_acq(dst: *mut T, src: T) -> T; /// Maximum with the current value using a signed comparison. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` signed integer types via the `fetch_max` method by passing - /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html#variant.Release) - /// as the `order`. For example, - /// [`AtomicI32::fetch_max`](../../std/sync/atomic/struct.AtomicI32.html#method.fetch_max). + /// [`atomic`] signed integer types via the `fetch_max` method by passing + /// [`Ordering::Release`] as the `order`. For example, [`AtomicI32::fetch_max`]. pub fn atomic_max_rel(dst: *mut T, src: T) -> T; /// Maximum with the current value using a signed comparison. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` signed integer types via the `fetch_max` method by passing - /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html#variant.AcqRel) - /// as the `order`. For example, - /// [`AtomicI32::fetch_max`](../../std/sync/atomic/struct.AtomicI32.html#method.fetch_max). + /// [`atomic`] signed integer types via the `fetch_max` method by passing + /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicI32::fetch_max`]. pub fn atomic_max_acqrel(dst: *mut T, src: T) -> T; /// Maximum with the current value. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` signed integer types via the `fetch_max` method by passing - /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html#variant.Relaxed) - /// as the `order`. For example, - /// [`AtomicI32::fetch_max`](../../std/sync/atomic/struct.AtomicI32.html#method.fetch_max). + /// [`atomic`] signed integer types via the `fetch_max` method by passing + /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicI32::fetch_max`]. pub fn atomic_max_relaxed(dst: *mut T, src: T) -> T; /// Minimum with the current value using a signed comparison. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` signed integer types via the `fetch_min` method by passing - /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html#variant.SeqCst) - /// as the `order`. For example, - /// [`AtomicI32::fetch_min`](../../std/sync/atomic/struct.AtomicI32.html#method.fetch_min). + /// [`atomic`] signed integer types via the `fetch_min` method by passing + /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicI32::fetch_min`]. pub fn atomic_min(dst: *mut T, src: T) -> T; /// Minimum with the current value using a signed comparison. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` signed integer types via the `fetch_min` method by passing - /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html#variant.Acquire) - /// as the `order`. For example, - /// [`AtomicI32::fetch_min`](../../std/sync/atomic/struct.AtomicI32.html#method.fetch_min). + /// [`atomic`] signed integer types via the `fetch_min` method by passing + /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicI32::fetch_min`]. pub fn atomic_min_acq(dst: *mut T, src: T) -> T; /// Minimum with the current value using a signed comparison. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` signed integer types via the `fetch_min` method by passing - /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html#variant.Release) - /// as the `order`. For example, - /// [`AtomicI32::fetch_min`](../../std/sync/atomic/struct.AtomicI32.html#method.fetch_min). + /// [`atomic`] signed integer types via the `fetch_min` method by passing + /// [`Ordering::Release`] as the `order`. For example, [`AtomicI32::fetch_min`]. pub fn atomic_min_rel(dst: *mut T, src: T) -> T; /// Minimum with the current value using a signed comparison. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` signed integer types via the `fetch_min` method by passing - /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html#variant.AcqRel) - /// as the `order`. For example, - /// [`AtomicI32::fetch_min`](../../std/sync/atomic/struct.AtomicI32.html#method.fetch_min). + /// [`atomic`] signed integer types via the `fetch_min` method by passing + /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicI32::fetch_min`]. pub fn atomic_min_acqrel(dst: *mut T, src: T) -> T; /// Minimum with the current value using a signed comparison. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` signed integer types via the `fetch_min` method by passing - /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html#variant.Relaxed) - /// as the `order`. For example, - /// [`AtomicI32::fetch_min`](../../std/sync/atomic/struct.AtomicI32.html#method.fetch_min). + /// [`atomic`] signed integer types via the `fetch_min` method by passing + /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicI32::fetch_min`]. pub fn atomic_min_relaxed(dst: *mut T, src: T) -> T; /// Minimum with the current value using an unsigned comparison. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` unsigned integer types via the `fetch_min` method by passing - /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html#variant.SeqCst) - /// as the `order`. For example, - /// [`AtomicU32::fetch_min`](../../std/sync/atomic/struct.AtomicU32.html#method.fetch_min). + /// [`atomic`] unsigned integer types via the `fetch_min` method by passing + /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicU32::fetch_min`]. pub fn atomic_umin(dst: *mut T, src: T) -> T; /// Minimum with the current value using an unsigned comparison. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` unsigned integer types via the `fetch_min` method by passing - /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html#variant.Acquire) - /// as the `order`. For example, - /// [`AtomicU32::fetch_min`](../../std/sync/atomic/struct.AtomicU32.html#method.fetch_min). + /// [`atomic`] unsigned integer types via the `fetch_min` method by passing + /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicU32::fetch_min`]. pub fn atomic_umin_acq(dst: *mut T, src: T) -> T; /// Minimum with the current value using an unsigned comparison. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` unsigned integer types via the `fetch_min` method by passing - /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html#variant.Release) - /// as the `order`. For example, - /// [`AtomicU32::fetch_min`](../../std/sync/atomic/struct.AtomicU32.html#method.fetch_min). + /// [`atomic`] unsigned integer types via the `fetch_min` method by passing + /// [`Ordering::Release`] as the `order`. For example, [`AtomicU32::fetch_min`]. pub fn atomic_umin_rel(dst: *mut T, src: T) -> T; /// Minimum with the current value using an unsigned comparison. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` unsigned integer types via the `fetch_min` method by passing - /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html#variant.AcqRel) - /// as the `order`. For example, - /// [`AtomicU32::fetch_min`](../../std/sync/atomic/struct.AtomicU32.html#method.fetch_min). + /// [`atomic`] unsigned integer types via the `fetch_min` method by passing + /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicU32::fetch_min`]. pub fn atomic_umin_acqrel(dst: *mut T, src: T) -> T; /// Minimum with the current value using an unsigned comparison. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` unsigned integer types via the `fetch_min` method by passing - /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html#variant.Relaxed) - /// as the `order`. For example, - /// [`AtomicU32::fetch_min`](../../std/sync/atomic/struct.AtomicU32.html#method.fetch_min). + /// [`atomic`] unsigned integer types via the `fetch_min` method by passing + /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicU32::fetch_min`]. pub fn atomic_umin_relaxed(dst: *mut T, src: T) -> T; /// Maximum with the current value using an unsigned comparison. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` unsigned integer types via the `fetch_max` method by passing - /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html#variant.SeqCst) - /// as the `order`. For example, - /// [`AtomicU32::fetch_max`](../../std/sync/atomic/struct.AtomicU32.html#method.fetch_max). + /// [`atomic`] unsigned integer types via the `fetch_max` method by passing + /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicU32::fetch_max`]. pub fn atomic_umax(dst: *mut T, src: T) -> T; /// Maximum with the current value using an unsigned comparison. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` unsigned integer types via the `fetch_max` method by passing - /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html#variant.Acquire) - /// as the `order`. For example, - /// [`AtomicU32::fetch_max`](../../std/sync/atomic/struct.AtomicU32.html#method.fetch_max). + /// [`atomic`] unsigned integer types via the `fetch_max` method by passing + /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicU32::fetch_max`]. pub fn atomic_umax_acq(dst: *mut T, src: T) -> T; /// Maximum with the current value using an unsigned comparison. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` unsigned integer types via the `fetch_max` method by passing - /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html#variant.Release) - /// as the `order`. For example, - /// [`AtomicU32::fetch_max`](../../std/sync/atomic/struct.AtomicU32.html#method.fetch_max). + /// [`atomic`] unsigned integer types via the `fetch_max` method by passing + /// [`Ordering::Release`] as the `order`. For example, [`AtomicU32::fetch_max`]. pub fn atomic_umax_rel(dst: *mut T, src: T) -> T; /// Maximum with the current value using an unsigned comparison. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` unsigned integer types via the `fetch_max` method by passing - /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html#variant.AcqRel) - /// as the `order`. For example, - /// [`AtomicU32::fetch_max`](../../std/sync/atomic/struct.AtomicU32.html#method.fetch_max). + /// [`atomic`] unsigned integer types via the `fetch_max` method by passing + /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicU32::fetch_max`]. pub fn atomic_umax_acqrel(dst: *mut T, src: T) -> T; /// Maximum with the current value using an unsigned comparison. /// /// The stabilized version of this intrinsic is available on the - /// `std::sync::atomic` unsigned integer types via the `fetch_max` method by passing - /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html#variant.Relaxed) - /// as the `order`. For example, - /// [`AtomicU32::fetch_max`](../../std/sync/atomic/struct.AtomicU32.html#method.fetch_max). + /// [`atomic`] unsigned integer types via the `fetch_max` method by passing + /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicU32::fetch_max`]. pub fn atomic_umax_relaxed(dst: *mut T, src: T) -> T; /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction @@ -823,33 +628,25 @@ /// An atomic fence. /// /// The stabilized version of this intrinsic is available in - /// [`std::sync::atomic::fence`](../../std/sync/atomic/fn.fence.html) - /// by passing - /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html#variant.SeqCst) + /// [`atomic::fence`] by passing [`Ordering::SeqCst`] /// as the `order`. pub fn atomic_fence(); /// An atomic fence. /// /// The stabilized version of this intrinsic is available in - /// [`std::sync::atomic::fence`](../../std/sync/atomic/fn.fence.html) - /// by passing - /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html#variant.Acquire) + /// [`atomic::fence`] by passing [`Ordering::Acquire`] /// as the `order`. pub fn atomic_fence_acq(); /// An atomic fence. /// /// The stabilized version of this intrinsic is available in - /// [`std::sync::atomic::fence`](../../std/sync/atomic/fn.fence.html) - /// by passing - /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html#variant.Release) + /// [`atomic::fence`] by passing [`Ordering::Release`] /// as the `order`. pub fn atomic_fence_rel(); /// An atomic fence. /// /// The stabilized version of this intrinsic is available in - /// [`std::sync::atomic::fence`](../../std/sync/atomic/fn.fence.html) - /// by passing - /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html#variant.AcqRel) + /// [`atomic::fence`] by passing [`Ordering::AcqRel`] /// as the `order`. pub fn atomic_fence_acqrel(); @@ -861,9 +658,7 @@ /// such as when interacting with signal handlers. /// /// The stabilized version of this intrinsic is available in - /// [`std::sync::atomic::compiler_fence`](../../std/sync/atomic/fn.compiler_fence.html) - /// by passing - /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html#variant.SeqCst) + /// [`atomic::compiler_fence`] by passing [`Ordering::SeqCst`] /// as the `order`. pub fn atomic_singlethreadfence(); /// A compiler-only memory barrier. @@ -874,9 +669,7 @@ /// such as when interacting with signal handlers. /// /// The stabilized version of this intrinsic is available in - /// [`std::sync::atomic::compiler_fence`](../../std/sync/atomic/fn.compiler_fence.html) - /// by passing - /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html#variant.Acquire) + /// [`atomic::compiler_fence`] by passing [`Ordering::Acquire`] /// as the `order`. pub fn atomic_singlethreadfence_acq(); /// A compiler-only memory barrier. @@ -887,9 +680,7 @@ /// such as when interacting with signal handlers. /// /// The stabilized version of this intrinsic is available in - /// [`std::sync::atomic::compiler_fence`](../../std/sync/atomic/fn.compiler_fence.html) - /// by passing - /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html#variant.Release) + /// [`atomic::compiler_fence`] by passing [`Ordering::Release`] /// as the `order`. pub fn atomic_singlethreadfence_rel(); /// A compiler-only memory barrier. @@ -900,9 +691,7 @@ /// such as when interacting with signal handlers. /// /// The stabilized version of this intrinsic is available in - /// [`std::sync::atomic::compiler_fence`](../../std/sync/atomic/fn.compiler_fence.html) - /// by passing - /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html#variant.AcqRel) + /// [`atomic::compiler_fence`] by passing [`Ordering::AcqRel`] /// as the `order`. pub fn atomic_singlethreadfence_acqrel(); @@ -930,8 +719,7 @@ /// macro, which panics when it is executed, it is *undefined behavior* to /// reach code marked with this function. /// - /// The stabilized version of this intrinsic is - /// [`std::hint::unreachable_unchecked`](../../std/hint/fn.unreachable_unchecked.html). + /// The stabilized version of this intrinsic is [`crate::hint::unreachable_unchecked`]. #[rustc_const_unstable(feature = "const_unreachable_unchecked", issue = "53188")] pub fn unreachable() -> !; @@ -975,8 +763,7 @@ /// More specifically, this is the offset in bytes between successive /// items of the same type, including alignment padding. /// - /// The stabilized version of this intrinsic is - /// [`std::mem::size_of`](../../std/mem/fn.size_of.html). + /// The stabilized version of this intrinsic is [`size_of`]. #[rustc_const_stable(feature = "const_size_of", since = "1.40.0")] pub fn size_of() -> usize; @@ -984,14 +771,12 @@ /// /// Drop glue is not run on the destination. /// - /// The stabilized version of this intrinsic is - /// [`std::ptr::write`](../../std/ptr/fn.write.html). + /// The stabilized version of this intrinsic is [`crate::ptr::write`]. pub fn move_val_init(dst: *mut T, src: T); /// The minimum alignment of a type. /// - /// The stabilized version of this intrinsic is - /// [`std::mem::align_of`](../../std/mem/fn.align_of.html). + /// The stabilized version of this intrinsic is [`crate::mem::align_of`]. #[rustc_const_stable(feature = "const_min_align_of", since = "1.40.0")] pub fn min_align_of() -> usize; /// The preferred alignment of a type. @@ -1002,21 +787,18 @@ /// The size of the referenced value in bytes. /// - /// The stabilized version of this intrinsic is - /// [`std::mem::size_of_val`](../../std/mem/fn.size_of_val.html). + /// The stabilized version of this intrinsic is [`size_of_val`]. #[rustc_const_unstable(feature = "const_size_of_val", issue = "46571")] pub fn size_of_val(_: *const T) -> usize; /// The required alignment of the referenced value. /// - /// The stabilized version of this intrinsic is - /// [`std::mem::align_of_val`](../../std/mem/fn.align_of_val.html). + /// The stabilized version of this intrinsic is [`crate::mem::align_of_val`]. #[rustc_const_unstable(feature = "const_align_of_val", issue = "46571")] pub fn min_align_of_val(_: *const T) -> usize; /// Gets a static string slice containing the name of a type. /// - /// The stabilized version of this intrinsic is - /// [`std::any::type_name`](../../std/any/fn.type_name.html) + /// The stabilized version of this intrinsic is [`crate::any::type_name`]. #[rustc_const_unstable(feature = "const_type_name", issue = "63084")] pub fn type_name() -> &'static str; @@ -1024,8 +806,7 @@ /// function will return the same value for a type regardless of whichever /// crate it is invoked in. /// - /// The stabilized version of this intrinsic is - /// [`std::any::TypeId::of`](../../std/any/struct.TypeId.html#method.of) + /// The stabilized version of this intrinsic is [`crate::any::TypeId::of`]. #[rustc_const_stable(feature = "const_type_id", since = "1.46.0")] pub fn type_id() -> u64; @@ -1049,15 +830,14 @@ /// Gets a reference to a static `Location` indicating where it was called. /// - /// Consider using [`std::panic::Location::caller`](../../std/panic/struct.Location.html#method.caller) - /// instead. + /// Consider using [`crate::panic::Location::caller`] instead. #[rustc_const_unstable(feature = "const_caller_location", issue = "47809")] pub fn caller_location() -> &'static crate::panic::Location<'static>; /// Moves a value out of scope without running drop glue. /// - /// This exists solely for [`mem::forget_unsized`](../../std/mem/fn.forget_unsized.html); - /// normal `forget` uses `ManuallyDrop` instead. + /// This exists solely for [`mem::forget_unsized`]; normal `forget` uses + /// `ManuallyDrop` instead. pub fn forget(_: T); /// Reinterprets the bits of a value of one type as another type. @@ -1300,8 +1080,7 @@ /// If the actual type neither requires drop glue nor implements /// `Copy`, then the return value of this function is unspecified. /// - /// The stabilized version of this intrinsic is - /// [`std::mem::needs_drop`](../../std/mem/fn.needs_drop.html). + /// The stabilized version of this intrinsic is [`needs_drop`]. #[rustc_const_stable(feature = "const_needs_drop", since = "1.40.0")] pub fn needs_drop() -> bool; @@ -1371,13 +1150,11 @@ /// Performs a volatile load from the `src` pointer. /// - /// The stabilized version of this intrinsic is - /// [`std::ptr::read_volatile`](../../std/ptr/fn.read_volatile.html). + /// The stabilized version of this intrinsic is [`crate::ptr::read_volatile`]. pub fn volatile_load(src: *const T) -> T; /// Performs a volatile store to the `dst` pointer. /// - /// The stabilized version of this intrinsic is - /// [`std::ptr::write_volatile`](../../std/ptr/fn.write_volatile.html). + /// The stabilized version of this intrinsic is [`crate::ptr::write_volatile`]. pub fn volatile_store(dst: *mut T, val: T); /// Performs a volatile load from the `src` pointer @@ -1526,22 +1303,22 @@ /// Returns the minimum of two `f32` values. /// /// The stabilized version of this intrinsic is - /// [`std::f32::min`](../../std/primitive.f32.html#method.min) + /// [`f32::min`] pub fn minnumf32(x: f32, y: f32) -> f32; /// Returns the minimum of two `f64` values. /// /// The stabilized version of this intrinsic is - /// [`std::f64::min`](../../std/primitive.f64.html#method.min) + /// [`f64::min`] pub fn minnumf64(x: f64, y: f64) -> f64; /// Returns the maximum of two `f32` values. /// /// The stabilized version of this intrinsic is - /// [`std::f32::max`](../../std/primitive.f32.html#method.max) + /// [`f32::max`] pub fn maxnumf32(x: f32, y: f32) -> f32; /// Returns the maximum of two `f64` values. /// /// The stabilized version of this intrinsic is - /// [`std::f64::max`](../../std/primitive.f64.html#method.max) + /// [`f64::max`] pub fn maxnumf64(x: f64, y: f64) -> f64; /// Copies the sign from `y` to `x` for `f32` values. @@ -1648,15 +1425,14 @@ /// Convert with LLVM’s fptoui/fptosi, which may return undef for values out of range /// () /// - /// Stabilized as [`f32::to_int_unchecked`](../../std/primitive.f32.html#method.to_int_unchecked) - /// and [`f64::to_int_unchecked`](../../std/primitive.f64.html#method.to_int_unchecked). + /// Stabilized as [`f32::to_int_unchecked`] and [`f64::to_int_unchecked`]. pub fn float_to_int_unchecked(value: Float) -> Int; /// Returns the number of bits set in an integer type `T` /// /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `count_ones` method. For example, - /// [`std::u32::count_ones`](../../std/primitive.u32.html#method.count_ones) + /// [`u32::count_ones`] #[rustc_const_stable(feature = "const_ctpop", since = "1.40.0")] pub fn ctpop(x: T) -> T; @@ -1664,7 +1440,7 @@ /// /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `leading_zeros` method. For example, - /// [`std::u32::leading_zeros`](../../std/primitive.u32.html#method.leading_zeros) + /// [`u32::leading_zeros`] /// /// # Examples /// @@ -1715,7 +1491,7 @@ /// /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `trailing_zeros` method. For example, - /// [`std::u32::trailing_zeros`](../../std/primitive.u32.html#method.trailing_zeros) + /// [`u32::trailing_zeros`] /// /// # Examples /// @@ -1766,7 +1542,7 @@ /// /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `swap_bytes` method. For example, - /// [`std::u32::swap_bytes`](../../std/primitive.u32.html#method.swap_bytes) + /// [`u32::swap_bytes`] #[rustc_const_stable(feature = "const_bswap", since = "1.40.0")] pub fn bswap(x: T) -> T; @@ -1774,7 +1550,7 @@ /// /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `reverse_bits` method. For example, - /// [`std::u32::reverse_bits`](../../std/primitive.u32.html#method.reverse_bits) + /// [`u32::reverse_bits`] #[rustc_const_stable(feature = "const_bitreverse", since = "1.40.0")] pub fn bitreverse(x: T) -> T; @@ -1782,7 +1558,7 @@ /// /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `overflowing_add` method. For example, - /// [`std::u32::overflowing_add`](../../std/primitive.u32.html#method.overflowing_add) + /// [`u32::overflowing_add`] #[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")] pub fn add_with_overflow(x: T, y: T) -> (T, bool); @@ -1790,7 +1566,7 @@ /// /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `overflowing_sub` method. For example, - /// [`std::u32::overflowing_sub`](../../std/primitive.u32.html#method.overflowing_sub) + /// [`u32::overflowing_sub`] #[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")] pub fn sub_with_overflow(x: T, y: T) -> (T, bool); @@ -1798,7 +1574,7 @@ /// /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `overflowing_mul` method. For example, - /// [`std::u32::overflowing_mul`](../../std/primitive.u32.html#method.overflowing_mul) + /// [`u32::overflowing_mul`] #[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")] pub fn mul_with_overflow(x: T, y: T) -> (T, bool); @@ -1813,7 +1589,7 @@ /// /// Safe wrappers for this intrinsic are available on the integer /// primitives via the `checked_div` method. For example, - /// [`std::u32::checked_div`](../../std/primitive.u32.html#method.checked_div) + /// [`u32::checked_div`] #[rustc_const_unstable(feature = "const_int_unchecked_arith", issue = "none")] pub fn unchecked_div(x: T, y: T) -> T; /// Returns the remainder of an unchecked division, resulting in @@ -1821,7 +1597,7 @@ /// /// Safe wrappers for this intrinsic are available on the integer /// primitives via the `checked_rem` method. For example, - /// [`std::u32::checked_rem`](../../std/primitive.u32.html#method.checked_rem) + /// [`u32::checked_rem`] #[rustc_const_unstable(feature = "const_int_unchecked_arith", issue = "none")] pub fn unchecked_rem(x: T, y: T) -> T; @@ -1830,7 +1606,7 @@ /// /// Safe wrappers for this intrinsic are available on the integer /// primitives via the `checked_shl` method. For example, - /// [`std::u32::checked_shl`](../../std/primitive.u32.html#method.checked_shl) + /// [`u32::checked_shl`] #[rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0")] pub fn unchecked_shl(x: T, y: T) -> T; /// Performs an unchecked right shift, resulting in undefined behavior when @@ -1838,7 +1614,7 @@ /// /// Safe wrappers for this intrinsic are available on the integer /// primitives via the `checked_shr` method. For example, - /// [`std::u32::checked_shr`](../../std/primitive.u32.html#method.checked_shr) + /// [`u32::checked_shr`] #[rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0")] pub fn unchecked_shr(x: T, y: T) -> T; @@ -1867,7 +1643,7 @@ /// /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `rotate_left` method. For example, - /// [`std::u32::rotate_left`](../../std/primitive.u32.html#method.rotate_left) + /// [`u32::rotate_left`] #[rustc_const_stable(feature = "const_int_rotate", since = "1.40.0")] pub fn rotate_left(x: T, y: T) -> T; @@ -1875,7 +1651,7 @@ /// /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `rotate_right` method. For example, - /// [`std::u32::rotate_right`](../../std/primitive.u32.html#method.rotate_right) + /// [`u32::rotate_right`] #[rustc_const_stable(feature = "const_int_rotate", since = "1.40.0")] pub fn rotate_right(x: T, y: T) -> T; @@ -1883,21 +1659,21 @@ /// /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `checked_add` method. For example, - /// [`std::u32::checked_add`](../../std/primitive.u32.html#method.checked_add) + /// [`u32::checked_add`] #[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")] pub fn wrapping_add(a: T, b: T) -> T; /// Returns (a - b) mod 2N, where N is the width of T in bits. /// /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `checked_sub` method. For example, - /// [`std::u32::checked_sub`](../../std/primitive.u32.html#method.checked_sub) + /// [`u32::checked_sub`] #[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")] pub fn wrapping_sub(a: T, b: T) -> T; /// Returns (a * b) mod 2N, where N is the width of T in bits. /// /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `checked_mul` method. For example, - /// [`std::u32::checked_mul`](../../std/primitive.u32.html#method.checked_mul) + /// [`u32::checked_mul`] #[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")] pub fn wrapping_mul(a: T, b: T) -> T; @@ -1905,30 +1681,28 @@ /// /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `saturating_add` method. For example, - /// [`std::u32::saturating_add`](../../std/primitive.u32.html#method.saturating_add) + /// [`u32::saturating_add`] #[rustc_const_stable(feature = "const_int_saturating", since = "1.40.0")] pub fn saturating_add(a: T, b: T) -> T; /// Computes `a - b`, while saturating at numeric bounds. /// /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `saturating_sub` method. For example, - /// [`std::u32::saturating_sub`](../../std/primitive.u32.html#method.saturating_sub) + /// [`u32::saturating_sub`] #[rustc_const_stable(feature = "const_int_saturating", since = "1.40.0")] pub fn saturating_sub(a: T, b: T) -> T; /// Returns the value of the discriminant for the variant in 'v', /// cast to a `u64`; if `T` has no discriminant, returns 0. /// - /// The stabilized version of this intrinsic is - /// [`std::mem::discriminant`](../../std/mem/fn.discriminant.html) + /// The stabilized version of this intrinsic is [`crate::mem::discriminant`]. #[rustc_const_unstable(feature = "const_discriminant", issue = "69821")] pub fn discriminant_value(v: &T) -> ::Discriminant; /// Returns the number of variants of the type `T` cast to a `usize`; /// if `T` has no variants, returns 0. Uninhabited variants will be counted. /// - /// The to-be-stabilized version of this intrinsic is - /// [`std::mem::variant_count`](../../std/mem/fn.variant_count.html) + /// The to-be-stabilized version of this intrinsic is [`variant_count`]. #[rustc_const_unstable(feature = "variant_count", issue = "73662")] pub fn variant_count() -> usize; @@ -1989,7 +1763,6 @@ pub(crate) fn is_nonoverlapping(src: *const T, dst: *const T, count: usize) - /// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`], but /// with the argument order swapped. /// -/// [`copy`]: ./fn.copy.html /// [`memcpy`]: https://en.cppreference.com/w/c/string/byte/memcpy /// /// # Safety @@ -2014,10 +1787,9 @@ pub(crate) fn is_nonoverlapping(src: *const T, dst: *const T, count: usize) - /// Note that even if the effectively copied size (`count * size_of::()`) is /// `0`, the pointers must be non-NULL and properly aligned. /// -/// [`Copy`]: ../marker/trait.Copy.html -/// [`read`]: ../ptr/fn.read.html -/// [read-ownership]: ../ptr/fn.read.html#ownership-of-the-returned-value -/// [valid]: ../ptr/index.html#safety +/// [`read`]: crate::ptr::read +/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value +/// [valid]: crate::ptr#safety /// /// # Examples /// @@ -2096,7 +1868,6 @@ pub unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { /// order swapped. Copying takes place as if the bytes were copied from `src` /// to a temporary array and then copied from the array to `dst`. /// -/// [`copy_nonoverlapping`]: ./fn.copy_nonoverlapping.html /// [`memmove`]: https://en.cppreference.com/w/c/string/byte/memmove /// /// # Safety @@ -2117,10 +1888,9 @@ pub unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { /// Note that even if the effectively copied size (`count * size_of::()`) is /// `0`, the pointers must be non-NULL and properly aligned. /// -/// [`Copy`]: ../marker/trait.Copy.html -/// [`read`]: ../ptr/fn.read.html -/// [read-ownership]: ../ptr/fn.read.html#ownership-of-the-returned-value -/// [valid]: ../ptr/index.html#safety +/// [`read`]: crate::ptr::read +/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value +/// [valid]: crate::ptr#safety /// /// # Examples /// @@ -2178,7 +1948,7 @@ pub unsafe fn copy(src: *const T, dst: *mut T, count: usize) { /// Note that even if the effectively copied size (`count * size_of::()`) is /// `0`, the pointer must be non-NULL and properly aligned. /// -/// [valid]: ../ptr/index.html#safety +/// [valid]: crate::ptr#safety /// /// # Examples /// diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs index d2e2fc04a2b..94ba6f56476 100644 --- a/library/core/src/iter/adapters/fuse.rs +++ b/library/core/src/iter/adapters/fuse.rs @@ -1,7 +1,7 @@ use crate::intrinsics; -use crate::iter::{ - DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator, TrustedRandomAccess, -}; +use crate::iter::adapters::zip::try_get_unchecked; +use crate::iter::TrustedRandomAccess; +use crate::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator}; use crate::ops::Try; /// An iterator that yields `None` forever after the underlying iterator @@ -114,6 +114,19 @@ fn find

(&mut self, predicate: P) -> Option { FuseImpl::find(self, predicate) } + + #[inline] + unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item + where + Self: TrustedRandomAccess, + { + match self.iter { + // SAFETY: the caller must uphold the contract for `Iterator::get_unchecked`. + Some(ref mut iter) => unsafe { try_get_unchecked(iter, idx) }, + // SAFETY: the caller asserts there is an item at `i`, so we're not exhausted. + None => unsafe { intrinsics::unreachable() }, + } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -172,19 +185,12 @@ fn is_empty(&self) -> bool { } } +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl TrustedRandomAccess for Fuse where I: TrustedRandomAccess, { - unsafe fn get_unchecked(&mut self, i: usize) -> I::Item { - match self.iter { - // SAFETY: the caller must uphold the contract for `TrustedRandomAccess::get_unchecked`. - Some(ref mut iter) => unsafe { iter.get_unchecked(i) }, - // SAFETY: the caller asserts there is an item at `i`, so we're not exhausted. - None => unsafe { intrinsics::unreachable() }, - } - } - fn may_have_side_effect() -> bool { I::may_have_side_effect() } diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index 133643a0c7f..9fcd137e1a6 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -15,6 +15,7 @@ #[stable(feature = "rust1", since = "1.0.0")] pub use self::flatten::{FlatMap, Flatten}; pub use self::fuse::Fuse; +use self::zip::try_get_unchecked; pub(crate) use self::zip::TrustedRandomAccess; pub use self::zip::Zip; @@ -213,6 +214,15 @@ fn last(self) -> Option { fn count(self) -> usize { self.it.count() } + + unsafe fn get_unchecked(&mut self, idx: usize) -> T + where + Self: TrustedRandomAccess, + { + // SAFETY: the caller must uphold the contract for + // `Iterator::get_unchecked`. + *unsafe { try_get_unchecked(&mut self.it, idx) } + } } #[stable(feature = "iter_copied", since = "1.36.0")] @@ -266,16 +276,11 @@ impl<'a, I, T: 'a> FusedIterator for Copied } #[doc(hidden)] -unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Copied +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccess for Copied where - I: TrustedRandomAccess, - T: Copy, + I: TrustedRandomAccess, { - unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item { - // SAFETY: the caller must uphold the contract for `TrustedRandomAccess::get_unchecked`. - unsafe { *self.it.get_unchecked(i) } - } - #[inline] fn may_have_side_effect() -> bool { I::may_have_side_effect() @@ -344,6 +349,15 @@ fn fold(self, init: Acc, f: F) -> Acc { self.it.map(T::clone).fold(init, f) } + + unsafe fn get_unchecked(&mut self, idx: usize) -> T + where + Self: TrustedRandomAccess, + { + // SAFETY: the caller must uphold the contract for + // `Iterator::get_unchecked`. + unsafe { try_get_unchecked(&mut self.it, idx).clone() } + } } #[stable(feature = "iter_cloned", since = "1.1.0")] @@ -397,36 +411,14 @@ impl<'a, I, T: 'a> FusedIterator for Cloned } #[doc(hidden)] -unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Cloned +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccess for Cloned where - I: TrustedRandomAccess, - T: Clone, -{ - default unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item { - // SAFETY: the caller must uphold the contract for `TrustedRandomAccess::get_unchecked`. - unsafe { self.it.get_unchecked(i) }.clone() - } - - #[inline] - default fn may_have_side_effect() -> bool { - true - } -} - -#[doc(hidden)] -unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Cloned -where - I: TrustedRandomAccess, - T: Copy, + I: TrustedRandomAccess, { - unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item { - // SAFETY: the caller must uphold the contract for `TrustedRandomAccess::get_unchecked`. - unsafe { *self.it.get_unchecked(i) } - } - #[inline] fn may_have_side_effect() -> bool { - I::may_have_side_effect() + true } } @@ -872,6 +864,15 @@ fn fold(self, init: Acc, g: G) -> Acc { self.iter.fold(init, map_fold(self.f, g)) } + + unsafe fn get_unchecked(&mut self, idx: usize) -> B + where + Self: TrustedRandomAccess, + { + // SAFETY: the caller must uphold the contract for + // `Iterator::get_unchecked`. + unsafe { (self.f)(try_get_unchecked(&mut self.iter, idx)) } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -927,15 +928,11 @@ unsafe impl TrustedLen for Map } #[doc(hidden)] -unsafe impl TrustedRandomAccess for Map +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccess for Map where I: TrustedRandomAccess, - F: FnMut(I::Item) -> B, { - unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item { - // SAFETY: the caller must uphold the contract for `TrustedRandomAccess::get_unchecked`. - (self.f)(unsafe { self.iter.get_unchecked(i) }) - } #[inline] fn may_have_side_effect() -> bool { true @@ -1306,6 +1303,16 @@ fn enumerate( self.iter.fold(init, enumerate(self.count, fold)) } + + unsafe fn get_unchecked(&mut self, idx: usize) -> ::Item + where + Self: TrustedRandomAccess, + { + // SAFETY: the caller must uphold the contract for + // `Iterator::get_unchecked`. + let value = unsafe { try_get_unchecked(&mut self.iter, idx) }; + (Add::add(self.count, idx), value) + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1391,15 +1398,11 @@ fn is_empty(&self) -> bool { } #[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl TrustedRandomAccess for Enumerate where I: TrustedRandomAccess, { - unsafe fn get_unchecked(&mut self, i: usize) -> (usize, I::Item) { - // SAFETY: the caller must uphold the contract for `TrustedRandomAccess::get_unchecked`. - (self.count + i, unsafe { self.iter.get_unchecked(i) }) - } - fn may_have_side_effect() -> bool { I::may_have_side_effect() } diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index 985e6561665..6cb61896483 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -1,4 +1,5 @@ use crate::cmp; +use crate::fmt::{self, Debug}; use super::super::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator, TrustedLen}; @@ -9,7 +10,7 @@ /// /// [`zip`]: trait.Iterator.html#method.zip /// [`Iterator`]: trait.Iterator.html -#[derive(Clone, Debug)] +#[derive(Clone)] #[must_use = "iterators are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] pub struct Zip { @@ -56,6 +57,16 @@ fn size_hint(&self) -> (usize, Option) { fn nth(&mut self, n: usize) -> Option { ZipImpl::nth(self, n) } + + #[inline] + unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item + where + Self: TrustedRandomAccess, + { + // SAFETY: `ZipImpl::get_unchecked` has same safety requirements as + // `Iterator::get_unchecked`. + unsafe { ZipImpl::get_unchecked(self, idx) } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -82,6 +93,10 @@ fn next_back(&mut self) -> Option where A: DoubleEndedIterator + ExactSizeIterator, B: DoubleEndedIterator + ExactSizeIterator; + // This has the same safety requirements as `Iterator::get_unchecked` + unsafe fn get_unchecked(&mut self, idx: usize) -> ::Item + where + Self: Iterator + TrustedRandomAccess; } // General Zip impl @@ -156,16 +171,23 @@ impl ZipImpl for Zip (lower, upper) } + + default unsafe fn get_unchecked(&mut self, _idx: usize) -> ::Item + where + Self: TrustedRandomAccess, + { + unreachable!("Always specialized"); + } } #[doc(hidden)] impl ZipImpl for Zip where - A: TrustedRandomAccess, - B: TrustedRandomAccess, + A: TrustedRandomAccess + Iterator, + B: TrustedRandomAccess + Iterator, { fn new(a: A, b: B) -> Self { - let len = cmp::min(a.len(), b.len()); + let len = cmp::min(a.size(), b.size()); Zip { a, b, index: 0, len } } @@ -176,7 +198,7 @@ fn next(&mut self) -> Option<(A::Item, B::Item)> { self.index += 1; // SAFETY: `i` is smaller than `self.len`, thus smaller than `self.a.len()` and `self.b.len()` unsafe { Some((self.a.get_unchecked(i), self.b.get_unchecked(i))) } - } else if A::may_have_side_effect() && self.index < self.a.len() { + } else if A::may_have_side_effect() && self.index < self.a.size() { // match the base implementation's potential side effects // SAFETY: we just checked that `self.index` < `self.a.len()` unsafe { @@ -227,20 +249,26 @@ fn next_back(&mut self) -> Option<(A::Item, B::Item)> A: DoubleEndedIterator + ExactSizeIterator, B: DoubleEndedIterator + ExactSizeIterator, { - // Adjust a, b to equal length - if A::may_have_side_effect() { - let sz = self.a.len(); - if sz > self.len { - for _ in 0..sz - cmp::max(self.len, self.index) { - self.a.next_back(); + let a_side_effect = A::may_have_side_effect(); + let b_side_effect = B::may_have_side_effect(); + if a_side_effect || b_side_effect { + let sz_a = self.a.size(); + let sz_b = self.b.size(); + // Adjust a, b to equal length, make sure that only the first call + // of `next_back` does this, otherwise we will break the restriction + // on calls to `self.next_back()` after calling `get_unchecked()`. + if sz_a != sz_b { + let sz_a = self.a.size(); + if a_side_effect && sz_a > self.len { + for _ in 0..sz_a - cmp::max(self.len, self.index) { + self.a.next_back(); + } } - } - } - if B::may_have_side_effect() { - let sz = self.b.len(); - if sz > self.len { - for _ in 0..sz - self.len { - self.b.next_back(); + let sz_b = self.b.size(); + if b_side_effect && sz_b > self.len { + for _ in 0..sz_b - self.len { + self.b.next_back(); + } } } } @@ -254,6 +282,13 @@ fn next_back(&mut self) -> Option<(A::Item, B::Item)> None } } + + #[inline] + unsafe fn get_unchecked(&mut self, idx: usize) -> ::Item { + // SAFETY: the caller must uphold the contract for + // `Iterator::get_unchecked`. + unsafe { (self.a.get_unchecked(idx), self.b.get_unchecked(idx)) } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -265,16 +300,12 @@ impl ExactSizeIterator for Zip } #[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl TrustedRandomAccess for Zip where A: TrustedRandomAccess, B: TrustedRandomAccess, { - unsafe fn get_unchecked(&mut self, i: usize) -> (A::Item, B::Item) { - // SAFETY: the caller must uphold the contract for `TrustedRandomAccess::get_unchecked`. - unsafe { (self.a.get_unchecked(i), self.b.get_unchecked(i)) } - } - fn may_have_side_effect() -> bool { A::may_have_side_effect() || B::may_have_side_effect() } @@ -296,19 +327,109 @@ unsafe impl TrustedLen for Zip { } +#[stable(feature = "rust1", since = "1.0.0")] +impl Debug for Zip { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ZipFmt::fmt(self, f) + } +} + +trait ZipFmt { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result; +} + +impl ZipFmt for Zip { + default fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Zip").field("a", &self.a).field("b", &self.b).finish() + } +} + +impl ZipFmt for Zip { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // It's *not safe* to call fmt on the contained iterators, since once + // we start iterating they're in strange, potentially unsafe, states. + f.debug_struct("Zip").finish() + } +} + /// An iterator whose items are random-accessible efficiently /// /// # Safety /// -/// The iterator's .len() and size_hint() must be exact. -/// `.len()` must be cheap to call. +/// The iterator's `size_hint` must be exact and cheap to call. +/// +/// `size` may not be overridden. +/// +/// `::get_unchecked` must be safe to call provided the +/// following conditions are met. /// -/// .get_unchecked() must return distinct mutable references for distinct -/// indices (if applicable), and must return a valid reference if index is in -/// 0..self.len(). -pub(crate) unsafe trait TrustedRandomAccess: ExactSizeIterator { - unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item; +/// 1. `0 <= idx` and `idx < self.size()`. +/// 2. If `self: !Clone`, then `get_unchecked` is never called with the same +/// index on `self` more than once. +/// 3. After `self.get_unchecked(idx)` has been called then `next_back` will +/// only be called at most `self.size() - idx - 1` times. +/// 4. After `get_unchecked` is called, then only the following methods will be +/// called on `self`: +/// * `std::clone::Clone::clone` +/// * `std::iter::Iterator::size_hint()` +/// * `std::iter::Iterator::next_back()` +/// * `std::iter::Iterator::get_unchecked()` +/// * `std::iter::TrustedRandomAccess::size()` +/// +/// Further, given that these conditions are met, it must guarantee that: +/// +/// * It does not change the value returned from `size_hint` +/// * It must be safe to call the methods listed above on `self` after calling +/// `get_unchecked`, assuming that the required traits are implemented. +/// * It must also be safe to drop `self` after calling `get_unchecked`. +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +#[rustc_specialization_trait] +pub unsafe trait TrustedRandomAccess: Sized { + // Convenience method. + fn size(&self) -> usize + where + Self: Iterator, + { + self.size_hint().0 + } /// Returns `true` if getting an iterator element may have /// side effects. Remember to take inner iterators into account. fn may_have_side_effect() -> bool; } + +/// Like `Iterator::get_unchecked`, but doesn't require the compiler to +/// know that `U: TrustedRandomAccess`. +/// +/// ## Safety +/// +/// Same requirements calling `get_unchecked` directly. +#[doc(hidden)] +pub(in crate::iter::adapters) unsafe fn try_get_unchecked(it: &mut I, idx: usize) -> I::Item +where + I: Iterator, +{ + // SAFETY: the caller must uphold the contract for + // `Iterator::get_unchecked`. + unsafe { it.try_get_unchecked(idx) } +} + +unsafe trait SpecTrustedRandomAccess: Iterator { + /// If `Self: TrustedRandomAccess`, it must be safe to call a + /// `Iterator::get_unchecked(self, index)`. + unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item; +} + +unsafe impl SpecTrustedRandomAccess for I { + default unsafe fn try_get_unchecked(&mut self, _: usize) -> Self::Item { + panic!("Should only be called on TrustedRandomAccess iterators"); + } +} + +unsafe impl SpecTrustedRandomAccess for I { + unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item { + // SAFETY: the caller must uphold the contract for + // `Iterator::get_unchecked`. + unsafe { self.get_unchecked(index) } + } +} diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 81d8f27ec19..32e43ed42f3 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -6,6 +6,7 @@ use crate::ops::{Add, Try}; use super::super::LoopState; +use super::super::TrustedRandomAccess; use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse}; use super::super::{FlatMap, Flatten}; use super::super::{FromIterator, Product, Sum, Zip}; @@ -3245,6 +3246,17 @@ fn is_sorted_by_key(self, f: F) -> bool { self.map(f).is_sorted() } + + /// See [TrustedRandomAccess] + #[inline] + #[doc(hidden)] + #[unstable(feature = "trusted_random_access", issue = "none")] + unsafe fn get_unchecked(&mut self, _idx: usize) -> Self::Item + where + Self: TrustedRandomAccess, + { + unreachable!("Always specialized"); + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 3838fcf74cc..99f8cc66638 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -73,6 +73,8 @@ #![feature(const_discriminant)] #![feature(const_checked_int_methods)] #![feature(const_euclidean_int_methods)] +#![feature(const_float_classify)] +#![feature(const_float_bits_conv)] #![feature(const_overflowing_int_methods)] #![feature(const_int_unchecked_arith)] #![feature(const_int_pow)] @@ -118,7 +120,7 @@ #![feature(repr_simd, platform_intrinsics)] #![feature(rustc_attrs)] #![feature(simd_ffi)] -#![feature(specialization)] +#![feature(min_specialization)] #![feature(staged_api)] #![feature(std_internals)] #![feature(stmt_expr_attributes)] diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 3b9057b7e83..d26f2124f15 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -28,9 +28,6 @@ macro_rules! panic { /// Like [`assert!`], this macro has a second form, where a custom /// panic message can be provided. /// -/// [`PartialEq`]: cmp/trait.PartialEq.html -/// [`assert!`]: macro.assert.html -/// /// # Examples /// /// ``` @@ -85,9 +82,6 @@ macro_rules! assert_eq { /// Like [`assert!`], this macro has a second form, where a custom /// panic message can be provided. /// -/// [`PartialEq`]: cmp/trait.PartialEq.html -/// [`assert!`]: macro.assert.html -/// /// # Examples /// /// ``` @@ -158,9 +152,6 @@ macro_rules! assert_ne { /// with `debug_assert!` is thus only encouraged after thorough profiling, and /// more importantly, only in safe code! /// -/// [`panic!`]: macro.panic.html -/// [`assert!`]: macro.assert.html -/// /// # Examples /// /// ``` @@ -196,8 +187,6 @@ macro_rules! debug_assert { /// expensive to be present in a release build but may be helpful during /// development. The result of expanding `debug_assert_eq!` is always type checked. /// -/// [`assert_eq!`]: ../std/macro.assert_eq.html -/// /// # Examples /// /// ``` @@ -223,8 +212,6 @@ macro_rules! debug_assert_eq { /// expensive to be present in a release build but may be helpful during /// development. The result of expanding `debug_assert_ne!` is always type checked. /// -/// [`assert_ne!`]: ../std/macro.assert_ne.html -/// /// # Examples /// /// ``` @@ -282,8 +269,6 @@ macro_rules! matches { /// Because of the early return, `try!` can only be used in functions that /// return [`Result`]. /// -/// [`Result`]: ../std/result/enum.Result.html -/// /// # Examples /// /// ``` @@ -354,10 +339,10 @@ macro_rules! r#try { /// /// See [`std::fmt`] for more information on the format string syntax. /// -/// [`std::fmt`]: ../std/fmt/index.html -/// [`std::fmt::Write`]: ../std/fmt/trait.Write.html +/// [`std::fmt`]: crate::fmt +/// [`std::fmt::Write`]: crate::fmt::Write /// [`std::io::Write`]: ../std/io/trait.Write.html -/// [`std::fmt::Result`]: ../std/fmt/type.Result.html +/// [`std::fmt::Result`]: crate::fmt::Result /// [`io::Result`]: ../std/io/type.Result.html /// /// # Examples @@ -426,9 +411,7 @@ macro_rules! write { /// For more information, see [`write!`]. For information on the format string syntax, see /// [`std::fmt`]. /// -/// [`write!`]: macro.write.html -/// [`std::fmt`]: ../std/fmt/index.html -/// +/// [`std::fmt`]: crate::fmt /// /// # Examples /// @@ -494,16 +477,12 @@ macro_rules! writeln { /// The unsafe counterpart of this macro is the [`unreachable_unchecked`] function, which /// will cause undefined behavior if the code is reached. /// -/// [`panic!`]: ../std/macro.panic.html -/// [`unreachable_unchecked`]: ../std/hint/fn.unreachable_unchecked.html -/// [`std::hint`]: ../std/hint/index.html +/// [`unreachable_unchecked`]: crate::hint::unreachable_unchecked /// /// # Panics /// /// This will always [`panic!`] /// -/// [`panic!`]: ../std/macro.panic.html -/// /// # Examples /// /// Match arms: @@ -637,8 +616,6 @@ macro_rules! unimplemented { /// implemented", `unimplemented!` makes no such claims. Its message is "not implemented". /// Also some IDEs will mark `todo!`s. /// -/// [`unimplemented!`]: macro.unimplemented.html -/// /// # Panics /// /// This will always [panic!](macro.panic.html) @@ -730,8 +707,6 @@ pub(crate) mod builtin { /// #[cfg(not(any(feature = "foo", feature = "bar")))] /// compile_error!("Either feature \"foo\" or \"bar\" must be enabled for this crate."); /// ``` - /// - /// [`panic!`]: ../std/macro.panic.html #[stable(feature = "compile_error_macro", since = "1.20.0")] #[rustc_builtin_macro] #[macro_export] @@ -769,12 +744,11 @@ macro_rules! compile_error { /// /// For more information, see the documentation in [`std::fmt`]. /// - /// [`Display`]: ../std/fmt/trait.Display.html - /// [`Debug`]: ../std/fmt/trait.Debug.html - /// [`fmt::Arguments`]: ../std/fmt/struct.Arguments.html - /// [`std::fmt`]: ../std/fmt/index.html + /// [`Display`]: crate::fmt::Display + /// [`Debug`]: crate::fmt::Debug + /// [`fmt::Arguments`]: crate::fmt::Arguments + /// [`std::fmt`]: crate::fmt /// [`format!`]: ../std/macro.format.html - /// [`write!`]: ../std/macro.write.html /// [`println!`]: ../std/macro.println.html /// /// # Examples @@ -818,8 +792,6 @@ macro_rules! format_args_nl { /// will be emitted. To not emit a compile error, use the [`option_env!`] /// macro instead. /// - /// [`option_env!`]: ../std/macro.option_env.html - /// /// # Examples /// /// ``` @@ -854,13 +826,11 @@ macro_rules! env { /// expand into an expression of type `Option<&'static str>` whose value is /// `Some` of the value of the environment variable. If the environment /// variable is not present, then this will expand to `None`. See - /// [`Option`][option] for more information on this type. + /// [`Option`][Option] for more information on this type. /// /// A compile time error is never emitted when using this macro regardless /// of whether the environment variable is present or not. /// - /// [option]: ../std/option/enum.Option.html - /// /// # Examples /// /// ``` @@ -946,9 +916,6 @@ macro_rules! concat { /// but rather the first macro invocation leading up to the invocation /// of the `line!` macro. /// - /// [`column!`]: macro.column.html - /// [`file!`]: macro.file.html - /// /// # Examples /// /// ``` @@ -976,9 +943,6 @@ macro_rules! line { /// but rather the first macro invocation leading up to the invocation /// of the `column!` macro. /// - /// [`line!`]: macro.line.html - /// [`file!`]: macro.file.html - /// /// # Examples /// /// ``` @@ -999,15 +963,11 @@ macro_rules! column { /// With [`line!`] and [`column!`], these macros provide debugging information for /// developers about the location within the source. /// - /// /// The expanded expression has type `&'static str`, and the returned file /// is not the invocation of the `file!` macro itself, but rather the /// first macro invocation leading up to the invocation of the `file!` /// macro. /// - /// [`line!`]: macro.line.html - /// [`column!`]: macro.column.html - /// /// # Examples /// /// ``` @@ -1258,9 +1218,7 @@ macro_rules! include { /// be provided with or without arguments for formatting. See [`std::fmt`] /// for syntax for this form. /// - /// [`panic!`]: macro.panic.html - /// [`debug_assert!`]: macro.debug_assert.html - /// [`std::fmt`]: ../std/fmt/index.html + /// [`std::fmt`]: crate::fmt /// /// # Examples /// diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 9326aaf5684..b44ca95b002 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -728,23 +728,23 @@ unsafe impl Freeze for &mut T {} /// Types that can be safely moved after being pinned. /// -/// Since Rust itself has no notion of immovable types, and considers moves -/// (e.g., through assignment or [`mem::replace`]) to always be safe, -/// this trait cannot prevent types from moving by itself. +/// Rust itself has no notion of immovable types, and considers moves (e.g., +/// through assignment or [`mem::replace`]) to always be safe. /// -/// Instead it is used to prevent moves through the type system, -/// by controlling the behavior of pointers `P` wrapped in the [`Pin

`] wrapper, -/// which "pin" the type in place by not allowing it to be moved out of them. -/// See the [`pin module`] documentation for more information on pinning. +/// The [`Pin`][Pin] type is used instead to prevent moves through the type +/// system. Pointers `P` wrapped in the [`Pin>`][Pin] wrapper can't be +/// moved out of. See the [`pin module`] documentation for more information on +/// pinning. /// -/// Implementing this trait lifts the restrictions of pinning off a type, -/// which then allows it to move out with functions such as [`mem::replace`]. +/// Implementing the `Unpin` trait for `T` lifts the restrictions of pinning off +/// the type, which then allows moving `T` out of [`Pin>`][Pin] with +/// functions such as [`mem::replace`]. /// /// `Unpin` has no consequence at all for non-pinned data. In particular, /// [`mem::replace`] happily moves `!Unpin` data (it works for any `&mut T`, not -/// just when `T: Unpin`). However, you cannot use -/// [`mem::replace`] on data wrapped inside a [`Pin

`] because you cannot get the -/// `&mut T` you need for that, and *that* is what makes this system work. +/// just when `T: Unpin`). However, you cannot use [`mem::replace`] on data +/// wrapped inside a [`Pin>`][Pin] because you cannot get the `&mut T` you +/// need for that, and *that* is what makes this system work. /// /// So this, for example, can only be done on types implementing `Unpin`: /// @@ -765,8 +765,8 @@ unsafe impl Freeze for &mut T {} /// This trait is automatically implemented for almost every type. /// /// [`mem::replace`]: ../../std/mem/fn.replace.html -/// [`Pin

`]: ../pin/struct.Pin.html -/// [`pin module`]: ../../std/pin/index.html +/// [Pin]: crate::pin::Pin +/// [`pin module`]: crate::pin #[stable(feature = "pin", since = "1.33.0")] #[rustc_on_unimplemented( on(_Self = "std::future::Future", note = "consider using `Box::pin`",), diff --git a/library/core/src/mem/manually_drop.rs b/library/core/src/mem/manually_drop.rs index e45aa86c079..aab0e96d83a 100644 --- a/library/core/src/mem/manually_drop.rs +++ b/library/core/src/mem/manually_drop.rs @@ -74,8 +74,12 @@ impl ManuallyDrop { /// /// ```rust /// use std::mem::ManuallyDrop; - /// ManuallyDrop::new(Box::new(())); + /// let mut x = ManuallyDrop::new(String::from("Hello World!")); + /// x.truncate(5); // You can still safely operate on the value + /// assert_eq!(*x, "Hello"); + /// // But `Drop` will not be run here /// ``` + #[must_use = "if you don't need the wrapper, you can use `mem::forget` instead"] #[stable(feature = "manually_drop", since = "1.20.0")] #[rustc_const_stable(feature = "const_manually_drop", since = "1.36.0")] #[inline(always)] diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 9107c570a89..6d8ed2f4ffb 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -145,7 +145,7 @@ #[rustc_const_stable(feature = "const_forget", since = "1.46.0")] #[stable(feature = "rust1", since = "1.0.0")] pub const fn forget(t: T) { - ManuallyDrop::new(t); + let _ = ManuallyDrop::new(t); } /// Like [`forget`], but also accepts unsized values. diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 9fb7296ce31..043f0b14f24 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -381,8 +381,9 @@ impl f32 { /// assert!(!f.is_nan()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] #[inline] - pub fn is_nan(self) -> bool { + pub const fn is_nan(self) -> bool { self != self } @@ -390,7 +391,8 @@ pub fn is_nan(self) -> bool { // concerns about portability, so this implementation is for // private use internally. #[inline] - fn abs_private(self) -> f32 { + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + const fn abs_private(self) -> f32 { f32::from_bits(self.to_bits() & 0x7fff_ffff) } @@ -410,8 +412,9 @@ fn abs_private(self) -> f32 { /// assert!(neg_inf.is_infinite()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] #[inline] - pub fn is_infinite(self) -> bool { + pub const fn is_infinite(self) -> bool { self.abs_private() == Self::INFINITY } @@ -430,8 +433,9 @@ pub fn is_infinite(self) -> bool { /// assert!(!neg_inf.is_finite()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] #[inline] - pub fn is_finite(self) -> bool { + pub const fn is_finite(self) -> bool { // There's no need to handle NaN separately: if self is NaN, // the comparison is not true, exactly as desired. self.abs_private() < Self::INFINITY @@ -457,9 +461,10 @@ pub fn is_finite(self) -> bool { /// ``` /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] #[inline] - pub fn is_normal(self) -> bool { - self.classify() == FpCategory::Normal + pub const fn is_normal(self) -> bool { + matches!(self.classify(), FpCategory::Normal) } /// Returns the floating point category of the number. If only one property @@ -476,7 +481,8 @@ pub fn is_normal(self) -> bool { /// assert_eq!(inf.classify(), FpCategory::Infinite); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn classify(self) -> FpCategory { + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + pub const fn classify(self) -> FpCategory { const EXP_MASK: u32 = 0x7f800000; const MAN_MASK: u32 = 0x007fffff; @@ -501,8 +507,9 @@ pub fn classify(self) -> FpCategory { /// assert!(!g.is_sign_positive()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] #[inline] - pub fn is_sign_positive(self) -> bool { + pub const fn is_sign_positive(self) -> bool { !self.is_sign_negative() } @@ -517,8 +524,9 @@ pub fn is_sign_positive(self) -> bool { /// assert!(g.is_sign_negative()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] #[inline] - pub fn is_sign_negative(self) -> bool { + pub const fn is_sign_negative(self) -> bool { // IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus // applies to zeros and NaNs as well. self.to_bits() & 0x8000_0000 != 0 @@ -652,8 +660,9 @@ pub unsafe fn to_int_unchecked(self) -> Int /// /// ``` #[stable(feature = "float_bits_conv", since = "1.20.0")] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[inline] - pub fn to_bits(self) -> u32 { + pub const fn to_bits(self) -> u32 { // SAFETY: `u32` is a plain old datatype so we can always transmute to it unsafe { mem::transmute(self) } } @@ -695,8 +704,9 @@ pub fn to_bits(self) -> u32 { /// assert_eq!(v, 12.5); /// ``` #[stable(feature = "float_bits_conv", since = "1.20.0")] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[inline] - pub fn from_bits(v: u32) -> Self { + pub const fn from_bits(v: u32) -> Self { // SAFETY: `u32` is a plain old datatype so we can always transmute from it // It turns out the safety issues with sNaN were overblown! Hooray! unsafe { mem::transmute(v) } @@ -712,8 +722,9 @@ pub fn from_bits(v: u32) -> Self { /// assert_eq!(bytes, [0x41, 0x48, 0x00, 0x00]); /// ``` #[stable(feature = "float_to_from_bytes", since = "1.40.0")] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[inline] - pub fn to_be_bytes(self) -> [u8; 4] { + pub const fn to_be_bytes(self) -> [u8; 4] { self.to_bits().to_be_bytes() } @@ -727,8 +738,9 @@ pub fn from_bits(v: u32) -> Self { /// assert_eq!(bytes, [0x00, 0x00, 0x48, 0x41]); /// ``` #[stable(feature = "float_to_from_bytes", since = "1.40.0")] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[inline] - pub fn to_le_bytes(self) -> [u8; 4] { + pub const fn to_le_bytes(self) -> [u8; 4] { self.to_bits().to_le_bytes() } @@ -755,8 +767,9 @@ pub fn from_bits(v: u32) -> Self { /// ); /// ``` #[stable(feature = "float_to_from_bytes", since = "1.40.0")] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[inline] - pub fn to_ne_bytes(self) -> [u8; 4] { + pub const fn to_ne_bytes(self) -> [u8; 4] { self.to_bits().to_ne_bytes() } @@ -769,8 +782,9 @@ pub fn from_bits(v: u32) -> Self { /// assert_eq!(value, 12.5); /// ``` #[stable(feature = "float_to_from_bytes", since = "1.40.0")] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[inline] - pub fn from_be_bytes(bytes: [u8; 4]) -> Self { + pub const fn from_be_bytes(bytes: [u8; 4]) -> Self { Self::from_bits(u32::from_be_bytes(bytes)) } @@ -783,8 +797,9 @@ pub fn from_bits(v: u32) -> Self { /// assert_eq!(value, 12.5); /// ``` #[stable(feature = "float_to_from_bytes", since = "1.40.0")] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[inline] - pub fn from_le_bytes(bytes: [u8; 4]) -> Self { + pub const fn from_le_bytes(bytes: [u8; 4]) -> Self { Self::from_bits(u32::from_le_bytes(bytes)) } @@ -808,8 +823,9 @@ pub fn from_bits(v: u32) -> Self { /// assert_eq!(value, 12.5); /// ``` #[stable(feature = "float_to_from_bytes", since = "1.40.0")] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[inline] - pub fn from_ne_bytes(bytes: [u8; 4]) -> Self { + pub const fn from_ne_bytes(bytes: [u8; 4]) -> Self { Self::from_bits(u32::from_ne_bytes(bytes)) } diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index a5b1eb3f1fd..24624b88d59 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -380,8 +380,9 @@ impl f64 { /// assert!(!f.is_nan()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] #[inline] - pub fn is_nan(self) -> bool { + pub const fn is_nan(self) -> bool { self != self } @@ -389,7 +390,8 @@ pub fn is_nan(self) -> bool { // concerns about portability, so this implementation is for // private use internally. #[inline] - fn abs_private(self) -> f64 { + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + const fn abs_private(self) -> f64 { f64::from_bits(self.to_bits() & 0x7fff_ffff_ffff_ffff) } @@ -409,8 +411,9 @@ fn abs_private(self) -> f64 { /// assert!(neg_inf.is_infinite()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] #[inline] - pub fn is_infinite(self) -> bool { + pub const fn is_infinite(self) -> bool { self.abs_private() == Self::INFINITY } @@ -429,8 +432,9 @@ pub fn is_infinite(self) -> bool { /// assert!(!neg_inf.is_finite()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] #[inline] - pub fn is_finite(self) -> bool { + pub const fn is_finite(self) -> bool { // There's no need to handle NaN separately: if self is NaN, // the comparison is not true, exactly as desired. self.abs_private() < Self::INFINITY @@ -456,9 +460,10 @@ pub fn is_finite(self) -> bool { /// ``` /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] #[inline] - pub fn is_normal(self) -> bool { - self.classify() == FpCategory::Normal + pub const fn is_normal(self) -> bool { + matches!(self.classify(), FpCategory::Normal) } /// Returns the floating point category of the number. If only one property @@ -475,7 +480,8 @@ pub fn is_normal(self) -> bool { /// assert_eq!(inf.classify(), FpCategory::Infinite); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn classify(self) -> FpCategory { + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + pub const fn classify(self) -> FpCategory { const EXP_MASK: u64 = 0x7ff0000000000000; const MAN_MASK: u64 = 0x000fffffffffffff; @@ -500,8 +506,9 @@ pub fn classify(self) -> FpCategory { /// assert!(!g.is_sign_positive()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] #[inline] - pub fn is_sign_positive(self) -> bool { + pub const fn is_sign_positive(self) -> bool { !self.is_sign_negative() } @@ -524,8 +531,9 @@ pub fn is_positive(self) -> bool { /// assert!(g.is_sign_negative()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] #[inline] - pub fn is_sign_negative(self) -> bool { + pub const fn is_sign_negative(self) -> bool { self.to_bits() & 0x8000_0000_0000_0000 != 0 } @@ -666,8 +674,9 @@ pub unsafe fn to_int_unchecked(self) -> Int /// /// ``` #[stable(feature = "float_bits_conv", since = "1.20.0")] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[inline] - pub fn to_bits(self) -> u64 { + pub const fn to_bits(self) -> u64 { // SAFETY: `u64` is a plain old datatype so we can always transmute to it unsafe { mem::transmute(self) } } @@ -709,8 +718,9 @@ pub fn to_bits(self) -> u64 { /// assert_eq!(v, 12.5); /// ``` #[stable(feature = "float_bits_conv", since = "1.20.0")] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[inline] - pub fn from_bits(v: u64) -> Self { + pub const fn from_bits(v: u64) -> Self { // SAFETY: `u64` is a plain old datatype so we can always transmute from it // It turns out the safety issues with sNaN were overblown! Hooray! unsafe { mem::transmute(v) } @@ -726,8 +736,9 @@ pub fn from_bits(v: u64) -> Self { /// assert_eq!(bytes, [0x40, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]); /// ``` #[stable(feature = "float_to_from_bytes", since = "1.40.0")] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[inline] - pub fn to_be_bytes(self) -> [u8; 8] { + pub const fn to_be_bytes(self) -> [u8; 8] { self.to_bits().to_be_bytes() } @@ -741,8 +752,9 @@ pub fn from_bits(v: u64) -> Self { /// assert_eq!(bytes, [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x40]); /// ``` #[stable(feature = "float_to_from_bytes", since = "1.40.0")] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[inline] - pub fn to_le_bytes(self) -> [u8; 8] { + pub const fn to_le_bytes(self) -> [u8; 8] { self.to_bits().to_le_bytes() } @@ -769,8 +781,9 @@ pub fn from_bits(v: u64) -> Self { /// ); /// ``` #[stable(feature = "float_to_from_bytes", since = "1.40.0")] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[inline] - pub fn to_ne_bytes(self) -> [u8; 8] { + pub const fn to_ne_bytes(self) -> [u8; 8] { self.to_bits().to_ne_bytes() } @@ -783,8 +796,9 @@ pub fn from_bits(v: u64) -> Self { /// assert_eq!(value, 12.5); /// ``` #[stable(feature = "float_to_from_bytes", since = "1.40.0")] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[inline] - pub fn from_be_bytes(bytes: [u8; 8]) -> Self { + pub const fn from_be_bytes(bytes: [u8; 8]) -> Self { Self::from_bits(u64::from_be_bytes(bytes)) } @@ -797,8 +811,9 @@ pub fn from_bits(v: u64) -> Self { /// assert_eq!(value, 12.5); /// ``` #[stable(feature = "float_to_from_bytes", since = "1.40.0")] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[inline] - pub fn from_le_bytes(bytes: [u8; 8]) -> Self { + pub const fn from_le_bytes(bytes: [u8; 8]) -> Self { Self::from_bits(u64::from_le_bytes(bytes)) } @@ -822,8 +837,9 @@ pub fn from_bits(v: u64) -> Self { /// assert_eq!(value, 12.5); /// ``` #[stable(feature = "float_to_from_bytes", since = "1.40.0")] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[inline] - pub fn from_ne_bytes(bytes: [u8; 8]) -> Self { + pub const fn from_ne_bytes(bytes: [u8; 8]) -> Self { Self::from_bits(u64::from_ne_bytes(bytes)) } diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 68937176270..7a88cfbb74d 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -1573,7 +1573,7 @@ pub const fn wrapping_shr(self, rhs: u32) -> Self { the boundary of the type. The only case where such wrapping can occur is when one takes the absolute value of the negative -minimal value for the type this is a positive value that is too large to represent in the type. In +minimal value for the type; this is a positive value that is too large to represent in the type. In such a case, this function returns `MIN` itself. # Examples diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs index 3faeb170b06..d6c097eee17 100644 --- a/library/core/src/ops/deref.rs +++ b/library/core/src/ops/deref.rs @@ -28,7 +28,6 @@ /// [method resolution] and [type coercions]. /// /// [book]: ../../book/ch15-02-deref.html -/// [`DerefMut`]: trait.DerefMut.html /// [more]: #more-on-deref-coercion /// [ref-deref-op]: ../../reference/expressions/operator-expr.html#the-dereference-operator /// [method resolution]: ../../reference/expressions/method-call-expr.html @@ -125,7 +124,6 @@ fn deref(&self) -> &T { /// [method resolution] and [type coercions]. /// /// [book]: ../../book/ch15-02-deref.html -/// [`Deref`]: trait.Deref.html /// [more]: #more-on-deref-coercion /// [ref-deref-op]: ../../reference/expressions/operator-expr.html#the-dereference-operator /// [method resolution]: ../../reference/expressions/method-call-expr.html diff --git a/library/core/src/ops/drop.rs b/library/core/src/ops/drop.rs index 06cfc363636..ce7d1c3d06d 100644 --- a/library/core/src/ops/drop.rs +++ b/library/core/src/ops/drop.rs @@ -78,9 +78,9 @@ /// /// In other words, if you tried to explicitly call `Drop::drop` in the above example, you'd get a compiler error. /// -/// If you'd like explicitly call the destructor of a value, [`std::mem::drop`] can be used instead. +/// If you'd like explicitly call the destructor of a value, [`mem::drop`] can be used instead. /// -/// [`std::mem::drop`]: ../../std/mem/fn.drop.html +/// [`mem::drop`]: drop /// /// ## Drop order /// @@ -132,8 +132,6 @@ /// are `Copy` get implicitly duplicated by the compiler, making it very /// hard to predict when, and how often destructors will be executed. As such, /// these types cannot have destructors. -/// -/// [`Copy`]: ../../std/marker/trait.Copy.html #[lang = "drop"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Drop { @@ -141,7 +139,7 @@ pub trait Drop { /// /// This method is called implicitly when the value goes out of scope, /// and cannot be called explicitly (this is compiler error [E0040]). - /// However, the [`std::mem::drop`] function in the prelude can be + /// However, the [`mem::drop`] function in the prelude can be /// used to call the argument's `Drop` implementation. /// /// When this method has been called, `self` has not yet been deallocated. @@ -156,12 +154,12 @@ pub trait Drop { /// Note that even if this panics, the value is considered to be dropped; /// you must not cause `drop` to be called again. This is normally automatically /// handled by the compiler, but when using unsafe code, can sometimes occur - /// unintentionally, particularly when using [`std::ptr::drop_in_place`]. + /// unintentionally, particularly when using [`ptr::drop_in_place`]. /// /// [E0040]: ../../error-index.html#E0040 - /// [`panic!`]: ../macro.panic.html - /// [`std::mem::drop`]: ../../std/mem/fn.drop.html - /// [`std::ptr::drop_in_place`]: ../../std/ptr/fn.drop_in_place.html + /// [`panic!`]: crate::panic! + /// [`mem::drop`]: drop + /// [`ptr::drop_in_place`]: crate::ptr::drop_in_place #[stable(feature = "rust1", since = "1.0.0")] fn drop(&mut self); } diff --git a/library/core/src/ops/function.rs b/library/core/src/ops/function.rs index 3e5cad2b185..bfdec43f7d8 100644 --- a/library/core/src/ops/function.rs +++ b/library/core/src/ops/function.rs @@ -28,8 +28,6 @@ /// this can refer to [the relevant section in the *Rustonomicon*][nomicon]. /// /// [book]: ../../book/ch13-01-closures.html -/// [`FnMut`]: trait.FnMut.html -/// [`FnOnce`]: trait.FnOnce.html /// [function pointers]: ../../std/primitive.fn.html /// [nomicon]: ../../nomicon/hrtb.html /// @@ -99,8 +97,6 @@ pub trait Fn: FnMut { /// this can refer to [the relevant section in the *Rustonomicon*][nomicon]. /// /// [book]: ../../book/ch13-01-closures.html -/// [`Fn`]: trait.Fn.html -/// [`FnOnce`]: trait.FnOnce.html /// [function pointers]: ../../std/primitive.fn.html /// [nomicon]: ../../nomicon/hrtb.html /// @@ -180,8 +176,6 @@ pub trait FnMut: FnOnce { /// this can refer to [the relevant section in the *Rustonomicon*][nomicon]. /// /// [book]: ../../book/ch13-01-closures.html -/// [`Fn`]: trait.Fn.html -/// [`FnMut`]: trait.FnMut.html /// [function pointers]: ../../std/primitive.fn.html /// [nomicon]: ../../nomicon/hrtb.html /// diff --git a/library/core/src/ops/index.rs b/library/core/src/ops/index.rs index 763b33606fe..3c2ada57612 100644 --- a/library/core/src/ops/index.rs +++ b/library/core/src/ops/index.rs @@ -5,9 +5,6 @@ /// [`IndexMut`] is used instead. This allows nice things such as /// `let value = v[index]` if the type of `value` implements [`Copy`]. /// -/// [`IndexMut`]: ../../std/ops/trait.IndexMut.html -/// [`Copy`]: ../../std/marker/trait.Copy.html -/// /// # Examples /// /// The following example implements `Index` on a read-only `NucleotideCount` @@ -76,8 +73,6 @@ pub trait Index { /// an immutable value is requested, the [`Index`] trait is used instead. This /// allows nice things such as `v[index] = value`. /// -/// [`Index`]: ../../std/ops/trait.Index.html -/// /// # Examples /// /// A very simple implementation of a `Balance` struct that has two sides, where diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index e3e5934b44b..c19bd6e441e 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs @@ -133,13 +133,7 @@ //! // `consume_and_return_x` can no longer be invoked at this point //! ``` //! -//! [`Fn`]: trait.Fn.html -//! [`FnMut`]: trait.FnMut.html -//! [`FnOnce`]: trait.FnOnce.html -//! [`Add`]: trait.Add.html -//! [`Sub`]: trait.Sub.html -//! [`Mul`]: trait.Mul.html -//! [`clone`]: ../clone/trait.Clone.html#tymethod.clone +//! [`clone`]: Clone::clone //! [operator precedence]: ../../reference/expressions.html#expression-precedence #![stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index e9ab82b5398..d10829832dd 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -35,9 +35,7 @@ /// assert_eq!(arr[1..=3], [ 1,2,3 ]); /// ``` /// -/// [`IntoIterator`]: ../iter/trait.Iterator.html -/// [`Iterator`]: ../iter/trait.IntoIterator.html -/// [slicing index]: ../slice/trait.SliceIndex.html +/// [slicing index]: crate::slice::SliceIndex #[cfg_attr(not(bootstrap), lang = "RangeFull")] #[doc(alias = "..")] #[derive(Copy, Clone, Default, PartialEq, Eq, Hash)] @@ -127,8 +125,6 @@ pub fn contains(&self, item: &U) -> bool /// # Examples /// /// ``` - /// #![feature(range_is_empty)] - /// /// assert!(!(3..5).is_empty()); /// assert!( (3..3).is_empty()); /// assert!( (3..2).is_empty()); @@ -137,13 +133,11 @@ pub fn contains(&self, item: &U) -> bool /// The range is empty if either side is incomparable: /// /// ``` - /// #![feature(range_is_empty)] - /// /// assert!(!(3.0..5.0).is_empty()); /// assert!( (3.0..f32::NAN).is_empty()); /// assert!( (f32::NAN..5.0).is_empty()); /// ``` - #[unstable(feature = "range_is_empty", reason = "recently added", issue = "48111")] + #[stable(feature = "range_is_empty", since = "1.47.0")] pub fn is_empty(&self) -> bool { !(self.start < self.end) } @@ -178,8 +172,6 @@ pub fn is_empty(&self) -> bool { /// assert_eq!(arr[1.. 3], [ 1,2 ]); /// assert_eq!(arr[1..=3], [ 1,2,3 ]); /// ``` -/// -/// [`Iterator`]: ../iter/trait.IntoIterator.html #[cfg_attr(not(bootstrap), lang = "RangeFrom")] #[doc(alias = "..")] #[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 @@ -260,9 +252,7 @@ pub fn contains(&self, item: &U) -> bool /// assert_eq!(arr[1..=3], [ 1,2,3 ]); /// ``` /// -/// [`IntoIterator`]: ../iter/trait.Iterator.html -/// [`Iterator`]: ../iter/trait.IntoIterator.html -/// [slicing index]: ../slice/trait.SliceIndex.html +/// [slicing index]: crate::slice::SliceIndex #[cfg_attr(not(bootstrap), lang = "RangeTo")] #[doc(alias = "..")] #[derive(Copy, Clone, PartialEq, Eq, Hash)] @@ -315,8 +305,8 @@ pub fn contains(&self, item: &U) -> bool /// iteration has finished are **unspecified** other than that [`.is_empty()`] /// will return `true` once no more values will be produced. /// -/// [fused]: ../iter/trait.FusedIterator.html -/// [`.is_empty()`]: #method.is_empty +/// [fused]: crate::iter::FusedIterator +/// [`.is_empty()`]: RangeInclusive::is_empty /// /// # Examples /// @@ -383,8 +373,8 @@ pub const fn new(start: Idx, end: Idx) -> Self { /// Note: the value returned by this method is unspecified after the range /// has been iterated to exhaustion. /// - /// [`end()`]: #method.end - /// [`is_empty()`]: #method.is_empty + /// [`end()`]: RangeInclusive::end + /// [`is_empty()`]: RangeInclusive::is_empty /// /// # Examples /// @@ -408,8 +398,8 @@ pub const fn start(&self) -> &Idx { /// Note: the value returned by this method is unspecified after the range /// has been iterated to exhaustion. /// - /// [`start()`]: #method.start - /// [`is_empty()`]: #method.is_empty + /// [`start()`]: RangeInclusive::start + /// [`is_empty()`]: RangeInclusive::is_empty /// /// # Examples /// @@ -487,8 +477,6 @@ pub fn contains(&self, item: &U) -> bool /// # Examples /// /// ``` - /// #![feature(range_is_empty)] - /// /// assert!(!(3..=5).is_empty()); /// assert!(!(3..=3).is_empty()); /// assert!( (3..=2).is_empty()); @@ -497,8 +485,6 @@ pub fn contains(&self, item: &U) -> bool /// The range is empty if either side is incomparable: /// /// ``` - /// #![feature(range_is_empty)] - /// /// assert!(!(3.0..=5.0).is_empty()); /// assert!( (3.0..=f32::NAN).is_empty()); /// assert!( (f32::NAN..=5.0).is_empty()); @@ -507,14 +493,12 @@ pub fn contains(&self, item: &U) -> bool /// This method returns `true` after iteration has finished: /// /// ``` - /// #![feature(range_is_empty)] - /// /// let mut r = 3..=5; /// for _ in r.by_ref() {} /// // Precise field values are unspecified here /// assert!(r.is_empty()); /// ``` - #[unstable(feature = "range_is_empty", reason = "recently added", issue = "48111")] + #[stable(feature = "range_is_empty", since = "1.47.0")] #[inline] pub fn is_empty(&self) -> bool { self.exhausted || !(self.start <= self.end) @@ -558,9 +542,7 @@ pub fn is_empty(&self) -> bool { /// assert_eq!(arr[1..=3], [ 1,2,3 ]); /// ``` /// -/// [`IntoIterator`]: ../iter/trait.Iterator.html -/// [`Iterator`]: ../iter/trait.IntoIterator.html -/// [slicing index]: ../slice/trait.SliceIndex.html +/// [slicing index]: crate::slice::SliceIndex #[cfg_attr(not(bootstrap), lang = "RangeToInclusive")] #[doc(alias = "..=")] #[derive(Copy, Clone, PartialEq, Eq, Hash)] diff --git a/library/core/src/ops/unsize.rs b/library/core/src/ops/unsize.rs index 95a4393592b..483362023b2 100644 --- a/library/core/src/ops/unsize.rs +++ b/library/core/src/ops/unsize.rs @@ -29,7 +29,7 @@ /// pointers. It is implemented automatically by the compiler. /// /// [dst-coerce]: https://github.com/rust-lang/rfcs/blob/master/text/0982-dst-coercion.md -/// [unsize]: ../marker/trait.Unsize.html +/// [unsize]: crate::marker::Unsize /// [nomicon-coerce]: ../../nomicon/coercions.html #[unstable(feature = "coerce_unsized", issue = "27732")] #[lang = "coerce_unsized"] diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index b63219a4403..290aa797fd9 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -349,37 +349,28 @@ //! mutable reference even when you just have [`Pin`]`<&mut Self>` (such as in your own //! [`poll`] implementation). //! -//! [`Pin

`]: struct.Pin.html -//! [`Unpin`]: ../marker/trait.Unpin.html -//! [`Deref`]: ../ops/trait.Deref.html -//! [`DerefMut`]: ../ops/trait.DerefMut.html -//! [`mem::swap`]: ../mem/fn.swap.html -//! [`mem::forget`]: ../mem/fn.forget.html +//! [`Pin

`]: Pin +//! [`Deref`]: crate::ops::Deref +//! [`DerefMut`]: crate::ops::DerefMut +//! [`mem::swap`]: crate::mem::swap +//! [`mem::forget`]: crate::mem::forget //! [`Box`]: ../../std/boxed/struct.Box.html //! [`Vec`]: ../../std/vec/struct.Vec.html //! [`Vec::set_len`]: ../../std/vec/struct.Vec.html#method.set_len -//! [`Pin`]: struct.Pin.html //! [`Box`]: ../../std/boxed/struct.Box.html //! [Vec::pop]: ../../std/vec/struct.Vec.html#method.pop //! [Vec::push]: ../../std/vec/struct.Vec.html#method.push //! [`Rc`]: ../../std/rc/struct.Rc.html -//! [`RefCell`]: ../../std/cell/struct.RefCell.html -//! [`Drop`]: ../../std/ops/trait.Drop.html -//! [`drop`]: ../../std/ops/trait.Drop.html#tymethod.drop +//! [`RefCell`]: crate::cell::RefCell +//! [`drop`]: Drop::drop //! [`VecDeque`]: ../../std/collections/struct.VecDeque.html -//! [`Option`]: ../../std/option/enum.Option.html -//! [`VecDeque`]: ../../std/collections/struct.VecDeque.html -//! [`RefCell`]: ../cell/struct.RefCell.html -//! [`None`]: ../option/enum.Option.html#variant.None -//! [`Some(v)`]: ../option/enum.Option.html#variant.Some -//! [`ptr::write`]: ../ptr/fn.write.html -//! [`Future`]: ../future/trait.Future.html +//! [`Option`]: Option +//! [`Some(v)`]: Some +//! [`ptr::write`]: crate::ptr::write +//! [`Future`]: crate::future::Future //! [drop-impl]: #drop-implementation //! [drop-guarantee]: #drop-guarantee -//! [`poll`]: ../../std/future/trait.Future.html#tymethod.poll -//! [`Pin::get_unchecked_mut`]: struct.Pin.html#method.get_unchecked_mut -//! [`bool`]: ../../std/primitive.bool.html -//! [`i32`]: ../../std/primitive.i32.html +//! [`poll`]: crate::future::Future::poll #![stable(feature = "pin", since = "1.33.0")] @@ -397,8 +388,7 @@ /// /// *See the [`pin` module] documentation for an explanation of pinning.* /// -/// [`Unpin`]: ../../std/marker/trait.Unpin.html -/// [`pin` module]: ../../std/pin/index.html +/// [`pin` module]: self // // Note: the `Clone` derive below causes unsoundness as it's possible to implement // `Clone` for mutable references. @@ -481,8 +471,6 @@ impl> Pin

{ /// /// Unlike `Pin::new_unchecked`, this method is safe because the pointer /// `P` dereferences to an [`Unpin`] type, which cancels the pinning guarantees. - /// - /// [`Unpin`]: ../../std/marker/trait.Unpin.html #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] pub fn new(pointer: P) -> Pin

{ @@ -495,8 +483,6 @@ pub fn new(pointer: P) -> Pin

{ /// /// This requires that the data inside this `Pin` is [`Unpin`] so that we /// can ignore the pinning invariants when unwrapping it. - /// - /// [`Unpin`]: ../../std/marker/trait.Unpin.html #[stable(feature = "pin_into_inner", since = "1.39.0")] #[inline(always)] pub fn into_inner(pin: Pin

) -> P { @@ -568,7 +554,7 @@ impl Pin

{ /// } /// ``` /// - /// [`mem::swap`]: ../../std/mem/fn.swap.html + /// [`mem::swap`]: crate::mem::swap #[cfg_attr(not(bootstrap), lang = "new_unchecked")] #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] @@ -603,9 +589,6 @@ pub fn as_ref(&self) -> Pin<&P::Target> { /// /// If the underlying data is [`Unpin`], [`Pin::into_inner`] should be used /// instead. - /// - /// [`Unpin`]: ../../std/marker/trait.Unpin.html - /// [`Pin::into_inner`]: #method.into_inner #[stable(feature = "pin_into_inner", since = "1.39.0")] #[inline(always)] pub unsafe fn into_inner_unchecked(pin: Pin

) -> P { diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 7d7306574a6..fc70dec16f6 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -240,8 +240,8 @@ pub unsafe fn as_uninit_ref<'a>(self) -> Option<&'a MaybeUninit> /// different allocated object. Note that in Rust, /// every (stack-allocated) variable is considered a separate allocated object. /// - /// In other words, `x.wrapping_offset(y.wrapping_offset_from(x))` is - /// *not* the same as `y`, and dereferencing it is undefined behavior + /// In other words, `x.wrapping_offset((y as usize).wrapping_sub(x as usize) / size_of::())` + /// is *not* the same as `y`, and dereferencing it is undefined behavior /// unless `x` and `y` point into the same allocated object. /// /// Compared to [`offset`], this method basically delays the requirement of staying @@ -292,7 +292,6 @@ pub const fn wrapping_offset(self, count: isize) -> *const T /// This function is the inverse of [`offset`]. /// /// [`offset`]: #method.offset - /// [`wrapping_offset_from`]: #method.wrapping_offset_from /// /// # Safety /// @@ -303,6 +302,9 @@ pub const fn wrapping_offset(self, count: isize) -> *const T /// byte past the end of the same allocated object. Note that in Rust, /// every (stack-allocated) variable is considered a separate allocated object. /// + /// * Both pointers must be *derived from* a pointer to the same object. + /// (See below for an example.) + /// /// * The distance between the pointers, **in bytes**, cannot overflow an `isize`. /// /// * The distance between the pointers, in bytes, must be an exact multiple @@ -323,10 +325,6 @@ pub const fn wrapping_offset(self, count: isize) -> *const T /// Extension. As such, memory acquired directly from allocators or memory /// mapped files *may* be too large to handle with this function. /// - /// Consider using [`wrapping_offset_from`] instead if these constraints are - /// difficult to satisfy. The only advantage of this method is that it - /// enables more aggressive compiler optimizations. - /// /// # Panics /// /// This function panics if `T` is a Zero-Sized Type ("ZST"). @@ -336,8 +334,6 @@ pub const fn wrapping_offset(self, count: isize) -> *const T /// Basic usage: /// /// ``` - /// #![feature(ptr_offset_from)] - /// /// let a = [0; 5]; /// let ptr1: *const i32 = &a[1]; /// let ptr2: *const i32 = &a[3]; @@ -348,7 +344,24 @@ pub const fn wrapping_offset(self, count: isize) -> *const T /// assert_eq!(ptr2.offset(-2), ptr1); /// } /// ``` - #[unstable(feature = "ptr_offset_from", issue = "41079")] + /// + /// *Incorrect* usage: + /// + /// ```rust,no_run + /// let ptr1 = Box::into_raw(Box::new(0u8)) as *const u8; + /// let ptr2 = Box::into_raw(Box::new(1u8)) as *const u8; + /// let diff = (ptr2 as isize).wrapping_sub(ptr1 as isize); + /// // Make ptr2_other an "alias" of ptr2, but derived from ptr1. + /// let ptr2_other = (ptr1 as *const u8).wrapping_offset(diff); + /// assert_eq!(ptr2 as usize, ptr2_other as usize); + /// // Since ptr2_other and ptr2 are derived from pointers to different objects, + /// // computing their offset is undefined behavior, even though + /// // they point to the same address! + /// unsafe { + /// let zero = ptr2_other.offset_from(ptr2); // Undefined Behavior + /// } + /// ``` + #[stable(feature = "ptr_offset_from", since = "1.47.0")] #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "41079")] #[inline] pub const unsafe fn offset_from(self, origin: *const T) -> isize @@ -423,59 +436,6 @@ pub const fn guaranteed_ne(self, other: *const T) -> bool intrinsics::ptr_guaranteed_ne(self, other) } - /// Calculates the distance between two pointers. The returned value is in - /// units of T: the distance in bytes is divided by `mem::size_of::()`. - /// - /// If the address different between the two pointers is not a multiple of - /// `mem::size_of::()` then the result of the division is rounded towards - /// zero. - /// - /// Though this method is safe for any two pointers, note that its result - /// will be mostly useless if the two pointers aren't into the same allocated - /// object, for example if they point to two different local variables. - /// - /// # Panics - /// - /// This function panics if `T` is a zero-sized type. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(ptr_wrapping_offset_from)] - /// - /// let a = [0; 5]; - /// let ptr1: *const i32 = &a[1]; - /// let ptr2: *const i32 = &a[3]; - /// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2); - /// assert_eq!(ptr1.wrapping_offset_from(ptr2), -2); - /// assert_eq!(ptr1.wrapping_offset(2), ptr2); - /// assert_eq!(ptr2.wrapping_offset(-2), ptr1); - /// - /// let ptr1: *const i32 = 3 as _; - /// let ptr2: *const i32 = 13 as _; - /// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2); - /// ``` - #[unstable(feature = "ptr_wrapping_offset_from", issue = "41079")] - #[rustc_deprecated( - since = "1.46.0", - reason = "Pointer distances across allocation \ - boundaries are not typically meaningful. \ - Use integer subtraction if you really need this." - )] - #[inline] - pub fn wrapping_offset_from(self, origin: *const T) -> isize - where - T: Sized, - { - let pointee_size = mem::size_of::(); - assert!(0 < pointee_size && pointee_size <= isize::MAX as usize); - - let d = isize::wrapping_sub(self as _, origin as _); - d.wrapping_div(pointee_size as _) - } - /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`). /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 3daeec36041..2d25f21e55c 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -246,8 +246,8 @@ pub unsafe fn as_uninit_ref<'a>(self) -> Option<&'a MaybeUninit> /// different allocated object. Note that in Rust, /// every (stack-allocated) variable is considered a separate allocated object. /// - /// In other words, `x.wrapping_offset(y.wrapping_offset_from(x))` is - /// *not* the same as `y`, and dereferencing it is undefined behavior + /// In other words, `x.wrapping_offset((y as usize).wrapping_sub(x as usize) / size_of::())` + /// is *not* the same as `y`, and dereferencing it is undefined behavior /// unless `x` and `y` point into the same allocated object. /// /// Compared to [`offset`], this method basically delays the requirement of staying @@ -463,7 +463,6 @@ pub const fn guaranteed_eq(self, other: *mut T) -> bool /// This function is the inverse of [`offset`]. /// /// [`offset`]: #method.offset-1 - /// [`wrapping_offset_from`]: #method.wrapping_offset_from-1 /// /// # Safety /// @@ -474,6 +473,9 @@ pub const fn guaranteed_eq(self, other: *mut T) -> bool /// byte past the end of the same allocated object. Note that in Rust, /// every (stack-allocated) variable is considered a separate allocated object. /// + /// * Both pointers must be *derived from* a pointer to the same object. + /// (See below for an example.) + /// /// * The distance between the pointers, **in bytes**, cannot overflow an `isize`. /// /// * The distance between the pointers, in bytes, must be an exact multiple @@ -494,10 +496,6 @@ pub const fn guaranteed_eq(self, other: *mut T) -> bool /// Extension. As such, memory acquired directly from allocators or memory /// mapped files *may* be too large to handle with this function. /// - /// Consider using [`wrapping_offset_from`] instead if these constraints are - /// difficult to satisfy. The only advantage of this method is that it - /// enables more aggressive compiler optimizations. - /// /// # Panics /// /// This function panics if `T` is a Zero-Sized Type ("ZST"). @@ -507,8 +505,6 @@ pub const fn guaranteed_eq(self, other: *mut T) -> bool /// Basic usage: /// /// ``` - /// #![feature(ptr_offset_from)] - /// /// let mut a = [0; 5]; /// let ptr1: *mut i32 = &mut a[1]; /// let ptr2: *mut i32 = &mut a[3]; @@ -519,7 +515,24 @@ pub const fn guaranteed_eq(self, other: *mut T) -> bool /// assert_eq!(ptr2.offset(-2), ptr1); /// } /// ``` - #[unstable(feature = "ptr_offset_from", issue = "41079")] + /// + /// *Incorrect* usage: + /// + /// ```rust,no_run + /// let ptr1 = Box::into_raw(Box::new(0u8)); + /// let ptr2 = Box::into_raw(Box::new(1u8)); + /// let diff = (ptr2 as isize).wrapping_sub(ptr1 as isize); + /// // Make ptr2_other an "alias" of ptr2, but derived from ptr1. + /// let ptr2_other = (ptr1 as *mut u8).wrapping_offset(diff); + /// assert_eq!(ptr2 as usize, ptr2_other as usize); + /// // Since ptr2_other and ptr2 are derived from pointers to different objects, + /// // computing their offset is undefined behavior, even though + /// // they point to the same address! + /// unsafe { + /// let zero = ptr2_other.offset_from(ptr2); // Undefined Behavior + /// } + /// ``` + #[stable(feature = "ptr_offset_from", since = "1.47.0")] #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "41079")] #[inline] pub const unsafe fn offset_from(self, origin: *const T) -> isize @@ -530,56 +543,6 @@ pub const fn guaranteed_eq(self, other: *mut T) -> bool unsafe { (self as *const T).offset_from(origin) } } - /// Calculates the distance between two pointers. The returned value is in - /// units of T: the distance in bytes is divided by `mem::size_of::()`. - /// - /// If the address different between the two pointers is not a multiple of - /// `mem::size_of::()` then the result of the division is rounded towards - /// zero. - /// - /// Though this method is safe for any two pointers, note that its result - /// will be mostly useless if the two pointers aren't into the same allocated - /// object, for example if they point to two different local variables. - /// - /// # Panics - /// - /// This function panics if `T` is a zero-sized type. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(ptr_wrapping_offset_from)] - /// - /// let mut a = [0; 5]; - /// let ptr1: *mut i32 = &mut a[1]; - /// let ptr2: *mut i32 = &mut a[3]; - /// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2); - /// assert_eq!(ptr1.wrapping_offset_from(ptr2), -2); - /// assert_eq!(ptr1.wrapping_offset(2), ptr2); - /// assert_eq!(ptr2.wrapping_offset(-2), ptr1); - /// - /// let ptr1: *mut i32 = 3 as _; - /// let ptr2: *mut i32 = 13 as _; - /// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2); - /// ``` - #[unstable(feature = "ptr_wrapping_offset_from", issue = "41079")] - #[rustc_deprecated( - since = "1.46.0", - reason = "Pointer distances across allocation \ - boundaries are not typically meaningful. \ - Use integer subtraction if you really need this." - )] - #[inline] - pub fn wrapping_offset_from(self, origin: *const T) -> isize - where - T: Sized, - { - #[allow(deprecated_in_future, deprecated)] - (self as *const T).wrapping_offset_from(origin) - } - /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`). /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer diff --git a/library/core/src/raw.rs b/library/core/src/raw.rs index 741a9dc8797..1227d9b01f0 100644 --- a/library/core/src/raw.rs +++ b/library/core/src/raw.rs @@ -26,7 +26,7 @@ /// [`std::mem::transmute`][transmute]. Similarly, the only way to create a true /// trait object from a `TraitObject` value is with `transmute`. /// -/// [transmute]: ../intrinsics/fn.transmute.html +/// [transmute]: crate::intrinsics::transmute /// /// Synthesizing a trait object with mismatched types—one where the /// vtable does not correspond to the type of the value to which the diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 5eddcb2172a..ade5472717d 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -216,17 +216,14 @@ //! [`?`] can only be used in functions that return [`Result`] because of the //! early return of [`Err`] that it provides. //! -//! [`expect`]: enum.Result.html#method.expect +//! [`expect`]: Result::expect //! [`Write`]: ../../std/io/trait.Write.html //! [`write_all`]: ../../std/io/trait.Write.html#method.write_all //! [`io::Result`]: ../../std/io/type.Result.html -//! [`?`]: ../../std/macro.try.html -//! [`Result`]: enum.Result.html -//! [`Ok(T)`]: enum.Result.html#variant.Ok -//! [`Err(E)`]: enum.Result.html#variant.Err +//! [`?`]: crate::ops::Try +//! [`Ok(T)`]: Ok +//! [`Err(E)`]: Err //! [`io::Error`]: ../../std/io/struct.Error.html -//! [`Ok`]: enum.Result.html#variant.Ok -//! [`Err`]: enum.Result.html#variant.Err #![stable(feature = "rust1", since = "1.0.0")] @@ -237,9 +234,6 @@ /// `Result` is a type that represents either success ([`Ok`]) or failure ([`Err`]). /// /// See the [`std::result`](index.html) module documentation for details. -/// -/// [`Ok`]: enum.Result.html#variant.Ok -/// [`Err`]: enum.Result.html#variant.Err #[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] #[must_use = "this `Result` may be an `Err` variant, which should be handled"] #[rustc_diagnostic_item = "result_type"] @@ -267,8 +261,6 @@ impl Result { /// Returns `true` if the result is [`Ok`]. /// - /// [`Ok`]: enum.Result.html#variant.Ok - /// /// # Examples /// /// Basic usage: @@ -290,8 +282,6 @@ pub const fn is_ok(&self) -> bool { /// Returns `true` if the result is [`Err`]. /// - /// [`Err`]: enum.Result.html#variant.Err - /// /// # Examples /// /// Basic usage: @@ -378,7 +368,7 @@ pub fn contains_err(&self, f: &F) -> bool /// Converts `self` into an [`Option`], consuming `self`, /// and discarding the error, if any. /// - /// [`Option`]: ../../std/option/enum.Option.html + /// [`Option`]: Option /// /// # Examples /// @@ -405,7 +395,7 @@ pub fn ok(self) -> Option { /// Converts `self` into an [`Option`], consuming `self`, /// and discarding the success value, if any. /// - /// [`Option`]: ../../std/option/enum.Option.html + /// [`Option`]: Option /// /// # Examples /// @@ -497,9 +487,6 @@ pub fn as_mut(&mut self) -> Result<&mut T, &mut E> { /// /// This function can be used to compose the results of two functions. /// - /// [`Ok`]: enum.Result.html#variant.Ok - /// [`Err`]: enum.Result.html#variant.Err - /// /// # Examples /// /// Print the numbers on each line of a string multiplied by two. @@ -530,9 +517,7 @@ pub fn map U>(self, op: F) -> Result { /// the result of a function call, it is recommended to use [`map_or_else`], /// which is lazily evaluated. /// - /// [`map_or_else`]: #method.map_or_else - /// [`Ok`]: enum.Result.html#variant.Ok - /// [`Err`]: enum.Result.html#variant.Err + /// [`map_or_else`]: Result::map_or_else /// /// # Examples /// @@ -559,8 +544,6 @@ pub fn map_or U>(self, default: U, f: F) -> U { /// This function can be used to unpack a successful result /// while handling an error. /// - /// [`Ok`]: enum.Result.html#variant.Ok - /// [`Err`]: enum.Result.html#variant.Err /// /// # Examples /// @@ -590,8 +573,6 @@ pub fn map_or_else U, F: FnOnce(T) -> U>(self, default: D, f: /// This function can be used to pass through a successful result while handling /// an error. /// - /// [`Ok`]: enum.Result.html#variant.Ok - /// [`Err`]: enum.Result.html#variant.Err /// /// # Examples /// @@ -671,8 +652,6 @@ pub fn iter_mut(&mut self) -> IterMut<'_, T> { /// Returns `res` if the result is [`Ok`], otherwise returns the [`Err`] value of `self`. /// - /// [`Ok`]: enum.Result.html#variant.Ok - /// [`Err`]: enum.Result.html#variant.Err /// /// # Examples /// @@ -706,8 +685,6 @@ pub fn and(self, res: Result) -> Result { /// Calls `op` if the result is [`Ok`], otherwise returns the [`Err`] value of `self`. /// - /// [`Ok`]: enum.Result.html#variant.Ok - /// [`Err`]: enum.Result.html#variant.Err /// /// This function can be used for control flow based on `Result` values. /// @@ -739,9 +716,7 @@ pub fn and_then Result>(self, op: F) -> Result { /// result of a function call, it is recommended to use [`or_else`], which is /// lazily evaluated. /// - /// [`Ok`]: enum.Result.html#variant.Ok - /// [`Err`]: enum.Result.html#variant.Err - /// [`or_else`]: #method.or_else + /// [`or_else`]: Result::or_else /// /// # Examples /// @@ -777,8 +752,6 @@ pub fn or(self, res: Result) -> Result { /// /// This function can be used for control flow based on result values. /// - /// [`Ok`]: enum.Result.html#variant.Ok - /// [`Err`]: enum.Result.html#variant.Err /// /// # Examples /// @@ -808,9 +781,7 @@ pub fn or_else Result>(self, op: O) -> Result { /// the result of a function call, it is recommended to use [`unwrap_or_else`], /// which is lazily evaluated. /// - /// [`Ok`]: enum.Result.html#variant.Ok - /// [`Err`]: enum.Result.html#variant.Err - /// [`unwrap_or_else`]: #method.unwrap_or_else + /// [`unwrap_or_else`]: Result::unwrap_or_else /// /// # Examples /// @@ -835,7 +806,6 @@ pub fn unwrap_or(self, default: T) -> T { /// Returns the contained [`Ok`] value or computes it from a closure. /// - /// [`Ok`]: enum.Result.html#variant.Ok /// /// # Examples /// @@ -945,8 +915,6 @@ impl Result { /// Panics if the value is an [`Err`], with a panic message including the /// passed message, and the content of the [`Err`]. /// - /// [`Ok`]: enum.Result.html#variant.Ok - /// [`Err`]: enum.Result.html#variant.Err /// /// # Examples /// @@ -973,17 +941,15 @@ pub fn expect(self, msg: &str) -> T { /// case explicitly, or call [`unwrap_or`], [`unwrap_or_else`], or /// [`unwrap_or_default`]. /// - /// [`unwrap_or`]: #method.unwrap_or - /// [`unwrap_or_else`]: #method.unwrap_or_else - /// [`unwrap_or_default`]: #method.unwrap_or_default + /// [`unwrap_or`]: Result::unwrap_or + /// [`unwrap_or_else`]: Result::unwrap_or_else + /// [`unwrap_or_default`]: Result::unwrap_or_default /// /// # Panics /// /// Panics if the value is an [`Err`], with a panic message provided by the /// [`Err`]'s value. /// - /// [`Ok`]: enum.Result.html#variant.Ok - /// [`Err`]: enum.Result.html#variant.Err /// /// # Examples /// @@ -1017,8 +983,6 @@ impl Result { /// Panics if the value is an [`Ok`], with a panic message including the /// passed message, and the content of the [`Ok`]. /// - /// [`Ok`]: enum.Result.html#variant.Ok - /// [`Err`]: enum.Result.html#variant.Err /// /// # Examples /// @@ -1045,8 +1009,6 @@ pub fn expect_err(self, msg: &str) -> E { /// Panics if the value is an [`Ok`], with a custom panic message provided /// by the [`Ok`]'s value. /// - /// [`Ok`]: enum.Result.html#variant.Ok - /// [`Err`]: enum.Result.html#variant.Err /// /// /// # Examples @@ -1095,10 +1057,8 @@ impl Result { /// assert_eq!(0, bad_year); /// ``` /// - /// [`parse`]: ../../std/primitive.str.html#method.parse - /// [`FromStr`]: ../../std/str/trait.FromStr.html - /// [`Ok`]: enum.Result.html#variant.Ok - /// [`Err`]: enum.Result.html#variant.Err + /// [`parse`]: str::parse + /// [`FromStr`]: crate::str::FromStr #[inline] #[stable(feature = "result_unwrap_or_default", since = "1.16.0")] pub fn unwrap_or_default(self) -> T { @@ -1119,9 +1079,7 @@ impl> Result { /// to compile if the error type of the `Result` is later changed /// to an error that can actually occur. /// - /// [`Ok`]: enum.Result.html#variant.Ok - /// [`Err`]: enum.Result.html#variant.Err - /// [`unwrap`]: enum.Result.html#method.unwrap + /// [`unwrap`]: Result::unwrap /// /// # Examples /// @@ -1343,10 +1301,6 @@ fn into_iter(self) -> IterMut<'a, T> { /// The iterator yields one value if the result is [`Ok`], otherwise none. /// /// Created by [`Result::iter`]. -/// -/// [`Ok`]: enum.Result.html#variant.Ok -/// [`Result`]: enum.Result.html -/// [`Result::iter`]: enum.Result.html#method.iter #[derive(Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, T: 'a> { @@ -1396,10 +1350,6 @@ fn clone(&self) -> Self { /// An iterator over a mutable reference to the [`Ok`] variant of a [`Result`]. /// /// Created by [`Result::iter_mut`]. -/// -/// [`Ok`]: enum.Result.html#variant.Ok -/// [`Result`]: enum.Result.html -/// [`Result::iter_mut`]: enum.Result.html#method.iter_mut #[derive(Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct IterMut<'a, T: 'a> { @@ -1445,10 +1395,7 @@ unsafe impl TrustedLen for IterMut<'_, A> {} /// This struct is created by the [`into_iter`] method on /// [`Result`] (provided by the [`IntoIterator`] trait). /// -/// [`Ok`]: enum.Result.html#variant.Ok -/// [`Result`]: enum.Result.html -/// [`into_iter`]: ../iter/trait.IntoIterator.html#tymethod.into_iter -/// [`IntoIterator`]: ../iter/trait.IntoIterator.html +/// [`into_iter`]: IntoIterator::into_iter #[derive(Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 59c536bcff9..0d97ddb29af 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -3647,21 +3647,21 @@ macro_rules! iterator { struct $name:ident -> $ptr:ty, $elem:ty, $raw_mut:tt, - {$( $mut_:tt )*}, + {$( $mut_:tt )?}, {$($extra:tt)*} ) => { // Returns the first element and moves the start of the iterator forwards by 1. // Greatly improves performance compared to an inlined function. The iterator // must not be empty. macro_rules! next_unchecked { - ($self: ident) => {& $( $mut_ )* *$self.post_inc_start(1)} + ($self: ident) => {& $( $mut_ )? *$self.post_inc_start(1)} } // Returns the last element and moves the end of the iterator backwards by 1. // Greatly improves performance compared to an inlined function. The iterator // must not be empty. macro_rules! next_back_unchecked { - ($self: ident) => {& $( $mut_ )* *$self.pre_dec_end(1)} + ($self: ident) => {& $( $mut_ )? *$self.pre_dec_end(1)} } // Shrinks the iterator when T is a ZST, by moving the end of the iterator @@ -3921,6 +3921,21 @@ fn rposition

(&mut self, mut predicate: P) -> Option where None } + #[doc(hidden)] + unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { + // SAFETY: the caller must guarantee that `i` is in bounds of + // the underlying slice, so `i` cannot overflow an `isize`, and + // the returned references is guaranteed to refer to an element + // of the slice and thus guaranteed to be valid. + // + // Also note that the caller also guarantees that we're never + // called with the same index again, and that no other methods + // that will access this subslice are called, so it is valid + // for the returned reference to be mutable in the case of + // `IterMut` + unsafe { & $( $mut_ )? * self.ptr.as_ptr().add(idx) } + } + $($extra)* } @@ -5005,6 +5020,15 @@ fn last(self) -> Option { Some(&self.v[start..]) } } + + #[doc(hidden)] + unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { + // SAFETY: since the caller guarantees that `i` is in bounds, + // which means that `i` cannot overflow an `isize`, and the + // slice created by `from_raw_parts` is a subslice of `self.v` + // thus is guaranteed to be valid for the lifetime `'a` of `self.v`. + unsafe { from_raw_parts(self.v.as_ptr().add(idx), self.size) } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -5044,14 +5068,8 @@ unsafe impl TrustedLen for Windows<'_, T> {} impl FusedIterator for Windows<'_, T> {} #[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccess for Windows<'a, T> { - unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T] { - // SAFETY: since the caller guarantees that `i` is in bounds, - // which means that `i` cannot overflow an `isize`, and the - // slice created by `from_raw_parts` is a subslice of `self.v` - // thus is guaranteed to be valid for the lifetime `'a` of `self.v`. - unsafe { from_raw_parts(self.v.as_ptr().add(i), self.size) } - } fn may_have_side_effect() -> bool { false } @@ -5141,6 +5159,23 @@ fn last(self) -> Option { Some(&self.v[start..]) } } + + #[doc(hidden)] + unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { + let start = idx * self.chunk_size; + let end = match start.checked_add(self.chunk_size) { + None => self.v.len(), + Some(end) => cmp::min(end, self.v.len()), + }; + // SAFETY: the caller guarantees that `i` is in bounds, + // which means that `start` must be in bounds of the + // underlying `self.v` slice, and we made sure that `end` + // is also in bounds of `self.v`. Thus, `start` cannot overflow + // an `isize`, and the slice constructed by `from_raw_parts` + // is a subslice of `self.v` which is guaranteed to be valid + // for the lifetime `'a` of `self.v`. + unsafe { from_raw_parts(self.v.as_ptr().add(start), end - start) } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -5187,22 +5222,8 @@ unsafe impl TrustedLen for Chunks<'_, T> {} impl FusedIterator for Chunks<'_, T> {} #[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccess for Chunks<'a, T> { - unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T] { - let start = i * self.chunk_size; - let end = match start.checked_add(self.chunk_size) { - None => self.v.len(), - Some(end) => cmp::min(end, self.v.len()), - }; - // SAFETY: the caller guarantees that `i` is in bounds, - // which means that `start` must be in bounds of the - // underlying `self.v` slice, and we made sure that `end` - // is also in bounds of `self.v`. Thus, `start` cannot overflow - // an `isize`, and the slice constructed by `from_raw_parts` - // is a subslice of `self.v` which is guaranteed to be valid - // for the lifetime `'a` of `self.v`. - unsafe { from_raw_parts(self.v.as_ptr().add(start), end - start) } - } fn may_have_side_effect() -> bool { false } @@ -5287,6 +5308,22 @@ fn last(self) -> Option { Some(&mut self.v[start..]) } } + + #[doc(hidden)] + unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { + let start = idx * self.chunk_size; + let end = match start.checked_add(self.chunk_size) { + None => self.v.len(), + Some(end) => cmp::min(end, self.v.len()), + }; + // SAFETY: see comments for `Chunks::get_unchecked`. + // + // Also note that the caller also guarantees that we're never called + // with the same index again, and that no other methods that will + // access this subslice are called, so it is valid for the returned + // slice to be mutable. + unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -5336,16 +5373,8 @@ unsafe impl TrustedLen for ChunksMut<'_, T> {} impl FusedIterator for ChunksMut<'_, T> {} #[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccess for ChunksMut<'a, T> { - unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut [T] { - let start = i * self.chunk_size; - let end = match start.checked_add(self.chunk_size) { - None => self.v.len(), - Some(end) => cmp::min(end, self.v.len()), - }; - // SAFETY: see comments for `Chunks::get_unchecked`. - unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) } - } fn may_have_side_effect() -> bool { false } @@ -5432,6 +5461,13 @@ fn nth(&mut self, n: usize) -> Option { fn last(mut self) -> Option { self.next_back() } + + #[doc(hidden)] + unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { + let start = idx * self.chunk_size; + // SAFETY: mostly identical to `Chunks::get_unchecked`. + unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) } + } } #[stable(feature = "chunks_exact", since = "1.31.0")] @@ -5477,13 +5513,8 @@ unsafe impl TrustedLen for ChunksExact<'_, T> {} impl FusedIterator for ChunksExact<'_, T> {} #[doc(hidden)] -#[stable(feature = "chunks_exact", since = "1.31.0")] +#[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccess for ChunksExact<'a, T> { - unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T] { - let start = i * self.chunk_size; - // SAFETY: mostly identical to `Chunks::get_unchecked`. - unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) } - } fn may_have_side_effect() -> bool { false } @@ -5564,6 +5595,13 @@ fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { fn last(mut self) -> Option { self.next_back() } + + #[doc(hidden)] + unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { + let start = idx * self.chunk_size; + // SAFETY: see comments for `ChunksMut::get_unchecked`. + unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) } + } } #[stable(feature = "chunks_exact", since = "1.31.0")] @@ -5612,13 +5650,8 @@ unsafe impl TrustedLen for ChunksExactMut<'_, T> {} impl FusedIterator for ChunksExactMut<'_, T> {} #[doc(hidden)] -#[stable(feature = "chunks_exact", since = "1.31.0")] +#[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> { - unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut [T] { - let start = i * self.chunk_size; - // SAFETY: see comments for `ChunksExactMut::get_unchecked`. - unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) } - } fn may_have_side_effect() -> bool { false } @@ -5689,6 +5722,12 @@ fn nth(&mut self, n: usize) -> Option { fn last(self) -> Option { self.iter.last() } + + unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T; N] { + // SAFETY: The safety guarantees of `get_unchecked` are transferred to + // the caller. + unsafe { self.iter.get_unchecked(i) } + } } #[unstable(feature = "array_chunks", issue = "74985")] @@ -5720,11 +5759,6 @@ impl FusedIterator for ArrayChunks<'_, T, N> {} #[doc(hidden)] #[unstable(feature = "array_chunks", issue = "74985")] unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunks<'a, T, N> { - unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T; N] { - // SAFETY: The safety guarantees of `get_unchecked` are transferred to - // the caller. - unsafe { self.iter.get_unchecked(i) } - } fn may_have_side_effect() -> bool { false } @@ -5817,6 +5851,17 @@ fn last(self) -> Option { Some(&self.v[0..end]) } } + + #[doc(hidden)] + unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { + let end = self.v.len() - idx * self.chunk_size; + let start = match end.checked_sub(self.chunk_size) { + None => 0, + Some(start) => start, + }; + // SAFETY: mostly identical to `Chunks::get_unchecked`. + unsafe { from_raw_parts(self.v.as_ptr().add(start), end - start) } + } } #[stable(feature = "rchunks", since = "1.31.0")] @@ -5862,17 +5907,8 @@ unsafe impl TrustedLen for RChunks<'_, T> {} impl FusedIterator for RChunks<'_, T> {} #[doc(hidden)] -#[stable(feature = "rchunks", since = "1.31.0")] +#[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccess for RChunks<'a, T> { - unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T] { - let end = self.v.len() - i * self.chunk_size; - let start = match end.checked_sub(self.chunk_size) { - None => 0, - Some(start) => start, - }; - // SAFETY: mostly identical to `Chunks::get_unchecked`. - unsafe { from_raw_parts(self.v.as_ptr().add(start), end - start) } - } fn may_have_side_effect() -> bool { false } @@ -5961,6 +5997,17 @@ fn last(self) -> Option { Some(&mut self.v[0..end]) } } + + #[doc(hidden)] + unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { + let end = self.v.len() - idx * self.chunk_size; + let start = match end.checked_sub(self.chunk_size) { + None => 0, + Some(start) => start, + }; + // SAFETY: see comments for `RChunks::get_unchecked` and `ChunksMut::get_unchecked` + unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) } + } } #[stable(feature = "rchunks", since = "1.31.0")] @@ -6008,17 +6055,8 @@ unsafe impl TrustedLen for RChunksMut<'_, T> {} impl FusedIterator for RChunksMut<'_, T> {} #[doc(hidden)] -#[stable(feature = "rchunks", since = "1.31.0")] +#[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccess for RChunksMut<'a, T> { - unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut [T] { - let end = self.v.len() - i * self.chunk_size; - let start = match end.checked_sub(self.chunk_size) { - None => 0, - Some(start) => start, - }; - // SAFETY: see comments for `RChunks::get_unchecked`. - unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) } - } fn may_have_side_effect() -> bool { false } @@ -6105,6 +6143,15 @@ fn nth(&mut self, n: usize) -> Option { fn last(mut self) -> Option { self.next_back() } + + #[doc(hidden)] + unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { + let end = self.v.len() - idx * self.chunk_size; + let start = end - self.chunk_size; + // SAFETY: + // SAFETY: mostmy identical to `Chunks::get_unchecked`. + unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) } + } } #[stable(feature = "rchunks", since = "1.31.0")] @@ -6153,14 +6200,8 @@ unsafe impl TrustedLen for RChunksExact<'_, T> {} impl FusedIterator for RChunksExact<'_, T> {} #[doc(hidden)] -#[stable(feature = "rchunks", since = "1.31.0")] +#[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccess for RChunksExact<'a, T> { - unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T] { - let end = self.v.len() - i * self.chunk_size; - let start = end - self.chunk_size; - // SAFETY: mostmy identical to `Chunks::get_unchecked`. - unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) } - } fn may_have_side_effect() -> bool { false } @@ -6243,6 +6284,14 @@ fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { fn last(mut self) -> Option { self.next_back() } + + #[doc(hidden)] + unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item { + let end = self.v.len() - idx * self.chunk_size; + let start = end - self.chunk_size; + // SAFETY: see comments for `RChunksMut::get_unchecked`. + unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) } + } } #[stable(feature = "rchunks", since = "1.31.0")] @@ -6293,14 +6342,8 @@ unsafe impl TrustedLen for RChunksExactMut<'_, T> {} impl FusedIterator for RChunksExactMut<'_, T> {} #[doc(hidden)] -#[stable(feature = "rchunks", since = "1.31.0")] +#[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> { - unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut [T] { - let end = self.v.len() - i * self.chunk_size; - let start = end - self.chunk_size; - // SAFETY: see comments for `RChunksExact::get_unchecked`. - unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) } - } fn may_have_side_effect() -> bool { false } @@ -6543,18 +6586,20 @@ impl SlicePartialEq for [A] } // Use an equal-pointer optimization when types are `Eq` -impl SlicePartialEq for [A] +// We can't make `A` and `B` the same type because `min_specialization` won't +// allow it. +impl SlicePartialEq for [A] where - A: PartialEq + Eq, + A: MarkerEq, { - default fn equal(&self, other: &[A]) -> bool { + default fn equal(&self, other: &[B]) -> bool { if self.len() != other.len() { return false; } // While performance would suffer if `guaranteed_eq` just returned `false` // for all arguments, correctness and return value of this function are not affected. - if self.as_ptr().guaranteed_eq(other.as_ptr()) { + if self.as_ptr().guaranteed_eq(other.as_ptr() as *const A) { return true; } @@ -6563,18 +6608,18 @@ impl SlicePartialEq for [A] } // Use memcmp for bytewise equality when the types allow -impl SlicePartialEq for [A] +impl SlicePartialEq for [A] where - A: PartialEq + BytewiseEquality, + A: BytewiseEquality, { - fn equal(&self, other: &[A]) -> bool { + fn equal(&self, other: &[B]) -> bool { if self.len() != other.len() { return false; } // While performance would suffer if `guaranteed_eq` just returned `false` // for all arguments, correctness and return value of this function are not affected. - if self.as_ptr().guaranteed_eq(other.as_ptr()) { + if self.as_ptr().guaranteed_eq(other.as_ptr() as *const A) { return true; } // SAFETY: `self` and `other` are references and are thus guaranteed to be valid. @@ -6631,6 +6676,7 @@ fn partial_compare(left: &[A], right: &[A]) -> Option { } } +#[rustc_specialization_trait] trait AlwaysApplicableOrd: SliceOrd + Ord {} macro_rules! always_applicable_ord { @@ -6695,15 +6741,22 @@ fn compare(left: &[Self], right: &[Self]) -> Ordering { } } +// Hack to allow specializing on `Eq` even though `Eq` has a method. +#[rustc_unsafe_specialization_marker] +trait MarkerEq: PartialEq {} + +impl MarkerEq for T {} + #[doc(hidden)] /// Trait implemented for types that can be compared for equality using /// their bytewise representation -trait BytewiseEquality: Eq + Copy {} +#[rustc_specialization_trait] +trait BytewiseEquality: MarkerEq + Copy {} macro_rules! impl_marker_for { ($traitname:ident, $($ty:ty)*) => { $( - impl $traitname for $ty { } + impl $traitname<$ty> for $ty { } )* } } @@ -6712,25 +6765,16 @@ impl $traitname for $ty { } u8 i8 u16 i16 u32 i32 u64 i64 u128 i128 usize isize char bool); #[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccess for Iter<'a, T> { - unsafe fn get_unchecked(&mut self, i: usize) -> &'a T { - // SAFETY: the caller must guarantee that `i` is in bounds - // of the underlying slice, so `i` cannot overflow an `isize`, - // and the returned references is guaranteed to refer to an element - // of the slice and thus guaranteed to be valid. - unsafe { &*self.ptr.as_ptr().add(i) } - } fn may_have_side_effect() -> bool { false } } #[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl<'a, T> TrustedRandomAccess for IterMut<'a, T> { - unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut T { - // SAFETY: see comments for `Iter::get_unchecked`. - unsafe { &mut *self.ptr.as_ptr().add(i) } - } fn may_have_side_effect() -> bool { false } diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 4705c984bd4..ab9afeb25e0 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -13,8 +13,9 @@ use crate::char; use crate::fmt::{self, Write}; +use crate::iter::TrustedRandomAccess; use crate::iter::{Chain, FlatMap, Flatten}; -use crate::iter::{Copied, Filter, FusedIterator, Map, TrustedLen, TrustedRandomAccess}; +use crate::iter::{Copied, Filter, FusedIterator, Map, TrustedLen}; use crate::mem; use crate::ops::Try; use crate::option; @@ -475,6 +476,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// This struct is created by the [`chars`] method on [`str`]. /// See its documentation for more. /// +/// [`char`]: prim@char /// [`chars`]: str::chars #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] @@ -672,6 +674,7 @@ pub fn as_str(&self) -> &'a str { /// This struct is created by the [`char_indices`] method on [`str`]. /// See its documentation for more. /// +/// [`char`]: prim@char /// [`char_indices`]: str::char_indices #[derive(Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] @@ -819,6 +822,13 @@ fn rposition

(&mut self, predicate: P) -> Option { self.0.rposition(predicate) } + + #[inline] + unsafe fn get_unchecked(&mut self, idx: usize) -> u8 { + // SAFETY: the caller must uphold the safety contract + // for `Iterator::get_unchecked`. + unsafe { self.0.get_unchecked(idx) } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -862,12 +872,8 @@ impl FusedIterator for Bytes<'_> {} unsafe impl TrustedLen for Bytes<'_> {} #[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] unsafe impl TrustedRandomAccess for Bytes<'_> { - unsafe fn get_unchecked(&mut self, i: usize) -> u8 { - // SAFETY: the caller must uphold the safety contract - // for `TrustedRandomAccess::get_unchecked`. - unsafe { self.0.get_unchecked(i) } - } fn may_have_side_effect() -> bool { false } @@ -2266,6 +2272,8 @@ impl str { /// This length is in bytes, not [`char`]s or graphemes. In other words, /// it may not be what a human considers the length of the string. /// + /// [`char`]: prim@char + /// /// # Examples /// /// Basic usage: @@ -2787,7 +2795,9 @@ pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) { /// assert_eq!(None, chars.next()); /// ``` /// - /// Remember, [`char`]s may not match your human intuition about characters: + /// Remember, [`char`]s may not match your intuition about characters: + /// + /// [`char`]: prim@char /// /// ``` /// let y = "y̆"; @@ -2838,7 +2848,9 @@ pub fn chars(&self) -> Chars<'_> { /// assert_eq!(None, char_indices.next()); /// ``` /// - /// Remember, [`char`]s may not match your human intuition about characters: + /// Remember, [`char`]s may not match your intuition about characters: + /// + /// [`char`]: prim@char /// /// ``` /// let yes = "y̆es"; @@ -3049,6 +3061,7 @@ pub fn encode_utf16(&self) -> EncodeUtf16<'_> { /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Examples @@ -3075,6 +3088,7 @@ pub fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool { /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Examples @@ -3100,6 +3114,7 @@ pub fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool { /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Examples @@ -3128,6 +3143,7 @@ pub fn ends_with<'a, P>(&'a self, pat: P) -> bool /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Examples @@ -3175,6 +3191,7 @@ pub fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option { /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Examples @@ -3221,6 +3238,7 @@ pub fn rfind<'a, P>(&'a self, pat: P) -> Option /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Iterator behavior @@ -3340,6 +3358,7 @@ pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> { /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Examples @@ -3379,6 +3398,7 @@ pub fn split_inclusive<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitInclusive<' /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Iterator behavior @@ -3430,6 +3450,7 @@ pub fn rsplit<'a, P>(&'a self, pat: P) -> RSplit<'a, P> /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// Equivalent to [`split`], except that the trailing substring @@ -3474,6 +3495,7 @@ pub fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// Equivalent to [`split`], except that the trailing substring is @@ -3522,6 +3544,7 @@ pub fn rsplit_terminator<'a, P>(&'a self, pat: P) -> RSplitTerminator<'a, P> /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Iterator behavior @@ -3574,6 +3597,7 @@ pub fn splitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> SplitN<'a, P> { /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Iterator behavior @@ -3662,6 +3686,7 @@ pub fn rsplit_once<'a, P>(&'a self, delimiter: P) -> Option<(&'a str, &'a str)> /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Iterator behavior @@ -3698,6 +3723,7 @@ pub fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P> { /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Iterator behavior @@ -3739,6 +3765,7 @@ pub fn rmatches<'a, P>(&'a self, pat: P) -> RMatches<'a, P> /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Iterator behavior @@ -3781,6 +3808,7 @@ pub fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Iterator behavior @@ -3999,6 +4027,7 @@ pub fn trim_right(&self) -> &str { /// The [pattern] can be a [`char`], a slice of [`char`]s, or a function /// or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Examples @@ -4046,6 +4075,7 @@ pub fn trim_matches<'a, P>(&'a self, pat: P) -> &'a str /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Text directionality @@ -4090,6 +4120,7 @@ pub fn trim_start_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str { /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Examples @@ -4117,6 +4148,7 @@ pub fn strip_prefix<'a, P: Pattern<'a>>(&'a self, prefix: P) -> Option<&'a str> /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Examples @@ -4143,6 +4175,7 @@ pub fn strip_suffix<'a, P>(&'a self, suffix: P) -> Option<&'a str> /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Text directionality @@ -4191,6 +4224,7 @@ pub fn trim_end_matches<'a, P>(&'a self, pat: P) -> &'a str /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Text directionality @@ -4227,6 +4261,7 @@ pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str { /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Text directionality diff --git a/library/core/src/str/pattern.rs b/library/core/src/str/pattern.rs index 14f1f293d40..1cc2de5b875 100644 --- a/library/core/src/str/pattern.rs +++ b/library/core/src/str/pattern.rs @@ -12,7 +12,7 @@ //! # Examples //! //! [`Pattern`] is [implemented][pattern-impls] in the stable API for -//! [`&str`], [`char`], slices of [`char`], and functions and closures +//! [`&str`][`str`], [`char`], slices of [`char`], and functions and closures //! implementing `FnMut(char) -> bool`. //! //! ``` @@ -28,13 +28,6 @@ //! assert_eq!(s.find(|c: char| c.is_ascii_punctuation()), Some(35)); //! ``` //! -//! [`&str`]: ../../../std/primitive.str.html -//! [`char`]: ../../../std/primitive.char.html -//! [`str`]: ../../../std/primitive.str.html -//! [`DoubleEndedSearcher`]: trait.DoubleEndedSearcher.html -//! [`Pattern`]: trait.Pattern.html -//! [`ReverseSearcher`]: trait.ReverseSearcher.html -//! [`Searcher`]: trait.Searcher.html //! [pattern-impls]: trait.Pattern.html#implementors #![unstable( @@ -52,13 +45,13 @@ /// A string pattern. /// /// A `Pattern<'a>` expresses that the implementing type -/// can be used as a string pattern for searching in a `&'a str`. +/// can be used as a string pattern for searching in a [`&'a str`][str]. /// /// For example, both `'a'` and `"aa"` are patterns that /// would match at index `1` in the string `"baaaab"`. /// /// The trait itself acts as a builder for an associated -/// `Searcher` type, which does the actual work of finding +/// [`Searcher`] type, which does the actual work of finding /// occurrences of the pattern in a string. /// /// Depending on the type of the pattern, the behaviour of methods like @@ -75,6 +68,7 @@ /// | `&String` | is substring | /// /// # Examples +/// /// ``` /// // &str /// assert_eq!("abaaa".find("ba"), Some(1)); @@ -94,9 +88,6 @@ /// assert_eq!("abcdef_z".find(|ch| ch > 'd' && ch < 'y'), Some(4)); /// assert_eq!("abcddd_z".find(|ch| ch > 'd' && ch < 'y'), None); /// ``` -/// -/// [`str::find`]: ../../../std/primitive.str.html#method.find -/// [`str::contains`]: ../../../std/primitive.str.html#method.contains pub trait Pattern<'a>: Sized { /// Associated searcher for this pattern type Searcher: Searcher<'a>; @@ -165,7 +156,7 @@ fn strip_suffix_of(self, haystack: &'a str) -> Option<&'a str> // Searcher -/// Result of calling `Searcher::next()` or `ReverseSearcher::next_back()`. +/// Result of calling [`Searcher::next()`] or [`ReverseSearcher::next_back()`]. #[derive(Copy, Clone, Eq, PartialEq, Debug)] pub enum SearchStep { /// Expresses that a match of the pattern has been found at @@ -188,44 +179,47 @@ pub enum SearchStep { /// matches of a pattern starting from the front (left) of a string. /// /// It will be implemented by associated `Searcher` -/// types of the `Pattern` trait. +/// types of the [`Pattern`] trait. /// /// The trait is marked unsafe because the indices returned by the -/// `next()` methods are required to lie on valid utf8 boundaries in -/// the haystack. This enables consumers of this trait to +/// [`next()`][Searcher::next] methods are required to lie on valid utf8 +/// boundaries in the haystack. This enables consumers of this trait to /// slice the haystack without additional runtime checks. pub unsafe trait Searcher<'a> { /// Getter for the underlying string to be searched in /// - /// Will always return the same `&str` + /// Will always return the same [`&str`][str]. fn haystack(&self) -> &'a str; /// Performs the next search step starting from the front. /// - /// - Returns `Match(a, b)` if `haystack[a..b]` matches the pattern. - /// - Returns `Reject(a, b)` if `haystack[a..b]` can not match the - /// pattern, even partially. - /// - Returns `Done` if every byte of the haystack has been visited + /// - Returns [`Match(a, b)`][SearchStep::Match] if `haystack[a..b]` matches + /// the pattern. + /// - Returns [`Reject(a, b)`][SearchStep::Reject] if `haystack[a..b]` can + /// not match the pattern, even partially. + /// - Returns [`Done`][SearchStep::Done] if every byte of the haystack has + /// been visited. /// - /// The stream of `Match` and `Reject` values up to a `Done` + /// The stream of [`Match`][SearchStep::Match] and + /// [`Reject`][SearchStep::Reject] values up to a [`Done`][SearchStep::Done] /// will contain index ranges that are adjacent, non-overlapping, /// covering the whole haystack, and laying on utf8 boundaries. /// - /// A `Match` result needs to contain the whole matched pattern, - /// however `Reject` results may be split up into arbitrary - /// many adjacent fragments. Both ranges may have zero length. + /// A [`Match`][SearchStep::Match] result needs to contain the whole matched + /// pattern, however [`Reject`][SearchStep::Reject] results may be split up + /// into arbitrary many adjacent fragments. Both ranges may have zero length. /// /// As an example, the pattern `"aaa"` and the haystack `"cbaaaaab"` /// might produce the stream /// `[Reject(0, 1), Reject(1, 2), Match(2, 5), Reject(5, 8)]` fn next(&mut self) -> SearchStep; - /// Finds the next `Match` result. See `next()` + /// Finds the next [`Match`][SearchStep::Match] result. See [`next()`][Searcher::next]. /// - /// Unlike next(), there is no guarantee that the returned ranges - /// of this and next_reject will overlap. This will return (start_match, end_match), - /// where start_match is the index of where the match begins, and end_match is - /// the index after the end of the match. + /// Unlike [`next()`][Searcher::next], there is no guarantee that the returned ranges + /// of this and [`next_reject`][Searcher::next_reject] will overlap. This will return + /// `(start_match, end_match)`, where start_match is the index of where + /// the match begins, and end_match is the index after the end of the match. #[inline] fn next_match(&mut self) -> Option<(usize, usize)> { loop { @@ -237,10 +231,11 @@ fn next_match(&mut self) -> Option<(usize, usize)> { } } - /// Finds the next `Reject` result. See `next()` and `next_match()` + /// Finds the next [`Reject`][SearchStep::Reject] result. See [`next()`][Searcher::next] + /// and [`next_match()`][Searcher::next_match]. /// - /// Unlike next(), there is no guarantee that the returned ranges - /// of this and next_match will overlap. + /// Unlike [`next()`][Searcher::next], there is no guarantee that the returned ranges + /// of this and [`next_match`][Searcher::next_match] will overlap. #[inline] fn next_reject(&mut self) -> Option<(usize, usize)> { loop { @@ -258,37 +253,41 @@ fn next_reject(&mut self) -> Option<(usize, usize)> { /// This trait provides methods for searching for non-overlapping /// matches of a pattern starting from the back (right) of a string. /// -/// It will be implemented by associated `Searcher` -/// types of the `Pattern` trait if the pattern supports searching +/// It will be implemented by associated [`Searcher`] +/// types of the [`Pattern`] trait if the pattern supports searching /// for it from the back. /// /// The index ranges returned by this trait are not required /// to exactly match those of the forward search in reverse. /// /// For the reason why this trait is marked unsafe, see them -/// parent trait `Searcher`. +/// parent trait [`Searcher`]. pub unsafe trait ReverseSearcher<'a>: Searcher<'a> { /// Performs the next search step starting from the back. /// - /// - Returns `Match(a, b)` if `haystack[a..b]` matches the pattern. - /// - Returns `Reject(a, b)` if `haystack[a..b]` can not match the - /// pattern, even partially. - /// - Returns `Done` if every byte of the haystack has been visited + /// - Returns [`Match(a, b)`][SearchStep::Match] if `haystack[a..b]` + /// matches the pattern. + /// - Returns [`Reject(a, b)`][SearchStep::Reject] if `haystack[a..b]` + /// can not match the pattern, even partially. + /// - Returns [`Done`][SearchStep::Done] if every byte of the haystack + /// has been visited /// - /// The stream of `Match` and `Reject` values up to a `Done` + /// The stream of [`Match`][SearchStep::Match] and + /// [`Reject`][SearchStep::Reject] values up to a [`Done`][SearchStep::Done] /// will contain index ranges that are adjacent, non-overlapping, /// covering the whole haystack, and laying on utf8 boundaries. /// - /// A `Match` result needs to contain the whole matched pattern, - /// however `Reject` results may be split up into arbitrary - /// many adjacent fragments. Both ranges may have zero length. + /// A [`Match`][SearchStep::Match] result needs to contain the whole matched + /// pattern, however [`Reject`][SearchStep::Reject] results may be split up + /// into arbitrary many adjacent fragments. Both ranges may have zero length. /// /// As an example, the pattern `"aaa"` and the haystack `"cbaaaaab"` /// might produce the stream - /// `[Reject(7, 8), Match(4, 7), Reject(1, 4), Reject(0, 1)]` + /// `[Reject(7, 8), Match(4, 7), Reject(1, 4), Reject(0, 1)]`. fn next_back(&mut self) -> SearchStep; - /// Finds the next `Match` result. See `next_back()` + /// Finds the next [`Match`][SearchStep::Match] result. + /// See [`next_back()`][ReverseSearcher::next_back]. #[inline] fn next_match_back(&mut self) -> Option<(usize, usize)> { loop { @@ -300,7 +299,8 @@ fn next_match_back(&mut self) -> Option<(usize, usize)> { } } - /// Finds the next `Reject` result. See `next_back()` + /// Finds the next [`Reject`][SearchStep::Reject] result. + /// See [`next_back()`][ReverseSearcher::next_back]. #[inline] fn next_reject_back(&mut self) -> Option<(usize, usize)> { loop { @@ -313,10 +313,10 @@ fn next_reject_back(&mut self) -> Option<(usize, usize)> { } } -/// A marker trait to express that a `ReverseSearcher` -/// can be used for a `DoubleEndedIterator` implementation. +/// A marker trait to express that a [`ReverseSearcher`] +/// can be used for a [`DoubleEndedIterator`] implementation. /// -/// For this, the impl of `Searcher` and `ReverseSearcher` need +/// For this, the impl of [`Searcher`] and [`ReverseSearcher`] need /// to follow these conditions: /// /// - All results of `next()` need to be identical @@ -328,7 +328,7 @@ fn next_reject_back(&mut self) -> Option<(usize, usize)> { /// # Examples /// /// `char::Searcher` is a `DoubleEndedSearcher` because searching for a -/// `char` only requires looking at one at a time, which behaves the same +/// [`char`] only requires looking at one at a time, which behaves the same /// from both ends. /// /// `(&str)::Searcher` is not a `DoubleEndedSearcher` because @@ -355,13 +355,13 @@ pub struct CharSearcher<'a> { /// `finger_back` is the current byte index of the reverse search. /// Imagine that it exists after the byte at its index, i.e. /// haystack[finger_back - 1] is the last byte of the slice we must inspect during - /// forward searching (and thus the first byte to be inspected when calling next_back()) + /// forward searching (and thus the first byte to be inspected when calling next_back()). finger_back: usize, /// The character being searched for needle: char, // safety invariant: `utf8_size` must be less than 5 - /// The number of bytes `needle` takes up when encoded in utf8 + /// The number of bytes `needle` takes up when encoded in utf8. utf8_size: usize, /// A utf8 encoded copy of the `needle` utf8_encoded: [u8; 4], @@ -521,7 +521,7 @@ fn next_match_back(&mut self) -> Option<(usize, usize)> { impl<'a> DoubleEndedSearcher<'a> for CharSearcher<'a> {} -/// Searches for chars that are equal to a given `char`. +/// Searches for chars that are equal to a given [`char`]. /// /// # Examples /// @@ -772,7 +772,7 @@ unsafe impl<'a, 'b> ReverseSearcher<'a> for CharSliceSearcher<'a, 'b> { impl<'a, 'b> DoubleEndedSearcher<'a> for CharSliceSearcher<'a, 'b> {} -/// Searches for chars that are equal to any of the chars in the slice. +/// Searches for chars that are equal to any of the [`char`]s in the slice. /// /// # Examples /// @@ -821,7 +821,7 @@ unsafe impl<'a, F> ReverseSearcher<'a> for CharPredicateSearcher<'a, F> impl<'a, F> DoubleEndedSearcher<'a> for CharPredicateSearcher<'a, F> where F: FnMut(char) -> bool {} -/// Searches for chars that match the given predicate. +/// Searches for [`char`]s that match the given predicate. /// /// # Examples /// diff --git a/library/core/tests/ascii.rs b/library/core/tests/ascii.rs index 57f2de16b2b..0b975083947 100644 --- a/library/core/tests/ascii.rs +++ b/library/core/tests/ascii.rs @@ -361,10 +361,8 @@ fn repeat_concat(b0: u8, b1: u8, l: usize) -> Vec { repeat(b0).take(l).chain(repeat(b1).take(l)).collect() } - // Miri is too slow for much of this, and in miri `align_offset` always - // returns `usize::max_value()` anyway (at the moment), so we just test - // lightly. - let iter = if cfg!(miri) { 0..5 } else { 0..100 }; + // Miri is too slow + let iter = if cfg!(miri) { 0..20 } else { 0..100 }; for i in iter { #[cfg(not(miri))] @@ -379,7 +377,7 @@ fn repeat_concat(b0: u8, b1: u8, l: usize) -> Vec { ]; #[cfg(miri)] - let cases = &[repeat_concat(b'a', 0x80u8, i)]; + let cases = &[b"a".repeat(i), b"\x80".repeat(i), repeat_concat(b'a', 0x80u8, i)]; for case in cases { for pos in 0..=case.len() { diff --git a/library/core/tests/iter.rs b/library/core/tests/iter.rs index 3b854b56c32..00e3972c42f 100644 --- a/library/core/tests/iter.rs +++ b/library/core/tests/iter.rs @@ -304,6 +304,103 @@ fn test_zip_nth_side_effects() { assert_eq!(b, vec![200, 300, 400, 500, 600]); } +#[test] +fn test_zip_next_back_side_effects() { + let mut a = Vec::new(); + let mut b = Vec::new(); + let mut iter = [1, 2, 3, 4, 5, 6] + .iter() + .cloned() + .map(|n| { + a.push(n); + n * 10 + }) + .zip([2, 3, 4, 5, 6, 7, 8].iter().cloned().map(|n| { + b.push(n * 100); + n * 1000 + })); + + // The second iterator is one item longer, so `next_back` is called on it + // one more time. + assert_eq!(iter.next_back(), Some((60, 7000))); + assert_eq!(iter.next_back(), Some((50, 6000))); + assert_eq!(iter.next_back(), Some((40, 5000))); + assert_eq!(iter.next_back(), Some((30, 4000))); + assert_eq!(a, vec![6, 5, 4, 3]); + assert_eq!(b, vec![800, 700, 600, 500, 400]); +} + +#[test] +fn test_zip_nth_back_side_effects() { + let mut a = Vec::new(); + let mut b = Vec::new(); + let value = [1, 2, 3, 4, 5, 6] + .iter() + .cloned() + .map(|n| { + a.push(n); + n * 10 + }) + .zip([2, 3, 4, 5, 6, 7, 8].iter().cloned().map(|n| { + b.push(n * 100); + n * 1000 + })) + .nth_back(3); + assert_eq!(value, Some((30, 4000))); + assert_eq!(a, vec![6, 5, 4, 3]); + assert_eq!(b, vec![800, 700, 600, 500, 400]); +} + +#[test] +fn test_zip_next_back_side_effects_exhausted() { + let mut a = Vec::new(); + let mut b = Vec::new(); + let mut iter = [1, 2, 3, 4, 5, 6] + .iter() + .cloned() + .map(|n| { + a.push(n); + n * 10 + }) + .zip([2, 3, 4].iter().cloned().map(|n| { + b.push(n * 100); + n * 1000 + })); + + iter.next(); + iter.next(); + iter.next(); + iter.next(); + assert_eq!(iter.next_back(), None); + assert_eq!(a, vec![1, 2, 3, 4, 6, 5]); + assert_eq!(b, vec![200, 300, 400]); +} + +#[test] +fn test_zip_nth_back_side_effects_exhausted() { + let mut a = Vec::new(); + let mut b = Vec::new(); + let mut iter = [1, 2, 3, 4, 5, 6] + .iter() + .cloned() + .map(|n| { + a.push(n); + n * 10 + }) + .zip([2, 3, 4].iter().cloned().map(|n| { + b.push(n * 100); + n * 1000 + })); + + iter.next(); + iter.next(); + iter.next(); + iter.next(); + assert_eq!(iter.nth_back(0), None); + assert_eq!(a, vec![1, 2, 3, 4, 6, 5]); + assert_eq!(b, vec![200, 300, 400]); +} + #[test] fn test_iterator_step_by() { // Identity diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 904e3f72840..81e621318e1 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -17,7 +17,6 @@ #![feature(try_find)] #![feature(is_sorted)] #![feature(pattern)] -#![feature(range_is_empty)] #![feature(raw)] #![feature(sort_internals)] #![feature(slice_partition_at_index)] diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs index 9fea34d668f..bf977c141cb 100644 --- a/library/core/tests/ptr.rs +++ b/library/core/tests/ptr.rs @@ -300,7 +300,6 @@ fn drop(&mut self) { } #[test] -#[cfg_attr(miri, ignore)] // Miri does not compute a maximal `mid` for `align_offset` fn align_offset_zst() { // For pointers of stride = 0, the pointer is already aligned or it cannot be aligned at // all, because no amount of elements will align the pointer. @@ -315,7 +314,6 @@ fn align_offset_zst() { } #[test] -#[cfg_attr(miri, ignore)] // Miri does not compute a maximal `mid` for `align_offset` fn align_offset_stride1() { // For pointers of stride = 1, the pointer can always be aligned. The offset is equal to // number of bytes. @@ -337,7 +335,6 @@ fn align_offset_stride1() { } #[test] -#[cfg_attr(miri, ignore)] // Miri is too slow fn align_offset_weird_strides() { #[repr(packed)] struct A3(u16, u8); @@ -384,7 +381,9 @@ unsafe fn test_weird_stride(ptr: *const T, align: usize) -> bool { // implementation let mut align = 1; let mut x = false; - while align < 1024 { + // Miri is too slow + let limit = if cfg!(miri) { 32 } else { 1024 }; + while align < limit { for ptr in 1usize..4 * align { unsafe { x |= test_weird_stride::(ptr as *const A3, align); diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs index 42b483f33ba..5650c98f9c7 100644 --- a/library/core/tests/slice.rs +++ b/library/core/tests/slice.rs @@ -1630,7 +1630,6 @@ fn each_alignment_reversed() { } #[test] -#[cfg_attr(miri, ignore)] // Miri does not compute a maximal `mid` for `align_offset` fn test_align_to_simple() { let bytes = [1u8, 2, 3, 4, 5, 6, 7]; let (prefix, aligned, suffix) = unsafe { bytes.align_to::() }; @@ -1660,7 +1659,6 @@ fn test_align_to_zst() { } #[test] -#[cfg_attr(miri, ignore)] // Miri does not compute a maximal `mid` for `align_offset` fn test_align_to_non_trivial() { #[repr(align(8))] struct U64(u64, u64); diff --git a/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs index cf52091f609..ccc067a3c94 100644 --- a/library/panic_abort/src/lib.rs +++ b/library/panic_abort/src/lib.rs @@ -17,6 +17,7 @@ #![feature(panic_runtime)] #![feature(staged_api)] #![feature(rustc_attrs)] +#![feature(llvm_asm)] use core::any::Any; @@ -26,16 +27,7 @@ unreachable!() } -// "Leak" the payload and shim to the relevant abort on the platform in -// question. -// -// For Unix we just use `abort` from libc as it'll trigger debuggers, core -// dumps, etc, as one might expect. On Windows, however, the best option we have -// is the `__fastfail` intrinsics, but that's unfortunately not defined in LLVM, -// and the `RaiseFailFastException` function isn't available until Windows 7 -// which would break compat with XP. For now just use `intrinsics::abort` which -// will kill us with an illegal instruction, which will do a good enough job for -// now hopefully. +// "Leak" the payload and shim to the relevant abort on the platform in question. #[rustc_std_internal_symbol] pub unsafe extern "C" fn __rust_start_panic(_payload: usize) -> u32 { abort(); @@ -55,6 +47,21 @@ unsafe fn abort() -> ! { } __rust_abort(); } + } else if #[cfg(all(windows, any(target_arch = "x86", target_arch = "x86_64")))] { + // On Windows, use the processor-specific __fastfail mechanism. In Windows 8 + // and later, this will terminate the process immediately without running any + // in-process exception handlers. In earlier versions of Windows, this + // sequence of instructions will be treated as an access violation, + // terminating the process but without necessarily bypassing all exception + // handlers. + // + // https://docs.microsoft.com/en-us/cpp/intrinsics/fastfail + // + // Note: this is the same implementation as in libstd's `abort_internal` + unsafe fn abort() -> ! { + llvm_asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT + core::intrinsics::unreachable(); + } } else { unsafe fn abort() -> ! { core::intrinsics::abort(); diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index de3866d92fc..c5a871e09a6 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -451,7 +451,7 @@ impl SourceFile { /// Also note that even if `is_real` returns `true`, if `--remap-path-prefix` was passed on /// the command line, the path as given may not actually be valid. /// - /// [`is_real`]: #method.is_real + /// [`is_real`]: Self::is_real #[unstable(feature = "proc_macro_span", issue = "54725")] pub fn path(&self) -> PathBuf { PathBuf::from(self.0.path()) diff --git a/library/profiler_builtins/build.rs b/library/profiler_builtins/build.rs index 0605ca4d94f..b674f73ebf3 100644 --- a/library/profiler_builtins/build.rs +++ b/library/profiler_builtins/build.rs @@ -65,7 +65,7 @@ fn main() { // This should be a pretty good heuristic for when to set // COMPILER_RT_HAS_ATOMICS if env::var_os("CARGO_CFG_TARGET_HAS_ATOMIC") - .map(|features| features.to_string_lossy().to_lowercase().contains("cas")) + .map(|features| features.to_string_lossy().to_lowercase().contains("ptr")) .unwrap_or(false) { cfg.define("COMPILER_RT_HAS_ATOMICS", Some("1")); diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs index b4009c86419..64d8edf33bd 100644 --- a/library/std/src/alloc.rs +++ b/library/std/src/alloc.rs @@ -154,36 +154,45 @@ fn alloc_impl(&mut self, layout: Layout, zeroed: bool) -> Result, unsafe fn grow_impl( &mut self, ptr: NonNull, - layout: Layout, - new_size: usize, + old_layout: Layout, + new_layout: Layout, zeroed: bool, ) -> Result, AllocErr> { debug_assert!( - new_size >= layout.size(), - "`new_size` must be greater than or equal to `layout.size()`" + new_layout.size() >= old_layout.size(), + "`new_layout.size()` must be greater than or equal to `old_layout.size()`" ); - match layout.size() { - // SAFETY: the caller must ensure that the `new_size` does not overflow. - // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid for a Layout. - 0 => unsafe { - let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); - self.alloc_impl(new_layout, zeroed) - }, + match old_layout.size() { + 0 => self.alloc_impl(new_layout, zeroed), // SAFETY: `new_size` is non-zero as `old_size` is greater than or equal to `new_size` // as required by safety conditions. Other conditions must be upheld by the caller - old_size => unsafe { - // `realloc` probably checks for `new_size >= size` or something similar. - intrinsics::assume(new_size >= layout.size()); + old_size if old_layout.align() == new_layout.align() => unsafe { + let new_size = new_layout.size(); + + // `realloc` probably checks for `new_size >= old_layout.size()` or something similar. + intrinsics::assume(new_size >= old_layout.size()); - let raw_ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size); + let raw_ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), old_layout, new_size); let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?; if zeroed { raw_ptr.add(old_size).write_bytes(0, new_size - old_size); } Ok(NonNull::slice_from_raw_parts(ptr, new_size)) }, + + // SAFETY: because `new_layout.size()` must be greater than or equal to `old_size`, + // both the old and new memory allocation are valid for reads and writes for `old_size` + // bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap + // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract + // for `dealloc` must be upheld by the caller. + old_size => unsafe { + let new_ptr = self.alloc_impl(new_layout, zeroed)?; + ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_size); + self.dealloc(ptr, old_layout); + Ok(new_ptr) + }, } } } @@ -215,52 +224,64 @@ unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { unsafe fn grow( &mut self, ptr: NonNull, - layout: Layout, - new_size: usize, + old_layout: Layout, + new_layout: Layout, ) -> Result, AllocErr> { // SAFETY: all conditions must be upheld by the caller - unsafe { self.grow_impl(ptr, layout, new_size, false) } + unsafe { self.grow_impl(ptr, old_layout, new_layout, false) } } #[inline] unsafe fn grow_zeroed( &mut self, ptr: NonNull, - layout: Layout, - new_size: usize, + old_layout: Layout, + new_layout: Layout, ) -> Result, AllocErr> { // SAFETY: all conditions must be upheld by the caller - unsafe { self.grow_impl(ptr, layout, new_size, true) } + unsafe { self.grow_impl(ptr, old_layout, new_layout, true) } } #[inline] unsafe fn shrink( &mut self, ptr: NonNull, - layout: Layout, - new_size: usize, + old_layout: Layout, + new_layout: Layout, ) -> Result, AllocErr> { debug_assert!( - new_size <= layout.size(), - "`new_size` must be smaller than or equal to `layout.size()`" + new_layout.size() <= old_layout.size(), + "`new_layout.size()` must be smaller than or equal to `old_layout.size()`" ); - match new_size { + match new_layout.size() { // SAFETY: conditions must be upheld by the caller 0 => unsafe { - self.dealloc(ptr, layout); - Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)) + self.dealloc(ptr, old_layout); + Ok(NonNull::slice_from_raw_parts(new_layout.dangling(), 0)) }, // SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller - new_size => unsafe { - // `realloc` probably checks for `new_size <= size` or something similar. - intrinsics::assume(new_size <= layout.size()); + new_size if old_layout.align() == new_layout.align() => unsafe { + // `realloc` probably checks for `new_size <= old_layout.size()` or something similar. + intrinsics::assume(new_size <= old_layout.size()); - let raw_ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size); + let raw_ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), old_layout, new_size); let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?; Ok(NonNull::slice_from_raw_parts(ptr, new_size)) }, + + // SAFETY: because `new_size` must be smaller than or equal to `old_layout.size()`, + // both the old and new memory allocation are valid for reads and writes for `new_size` + // bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap + // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract + // for `dealloc` must be upheld by the caller. + new_size => unsafe { + let new_ptr = self.alloc(new_layout)?; + ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), new_size); + self.dealloc(ptr, old_layout); + Ok(new_ptr) + }, } } } diff --git a/library/std/src/collections/mod.rs b/library/std/src/collections/mod.rs index b6488ae61b1..a1aab767eb2 100644 --- a/library/std/src/collections/mod.rs +++ b/library/std/src/collections/mod.rs @@ -396,15 +396,7 @@ //! assert_eq!(map.keys().next().unwrap().b, "baz"); //! ``` //! -//! [`Vec`]: ../../std/vec/struct.Vec.html -//! [`HashMap`]: ../../std/collections/struct.HashMap.html -//! [`VecDeque`]: ../../std/collections/struct.VecDeque.html -//! [`LinkedList`]: ../../std/collections/struct.LinkedList.html -//! [`BTreeMap`]: ../../std/collections/struct.BTreeMap.html -//! [`HashSet`]: ../../std/collections/struct.HashSet.html -//! [`BTreeSet`]: ../../std/collections/struct.BTreeSet.html -//! [`BinaryHeap`]: ../../std/collections/struct.BinaryHeap.html -//! [`IntoIterator`]: ../../std/iter/trait.IntoIterator.html +//! [`IntoIterator`]: crate::iter::IntoIterator #![stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 1b7681bd4bb..84e686c2fef 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -296,6 +296,8 @@ fn from(str_err: String) -> Box { impl<'a> From<&str> for Box { /// Converts a [`str`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. /// + /// [`str`]: prim@str + /// /// # Examples /// /// ``` @@ -317,6 +319,8 @@ fn from(err: &str) -> Box { impl From<&str> for Box { /// Converts a [`str`] into a box of dyn [`Error`]. /// + /// [`str`]: prim@str + /// /// # Examples /// /// ``` diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs index 11b3f22503e..717967fb768 100644 --- a/library/std/src/ffi/c_str.rs +++ b/library/std/src/ffi/c_str.rs @@ -69,7 +69,7 @@ /// extern functions. See the documentation for that function for a /// discussion on ensuring the lifetime of the raw pointer. /// -/// [`&str`]: str +/// [`&str`]: prim@str /// [slice.as_ptr]: ../primitive.slice.html#method.as_ptr /// [slice.len]: ../primitive.slice.html#method.len /// [`Deref`]: ops::Deref @@ -180,7 +180,7 @@ pub struct CString { /// println!("string: {}", my_string_safe()); /// ``` /// -/// [`&str`]: str +/// [`&str`]: prim@str #[derive(Hash)] #[stable(feature = "rust1", since = "1.0.0")] // FIXME: @@ -1351,7 +1351,7 @@ pub fn to_bytes_with_nul(&self) -> &[u8] { /// function will return the corresponding [`&str`] slice. Otherwise, /// it will return an error with details of where UTF-8 validation failed. /// - /// [`&str`]: str + /// [`&str`]: prim@str /// /// # Examples /// @@ -1379,6 +1379,7 @@ pub fn to_str(&self) -> Result<&str, str::Utf8Error> { /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD] and return a /// [`Cow`]`::`[`Owned`]`(`[`String`]`)` with the result. /// + /// [`str`]: prim@str /// [`Borrowed`]: Cow::Borrowed /// [`Owned`]: Cow::Owned /// [U+FFFD]: crate::char::REPLACEMENT_CHARACTER diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 2767675ff92..b1630f8f549 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -1921,7 +1921,7 @@ pub fn create_dir_all>(path: P) -> io::Result<()> { DirBuilder::new().recursive(true).create(path.as_ref()) } -/// Removes an existing, empty directory. +/// Removes an empty directory. /// /// # Platform-specific behavior /// @@ -1936,6 +1936,8 @@ pub fn create_dir_all>(path: P) -> io::Result<()> { /// This function will return an error in the following situations, but is not /// limited to just these cases: /// +/// * `path` doesn't exist. +/// * `path` isn't a directory. /// * The user lacks permissions to remove the directory at the provided `path`. /// * The directory isn't empty. /// diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 32456294838..462b696db40 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -480,7 +480,7 @@ pub(crate) fn default_write_vectored(write: F, bufs: &[IoSlice<'_>]) -> Resul /// ``` /// /// [`read()`]: Read::read -/// [`&str`]: str +/// [`&str`]: prim@str /// [`std::io`]: self /// [`File`]: crate::fs::File /// [slice]: ../../std/primitive.slice.html diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 286eb92915e..3943c66aad5 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -50,8 +50,9 @@ /// handles is **not** available to raw handles returned from this function. /// /// The returned handle has no external synchronization or buffering. -fn stdin_raw() -> io::Result { - stdio::Stdin::new().map(StdinRaw) +#[unstable(feature = "libstd_sys_internals", issue = "none")] +const fn stdin_raw() -> StdinRaw { + StdinRaw(stdio::Stdin::new()) } /// Constructs a new raw handle to the standard output stream of this process. @@ -63,8 +64,9 @@ fn stdin_raw() -> io::Result { /// /// The returned handle has no external synchronization or buffering layered on /// top. -fn stdout_raw() -> io::Result { - stdio::Stdout::new().map(StdoutRaw) +#[unstable(feature = "libstd_sys_internals", issue = "none")] +const fn stdout_raw() -> StdoutRaw { + StdoutRaw(stdio::Stdout::new()) } /// Constructs a new raw handle to the standard error stream of this process. @@ -74,17 +76,18 @@ fn stdout_raw() -> io::Result { /// /// The returned handle has no external synchronization or buffering layered on /// top. -fn stderr_raw() -> io::Result { - stdio::Stderr::new().map(StderrRaw) +#[unstable(feature = "libstd_sys_internals", issue = "none")] +const fn stderr_raw() -> StderrRaw { + StderrRaw(stdio::Stderr::new()) } impl Read for StdinRaw { fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) + handle_ebadf(self.0.read(buf), 0) } fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - self.0.read_vectored(bufs) + handle_ebadf(self.0.read_vectored(bufs), 0) } #[inline] @@ -98,25 +101,22 @@ unsafe fn initializer(&self) -> Initializer { } fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - self.0.read_to_end(buf) + handle_ebadf(self.0.read_to_end(buf), 0) } fn read_to_string(&mut self, buf: &mut String) -> io::Result { - self.0.read_to_string(buf) - } - - fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { - self.0.read_exact(buf) + handle_ebadf(self.0.read_to_string(buf), 0) } } impl Write for StdoutRaw { fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.write(buf) + handle_ebadf(self.0.write(buf), buf.len()) } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - self.0.write_vectored(bufs) + let total = bufs.iter().map(|b| b.len()).sum(); + handle_ebadf(self.0.write_vectored(bufs), total) } #[inline] @@ -125,29 +125,30 @@ fn is_write_vectored(&self) -> bool { } fn flush(&mut self) -> io::Result<()> { - self.0.flush() + handle_ebadf(self.0.flush(), ()) } fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - self.0.write_all(buf) + handle_ebadf(self.0.write_all(buf), ()) } fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - self.0.write_all_vectored(bufs) + handle_ebadf(self.0.write_all_vectored(bufs), ()) } fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { - self.0.write_fmt(fmt) + handle_ebadf(self.0.write_fmt(fmt), ()) } } impl Write for StderrRaw { fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.write(buf) + handle_ebadf(self.0.write(buf), buf.len()) } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - self.0.write_vectored(bufs) + let total = bufs.iter().map(|b| b.len()).sum(); + handle_ebadf(self.0.write_vectored(bufs), total) } #[inline] @@ -156,80 +157,19 @@ fn is_write_vectored(&self) -> bool { } fn flush(&mut self) -> io::Result<()> { - self.0.flush() + handle_ebadf(self.0.flush(), ()) } fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - self.0.write_all(buf) + handle_ebadf(self.0.write_all(buf), ()) } fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - self.0.write_all_vectored(bufs) + handle_ebadf(self.0.write_all_vectored(bufs), ()) } fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { - self.0.write_fmt(fmt) - } -} - -enum Maybe { - Real(T), - Fake, -} - -impl io::Write for Maybe { - fn write(&mut self, buf: &[u8]) -> io::Result { - match *self { - Maybe::Real(ref mut w) => handle_ebadf(w.write(buf), buf.len()), - Maybe::Fake => Ok(buf.len()), - } - } - - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - let total = bufs.iter().map(|b| b.len()).sum(); - match self { - Maybe::Real(w) => handle_ebadf(w.write_vectored(bufs), total), - Maybe::Fake => Ok(total), - } - } - - #[inline] - fn is_write_vectored(&self) -> bool { - match self { - Maybe::Real(w) => w.is_write_vectored(), - Maybe::Fake => true, - } - } - - fn flush(&mut self) -> io::Result<()> { - match *self { - Maybe::Real(ref mut w) => handle_ebadf(w.flush(), ()), - Maybe::Fake => Ok(()), - } - } -} - -impl io::Read for Maybe { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - match *self { - Maybe::Real(ref mut r) => handle_ebadf(r.read(buf), 0), - Maybe::Fake => Ok(0), - } - } - - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - match self { - Maybe::Real(r) => handle_ebadf(r.read_vectored(bufs), 0), - Maybe::Fake => Ok(0), - } - } - - #[inline] - fn is_read_vectored(&self) -> bool { - match self { - Maybe::Real(w) => w.is_read_vectored(), - Maybe::Fake => true, - } + handle_ebadf(self.0.write_fmt(fmt), ()) } } @@ -274,7 +214,7 @@ fn handle_ebadf(r: io::Result, default: T) -> io::Result { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Stdin { - inner: Arc>>>, + inner: Arc>>, } /// A locked reference to the `Stdin` handle. @@ -305,7 +245,7 @@ pub struct Stdin { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct StdinLock<'a> { - inner: MutexGuard<'a, BufReader>>, + inner: MutexGuard<'a, BufReader>, } /// Constructs a new handle to the standard input of the current process. @@ -349,18 +289,14 @@ pub struct StdinLock<'a> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn stdin() -> Stdin { - static INSTANCE: Lazy>>> = Lazy::new(); + static INSTANCE: Lazy>> = Lazy::new(); return Stdin { inner: unsafe { INSTANCE.get(stdin_init).expect("cannot access stdin during shutdown") }, }; - fn stdin_init() -> Arc>>> { + fn stdin_init() -> Arc>> { // This must not reentrantly access `INSTANCE` - let stdin = match stdin_raw() { - Ok(stdin) => Maybe::Real(stdin), - _ => Maybe::Fake, - }; - + let stdin = stdin_raw(); Arc::new(Mutex::new(BufReader::with_capacity(stdio::STDIN_BUF_SIZE, stdin))) } } @@ -537,7 +473,7 @@ pub struct Stdout { // FIXME: this should be LineWriter or BufWriter depending on the state of // stdout (tty or not). Note that if this is not line buffered it // should also flush-on-panic or some form of flush-on-abort. - inner: Arc>>>>, + inner: Arc>>>, } /// A locked reference to the `Stdout` handle. @@ -551,7 +487,7 @@ pub struct Stdout { /// an error. #[stable(feature = "rust1", since = "1.0.0")] pub struct StdoutLock<'a> { - inner: ReentrantMutexGuard<'a, RefCell>>>, + inner: ReentrantMutexGuard<'a, RefCell>>, } /// Constructs a new handle to the standard output of the current process. @@ -595,17 +531,14 @@ pub struct StdoutLock<'a> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn stdout() -> Stdout { - static INSTANCE: Lazy>>>> = Lazy::new(); + static INSTANCE: Lazy>>> = Lazy::new(); return Stdout { inner: unsafe { INSTANCE.get(stdout_init).expect("cannot access stdout during shutdown") }, }; - fn stdout_init() -> Arc>>>> { + fn stdout_init() -> Arc>>> { // This must not reentrantly access `INSTANCE` - let stdout = match stdout_raw() { - Ok(stdout) => Maybe::Real(stdout), - _ => Maybe::Fake, - }; + let stdout = stdout_raw(); unsafe { let ret = Arc::new(ReentrantMutex::new(RefCell::new(LineWriter::new(stdout)))); ret.init(); @@ -715,7 +648,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// an error. #[stable(feature = "rust1", since = "1.0.0")] pub struct Stderr { - inner: &'static ReentrantMutex>>, + inner: &'static ReentrantMutex>, } /// A locked reference to the `Stderr` handle. @@ -729,7 +662,7 @@ pub struct Stderr { /// an error. #[stable(feature = "rust1", since = "1.0.0")] pub struct StderrLock<'a> { - inner: ReentrantMutexGuard<'a, RefCell>>, + inner: ReentrantMutexGuard<'a, RefCell>, } /// Constructs a new handle to the standard error of the current process. @@ -778,19 +711,14 @@ pub fn stderr() -> Stderr { // // This has the added benefit of allowing `stderr` to be usable during // process shutdown as well! - static INSTANCE: ReentrantMutex>> = - unsafe { ReentrantMutex::new(RefCell::new(Maybe::Fake)) }; + static INSTANCE: ReentrantMutex> = + unsafe { ReentrantMutex::new(RefCell::new(stderr_raw())) }; // When accessing stderr we need one-time initialization of the reentrant - // mutex, followed by one-time detection of whether we actually have a - // stderr handle or not. Afterwards we can just always use the now-filled-in - // `INSTANCE` value. + // mutex. Afterwards we can just always use the now-filled-in `INSTANCE` value. static INIT: Once = Once::new(); INIT.call_once(|| unsafe { INSTANCE.init(); - if let Ok(stderr) = stderr_raw() { - *INSTANCE.lock().borrow_mut() = Maybe::Real(stderr); - } }); Stderr { inner: &INSTANCE } } diff --git a/library/std/src/lazy.rs b/library/std/src/lazy.rs index f0548582d2f..d0f27df5185 100644 --- a/library/std/src/lazy.rs +++ b/library/std/src/lazy.rs @@ -293,7 +293,7 @@ pub fn into_inner(mut self) -> Option { // Don't drop this `SyncOnceCell`. We just moved out one of the fields, but didn't set // the state to uninitialized. - mem::ManuallyDrop::new(self); + mem::forget(self); inner } diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 1144a13b52c..1142b74ff0d 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -172,6 +172,7 @@ //! [`Vec`]: vec::Vec //! [`atomic`]: sync::atomic //! [`for`]: ../book/ch03-05-control-flow.html#looping-through-a-collection-with-for +//! [`str`]: prim@str //! [`mpsc`]: sync::mpsc //! [`std::cmp`]: cmp //! [`std::slice`]: slice @@ -208,7 +209,7 @@ #![cfg_attr(test, feature(print_internals, set_stdio, update_panic_count))] #![cfg_attr( all(target_vendor = "fortanix", target_env = "sgx"), - feature(slice_index_methods, coerce_unsized, sgx_platform, ptr_wrapping_offset_from) + feature(slice_index_methods, coerce_unsized, sgx_platform) )] #![cfg_attr(all(test, target_vendor = "fortanix", target_env = "sgx"), feature(fixed_size_array))] // std is implemented with unstable features, many of which are internal diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs index 724dbada930..e8898d98ff3 100644 --- a/library/std/src/macros.rs +++ b/library/std/src/macros.rs @@ -1,6 +1,6 @@ //! Standard library macros //! -//! This modules contains a set of macros which are exported from the standard +//! This module contains a set of macros which are exported from the standard //! library. Each macro is available for use when linking against the standard //! library. @@ -29,9 +29,7 @@ macro_rules! panic { /// Use `print!` only for the primary output of your program. Use /// [`eprint!`] instead to print error and progress messages. /// -/// [`println!`]: ../std/macro.println.html -/// [flush]: ../std/io/trait.Write.html#tymethod.flush -/// [`eprint!`]: ../std/macro.eprint.html +/// [flush]: crate::io::Write::flush /// /// # Panics /// @@ -74,12 +72,13 @@ macro_rules! print { /// Use `println!` only for the primary output of your program. Use /// [`eprintln!`] instead to print error and progress messages. /// -/// [`format!`]: ../std/macro.format.html -/// [`std::fmt`]: ../std/fmt/index.html -/// [`eprintln!`]: ../std/macro.eprintln.html +/// [`std::fmt`]: crate::fmt +/// /// # Panics /// -/// Panics if writing to `io::stdout` fails. +/// Panics if writing to [`io::stdout`] fails. +/// +/// [`io::stdout`]: crate::io::stdout /// /// # Examples /// @@ -101,14 +100,14 @@ macro_rules! println { /// Prints to the standard error. /// /// Equivalent to the [`print!`] macro, except that output goes to -/// [`io::stderr`] instead of `io::stdout`. See [`print!`] for +/// [`io::stderr`] instead of [`io::stdout`]. See [`print!`] for /// example usage. /// /// Use `eprint!` only for error and progress messages. Use `print!` /// instead for the primary output of your program. /// -/// [`io::stderr`]: ../std/io/struct.Stderr.html -/// [`print!`]: ../std/macro.print.html +/// [`io::stderr`]: crate::io::stderr +/// [`io::stdout`]: crate::io::stdout /// /// # Panics /// @@ -129,14 +128,14 @@ macro_rules! eprint { /// Prints to the standard error, with a newline. /// /// Equivalent to the [`println!`] macro, except that output goes to -/// [`io::stderr`] instead of `io::stdout`. See [`println!`] for +/// [`io::stderr`] instead of [`io::stdout`]. See [`println!`] for /// example usage. /// /// Use `eprintln!` only for error and progress messages. Use `println!` /// instead for the primary output of your program. /// -/// [`io::stderr`]: ../std/io/struct.Stderr.html -/// [`println!`]: ../std/macro.println.html +/// [`io::stderr`]: crate::io::stderr +/// [`io::stdout`]: crate::io::stdout /// /// # Panics /// diff --git a/library/std/src/net/addr.rs b/library/std/src/net/addr.rs index c11049fb981..d7d96862b21 100644 --- a/library/std/src/net/addr.rs +++ b/library/std/src/net/addr.rs @@ -268,7 +268,7 @@ pub fn new(ip: Ipv4Addr, port: u16) -> SocketAddrV4 { inner: c::sockaddr_in { sin_family: c::AF_INET as c::sa_family_t, sin_port: htons(port), - sin_addr: *ip.as_inner(), + sin_addr: ip.into_inner(), ..unsafe { mem::zeroed() } }, } @@ -286,6 +286,8 @@ pub fn new(ip: Ipv4Addr, port: u16) -> SocketAddrV4 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn ip(&self) -> &Ipv4Addr { + // SAFETY: `Ipv4Addr` is `#[repr(C)] struct { _: in_addr; }`. + // It is safe to cast from `&in_addr` to `&Ipv4Addr`. unsafe { &*(&self.inner.sin_addr as *const c::in_addr as *const Ipv4Addr) } } @@ -302,7 +304,7 @@ pub fn ip(&self) -> &Ipv4Addr { /// ``` #[stable(feature = "sockaddr_setters", since = "1.9.0")] pub fn set_ip(&mut self, new_ip: Ipv4Addr) { - self.inner.sin_addr = *new_ip.as_inner() + self.inner.sin_addr = new_ip.into_inner() } /// Returns the port number associated with this socket address. diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index de28268ea36..85bb6b60e68 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -12,7 +12,7 @@ use crate::io::Write as IoWrite; use crate::mem::transmute; use crate::sys::net::netc as c; -use crate::sys_common::{AsInner, FromInner}; +use crate::sys_common::{AsInner, FromInner, IntoInner}; /// An IP address, either IPv4 or IPv6. /// @@ -909,7 +909,10 @@ impl Eq for Ipv4Addr {} #[stable(feature = "rust1", since = "1.0.0")] impl hash::Hash for Ipv4Addr { fn hash(&self, s: &mut H) { - // `inner` is #[repr(packed)], so we need to copy `s_addr`. + // NOTE: + // * hash in big endian order + // * in netbsd, `in_addr` has `repr(packed)`, we need to + // copy `s_addr` to avoid unsafe borrowing { self.inner.s_addr }.hash(s) } } @@ -944,13 +947,14 @@ fn partial_cmp(&self, other: &IpAddr) -> Option { #[stable(feature = "rust1", since = "1.0.0")] impl Ord for Ipv4Addr { fn cmp(&self, other: &Ipv4Addr) -> Ordering { + // Compare as native endian u32::from_be(self.inner.s_addr).cmp(&u32::from_be(other.inner.s_addr)) } } -impl AsInner for Ipv4Addr { - fn as_inner(&self) -> &c::in_addr { - &self.inner +impl IntoInner for Ipv4Addr { + fn into_inner(self) -> c::in_addr { + self.inner } } @@ -2019,6 +2023,7 @@ fn test_from_str_socket_addr() { #[test] fn ipv4_addr_to_string() { + assert_eq!(Ipv4Addr::new(127, 0, 0, 1).to_string(), "127.0.0.1"); // Short address assert_eq!(Ipv4Addr::new(1, 1, 1, 1).to_string(), "1.1.1.1"); // Long address diff --git a/library/std/src/os/linux/raw.rs b/library/std/src/os/linux/raw.rs index eb8589eb58f..1950ffcb21b 100644 --- a/library/std/src/os/linux/raw.rs +++ b/library/std/src/os/linux/raw.rs @@ -170,63 +170,63 @@ pub struct stat { #[cfg(target_arch = "hexagon")] mod arch { - use crate::os::raw::{c_int, c_long, c_longlong, c_ulonglong}; + use crate::os::raw::{c_int, c_long, c_uint}; #[stable(feature = "raw_ext", since = "1.1.0")] - pub type blkcnt_t = c_longlong; + pub type blkcnt_t = i64; #[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = c_long; #[stable(feature = "raw_ext", since = "1.1.0")] - pub type ino_t = c_ulonglong; + pub type ino_t = u64; #[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = c_uint; #[stable(feature = "raw_ext", since = "1.1.0")] - pub type off_t = c_longlong; + pub type off_t = i64; #[stable(feature = "raw_ext", since = "1.1.0")] - pub type time_t = c_long; + pub type time_t = i64; #[repr(C)] #[derive(Clone)] #[stable(feature = "raw_ext", since = "1.1.0")] pub struct stat { #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: ::dev_t, + pub st_dev: u64, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: ::c_ulonglong, + pub st_ino: u64, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: ::c_uint, + pub st_mode: u32, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: ::c_uint, + pub st_nlink: u32, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: ::c_uint, + pub st_uid: u32, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: ::c_uint, + pub st_gid: u32, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: ::c_ulonglong, + pub st_rdev: u64, #[stable(feature = "raw_ext", since = "1.1.0")] - pub __pad1: ::c_ulong, + pub __pad1: u32, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: ::c_longlong, + pub st_size: i64, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: ::blksize_t, + pub st_blksize: i32, #[stable(feature = "raw_ext", since = "1.1.0")] - pub __pad2: ::c_int, + pub __pad2: i32, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: ::blkcnt_t, + pub st_blocks: i64, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: ::time_t, + pub st_atime: i64, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: ::c_long, + pub st_atime_nsec: c_long, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: ::time_t, + pub st_mtime: i64, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: ::c_long, + pub st_mtime_nsec: c_long, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: ::time_t, + pub st_ctime: i64, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: ::c_long, + pub st_ctime_nsec: c_long, #[stable(feature = "raw_ext", since = "1.1.0")] - pub __pad3: [::c_int; 2], + pub __pad3: [c_int; 2], } } diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index bca1732b84d..be7fd0dd6c4 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -587,6 +587,20 @@ mod prim_array {} /// x[1] = 7; /// assert_eq!(x, &[1, 7, 3]); /// ``` +/// +/// As slices store the length of the sequence they refer to, they have twice +/// the size of pointers to [`Sized`](marker/trait.Sized.html) types. +/// Also see the reference on +/// [dynamically sized types](../reference/dynamically-sized-types.html). +/// +/// ``` +/// # use std::rc::Rc; +/// let pointer_size = std::mem::size_of::<&u8>(); +/// assert_eq!(2 * pointer_size, std::mem::size_of::<&[u8]>()); +/// assert_eq!(2 * pointer_size, std::mem::size_of::<*const [u8]>()); +/// assert_eq!(2 * pointer_size, std::mem::size_of::>()); +/// assert_eq!(2 * pointer_size, std::mem::size_of::>()); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] mod prim_slice {} diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 6d94fa9ebfe..c42bc109652 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -126,7 +126,7 @@ /// /// # Warning /// -/// On some system, calling [`wait`] or similar is necessary for the OS to +/// On some systems, calling [`wait`] or similar is necessary for the OS to /// release resources. A process that terminated but has not been waited on is /// still around as a "zombie". Leaving too many zombies around may exhaust /// global resources (for example process IDs). diff --git a/library/std/src/sync/barrier.rs b/library/std/src/sync/barrier.rs index 01314370ce3..23c989fd2fd 100644 --- a/library/std/src/sync/barrier.rs +++ b/library/std/src/sync/barrier.rs @@ -131,7 +131,7 @@ pub fn wait(&self) -> BarrierWaitResult { lock.count += 1; if lock.count < self.num_threads { // We need a while loop to guard against spurious wakeups. - // http://en.wikipedia.org/wiki/Spurious_wakeup + // https://en.wikipedia.org/wiki/Spurious_wakeup while local_gen == lock.generation_id && lock.count < self.num_threads { lock = self.cvar.wait(lock).unwrap(); } diff --git a/library/std/src/sync/condvar.rs b/library/std/src/sync/condvar.rs index 9b90bfd68b5..4efd86aa3ed 100644 --- a/library/std/src/sync/condvar.rs +++ b/library/std/src/sync/condvar.rs @@ -11,7 +11,7 @@ /// /// It is returned by the [`wait_timeout`] method. /// -/// [`wait_timeout`]: struct.Condvar.html#method.wait_timeout +/// [`wait_timeout`]: Condvar::wait_timeout #[derive(Debug, PartialEq, Eq, Copy, Clone)] #[stable(feature = "wait_timeout", since = "1.5.0")] pub struct WaitTimeoutResult(bool); @@ -161,11 +161,10 @@ pub fn new() -> Condvar { /// mutex to ensure defined behavior across platforms. If this functionality /// is not desired, then unsafe primitives in `sys` are provided. /// - /// [`notify_one`]: #method.notify_one - /// [`notify_all`]: #method.notify_all - /// [poisoning]: ../sync/struct.Mutex.html#poisoning - /// [`Mutex`]: ../sync/struct.Mutex.html - /// [`panic!`]: ../../std/macro.panic.html + /// [`notify_one`]: Self::notify_one + /// [`notify_all`]: Self::notify_all + /// [poisoning]: super::Mutex#poisoning + /// [`Mutex`]: super::Mutex /// /// # Examples /// @@ -218,10 +217,10 @@ pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>) -> LockResult( /// Like [`wait`], the lock specified will be re-acquired when this function /// returns, regardless of whether the timeout elapsed or not. /// - /// [`wait`]: #method.wait + /// [`wait`]: Self::wait /// /// # Examples /// @@ -350,9 +349,8 @@ pub fn wait_timeout_ms<'a, T>( /// Like [`wait`], the lock specified will be re-acquired when this function /// returns, regardless of whether the timeout elapsed or not. /// - /// [`wait`]: #method.wait - /// [`wait_timeout_while`]: #method.wait_timeout_while - /// [`WaitTimeoutResult`]: struct.WaitTimeoutResult.html + /// [`wait`]: Self::wait + /// [`wait_timeout_while`]: Self::wait_timeout_while /// /// # Examples /// @@ -420,9 +418,8 @@ pub fn wait_timeout<'a, T>( /// Like [`wait_while`], the lock specified will be re-acquired when this /// function returns, regardless of whether the timeout elapsed or not. /// - /// [`wait_while`]: #method.wait_while - /// [`wait_timeout`]: #method.wait_timeout - /// [`WaitTimeoutResult`]: struct.WaitTimeoutResult.html + /// [`wait_while`]: Self::wait_while + /// [`wait_timeout`]: Self::wait_timeout /// /// # Examples /// @@ -485,9 +482,9 @@ pub fn wait_timeout_while<'a, T, F>( /// /// To wake up all threads, see [`notify_all`]. /// - /// [`wait`]: #method.wait - /// [`wait_timeout`]: #method.wait_timeout - /// [`notify_all`]: #method.notify_all + /// [`wait`]: Self::wait + /// [`wait_timeout`]: Self::wait_timeout + /// [`notify_all`]: Self::notify_all /// /// # Examples /// @@ -527,7 +524,7 @@ pub fn notify_one(&self) { /// /// To wake up only one thread, see [`notify_one`]. /// - /// [`notify_one`]: #method.notify_one + /// [`notify_one`]: Self::notify_one /// /// # Examples /// diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs index 3ff50e9f213..ac83017d9e1 100644 --- a/library/std/src/sync/mpsc/mod.rs +++ b/library/std/src/sync/mpsc/mod.rs @@ -1,5 +1,3 @@ -// ignore-tidy-filelength - //! Multi-producer, single-consumer FIFO queue communication primitives. //! //! This module provides message-based communication over channels, concretely @@ -27,12 +25,7 @@ //! that a bound of 0 is allowed, causing the channel to become a "rendezvous" //! channel where each sender atomically hands off a message to a receiver. //! -//! [`Sender`]: ../../../std/sync/mpsc/struct.Sender.html -//! [`SyncSender`]: ../../../std/sync/mpsc/struct.SyncSender.html -//! [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html -//! [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send -//! [`channel`]: ../../../std/sync/mpsc/fn.channel.html -//! [`sync_channel`]: ../../../std/sync/mpsc/fn.sync_channel.html +//! [`send`]: Sender::send //! //! ## Disconnection //! @@ -46,9 +39,7 @@ //! will continue to [`unwrap`] the results returned from this module, //! instigating a propagation of failure among threads if one unexpectedly dies. //! -//! [`Result`]: ../../../std/result/enum.Result.html -//! [`Err`]: ../../../std/result/enum.Result.html#variant.Err -//! [`unwrap`]: ../../../std/result/enum.Result.html#method.unwrap +//! [`unwrap`]: Result::unwrap //! //! # Examples //! @@ -291,9 +282,7 @@ /// /// Messages sent to the channel can be retrieved using [`recv`]. /// -/// [`channel`]: fn.channel.html -/// [`sync_channel`]: fn.sync_channel.html -/// [`recv`]: struct.Receiver.html#method.recv +/// [`recv`]: Receiver::recv /// /// # Examples /// @@ -333,10 +322,8 @@ impl !Sync for Receiver {} /// waiting for a new message, and [`None`] will be returned /// when the corresponding channel has hung up. /// -/// [`iter`]: struct.Receiver.html#method.iter -/// [`Receiver`]: struct.Receiver.html -/// [`next`]: ../../../std/iter/trait.Iterator.html#tymethod.next -/// [`None`]: ../../../std/option/enum.Option.html#variant.None +/// [`iter`]: Receiver::iter +/// [`next`]: Iterator::next /// /// # Examples /// @@ -371,9 +358,7 @@ pub struct Iter<'a, T: 'a> { /// This iterator will never block the caller in order to wait for data to /// become available. Instead, it will return [`None`]. /// -/// [`Receiver`]: struct.Receiver.html -/// [`try_iter`]: struct.Receiver.html#method.try_iter -/// [`None`]: ../../../std/option/enum.Option.html#variant.None +/// [`try_iter`]: Receiver::try_iter /// /// # Examples /// @@ -414,9 +399,7 @@ pub struct TryIter<'a, T: 'a> { /// is called, waiting for a new message, and [`None`] will be /// returned if the corresponding channel has hung up. /// -/// [`Receiver`]: struct.Receiver.html -/// [`next`]: ../../../std/iter/trait.Iterator.html#tymethod.next -/// [`None`]: ../../../std/option/enum.Option.html#variant.None +/// [`next`]: Iterator::next /// /// # Examples /// @@ -447,8 +430,7 @@ pub struct IntoIter { /// /// Messages can be sent through this channel with [`send`]. /// -/// [`channel`]: fn.channel.html -/// [`send`]: struct.Sender.html#method.send +/// [`send`]: Sender::send /// /// # Examples /// @@ -493,9 +475,8 @@ impl !Sync for Sender {} /// /// [`send`] will block if there is no space in the internal buffer. /// -/// [`sync_channel`]: fn.sync_channel.html -/// [`send`]: struct.SyncSender.html#method.send -/// [`try_send`]: struct.SyncSender.html#method.try_send +/// [`send`]: SyncSender::send +/// [`try_send`]: SyncSender::try_send /// /// # Examples /// @@ -549,8 +530,8 @@ unsafe impl Send for SyncSender {} /// disconnected, implying that the data could never be received. The error /// contains the data being sent as a payload so it can be recovered. /// -/// [`Sender::send`]: struct.Sender.html#method.send -/// [`SyncSender::send`]: struct.SyncSender.html#method.send +/// [`Sender::send`]: Sender::send +/// [`SyncSender::send`]: SyncSender::send #[stable(feature = "rust1", since = "1.0.0")] #[derive(PartialEq, Eq, Clone, Copy)] pub struct SendError(#[stable(feature = "rust1", since = "1.0.0")] pub T); @@ -561,10 +542,7 @@ unsafe impl Send for SyncSender {} /// [`channel`] (or [`sync_channel`]) is disconnected, implying that no further /// messages will ever be received. /// -/// [`recv`]: struct.Receiver.html#method.recv -/// [`Receiver`]: struct.Receiver.html -/// [`channel`]: fn.channel.html -/// [`sync_channel`]: fn.sync_channel.html +/// [`recv`]: Receiver::recv #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct RecvError; @@ -573,9 +551,7 @@ unsafe impl Send for SyncSender {} /// not return data when called. This can occur with both a [`channel`] and /// a [`sync_channel`]. /// -/// [`try_recv`]: struct.Receiver.html#method.try_recv -/// [`channel`]: fn.channel.html -/// [`sync_channel`]: fn.sync_channel.html +/// [`try_recv`]: Receiver::try_recv #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub enum TryRecvError { @@ -594,9 +570,7 @@ pub enum TryRecvError { /// unable to return data when called. This can occur with both a [`channel`] and /// a [`sync_channel`]. /// -/// [`recv_timeout`]: struct.Receiver.html#method.recv_timeout -/// [`channel`]: fn.channel.html -/// [`sync_channel`]: fn.sync_channel.html +/// [`recv_timeout`]: Receiver::recv_timeout #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[stable(feature = "mpsc_recv_timeout", since = "1.12.0")] pub enum RecvTimeoutError { @@ -613,7 +587,7 @@ pub enum RecvTimeoutError { /// This enumeration is the list of the possible error outcomes for the /// [`try_send`] method. /// -/// [`try_send`]: struct.SyncSender.html#method.try_send +/// [`try_send`]: SyncSender::try_send #[stable(feature = "rust1", since = "1.0.0")] #[derive(PartialEq, Eq, Clone, Copy)] pub enum TrySendError { @@ -623,16 +597,11 @@ pub enum TrySendError { /// If this is a buffered channel, then the buffer is full at this time. If /// this is not a buffered channel, then there is no [`Receiver`] available to /// acquire the data. - /// - /// [`sync_channel`]: fn.sync_channel.html - /// [`Receiver`]: struct.Receiver.html #[stable(feature = "rust1", since = "1.0.0")] Full(#[stable(feature = "rust1", since = "1.0.0")] T), /// This [`sync_channel`]'s receiving half has disconnected, so the data could not be /// sent. The data is returned back to the callee in this case. - /// - /// [`sync_channel`]: fn.sync_channel.html #[stable(feature = "rust1", since = "1.0.0")] Disconnected(#[stable(feature = "rust1", since = "1.0.0")] T), } @@ -680,13 +649,8 @@ fn inner_unsafe(&self) -> &UnsafeCell> { /// [`Sender`] is disconnected while trying to [`recv`], the [`recv`] method will /// return a [`RecvError`]. /// -/// [`send`]: struct.Sender.html#method.send -/// [`recv`]: struct.Receiver.html#method.recv -/// [`Sender`]: struct.Sender.html -/// [`Receiver`]: struct.Receiver.html -/// [`sync_channel`]: fn.sync_channel.html -/// [`SendError`]: struct.SendError.html -/// [`RecvError`]: struct.RecvError.html +/// [`send`]: Sender::send +/// [`recv`]: Receiver::recv /// /// # Examples /// @@ -733,13 +697,8 @@ pub fn channel() -> (Sender, Receiver) { /// [`SendError`]. Similarly, If the [`SyncSender`] is disconnected while trying /// to [`recv`], the [`recv`] method will return a [`RecvError`]. /// -/// [`channel`]: fn.channel.html -/// [`send`]: struct.SyncSender.html#method.send -/// [`recv`]: struct.Receiver.html#method.recv -/// [`SyncSender`]: struct.SyncSender.html -/// [`Receiver`]: struct.Receiver.html -/// [`SendError`]: struct.SendError.html -/// [`RecvError`]: struct.RecvError.html +/// [`send`]: SyncSender::send +/// [`recv`]: Receiver::recv /// /// # Examples /// @@ -786,9 +745,6 @@ fn new(inner: Flavor) -> Sender { /// will be received. It is possible for the corresponding receiver to /// hang up immediately after this function returns [`Ok`]. /// - /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err - /// [`Ok`]: ../../../std/result/enum.Result.html#variant.Ok - /// /// This method will never block the current thread. /// /// # Examples @@ -933,9 +889,6 @@ fn new(inner: Arc>) -> SyncSender { /// [`Receiver`] has disconnected and is no longer able to receive /// information. /// - /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err - /// [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html - /// /// # Examples /// /// ```rust @@ -971,7 +924,7 @@ pub fn send(&self, t: T) -> Result<(), SendError> { /// See [`send`] for notes about guarantees of whether the /// receiver has received the data or not if this function is successful. /// - /// [`send`]: ../../../std/sync/mpsc/struct.SyncSender.html#method.send + /// [`send`]: Self::send /// /// # Examples /// @@ -1059,7 +1012,7 @@ fn new(inner: Flavor) -> Receiver { /// Compared with [`recv`], this function has two failure cases instead of one /// (one for disconnection, one for an empty buffer). /// - /// [`recv`]: struct.Receiver.html#method.recv + /// [`recv`]: Self::recv /// /// # Examples /// @@ -1117,10 +1070,6 @@ pub fn try_recv(&self) -> Result { /// However, since channels are buffered, messages sent before the disconnect /// will still be properly received. /// - /// [`Sender`]: struct.Sender.html - /// [`SyncSender`]: struct.SyncSender.html - /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err - /// /// # Examples /// /// ``` @@ -1203,10 +1152,6 @@ pub fn recv(&self) -> Result { /// However, since channels are buffered, messages sent before the disconnect /// will still be properly received. /// - /// [`Sender`]: struct.Sender.html - /// [`SyncSender`]: struct.SyncSender.html - /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err - /// /// # Known Issues /// /// There is currently a known issue (see [`#39364`]) that causes `recv_timeout` @@ -1304,10 +1249,6 @@ pub fn recv_timeout(&self, timeout: Duration) -> Result { /// However, since channels are buffered, messages sent before the disconnect /// will still be properly received. /// - /// [`Sender`]: struct.Sender.html - /// [`SyncSender`]: struct.SyncSender.html - /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err - /// /// # Examples /// /// Successfully receiving value before reaching deadline: @@ -1397,9 +1338,6 @@ pub fn recv_deadline(&self, deadline: Instant) -> Result { /// Returns an iterator that will block waiting for messages, but never /// [`panic!`]. It will return [`None`] when the channel has hung up. /// - /// [`panic!`]: ../../../std/macro.panic.html - /// [`None`]: ../../../std/option/enum.Option.html#variant.None - /// /// # Examples /// /// ```rust @@ -1430,8 +1368,6 @@ pub fn iter(&self) -> Iter<'_, T> { /// channel has hung up. The iterator will never [`panic!`] or block the /// user by waiting for values. /// - /// [`panic!`]: ../../../std/macro.panic.html - /// /// # Examples /// /// ```no_run diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs index 8478457eabf..d7a4f00305c 100644 --- a/library/std/src/sync/mutex.rs +++ b/library/std/src/sync/mutex.rs @@ -33,13 +33,12 @@ /// the guard that would have otherwise been returned on a successful lock. This /// allows access to the data, despite the lock being poisoned. /// -/// [`new`]: #method.new -/// [`lock`]: #method.lock -/// [`try_lock`]: #method.try_lock -/// [`Result`]: ../../std/result/enum.Result.html -/// [`unwrap()`]: ../../std/result/enum.Result.html#method.unwrap -/// [`PoisonError`]: ../../std/sync/struct.PoisonError.html -/// [`into_inner`]: ../../std/sync/struct.PoisonError.html#method.into_inner +/// [`new`]: Self::new +/// [`lock`]: Self::lock +/// [`try_lock`]: Self::try_lock +/// [`unwrap()`]: Result::unwrap +/// [`PoisonError`]: super::PoisonError +/// [`into_inner`]: super::PoisonError::into_inner /// /// # Examples /// @@ -190,11 +189,8 @@ unsafe impl Sync for Mutex {} /// This structure is created by the [`lock`] and [`try_lock`] methods on /// [`Mutex`]. /// -/// [`Deref`]: ../../std/ops/trait.Deref.html -/// [`DerefMut`]: ../../std/ops/trait.DerefMut.html -/// [`lock`]: struct.Mutex.html#method.lock -/// [`try_lock`]: struct.Mutex.html#method.try_lock -/// [`Mutex`]: struct.Mutex.html +/// [`lock`]: Mutex::lock +/// [`try_lock`]: Mutex::try_lock #[must_use = "if unused the Mutex will immediately unlock"] #[stable(feature = "rust1", since = "1.0.0")] pub struct MutexGuard<'a, T: ?Sized + 'a> { @@ -289,8 +285,6 @@ pub fn lock(&self) -> LockResult> { /// this call will return failure if the mutex would otherwise be /// acquired. /// - /// [`Err`]: ../../std/result/enum.Result.html#variant.Err - /// /// # Examples /// /// ``` @@ -432,8 +426,6 @@ fn drop(&mut self) { impl From for Mutex { /// Creates a new mutex in an unlocked state ready for use. /// This is equivalent to [`Mutex::new`]. - /// - /// [`Mutex::new`]: ../../std/sync/struct.Mutex.html#method.new fn from(t: T) -> Self { Mutex::new(t) } diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs index 50f54dbf143..586093c916d 100644 --- a/library/std/src/sync/rwlock.rs +++ b/library/std/src/sync/rwlock.rs @@ -58,11 +58,7 @@ /// } // write lock is dropped here /// ``` /// -/// [`Deref`]: ../../std/ops/trait.Deref.html -/// [`DerefMut`]: ../../std/ops/trait.DerefMut.html -/// [`Send`]: ../../std/marker/trait.Send.html -/// [`Sync`]: ../../std/marker/trait.Sync.html -/// [`Mutex`]: struct.Mutex.html +/// [`Mutex`]: super::Mutex #[stable(feature = "rust1", since = "1.0.0")] pub struct RwLock { inner: Box, @@ -81,9 +77,8 @@ unsafe impl Sync for RwLock {} /// This structure is created by the [`read`] and [`try_read`] methods on /// [`RwLock`]. /// -/// [`read`]: struct.RwLock.html#method.read -/// [`try_read`]: struct.RwLock.html#method.try_read -/// [`RwLock`]: struct.RwLock.html +/// [`read`]: RwLock::read +/// [`try_read`]: RwLock::try_read #[must_use = "if unused the RwLock will immediately unlock"] #[stable(feature = "rust1", since = "1.0.0")] pub struct RwLockReadGuard<'a, T: ?Sized + 'a> { @@ -102,9 +97,8 @@ unsafe impl Sync for RwLockReadGuard<'_, T> {} /// This structure is created by the [`write`] and [`try_write`] methods /// on [`RwLock`]. /// -/// [`write`]: struct.RwLock.html#method.write -/// [`try_write`]: struct.RwLock.html#method.try_write -/// [`RwLock`]: struct.RwLock.html +/// [`write`]: RwLock::write +/// [`try_write`]: RwLock::try_write #[must_use = "if unused the RwLock will immediately unlock"] #[stable(feature = "rust1", since = "1.0.0")] pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> { @@ -456,8 +450,6 @@ fn default() -> RwLock { impl From for RwLock { /// Creates a new instance of an `RwLock` which is unlocked. /// This is equivalent to [`RwLock::new`]. - /// - /// [`RwLock::new`]: ../../std/sync/struct.RwLock.html#method.new fn from(t: T) -> Self { RwLock::new(t) } diff --git a/library/std/src/sys/cloudabi/stdio.rs b/library/std/src/sys/cloudabi/stdio.rs index 601563c5b1f..7fec4731a46 100644 --- a/library/std/src/sys/cloudabi/stdio.rs +++ b/library/std/src/sys/cloudabi/stdio.rs @@ -6,8 +6,8 @@ pub struct Stderr(()); impl Stdin { - pub fn new() -> io::Result { - Ok(Stdin(())) + pub const fn new() -> Stdin { + Stdin(()) } } @@ -18,8 +18,8 @@ fn read(&mut self, _buf: &mut [u8]) -> io::Result { } impl Stdout { - pub fn new() -> io::Result { - Ok(Stdout(())) + pub const fn new() -> Stdout { + Stdout(()) } } @@ -37,8 +37,8 @@ fn flush(&mut self) -> io::Result<()> { } impl Stderr { - pub fn new() -> io::Result { - Ok(Stderr(())) + pub const fn new() -> Stderr { + Stderr(()) } } @@ -62,5 +62,5 @@ pub fn is_ebadf(err: &io::Error) -> bool { pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE; pub fn panic_output() -> Option { - Stderr::new().ok() + Some(Stderr::new()) } diff --git a/library/std/src/sys/hermit/stdio.rs b/library/std/src/sys/hermit/stdio.rs index f3654ee3871..82304dd6dc2 100644 --- a/library/std/src/sys/hermit/stdio.rs +++ b/library/std/src/sys/hermit/stdio.rs @@ -7,8 +7,8 @@ pub struct Stderr; impl Stdin { - pub fn new() -> io::Result { - Ok(Stdin) + pub const fn new() -> Stdin { + Stdin } } @@ -28,8 +28,8 @@ fn is_read_vectored(&self) -> bool { } impl Stdout { - pub fn new() -> io::Result { - Ok(Stdout) + pub const fn new() -> Stdout { + Stdout } } @@ -69,8 +69,8 @@ fn flush(&mut self) -> io::Result<()> { } impl Stderr { - pub fn new() -> io::Result { - Ok(Stderr) + pub const fn new() -> Stderr { + Stderr } } @@ -116,5 +116,5 @@ pub fn is_ebadf(_err: &io::Error) -> bool { } pub fn panic_output() -> Option { - Stderr::new().ok() + Some(Stderr::new()) } diff --git a/library/std/src/sys/sgx/stdio.rs b/library/std/src/sys/sgx/stdio.rs index 716c174bd53..49f44f9f498 100644 --- a/library/std/src/sys/sgx/stdio.rs +++ b/library/std/src/sys/sgx/stdio.rs @@ -19,8 +19,8 @@ fn with_std_fd R, R>(fd: abi::Fd, f: F) -> R { } impl Stdin { - pub fn new() -> io::Result { - Ok(Stdin(())) + pub const fn new() -> Stdin { + Stdin(()) } } @@ -31,8 +31,8 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result { } impl Stdout { - pub fn new() -> io::Result { - Ok(Stdout(())) + pub const fn new() -> Stdout { + Stdout(()) } } @@ -47,8 +47,8 @@ fn flush(&mut self) -> io::Result<()> { } impl Stderr { - pub fn new() -> io::Result { - Ok(Stderr(())) + pub const fn new() -> Stderr { + Stderr(()) } } diff --git a/library/std/src/sys/unix/stdio.rs b/library/std/src/sys/unix/stdio.rs index f8353214cbc..a05fe8165cf 100644 --- a/library/std/src/sys/unix/stdio.rs +++ b/library/std/src/sys/unix/stdio.rs @@ -7,8 +7,8 @@ pub struct Stderr(()); impl Stdin { - pub fn new() -> io::Result { - Ok(Stdin(())) + pub const fn new() -> Stdin { + Stdin(()) } } @@ -28,8 +28,8 @@ fn is_read_vectored(&self) -> bool { } impl Stdout { - pub fn new() -> io::Result { - Ok(Stdout(())) + pub const fn new() -> Stdout { + Stdout(()) } } @@ -53,8 +53,8 @@ fn flush(&mut self) -> io::Result<()> { } impl Stderr { - pub fn new() -> io::Result { - Ok(Stderr(())) + pub const fn new() -> Stderr { + Stderr(()) } } @@ -84,5 +84,5 @@ pub fn is_ebadf(err: &io::Error) -> bool { pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE; pub fn panic_output() -> Option { - Stderr::new().ok() + Some(Stderr::new()) } diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index c1bda6b430e..04da9812ddc 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -213,7 +213,7 @@ fn drop(&mut self) { } #[cfg(all( - not(all(target_os = "linux", not(target_env = "musl"))), + not(target_os = "linux"), not(target_os = "freebsd"), not(target_os = "macos"), not(all(target_os = "netbsd", not(target_vendor = "rumprun"))), @@ -233,7 +233,7 @@ pub unsafe fn init() -> Option { } #[cfg(any( - all(target_os = "linux", not(target_env = "musl")), + target_os = "linux", target_os = "freebsd", target_os = "macos", all(target_os = "netbsd", not(target_vendor = "rumprun")), @@ -333,9 +333,7 @@ pub unsafe fn init() -> Option { let page_size = os::page_size(); PAGE_SIZE.store(page_size, Ordering::Relaxed); - let stackaddr = get_stack_start_aligned()?; - - if cfg!(target_os = "linux") { + if cfg!(all(target_os = "linux", not(target_env = "musl"))) { // Linux doesn't allocate the whole stack right away, and // the kernel has its own stack-guard mechanism to fault // when growing too close to an existing mapping. If we map @@ -346,8 +344,15 @@ pub unsafe fn init() -> Option { // Instead, we'll just note where we expect rlimit to start // faulting, so our handler can report "stack overflow", and // trust that the kernel's own stack guard will work. + let stackaddr = get_stack_start_aligned()?; let stackaddr = stackaddr as usize; Some(stackaddr - page_size..stackaddr) + } else if cfg!(all(target_os = "linux", target_env = "musl")) { + // For the main thread, the musl's pthread_attr_getstack + // returns the current stack size, rather than maximum size + // it can eventually grow to. It cannot be used to determine + // the position of kernel's stack guard. + None } else { // Reallocate the last page of the stack. // This ensures SIGBUS will be raised on @@ -357,6 +362,7 @@ pub unsafe fn init() -> Option { // than the initial mmap() used, so we mmap() here with // read/write permissions and only then mprotect() it to // no permissions at all. See issue #50313. + let stackaddr = get_stack_start_aligned()?; let result = mmap( stackaddr, page_size, @@ -406,7 +412,14 @@ pub unsafe fn current() -> Option { let mut guardsize = 0; assert_eq!(libc::pthread_attr_getguardsize(&attr, &mut guardsize), 0); if guardsize == 0 { - panic!("there is no guard page"); + if cfg!(all(target_os = "linux", target_env = "musl")) { + // musl versions before 1.1.19 always reported guard + // size obtained from pthread_attr_get_np as zero. + // Use page size as a fallback. + guardsize = PAGE_SIZE.load(Ordering::Relaxed); + } else { + panic!("there is no guard page"); + } } let mut stackaddr = crate::ptr::null_mut(); let mut size = 0; @@ -419,6 +432,8 @@ pub unsafe fn current() -> Option { Some(guardaddr - PAGE_SIZE.load(Ordering::Relaxed)..guardaddr) } else if cfg!(target_os = "netbsd") { Some(stackaddr - guardsize..stackaddr) + } else if cfg!(all(target_os = "linux", target_env = "musl")) { + Some(stackaddr - guardsize..stackaddr) } else if cfg!(all(target_os = "linux", target_env = "gnu")) { // glibc used to include the guard area within the stack, as noted in the BUGS // section of `man pthread_attr_getguardsize`. This has been corrected starting diff --git a/library/std/src/sys/unsupported/stdio.rs b/library/std/src/sys/unsupported/stdio.rs index 5a4e4505e93..b5e3f5be988 100644 --- a/library/std/src/sys/unsupported/stdio.rs +++ b/library/std/src/sys/unsupported/stdio.rs @@ -5,8 +5,8 @@ pub struct Stderr; impl Stdin { - pub fn new() -> io::Result { - Ok(Stdin) + pub const fn new() -> Stdin { + Stdin } } @@ -17,8 +17,8 @@ fn read(&mut self, _buf: &mut [u8]) -> io::Result { } impl Stdout { - pub fn new() -> io::Result { - Ok(Stdout) + pub const fn new() -> Stdout { + Stdout } } @@ -33,8 +33,8 @@ fn flush(&mut self) -> io::Result<()> { } impl Stderr { - pub fn new() -> io::Result { - Ok(Stderr) + pub const fn new() -> Stderr { + Stderr } } diff --git a/library/std/src/sys/vxworks/fd.rs b/library/std/src/sys/vxworks/fd.rs index ea186846929..d58468ad539 100644 --- a/library/std/src/sys/vxworks/fd.rs +++ b/library/std/src/sys/vxworks/fd.rs @@ -53,7 +53,7 @@ pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { } #[inline] - fn is_read_vectored(&self) -> bool { + pub fn is_read_vectored(&self) -> bool { true } diff --git a/library/std/src/sys/vxworks/process/process_common.rs b/library/std/src/sys/vxworks/process/process_common.rs index bbbd5eda773..6473a0c3cec 100644 --- a/library/std/src/sys/vxworks/process/process_common.rs +++ b/library/std/src/sys/vxworks/process/process_common.rs @@ -351,8 +351,7 @@ pub fn new(status: c_int) -> ExitStatus { } fn exited(&self) -> bool { - /*unsafe*/ - { libc::WIFEXITED(self.0) } + libc::WIFEXITED(self.0) } pub fn success(&self) -> bool { @@ -360,19 +359,11 @@ pub fn success(&self) -> bool { } pub fn code(&self) -> Option { - if self.exited() { - Some(/*unsafe*/ { libc::WEXITSTATUS(self.0) }) - } else { - None - } + if self.exited() { Some(libc::WEXITSTATUS(self.0)) } else { None } } pub fn signal(&self) -> Option { - if !self.exited() { - Some(/*unsafe*/ { libc::WTERMSIG(self.0) }) - } else { - None - } + if !self.exited() { Some(libc::WTERMSIG(self.0)) } else { None } } } diff --git a/library/std/src/sys/vxworks/stdio.rs b/library/std/src/sys/vxworks/stdio.rs index 622444ccafd..92e9f205b4e 100644 --- a/library/std/src/sys/vxworks/stdio.rs +++ b/library/std/src/sys/vxworks/stdio.rs @@ -6,8 +6,8 @@ pub struct Stderr(()); impl Stdin { - pub fn new() -> io::Result { - Ok(Stdin(())) + pub const fn new() -> Stdin { + Stdin(()) } } @@ -21,8 +21,8 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result { } impl Stdout { - pub fn new() -> io::Result { - Ok(Stdout(())) + pub const fn new() -> Stdout { + Stdout(()) } } @@ -40,8 +40,8 @@ fn flush(&mut self) -> io::Result<()> { } impl Stderr { - pub fn new() -> io::Result { - Ok(Stderr(())) + pub const fn new() -> Stderr { + Stderr(()) } } @@ -65,5 +65,5 @@ pub fn is_ebadf(err: &io::Error) -> bool { pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE; pub fn panic_output() -> Option { - Stderr::new().ok() + Some(Stderr::new()) } diff --git a/library/std/src/sys/vxworks/thread_local_dtor.rs b/library/std/src/sys/vxworks/thread_local_dtor.rs index 3f73f6c4903..5391ed83ebc 100644 --- a/library/std/src/sys/vxworks/thread_local_dtor.rs +++ b/library/std/src/sys/vxworks/thread_local_dtor.rs @@ -2,6 +2,6 @@ #![unstable(feature = "thread_local_internals", issue = "none")] pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { - use crate::sys_common::thread_local::register_dtor_fallback; + use crate::sys_common::thread_local_dtor::register_dtor_fallback; register_dtor_fallback(t, dtor); } diff --git a/library/std/src/sys/wasi/stdio.rs b/library/std/src/sys/wasi/stdio.rs index 78e3911dc4e..23baafabf79 100644 --- a/library/std/src/sys/wasi/stdio.rs +++ b/library/std/src/sys/wasi/stdio.rs @@ -7,8 +7,8 @@ pub struct Stderr; impl Stdin { - pub fn new() -> io::Result { - Ok(Stdin) + pub const fn new() -> Stdin { + Stdin } #[inline] @@ -33,8 +33,8 @@ fn is_read_vectored(&self) -> bool { } impl Stdout { - pub fn new() -> io::Result { - Ok(Stdout) + pub const fn new() -> Stdout { + Stdout } #[inline] @@ -62,8 +62,8 @@ fn flush(&mut self) -> io::Result<()> { } impl Stderr { - pub fn new() -> io::Result { - Ok(Stderr) + pub const fn new() -> Stderr { + Stderr } #[inline] @@ -98,5 +98,5 @@ pub fn is_ebadf(err: &io::Error) -> bool { } pub fn panic_output() -> Option { - Stderr::new().ok() + Some(Stderr::new()) } diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs index 982ec912c44..a0d5a7471d8 100644 --- a/library/std/src/sys/windows/mod.rs +++ b/library/std/src/sys/windows/mod.rs @@ -300,14 +300,10 @@ pub fn dur2timeout(dur: Duration) -> c::DWORD { .unwrap_or(c::INFINITE) } -// On Windows, use the processor-specific __fastfail mechanism. In Windows 8 -// and later, this will terminate the process immediately without running any -// in-process exception handlers. In earlier versions of Windows, this -// sequence of instructions will be treated as an access violation, -// terminating the process but without necessarily bypassing all exception -// handlers. -// -// https://docs.microsoft.com/en-us/cpp/intrinsics/fastfail +/// Use `__fastfail` to abort the process +/// +/// This is the same implementation as in libpanic_abort's `__rust_start_panic`. See +/// that function for more information on `__fastfail` #[allow(unreachable_code)] pub fn abort_internal() -> ! { #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] diff --git a/library/std/src/sys/windows/stdio.rs b/library/std/src/sys/windows/stdio.rs index c84896296ec..ff214497166 100644 --- a/library/std/src/sys/windows/stdio.rs +++ b/library/std/src/sys/windows/stdio.rs @@ -131,8 +131,8 @@ fn write_u16s(handle: c::HANDLE, data: &[u16]) -> io::Result { } impl Stdin { - pub fn new() -> io::Result { - Ok(Stdin { surrogate: 0 }) + pub const fn new() -> Stdin { + Stdin { surrogate: 0 } } } @@ -255,8 +255,8 @@ fn utf16_to_utf8(utf16: &[u16], utf8: &mut [u8]) -> io::Result { } impl Stdout { - pub fn new() -> io::Result { - Ok(Stdout) + pub const fn new() -> Stdout { + Stdout } } @@ -271,8 +271,8 @@ fn flush(&mut self) -> io::Result<()> { } impl Stderr { - pub fn new() -> io::Result { - Ok(Stderr) + pub const fn new() -> Stderr { + Stderr } } @@ -291,5 +291,5 @@ pub fn is_ebadf(err: &io::Error) -> bool { } pub fn panic_output() -> Option { - Stderr::new().ok() + Some(Stderr::new()) } diff --git a/library/std/src/sys/windows/stdio_uwp.rs b/library/std/src/sys/windows/stdio_uwp.rs index 5bdabf6d4b7..872511af862 100644 --- a/library/std/src/sys/windows/stdio_uwp.rs +++ b/library/std/src/sys/windows/stdio_uwp.rs @@ -30,8 +30,8 @@ fn write(handle_id: c::DWORD, data: &[u8]) -> io::Result { } impl Stdin { - pub fn new() -> io::Result { - Ok(Stdin {}) + pub const fn new() -> Stdin { + Stdin {} } } @@ -44,8 +44,8 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result { } impl Stdout { - pub fn new() -> io::Result { - Ok(Stdout) + pub const fn new() -> Stdout { + Stdout } } @@ -60,8 +60,8 @@ fn flush(&mut self) -> io::Result<()> { } impl Stderr { - pub fn new() -> io::Result { - Ok(Stderr) + pub const fn new() -> Stderr { + Stderr } } @@ -80,5 +80,5 @@ pub fn is_ebadf(err: &io::Error) -> bool { } pub fn panic_output() -> Option { - Stderr::new().ok() + Some(Stderr::new()) } diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index 81a5ef95e82..0bb136078bc 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -585,8 +585,8 @@ pub fn multicast_loop_v6(&self) -> io::Result { pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { let mreq = c::ip_mreq { - imr_multiaddr: *multiaddr.as_inner(), - imr_interface: *interface.as_inner(), + imr_multiaddr: multiaddr.into_inner(), + imr_interface: interface.into_inner(), }; setsockopt(&self.inner, c::IPPROTO_IP, c::IP_ADD_MEMBERSHIP, mreq) } @@ -601,8 +601,8 @@ pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Res pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { let mreq = c::ip_mreq { - imr_multiaddr: *multiaddr.as_inner(), - imr_interface: *interface.as_inner(), + imr_multiaddr: multiaddr.into_inner(), + imr_interface: interface.into_inner(), }; setsockopt(&self.inner, c::IPPROTO_IP, c::IP_DROP_MEMBERSHIP, mreq) } diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 66508f06b28..a4562967f0b 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -71,9 +71,7 @@ /// not guard typically have a synthetic limit after which point no more /// destructors are run. /// -/// [`with`]: ../../std/thread/struct.LocalKey.html#method.with -/// [`thread_local!`]: ../../std/macro.thread_local.html -/// [`Drop`]: ../../std/ops/trait.Drop.html +/// [`with`]: LocalKey::with #[stable(feature = "rust1", since = "1.0.0")] pub struct LocalKey { // This outer `LocalKey` type is what's going to be stored in statics, @@ -118,10 +116,10 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// # fn main() {} /// ``` /// -/// See [LocalKey documentation][`std::thread::LocalKey`] for more +/// See [`LocalKey` documentation][`std::thread::LocalKey`] for more /// information. /// -/// [`std::thread::LocalKey`]: ../std/thread/struct.LocalKey.html +/// [`std::thread::LocalKey`]: crate::thread::LocalKey #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] #[allow_internal_unstable(thread_local_internals)] diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 202867258f1..0b9849517c2 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -129,30 +129,19 @@ //! //! Note that the stack size of the main thread is *not* determined by Rust. //! -//! [channels]: ../../std/sync/mpsc/index.html -//! [`Arc`]: ../../std/sync/struct.Arc.html -//! [`spawn`]: ../../std/thread/fn.spawn.html -//! [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html -//! [`JoinHandle::thread`]: ../../std/thread/struct.JoinHandle.html#method.thread -//! [`join`]: ../../std/thread/struct.JoinHandle.html#method.join -//! [`Result`]: ../../std/result/enum.Result.html -//! [`Ok`]: ../../std/result/enum.Result.html#variant.Ok -//! [`Err`]: ../../std/result/enum.Result.html#variant.Err -//! [`panic!`]: ../../std/macro.panic.html -//! [`Builder`]: ../../std/thread/struct.Builder.html -//! [`Builder::stack_size`]: ../../std/thread/struct.Builder.html#method.stack_size -//! [`Builder::name`]: ../../std/thread/struct.Builder.html#method.name -//! [`thread::current`]: ../../std/thread/fn.current.html -//! [`thread::Result`]: ../../std/thread/type.Result.html -//! [`Thread`]: ../../std/thread/struct.Thread.html -//! [`park`]: ../../std/thread/fn.park.html -//! [`unpark`]: ../../std/thread/struct.Thread.html#method.unpark -//! [`Thread::name`]: ../../std/thread/struct.Thread.html#method.name -//! [`thread::park_timeout`]: ../../std/thread/fn.park_timeout.html -//! [`Cell`]: ../cell/struct.Cell.html -//! [`RefCell`]: ../cell/struct.RefCell.html -//! [`thread_local!`]: ../macro.thread_local.html -//! [`with`]: struct.LocalKey.html#method.with +//! [channels]: crate::sync::mpsc +//! [`join`]: JoinHandle::join +//! [`Result`]: crate::result::Result +//! [`Ok`]: crate::result::Result::Ok +//! [`Err`]: crate::result::Result::Err +//! [`thread::current`]: current +//! [`thread::Result`]: Result +//! [`unpark`]: Thread::unpark +//! [`Thread::name`]: Thread::name +//! [`thread::park_timeout`]: park_timeout +//! [`Cell`]: crate::cell::Cell +//! [`RefCell`]: crate::cell::RefCell +//! [`with`]: LocalKey::with #![stable(feature = "rust1", since = "1.0.0")] @@ -245,12 +234,12 @@ /// handler.join().unwrap(); /// ``` /// -/// [`thread::spawn`]: ../../std/thread/fn.spawn.html -/// [`stack_size`]: ../../std/thread/struct.Builder.html#method.stack_size -/// [`name`]: ../../std/thread/struct.Builder.html#method.name -/// [`spawn`]: ../../std/thread/struct.Builder.html#method.spawn -/// [`io::Result`]: ../../std/io/type.Result.html -/// [`unwrap`]: ../../std/result/enum.Result.html#method.unwrap +/// [`stack_size`]: Builder::stack_size +/// [`name`]: Builder::name +/// [`spawn`]: Builder::spawn +/// [`thread::spawn`]: spawn +/// [`io::Result`]: crate::io::Result +/// [`unwrap`]: crate::result::Result::unwrap /// [naming-threads]: ./index.html#naming-threads /// [stack-size]: ./index.html#stack-size #[stable(feature = "rust1", since = "1.0.0")] @@ -355,9 +344,7 @@ pub fn stack_size(mut self, size: usize) -> Builder { /// [`io::Result`] to capture any failure to create the thread at /// the OS level. /// - /// [`spawn`]: ../../std/thread/fn.spawn.html - /// [`io::Result`]: ../../std/io/type.Result.html - /// [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html + /// [`io::Result`]: crate::io::Result /// /// # Panics /// @@ -443,11 +430,7 @@ pub fn spawn(self, f: F) -> io::Result> /// handler.join().unwrap(); /// ``` /// - /// [`spawn`]: ../../std/thread/fn.spawn.html - /// [`Builder::spawn`]: ../../std/thread/struct.Builder.html#method.spawn - /// [`io::Result`]: ../../std/io/type.Result.html - /// [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html - /// [`JoinHandle::join`]: ../../std/thread/struct.JoinHandle.html#method.join + /// [`io::Result`]: crate::io::Result #[unstable(feature = "thread_spawn_unchecked", issue = "55132")] pub unsafe fn spawn_unchecked<'a, F, T>(self, f: F) -> io::Result> where @@ -513,7 +496,7 @@ pub unsafe fn spawn_unchecked<'a, F, T>(self, f: F) -> io::Result> /// the main thread finishes). Additionally, the join handle provides a [`join`] /// method that can be used to join the child thread. If the child thread /// panics, [`join`] will return an [`Err`] containing the argument given to -/// [`panic`]. +/// [`panic!`]. /// /// This will create a thread using default parameters of [`Builder`], if you /// want to specify the stack size or the name of the thread, use this API @@ -600,15 +583,9 @@ pub unsafe fn spawn_unchecked<'a, F, T>(self, f: F) -> io::Result> /// println!("{}", result); /// ``` /// -/// [`channels`]: ../../std/sync/mpsc/index.html -/// [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html -/// [`join`]: ../../std/thread/struct.JoinHandle.html#method.join -/// [`Err`]: ../../std/result/enum.Result.html#variant.Err -/// [`panic`]: ../../std/macro.panic.html -/// [`Builder::spawn`]: ../../std/thread/struct.Builder.html#method.spawn -/// [`Builder`]: ../../std/thread/struct.Builder.html -/// [`Send`]: ../../std/marker/trait.Send.html -/// [`Sync`]: ../../std/marker/trait.Sync.html +/// [`channels`]: crate::sync::mpsc +/// [`join`]: JoinHandle::join +/// [`Err`]: crate::result::Result::Err #[stable(feature = "rust1", since = "1.0.0")] pub fn spawn(f: F) -> JoinHandle where @@ -673,11 +650,8 @@ pub fn current() -> Thread { /// thread::yield_now(); /// ``` /// -/// [`channel`]: ../../std/sync/mpsc/index.html -/// [`spawn`]: ../../std/thread/fn.spawn.html -/// [`join`]: ../../std/thread/struct.JoinHandle.html#method.join -/// [`Mutex`]: ../../std/sync/struct.Mutex.html -/// [`Condvar`]: ../../std/sync/struct.Condvar.html +/// [`channel`]: crate::sync::mpsc +/// [`join`]: JoinHandle::join #[stable(feature = "rust1", since = "1.0.0")] pub fn yield_now() { imp::Thread::yield_now() @@ -723,8 +697,6 @@ pub fn yield_now() { /// panic!() /// } /// ``` -/// -/// [Mutex]: ../../std/sync/struct.Mutex.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn panicking() -> bool { @@ -881,10 +853,8 @@ pub fn sleep(dur: Duration) { /// parked_thread.join().unwrap(); /// ``` /// -/// [`Thread`]: ../../std/thread/struct.Thread.html -/// [`park`]: ../../std/thread/fn.park.html -/// [`unpark`]: ../../std/thread/struct.Thread.html#method.unpark -/// [`thread::park_timeout`]: ../../std/thread/fn.park_timeout.html +/// [`unpark`]: Thread::unpark +/// [`thread::park_timeout`]: park_timeout // // The implementation currently uses the trivial strategy of a Mutex+Condvar // with wakeup flag, which does not actually allow spurious wakeups. In the @@ -939,9 +909,6 @@ pub fn park() { /// amount of time waited to be precisely `ms` long. /// /// See the [park documentation][`park`] for more detail. -/// -/// [`park_timeout`]: fn.park_timeout.html -/// [`park`]: ../../std/thread/fn.park.html #[stable(feature = "rust1", since = "1.0.0")] #[rustc_deprecated(since = "1.6.0", reason = "replaced by `std::thread::park_timeout`")] pub fn park_timeout_ms(ms: u32) { @@ -986,8 +953,6 @@ pub fn park_timeout_ms(ms: u32) { /// timeout_remaining = timeout - elapsed; /// } /// ``` -/// -/// [park]: fn.park.html #[stable(feature = "park_timeout", since = "1.4.0")] pub fn park_timeout(dur: Duration) { let thread = current(); @@ -1046,8 +1011,7 @@ pub fn park_timeout(dur: Duration) { /// assert!(thread::current().id() != other_thread_id); /// ``` /// -/// [`id`]: ../../std/thread/struct.Thread.html#method.id -/// [`Thread`]: ../../std/thread/struct.Thread.html +/// [`id`]: Thread::id #[stable(feature = "thread_id", since = "1.19.0")] #[derive(Eq, PartialEq, Clone, Copy, Hash, Debug)] pub struct ThreadId(NonZeroU64); @@ -1124,12 +1088,7 @@ struct Inner { /// should instead use a function like `spawn` to create new threads, see the /// docs of [`Builder`] and [`spawn`] for more details. /// -/// [`Builder`]: ../../std/thread/struct.Builder.html -/// [`JoinHandle::thread`]: ../../std/thread/struct.JoinHandle.html#method.thread -/// [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html -/// [`thread::current`]: ../../std/thread/fn.current.html -/// [`spawn`]: ../../std/thread/fn.spawn.html - +/// [`thread::current`]: current pub struct Thread { inner: Arc, } @@ -1181,8 +1140,6 @@ pub(crate) fn new(name: Option) -> Thread { /// /// parked_thread.join().unwrap(); /// ``` - /// - /// [park]: fn.park.html #[stable(feature = "rust1", since = "1.0.0")] pub fn unpark(&self) { // To ensure the unparked thread will observe any writes we made @@ -1326,7 +1283,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// } /// ``` /// -/// [`Result`]: ../../std/result/enum.Result.html +/// [`Result`]: crate::result::Result #[stable(feature = "rust1", since = "1.0.0")] pub type Result = crate::result::Result>; @@ -1421,9 +1378,8 @@ fn join(&mut self) -> Result { /// thread::sleep(Duration::from_millis(1000)); /// ``` /// -/// [`Clone`]: ../../std/clone/trait.Clone.html -/// [`thread::spawn`]: fn.spawn.html -/// [`thread::Builder::spawn`]: struct.Builder.html#method.spawn +/// [`thread::Builder::spawn`]: Builder::spawn +/// [`thread::spawn`]: spawn #[stable(feature = "rust1", since = "1.0.0")] pub struct JoinHandle(JoinInner); @@ -1462,11 +1418,10 @@ pub fn thread(&self) -> &Thread { /// operations that happen after `join` returns. /// /// If the child thread panics, [`Err`] is returned with the parameter given - /// to [`panic`]. + /// to [`panic!`]. /// - /// [`Err`]: ../../std/result/enum.Result.html#variant.Err - /// [`panic`]: ../../std/macro.panic.html - /// [atomic memory orderings]: ../../std/sync/atomic/index.html + /// [`Err`]: crate::result::Result::Err + /// [atomic memory orderings]: crate::sync::atomic /// /// # Panics /// diff --git a/library/std/src/time.rs b/library/std/src/time.rs index 02161ecb4c8..c8aee1da39b 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -159,7 +159,7 @@ /// | DARWIN | [gettimeofday] | /// | VXWorks | [clock_gettime (Realtime Clock)] | /// | WASI | [__wasi_clock_time_get (Realtime Clock)] | -/// | Windows | [GetSystemTimeAsFileTime] | +/// | Windows | [GetSystemTimePreciseAsFileTime] / [GetSystemTimeAsFileTime] | /// /// [clock_time_get (Realtime Clock)]: https://nuxi.nl/cloudabi/#clock_time_get /// [`insecure_time` usercall]: https://edp.fortanix.com/docs/api/fortanix_sgx_abi/struct.Usercalls.html#method.insecure_time @@ -167,6 +167,7 @@ /// [gettimeofday]: http://man7.org/linux/man-pages/man2/gettimeofday.2.html /// [clock_gettime (Realtime Clock)]: https://linux.die.net/man/3/clock_gettime /// [__wasi_clock_time_get (Realtime Clock)]: https://github.com/WebAssembly/WASI/blob/master/phases/snapshot/docs.md#clock_time_get +/// [GetSystemTimePreciseAsFileTime]: https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime /// [GetSystemTimeAsFileTime]: https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimeasfiletime /// /// **Disclaimer:** These system calls might change over time. diff --git a/library/test/src/stats.rs b/library/test/src/stats.rs index 077005371c0..c02f93bf9d4 100644 --- a/library/test/src/stats.rs +++ b/library/test/src/stats.rs @@ -84,7 +84,7 @@ pub trait Stats { /// by the constant `1.4826` to allow its use as a consistent estimator for the standard /// deviation. /// - /// See: + /// See: fn median_abs_dev(&self) -> f64; /// Median absolute deviation as a percent of the median. See `median_abs_dev` and `median`. @@ -96,7 +96,7 @@ pub trait Stats { /// /// Calculated by linear interpolation between closest ranks. /// - /// See: + /// See: fn percentile(&self, pct: f64) -> f64; /// Quartiles of the sample: three values that divide the sample into four equal groups, each @@ -302,7 +302,7 @@ fn percentile_of_sorted(sorted_samples: &[f64], pct: f64) -> f64 { /// It differs from trimming in that it does not change the number of samples, /// just changes the values of those that are outliers. /// -/// See: +/// See: pub fn winsorize(samples: &mut [f64], pct: f64) { let mut tmp = samples.to_vec(); local_sort(&mut tmp); diff --git a/src/bootstrap/cc_detect.rs b/src/bootstrap/cc_detect.rs index 7ff00d85dd2..d50e4cf5269 100644 --- a/src/bootstrap/cc_detect.rs +++ b/src/bootstrap/cc_detect.rs @@ -132,7 +132,8 @@ pub fn find(build: &mut Build) { false }; - if cxx_configured { + // for VxWorks, record CXX compiler which will be used in lib.rs:linker() + if cxx_configured || target.contains("vxworks") { let compiler = cfg.get_compiler(); build.cxx.insert(target, compiler); } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 70b1c471ac3..8b8b01b1153 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -527,7 +527,7 @@ pub fn parse(args: &[String]) -> Config { let build = toml.build.clone().unwrap_or_default(); // set by bootstrap.py - config.hosts.push(config.build.clone()); + config.hosts.push(config.build); for host in build.host.iter().map(|h| TargetSelection::from_user(h)) { if !config.hosts.contains(&host) { config.hosts.push(host); diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 01121977f13..f0b2254be9e 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -226,7 +226,7 @@ fn make_win_dist( let idx = line.find(':').unwrap(); let key = &line[..idx]; let trim_chars: &[_] = &[' ', '=']; - let value = line[(idx + 1)..].trim_start_matches(trim_chars).split(';').map(PathBuf::from); + let value = env::split_paths(line[(idx + 1)..].trim_start_matches(trim_chars)); if key == "programs" { bin_path.extend(value); diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index a1b5ca2ea2f..2a8f43950db 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -96,7 +96,7 @@ fn is_explicit_request(builder: &Builder<'_>, path: &str) -> bool { .paths .iter() .map(components_simplified) - .any(|requested| requested.iter().copied().eq(path.split("/"))) + .any(|requested| requested.iter().copied().eq(path.split('/'))) } #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 56e4f0467cc..38b3a32e3b5 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -505,14 +505,11 @@ pub fn parse(args: &[String]) -> Flags { if let Subcommand::Check { .. } = &cmd { if matches.opt_str("stage").is_some() { - println!("{}", "--stage not supported for x.py check, always treated as stage 0"); + println!("--stage not supported for x.py check, always treated as stage 0"); process::exit(1); } if matches.opt_str("keep-stage").is_some() { - println!( - "{}", - "--keep-stage not supported for x.py check, only one stage available" - ); + println!("--keep-stage not supported for x.py check, only one stage available"); process::exit(1); } } diff --git a/src/bootstrap/format.rs b/src/bootstrap/format.rs index 390b7e96b9a..6f93082e675 100644 --- a/src/bootstrap/format.rs +++ b/src/bootstrap/format.rs @@ -87,7 +87,7 @@ pub fn format(build: &Build, check: bool) { .lines() .filter(|entry| entry.starts_with("??")) .map(|entry| { - entry.split(" ").nth(1).expect("every git status entry should list a path") + entry.split(' ').nth(1).expect("every git status entry should list a path") }); for untracked_path in untracked_paths { eprintln!("skip untracked path {} during rustfmt invocations", untracked_path); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 77820ef87e3..191cc5b0b64 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -323,10 +323,7 @@ pub enum Mode { impl Mode { pub fn is_tool(&self) -> bool { - match self { - Mode::ToolBootstrap | Mode::ToolRustc | Mode::ToolStd => true, - _ => false, - } + matches!(self, Mode::ToolBootstrap | Mode::ToolRustc | Mode::ToolStd) } } @@ -857,6 +854,10 @@ fn linker(&self, target: TargetSelection, can_use_lld: bool) -> Option<&Path> { if let Some(linker) = self.config.target_config.get(&target).and_then(|c| c.linker.as_ref()) { Some(linker) + } else if target.contains("vxworks") { + // need to use CXX compiler as linker to resolve the exception functions + // that are only existed in CXX libraries + Some(self.cxx[&target].path()) } else if target != self.config.build && util::use_host_linker(target) && !target.contains("msvc") diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index eca9ddceae1..97d9dbdd63f 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -767,7 +767,7 @@ fn supported_sanitizers( ) -> Vec { let darwin_libs = |os: &str, components: &[&str]| -> Vec { components - .into_iter() + .iter() .map(move |c| SanitizerRuntime { cmake_target: format!("clang_rt.{}_{}_dynamic", c, os), path: out_dir @@ -779,7 +779,7 @@ fn supported_sanitizers( let common_libs = |os: &str, arch: &str, components: &[&str]| -> Vec { components - .into_iter() + .iter() .map(move |c| SanitizerRuntime { cmake_target: format!("clang_rt.{}-{}", c, arch), path: out_dir.join(&format!("build/lib/{}/libclang_rt.{}-{}.a", os, c, arch)), diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index ac833a55d4c..afa72b5d58c 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1754,6 +1754,11 @@ fn run(self, builder: &Builder<'_>) { cargo.arg("--quiet"); } + if builder.config.cmd.bless() { + // Bless `expect!` tests. + cargo.env("UPDATE_EXPECT", "1"); + } + if target.contains("emscripten") { cargo.env( format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)), diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh index 2c00a628a1d..969443ac094 100755 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh @@ -4,7 +4,7 @@ set -ex source shared.sh -LLVM=llvmorg-9.0.0 +LLVM=llvmorg-10.0.0 mkdir llvm-project cd llvm-project @@ -18,17 +18,7 @@ cd clang-build # For whatever reason the default set of include paths for clang is different # than that of gcc. As a result we need to manually include our sysroot's # include path, /rustroot/include, to clang's default include path. -# -# Alsow there's this weird oddity with gcc where there's an 'include-fixed' -# directory that it generates. It turns out [1] that Centos 5's headers are so -# old that they're incompatible with modern C semantics. While gcc automatically -# fixes that clang doesn't account for this. Tell clang to manually include the -# fixed headers so we can successfully compile code later on. -# -# [1]: https://sourceware.org/ml/crossgcc/2008-11/msg00028.html -INC="/rustroot/include" -INC="$INC:/rustroot/lib/gcc/x86_64-unknown-linux-gnu/5.5.0/include-fixed" -INC="$INC:/usr/include" +INC="/rustroot/include:/usr/include" hide_output \ cmake ../llvm \ diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-full-bootstrap/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-full-bootstrap/Dockerfile deleted file mode 100644 index 8648e5ed7a4..00000000000 --- a/src/ci/docker/host-x86_64/x86_64-gnu-full-bootstrap/Dockerfile +++ /dev/null @@ -1,30 +0,0 @@ -FROM ubuntu:16.04 - -RUN apt-get update && apt-get install -y --no-install-recommends \ - g++ \ - make \ - file \ - curl \ - ca-certificates \ - python3 \ - git \ - cmake \ - sudo \ - gdb \ - libssl-dev \ - pkg-config \ - xz-utils - -COPY scripts/sccache.sh /scripts/ -RUN sh /scripts/sccache.sh - -ENV RUST_CONFIGURE_ARGS \ - --build=x86_64-unknown-linux-gnu \ - --enable-full-bootstrap -ENV SCRIPT python3 ../x.py --stage 2 build - -# In general this just slows down the build and we're just a smoke test that -# a full bootstrap works in general, so there's not much need to take this -# penalty in build times. -ENV NO_LLVM_ASSERTIONS 1 -ENV NO_DEBUG_ASSERTIONS 1 diff --git a/src/ci/docker/scripts/emscripten.sh b/src/ci/docker/scripts/emscripten.sh index 9f6a7f2e5db..9481ee95399 100644 --- a/src/ci/docker/scripts/emscripten.sh +++ b/src/ci/docker/scripts/emscripten.sh @@ -19,5 +19,5 @@ exit 1 git clone https://github.com/emscripten-core/emsdk.git /emsdk-portable cd /emsdk-portable -hide_output ./emsdk install 1.38.47-upstream -./emsdk activate 1.38.47-upstream +hide_output ./emsdk install 1.39.20 +./emsdk activate 1.39.20 diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 165ecc79180..db2def483ac 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -419,9 +419,6 @@ jobs: - name: x86_64-gnu-distcheck <<: *job-linux-xl - - name: x86_64-gnu-full-bootstrap - <<: *job-linux-xl - - name: x86_64-gnu-llvm-8 env: RUST_BACKTRACE: 1 diff --git a/src/ci/scripts/install-clang.sh b/src/ci/scripts/install-clang.sh index c242f5d4562..a1481f22f50 100755 --- a/src/ci/scripts/install-clang.sh +++ b/src/ci/scripts/install-clang.sh @@ -8,11 +8,14 @@ IFS=$'\n\t' source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" +# Update both macOS's and Windows's tarballs when bumping the version here. +LLVM_VERSION="10.0.0" + if isMacOS; then - curl -f "${MIRRORS_BASE}/clang%2Bllvm-9.0.0-x86_64-darwin-apple.tar.xz" | tar xJf - + curl -f "${MIRRORS_BASE}/clang%2Bllvm-${LLVM_VERSION}-x86_64-apple-darwin.tar.xz" | tar xJf - - ciCommandSetEnv CC "$(pwd)/clang+llvm-9.0.0-x86_64-darwin-apple/bin/clang" - ciCommandSetEnv CXX "$(pwd)/clang+llvm-9.0.0-x86_64-darwin-apple/bin/clang++" + ciCommandSetEnv CC "$(pwd)/clang+llvm-${LLVM_VERSION}-x86_64-apple-darwin/bin/clang" + ciCommandSetEnv CXX "$(pwd)/clang+llvm-${LLVM_VERSION}-x86_64-apple-darwin/bin/clang++" # macOS 10.15 onwards doesn't have libraries in /usr/include anymore: those # are now located deep into the filesystem, under Xcode's own files. The @@ -33,8 +36,10 @@ elif isWindows && [[ ${CUSTOM_MINGW-0} -ne 1 ]]; then # # Note that the LLVM installer is an NSIS installer # - # Original downloaded here came from - # http://releases.llvm.org/9.0.0/LLVM-9.0.0-win64.exe + # Original downloaded here came from: + # + # https://github.com/llvm/llvm-project/releases/download/llvmorg-10.0.0/LLVM-10.0.0-win64.exe + # # That installer was run through `wine ./installer.exe /S /NCRC` on Linux # and then the resulting installation directory (found in # `$HOME/.wine/drive_c/Program Files/LLVM`) was packaged up into a tarball. @@ -45,7 +50,7 @@ elif isWindows && [[ ${CUSTOM_MINGW-0} -ne 1 ]]; then mkdir -p citools cd citools - curl -f "${MIRRORS_BASE}/LLVM-9.0.0-win64.tar.gz" | tar xzf - + curl -f "${MIRRORS_BASE}/LLVM-${LLVM_VERSION}-win64.tar.gz" | tar xzf - ciCommandSetEnv RUST_CONFIGURE_ARGS \ "${RUST_CONFIGURE_ARGS} --set llvm.clang-cl=$(pwd)/clang-rust/bin/clang-cl.exe" fi diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index d16c2a9d034..2f49fc8a415 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -81,7 +81,7 @@ impl AsyncReceiver { } ``` -Paths in Rust have three namespaces: type, value, and macro. Items from these namespaces are allowed to overlap. In case of ambiguity, rustdoc will warn about the ambiguity and ask you to disambiguate, which can be done by using a prefix like `struct@`, `enum@`, `type@`, `trait@`, `union@`, `const@`, `static@`, `value@`, `function@`, `mod@`, `fn@`, `module@`, `method@` , `macro@`, or `derive@`: +Paths in Rust have three namespaces: type, value, and macro. Items from these namespaces are allowed to overlap. In case of ambiguity, rustdoc will warn about the ambiguity and ask you to disambiguate, which can be done by using a prefix like `struct@`, `enum@`, `type@`, `trait@`, `union@`, `const@`, `static@`, `value@`, `function@`, `mod@`, `fn@`, `module@`, `method@`, `prim@`, `primitive@`, `macro@`, or `derive@`: ```rust /// See also: [`Foo`](struct@Foo) @@ -467,3 +467,36 @@ $ rustdoc src/lib.rs -Z unstable-options --runtool valgrind ``` Another use case would be to run a test inside an emulator, or through a Virtual Machine. + +### `--show-coverage`: get statistics about code documentation coverage + +This option allows you to get a nice overview over your code documentation coverage, including both +doc-comments and code examples in the doc-comments. Example: + +```bash +$ rustdoc src/lib.rs -Z unstable-options --show-coverage ++-------------------------------------+------------+------------+------------+------------+ +| File | Documented | Percentage | Examples | Percentage | ++-------------------------------------+------------+------------+------------+------------+ +| lib.rs | 4 | 100.0% | 1 | 25.0% | ++-------------------------------------+------------+------------+------------+------------+ +| Total | 4 | 100.0% | 1 | 25.0% | ++-------------------------------------+------------+------------+------------+------------+ +``` + +You can also use this option with the `--output-format` one: + +```bash +$ rustdoc src/lib.rs -Z unstable-options --show-coverage --output-format json +{"lib.rs":{"total":4,"with_docs":4,"total_examples":4,"with_examples":1}} +``` + +Calculating code examples follows these rules: + +1. These items aren't accounted by default: + * struct/union field + * enum variant + * constant + * static + * typedef +2. If one of the previously listed items has a code example, then it'll be counted. diff --git a/src/doc/unstable-book/src/compiler-flags/control-flow-guard.md b/src/doc/unstable-book/src/compiler-flags/control-flow-guard.md index 4115825e920..c43d91bf070 100644 --- a/src/doc/unstable-book/src/compiler-flags/control-flow-guard.md +++ b/src/doc/unstable-book/src/compiler-flags/control-flow-guard.md @@ -6,7 +6,7 @@ The tracking issue for this feature is: [#68793](https://github.com/rust-lang/ru The rustc flag `-Z control-flow-guard` enables the Windows [Control Flow Guard](https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard) (CFG) platform security feature. -CFG is an exploit mitigation designed to enforce control-flow integrity for software running on supported Windows platforms (Windows 8.1 onwards). Specifically, CFG uses runtime checks to validate the target address of every indirect call/jump before allowing the call to complete. +CFG is an exploit mitigation designed to enforce control-flow integrity for software running on supported [Windows platforms (Windows 8.1 onwards)](https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard). Specifically, CFG uses runtime checks to validate the target address of every indirect call/jump before allowing the call to complete. During compilation, the compiler identifies all indirect calls/jumps and adds CFG checks. It also emits metadata containing the relative addresses of all address-taken functions. At runtime, if the binary is run on a CFG-aware operating system, the loader uses the CFG metadata to generate a bitmap of the address space and marks those addresses that contain valid targets. On each indirect call, the inserted check determines whether the target address is marked in this bitmap. If the target is not valid, the process is terminated. @@ -19,8 +19,9 @@ CFG functionality is completely implemented in the LLVM backend and is supported ## When to use Control Flow Guard -The primary motivation for enabling CFG in Rust is to enhance security when linking against non-Rust code, especially C/C++ code. To achieve full CFG protection, all indirect calls (including any from Rust code) must have the appropriate CFG checks, as added by this flag. CFG can also improve security for Rust code that uses the `unsafe` keyword +The primary motivation for enabling CFG in Rust is to enhance security when linking against non-Rust code, especially C/C++ code. To achieve full CFG protection, all indirect calls (including any from Rust code) must have the appropriate CFG checks, as added by this flag. CFG can also improve security for Rust code that uses the `unsafe` keyword. +Another motivation behind CFG is to harden programs against [return-oriented programming (ROP)](https://en.wikipedia.org/wiki/Return-oriented_programming) attacks. CFG disallows an attacker from taking advantage of the program's own instructions while redirecting control flow in unexpected ways. ## Overhead of Control Flow Guard diff --git a/src/librustc_ast/ast.rs b/src/librustc_ast/ast.rs index 6dff02486ff..127a53cad2b 100644 --- a/src/librustc_ast/ast.rs +++ b/src/librustc_ast/ast.rs @@ -550,6 +550,7 @@ pub struct Pat { pub id: NodeId, pub kind: PatKind, pub span: Span, + pub tokens: Option, } impl Pat { @@ -1670,6 +1671,7 @@ pub struct MutTy { pub struct FnSig { pub header: FnHeader, pub decl: P, + pub span: Span, } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] @@ -2138,6 +2140,7 @@ pub fn from_self(attrs: AttrVec, eself: ExplicitSelf, eself_ident: Ident) -> Par id: DUMMY_NODE_ID, kind: PatKind::Ident(BindingMode::ByValue(mutbl), eself_ident, None), span, + tokens: None, }), span, ty, diff --git a/src/librustc_ast/mut_visit.rs b/src/librustc_ast/mut_visit.rs index df6e8218f6c..965571aaa54 100644 --- a/src/librustc_ast/mut_visit.rs +++ b/src/librustc_ast/mut_visit.rs @@ -363,9 +363,10 @@ pub fn visit_bounds(bounds: &mut GenericBounds, vis: &mut T) { } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_fn_sig(FnSig { header, decl }: &mut FnSig, vis: &mut T) { +pub fn visit_fn_sig(FnSig { header, decl, span }: &mut FnSig, vis: &mut T) { vis.visit_fn_header(header); vis.visit_fn_decl(decl); + vis.visit_span(span); } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. @@ -1053,7 +1054,7 @@ pub fn noop_flat_map_foreign_item( } pub fn noop_visit_pat(pat: &mut P, vis: &mut T) { - let Pat { id, kind, span } = pat.deref_mut(); + let Pat { id, kind, span, tokens: _ } = pat.deref_mut(); vis.visit_id(id); match kind { PatKind::Wild | PatKind::Rest => {} diff --git a/src/librustc_ast/token.rs b/src/librustc_ast/token.rs index 46c4be0a33b..4a8bf6b4f19 100644 --- a/src/librustc_ast/token.rs +++ b/src/librustc_ast/token.rs @@ -11,9 +11,11 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::Lrc; use rustc_macros::HashStable_Generic; +use rustc_span::hygiene::ExpnKind; +use rustc_span::source_map::SourceMap; use rustc_span::symbol::{kw, sym}; use rustc_span::symbol::{Ident, Symbol}; -use rustc_span::{self, Span, DUMMY_SP}; +use rustc_span::{self, FileName, RealFileName, Span, DUMMY_SP}; use std::borrow::Cow; use std::{fmt, mem}; @@ -808,6 +810,31 @@ pub fn pretty_printing_compatibility_hack(&self) -> bool { } false } + + // See issue #74616 for details + pub fn ident_name_compatibility_hack( + &self, + orig_span: Span, + source_map: &SourceMap, + ) -> Option<(Ident, bool)> { + if let NtIdent(ident, is_raw) = self { + if let ExpnKind::Macro(_, macro_name) = orig_span.ctxt().outer_expn_data().kind { + let filename = source_map.span_to_filename(orig_span); + if let FileName::Real(RealFileName::Named(path)) = filename { + if (path.ends_with("time-macros-impl/src/lib.rs") + && macro_name == sym::impl_macros) + || (path.ends_with("js-sys/src/lib.rs") && macro_name == sym::arrays) + { + let snippet = source_map.span_to_snippet(orig_span); + if snippet.as_deref() == Ok("$name") { + return Some((*ident, *is_raw)); + } + } + } + } + } + None + } } impl PartialEq for Nonterminal { diff --git a/src/librustc_ast/util/comments.rs b/src/librustc_ast/util/comments.rs index a73891db160..e97c8cc4562 100644 --- a/src/librustc_ast/util/comments.rs +++ b/src/librustc_ast/util/comments.rs @@ -1,4 +1,3 @@ -use crate::ast::AttrStyle; use rustc_span::source_map::SourceMap; use rustc_span::{BytePos, CharPos, FileName, Pos, Symbol}; @@ -24,45 +23,6 @@ pub struct Comment { pub pos: BytePos, } -/// For a full line comment string returns its doc comment style if it's a doc comment -/// and returns `None` if it's a regular comment. -pub fn line_doc_comment_style(line_comment: &str) -> Option { - let line_comment = line_comment.as_bytes(); - assert!(line_comment.starts_with(b"//")); - match line_comment.get(2) { - // `//!` is an inner line doc comment. - Some(b'!') => Some(AttrStyle::Inner), - Some(b'/') => match line_comment.get(3) { - // `////` (more than 3 slashes) is not considered a doc comment. - Some(b'/') => None, - // Otherwise `///` is an outer line doc comment. - _ => Some(AttrStyle::Outer), - }, - _ => None, - } -} - -/// For a full block comment string returns its doc comment style if it's a doc comment -/// and returns `None` if it's a regular comment. -pub fn block_doc_comment_style(block_comment: &str, terminated: bool) -> Option { - let block_comment = block_comment.as_bytes(); - assert!(block_comment.starts_with(b"/*")); - assert!(!terminated || block_comment.ends_with(b"*/")); - match block_comment.get(2) { - // `/*!` is an inner block doc comment. - Some(b'!') => Some(AttrStyle::Inner), - Some(b'*') => match block_comment.get(3) { - // `/***` (more than 2 stars) is not considered a doc comment. - Some(b'*') => None, - // `/**/` is not considered a doc comment. - Some(b'/') if block_comment.len() == 4 => None, - // Otherwise `/**` is an outer block doc comment. - _ => Some(AttrStyle::Outer), - }, - _ => None, - } -} - /// Makes a doc string more presentable to users. /// Used by rustdoc and perhaps other tools, but not by rustc. pub fn beautify_doc_string(data: Symbol) -> String { @@ -216,8 +176,8 @@ pub fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec { - if block_doc_comment_style(token_text, terminated).is_none() { + rustc_lexer::TokenKind::BlockComment { doc_style, .. } => { + if doc_style.is_none() { let code_to_the_right = match text[pos + token.len..].chars().next() { Some('\r' | '\n') => false, _ => true, @@ -238,8 +198,8 @@ pub fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec { - if line_doc_comment_style(token_text).is_none() { + rustc_lexer::TokenKind::LineComment { doc_style } => { + if doc_style.is_none() { comments.push(Comment { style: if code_to_the_left { CommentStyle::Trailing diff --git a/src/librustc_ast/util/comments/tests.rs b/src/librustc_ast/util/comments/tests.rs index 1919b9341aa..e19198f863b 100644 --- a/src/librustc_ast/util/comments/tests.rs +++ b/src/librustc_ast/util/comments/tests.rs @@ -1,13 +1,6 @@ use super::*; use rustc_span::with_default_session_globals; -#[test] -fn line_doc_comments() { - assert!(line_doc_comment_style("///").is_some()); - assert!(line_doc_comment_style("/// blah").is_some()); - assert!(line_doc_comment_style("////").is_none()); -} - #[test] fn test_block_doc_comment_1() { with_default_session_globals(|| { diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs index 473fb7ccc70..f3309afec7d 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/src/librustc_ast_lowering/item.rs @@ -263,7 +263,12 @@ fn lower_item_kind( let (ty, body_id) = self.lower_const_item(t, span, e.as_deref()); hir::ItemKind::Const(ty, body_id) } - ItemKind::Fn(_, FnSig { ref decl, header }, ref generics, ref body) => { + ItemKind::Fn( + _, + FnSig { ref decl, header, span: fn_sig_span }, + ref generics, + ref body, + ) => { let fn_def_id = self.resolver.local_def_id(id); self.with_new_scopes(|this| { this.current_item = Some(ident.span); @@ -290,7 +295,11 @@ fn lower_item_kind( ) }, ); - let sig = hir::FnSig { decl, header: this.lower_fn_header(header) }; + let sig = hir::FnSig { + decl, + header: this.lower_fn_header(header), + span: fn_sig_span, + }; hir::ItemKind::Fn(sig, generics, body_id) }) } @@ -1243,7 +1252,7 @@ fn lower_method_sig( ) }, ); - (generics, hir::FnSig { header, decl }) + (generics, hir::FnSig { header, decl, span: sig.span }) } fn lower_fn_header(&mut self, h: FnHeader) -> hir::FnHeader { diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index 31eedeaed0a..586355fe613 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -2058,7 +2058,7 @@ fn lower_async_fn_output_type_to_future_bound( hir::GenericBound::LangItemTrait( // ::std::future::Future - hir::LangItem::FutureTraitLangItem, + hir::LangItem::Future, span, self.next_id(), future_args, diff --git a/src/librustc_ast_passes/feature_gate.rs b/src/librustc_ast_passes/feature_gate.rs index b15792dfd4c..0ee8ef55e61 100644 --- a/src/librustc_ast_passes/feature_gate.rs +++ b/src/librustc_ast_passes/feature_gate.rs @@ -613,11 +613,14 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) { let spans = sess.parse_sess.gated_spans.spans.borrow(); macro_rules! gate_all { ($gate:ident, $msg:literal) => { - for span in spans.get(&sym::$gate).unwrap_or(&vec![]) { - gate_feature_post!(&visitor, $gate, *span, $msg); + if let Some(spans) = spans.get(&sym::$gate) { + for span in spans { + gate_feature_post!(&visitor, $gate, *span, $msg); + } } }; } + gate_all!(if_let_guard, "`if let` guard is not implemented"); gate_all!(let_chains, "`let` expressions in this position are experimental"); gate_all!(async_closure, "async closures are unstable"); gate_all!(generators, "yield syntax is experimental"); diff --git a/src/librustc_builtin_macros/deriving/generic/mod.rs b/src/librustc_builtin_macros/deriving/generic/mod.rs index accb0b3c949..849e8b136e1 100644 --- a/src/librustc_builtin_macros/deriving/generic/mod.rs +++ b/src/librustc_builtin_macros/deriving/generic/mod.rs @@ -924,6 +924,7 @@ fn create_method( let sig = ast::FnSig { header: ast::FnHeader { unsafety, ext: ast::Extern::None, ..ast::FnHeader::default() }, decl: fn_decl, + span: trait_.span, }; let def = ast::Defaultness::Final; diff --git a/src/librustc_builtin_macros/global_allocator.rs b/src/librustc_builtin_macros/global_allocator.rs index c37adb7baa0..8478fcfbf09 100644 --- a/src/librustc_builtin_macros/global_allocator.rs +++ b/src/librustc_builtin_macros/global_allocator.rs @@ -67,7 +67,7 @@ fn allocator_fn(&self, method: &AllocatorMethod) -> Stmt { let (output_ty, output_expr) = self.ret_ty(&method.output, result); let decl = self.cx.fn_decl(abi_args, ast::FnRetTy::Ty(output_ty)); let header = FnHeader { unsafety: Unsafe::Yes(self.span), ..FnHeader::default() }; - let sig = FnSig { decl, header }; + let sig = FnSig { decl, header, span: self.span }; let block = Some(self.cx.block_expr(output_expr)); let kind = ItemKind::Fn(ast::Defaultness::Final, sig, Generics::default(), block); let item = self.cx.item( diff --git a/src/librustc_builtin_macros/test_harness.rs b/src/librustc_builtin_macros/test_harness.rs index 277cd8389e3..0ea60665d67 100644 --- a/src/librustc_builtin_macros/test_harness.rs +++ b/src/librustc_builtin_macros/test_harness.rs @@ -318,7 +318,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P { }; let decl = ecx.fn_decl(vec![], ast::FnRetTy::Ty(main_ret_ty)); - let sig = ast::FnSig { decl, header: ast::FnHeader::default() }; + let sig = ast::FnSig { decl, header: ast::FnHeader::default(), span: sp }; let def = ast::Defaultness::Final; let main = ast::ItemKind::Fn(def, sig, ast::Generics::default(), Some(main_body)); diff --git a/src/librustc_codegen_llvm/asm.rs b/src/librustc_codegen_llvm/asm.rs index a6062de6bf8..4fef94dde5f 100644 --- a/src/librustc_codegen_llvm/asm.rs +++ b/src/librustc_codegen_llvm/asm.rs @@ -479,10 +479,13 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'tcx>>) _ => unreachable!(), } } else { - // We use i32 as the type for discarded outputs - 's' + // We use i64x2 as the type for discarded outputs + 'q' }; format!("{{{}{}}}", class, idx) + } else if reg == InlineAsmReg::AArch64(AArch64InlineAsmReg::x30) { + // LLVM doesn't recognize x30 + "lr".to_string() } else { format!("{{{}}}", reg.name()) } diff --git a/src/librustc_codegen_ssa/base.rs b/src/librustc_codegen_ssa/base.rs index b28cb071de6..77c12c410d5 100644 --- a/src/librustc_codegen_ssa/base.rs +++ b/src/librustc_codegen_ssa/base.rs @@ -31,7 +31,7 @@ use rustc_data_structures::sync::{par_iter, Lock, ParallelIterator}; use rustc_hir as hir; use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE}; -use rustc_hir::lang_items::StartFnLangItem; +use rustc_hir::lang_items::LangItem; use rustc_index::vec::Idx; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::middle::cstore::EncodedMetadata; @@ -458,7 +458,7 @@ fn create_entry_fn<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let (arg_argc, arg_argv) = get_argc_argv(cx, &mut bx); let (start_fn, args) = if use_start_lang_item { - let start_def_id = cx.tcx().require_lang_item(StartFnLangItem, None); + let start_def_id = cx.tcx().require_lang_item(LangItem::Start, None); let start_fn = cx.get_fn_addr( ty::Instance::resolve( cx.tcx(), diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index a4e039de4df..8048a569f79 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -10,7 +10,7 @@ use crate::MemFlags; use rustc_ast as ast; -use rustc_hir::lang_items; +use rustc_hir::lang_items::LangItem; use rustc_index::vec::Idx; use rustc_middle::mir; use rustc_middle::mir::interpret::{AllocId, ConstValue, Pointer, Scalar}; @@ -420,14 +420,14 @@ fn codegen_assert_terminator( let index = self.codegen_operand(&mut bx, index).immediate(); // It's `fn panic_bounds_check(index: usize, len: usize)`, // and `#[track_caller]` adds an implicit third argument. - (lang_items::PanicBoundsCheckFnLangItem, vec![index, len, location]) + (LangItem::PanicBoundsCheck, vec![index, len, location]) } _ => { let msg_str = Symbol::intern(msg.description()); let msg = bx.const_str(msg_str); // It's `pub fn panic(expr: &str)`, with the wide reference being passed // as two arguments, and `#[track_caller]` adds an implicit third argument. - (lang_items::PanicFnLangItem, vec![msg.0, msg.1, location]) + (LangItem::Panic, vec![msg.0, msg.1, location]) } }; @@ -492,8 +492,7 @@ enum AssertIntrinsic { // Obtain the panic entry point. // FIXME: dedup this with `codegen_assert_terminator` above. - let def_id = - common::langcall(bx.tcx(), Some(span), "", lang_items::PanicFnLangItem); + let def_id = common::langcall(bx.tcx(), Some(span), "", LangItem::Panic); let instance = ty::Instance::mono(bx.tcx(), def_id); let fn_abi = FnAbi::of_instance(bx, instance, &[]); let llfn = bx.get_fn_addr(instance); diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs index 77e94fe3d0a..71f924df119 100644 --- a/src/librustc_codegen_ssa/mir/rvalue.rs +++ b/src/librustc_codegen_ssa/mir/rvalue.rs @@ -8,7 +8,7 @@ use crate::MemFlags; use rustc_apfloat::{ieee, Float, Round, Status}; -use rustc_hir::lang_items::ExchangeMallocFnLangItem; +use rustc_hir::lang_items::LangItem; use rustc_middle::mir; use rustc_middle::ty::cast::{CastTy, IntTy}; use rustc_middle::ty::layout::{HasTyCtxt, TyAndLayout}; @@ -507,7 +507,7 @@ pub fn codegen_rvalue_operand( let llty_ptr = bx.cx().backend_type(box_layout); // Allocate space: - let def_id = match bx.tcx().lang_items().require(ExchangeMallocFnLangItem) { + let def_id = match bx.tcx().lang_items().require(LangItem::ExchangeMalloc) { Ok(id) => id, Err(s) => { bx.cx().sess().fatal(&format!("allocation of `{}` {}", box_layout.ty, s)); diff --git a/src/librustc_error_codes/error_codes/E0759.md b/src/librustc_error_codes/error_codes/E0759.md index a74759bdf63..6d525310f75 100644 --- a/src/librustc_error_codes/error_codes/E0759.md +++ b/src/librustc_error_codes/error_codes/E0759.md @@ -1,34 +1,28 @@ -A `'static` requirement in a return type involving a trait is not fulfilled. +Return type involving a trait did not require `'static` lifetime. Erroneous code examples: ```compile_fail,E0759 use std::fmt::Debug; -fn foo(x: &i32) -> impl Debug { +fn foo(x: &i32) -> impl Debug { // error! x } -``` -```compile_fail,E0759 -# use std::fmt::Debug; -fn bar(x: &i32) -> Box { +fn bar(x: &i32) -> Box { // error! Box::new(x) } ``` -These examples have the same semantics as the following: +Add `'static` requirement to fix them: ```compile_fail,E0759 # use std::fmt::Debug; -fn foo(x: &i32) -> impl Debug + 'static { +fn foo(x: &i32) -> impl Debug + 'static { // ok! x } -``` -```compile_fail,E0759 -# use std::fmt::Debug; -fn bar(x: &i32) -> Box { +fn bar(x: &i32) -> Box { // ok! Box::new(x) } ``` diff --git a/src/librustc_expand/base.rs b/src/librustc_expand/base.rs index 0a5e1f76d10..4c01cb8159a 100644 --- a/src/librustc_expand/base.rs +++ b/src/librustc_expand/base.rs @@ -551,6 +551,7 @@ fn make_pat(self: Box) -> Option> { id: ast::DUMMY_NODE_ID, span: e.span, kind: PatKind::Lit(e), + tokens: None, })); } } @@ -597,7 +598,7 @@ pub fn raw_expr(sp: Span, is_error: bool) -> P { /// A plain dummy pattern. pub fn raw_pat(sp: Span) -> ast::Pat { - ast::Pat { id: ast::DUMMY_NODE_ID, kind: PatKind::Wild, span: sp } + ast::Pat { id: ast::DUMMY_NODE_ID, kind: PatKind::Wild, span: sp, tokens: None } } /// A plain dummy type. diff --git a/src/librustc_expand/build.rs b/src/librustc_expand/build.rs index 7f4737a38ab..9490b62aa17 100644 --- a/src/librustc_expand/build.rs +++ b/src/librustc_expand/build.rs @@ -392,7 +392,7 @@ pub fn expr_try(&self, sp: Span, head: P) -> P { } pub fn pat(&self, span: Span, kind: PatKind) -> P { - P(ast::Pat { id: ast::DUMMY_NODE_ID, kind, span }) + P(ast::Pat { id: ast::DUMMY_NODE_ID, kind, span, tokens: None }) } pub fn pat_wild(&self, span: Span) -> P { self.pat(span, PatKind::Wild) diff --git a/src/librustc_expand/mbe.rs b/src/librustc_expand/mbe.rs index e9e6fc5af22..9aed307ec93 100644 --- a/src/librustc_expand/mbe.rs +++ b/src/librustc_expand/mbe.rs @@ -61,7 +61,7 @@ fn new(op: KleeneOp, span: Span) -> KleeneToken { } } -/// A Kleene-style [repetition operator](http://en.wikipedia.org/wiki/Kleene_star) +/// A Kleene-style [repetition operator](https://en.wikipedia.org/wiki/Kleene_star) /// for token sequences. #[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy)] enum KleeneOp { diff --git a/src/librustc_expand/placeholders.rs b/src/librustc_expand/placeholders.rs index 0788823b0e7..29fb4c95ec6 100644 --- a/src/librustc_expand/placeholders.rs +++ b/src/librustc_expand/placeholders.rs @@ -38,7 +38,8 @@ fn mac_placeholder() -> ast::MacCall { }) }; let ty = || P(ast::Ty { id, kind: ast::TyKind::MacCall(mac_placeholder()), span }); - let pat = || P(ast::Pat { id, kind: ast::PatKind::MacCall(mac_placeholder()), span }); + let pat = + || P(ast::Pat { id, kind: ast::PatKind::MacCall(mac_placeholder()), span, tokens: None }); match kind { AstFragmentKind::Expr => AstFragment::Expr(expr_placeholder()), @@ -85,6 +86,7 @@ fn mac_placeholder() -> ast::MacCall { id, span, kind: ast::PatKind::MacCall(mac_placeholder()), + tokens: None, })), AstFragmentKind::Ty => { AstFragment::Ty(P(ast::Ty { id, span, kind: ast::TyKind::MacCall(mac_placeholder()) })) diff --git a/src/librustc_expand/proc_macro_server.rs b/src/librustc_expand/proc_macro_server.rs index 33e35cd0404..409784812f5 100644 --- a/src/librustc_expand/proc_macro_server.rs +++ b/src/librustc_expand/proc_macro_server.rs @@ -173,13 +173,19 @@ macro_rules! op { } Interpolated(nt) => { - let stream = nt_to_tokenstream(&nt, sess, span); - TokenTree::Group(Group { - delimiter: Delimiter::None, - stream, - span: DelimSpan::from_single(span), - flatten: nt.pretty_printing_compatibility_hack(), - }) + if let Some((name, is_raw)) = + nt.ident_name_compatibility_hack(span, sess.source_map()) + { + TokenTree::Ident(Ident::new(sess, name.name, is_raw, name.span)) + } else { + let stream = nt_to_tokenstream(&nt, sess, span); + TokenTree::Group(Group { + delimiter: Delimiter::None, + stream, + span: DelimSpan::from_single(span), + flatten: nt.pretty_printing_compatibility_hack(), + }) + } } OpenDelim(..) | CloseDelim(..) => unreachable!(), diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs index 31aba8aba25..e858980738d 100644 --- a/src/librustc_feature/active.rs +++ b/src/librustc_feature/active.rs @@ -582,6 +582,9 @@ pub fn set(&self, features: &mut Features, span: Span) { /// The smallest useful subset of `const_generics`. (active, min_const_generics, "1.47.0", Some(74878), None), + /// Allows `if let` guard in match arms. + (active, if_let_guard, "1.47.0", Some(51114), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- @@ -591,6 +594,7 @@ pub fn set(&self, features: &mut Features, span: Span) { /// unanticipated results, such as compiler crashes. We warn the user about these /// to alert them. pub const INCOMPLETE_FEATURES: &[Symbol] = &[ + sym::if_let_guard, sym::impl_trait_in_bindings, sym::generic_associated_types, sym::const_generics, diff --git a/src/librustc_hir/definitions.rs b/src/librustc_hir/definitions.rs index 628fc931411..45735ead256 100644 --- a/src/librustc_hir/definitions.rs +++ b/src/librustc_hir/definitions.rs @@ -23,7 +23,7 @@ /// Internally the `DefPathTable` holds a tree of `DefKey`s, where each `DefKey` /// stores the `DefIndex` of its parent. /// There is one `DefPathTable` for each crate. -#[derive(Clone, Default, Decodable, Encodable)] +#[derive(Clone, Default)] pub struct DefPathTable { index_to_key: IndexVec, def_path_hashes: IndexVec, @@ -42,10 +42,6 @@ fn allocate(&mut self, key: DefKey, def_path_hash: DefPathHash) -> DefIndex { index } - pub fn next_id(&self) -> DefIndex { - DefIndex::from(self.index_to_key.len()) - } - #[inline(always)] pub fn def_key(&self, index: DefIndex) -> DefKey { self.index_to_key[index] @@ -58,15 +54,25 @@ pub fn def_path_hash(&self, index: DefIndex) -> DefPathHash { hash } - pub fn add_def_path_hashes_to(&self, cnum: CrateNum, out: &mut FxHashMap) { - out.extend(self.def_path_hashes.iter().enumerate().map(|(index, &hash)| { - let def_id = DefId { krate: cnum, index: DefIndex::from(index) }; - (hash, def_id) - })); + pub fn num_def_ids(&self) -> usize { + self.index_to_key.len() } - pub fn size(&self) -> usize { - self.index_to_key.len() + pub fn enumerated_keys_and_path_hashes( + &self, + ) -> impl Iterator + '_ { + self.index_to_key + .iter_enumerated() + .map(move |(index, key)| (index, key, &self.def_path_hashes[index])) + } + + pub fn all_def_path_hashes_and_def_ids( + &self, + krate: CrateNum, + ) -> impl Iterator + '_ { + self.def_path_hashes + .iter_enumerated() + .map(move |(index, hash)| (*hash, DefId { krate, index })) } } diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index cf356763130..cd4185226dc 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -1851,6 +1851,7 @@ pub struct MutTy<'hir> { pub struct FnSig<'hir> { pub header: FnHeader, pub decl: &'hir FnDecl<'hir>, + pub span: Span, } // The bodies for items are stored "out of line", in a separate diff --git a/src/librustc_hir/lang_items.rs b/src/librustc_hir/lang_items.rs index 978f73760ec..acf6847c014 100644 --- a/src/librustc_hir/lang_items.rs +++ b/src/librustc_hir/lang_items.rs @@ -7,8 +7,6 @@ //! * Traits that represent operators; e.g., `Add`, `Sub`, `Index`. //! * Functions called by the compiler itself. -pub use self::LangItem::*; - use crate::def_id::DefId; use crate::{MethodKind, Target}; @@ -57,14 +55,14 @@ impl LangItem { /// that is `#[lang = "eq"]` would result in `sym::eq`. pub fn name(self) -> Symbol { match self { - $( $variant => $name, )* + $( LangItem::$variant => $name, )* } } pub fn group(self) -> Option { use LangItemGroup::*; match self { - $( $variant => expand_group!($($group)*), )* + $( LangItem::$variant => expand_group!($($group)*), )* } } } @@ -87,7 +85,7 @@ pub fn new() -> Self { fn init_none(_: LangItem) -> Option { None } Self { - items: vec![$(init_none($variant)),*], + items: vec![$(init_none(LangItem::$variant)),*], missing: Vec::new(), groups: [vec![]; NUM_GROUPS], } @@ -114,7 +112,7 @@ pub fn group(&self, group: LangItemGroup) -> &[DefId] { /// exists. #[allow(dead_code)] pub fn $method(&self) -> Option { - self.items[$variant as usize] + self.items[LangItem::$variant as usize] } )* } @@ -123,7 +121,7 @@ pub fn $method(&self) -> Option { /// A mapping from the name of the lang item to its order and the form it must be of. pub static ref ITEM_REFS: FxHashMap = { let mut item_refs = FxHashMap::default(); - $( item_refs.insert($name, ($variant as usize, $target)); )* + $( item_refs.insert($name, (LangItem::$variant as usize, $target)); )* item_refs }; } @@ -161,179 +159,176 @@ pub fn extract<'a, F>(check_name: F, attrs: &'a [ast::Attribute]) -> Option<(Sym } language_item_table! { -// Variant name, Name, Method name, Target; - BoolImplItem, sym::bool, bool_impl, Target::Impl; - CharImplItem, sym::char, char_impl, Target::Impl; - StrImplItem, sym::str, str_impl, Target::Impl; - ArrayImplItem, sym::array, array_impl, Target::Impl; - SliceImplItem, sym::slice, slice_impl, Target::Impl; - SliceU8ImplItem, sym::slice_u8, slice_u8_impl, Target::Impl; - StrAllocImplItem, sym::str_alloc, str_alloc_impl, Target::Impl; - SliceAllocImplItem, sym::slice_alloc, slice_alloc_impl, Target::Impl; - SliceU8AllocImplItem, sym::slice_u8_alloc, slice_u8_alloc_impl, Target::Impl; - ConstPtrImplItem, sym::const_ptr, const_ptr_impl, Target::Impl; - MutPtrImplItem, sym::mut_ptr, mut_ptr_impl, Target::Impl; - ConstSlicePtrImplItem, sym::const_slice_ptr, const_slice_ptr_impl, Target::Impl; - MutSlicePtrImplItem, sym::mut_slice_ptr, mut_slice_ptr_impl, Target::Impl; - I8ImplItem, sym::i8, i8_impl, Target::Impl; - I16ImplItem, sym::i16, i16_impl, Target::Impl; - I32ImplItem, sym::i32, i32_impl, Target::Impl; - I64ImplItem, sym::i64, i64_impl, Target::Impl; - I128ImplItem, sym::i128, i128_impl, Target::Impl; - IsizeImplItem, sym::isize, isize_impl, Target::Impl; - U8ImplItem, sym::u8, u8_impl, Target::Impl; - U16ImplItem, sym::u16, u16_impl, Target::Impl; - U32ImplItem, sym::u32, u32_impl, Target::Impl; - U64ImplItem, sym::u64, u64_impl, Target::Impl; - U128ImplItem, sym::u128, u128_impl, Target::Impl; - UsizeImplItem, sym::usize, usize_impl, Target::Impl; - F32ImplItem, sym::f32, f32_impl, Target::Impl; - F64ImplItem, sym::f64, f64_impl, Target::Impl; - F32RuntimeImplItem, sym::f32_runtime, f32_runtime_impl, Target::Impl; - F64RuntimeImplItem, sym::f64_runtime, f64_runtime_impl, Target::Impl; - - SizedTraitLangItem, sym::sized, sized_trait, Target::Trait; - UnsizeTraitLangItem, sym::unsize, unsize_trait, Target::Trait; - // trait injected by #[derive(PartialEq)], (i.e. "Partial EQ"). - StructuralPeqTraitLangItem, sym::structural_peq, structural_peq_trait, Target::Trait; - // trait injected by #[derive(Eq)], (i.e. "Total EQ"; no, I will not apologize). - StructuralTeqTraitLangItem, sym::structural_teq, structural_teq_trait, Target::Trait; - CopyTraitLangItem, sym::copy, copy_trait, Target::Trait; - CloneTraitLangItem, sym::clone, clone_trait, Target::Trait; - SyncTraitLangItem, sym::sync, sync_trait, Target::Trait; - DiscriminantKindTraitLangItem, sym::discriminant_kind, discriminant_kind_trait, Target::Trait; +// Variant name, Name, Method name, Target; + Bool, sym::bool, bool_impl, Target::Impl; + Char, sym::char, char_impl, Target::Impl; + Str, sym::str, str_impl, Target::Impl; + Array, sym::array, array_impl, Target::Impl; + Slice, sym::slice, slice_impl, Target::Impl; + SliceU8, sym::slice_u8, slice_u8_impl, Target::Impl; + StrAlloc, sym::str_alloc, str_alloc_impl, Target::Impl; + SliceAlloc, sym::slice_alloc, slice_alloc_impl, Target::Impl; + SliceU8Alloc, sym::slice_u8_alloc, slice_u8_alloc_impl, Target::Impl; + ConstPtr, sym::const_ptr, const_ptr_impl, Target::Impl; + MutPtr, sym::mut_ptr, mut_ptr_impl, Target::Impl; + ConstSlicePtr, sym::const_slice_ptr, const_slice_ptr_impl, Target::Impl; + MutSlicePtr, sym::mut_slice_ptr, mut_slice_ptr_impl, Target::Impl; + I8, sym::i8, i8_impl, Target::Impl; + I16, sym::i16, i16_impl, Target::Impl; + I32, sym::i32, i32_impl, Target::Impl; + I64, sym::i64, i64_impl, Target::Impl; + I128, sym::i128, i128_impl, Target::Impl; + Isize, sym::isize, isize_impl, Target::Impl; + U8, sym::u8, u8_impl, Target::Impl; + U16, sym::u16, u16_impl, Target::Impl; + U32, sym::u32, u32_impl, Target::Impl; + U64, sym::u64, u64_impl, Target::Impl; + U128, sym::u128, u128_impl, Target::Impl; + Usize, sym::usize, usize_impl, Target::Impl; + F32, sym::f32, f32_impl, Target::Impl; + F64, sym::f64, f64_impl, Target::Impl; + F32Runtime, sym::f32_runtime, f32_runtime_impl, Target::Impl; + F64Runtime, sym::f64_runtime, f64_runtime_impl, Target::Impl; + + Sized, sym::sized, sized_trait, Target::Trait; + Unsize, sym::unsize, unsize_trait, Target::Trait; + // Trait injected by #[derive(PartialEq)], (i.e. "Partial EQ"). + StructuralPeq, sym::structural_peq, structural_peq_trait, Target::Trait; + // Trait injected by #[derive(Eq)], (i.e. "Total EQ"; no, I will not apologize). + StructuralTeq, sym::structural_teq, structural_teq_trait, Target::Trait; + Copy, sym::copy, copy_trait, Target::Trait; + Clone, sym::clone, clone_trait, Target::Trait; + Sync, sym::sync, sync_trait, Target::Trait; + DiscriminantKind, sym::discriminant_kind, discriminant_kind_trait, Target::Trait; // The associated item of `trait DiscriminantKind`. - DiscriminantTypeLangItem, sym::discriminant_type, discriminant_type, Target::AssocTy; - - FreezeTraitLangItem, sym::freeze, freeze_trait, Target::Trait; - - DropTraitLangItem, sym::drop, drop_trait, Target::Trait; - - CoerceUnsizedTraitLangItem, sym::coerce_unsized, coerce_unsized_trait, Target::Trait; - DispatchFromDynTraitLangItem, sym::dispatch_from_dyn, dispatch_from_dyn_trait, Target::Trait; - - AddTraitLangItem(Op), sym::add, add_trait, Target::Trait; - SubTraitLangItem(Op), sym::sub, sub_trait, Target::Trait; - MulTraitLangItem(Op), sym::mul, mul_trait, Target::Trait; - DivTraitLangItem(Op), sym::div, div_trait, Target::Trait; - RemTraitLangItem(Op), sym::rem, rem_trait, Target::Trait; - NegTraitLangItem(Op), sym::neg, neg_trait, Target::Trait; - NotTraitLangItem(Op), sym::not, not_trait, Target::Trait; - BitXorTraitLangItem(Op), sym::bitxor, bitxor_trait, Target::Trait; - BitAndTraitLangItem(Op), sym::bitand, bitand_trait, Target::Trait; - BitOrTraitLangItem(Op), sym::bitor, bitor_trait, Target::Trait; - ShlTraitLangItem(Op), sym::shl, shl_trait, Target::Trait; - ShrTraitLangItem(Op), sym::shr, shr_trait, Target::Trait; - AddAssignTraitLangItem(Op), sym::add_assign, add_assign_trait, Target::Trait; - SubAssignTraitLangItem(Op), sym::sub_assign, sub_assign_trait, Target::Trait; - MulAssignTraitLangItem(Op), sym::mul_assign, mul_assign_trait, Target::Trait; - DivAssignTraitLangItem(Op), sym::div_assign, div_assign_trait, Target::Trait; - RemAssignTraitLangItem(Op), sym::rem_assign, rem_assign_trait, Target::Trait; - BitXorAssignTraitLangItem(Op), sym::bitxor_assign, bitxor_assign_trait, Target::Trait; - BitAndAssignTraitLangItem(Op), sym::bitand_assign, bitand_assign_trait, Target::Trait; - BitOrAssignTraitLangItem(Op), sym::bitor_assign, bitor_assign_trait, Target::Trait; - ShlAssignTraitLangItem(Op), sym::shl_assign, shl_assign_trait, Target::Trait; - ShrAssignTraitLangItem(Op), sym::shr_assign, shr_assign_trait, Target::Trait; - IndexTraitLangItem(Op), sym::index, index_trait, Target::Trait; - IndexMutTraitLangItem(Op), sym::index_mut, index_mut_trait, Target::Trait; - - UnsafeCellTypeLangItem, sym::unsafe_cell, unsafe_cell_type, Target::Struct; - VaListTypeLangItem, sym::va_list, va_list, Target::Struct; - - DerefTraitLangItem, sym::deref, deref_trait, Target::Trait; - DerefMutTraitLangItem, sym::deref_mut, deref_mut_trait, Target::Trait; - ReceiverTraitLangItem, sym::receiver, receiver_trait, Target::Trait; - - FnTraitLangItem, kw::Fn, fn_trait, Target::Trait; - FnMutTraitLangItem, sym::fn_mut, fn_mut_trait, Target::Trait; - FnOnceTraitLangItem, sym::fn_once, fn_once_trait, Target::Trait; - - FnOnceOutputLangItem, sym::fn_once_output, fn_once_output, Target::AssocTy; - - FutureTraitLangItem, sym::future_trait, future_trait, Target::Trait; - GeneratorStateLangItem, sym::generator_state, gen_state, Target::Enum; - GeneratorTraitLangItem, sym::generator, gen_trait, Target::Trait; - UnpinTraitLangItem, sym::unpin, unpin_trait, Target::Trait; - PinTypeLangItem, sym::pin, pin_type, Target::Struct; - - // Don't be fooled by the naming here: this lang item denotes `PartialEq`, not `Eq`. - EqTraitLangItem, sym::eq, eq_trait, Target::Trait; - PartialOrdTraitLangItem, sym::partial_ord, partial_ord_trait, Target::Trait; - - // A number of panic-related lang items. The `panic` item corresponds to - // divide-by-zero and various panic cases with `match`. The - // `panic_bounds_check` item is for indexing arrays. + Discriminant, sym::discriminant_type, discriminant_type, Target::AssocTy; + + Freeze, sym::freeze, freeze_trait, Target::Trait; + + Drop, sym::drop, drop_trait, Target::Trait; + + CoerceUnsized, sym::coerce_unsized, coerce_unsized_trait, Target::Trait; + DispatchFromDyn, sym::dispatch_from_dyn, dispatch_from_dyn_trait, Target::Trait; + + Add(Op), sym::add, add_trait, Target::Trait; + Sub(Op), sym::sub, sub_trait, Target::Trait; + Mul(Op), sym::mul, mul_trait, Target::Trait; + Div(Op), sym::div, div_trait, Target::Trait; + Rem(Op), sym::rem, rem_trait, Target::Trait; + Neg(Op), sym::neg, neg_trait, Target::Trait; + Not(Op), sym::not, not_trait, Target::Trait; + BitXor(Op), sym::bitxor, bitxor_trait, Target::Trait; + BitAnd(Op), sym::bitand, bitand_trait, Target::Trait; + BitOr(Op), sym::bitor, bitor_trait, Target::Trait; + Shl(Op), sym::shl, shl_trait, Target::Trait; + Shr(Op), sym::shr, shr_trait, Target::Trait; + AddAssign(Op), sym::add_assign, add_assign_trait, Target::Trait; + SubAssign(Op), sym::sub_assign, sub_assign_trait, Target::Trait; + MulAssign(Op), sym::mul_assign, mul_assign_trait, Target::Trait; + DivAssign(Op), sym::div_assign, div_assign_trait, Target::Trait; + RemAssign(Op), sym::rem_assign, rem_assign_trait, Target::Trait; + BitXorAssign(Op), sym::bitxor_assign, bitxor_assign_trait, Target::Trait; + BitAndAssign(Op), sym::bitand_assign, bitand_assign_trait, Target::Trait; + BitOrAssign(Op), sym::bitor_assign, bitor_assign_trait, Target::Trait; + ShlAssign(Op), sym::shl_assign, shl_assign_trait, Target::Trait; + ShrAssign(Op), sym::shr_assign, shr_assign_trait, Target::Trait; + Index(Op), sym::index, index_trait, Target::Trait; + IndexMut(Op), sym::index_mut, index_mut_trait, Target::Trait; + + UnsafeCell, sym::unsafe_cell, unsafe_cell_type, Target::Struct; + VaList, sym::va_list, va_list, Target::Struct; + + Deref, sym::deref, deref_trait, Target::Trait; + DerefMut, sym::deref_mut, deref_mut_trait, Target::Trait; + Receiver, sym::receiver, receiver_trait, Target::Trait; + + Fn, kw::Fn, fn_trait, Target::Trait; + FnMut, sym::fn_mut, fn_mut_trait, Target::Trait; + FnOnce, sym::fn_once, fn_once_trait, Target::Trait; + + FnOnceOutput, sym::fn_once_output, fn_once_output, Target::AssocTy; + + Future, sym::future_trait, future_trait, Target::Trait; + GeneratorState, sym::generator_state, gen_state, Target::Enum; + Generator, sym::generator, gen_trait, Target::Trait; + Unpin, sym::unpin, unpin_trait, Target::Trait; + Pin, sym::pin, pin_type, Target::Struct; + + PartialEq, sym::eq, eq_trait, Target::Trait; + PartialOrd, sym::partial_ord, partial_ord_trait, Target::Trait; + + // A number of panic-related lang items. The `panic` item corresponds to divide-by-zero and + // various panic cases with `match`. The `panic_bounds_check` item is for indexing arrays. // - // The `begin_unwind` lang item has a predefined symbol name and is sort of - // a "weak lang item" in the sense that a crate is not required to have it - // defined to use it, but a final product is required to define it - // somewhere. Additionally, there are restrictions on crates that use a weak - // lang item, but do not have it defined. - PanicFnLangItem, sym::panic, panic_fn, Target::Fn; - PanicBoundsCheckFnLangItem, sym::panic_bounds_check, panic_bounds_check_fn, Target::Fn; - PanicInfoLangItem, sym::panic_info, panic_info, Target::Struct; - PanicLocationLangItem, sym::panic_location, panic_location, Target::Struct; - PanicImplLangItem, sym::panic_impl, panic_impl, Target::Fn; - // Libstd panic entry point. Necessary for const eval to be able to catch it - BeginPanicFnLangItem, sym::begin_panic, begin_panic_fn, Target::Fn; + // The `begin_unwind` lang item has a predefined symbol name and is sort of a "weak lang item" + // in the sense that a crate is not required to have it defined to use it, but a final product + // is required to define it somewhere. Additionally, there are restrictions on crates that use + // a weak lang item, but do not have it defined. + Panic, sym::panic, panic_fn, Target::Fn; + PanicBoundsCheck, sym::panic_bounds_check, panic_bounds_check_fn, Target::Fn; + PanicInfo, sym::panic_info, panic_info, Target::Struct; + PanicLocation, sym::panic_location, panic_location, Target::Struct; + PanicImpl, sym::panic_impl, panic_impl, Target::Fn; + // libstd panic entry point. Necessary for const eval to be able to catch it + BeginPanic, sym::begin_panic, begin_panic_fn, Target::Fn; - ExchangeMallocFnLangItem, sym::exchange_malloc, exchange_malloc_fn, Target::Fn; - BoxFreeFnLangItem, sym::box_free, box_free_fn, Target::Fn; - DropInPlaceFnLangItem, sym::drop_in_place, drop_in_place_fn, Target::Fn; - OomLangItem, sym::oom, oom, Target::Fn; - AllocLayoutLangItem, sym::alloc_layout, alloc_layout, Target::Struct; + ExchangeMalloc, sym::exchange_malloc, exchange_malloc_fn, Target::Fn; + BoxFree, sym::box_free, box_free_fn, Target::Fn; + DropInPlace, sym::drop_in_place, drop_in_place_fn, Target::Fn; + Oom, sym::oom, oom, Target::Fn; + AllocLayout, sym::alloc_layout, alloc_layout, Target::Struct; - StartFnLangItem, sym::start, start_fn, Target::Fn; + Start, sym::start, start_fn, Target::Fn; - EhPersonalityLangItem, sym::eh_personality, eh_personality, Target::Fn; - EhCatchTypeinfoLangItem, sym::eh_catch_typeinfo, eh_catch_typeinfo, Target::Static; + EhPersonality, sym::eh_personality, eh_personality, Target::Fn; + EhCatchTypeinfo, sym::eh_catch_typeinfo, eh_catch_typeinfo, Target::Static; - OwnedBoxLangItem, sym::owned_box, owned_box, Target::Struct; + OwnedBox, sym::owned_box, owned_box, Target::Struct; - PhantomDataItem, sym::phantom_data, phantom_data, Target::Struct; + PhantomData, sym::phantom_data, phantom_data, Target::Struct; - ManuallyDropItem, sym::manually_drop, manually_drop, Target::Struct; + ManuallyDrop, sym::manually_drop, manually_drop, Target::Struct; - MaybeUninitLangItem, sym::maybe_uninit, maybe_uninit, Target::Union; + MaybeUninit, sym::maybe_uninit, maybe_uninit, Target::Union; // Align offset for stride != 1; must not panic. - AlignOffsetLangItem, sym::align_offset, align_offset_fn, Target::Fn; + AlignOffset, sym::align_offset, align_offset_fn, Target::Fn; - TerminationTraitLangItem, sym::termination, termination, Target::Trait; + Termination, sym::termination, termination, Target::Trait; - TryTraitLangItem, kw::Try, try_trait, Target::Trait; + Try, kw::Try, try_trait, Target::Trait; // Language items from AST lowering - TryFromError, sym::from_error, from_error_fn, Target::Method(MethodKind::Trait { body: false }); - TryFromOk, sym::from_ok, from_ok_fn, Target::Method(MethodKind::Trait { body: false }); - TryIntoResult, sym::into_result, into_result_fn, Target::Method(MethodKind::Trait { body: false }); + TryFromError, sym::from_error, from_error_fn, Target::Method(MethodKind::Trait { body: false }); + TryFromOk, sym::from_ok, from_ok_fn, Target::Method(MethodKind::Trait { body: false }); + TryIntoResult, sym::into_result, into_result_fn, Target::Method(MethodKind::Trait { body: false }); - PollReady, sym::Ready, poll_ready_variant, Target::Variant; - PollPending, sym::Pending, poll_pending_variant, Target::Variant; + PollReady, sym::Ready, poll_ready_variant, Target::Variant; + PollPending, sym::Pending, poll_pending_variant, Target::Variant; - FromGenerator, sym::from_generator, from_generator_fn, Target::Fn; - GetContext, sym::get_context, get_context_fn, Target::Fn; + FromGenerator, sym::from_generator, from_generator_fn, Target::Fn; + GetContext, sym::get_context, get_context_fn, Target::Fn; - FuturePoll, sym::poll, future_poll_fn, Target::Method(MethodKind::Trait { body: false }); + FuturePoll, sym::poll, future_poll_fn, Target::Method(MethodKind::Trait { body: false }); - FromFrom, sym::from, from_fn, Target::Method(MethodKind::Trait { body: false }); + FromFrom, sym::from, from_fn, Target::Method(MethodKind::Trait { body: false }); - OptionSome, sym::Some, option_some_variant, Target::Variant; - OptionNone, sym::None, option_none_variant, Target::Variant; + OptionSome, sym::Some, option_some_variant, Target::Variant; + OptionNone, sym::None, option_none_variant, Target::Variant; - ResultOk, sym::Ok, result_ok_variant, Target::Variant; - ResultErr, sym::Err, result_err_variant, Target::Variant; + ResultOk, sym::Ok, result_ok_variant, Target::Variant; + ResultErr, sym::Err, result_err_variant, Target::Variant; - IntoIterIntoIter, sym::into_iter, into_iter_fn, Target::Method(MethodKind::Trait { body: false }); - IteratorNext, sym::next, next_fn, Target::Method(MethodKind::Trait { body: false}); + IntoIterIntoIter, sym::into_iter, into_iter_fn, Target::Method(MethodKind::Trait { body: false }); + IteratorNext, sym::next, next_fn, Target::Method(MethodKind::Trait { body: false}); - PinNewUnchecked, sym::new_unchecked, new_unchecked_fn, Target::Method(MethodKind::Inherent); + PinNewUnchecked, sym::new_unchecked, new_unchecked_fn, Target::Method(MethodKind::Inherent); - RangeFrom, sym::RangeFrom, range_from_struct, Target::Struct; - RangeFull, sym::RangeFull, range_full_struct, Target::Struct; - RangeInclusiveStruct, sym::RangeInclusive, range_inclusive_struct, Target::Struct; - RangeInclusiveNew, sym::range_inclusive_new, range_inclusive_new_method, Target::Method(MethodKind::Inherent); - Range, sym::Range, range_struct, Target::Struct; - RangeToInclusive, sym::RangeToInclusive, range_to_inclusive_struct, Target::Struct; - RangeTo, sym::RangeTo, range_to_struct, Target::Struct; + RangeFrom, sym::RangeFrom, range_from_struct, Target::Struct; + RangeFull, sym::RangeFull, range_full_struct, Target::Struct; + RangeInclusiveStruct, sym::RangeInclusive, range_inclusive_struct, Target::Struct; + RangeInclusiveNew, sym::range_inclusive_new, range_inclusive_new_method, Target::Method(MethodKind::Inherent); + Range, sym::Range, range_struct, Target::Struct; + RangeToInclusive, sym::RangeToInclusive, range_to_inclusive_struct, Target::Struct; + RangeTo, sym::RangeTo, range_to_struct, Target::Struct; } diff --git a/src/librustc_hir/weak_lang_items.rs b/src/librustc_hir/weak_lang_items.rs index 76b95c696f7..74e2a90262c 100644 --- a/src/librustc_hir/weak_lang_items.rs +++ b/src/librustc_hir/weak_lang_items.rs @@ -15,7 +15,7 @@ macro_rules! weak_lang_items { lazy_static! { pub static ref WEAK_ITEMS_REFS: FxHashMap = { let mut map = FxHashMap::default(); - $(map.insert(sym::$name, lang_items::$item);)* + $(map.insert(sym::$name, LangItem::$item);)* map }; } @@ -46,7 +46,7 @@ pub fn is_weak_lang_item(&self, item_def_id: DefId) -> bool { ) } weak_lang_items! { - panic_impl, PanicImplLangItem, rust_begin_unwind; - eh_personality, EhPersonalityLangItem, rust_eh_personality; - oom, OomLangItem, rust_oom; + panic_impl, PanicImpl, rust_begin_unwind; + eh_personality, EhPersonality, rust_eh_personality; + oom, Oom, rust_oom; } diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs index 2b2c42207e4..8212958510a 100644 --- a/src/librustc_infer/infer/error_reporting/mod.rs +++ b/src/librustc_infer/infer/error_reporting/mod.rs @@ -609,6 +609,7 @@ fn note_error_origin( err.span_label(span, "expected due to this"); } ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { + semi_span, source, ref prior_arms, last_ty, @@ -663,6 +664,14 @@ fn note_error_origin( format!("this and all prior arms are found to be of type `{}`", t), ); } + if let Some(sp) = semi_span { + err.span_suggestion_short( + sp, + "consider removing this semicolon", + String::new(), + Applicability::MachineApplicable, + ); + } } }, ObligationCauseCode::IfExpression(box IfExpressionCause { then, outer, semicolon }) => { diff --git a/src/librustc_infer/lib.rs b/src/librustc_infer/lib.rs index f135bde7f83..e05041d8846 100644 --- a/src/librustc_infer/lib.rs +++ b/src/librustc_infer/lib.rs @@ -22,7 +22,6 @@ #![feature(extend_one)] #![feature(never_type)] #![feature(or_patterns)] -#![feature(range_is_empty)] #![feature(in_band_lifetimes)] #![feature(crate_visibility_modifier)] #![recursion_limit = "512"] // For rustdoc diff --git a/src/librustc_lexer/Cargo.toml b/src/librustc_lexer/Cargo.toml index 950771f0a69..28b56f6fef4 100644 --- a/src/librustc_lexer/Cargo.toml +++ b/src/librustc_lexer/Cargo.toml @@ -19,3 +19,6 @@ name = "rustc_lexer" # Note that this crate purposefully does not depend on other rustc crates [dependencies] unicode-xid = "0.2.0" + +[dev-dependencies] +expect-test = "0.1" diff --git a/src/librustc_lexer/src/lib.rs b/src/librustc_lexer/src/lib.rs index 7949a232b9b..b7d6194cd77 100644 --- a/src/librustc_lexer/src/lib.rs +++ b/src/librustc_lexer/src/lib.rs @@ -35,6 +35,7 @@ /// Parsed token. /// It doesn't contain information about data that has been parsed, /// only the type of the token and its size. +#[derive(Debug)] pub struct Token { pub kind: TokenKind, pub len: usize, @@ -51,12 +52,12 @@ fn new(kind: TokenKind, len: usize) -> Token { pub enum TokenKind { // Multi-char tokens: /// "// comment" - LineComment, + LineComment { doc_style: Option }, /// `/* block comment */` /// /// Block comments can be recursive, so the sequence like `/* /* */` /// will not be considered terminated and will result in a parsing error. - BlockComment { terminated: bool }, + BlockComment { doc_style: Option, terminated: bool }, /// Any whitespace characters sequence. Whitespace, /// "ident" or "continue" @@ -103,7 +104,7 @@ pub enum TokenKind { /// "=" Eq, /// "!" - Not, + Bang, /// "<" Lt, /// ">" @@ -129,6 +130,12 @@ pub enum TokenKind { Unknown, } +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum DocStyle { + Outer, + Inner, +} + #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum LiteralKind { /// "12_u8", "0o100", "0b120i99" @@ -188,7 +195,7 @@ pub fn strip_shebang(input: &str) -> Option { // a doc comment (due to `TokenKind::(Line,Block)Comment` ambiguity at lexer level), // then it may be valid Rust code, so consider it Rust code. let next_non_whitespace_token = tokenize(input_tail).map(|tok| tok.kind).find(|tok| - !matches!(tok, TokenKind::Whitespace | TokenKind::LineComment | TokenKind::BlockComment { .. }) + !matches!(tok, TokenKind::Whitespace | TokenKind::LineComment { .. } | TokenKind::BlockComment { .. }) ); if next_non_whitespace_token != Some(TokenKind::OpenBracket) { // No other choice than to consider this a shebang. @@ -378,7 +385,7 @@ fn advance_token(&mut self) -> Token { ':' => Colon, '$' => Dollar, '=' => Eq, - '!' => Not, + '!' => Bang, '<' => Lt, '>' => Gt, '-' => Minus, @@ -410,13 +417,32 @@ fn advance_token(&mut self) -> Token { fn line_comment(&mut self) -> TokenKind { debug_assert!(self.prev() == '/' && self.first() == '/'); self.bump(); + + let doc_style = match self.first() { + // `//!` is an inner line doc comment. + '!' => Some(DocStyle::Inner), + // `////` (more than 3 slashes) is not considered a doc comment. + '/' if self.second() != '/' => Some(DocStyle::Outer), + _ => None, + }; + self.eat_while(|c| c != '\n'); - LineComment + LineComment { doc_style } } fn block_comment(&mut self) -> TokenKind { debug_assert!(self.prev() == '/' && self.first() == '*'); self.bump(); + + let doc_style = match self.first() { + // `/*!` is an inner block doc comment. + '!' => Some(DocStyle::Inner), + // `/***` (more than 2 stars) is not considered a doc comment. + // `/**/` is not considered a doc comment. + '*' if !matches!(self.second(), '*' | '/') => Some(DocStyle::Outer), + _ => None, + }; + let mut depth = 1usize; while let Some(c) = self.bump() { match c { @@ -438,7 +464,7 @@ fn block_comment(&mut self) -> TokenKind { } } - BlockComment { terminated: depth == 0 } + BlockComment { doc_style, terminated: depth == 0 } } fn whitespace(&mut self) -> TokenKind { diff --git a/src/librustc_lexer/src/tests.rs b/src/librustc_lexer/src/tests.rs index e6acc26ec2f..a1ea5ceb1f6 100644 --- a/src/librustc_lexer/src/tests.rs +++ b/src/librustc_lexer/src/tests.rs @@ -1,137 +1,167 @@ -#[cfg(test)] -mod tests { - use crate::*; - - fn check_raw_str(s: &str, expected_hashes: u16, expected_err: Option) { - let s = &format!("r{}", s); - let mut cursor = Cursor::new(s); - cursor.bump(); - let (n_hashes, err) = cursor.raw_double_quoted_string(0); - assert_eq!(n_hashes, expected_hashes); - assert_eq!(err, expected_err); - } - - #[test] - fn test_naked_raw_str() { - check_raw_str(r#""abc""#, 0, None); - } - - #[test] - fn test_raw_no_start() { - check_raw_str(r##""abc"#"##, 0, None); - } - - #[test] - fn test_too_many_terminators() { - // this error is handled in the parser later - check_raw_str(r###"#"abc"##"###, 1, None); - } - - #[test] - fn test_unterminated() { - check_raw_str( - r#"#"abc"#, - 1, - Some(RawStrError::NoTerminator { - expected: 1, - found: 0, - possible_terminator_offset: None, - }), - ); - check_raw_str( - r###"##"abc"#"###, - 2, - Some(RawStrError::NoTerminator { - expected: 2, - found: 1, - possible_terminator_offset: Some(7), - }), - ); - // We're looking for "# not just any # - check_raw_str( - r###"##"abc#"###, - 2, - Some(RawStrError::NoTerminator { - expected: 2, - found: 0, - possible_terminator_offset: None, - }), - ) - } - - #[test] - fn test_invalid_start() { - check_raw_str(r##"#~"abc"#"##, 1, Some(RawStrError::InvalidStarter { bad_char: '~' })); - } - - #[test] - fn test_unterminated_no_pound() { - // https://github.com/rust-lang/rust/issues/70677 - check_raw_str( - r#"""#, - 0, - Some(RawStrError::NoTerminator { - expected: 0, - found: 0, - possible_terminator_offset: None, - }), - ); - } - - #[test] - fn test_valid_shebang() { - // https://github.com/rust-lang/rust/issues/70528 - let input = "#!/usr/bin/rustrun\nlet x = 5;"; - assert_eq!(strip_shebang(input), Some(18)); - } - - #[test] - fn test_invalid_shebang_valid_rust_syntax() { - // https://github.com/rust-lang/rust/issues/70528 - let input = "#! [bad_attribute]"; - assert_eq!(strip_shebang(input), None); - } - - #[test] - fn test_shebang_second_line() { - // Because shebangs are interpreted by the kernel, they must be on the first line - let input = "\n#!/bin/bash"; - assert_eq!(strip_shebang(input), None); - } - - #[test] - fn test_shebang_space() { - let input = "#! /bin/bash"; - assert_eq!(strip_shebang(input), Some(input.len())); - } - - #[test] - fn test_shebang_empty_shebang() { - let input = "#! \n[attribute(foo)]"; - assert_eq!(strip_shebang(input), None); - } - - #[test] - fn test_invalid_shebang_comment() { - let input = "#!//bin/ami/a/comment\n["; - assert_eq!(strip_shebang(input), None) - } - - #[test] - fn test_invalid_shebang_another_comment() { - let input = "#!/*bin/ami/a/comment*/\n[attribute"; - assert_eq!(strip_shebang(input), None) - } - - #[test] - fn test_shebang_valid_rust_after() { - let input = "#!/*bin/ami/a/comment*/\npub fn main() {}"; - assert_eq!(strip_shebang(input), Some(23)) - } - - #[test] - fn test_shebang_followed_by_attrib() { - let input = "#!/bin/rust-scripts\n#![allow_unused(true)]"; - assert_eq!(strip_shebang(input), Some(19)); - } +use super::*; + +use expect_test::{expect, Expect}; + +fn check_raw_str(s: &str, expected_hashes: u16, expected_err: Option) { + let s = &format!("r{}", s); + let mut cursor = Cursor::new(s); + cursor.bump(); + let (n_hashes, err) = cursor.raw_double_quoted_string(0); + assert_eq!(n_hashes, expected_hashes); + assert_eq!(err, expected_err); +} + +#[test] +fn test_naked_raw_str() { + check_raw_str(r#""abc""#, 0, None); +} + +#[test] +fn test_raw_no_start() { + check_raw_str(r##""abc"#"##, 0, None); +} + +#[test] +fn test_too_many_terminators() { + // this error is handled in the parser later + check_raw_str(r###"#"abc"##"###, 1, None); +} + +#[test] +fn test_unterminated() { + check_raw_str( + r#"#"abc"#, + 1, + Some(RawStrError::NoTerminator { expected: 1, found: 0, possible_terminator_offset: None }), + ); + check_raw_str( + r###"##"abc"#"###, + 2, + Some(RawStrError::NoTerminator { + expected: 2, + found: 1, + possible_terminator_offset: Some(7), + }), + ); + // We're looking for "# not just any # + check_raw_str( + r###"##"abc#"###, + 2, + Some(RawStrError::NoTerminator { expected: 2, found: 0, possible_terminator_offset: None }), + ) +} + +#[test] +fn test_invalid_start() { + check_raw_str(r##"#~"abc"#"##, 1, Some(RawStrError::InvalidStarter { bad_char: '~' })); +} + +#[test] +fn test_unterminated_no_pound() { + // https://github.com/rust-lang/rust/issues/70677 + check_raw_str( + r#"""#, + 0, + Some(RawStrError::NoTerminator { expected: 0, found: 0, possible_terminator_offset: None }), + ); +} + +#[test] +fn test_valid_shebang() { + // https://github.com/rust-lang/rust/issues/70528 + let input = "#!/usr/bin/rustrun\nlet x = 5;"; + assert_eq!(strip_shebang(input), Some(18)); +} + +#[test] +fn test_invalid_shebang_valid_rust_syntax() { + // https://github.com/rust-lang/rust/issues/70528 + let input = "#! [bad_attribute]"; + assert_eq!(strip_shebang(input), None); +} + +#[test] +fn test_shebang_second_line() { + // Because shebangs are interpreted by the kernel, they must be on the first line + let input = "\n#!/bin/bash"; + assert_eq!(strip_shebang(input), None); +} + +#[test] +fn test_shebang_space() { + let input = "#! /bin/bash"; + assert_eq!(strip_shebang(input), Some(input.len())); +} + +#[test] +fn test_shebang_empty_shebang() { + let input = "#! \n[attribute(foo)]"; + assert_eq!(strip_shebang(input), None); +} + +#[test] +fn test_invalid_shebang_comment() { + let input = "#!//bin/ami/a/comment\n["; + assert_eq!(strip_shebang(input), None) +} + +#[test] +fn test_invalid_shebang_another_comment() { + let input = "#!/*bin/ami/a/comment*/\n[attribute"; + assert_eq!(strip_shebang(input), None) +} + +#[test] +fn test_shebang_valid_rust_after() { + let input = "#!/*bin/ami/a/comment*/\npub fn main() {}"; + assert_eq!(strip_shebang(input), Some(23)) +} + +#[test] +fn test_shebang_followed_by_attrib() { + let input = "#!/bin/rust-scripts\n#![allow_unused(true)]"; + assert_eq!(strip_shebang(input), Some(19)); +} + +fn check_lexing(src: &str, expect: Expect) { + let actual: String = tokenize(src).map(|token| format!("{:?}\n", token)).collect(); + expect.assert_eq(&actual) +} + +#[test] +fn comment_flavors() { + check_lexing( + r" +// line +//// line as well +/// outer doc line +//! inner doc line +/* block */ +/**/ +/*** also block */ +/** outer doc block */ +/*! inner doc block */ +", + expect![[r#" + Token { kind: Whitespace, len: 1 } + Token { kind: LineComment { doc_style: None }, len: 7 } + Token { kind: Whitespace, len: 1 } + Token { kind: LineComment { doc_style: None }, len: 17 } + Token { kind: Whitespace, len: 1 } + Token { kind: LineComment { doc_style: Some(Outer) }, len: 18 } + Token { kind: Whitespace, len: 1 } + Token { kind: LineComment { doc_style: Some(Inner) }, len: 18 } + Token { kind: Whitespace, len: 1 } + Token { kind: BlockComment { doc_style: None, terminated: true }, len: 11 } + Token { kind: Whitespace, len: 1 } + Token { kind: BlockComment { doc_style: None, terminated: true }, len: 4 } + Token { kind: Whitespace, len: 1 } + Token { kind: BlockComment { doc_style: None, terminated: true }, len: 18 } + Token { kind: Whitespace, len: 1 } + Token { kind: BlockComment { doc_style: Some(Outer), terminated: true }, len: 22 } + Token { kind: Whitespace, len: 1 } + Token { kind: BlockComment { doc_style: Some(Inner), terminated: true }, len: 22 } + Token { kind: Whitespace, len: 1 } + "#]], + ) } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index b337bf0a3f9..4bcf31ef0bf 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -40,7 +40,7 @@ use rustc_hir::{HirId, HirIdSet, Node}; use rustc_middle::lint::LintDiagnosticBuilder; use rustc_middle::ty::subst::{GenericArgKind, Subst}; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, layout::LayoutError, Ty, TyCtxt}; use rustc_session::lint::FutureIncompatibleInfo; use rustc_session::Session; use rustc_span::edition::Edition; @@ -2177,11 +2177,17 @@ fn structurally_same_type_impl<'tcx>( let a_kind = &a.kind; let b_kind = &b.kind; - let compare_layouts = |a, b| -> bool { - let a_layout = &cx.layout_of(a).unwrap().layout.abi; - let b_layout = &cx.layout_of(b).unwrap().layout.abi; - debug!("{:?} == {:?} = {}", a_layout, b_layout, a_layout == b_layout); - a_layout == b_layout + let compare_layouts = |a, b| -> Result> { + debug!("compare_layouts({:?}, {:?})", a, b); + let a_layout = &cx.layout_of(a)?.layout.abi; + let b_layout = &cx.layout_of(b)?.layout.abi; + debug!( + "comparing layouts: {:?} == {:?} = {}", + a_layout, + b_layout, + a_layout == b_layout + ); + Ok(a_layout == b_layout) }; #[allow(rustc::usage_of_ty_tykind)] @@ -2196,11 +2202,19 @@ fn structurally_same_type_impl<'tcx>( let b = b.subst(cx.tcx, b_substs); debug!("Comparing {:?} and {:?}", a, b); + // We can immediately rule out these types as structurally same if + // their layouts differ. + match compare_layouts(a, b) { + Ok(false) => return false, + _ => (), // otherwise, continue onto the full, fields comparison + } + // Grab a flattened representation of all fields. let a_fields = a_def.variants.iter().flat_map(|v| v.fields.iter()); let b_fields = b_def.variants.iter().flat_map(|v| v.fields.iter()); - compare_layouts(a, b) - && a_fields.eq_by( + + // Perform a structural comparison for each field. + a_fields.eq_by( b_fields, |&ty::FieldDef { did: a_did, .. }, &ty::FieldDef { did: b_did, .. }| { @@ -2287,13 +2301,13 @@ fn structurally_same_type_impl<'tcx>( if let Some(ty) = crate::types::repr_nullable_ptr(cx, adt, ckind) { ty == primitive } else { - compare_layouts(a, b) + compare_layouts(a, b).unwrap_or(false) } } // Otherwise, just compare the layouts. This may fail to lint for some // incompatible types, but at the very least, will stop reads into // uninitialised memory. - _ => compare_layouts(a, b), + _ => compare_layouts(a, b).unwrap_or(false), } }) } diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index 21b8080714c..25c0b40c495 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -151,6 +151,12 @@ fn main() { continue; } + // Include path contains host directory, replace it with target + if is_crossed && flag.starts_with("-I") { + cfg.flag(&flag.replace(&host, &target)); + continue; + } + cfg.flag(flag); } @@ -189,6 +195,9 @@ fn main() { if !is_crossed { cmd.arg("--system-libs"); + } else if target.contains("windows-gnu") { + println!("cargo:rustc-link-lib=shell32"); + println!("cargo:rustc-link-lib=uuid"); } cmd.args(&components); diff --git a/src/librustc_metadata/dynamic_lib.rs b/src/librustc_metadata/dynamic_lib.rs index ce19240a009..bdb53e3f75a 100644 --- a/src/librustc_metadata/dynamic_lib.rs +++ b/src/librustc_metadata/dynamic_lib.rs @@ -51,51 +51,90 @@ pub unsafe fn symbol(&self, symbol: &str) -> Result<*mut T, String> { #[cfg(unix)] mod dl { - use std::ffi::{CStr, CString, OsStr}; + use std::ffi::{CString, OsStr}; use std::os::unix::prelude::*; - use std::ptr; - use std::str; - pub(super) fn open(filename: &OsStr) -> Result<*mut u8, String> { - check_for_errors_in(|| unsafe { - let s = CString::new(filename.as_bytes()).unwrap(); - libc::dlopen(s.as_ptr(), libc::RTLD_LAZY) as *mut u8 - }) - } + // As of the 2017 revision of the POSIX standard (IEEE 1003.1-2017), it is + // implementation-defined whether `dlerror` is thread-safe (in which case it returns the most + // recent error in the calling thread) or not thread-safe (in which case it returns the most + // recent error in *any* thread). + // + // There's no easy way to tell what strategy is used by a given POSIX implementation, so we + // lock around all calls that can modify `dlerror` in this module lest we accidentally read an + // error from a different thread. This is bulletproof when we are the *only* code using the + // dynamic library APIs at a given point in time. However, it's still possible for us to race + // with other code (see #74469) on platforms where `dlerror` is not thread-safe. + mod error { + use std::ffi::CStr; + use std::lazy::SyncLazy; + use std::sync::{Mutex, MutexGuard}; + + pub fn lock() -> MutexGuard<'static, Guard> { + static LOCK: SyncLazy> = SyncLazy::new(|| Mutex::new(Guard { _priv: () })); + LOCK.lock().unwrap() + } - fn check_for_errors_in(f: F) -> Result - where - F: FnOnce() -> T, - { - use std::sync::{Mutex, Once}; - static INIT: Once = Once::new(); - static mut LOCK: *mut Mutex<()> = ptr::null_mut(); - unsafe { - INIT.call_once(|| { - LOCK = Box::into_raw(Box::new(Mutex::new(()))); - }); - // dlerror isn't thread safe, so we need to lock around this entire - // sequence - let _guard = (*LOCK).lock(); - let _old_error = libc::dlerror(); - - let result = f(); - - let last_error = libc::dlerror() as *const _; - if ptr::null() == last_error { - Ok(result) - } else { - let s = CStr::from_ptr(last_error).to_bytes(); - Err(str::from_utf8(s).unwrap().to_owned()) + pub struct Guard { + _priv: (), + } + + impl Guard { + pub fn get(&mut self) -> Result<(), String> { + let msg = unsafe { libc::dlerror() }; + if msg.is_null() { + Ok(()) + } else { + let msg = unsafe { CStr::from_ptr(msg as *const _) }; + Err(msg.to_string_lossy().into_owned()) + } + } + + pub fn clear(&mut self) { + let _ = unsafe { libc::dlerror() }; } } } + pub(super) fn open(filename: &OsStr) -> Result<*mut u8, String> { + let s = CString::new(filename.as_bytes()).unwrap(); + + let mut dlerror = error::lock(); + let ret = unsafe { libc::dlopen(s.as_ptr(), libc::RTLD_LAZY | libc::RTLD_LOCAL) }; + + if !ret.is_null() { + return Ok(ret.cast()); + } + + // A NULL return from `dlopen` indicates that an error has definitely occurred, so if + // nothing is in `dlerror`, we are racing with another thread that has stolen our error + // message. See the explanation on the `dl::error` module for more information. + dlerror.get().and_then(|()| Err("Unknown error".to_string())) + } + pub(super) unsafe fn symbol( handle: *mut u8, symbol: *const libc::c_char, ) -> Result<*mut u8, String> { - check_for_errors_in(|| libc::dlsym(handle as *mut libc::c_void, symbol) as *mut u8) + let mut dlerror = error::lock(); + + // Unlike `dlopen`, it's possible for `dlsym` to return NULL without overwriting `dlerror`. + // Because of this, we clear `dlerror` before calling `dlsym` to avoid picking up a stale + // error message by accident. + dlerror.clear(); + + let ret = libc::dlsym(handle as *mut libc::c_void, symbol); + + if !ret.is_null() { + return Ok(ret.cast()); + } + + // If `dlsym` returns NULL but there is nothing in `dlerror` it means one of two things: + // - We tried to load a symbol mapped to address 0. This is not technically an error but is + // unlikely to occur in practice and equally unlikely to be handled correctly by calling + // code. Therefore we treat it as an error anyway. + // - An error has occurred, but we are racing with another thread that has stolen our error + // message. See the explanation on the `dl::error` module for more information. + dlerror.get().and_then(|()| Err("Tried to load symbol mapped to address 0".to_string())) } pub(super) unsafe fn close(handle: *mut u8) { diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index e50fa34554d..85490f5f6e9 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -5,6 +5,7 @@ #![feature(drain_filter)] #![feature(in_band_lifetimes)] #![feature(nll)] +#![feature(once_cell)] #![feature(or_patterns)] #![feature(proc_macro_internals)] #![feature(min_specialization)] diff --git a/src/librustc_metadata/rmeta/decoder.rs b/src/librustc_metadata/rmeta/decoder.rs index 10f5b671748..43d76e9fdb4 100644 --- a/src/librustc_metadata/rmeta/decoder.rs +++ b/src/librustc_metadata/rmeta/decoder.rs @@ -16,7 +16,6 @@ use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; -use rustc_hir::definitions::DefPathTable; use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash}; use rustc_hir::lang_items; use rustc_index::vec::{Idx, IndexVec}; @@ -29,7 +28,6 @@ use rustc_middle::mir::{self, Body, Promoted}; use rustc_middle::ty::codec::TyDecoder; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_middle::util::common::record_time; use rustc_serialize::{opaque, Decodable, Decoder}; use rustc_session::Session; use rustc_span::hygiene::ExpnDataDecodeMode; @@ -69,12 +67,6 @@ /// universal (`for<'tcx>`), that is paired up with whichever `TyCtxt` /// is being used to decode those values. root: CrateRoot<'static>, - /// For each definition in this crate, we encode a key. When the - /// crate is loaded, we read all the keys and put them in this - /// hashmap, which gives the reverse mapping. This allows us to - /// quickly retrace a `DefPath`, which is needed for incremental - /// compilation support. - def_path_table: DefPathTable, /// Trait impl data. /// FIXME: Used only from queries and can use query cache, /// so pre-decoding can probably be avoided. @@ -91,6 +83,10 @@ /// Do not access the value directly, as it might not have been initialized yet. /// The field must always be initialized to `DepNodeIndex::INVALID`. dep_node_index: AtomicCell, + /// Caches decoded `DefKey`s. + def_key_cache: Lock>, + /// Caches decoded `DefPathHash`es. + def_path_hash_cache: Lock>, // --- Other significant crate properties --- /// ID of this crate, from the current compilation session's point of view. @@ -807,7 +803,7 @@ fn get_trait_def(&self, item_id: DefIndex, sess: &Session) -> ty::TraitDef { data.has_auto_impl, data.is_marker, data.specialization_kind, - self.def_path_table.def_path_hash(item_id), + self.def_path_hash(item_id), ) } EntryKind::TraitAlias => ty::TraitDef::new( @@ -817,7 +813,7 @@ fn get_trait_def(&self, item_id: DefIndex, sess: &Session) -> ty::TraitDef { false, false, ty::trait_def::TraitSpecializationKind::None, - self.def_path_table.def_path_hash(item_id), + self.def_path_hash(item_id), ), _ => bug!("def-index does not refer to trait or trait alias"), } @@ -1509,12 +1505,14 @@ fn fn_sig(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> { #[inline] fn def_key(&self, index: DefIndex) -> DefKey { - let mut key = self.def_path_table.def_key(index); - if self.is_proc_macro(index) { - let name = self.raw_proc_macro(index).name(); - key.disambiguated_data.data = DefPathData::MacroNs(Symbol::intern(name)); - } - key + *self.def_key_cache.lock().entry(index).or_insert_with(|| { + let mut key = self.root.tables.def_keys.get(self, index).unwrap().decode(self); + if self.is_proc_macro(index) { + let name = self.raw_proc_macro(index).name(); + key.disambiguated_data.data = DefPathData::MacroNs(Symbol::intern(name)); + } + key + }) } // Returns the path leading to the thing with this `id`. @@ -1523,6 +1521,57 @@ fn def_path(&self, id: DefIndex) -> DefPath { DefPath::make(self.cnum, id, |parent| self.def_key(parent)) } + fn def_path_hash_unlocked( + &self, + index: DefIndex, + def_path_hashes: &mut FxHashMap, + ) -> DefPathHash { + *def_path_hashes.entry(index).or_insert_with(|| { + self.root.tables.def_path_hashes.get(self, index).unwrap().decode(self) + }) + } + + #[inline] + fn def_path_hash(&self, index: DefIndex) -> DefPathHash { + let mut def_path_hashes = self.def_path_hash_cache.lock(); + self.def_path_hash_unlocked(index, &mut def_path_hashes) + } + + fn all_def_path_hashes_and_def_ids(&self) -> Vec<(DefPathHash, DefId)> { + let mut def_path_hashes = self.def_path_hash_cache.lock(); + (0..self.num_def_ids()) + .map(|index| { + let index = DefIndex::from_usize(index); + (self.def_path_hash_unlocked(index, &mut def_path_hashes), self.local_def_id(index)) + }) + .collect() + } + + /// Get the `DepNodeIndex` corresponding this crate. The result of this + /// method is cached in the `dep_node_index` field. + fn get_crate_dep_node_index(&self, tcx: TyCtxt<'tcx>) -> DepNodeIndex { + let mut dep_node_index = self.dep_node_index.load(); + + if unlikely!(dep_node_index == DepNodeIndex::INVALID) { + // We have not cached the DepNodeIndex for this upstream crate yet, + // so use the dep-graph to find it out and cache it. + // Note that multiple threads can enter this block concurrently. + // That is fine because the DepNodeIndex remains constant + // throughout the whole compilation session, and multiple stores + // would always write the same value. + + let def_path_hash = self.def_path_hash(CRATE_DEF_INDEX); + let dep_node = + DepNode::from_def_path_hash(def_path_hash, dep_graph::DepKind::CrateMetadata); + + dep_node_index = tcx.dep_graph.dep_node_index_of(&dep_node); + assert!(dep_node_index != DepNodeIndex::INVALID); + self.dep_node_index.store(dep_node_index); + } + + dep_node_index + } + /// Imports the source_map from an external crate into the source_map of the crate /// currently being compiled (the "local crate"). /// @@ -1723,9 +1772,6 @@ impl CrateMetadata { private_dep: bool, host_hash: Option, ) -> CrateMetadata { - let def_path_table = record_time(&sess.perf_stats.decode_def_path_tables_time, || { - root.def_path_table.decode((&blob, sess)) - }); let trait_impls = root .impls .decode((&blob, sess)) @@ -1737,7 +1783,6 @@ impl CrateMetadata { CrateMetadata { blob, root, - def_path_table, trait_impls, raw_proc_macros, source_map_import_info: OnceCell::new(), @@ -1752,6 +1797,8 @@ impl CrateMetadata { host_hash, extern_crate: Lock::new(None), hygiene_context: Default::default(), + def_key_cache: Default::default(), + def_path_hash_cache: Default::default(), } } @@ -1828,6 +1875,10 @@ impl CrateMetadata { self.root.hash } + fn num_def_ids(&self) -> usize { + self.root.tables.def_keys.size() + } + fn local_def_id(&self, index: DefIndex) -> DefId { DefId { krate: self.cnum, index } } @@ -1843,36 +1894,6 @@ fn reverse_translate_def_id(&self, did: DefId) -> Option { None } - - #[inline] - fn def_path_hash(&self, index: DefIndex) -> DefPathHash { - self.def_path_table.def_path_hash(index) - } - - /// Get the `DepNodeIndex` corresponding this crate. The result of this - /// method is cached in the `dep_node_index` field. - fn get_crate_dep_node_index(&self, tcx: TyCtxt<'tcx>) -> DepNodeIndex { - let mut dep_node_index = self.dep_node_index.load(); - - if unlikely!(dep_node_index == DepNodeIndex::INVALID) { - // We have not cached the DepNodeIndex for this upstream crate yet, - // so use the dep-graph to find it out and cache it. - // Note that multiple threads can enter this block concurrently. - // That is fine because the DepNodeIndex remains constant - // throughout the whole compilation session, and multiple stores - // would always write the same value. - - let def_path_hash = self.def_path_hash(CRATE_DEF_INDEX); - let dep_node = - DepNode::from_def_path_hash(def_path_hash, dep_graph::DepKind::CrateMetadata); - - dep_node_index = tcx.dep_graph.dep_node_index_of(&dep_node); - assert!(dep_node_index != DepNodeIndex::INVALID); - self.dep_node_index.store(dep_node_index); - } - - dep_node_index - } } // Cannot be implemented on 'ProcMacro', as libproc_macro diff --git a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs index 50c2ad8148a..36ff65fc5eb 100644 --- a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs +++ b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs @@ -9,7 +9,6 @@ use rustc_data_structures::svh::Svh; use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, CRATE_DEF_INDEX, LOCAL_CRATE}; -use rustc_hir::definitions::DefPathTable; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; use rustc_middle::hir::exports::Export; use rustc_middle::middle::cstore::{CrateSource, CrateStore, EncodedMetadata}; @@ -486,8 +485,12 @@ fn def_path_hash(&self, def: DefId) -> DefPathHash { self.get_crate_data(def.krate).def_path_hash(def.index) } - fn def_path_table(&self, cnum: CrateNum) -> &DefPathTable { - &self.get_crate_data(cnum).cdata.def_path_table + fn all_def_path_hashes_and_def_ids(&self, cnum: CrateNum) -> Vec<(DefPathHash, DefId)> { + self.get_crate_data(cnum).all_def_path_hashes_and_def_ids() + } + + fn num_def_ids(&self, cnum: CrateNum) -> usize { + self.get_crate_data(cnum).num_def_ids() } fn crates_untracked(&self) -> Vec { diff --git a/src/librustc_metadata/rmeta/encoder.rs b/src/librustc_metadata/rmeta/encoder.rs index 78abf341e33..509ef1caf1a 100644 --- a/src/librustc_metadata/rmeta/encoder.rs +++ b/src/librustc_metadata/rmeta/encoder.rs @@ -9,7 +9,6 @@ use rustc_hir as hir; use rustc_hir::def::CtorKind; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; -use rustc_hir::definitions::DefPathTable; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::itemlikevisit::{ItemLikeVisitor, ParItemLikeVisitor}; use rustc_hir::lang_items; @@ -418,9 +417,14 @@ fn encode_info_for_items(&mut self) { } } - fn encode_def_path_table(&mut self) -> Lazy { - let definitions = self.tcx.hir().definitions(); - self.lazy(definitions.def_path_table()) + fn encode_def_path_table(&mut self) { + let table = self.tcx.hir().definitions().def_path_table(); + for (def_index, def_key, def_path_hash) in table.enumerated_keys_and_path_hashes() { + let def_key = self.lazy(def_key); + let def_path_hash = self.lazy(def_path_hash); + self.tables.def_keys.set(def_index, def_key); + self.tables.def_path_hashes.set(def_index, def_path_hash); + } } fn encode_source_map(&mut self) -> Lazy<[rustc_span::SourceFile]> { @@ -525,7 +529,7 @@ fn encode_crate_root(&mut self) -> Lazy> { // Encode DefPathTable i = self.position(); - let def_path_table = self.encode_def_path_table(); + self.encode_def_path_table(); let def_path_table_bytes = self.position() - i; // Encode the def IDs of impls, for coherence checking. @@ -642,7 +646,6 @@ fn encode_crate_root(&mut self) -> Lazy> { native_libraries, foreign_modules, source_map, - def_path_table, impls, exported_symbols, interpret_alloc_index, diff --git a/src/librustc_metadata/rmeta/mod.rs b/src/librustc_metadata/rmeta/mod.rs index ac1ac360701..1ba5962d119 100644 --- a/src/librustc_metadata/rmeta/mod.rs +++ b/src/librustc_metadata/rmeta/mod.rs @@ -7,7 +7,8 @@ use rustc_data_structures::sync::MetadataRef; use rustc_hir as hir; use rustc_hir::def::CtorKind; -use rustc_hir::def_id::{DefId, DefIndex}; +use rustc_hir::def_id::{DefId, DefIndex, DefPathHash}; +use rustc_hir::definitions::DefKey; use rustc_hir::lang_items; use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec}; use rustc_middle::hir::exports::Export; @@ -195,7 +196,6 @@ macro_rules! Lazy { diagnostic_items: Lazy<[(Symbol, DefIndex)]>, native_libraries: Lazy<[NativeLib]>, foreign_modules: Lazy<[ForeignModule]>, - def_path_table: Lazy, impls: Lazy<[TraitImpls]>, interpret_alloc_index: Lazy<[u32]>, @@ -285,6 +285,12 @@ fn encode(&self, buf: &mut Encoder) -> LazyTables<'tcx> { mir: Table)>, promoted_mir: Table>)>, unused_generic_params: Table>>, + // `def_keys` and `def_path_hashes` represent a lazy version of a + // `DefPathTable`. This allows us to avoid deserializing an entire + // `DefPathTable` up front, since we may only ever use a few + // definitions from any given crate. + def_keys: Table>, + def_path_hashes: Table> } #[derive(Copy, Clone, MetadataEncodable, MetadataDecodable)] diff --git a/src/librustc_metadata/rmeta/table.rs b/src/librustc_metadata/rmeta/table.rs index 28858e146e4..03bd4170ea9 100644 --- a/src/librustc_metadata/rmeta/table.rs +++ b/src/librustc_metadata/rmeta/table.rs @@ -201,4 +201,9 @@ pub(super) fn get<'a, 'tcx, M: Metadata<'a, 'tcx>>(&self, metadata: M, i: I) -> let bytes = &metadata.raw_bytes()[start..start + self.meta]; >::maybe_read_from_bytes_at(bytes, i.index())? } + + /// Size of the table in entries, including possible gaps. + pub(super) fn size(&self) -> usize { + self.meta / >::BYTE_LEN + } } diff --git a/src/librustc_middle/hir/map/mod.rs b/src/librustc_middle/hir/map/mod.rs index a6cc7cbc920..1e57411f9c5 100644 --- a/src/librustc_middle/hir/map/mod.rs +++ b/src/librustc_middle/hir/map/mod.rs @@ -828,13 +828,24 @@ pub fn attrs(&self, id: HirId) -> &'hir [ast::Attribute] { attrs.unwrap_or(&[]) } + /// Gets the span of the definition of the specified HIR node. + /// This is used by `tcx.get_span` pub fn span(&self, hir_id: HirId) -> Span { match self.find_entry(hir_id).map(|entry| entry.node) { Some(Node::Param(param)) => param.span, - Some(Node::Item(item)) => item.span, + Some(Node::Item(item)) => match &item.kind { + ItemKind::Fn(sig, _, _) => sig.span, + _ => item.span, + }, Some(Node::ForeignItem(foreign_item)) => foreign_item.span, - Some(Node::TraitItem(trait_method)) => trait_method.span, - Some(Node::ImplItem(impl_item)) => impl_item.span, + Some(Node::TraitItem(trait_item)) => match &trait_item.kind { + TraitItemKind::Fn(sig, _) => sig.span, + _ => trait_item.span, + }, + Some(Node::ImplItem(impl_item)) => match &impl_item.kind { + ImplItemKind::Fn(sig, _) => sig.span, + _ => impl_item.span, + }, Some(Node::Variant(variant)) => variant.span, Some(Node::Field(field)) => field.span, Some(Node::AnonConst(constant)) => self.body(constant.body).value.span, @@ -866,6 +877,18 @@ pub fn span(&self, hir_id: HirId) -> Span { } } + /// Like `hir.span()`, but includes the body of function items + /// (instead of just the function header) + pub fn span_with_body(&self, hir_id: HirId) -> Span { + match self.find_entry(hir_id).map(|entry| entry.node) { + Some(Node::TraitItem(item)) => item.span, + Some(Node::ImplItem(impl_item)) => impl_item.span, + Some(Node::Item(item)) => item.span, + Some(_) => self.span(hir_id), + _ => bug!("hir::map::Map::span_with_body: id not in map: {:?}", hir_id), + } + } + pub fn span_if_local(&self, id: DefId) -> Option { id.as_local().map(|id| self.span(self.local_def_id_to_hir_id(id))) } diff --git a/src/librustc_middle/lib.rs b/src/librustc_middle/lib.rs index ec1dcd29ef2..1b2dea8a378 100644 --- a/src/librustc_middle/lib.rs +++ b/src/librustc_middle/lib.rs @@ -40,7 +40,6 @@ #![feature(nll)] #![feature(option_expect_none)] #![feature(or_patterns)] -#![feature(range_is_empty)] #![feature(min_specialization)] #![feature(trusted_len)] #![feature(stmt_expr_attributes)] diff --git a/src/librustc_middle/middle/cstore.rs b/src/librustc_middle/middle/cstore.rs index 6759ad61d3a..1af1d581817 100644 --- a/src/librustc_middle/middle/cstore.rs +++ b/src/librustc_middle/middle/cstore.rs @@ -9,7 +9,7 @@ use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{self, MetadataRef}; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; -use rustc_hir::definitions::{DefKey, DefPath, DefPathHash, DefPathTable}; +use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; use rustc_macros::HashStable; use rustc_session::search_paths::PathKind; use rustc_session::utils::NativeLibKind; @@ -187,7 +187,8 @@ pub trait CrateStore { fn def_key(&self, def: DefId) -> DefKey; fn def_path(&self, def: DefId) -> DefPath; fn def_path_hash(&self, def: DefId) -> DefPathHash; - fn def_path_table(&self, cnum: CrateNum) -> &DefPathTable; + fn all_def_path_hashes_and_def_ids(&self, cnum: CrateNum) -> Vec<(DefPathHash, DefId)>; + fn num_def_ids(&self, cnum: CrateNum) -> usize; // "queries" used in resolve that aren't tracked for incremental compilation fn crate_name_untracked(&self, cnum: CrateNum) -> Symbol; diff --git a/src/librustc_middle/middle/lang_items.rs b/src/librustc_middle/middle/lang_items.rs index 70c90198276..3e1caa3b549 100644 --- a/src/librustc_middle/middle/lang_items.rs +++ b/src/librustc_middle/middle/lang_items.rs @@ -53,7 +53,7 @@ pub fn required(tcx: TyCtxt<'_>, lang_item: LangItem) -> bool { // symbols. Other panic runtimes ensure that the relevant symbols are // available to link things together, but they're never exercised. match tcx.sess.panic_strategy() { - PanicStrategy::Abort => lang_item != LangItem::EhPersonalityLangItem, + PanicStrategy::Abort => lang_item != LangItem::EhPersonality, PanicStrategy::Unwind => true, } } diff --git a/src/librustc_middle/mir/interpret/mod.rs b/src/librustc_middle/mir/interpret/mod.rs index fb7269f648f..0dc3d6e344a 100644 --- a/src/librustc_middle/mir/interpret/mod.rs +++ b/src/librustc_middle/mir/interpret/mod.rs @@ -143,6 +143,17 @@ pub struct GlobalId<'tcx> { pub promoted: Option, } +impl GlobalId<'tcx> { + pub fn display(self, tcx: TyCtxt<'tcx>) -> String { + let instance_name = tcx.def_path_str(self.instance.def.def_id()); + if let Some(promoted) = self.promoted { + format!("{}::{:?}", instance_name, promoted) + } else { + instance_name + } + } +} + /// Input argument for `tcx.lit_to_const`. #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, HashStable)] pub struct LitToConstInput<'tcx> { diff --git a/src/librustc_middle/mir/mod.rs b/src/librustc_middle/mir/mod.rs index 9cce8ee2c5d..7ac7d9b23f1 100644 --- a/src/librustc_middle/mir/mod.rs +++ b/src/librustc_middle/mir/mod.rs @@ -73,15 +73,35 @@ fn local_decls(&self) -> &LocalDecls<'tcx> { /// The various "big phases" that MIR goes through. /// +/// These phases all describe dialects of MIR. Since all MIR uses the same datastructures, the +/// dialects forbid certain variants or values in certain phases. +/// +/// Note: Each phase's validation checks all invariants of the *previous* phases' dialects. A phase +/// that changes the dialect documents what invariants must be upheld *after* that phase finishes. +/// /// Warning: ordering of variants is significant. #[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)] #[derive(HashStable)] pub enum MirPhase { Build = 0, + // FIXME(oli-obk): it's unclear whether we still need this phase (and its corresponding query). + // We used to have this for pre-miri MIR based const eval. Const = 1, - Validated = 2, - DropElab = 3, - Optimized = 4, + /// This phase checks the MIR for promotable elements and takes them out of the main MIR body + /// by creating a new MIR body per promoted element. After this phase (and thus the termination + /// of the `mir_promoted` query), these promoted elements are available in the `promoted_mir` + /// query. + ConstPromotion = 2, + /// After this phase + /// * the only `AggregateKind`s allowed are `Array` and `Generator`, + /// * `DropAndReplace` is gone for good + /// * `Drop` now uses explicit drop flags visible in the MIR and reaching a `Drop` terminator + /// means that the auto-generated drop glue will be invoked. + DropLowering = 3, + /// After this phase, generators are explicit state machines (no more `Yield`). + /// `AggregateKind::Generator` is gone for good. + GeneratorLowering = 4, + Optimization = 5, } impl MirPhase { @@ -1544,10 +1564,10 @@ pub enum ProjectionElem { /// ``` ConstantIndex { /// index or -index (in Python terms), depending on from_end - offset: u32, + offset: u64, /// The thing being indexed must be at least this long. For arrays this /// is always the exact length. - min_length: u32, + min_length: u64, /// Counting backwards from end? This is always false when indexing an /// array. from_end: bool, @@ -1558,8 +1578,8 @@ pub enum ProjectionElem { /// If `from_end` is true `slice[from..slice.len() - to]`. /// Otherwise `array[from..to]`. Subslice { - from: u32, - to: u32, + from: u64, + to: u64, /// Whether `to` counts from the start or end of the array/slice. /// For `PlaceElem`s this is `true` if and only if the base is a slice. /// For `ProjectionKind`, this can also be `true` for arrays. @@ -1596,7 +1616,7 @@ fn is_indirect(&self) -> bool { // At least on 64 bit systems, `PlaceElem` should not be larger than two pointers. #[cfg(target_arch = "x86_64")] -static_assert_size!(PlaceElem<'_>, 16); +static_assert_size!(PlaceElem<'_>, 24); /// Alias for projections as they appear in `UserTypeProjection`, where we /// need neither the `V` parameter for `Index` nor the `T` for `Field`. @@ -2310,7 +2330,7 @@ pub fn index(self) -> Self { self.map_projections(|pat_ty_proj| pat_ty_proj.index()) } - pub fn subslice(self, from: u32, to: u32) -> Self { + pub fn subslice(self, from: u64, to: u64) -> Self { self.map_projections(|pat_ty_proj| pat_ty_proj.subslice(from, to)) } @@ -2356,7 +2376,7 @@ pub(crate) fn index(mut self) -> Self { self } - pub(crate) fn subslice(mut self, from: u32, to: u32) -> Self { + pub(crate) fn subslice(mut self, from: u64, to: u64) -> Self { self.projs.push(ProjectionElem::Subslice { from, to, from_end: true }); self } @@ -2432,7 +2452,10 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { impl<'tcx> Display for Constant<'tcx> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { - write!(fmt, "const ")?; + match self.literal.ty.kind { + ty::FnDef(..) => {} + _ => write!(fmt, "const ")?, + } pretty_print_const(self.literal, fmt, true) } } diff --git a/src/librustc_middle/mir/terminator/mod.rs b/src/librustc_middle/mir/terminator/mod.rs index e8fe3a97a10..fcfd648c2b7 100644 --- a/src/librustc_middle/mir/terminator/mod.rs +++ b/src/librustc_middle/mir/terminator/mod.rs @@ -103,7 +103,7 @@ pub enum TerminatorKind<'tcx> { unwind: Option, }, - /// Block ends with a call of a converging function. + /// Block ends with a call of a function. Call { /// The function that’s being called. func: Operand<'tcx>, diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs index d874edf6274..d6836d2ee36 100644 --- a/src/librustc_middle/query/mod.rs +++ b/src/librustc_middle/query/mod.rs @@ -247,7 +247,7 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String { desc { |tcx| "elaborating drops for `{}`", tcx.def_path_str(key.did.to_def_id()) } } - query mir_validated(key: ty::WithOptConstParam) -> + query mir_promoted(key: ty::WithOptConstParam) -> ( &'tcx Steal>, &'tcx Steal>> @@ -281,6 +281,11 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String { cache_on_disk_if { key.is_local() } } + /// The `DefId` is the `DefId` of the containing MIR body. Promoteds do not have their own + /// `DefId`. This function returns all promoteds in the specified body. The body references + /// promoteds by the `DefId` and the `mir::Promoted` index. This is necessary, because + /// after inlining a body may refer to promoteds from other bodies. In that case you still + /// need to use the `DefId` of the original body. query promoted_mir(key: DefId) -> &'tcx IndexVec> { desc { |tcx| "optimizing promoted MIR for `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } @@ -679,7 +684,7 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String { -> ConstEvalRawResult<'tcx> { desc { |tcx| "const-evaluating `{}`", - tcx.def_path_str(key.value.instance.def.def_id()) + key.value.display(tcx) } } @@ -695,7 +700,7 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String { -> ConstEvalResult<'tcx> { desc { |tcx| "const-evaluating + checking `{}`", - tcx.def_path_str(key.value.instance.def.def_id()) + key.value.display(tcx) } cache_on_disk_if(_, opt_result) { // Only store results without errors diff --git a/src/librustc_middle/traits/mod.rs b/src/librustc_middle/traits/mod.rs index ea9c8b7a415..f86403fa502 100644 --- a/src/librustc_middle/traits/mod.rs +++ b/src/librustc_middle/traits/mod.rs @@ -345,6 +345,7 @@ pub fn peel_derives(&self) -> &Self { #[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)] pub struct MatchExpressionArmCause<'tcx> { pub arm_span: Span, + pub semi_span: Option, pub source: hir::MatchSource, pub prior_arms: Vec, pub last_ty: Ty<'tcx>, diff --git a/src/librustc_middle/ty/adjustment.rs b/src/librustc_middle/ty/adjustment.rs index 0ab07aea426..6a9bb8d6c28 100644 --- a/src/librustc_middle/ty/adjustment.rs +++ b/src/librustc_middle/ty/adjustment.rs @@ -2,7 +2,7 @@ use crate::ty::{self, Ty, TyCtxt}; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_hir::lang_items::{DerefMutTraitLangItem, DerefTraitLangItem}; +use rustc_hir::lang_items::LangItem; use rustc_macros::HashStable; #[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)] @@ -118,8 +118,8 @@ pub struct OverloadedDeref<'tcx> { impl<'tcx> OverloadedDeref<'tcx> { pub fn method_call(&self, tcx: TyCtxt<'tcx>, source: Ty<'tcx>) -> (DefId, SubstsRef<'tcx>) { let trait_def_id = match self.mutbl { - hir::Mutability::Not => tcx.require_lang_item(DerefTraitLangItem, None), - hir::Mutability::Mut => tcx.require_lang_item(DerefMutTraitLangItem, None), + hir::Mutability::Not => tcx.require_lang_item(LangItem::Deref, None), + hir::Mutability::Mut => tcx.require_lang_item(LangItem::DerefMut, None), }; let method_def_id = tcx .associated_items(trait_def_id) diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index e6b05fe4094..18ae744cb1e 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -40,7 +40,7 @@ use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; use rustc_hir::definitions::{DefPathHash, Definitions}; use rustc_hir::intravisit::Visitor; -use rustc_hir::lang_items::{self, PanicLocationLangItem}; +use rustc_hir::lang_items::LangItem; use rustc_hir::{HirId, ItemKind, ItemLocalId, ItemLocalMap, ItemLocalSet, Node, TraitCandidate}; use rustc_index::vec::{Idx, IndexVec}; use rustc_macros::HashStable; @@ -1102,20 +1102,13 @@ pub fn create_global_ctxt( providers[LOCAL_CRATE] = local_providers; let def_path_hash_to_def_id = if s.opts.build_dep_graph() { - let def_path_tables = crates - .iter() - .map(|&cnum| (cnum, cstore.def_path_table(cnum))) - .chain(iter::once((LOCAL_CRATE, definitions.def_path_table()))); + let capacity = definitions.def_path_table().num_def_ids() + + crates.iter().map(|cnum| cstore.num_def_ids(*cnum)).sum::(); + let mut map = FxHashMap::with_capacity_and_hasher(capacity, Default::default()); - // Precompute the capacity of the hashmap so we don't have to - // re-allocate when populating it. - let capacity = def_path_tables.clone().map(|(_, t)| t.size()).sum::(); - - let mut map: FxHashMap<_, _> = - FxHashMap::with_capacity_and_hasher(capacity, ::std::default::Default::default()); - - for (cnum, def_path_table) in def_path_tables { - def_path_table.add_def_path_hashes_to(cnum, &mut map); + map.extend(definitions.def_path_table().all_def_path_hashes_and_def_ids(LOCAL_CRATE)); + for cnum in &crates { + map.extend(cstore.all_def_path_hashes_and_def_ids(*cnum).into_iter()); } Some(map) @@ -1545,7 +1538,7 @@ pub fn has_strict_asm_symbol_naming(&self) -> bool { pub fn caller_location_ty(&self) -> Ty<'tcx> { self.mk_imm_ref( self.lifetimes.re_static, - self.type_of(self.require_lang_item(PanicLocationLangItem, None)) + self.type_of(self.require_lang_item(LangItem::PanicLocation, None)) .subst(*self, self.mk_substs([self.lifetimes.re_static.into()].iter())), ) } @@ -2192,12 +2185,12 @@ fn mk_generic_adt(self, wrapper_def_id: DefId, ty_param: Ty<'tcx>) -> Ty<'tcx> { #[inline] pub fn mk_box(self, ty: Ty<'tcx>) -> Ty<'tcx> { - let def_id = self.require_lang_item(lang_items::OwnedBoxLangItem, None); + let def_id = self.require_lang_item(LangItem::OwnedBox, None); self.mk_generic_adt(def_id, ty) } #[inline] - pub fn mk_lang_item(self, ty: Ty<'tcx>, item: lang_items::LangItem) -> Option> { + pub fn mk_lang_item(self, ty: Ty<'tcx>, item: LangItem) -> Option> { let def_id = self.lang_items().require(item).ok()?; Some(self.mk_generic_adt(def_id, ty)) } @@ -2210,7 +2203,7 @@ pub fn mk_diagnostic_item(self, ty: Ty<'tcx>, name: Symbol) -> Option> #[inline] pub fn mk_maybe_uninit(self, ty: Ty<'tcx>) -> Ty<'tcx> { - let def_id = self.require_lang_item(lang_items::MaybeUninitLangItem, None); + let def_id = self.require_lang_item(LangItem::MaybeUninit, None); self.mk_generic_adt(def_id, ty) } diff --git a/src/librustc_middle/ty/instance.rs b/src/librustc_middle/ty/instance.rs index e6dafd4965b..8e08fe4b87b 100644 --- a/src/librustc_middle/ty/instance.rs +++ b/src/librustc_middle/ty/instance.rs @@ -5,7 +5,7 @@ use rustc_errors::ErrorReported; use rustc_hir::def::Namespace; use rustc_hir::def_id::{CrateNum, DefId}; -use rustc_hir::lang_items::{DropInPlaceFnLangItem, FnOnceTraitLangItem}; +use rustc_hir::lang_items::LangItem; use rustc_macros::HashStable; use std::fmt; @@ -408,7 +408,7 @@ pub fn resolve_closure( } pub fn resolve_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> { - let def_id = tcx.require_lang_item(DropInPlaceFnLangItem, None); + let def_id = tcx.require_lang_item(LangItem::DropInPlace, None); let substs = tcx.intern_substs(&[ty.into()]); Instance::resolve(tcx, ty::ParamEnv::reveal_all(), def_id, substs).unwrap().unwrap() } @@ -419,7 +419,7 @@ pub fn fn_once_adapter_instance( substs: ty::SubstsRef<'tcx>, ) -> Instance<'tcx> { debug!("fn_once_adapter_shim({:?}, {:?})", closure_did, substs); - let fn_once = tcx.require_lang_item(FnOnceTraitLangItem, None); + let fn_once = tcx.require_lang_item(LangItem::FnOnce, None); let call_once = tcx .associated_items(fn_once) .in_definition_order() diff --git a/src/librustc_middle/ty/layout.rs b/src/librustc_middle/ty/layout.rs index 928cba324d5..08bd131565b 100644 --- a/src/librustc_middle/ty/layout.rs +++ b/src/librustc_middle/ty/layout.rs @@ -8,7 +8,7 @@ use rustc_attr as attr; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir as hir; -use rustc_hir::lang_items::{GeneratorStateLangItem, PinTypeLangItem}; +use rustc_hir::lang_items::LangItem; use rustc_index::bit_set::BitSet; use rustc_index::vec::{Idx, IndexVec}; use rustc_session::{DataTypeKind, FieldInfo, SizeKind, VariantInfo}; @@ -2371,13 +2371,13 @@ fn fn_sig_for_fn_abi(&self, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> { let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv); let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty); - let pin_did = tcx.require_lang_item(PinTypeLangItem, None); + let pin_did = tcx.require_lang_item(LangItem::Pin, None); let pin_adt_ref = tcx.adt_def(pin_did); let pin_substs = tcx.intern_substs(&[env_ty.into()]); let env_ty = tcx.mk_adt(pin_adt_ref, pin_substs); sig.map_bound(|sig| { - let state_did = tcx.require_lang_item(GeneratorStateLangItem, None); + let state_did = tcx.require_lang_item(LangItem::GeneratorState, None); let state_adt_ref = tcx.adt_def(state_did); let state_substs = tcx.intern_substs(&[sig.yield_ty.into(), sig.return_ty.into()]); diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 4fa86a91254..a961d02f7a2 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -32,7 +32,7 @@ use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Namespace, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX}; -use rustc_hir::lang_items::{FnMutTraitLangItem, FnOnceTraitLangItem, FnTraitLangItem}; +use rustc_hir::lang_items::LangItem; use rustc_hir::{Constness, Node}; use rustc_index::vec::{Idx, IndexVec}; use rustc_macros::HashStable; @@ -2670,9 +2670,9 @@ impl<'tcx> ClosureKind { pub fn trait_did(&self, tcx: TyCtxt<'tcx>) -> DefId { match *self { - ClosureKind::Fn => tcx.require_lang_item(FnTraitLangItem, None), - ClosureKind::FnMut => tcx.require_lang_item(FnMutTraitLangItem, None), - ClosureKind::FnOnce => tcx.require_lang_item(FnOnceTraitLangItem, None), + ClosureKind::Fn => tcx.require_lang_item(LangItem::Fn, None), + ClosureKind::FnMut => tcx.require_lang_item(LangItem::FnMut, None), + ClosureKind::FnOnce => tcx.require_lang_item(LangItem::FnOnce, None), } } diff --git a/src/librustc_middle/ty/query/mod.rs b/src/librustc_middle/ty/query/mod.rs index f220c4fb072..ee9b203b151 100644 --- a/src/librustc_middle/ty/query/mod.rs +++ b/src/librustc_middle/ty/query/mod.rs @@ -133,7 +133,7 @@ /// `DefPathHash` in the current codebase to the corresponding `DefId`, we have /// everything we need to re-run the query. /// -/// Take the `mir_validated` query as an example. Like many other queries, it +/// Take the `mir_promoted` query as an example. Like many other queries, it /// just has a single parameter: the `DefId` of the item it will compute the /// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode` /// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode` diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs index 176bad6277f..c1f354c7a15 100644 --- a/src/librustc_middle/ty/sty.rs +++ b/src/librustc_middle/ty/sty.rs @@ -185,7 +185,7 @@ pub enum TyKind<'tcx> { /// After typeck, the concrete type can be found in the `types` map. Opaque(DefId, SubstsRef<'tcx>), - /// A type parameter; for example, `T` in `fn f(x: T) {} + /// A type parameter; for example, `T` in `fn f(x: T) {}`. Param(ParamTy), /// Bound type variable, used only when preparing a trait query. @@ -1264,7 +1264,7 @@ pub fn to_const(self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx ty::Const<'tcx> /// De Bruijn index of 0, because the innermost binder in that location /// is the outer fn. /// - /// [dbi]: http://en.wikipedia.org/wiki/De_Bruijn_index + /// [dbi]: https://en.wikipedia.org/wiki/De_Bruijn_index #[derive(HashStable)] pub struct DebruijnIndex { DEBUG_FORMAT = "DebruijnIndex({})", diff --git a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs index 7a50bdfeef6..9076dbccb52 100644 --- a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs @@ -113,23 +113,32 @@ pub(in crate::borrow_check) fn report_use_of_moved_or_uninitialized( } } - let msg = ""; //FIXME: add "partially " or "collaterally " + let is_partial_move = move_site_vec.iter().any(|move_site| { + let move_out = self.move_data.moves[(*move_site).moi]; + let moved_place = &self.move_data.move_paths[move_out.path].place; + // `*(_1)` where `_1` is a `Box` is actually a move out. + let is_box_move = moved_place.as_ref().projection == &[ProjectionElem::Deref] + && self.body.local_decls[moved_place.local].ty.is_box(); + + !is_box_move + && used_place != moved_place.as_ref() + && used_place.is_prefix_of(moved_place.as_ref()) + }); + + let partial_str = if is_partial_move { "partial " } else { "" }; + let partially_str = if is_partial_move { "partially " } else { "" }; let mut err = self.cannot_act_on_moved_value( span, desired_action.as_noun(), - msg, + partially_str, self.describe_place_with_options(moved_place, IncludingDowncast(true)), ); self.add_moved_or_invoked_closure_note(location, used_place, &mut err); let mut is_loop_move = false; - let is_partial_move = move_site_vec.iter().any(|move_site| { - let move_out = self.move_data.moves[(*move_site).moi]; - let moved_place = &self.move_data.move_paths[move_out.path].place; - used_place != moved_place.as_ref() && used_place.is_prefix_of(moved_place.as_ref()) - }); + for move_site in &move_site_vec { let move_out = self.move_data.moves[(*move_site).moi]; let moved_place = &self.move_data.move_paths[move_out.path].place; @@ -142,13 +151,19 @@ pub(in crate::borrow_check) fn report_use_of_moved_or_uninitialized( if location == move_out.source { err.span_label( span, - format!("value moved{} here, in previous iteration of loop", move_msg), + format!( + "value {}moved{} here, in previous iteration of loop", + partially_str, move_msg + ), ); is_loop_move = true; } else if move_site.traversed_back_edge { err.span_label( move_span, - format!("value moved{} here, in previous iteration of loop", move_msg), + format!( + "value {}moved{} here, in previous iteration of loop", + partially_str, move_msg + ), ); } else { if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = @@ -162,7 +177,10 @@ pub(in crate::borrow_check) fn report_use_of_moved_or_uninitialized( FnSelfUseKind::FnOnceCall => { err.span_label( fn_call_span, - &format!("{} moved due to this call", place_name), + &format!( + "{} {}moved due to this call", + place_name, partially_str + ), ); err.span_note( var_span, @@ -172,7 +190,10 @@ pub(in crate::borrow_check) fn report_use_of_moved_or_uninitialized( FnSelfUseKind::Operator { self_arg } => { err.span_label( fn_call_span, - &format!("{} moved due to usage in operator", place_name), + &format!( + "{} {}moved due to usage in operator", + place_name, partially_str + ), ); if self.fn_self_span_reported.insert(fn_span) { err.span_note( @@ -186,14 +207,17 @@ pub(in crate::borrow_check) fn report_use_of_moved_or_uninitialized( err.span_label( fn_call_span, &format!( - "{} moved due to this implicit call to `.into_iter()`", - place_name + "{} {}moved due to this implicit call to `.into_iter()`", + place_name, partially_str ), ); } else { err.span_label( fn_call_span, - &format!("{} moved due to this method call", place_name), + &format!( + "{} {}moved due to this method call", + place_name, partially_str + ), ); } // Avoid pointing to the same function in multiple different @@ -207,10 +231,17 @@ pub(in crate::borrow_check) fn report_use_of_moved_or_uninitialized( } } } else { - err.span_label(move_span, format!("value moved{} here", move_msg)); + err.span_label( + move_span, + format!("value {}moved{} here", partially_str, move_msg), + ); move_spans.var_span_label( &mut err, - format!("variable moved due to use{}", move_spans.describe()), + format!( + "variable {}moved due to use{}", + partially_str, + move_spans.describe() + ), ); } } @@ -250,9 +281,9 @@ pub(in crate::borrow_check) fn report_use_of_moved_or_uninitialized( err.span_label( span, format!( - "value {} here {}", + "value {} here after {}move", desired_action.as_verb_in_past_tense(), - if is_partial_move { "after partial move" } else { "after move" }, + partial_str ), ); } @@ -321,7 +352,7 @@ pub(in crate::borrow_check) fn report_use_of_moved_or_uninitialized( } else { None }; - self.note_type_does_not_implement_copy(&mut err, ¬e_msg, ty, span); + self.note_type_does_not_implement_copy(&mut err, ¬e_msg, ty, span, partial_str); } if let Some((_, mut old_err)) = @@ -1398,8 +1429,12 @@ fn predecessor_locations( for moi in &self.move_data.loc_map[location] { debug!("report_use_of_moved_or_uninitialized: moi={:?}", moi); - if mpis.contains(&self.move_data.moves[*moi].path) { - debug!("report_use_of_moved_or_uninitialized: found"); + let path = self.move_data.moves[*moi].path; + if mpis.contains(&path) { + debug!( + "report_use_of_moved_or_uninitialized: found {:?}", + move_paths[path].place + ); result.push(MoveSite { moi: *moi, traversed_back_edge: is_back_edge }); // Strictly speaking, we could continue our DFS here. There may be diff --git a/src/librustc_mir/borrow_check/diagnostics/mod.rs b/src/librustc_mir/borrow_check/diagnostics/mod.rs index daffdec2a83..e73a78811d4 100644 --- a/src/librustc_mir/borrow_check/diagnostics/mod.rs +++ b/src/librustc_mir/borrow_check/diagnostics/mod.rs @@ -412,10 +412,11 @@ pub(super) fn note_type_does_not_implement_copy( place_desc: &str, ty: Ty<'tcx>, span: Option, + move_prefix: &str, ) { let message = format!( - "move occurs because {} has type `{}`, which does not implement the `Copy` trait", - place_desc, ty, + "{}move occurs because {} has type `{}`, which does not implement the `Copy` trait", + move_prefix, place_desc, ty, ); if let Some(span) = span { err.span_label(span, message); diff --git a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs index bd3e20458b0..1c8da212f10 100644 --- a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs @@ -445,7 +445,13 @@ fn add_move_hints( None => "value".to_string(), }; - self.note_type_does_not_implement_copy(err, &place_desc, place_ty, Some(span)); + self.note_type_does_not_implement_copy( + err, + &place_desc, + place_ty, + Some(span), + "", + ); } else { binds_to.sort(); binds_to.dedup(); @@ -467,7 +473,7 @@ fn add_move_hints( Some(desc) => format!("`{}`", desc), None => "value".to_string(), }; - self.note_type_does_not_implement_copy(err, &place_desc, place_ty, Some(span)); + self.note_type_does_not_implement_copy(err, &place_desc, place_ty, Some(span), ""); use_spans.args_span_label(err, format!("move out of {} occurs here", place_desc)); use_spans @@ -529,6 +535,7 @@ fn add_move_error_details(&self, err: &mut DiagnosticBuilder<'a>, binds_to: &[Lo &format!("`{}`", self.local_names[*local].unwrap()), bind_to.ty, Some(binding_span), + "", ); } } diff --git a/src/librustc_mir/borrow_check/diagnostics/outlives_suggestion.rs b/src/librustc_mir/borrow_check/diagnostics/outlives_suggestion.rs index 9197a83cdd0..a775fa59c1b 100644 --- a/src/librustc_mir/borrow_check/diagnostics/outlives_suggestion.rs +++ b/src/librustc_mir/borrow_check/diagnostics/outlives_suggestion.rs @@ -257,7 +257,7 @@ fn compile_all_suggestions( }; // We want this message to appear after other messages on the mir def. - let mir_span = mbcx.infcx.tcx.def_span(mbcx.mir_def_id); + let mir_span = mbcx.body.span; diag.sort_span = mir_span.shrink_to_hi(); // Buffer the diagnostic diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 9a28321a6cc..b486b8b589c 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -106,7 +106,7 @@ fn mir_borrowck<'tcx>( tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam, ) -> &'tcx BorrowCheckResult<'tcx> { - let (input_body, promoted) = tcx.mir_validated(def); + let (input_body, promoted) = tcx.mir_promoted(def); debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id())); let opt_closure_req = tcx.infer_ctxt().enter(|infcx| { @@ -1694,8 +1694,8 @@ fn check_if_subslice_element_is_moved( desired_action: InitializationRequiringAction, place_span: (PlaceRef<'tcx>, Span), maybe_uninits: &BitSet, - from: u32, - to: u32, + from: u64, + to: u64, ) { if let Some(mpi) = self.move_path_for_place(place_span.0) { let move_paths = &self.move_data.move_paths; diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs index 168a352591d..69c4f633770 100644 --- a/src/librustc_mir/borrow_check/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/type_check/mod.rs @@ -10,7 +10,7 @@ use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::lang_items::{CoerceUnsizedTraitLangItem, CopyTraitLangItem, SizedTraitLangItem}; +use rustc_hir::lang_items::LangItem; use rustc_index::vec::{Idx, IndexVec}; use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_infer::infer::outlives::env::RegionBoundPairs; @@ -507,7 +507,7 @@ fn sanitize_place( if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context { let tcx = self.tcx(); let trait_ref = ty::TraitRef { - def_id: tcx.require_lang_item(CopyTraitLangItem, Some(self.last_span)), + def_id: tcx.require_lang_item(LangItem::Copy, Some(self.last_span)), substs: tcx.mk_substs_trait(place_ty.ty, &[]), }; @@ -649,7 +649,7 @@ fn sanitize_projection( PlaceTy::from_ty(match base_ty.kind { ty::Array(inner, _) => { assert!(!from_end, "array subslices should not use from_end"); - tcx.mk_array(inner, (to - from) as u64) + tcx.mk_array(inner, to - from) } ty::Slice(..) => { assert!(from_end, "slice subslices should use from_end"); @@ -1474,7 +1474,7 @@ fn check_stmt(&mut self, body: &Body<'tcx>, stmt: &Statement<'tcx>, location: Lo self.check_rvalue(body, rv, location); if !self.tcx().features().unsized_locals { let trait_ref = ty::TraitRef { - def_id: tcx.require_lang_item(SizedTraitLangItem, Some(self.last_span)), + def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)), substs: tcx.mk_substs_trait(place_ty, &[]), }; self.prove_trait_ref( @@ -2025,7 +2025,7 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L self.param_env, ty::Binder::bind(ty::TraitRef::new( self.tcx().require_lang_item( - CopyTraitLangItem, + LangItem::Copy, Some(self.last_span), ), tcx.mk_substs_trait(ty, &[]), @@ -2050,7 +2050,7 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L } let trait_ref = ty::TraitRef { - def_id: tcx.require_lang_item(SizedTraitLangItem, Some(self.last_span)), + def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)), substs: tcx.mk_substs_trait(ty, &[]), }; @@ -2148,10 +2148,8 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L CastKind::Pointer(PointerCast::Unsize) => { let &ty = ty; let trait_ref = ty::TraitRef { - def_id: tcx.require_lang_item( - CoerceUnsizedTraitLangItem, - Some(self.last_span), - ), + def_id: tcx + .require_lang_item(LangItem::CoerceUnsized, Some(self.last_span)), substs: tcx.mk_substs_trait(op.ty(body, tcx), &[ty.into()]), }; diff --git a/src/librustc_mir/borrow_check/universal_regions.rs b/src/librustc_mir/borrow_check/universal_regions.rs index cd6b75cf556..9dfc67bcf67 100644 --- a/src/librustc_mir/borrow_check/universal_regions.rs +++ b/src/librustc_mir/borrow_check/universal_regions.rs @@ -17,7 +17,7 @@ use rustc_errors::DiagnosticBuilder; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::lang_items; +use rustc_hir::lang_items::LangItem; use rustc_hir::{BodyOwnerKind, HirId}; use rustc_index::vec::{Idx, IndexVec}; use rustc_infer::infer::{InferCtxt, NLLRegionVariableOrigin}; @@ -456,7 +456,7 @@ fn build(self) -> UniversalRegions<'tcx> { if let DefiningTy::FnDef(def_id, _) = defining_ty { if self.infcx.tcx.fn_sig(def_id).c_variadic() { let va_list_did = self.infcx.tcx.require_lang_item( - lang_items::VaListTypeLangItem, + LangItem::VaList, Some(self.infcx.tcx.def_span(self.mir_def.did)), ); let region = self diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index e567063e0d5..e088dc6a954 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -480,7 +480,7 @@ fn gather_move(&mut self, place: Place<'tcx>) { } }; let base_ty = base_place.ty(self.builder.body, self.builder.tcx).ty; - let len: u32 = match base_ty.kind { + let len: u64 = match base_ty.kind { ty::Array(_, size) => { let length = size.eval_usize(self.builder.tcx, self.builder.param_env); length diff --git a/src/librustc_mir/interpret/intern.rs b/src/librustc_mir/interpret/intern.rs index 9959c38e5c7..606be7cad2b 100644 --- a/src/librustc_mir/interpret/intern.rs +++ b/src/librustc_mir/interpret/intern.rs @@ -7,7 +7,8 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_middle::mir::interpret::InterpResult; -use rustc_middle::ty::{self, query::TyCtxtAt, Ty}; +use rustc_middle::ty::{self, layout::TyAndLayout, query::TyCtxtAt, Ty}; +use rustc_target::abi::Size; use rustc_ast::Mutability; @@ -430,3 +431,25 @@ pub fn intern_const_alloc_recursive>( } } } + +impl<'mir, 'tcx: 'mir, M: super::intern::CompileTimeMachine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { + /// A helper function that allocates memory for the layout given and gives you access to mutate + /// it. Once your own mutation code is done, the backing `Allocation` is removed from the + /// current `Memory` and returned. + pub(crate) fn intern_with_temp_alloc( + &mut self, + layout: TyAndLayout<'tcx>, + f: impl FnOnce( + &mut InterpCx<'mir, 'tcx, M>, + MPlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, ()>, + ) -> InterpResult<'tcx, &'tcx Allocation> { + let dest = self.allocate(layout, MemoryKind::Stack); + f(self, dest)?; + let ptr = dest.ptr.assert_ptr(); + assert_eq!(ptr.offset, Size::ZERO); + let mut alloc = self.memory.alloc_map.remove(&ptr.alloc_id).unwrap().1; + alloc.mutability = Mutability::Not; + Ok(self.tcx.intern_const_alloc(alloc)) + } +} diff --git a/src/librustc_mir/interpret/intrinsics/caller_location.rs b/src/librustc_mir/interpret/intrinsics/caller_location.rs index fb3a670714b..d9be28cf9db 100644 --- a/src/librustc_mir/interpret/intrinsics/caller_location.rs +++ b/src/librustc_mir/interpret/intrinsics/caller_location.rs @@ -1,6 +1,6 @@ use std::convert::TryFrom; -use rustc_hir::lang_items::PanicLocationLangItem; +use rustc_hir::lang_items::LangItem; use rustc_middle::mir::TerminatorKind; use rustc_middle::ty::subst::Subst; use rustc_span::{Span, Symbol}; @@ -63,7 +63,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Allocate memory for `CallerLocation` struct. let loc_ty = self .tcx - .type_of(self.tcx.require_lang_item(PanicLocationLangItem, None)) + .type_of(self.tcx.require_lang_item(LangItem::PanicLocation, None)) .subst(*self.tcx, self.tcx.mk_substs([self.tcx.lifetimes.re_erased.into()].iter())); let loc_layout = self.layout_of(loc_ty).unwrap(); let location = self.allocate(loc_layout, MemoryKind::CallerLocation); diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 20fd8e43361..6ba6103b311 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -549,17 +549,17 @@ pub(super) fn mplace_projection( ConstantIndex { offset, min_length, from_end } => { let n = base.len(self)?; - if n < u64::from(min_length) { + if n < min_length { // This can only be reached in ConstProp and non-rustc-MIR. throw_ub!(BoundsCheckFailed { len: min_length.into(), index: n }); } let index = if from_end { assert!(0 < offset && offset <= min_length); - n.checked_sub(u64::from(offset)).unwrap() + n.checked_sub(offset).unwrap() } else { assert!(offset < min_length); - u64::from(offset) + offset }; self.mplace_index(base, index)? diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 3118e7ac3ab..2e3b5084635 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -22,7 +22,6 @@ #![feature(try_blocks)] #![feature(associated_type_bounds)] #![feature(associated_type_defaults)] -#![feature(range_is_empty)] #![feature(stmt_expr_attributes)] #![feature(trait_alias)] #![feature(option_expect_none)] diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index e724180f4d8..d379f4ef428 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -182,7 +182,7 @@ use rustc_hir as hir; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; use rustc_hir::itemlikevisit::ItemLikeVisitor; -use rustc_hir::lang_items::{ExchangeMallocFnLangItem, StartFnLangItem}; +use rustc_hir::lang_items::LangItem; use rustc_index::bit_set::GrowableBitSet; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::interpret::{AllocId, ConstValue}; @@ -594,7 +594,7 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) { mir::Rvalue::NullaryOp(mir::NullOp::Box, _) => { let tcx = self.tcx; let exchange_malloc_fn_def_id = - tcx.require_lang_item(ExchangeMallocFnLangItem, None); + tcx.require_lang_item(LangItem::ExchangeMalloc, None); let instance = Instance::mono(tcx, exchange_malloc_fn_def_id); if should_codegen_locally(tcx, &instance) { self.output.push(create_fn_mono_item(self.tcx, instance, span)); @@ -1083,7 +1083,7 @@ fn push_extra_entry_roots(&mut self) { _ => return, }; - let start_def_id = match self.tcx.lang_items().require(StartFnLangItem) { + let start_def_id = match self.tcx.lang_items().require(LangItem::Start) { Ok(s) => s, Err(err) => self.tcx.sess.fatal(&err), }; diff --git a/src/librustc_mir/monomorphize/mod.rs b/src/librustc_mir/monomorphize/mod.rs index 15d7b111240..edafa00a03a 100644 --- a/src/librustc_mir/monomorphize/mod.rs +++ b/src/librustc_mir/monomorphize/mod.rs @@ -2,7 +2,7 @@ use rustc_middle::ty::adjustment::CustomCoerceUnsized; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_hir::lang_items::CoerceUnsizedTraitLangItem; +use rustc_hir::lang_items::LangItem; pub mod collector; pub mod partitioning; @@ -13,7 +13,7 @@ pub fn custom_coerce_unsize_info<'tcx>( source_ty: Ty<'tcx>, target_ty: Ty<'tcx>, ) -> CustomCoerceUnsized { - let def_id = tcx.require_lang_item(CoerceUnsizedTraitLangItem, None); + let def_id = tcx.require_lang_item(LangItem::CoerceUnsized, None); let trait_ref = ty::Binder::bind(ty::TraitRef { def_id, diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs deleted file mode 100644 index 6162651db14..00000000000 --- a/src/librustc_mir/monomorphize/partitioning.rs +++ /dev/null @@ -1,1012 +0,0 @@ -//! Partitioning Codegen Units for Incremental Compilation -//! ====================================================== -//! -//! The task of this module is to take the complete set of monomorphizations of -//! a crate and produce a set of codegen units from it, where a codegen unit -//! is a named set of (mono-item, linkage) pairs. That is, this module -//! decides which monomorphization appears in which codegen units with which -//! linkage. The following paragraphs describe some of the background on the -//! partitioning scheme. -//! -//! The most important opportunity for saving on compilation time with -//! incremental compilation is to avoid re-codegenning and re-optimizing code. -//! Since the unit of codegen and optimization for LLVM is "modules" or, how -//! we call them "codegen units", the particulars of how much time can be saved -//! by incremental compilation are tightly linked to how the output program is -//! partitioned into these codegen units prior to passing it to LLVM -- -//! especially because we have to treat codegen units as opaque entities once -//! they are created: There is no way for us to incrementally update an existing -//! LLVM module and so we have to build any such module from scratch if it was -//! affected by some change in the source code. -//! -//! From that point of view it would make sense to maximize the number of -//! codegen units by, for example, putting each function into its own module. -//! That way only those modules would have to be re-compiled that were actually -//! affected by some change, minimizing the number of functions that could have -//! been re-used but just happened to be located in a module that is -//! re-compiled. -//! -//! However, since LLVM optimization does not work across module boundaries, -//! using such a highly granular partitioning would lead to very slow runtime -//! code since it would effectively prohibit inlining and other inter-procedure -//! optimizations. We want to avoid that as much as possible. -//! -//! Thus we end up with a trade-off: The bigger the codegen units, the better -//! LLVM's optimizer can do its work, but also the smaller the compilation time -//! reduction we get from incremental compilation. -//! -//! Ideally, we would create a partitioning such that there are few big codegen -//! units with few interdependencies between them. For now though, we use the -//! following heuristic to determine the partitioning: -//! -//! - There are two codegen units for every source-level module: -//! - One for "stable", that is non-generic, code -//! - One for more "volatile" code, i.e., monomorphized instances of functions -//! defined in that module -//! -//! In order to see why this heuristic makes sense, let's take a look at when a -//! codegen unit can get invalidated: -//! -//! 1. The most straightforward case is when the BODY of a function or global -//! changes. Then any codegen unit containing the code for that item has to be -//! re-compiled. Note that this includes all codegen units where the function -//! has been inlined. -//! -//! 2. The next case is when the SIGNATURE of a function or global changes. In -//! this case, all codegen units containing a REFERENCE to that item have to be -//! re-compiled. This is a superset of case 1. -//! -//! 3. The final and most subtle case is when a REFERENCE to a generic function -//! is added or removed somewhere. Even though the definition of the function -//! might be unchanged, a new REFERENCE might introduce a new monomorphized -//! instance of this function which has to be placed and compiled somewhere. -//! Conversely, when removing a REFERENCE, it might have been the last one with -//! that particular set of generic arguments and thus we have to remove it. -//! -//! From the above we see that just using one codegen unit per source-level -//! module is not such a good idea, since just adding a REFERENCE to some -//! generic item somewhere else would invalidate everything within the module -//! containing the generic item. The heuristic above reduces this detrimental -//! side-effect of references a little by at least not touching the non-generic -//! code of the module. -//! -//! A Note on Inlining -//! ------------------ -//! As briefly mentioned above, in order for LLVM to be able to inline a -//! function call, the body of the function has to be available in the LLVM -//! module where the call is made. This has a few consequences for partitioning: -//! -//! - The partitioning algorithm has to take care of placing functions into all -//! codegen units where they should be available for inlining. It also has to -//! decide on the correct linkage for these functions. -//! -//! - The partitioning algorithm has to know which functions are likely to get -//! inlined, so it can distribute function instantiations accordingly. Since -//! there is no way of knowing for sure which functions LLVM will decide to -//! inline in the end, we apply a heuristic here: Only functions marked with -//! `#[inline]` are considered for inlining by the partitioner. The current -//! implementation will not try to determine if a function is likely to be -//! inlined by looking at the functions definition. -//! -//! Note though that as a side-effect of creating a codegen units per -//! source-level module, functions from the same module will be available for -//! inlining, even when they are not marked `#[inline]`. - -use std::cmp; -use std::collections::hash_map::Entry; - -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::sync; -use rustc_hir::def::DefKind; -use rustc_hir::def_id::{CrateNum, DefId, DefIdSet, CRATE_DEF_INDEX, LOCAL_CRATE}; -use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::middle::exported_symbols::SymbolExportLevel; -use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, Linkage, Visibility}; -use rustc_middle::mir::mono::{InstantiationMode, MonoItem}; -use rustc_middle::ty::print::characteristic_def_id_of_type; -use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{self, DefIdTree, InstanceDef, TyCtxt}; -use rustc_span::symbol::{Symbol, SymbolStr}; - -use crate::monomorphize::collector::InliningMap; -use crate::monomorphize::collector::{self, MonoItemCollectionMode}; - -// Anything we can't find a proper codegen unit for goes into this. -fn fallback_cgu_name(name_builder: &mut CodegenUnitNameBuilder<'_>) -> Symbol { - name_builder.build_cgu_name(LOCAL_CRATE, &["fallback"], Some("cgu")) -} - -pub fn partition<'tcx, I>( - tcx: TyCtxt<'tcx>, - mono_items: I, - max_cgu_count: usize, - inlining_map: &InliningMap<'tcx>, -) -> Vec> -where - I: Iterator>, -{ - let _prof_timer = tcx.prof.generic_activity("cgu_partitioning"); - - // In the first step, we place all regular monomorphizations into their - // respective 'home' codegen unit. Regular monomorphizations are all - // functions and statics defined in the local crate. - let mut initial_partitioning = { - let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_roots"); - place_root_mono_items(tcx, mono_items) - }; - - initial_partitioning.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx)); - - debug_dump(tcx, "INITIAL PARTITIONING:", initial_partitioning.codegen_units.iter()); - - // Merge until we have at most `max_cgu_count` codegen units. - { - let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_merge_cgus"); - merge_codegen_units(tcx, &mut initial_partitioning, max_cgu_count); - debug_dump(tcx, "POST MERGING:", initial_partitioning.codegen_units.iter()); - } - - // In the next step, we use the inlining map to determine which additional - // monomorphizations have to go into each codegen unit. These additional - // monomorphizations can be drop-glue, functions from external crates, and - // local functions the definition of which is marked with `#[inline]`. - let mut post_inlining = { - let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_inline_items"); - place_inlined_mono_items(initial_partitioning, inlining_map) - }; - - post_inlining.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx)); - - debug_dump(tcx, "POST INLINING:", post_inlining.codegen_units.iter()); - - // Next we try to make as many symbols "internal" as possible, so LLVM has - // more freedom to optimize. - if tcx.sess.opts.cg.link_dead_code != Some(true) { - let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_internalize_symbols"); - internalize_symbols(tcx, &mut post_inlining, inlining_map); - } - - // Finally, sort by codegen unit name, so that we get deterministic results. - let PostInliningPartitioning { - codegen_units: mut result, - mono_item_placements: _, - internalization_candidates: _, - } = post_inlining; - - result.sort_by_cached_key(|cgu| cgu.name().as_str()); - - result -} - -struct PreInliningPartitioning<'tcx> { - codegen_units: Vec>, - roots: FxHashSet>, - internalization_candidates: FxHashSet>, -} - -/// For symbol internalization, we need to know whether a symbol/mono-item is -/// accessed from outside the codegen unit it is defined in. This type is used -/// to keep track of that. -#[derive(Clone, PartialEq, Eq, Debug)] -enum MonoItemPlacement { - SingleCgu { cgu_name: Symbol }, - MultipleCgus, -} - -struct PostInliningPartitioning<'tcx> { - codegen_units: Vec>, - mono_item_placements: FxHashMap, MonoItemPlacement>, - internalization_candidates: FxHashSet>, -} - -fn place_root_mono_items<'tcx, I>(tcx: TyCtxt<'tcx>, mono_items: I) -> PreInliningPartitioning<'tcx> -where - I: Iterator>, -{ - let mut roots = FxHashSet::default(); - let mut codegen_units = FxHashMap::default(); - let is_incremental_build = tcx.sess.opts.incremental.is_some(); - let mut internalization_candidates = FxHashSet::default(); - - // Determine if monomorphizations instantiated in this crate will be made - // available to downstream crates. This depends on whether we are in - // share-generics mode and whether the current crate can even have - // downstream crates. - let export_generics = tcx.sess.opts.share_generics() && tcx.local_crate_exports_generics(); - - let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx); - let cgu_name_cache = &mut FxHashMap::default(); - - for mono_item in mono_items { - match mono_item.instantiation_mode(tcx) { - InstantiationMode::GloballyShared { .. } => {} - InstantiationMode::LocalCopy => continue, - } - - let characteristic_def_id = characteristic_def_id_of_mono_item(tcx, mono_item); - let is_volatile = is_incremental_build && mono_item.is_generic_fn(); - - let codegen_unit_name = match characteristic_def_id { - Some(def_id) => compute_codegen_unit_name( - tcx, - cgu_name_builder, - def_id, - is_volatile, - cgu_name_cache, - ), - None => fallback_cgu_name(cgu_name_builder), - }; - - let codegen_unit = codegen_units - .entry(codegen_unit_name) - .or_insert_with(|| CodegenUnit::new(codegen_unit_name)); - - let mut can_be_internalized = true; - let (linkage, visibility) = mono_item_linkage_and_visibility( - tcx, - &mono_item, - &mut can_be_internalized, - export_generics, - ); - if visibility == Visibility::Hidden && can_be_internalized { - internalization_candidates.insert(mono_item); - } - - codegen_unit.items_mut().insert(mono_item, (linkage, visibility)); - roots.insert(mono_item); - } - - // Always ensure we have at least one CGU; otherwise, if we have a - // crate with just types (for example), we could wind up with no CGU. - if codegen_units.is_empty() { - let codegen_unit_name = fallback_cgu_name(cgu_name_builder); - codegen_units.insert(codegen_unit_name, CodegenUnit::new(codegen_unit_name)); - } - - PreInliningPartitioning { - codegen_units: codegen_units.into_iter().map(|(_, codegen_unit)| codegen_unit).collect(), - roots, - internalization_candidates, - } -} - -fn mono_item_linkage_and_visibility( - tcx: TyCtxt<'tcx>, - mono_item: &MonoItem<'tcx>, - can_be_internalized: &mut bool, - export_generics: bool, -) -> (Linkage, Visibility) { - if let Some(explicit_linkage) = mono_item.explicit_linkage(tcx) { - return (explicit_linkage, Visibility::Default); - } - let vis = mono_item_visibility(tcx, mono_item, can_be_internalized, export_generics); - (Linkage::External, vis) -} - -fn mono_item_visibility( - tcx: TyCtxt<'tcx>, - mono_item: &MonoItem<'tcx>, - can_be_internalized: &mut bool, - export_generics: bool, -) -> Visibility { - let instance = match mono_item { - // This is pretty complicated; see below. - MonoItem::Fn(instance) => instance, - - // Misc handling for generics and such, but otherwise: - MonoItem::Static(def_id) => { - return if tcx.is_reachable_non_generic(*def_id) { - *can_be_internalized = false; - default_visibility(tcx, *def_id, false) - } else { - Visibility::Hidden - }; - } - MonoItem::GlobalAsm(hir_id) => { - let def_id = tcx.hir().local_def_id(*hir_id); - return if tcx.is_reachable_non_generic(def_id) { - *can_be_internalized = false; - default_visibility(tcx, def_id.to_def_id(), false) - } else { - Visibility::Hidden - }; - } - }; - - let def_id = match instance.def { - InstanceDef::Item(def) => def.did, - InstanceDef::DropGlue(def_id, Some(_)) => def_id, - - // These are all compiler glue and such, never exported, always hidden. - InstanceDef::VtableShim(..) - | InstanceDef::ReifyShim(..) - | InstanceDef::FnPtrShim(..) - | InstanceDef::Virtual(..) - | InstanceDef::Intrinsic(..) - | InstanceDef::ClosureOnceShim { .. } - | InstanceDef::DropGlue(..) - | InstanceDef::CloneShim(..) => return Visibility::Hidden, - }; - - // The `start_fn` lang item is actually a monomorphized instance of a - // function in the standard library, used for the `main` function. We don't - // want to export it so we tag it with `Hidden` visibility but this symbol - // is only referenced from the actual `main` symbol which we unfortunately - // don't know anything about during partitioning/collection. As a result we - // forcibly keep this symbol out of the `internalization_candidates` set. - // - // FIXME: eventually we don't want to always force this symbol to have - // hidden visibility, it should indeed be a candidate for - // internalization, but we have to understand that it's referenced - // from the `main` symbol we'll generate later. - // - // This may be fixable with a new `InstanceDef` perhaps? Unsure! - if tcx.lang_items().start_fn() == Some(def_id) { - *can_be_internalized = false; - return Visibility::Hidden; - } - - let is_generic = instance.substs.non_erasable_generics().next().is_some(); - - // Upstream `DefId` instances get different handling than local ones. - if !def_id.is_local() { - return if export_generics && is_generic { - // If it is a upstream monomorphization and we export generics, we must make - // it available to downstream crates. - *can_be_internalized = false; - default_visibility(tcx, def_id, true) - } else { - Visibility::Hidden - }; - } - - if is_generic { - if export_generics { - if tcx.is_unreachable_local_definition(def_id) { - // This instance cannot be used from another crate. - Visibility::Hidden - } else { - // This instance might be useful in a downstream crate. - *can_be_internalized = false; - default_visibility(tcx, def_id, true) - } - } else { - // We are not exporting generics or the definition is not reachable - // for downstream crates, we can internalize its instantiations. - Visibility::Hidden - } - } else { - // If this isn't a generic function then we mark this a `Default` if - // this is a reachable item, meaning that it's a symbol other crates may - // access when they link to us. - if tcx.is_reachable_non_generic(def_id) { - *can_be_internalized = false; - debug_assert!(!is_generic); - return default_visibility(tcx, def_id, false); - } - - // If this isn't reachable then we're gonna tag this with `Hidden` - // visibility. In some situations though we'll want to prevent this - // symbol from being internalized. - // - // There's two categories of items here: - // - // * First is weak lang items. These are basically mechanisms for - // libcore to forward-reference symbols defined later in crates like - // the standard library or `#[panic_handler]` definitions. The - // definition of these weak lang items needs to be referenceable by - // libcore, so we're no longer a candidate for internalization. - // Removal of these functions can't be done by LLVM but rather must be - // done by the linker as it's a non-local decision. - // - // * Second is "std internal symbols". Currently this is primarily used - // for allocator symbols. Allocators are a little weird in their - // implementation, but the idea is that the compiler, at the last - // minute, defines an allocator with an injected object file. The - // `alloc` crate references these symbols (`__rust_alloc`) and the - // definition doesn't get hooked up until a linked crate artifact is - // generated. - // - // The symbols synthesized by the compiler (`__rust_alloc`) are thin - // veneers around the actual implementation, some other symbol which - // implements the same ABI. These symbols (things like `__rg_alloc`, - // `__rdl_alloc`, `__rde_alloc`, etc), are all tagged with "std - // internal symbols". - // - // The std-internal symbols here **should not show up in a dll as an - // exported interface**, so they return `false` from - // `is_reachable_non_generic` above and we'll give them `Hidden` - // visibility below. Like the weak lang items, though, we can't let - // LLVM internalize them as this decision is left up to the linker to - // omit them, so prevent them from being internalized. - let attrs = tcx.codegen_fn_attrs(def_id); - if attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) { - *can_be_internalized = false; - } - - Visibility::Hidden - } -} - -fn default_visibility(tcx: TyCtxt<'_>, id: DefId, is_generic: bool) -> Visibility { - if !tcx.sess.target.target.options.default_hidden_visibility { - return Visibility::Default; - } - - // Generic functions never have export-level C. - if is_generic { - return Visibility::Hidden; - } - - // Things with export level C don't get instantiated in - // downstream crates. - if !id.is_local() { - return Visibility::Hidden; - } - - // C-export level items remain at `Default`, all other internal - // items become `Hidden`. - match tcx.reachable_non_generics(id.krate).get(&id) { - Some(SymbolExportLevel::C) => Visibility::Default, - _ => Visibility::Hidden, - } -} - -fn merge_codegen_units<'tcx>( - tcx: TyCtxt<'tcx>, - initial_partitioning: &mut PreInliningPartitioning<'tcx>, - target_cgu_count: usize, -) { - assert!(target_cgu_count >= 1); - let codegen_units = &mut initial_partitioning.codegen_units; - - // Note that at this point in time the `codegen_units` here may not be in a - // deterministic order (but we know they're deterministically the same set). - // We want this merging to produce a deterministic ordering of codegen units - // from the input. - // - // Due to basically how we've implemented the merging below (merge the two - // smallest into each other) we're sure to start off with a deterministic - // order (sorted by name). This'll mean that if two cgus have the same size - // the stable sort below will keep everything nice and deterministic. - codegen_units.sort_by_cached_key(|cgu| cgu.name().as_str()); - - // This map keeps track of what got merged into what. - let mut cgu_contents: FxHashMap> = - codegen_units.iter().map(|cgu| (cgu.name(), vec![cgu.name().as_str()])).collect(); - - // Merge the two smallest codegen units until the target size is reached. - while codegen_units.len() > target_cgu_count { - // Sort small cgus to the back - codegen_units.sort_by_cached_key(|cgu| cmp::Reverse(cgu.size_estimate())); - let mut smallest = codegen_units.pop().unwrap(); - let second_smallest = codegen_units.last_mut().unwrap(); - - // Move the mono-items from `smallest` to `second_smallest` - second_smallest.modify_size_estimate(smallest.size_estimate()); - for (k, v) in smallest.items_mut().drain() { - second_smallest.items_mut().insert(k, v); - } - - // Record that `second_smallest` now contains all the stuff that was in - // `smallest` before. - let mut consumed_cgu_names = cgu_contents.remove(&smallest.name()).unwrap(); - cgu_contents.get_mut(&second_smallest.name()).unwrap().extend(consumed_cgu_names.drain(..)); - - debug!( - "CodegenUnit {} merged into CodegenUnit {}", - smallest.name(), - second_smallest.name() - ); - } - - let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx); - - if tcx.sess.opts.incremental.is_some() { - // If we are doing incremental compilation, we want CGU names to - // reflect the path of the source level module they correspond to. - // For CGUs that contain the code of multiple modules because of the - // merging done above, we use a concatenation of the names of - // all contained CGUs. - let new_cgu_names: FxHashMap = cgu_contents - .into_iter() - // This `filter` makes sure we only update the name of CGUs that - // were actually modified by merging. - .filter(|(_, cgu_contents)| cgu_contents.len() > 1) - .map(|(current_cgu_name, cgu_contents)| { - let mut cgu_contents: Vec<&str> = cgu_contents.iter().map(|s| &s[..]).collect(); - - // Sort the names, so things are deterministic and easy to - // predict. - cgu_contents.sort(); - - (current_cgu_name, cgu_contents.join("--")) - }) - .collect(); - - for cgu in codegen_units.iter_mut() { - if let Some(new_cgu_name) = new_cgu_names.get(&cgu.name()) { - if tcx.sess.opts.debugging_opts.human_readable_cgu_names { - cgu.set_name(Symbol::intern(&new_cgu_name)); - } else { - // If we don't require CGU names to be human-readable, we - // use a fixed length hash of the composite CGU name - // instead. - let new_cgu_name = CodegenUnit::mangle_name(&new_cgu_name); - cgu.set_name(Symbol::intern(&new_cgu_name)); - } - } - } - } else { - // If we are compiling non-incrementally we just generate simple CGU - // names containing an index. - for (index, cgu) in codegen_units.iter_mut().enumerate() { - cgu.set_name(numbered_codegen_unit_name(cgu_name_builder, index)); - } - } -} - -fn place_inlined_mono_items<'tcx>( - initial_partitioning: PreInliningPartitioning<'tcx>, - inlining_map: &InliningMap<'tcx>, -) -> PostInliningPartitioning<'tcx> { - let mut new_partitioning = Vec::new(); - let mut mono_item_placements = FxHashMap::default(); - - let PreInliningPartitioning { codegen_units: initial_cgus, roots, internalization_candidates } = - initial_partitioning; - - let single_codegen_unit = initial_cgus.len() == 1; - - for old_codegen_unit in initial_cgus { - // Collect all items that need to be available in this codegen unit. - let mut reachable = FxHashSet::default(); - for root in old_codegen_unit.items().keys() { - follow_inlining(*root, inlining_map, &mut reachable); - } - - let mut new_codegen_unit = CodegenUnit::new(old_codegen_unit.name()); - - // Add all monomorphizations that are not already there. - for mono_item in reachable { - if let Some(linkage) = old_codegen_unit.items().get(&mono_item) { - // This is a root, just copy it over. - new_codegen_unit.items_mut().insert(mono_item, *linkage); - } else { - if roots.contains(&mono_item) { - bug!( - "GloballyShared mono-item inlined into other CGU: \ - {:?}", - mono_item - ); - } - - // This is a CGU-private copy. - new_codegen_unit - .items_mut() - .insert(mono_item, (Linkage::Internal, Visibility::Default)); - } - - if !single_codegen_unit { - // If there is more than one codegen unit, we need to keep track - // in which codegen units each monomorphization is placed. - match mono_item_placements.entry(mono_item) { - Entry::Occupied(e) => { - let placement = e.into_mut(); - debug_assert!(match *placement { - MonoItemPlacement::SingleCgu { cgu_name } => { - cgu_name != new_codegen_unit.name() - } - MonoItemPlacement::MultipleCgus => true, - }); - *placement = MonoItemPlacement::MultipleCgus; - } - Entry::Vacant(e) => { - e.insert(MonoItemPlacement::SingleCgu { - cgu_name: new_codegen_unit.name(), - }); - } - } - } - } - - new_partitioning.push(new_codegen_unit); - } - - return PostInliningPartitioning { - codegen_units: new_partitioning, - mono_item_placements, - internalization_candidates, - }; - - fn follow_inlining<'tcx>( - mono_item: MonoItem<'tcx>, - inlining_map: &InliningMap<'tcx>, - visited: &mut FxHashSet>, - ) { - if !visited.insert(mono_item) { - return; - } - - inlining_map.with_inlining_candidates(mono_item, |target| { - follow_inlining(target, inlining_map, visited); - }); - } -} - -fn internalize_symbols<'tcx>( - _tcx: TyCtxt<'tcx>, - partitioning: &mut PostInliningPartitioning<'tcx>, - inlining_map: &InliningMap<'tcx>, -) { - if partitioning.codegen_units.len() == 1 { - // Fast path for when there is only one codegen unit. In this case we - // can internalize all candidates, since there is nowhere else they - // could be accessed from. - for cgu in &mut partitioning.codegen_units { - for candidate in &partitioning.internalization_candidates { - cgu.items_mut().insert(*candidate, (Linkage::Internal, Visibility::Default)); - } - } - - return; - } - - // Build a map from every monomorphization to all the monomorphizations that - // reference it. - let mut accessor_map: FxHashMap, Vec>> = Default::default(); - inlining_map.iter_accesses(|accessor, accessees| { - for accessee in accessees { - accessor_map.entry(*accessee).or_default().push(accessor); - } - }); - - let mono_item_placements = &partitioning.mono_item_placements; - - // For each internalization candidates in each codegen unit, check if it is - // accessed from outside its defining codegen unit. - for cgu in &mut partitioning.codegen_units { - let home_cgu = MonoItemPlacement::SingleCgu { cgu_name: cgu.name() }; - - for (accessee, linkage_and_visibility) in cgu.items_mut() { - if !partitioning.internalization_candidates.contains(accessee) { - // This item is no candidate for internalizing, so skip it. - continue; - } - debug_assert_eq!(mono_item_placements[accessee], home_cgu); - - if let Some(accessors) = accessor_map.get(accessee) { - if accessors - .iter() - .filter_map(|accessor| { - // Some accessors might not have been - // instantiated. We can safely ignore those. - mono_item_placements.get(accessor) - }) - .any(|placement| *placement != home_cgu) - { - // Found an accessor from another CGU, so skip to the next - // item without marking this one as internal. - continue; - } - } - - // If we got here, we did not find any accesses from other CGUs, - // so it's fine to make this monomorphization internal. - *linkage_and_visibility = (Linkage::Internal, Visibility::Default); - } - } -} - -fn characteristic_def_id_of_mono_item<'tcx>( - tcx: TyCtxt<'tcx>, - mono_item: MonoItem<'tcx>, -) -> Option { - match mono_item { - MonoItem::Fn(instance) => { - let def_id = match instance.def { - ty::InstanceDef::Item(def) => def.did, - ty::InstanceDef::VtableShim(..) - | ty::InstanceDef::ReifyShim(..) - | ty::InstanceDef::FnPtrShim(..) - | ty::InstanceDef::ClosureOnceShim { .. } - | ty::InstanceDef::Intrinsic(..) - | ty::InstanceDef::DropGlue(..) - | ty::InstanceDef::Virtual(..) - | ty::InstanceDef::CloneShim(..) => return None, - }; - - // If this is a method, we want to put it into the same module as - // its self-type. If the self-type does not provide a characteristic - // DefId, we use the location of the impl after all. - - if tcx.trait_of_item(def_id).is_some() { - let self_ty = instance.substs.type_at(0); - // This is a default implementation of a trait method. - return characteristic_def_id_of_type(self_ty).or(Some(def_id)); - } - - if let Some(impl_def_id) = tcx.impl_of_method(def_id) { - if tcx.sess.opts.incremental.is_some() - && tcx.trait_id_of_impl(impl_def_id) == tcx.lang_items().drop_trait() - { - // Put `Drop::drop` into the same cgu as `drop_in_place` - // since `drop_in_place` is the only thing that can - // call it. - return None; - } - // This is a method within an impl, find out what the self-type is: - let impl_self_ty = tcx.subst_and_normalize_erasing_regions( - instance.substs, - ty::ParamEnv::reveal_all(), - &tcx.type_of(impl_def_id), - ); - if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) { - return Some(def_id); - } - } - - Some(def_id) - } - MonoItem::Static(def_id) => Some(def_id), - MonoItem::GlobalAsm(hir_id) => Some(tcx.hir().local_def_id(hir_id).to_def_id()), - } -} - -type CguNameCache = FxHashMap<(DefId, bool), Symbol>; - -fn compute_codegen_unit_name( - tcx: TyCtxt<'_>, - name_builder: &mut CodegenUnitNameBuilder<'_>, - def_id: DefId, - volatile: bool, - cache: &mut CguNameCache, -) -> Symbol { - // Find the innermost module that is not nested within a function. - let mut current_def_id = def_id; - let mut cgu_def_id = None; - // Walk backwards from the item we want to find the module for. - loop { - if current_def_id.index == CRATE_DEF_INDEX { - if cgu_def_id.is_none() { - // If we have not found a module yet, take the crate root. - cgu_def_id = Some(DefId { krate: def_id.krate, index: CRATE_DEF_INDEX }); - } - break; - } else if tcx.def_kind(current_def_id) == DefKind::Mod { - if cgu_def_id.is_none() { - cgu_def_id = Some(current_def_id); - } - } else { - // If we encounter something that is not a module, throw away - // any module that we've found so far because we now know that - // it is nested within something else. - cgu_def_id = None; - } - - current_def_id = tcx.parent(current_def_id).unwrap(); - } - - let cgu_def_id = cgu_def_id.unwrap(); - - *cache.entry((cgu_def_id, volatile)).or_insert_with(|| { - let def_path = tcx.def_path(cgu_def_id); - - let components = def_path.data.iter().map(|part| part.data.as_symbol()); - - let volatile_suffix = volatile.then_some("volatile"); - - name_builder.build_cgu_name(def_path.krate, components, volatile_suffix) - }) -} - -fn numbered_codegen_unit_name( - name_builder: &mut CodegenUnitNameBuilder<'_>, - index: usize, -) -> Symbol { - name_builder.build_cgu_name_no_mangle(LOCAL_CRATE, &["cgu"], Some(index)) -} - -fn debug_dump<'a, 'tcx, I>(tcx: TyCtxt<'tcx>, label: &str, cgus: I) -where - I: Iterator>, - 'tcx: 'a, -{ - if cfg!(debug_assertions) { - debug!("{}", label); - for cgu in cgus { - debug!("CodegenUnit {} estimated size {} :", cgu.name(), cgu.size_estimate()); - - for (mono_item, linkage) in cgu.items() { - let symbol_name = mono_item.symbol_name(tcx).name; - let symbol_hash_start = symbol_name.rfind('h'); - let symbol_hash = - symbol_hash_start.map(|i| &symbol_name[i..]).unwrap_or(""); - - debug!( - " - {} [{:?}] [{}] estimated size {}", - mono_item.to_string(tcx, true), - linkage, - symbol_hash, - mono_item.size_estimate(tcx) - ); - } - - debug!(""); - } - } -} - -#[inline(never)] // give this a place in the profiler -fn assert_symbols_are_distinct<'a, 'tcx, I>(tcx: TyCtxt<'tcx>, mono_items: I) -where - I: Iterator>, - 'tcx: 'a, -{ - let _prof_timer = tcx.prof.generic_activity("assert_symbols_are_distinct"); - - let mut symbols: Vec<_> = - mono_items.map(|mono_item| (mono_item, mono_item.symbol_name(tcx))).collect(); - - symbols.sort_by_key(|sym| sym.1); - - for pair in symbols.windows(2) { - let sym1 = &pair[0].1; - let sym2 = &pair[1].1; - - if sym1 == sym2 { - let mono_item1 = pair[0].0; - let mono_item2 = pair[1].0; - - let span1 = mono_item1.local_span(tcx); - let span2 = mono_item2.local_span(tcx); - - // Deterministically select one of the spans for error reporting - let span = match (span1, span2) { - (Some(span1), Some(span2)) => { - Some(if span1.lo().0 > span2.lo().0 { span1 } else { span2 }) - } - (span1, span2) => span1.or(span2), - }; - - let error_message = format!("symbol `{}` is already defined", sym1); - - if let Some(span) = span { - tcx.sess.span_fatal(span, &error_message) - } else { - tcx.sess.fatal(&error_message) - } - } - } -} - -fn collect_and_partition_mono_items( - tcx: TyCtxt<'tcx>, - cnum: CrateNum, -) -> (&'tcx DefIdSet, &'tcx [CodegenUnit<'tcx>]) { - assert_eq!(cnum, LOCAL_CRATE); - - let collection_mode = match tcx.sess.opts.debugging_opts.print_mono_items { - Some(ref s) => { - let mode_string = s.to_lowercase(); - let mode_string = mode_string.trim(); - if mode_string == "eager" { - MonoItemCollectionMode::Eager - } else { - if mode_string != "lazy" { - let message = format!( - "Unknown codegen-item collection mode '{}'. \ - Falling back to 'lazy' mode.", - mode_string - ); - tcx.sess.warn(&message); - } - - MonoItemCollectionMode::Lazy - } - } - None => { - if tcx.sess.opts.cg.link_dead_code == Some(true) { - MonoItemCollectionMode::Eager - } else { - MonoItemCollectionMode::Lazy - } - } - }; - - let (items, inlining_map) = collector::collect_crate_mono_items(tcx, collection_mode); - - tcx.sess.abort_if_errors(); - - let (codegen_units, _) = tcx.sess.time("partition_and_assert_distinct_symbols", || { - sync::join( - || { - &*tcx.arena.alloc_from_iter(partition( - tcx, - items.iter().cloned(), - tcx.sess.codegen_units(), - &inlining_map, - )) - }, - || assert_symbols_are_distinct(tcx, items.iter()), - ) - }); - - let mono_items: DefIdSet = items - .iter() - .filter_map(|mono_item| match *mono_item { - MonoItem::Fn(ref instance) => Some(instance.def_id()), - MonoItem::Static(def_id) => Some(def_id), - _ => None, - }) - .collect(); - - if tcx.sess.opts.debugging_opts.print_mono_items.is_some() { - let mut item_to_cgus: FxHashMap<_, Vec<_>> = Default::default(); - - for cgu in codegen_units { - for (&mono_item, &linkage) in cgu.items() { - item_to_cgus.entry(mono_item).or_default().push((cgu.name(), linkage)); - } - } - - let mut item_keys: Vec<_> = items - .iter() - .map(|i| { - let mut output = i.to_string(tcx, false); - output.push_str(" @@"); - let mut empty = Vec::new(); - let cgus = item_to_cgus.get_mut(i).unwrap_or(&mut empty); - cgus.sort_by_key(|(name, _)| *name); - cgus.dedup(); - for &(ref cgu_name, (linkage, _)) in cgus.iter() { - output.push_str(" "); - output.push_str(&cgu_name.as_str()); - - let linkage_abbrev = match linkage { - Linkage::External => "External", - Linkage::AvailableExternally => "Available", - Linkage::LinkOnceAny => "OnceAny", - Linkage::LinkOnceODR => "OnceODR", - Linkage::WeakAny => "WeakAny", - Linkage::WeakODR => "WeakODR", - Linkage::Appending => "Appending", - Linkage::Internal => "Internal", - Linkage::Private => "Private", - Linkage::ExternalWeak => "ExternalWeak", - Linkage::Common => "Common", - }; - - output.push_str("["); - output.push_str(linkage_abbrev); - output.push_str("]"); - } - output - }) - .collect(); - - item_keys.sort(); - - for item in item_keys { - println!("MONO_ITEM {}", item); - } - } - - (tcx.arena.alloc(mono_items), codegen_units) -} - -pub fn provide(providers: &mut Providers) { - providers.collect_and_partition_mono_items = collect_and_partition_mono_items; - - providers.is_codegened_item = |tcx, def_id| { - let (all_mono_items, _) = tcx.collect_and_partition_mono_items(LOCAL_CRATE); - all_mono_items.contains(&def_id) - }; - - providers.codegen_unit = |tcx, name| { - let (_, all) = tcx.collect_and_partition_mono_items(LOCAL_CRATE); - all.iter() - .find(|cgu| cgu.name() == name) - .unwrap_or_else(|| panic!("failed to find cgu with name {:?}", name)) - }; -} diff --git a/src/librustc_mir/monomorphize/partitioning/default.rs b/src/librustc_mir/monomorphize/partitioning/default.rs new file mode 100644 index 00000000000..b48bae83787 --- /dev/null +++ b/src/librustc_mir/monomorphize/partitioning/default.rs @@ -0,0 +1,552 @@ +use std::collections::hash_map::Entry; + +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_hir::def::DefKind; +use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use rustc_middle::middle::exported_symbols::SymbolExportLevel; +use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, Linkage, Visibility}; +use rustc_middle::mir::mono::{InstantiationMode, MonoItem}; +use rustc_middle::ty::print::characteristic_def_id_of_type; +use rustc_middle::ty::{self, DefIdTree, InstanceDef, TyCtxt}; +use rustc_span::symbol::Symbol; + +use crate::monomorphize::collector::InliningMap; +use crate::monomorphize::partitioning::merging; +use crate::monomorphize::partitioning::{ + MonoItemPlacement, Partitioner, PostInliningPartitioning, PreInliningPartitioning, +}; + +pub struct DefaultPartitioning; + +impl<'tcx> Partitioner<'tcx> for DefaultPartitioning { + fn place_root_mono_items( + &mut self, + tcx: TyCtxt<'tcx>, + mono_items: &mut dyn Iterator>, + ) -> PreInliningPartitioning<'tcx> { + let mut roots = FxHashSet::default(); + let mut codegen_units = FxHashMap::default(); + let is_incremental_build = tcx.sess.opts.incremental.is_some(); + let mut internalization_candidates = FxHashSet::default(); + + // Determine if monomorphizations instantiated in this crate will be made + // available to downstream crates. This depends on whether we are in + // share-generics mode and whether the current crate can even have + // downstream crates. + let export_generics = tcx.sess.opts.share_generics() && tcx.local_crate_exports_generics(); + + let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx); + let cgu_name_cache = &mut FxHashMap::default(); + + for mono_item in mono_items { + match mono_item.instantiation_mode(tcx) { + InstantiationMode::GloballyShared { .. } => {} + InstantiationMode::LocalCopy => continue, + } + + let characteristic_def_id = characteristic_def_id_of_mono_item(tcx, mono_item); + let is_volatile = is_incremental_build && mono_item.is_generic_fn(); + + let codegen_unit_name = match characteristic_def_id { + Some(def_id) => compute_codegen_unit_name( + tcx, + cgu_name_builder, + def_id, + is_volatile, + cgu_name_cache, + ), + None => fallback_cgu_name(cgu_name_builder), + }; + + let codegen_unit = codegen_units + .entry(codegen_unit_name) + .or_insert_with(|| CodegenUnit::new(codegen_unit_name)); + + let mut can_be_internalized = true; + let (linkage, visibility) = mono_item_linkage_and_visibility( + tcx, + &mono_item, + &mut can_be_internalized, + export_generics, + ); + if visibility == Visibility::Hidden && can_be_internalized { + internalization_candidates.insert(mono_item); + } + + codegen_unit.items_mut().insert(mono_item, (linkage, visibility)); + roots.insert(mono_item); + } + + // Always ensure we have at least one CGU; otherwise, if we have a + // crate with just types (for example), we could wind up with no CGU. + if codegen_units.is_empty() { + let codegen_unit_name = fallback_cgu_name(cgu_name_builder); + codegen_units.insert(codegen_unit_name, CodegenUnit::new(codegen_unit_name)); + } + + PreInliningPartitioning { + codegen_units: codegen_units + .into_iter() + .map(|(_, codegen_unit)| codegen_unit) + .collect(), + roots, + internalization_candidates, + } + } + + fn merge_codegen_units( + &mut self, + tcx: TyCtxt<'tcx>, + initial_partitioning: &mut PreInliningPartitioning<'tcx>, + target_cgu_count: usize, + ) { + merging::merge_codegen_units(tcx, initial_partitioning, target_cgu_count); + } + + fn place_inlined_mono_items( + &mut self, + initial_partitioning: PreInliningPartitioning<'tcx>, + inlining_map: &InliningMap<'tcx>, + ) -> PostInliningPartitioning<'tcx> { + let mut new_partitioning = Vec::new(); + let mut mono_item_placements = FxHashMap::default(); + + let PreInliningPartitioning { + codegen_units: initial_cgus, + roots, + internalization_candidates, + } = initial_partitioning; + + let single_codegen_unit = initial_cgus.len() == 1; + + for old_codegen_unit in initial_cgus { + // Collect all items that need to be available in this codegen unit. + let mut reachable = FxHashSet::default(); + for root in old_codegen_unit.items().keys() { + follow_inlining(*root, inlining_map, &mut reachable); + } + + let mut new_codegen_unit = CodegenUnit::new(old_codegen_unit.name()); + + // Add all monomorphizations that are not already there. + for mono_item in reachable { + if let Some(linkage) = old_codegen_unit.items().get(&mono_item) { + // This is a root, just copy it over. + new_codegen_unit.items_mut().insert(mono_item, *linkage); + } else { + if roots.contains(&mono_item) { + bug!( + "GloballyShared mono-item inlined into other CGU: \ + {:?}", + mono_item + ); + } + + // This is a CGU-private copy. + new_codegen_unit + .items_mut() + .insert(mono_item, (Linkage::Internal, Visibility::Default)); + } + + if !single_codegen_unit { + // If there is more than one codegen unit, we need to keep track + // in which codegen units each monomorphization is placed. + match mono_item_placements.entry(mono_item) { + Entry::Occupied(e) => { + let placement = e.into_mut(); + debug_assert!(match *placement { + MonoItemPlacement::SingleCgu { cgu_name } => { + cgu_name != new_codegen_unit.name() + } + MonoItemPlacement::MultipleCgus => true, + }); + *placement = MonoItemPlacement::MultipleCgus; + } + Entry::Vacant(e) => { + e.insert(MonoItemPlacement::SingleCgu { + cgu_name: new_codegen_unit.name(), + }); + } + } + } + } + + new_partitioning.push(new_codegen_unit); + } + + return PostInliningPartitioning { + codegen_units: new_partitioning, + mono_item_placements, + internalization_candidates, + }; + + fn follow_inlining<'tcx>( + mono_item: MonoItem<'tcx>, + inlining_map: &InliningMap<'tcx>, + visited: &mut FxHashSet>, + ) { + if !visited.insert(mono_item) { + return; + } + + inlining_map.with_inlining_candidates(mono_item, |target| { + follow_inlining(target, inlining_map, visited); + }); + } + } + + fn internalize_symbols( + &mut self, + _tcx: TyCtxt<'tcx>, + partitioning: &mut PostInliningPartitioning<'tcx>, + inlining_map: &InliningMap<'tcx>, + ) { + if partitioning.codegen_units.len() == 1 { + // Fast path for when there is only one codegen unit. In this case we + // can internalize all candidates, since there is nowhere else they + // could be accessed from. + for cgu in &mut partitioning.codegen_units { + for candidate in &partitioning.internalization_candidates { + cgu.items_mut().insert(*candidate, (Linkage::Internal, Visibility::Default)); + } + } + + return; + } + + // Build a map from every monomorphization to all the monomorphizations that + // reference it. + let mut accessor_map: FxHashMap, Vec>> = Default::default(); + inlining_map.iter_accesses(|accessor, accessees| { + for accessee in accessees { + accessor_map.entry(*accessee).or_default().push(accessor); + } + }); + + let mono_item_placements = &partitioning.mono_item_placements; + + // For each internalization candidates in each codegen unit, check if it is + // accessed from outside its defining codegen unit. + for cgu in &mut partitioning.codegen_units { + let home_cgu = MonoItemPlacement::SingleCgu { cgu_name: cgu.name() }; + + for (accessee, linkage_and_visibility) in cgu.items_mut() { + if !partitioning.internalization_candidates.contains(accessee) { + // This item is no candidate for internalizing, so skip it. + continue; + } + debug_assert_eq!(mono_item_placements[accessee], home_cgu); + + if let Some(accessors) = accessor_map.get(accessee) { + if accessors + .iter() + .filter_map(|accessor| { + // Some accessors might not have been + // instantiated. We can safely ignore those. + mono_item_placements.get(accessor) + }) + .any(|placement| *placement != home_cgu) + { + // Found an accessor from another CGU, so skip to the next + // item without marking this one as internal. + continue; + } + } + + // If we got here, we did not find any accesses from other CGUs, + // so it's fine to make this monomorphization internal. + *linkage_and_visibility = (Linkage::Internal, Visibility::Default); + } + } + } +} + +fn characteristic_def_id_of_mono_item<'tcx>( + tcx: TyCtxt<'tcx>, + mono_item: MonoItem<'tcx>, +) -> Option { + match mono_item { + MonoItem::Fn(instance) => { + let def_id = match instance.def { + ty::InstanceDef::Item(def) => def.did, + ty::InstanceDef::VtableShim(..) + | ty::InstanceDef::ReifyShim(..) + | ty::InstanceDef::FnPtrShim(..) + | ty::InstanceDef::ClosureOnceShim { .. } + | ty::InstanceDef::Intrinsic(..) + | ty::InstanceDef::DropGlue(..) + | ty::InstanceDef::Virtual(..) + | ty::InstanceDef::CloneShim(..) => return None, + }; + + // If this is a method, we want to put it into the same module as + // its self-type. If the self-type does not provide a characteristic + // DefId, we use the location of the impl after all. + + if tcx.trait_of_item(def_id).is_some() { + let self_ty = instance.substs.type_at(0); + // This is a default implementation of a trait method. + return characteristic_def_id_of_type(self_ty).or(Some(def_id)); + } + + if let Some(impl_def_id) = tcx.impl_of_method(def_id) { + if tcx.sess.opts.incremental.is_some() + && tcx.trait_id_of_impl(impl_def_id) == tcx.lang_items().drop_trait() + { + // Put `Drop::drop` into the same cgu as `drop_in_place` + // since `drop_in_place` is the only thing that can + // call it. + return None; + } + // This is a method within an impl, find out what the self-type is: + let impl_self_ty = tcx.subst_and_normalize_erasing_regions( + instance.substs, + ty::ParamEnv::reveal_all(), + &tcx.type_of(impl_def_id), + ); + if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) { + return Some(def_id); + } + } + + Some(def_id) + } + MonoItem::Static(def_id) => Some(def_id), + MonoItem::GlobalAsm(hir_id) => Some(tcx.hir().local_def_id(hir_id).to_def_id()), + } +} + +fn compute_codegen_unit_name( + tcx: TyCtxt<'_>, + name_builder: &mut CodegenUnitNameBuilder<'_>, + def_id: DefId, + volatile: bool, + cache: &mut CguNameCache, +) -> Symbol { + // Find the innermost module that is not nested within a function. + let mut current_def_id = def_id; + let mut cgu_def_id = None; + // Walk backwards from the item we want to find the module for. + loop { + if current_def_id.index == CRATE_DEF_INDEX { + if cgu_def_id.is_none() { + // If we have not found a module yet, take the crate root. + cgu_def_id = Some(DefId { krate: def_id.krate, index: CRATE_DEF_INDEX }); + } + break; + } else if tcx.def_kind(current_def_id) == DefKind::Mod { + if cgu_def_id.is_none() { + cgu_def_id = Some(current_def_id); + } + } else { + // If we encounter something that is not a module, throw away + // any module that we've found so far because we now know that + // it is nested within something else. + cgu_def_id = None; + } + + current_def_id = tcx.parent(current_def_id).unwrap(); + } + + let cgu_def_id = cgu_def_id.unwrap(); + + *cache.entry((cgu_def_id, volatile)).or_insert_with(|| { + let def_path = tcx.def_path(cgu_def_id); + + let components = def_path.data.iter().map(|part| part.data.as_symbol()); + + let volatile_suffix = volatile.then_some("volatile"); + + name_builder.build_cgu_name(def_path.krate, components, volatile_suffix) + }) +} + +// Anything we can't find a proper codegen unit for goes into this. +fn fallback_cgu_name(name_builder: &mut CodegenUnitNameBuilder<'_>) -> Symbol { + name_builder.build_cgu_name(LOCAL_CRATE, &["fallback"], Some("cgu")) +} + +fn mono_item_linkage_and_visibility( + tcx: TyCtxt<'tcx>, + mono_item: &MonoItem<'tcx>, + can_be_internalized: &mut bool, + export_generics: bool, +) -> (Linkage, Visibility) { + if let Some(explicit_linkage) = mono_item.explicit_linkage(tcx) { + return (explicit_linkage, Visibility::Default); + } + let vis = mono_item_visibility(tcx, mono_item, can_be_internalized, export_generics); + (Linkage::External, vis) +} + +type CguNameCache = FxHashMap<(DefId, bool), Symbol>; + +fn mono_item_visibility( + tcx: TyCtxt<'tcx>, + mono_item: &MonoItem<'tcx>, + can_be_internalized: &mut bool, + export_generics: bool, +) -> Visibility { + let instance = match mono_item { + // This is pretty complicated; see below. + MonoItem::Fn(instance) => instance, + + // Misc handling for generics and such, but otherwise: + MonoItem::Static(def_id) => { + return if tcx.is_reachable_non_generic(*def_id) { + *can_be_internalized = false; + default_visibility(tcx, *def_id, false) + } else { + Visibility::Hidden + }; + } + MonoItem::GlobalAsm(hir_id) => { + let def_id = tcx.hir().local_def_id(*hir_id); + return if tcx.is_reachable_non_generic(def_id) { + *can_be_internalized = false; + default_visibility(tcx, def_id.to_def_id(), false) + } else { + Visibility::Hidden + }; + } + }; + + let def_id = match instance.def { + InstanceDef::Item(def) => def.did, + InstanceDef::DropGlue(def_id, Some(_)) => def_id, + + // These are all compiler glue and such, never exported, always hidden. + InstanceDef::VtableShim(..) + | InstanceDef::ReifyShim(..) + | InstanceDef::FnPtrShim(..) + | InstanceDef::Virtual(..) + | InstanceDef::Intrinsic(..) + | InstanceDef::ClosureOnceShim { .. } + | InstanceDef::DropGlue(..) + | InstanceDef::CloneShim(..) => return Visibility::Hidden, + }; + + // The `start_fn` lang item is actually a monomorphized instance of a + // function in the standard library, used for the `main` function. We don't + // want to export it so we tag it with `Hidden` visibility but this symbol + // is only referenced from the actual `main` symbol which we unfortunately + // don't know anything about during partitioning/collection. As a result we + // forcibly keep this symbol out of the `internalization_candidates` set. + // + // FIXME: eventually we don't want to always force this symbol to have + // hidden visibility, it should indeed be a candidate for + // internalization, but we have to understand that it's referenced + // from the `main` symbol we'll generate later. + // + // This may be fixable with a new `InstanceDef` perhaps? Unsure! + if tcx.lang_items().start_fn() == Some(def_id) { + *can_be_internalized = false; + return Visibility::Hidden; + } + + let is_generic = instance.substs.non_erasable_generics().next().is_some(); + + // Upstream `DefId` instances get different handling than local ones. + if !def_id.is_local() { + return if export_generics && is_generic { + // If it is a upstream monomorphization and we export generics, we must make + // it available to downstream crates. + *can_be_internalized = false; + default_visibility(tcx, def_id, true) + } else { + Visibility::Hidden + }; + } + + if is_generic { + if export_generics { + if tcx.is_unreachable_local_definition(def_id) { + // This instance cannot be used from another crate. + Visibility::Hidden + } else { + // This instance might be useful in a downstream crate. + *can_be_internalized = false; + default_visibility(tcx, def_id, true) + } + } else { + // We are not exporting generics or the definition is not reachable + // for downstream crates, we can internalize its instantiations. + Visibility::Hidden + } + } else { + // If this isn't a generic function then we mark this a `Default` if + // this is a reachable item, meaning that it's a symbol other crates may + // access when they link to us. + if tcx.is_reachable_non_generic(def_id) { + *can_be_internalized = false; + debug_assert!(!is_generic); + return default_visibility(tcx, def_id, false); + } + + // If this isn't reachable then we're gonna tag this with `Hidden` + // visibility. In some situations though we'll want to prevent this + // symbol from being internalized. + // + // There's two categories of items here: + // + // * First is weak lang items. These are basically mechanisms for + // libcore to forward-reference symbols defined later in crates like + // the standard library or `#[panic_handler]` definitions. The + // definition of these weak lang items needs to be referenceable by + // libcore, so we're no longer a candidate for internalization. + // Removal of these functions can't be done by LLVM but rather must be + // done by the linker as it's a non-local decision. + // + // * Second is "std internal symbols". Currently this is primarily used + // for allocator symbols. Allocators are a little weird in their + // implementation, but the idea is that the compiler, at the last + // minute, defines an allocator with an injected object file. The + // `alloc` crate references these symbols (`__rust_alloc`) and the + // definition doesn't get hooked up until a linked crate artifact is + // generated. + // + // The symbols synthesized by the compiler (`__rust_alloc`) are thin + // veneers around the actual implementation, some other symbol which + // implements the same ABI. These symbols (things like `__rg_alloc`, + // `__rdl_alloc`, `__rde_alloc`, etc), are all tagged with "std + // internal symbols". + // + // The std-internal symbols here **should not show up in a dll as an + // exported interface**, so they return `false` from + // `is_reachable_non_generic` above and we'll give them `Hidden` + // visibility below. Like the weak lang items, though, we can't let + // LLVM internalize them as this decision is left up to the linker to + // omit them, so prevent them from being internalized. + let attrs = tcx.codegen_fn_attrs(def_id); + if attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) { + *can_be_internalized = false; + } + + Visibility::Hidden + } +} + +fn default_visibility(tcx: TyCtxt<'_>, id: DefId, is_generic: bool) -> Visibility { + if !tcx.sess.target.target.options.default_hidden_visibility { + return Visibility::Default; + } + + // Generic functions never have export-level C. + if is_generic { + return Visibility::Hidden; + } + + // Things with export level C don't get instantiated in + // downstream crates. + if !id.is_local() { + return Visibility::Hidden; + } + + // C-export level items remain at `Default`, all other internal + // items become `Hidden`. + match tcx.reachable_non_generics(id.krate).get(&id) { + Some(SymbolExportLevel::C) => Visibility::Default, + _ => Visibility::Hidden, + } +} diff --git a/src/librustc_mir/monomorphize/partitioning/merging.rs b/src/librustc_mir/monomorphize/partitioning/merging.rs new file mode 100644 index 00000000000..1787e6df1b9 --- /dev/null +++ b/src/librustc_mir/monomorphize/partitioning/merging.rs @@ -0,0 +1,110 @@ +use std::cmp; + +use rustc_data_structures::fx::FxHashMap; +use rustc_hir::def_id::LOCAL_CRATE; +use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder}; +use rustc_middle::ty::TyCtxt; +use rustc_span::symbol::{Symbol, SymbolStr}; + +use crate::monomorphize::partitioning::PreInliningPartitioning; + +pub fn merge_codegen_units<'tcx>( + tcx: TyCtxt<'tcx>, + initial_partitioning: &mut PreInliningPartitioning<'tcx>, + target_cgu_count: usize, +) { + assert!(target_cgu_count >= 1); + let codegen_units = &mut initial_partitioning.codegen_units; + + // Note that at this point in time the `codegen_units` here may not be in a + // deterministic order (but we know they're deterministically the same set). + // We want this merging to produce a deterministic ordering of codegen units + // from the input. + // + // Due to basically how we've implemented the merging below (merge the two + // smallest into each other) we're sure to start off with a deterministic + // order (sorted by name). This'll mean that if two cgus have the same size + // the stable sort below will keep everything nice and deterministic. + codegen_units.sort_by_cached_key(|cgu| cgu.name().as_str()); + + // This map keeps track of what got merged into what. + let mut cgu_contents: FxHashMap> = + codegen_units.iter().map(|cgu| (cgu.name(), vec![cgu.name().as_str()])).collect(); + + // Merge the two smallest codegen units until the target size is reached. + while codegen_units.len() > target_cgu_count { + // Sort small cgus to the back + codegen_units.sort_by_cached_key(|cgu| cmp::Reverse(cgu.size_estimate())); + let mut smallest = codegen_units.pop().unwrap(); + let second_smallest = codegen_units.last_mut().unwrap(); + + // Move the mono-items from `smallest` to `second_smallest` + second_smallest.modify_size_estimate(smallest.size_estimate()); + for (k, v) in smallest.items_mut().drain() { + second_smallest.items_mut().insert(k, v); + } + + // Record that `second_smallest` now contains all the stuff that was in + // `smallest` before. + let mut consumed_cgu_names = cgu_contents.remove(&smallest.name()).unwrap(); + cgu_contents.get_mut(&second_smallest.name()).unwrap().extend(consumed_cgu_names.drain(..)); + + debug!( + "CodegenUnit {} merged into CodegenUnit {}", + smallest.name(), + second_smallest.name() + ); + } + + let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx); + + if tcx.sess.opts.incremental.is_some() { + // If we are doing incremental compilation, we want CGU names to + // reflect the path of the source level module they correspond to. + // For CGUs that contain the code of multiple modules because of the + // merging done above, we use a concatenation of the names of + // all contained CGUs. + let new_cgu_names: FxHashMap = cgu_contents + .into_iter() + // This `filter` makes sure we only update the name of CGUs that + // were actually modified by merging. + .filter(|(_, cgu_contents)| cgu_contents.len() > 1) + .map(|(current_cgu_name, cgu_contents)| { + let mut cgu_contents: Vec<&str> = cgu_contents.iter().map(|s| &s[..]).collect(); + + // Sort the names, so things are deterministic and easy to + // predict. + cgu_contents.sort(); + + (current_cgu_name, cgu_contents.join("--")) + }) + .collect(); + + for cgu in codegen_units.iter_mut() { + if let Some(new_cgu_name) = new_cgu_names.get(&cgu.name()) { + if tcx.sess.opts.debugging_opts.human_readable_cgu_names { + cgu.set_name(Symbol::intern(&new_cgu_name)); + } else { + // If we don't require CGU names to be human-readable, we + // use a fixed length hash of the composite CGU name + // instead. + let new_cgu_name = CodegenUnit::mangle_name(&new_cgu_name); + cgu.set_name(Symbol::intern(&new_cgu_name)); + } + } + } + } else { + // If we are compiling non-incrementally we just generate simple CGU + // names containing an index. + for (index, cgu) in codegen_units.iter_mut().enumerate() { + cgu.set_name(numbered_codegen_unit_name(cgu_name_builder, index)); + } + } +} + +fn numbered_codegen_unit_name( + name_builder: &mut CodegenUnitNameBuilder<'_>, + index: usize, +) -> Symbol { + name_builder.build_cgu_name_no_mangle(LOCAL_CRATE, &["cgu"], Some(index)) +} diff --git a/src/librustc_mir/monomorphize/partitioning/mod.rs b/src/librustc_mir/monomorphize/partitioning/mod.rs new file mode 100644 index 00000000000..9dfbd65e1b1 --- /dev/null +++ b/src/librustc_mir/monomorphize/partitioning/mod.rs @@ -0,0 +1,433 @@ +//! Partitioning Codegen Units for Incremental Compilation +//! ====================================================== +//! +//! The task of this module is to take the complete set of monomorphizations of +//! a crate and produce a set of codegen units from it, where a codegen unit +//! is a named set of (mono-item, linkage) pairs. That is, this module +//! decides which monomorphization appears in which codegen units with which +//! linkage. The following paragraphs describe some of the background on the +//! partitioning scheme. +//! +//! The most important opportunity for saving on compilation time with +//! incremental compilation is to avoid re-codegenning and re-optimizing code. +//! Since the unit of codegen and optimization for LLVM is "modules" or, how +//! we call them "codegen units", the particulars of how much time can be saved +//! by incremental compilation are tightly linked to how the output program is +//! partitioned into these codegen units prior to passing it to LLVM -- +//! especially because we have to treat codegen units as opaque entities once +//! they are created: There is no way for us to incrementally update an existing +//! LLVM module and so we have to build any such module from scratch if it was +//! affected by some change in the source code. +//! +//! From that point of view it would make sense to maximize the number of +//! codegen units by, for example, putting each function into its own module. +//! That way only those modules would have to be re-compiled that were actually +//! affected by some change, minimizing the number of functions that could have +//! been re-used but just happened to be located in a module that is +//! re-compiled. +//! +//! However, since LLVM optimization does not work across module boundaries, +//! using such a highly granular partitioning would lead to very slow runtime +//! code since it would effectively prohibit inlining and other inter-procedure +//! optimizations. We want to avoid that as much as possible. +//! +//! Thus we end up with a trade-off: The bigger the codegen units, the better +//! LLVM's optimizer can do its work, but also the smaller the compilation time +//! reduction we get from incremental compilation. +//! +//! Ideally, we would create a partitioning such that there are few big codegen +//! units with few interdependencies between them. For now though, we use the +//! following heuristic to determine the partitioning: +//! +//! - There are two codegen units for every source-level module: +//! - One for "stable", that is non-generic, code +//! - One for more "volatile" code, i.e., monomorphized instances of functions +//! defined in that module +//! +//! In order to see why this heuristic makes sense, let's take a look at when a +//! codegen unit can get invalidated: +//! +//! 1. The most straightforward case is when the BODY of a function or global +//! changes. Then any codegen unit containing the code for that item has to be +//! re-compiled. Note that this includes all codegen units where the function +//! has been inlined. +//! +//! 2. The next case is when the SIGNATURE of a function or global changes. In +//! this case, all codegen units containing a REFERENCE to that item have to be +//! re-compiled. This is a superset of case 1. +//! +//! 3. The final and most subtle case is when a REFERENCE to a generic function +//! is added or removed somewhere. Even though the definition of the function +//! might be unchanged, a new REFERENCE might introduce a new monomorphized +//! instance of this function which has to be placed and compiled somewhere. +//! Conversely, when removing a REFERENCE, it might have been the last one with +//! that particular set of generic arguments and thus we have to remove it. +//! +//! From the above we see that just using one codegen unit per source-level +//! module is not such a good idea, since just adding a REFERENCE to some +//! generic item somewhere else would invalidate everything within the module +//! containing the generic item. The heuristic above reduces this detrimental +//! side-effect of references a little by at least not touching the non-generic +//! code of the module. +//! +//! A Note on Inlining +//! ------------------ +//! As briefly mentioned above, in order for LLVM to be able to inline a +//! function call, the body of the function has to be available in the LLVM +//! module where the call is made. This has a few consequences for partitioning: +//! +//! - The partitioning algorithm has to take care of placing functions into all +//! codegen units where they should be available for inlining. It also has to +//! decide on the correct linkage for these functions. +//! +//! - The partitioning algorithm has to know which functions are likely to get +//! inlined, so it can distribute function instantiations accordingly. Since +//! there is no way of knowing for sure which functions LLVM will decide to +//! inline in the end, we apply a heuristic here: Only functions marked with +//! `#[inline]` are considered for inlining by the partitioner. The current +//! implementation will not try to determine if a function is likely to be +//! inlined by looking at the functions definition. +//! +//! Note though that as a side-effect of creating a codegen units per +//! source-level module, functions from the same module will be available for +//! inlining, even when they are not marked `#[inline]`. + +mod default; +mod merging; + +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::sync; +use rustc_hir::def_id::{CrateNum, DefIdSet, LOCAL_CRATE}; +use rustc_middle::mir::mono::MonoItem; +use rustc_middle::mir::mono::{CodegenUnit, Linkage}; +use rustc_middle::ty::query::Providers; +use rustc_middle::ty::TyCtxt; +use rustc_span::symbol::Symbol; + +use crate::monomorphize::collector::InliningMap; +use crate::monomorphize::collector::{self, MonoItemCollectionMode}; + +trait Partitioner<'tcx> { + fn place_root_mono_items( + &mut self, + tcx: TyCtxt<'tcx>, + mono_items: &mut dyn Iterator>, + ) -> PreInliningPartitioning<'tcx>; + + fn merge_codegen_units( + &mut self, + tcx: TyCtxt<'tcx>, + initial_partitioning: &mut PreInliningPartitioning<'tcx>, + target_cgu_count: usize, + ); + + fn place_inlined_mono_items( + &mut self, + initial_partitioning: PreInliningPartitioning<'tcx>, + inlining_map: &InliningMap<'tcx>, + ) -> PostInliningPartitioning<'tcx>; + + fn internalize_symbols( + &mut self, + tcx: TyCtxt<'tcx>, + partitioning: &mut PostInliningPartitioning<'tcx>, + inlining_map: &InliningMap<'tcx>, + ); +} + +fn get_partitioner<'tcx>(tcx: TyCtxt<'tcx>) -> Box> { + let strategy = match &tcx.sess.opts.debugging_opts.cgu_partitioning_strategy { + None => "default", + Some(s) => &s[..], + }; + + match strategy { + "default" => Box::new(default::DefaultPartitioning), + _ => tcx.sess.fatal("unknown partitioning strategy"), + } +} + +pub fn partition<'tcx>( + tcx: TyCtxt<'tcx>, + mono_items: &mut dyn Iterator>, + max_cgu_count: usize, + inlining_map: &InliningMap<'tcx>, +) -> Vec> { + let _prof_timer = tcx.prof.generic_activity("cgu_partitioning"); + + let mut partitioner = get_partitioner(tcx); + // In the first step, we place all regular monomorphizations into their + // respective 'home' codegen unit. Regular monomorphizations are all + // functions and statics defined in the local crate. + let mut initial_partitioning = { + let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_roots"); + partitioner.place_root_mono_items(tcx, mono_items) + }; + + initial_partitioning.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx)); + + debug_dump(tcx, "INITIAL PARTITIONING:", initial_partitioning.codegen_units.iter()); + + // Merge until we have at most `max_cgu_count` codegen units. + { + let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_merge_cgus"); + partitioner.merge_codegen_units(tcx, &mut initial_partitioning, max_cgu_count); + debug_dump(tcx, "POST MERGING:", initial_partitioning.codegen_units.iter()); + } + + // In the next step, we use the inlining map to determine which additional + // monomorphizations have to go into each codegen unit. These additional + // monomorphizations can be drop-glue, functions from external crates, and + // local functions the definition of which is marked with `#[inline]`. + let mut post_inlining = { + let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_inline_items"); + partitioner.place_inlined_mono_items(initial_partitioning, inlining_map) + }; + + post_inlining.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx)); + + debug_dump(tcx, "POST INLINING:", post_inlining.codegen_units.iter()); + + // Next we try to make as many symbols "internal" as possible, so LLVM has + // more freedom to optimize. + if tcx.sess.opts.cg.link_dead_code != Some(true) { + let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_internalize_symbols"); + partitioner.internalize_symbols(tcx, &mut post_inlining, inlining_map); + } + + // Finally, sort by codegen unit name, so that we get deterministic results. + let PostInliningPartitioning { + codegen_units: mut result, + mono_item_placements: _, + internalization_candidates: _, + } = post_inlining; + + result.sort_by_cached_key(|cgu| cgu.name().as_str()); + + result +} + +pub struct PreInliningPartitioning<'tcx> { + codegen_units: Vec>, + roots: FxHashSet>, + internalization_candidates: FxHashSet>, +} + +/// For symbol internalization, we need to know whether a symbol/mono-item is +/// accessed from outside the codegen unit it is defined in. This type is used +/// to keep track of that. +#[derive(Clone, PartialEq, Eq, Debug)] +enum MonoItemPlacement { + SingleCgu { cgu_name: Symbol }, + MultipleCgus, +} + +struct PostInliningPartitioning<'tcx> { + codegen_units: Vec>, + mono_item_placements: FxHashMap, MonoItemPlacement>, + internalization_candidates: FxHashSet>, +} + +fn debug_dump<'a, 'tcx, I>(tcx: TyCtxt<'tcx>, label: &str, cgus: I) +where + I: Iterator>, + 'tcx: 'a, +{ + if cfg!(debug_assertions) { + debug!("{}", label); + for cgu in cgus { + debug!("CodegenUnit {} estimated size {} :", cgu.name(), cgu.size_estimate()); + + for (mono_item, linkage) in cgu.items() { + let symbol_name = mono_item.symbol_name(tcx).name; + let symbol_hash_start = symbol_name.rfind('h'); + let symbol_hash = + symbol_hash_start.map(|i| &symbol_name[i..]).unwrap_or(""); + + debug!( + " - {} [{:?}] [{}] estimated size {}", + mono_item.to_string(tcx, true), + linkage, + symbol_hash, + mono_item.size_estimate(tcx) + ); + } + + debug!(""); + } + } +} + +#[inline(never)] // give this a place in the profiler +fn assert_symbols_are_distinct<'a, 'tcx, I>(tcx: TyCtxt<'tcx>, mono_items: I) +where + I: Iterator>, + 'tcx: 'a, +{ + let _prof_timer = tcx.prof.generic_activity("assert_symbols_are_distinct"); + + let mut symbols: Vec<_> = + mono_items.map(|mono_item| (mono_item, mono_item.symbol_name(tcx))).collect(); + + symbols.sort_by_key(|sym| sym.1); + + for pair in symbols.windows(2) { + let sym1 = &pair[0].1; + let sym2 = &pair[1].1; + + if sym1 == sym2 { + let mono_item1 = pair[0].0; + let mono_item2 = pair[1].0; + + let span1 = mono_item1.local_span(tcx); + let span2 = mono_item2.local_span(tcx); + + // Deterministically select one of the spans for error reporting + let span = match (span1, span2) { + (Some(span1), Some(span2)) => { + Some(if span1.lo().0 > span2.lo().0 { span1 } else { span2 }) + } + (span1, span2) => span1.or(span2), + }; + + let error_message = format!("symbol `{}` is already defined", sym1); + + if let Some(span) = span { + tcx.sess.span_fatal(span, &error_message) + } else { + tcx.sess.fatal(&error_message) + } + } + } +} + +fn collect_and_partition_mono_items<'tcx>( + tcx: TyCtxt<'tcx>, + cnum: CrateNum, +) -> (&'tcx DefIdSet, &'tcx [CodegenUnit<'tcx>]) { + assert_eq!(cnum, LOCAL_CRATE); + + let collection_mode = match tcx.sess.opts.debugging_opts.print_mono_items { + Some(ref s) => { + let mode_string = s.to_lowercase(); + let mode_string = mode_string.trim(); + if mode_string == "eager" { + MonoItemCollectionMode::Eager + } else { + if mode_string != "lazy" { + let message = format!( + "Unknown codegen-item collection mode '{}'. \ + Falling back to 'lazy' mode.", + mode_string + ); + tcx.sess.warn(&message); + } + + MonoItemCollectionMode::Lazy + } + } + None => { + if tcx.sess.opts.cg.link_dead_code == Some(true) { + MonoItemCollectionMode::Eager + } else { + MonoItemCollectionMode::Lazy + } + } + }; + + let (items, inlining_map) = collector::collect_crate_mono_items(tcx, collection_mode); + + tcx.sess.abort_if_errors(); + + let (codegen_units, _) = tcx.sess.time("partition_and_assert_distinct_symbols", || { + sync::join( + || { + &*tcx.arena.alloc_from_iter(partition( + tcx, + &mut items.iter().cloned(), + tcx.sess.codegen_units(), + &inlining_map, + )) + }, + || assert_symbols_are_distinct(tcx, items.iter()), + ) + }); + + let mono_items: DefIdSet = items + .iter() + .filter_map(|mono_item| match *mono_item { + MonoItem::Fn(ref instance) => Some(instance.def_id()), + MonoItem::Static(def_id) => Some(def_id), + _ => None, + }) + .collect(); + + if tcx.sess.opts.debugging_opts.print_mono_items.is_some() { + let mut item_to_cgus: FxHashMap<_, Vec<_>> = Default::default(); + + for cgu in codegen_units { + for (&mono_item, &linkage) in cgu.items() { + item_to_cgus.entry(mono_item).or_default().push((cgu.name(), linkage)); + } + } + + let mut item_keys: Vec<_> = items + .iter() + .map(|i| { + let mut output = i.to_string(tcx, false); + output.push_str(" @@"); + let mut empty = Vec::new(); + let cgus = item_to_cgus.get_mut(i).unwrap_or(&mut empty); + cgus.sort_by_key(|(name, _)| *name); + cgus.dedup(); + for &(ref cgu_name, (linkage, _)) in cgus.iter() { + output.push_str(" "); + output.push_str(&cgu_name.as_str()); + + let linkage_abbrev = match linkage { + Linkage::External => "External", + Linkage::AvailableExternally => "Available", + Linkage::LinkOnceAny => "OnceAny", + Linkage::LinkOnceODR => "OnceODR", + Linkage::WeakAny => "WeakAny", + Linkage::WeakODR => "WeakODR", + Linkage::Appending => "Appending", + Linkage::Internal => "Internal", + Linkage::Private => "Private", + Linkage::ExternalWeak => "ExternalWeak", + Linkage::Common => "Common", + }; + + output.push_str("["); + output.push_str(linkage_abbrev); + output.push_str("]"); + } + output + }) + .collect(); + + item_keys.sort(); + + for item in item_keys { + println!("MONO_ITEM {}", item); + } + } + + (tcx.arena.alloc(mono_items), codegen_units) +} + +pub fn provide(providers: &mut Providers) { + providers.collect_and_partition_mono_items = collect_and_partition_mono_items; + + providers.is_codegened_item = |tcx, def_id| { + let (all_mono_items, _) = tcx.collect_and_partition_mono_items(LOCAL_CRATE); + all_mono_items.contains(&def_id) + }; + + providers.codegen_unit = |tcx, name| { + let (_, all) = tcx.collect_and_partition_mono_items(LOCAL_CRATE); + all.iter() + .find(|cgu| cgu.name() == name) + .unwrap_or_else(|| panic!("failed to find cgu with name {:?}", name)) + }; +} diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 6a7653b6075..479b6c2a6ca 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -1,6 +1,6 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_hir::lang_items::FnMutTraitLangItem; +use rustc_hir::lang_items::LangItem; use rustc_middle::mir::*; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::{InternalSubsts, Subst}; @@ -62,7 +62,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' build_call_shim(tcx, instance, None, CallKind::Direct(def_id), None) } ty::InstanceDef::ClosureOnceShim { call_once: _ } => { - let fn_mut = tcx.require_lang_item(FnMutTraitLangItem, None); + let fn_mut = tcx.require_lang_item(LangItem::FnMut, None); let call_mut = tcx .associated_items(fn_mut) .in_definition_order() @@ -295,7 +295,7 @@ fn deref_subpath(&self, _path: Self::Path) -> Option { fn downcast_subpath(&self, _path: Self::Path, _variant: VariantIdx) -> Option { Some(()) } - fn array_subpath(&self, _path: Self::Path, _index: u32, _size: u32) -> Option { + fn array_subpath(&self, _path: Self::Path, _index: u64, _size: u64) -> Option { None } } diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs index 4812ef5a894..e21f314ca15 100644 --- a/src/librustc_mir/transform/check_consts/validation.rs +++ b/src/librustc_mir/transform/check_consts/validation.rs @@ -1,7 +1,7 @@ //! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations. use rustc_errors::struct_span_err; -use rustc_hir::{self as hir, lang_items}; +use rustc_hir::{self as hir, LangItem}; use rustc_hir::{def_id::DefId, HirId}; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; @@ -618,7 +618,7 @@ fn check_return_ty_is_sync(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, hir_id: HirId) tcx.infer_ctxt().enter(|infcx| { let cause = traits::ObligationCause::new(body.span, hir_id, traits::SharedStatic); let mut fulfillment_cx = traits::FulfillmentContext::new(); - let sync_def_id = tcx.require_lang_item(lang_items::SyncTraitLangItem, Some(body.span)); + let sync_def_id = tcx.require_lang_item(LangItem::Sync, Some(body.span)); fulfillment_cx.register_bound(&infcx, ty::ParamEnv::empty(), ty, sync_def_id, cause); if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) { infcx.report_fulfillment_errors(&err, None, false); diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index be23fe7247e..56479b047fa 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -14,9 +14,9 @@ MutVisitor, MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor, }; use rustc_middle::mir::{ - AggregateKind, AssertKind, BasicBlock, BinOp, Body, ClearCrossCrate, Constant, Local, - LocalDecl, LocalKind, Location, Operand, Place, Rvalue, SourceInfo, SourceScope, - SourceScopeData, Statement, StatementKind, Terminator, TerminatorKind, UnOp, RETURN_PLACE, + AssertKind, BasicBlock, BinOp, Body, ClearCrossCrate, Constant, Local, LocalDecl, LocalKind, + Location, Operand, Place, Rvalue, SourceInfo, SourceScope, SourceScopeData, Statement, + StatementKind, Terminator, TerminatorKind, UnOp, RETURN_PLACE, }; use rustc_middle::ty::layout::{HasTyCtxt, LayoutError, TyAndLayout}; use rustc_middle::ty::subst::{InternalSubsts, Subst}; @@ -28,9 +28,9 @@ use crate::const_eval::ConstEvalErr; use crate::interpret::{ - self, compile_time_machine, truncate, AllocId, Allocation, Frame, ImmTy, Immediate, InterpCx, - LocalState, LocalValue, MemPlace, Memory, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy, - Pointer, ScalarMaybeUninit, StackPopCleanup, + self, compile_time_machine, truncate, AllocId, Allocation, ConstValue, Frame, ImmTy, Immediate, + InterpCx, LocalState, LocalValue, MemPlace, Memory, MemoryKind, OpTy, Operand as InterpOperand, + PlaceTy, Pointer, ScalarMaybeUninit, StackPopCleanup, }; use crate::transform::{MirPass, MirSource}; @@ -824,19 +824,18 @@ fn replace_with_const( )); } Immediate::ScalarPair( - ScalarMaybeUninit::Scalar(one), - ScalarMaybeUninit::Scalar(two), + ScalarMaybeUninit::Scalar(_), + ScalarMaybeUninit::Scalar(_), ) => { - // Found a value represented as a pair. For now only do cont-prop if type of - // Rvalue is also a pair with two scalars. The more general case is more - // complicated to implement so we'll do it later. - // FIXME: implement the general case stated above ^. - let ty = &value.layout.ty.kind; + // Found a value represented as a pair. For now only do const-prop if the type + // of `rvalue` is also a tuple with two scalars. + // FIXME: enable the general case stated above ^. + let ty = &value.layout.ty; // Only do it for tuples - if let ty::Tuple(substs) = ty { + if let ty::Tuple(substs) = ty.kind { // Only do it if tuple is also a pair with two scalars if substs.len() == 2 { - let opt_ty1_ty2 = self.use_ecx(|this| { + let alloc = self.use_ecx(|this| { let ty1 = substs[0].expect_ty(); let ty2 = substs[1].expect_ty(); let ty_is_scalar = |ty| { @@ -844,24 +843,38 @@ fn replace_with_const( == Some(true) }; if ty_is_scalar(ty1) && ty_is_scalar(ty2) { - Ok(Some((ty1, ty2))) + let alloc = this + .ecx + .intern_with_temp_alloc(value.layout, |ecx, dest| { + ecx.write_immediate_to_mplace(*imm, dest) + }) + .unwrap(); + Ok(Some(alloc)) } else { Ok(None) } }); - if let Some(Some((ty1, ty2))) = opt_ty1_ty2 { - *rval = Rvalue::Aggregate( - Box::new(AggregateKind::Tuple), - vec![ - self.operand_from_scalar(one, ty1, source_info.span), - self.operand_from_scalar(two, ty2, source_info.span), - ], - ); + if let Some(Some(alloc)) = alloc { + // Assign entire constant in a single statement. + // We can't use aggregates, as we run after the aggregate-lowering `MirPhase`. + *rval = Rvalue::Use(Operand::Constant(Box::new(Constant { + span: source_info.span, + user_ty: None, + literal: self.ecx.tcx.mk_const(ty::Const { + ty, + val: ty::ConstKind::Value(ConstValue::ByRef { + alloc, + offset: Size::ZERO, + }), + }), + }))); } } } } + // Scalars or scalar pairs that contain undef values are assumed to not have + // successfully evaluated and are thus not propagated. _ => {} } } diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index ad49090bfc5..5f193069356 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -219,7 +219,7 @@ fn field_subpath(&self, path: Self::Path, field: Field) -> Option { }) } - fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option { + fn array_subpath(&self, path: Self::Path, index: u64, size: u64) -> Option { dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e { ProjectionElem::ConstantIndex { offset, min_length, from_end } => { debug_assert!(size == min_length, "min_length should be exact for arrays"); diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 52c5f4e25cf..a22075e760a 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -57,16 +57,17 @@ use crate::transform::simplify; use crate::transform::{MirPass, MirSource}; use crate::util::dump_mir; +use crate::util::expand_aggregate; use crate::util::storage; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_hir::lang_items::{GeneratorStateLangItem, PinTypeLangItem}; +use rustc_hir::lang_items::LangItem; use rustc_index::bit_set::{BitMatrix, BitSet}; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; use rustc_middle::mir::*; -use rustc_middle::ty::subst::SubstsRef; +use rustc_middle::ty::subst::{Subst, SubstsRef}; use rustc_middle::ty::GeneratorSubsts; use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt}; use rustc_target::abi::VariantIdx; @@ -236,10 +237,28 @@ struct TransformVisitor<'tcx> { } impl TransformVisitor<'tcx> { - // Make a GeneratorState rvalue - fn make_state(&self, idx: VariantIdx, val: Operand<'tcx>) -> Rvalue<'tcx> { - let adt = AggregateKind::Adt(self.state_adt_ref, idx, self.state_substs, None, None); - Rvalue::Aggregate(box adt, vec![val]) + // Make a GeneratorState variant assignment. `core::ops::GeneratorState` only has single + // element tuple variants, so we can just write to the downcasted first field and then set the + // discriminant to the appropriate variant. + fn make_state( + &self, + idx: VariantIdx, + val: Operand<'tcx>, + source_info: SourceInfo, + ) -> impl Iterator> { + let kind = AggregateKind::Adt(self.state_adt_ref, idx, self.state_substs, None, None); + assert_eq!(self.state_adt_ref.variants[idx].fields.len(), 1); + let ty = self + .tcx + .type_of(self.state_adt_ref.variants[idx].fields[0].did) + .subst(self.tcx, self.state_substs); + expand_aggregate( + Place::return_place(), + std::iter::once((val, ty)), + kind, + source_info, + self.tcx, + ) } // Create a Place referencing a generator struct field @@ -325,13 +344,7 @@ fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockDat if let Some((state_idx, resume, v, drop)) = ret_val { let source_info = data.terminator().source_info; // We must assign the value first in case it gets declared dead below - data.statements.push(Statement { - source_info, - kind: StatementKind::Assign(box ( - Place::return_place(), - self.make_state(state_idx, v), - )), - }); + data.statements.extend(self.make_state(state_idx, v, source_info)); let state = if let Some((resume, resume_arg)) = resume { // Yield let state = 3 + self.suspension_points.len(); @@ -382,7 +395,7 @@ fn make_generator_state_argument_indirect<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Bo fn make_generator_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let ref_gen_ty = body.local_decls.raw[1].ty; - let pin_did = tcx.require_lang_item(PinTypeLangItem, Some(body.span)); + let pin_did = tcx.require_lang_item(LangItem::Pin, Some(body.span)); let pin_adt_ref = tcx.adt_def(pin_did); let substs = tcx.intern_substs(&[ref_gen_ty.into()]); let pin_ref_gen_ty = tcx.mk_adt(pin_adt_ref, substs); @@ -1257,7 +1270,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<' }; // Compute GeneratorState - let state_did = tcx.require_lang_item(GeneratorStateLangItem, None); + let state_did = tcx.require_lang_item(LangItem::GeneratorState, None); let state_adt_ref = tcx.adt_def(state_did); let state_substs = tcx.intern_substs(&[yield_ty.into(), body.return_ty().into()]); let ret_ty = tcx.mk_adt(state_adt_ref, state_substs); diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 1c1c54434d6..0db5bd662ca 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -60,7 +60,7 @@ pub(crate) fn provide(providers: &mut Providers) { mir_const_qualif_const_arg: |tcx, (did, param_did)| { mir_const_qualif(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) }) }, - mir_validated, + mir_promoted, mir_drops_elaborated_and_const_checked, optimized_mir, optimized_mir_of_const_arg, @@ -189,7 +189,7 @@ pub fn run_passes( } if validate { - validate::Validator { when: format!("input to phase {:?}", mir_phase) } + validate::Validator { when: format!("input to phase {:?}", mir_phase), mir_phase } .run_pass(tcx, source, body); } @@ -210,8 +210,11 @@ pub fn run_passes( run_hooks(body, index, true); if validate { - validate::Validator { when: format!("after {} in phase {:?}", pass.name(), mir_phase) } - .run_pass(tcx, source, body); + validate::Validator { + when: format!("after {} in phase {:?}", pass.name(), mir_phase), + mir_phase, + } + .run_pass(tcx, source, body); } index += 1; @@ -225,8 +228,8 @@ pub fn run_passes( body.phase = mir_phase; - if mir_phase == MirPhase::Optimized { - validate::Validator { when: format!("end of phase {:?}", mir_phase) } + if mir_phase == MirPhase::Optimization { + validate::Validator { when: format!("end of phase {:?}", mir_phase), mir_phase } .run_pass(tcx, source, body); } } @@ -240,7 +243,7 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> } // N.B., this `borrow()` is guaranteed to be valid (i.e., the value - // cannot yet be stolen), because `mir_validated()`, which steals + // cannot yet be stolen), because `mir_promoted()`, which steals // from `mir_const(), forces this query to execute before // performing the steal. let body = &tcx.mir_const(def).borrow(); @@ -311,12 +314,12 @@ fn mir_const<'tcx>( tcx.alloc_steal_mir(body) } -fn mir_validated( +fn mir_promoted( tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam, ) -> (&'tcx Steal>, &'tcx Steal>>) { if let Some(def) = def.try_upgrade(tcx) { - return tcx.mir_validated(def); + return tcx.mir_promoted(def); } // Ensure that we compute the `mir_const_qualif` for constants at @@ -351,7 +354,7 @@ fn mir_validated( &mut body, InstanceDef::Item(def.to_global()), None, - MirPhase::Validated, + MirPhase::ConstPromotion, &[promote, opt_coverage], ); @@ -367,7 +370,7 @@ fn mir_drops_elaborated_and_const_checked<'tcx>( return tcx.mir_drops_elaborated_and_const_checked(def); } - // (Mir-)Borrowck uses `mir_validated`, so we have to force it to + // (Mir-)Borrowck uses `mir_promoted`, so we have to force it to // execute before we can steal. if let Some(param_did) = def.const_param_did { tcx.ensure().mir_borrowck_const_arg((def.did, param_did)); @@ -375,7 +378,7 @@ fn mir_drops_elaborated_and_const_checked<'tcx>( tcx.ensure().mir_borrowck(def.did); } - let (body, _) = tcx.mir_validated(def); + let (body, _) = tcx.mir_promoted(def); let mut body = body.steal(); run_post_borrowck_cleanup_passes(tcx, &mut body, def.did, None); @@ -420,7 +423,7 @@ fn run_post_borrowck_cleanup_passes<'tcx>( body, InstanceDef::Item(ty::WithOptConstParam::unknown(def_id.to_def_id())), promoted, - MirPhase::DropElab, + MirPhase::DropLowering, &[post_borrowck_cleanup], ); } @@ -431,16 +434,24 @@ fn run_optimization_passes<'tcx>( def_id: LocalDefId, promoted: Option, ) { - let optimizations: &[&dyn MirPass<'tcx>] = &[ + let mir_opt_level = tcx.sess.opts.debugging_opts.mir_opt_level; + + // Lowering generator control-flow and variables has to happen before we do anything else + // to them. We run some optimizations before that, because they may be harder to do on the state + // machine than on MIR with async primitives. + let optimizations_with_generators: &[&dyn MirPass<'tcx>] = &[ &unreachable_prop::UnreachablePropagation, &uninhabited_enum_branching::UninhabitedEnumBranching, &simplify::SimplifyCfg::new("after-uninhabited-enum-branching"), &inline::Inline, - // Lowering generator control-flow and variables has to happen before we do anything else - // to them. We do this inside the "optimizations" block so that it can benefit from - // optimizations that run before, that might be harder to do on the state machine than MIR - // with async primitives. &generator::StateTransform, + ]; + + // Even if we don't do optimizations, we still have to lower generators for codegen. + let no_optimizations_with_generators: &[&dyn MirPass<'tcx>] = &[&generator::StateTransform]; + + // The main optimizations that we do on MIR. + let optimizations: &[&dyn MirPass<'tcx>] = &[ &instcombine::InstCombine, &match_branches::MatchBranchSimplification, &const_prop::ConstProp, @@ -456,28 +467,45 @@ fn run_optimization_passes<'tcx>( &simplify::SimplifyLocals, ]; + // Optimizations to run even if mir optimizations have been disabled. let no_optimizations: &[&dyn MirPass<'tcx>] = &[ - // Even if we don't do optimizations, we still have to lower generators for codegen. - &generator::StateTransform, // FIXME(#70073): This pass is responsible for both optimization as well as some lints. &const_prop::ConstProp, ]; + // Some cleanup necessary at least for LLVM and potentially other codegen backends. let pre_codegen_cleanup: &[&dyn MirPass<'tcx>] = &[ &add_call_guards::CriticalCallEdges, // Dump the end result for testing and debugging purposes. &dump_mir::Marker("PreCodegen"), ]; - let mir_opt_level = tcx.sess.opts.debugging_opts.mir_opt_level; + // End of pass declarations, now actually run the passes. + // Generator Lowering + #[rustfmt::skip] + run_passes( + tcx, + body, + InstanceDef::Item(ty::WithOptConstParam::unknown(def_id.to_def_id())), + promoted, + MirPhase::GeneratorLowering, + &[ + if mir_opt_level > 0 { + optimizations_with_generators + } else { + no_optimizations_with_generators + } + ], + ); + // Main optimization passes #[rustfmt::skip] run_passes( tcx, body, InstanceDef::Item(ty::WithOptConstParam::unknown(def_id.to_def_id())), promoted, - MirPhase::Optimized, + MirPhase::Optimization, &[ if mir_opt_level > 0 { optimizations } else { no_optimizations }, pre_codegen_cleanup, @@ -534,7 +562,7 @@ fn promoted_mir<'tcx>( } else { tcx.ensure().mir_borrowck(def.did); } - let (_, promoted) = tcx.mir_validated(def); + let (_, promoted) = tcx.mir_promoted(def); let mut promoted = promoted.steal(); for (p, mut body) in promoted.iter_enumerated_mut() { diff --git a/src/librustc_mir/transform/validate.rs b/src/librustc_mir/transform/validate.rs index 9296e2ca700..d7c9ecd0655 100644 --- a/src/librustc_mir/transform/validate.rs +++ b/src/librustc_mir/transform/validate.rs @@ -4,8 +4,8 @@ use rustc_middle::mir::visit::Visitor; use rustc_middle::{ mir::{ - BasicBlock, Body, Location, Operand, Rvalue, Statement, StatementKind, Terminator, - TerminatorKind, + AggregateKind, BasicBlock, Body, Location, MirPhase, Operand, Rvalue, Statement, + StatementKind, Terminator, TerminatorKind, }, ty::{ self, @@ -23,12 +23,19 @@ enum EdgeKind { pub struct Validator { /// Describes at which point in the pipeline this validation is happening. pub when: String, + /// The phase for which we are upholding the dialect. If the given phase forbids a specific + /// element, this validator will now emit errors if that specific element is encountered. + /// Note that phases that change the dialect cause all *following* phases to check the + /// invariants of the new dialect. A phase that changes dialects never checks the new invariants + /// itself. + pub mir_phase: MirPhase, } impl<'tcx> MirPass<'tcx> for Validator { fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { let param_env = tcx.param_env(source.def_id()); - TypeChecker { when: &self.when, source, body, tcx, param_env }.visit_body(body); + let mir_phase = self.mir_phase; + TypeChecker { when: &self.when, source, body, tcx, param_env, mir_phase }.visit_body(body); } } @@ -130,6 +137,7 @@ struct TypeChecker<'a, 'tcx> { body: &'a Body<'tcx>, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, + mir_phase: MirPhase, } impl<'a, 'tcx> TypeChecker<'a, 'tcx> { @@ -226,16 +234,16 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { self.fail( location, format!( - "encountered `Assign` statement with incompatible types:\n\ + "encountered `{:?}` with incompatible types:\n\ left-hand side has type: {}\n\ right-hand side has type: {}", - left_ty, right_ty, + statement.kind, left_ty, right_ty, ), ); } - // The sides of an assignment must not alias. Currently this just checks whether the places - // are identical. match rvalue { + // The sides of an assignment must not alias. Currently this just checks whether the places + // are identical. Rvalue::Use(Operand::Copy(src) | Operand::Move(src)) => { if dest == src { self.fail( @@ -244,6 +252,28 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { ); } } + // The deaggregator currently does not deaggreagate arrays. + // So for now, we ignore them here. + Rvalue::Aggregate(box AggregateKind::Array { .. }, _) => {} + // All other aggregates must be gone after some phases. + Rvalue::Aggregate(box kind, _) => { + if self.mir_phase > MirPhase::DropLowering + && !matches!(kind, AggregateKind::Generator(..)) + { + // Generators persist until the state machine transformation, but all + // other aggregates must have been lowered. + self.fail( + location, + format!("{:?} have been lowered to field assignments", rvalue), + ) + } else if self.mir_phase > MirPhase::GeneratorLowering { + // No more aggregates after drop and generator lowering. + self.fail( + location, + format!("{:?} have been lowered to field assignments", rvalue), + ) + } + } _ => {} } } @@ -288,6 +318,12 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location } } TerminatorKind::DropAndReplace { target, unwind, .. } => { + if self.mir_phase > MirPhase::DropLowering { + self.fail( + location, + "`DropAndReplace` is not permitted to exist after drop elaboration", + ); + } self.check_edge(location, *target, EdgeKind::Normal); if let Some(unwind) = unwind { self.check_edge(location, *unwind, EdgeKind::Unwind); @@ -326,6 +362,9 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location } } TerminatorKind::Yield { resume, drop, .. } => { + if self.mir_phase > MirPhase::GeneratorLowering { + self.fail(location, "`Yield` should have been replaced by generator lowering"); + } self.check_edge(location, *resume, EdgeKind::Normal); if let Some(drop) = drop { self.check_edge(location, *drop, EdgeKind::Normal); diff --git a/src/librustc_mir/util/aggregate.rs b/src/librustc_mir/util/aggregate.rs index 1a22eee3a03..130409b9df5 100644 --- a/src/librustc_mir/util/aggregate.rs +++ b/src/librustc_mir/util/aggregate.rs @@ -3,6 +3,7 @@ use rustc_middle::ty::{Ty, TyCtxt}; use rustc_target::abi::VariantIdx; +use std::convert::TryFrom; use std::iter::TrustedLen; /// Expand `lhs = Rvalue::Aggregate(kind, operands)` into assignments to the fields. @@ -52,14 +53,11 @@ pub fn expand_aggregate<'tcx>( .enumerate() .map(move |(i, (op, ty))| { let lhs_field = if let AggregateKind::Array(_) = kind { - // FIXME(eddyb) `offset` should be u64. - let offset = i as u32; - assert_eq!(offset as usize, i); + let offset = u64::try_from(i).unwrap(); tcx.mk_place_elem( lhs, ProjectionElem::ConstantIndex { offset, - // FIXME(eddyb) `min_length` doesn't appear to be used. min_length: offset + 1, from_end: false, }, diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index 20c2f5688eb..642935d243d 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -1,6 +1,6 @@ use crate::util::patch::MirPatch; use rustc_hir as hir; -use rustc_hir::lang_items::{BoxFreeFnLangItem, DropTraitLangItem}; +use rustc_hir::lang_items::LangItem; use rustc_index::vec::Idx; use rustc_middle::mir::*; use rustc_middle::traits::Reveal; @@ -10,8 +10,6 @@ use rustc_target::abi::VariantIdx; use std::fmt; -use std::convert::TryInto; - /// The value of an inserted drop flag. #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum DropFlagState { @@ -150,7 +148,7 @@ pub trait DropElaborator<'a, 'tcx>: fmt::Debug { /// If this returns `None`, elements of `path` will not get a dedicated drop flag. /// /// This is only relevant for array patterns, which can move out of individual array elements. - fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option; + fn array_subpath(&self, path: Self::Path, index: u64, size: u64) -> Option; } #[derive(Debug)] @@ -613,7 +611,7 @@ fn adt_switch_block( fn destructor_call_block(&mut self, (succ, unwind): (BasicBlock, Unwind)) -> BasicBlock { debug!("destructor_call_block({:?}, {:?})", self, succ); let tcx = self.tcx(); - let drop_trait = tcx.require_lang_item(DropTraitLangItem, None); + let drop_trait = tcx.require_lang_item(LangItem::Drop, None); let drop_fn = tcx.associated_items(drop_trait).in_definition_order().next().unwrap(); let ty = self.place_ty(self.place); let substs = tcx.mk_substs_trait(ty, &[]); @@ -744,9 +742,6 @@ fn open_drop_for_array(&mut self, ety: Ty<'tcx>, opt_size: Option) -> Basic let tcx = self.tcx(); if let Some(size) = opt_size { - let size: u32 = size.try_into().unwrap_or_else(|_| { - bug!("move out check isn't implemented for array sizes bigger than u32::MAX"); - }); let fields: Vec<(Place<'tcx>, Option)> = (0..size) .map(|i| { ( @@ -971,7 +966,7 @@ fn unelaborated_free_block( ) -> BasicBlock { let tcx = self.tcx(); let unit_temp = Place::from(self.new_temp(tcx.mk_unit())); - let free_func = tcx.require_lang_item(BoxFreeFnLangItem, Some(self.source_info.span)); + let free_func = tcx.require_lang_item(LangItem::BoxFree, Some(self.source_info.span)); let args = adt.variants[VariantIdx::new(0)] .fields .iter() diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index 0294a7cd7af..2a9cbc7fc0e 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -389,6 +389,8 @@ fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { let Constant { span, user_ty, literal } = constant; match literal.ty.kind { ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char => {} + // Unit type + ty::Tuple(tys) if tys.is_empty() => {} _ => { self.push("mir::Constant"); self.push(&format!("+ span: {}", self.tcx.sess.source_map().span_to_string(*span))); @@ -404,7 +406,10 @@ fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, _: Location) { self.super_const(constant); let ty::Const { ty, val, .. } = constant; match ty.kind { - ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char => {} + ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char | ty::Float(_) => {} + // Unit type + ty::Tuple(tys) if tys.is_empty() => {} + ty::FnDef(..) => {} _ => { self.push("ty::Const"); self.push(&format!("+ ty: {:?}", ty)); diff --git a/src/librustc_mir_build/build/matches/mod.rs b/src/librustc_mir_build/build/matches/mod.rs index 5f87cb364b8..3a525d10b08 100644 --- a/src/librustc_mir_build/build/matches/mod.rs +++ b/src/librustc_mir_build/build/matches/mod.rs @@ -609,8 +609,8 @@ pub(super) fn visit_primary_bindings( PatKind::Array { ref prefix, ref slice, ref suffix } | PatKind::Slice { ref prefix, ref slice, ref suffix } => { - let from = u32::try_from(prefix.len()).unwrap(); - let to = u32::try_from(suffix.len()).unwrap(); + let from = u64::try_from(prefix.len()).unwrap(); + let to = u64::try_from(suffix.len()).unwrap(); for subpattern in prefix { self.visit_primary_bindings(subpattern, pattern_user_ty.clone().index(), f); } diff --git a/src/librustc_mir_build/build/matches/test.rs b/src/librustc_mir_build/build/matches/test.rs index 87977d6fe89..c4a87a554a3 100644 --- a/src/librustc_mir_build/build/matches/test.rs +++ b/src/librustc_mir_build/build/matches/test.rs @@ -10,7 +10,7 @@ use crate::thir::pattern::compare_const_vals; use crate::thir::*; use rustc_data_structures::fx::FxIndexMap; -use rustc_hir::RangeEnd; +use rustc_hir::{LangItem, RangeEnd}; use rustc_index::bit_set::BitSet; use rustc_middle::mir::*; use rustc_middle::ty::util::IntTypeExt; @@ -359,8 +359,6 @@ fn non_scalar_compare( place: Place<'tcx>, mut ty: Ty<'tcx>, ) { - use rustc_hir::lang_items::EqTraitLangItem; - let mut expect = self.literal_operand(source_info.span, value); let mut val = Operand::Copy(place); @@ -414,7 +412,7 @@ fn non_scalar_compare( _ => bug!("non_scalar_compare called on non-reference type: {}", ty), }; - let eq_def_id = self.hir.tcx().require_lang_item(EqTraitLangItem, None); + let eq_def_id = self.hir.tcx().require_lang_item(LangItem::PartialEq, None); let method = self.hir.trait_method(eq_def_id, sym::eq, deref_ty, &[deref_ty.into()]); let bool_ty = self.hir.bool_ty(); @@ -537,10 +535,7 @@ pub(super) fn sort_candidate<'pat>( Some(index) } - ( - &TestKind::SwitchInt { switch_ty: _, ref options }, - &PatKind::Range(range), - ) => { + (&TestKind::SwitchInt { switch_ty: _, ref options }, &PatKind::Range(range)) => { let not_contained = self.values_not_contained_in_range(range, options).unwrap_or(false); diff --git a/src/librustc_mir_build/build/matches/util.rs b/src/librustc_mir_build/build/matches/util.rs index 605396c5eb6..c6d39947f7d 100644 --- a/src/librustc_mir_build/build/matches/util.rs +++ b/src/librustc_mir_build/build/matches/util.rs @@ -40,17 +40,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| { let elem = - ProjectionElem::ConstantIndex { offset: idx as u32, min_length, from_end: false }; + ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false }; let place = tcx.mk_place_elem(*place, elem); MatchPair::new(place, subpattern) })); if let Some(subslice_pat) = opt_slice { - let suffix_len = suffix.len() as u32; + let suffix_len = suffix.len() as u64; let subslice = tcx.mk_place_elem( *place, ProjectionElem::Subslice { - from: prefix.len() as u32, + from: prefix.len() as u64, to: if exact_size { min_length - suffix_len } else { suffix_len }, from_end: !exact_size, }, @@ -59,7 +59,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } match_pairs.extend(suffix.iter().rev().enumerate().map(|(idx, subpattern)| { - let end_offset = (idx + 1) as u32; + let end_offset = (idx + 1) as u64; let elem = ProjectionElem::ConstantIndex { offset: if exact_size { min_length - end_offset } else { end_offset }, min_length, diff --git a/src/librustc_mir_build/build/mod.rs b/src/librustc_mir_build/build/mod.rs index 0c3f6fee665..71026f5096d 100644 --- a/src/librustc_mir_build/build/mod.rs +++ b/src/librustc_mir_build/build/mod.rs @@ -6,7 +6,7 @@ use rustc_errors::ErrorReported; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::lang_items; +use rustc_hir::lang_items::LangItem; use rustc_hir::{GeneratorKind, HirIdMap, Node}; use rustc_index::vec::{Idx, IndexVec}; use rustc_infer::infer::TyCtxtInferExt; @@ -37,22 +37,29 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_ let id = tcx.hir().local_def_id_to_hir_id(def.did); // Figure out what primary body this item has. - let (body_id, return_ty_span) = match tcx.hir().get(id) { + let (body_id, return_ty_span, span_with_body) = match tcx.hir().get(id) { Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(_, decl, body_id, _, _), .. }) => { - (*body_id, decl.output.span()) + (*body_id, decl.output.span(), None) } Node::Item(hir::Item { kind: hir::ItemKind::Fn(hir::FnSig { decl, .. }, _, body_id), + span, .. }) | Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(hir::FnSig { decl, .. }, body_id), + span, .. }) | Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(hir::FnSig { decl, .. }, hir::TraitFn::Provided(body_id)), + span, .. - }) => (*body_id, decl.output.span()), + }) => { + // Use the `Span` of the `Item/ImplItem/TraitItem` as the body span, + // since the def span of a function does not include the body + (*body_id, decl.output.span(), Some(*span)) + } Node::Item(hir::Item { kind: hir::ItemKind::Static(ty, _, body_id) | hir::ItemKind::Const(ty, body_id), .. @@ -61,12 +68,16 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_ | Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Const(ty, Some(body_id)), .. - }) => (*body_id, ty.span), - Node::AnonConst(hir::AnonConst { body, hir_id, .. }) => (*body, tcx.hir().span(*hir_id)), + }) => (*body_id, ty.span, None), + Node::AnonConst(hir::AnonConst { body, hir_id, .. }) => (*body, tcx.hir().span(*hir_id), None), _ => span_bug!(tcx.hir().span(id), "can't build MIR for {:?}", def.did), }; + // If we don't have a specialized span for the body, just use the + // normal def span. + let span_with_body = span_with_body.unwrap_or_else(|| tcx.hir().span(id)); + tcx.infer_ctxt().enter(|infcx| { let cx = Cx::new(&infcx, def, id); let body = if let Some(ErrorReported) = cx.typeck_results().tainted_by_errors { @@ -134,8 +145,7 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_ // C-variadic fns also have a `VaList` input that's not listed in `fn_sig` // (as it's created inside the body itself, not passed in from outside). let ty = if fn_sig.c_variadic && index == fn_sig.inputs().len() { - let va_list_did = - tcx.require_lang_item(lang_items::VaListTypeLangItem, Some(arg.span)); + let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(arg.span)); tcx.type_of(va_list_did).subst(tcx, &[tcx.lifetimes.re_erased.into()]) } else { @@ -167,6 +177,7 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_ return_ty, return_ty_span, body, + span_with_body ); mir.yield_ty = yield_ty; mir @@ -571,6 +582,7 @@ fn construct_fn<'a, 'tcx, A>( return_ty: Ty<'tcx>, return_ty_span: Span, body: &'tcx hir::Body<'tcx>, + span_with_body: Span ) -> Body<'tcx> where A: Iterator>, @@ -585,7 +597,7 @@ fn construct_fn<'a, 'tcx, A>( let mut builder = Builder::new( hir, - span, + span_with_body, arguments.len(), safety, return_ty, @@ -628,7 +640,7 @@ fn construct_fn<'a, 'tcx, A>( ) ); // Attribute epilogue to function's closing brace - let fn_end = span.shrink_to_hi(); + let fn_end = span_with_body.shrink_to_hi(); let source_info = builder.source_info(fn_end); let return_block = builder.return_block(); builder.cfg.goto(block, source_info, return_block); diff --git a/src/librustc_mir_build/lints.rs b/src/librustc_mir_build/lints.rs index 662b6c77357..fd2d5a4abd4 100644 --- a/src/librustc_mir_build/lints.rs +++ b/src/librustc_mir_build/lints.rs @@ -38,7 +38,7 @@ vis.reachable_recursive_calls.sort(); let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - let sp = tcx.sess.source_map().guess_head_span(tcx.hir().span(hir_id)); + let sp = tcx.sess.source_map().guess_head_span(tcx.hir().span_with_body(hir_id)); tcx.struct_span_lint_hir(UNCONDITIONAL_RECURSION, hir_id, sp, |lint| { let mut db = lint.build("function cannot return without recursing"); db.span_label(sp, "cannot return without recursing"); diff --git a/src/librustc_mir_build/thir/pattern/const_to_pat.rs b/src/librustc_mir_build/thir/pattern/const_to_pat.rs index 6dd7e0871b4..f6d3ccc1ae0 100644 --- a/src/librustc_mir_build/thir/pattern/const_to_pat.rs +++ b/src/librustc_mir_build/thir/pattern/const_to_pat.rs @@ -1,5 +1,4 @@ use rustc_hir as hir; -use rustc_hir::lang_items::EqTraitLangItem; use rustc_index::vec::Idx; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_middle::mir::Field; @@ -164,7 +163,7 @@ fn to_pat( // not *yet* implement `PartialEq`. So for now we leave this here. let ty_is_partial_eq: bool = { let partial_eq_trait_id = - self.tcx().require_lang_item(EqTraitLangItem, Some(self.span)); + self.tcx().require_lang_item(hir::LangItem::PartialEq, Some(self.span)); let obligation: PredicateObligation<'_> = predicate_for_trait_def( self.tcx(), self.param_env, diff --git a/src/librustc_parse/lexer/mod.rs b/src/librustc_parse/lexer/mod.rs index 675cfa41f10..7503f15ac55 100644 --- a/src/librustc_parse/lexer/mod.rs +++ b/src/librustc_parse/lexer/mod.rs @@ -1,5 +1,5 @@ +use rustc_ast::ast::AttrStyle; use rustc_ast::token::{self, CommentKind, Token, TokenKind}; -use rustc_ast::util::comments; use rustc_data_structures::sync::Lrc; use rustc_errors::{error_code, Applicability, DiagnosticBuilder, FatalError}; use rustc_lexer::Base; @@ -15,7 +15,7 @@ mod unescape_error_reporting; mod unicode_chars; -use rustc_lexer::unescape::Mode; +use rustc_lexer::{unescape::Mode, DocStyle}; use unescape_error_reporting::{emit_unescape_error, push_escaped_char}; #[derive(Clone, Debug)] @@ -168,25 +168,23 @@ fn struct_fatal_span_char( /// symbols and runs additional validation. fn cook_lexer_token(&self, token: rustc_lexer::TokenKind, start: BytePos) -> TokenKind { match token { - rustc_lexer::TokenKind::LineComment => { - let string = self.str_from(start); - if let Some(attr_style) = comments::line_doc_comment_style(string) { - self.forbid_bare_cr(start, string, "bare CR not allowed in doc-comment"); - // Opening delimiter of the length 3 is not included into the symbol. - token::DocComment(CommentKind::Line, attr_style, Symbol::intern(&string[3..])) - } else { - token::Comment + rustc_lexer::TokenKind::LineComment { doc_style } => { + match doc_style { + Some(doc_style) => { + // Opening delimiter of the length 3 is not included into the symbol. + let content_start = start + BytePos(3); + let content = self.str_from(content_start); + + self.cook_doc_comment(content_start, content, CommentKind::Line, doc_style) + } + None => token::Comment, } } - rustc_lexer::TokenKind::BlockComment { terminated } => { - let string = self.str_from(start); - let attr_style = comments::block_doc_comment_style(string, terminated); - + rustc_lexer::TokenKind::BlockComment { doc_style, terminated } => { if !terminated { - let msg = if attr_style.is_some() { - "unterminated block doc-comment" - } else { - "unterminated block comment" + let msg = match doc_style { + Some(_) => "unterminated block doc-comment", + None => "unterminated block comment", }; let last_bpos = self.pos; self.sess @@ -199,18 +197,17 @@ fn cook_lexer_token(&self, token: rustc_lexer::TokenKind, start: BytePos) -> Tok .emit(); FatalError.raise(); } - - if let Some(attr_style) = attr_style { - self.forbid_bare_cr(start, string, "bare CR not allowed in block doc-comment"); - // Opening delimiter of the length 3 and closing delimiter of the length 2 - // are not included into the symbol. - token::DocComment( - CommentKind::Block, - attr_style, - Symbol::intern(&string[3..string.len() - if terminated { 2 } else { 0 }]), - ) - } else { - token::Comment + match doc_style { + Some(doc_style) => { + // Opening delimiter of the length 3 and closing delimiter of the length 2 + // are not included into the symbol. + let content_start = start + BytePos(3); + let content_end = self.pos - BytePos(if terminated { 2 } else { 0 }); + let content = self.str_from_to(content_start, content_end); + + self.cook_doc_comment(content_start, content, CommentKind::Block, doc_style) + } + None => token::Comment, } } rustc_lexer::TokenKind::Whitespace => token::Whitespace, @@ -290,7 +287,7 @@ fn cook_lexer_token(&self, token: rustc_lexer::TokenKind, start: BytePos) -> Tok rustc_lexer::TokenKind::Colon => token::Colon, rustc_lexer::TokenKind::Dollar => token::Dollar, rustc_lexer::TokenKind::Eq => token::Eq, - rustc_lexer::TokenKind::Not => token::Not, + rustc_lexer::TokenKind::Bang => token::Not, rustc_lexer::TokenKind::Lt => token::Lt, rustc_lexer::TokenKind::Gt => token::Gt, rustc_lexer::TokenKind::Minus => token::BinOp(token::Minus), @@ -319,6 +316,34 @@ fn cook_lexer_token(&self, token: rustc_lexer::TokenKind, start: BytePos) -> Tok } } + fn cook_doc_comment( + &self, + content_start: BytePos, + content: &str, + comment_kind: CommentKind, + doc_style: DocStyle, + ) -> TokenKind { + if content.contains('\r') { + for (idx, _) in content.char_indices().filter(|&(_, c)| c == '\r') { + self.err_span_( + content_start + BytePos(idx as u32), + content_start + BytePos(idx as u32 + 1), + match comment_kind { + CommentKind::Line => "bare CR not allowed in doc-comment", + CommentKind::Block => "bare CR not allowed in block doc-comment", + }, + ); + } + } + + let attr_style = match doc_style { + DocStyle::Outer => AttrStyle::Outer, + DocStyle::Inner => AttrStyle::Inner, + }; + + token::DocComment(comment_kind, attr_style, Symbol::intern(content)) + } + fn cook_lexer_literal( &self, start: BytePos, @@ -472,17 +497,6 @@ fn str_from_to(&self, start: BytePos, end: BytePos) -> &str { &self.src[self.src_index(start)..self.src_index(end)] } - fn forbid_bare_cr(&self, start: BytePos, s: &str, errmsg: &str) { - let mut idx = 0; - loop { - idx = match s[idx..].find('\r') { - None => break, - Some(it) => idx + it + 1, - }; - self.err_span_(start + BytePos(idx as u32 - 1), start + BytePos(idx as u32), errmsg); - } - } - fn report_raw_str_error(&self, start: BytePos, opt_err: Option) { match opt_err { Some(RawStrError::InvalidStarter { bad_char }) => { diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs index 49deb3474d9..bc857c97742 100644 --- a/src/librustc_parse/lib.rs +++ b/src/librustc_parse/lib.rs @@ -7,8 +7,8 @@ #![feature(or_patterns)] use rustc_ast as ast; -use rustc_ast::token::{self, DelimToken, Nonterminal, Token}; -use rustc_ast::tokenstream::{self, TokenStream, TokenTree}; +use rustc_ast::token::{self, DelimToken, Nonterminal, Token, TokenKind}; +use rustc_ast::tokenstream::{self, IsJoint, TokenStream, TokenTree}; use rustc_ast_pretty::pprust; use rustc_data_structures::sync::Lrc; use rustc_errors::{Diagnostic, FatalError, Level, PResult}; @@ -263,6 +263,7 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke Nonterminal::NtItem(ref item) => { prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span) } + Nonterminal::NtPat(ref pat) => pat.tokens.clone(), Nonterminal::NtIdent(ident, is_raw) => { Some(tokenstream::TokenTree::token(token::Ident(ident.name, is_raw), ident.span).into()) } @@ -308,7 +309,7 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke // modifications, including adding/removing typically non-semantic // tokens such as extra braces and commas, don't happen. if let Some(tokens) = tokens { - if tokenstream_probably_equal_for_proc_macro(&tokens, &tokens_for_real) { + if tokenstream_probably_equal_for_proc_macro(&tokens, &tokens_for_real, sess) { return tokens; } info!( @@ -326,7 +327,11 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke // // This is otherwise the same as `eq_unspanned`, only recursing with a // different method. -pub fn tokenstream_probably_equal_for_proc_macro(first: &TokenStream, other: &TokenStream) -> bool { +pub fn tokenstream_probably_equal_for_proc_macro( + first: &TokenStream, + other: &TokenStream, + sess: &ParseSess, +) -> bool { // When checking for `probably_eq`, we ignore certain tokens that aren't // preserved in the AST. Because they are not preserved, the pretty // printer arbitrarily adds or removes them when printing as token @@ -407,9 +412,6 @@ fn break_tokens(tree: TokenTree) -> impl Iterator { } } token_trees = out.into_iter().map(TokenTree::Token).collect(); - if token_trees.len() != 1 { - debug!("break_tokens: broke {:?} to {:?}", tree, token_trees); - } } else { token_trees = SmallVec::new(); token_trees.push(tree); @@ -417,10 +419,32 @@ fn break_tokens(tree: TokenTree) -> impl Iterator { token_trees.into_iter() } - let mut t1 = first.trees().filter(semantic_tree).flat_map(break_tokens); - let mut t2 = other.trees().filter(semantic_tree).flat_map(break_tokens); + let expand_nt = |tree: TokenTree| { + if let TokenTree::Token(Token { kind: TokenKind::Interpolated(nt), span }) = &tree { + // When checking tokenstreams for 'probable equality', we are comparing + // a captured (from parsing) `TokenStream` to a reparsed tokenstream. + // The reparsed Tokenstream will never have `None`-delimited groups, + // since they are only ever inserted as a result of macro expansion. + // Therefore, inserting a `None`-delimtied group here (when we + // convert a nested `Nonterminal` to a tokenstream) would cause + // a mismatch with the reparsed tokenstream. + // + // Note that we currently do not handle the case where the + // reparsed stream has a `Parenthesis`-delimited group + // inserted. This will cause a spurious mismatch: + // issue #75734 tracks resolving this. + nt_to_tokenstream(nt, sess, *span).into_trees() + } else { + TokenStream::new(vec![(tree, IsJoint::NonJoint)]).into_trees() + } + }; + + // Break tokens after we expand any nonterminals, so that we break tokens + // that are produced as a result of nonterminal expansion. + let mut t1 = first.trees().filter(semantic_tree).flat_map(expand_nt).flat_map(break_tokens); + let mut t2 = other.trees().filter(semantic_tree).flat_map(expand_nt).flat_map(break_tokens); for (t1, t2) in t1.by_ref().zip(t2.by_ref()) { - if !tokentree_probably_equal_for_proc_macro(&t1, &t2) { + if !tokentree_probably_equal_for_proc_macro(&t1, &t2, sess) { return false; } } @@ -432,13 +456,17 @@ fn break_tokens(tree: TokenTree) -> impl Iterator { // // This is otherwise the same as `eq_unspanned`, only recursing with a // different method. -fn tokentree_probably_equal_for_proc_macro(first: &TokenTree, other: &TokenTree) -> bool { +pub fn tokentree_probably_equal_for_proc_macro( + first: &TokenTree, + other: &TokenTree, + sess: &ParseSess, +) -> bool { match (first, other) { (TokenTree::Token(token), TokenTree::Token(token2)) => { token_probably_equal_for_proc_macro(token, token2) } (TokenTree::Delimited(_, delim, tts), TokenTree::Delimited(_, delim2, tts2)) => { - delim == delim2 && tokenstream_probably_equal_for_proc_macro(&tts, &tts2) + delim == delim2 && tokenstream_probably_equal_for_proc_macro(&tts, &tts2, sess) } _ => false, } @@ -497,7 +525,7 @@ fn token_probably_equal_for_proc_macro(first: &Token, other: &Token) -> bool { b == d && (a == c || a == kw::DollarCrate || c == kw::DollarCrate) } - (&Interpolated(..), &Interpolated(..)) => false, + (&Interpolated(..), &Interpolated(..)) => panic!("Unexpanded Interpolated!"), _ => panic!("forgot to add a token?"), } diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs index be01c7f8498..12efe391fb9 100644 --- a/src/librustc_parse/parser/diagnostics.rs +++ b/src/librustc_parse/parser/diagnostics.rs @@ -26,6 +26,7 @@ pub(super) fn dummy_arg(ident: Ident) -> Param { id: ast::DUMMY_NODE_ID, kind: PatKind::Ident(BindingMode::ByValue(Mutability::Not), ident, None), span: ident.span, + tokens: None, }); let ty = Ty { kind: TyKind::Err, span: ident.span, id: ast::DUMMY_NODE_ID }; Param { @@ -83,7 +84,12 @@ fn to_ty(&self) -> Option> { self.to_ty() } fn recovered(qself: Option, path: ast::Path) -> Self { - Self { span: path.span, kind: PatKind::Path(qself, path), id: ast::DUMMY_NODE_ID } + Self { + span: path.span, + kind: PatKind::Path(qself, path), + id: ast::DUMMY_NODE_ID, + tokens: None, + } } } @@ -1526,7 +1532,8 @@ pub(super) fn recover_arg_parse(&mut self) -> PResult<'a, (P, P PResult<'a, Arm> { let attrs = self.parse_outer_attributes()?; let lo = self.token.span; let pat = self.parse_top_pat(GateOr::No)?; - let guard = if self.eat_keyword(kw::If) { Some(self.parse_expr()?) } else { None }; + let guard = if self.eat_keyword(kw::If) { + let if_span = self.prev_token.span; + let cond = self.parse_expr()?; + if let ExprKind::Let(..) = cond.kind { + // Remove the last feature gating of a `let` expression since it's stable. + self.sess.gated_spans.ungate_last(sym::let_chains, cond.span); + let span = if_span.to(cond.span); + self.sess.gated_spans.gate(sym::if_let_guard, span); + } + Some(cond) + } else { + None + }; let arrow_span = self.token.span; self.expect(&token::FatArrow)?; let arm_start_span = self.token.span; diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 64479bc36e0..9143af651df 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -227,7 +227,7 @@ fn parse_item_kind( (Ident::invalid(), ItemKind::Use(P(tree))) } else if self.check_fn_front_matter() { // FUNCTION ITEM - let (ident, sig, generics, body) = self.parse_fn(attrs, req_name)?; + let (ident, sig, generics, body) = self.parse_fn(attrs, req_name, lo)?; (ident, ItemKind::Fn(def(), sig, generics, body)) } else if self.eat_keyword(kw::Extern) { if self.eat_keyword(kw::Crate) { @@ -1492,21 +1492,31 @@ fn parse_fn( &mut self, attrs: &mut Vec, req_name: ReqName, + sig_lo: Span, ) -> PResult<'a, (Ident, FnSig, Generics, Option>)> { let header = self.parse_fn_front_matter()?; // `const ... fn` let ident = self.parse_ident()?; // `foo` let mut generics = self.parse_generics()?; // `<'a, T, ...>` let decl = self.parse_fn_decl(req_name, AllowPlus::Yes)?; // `(p: u8, ...)` generics.where_clause = self.parse_where_clause()?; // `where T: Ord` - let body = self.parse_fn_body(attrs)?; // `;` or `{ ... }`. - Ok((ident, FnSig { header, decl }, generics, body)) + + let mut sig_hi = self.prev_token.span; + let body = self.parse_fn_body(attrs, &mut sig_hi)?; // `;` or `{ ... }`. + let fn_sig_span = sig_lo.to(sig_hi); + Ok((ident, FnSig { header, decl, span: fn_sig_span }, generics, body)) } /// Parse the "body" of a function. /// This can either be `;` when there's no body, /// or e.g. a block when the function is a provided one. - fn parse_fn_body(&mut self, attrs: &mut Vec) -> PResult<'a, Option>> { + fn parse_fn_body( + &mut self, + attrs: &mut Vec, + sig_hi: &mut Span, + ) -> PResult<'a, Option>> { let (inner_attrs, body) = if self.check(&token::Semi) { + // Include the trailing semicolon in the span of the signature + *sig_hi = self.token.span; self.bump(); // `;` (Vec::new(), None) } else if self.check(&token::OpenDelim(token::Brace)) || self.token.is_whole_block() { diff --git a/src/librustc_parse/parser/nonterminal.rs b/src/librustc_parse/parser/nonterminal.rs index 12139771bbf..f40cd1131d2 100644 --- a/src/librustc_parse/parser/nonterminal.rs +++ b/src/librustc_parse/parser/nonterminal.rs @@ -116,7 +116,14 @@ pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, Nonter Some(s) => token::NtStmt(s), None => return Err(self.struct_span_err(self.token.span, "expected a statement")), }, - NonterminalKind::Pat => token::NtPat(self.parse_pat(None)?), + NonterminalKind::Pat => { + let (mut pat, tokens) = self.collect_tokens(|this| this.parse_pat(None))?; + // We have have eaten an NtPat, which could already have tokens + if pat.tokens.is_none() { + pat.tokens = Some(tokens); + } + token::NtPat(pat) + } NonterminalKind::Expr => { let (mut expr, tokens) = self.collect_tokens(|this| this.parse_expr())?; // If we captured tokens during parsing (due to outer attributes), diff --git a/src/librustc_parse/parser/pat.rs b/src/librustc_parse/parser/pat.rs index 1d8e6cc9bac..2c0133a24dc 100644 --- a/src/librustc_parse/parser/pat.rs +++ b/src/librustc_parse/parser/pat.rs @@ -1007,6 +1007,6 @@ pub(super) fn mk_pat_ident(&self, span: Span, bm: BindingMode, ident: Ident) -> } fn mk_pat(&self, span: Span, kind: PatKind) -> P { - P(Pat { kind, span, id: ast::DUMMY_NODE_ID }) + P(Pat { kind, span, id: ast::DUMMY_NODE_ID, tokens: None }) } } diff --git a/src/librustc_passes/weak_lang_items.rs b/src/librustc_passes/weak_lang_items.rs index d5ce82ae28f..f559d66587b 100644 --- a/src/librustc_passes/weak_lang_items.rs +++ b/src/librustc_passes/weak_lang_items.rs @@ -4,7 +4,7 @@ use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; -use rustc_hir::lang_items; +use rustc_hir::lang_items::{self, LangItem}; use rustc_hir::weak_lang_items::WEAK_ITEMS_REFS; use rustc_middle::middle::lang_items::required; use rustc_middle::ty::TyCtxt; @@ -24,7 +24,7 @@ pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>, items: &mut lang_items::LanguageItem // They will never implicitly be added to the `missing` array unless we do // so here. if items.eh_personality().is_none() { - items.missing.push(lang_items::EhPersonalityLangItem); + items.missing.push(LangItem::EhPersonality); } { @@ -58,9 +58,9 @@ fn verify<'tcx>(tcx: TyCtxt<'tcx>, items: &lang_items::LanguageItems) { for (name, &item) in WEAK_ITEMS_REFS.iter() { if missing.contains(&item) && required(tcx, item) && items.require(item).is_err() { - if item == lang_items::PanicImplLangItem { + if item == LangItem::PanicImpl { tcx.sess.err("`#[panic_handler]` function required, but not found"); - } else if item == lang_items::OomLangItem { + } else if item == LangItem::Oom { tcx.sess.err("`#[alloc_error_handler]` function required, but not found"); } else { tcx.sess.err(&format!("language item required, but not found: `{}`", name)); @@ -91,7 +91,7 @@ fn nested_visit_map(&mut self) -> NestedVisitorMap { fn visit_foreign_item(&mut self, i: &hir::ForeignItem<'_>) { let check_name = |attr, sym| self.tcx.sess.check_name(attr, sym); - if let Some((lang_item, _)) = hir::lang_items::extract(check_name, &i.attrs) { + if let Some((lang_item, _)) = lang_items::extract(check_name, &i.attrs) { self.register(lang_item, i.span); } intravisit::walk_foreign_item(self, i) diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 0dbb6269d2e..d113eb22aba 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -8,7 +8,7 @@ use RibKind::*; use crate::{path_names_to_string, BindingError, CrateLint, LexicalScopeBinding}; -use crate::{Module, ModuleOrUniformRoot, NameBindingKind, ParentScope, PathResult}; +use crate::{Module, ModuleOrUniformRoot, ParentScope, PathResult}; use crate::{ResolutionError, Resolver, Segment, UseError}; use rustc_ast::ptr::P; @@ -24,7 +24,6 @@ use rustc_hir::TraitCandidate; use rustc_middle::{bug, span_bug}; use rustc_session::lint; -use rustc_span::def_id::LocalDefId; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; use smallvec::{smallvec, SmallVec}; @@ -2342,95 +2341,31 @@ fn get_traits_containing_item( ident.span = ident.span.normalize_to_macros_2_0(); let mut search_module = self.parent_scope.module; loop { - self.get_traits_in_module_containing_item(ident, ns, search_module, &mut found_traits); + self.r.get_traits_in_module_containing_item( + ident, + ns, + search_module, + &mut found_traits, + &self.parent_scope, + ); search_module = unwrap_or!(self.r.hygienic_lexical_parent(search_module, &mut ident.span), break); } if let Some(prelude) = self.r.prelude { if !search_module.no_implicit_prelude { - self.get_traits_in_module_containing_item(ident, ns, prelude, &mut found_traits); + self.r.get_traits_in_module_containing_item( + ident, + ns, + prelude, + &mut found_traits, + &self.parent_scope, + ); } } found_traits } - - fn get_traits_in_module_containing_item( - &mut self, - ident: Ident, - ns: Namespace, - module: Module<'a>, - found_traits: &mut Vec, - ) { - assert!(ns == TypeNS || ns == ValueNS); - let mut traits = module.traits.borrow_mut(); - if traits.is_none() { - let mut collected_traits = Vec::new(); - module.for_each_child(self.r, |_, name, ns, binding| { - if ns != TypeNS { - return; - } - match binding.res() { - Res::Def(DefKind::Trait | DefKind::TraitAlias, _) => { - collected_traits.push((name, binding)) - } - _ => (), - } - }); - *traits = Some(collected_traits.into_boxed_slice()); - } - - for &(trait_name, binding) in traits.as_ref().unwrap().iter() { - // Traits have pseudo-modules that can be used to search for the given ident. - if let Some(module) = binding.module() { - let mut ident = ident; - if ident.span.glob_adjust(module.expansion, binding.span).is_none() { - continue; - } - if self - .r - .resolve_ident_in_module_unadjusted( - ModuleOrUniformRoot::Module(module), - ident, - ns, - &self.parent_scope, - false, - module.span, - ) - .is_ok() - { - let import_ids = self.find_transitive_imports(&binding.kind, trait_name); - let trait_def_id = module.def_id().unwrap(); - found_traits.push(TraitCandidate { def_id: trait_def_id, import_ids }); - } - } else if let Res::Def(DefKind::TraitAlias, _) = binding.res() { - // For now, just treat all trait aliases as possible candidates, since we don't - // know if the ident is somewhere in the transitive bounds. - let import_ids = self.find_transitive_imports(&binding.kind, trait_name); - let trait_def_id = binding.res().def_id(); - found_traits.push(TraitCandidate { def_id: trait_def_id, import_ids }); - } else { - bug!("candidate is not trait or trait alias?") - } - } - } - - fn find_transitive_imports( - &mut self, - mut kind: &NameBindingKind<'_>, - trait_name: Ident, - ) -> SmallVec<[LocalDefId; 1]> { - let mut import_ids = smallvec![]; - while let NameBindingKind::Import { import, binding, .. } = kind { - let id = self.r.local_def_id(import.id); - self.r.maybe_unused_trait_imports.insert(id); - self.r.add_to_glob_map(&import, trait_name); - import_ids.push(id); - kind = &binding.kind; - } - import_ids - } } impl<'a> Resolver<'a> { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 36b7a430f78..f2319bfe64d 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -43,9 +43,9 @@ use rustc_metadata::creader::{CStore, CrateLoader}; use rustc_middle::hir::exports::ExportMap; use rustc_middle::middle::cstore::{CrateStore, MetadataLoaderDyn}; -use rustc_middle::span_bug; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, DefIdTree, ResolverOutputs}; +use rustc_middle::{bug, span_bug}; use rustc_session::lint; use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer}; use rustc_session::Session; @@ -54,6 +54,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; +use smallvec::{smallvec, SmallVec}; use std::cell::{Cell, RefCell}; use std::collections::BTreeSet; use std::{cmp, fmt, iter, ptr}; @@ -521,6 +522,29 @@ fn for_each_child(&'a self, resolver: &mut R, mut f: F) } } + /// This modifies `self` in place. The traits will be stored in `self.traits`. + fn ensure_traits(&'a self, resolver: &mut R) + where + R: AsMut>, + { + let mut traits = self.traits.borrow_mut(); + if traits.is_none() { + let mut collected_traits = Vec::new(); + self.for_each_child(resolver, |_, name, ns, binding| { + if ns != TypeNS { + return; + } + match binding.res() { + Res::Def(DefKind::Trait | DefKind::TraitAlias, _) => { + collected_traits.push((name, binding)) + } + _ => (), + } + }); + *traits = Some(collected_traits.into_boxed_slice()); + } + } + fn res(&self) -> Option { match self.kind { ModuleKind::Def(kind, def_id, _) => Some(Res::Def(kind, def_id)), @@ -1430,6 +1454,68 @@ pub fn resolve_crate(&mut self, krate: &Crate) { self.crate_loader.postprocess(krate); } + fn get_traits_in_module_containing_item( + &mut self, + ident: Ident, + ns: Namespace, + module: Module<'a>, + found_traits: &mut Vec, + parent_scope: &ParentScope<'a>, + ) { + assert!(ns == TypeNS || ns == ValueNS); + module.ensure_traits(self); + let traits = module.traits.borrow(); + + for &(trait_name, binding) in traits.as_ref().unwrap().iter() { + // Traits have pseudo-modules that can be used to search for the given ident. + if let Some(module) = binding.module() { + let mut ident = ident; + if ident.span.glob_adjust(module.expansion, binding.span).is_none() { + continue; + } + if self + .resolve_ident_in_module_unadjusted( + ModuleOrUniformRoot::Module(module), + ident, + ns, + parent_scope, + false, + module.span, + ) + .is_ok() + { + let import_ids = self.find_transitive_imports(&binding.kind, trait_name); + let trait_def_id = module.def_id().unwrap(); + found_traits.push(TraitCandidate { def_id: trait_def_id, import_ids }); + } + } else if let Res::Def(DefKind::TraitAlias, _) = binding.res() { + // For now, just treat all trait aliases as possible candidates, since we don't + // know if the ident is somewhere in the transitive bounds. + let import_ids = self.find_transitive_imports(&binding.kind, trait_name); + let trait_def_id = binding.res().def_id(); + found_traits.push(TraitCandidate { def_id: trait_def_id, import_ids }); + } else { + bug!("candidate is not trait or trait alias?") + } + } + } + + fn find_transitive_imports( + &mut self, + mut kind: &NameBindingKind<'_>, + trait_name: Ident, + ) -> SmallVec<[LocalDefId; 1]> { + let mut import_ids = smallvec![]; + while let NameBindingKind::Import { import, binding, .. } = kind { + let id = self.local_def_id(import.id); + self.maybe_unused_trait_imports.insert(id); + self.add_to_glob_map(&import, trait_name); + import_ids.push(id); + kind = &binding.kind; + } + import_ids + } + fn new_module( &self, parent: Module<'a>, @@ -3039,6 +3125,34 @@ fn extern_prelude_get( }) } + /// This is equivalent to `get_traits_in_module_containing_item`, but without filtering by the associated item. + /// + /// This is used by rustdoc for intra-doc links. + pub fn traits_in_scope(&mut self, module_id: DefId) -> Vec { + let module = self.get_module(module_id); + module.ensure_traits(self); + let traits = module.traits.borrow(); + let to_candidate = + |this: &mut Self, &(trait_name, binding): &(Ident, &NameBinding<'_>)| TraitCandidate { + def_id: binding.res().def_id(), + import_ids: this.find_transitive_imports(&binding.kind, trait_name), + }; + + let mut candidates: Vec<_> = + traits.as_ref().unwrap().iter().map(|x| to_candidate(self, x)).collect(); + + if let Some(prelude) = self.prelude { + if !module.no_implicit_prelude { + prelude.ensure_traits(self); + candidates.extend( + prelude.traits.borrow().as_ref().unwrap().iter().map(|x| to_candidate(self, x)), + ); + } + } + + candidates + } + /// Rustdoc uses this to resolve things in a recoverable way. `ResolutionError<'a>` /// isn't something that can be returned because it can't be made to live that long, /// and also it's a private type. Fortunately rustdoc doesn't need to know the error, diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index b3003cc63d3..6dd7f89d594 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -377,7 +377,7 @@ fn make(&self, offset: usize, _parent_id: Option, scx: &SaveContext< Ok(extend_sig(ty, text, defs, vec![])) } - hir::ItemKind::Fn(hir::FnSig { ref decl, header }, ref generics, _) => { + hir::ItemKind::Fn(hir::FnSig { ref decl, header, span: _ }, ref generics, _) => { let mut text = String::new(); if let hir::Constness::Const = header.constness { text.push_str("const "); diff --git a/src/librustc_session/options.rs b/src/librustc_session/options.rs index 80164840334..d05f1a3f34b 100644 --- a/src/librustc_session/options.rs +++ b/src/librustc_session/options.rs @@ -807,6 +807,8 @@ fn parse_target_feature(slot: &mut String, v: Option<&str>) -> bool { "select which borrowck is used (`mir` or `migrate`) (default: `migrate`)"), borrowck_stats: bool = (false, parse_bool, [UNTRACKED], "gather borrowck statistics (default: no)"), + cgu_partitioning_strategy: Option = (None, parse_opt_string, [TRACKED], + "the codegen unit partitioning strategy to use"), chalk: bool = (false, parse_bool, [TRACKED], "enable the experimental Chalk-based trait solving engine"), codegen_backend: Option = (None, parse_opt_string, [TRACKED], diff --git a/src/librustc_session/session.rs b/src/librustc_session/session.rs index d7da2038b54..c006e593e47 100644 --- a/src/librustc_session/session.rs +++ b/src/librustc_session/session.rs @@ -218,8 +218,6 @@ pub struct Session { pub struct PerfStats { /// The accumulated time spent on computing symbol hashes. pub symbol_hash_time: Lock, - /// The accumulated time spent decoding def path tables from metadata. - pub decode_def_path_tables_time: Lock, /// Total number of values canonicalized queries constructed. pub queries_canonicalized: AtomicUsize, /// Number of times this query is invoked. @@ -862,10 +860,6 @@ pub fn print_perf_stats(&self) { "Total time spent computing symbol hashes: {}", duration_to_secs_str(*self.perf_stats.symbol_hash_time.lock()) ); - println!( - "Total time spent decoding DefPath tables: {}", - duration_to_secs_str(*self.perf_stats.decode_def_path_tables_time.lock()) - ); println!( "Total queries canonicalized: {}", self.perf_stats.queries_canonicalized.load(Ordering::Relaxed) @@ -1339,7 +1333,6 @@ pub fn build_session( prof, perf_stats: PerfStats { symbol_hash_time: Lock::new(Duration::from_secs(0)), - decode_def_path_tables_time: Lock::new(Duration::from_secs(0)), queries_canonicalized: AtomicUsize::new(0), normalize_generic_arg_after_erasing_regions: AtomicUsize::new(0), normalize_projection_ty: AtomicUsize::new(0), diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index 3883d86520f..46612145bf0 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -258,6 +258,7 @@ arith_offset, arm_target_feature, array, + arrays, as_str, asm, assert, @@ -567,10 +568,12 @@ i8, ident, if_let, + if_let_guard, if_while_or_patterns, ignore, impl_header_lifetime_elision, impl_lint_pass, + impl_macros, impl_trait_in_bindings, import_shadowing, in_band_lifetimes, diff --git a/src/librustc_symbol_mangling/legacy.rs b/src/librustc_symbol_mangling/legacy.rs index 2ae13b501e9..24356844baf 100644 --- a/src/librustc_symbol_mangling/legacy.rs +++ b/src/librustc_symbol_mangling/legacy.rs @@ -136,7 +136,7 @@ fn get_symbol_hash<'tcx>( } // Follow C++ namespace-mangling style, see -// http://en.wikipedia.org/wiki/Name_mangling for more info. +// https://en.wikipedia.org/wiki/Name_mangling for more info. // // It turns out that on macOS you can actually have arbitrary symbols in // function names (at least when given to LLVM), but this is not possible diff --git a/src/librustc_target/spec/aarch64_unknown_hermit.rs b/src/librustc_target/spec/aarch64_unknown_hermit.rs index 5f978c03248..e07b8f7a756 100644 --- a/src/librustc_target/spec/aarch64_unknown_hermit.rs +++ b/src/librustc_target/spec/aarch64_unknown_hermit.rs @@ -1,10 +1,8 @@ -use crate::spec::{LinkerFlavor, Target, TargetResult}; +use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::hermit_base::opts(); base.max_atomic_width = Some(128); - base.unsupported_abis = super::arm_base::unsupported_abis(); - base.linker = Some("aarch64-hermit-gcc".to_string()); Ok(Target { llvm_target: "aarch64-unknown-hermit".to_string(), @@ -16,7 +14,7 @@ pub fn target() -> TargetResult { target_os: "hermit".to_string(), target_env: String::new(), target_vendor: "unknown".to_string(), - linker_flavor: LinkerFlavor::Gcc, + linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), options: base, }) } diff --git a/src/librustc_target/spec/hermit_base.rs b/src/librustc_target/spec/hermit_base.rs index 18fb2aa3d56..e063c94cf2c 100644 --- a/src/librustc_target/spec/hermit_base.rs +++ b/src/librustc_target/spec/hermit_base.rs @@ -16,7 +16,8 @@ pub fn opts() -> TargetOptions { pre_link_args, panic_strategy: PanicStrategy::Abort, position_independent_executables: true, - relocation_model: RelocModel::Static, + static_position_independent_executables: true, + relocation_model: RelocModel::Pic, target_family: None, tls_model: TlsModel::InitialExec, ..Default::default() diff --git a/src/librustc_target/spec/hermit_kernel_base.rs b/src/librustc_target/spec/hermit_kernel_base.rs index 7f2dada714d..01b9f75637f 100644 --- a/src/librustc_target/spec/hermit_kernel_base.rs +++ b/src/librustc_target/spec/hermit_kernel_base.rs @@ -17,7 +17,8 @@ pub fn opts() -> TargetOptions { pre_link_args, panic_strategy: PanicStrategy::Abort, position_independent_executables: true, - relocation_model: RelocModel::Static, + static_position_independent_executables: true, + relocation_model: RelocModel::Pic, target_family: None, tls_model: TlsModel::InitialExec, ..Default::default() diff --git a/src/librustc_trait_selection/infer.rs b/src/librustc_trait_selection/infer.rs index dc895ad34a9..4ec1b29bca4 100644 --- a/src/librustc_trait_selection/infer.rs +++ b/src/librustc_trait_selection/infer.rs @@ -2,7 +2,7 @@ use crate::traits::{self, TraitEngine, TraitEngineExt}; use rustc_hir as hir; -use rustc_hir::lang_items; +use rustc_hir::lang_items::LangItem; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::traits::ObligationCause; use rustc_middle::arena::ArenaAllocatable; @@ -47,7 +47,7 @@ fn type_is_copy_modulo_regions( return ty.is_copy_modulo_regions(self.tcx.at(span), param_env); } - let copy_def_id = self.tcx.require_lang_item(lang_items::CopyTraitLangItem, None); + let copy_def_id = self.tcx.require_lang_item(LangItem::Copy, None); // This can get called from typeck (by euv), and `moves_by_default` // rightly refuses to work with inference variables, but diff --git a/src/librustc_trait_selection/traits/auto_trait.rs b/src/librustc_trait_selection/traits/auto_trait.rs index 820f8716f05..fa3d0241998 100644 --- a/src/librustc_trait_selection/traits/auto_trait.rs +++ b/src/librustc_trait_selection/traits/auto_trait.rs @@ -738,7 +738,7 @@ fn evaluate_nested_obligations( // and turn them into an explicit negative impl for our type. debug!("Projecting and unifying projection predicate {:?}", predicate); - match poly_project_and_unify_type(select, &obligation.with(p)) { + match project::poly_project_and_unify_type(select, &obligation.with(p)) { Err(e) => { debug!( "evaluate_nested_obligations: Unable to unify predicate \ @@ -747,7 +747,11 @@ fn evaluate_nested_obligations( ); return false; } - Ok(Some(v)) => { + Ok(Err(project::InProgress)) => { + debug!("evaluate_nested_obligations: recursive projection predicate"); + return false; + } + Ok(Ok(Some(v))) => { // We only care about sub-obligations // when we started out trying to unify // some inference variables. See the comment above @@ -766,7 +770,7 @@ fn evaluate_nested_obligations( } } } - Ok(None) => { + Ok(Ok(None)) => { // It's ok not to make progress when have no inference variables - // in that case, we were only performing unifcation to check if an // error occurred (which would indicate that it's impossible for our diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index e597843e6ce..28542d4b12e 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -399,16 +399,17 @@ fn report_selection_error( err.note(s.as_str()); } if let Some(ref s) = enclosing_scope { - let enclosing_scope_span = tcx.def_span( - tcx.hir() - .opt_local_def_id(obligation.cause.body_id) - .unwrap_or_else(|| { - tcx.hir().body_owner_def_id(hir::BodyId { - hir_id: obligation.cause.body_id, - }) + let body = tcx + .hir() + .opt_local_def_id(obligation.cause.body_id) + .unwrap_or_else(|| { + tcx.hir().body_owner_def_id(hir::BodyId { + hir_id: obligation.cause.body_id, }) - .to_def_id(), - ); + }); + + let enclosing_scope_span = + tcx.hir().span_with_body(tcx.hir().local_def_id_to_hir_id(body)); err.span_label(enclosing_scope_span, s.as_str()); } diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index 7513ff6b37e..138293c9533 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -13,7 +13,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; -use rustc_hir::lang_items; +use rustc_hir::lang_items::LangItem; use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node}; use rustc_middle::ty::{ self, suggest_constraining_type_param, AdtKind, DefIdTree, Infer, InferTy, ToPredicate, Ty, @@ -2015,8 +2015,7 @@ fn suggest_await_before_try( if let Some(body_id) = self.tcx.hir().maybe_body_owned_by(item_id) { let body = self.tcx.hir().body(body_id); if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind { - let future_trait = - self.tcx.require_lang_item(lang_items::FutureTraitLangItem, None); + let future_trait = self.tcx.require_lang_item(LangItem::Future, None); let self_ty = self.resolve_vars_if_possible(&trait_ref.self_ty()); diff --git a/src/librustc_trait_selection/traits/fulfill.rs b/src/librustc_trait_selection/traits/fulfill.rs index 2eda1ce595a..a5c6dc042ab 100644 --- a/src/librustc_trait_selection/traits/fulfill.rs +++ b/src/librustc_trait_selection/traits/fulfill.rs @@ -622,15 +622,20 @@ fn process_projection_obligation( project_obligation: PolyProjectionObligation<'tcx>, stalled_on: &mut Vec>, ) -> ProcessResult, FulfillmentErrorCode<'tcx>> { + let tcx = self.selcx.tcx(); match project::poly_project_and_unify_type(self.selcx, &project_obligation) { - Ok(None) => { + Ok(Ok(Some(os))) => ProcessResult::Changed(mk_pending(os)), + Ok(Ok(None)) => { *stalled_on = trait_ref_infer_vars( self.selcx, project_obligation.predicate.to_poly_trait_ref(self.selcx.tcx()), ); ProcessResult::Unchanged } - Ok(Some(os)) => ProcessResult::Changed(mk_pending(os)), + // Let the caller handle the recursion + Ok(Err(project::InProgress)) => ProcessResult::Changed(mk_pending(vec![ + project_obligation.with(project_obligation.predicate.to_predicate(tcx)), + ])), Err(e) => ProcessResult::Error(CodeProjectionError(e)), } } diff --git a/src/librustc_trait_selection/traits/mod.rs b/src/librustc_trait_selection/traits/mod.rs index afa48c2f76c..fe406e88c52 100644 --- a/src/librustc_trait_selection/traits/mod.rs +++ b/src/librustc_trait_selection/traits/mod.rs @@ -51,9 +51,7 @@ pub use self::object_safety::MethodViolationCode; pub use self::object_safety::ObjectSafetyViolation; pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote}; -pub use self::project::{ - normalize, normalize_projection_type, normalize_to, poly_project_and_unify_type, -}; +pub use self::project::{normalize, normalize_projection_type, normalize_to}; pub use self::select::{EvaluationCache, SelectionCache, SelectionContext}; pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError}; pub use self::specialize::specialization_graph::FutureCompatOverlapError; diff --git a/src/librustc_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs index 316181ce7d4..c788e4f5c90 100644 --- a/src/librustc_trait_selection/traits/project.rs +++ b/src/librustc_trait_selection/traits/project.rs @@ -23,9 +23,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::ErrorReported; use rustc_hir::def_id::DefId; -use rustc_hir::lang_items::{ - DiscriminantTypeLangItem, FnOnceOutputLangItem, FnOnceTraitLangItem, GeneratorTraitLangItem, -}; +use rustc_hir::lang_items::LangItem; use rustc_infer::infer::resolve::OpportunisticRegionResolver; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; use rustc_middle::ty::subst::Subst; @@ -41,6 +39,8 @@ pub type ProjectionTyObligation<'tcx> = Obligation<'tcx, ty::ProjectionTy<'tcx>>; +pub(super) struct InProgress; + /// When attempting to resolve `::Name` ... #[derive(Debug)] pub enum ProjectionTyError<'tcx> { @@ -143,10 +143,26 @@ fn push_candidate(&mut self, candidate: ProjectionTyCandidate<'tcx>) -> bool { /// /// If successful, this may result in additional obligations. Also returns /// the projection cache key used to track these additional obligations. -pub fn poly_project_and_unify_type<'cx, 'tcx>( +/// +/// ## Returns +/// +/// - `Err(_)`: the projection can be normalized, but is not equal to the +/// expected type. +/// - `Ok(Err(InProgress))`: this is called recursively while normalizing +/// the same projection. +/// - `Ok(Ok(None))`: The projection cannot be normalized due to ambiguity +/// (resolving some inference variables in the projection may fix this). +/// - `Ok(Ok(Some(obligations)))`: The projection bound holds subject to +/// the given obligations. If the projection cannot be normalized because +/// the required trait bound doesn't hold this returned with `obligations` +/// being a predicate that cannot be proven. +pub(super) fn poly_project_and_unify_type<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &PolyProjectionObligation<'tcx>, -) -> Result>>, MismatchedProjectionTypes<'tcx>> { +) -> Result< + Result>>, InProgress>, + MismatchedProjectionTypes<'tcx>, +> { debug!("poly_project_and_unify_type(obligation={:?})", obligation); let infcx = selcx.infcx(); @@ -165,10 +181,15 @@ pub fn poly_project_and_unify_type<'cx, 'tcx>( /// ::U == V /// /// If successful, this may result in additional obligations. +/// +/// See [poly_project_and_unify_type] for an explanation of the return value. fn project_and_unify_type<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionObligation<'tcx>, -) -> Result>>, MismatchedProjectionTypes<'tcx>> { +) -> Result< + Result>>, InProgress>, + MismatchedProjectionTypes<'tcx>, +> { debug!("project_and_unify_type(obligation={:?})", obligation); let mut obligations = vec![]; @@ -180,8 +201,9 @@ fn project_and_unify_type<'cx, 'tcx>( obligation.recursion_depth, &mut obligations, ) { - Some(n) => n, - None => return Ok(None), + Ok(Some(n)) => n, + Ok(None) => return Ok(Ok(None)), + Err(InProgress) => return Ok(Err(InProgress)), }; debug!( @@ -196,7 +218,7 @@ fn project_and_unify_type<'cx, 'tcx>( { Ok(InferOk { obligations: inferred_obligations, value: () }) => { obligations.extend(inferred_obligations); - Ok(Some(obligations)) + Ok(Ok(Some(obligations))) } Err(err) => { debug!("project_and_unify_type: equating types encountered error {:?}", err); @@ -419,6 +441,8 @@ pub fn normalize_projection_type<'a, 'b, 'tcx>( depth, obligations, ) + .ok() + .flatten() .unwrap_or_else(move || { // if we bottom out in ambiguity, create a type variable // and a deferred predicate to resolve this when more type @@ -455,7 +479,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( cause: ObligationCause<'tcx>, depth: usize, obligations: &mut Vec>, -) -> Option> { +) -> Result>, InProgress> { let infcx = selcx.infcx(); let projection_ty = infcx.resolve_vars_if_possible(&projection_ty); @@ -487,7 +511,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( "opt_normalize_projection_type: \ found cache entry: ambiguous" ); - return None; + return Ok(None); } Err(ProjectionCacheEntry::InProgress) => { // If while normalized A::B, we are asked to normalize @@ -502,24 +526,14 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( // to normalize `A::B`, we will want to check the // where-clauses in scope. So we will try to unify `A::B` // with `A::B`, which can trigger a recursive - // normalization. In that case, I think we will want this code: - // - // ``` - // let ty = selcx.tcx().mk_projection(projection_ty.item_def_id, - // projection_ty.substs; - // return Some(NormalizedTy { value: v, obligations: vec![] }); - // ``` + // normalization. debug!( "opt_normalize_projection_type: \ found cache entry: in-progress" ); - // But for now, let's classify this as an overflow: - let recursion_limit = selcx.tcx().sess.recursion_limit(); - let obligation = - Obligation::with_depth(cause, recursion_limit.0, param_env, projection_ty); - selcx.infcx().report_overflow_error(&obligation, false); + return Err(InProgress); } Err(ProjectionCacheEntry::NormalizedTy(ty)) => { // This is the hottest path in this function. @@ -555,7 +569,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( cause, depth, )); - return Some(ty.value); + return Ok(Some(ty.value)); } Err(ProjectionCacheEntry::Error) => { debug!( @@ -564,7 +578,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( ); let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth); obligations.extend(result.obligations); - return Some(result.value); + return Ok(Some(result.value)); } } @@ -611,7 +625,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( let cache_value = prune_cache_value_obligations(infcx, &result); infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, cache_value); obligations.extend(result.obligations); - Some(result.value) + Ok(Some(result.value)) } Ok(ProjectedTy::NoProgress(projected_ty)) => { debug!( @@ -622,7 +636,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( let result = Normalized { value: projected_ty, obligations: vec![] }; infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, result.clone()); // No need to extend `obligations`. - Some(result.value) + Ok(Some(result.value)) } Err(ProjectionTyError::TooManyCandidates) => { debug!( @@ -630,7 +644,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( too many candidates" ); infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key); - None + Ok(None) } Err(ProjectionTyError::TraitSelectionError(_)) => { debug!("opt_normalize_projection_type: ERROR"); @@ -642,7 +656,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( infcx.inner.borrow_mut().projection_cache().error(cache_key); let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth); obligations.extend(result.obligations); - Some(result.value) + Ok(Some(result.value)) } } } @@ -1116,11 +1130,11 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( } super::ImplSourceAutoImpl(..) | super::ImplSourceBuiltin(..) => { // These traits have no associated types. - span_bug!( + selcx.tcx().sess.delay_span_bug( obligation.cause.span, - "Cannot project an associated type from `{:?}`", - impl_source + &format!("Cannot project an associated type from `{:?}`", impl_source), ); + return Err(()); } }; @@ -1284,7 +1298,7 @@ fn confirm_generator_candidate<'cx, 'tcx>( let tcx = selcx.tcx(); - let gen_def_id = tcx.require_lang_item(GeneratorTraitLangItem, None); + let gen_def_id = tcx.require_lang_item(LangItem::Generator, None); let predicate = super::util::generator_trait_ref_and_outputs( tcx, @@ -1326,7 +1340,7 @@ fn confirm_discriminant_kind_candidate<'cx, 'tcx>( let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty()); let substs = tcx.mk_substs([self_ty.into()].iter()); - let discriminant_def_id = tcx.require_lang_item(DiscriminantTypeLangItem, None); + let discriminant_def_id = tcx.require_lang_item(LangItem::Discriminant, None); let predicate = ty::ProjectionPredicate { projection_ty: ty::ProjectionTy { substs, item_def_id: discriminant_def_id }, @@ -1390,8 +1404,8 @@ fn confirm_callable_candidate<'cx, 'tcx>( debug!("confirm_callable_candidate({:?},{:?})", obligation, fn_sig); - let fn_once_def_id = tcx.require_lang_item(FnOnceTraitLangItem, None); - let fn_once_output_def_id = tcx.require_lang_item(FnOnceOutputLangItem, None); + let fn_once_def_id = tcx.require_lang_item(LangItem::FnOnce, None); + let fn_once_output_def_id = tcx.require_lang_item(LangItem::FnOnceOutput, None); let predicate = super::util::closure_trait_ref_and_return_type( tcx, diff --git a/src/librustc_trait_selection/traits/select/confirmation.rs b/src/librustc_trait_selection/traits/select/confirmation.rs index a04636af579..3d6eb845136 100644 --- a/src/librustc_trait_selection/traits/select/confirmation.rs +++ b/src/librustc_trait_selection/traits/select/confirmation.rs @@ -7,7 +7,7 @@ //! [rustc dev guide]: //! https://rustc-dev-guide.rust-lang.org/traits/resolution.html#confirmation use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_hir::lang_items; +use rustc_hir::lang_items::LangItem; use rustc_index::bit_set::GrowableBitSet; use rustc_infer::infer::InferOk; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef}; @@ -669,7 +669,7 @@ fn confirm_builtin_unsize_candidate( // We can only make objects from sized types. let tr = ty::TraitRef::new( - tcx.require_lang_item(lang_items::SizedTraitLangItem, None), + tcx.require_lang_item(LangItem::Sized, None), tcx.mk_substs_trait(source, &[]), ); nested.push(predicate_to_obligation(tr.without_const().to_predicate(tcx))); diff --git a/src/librustc_trait_selection/traits/select/mod.rs b/src/librustc_trait_selection/traits/select/mod.rs index 4c575f1c6ac..82f476b463d 100644 --- a/src/librustc_trait_selection/traits/select/mod.rs +++ b/src/librustc_trait_selection/traits/select/mod.rs @@ -503,7 +503,7 @@ fn evaluate_predicate_recursively<'o>( let data = ty::Binder::bind(data); let project_obligation = obligation.with(data); match project::poly_project_and_unify_type(self, &project_obligation) { - Ok(Some(mut subobligations)) => { + Ok(Ok(Some(mut subobligations))) => { self.add_depth(subobligations.iter_mut(), obligation.recursion_depth); let result = self.evaluate_predicates_recursively( previous_stack, @@ -516,7 +516,13 @@ fn evaluate_predicate_recursively<'o>( } result } - Ok(None) => Ok(EvaluatedToAmbig), + Ok(Ok(None)) => Ok(EvaluatedToAmbig), + // EvaluatedToRecur might also be acceptable here, but use + // Unknown for now because it means that we won't dismiss a + // selection candidate solely because it has a projection + // cycle. This is closest to the previous behavior of + // immediately erroring. + Ok(Err(project::InProgress)) => Ok(EvaluatedToUnknown), Err(_) => Ok(EvaluatedToErr), } } diff --git a/src/librustc_trait_selection/traits/structural_match.rs b/src/librustc_trait_selection/traits/structural_match.rs index 377d163d104..78186a5e8a5 100644 --- a/src/librustc_trait_selection/traits/structural_match.rs +++ b/src/librustc_trait_selection/traits/structural_match.rs @@ -4,7 +4,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; -use rustc_hir::lang_items::{StructuralPeqTraitLangItem, StructuralTeqTraitLangItem}; +use rustc_hir::lang_items::LangItem; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeFoldable, TypeVisitor}; use rustc_span::Span; @@ -75,7 +75,7 @@ fn type_marked_structural( let mut fulfillment_cx = traits::FulfillmentContext::new(); // require `#[derive(PartialEq)]` let structural_peq_def_id = - infcx.tcx.require_lang_item(StructuralPeqTraitLangItem, Some(cause.span)); + infcx.tcx.require_lang_item(LangItem::StructuralPeq, Some(cause.span)); fulfillment_cx.register_bound( infcx, ty::ParamEnv::empty(), @@ -86,7 +86,7 @@ fn type_marked_structural( // for now, require `#[derive(Eq)]`. (Doing so is a hack to work around // the type `for<'a> fn(&'a ())` failing to implement `Eq` itself.) let structural_teq_def_id = - infcx.tcx.require_lang_item(StructuralTeqTraitLangItem, Some(cause.span)); + infcx.tcx.require_lang_item(LangItem::StructuralTeq, Some(cause.span)); fulfillment_cx.register_bound( infcx, ty::ParamEnv::empty(), diff --git a/src/librustc_trait_selection/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs index d225b10834a..0ac3c6ffe62 100644 --- a/src/librustc_trait_selection/traits/wf.rs +++ b/src/librustc_trait_selection/traits/wf.rs @@ -3,7 +3,7 @@ use crate::traits; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_hir::lang_items; +use rustc_hir::lang_items::LangItem; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use rustc_span::Span; @@ -340,7 +340,7 @@ fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode< if !subty.has_escaping_bound_vars() { let cause = self.cause(cause); let trait_ref = ty::TraitRef { - def_id: self.infcx.tcx.require_lang_item(lang_items::SizedTraitLangItem, None), + def_id: self.infcx.tcx.require_lang_item(LangItem::Sized, None), substs: self.infcx.tcx.mk_substs_trait(subty, &[]), }; self.out.push(traits::Obligation::new( diff --git a/src/librustc_ty/common_traits.rs b/src/librustc_ty/common_traits.rs index 8d153e77f0b..24ba0717866 100644 --- a/src/librustc_ty/common_traits.rs +++ b/src/librustc_ty/common_traits.rs @@ -1,27 +1,27 @@ //! Queries for checking whether a type implements one of a few common traits. -use rustc_hir::lang_items; +use rustc_hir::lang_items::LangItem; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::DUMMY_SP; use rustc_trait_selection::traits; fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { - is_item_raw(tcx, query, lang_items::CopyTraitLangItem) + is_item_raw(tcx, query, LangItem::Copy) } fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { - is_item_raw(tcx, query, lang_items::SizedTraitLangItem) + is_item_raw(tcx, query, LangItem::Sized) } fn is_freeze_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { - is_item_raw(tcx, query, lang_items::FreezeTraitLangItem) + is_item_raw(tcx, query, LangItem::Freeze) } fn is_item_raw<'tcx>( tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, - item: lang_items::LangItem, + item: LangItem, ) -> bool { let (param_env, ty) = query.into_parts(); let trait_def_id = tcx.require_lang_item(item, None); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs deleted file mode 100644 index 86081b15071..00000000000 --- a/src/librustc_typeck/astconv.rs +++ /dev/null @@ -1,3339 +0,0 @@ -// ignore-tidy-filelength FIXME(#67418) Split up this file. -//! Conversion from AST representation of types to the `ty.rs` representation. -//! The main routine here is `ast_ty_to_ty()`; each use is parameterized by an -//! instance of `AstConv`. - -// ignore-tidy-filelength - -use crate::collect::PlaceholderHirTyCollector; -use crate::middle::resolve_lifetime as rl; -use crate::require_c_abi_if_c_variadic; -use rustc_ast::{util::lev_distance::find_best_match_for_name, ParamKindOrd}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::ErrorReported; -use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, FatalError}; -use rustc_hir as hir; -use rustc_hir::def::{CtorOf, DefKind, Namespace, Res}; -use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::intravisit::{walk_generics, Visitor as _}; -use rustc_hir::lang_items::SizedTraitLangItem; -use rustc_hir::{Constness, GenericArg, GenericArgs}; -use rustc_middle::ty::subst::{self, InternalSubsts, Subst, SubstsRef}; -use rustc_middle::ty::{ - self, Const, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, -}; -use rustc_middle::ty::{GenericParamDef, GenericParamDefKind}; -use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, LATE_BOUND_LIFETIME_ARGUMENTS}; -use rustc_session::parse::feature_err; -use rustc_session::Session; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{MultiSpan, Span, DUMMY_SP}; -use rustc_target::spec::abi; -use rustc_trait_selection::traits; -use rustc_trait_selection::traits::astconv_object_safety_violations; -use rustc_trait_selection::traits::error_reporting::report_object_safety_error; -use rustc_trait_selection::traits::wf::object_region_bounds; - -use smallvec::SmallVec; -use std::collections::BTreeSet; -use std::iter; -use std::slice; - -#[derive(Debug)] -pub struct PathSeg(pub DefId, pub usize); - -pub trait AstConv<'tcx> { - fn tcx<'a>(&'a self) -> TyCtxt<'tcx>; - - fn item_def_id(&self) -> Option; - - fn default_constness_for_trait_bounds(&self) -> Constness; - - /// Returns predicates in scope of the form `X: Foo`, where `X` is - /// a type parameter `X` with the given id `def_id`. This is a - /// subset of the full set of predicates. - /// - /// This is used for one specific purpose: resolving "short-hand" - /// associated type references like `T::Item`. In principle, we - /// would do that by first getting the full set of predicates in - /// scope and then filtering down to find those that apply to `T`, - /// but this can lead to cycle errors. The problem is that we have - /// to do this resolution *in order to create the predicates in - /// the first place*. Hence, we have this "special pass". - fn get_type_parameter_bounds(&self, span: Span, def_id: DefId) -> ty::GenericPredicates<'tcx>; - - /// Returns the lifetime to use when a lifetime is omitted (and not elided). - fn re_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) - -> Option>; - - /// Returns the type to use when a type is omitted. - fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx>; - - /// Returns `true` if `_` is allowed in type signatures in the current context. - fn allow_ty_infer(&self) -> bool; - - /// Returns the const to use when a const is omitted. - fn ct_infer( - &self, - ty: Ty<'tcx>, - param: Option<&ty::GenericParamDef>, - span: Span, - ) -> &'tcx Const<'tcx>; - - /// Projecting an associated type from a (potentially) - /// higher-ranked trait reference is more complicated, because of - /// the possibility of late-bound regions appearing in the - /// associated type binding. This is not legal in function - /// signatures for that reason. In a function body, we can always - /// handle it because we can use inference variables to remove the - /// late-bound regions. - fn projected_ty_from_poly_trait_ref( - &self, - span: Span, - item_def_id: DefId, - item_segment: &hir::PathSegment<'_>, - poly_trait_ref: ty::PolyTraitRef<'tcx>, - ) -> Ty<'tcx>; - - /// Normalize an associated type coming from the user. - fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx>; - - /// Invoked when we encounter an error from some prior pass - /// (e.g., resolve) that is translated into a ty-error. This is - /// used to help suppress derived errors typeck might otherwise - /// report. - fn set_tainted_by_errors(&self); - - fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span); -} - -pub enum SizedByDefault { - Yes, - No, -} - -struct ConvertedBinding<'a, 'tcx> { - item_name: Ident, - kind: ConvertedBindingKind<'a, 'tcx>, - span: Span, -} - -enum ConvertedBindingKind<'a, 'tcx> { - Equality(Ty<'tcx>), - Constraint(&'a [hir::GenericBound<'a>]), -} - -/// New-typed boolean indicating whether explicit late-bound lifetimes -/// are present in a set of generic arguments. -/// -/// For example if we have some method `fn f<'a>(&'a self)` implemented -/// for some type `T`, although `f` is generic in the lifetime `'a`, `'a` -/// is late-bound so should not be provided explicitly. Thus, if `f` is -/// instantiated with some generic arguments providing `'a` explicitly, -/// we taint those arguments with `ExplicitLateBound::Yes` so that we -/// can provide an appropriate diagnostic later. -#[derive(Copy, Clone, PartialEq)] -pub enum ExplicitLateBound { - Yes, - No, -} - -#[derive(Copy, Clone, PartialEq)] -enum GenericArgPosition { - Type, - Value, // e.g., functions - MethodCall, -} - -/// A marker denoting that the generic arguments that were -/// provided did not match the respective generic parameters. -#[derive(Clone, Default)] -pub struct GenericArgCountMismatch { - /// Indicates whether a fatal error was reported (`Some`), or just a lint (`None`). - pub reported: Option, - /// A list of spans of arguments provided that were not valid. - pub invalid_args: Vec, -} - -/// Decorates the result of a generic argument count mismatch -/// check with whether explicit late bounds were provided. -#[derive(Clone)] -pub struct GenericArgCountResult { - pub explicit_late_bound: ExplicitLateBound, - pub correct: Result<(), GenericArgCountMismatch>, -} - -impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { - pub fn ast_region_to_region( - &self, - lifetime: &hir::Lifetime, - def: Option<&ty::GenericParamDef>, - ) -> ty::Region<'tcx> { - let tcx = self.tcx(); - let lifetime_name = |def_id| tcx.hir().name(tcx.hir().local_def_id_to_hir_id(def_id)); - - let r = match tcx.named_region(lifetime.hir_id) { - Some(rl::Region::Static) => tcx.lifetimes.re_static, - - Some(rl::Region::LateBound(debruijn, id, _)) => { - let name = lifetime_name(id.expect_local()); - tcx.mk_region(ty::ReLateBound(debruijn, ty::BrNamed(id, name))) - } - - Some(rl::Region::LateBoundAnon(debruijn, index)) => { - tcx.mk_region(ty::ReLateBound(debruijn, ty::BrAnon(index))) - } - - Some(rl::Region::EarlyBound(index, id, _)) => { - let name = lifetime_name(id.expect_local()); - tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { def_id: id, index, name })) - } - - Some(rl::Region::Free(scope, id)) => { - let name = lifetime_name(id.expect_local()); - tcx.mk_region(ty::ReFree(ty::FreeRegion { - scope, - bound_region: ty::BrNamed(id, name), - })) - - // (*) -- not late-bound, won't change - } - - None => { - self.re_infer(def, lifetime.span).unwrap_or_else(|| { - // This indicates an illegal lifetime - // elision. `resolve_lifetime` should have - // reported an error in this case -- but if - // not, let's error out. - tcx.sess.delay_span_bug(lifetime.span, "unelided lifetime in signature"); - - // Supply some dummy value. We don't have an - // `re_error`, annoyingly, so use `'static`. - tcx.lifetimes.re_static - }) - } - }; - - debug!("ast_region_to_region(lifetime={:?}) yields {:?}", lifetime, r); - - r - } - - /// Given a path `path` that refers to an item `I` with the declared generics `decl_generics`, - /// returns an appropriate set of substitutions for this particular reference to `I`. - pub fn ast_path_substs_for_ty( - &self, - span: Span, - def_id: DefId, - item_segment: &hir::PathSegment<'_>, - ) -> SubstsRef<'tcx> { - let (substs, assoc_bindings, _) = self.create_substs_for_ast_path( - span, - def_id, - &[], - item_segment.generic_args(), - item_segment.infer_args, - None, - ); - - if let Some(b) = assoc_bindings.first() { - Self::prohibit_assoc_ty_binding(self.tcx(), b.span); - } - - substs - } - - /// Report error if there is an explicit type parameter when using `impl Trait`. - fn check_impl_trait( - tcx: TyCtxt<'_>, - seg: &hir::PathSegment<'_>, - generics: &ty::Generics, - ) -> bool { - let explicit = !seg.infer_args; - let impl_trait = generics.params.iter().any(|param| match param.kind { - ty::GenericParamDefKind::Type { - synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), - .. - } => true, - _ => false, - }); - - if explicit && impl_trait { - let spans = seg - .generic_args() - .args - .iter() - .filter_map(|arg| match arg { - GenericArg::Type(_) => Some(arg.span()), - _ => None, - }) - .collect::>(); - - let mut err = struct_span_err! { - tcx.sess, - spans.clone(), - E0632, - "cannot provide explicit generic arguments when `impl Trait` is \ - used in argument position" - }; - - for span in spans { - err.span_label(span, "explicit generic argument not allowed"); - } - - err.emit(); - } - - impl_trait - } - - /// Checks that the correct number of generic arguments have been provided. - /// Used specifically for function calls. - pub fn check_generic_arg_count_for_call( - tcx: TyCtxt<'_>, - span: Span, - def: &ty::Generics, - seg: &hir::PathSegment<'_>, - is_method_call: bool, - ) -> GenericArgCountResult { - let empty_args = hir::GenericArgs::none(); - let suppress_mismatch = Self::check_impl_trait(tcx, seg, &def); - Self::check_generic_arg_count( - tcx, - span, - def, - if let Some(ref args) = seg.args { args } else { &empty_args }, - if is_method_call { GenericArgPosition::MethodCall } else { GenericArgPosition::Value }, - def.parent.is_none() && def.has_self, // `has_self` - seg.infer_args || suppress_mismatch, // `infer_args` - ) - } - - /// Checks that the correct number of generic arguments have been provided. - /// This is used both for datatypes and function calls. - fn check_generic_arg_count( - tcx: TyCtxt<'_>, - span: Span, - def: &ty::Generics, - args: &hir::GenericArgs<'_>, - position: GenericArgPosition, - has_self: bool, - infer_args: bool, - ) -> GenericArgCountResult { - // At this stage we are guaranteed that the generic arguments are in the correct order, e.g. - // that lifetimes will proceed types. So it suffices to check the number of each generic - // arguments in order to validate them with respect to the generic parameters. - let param_counts = def.own_counts(); - let arg_counts = args.own_counts(); - let infer_lifetimes = position != GenericArgPosition::Type && arg_counts.lifetimes == 0; - - let mut defaults: ty::GenericParamCount = Default::default(); - for param in &def.params { - match param.kind { - GenericParamDefKind::Lifetime => {} - GenericParamDefKind::Type { has_default, .. } => { - defaults.types += has_default as usize - } - GenericParamDefKind::Const => { - // FIXME(const_generics:defaults) - } - }; - } - - if position != GenericArgPosition::Type && !args.bindings.is_empty() { - AstConv::prohibit_assoc_ty_binding(tcx, args.bindings[0].span); - } - - let explicit_late_bound = - Self::prohibit_explicit_late_bound_lifetimes(tcx, def, args, position); - - let check_kind_count = |kind, - required, - permitted, - provided, - offset, - unexpected_spans: &mut Vec, - silent| { - debug!( - "check_kind_count: kind: {} required: {} permitted: {} provided: {} offset: {}", - kind, required, permitted, provided, offset - ); - // We enforce the following: `required` <= `provided` <= `permitted`. - // For kinds without defaults (e.g.., lifetimes), `required == permitted`. - // For other kinds (i.e., types), `permitted` may be greater than `required`. - if required <= provided && provided <= permitted { - return Ok(()); - } - - if silent { - return Err(true); - } - - // Unfortunately lifetime and type parameter mismatches are typically styled - // differently in diagnostics, which means we have a few cases to consider here. - let (bound, quantifier) = if required != permitted { - if provided < required { - (required, "at least ") - } else { - // provided > permitted - (permitted, "at most ") - } - } else { - (required, "") - }; - - let (spans, label) = if required == permitted && provided > permitted { - // In the case when the user has provided too many arguments, - // we want to point to the unexpected arguments. - let spans: Vec = args.args[offset + permitted..offset + provided] - .iter() - .map(|arg| arg.span()) - .collect(); - unexpected_spans.extend(spans.clone()); - (spans, format!("unexpected {} argument", kind)) - } else { - ( - vec![span], - format!( - "expected {}{} {} argument{}", - quantifier, - bound, - kind, - pluralize!(bound), - ), - ) - }; - - let mut err = tcx.sess.struct_span_err_with_code( - spans.clone(), - &format!( - "wrong number of {} arguments: expected {}{}, found {}", - kind, quantifier, bound, provided, - ), - DiagnosticId::Error("E0107".into()), - ); - for span in spans { - err.span_label(span, label.as_str()); - } - err.emit(); - - Err(true) - }; - - let mut arg_count_correct = Ok(()); - let mut unexpected_spans = vec![]; - - if !infer_lifetimes || arg_counts.lifetimes > param_counts.lifetimes { - arg_count_correct = check_kind_count( - "lifetime", - param_counts.lifetimes, - param_counts.lifetimes, - arg_counts.lifetimes, - 0, - &mut unexpected_spans, - explicit_late_bound == ExplicitLateBound::Yes, - ) - .and(arg_count_correct); - } - // FIXME(const_generics:defaults) - if !infer_args || arg_counts.consts > param_counts.consts { - arg_count_correct = check_kind_count( - "const", - param_counts.consts, - param_counts.consts, - arg_counts.consts, - arg_counts.lifetimes + arg_counts.types, - &mut unexpected_spans, - false, - ) - .and(arg_count_correct); - } - // Note that type errors are currently be emitted *after* const errors. - if !infer_args || arg_counts.types > param_counts.types - defaults.types - has_self as usize - { - arg_count_correct = check_kind_count( - "type", - param_counts.types - defaults.types - has_self as usize, - param_counts.types - has_self as usize, - arg_counts.types, - arg_counts.lifetimes, - &mut unexpected_spans, - false, - ) - .and(arg_count_correct); - } - - GenericArgCountResult { - explicit_late_bound, - correct: arg_count_correct.map_err(|reported_err| GenericArgCountMismatch { - reported: if reported_err { Some(ErrorReported) } else { None }, - invalid_args: unexpected_spans, - }), - } - } - - /// Report an error that a generic argument did not match the generic parameter that was - /// expected. - fn generic_arg_mismatch_err( - sess: &Session, - arg: &GenericArg<'_>, - kind: &'static str, - help: Option<&str>, - ) { - let mut err = struct_span_err!( - sess, - arg.span(), - E0747, - "{} provided when a {} was expected", - arg.descr(), - kind, - ); - - let unordered = sess.features_untracked().const_generics; - let kind_ord = match kind { - "lifetime" => ParamKindOrd::Lifetime, - "type" => ParamKindOrd::Type, - "constant" => ParamKindOrd::Const { unordered }, - // It's more concise to match on the string representation, though it means - // the match is non-exhaustive. - _ => bug!("invalid generic parameter kind {}", kind), - }; - let arg_ord = match arg { - GenericArg::Lifetime(_) => ParamKindOrd::Lifetime, - GenericArg::Type(_) => ParamKindOrd::Type, - GenericArg::Const(_) => ParamKindOrd::Const { unordered }, - }; - - // This note is only true when generic parameters are strictly ordered by their kind. - if kind_ord.cmp(&arg_ord) != core::cmp::Ordering::Equal { - let (first, last) = - if kind_ord < arg_ord { (kind, arg.descr()) } else { (arg.descr(), kind) }; - err.note(&format!("{} arguments must be provided before {} arguments", first, last)); - if let Some(help) = help { - err.help(help); - } - } - - err.emit(); - } - - /// Creates the relevant generic argument substitutions - /// corresponding to a set of generic parameters. This is a - /// rather complex function. Let us try to explain the role - /// of each of its parameters: - /// - /// To start, we are given the `def_id` of the thing we are - /// creating the substitutions for, and a partial set of - /// substitutions `parent_substs`. In general, the substitutions - /// for an item begin with substitutions for all the "parents" of - /// that item -- e.g., for a method it might include the - /// parameters from the impl. - /// - /// Therefore, the method begins by walking down these parents, - /// starting with the outermost parent and proceed inwards until - /// it reaches `def_id`. For each parent `P`, it will check `parent_substs` - /// first to see if the parent's substitutions are listed in there. If so, - /// we can append those and move on. Otherwise, it invokes the - /// three callback functions: - /// - /// - `args_for_def_id`: given the `DefId` `P`, supplies back the - /// generic arguments that were given to that parent from within - /// the path; so e.g., if you have `::Bar`, the `DefId` - /// might refer to the trait `Foo`, and the arguments might be - /// `[T]`. The boolean value indicates whether to infer values - /// for arguments whose values were not explicitly provided. - /// - `provided_kind`: given the generic parameter and the value from `args_for_def_id`, - /// instantiate a `GenericArg`. - /// - `inferred_kind`: if no parameter was provided, and inference is enabled, then - /// creates a suitable inference variable. - pub fn create_substs_for_generic_args<'b>( - tcx: TyCtxt<'tcx>, - def_id: DefId, - parent_substs: &[subst::GenericArg<'tcx>], - has_self: bool, - self_ty: Option>, - arg_count: GenericArgCountResult, - args_for_def_id: impl Fn(DefId) -> (Option<&'b GenericArgs<'b>>, bool), - mut provided_kind: impl FnMut(&GenericParamDef, &GenericArg<'_>) -> subst::GenericArg<'tcx>, - mut inferred_kind: impl FnMut( - Option<&[subst::GenericArg<'tcx>]>, - &GenericParamDef, - bool, - ) -> subst::GenericArg<'tcx>, - ) -> SubstsRef<'tcx> { - // Collect the segments of the path; we need to substitute arguments - // for parameters throughout the entire path (wherever there are - // generic parameters). - let mut parent_defs = tcx.generics_of(def_id); - let count = parent_defs.count(); - let mut stack = vec![(def_id, parent_defs)]; - while let Some(def_id) = parent_defs.parent { - parent_defs = tcx.generics_of(def_id); - stack.push((def_id, parent_defs)); - } - - // We manually build up the substitution, rather than using convenience - // methods in `subst.rs`, so that we can iterate over the arguments and - // parameters in lock-step linearly, instead of trying to match each pair. - let mut substs: SmallVec<[subst::GenericArg<'tcx>; 8]> = SmallVec::with_capacity(count); - // Iterate over each segment of the path. - while let Some((def_id, defs)) = stack.pop() { - let mut params = defs.params.iter().peekable(); - - // If we have already computed substitutions for parents, we can use those directly. - while let Some(¶m) = params.peek() { - if let Some(&kind) = parent_substs.get(param.index as usize) { - substs.push(kind); - params.next(); - } else { - break; - } - } - - // `Self` is handled first, unless it's been handled in `parent_substs`. - if has_self { - if let Some(¶m) = params.peek() { - if param.index == 0 { - if let GenericParamDefKind::Type { .. } = param.kind { - substs.push( - self_ty - .map(|ty| ty.into()) - .unwrap_or_else(|| inferred_kind(None, param, true)), - ); - params.next(); - } - } - } - } - - // Check whether this segment takes generic arguments and the user has provided any. - let (generic_args, infer_args) = args_for_def_id(def_id); - - let mut args = - generic_args.iter().flat_map(|generic_args| generic_args.args.iter()).peekable(); - - // If we encounter a type or const when we expect a lifetime, we infer the lifetimes. - // If we later encounter a lifetime, we know that the arguments were provided in the - // wrong order. `force_infer_lt` records the type or const that forced lifetimes to be - // inferred, so we can use it for diagnostics later. - let mut force_infer_lt = None; - - loop { - // We're going to iterate through the generic arguments that the user - // provided, matching them with the generic parameters we expect. - // Mismatches can occur as a result of elided lifetimes, or for malformed - // input. We try to handle both sensibly. - match (args.peek(), params.peek()) { - (Some(&arg), Some(¶m)) => { - match (arg, ¶m.kind, arg_count.explicit_late_bound) { - (GenericArg::Lifetime(_), GenericParamDefKind::Lifetime, _) - | (GenericArg::Type(_), GenericParamDefKind::Type { .. }, _) - | (GenericArg::Const(_), GenericParamDefKind::Const, _) => { - substs.push(provided_kind(param, arg)); - args.next(); - params.next(); - } - ( - GenericArg::Type(_) | GenericArg::Const(_), - GenericParamDefKind::Lifetime, - _, - ) => { - // We expected a lifetime argument, but got a type or const - // argument. That means we're inferring the lifetimes. - substs.push(inferred_kind(None, param, infer_args)); - force_infer_lt = Some(arg); - params.next(); - } - (GenericArg::Lifetime(_), _, ExplicitLateBound::Yes) => { - // We've come across a lifetime when we expected something else in - // the presence of explicit late bounds. This is most likely - // due to the presence of the explicit bound so we're just going to - // ignore it. - args.next(); - } - (_, kind, _) => { - // We expected one kind of parameter, but the user provided - // another. This is an error. However, if we already know that - // the arguments don't match up with the parameters, we won't issue - // an additional error, as the user already knows what's wrong. - if arg_count.correct.is_ok() - && arg_count.explicit_late_bound == ExplicitLateBound::No - { - // We're going to iterate over the parameters to sort them out, and - // show that order to the user as a possible order for the parameters - let mut param_types_present = defs - .params - .clone() - .into_iter() - .map(|param| { - ( - match param.kind { - GenericParamDefKind::Lifetime => { - ParamKindOrd::Lifetime - } - GenericParamDefKind::Type { .. } => { - ParamKindOrd::Type - } - GenericParamDefKind::Const => { - ParamKindOrd::Const { - unordered: tcx - .sess - .features_untracked() - .const_generics, - } - } - }, - param, - ) - }) - .collect::>(); - param_types_present.sort_by_key(|(ord, _)| *ord); - let (mut param_types_present, ordered_params): ( - Vec, - Vec, - ) = param_types_present.into_iter().unzip(); - param_types_present.dedup(); - - Self::generic_arg_mismatch_err( - tcx.sess, - arg, - kind.descr(), - Some(&format!( - "reorder the arguments: {}: `<{}>`", - param_types_present - .into_iter() - .map(|ord| format!("{}s", ord.to_string())) - .collect::>() - .join(", then "), - ordered_params - .into_iter() - .filter_map(|param| { - if param.name == kw::SelfUpper { - None - } else { - Some(param.name.to_string()) - } - }) - .collect::>() - .join(", ") - )), - ); - } - - // We've reported the error, but we want to make sure that this - // problem doesn't bubble down and create additional, irrelevant - // errors. In this case, we're simply going to ignore the argument - // and any following arguments. The rest of the parameters will be - // inferred. - while args.next().is_some() {} - } - } - } - - (Some(&arg), None) => { - // We should never be able to reach this point with well-formed input. - // There are three situations in which we can encounter this issue. - // - // 1. The number of arguments is incorrect. In this case, an error - // will already have been emitted, and we can ignore it. - // 2. There are late-bound lifetime parameters present, yet the - // lifetime arguments have also been explicitly specified by the - // user. - // 3. We've inferred some lifetimes, which have been provided later (i.e. - // after a type or const). We want to throw an error in this case. - - if arg_count.correct.is_ok() - && arg_count.explicit_late_bound == ExplicitLateBound::No - { - let kind = arg.descr(); - assert_eq!(kind, "lifetime"); - let provided = - force_infer_lt.expect("lifetimes ought to have been inferred"); - Self::generic_arg_mismatch_err(tcx.sess, provided, kind, None); - } - - break; - } - - (None, Some(¶m)) => { - // If there are fewer arguments than parameters, it means - // we're inferring the remaining arguments. - substs.push(inferred_kind(Some(&substs), param, infer_args)); - params.next(); - } - - (None, None) => break, - } - } - } - - tcx.intern_substs(&substs) - } - - /// Given the type/lifetime/const arguments provided to some path (along with - /// an implicit `Self`, if this is a trait reference), returns the complete - /// set of substitutions. This may involve applying defaulted type parameters. - /// Also returns back constraints on associated types. - /// - /// Example: - /// - /// ``` - /// T: std::ops::Index - /// ^1 ^^^^^^^^^^^^^^2 ^^^^3 ^^^^^^^^^^^4 - /// ``` - /// - /// 1. The `self_ty` here would refer to the type `T`. - /// 2. The path in question is the path to the trait `std::ops::Index`, - /// which will have been resolved to a `def_id` - /// 3. The `generic_args` contains info on the `<...>` contents. The `usize` type - /// parameters are returned in the `SubstsRef`, the associated type bindings like - /// `Output = u32` are returned in the `Vec` result. - /// - /// Note that the type listing given here is *exactly* what the user provided. - /// - /// For (generic) associated types - /// - /// ``` - /// as Iterable>::Iter::<'a> - /// ``` - /// - /// We have the parent substs are the substs for the parent trait: - /// `[Vec, u8]` and `generic_args` are the arguments for the associated - /// type itself: `['a]`. The returned `SubstsRef` concatenates these two - /// lists: `[Vec, u8, 'a]`. - fn create_substs_for_ast_path<'a>( - &self, - span: Span, - def_id: DefId, - parent_substs: &[subst::GenericArg<'tcx>], - generic_args: &'a hir::GenericArgs<'_>, - infer_args: bool, - self_ty: Option>, - ) -> (SubstsRef<'tcx>, Vec>, GenericArgCountResult) { - // If the type is parameterized by this region, then replace this - // region with the current anon region binding (in other words, - // whatever & would get replaced with). - debug!( - "create_substs_for_ast_path(def_id={:?}, self_ty={:?}, \ - generic_args={:?})", - def_id, self_ty, generic_args - ); - - let tcx = self.tcx(); - let generic_params = tcx.generics_of(def_id); - - if generic_params.has_self { - if generic_params.parent.is_some() { - // The parent is a trait so it should have at least one subst - // for the `Self` type. - assert!(!parent_substs.is_empty()) - } else { - // This item (presumably a trait) needs a self-type. - assert!(self_ty.is_some()); - } - } else { - assert!(self_ty.is_none() && parent_substs.is_empty()); - } - - let arg_count = Self::check_generic_arg_count( - tcx, - span, - &generic_params, - &generic_args, - GenericArgPosition::Type, - self_ty.is_some(), - infer_args, - ); - - let is_object = self_ty.map_or(false, |ty| ty == self.tcx().types.trait_object_dummy_self); - let default_needs_object_self = |param: &ty::GenericParamDef| { - if let GenericParamDefKind::Type { has_default, .. } = param.kind { - if is_object && has_default { - let default_ty = tcx.at(span).type_of(param.def_id); - let self_param = tcx.types.self_param; - if default_ty.walk().any(|arg| arg == self_param.into()) { - // There is no suitable inference default for a type parameter - // that references self, in an object type. - return true; - } - } - } - - false - }; - - let mut missing_type_params = vec![]; - let mut inferred_params = vec![]; - let substs = Self::create_substs_for_generic_args( - tcx, - def_id, - parent_substs, - self_ty.is_some(), - self_ty, - arg_count.clone(), - // Provide the generic args, and whether types should be inferred. - |did| { - if did == def_id { - (Some(generic_args), infer_args) - } else { - // The last component of this tuple is unimportant. - (None, false) - } - }, - // Provide substitutions for parameters for which (valid) arguments have been provided. - |param, arg| match (¶m.kind, arg) { - (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { - self.ast_region_to_region(<, Some(param)).into() - } - (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { - if let (hir::TyKind::Infer, false) = (&ty.kind, self.allow_ty_infer()) { - inferred_params.push(ty.span); - tcx.ty_error().into() - } else { - self.ast_ty_to_ty(&ty).into() - } - } - (GenericParamDefKind::Const, GenericArg::Const(ct)) => { - ty::Const::from_opt_const_arg_anon_const( - tcx, - ty::WithOptConstParam { - did: tcx.hir().local_def_id(ct.value.hir_id), - const_param_did: Some(param.def_id), - }, - ) - .into() - } - _ => unreachable!(), - }, - // Provide substitutions for parameters for which arguments are inferred. - |substs, param, infer_args| { - match param.kind { - GenericParamDefKind::Lifetime => tcx.lifetimes.re_static.into(), - GenericParamDefKind::Type { has_default, .. } => { - if !infer_args && has_default { - // No type parameter provided, but a default exists. - - // If we are converting an object type, then the - // `Self` parameter is unknown. However, some of the - // other type parameters may reference `Self` in their - // defaults. This will lead to an ICE if we are not - // careful! - if default_needs_object_self(param) { - missing_type_params.push(param.name.to_string()); - tcx.ty_error().into() - } else { - // This is a default type parameter. - self.normalize_ty( - span, - tcx.at(span).type_of(param.def_id).subst_spanned( - tcx, - substs.unwrap(), - Some(span), - ), - ) - .into() - } - } else if infer_args { - // No type parameters were provided, we can infer all. - let param = - if !default_needs_object_self(param) { Some(param) } else { None }; - self.ty_infer(param, span).into() - } else { - // We've already errored above about the mismatch. - tcx.ty_error().into() - } - } - GenericParamDefKind::Const => { - let ty = tcx.at(span).type_of(param.def_id); - // FIXME(const_generics:defaults) - if infer_args { - // No const parameters were provided, we can infer all. - self.ct_infer(ty, Some(param), span).into() - } else { - // We've already errored above about the mismatch. - tcx.const_error(ty).into() - } - } - } - }, - ); - - self.complain_about_missing_type_params( - missing_type_params, - def_id, - span, - generic_args.args.is_empty(), - ); - - // Convert associated-type bindings or constraints into a separate vector. - // Example: Given this: - // - // T: Iterator - // - // The `T` is passed in as a self-type; the `Item = u32` is - // not a "type parameter" of the `Iterator` trait, but rather - // a restriction on `::Item`, so it is passed - // back separately. - let assoc_bindings = generic_args - .bindings - .iter() - .map(|binding| { - let kind = match binding.kind { - hir::TypeBindingKind::Equality { ref ty } => { - ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty)) - } - hir::TypeBindingKind::Constraint { ref bounds } => { - ConvertedBindingKind::Constraint(bounds) - } - }; - ConvertedBinding { item_name: binding.ident, kind, span: binding.span } - }) - .collect(); - - debug!( - "create_substs_for_ast_path(generic_params={:?}, self_ty={:?}) -> {:?}", - generic_params, self_ty, substs - ); - - (substs, assoc_bindings, arg_count) - } - - crate fn create_substs_for_associated_item( - &self, - tcx: TyCtxt<'tcx>, - span: Span, - item_def_id: DefId, - item_segment: &hir::PathSegment<'_>, - parent_substs: SubstsRef<'tcx>, - ) -> SubstsRef<'tcx> { - if tcx.generics_of(item_def_id).params.is_empty() { - self.prohibit_generics(slice::from_ref(item_segment)); - - parent_substs - } else { - self.create_substs_for_ast_path( - span, - item_def_id, - parent_substs, - item_segment.generic_args(), - item_segment.infer_args, - None, - ) - .0 - } - } - - /// On missing type parameters, emit an E0393 error and provide a structured suggestion using - /// the type parameter's name as a placeholder. - fn complain_about_missing_type_params( - &self, - missing_type_params: Vec, - def_id: DefId, - span: Span, - empty_generic_args: bool, - ) { - if missing_type_params.is_empty() { - return; - } - let display = - missing_type_params.iter().map(|n| format!("`{}`", n)).collect::>().join(", "); - let mut err = struct_span_err!( - self.tcx().sess, - span, - E0393, - "the type parameter{} {} must be explicitly specified", - pluralize!(missing_type_params.len()), - display, - ); - err.span_label( - self.tcx().def_span(def_id), - &format!( - "type parameter{} {} must be specified for this", - pluralize!(missing_type_params.len()), - display, - ), - ); - let mut suggested = false; - if let (Ok(snippet), true) = ( - self.tcx().sess.source_map().span_to_snippet(span), - // Don't suggest setting the type params if there are some already: the order is - // tricky to get right and the user will already know what the syntax is. - empty_generic_args, - ) { - if snippet.ends_with('>') { - // The user wrote `Trait<'a, T>` or similar. To provide an accurate suggestion - // we would have to preserve the right order. For now, as clearly the user is - // aware of the syntax, we do nothing. - } else { - // The user wrote `Iterator`, so we don't have a type we can suggest, but at - // least we can clue them to the correct syntax `Iterator`. - err.span_suggestion( - span, - &format!( - "set the type parameter{plural} to the desired type{plural}", - plural = pluralize!(missing_type_params.len()), - ), - format!("{}<{}>", snippet, missing_type_params.join(", ")), - Applicability::HasPlaceholders, - ); - suggested = true; - } - } - if !suggested { - err.span_label( - span, - format!( - "missing reference{} to {}", - pluralize!(missing_type_params.len()), - display, - ), - ); - } - err.note( - "because of the default `Self` reference, type parameters must be \ - specified on object types", - ); - err.emit(); - } - - /// Instantiates the path for the given trait reference, assuming that it's - /// bound to a valid trait type. Returns the `DefId` of the defining trait. - /// The type _cannot_ be a type other than a trait type. - /// - /// If the `projections` argument is `None`, then assoc type bindings like `Foo` - /// are disallowed. Otherwise, they are pushed onto the vector given. - pub fn instantiate_mono_trait_ref( - &self, - trait_ref: &hir::TraitRef<'_>, - self_ty: Ty<'tcx>, - ) -> ty::TraitRef<'tcx> { - self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1); - - self.ast_path_to_mono_trait_ref( - trait_ref.path.span, - trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()), - self_ty, - trait_ref.path.segments.last().unwrap(), - ) - } - - /// The given trait-ref must actually be a trait. - pub(super) fn instantiate_poly_trait_ref_inner( - &self, - trait_ref: &hir::TraitRef<'_>, - span: Span, - constness: Constness, - self_ty: Ty<'tcx>, - bounds: &mut Bounds<'tcx>, - speculative: bool, - ) -> GenericArgCountResult { - let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()); - - debug!("instantiate_poly_trait_ref({:?}, def_id={:?})", trait_ref, trait_def_id); - - self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1); - - let (substs, assoc_bindings, arg_count) = self.create_substs_for_ast_trait_ref( - trait_ref.path.span, - trait_def_id, - self_ty, - trait_ref.path.segments.last().unwrap(), - ); - let poly_trait_ref = ty::Binder::bind(ty::TraitRef::new(trait_def_id, substs)); - - bounds.trait_bounds.push((poly_trait_ref, span, constness)); - - let mut dup_bindings = FxHashMap::default(); - for binding in &assoc_bindings { - // Specify type to assert that error was already reported in `Err` case. - let _: Result<_, ErrorReported> = self.add_predicates_for_ast_type_binding( - trait_ref.hir_ref_id, - poly_trait_ref, - binding, - bounds, - speculative, - &mut dup_bindings, - binding.span, - ); - // Okay to ignore `Err` because of `ErrorReported` (see above). - } - - debug!( - "instantiate_poly_trait_ref({:?}, bounds={:?}) -> {:?}", - trait_ref, bounds, poly_trait_ref - ); - - arg_count - } - - /// Given a trait bound like `Debug`, applies that trait bound the given self-type to construct - /// a full trait reference. The resulting trait reference is returned. This may also generate - /// auxiliary bounds, which are added to `bounds`. - /// - /// Example: - /// - /// ``` - /// poly_trait_ref = Iterator - /// self_ty = Foo - /// ``` - /// - /// this would return `Foo: Iterator` and add `::Item = u32` into `bounds`. - /// - /// **A note on binders:** against our usual convention, there is an implied bounder around - /// the `self_ty` and `poly_trait_ref` parameters here. So they may reference bound regions. - /// If for example you had `for<'a> Foo<'a>: Bar<'a>`, then the `self_ty` would be `Foo<'a>` - /// where `'a` is a bound region at depth 0. Similarly, the `poly_trait_ref` would be - /// `Bar<'a>`. The returned poly-trait-ref will have this binder instantiated explicitly, - /// however. - pub fn instantiate_poly_trait_ref( - &self, - poly_trait_ref: &hir::PolyTraitRef<'_>, - constness: Constness, - self_ty: Ty<'tcx>, - bounds: &mut Bounds<'tcx>, - ) -> GenericArgCountResult { - self.instantiate_poly_trait_ref_inner( - &poly_trait_ref.trait_ref, - poly_trait_ref.span, - constness, - self_ty, - bounds, - false, - ) - } - - pub fn instantiate_lang_item_trait_ref( - &self, - lang_item: hir::LangItem, - span: Span, - hir_id: hir::HirId, - args: &GenericArgs<'_>, - self_ty: Ty<'tcx>, - bounds: &mut Bounds<'tcx>, - ) { - let trait_def_id = self.tcx().require_lang_item(lang_item, Some(span)); - - let (substs, assoc_bindings, _) = - self.create_substs_for_ast_path(span, trait_def_id, &[], args, false, Some(self_ty)); - let poly_trait_ref = ty::Binder::bind(ty::TraitRef::new(trait_def_id, substs)); - bounds.trait_bounds.push((poly_trait_ref, span, Constness::NotConst)); - - let mut dup_bindings = FxHashMap::default(); - for binding in assoc_bindings { - let _: Result<_, ErrorReported> = self.add_predicates_for_ast_type_binding( - hir_id, - poly_trait_ref, - &binding, - bounds, - false, - &mut dup_bindings, - span, - ); - } - } - - fn ast_path_to_mono_trait_ref( - &self, - span: Span, - trait_def_id: DefId, - self_ty: Ty<'tcx>, - trait_segment: &hir::PathSegment<'_>, - ) -> ty::TraitRef<'tcx> { - let (substs, assoc_bindings, _) = - self.create_substs_for_ast_trait_ref(span, trait_def_id, self_ty, trait_segment); - if let Some(b) = assoc_bindings.first() { - AstConv::prohibit_assoc_ty_binding(self.tcx(), b.span); - } - ty::TraitRef::new(trait_def_id, substs) - } - - /// When the code is using the `Fn` traits directly, instead of the `Fn(A) -> B` syntax, emit - /// an error and attempt to build a reasonable structured suggestion. - fn complain_about_internal_fn_trait( - &self, - span: Span, - trait_def_id: DefId, - trait_segment: &'a hir::PathSegment<'a>, - ) { - let trait_def = self.tcx().trait_def(trait_def_id); - - if !self.tcx().features().unboxed_closures - && trait_segment.generic_args().parenthesized != trait_def.paren_sugar - { - let sess = &self.tcx().sess.parse_sess; - // For now, require that parenthetical notation be used only with `Fn()` etc. - let (msg, sugg) = if trait_def.paren_sugar { - ( - "the precise format of `Fn`-family traits' type parameters is subject to \ - change", - Some(format!( - "{}{} -> {}", - trait_segment.ident, - trait_segment - .args - .as_ref() - .and_then(|args| args.args.get(0)) - .and_then(|arg| match arg { - hir::GenericArg::Type(ty) => match ty.kind { - hir::TyKind::Tup(t) => t - .iter() - .map(|e| sess.source_map().span_to_snippet(e.span)) - .collect::, _>>() - .map(|a| a.join(", ")), - _ => sess.source_map().span_to_snippet(ty.span), - } - .map(|s| format!("({})", s)) - .ok(), - _ => None, - }) - .unwrap_or_else(|| "()".to_string()), - trait_segment - .generic_args() - .bindings - .iter() - .find_map(|b| match (b.ident.name == sym::Output, &b.kind) { - (true, hir::TypeBindingKind::Equality { ty }) => { - sess.source_map().span_to_snippet(ty.span).ok() - } - _ => None, - }) - .unwrap_or_else(|| "()".to_string()), - )), - ) - } else { - ("parenthetical notation is only stable when used with `Fn`-family traits", None) - }; - let mut err = feature_err(sess, sym::unboxed_closures, span, msg); - if let Some(sugg) = sugg { - let msg = "use parenthetical notation instead"; - err.span_suggestion(span, msg, sugg, Applicability::MaybeIncorrect); - } - err.emit(); - } - } - - fn create_substs_for_ast_trait_ref<'a>( - &self, - span: Span, - trait_def_id: DefId, - self_ty: Ty<'tcx>, - trait_segment: &'a hir::PathSegment<'a>, - ) -> (SubstsRef<'tcx>, Vec>, GenericArgCountResult) { - debug!("create_substs_for_ast_trait_ref(trait_segment={:?})", trait_segment); - - self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment); - - self.create_substs_for_ast_path( - span, - trait_def_id, - &[], - trait_segment.generic_args(), - trait_segment.infer_args, - Some(self_ty), - ) - } - - fn trait_defines_associated_type_named(&self, trait_def_id: DefId, assoc_name: Ident) -> bool { - self.tcx() - .associated_items(trait_def_id) - .find_by_name_and_kind(self.tcx(), assoc_name, ty::AssocKind::Type, trait_def_id) - .is_some() - } - - // Returns `true` if a bounds list includes `?Sized`. - pub fn is_unsized(&self, ast_bounds: &[hir::GenericBound<'_>], span: Span) -> bool { - let tcx = self.tcx(); - - // Try to find an unbound in bounds. - let mut unbound = None; - for ab in ast_bounds { - if let &hir::GenericBound::Trait(ref ptr, hir::TraitBoundModifier::Maybe) = ab { - if unbound.is_none() { - unbound = Some(&ptr.trait_ref); - } else { - struct_span_err!( - tcx.sess, - span, - E0203, - "type parameter has more than one relaxed default \ - bound, only one is supported" - ) - .emit(); - } - } - } - - let kind_id = tcx.lang_items().require(SizedTraitLangItem); - match unbound { - Some(tpb) => { - // FIXME(#8559) currently requires the unbound to be built-in. - if let Ok(kind_id) = kind_id { - if tpb.path.res != Res::Def(DefKind::Trait, kind_id) { - tcx.sess.span_warn( - span, - "default bound relaxed for a type parameter, but \ - this does nothing because the given bound is not \ - a default; only `?Sized` is supported", - ); - } - } - } - _ if kind_id.is_ok() => { - return false; - } - // No lang item for `Sized`, so we can't add it as a bound. - None => {} - } - - true - } - - /// This helper takes a *converted* parameter type (`param_ty`) - /// and an *unconverted* list of bounds: - /// - /// ```text - /// fn foo - /// ^ ^^^^^ `ast_bounds` parameter, in HIR form - /// | - /// `param_ty`, in ty form - /// ``` - /// - /// It adds these `ast_bounds` into the `bounds` structure. - /// - /// **A note on binders:** there is an implied binder around - /// `param_ty` and `ast_bounds`. See `instantiate_poly_trait_ref` - /// for more details. - fn add_bounds( - &self, - param_ty: Ty<'tcx>, - ast_bounds: &[hir::GenericBound<'_>], - bounds: &mut Bounds<'tcx>, - ) { - let mut trait_bounds = Vec::new(); - let mut region_bounds = Vec::new(); - - let constness = self.default_constness_for_trait_bounds(); - for ast_bound in ast_bounds { - match *ast_bound { - hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::None) => { - trait_bounds.push((b, constness)) - } - hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::MaybeConst) => { - trait_bounds.push((b, Constness::NotConst)) - } - hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => {} - hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => self - .instantiate_lang_item_trait_ref( - lang_item, span, hir_id, args, param_ty, bounds, - ), - hir::GenericBound::Outlives(ref l) => region_bounds.push(l), - } - } - - for (bound, constness) in trait_bounds { - let _ = self.instantiate_poly_trait_ref(bound, constness, param_ty, bounds); - } - - bounds.region_bounds.extend( - region_bounds.into_iter().map(|r| (self.ast_region_to_region(r, None), r.span)), - ); - } - - /// Translates a list of bounds from the HIR into the `Bounds` data structure. - /// The self-type for the bounds is given by `param_ty`. - /// - /// Example: - /// - /// ``` - /// fn foo() { } - /// ^ ^^^^^^^^^ ast_bounds - /// param_ty - /// ``` - /// - /// The `sized_by_default` parameter indicates if, in this context, the `param_ty` should be - /// considered `Sized` unless there is an explicit `?Sized` bound. This would be true in the - /// example above, but is not true in supertrait listings like `trait Foo: Bar + Baz`. - /// - /// `span` should be the declaration size of the parameter. - pub fn compute_bounds( - &self, - param_ty: Ty<'tcx>, - ast_bounds: &[hir::GenericBound<'_>], - sized_by_default: SizedByDefault, - span: Span, - ) -> Bounds<'tcx> { - let mut bounds = Bounds::default(); - - self.add_bounds(param_ty, ast_bounds, &mut bounds); - bounds.trait_bounds.sort_by_key(|(t, _, _)| t.def_id()); - - bounds.implicitly_sized = if let SizedByDefault::Yes = sized_by_default { - if !self.is_unsized(ast_bounds, span) { Some(span) } else { None } - } else { - None - }; - - bounds - } - - /// Given an HIR binding like `Item = Foo` or `Item: Foo`, pushes the corresponding predicates - /// onto `bounds`. - /// - /// **A note on binders:** given something like `T: for<'a> Iterator`, the - /// `trait_ref` here will be `for<'a> T: Iterator`. The `binding` data however is from *inside* - /// the binder (e.g., `&'a u32`) and hence may reference bound regions. - fn add_predicates_for_ast_type_binding( - &self, - hir_ref_id: hir::HirId, - trait_ref: ty::PolyTraitRef<'tcx>, - binding: &ConvertedBinding<'_, 'tcx>, - bounds: &mut Bounds<'tcx>, - speculative: bool, - dup_bindings: &mut FxHashMap, - path_span: Span, - ) -> Result<(), ErrorReported> { - let tcx = self.tcx(); - - if !speculative { - // Given something like `U: SomeTrait`, we want to produce a - // predicate like `::T = X`. This is somewhat - // subtle in the event that `T` is defined in a supertrait of - // `SomeTrait`, because in that case we need to upcast. - // - // That is, consider this case: - // - // ``` - // trait SubTrait: SuperTrait { } - // trait SuperTrait { type T; } - // - // ... B: SubTrait ... - // ``` - // - // We want to produce `>::T == foo`. - - // Find any late-bound regions declared in `ty` that are not - // declared in the trait-ref. These are not well-formed. - // - // Example: - // - // for<'a> ::Item = &'a str // <-- 'a is bad - // for<'a> >::Output = &'a str // <-- 'a is ok - if let ConvertedBindingKind::Equality(ty) = binding.kind { - let late_bound_in_trait_ref = - tcx.collect_constrained_late_bound_regions(&trait_ref); - let late_bound_in_ty = - tcx.collect_referenced_late_bound_regions(&ty::Binder::bind(ty)); - debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref); - debug!("late_bound_in_ty = {:?}", late_bound_in_ty); - - // FIXME: point at the type params that don't have appropriate lifetimes: - // struct S1 Fn(&i32, &i32) -> &'a i32>(F); - // ---- ---- ^^^^^^^ - self.validate_late_bound_regions( - late_bound_in_trait_ref, - late_bound_in_ty, - |br_name| { - struct_span_err!( - tcx.sess, - binding.span, - E0582, - "binding for associated type `{}` references {}, \ - which does not appear in the trait input types", - binding.item_name, - br_name - ) - }, - ); - } - } - - let candidate = - if self.trait_defines_associated_type_named(trait_ref.def_id(), binding.item_name) { - // Simple case: X is defined in the current trait. - trait_ref - } else { - // Otherwise, we have to walk through the supertraits to find - // those that do. - self.one_bound_for_assoc_type( - || traits::supertraits(tcx, trait_ref), - || trait_ref.print_only_trait_path().to_string(), - binding.item_name, - path_span, - || match binding.kind { - ConvertedBindingKind::Equality(ty) => Some(ty.to_string()), - _ => None, - }, - )? - }; - - let (assoc_ident, def_scope) = - tcx.adjust_ident_and_get_scope(binding.item_name, candidate.def_id(), hir_ref_id); - - // We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead - // of calling `filter_by_name_and_kind`. - let assoc_ty = tcx - .associated_items(candidate.def_id()) - .filter_by_name_unhygienic(assoc_ident.name) - .find(|i| { - i.kind == ty::AssocKind::Type && i.ident.normalize_to_macros_2_0() == assoc_ident - }) - .expect("missing associated type"); - - if !assoc_ty.vis.is_accessible_from(def_scope, tcx) { - tcx.sess - .struct_span_err( - binding.span, - &format!("associated type `{}` is private", binding.item_name), - ) - .span_label(binding.span, "private associated type") - .emit(); - } - tcx.check_stability(assoc_ty.def_id, Some(hir_ref_id), binding.span); - - if !speculative { - dup_bindings - .entry(assoc_ty.def_id) - .and_modify(|prev_span| { - struct_span_err!( - self.tcx().sess, - binding.span, - E0719, - "the value of the associated type `{}` (from trait `{}`) \ - is already specified", - binding.item_name, - tcx.def_path_str(assoc_ty.container.id()) - ) - .span_label(binding.span, "re-bound here") - .span_label(*prev_span, format!("`{}` bound here first", binding.item_name)) - .emit(); - }) - .or_insert(binding.span); - } - - match binding.kind { - ConvertedBindingKind::Equality(ref ty) => { - // "Desugar" a constraint like `T: Iterator` this to - // the "projection predicate" for: - // - // `::Item = u32` - bounds.projection_bounds.push(( - candidate.map_bound(|trait_ref| ty::ProjectionPredicate { - projection_ty: ty::ProjectionTy::from_ref_and_name( - tcx, - trait_ref, - binding.item_name, - ), - ty, - }), - binding.span, - )); - } - ConvertedBindingKind::Constraint(ast_bounds) => { - // "Desugar" a constraint like `T: Iterator` to - // - // `::Item: Debug` - // - // Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty` - // parameter to have a skipped binder. - let param_ty = tcx.mk_projection(assoc_ty.def_id, candidate.skip_binder().substs); - self.add_bounds(param_ty, ast_bounds, bounds); - } - } - Ok(()) - } - - fn ast_path_to_ty( - &self, - span: Span, - did: DefId, - item_segment: &hir::PathSegment<'_>, - ) -> Ty<'tcx> { - let substs = self.ast_path_substs_for_ty(span, did, item_segment); - self.normalize_ty(span, self.tcx().at(span).type_of(did).subst(self.tcx(), substs)) - } - - fn conv_object_ty_poly_trait_ref( - &self, - span: Span, - trait_bounds: &[hir::PolyTraitRef<'_>], - lifetime: &hir::Lifetime, - borrowed: bool, - ) -> Ty<'tcx> { - let tcx = self.tcx(); - - let mut bounds = Bounds::default(); - let mut potential_assoc_types = Vec::new(); - let dummy_self = self.tcx().types.trait_object_dummy_self; - for trait_bound in trait_bounds.iter().rev() { - if let GenericArgCountResult { - correct: - Err(GenericArgCountMismatch { invalid_args: cur_potential_assoc_types, .. }), - .. - } = self.instantiate_poly_trait_ref( - trait_bound, - Constness::NotConst, - dummy_self, - &mut bounds, - ) { - potential_assoc_types.extend(cur_potential_assoc_types.into_iter()); - } - } - - // Expand trait aliases recursively and check that only one regular (non-auto) trait - // is used and no 'maybe' bounds are used. - let expanded_traits = - traits::expand_trait_aliases(tcx, bounds.trait_bounds.iter().map(|&(a, b, _)| (a, b))); - let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) = - expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id())); - if regular_traits.len() > 1 { - let first_trait = ®ular_traits[0]; - let additional_trait = ®ular_traits[1]; - let mut err = struct_span_err!( - tcx.sess, - additional_trait.bottom().1, - E0225, - "only auto traits can be used as additional traits in a trait object" - ); - additional_trait.label_with_exp_info( - &mut err, - "additional non-auto trait", - "additional use", - ); - first_trait.label_with_exp_info(&mut err, "first non-auto trait", "first use"); - err.help(&format!( - "consider creating a new trait with all of these as super-traits and using that \ - trait here instead: `trait NewTrait: {} {{}}`", - regular_traits - .iter() - .map(|t| t.trait_ref().print_only_trait_path().to_string()) - .collect::>() - .join(" + "), - )); - err.note( - "auto-traits like `Send` and `Sync` are traits that have special properties; \ - for more information on them, visit \ - ", - ); - err.emit(); - } - - if regular_traits.is_empty() && auto_traits.is_empty() { - struct_span_err!( - tcx.sess, - span, - E0224, - "at least one trait is required for an object type" - ) - .emit(); - return tcx.ty_error(); - } - - // Check that there are no gross object safety violations; - // most importantly, that the supertraits don't contain `Self`, - // to avoid ICEs. - for item in ®ular_traits { - let object_safety_violations = - astconv_object_safety_violations(tcx, item.trait_ref().def_id()); - if !object_safety_violations.is_empty() { - report_object_safety_error( - tcx, - span, - item.trait_ref().def_id(), - &object_safety_violations[..], - ) - .emit(); - return tcx.ty_error(); - } - } - - // Use a `BTreeSet` to keep output in a more consistent order. - let mut associated_types: FxHashMap> = FxHashMap::default(); - - let regular_traits_refs_spans = bounds - .trait_bounds - .into_iter() - .filter(|(trait_ref, _, _)| !tcx.trait_is_auto(trait_ref.def_id())); - - for (base_trait_ref, span, constness) in regular_traits_refs_spans { - assert_eq!(constness, Constness::NotConst); - - for obligation in traits::elaborate_trait_ref(tcx, base_trait_ref) { - debug!( - "conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", - obligation.predicate - ); - - match obligation.predicate.skip_binders() { - ty::PredicateAtom::Trait(pred, _) => { - let pred = ty::Binder::bind(pred); - associated_types.entry(span).or_default().extend( - tcx.associated_items(pred.def_id()) - .in_definition_order() - .filter(|item| item.kind == ty::AssocKind::Type) - .map(|item| item.def_id), - ); - } - ty::PredicateAtom::Projection(pred) => { - let pred = ty::Binder::bind(pred); - // A `Self` within the original bound will be substituted with a - // `trait_object_dummy_self`, so check for that. - let references_self = - pred.skip_binder().ty.walk().any(|arg| arg == dummy_self.into()); - - // If the projection output contains `Self`, force the user to - // elaborate it explicitly to avoid a lot of complexity. - // - // The "classicaly useful" case is the following: - // ``` - // trait MyTrait: FnMut() -> ::MyOutput { - // type MyOutput; - // } - // ``` - // - // Here, the user could theoretically write `dyn MyTrait`, - // but actually supporting that would "expand" to an infinitely-long type - // `fix $ τ → dyn MyTrait::MyOutput`. - // - // Instead, we force the user to write - // `dyn MyTrait`, which is uglier but works. See - // the discussion in #56288 for alternatives. - if !references_self { - // Include projections defined on supertraits. - bounds.projection_bounds.push((pred, span)); - } - } - _ => (), - } - } - } - - for (projection_bound, _) in &bounds.projection_bounds { - for def_ids in associated_types.values_mut() { - def_ids.remove(&projection_bound.projection_def_id()); - } - } - - self.complain_about_missing_associated_types( - associated_types, - potential_assoc_types, - trait_bounds, - ); - - // De-duplicate auto traits so that, e.g., `dyn Trait + Send + Send` is the same as - // `dyn Trait + Send`. - auto_traits.sort_by_key(|i| i.trait_ref().def_id()); - auto_traits.dedup_by_key(|i| i.trait_ref().def_id()); - debug!("regular_traits: {:?}", regular_traits); - debug!("auto_traits: {:?}", auto_traits); - - // Transform a `PolyTraitRef` into a `PolyExistentialTraitRef` by - // removing the dummy `Self` type (`trait_object_dummy_self`). - let trait_ref_to_existential = |trait_ref: ty::TraitRef<'tcx>| { - if trait_ref.self_ty() != dummy_self { - // FIXME: There appears to be a missing filter on top of `expand_trait_aliases`, - // which picks up non-supertraits where clauses - but also, the object safety - // completely ignores trait aliases, which could be object safety hazards. We - // `delay_span_bug` here to avoid an ICE in stable even when the feature is - // disabled. (#66420) - tcx.sess.delay_span_bug( - DUMMY_SP, - &format!( - "trait_ref_to_existential called on {:?} with non-dummy Self", - trait_ref, - ), - ); - } - ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref) - }; - - // Erase the `dummy_self` (`trait_object_dummy_self`) used above. - let existential_trait_refs = - regular_traits.iter().map(|i| i.trait_ref().map_bound(trait_ref_to_existential)); - let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| { - bound.map_bound(|b| { - let trait_ref = trait_ref_to_existential(b.projection_ty.trait_ref(tcx)); - ty::ExistentialProjection { - ty: b.ty, - item_def_id: b.projection_ty.item_def_id, - substs: trait_ref.substs, - } - }) - }); - - // Calling `skip_binder` is okay because the predicates are re-bound. - let regular_trait_predicates = existential_trait_refs - .map(|trait_ref| ty::ExistentialPredicate::Trait(trait_ref.skip_binder())); - let auto_trait_predicates = auto_traits - .into_iter() - .map(|trait_ref| ty::ExistentialPredicate::AutoTrait(trait_ref.trait_ref().def_id())); - let mut v = regular_trait_predicates - .chain(auto_trait_predicates) - .chain( - existential_projections - .map(|x| ty::ExistentialPredicate::Projection(x.skip_binder())), - ) - .collect::>(); - v.sort_by(|a, b| a.stable_cmp(tcx, b)); - v.dedup(); - let existential_predicates = ty::Binder::bind(tcx.mk_existential_predicates(v.into_iter())); - - // Use explicitly-specified region bound. - let region_bound = if !lifetime.is_elided() { - self.ast_region_to_region(lifetime, None) - } else { - self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| { - if tcx.named_region(lifetime.hir_id).is_some() { - self.ast_region_to_region(lifetime, None) - } else { - self.re_infer(None, span).unwrap_or_else(|| { - let mut err = struct_span_err!( - tcx.sess, - span, - E0228, - "the lifetime bound for this object type cannot be deduced \ - from context; please supply an explicit bound" - ); - if borrowed { - // We will have already emitted an error E0106 complaining about a - // missing named lifetime in `&dyn Trait`, so we elide this one. - err.delay_as_bug(); - } else { - err.emit(); - } - tcx.lifetimes.re_static - }) - } - }) - }; - debug!("region_bound: {:?}", region_bound); - - let ty = tcx.mk_dynamic(existential_predicates, region_bound); - debug!("trait_object_type: {:?}", ty); - ty - } - - /// When there are any missing associated types, emit an E0191 error and attempt to supply a - /// reasonable suggestion on how to write it. For the case of multiple associated types in the - /// same trait bound have the same name (as they come from different super-traits), we instead - /// emit a generic note suggesting using a `where` clause to constraint instead. - fn complain_about_missing_associated_types( - &self, - associated_types: FxHashMap>, - potential_assoc_types: Vec, - trait_bounds: &[hir::PolyTraitRef<'_>], - ) { - if associated_types.values().all(|v| v.is_empty()) { - return; - } - let tcx = self.tcx(); - // FIXME: Marked `mut` so that we can replace the spans further below with a more - // appropriate one, but this should be handled earlier in the span assignment. - let mut associated_types: FxHashMap> = associated_types - .into_iter() - .map(|(span, def_ids)| { - (span, def_ids.into_iter().map(|did| tcx.associated_item(did)).collect()) - }) - .collect(); - let mut names = vec![]; - - // Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and - // `issue-22560.rs`. - let mut trait_bound_spans: Vec = vec![]; - for (span, items) in &associated_types { - if !items.is_empty() { - trait_bound_spans.push(*span); - } - for assoc_item in items { - let trait_def_id = assoc_item.container.id(); - names.push(format!( - "`{}` (from trait `{}`)", - assoc_item.ident, - tcx.def_path_str(trait_def_id), - )); - } - } - if let ([], [bound]) = (&potential_assoc_types[..], &trait_bounds) { - match &bound.trait_ref.path.segments[..] { - // FIXME: `trait_ref.path.span` can point to a full path with multiple - // segments, even though `trait_ref.path.segments` is of length `1`. Work - // around that bug here, even though it should be fixed elsewhere. - // This would otherwise cause an invalid suggestion. For an example, look at - // `src/test/ui/issues/issue-28344.rs` where instead of the following: - // - // error[E0191]: the value of the associated type `Output` - // (from trait `std::ops::BitXor`) must be specified - // --> $DIR/issue-28344.rs:4:17 - // | - // LL | let x: u8 = BitXor::bitor(0 as u8, 0 as u8); - // | ^^^^^^ help: specify the associated type: - // | `BitXor` - // - // we would output: - // - // error[E0191]: the value of the associated type `Output` - // (from trait `std::ops::BitXor`) must be specified - // --> $DIR/issue-28344.rs:4:17 - // | - // LL | let x: u8 = BitXor::bitor(0 as u8, 0 as u8); - // | ^^^^^^^^^^^^^ help: specify the associated type: - // | `BitXor::bitor` - [segment] if segment.args.is_none() => { - trait_bound_spans = vec![segment.ident.span]; - associated_types = associated_types - .into_iter() - .map(|(_, items)| (segment.ident.span, items)) - .collect(); - } - _ => {} - } - } - names.sort(); - trait_bound_spans.sort(); - let mut err = struct_span_err!( - tcx.sess, - trait_bound_spans, - E0191, - "the value of the associated type{} {} must be specified", - pluralize!(names.len()), - names.join(", "), - ); - let mut suggestions = vec![]; - let mut types_count = 0; - let mut where_constraints = vec![]; - for (span, assoc_items) in &associated_types { - let mut names: FxHashMap<_, usize> = FxHashMap::default(); - for item in assoc_items { - types_count += 1; - *names.entry(item.ident.name).or_insert(0) += 1; - } - let mut dupes = false; - for item in assoc_items { - let prefix = if names[&item.ident.name] > 1 { - let trait_def_id = item.container.id(); - dupes = true; - format!("{}::", tcx.def_path_str(trait_def_id)) - } else { - String::new() - }; - if let Some(sp) = tcx.hir().span_if_local(item.def_id) { - err.span_label(sp, format!("`{}{}` defined here", prefix, item.ident)); - } - } - if potential_assoc_types.len() == assoc_items.len() { - // Only suggest when the amount of missing associated types equals the number of - // extra type arguments present, as that gives us a relatively high confidence - // that the user forgot to give the associtated type's name. The canonical - // example would be trying to use `Iterator` instead of - // `Iterator`. - for (potential, item) in potential_assoc_types.iter().zip(assoc_items.iter()) { - if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*potential) { - suggestions.push((*potential, format!("{} = {}", item.ident, snippet))); - } - } - } else if let (Ok(snippet), false) = - (tcx.sess.source_map().span_to_snippet(*span), dupes) - { - let types: Vec<_> = - assoc_items.iter().map(|item| format!("{} = Type", item.ident)).collect(); - let code = if snippet.ends_with('>') { - // The user wrote `Trait<'a>` or similar and we don't have a type we can - // suggest, but at least we can clue them to the correct syntax - // `Trait<'a, Item = Type>` while accounting for the `<'a>` in the - // suggestion. - format!("{}, {}>", &snippet[..snippet.len() - 1], types.join(", ")) - } else { - // The user wrote `Iterator`, so we don't have a type we can suggest, but at - // least we can clue them to the correct syntax `Iterator`. - format!("{}<{}>", snippet, types.join(", ")) - }; - suggestions.push((*span, code)); - } else if dupes { - where_constraints.push(*span); - } - } - let where_msg = "consider introducing a new type parameter, adding `where` constraints \ - using the fully-qualified path to the associated types"; - if !where_constraints.is_empty() && suggestions.is_empty() { - // If there are duplicates associated type names and a single trait bound do not - // use structured suggestion, it means that there are multiple super-traits with - // the same associated type name. - err.help(where_msg); - } - if suggestions.len() != 1 { - // We don't need this label if there's an inline suggestion, show otherwise. - for (span, assoc_items) in &associated_types { - let mut names: FxHashMap<_, usize> = FxHashMap::default(); - for item in assoc_items { - types_count += 1; - *names.entry(item.ident.name).or_insert(0) += 1; - } - let mut label = vec![]; - for item in assoc_items { - let postfix = if names[&item.ident.name] > 1 { - let trait_def_id = item.container.id(); - format!(" (from trait `{}`)", tcx.def_path_str(trait_def_id)) - } else { - String::new() - }; - label.push(format!("`{}`{}", item.ident, postfix)); - } - if !label.is_empty() { - err.span_label( - *span, - format!( - "associated type{} {} must be specified", - pluralize!(label.len()), - label.join(", "), - ), - ); - } - } - } - if !suggestions.is_empty() { - err.multipart_suggestion( - &format!("specify the associated type{}", pluralize!(types_count)), - suggestions, - Applicability::HasPlaceholders, - ); - if !where_constraints.is_empty() { - err.span_help(where_constraints, where_msg); - } - } - err.emit(); - } - - fn report_ambiguous_associated_type( - &self, - span: Span, - type_str: &str, - trait_str: &str, - name: Symbol, - ) { - let mut err = struct_span_err!(self.tcx().sess, span, E0223, "ambiguous associated type"); - if let (Some(_), Ok(snippet)) = ( - self.tcx().sess.confused_type_with_std_module.borrow().get(&span), - self.tcx().sess.source_map().span_to_snippet(span), - ) { - err.span_suggestion( - span, - "you are looking for the module in `std`, not the primitive type", - format!("std::{}", snippet), - Applicability::MachineApplicable, - ); - } else { - err.span_suggestion( - span, - "use fully-qualified syntax", - format!("<{} as {}>::{}", type_str, trait_str, name), - Applicability::HasPlaceholders, - ); - } - err.emit(); - } - - // Search for a bound on a type parameter which includes the associated item - // given by `assoc_name`. `ty_param_def_id` is the `DefId` of the type parameter - // This function will fail if there are no suitable bounds or there is - // any ambiguity. - fn find_bound_for_assoc_item( - &self, - ty_param_def_id: LocalDefId, - assoc_name: Ident, - span: Span, - ) -> Result, ErrorReported> { - let tcx = self.tcx(); - - debug!( - "find_bound_for_assoc_item(ty_param_def_id={:?}, assoc_name={:?}, span={:?})", - ty_param_def_id, assoc_name, span, - ); - - let predicates = - &self.get_type_parameter_bounds(span, ty_param_def_id.to_def_id()).predicates; - - debug!("find_bound_for_assoc_item: predicates={:#?}", predicates); - - let param_hir_id = tcx.hir().local_def_id_to_hir_id(ty_param_def_id); - let param_name = tcx.hir().ty_param_name(param_hir_id); - self.one_bound_for_assoc_type( - || { - traits::transitive_bounds( - tcx, - predicates.iter().filter_map(|(p, _)| p.to_opt_poly_trait_ref()), - ) - }, - || param_name.to_string(), - assoc_name, - span, - || None, - ) - } - - // Checks that `bounds` contains exactly one element and reports appropriate - // errors otherwise. - fn one_bound_for_assoc_type( - &self, - all_candidates: impl Fn() -> I, - ty_param_name: impl Fn() -> String, - assoc_name: Ident, - span: Span, - is_equality: impl Fn() -> Option, - ) -> Result, ErrorReported> - where - I: Iterator>, - { - let mut matching_candidates = all_candidates() - .filter(|r| self.trait_defines_associated_type_named(r.def_id(), assoc_name)); - - let bound = match matching_candidates.next() { - Some(bound) => bound, - None => { - self.complain_about_assoc_type_not_found( - all_candidates, - &ty_param_name(), - assoc_name, - span, - ); - return Err(ErrorReported); - } - }; - - debug!("one_bound_for_assoc_type: bound = {:?}", bound); - - if let Some(bound2) = matching_candidates.next() { - debug!("one_bound_for_assoc_type: bound2 = {:?}", bound2); - - let is_equality = is_equality(); - let bounds = iter::once(bound).chain(iter::once(bound2)).chain(matching_candidates); - let mut err = if is_equality.is_some() { - // More specific Error Index entry. - struct_span_err!( - self.tcx().sess, - span, - E0222, - "ambiguous associated type `{}` in bounds of `{}`", - assoc_name, - ty_param_name() - ) - } else { - struct_span_err!( - self.tcx().sess, - span, - E0221, - "ambiguous associated type `{}` in bounds of `{}`", - assoc_name, - ty_param_name() - ) - }; - err.span_label(span, format!("ambiguous associated type `{}`", assoc_name)); - - let mut where_bounds = vec![]; - for bound in bounds { - let bound_id = bound.def_id(); - let bound_span = self - .tcx() - .associated_items(bound_id) - .find_by_name_and_kind(self.tcx(), assoc_name, ty::AssocKind::Type, bound_id) - .and_then(|item| self.tcx().hir().span_if_local(item.def_id)); - - if let Some(bound_span) = bound_span { - err.span_label( - bound_span, - format!( - "ambiguous `{}` from `{}`", - assoc_name, - bound.print_only_trait_path(), - ), - ); - if let Some(constraint) = &is_equality { - where_bounds.push(format!( - " T: {trait}::{assoc} = {constraint}", - trait=bound.print_only_trait_path(), - assoc=assoc_name, - constraint=constraint, - )); - } else { - err.span_suggestion( - span, - "use fully qualified syntax to disambiguate", - format!( - "<{} as {}>::{}", - ty_param_name(), - bound.print_only_trait_path(), - assoc_name, - ), - Applicability::MaybeIncorrect, - ); - } - } else { - err.note(&format!( - "associated type `{}` could derive from `{}`", - ty_param_name(), - bound.print_only_trait_path(), - )); - } - } - if !where_bounds.is_empty() { - err.help(&format!( - "consider introducing a new type parameter `T` and adding `where` constraints:\ - \n where\n T: {},\n{}", - ty_param_name(), - where_bounds.join(",\n"), - )); - } - err.emit(); - if !where_bounds.is_empty() { - return Err(ErrorReported); - } - } - Ok(bound) - } - - fn complain_about_assoc_type_not_found( - &self, - all_candidates: impl Fn() -> I, - ty_param_name: &str, - assoc_name: Ident, - span: Span, - ) where - I: Iterator>, - { - // The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a - // valid span, so we point at the whole path segment instead. - let span = if assoc_name.span != DUMMY_SP { assoc_name.span } else { span }; - let mut err = struct_span_err!( - self.tcx().sess, - span, - E0220, - "associated type `{}` not found for `{}`", - assoc_name, - ty_param_name - ); - - let all_candidate_names: Vec<_> = all_candidates() - .map(|r| self.tcx().associated_items(r.def_id()).in_definition_order()) - .flatten() - .filter_map( - |item| if item.kind == ty::AssocKind::Type { Some(item.ident.name) } else { None }, - ) - .collect(); - - if let (Some(suggested_name), true) = ( - find_best_match_for_name(all_candidate_names.iter(), assoc_name.name, None), - assoc_name.span != DUMMY_SP, - ) { - err.span_suggestion( - assoc_name.span, - "there is an associated type with a similar name", - suggested_name.to_string(), - Applicability::MaybeIncorrect, - ); - } else { - err.span_label(span, format!("associated type `{}` not found", assoc_name)); - } - - err.emit(); - } - - // Create a type from a path to an associated type. - // For a path `A::B::C::D`, `qself_ty` and `qself_def` are the type and def for `A::B::C` - // and item_segment is the path segment for `D`. We return a type and a def for - // the whole path. - // Will fail except for `T::A` and `Self::A`; i.e., if `qself_ty`/`qself_def` are not a type - // parameter or `Self`. - pub fn associated_path_to_ty( - &self, - hir_ref_id: hir::HirId, - span: Span, - qself_ty: Ty<'tcx>, - qself_res: Res, - assoc_segment: &hir::PathSegment<'_>, - permit_variants: bool, - ) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorReported> { - let tcx = self.tcx(); - let assoc_ident = assoc_segment.ident; - - debug!("associated_path_to_ty: {:?}::{}", qself_ty, assoc_ident); - - // Check if we have an enum variant. - let mut variant_resolution = None; - if let ty::Adt(adt_def, _) = qself_ty.kind { - if adt_def.is_enum() { - let variant_def = adt_def - .variants - .iter() - .find(|vd| tcx.hygienic_eq(assoc_ident, vd.ident, adt_def.did)); - if let Some(variant_def) = variant_def { - if permit_variants { - tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span); - self.prohibit_generics(slice::from_ref(assoc_segment)); - return Ok((qself_ty, DefKind::Variant, variant_def.def_id)); - } else { - variant_resolution = Some(variant_def.def_id); - } - } - } - } - - // Find the type of the associated item, and the trait where the associated - // item is declared. - let bound = match (&qself_ty.kind, qself_res) { - (_, Res::SelfTy(Some(_), Some(impl_def_id))) => { - // `Self` in an impl of a trait -- we have a concrete self type and a - // trait reference. - let trait_ref = match tcx.impl_trait_ref(impl_def_id) { - Some(trait_ref) => trait_ref, - None => { - // A cycle error occurred, most likely. - return Err(ErrorReported); - } - }; - - self.one_bound_for_assoc_type( - || traits::supertraits(tcx, ty::Binder::bind(trait_ref)), - || "Self".to_string(), - assoc_ident, - span, - || None, - )? - } - ( - &ty::Param(_), - Res::SelfTy(Some(param_did), None) | Res::Def(DefKind::TyParam, param_did), - ) => self.find_bound_for_assoc_item(param_did.expect_local(), assoc_ident, span)?, - _ => { - if variant_resolution.is_some() { - // Variant in type position - let msg = format!("expected type, found variant `{}`", assoc_ident); - tcx.sess.span_err(span, &msg); - } else if qself_ty.is_enum() { - let mut err = struct_span_err!( - tcx.sess, - assoc_ident.span, - E0599, - "no variant named `{}` found for enum `{}`", - assoc_ident, - qself_ty, - ); - - let adt_def = qself_ty.ty_adt_def().expect("enum is not an ADT"); - if let Some(suggested_name) = find_best_match_for_name( - adt_def.variants.iter().map(|variant| &variant.ident.name), - assoc_ident.name, - None, - ) { - err.span_suggestion( - assoc_ident.span, - "there is a variant with a similar name", - suggested_name.to_string(), - Applicability::MaybeIncorrect, - ); - } else { - err.span_label( - assoc_ident.span, - format!("variant not found in `{}`", qself_ty), - ); - } - - if let Some(sp) = tcx.hir().span_if_local(adt_def.did) { - let sp = tcx.sess.source_map().guess_head_span(sp); - err.span_label(sp, format!("variant `{}` not found here", assoc_ident)); - } - - err.emit(); - } else if !qself_ty.references_error() { - // Don't print `TyErr` to the user. - self.report_ambiguous_associated_type( - span, - &qself_ty.to_string(), - "Trait", - assoc_ident.name, - ); - } - return Err(ErrorReported); - } - }; - - let trait_did = bound.def_id(); - let (assoc_ident, def_scope) = - tcx.adjust_ident_and_get_scope(assoc_ident, trait_did, hir_ref_id); - - // We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead - // of calling `filter_by_name_and_kind`. - let item = tcx - .associated_items(trait_did) - .in_definition_order() - .find(|i| { - i.kind.namespace() == Namespace::TypeNS - && i.ident.normalize_to_macros_2_0() == assoc_ident - }) - .expect("missing associated type"); - - let ty = self.projected_ty_from_poly_trait_ref(span, item.def_id, assoc_segment, bound); - let ty = self.normalize_ty(span, ty); - - let kind = DefKind::AssocTy; - if !item.vis.is_accessible_from(def_scope, tcx) { - let kind = kind.descr(item.def_id); - let msg = format!("{} `{}` is private", kind, assoc_ident); - tcx.sess - .struct_span_err(span, &msg) - .span_label(span, &format!("private {}", kind)) - .emit(); - } - tcx.check_stability(item.def_id, Some(hir_ref_id), span); - - if let Some(variant_def_id) = variant_resolution { - tcx.struct_span_lint_hir(AMBIGUOUS_ASSOCIATED_ITEMS, hir_ref_id, span, |lint| { - let mut err = lint.build("ambiguous associated item"); - let mut could_refer_to = |kind: DefKind, def_id, also| { - let note_msg = format!( - "`{}` could{} refer to the {} defined here", - assoc_ident, - also, - kind.descr(def_id) - ); - err.span_note(tcx.def_span(def_id), ¬e_msg); - }; - - could_refer_to(DefKind::Variant, variant_def_id, ""); - could_refer_to(kind, item.def_id, " also"); - - err.span_suggestion( - span, - "use fully-qualified syntax", - format!("<{} as {}>::{}", qself_ty, tcx.item_name(trait_did), assoc_ident), - Applicability::MachineApplicable, - ); - - err.emit(); - }); - } - Ok((ty, kind, item.def_id)) - } - - fn qpath_to_ty( - &self, - span: Span, - opt_self_ty: Option>, - item_def_id: DefId, - trait_segment: &hir::PathSegment<'_>, - item_segment: &hir::PathSegment<'_>, - ) -> Ty<'tcx> { - let tcx = self.tcx(); - - let trait_def_id = tcx.parent(item_def_id).unwrap(); - - debug!("qpath_to_ty: trait_def_id={:?}", trait_def_id); - - let self_ty = if let Some(ty) = opt_self_ty { - ty - } else { - let path_str = tcx.def_path_str(trait_def_id); - - let def_id = self.item_def_id(); - - debug!("qpath_to_ty: self.item_def_id()={:?}", def_id); - - let parent_def_id = def_id - .and_then(|def_id| { - def_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id)) - }) - .map(|hir_id| tcx.hir().get_parent_did(hir_id).to_def_id()); - - debug!("qpath_to_ty: parent_def_id={:?}", parent_def_id); - - // If the trait in segment is the same as the trait defining the item, - // use the `` syntax in the error. - let is_part_of_self_trait_constraints = def_id == Some(trait_def_id); - let is_part_of_fn_in_self_trait = parent_def_id == Some(trait_def_id); - - let type_name = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait { - "Self" - } else { - "Type" - }; - - self.report_ambiguous_associated_type( - span, - type_name, - &path_str, - item_segment.ident.name, - ); - return tcx.ty_error(); - }; - - debug!("qpath_to_ty: self_type={:?}", self_ty); - - let trait_ref = self.ast_path_to_mono_trait_ref(span, trait_def_id, self_ty, trait_segment); - - let item_substs = self.create_substs_for_associated_item( - tcx, - span, - item_def_id, - item_segment, - trait_ref.substs, - ); - - debug!("qpath_to_ty: trait_ref={:?}", trait_ref); - - self.normalize_ty(span, tcx.mk_projection(item_def_id, item_substs)) - } - - pub fn prohibit_generics<'a, T: IntoIterator>>( - &self, - segments: T, - ) -> bool { - let mut has_err = false; - for segment in segments { - let (mut err_for_lt, mut err_for_ty, mut err_for_ct) = (false, false, false); - for arg in segment.generic_args().args { - let (span, kind) = match arg { - hir::GenericArg::Lifetime(lt) => { - if err_for_lt { - continue; - } - err_for_lt = true; - has_err = true; - (lt.span, "lifetime") - } - hir::GenericArg::Type(ty) => { - if err_for_ty { - continue; - } - err_for_ty = true; - has_err = true; - (ty.span, "type") - } - hir::GenericArg::Const(ct) => { - if err_for_ct { - continue; - } - err_for_ct = true; - has_err = true; - (ct.span, "const") - } - }; - let mut err = struct_span_err!( - self.tcx().sess, - span, - E0109, - "{} arguments are not allowed for this type", - kind, - ); - err.span_label(span, format!("{} argument not allowed", kind)); - err.emit(); - if err_for_lt && err_for_ty && err_for_ct { - break; - } - } - - // Only emit the first error to avoid overloading the user with error messages. - if let [binding, ..] = segment.generic_args().bindings { - has_err = true; - Self::prohibit_assoc_ty_binding(self.tcx(), binding.span); - } - } - has_err - } - - pub fn prohibit_assoc_ty_binding(tcx: TyCtxt<'_>, span: Span) { - let mut err = struct_span_err!( - tcx.sess, - span, - E0229, - "associated type bindings are not allowed here" - ); - err.span_label(span, "associated type not allowed here").emit(); - } - - /// Prohibits explicit lifetime arguments if late-bound lifetime parameters - /// are present. This is used both for datatypes and function calls. - fn prohibit_explicit_late_bound_lifetimes( - tcx: TyCtxt<'_>, - def: &ty::Generics, - args: &hir::GenericArgs<'_>, - position: GenericArgPosition, - ) -> ExplicitLateBound { - let param_counts = def.own_counts(); - let arg_counts = args.own_counts(); - let infer_lifetimes = position != GenericArgPosition::Type && arg_counts.lifetimes == 0; - - if infer_lifetimes { - ExplicitLateBound::No - } else if let Some(span_late) = def.has_late_bound_regions { - let msg = "cannot specify lifetime arguments explicitly \ - if late bound lifetime parameters are present"; - let note = "the late bound lifetime parameter is introduced here"; - let span = args.args[0].span(); - if position == GenericArgPosition::Value - && arg_counts.lifetimes != param_counts.lifetimes - { - let mut err = tcx.sess.struct_span_err(span, msg); - err.span_note(span_late, note); - err.emit(); - } else { - let mut multispan = MultiSpan::from_span(span); - multispan.push_span_label(span_late, note.to_string()); - tcx.struct_span_lint_hir( - LATE_BOUND_LIFETIME_ARGUMENTS, - args.args[0].id(), - multispan, - |lint| lint.build(msg).emit(), - ); - } - ExplicitLateBound::Yes - } else { - ExplicitLateBound::No - } - } - - // FIXME(eddyb, varkor) handle type paths here too, not just value ones. - pub fn def_ids_for_value_path_segments( - &self, - segments: &[hir::PathSegment<'_>], - self_ty: Option>, - kind: DefKind, - def_id: DefId, - ) -> Vec { - // We need to extract the type parameters supplied by the user in - // the path `path`. Due to the current setup, this is a bit of a - // tricky-process; the problem is that resolve only tells us the - // end-point of the path resolution, and not the intermediate steps. - // Luckily, we can (at least for now) deduce the intermediate steps - // just from the end-point. - // - // There are basically five cases to consider: - // - // 1. Reference to a constructor of a struct: - // - // struct Foo(...) - // - // In this case, the parameters are declared in the type space. - // - // 2. Reference to a constructor of an enum variant: - // - // enum E { Foo(...) } - // - // In this case, the parameters are defined in the type space, - // but may be specified either on the type or the variant. - // - // 3. Reference to a fn item or a free constant: - // - // fn foo() { } - // - // In this case, the path will again always have the form - // `a::b::foo::` where only the final segment should have - // type parameters. However, in this case, those parameters are - // declared on a value, and hence are in the `FnSpace`. - // - // 4. Reference to a method or an associated constant: - // - // impl SomeStruct { - // fn foo(...) - // } - // - // Here we can have a path like - // `a::b::SomeStruct::::foo::`, in which case parameters - // may appear in two places. The penultimate segment, - // `SomeStruct::`, contains parameters in TypeSpace, and the - // final segment, `foo::` contains parameters in fn space. - // - // The first step then is to categorize the segments appropriately. - - let tcx = self.tcx(); - - assert!(!segments.is_empty()); - let last = segments.len() - 1; - - let mut path_segs = vec![]; - - match kind { - // Case 1. Reference to a struct constructor. - DefKind::Ctor(CtorOf::Struct, ..) => { - // Everything but the final segment should have no - // parameters at all. - let generics = tcx.generics_of(def_id); - // Variant and struct constructors use the - // generics of their parent type definition. - let generics_def_id = generics.parent.unwrap_or(def_id); - path_segs.push(PathSeg(generics_def_id, last)); - } - - // Case 2. Reference to a variant constructor. - DefKind::Ctor(CtorOf::Variant, ..) | DefKind::Variant => { - let adt_def = self_ty.map(|t| t.ty_adt_def().unwrap()); - let (generics_def_id, index) = if let Some(adt_def) = adt_def { - debug_assert!(adt_def.is_enum()); - (adt_def.did, last) - } else if last >= 1 && segments[last - 1].args.is_some() { - // Everything but the penultimate segment should have no - // parameters at all. - let mut def_id = def_id; - - // `DefKind::Ctor` -> `DefKind::Variant` - if let DefKind::Ctor(..) = kind { - def_id = tcx.parent(def_id).unwrap() - } - - // `DefKind::Variant` -> `DefKind::Enum` - let enum_def_id = tcx.parent(def_id).unwrap(); - (enum_def_id, last - 1) - } else { - // FIXME: lint here recommending `Enum::<...>::Variant` form - // instead of `Enum::Variant::<...>` form. - - // Everything but the final segment should have no - // parameters at all. - let generics = tcx.generics_of(def_id); - // Variant and struct constructors use the - // generics of their parent type definition. - (generics.parent.unwrap_or(def_id), last) - }; - path_segs.push(PathSeg(generics_def_id, index)); - } - - // Case 3. Reference to a top-level value. - DefKind::Fn | DefKind::Const | DefKind::ConstParam | DefKind::Static => { - path_segs.push(PathSeg(def_id, last)); - } - - // Case 4. Reference to a method or associated const. - DefKind::AssocFn | DefKind::AssocConst => { - if segments.len() >= 2 { - let generics = tcx.generics_of(def_id); - path_segs.push(PathSeg(generics.parent.unwrap(), last - 1)); - } - path_segs.push(PathSeg(def_id, last)); - } - - kind => bug!("unexpected definition kind {:?} for {:?}", kind, def_id), - } - - debug!("path_segs = {:?}", path_segs); - - path_segs - } - - // Check a type `Path` and convert it to a `Ty`. - pub fn res_to_ty( - &self, - opt_self_ty: Option>, - path: &hir::Path<'_>, - permit_variants: bool, - ) -> Ty<'tcx> { - let tcx = self.tcx(); - - debug!( - "res_to_ty(res={:?}, opt_self_ty={:?}, path_segments={:?})", - path.res, opt_self_ty, path.segments - ); - - let span = path.span; - match path.res { - Res::Def(DefKind::OpaqueTy, did) => { - // Check for desugared `impl Trait`. - assert!(ty::is_impl_trait_defn(tcx, did).is_none()); - let item_segment = path.segments.split_last().unwrap(); - self.prohibit_generics(item_segment.1); - let substs = self.ast_path_substs_for_ty(span, did, item_segment.0); - self.normalize_ty(span, tcx.mk_opaque(did, substs)) - } - Res::Def( - DefKind::Enum - | DefKind::TyAlias - | DefKind::Struct - | DefKind::Union - | DefKind::ForeignTy, - did, - ) => { - assert_eq!(opt_self_ty, None); - self.prohibit_generics(path.segments.split_last().unwrap().1); - self.ast_path_to_ty(span, did, path.segments.last().unwrap()) - } - Res::Def(kind @ DefKind::Variant, def_id) if permit_variants => { - // Convert "variant type" as if it were a real type. - // The resulting `Ty` is type of the variant's enum for now. - assert_eq!(opt_self_ty, None); - - let path_segs = - self.def_ids_for_value_path_segments(&path.segments, None, kind, def_id); - let generic_segs: FxHashSet<_> = - path_segs.iter().map(|PathSeg(_, index)| index).collect(); - self.prohibit_generics(path.segments.iter().enumerate().filter_map( - |(index, seg)| { - if !generic_segs.contains(&index) { Some(seg) } else { None } - }, - )); - - let PathSeg(def_id, index) = path_segs.last().unwrap(); - self.ast_path_to_ty(span, *def_id, &path.segments[*index]) - } - Res::Def(DefKind::TyParam, def_id) => { - assert_eq!(opt_self_ty, None); - self.prohibit_generics(path.segments); - - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); - let item_id = tcx.hir().get_parent_node(hir_id); - let item_def_id = tcx.hir().local_def_id(item_id); - let generics = tcx.generics_of(item_def_id); - let index = generics.param_def_id_to_index[&def_id]; - tcx.mk_ty_param(index, tcx.hir().name(hir_id)) - } - Res::SelfTy(Some(_), None) => { - // `Self` in trait or type alias. - assert_eq!(opt_self_ty, None); - self.prohibit_generics(path.segments); - tcx.types.self_param - } - Res::SelfTy(_, Some(def_id)) => { - // `Self` in impl (we know the concrete type). - assert_eq!(opt_self_ty, None); - self.prohibit_generics(path.segments); - // Try to evaluate any array length constants. - self.normalize_ty(span, tcx.at(span).type_of(def_id)) - } - Res::Def(DefKind::AssocTy, def_id) => { - debug_assert!(path.segments.len() >= 2); - self.prohibit_generics(&path.segments[..path.segments.len() - 2]); - self.qpath_to_ty( - span, - opt_self_ty, - def_id, - &path.segments[path.segments.len() - 2], - path.segments.last().unwrap(), - ) - } - Res::PrimTy(prim_ty) => { - assert_eq!(opt_self_ty, None); - self.prohibit_generics(path.segments); - match prim_ty { - hir::PrimTy::Bool => tcx.types.bool, - hir::PrimTy::Char => tcx.types.char, - hir::PrimTy::Int(it) => tcx.mk_mach_int(it), - hir::PrimTy::Uint(uit) => tcx.mk_mach_uint(uit), - hir::PrimTy::Float(ft) => tcx.mk_mach_float(ft), - hir::PrimTy::Str => tcx.types.str_, - } - } - Res::Err => { - self.set_tainted_by_errors(); - self.tcx().ty_error() - } - _ => span_bug!(span, "unexpected resolution: {:?}", path.res), - } - } - - /// Parses the programmer's textual representation of a type into our - /// internal notion of a type. - pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> { - self.ast_ty_to_ty_inner(ast_ty, false) - } - - /// Turns a `hir::Ty` into a `Ty`. For diagnostics' purposes we keep track of whether trait - /// objects are borrowed like `&dyn Trait` to avoid emitting redundant errors. - fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool) -> Ty<'tcx> { - debug!("ast_ty_to_ty(id={:?}, ast_ty={:?} ty_ty={:?})", ast_ty.hir_id, ast_ty, ast_ty.kind); - - let tcx = self.tcx(); - - let result_ty = match ast_ty.kind { - hir::TyKind::Slice(ref ty) => tcx.mk_slice(self.ast_ty_to_ty(&ty)), - hir::TyKind::Ptr(ref mt) => { - tcx.mk_ptr(ty::TypeAndMut { ty: self.ast_ty_to_ty(&mt.ty), mutbl: mt.mutbl }) - } - hir::TyKind::Rptr(ref region, ref mt) => { - let r = self.ast_region_to_region(region, None); - debug!("ast_ty_to_ty: r={:?}", r); - let t = self.ast_ty_to_ty_inner(&mt.ty, true); - tcx.mk_ref(r, ty::TypeAndMut { ty: t, mutbl: mt.mutbl }) - } - hir::TyKind::Never => tcx.types.never, - hir::TyKind::Tup(ref fields) => { - tcx.mk_tup(fields.iter().map(|t| self.ast_ty_to_ty(&t))) - } - hir::TyKind::BareFn(ref bf) => { - require_c_abi_if_c_variadic(tcx, &bf.decl, bf.abi, ast_ty.span); - tcx.mk_fn_ptr(self.ty_of_fn( - bf.unsafety, - bf.abi, - &bf.decl, - &hir::Generics::empty(), - None, - )) - } - hir::TyKind::TraitObject(ref bounds, ref lifetime) => { - self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed) - } - hir::TyKind::Path(hir::QPath::Resolved(ref maybe_qself, ref path)) => { - debug!("ast_ty_to_ty: maybe_qself={:?} path={:?}", maybe_qself, path); - let opt_self_ty = maybe_qself.as_ref().map(|qself| self.ast_ty_to_ty(qself)); - self.res_to_ty(opt_self_ty, path, false) - } - hir::TyKind::OpaqueDef(item_id, ref lifetimes) => { - let opaque_ty = tcx.hir().expect_item(item_id.id); - let def_id = tcx.hir().local_def_id(item_id.id).to_def_id(); - - match opaque_ty.kind { - hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn, .. }) => { - self.impl_trait_ty_to_ty(def_id, lifetimes, impl_trait_fn.is_some()) - } - ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i), - } - } - hir::TyKind::Path(hir::QPath::TypeRelative(ref qself, ref segment)) => { - debug!("ast_ty_to_ty: qself={:?} segment={:?}", qself, segment); - let ty = self.ast_ty_to_ty(qself); - - let res = if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = qself.kind { - path.res - } else { - Res::Err - }; - self.associated_path_to_ty(ast_ty.hir_id, ast_ty.span, ty, res, segment, false) - .map(|(ty, _, _)| ty) - .unwrap_or_else(|_| tcx.ty_error()) - } - hir::TyKind::Path(hir::QPath::LangItem(lang_item, span)) => { - let def_id = tcx.require_lang_item(lang_item, Some(span)); - let (substs, _, _) = self.create_substs_for_ast_path( - span, - def_id, - &[], - &GenericArgs::none(), - true, - None, - ); - self.normalize_ty(span, tcx.at(span).type_of(def_id).subst(tcx, substs)) - } - hir::TyKind::Array(ref ty, ref length) => { - let length_def_id = tcx.hir().local_def_id(length.hir_id); - let length = ty::Const::from_anon_const(tcx, length_def_id); - let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(&ty), length)); - self.normalize_ty(ast_ty.span, array_ty) - } - hir::TyKind::Typeof(ref _e) => { - struct_span_err!( - tcx.sess, - ast_ty.span, - E0516, - "`typeof` is a reserved keyword but unimplemented" - ) - .span_label(ast_ty.span, "reserved keyword") - .emit(); - - tcx.ty_error() - } - hir::TyKind::Infer => { - // Infer also appears as the type of arguments or return - // values in a ExprKind::Closure, or as - // the type of local variables. Both of these cases are - // handled specially and will not descend into this routine. - self.ty_infer(None, ast_ty.span) - } - hir::TyKind::Err => tcx.ty_error(), - }; - - debug!("ast_ty_to_ty: result_ty={:?}", result_ty); - - self.record_ty(ast_ty.hir_id, result_ty, ast_ty.span); - result_ty - } - - pub fn impl_trait_ty_to_ty( - &self, - def_id: DefId, - lifetimes: &[hir::GenericArg<'_>], - replace_parent_lifetimes: bool, - ) -> Ty<'tcx> { - debug!("impl_trait_ty_to_ty(def_id={:?}, lifetimes={:?})", def_id, lifetimes); - let tcx = self.tcx(); - - let generics = tcx.generics_of(def_id); - - debug!("impl_trait_ty_to_ty: generics={:?}", generics); - let substs = InternalSubsts::for_item(tcx, def_id, |param, _| { - if let Some(i) = (param.index as usize).checked_sub(generics.parent_count) { - // Our own parameters are the resolved lifetimes. - match param.kind { - GenericParamDefKind::Lifetime => { - if let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] { - self.ast_region_to_region(lifetime, None).into() - } else { - bug!() - } - } - _ => bug!(), - } - } else { - match param.kind { - // For RPIT (return position impl trait), only lifetimes - // mentioned in the impl Trait predicate are captured by - // the opaque type, so the lifetime parameters from the - // parent item need to be replaced with `'static`. - // - // For `impl Trait` in the types of statics, constants, - // locals and type aliases. These capture all parent - // lifetimes, so they can use their identity subst. - GenericParamDefKind::Lifetime if replace_parent_lifetimes => { - tcx.lifetimes.re_static.into() - } - _ => tcx.mk_param_from_def(param), - } - } - }); - debug!("impl_trait_ty_to_ty: substs={:?}", substs); - - let ty = tcx.mk_opaque(def_id, substs); - debug!("impl_trait_ty_to_ty: {}", ty); - ty - } - - pub fn ty_of_arg(&self, ty: &hir::Ty<'_>, expected_ty: Option>) -> Ty<'tcx> { - match ty.kind { - hir::TyKind::Infer if expected_ty.is_some() => { - self.record_ty(ty.hir_id, expected_ty.unwrap(), ty.span); - expected_ty.unwrap() - } - _ => self.ast_ty_to_ty(ty), - } - } - - pub fn ty_of_fn( - &self, - unsafety: hir::Unsafety, - abi: abi::Abi, - decl: &hir::FnDecl<'_>, - generics: &hir::Generics<'_>, - ident_span: Option, - ) -> ty::PolyFnSig<'tcx> { - debug!("ty_of_fn"); - - let tcx = self.tcx(); - - // We proactively collect all the inferred type params to emit a single error per fn def. - let mut visitor = PlaceholderHirTyCollector::default(); - for ty in decl.inputs { - visitor.visit_ty(ty); - } - walk_generics(&mut visitor, generics); - - let input_tys = decl.inputs.iter().map(|a| self.ty_of_arg(a, None)); - let output_ty = match decl.output { - hir::FnRetTy::Return(ref output) => { - visitor.visit_ty(output); - self.ast_ty_to_ty(output) - } - hir::FnRetTy::DefaultReturn(..) => tcx.mk_unit(), - }; - - debug!("ty_of_fn: output_ty={:?}", output_ty); - - let bare_fn_ty = - ty::Binder::bind(tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, unsafety, abi)); - - if !self.allow_ty_infer() { - // We always collect the spans for placeholder types when evaluating `fn`s, but we - // only want to emit an error complaining about them if infer types (`_`) are not - // allowed. `allow_ty_infer` gates this behavior. We check for the presence of - // `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`. - crate::collect::placeholder_type_error( - tcx, - ident_span.map(|sp| sp.shrink_to_hi()), - &generics.params[..], - visitor.0, - true, - ); - } - - // Find any late-bound regions declared in return type that do - // not appear in the arguments. These are not well-formed. - // - // Example: - // for<'a> fn() -> &'a str <-- 'a is bad - // for<'a> fn(&'a String) -> &'a str <-- 'a is ok - let inputs = bare_fn_ty.inputs(); - let late_bound_in_args = - tcx.collect_constrained_late_bound_regions(&inputs.map_bound(|i| i.to_owned())); - let output = bare_fn_ty.output(); - let late_bound_in_ret = tcx.collect_referenced_late_bound_regions(&output); - - self.validate_late_bound_regions(late_bound_in_args, late_bound_in_ret, |br_name| { - struct_span_err!( - tcx.sess, - decl.output.span(), - E0581, - "return type references {}, which is not constrained by the fn input types", - br_name - ) - }); - - bare_fn_ty - } - - fn validate_late_bound_regions( - &self, - constrained_regions: FxHashSet, - referenced_regions: FxHashSet, - generate_err: impl Fn(&str) -> rustc_errors::DiagnosticBuilder<'tcx>, - ) { - for br in referenced_regions.difference(&constrained_regions) { - let br_name = match *br { - ty::BrNamed(_, name) => format!("lifetime `{}`", name), - ty::BrAnon(_) | ty::BrEnv => "an anonymous lifetime".to_string(), - }; - - let mut err = generate_err(&br_name); - - if let ty::BrAnon(_) = *br { - // The only way for an anonymous lifetime to wind up - // in the return type but **also** be unconstrained is - // if it only appears in "associated types" in the - // input. See #47511 and #62200 for examples. In this case, - // though we can easily give a hint that ought to be - // relevant. - err.note( - "lifetimes appearing in an associated type are not considered constrained", - ); - } - - err.emit(); - } - } - - /// Given the bounds on an object, determines what single region bound (if any) we can - /// use to summarize this type. The basic idea is that we will use the bound the user - /// provided, if they provided one, and otherwise search the supertypes of trait bounds - /// for region bounds. It may be that we can derive no bound at all, in which case - /// we return `None`. - fn compute_object_lifetime_bound( - &self, - span: Span, - existential_predicates: ty::Binder<&'tcx ty::List>>, - ) -> Option> // if None, use the default - { - let tcx = self.tcx(); - - debug!("compute_opt_region_bound(existential_predicates={:?})", existential_predicates); - - // No explicit region bound specified. Therefore, examine trait - // bounds and see if we can derive region bounds from those. - let derived_region_bounds = object_region_bounds(tcx, existential_predicates); - - // If there are no derived region bounds, then report back that we - // can find no region bound. The caller will use the default. - if derived_region_bounds.is_empty() { - return None; - } - - // If any of the derived region bounds are 'static, that is always - // the best choice. - if derived_region_bounds.iter().any(|&r| ty::ReStatic == *r) { - return Some(tcx.lifetimes.re_static); - } - - // Determine whether there is exactly one unique region in the set - // of derived region bounds. If so, use that. Otherwise, report an - // error. - let r = derived_region_bounds[0]; - if derived_region_bounds[1..].iter().any(|r1| r != *r1) { - struct_span_err!( - tcx.sess, - span, - E0227, - "ambiguous lifetime bound, explicit lifetime bound required" - ) - .emit(); - } - Some(r) - } -} - -/// Collects together a list of bounds that are applied to some type, -/// after they've been converted into `ty` form (from the HIR -/// representations). These lists of bounds occur in many places in -/// Rust's syntax: -/// -/// ```text -/// trait Foo: Bar + Baz { } -/// ^^^^^^^^^ supertrait list bounding the `Self` type parameter -/// -/// fn foo() { } -/// ^^^^^^^^^ bounding the type parameter `T` -/// -/// impl dyn Bar + Baz -/// ^^^^^^^^^ bounding the forgotten dynamic type -/// ``` -/// -/// Our representation is a bit mixed here -- in some cases, we -/// include the self type (e.g., `trait_bounds`) but in others we do -#[derive(Default, PartialEq, Eq, Clone, Debug)] -pub struct Bounds<'tcx> { - /// A list of region bounds on the (implicit) self type. So if you - /// had `T: 'a + 'b` this might would be a list `['a, 'b]` (but - /// the `T` is not explicitly included). - pub region_bounds: Vec<(ty::Region<'tcx>, Span)>, - - /// A list of trait bounds. So if you had `T: Debug` this would be - /// `T: Debug`. Note that the self-type is explicit here. - pub trait_bounds: Vec<(ty::PolyTraitRef<'tcx>, Span, Constness)>, - - /// A list of projection equality bounds. So if you had `T: - /// Iterator` this would include `::Item => u32`. Note that the self-type is explicit - /// here. - pub projection_bounds: Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>, - - /// `Some` if there is *no* `?Sized` predicate. The `span` - /// is the location in the source of the `T` declaration which can - /// be cited as the source of the `T: Sized` requirement. - pub implicitly_sized: Option, -} - -impl<'tcx> Bounds<'tcx> { - /// Converts a bounds list into a flat set of predicates (like - /// where-clauses). Because some of our bounds listings (e.g., - /// regions) don't include the self-type, you must supply the - /// self-type here (the `param_ty` parameter). - pub fn predicates( - &self, - tcx: TyCtxt<'tcx>, - param_ty: Ty<'tcx>, - ) -> Vec<(ty::Predicate<'tcx>, Span)> { - // If it could be sized, and is, add the `Sized` predicate. - let sized_predicate = self.implicitly_sized.and_then(|span| { - tcx.lang_items().sized_trait().map(|sized| { - let trait_ref = ty::Binder::bind(ty::TraitRef { - def_id: sized, - substs: tcx.mk_substs_trait(param_ty, &[]), - }); - (trait_ref.without_const().to_predicate(tcx), span) - }) - }); - - sized_predicate - .into_iter() - .chain( - self.region_bounds - .iter() - .map(|&(region_bound, span)| { - // Account for the binder being introduced below; no need to shift `param_ty` - // because, at present at least, it either only refers to early-bound regions, - // or it's a generic associated type that deliberately has escaping bound vars. - let region_bound = ty::fold::shift_region(tcx, region_bound, 1); - let outlives = ty::OutlivesPredicate(param_ty, region_bound); - (ty::Binder::bind(outlives).to_predicate(tcx), span) - }) - .chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| { - let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx); - (predicate, span) - })) - .chain( - self.projection_bounds - .iter() - .map(|&(projection, span)| (projection.to_predicate(tcx), span)), - ), - ) - .collect() - } -} diff --git a/src/librustc_typeck/astconv/errors.rs b/src/librustc_typeck/astconv/errors.rs new file mode 100644 index 00000000000..685243f54cb --- /dev/null +++ b/src/librustc_typeck/astconv/errors.rs @@ -0,0 +1,388 @@ +use crate::astconv::AstConv; +use rustc_ast::util::lev_distance::find_best_match_for_name; +use rustc_data_structures::fx::FxHashMap; +use rustc_errors::{pluralize, struct_span_err, Applicability}; +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_middle::ty; +use rustc_session::parse::feature_err; +use rustc_span::symbol::{sym, Ident}; +use rustc_span::{Span, DUMMY_SP}; + +use std::collections::BTreeSet; + +impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { + /// On missing type parameters, emit an E0393 error and provide a structured suggestion using + /// the type parameter's name as a placeholder. + pub(crate) fn complain_about_missing_type_params( + &self, + missing_type_params: Vec, + def_id: DefId, + span: Span, + empty_generic_args: bool, + ) { + if missing_type_params.is_empty() { + return; + } + let display = + missing_type_params.iter().map(|n| format!("`{}`", n)).collect::>().join(", "); + let mut err = struct_span_err!( + self.tcx().sess, + span, + E0393, + "the type parameter{} {} must be explicitly specified", + pluralize!(missing_type_params.len()), + display, + ); + err.span_label( + self.tcx().def_span(def_id), + &format!( + "type parameter{} {} must be specified for this", + pluralize!(missing_type_params.len()), + display, + ), + ); + let mut suggested = false; + if let (Ok(snippet), true) = ( + self.tcx().sess.source_map().span_to_snippet(span), + // Don't suggest setting the type params if there are some already: the order is + // tricky to get right and the user will already know what the syntax is. + empty_generic_args, + ) { + if snippet.ends_with('>') { + // The user wrote `Trait<'a, T>` or similar. To provide an accurate suggestion + // we would have to preserve the right order. For now, as clearly the user is + // aware of the syntax, we do nothing. + } else { + // The user wrote `Iterator`, so we don't have a type we can suggest, but at + // least we can clue them to the correct syntax `Iterator`. + err.span_suggestion( + span, + &format!( + "set the type parameter{plural} to the desired type{plural}", + plural = pluralize!(missing_type_params.len()), + ), + format!("{}<{}>", snippet, missing_type_params.join(", ")), + Applicability::HasPlaceholders, + ); + suggested = true; + } + } + if !suggested { + err.span_label( + span, + format!( + "missing reference{} to {}", + pluralize!(missing_type_params.len()), + display, + ), + ); + } + err.note( + "because of the default `Self` reference, type parameters must be \ + specified on object types", + ); + err.emit(); + } + + /// When the code is using the `Fn` traits directly, instead of the `Fn(A) -> B` syntax, emit + /// an error and attempt to build a reasonable structured suggestion. + pub(crate) fn complain_about_internal_fn_trait( + &self, + span: Span, + trait_def_id: DefId, + trait_segment: &'a hir::PathSegment<'a>, + ) { + let trait_def = self.tcx().trait_def(trait_def_id); + + if !self.tcx().features().unboxed_closures + && trait_segment.generic_args().parenthesized != trait_def.paren_sugar + { + let sess = &self.tcx().sess.parse_sess; + // For now, require that parenthetical notation be used only with `Fn()` etc. + let (msg, sugg) = if trait_def.paren_sugar { + ( + "the precise format of `Fn`-family traits' type parameters is subject to \ + change", + Some(format!( + "{}{} -> {}", + trait_segment.ident, + trait_segment + .args + .as_ref() + .and_then(|args| args.args.get(0)) + .and_then(|arg| match arg { + hir::GenericArg::Type(ty) => match ty.kind { + hir::TyKind::Tup(t) => t + .iter() + .map(|e| sess.source_map().span_to_snippet(e.span)) + .collect::, _>>() + .map(|a| a.join(", ")), + _ => sess.source_map().span_to_snippet(ty.span), + } + .map(|s| format!("({})", s)) + .ok(), + _ => None, + }) + .unwrap_or_else(|| "()".to_string()), + trait_segment + .generic_args() + .bindings + .iter() + .find_map(|b| match (b.ident.name == sym::Output, &b.kind) { + (true, hir::TypeBindingKind::Equality { ty }) => { + sess.source_map().span_to_snippet(ty.span).ok() + } + _ => None, + }) + .unwrap_or_else(|| "()".to_string()), + )), + ) + } else { + ("parenthetical notation is only stable when used with `Fn`-family traits", None) + }; + let mut err = feature_err(sess, sym::unboxed_closures, span, msg); + if let Some(sugg) = sugg { + let msg = "use parenthetical notation instead"; + err.span_suggestion(span, msg, sugg, Applicability::MaybeIncorrect); + } + err.emit(); + } + } + + pub(crate) fn complain_about_assoc_type_not_found( + &self, + all_candidates: impl Fn() -> I, + ty_param_name: &str, + assoc_name: Ident, + span: Span, + ) where + I: Iterator>, + { + // The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a + // valid span, so we point at the whole path segment instead. + let span = if assoc_name.span != DUMMY_SP { assoc_name.span } else { span }; + let mut err = struct_span_err!( + self.tcx().sess, + span, + E0220, + "associated type `{}` not found for `{}`", + assoc_name, + ty_param_name + ); + + let all_candidate_names: Vec<_> = all_candidates() + .map(|r| self.tcx().associated_items(r.def_id()).in_definition_order()) + .flatten() + .filter_map( + |item| if item.kind == ty::AssocKind::Type { Some(item.ident.name) } else { None }, + ) + .collect(); + + if let (Some(suggested_name), true) = ( + find_best_match_for_name(all_candidate_names.iter(), assoc_name.name, None), + assoc_name.span != DUMMY_SP, + ) { + err.span_suggestion( + assoc_name.span, + "there is an associated type with a similar name", + suggested_name.to_string(), + Applicability::MaybeIncorrect, + ); + } else { + err.span_label(span, format!("associated type `{}` not found", assoc_name)); + } + + err.emit(); + } + + /// When there are any missing associated types, emit an E0191 error and attempt to supply a + /// reasonable suggestion on how to write it. For the case of multiple associated types in the + /// same trait bound have the same name (as they come from different super-traits), we instead + /// emit a generic note suggesting using a `where` clause to constraint instead. + pub(crate) fn complain_about_missing_associated_types( + &self, + associated_types: FxHashMap>, + potential_assoc_types: Vec, + trait_bounds: &[hir::PolyTraitRef<'_>], + ) { + if associated_types.values().all(|v| v.is_empty()) { + return; + } + let tcx = self.tcx(); + // FIXME: Marked `mut` so that we can replace the spans further below with a more + // appropriate one, but this should be handled earlier in the span assignment. + let mut associated_types: FxHashMap> = associated_types + .into_iter() + .map(|(span, def_ids)| { + (span, def_ids.into_iter().map(|did| tcx.associated_item(did)).collect()) + }) + .collect(); + let mut names = vec![]; + + // Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and + // `issue-22560.rs`. + let mut trait_bound_spans: Vec = vec![]; + for (span, items) in &associated_types { + if !items.is_empty() { + trait_bound_spans.push(*span); + } + for assoc_item in items { + let trait_def_id = assoc_item.container.id(); + names.push(format!( + "`{}` (from trait `{}`)", + assoc_item.ident, + tcx.def_path_str(trait_def_id), + )); + } + } + if let ([], [bound]) = (&potential_assoc_types[..], &trait_bounds) { + match &bound.trait_ref.path.segments[..] { + // FIXME: `trait_ref.path.span` can point to a full path with multiple + // segments, even though `trait_ref.path.segments` is of length `1`. Work + // around that bug here, even though it should be fixed elsewhere. + // This would otherwise cause an invalid suggestion. For an example, look at + // `src/test/ui/issues/issue-28344.rs` where instead of the following: + // + // error[E0191]: the value of the associated type `Output` + // (from trait `std::ops::BitXor`) must be specified + // --> $DIR/issue-28344.rs:4:17 + // | + // LL | let x: u8 = BitXor::bitor(0 as u8, 0 as u8); + // | ^^^^^^ help: specify the associated type: + // | `BitXor` + // + // we would output: + // + // error[E0191]: the value of the associated type `Output` + // (from trait `std::ops::BitXor`) must be specified + // --> $DIR/issue-28344.rs:4:17 + // | + // LL | let x: u8 = BitXor::bitor(0 as u8, 0 as u8); + // | ^^^^^^^^^^^^^ help: specify the associated type: + // | `BitXor::bitor` + [segment] if segment.args.is_none() => { + trait_bound_spans = vec![segment.ident.span]; + associated_types = associated_types + .into_iter() + .map(|(_, items)| (segment.ident.span, items)) + .collect(); + } + _ => {} + } + } + names.sort(); + trait_bound_spans.sort(); + let mut err = struct_span_err!( + tcx.sess, + trait_bound_spans, + E0191, + "the value of the associated type{} {} must be specified", + pluralize!(names.len()), + names.join(", "), + ); + let mut suggestions = vec![]; + let mut types_count = 0; + let mut where_constraints = vec![]; + for (span, assoc_items) in &associated_types { + let mut names: FxHashMap<_, usize> = FxHashMap::default(); + for item in assoc_items { + types_count += 1; + *names.entry(item.ident.name).or_insert(0) += 1; + } + let mut dupes = false; + for item in assoc_items { + let prefix = if names[&item.ident.name] > 1 { + let trait_def_id = item.container.id(); + dupes = true; + format!("{}::", tcx.def_path_str(trait_def_id)) + } else { + String::new() + }; + if let Some(sp) = tcx.hir().span_if_local(item.def_id) { + err.span_label(sp, format!("`{}{}` defined here", prefix, item.ident)); + } + } + if potential_assoc_types.len() == assoc_items.len() { + // Only suggest when the amount of missing associated types equals the number of + // extra type arguments present, as that gives us a relatively high confidence + // that the user forgot to give the associtated type's name. The canonical + // example would be trying to use `Iterator` instead of + // `Iterator`. + for (potential, item) in potential_assoc_types.iter().zip(assoc_items.iter()) { + if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*potential) { + suggestions.push((*potential, format!("{} = {}", item.ident, snippet))); + } + } + } else if let (Ok(snippet), false) = + (tcx.sess.source_map().span_to_snippet(*span), dupes) + { + let types: Vec<_> = + assoc_items.iter().map(|item| format!("{} = Type", item.ident)).collect(); + let code = if snippet.ends_with('>') { + // The user wrote `Trait<'a>` or similar and we don't have a type we can + // suggest, but at least we can clue them to the correct syntax + // `Trait<'a, Item = Type>` while accounting for the `<'a>` in the + // suggestion. + format!("{}, {}>", &snippet[..snippet.len() - 1], types.join(", ")) + } else { + // The user wrote `Iterator`, so we don't have a type we can suggest, but at + // least we can clue them to the correct syntax `Iterator`. + format!("{}<{}>", snippet, types.join(", ")) + }; + suggestions.push((*span, code)); + } else if dupes { + where_constraints.push(*span); + } + } + let where_msg = "consider introducing a new type parameter, adding `where` constraints \ + using the fully-qualified path to the associated types"; + if !where_constraints.is_empty() && suggestions.is_empty() { + // If there are duplicates associated type names and a single trait bound do not + // use structured suggestion, it means that there are multiple super-traits with + // the same associated type name. + err.help(where_msg); + } + if suggestions.len() != 1 { + // We don't need this label if there's an inline suggestion, show otherwise. + for (span, assoc_items) in &associated_types { + let mut names: FxHashMap<_, usize> = FxHashMap::default(); + for item in assoc_items { + types_count += 1; + *names.entry(item.ident.name).or_insert(0) += 1; + } + let mut label = vec![]; + for item in assoc_items { + let postfix = if names[&item.ident.name] > 1 { + let trait_def_id = item.container.id(); + format!(" (from trait `{}`)", tcx.def_path_str(trait_def_id)) + } else { + String::new() + }; + label.push(format!("`{}`{}", item.ident, postfix)); + } + if !label.is_empty() { + err.span_label( + *span, + format!( + "associated type{} {} must be specified", + pluralize!(label.len()), + label.join(", "), + ), + ); + } + } + } + if !suggestions.is_empty() { + err.multipart_suggestion( + &format!("specify the associated type{}", pluralize!(types_count)), + suggestions, + Applicability::HasPlaceholders, + ); + if !where_constraints.is_empty() { + err.span_help(where_constraints, where_msg); + } + } + err.emit(); + } +} diff --git a/src/librustc_typeck/astconv/generics.rs b/src/librustc_typeck/astconv/generics.rs new file mode 100644 index 00000000000..84dab6de958 --- /dev/null +++ b/src/librustc_typeck/astconv/generics.rs @@ -0,0 +1,596 @@ +use crate::astconv::{ + AstConv, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, GenericArgPosition, +}; +use rustc_ast::ast::ParamKindOrd; +use rustc_errors::{pluralize, struct_span_err, DiagnosticId, ErrorReported}; +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_hir::{GenericArg, GenericArgs}; +use rustc_middle::ty::{ + self, subst, subst::SubstsRef, GenericParamDef, GenericParamDefKind, Ty, TyCtxt, +}; +use rustc_session::{lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS, Session}; +use rustc_span::{symbol::kw, MultiSpan, Span}; + +use smallvec::SmallVec; + +impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { + /// Report an error that a generic argument did not match the generic parameter that was + /// expected. + fn generic_arg_mismatch_err( + sess: &Session, + arg: &GenericArg<'_>, + kind: &'static str, + help: Option<&str>, + ) { + let mut err = struct_span_err!( + sess, + arg.span(), + E0747, + "{} provided when a {} was expected", + arg.descr(), + kind, + ); + + let unordered = sess.features_untracked().const_generics; + let kind_ord = match kind { + "lifetime" => ParamKindOrd::Lifetime, + "type" => ParamKindOrd::Type, + "constant" => ParamKindOrd::Const { unordered }, + // It's more concise to match on the string representation, though it means + // the match is non-exhaustive. + _ => bug!("invalid generic parameter kind {}", kind), + }; + let arg_ord = match arg { + GenericArg::Lifetime(_) => ParamKindOrd::Lifetime, + GenericArg::Type(_) => ParamKindOrd::Type, + GenericArg::Const(_) => ParamKindOrd::Const { unordered }, + }; + + // This note is only true when generic parameters are strictly ordered by their kind. + if kind_ord.cmp(&arg_ord) != core::cmp::Ordering::Equal { + let (first, last) = + if kind_ord < arg_ord { (kind, arg.descr()) } else { (arg.descr(), kind) }; + err.note(&format!("{} arguments must be provided before {} arguments", first, last)); + if let Some(help) = help { + err.help(help); + } + } + + err.emit(); + } + + /// Creates the relevant generic argument substitutions + /// corresponding to a set of generic parameters. This is a + /// rather complex function. Let us try to explain the role + /// of each of its parameters: + /// + /// To start, we are given the `def_id` of the thing we are + /// creating the substitutions for, and a partial set of + /// substitutions `parent_substs`. In general, the substitutions + /// for an item begin with substitutions for all the "parents" of + /// that item -- e.g., for a method it might include the + /// parameters from the impl. + /// + /// Therefore, the method begins by walking down these parents, + /// starting with the outermost parent and proceed inwards until + /// it reaches `def_id`. For each parent `P`, it will check `parent_substs` + /// first to see if the parent's substitutions are listed in there. If so, + /// we can append those and move on. Otherwise, it invokes the + /// three callback functions: + /// + /// - `args_for_def_id`: given the `DefId` `P`, supplies back the + /// generic arguments that were given to that parent from within + /// the path; so e.g., if you have `::Bar`, the `DefId` + /// might refer to the trait `Foo`, and the arguments might be + /// `[T]`. The boolean value indicates whether to infer values + /// for arguments whose values were not explicitly provided. + /// - `provided_kind`: given the generic parameter and the value from `args_for_def_id`, + /// instantiate a `GenericArg`. + /// - `inferred_kind`: if no parameter was provided, and inference is enabled, then + /// creates a suitable inference variable. + pub fn create_substs_for_generic_args<'b>( + tcx: TyCtxt<'tcx>, + def_id: DefId, + parent_substs: &[subst::GenericArg<'tcx>], + has_self: bool, + self_ty: Option>, + arg_count: GenericArgCountResult, + args_for_def_id: impl Fn(DefId) -> (Option<&'b GenericArgs<'b>>, bool), + mut provided_kind: impl FnMut(&GenericParamDef, &GenericArg<'_>) -> subst::GenericArg<'tcx>, + mut inferred_kind: impl FnMut( + Option<&[subst::GenericArg<'tcx>]>, + &GenericParamDef, + bool, + ) -> subst::GenericArg<'tcx>, + ) -> SubstsRef<'tcx> { + // Collect the segments of the path; we need to substitute arguments + // for parameters throughout the entire path (wherever there are + // generic parameters). + let mut parent_defs = tcx.generics_of(def_id); + let count = parent_defs.count(); + let mut stack = vec![(def_id, parent_defs)]; + while let Some(def_id) = parent_defs.parent { + parent_defs = tcx.generics_of(def_id); + stack.push((def_id, parent_defs)); + } + + // We manually build up the substitution, rather than using convenience + // methods in `subst.rs`, so that we can iterate over the arguments and + // parameters in lock-step linearly, instead of trying to match each pair. + let mut substs: SmallVec<[subst::GenericArg<'tcx>; 8]> = SmallVec::with_capacity(count); + // Iterate over each segment of the path. + while let Some((def_id, defs)) = stack.pop() { + let mut params = defs.params.iter().peekable(); + + // If we have already computed substitutions for parents, we can use those directly. + while let Some(¶m) = params.peek() { + if let Some(&kind) = parent_substs.get(param.index as usize) { + substs.push(kind); + params.next(); + } else { + break; + } + } + + // `Self` is handled first, unless it's been handled in `parent_substs`. + if has_self { + if let Some(¶m) = params.peek() { + if param.index == 0 { + if let GenericParamDefKind::Type { .. } = param.kind { + substs.push( + self_ty + .map(|ty| ty.into()) + .unwrap_or_else(|| inferred_kind(None, param, true)), + ); + params.next(); + } + } + } + } + + // Check whether this segment takes generic arguments and the user has provided any. + let (generic_args, infer_args) = args_for_def_id(def_id); + + let mut args = + generic_args.iter().flat_map(|generic_args| generic_args.args.iter()).peekable(); + + // If we encounter a type or const when we expect a lifetime, we infer the lifetimes. + // If we later encounter a lifetime, we know that the arguments were provided in the + // wrong order. `force_infer_lt` records the type or const that forced lifetimes to be + // inferred, so we can use it for diagnostics later. + let mut force_infer_lt = None; + + loop { + // We're going to iterate through the generic arguments that the user + // provided, matching them with the generic parameters we expect. + // Mismatches can occur as a result of elided lifetimes, or for malformed + // input. We try to handle both sensibly. + match (args.peek(), params.peek()) { + (Some(&arg), Some(¶m)) => { + match (arg, ¶m.kind, arg_count.explicit_late_bound) { + (GenericArg::Lifetime(_), GenericParamDefKind::Lifetime, _) + | (GenericArg::Type(_), GenericParamDefKind::Type { .. }, _) + | (GenericArg::Const(_), GenericParamDefKind::Const, _) => { + substs.push(provided_kind(param, arg)); + args.next(); + params.next(); + } + ( + GenericArg::Type(_) | GenericArg::Const(_), + GenericParamDefKind::Lifetime, + _, + ) => { + // We expected a lifetime argument, but got a type or const + // argument. That means we're inferring the lifetimes. + substs.push(inferred_kind(None, param, infer_args)); + force_infer_lt = Some(arg); + params.next(); + } + (GenericArg::Lifetime(_), _, ExplicitLateBound::Yes) => { + // We've come across a lifetime when we expected something else in + // the presence of explicit late bounds. This is most likely + // due to the presence of the explicit bound so we're just going to + // ignore it. + args.next(); + } + (_, kind, _) => { + // We expected one kind of parameter, but the user provided + // another. This is an error. However, if we already know that + // the arguments don't match up with the parameters, we won't issue + // an additional error, as the user already knows what's wrong. + if arg_count.correct.is_ok() + && arg_count.explicit_late_bound == ExplicitLateBound::No + { + // We're going to iterate over the parameters to sort them out, and + // show that order to the user as a possible order for the parameters + let mut param_types_present = defs + .params + .clone() + .into_iter() + .map(|param| { + ( + match param.kind { + GenericParamDefKind::Lifetime => { + ParamKindOrd::Lifetime + } + GenericParamDefKind::Type { .. } => { + ParamKindOrd::Type + } + GenericParamDefKind::Const => { + ParamKindOrd::Const { + unordered: tcx + .sess + .features_untracked() + .const_generics, + } + } + }, + param, + ) + }) + .collect::>(); + param_types_present.sort_by_key(|(ord, _)| *ord); + let (mut param_types_present, ordered_params): ( + Vec, + Vec, + ) = param_types_present.into_iter().unzip(); + param_types_present.dedup(); + + Self::generic_arg_mismatch_err( + tcx.sess, + arg, + kind.descr(), + Some(&format!( + "reorder the arguments: {}: `<{}>`", + param_types_present + .into_iter() + .map(|ord| format!("{}s", ord.to_string())) + .collect::>() + .join(", then "), + ordered_params + .into_iter() + .filter_map(|param| { + if param.name == kw::SelfUpper { + None + } else { + Some(param.name.to_string()) + } + }) + .collect::>() + .join(", ") + )), + ); + } + + // We've reported the error, but we want to make sure that this + // problem doesn't bubble down and create additional, irrelevant + // errors. In this case, we're simply going to ignore the argument + // and any following arguments. The rest of the parameters will be + // inferred. + while args.next().is_some() {} + } + } + } + + (Some(&arg), None) => { + // We should never be able to reach this point with well-formed input. + // There are three situations in which we can encounter this issue. + // + // 1. The number of arguments is incorrect. In this case, an error + // will already have been emitted, and we can ignore it. + // 2. There are late-bound lifetime parameters present, yet the + // lifetime arguments have also been explicitly specified by the + // user. + // 3. We've inferred some lifetimes, which have been provided later (i.e. + // after a type or const). We want to throw an error in this case. + + if arg_count.correct.is_ok() + && arg_count.explicit_late_bound == ExplicitLateBound::No + { + let kind = arg.descr(); + assert_eq!(kind, "lifetime"); + let provided = + force_infer_lt.expect("lifetimes ought to have been inferred"); + Self::generic_arg_mismatch_err(tcx.sess, provided, kind, None); + } + + break; + } + + (None, Some(¶m)) => { + // If there are fewer arguments than parameters, it means + // we're inferring the remaining arguments. + substs.push(inferred_kind(Some(&substs), param, infer_args)); + params.next(); + } + + (None, None) => break, + } + } + } + + tcx.intern_substs(&substs) + } + + /// Checks that the correct number of generic arguments have been provided. + /// Used specifically for function calls. + pub fn check_generic_arg_count_for_call( + tcx: TyCtxt<'_>, + span: Span, + def: &ty::Generics, + seg: &hir::PathSegment<'_>, + is_method_call: bool, + ) -> GenericArgCountResult { + let empty_args = hir::GenericArgs::none(); + let suppress_mismatch = Self::check_impl_trait(tcx, seg, &def); + Self::check_generic_arg_count( + tcx, + span, + def, + if let Some(ref args) = seg.args { args } else { &empty_args }, + if is_method_call { GenericArgPosition::MethodCall } else { GenericArgPosition::Value }, + def.parent.is_none() && def.has_self, // `has_self` + seg.infer_args || suppress_mismatch, // `infer_args` + ) + } + + /// Checks that the correct number of generic arguments have been provided. + /// This is used both for datatypes and function calls. + pub(crate) fn check_generic_arg_count( + tcx: TyCtxt<'_>, + span: Span, + def: &ty::Generics, + args: &hir::GenericArgs<'_>, + position: GenericArgPosition, + has_self: bool, + infer_args: bool, + ) -> GenericArgCountResult { + // At this stage we are guaranteed that the generic arguments are in the correct order, e.g. + // that lifetimes will proceed types. So it suffices to check the number of each generic + // arguments in order to validate them with respect to the generic parameters. + let param_counts = def.own_counts(); + let arg_counts = args.own_counts(); + let infer_lifetimes = position != GenericArgPosition::Type && arg_counts.lifetimes == 0; + + let mut defaults: ty::GenericParamCount = Default::default(); + for param in &def.params { + match param.kind { + GenericParamDefKind::Lifetime => {} + GenericParamDefKind::Type { has_default, .. } => { + defaults.types += has_default as usize + } + GenericParamDefKind::Const => { + // FIXME(const_generics:defaults) + } + }; + } + + if position != GenericArgPosition::Type && !args.bindings.is_empty() { + Self::prohibit_assoc_ty_binding(tcx, args.bindings[0].span); + } + + let explicit_late_bound = + Self::prohibit_explicit_late_bound_lifetimes(tcx, def, args, position); + + let check_kind_count = |kind, + required, + permitted, + provided, + offset, + unexpected_spans: &mut Vec, + silent| { + debug!( + "check_kind_count: kind: {} required: {} permitted: {} provided: {} offset: {}", + kind, required, permitted, provided, offset + ); + // We enforce the following: `required` <= `provided` <= `permitted`. + // For kinds without defaults (e.g.., lifetimes), `required == permitted`. + // For other kinds (i.e., types), `permitted` may be greater than `required`. + if required <= provided && provided <= permitted { + return Ok(()); + } + + if silent { + return Err(true); + } + + // Unfortunately lifetime and type parameter mismatches are typically styled + // differently in diagnostics, which means we have a few cases to consider here. + let (bound, quantifier) = if required != permitted { + if provided < required { + (required, "at least ") + } else { + // provided > permitted + (permitted, "at most ") + } + } else { + (required, "") + }; + + let (spans, label) = if required == permitted && provided > permitted { + // In the case when the user has provided too many arguments, + // we want to point to the unexpected arguments. + let spans: Vec = args.args[offset + permitted..offset + provided] + .iter() + .map(|arg| arg.span()) + .collect(); + unexpected_spans.extend(spans.clone()); + (spans, format!("unexpected {} argument", kind)) + } else { + ( + vec![span], + format!( + "expected {}{} {} argument{}", + quantifier, + bound, + kind, + pluralize!(bound), + ), + ) + }; + + let mut err = tcx.sess.struct_span_err_with_code( + spans.clone(), + &format!( + "wrong number of {} arguments: expected {}{}, found {}", + kind, quantifier, bound, provided, + ), + DiagnosticId::Error("E0107".into()), + ); + for span in spans { + err.span_label(span, label.as_str()); + } + err.emit(); + + Err(true) + }; + + let mut arg_count_correct = Ok(()); + let mut unexpected_spans = vec![]; + + if !infer_lifetimes || arg_counts.lifetimes > param_counts.lifetimes { + arg_count_correct = check_kind_count( + "lifetime", + param_counts.lifetimes, + param_counts.lifetimes, + arg_counts.lifetimes, + 0, + &mut unexpected_spans, + explicit_late_bound == ExplicitLateBound::Yes, + ) + .and(arg_count_correct); + } + // FIXME(const_generics:defaults) + if !infer_args || arg_counts.consts > param_counts.consts { + arg_count_correct = check_kind_count( + "const", + param_counts.consts, + param_counts.consts, + arg_counts.consts, + arg_counts.lifetimes + arg_counts.types, + &mut unexpected_spans, + false, + ) + .and(arg_count_correct); + } + // Note that type errors are currently be emitted *after* const errors. + if !infer_args || arg_counts.types > param_counts.types - defaults.types - has_self as usize + { + arg_count_correct = check_kind_count( + "type", + param_counts.types - defaults.types - has_self as usize, + param_counts.types - has_self as usize, + arg_counts.types, + arg_counts.lifetimes, + &mut unexpected_spans, + false, + ) + .and(arg_count_correct); + } + + GenericArgCountResult { + explicit_late_bound, + correct: arg_count_correct.map_err(|reported_err| GenericArgCountMismatch { + reported: if reported_err { Some(ErrorReported) } else { None }, + invalid_args: unexpected_spans, + }), + } + } + + /// Report error if there is an explicit type parameter when using `impl Trait`. + pub(crate) fn check_impl_trait( + tcx: TyCtxt<'_>, + seg: &hir::PathSegment<'_>, + generics: &ty::Generics, + ) -> bool { + let explicit = !seg.infer_args; + let impl_trait = generics.params.iter().any(|param| match param.kind { + ty::GenericParamDefKind::Type { + synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), + .. + } => true, + _ => false, + }); + + if explicit && impl_trait { + let spans = seg + .generic_args() + .args + .iter() + .filter_map(|arg| match arg { + GenericArg::Type(_) => Some(arg.span()), + _ => None, + }) + .collect::>(); + + let mut err = struct_span_err! { + tcx.sess, + spans.clone(), + E0632, + "cannot provide explicit generic arguments when `impl Trait` is \ + used in argument position" + }; + + for span in spans { + err.span_label(span, "explicit generic argument not allowed"); + } + + err.emit(); + } + + impl_trait + } + + /// Emits an error regarding forbidden type binding associations + pub fn prohibit_assoc_ty_binding(tcx: TyCtxt<'_>, span: Span) { + let mut err = struct_span_err!( + tcx.sess, + span, + E0229, + "associated type bindings are not allowed here" + ); + err.span_label(span, "associated type not allowed here").emit(); + } + + /// Prohibits explicit lifetime arguments if late-bound lifetime parameters + /// are present. This is used both for datatypes and function calls. + pub(crate) fn prohibit_explicit_late_bound_lifetimes( + tcx: TyCtxt<'_>, + def: &ty::Generics, + args: &hir::GenericArgs<'_>, + position: GenericArgPosition, + ) -> ExplicitLateBound { + let param_counts = def.own_counts(); + let arg_counts = args.own_counts(); + let infer_lifetimes = position != GenericArgPosition::Type && arg_counts.lifetimes == 0; + + if infer_lifetimes { + ExplicitLateBound::No + } else if let Some(span_late) = def.has_late_bound_regions { + let msg = "cannot specify lifetime arguments explicitly \ + if late bound lifetime parameters are present"; + let note = "the late bound lifetime parameter is introduced here"; + let span = args.args[0].span(); + if position == GenericArgPosition::Value + && arg_counts.lifetimes != param_counts.lifetimes + { + let mut err = tcx.sess.struct_span_err(span, msg); + err.span_note(span_late, note); + err.emit(); + } else { + let mut multispan = MultiSpan::from_span(span); + multispan.push_span_label(span_late, note.to_string()); + tcx.struct_span_lint_hir( + LATE_BOUND_LIFETIME_ARGUMENTS, + args.args[0].id(), + multispan, + |lint| lint.build(msg).emit(), + ); + } + ExplicitLateBound::Yes + } else { + ExplicitLateBound::No + } + } +} diff --git a/src/librustc_typeck/astconv/mod.rs b/src/librustc_typeck/astconv/mod.rs new file mode 100644 index 00000000000..80dd26e9154 --- /dev/null +++ b/src/librustc_typeck/astconv/mod.rs @@ -0,0 +1,2296 @@ +//! Conversion from AST representation of types to the `ty.rs` representation. +//! The main routine here is `ast_ty_to_ty()`; each use is parameterized by an +//! instance of `AstConv`. + +mod errors; +mod generics; + +use crate::bounds::Bounds; +use crate::collect::PlaceholderHirTyCollector; +use crate::middle::resolve_lifetime as rl; +use crate::require_c_abi_if_c_variadic; +use rustc_ast::util::lev_distance::find_best_match_for_name; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_errors::{struct_span_err, Applicability, ErrorReported, FatalError}; +use rustc_hir as hir; +use rustc_hir::def::{CtorOf, DefKind, Namespace, Res}; +use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::intravisit::{walk_generics, Visitor as _}; +use rustc_hir::lang_items::LangItem; +use rustc_hir::{Constness, GenericArg, GenericArgs}; +use rustc_middle::ty::subst::{self, InternalSubsts, Subst, SubstsRef}; +use rustc_middle::ty::GenericParamDefKind; +use rustc_middle::ty::{self, Const, DefIdTree, Ty, TyCtxt, TypeFoldable}; +use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; +use rustc_span::symbol::{Ident, Symbol}; +use rustc_span::{Span, DUMMY_SP}; +use rustc_target::spec::abi; +use rustc_trait_selection::traits; +use rustc_trait_selection::traits::astconv_object_safety_violations; +use rustc_trait_selection::traits::error_reporting::report_object_safety_error; +use rustc_trait_selection::traits::wf::object_region_bounds; + +use smallvec::SmallVec; +use std::collections::BTreeSet; +use std::iter; +use std::slice; + +#[derive(Debug)] +pub struct PathSeg(pub DefId, pub usize); + +pub trait AstConv<'tcx> { + fn tcx<'a>(&'a self) -> TyCtxt<'tcx>; + + fn item_def_id(&self) -> Option; + + fn default_constness_for_trait_bounds(&self) -> Constness; + + /// Returns predicates in scope of the form `X: Foo`, where `X` is + /// a type parameter `X` with the given id `def_id`. This is a + /// subset of the full set of predicates. + /// + /// This is used for one specific purpose: resolving "short-hand" + /// associated type references like `T::Item`. In principle, we + /// would do that by first getting the full set of predicates in + /// scope and then filtering down to find those that apply to `T`, + /// but this can lead to cycle errors. The problem is that we have + /// to do this resolution *in order to create the predicates in + /// the first place*. Hence, we have this "special pass". + fn get_type_parameter_bounds(&self, span: Span, def_id: DefId) -> ty::GenericPredicates<'tcx>; + + /// Returns the lifetime to use when a lifetime is omitted (and not elided). + fn re_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) + -> Option>; + + /// Returns the type to use when a type is omitted. + fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx>; + + /// Returns `true` if `_` is allowed in type signatures in the current context. + fn allow_ty_infer(&self) -> bool; + + /// Returns the const to use when a const is omitted. + fn ct_infer( + &self, + ty: Ty<'tcx>, + param: Option<&ty::GenericParamDef>, + span: Span, + ) -> &'tcx Const<'tcx>; + + /// Projecting an associated type from a (potentially) + /// higher-ranked trait reference is more complicated, because of + /// the possibility of late-bound regions appearing in the + /// associated type binding. This is not legal in function + /// signatures for that reason. In a function body, we can always + /// handle it because we can use inference variables to remove the + /// late-bound regions. + fn projected_ty_from_poly_trait_ref( + &self, + span: Span, + item_def_id: DefId, + item_segment: &hir::PathSegment<'_>, + poly_trait_ref: ty::PolyTraitRef<'tcx>, + ) -> Ty<'tcx>; + + /// Normalize an associated type coming from the user. + fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx>; + + /// Invoked when we encounter an error from some prior pass + /// (e.g., resolve) that is translated into a ty-error. This is + /// used to help suppress derived errors typeck might otherwise + /// report. + fn set_tainted_by_errors(&self); + + fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span); +} + +pub enum SizedByDefault { + Yes, + No, +} + +struct ConvertedBinding<'a, 'tcx> { + item_name: Ident, + kind: ConvertedBindingKind<'a, 'tcx>, + span: Span, +} + +enum ConvertedBindingKind<'a, 'tcx> { + Equality(Ty<'tcx>), + Constraint(&'a [hir::GenericBound<'a>]), +} + +/// New-typed boolean indicating whether explicit late-bound lifetimes +/// are present in a set of generic arguments. +/// +/// For example if we have some method `fn f<'a>(&'a self)` implemented +/// for some type `T`, although `f` is generic in the lifetime `'a`, `'a` +/// is late-bound so should not be provided explicitly. Thus, if `f` is +/// instantiated with some generic arguments providing `'a` explicitly, +/// we taint those arguments with `ExplicitLateBound::Yes` so that we +/// can provide an appropriate diagnostic later. +#[derive(Copy, Clone, PartialEq)] +pub enum ExplicitLateBound { + Yes, + No, +} + +/// Denotes the "position" of a generic argument, indicating if it is a generic type, +/// generic function or generic method call. +#[derive(Copy, Clone, PartialEq)] +pub(crate) enum GenericArgPosition { + Type, + Value, // e.g., functions + MethodCall, +} + +/// A marker denoting that the generic arguments that were +/// provided did not match the respective generic parameters. +#[derive(Clone, Default)] +pub struct GenericArgCountMismatch { + /// Indicates whether a fatal error was reported (`Some`), or just a lint (`None`). + pub reported: Option, + /// A list of spans of arguments provided that were not valid. + pub invalid_args: Vec, +} + +/// Decorates the result of a generic argument count mismatch +/// check with whether explicit late bounds were provided. +#[derive(Clone)] +pub struct GenericArgCountResult { + pub explicit_late_bound: ExplicitLateBound, + pub correct: Result<(), GenericArgCountMismatch>, +} + +impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { + pub fn ast_region_to_region( + &self, + lifetime: &hir::Lifetime, + def: Option<&ty::GenericParamDef>, + ) -> ty::Region<'tcx> { + let tcx = self.tcx(); + let lifetime_name = |def_id| tcx.hir().name(tcx.hir().local_def_id_to_hir_id(def_id)); + + let r = match tcx.named_region(lifetime.hir_id) { + Some(rl::Region::Static) => tcx.lifetimes.re_static, + + Some(rl::Region::LateBound(debruijn, id, _)) => { + let name = lifetime_name(id.expect_local()); + tcx.mk_region(ty::ReLateBound(debruijn, ty::BrNamed(id, name))) + } + + Some(rl::Region::LateBoundAnon(debruijn, index)) => { + tcx.mk_region(ty::ReLateBound(debruijn, ty::BrAnon(index))) + } + + Some(rl::Region::EarlyBound(index, id, _)) => { + let name = lifetime_name(id.expect_local()); + tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { def_id: id, index, name })) + } + + Some(rl::Region::Free(scope, id)) => { + let name = lifetime_name(id.expect_local()); + tcx.mk_region(ty::ReFree(ty::FreeRegion { + scope, + bound_region: ty::BrNamed(id, name), + })) + + // (*) -- not late-bound, won't change + } + + None => { + self.re_infer(def, lifetime.span).unwrap_or_else(|| { + // This indicates an illegal lifetime + // elision. `resolve_lifetime` should have + // reported an error in this case -- but if + // not, let's error out. + tcx.sess.delay_span_bug(lifetime.span, "unelided lifetime in signature"); + + // Supply some dummy value. We don't have an + // `re_error`, annoyingly, so use `'static`. + tcx.lifetimes.re_static + }) + } + }; + + debug!("ast_region_to_region(lifetime={:?}) yields {:?}", lifetime, r); + + r + } + + /// Given a path `path` that refers to an item `I` with the declared generics `decl_generics`, + /// returns an appropriate set of substitutions for this particular reference to `I`. + pub fn ast_path_substs_for_ty( + &self, + span: Span, + def_id: DefId, + item_segment: &hir::PathSegment<'_>, + ) -> SubstsRef<'tcx> { + let (substs, assoc_bindings, _) = self.create_substs_for_ast_path( + span, + def_id, + &[], + item_segment.generic_args(), + item_segment.infer_args, + None, + ); + + if let Some(b) = assoc_bindings.first() { + Self::prohibit_assoc_ty_binding(self.tcx(), b.span); + } + + substs + } + + /// Given the type/lifetime/const arguments provided to some path (along with + /// an implicit `Self`, if this is a trait reference), returns the complete + /// set of substitutions. This may involve applying defaulted type parameters. + /// Also returns back constraints on associated types. + /// + /// Example: + /// + /// ``` + /// T: std::ops::Index + /// ^1 ^^^^^^^^^^^^^^2 ^^^^3 ^^^^^^^^^^^4 + /// ``` + /// + /// 1. The `self_ty` here would refer to the type `T`. + /// 2. The path in question is the path to the trait `std::ops::Index`, + /// which will have been resolved to a `def_id` + /// 3. The `generic_args` contains info on the `<...>` contents. The `usize` type + /// parameters are returned in the `SubstsRef`, the associated type bindings like + /// `Output = u32` are returned in the `Vec` result. + /// + /// Note that the type listing given here is *exactly* what the user provided. + /// + /// For (generic) associated types + /// + /// ``` + /// as Iterable>::Iter::<'a> + /// ``` + /// + /// We have the parent substs are the substs for the parent trait: + /// `[Vec, u8]` and `generic_args` are the arguments for the associated + /// type itself: `['a]`. The returned `SubstsRef` concatenates these two + /// lists: `[Vec, u8, 'a]`. + fn create_substs_for_ast_path<'a>( + &self, + span: Span, + def_id: DefId, + parent_substs: &[subst::GenericArg<'tcx>], + generic_args: &'a hir::GenericArgs<'_>, + infer_args: bool, + self_ty: Option>, + ) -> (SubstsRef<'tcx>, Vec>, GenericArgCountResult) { + // If the type is parameterized by this region, then replace this + // region with the current anon region binding (in other words, + // whatever & would get replaced with). + debug!( + "create_substs_for_ast_path(def_id={:?}, self_ty={:?}, \ + generic_args={:?})", + def_id, self_ty, generic_args + ); + + let tcx = self.tcx(); + let generic_params = tcx.generics_of(def_id); + + if generic_params.has_self { + if generic_params.parent.is_some() { + // The parent is a trait so it should have at least one subst + // for the `Self` type. + assert!(!parent_substs.is_empty()) + } else { + // This item (presumably a trait) needs a self-type. + assert!(self_ty.is_some()); + } + } else { + assert!(self_ty.is_none() && parent_substs.is_empty()); + } + + let arg_count = Self::check_generic_arg_count( + tcx, + span, + &generic_params, + &generic_args, + GenericArgPosition::Type, + self_ty.is_some(), + infer_args, + ); + + let is_object = self_ty.map_or(false, |ty| ty == self.tcx().types.trait_object_dummy_self); + let default_needs_object_self = |param: &ty::GenericParamDef| { + if let GenericParamDefKind::Type { has_default, .. } = param.kind { + if is_object && has_default { + let default_ty = tcx.at(span).type_of(param.def_id); + let self_param = tcx.types.self_param; + if default_ty.walk().any(|arg| arg == self_param.into()) { + // There is no suitable inference default for a type parameter + // that references self, in an object type. + return true; + } + } + } + + false + }; + + let mut missing_type_params = vec![]; + let mut inferred_params = vec![]; + let substs = Self::create_substs_for_generic_args( + tcx, + def_id, + parent_substs, + self_ty.is_some(), + self_ty, + arg_count.clone(), + // Provide the generic args, and whether types should be inferred. + |did| { + if did == def_id { + (Some(generic_args), infer_args) + } else { + // The last component of this tuple is unimportant. + (None, false) + } + }, + // Provide substitutions for parameters for which (valid) arguments have been provided. + |param, arg| match (¶m.kind, arg) { + (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { + self.ast_region_to_region(<, Some(param)).into() + } + (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { + if let (hir::TyKind::Infer, false) = (&ty.kind, self.allow_ty_infer()) { + inferred_params.push(ty.span); + tcx.ty_error().into() + } else { + self.ast_ty_to_ty(&ty).into() + } + } + (GenericParamDefKind::Const, GenericArg::Const(ct)) => { + ty::Const::from_opt_const_arg_anon_const( + tcx, + ty::WithOptConstParam { + did: tcx.hir().local_def_id(ct.value.hir_id), + const_param_did: Some(param.def_id), + }, + ) + .into() + } + _ => unreachable!(), + }, + // Provide substitutions for parameters for which arguments are inferred. + |substs, param, infer_args| { + match param.kind { + GenericParamDefKind::Lifetime => tcx.lifetimes.re_static.into(), + GenericParamDefKind::Type { has_default, .. } => { + if !infer_args && has_default { + // No type parameter provided, but a default exists. + + // If we are converting an object type, then the + // `Self` parameter is unknown. However, some of the + // other type parameters may reference `Self` in their + // defaults. This will lead to an ICE if we are not + // careful! + if default_needs_object_self(param) { + missing_type_params.push(param.name.to_string()); + tcx.ty_error().into() + } else { + // This is a default type parameter. + self.normalize_ty( + span, + tcx.at(span).type_of(param.def_id).subst_spanned( + tcx, + substs.unwrap(), + Some(span), + ), + ) + .into() + } + } else if infer_args { + // No type parameters were provided, we can infer all. + let param = + if !default_needs_object_self(param) { Some(param) } else { None }; + self.ty_infer(param, span).into() + } else { + // We've already errored above about the mismatch. + tcx.ty_error().into() + } + } + GenericParamDefKind::Const => { + let ty = tcx.at(span).type_of(param.def_id); + // FIXME(const_generics:defaults) + if infer_args { + // No const parameters were provided, we can infer all. + self.ct_infer(ty, Some(param), span).into() + } else { + // We've already errored above about the mismatch. + tcx.const_error(ty).into() + } + } + } + }, + ); + + self.complain_about_missing_type_params( + missing_type_params, + def_id, + span, + generic_args.args.is_empty(), + ); + + // Convert associated-type bindings or constraints into a separate vector. + // Example: Given this: + // + // T: Iterator + // + // The `T` is passed in as a self-type; the `Item = u32` is + // not a "type parameter" of the `Iterator` trait, but rather + // a restriction on `::Item`, so it is passed + // back separately. + let assoc_bindings = generic_args + .bindings + .iter() + .map(|binding| { + let kind = match binding.kind { + hir::TypeBindingKind::Equality { ref ty } => { + ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty)) + } + hir::TypeBindingKind::Constraint { ref bounds } => { + ConvertedBindingKind::Constraint(bounds) + } + }; + ConvertedBinding { item_name: binding.ident, kind, span: binding.span } + }) + .collect(); + + debug!( + "create_substs_for_ast_path(generic_params={:?}, self_ty={:?}) -> {:?}", + generic_params, self_ty, substs + ); + + (substs, assoc_bindings, arg_count) + } + + crate fn create_substs_for_associated_item( + &self, + tcx: TyCtxt<'tcx>, + span: Span, + item_def_id: DefId, + item_segment: &hir::PathSegment<'_>, + parent_substs: SubstsRef<'tcx>, + ) -> SubstsRef<'tcx> { + if tcx.generics_of(item_def_id).params.is_empty() { + self.prohibit_generics(slice::from_ref(item_segment)); + + parent_substs + } else { + self.create_substs_for_ast_path( + span, + item_def_id, + parent_substs, + item_segment.generic_args(), + item_segment.infer_args, + None, + ) + .0 + } + } + + /// Instantiates the path for the given trait reference, assuming that it's + /// bound to a valid trait type. Returns the `DefId` of the defining trait. + /// The type _cannot_ be a type other than a trait type. + /// + /// If the `projections` argument is `None`, then assoc type bindings like `Foo` + /// are disallowed. Otherwise, they are pushed onto the vector given. + pub fn instantiate_mono_trait_ref( + &self, + trait_ref: &hir::TraitRef<'_>, + self_ty: Ty<'tcx>, + ) -> ty::TraitRef<'tcx> { + self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1); + + self.ast_path_to_mono_trait_ref( + trait_ref.path.span, + trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()), + self_ty, + trait_ref.path.segments.last().unwrap(), + ) + } + + /// The given trait-ref must actually be a trait. + pub(super) fn instantiate_poly_trait_ref_inner( + &self, + trait_ref: &hir::TraitRef<'_>, + span: Span, + constness: Constness, + self_ty: Ty<'tcx>, + bounds: &mut Bounds<'tcx>, + speculative: bool, + ) -> GenericArgCountResult { + let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()); + + debug!("instantiate_poly_trait_ref({:?}, def_id={:?})", trait_ref, trait_def_id); + + self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1); + + let (substs, assoc_bindings, arg_count) = self.create_substs_for_ast_trait_ref( + trait_ref.path.span, + trait_def_id, + self_ty, + trait_ref.path.segments.last().unwrap(), + ); + let poly_trait_ref = ty::Binder::bind(ty::TraitRef::new(trait_def_id, substs)); + + bounds.trait_bounds.push((poly_trait_ref, span, constness)); + + let mut dup_bindings = FxHashMap::default(); + for binding in &assoc_bindings { + // Specify type to assert that error was already reported in `Err` case. + let _: Result<_, ErrorReported> = self.add_predicates_for_ast_type_binding( + trait_ref.hir_ref_id, + poly_trait_ref, + binding, + bounds, + speculative, + &mut dup_bindings, + binding.span, + ); + // Okay to ignore `Err` because of `ErrorReported` (see above). + } + + debug!( + "instantiate_poly_trait_ref({:?}, bounds={:?}) -> {:?}", + trait_ref, bounds, poly_trait_ref + ); + + arg_count + } + + /// Given a trait bound like `Debug`, applies that trait bound the given self-type to construct + /// a full trait reference. The resulting trait reference is returned. This may also generate + /// auxiliary bounds, which are added to `bounds`. + /// + /// Example: + /// + /// ``` + /// poly_trait_ref = Iterator + /// self_ty = Foo + /// ``` + /// + /// this would return `Foo: Iterator` and add `::Item = u32` into `bounds`. + /// + /// **A note on binders:** against our usual convention, there is an implied bounder around + /// the `self_ty` and `poly_trait_ref` parameters here. So they may reference bound regions. + /// If for example you had `for<'a> Foo<'a>: Bar<'a>`, then the `self_ty` would be `Foo<'a>` + /// where `'a` is a bound region at depth 0. Similarly, the `poly_trait_ref` would be + /// `Bar<'a>`. The returned poly-trait-ref will have this binder instantiated explicitly, + /// however. + pub fn instantiate_poly_trait_ref( + &self, + poly_trait_ref: &hir::PolyTraitRef<'_>, + constness: Constness, + self_ty: Ty<'tcx>, + bounds: &mut Bounds<'tcx>, + ) -> GenericArgCountResult { + self.instantiate_poly_trait_ref_inner( + &poly_trait_ref.trait_ref, + poly_trait_ref.span, + constness, + self_ty, + bounds, + false, + ) + } + + pub fn instantiate_lang_item_trait_ref( + &self, + lang_item: hir::LangItem, + span: Span, + hir_id: hir::HirId, + args: &GenericArgs<'_>, + self_ty: Ty<'tcx>, + bounds: &mut Bounds<'tcx>, + ) { + let trait_def_id = self.tcx().require_lang_item(lang_item, Some(span)); + + let (substs, assoc_bindings, _) = + self.create_substs_for_ast_path(span, trait_def_id, &[], args, false, Some(self_ty)); + let poly_trait_ref = ty::Binder::bind(ty::TraitRef::new(trait_def_id, substs)); + bounds.trait_bounds.push((poly_trait_ref, span, Constness::NotConst)); + + let mut dup_bindings = FxHashMap::default(); + for binding in assoc_bindings { + let _: Result<_, ErrorReported> = self.add_predicates_for_ast_type_binding( + hir_id, + poly_trait_ref, + &binding, + bounds, + false, + &mut dup_bindings, + span, + ); + } + } + + fn ast_path_to_mono_trait_ref( + &self, + span: Span, + trait_def_id: DefId, + self_ty: Ty<'tcx>, + trait_segment: &hir::PathSegment<'_>, + ) -> ty::TraitRef<'tcx> { + let (substs, assoc_bindings, _) = + self.create_substs_for_ast_trait_ref(span, trait_def_id, self_ty, trait_segment); + if let Some(b) = assoc_bindings.first() { + Self::prohibit_assoc_ty_binding(self.tcx(), b.span); + } + ty::TraitRef::new(trait_def_id, substs) + } + + fn create_substs_for_ast_trait_ref<'a>( + &self, + span: Span, + trait_def_id: DefId, + self_ty: Ty<'tcx>, + trait_segment: &'a hir::PathSegment<'a>, + ) -> (SubstsRef<'tcx>, Vec>, GenericArgCountResult) { + debug!("create_substs_for_ast_trait_ref(trait_segment={:?})", trait_segment); + + self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment); + + self.create_substs_for_ast_path( + span, + trait_def_id, + &[], + trait_segment.generic_args(), + trait_segment.infer_args, + Some(self_ty), + ) + } + + fn trait_defines_associated_type_named(&self, trait_def_id: DefId, assoc_name: Ident) -> bool { + self.tcx() + .associated_items(trait_def_id) + .find_by_name_and_kind(self.tcx(), assoc_name, ty::AssocKind::Type, trait_def_id) + .is_some() + } + + // Returns `true` if a bounds list includes `?Sized`. + pub fn is_unsized(&self, ast_bounds: &[hir::GenericBound<'_>], span: Span) -> bool { + let tcx = self.tcx(); + + // Try to find an unbound in bounds. + let mut unbound = None; + for ab in ast_bounds { + if let &hir::GenericBound::Trait(ref ptr, hir::TraitBoundModifier::Maybe) = ab { + if unbound.is_none() { + unbound = Some(&ptr.trait_ref); + } else { + struct_span_err!( + tcx.sess, + span, + E0203, + "type parameter has more than one relaxed default \ + bound, only one is supported" + ) + .emit(); + } + } + } + + let kind_id = tcx.lang_items().require(LangItem::Sized); + match unbound { + Some(tpb) => { + // FIXME(#8559) currently requires the unbound to be built-in. + if let Ok(kind_id) = kind_id { + if tpb.path.res != Res::Def(DefKind::Trait, kind_id) { + tcx.sess.span_warn( + span, + "default bound relaxed for a type parameter, but \ + this does nothing because the given bound is not \ + a default; only `?Sized` is supported", + ); + } + } + } + _ if kind_id.is_ok() => { + return false; + } + // No lang item for `Sized`, so we can't add it as a bound. + None => {} + } + + true + } + + /// This helper takes a *converted* parameter type (`param_ty`) + /// and an *unconverted* list of bounds: + /// + /// ```text + /// fn foo + /// ^ ^^^^^ `ast_bounds` parameter, in HIR form + /// | + /// `param_ty`, in ty form + /// ``` + /// + /// It adds these `ast_bounds` into the `bounds` structure. + /// + /// **A note on binders:** there is an implied binder around + /// `param_ty` and `ast_bounds`. See `instantiate_poly_trait_ref` + /// for more details. + fn add_bounds( + &self, + param_ty: Ty<'tcx>, + ast_bounds: &[hir::GenericBound<'_>], + bounds: &mut Bounds<'tcx>, + ) { + let mut trait_bounds = Vec::new(); + let mut region_bounds = Vec::new(); + + let constness = self.default_constness_for_trait_bounds(); + for ast_bound in ast_bounds { + match *ast_bound { + hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::None) => { + trait_bounds.push((b, constness)) + } + hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::MaybeConst) => { + trait_bounds.push((b, Constness::NotConst)) + } + hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => {} + hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => self + .instantiate_lang_item_trait_ref( + lang_item, span, hir_id, args, param_ty, bounds, + ), + hir::GenericBound::Outlives(ref l) => region_bounds.push(l), + } + } + + for (bound, constness) in trait_bounds { + let _ = self.instantiate_poly_trait_ref(bound, constness, param_ty, bounds); + } + + bounds.region_bounds.extend( + region_bounds.into_iter().map(|r| (self.ast_region_to_region(r, None), r.span)), + ); + } + + /// Translates a list of bounds from the HIR into the `Bounds` data structure. + /// The self-type for the bounds is given by `param_ty`. + /// + /// Example: + /// + /// ``` + /// fn foo() { } + /// ^ ^^^^^^^^^ ast_bounds + /// param_ty + /// ``` + /// + /// The `sized_by_default` parameter indicates if, in this context, the `param_ty` should be + /// considered `Sized` unless there is an explicit `?Sized` bound. This would be true in the + /// example above, but is not true in supertrait listings like `trait Foo: Bar + Baz`. + /// + /// `span` should be the declaration size of the parameter. + pub fn compute_bounds( + &self, + param_ty: Ty<'tcx>, + ast_bounds: &[hir::GenericBound<'_>], + sized_by_default: SizedByDefault, + span: Span, + ) -> Bounds<'tcx> { + let mut bounds = Bounds::default(); + + self.add_bounds(param_ty, ast_bounds, &mut bounds); + bounds.trait_bounds.sort_by_key(|(t, _, _)| t.def_id()); + + bounds.implicitly_sized = if let SizedByDefault::Yes = sized_by_default { + if !self.is_unsized(ast_bounds, span) { Some(span) } else { None } + } else { + None + }; + + bounds + } + + /// Given an HIR binding like `Item = Foo` or `Item: Foo`, pushes the corresponding predicates + /// onto `bounds`. + /// + /// **A note on binders:** given something like `T: for<'a> Iterator`, the + /// `trait_ref` here will be `for<'a> T: Iterator`. The `binding` data however is from *inside* + /// the binder (e.g., `&'a u32`) and hence may reference bound regions. + fn add_predicates_for_ast_type_binding( + &self, + hir_ref_id: hir::HirId, + trait_ref: ty::PolyTraitRef<'tcx>, + binding: &ConvertedBinding<'_, 'tcx>, + bounds: &mut Bounds<'tcx>, + speculative: bool, + dup_bindings: &mut FxHashMap, + path_span: Span, + ) -> Result<(), ErrorReported> { + let tcx = self.tcx(); + + if !speculative { + // Given something like `U: SomeTrait`, we want to produce a + // predicate like `::T = X`. This is somewhat + // subtle in the event that `T` is defined in a supertrait of + // `SomeTrait`, because in that case we need to upcast. + // + // That is, consider this case: + // + // ``` + // trait SubTrait: SuperTrait { } + // trait SuperTrait { type T; } + // + // ... B: SubTrait ... + // ``` + // + // We want to produce `>::T == foo`. + + // Find any late-bound regions declared in `ty` that are not + // declared in the trait-ref. These are not well-formed. + // + // Example: + // + // for<'a> ::Item = &'a str // <-- 'a is bad + // for<'a> >::Output = &'a str // <-- 'a is ok + if let ConvertedBindingKind::Equality(ty) = binding.kind { + let late_bound_in_trait_ref = + tcx.collect_constrained_late_bound_regions(&trait_ref); + let late_bound_in_ty = + tcx.collect_referenced_late_bound_regions(&ty::Binder::bind(ty)); + debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref); + debug!("late_bound_in_ty = {:?}", late_bound_in_ty); + + // FIXME: point at the type params that don't have appropriate lifetimes: + // struct S1 Fn(&i32, &i32) -> &'a i32>(F); + // ---- ---- ^^^^^^^ + self.validate_late_bound_regions( + late_bound_in_trait_ref, + late_bound_in_ty, + |br_name| { + struct_span_err!( + tcx.sess, + binding.span, + E0582, + "binding for associated type `{}` references {}, \ + which does not appear in the trait input types", + binding.item_name, + br_name + ) + }, + ); + } + } + + let candidate = + if self.trait_defines_associated_type_named(trait_ref.def_id(), binding.item_name) { + // Simple case: X is defined in the current trait. + trait_ref + } else { + // Otherwise, we have to walk through the supertraits to find + // those that do. + self.one_bound_for_assoc_type( + || traits::supertraits(tcx, trait_ref), + || trait_ref.print_only_trait_path().to_string(), + binding.item_name, + path_span, + || match binding.kind { + ConvertedBindingKind::Equality(ty) => Some(ty.to_string()), + _ => None, + }, + )? + }; + + let (assoc_ident, def_scope) = + tcx.adjust_ident_and_get_scope(binding.item_name, candidate.def_id(), hir_ref_id); + + // We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead + // of calling `filter_by_name_and_kind`. + let assoc_ty = tcx + .associated_items(candidate.def_id()) + .filter_by_name_unhygienic(assoc_ident.name) + .find(|i| { + i.kind == ty::AssocKind::Type && i.ident.normalize_to_macros_2_0() == assoc_ident + }) + .expect("missing associated type"); + + if !assoc_ty.vis.is_accessible_from(def_scope, tcx) { + tcx.sess + .struct_span_err( + binding.span, + &format!("associated type `{}` is private", binding.item_name), + ) + .span_label(binding.span, "private associated type") + .emit(); + } + tcx.check_stability(assoc_ty.def_id, Some(hir_ref_id), binding.span); + + if !speculative { + dup_bindings + .entry(assoc_ty.def_id) + .and_modify(|prev_span| { + struct_span_err!( + self.tcx().sess, + binding.span, + E0719, + "the value of the associated type `{}` (from trait `{}`) \ + is already specified", + binding.item_name, + tcx.def_path_str(assoc_ty.container.id()) + ) + .span_label(binding.span, "re-bound here") + .span_label(*prev_span, format!("`{}` bound here first", binding.item_name)) + .emit(); + }) + .or_insert(binding.span); + } + + match binding.kind { + ConvertedBindingKind::Equality(ref ty) => { + // "Desugar" a constraint like `T: Iterator` this to + // the "projection predicate" for: + // + // `::Item = u32` + bounds.projection_bounds.push(( + candidate.map_bound(|trait_ref| ty::ProjectionPredicate { + projection_ty: ty::ProjectionTy::from_ref_and_name( + tcx, + trait_ref, + binding.item_name, + ), + ty, + }), + binding.span, + )); + } + ConvertedBindingKind::Constraint(ast_bounds) => { + // "Desugar" a constraint like `T: Iterator` to + // + // `::Item: Debug` + // + // Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty` + // parameter to have a skipped binder. + let param_ty = tcx.mk_projection(assoc_ty.def_id, candidate.skip_binder().substs); + self.add_bounds(param_ty, ast_bounds, bounds); + } + } + Ok(()) + } + + fn ast_path_to_ty( + &self, + span: Span, + did: DefId, + item_segment: &hir::PathSegment<'_>, + ) -> Ty<'tcx> { + let substs = self.ast_path_substs_for_ty(span, did, item_segment); + self.normalize_ty(span, self.tcx().at(span).type_of(did).subst(self.tcx(), substs)) + } + + fn conv_object_ty_poly_trait_ref( + &self, + span: Span, + trait_bounds: &[hir::PolyTraitRef<'_>], + lifetime: &hir::Lifetime, + borrowed: bool, + ) -> Ty<'tcx> { + let tcx = self.tcx(); + + let mut bounds = Bounds::default(); + let mut potential_assoc_types = Vec::new(); + let dummy_self = self.tcx().types.trait_object_dummy_self; + for trait_bound in trait_bounds.iter().rev() { + if let GenericArgCountResult { + correct: + Err(GenericArgCountMismatch { invalid_args: cur_potential_assoc_types, .. }), + .. + } = self.instantiate_poly_trait_ref( + trait_bound, + Constness::NotConst, + dummy_self, + &mut bounds, + ) { + potential_assoc_types.extend(cur_potential_assoc_types.into_iter()); + } + } + + // Expand trait aliases recursively and check that only one regular (non-auto) trait + // is used and no 'maybe' bounds are used. + let expanded_traits = + traits::expand_trait_aliases(tcx, bounds.trait_bounds.iter().map(|&(a, b, _)| (a, b))); + let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) = + expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id())); + if regular_traits.len() > 1 { + let first_trait = ®ular_traits[0]; + let additional_trait = ®ular_traits[1]; + let mut err = struct_span_err!( + tcx.sess, + additional_trait.bottom().1, + E0225, + "only auto traits can be used as additional traits in a trait object" + ); + additional_trait.label_with_exp_info( + &mut err, + "additional non-auto trait", + "additional use", + ); + first_trait.label_with_exp_info(&mut err, "first non-auto trait", "first use"); + err.help(&format!( + "consider creating a new trait with all of these as super-traits and using that \ + trait here instead: `trait NewTrait: {} {{}}`", + regular_traits + .iter() + .map(|t| t.trait_ref().print_only_trait_path().to_string()) + .collect::>() + .join(" + "), + )); + err.note( + "auto-traits like `Send` and `Sync` are traits that have special properties; \ + for more information on them, visit \ + ", + ); + err.emit(); + } + + if regular_traits.is_empty() && auto_traits.is_empty() { + struct_span_err!( + tcx.sess, + span, + E0224, + "at least one trait is required for an object type" + ) + .emit(); + return tcx.ty_error(); + } + + // Check that there are no gross object safety violations; + // most importantly, that the supertraits don't contain `Self`, + // to avoid ICEs. + for item in ®ular_traits { + let object_safety_violations = + astconv_object_safety_violations(tcx, item.trait_ref().def_id()); + if !object_safety_violations.is_empty() { + report_object_safety_error( + tcx, + span, + item.trait_ref().def_id(), + &object_safety_violations[..], + ) + .emit(); + return tcx.ty_error(); + } + } + + // Use a `BTreeSet` to keep output in a more consistent order. + let mut associated_types: FxHashMap> = FxHashMap::default(); + + let regular_traits_refs_spans = bounds + .trait_bounds + .into_iter() + .filter(|(trait_ref, _, _)| !tcx.trait_is_auto(trait_ref.def_id())); + + for (base_trait_ref, span, constness) in regular_traits_refs_spans { + assert_eq!(constness, Constness::NotConst); + + for obligation in traits::elaborate_trait_ref(tcx, base_trait_ref) { + debug!( + "conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", + obligation.predicate + ); + + match obligation.predicate.skip_binders() { + ty::PredicateAtom::Trait(pred, _) => { + let pred = ty::Binder::bind(pred); + associated_types.entry(span).or_default().extend( + tcx.associated_items(pred.def_id()) + .in_definition_order() + .filter(|item| item.kind == ty::AssocKind::Type) + .map(|item| item.def_id), + ); + } + ty::PredicateAtom::Projection(pred) => { + let pred = ty::Binder::bind(pred); + // A `Self` within the original bound will be substituted with a + // `trait_object_dummy_self`, so check for that. + let references_self = + pred.skip_binder().ty.walk().any(|arg| arg == dummy_self.into()); + + // If the projection output contains `Self`, force the user to + // elaborate it explicitly to avoid a lot of complexity. + // + // The "classicaly useful" case is the following: + // ``` + // trait MyTrait: FnMut() -> ::MyOutput { + // type MyOutput; + // } + // ``` + // + // Here, the user could theoretically write `dyn MyTrait`, + // but actually supporting that would "expand" to an infinitely-long type + // `fix $ τ → dyn MyTrait::MyOutput`. + // + // Instead, we force the user to write + // `dyn MyTrait`, which is uglier but works. See + // the discussion in #56288 for alternatives. + if !references_self { + // Include projections defined on supertraits. + bounds.projection_bounds.push((pred, span)); + } + } + _ => (), + } + } + } + + for (projection_bound, _) in &bounds.projection_bounds { + for def_ids in associated_types.values_mut() { + def_ids.remove(&projection_bound.projection_def_id()); + } + } + + self.complain_about_missing_associated_types( + associated_types, + potential_assoc_types, + trait_bounds, + ); + + // De-duplicate auto traits so that, e.g., `dyn Trait + Send + Send` is the same as + // `dyn Trait + Send`. + auto_traits.sort_by_key(|i| i.trait_ref().def_id()); + auto_traits.dedup_by_key(|i| i.trait_ref().def_id()); + debug!("regular_traits: {:?}", regular_traits); + debug!("auto_traits: {:?}", auto_traits); + + // Transform a `PolyTraitRef` into a `PolyExistentialTraitRef` by + // removing the dummy `Self` type (`trait_object_dummy_self`). + let trait_ref_to_existential = |trait_ref: ty::TraitRef<'tcx>| { + if trait_ref.self_ty() != dummy_self { + // FIXME: There appears to be a missing filter on top of `expand_trait_aliases`, + // which picks up non-supertraits where clauses - but also, the object safety + // completely ignores trait aliases, which could be object safety hazards. We + // `delay_span_bug` here to avoid an ICE in stable even when the feature is + // disabled. (#66420) + tcx.sess.delay_span_bug( + DUMMY_SP, + &format!( + "trait_ref_to_existential called on {:?} with non-dummy Self", + trait_ref, + ), + ); + } + ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref) + }; + + // Erase the `dummy_self` (`trait_object_dummy_self`) used above. + let existential_trait_refs = + regular_traits.iter().map(|i| i.trait_ref().map_bound(trait_ref_to_existential)); + let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| { + bound.map_bound(|b| { + let trait_ref = trait_ref_to_existential(b.projection_ty.trait_ref(tcx)); + ty::ExistentialProjection { + ty: b.ty, + item_def_id: b.projection_ty.item_def_id, + substs: trait_ref.substs, + } + }) + }); + + // Calling `skip_binder` is okay because the predicates are re-bound. + let regular_trait_predicates = existential_trait_refs + .map(|trait_ref| ty::ExistentialPredicate::Trait(trait_ref.skip_binder())); + let auto_trait_predicates = auto_traits + .into_iter() + .map(|trait_ref| ty::ExistentialPredicate::AutoTrait(trait_ref.trait_ref().def_id())); + let mut v = regular_trait_predicates + .chain(auto_trait_predicates) + .chain( + existential_projections + .map(|x| ty::ExistentialPredicate::Projection(x.skip_binder())), + ) + .collect::>(); + v.sort_by(|a, b| a.stable_cmp(tcx, b)); + v.dedup(); + let existential_predicates = ty::Binder::bind(tcx.mk_existential_predicates(v.into_iter())); + + // Use explicitly-specified region bound. + let region_bound = if !lifetime.is_elided() { + self.ast_region_to_region(lifetime, None) + } else { + self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| { + if tcx.named_region(lifetime.hir_id).is_some() { + self.ast_region_to_region(lifetime, None) + } else { + self.re_infer(None, span).unwrap_or_else(|| { + let mut err = struct_span_err!( + tcx.sess, + span, + E0228, + "the lifetime bound for this object type cannot be deduced \ + from context; please supply an explicit bound" + ); + if borrowed { + // We will have already emitted an error E0106 complaining about a + // missing named lifetime in `&dyn Trait`, so we elide this one. + err.delay_as_bug(); + } else { + err.emit(); + } + tcx.lifetimes.re_static + }) + } + }) + }; + debug!("region_bound: {:?}", region_bound); + + let ty = tcx.mk_dynamic(existential_predicates, region_bound); + debug!("trait_object_type: {:?}", ty); + ty + } + + fn report_ambiguous_associated_type( + &self, + span: Span, + type_str: &str, + trait_str: &str, + name: Symbol, + ) { + let mut err = struct_span_err!(self.tcx().sess, span, E0223, "ambiguous associated type"); + if let (Some(_), Ok(snippet)) = ( + self.tcx().sess.confused_type_with_std_module.borrow().get(&span), + self.tcx().sess.source_map().span_to_snippet(span), + ) { + err.span_suggestion( + span, + "you are looking for the module in `std`, not the primitive type", + format!("std::{}", snippet), + Applicability::MachineApplicable, + ); + } else { + err.span_suggestion( + span, + "use fully-qualified syntax", + format!("<{} as {}>::{}", type_str, trait_str, name), + Applicability::HasPlaceholders, + ); + } + err.emit(); + } + + // Search for a bound on a type parameter which includes the associated item + // given by `assoc_name`. `ty_param_def_id` is the `DefId` of the type parameter + // This function will fail if there are no suitable bounds or there is + // any ambiguity. + fn find_bound_for_assoc_item( + &self, + ty_param_def_id: LocalDefId, + assoc_name: Ident, + span: Span, + ) -> Result, ErrorReported> { + let tcx = self.tcx(); + + debug!( + "find_bound_for_assoc_item(ty_param_def_id={:?}, assoc_name={:?}, span={:?})", + ty_param_def_id, assoc_name, span, + ); + + let predicates = + &self.get_type_parameter_bounds(span, ty_param_def_id.to_def_id()).predicates; + + debug!("find_bound_for_assoc_item: predicates={:#?}", predicates); + + let param_hir_id = tcx.hir().local_def_id_to_hir_id(ty_param_def_id); + let param_name = tcx.hir().ty_param_name(param_hir_id); + self.one_bound_for_assoc_type( + || { + traits::transitive_bounds( + tcx, + predicates.iter().filter_map(|(p, _)| p.to_opt_poly_trait_ref()), + ) + }, + || param_name.to_string(), + assoc_name, + span, + || None, + ) + } + + // Checks that `bounds` contains exactly one element and reports appropriate + // errors otherwise. + fn one_bound_for_assoc_type( + &self, + all_candidates: impl Fn() -> I, + ty_param_name: impl Fn() -> String, + assoc_name: Ident, + span: Span, + is_equality: impl Fn() -> Option, + ) -> Result, ErrorReported> + where + I: Iterator>, + { + let mut matching_candidates = all_candidates() + .filter(|r| self.trait_defines_associated_type_named(r.def_id(), assoc_name)); + + let bound = match matching_candidates.next() { + Some(bound) => bound, + None => { + self.complain_about_assoc_type_not_found( + all_candidates, + &ty_param_name(), + assoc_name, + span, + ); + return Err(ErrorReported); + } + }; + + debug!("one_bound_for_assoc_type: bound = {:?}", bound); + + if let Some(bound2) = matching_candidates.next() { + debug!("one_bound_for_assoc_type: bound2 = {:?}", bound2); + + let is_equality = is_equality(); + let bounds = iter::once(bound).chain(iter::once(bound2)).chain(matching_candidates); + let mut err = if is_equality.is_some() { + // More specific Error Index entry. + struct_span_err!( + self.tcx().sess, + span, + E0222, + "ambiguous associated type `{}` in bounds of `{}`", + assoc_name, + ty_param_name() + ) + } else { + struct_span_err!( + self.tcx().sess, + span, + E0221, + "ambiguous associated type `{}` in bounds of `{}`", + assoc_name, + ty_param_name() + ) + }; + err.span_label(span, format!("ambiguous associated type `{}`", assoc_name)); + + let mut where_bounds = vec![]; + for bound in bounds { + let bound_id = bound.def_id(); + let bound_span = self + .tcx() + .associated_items(bound_id) + .find_by_name_and_kind(self.tcx(), assoc_name, ty::AssocKind::Type, bound_id) + .and_then(|item| self.tcx().hir().span_if_local(item.def_id)); + + if let Some(bound_span) = bound_span { + err.span_label( + bound_span, + format!( + "ambiguous `{}` from `{}`", + assoc_name, + bound.print_only_trait_path(), + ), + ); + if let Some(constraint) = &is_equality { + where_bounds.push(format!( + " T: {trait}::{assoc} = {constraint}", + trait=bound.print_only_trait_path(), + assoc=assoc_name, + constraint=constraint, + )); + } else { + err.span_suggestion( + span, + "use fully qualified syntax to disambiguate", + format!( + "<{} as {}>::{}", + ty_param_name(), + bound.print_only_trait_path(), + assoc_name, + ), + Applicability::MaybeIncorrect, + ); + } + } else { + err.note(&format!( + "associated type `{}` could derive from `{}`", + ty_param_name(), + bound.print_only_trait_path(), + )); + } + } + if !where_bounds.is_empty() { + err.help(&format!( + "consider introducing a new type parameter `T` and adding `where` constraints:\ + \n where\n T: {},\n{}", + ty_param_name(), + where_bounds.join(",\n"), + )); + } + err.emit(); + if !where_bounds.is_empty() { + return Err(ErrorReported); + } + } + Ok(bound) + } + + // Create a type from a path to an associated type. + // For a path `A::B::C::D`, `qself_ty` and `qself_def` are the type and def for `A::B::C` + // and item_segment is the path segment for `D`. We return a type and a def for + // the whole path. + // Will fail except for `T::A` and `Self::A`; i.e., if `qself_ty`/`qself_def` are not a type + // parameter or `Self`. + pub fn associated_path_to_ty( + &self, + hir_ref_id: hir::HirId, + span: Span, + qself_ty: Ty<'tcx>, + qself_res: Res, + assoc_segment: &hir::PathSegment<'_>, + permit_variants: bool, + ) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorReported> { + let tcx = self.tcx(); + let assoc_ident = assoc_segment.ident; + + debug!("associated_path_to_ty: {:?}::{}", qself_ty, assoc_ident); + + // Check if we have an enum variant. + let mut variant_resolution = None; + if let ty::Adt(adt_def, _) = qself_ty.kind { + if adt_def.is_enum() { + let variant_def = adt_def + .variants + .iter() + .find(|vd| tcx.hygienic_eq(assoc_ident, vd.ident, adt_def.did)); + if let Some(variant_def) = variant_def { + if permit_variants { + tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span); + self.prohibit_generics(slice::from_ref(assoc_segment)); + return Ok((qself_ty, DefKind::Variant, variant_def.def_id)); + } else { + variant_resolution = Some(variant_def.def_id); + } + } + } + } + + // Find the type of the associated item, and the trait where the associated + // item is declared. + let bound = match (&qself_ty.kind, qself_res) { + (_, Res::SelfTy(Some(_), Some(impl_def_id))) => { + // `Self` in an impl of a trait -- we have a concrete self type and a + // trait reference. + let trait_ref = match tcx.impl_trait_ref(impl_def_id) { + Some(trait_ref) => trait_ref, + None => { + // A cycle error occurred, most likely. + return Err(ErrorReported); + } + }; + + self.one_bound_for_assoc_type( + || traits::supertraits(tcx, ty::Binder::bind(trait_ref)), + || "Self".to_string(), + assoc_ident, + span, + || None, + )? + } + ( + &ty::Param(_), + Res::SelfTy(Some(param_did), None) | Res::Def(DefKind::TyParam, param_did), + ) => self.find_bound_for_assoc_item(param_did.expect_local(), assoc_ident, span)?, + _ => { + if variant_resolution.is_some() { + // Variant in type position + let msg = format!("expected type, found variant `{}`", assoc_ident); + tcx.sess.span_err(span, &msg); + } else if qself_ty.is_enum() { + let mut err = struct_span_err!( + tcx.sess, + assoc_ident.span, + E0599, + "no variant named `{}` found for enum `{}`", + assoc_ident, + qself_ty, + ); + + let adt_def = qself_ty.ty_adt_def().expect("enum is not an ADT"); + if let Some(suggested_name) = find_best_match_for_name( + adt_def.variants.iter().map(|variant| &variant.ident.name), + assoc_ident.name, + None, + ) { + err.span_suggestion( + assoc_ident.span, + "there is a variant with a similar name", + suggested_name.to_string(), + Applicability::MaybeIncorrect, + ); + } else { + err.span_label( + assoc_ident.span, + format!("variant not found in `{}`", qself_ty), + ); + } + + if let Some(sp) = tcx.hir().span_if_local(adt_def.did) { + let sp = tcx.sess.source_map().guess_head_span(sp); + err.span_label(sp, format!("variant `{}` not found here", assoc_ident)); + } + + err.emit(); + } else if !qself_ty.references_error() { + // Don't print `TyErr` to the user. + self.report_ambiguous_associated_type( + span, + &qself_ty.to_string(), + "Trait", + assoc_ident.name, + ); + } + return Err(ErrorReported); + } + }; + + let trait_did = bound.def_id(); + let (assoc_ident, def_scope) = + tcx.adjust_ident_and_get_scope(assoc_ident, trait_did, hir_ref_id); + + // We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead + // of calling `filter_by_name_and_kind`. + let item = tcx + .associated_items(trait_did) + .in_definition_order() + .find(|i| { + i.kind.namespace() == Namespace::TypeNS + && i.ident.normalize_to_macros_2_0() == assoc_ident + }) + .expect("missing associated type"); + + let ty = self.projected_ty_from_poly_trait_ref(span, item.def_id, assoc_segment, bound); + let ty = self.normalize_ty(span, ty); + + let kind = DefKind::AssocTy; + if !item.vis.is_accessible_from(def_scope, tcx) { + let kind = kind.descr(item.def_id); + let msg = format!("{} `{}` is private", kind, assoc_ident); + tcx.sess + .struct_span_err(span, &msg) + .span_label(span, &format!("private {}", kind)) + .emit(); + } + tcx.check_stability(item.def_id, Some(hir_ref_id), span); + + if let Some(variant_def_id) = variant_resolution { + tcx.struct_span_lint_hir(AMBIGUOUS_ASSOCIATED_ITEMS, hir_ref_id, span, |lint| { + let mut err = lint.build("ambiguous associated item"); + let mut could_refer_to = |kind: DefKind, def_id, also| { + let note_msg = format!( + "`{}` could{} refer to the {} defined here", + assoc_ident, + also, + kind.descr(def_id) + ); + err.span_note(tcx.def_span(def_id), ¬e_msg); + }; + + could_refer_to(DefKind::Variant, variant_def_id, ""); + could_refer_to(kind, item.def_id, " also"); + + err.span_suggestion( + span, + "use fully-qualified syntax", + format!("<{} as {}>::{}", qself_ty, tcx.item_name(trait_did), assoc_ident), + Applicability::MachineApplicable, + ); + + err.emit(); + }); + } + Ok((ty, kind, item.def_id)) + } + + fn qpath_to_ty( + &self, + span: Span, + opt_self_ty: Option>, + item_def_id: DefId, + trait_segment: &hir::PathSegment<'_>, + item_segment: &hir::PathSegment<'_>, + ) -> Ty<'tcx> { + let tcx = self.tcx(); + + let trait_def_id = tcx.parent(item_def_id).unwrap(); + + debug!("qpath_to_ty: trait_def_id={:?}", trait_def_id); + + let self_ty = if let Some(ty) = opt_self_ty { + ty + } else { + let path_str = tcx.def_path_str(trait_def_id); + + let def_id = self.item_def_id(); + + debug!("qpath_to_ty: self.item_def_id()={:?}", def_id); + + let parent_def_id = def_id + .and_then(|def_id| { + def_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id)) + }) + .map(|hir_id| tcx.hir().get_parent_did(hir_id).to_def_id()); + + debug!("qpath_to_ty: parent_def_id={:?}", parent_def_id); + + // If the trait in segment is the same as the trait defining the item, + // use the `` syntax in the error. + let is_part_of_self_trait_constraints = def_id == Some(trait_def_id); + let is_part_of_fn_in_self_trait = parent_def_id == Some(trait_def_id); + + let type_name = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait { + "Self" + } else { + "Type" + }; + + self.report_ambiguous_associated_type( + span, + type_name, + &path_str, + item_segment.ident.name, + ); + return tcx.ty_error(); + }; + + debug!("qpath_to_ty: self_type={:?}", self_ty); + + let trait_ref = self.ast_path_to_mono_trait_ref(span, trait_def_id, self_ty, trait_segment); + + let item_substs = self.create_substs_for_associated_item( + tcx, + span, + item_def_id, + item_segment, + trait_ref.substs, + ); + + debug!("qpath_to_ty: trait_ref={:?}", trait_ref); + + self.normalize_ty(span, tcx.mk_projection(item_def_id, item_substs)) + } + + pub fn prohibit_generics<'a, T: IntoIterator>>( + &self, + segments: T, + ) -> bool { + let mut has_err = false; + for segment in segments { + let (mut err_for_lt, mut err_for_ty, mut err_for_ct) = (false, false, false); + for arg in segment.generic_args().args { + let (span, kind) = match arg { + hir::GenericArg::Lifetime(lt) => { + if err_for_lt { + continue; + } + err_for_lt = true; + has_err = true; + (lt.span, "lifetime") + } + hir::GenericArg::Type(ty) => { + if err_for_ty { + continue; + } + err_for_ty = true; + has_err = true; + (ty.span, "type") + } + hir::GenericArg::Const(ct) => { + if err_for_ct { + continue; + } + err_for_ct = true; + has_err = true; + (ct.span, "const") + } + }; + let mut err = struct_span_err!( + self.tcx().sess, + span, + E0109, + "{} arguments are not allowed for this type", + kind, + ); + err.span_label(span, format!("{} argument not allowed", kind)); + err.emit(); + if err_for_lt && err_for_ty && err_for_ct { + break; + } + } + + // Only emit the first error to avoid overloading the user with error messages. + if let [binding, ..] = segment.generic_args().bindings { + has_err = true; + Self::prohibit_assoc_ty_binding(self.tcx(), binding.span); + } + } + has_err + } + + // FIXME(eddyb, varkor) handle type paths here too, not just value ones. + pub fn def_ids_for_value_path_segments( + &self, + segments: &[hir::PathSegment<'_>], + self_ty: Option>, + kind: DefKind, + def_id: DefId, + ) -> Vec { + // We need to extract the type parameters supplied by the user in + // the path `path`. Due to the current setup, this is a bit of a + // tricky-process; the problem is that resolve only tells us the + // end-point of the path resolution, and not the intermediate steps. + // Luckily, we can (at least for now) deduce the intermediate steps + // just from the end-point. + // + // There are basically five cases to consider: + // + // 1. Reference to a constructor of a struct: + // + // struct Foo(...) + // + // In this case, the parameters are declared in the type space. + // + // 2. Reference to a constructor of an enum variant: + // + // enum E { Foo(...) } + // + // In this case, the parameters are defined in the type space, + // but may be specified either on the type or the variant. + // + // 3. Reference to a fn item or a free constant: + // + // fn foo() { } + // + // In this case, the path will again always have the form + // `a::b::foo::` where only the final segment should have + // type parameters. However, in this case, those parameters are + // declared on a value, and hence are in the `FnSpace`. + // + // 4. Reference to a method or an associated constant: + // + // impl SomeStruct { + // fn foo(...) + // } + // + // Here we can have a path like + // `a::b::SomeStruct::::foo::`, in which case parameters + // may appear in two places. The penultimate segment, + // `SomeStruct::`, contains parameters in TypeSpace, and the + // final segment, `foo::` contains parameters in fn space. + // + // The first step then is to categorize the segments appropriately. + + let tcx = self.tcx(); + + assert!(!segments.is_empty()); + let last = segments.len() - 1; + + let mut path_segs = vec![]; + + match kind { + // Case 1. Reference to a struct constructor. + DefKind::Ctor(CtorOf::Struct, ..) => { + // Everything but the final segment should have no + // parameters at all. + let generics = tcx.generics_of(def_id); + // Variant and struct constructors use the + // generics of their parent type definition. + let generics_def_id = generics.parent.unwrap_or(def_id); + path_segs.push(PathSeg(generics_def_id, last)); + } + + // Case 2. Reference to a variant constructor. + DefKind::Ctor(CtorOf::Variant, ..) | DefKind::Variant => { + let adt_def = self_ty.map(|t| t.ty_adt_def().unwrap()); + let (generics_def_id, index) = if let Some(adt_def) = adt_def { + debug_assert!(adt_def.is_enum()); + (adt_def.did, last) + } else if last >= 1 && segments[last - 1].args.is_some() { + // Everything but the penultimate segment should have no + // parameters at all. + let mut def_id = def_id; + + // `DefKind::Ctor` -> `DefKind::Variant` + if let DefKind::Ctor(..) = kind { + def_id = tcx.parent(def_id).unwrap() + } + + // `DefKind::Variant` -> `DefKind::Enum` + let enum_def_id = tcx.parent(def_id).unwrap(); + (enum_def_id, last - 1) + } else { + // FIXME: lint here recommending `Enum::<...>::Variant` form + // instead of `Enum::Variant::<...>` form. + + // Everything but the final segment should have no + // parameters at all. + let generics = tcx.generics_of(def_id); + // Variant and struct constructors use the + // generics of their parent type definition. + (generics.parent.unwrap_or(def_id), last) + }; + path_segs.push(PathSeg(generics_def_id, index)); + } + + // Case 3. Reference to a top-level value. + DefKind::Fn | DefKind::Const | DefKind::ConstParam | DefKind::Static => { + path_segs.push(PathSeg(def_id, last)); + } + + // Case 4. Reference to a method or associated const. + DefKind::AssocFn | DefKind::AssocConst => { + if segments.len() >= 2 { + let generics = tcx.generics_of(def_id); + path_segs.push(PathSeg(generics.parent.unwrap(), last - 1)); + } + path_segs.push(PathSeg(def_id, last)); + } + + kind => bug!("unexpected definition kind {:?} for {:?}", kind, def_id), + } + + debug!("path_segs = {:?}", path_segs); + + path_segs + } + + // Check a type `Path` and convert it to a `Ty`. + pub fn res_to_ty( + &self, + opt_self_ty: Option>, + path: &hir::Path<'_>, + permit_variants: bool, + ) -> Ty<'tcx> { + let tcx = self.tcx(); + + debug!( + "res_to_ty(res={:?}, opt_self_ty={:?}, path_segments={:?})", + path.res, opt_self_ty, path.segments + ); + + let span = path.span; + match path.res { + Res::Def(DefKind::OpaqueTy, did) => { + // Check for desugared `impl Trait`. + assert!(ty::is_impl_trait_defn(tcx, did).is_none()); + let item_segment = path.segments.split_last().unwrap(); + self.prohibit_generics(item_segment.1); + let substs = self.ast_path_substs_for_ty(span, did, item_segment.0); + self.normalize_ty(span, tcx.mk_opaque(did, substs)) + } + Res::Def( + DefKind::Enum + | DefKind::TyAlias + | DefKind::Struct + | DefKind::Union + | DefKind::ForeignTy, + did, + ) => { + assert_eq!(opt_self_ty, None); + self.prohibit_generics(path.segments.split_last().unwrap().1); + self.ast_path_to_ty(span, did, path.segments.last().unwrap()) + } + Res::Def(kind @ DefKind::Variant, def_id) if permit_variants => { + // Convert "variant type" as if it were a real type. + // The resulting `Ty` is type of the variant's enum for now. + assert_eq!(opt_self_ty, None); + + let path_segs = + self.def_ids_for_value_path_segments(&path.segments, None, kind, def_id); + let generic_segs: FxHashSet<_> = + path_segs.iter().map(|PathSeg(_, index)| index).collect(); + self.prohibit_generics(path.segments.iter().enumerate().filter_map( + |(index, seg)| { + if !generic_segs.contains(&index) { Some(seg) } else { None } + }, + )); + + let PathSeg(def_id, index) = path_segs.last().unwrap(); + self.ast_path_to_ty(span, *def_id, &path.segments[*index]) + } + Res::Def(DefKind::TyParam, def_id) => { + assert_eq!(opt_self_ty, None); + self.prohibit_generics(path.segments); + + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + let item_id = tcx.hir().get_parent_node(hir_id); + let item_def_id = tcx.hir().local_def_id(item_id); + let generics = tcx.generics_of(item_def_id); + let index = generics.param_def_id_to_index[&def_id]; + tcx.mk_ty_param(index, tcx.hir().name(hir_id)) + } + Res::SelfTy(Some(_), None) => { + // `Self` in trait or type alias. + assert_eq!(opt_self_ty, None); + self.prohibit_generics(path.segments); + tcx.types.self_param + } + Res::SelfTy(_, Some(def_id)) => { + // `Self` in impl (we know the concrete type). + assert_eq!(opt_self_ty, None); + self.prohibit_generics(path.segments); + // Try to evaluate any array length constants. + self.normalize_ty(span, tcx.at(span).type_of(def_id)) + } + Res::Def(DefKind::AssocTy, def_id) => { + debug_assert!(path.segments.len() >= 2); + self.prohibit_generics(&path.segments[..path.segments.len() - 2]); + self.qpath_to_ty( + span, + opt_self_ty, + def_id, + &path.segments[path.segments.len() - 2], + path.segments.last().unwrap(), + ) + } + Res::PrimTy(prim_ty) => { + assert_eq!(opt_self_ty, None); + self.prohibit_generics(path.segments); + match prim_ty { + hir::PrimTy::Bool => tcx.types.bool, + hir::PrimTy::Char => tcx.types.char, + hir::PrimTy::Int(it) => tcx.mk_mach_int(it), + hir::PrimTy::Uint(uit) => tcx.mk_mach_uint(uit), + hir::PrimTy::Float(ft) => tcx.mk_mach_float(ft), + hir::PrimTy::Str => tcx.types.str_, + } + } + Res::Err => { + self.set_tainted_by_errors(); + self.tcx().ty_error() + } + _ => span_bug!(span, "unexpected resolution: {:?}", path.res), + } + } + + /// Parses the programmer's textual representation of a type into our + /// internal notion of a type. + pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> { + self.ast_ty_to_ty_inner(ast_ty, false) + } + + /// Turns a `hir::Ty` into a `Ty`. For diagnostics' purposes we keep track of whether trait + /// objects are borrowed like `&dyn Trait` to avoid emitting redundant errors. + fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool) -> Ty<'tcx> { + debug!("ast_ty_to_ty(id={:?}, ast_ty={:?} ty_ty={:?})", ast_ty.hir_id, ast_ty, ast_ty.kind); + + let tcx = self.tcx(); + + let result_ty = match ast_ty.kind { + hir::TyKind::Slice(ref ty) => tcx.mk_slice(self.ast_ty_to_ty(&ty)), + hir::TyKind::Ptr(ref mt) => { + tcx.mk_ptr(ty::TypeAndMut { ty: self.ast_ty_to_ty(&mt.ty), mutbl: mt.mutbl }) + } + hir::TyKind::Rptr(ref region, ref mt) => { + let r = self.ast_region_to_region(region, None); + debug!("ast_ty_to_ty: r={:?}", r); + let t = self.ast_ty_to_ty_inner(&mt.ty, true); + tcx.mk_ref(r, ty::TypeAndMut { ty: t, mutbl: mt.mutbl }) + } + hir::TyKind::Never => tcx.types.never, + hir::TyKind::Tup(ref fields) => { + tcx.mk_tup(fields.iter().map(|t| self.ast_ty_to_ty(&t))) + } + hir::TyKind::BareFn(ref bf) => { + require_c_abi_if_c_variadic(tcx, &bf.decl, bf.abi, ast_ty.span); + tcx.mk_fn_ptr(self.ty_of_fn( + bf.unsafety, + bf.abi, + &bf.decl, + &hir::Generics::empty(), + None, + )) + } + hir::TyKind::TraitObject(ref bounds, ref lifetime) => { + self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed) + } + hir::TyKind::Path(hir::QPath::Resolved(ref maybe_qself, ref path)) => { + debug!("ast_ty_to_ty: maybe_qself={:?} path={:?}", maybe_qself, path); + let opt_self_ty = maybe_qself.as_ref().map(|qself| self.ast_ty_to_ty(qself)); + self.res_to_ty(opt_self_ty, path, false) + } + hir::TyKind::OpaqueDef(item_id, ref lifetimes) => { + let opaque_ty = tcx.hir().expect_item(item_id.id); + let def_id = tcx.hir().local_def_id(item_id.id).to_def_id(); + + match opaque_ty.kind { + hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn, .. }) => { + self.impl_trait_ty_to_ty(def_id, lifetimes, impl_trait_fn.is_some()) + } + ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i), + } + } + hir::TyKind::Path(hir::QPath::TypeRelative(ref qself, ref segment)) => { + debug!("ast_ty_to_ty: qself={:?} segment={:?}", qself, segment); + let ty = self.ast_ty_to_ty(qself); + + let res = if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = qself.kind { + path.res + } else { + Res::Err + }; + self.associated_path_to_ty(ast_ty.hir_id, ast_ty.span, ty, res, segment, false) + .map(|(ty, _, _)| ty) + .unwrap_or_else(|_| tcx.ty_error()) + } + hir::TyKind::Path(hir::QPath::LangItem(lang_item, span)) => { + let def_id = tcx.require_lang_item(lang_item, Some(span)); + let (substs, _, _) = self.create_substs_for_ast_path( + span, + def_id, + &[], + &GenericArgs::none(), + true, + None, + ); + self.normalize_ty(span, tcx.at(span).type_of(def_id).subst(tcx, substs)) + } + hir::TyKind::Array(ref ty, ref length) => { + let length_def_id = tcx.hir().local_def_id(length.hir_id); + let length = ty::Const::from_anon_const(tcx, length_def_id); + let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(&ty), length)); + self.normalize_ty(ast_ty.span, array_ty) + } + hir::TyKind::Typeof(ref _e) => { + struct_span_err!( + tcx.sess, + ast_ty.span, + E0516, + "`typeof` is a reserved keyword but unimplemented" + ) + .span_label(ast_ty.span, "reserved keyword") + .emit(); + + tcx.ty_error() + } + hir::TyKind::Infer => { + // Infer also appears as the type of arguments or return + // values in a ExprKind::Closure, or as + // the type of local variables. Both of these cases are + // handled specially and will not descend into this routine. + self.ty_infer(None, ast_ty.span) + } + hir::TyKind::Err => tcx.ty_error(), + }; + + debug!("ast_ty_to_ty: result_ty={:?}", result_ty); + + self.record_ty(ast_ty.hir_id, result_ty, ast_ty.span); + result_ty + } + + pub fn impl_trait_ty_to_ty( + &self, + def_id: DefId, + lifetimes: &[hir::GenericArg<'_>], + replace_parent_lifetimes: bool, + ) -> Ty<'tcx> { + debug!("impl_trait_ty_to_ty(def_id={:?}, lifetimes={:?})", def_id, lifetimes); + let tcx = self.tcx(); + + let generics = tcx.generics_of(def_id); + + debug!("impl_trait_ty_to_ty: generics={:?}", generics); + let substs = InternalSubsts::for_item(tcx, def_id, |param, _| { + if let Some(i) = (param.index as usize).checked_sub(generics.parent_count) { + // Our own parameters are the resolved lifetimes. + match param.kind { + GenericParamDefKind::Lifetime => { + if let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] { + self.ast_region_to_region(lifetime, None).into() + } else { + bug!() + } + } + _ => bug!(), + } + } else { + match param.kind { + // For RPIT (return position impl trait), only lifetimes + // mentioned in the impl Trait predicate are captured by + // the opaque type, so the lifetime parameters from the + // parent item need to be replaced with `'static`. + // + // For `impl Trait` in the types of statics, constants, + // locals and type aliases. These capture all parent + // lifetimes, so they can use their identity subst. + GenericParamDefKind::Lifetime if replace_parent_lifetimes => { + tcx.lifetimes.re_static.into() + } + _ => tcx.mk_param_from_def(param), + } + } + }); + debug!("impl_trait_ty_to_ty: substs={:?}", substs); + + let ty = tcx.mk_opaque(def_id, substs); + debug!("impl_trait_ty_to_ty: {}", ty); + ty + } + + pub fn ty_of_arg(&self, ty: &hir::Ty<'_>, expected_ty: Option>) -> Ty<'tcx> { + match ty.kind { + hir::TyKind::Infer if expected_ty.is_some() => { + self.record_ty(ty.hir_id, expected_ty.unwrap(), ty.span); + expected_ty.unwrap() + } + _ => self.ast_ty_to_ty(ty), + } + } + + pub fn ty_of_fn( + &self, + unsafety: hir::Unsafety, + abi: abi::Abi, + decl: &hir::FnDecl<'_>, + generics: &hir::Generics<'_>, + ident_span: Option, + ) -> ty::PolyFnSig<'tcx> { + debug!("ty_of_fn"); + + let tcx = self.tcx(); + + // We proactively collect all the inferred type params to emit a single error per fn def. + let mut visitor = PlaceholderHirTyCollector::default(); + for ty in decl.inputs { + visitor.visit_ty(ty); + } + walk_generics(&mut visitor, generics); + + let input_tys = decl.inputs.iter().map(|a| self.ty_of_arg(a, None)); + let output_ty = match decl.output { + hir::FnRetTy::Return(ref output) => { + visitor.visit_ty(output); + self.ast_ty_to_ty(output) + } + hir::FnRetTy::DefaultReturn(..) => tcx.mk_unit(), + }; + + debug!("ty_of_fn: output_ty={:?}", output_ty); + + let bare_fn_ty = + ty::Binder::bind(tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, unsafety, abi)); + + if !self.allow_ty_infer() { + // We always collect the spans for placeholder types when evaluating `fn`s, but we + // only want to emit an error complaining about them if infer types (`_`) are not + // allowed. `allow_ty_infer` gates this behavior. We check for the presence of + // `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`. + crate::collect::placeholder_type_error( + tcx, + ident_span.map(|sp| sp.shrink_to_hi()), + &generics.params[..], + visitor.0, + true, + ); + } + + // Find any late-bound regions declared in return type that do + // not appear in the arguments. These are not well-formed. + // + // Example: + // for<'a> fn() -> &'a str <-- 'a is bad + // for<'a> fn(&'a String) -> &'a str <-- 'a is ok + let inputs = bare_fn_ty.inputs(); + let late_bound_in_args = + tcx.collect_constrained_late_bound_regions(&inputs.map_bound(|i| i.to_owned())); + let output = bare_fn_ty.output(); + let late_bound_in_ret = tcx.collect_referenced_late_bound_regions(&output); + + self.validate_late_bound_regions(late_bound_in_args, late_bound_in_ret, |br_name| { + struct_span_err!( + tcx.sess, + decl.output.span(), + E0581, + "return type references {}, which is not constrained by the fn input types", + br_name + ) + }); + + bare_fn_ty + } + + fn validate_late_bound_regions( + &self, + constrained_regions: FxHashSet, + referenced_regions: FxHashSet, + generate_err: impl Fn(&str) -> rustc_errors::DiagnosticBuilder<'tcx>, + ) { + for br in referenced_regions.difference(&constrained_regions) { + let br_name = match *br { + ty::BrNamed(_, name) => format!("lifetime `{}`", name), + ty::BrAnon(_) | ty::BrEnv => "an anonymous lifetime".to_string(), + }; + + let mut err = generate_err(&br_name); + + if let ty::BrAnon(_) = *br { + // The only way for an anonymous lifetime to wind up + // in the return type but **also** be unconstrained is + // if it only appears in "associated types" in the + // input. See #47511 and #62200 for examples. In this case, + // though we can easily give a hint that ought to be + // relevant. + err.note( + "lifetimes appearing in an associated type are not considered constrained", + ); + } + + err.emit(); + } + } + + /// Given the bounds on an object, determines what single region bound (if any) we can + /// use to summarize this type. The basic idea is that we will use the bound the user + /// provided, if they provided one, and otherwise search the supertypes of trait bounds + /// for region bounds. It may be that we can derive no bound at all, in which case + /// we return `None`. + fn compute_object_lifetime_bound( + &self, + span: Span, + existential_predicates: ty::Binder<&'tcx ty::List>>, + ) -> Option> // if None, use the default + { + let tcx = self.tcx(); + + debug!("compute_opt_region_bound(existential_predicates={:?})", existential_predicates); + + // No explicit region bound specified. Therefore, examine trait + // bounds and see if we can derive region bounds from those. + let derived_region_bounds = object_region_bounds(tcx, existential_predicates); + + // If there are no derived region bounds, then report back that we + // can find no region bound. The caller will use the default. + if derived_region_bounds.is_empty() { + return None; + } + + // If any of the derived region bounds are 'static, that is always + // the best choice. + if derived_region_bounds.iter().any(|&r| ty::ReStatic == *r) { + return Some(tcx.lifetimes.re_static); + } + + // Determine whether there is exactly one unique region in the set + // of derived region bounds. If so, use that. Otherwise, report an + // error. + let r = derived_region_bounds[0]; + if derived_region_bounds[1..].iter().any(|r1| r != *r1) { + struct_span_err!( + tcx.sess, + span, + E0227, + "ambiguous lifetime bound, explicit lifetime bound required" + ) + .emit(); + } + Some(r) + } +} diff --git a/src/librustc_typeck/bounds.rs b/src/librustc_typeck/bounds.rs new file mode 100644 index 00000000000..63295f5faac --- /dev/null +++ b/src/librustc_typeck/bounds.rs @@ -0,0 +1,93 @@ +//! Bounds are restrictions applied to some types after they've been converted into the +//! `ty` form from the HIR. + +use rustc_hir::Constness; +use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness}; +use rustc_span::Span; + +/// Collects together a list of type bounds. These lists of bounds occur in many places +/// in Rust's syntax: +/// +/// ```text +/// trait Foo: Bar + Baz { } +/// ^^^^^^^^^ supertrait list bounding the `Self` type parameter +/// +/// fn foo() { } +/// ^^^^^^^^^ bounding the type parameter `T` +/// +/// impl dyn Bar + Baz +/// ^^^^^^^^^ bounding the forgotten dynamic type +/// ``` +/// +/// Our representation is a bit mixed here -- in some cases, we +/// include the self type (e.g., `trait_bounds`) but in others we do not +#[derive(Default, PartialEq, Eq, Clone, Debug)] +pub struct Bounds<'tcx> { + /// A list of region bounds on the (implicit) self type. So if you + /// had `T: 'a + 'b` this might would be a list `['a, 'b]` (but + /// the `T` is not explicitly included). + pub region_bounds: Vec<(ty::Region<'tcx>, Span)>, + + /// A list of trait bounds. So if you had `T: Debug` this would be + /// `T: Debug`. Note that the self-type is explicit here. + pub trait_bounds: Vec<(ty::PolyTraitRef<'tcx>, Span, Constness)>, + + /// A list of projection equality bounds. So if you had `T: + /// Iterator` this would include `::Item => u32`. Note that the self-type is explicit + /// here. + pub projection_bounds: Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>, + + /// `Some` if there is *no* `?Sized` predicate. The `span` + /// is the location in the source of the `T` declaration which can + /// be cited as the source of the `T: Sized` requirement. + pub implicitly_sized: Option, +} + +impl<'tcx> Bounds<'tcx> { + /// Converts a bounds list into a flat set of predicates (like + /// where-clauses). Because some of our bounds listings (e.g., + /// regions) don't include the self-type, you must supply the + /// self-type here (the `param_ty` parameter). + pub fn predicates( + &self, + tcx: TyCtxt<'tcx>, + param_ty: Ty<'tcx>, + ) -> Vec<(ty::Predicate<'tcx>, Span)> { + // If it could be sized, and is, add the `Sized` predicate. + let sized_predicate = self.implicitly_sized.and_then(|span| { + tcx.lang_items().sized_trait().map(|sized| { + let trait_ref = ty::Binder::bind(ty::TraitRef { + def_id: sized, + substs: tcx.mk_substs_trait(param_ty, &[]), + }); + (trait_ref.without_const().to_predicate(tcx), span) + }) + }); + + sized_predicate + .into_iter() + .chain( + self.region_bounds + .iter() + .map(|&(region_bound, span)| { + // Account for the binder being introduced below; no need to shift `param_ty` + // because, at present at least, it either only refers to early-bound regions, + // or it's a generic associated type that deliberately has escaping bound vars. + let region_bound = ty::fold::shift_region(tcx, region_bound, 1); + let outlives = ty::OutlivesPredicate(param_ty, region_bound); + (ty::Binder::bind(outlives).to_predicate(tcx), span) + }) + .chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| { + let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx); + (predicate, span) + })) + .chain( + self.projection_bounds + .iter() + .map(|&(projection, span)| (projection.to_predicate(tcx), span)), + ), + ) + .collect() + } +} diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 9e23f5df3c6..40088bc0690 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -124,11 +124,10 @@ pub fn check_match( } } } else { - let arm_span = if let hir::ExprKind::Block(blk, _) = &arm.body.kind { - // Point at the block expr instead of the entire block - blk.expr.as_ref().map(|e| e.span).unwrap_or(arm.body.span) + let (arm_span, semi_span) = if let hir::ExprKind::Block(blk, _) = &arm.body.kind { + self.find_block_span(blk, prior_arm_ty) } else { - arm.body.span + (arm.body.span, None) }; let (span, code) = match i { // The reason for the first arm to fail is not that the match arms diverge, @@ -138,6 +137,7 @@ pub fn check_match( expr.span, ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { arm_span, + semi_span, source: match_src, prior_arms: other_arms.clone(), last_ty: prior_arm_ty.unwrap(), @@ -295,14 +295,9 @@ fn if_cause( let mut remove_semicolon = None; let error_sp = if let ExprKind::Block(block, _) = &else_expr.kind { - if let Some(expr) = &block.expr { - expr.span - } else if let Some(stmt) = block.stmts.last() { - // possibly incorrect trailing `;` in the else arm - remove_semicolon = self.could_remove_semicolon(block, then_ty); - stmt.span - } else { - // empty block; point at its entirety + let (error_sp, semi_sp) = self.find_block_span(block, Some(then_ty)); + remove_semicolon = semi_sp; + if block.expr.is_none() && block.stmts.is_empty() { // Avoid overlapping spans that aren't as readable: // ``` // 2 | let x = if true { @@ -333,8 +328,8 @@ fn if_cause( if outer_sp.is_some() { outer_sp = Some(self.tcx.sess.source_map().guess_head_span(span)); } - else_expr.span } + error_sp } else { // shouldn't happen unless the parser has done something weird else_expr.span @@ -342,17 +337,12 @@ fn if_cause( // Compute `Span` of `then` part of `if`-expression. let then_sp = if let ExprKind::Block(block, _) = &then_expr.kind { - if let Some(expr) = &block.expr { - expr.span - } else if let Some(stmt) = block.stmts.last() { - // possibly incorrect trailing `;` in the else arm - remove_semicolon = remove_semicolon.or(self.could_remove_semicolon(block, else_ty)); - stmt.span - } else { - // empty block; point at its entirety + let (then_sp, semi_sp) = self.find_block_span(block, Some(else_ty)); + remove_semicolon = remove_semicolon.or(semi_sp); + if block.expr.is_none() && block.stmts.is_empty() { outer_sp = None; // same as in `error_sp`; cleanup output - then_expr.span } + then_sp } else { // shouldn't happen unless the parser has done something weird then_expr.span @@ -450,4 +440,20 @@ fn demand_scrutinee_type( scrut_ty } } + + fn find_block_span( + &self, + block: &'tcx hir::Block<'tcx>, + expected_ty: Option>, + ) -> (Span, Option) { + if let Some(expr) = &block.expr { + (expr.span, None) + } else if let Some(stmt) = block.stmts.last() { + // possibly incorrect trailing `;` in the else arm + (stmt.span, expected_ty.and_then(|ty| self.could_remove_semicolon(block, ty))) + } else { + // empty block; point at its entirety + (block.span, None) + } + } } diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 34693a73217..e41314e8ab0 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -35,7 +35,7 @@ use rustc_ast as ast; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported}; use rustc_hir as hir; -use rustc_hir::lang_items; +use rustc_hir::lang_items::LangItem; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::cast::{CastKind, CastTy}; use rustc_middle::ty::error::TypeError; @@ -838,7 +838,7 @@ fn cenum_impl_drop_lint(&self, fcx: &FnCtxt<'a, 'tcx>) { impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn type_is_known_to_be_sized_modulo_regions(&self, ty: Ty<'tcx>, span: Span) -> bool { - let lang_item = self.tcx.require_lang_item(lang_items::SizedTraitLangItem, None); + let lang_item = self.tcx.require_lang_item(LangItem::Sized, None); traits::type_known_to_meet_bound_modulo_regions(self, self.param_env, ty, lang_item, span) } } diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index c7f9e9d63e0..97f7e4537ce 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -5,7 +5,7 @@ use crate::astconv::AstConv; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_hir::lang_items::{FutureTraitLangItem, GeneratorTraitLangItem}; +use rustc_hir::lang_items::LangItem; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_infer::infer::{InferOk, InferResult}; @@ -245,7 +245,7 @@ fn deduce_sig_from_projection( let trait_ref = projection.to_poly_trait_ref(tcx); let is_fn = tcx.fn_trait_kind_from_lang_item(trait_ref.def_id()).is_some(); - let gen_trait = tcx.require_lang_item(GeneratorTraitLangItem, cause_span); + let gen_trait = tcx.require_lang_item(LangItem::Generator, cause_span); let is_gen = gen_trait == trait_ref.def_id(); if !is_fn && !is_gen { debug!("deduce_sig_from_projection: not fn or generator"); @@ -668,7 +668,7 @@ fn deduce_future_output_from_projection( // Check that this is a projection from the `Future` trait. let trait_ref = predicate.projection_ty.trait_ref(self.tcx); - let future_trait = self.tcx.require_lang_item(FutureTraitLangItem, Some(cause_span)); + let future_trait = self.tcx.require_lang_item(LangItem::Future, Some(cause_span)); if trait_ref.def_id != future_trait { debug!("deduce_future_output_from_projection: not a future"); return None; diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index aa92d8b8b2b..5dc5480c335 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -6,7 +6,7 @@ use rustc_ast::util::parser::PREC_POSTFIX; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; -use rustc_hir::lang_items::CloneTraitLangItem; +use rustc_hir::lang_items::LangItem; use rustc_hir::{is_range_literal, Node}; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::{self, AssocItem, Ty, TypeAndMut}; @@ -465,7 +465,7 @@ pub fn check_ref( if self.can_coerce(ref_ty, expected) { let mut sugg_sp = sp; if let hir::ExprKind::MethodCall(ref segment, sp, ref args, _) = expr.kind { - let clone_trait = self.tcx.require_lang_item(CloneTraitLangItem, Some(sp)); + let clone_trait = self.tcx.require_lang_item(LangItem::Clone, Some(sp)); if let ([arg], Some(true), sym::clone) = ( &args[..], self.typeck_results.borrow().type_dependent_def_id(expr.hir_id).map( diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index ff0c788c18b..0e9f64c3596 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -25,7 +25,7 @@ use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::lang_items; +use rustc_hir::lang_items::LangItem; use rustc_hir::{ExprKind, QPath}; use rustc_infer::infer; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; @@ -926,8 +926,8 @@ fn report_extended_method_error( // Try alternative arbitrary self types that could fulfill this call. // FIXME: probe for all types that *could* be arbitrary self-types, not // just this list. - try_alt_rcvr(&mut err, self.tcx.mk_lang_item(rcvr_t, lang_items::OwnedBoxLangItem)); - try_alt_rcvr(&mut err, self.tcx.mk_lang_item(rcvr_t, lang_items::PinTypeLangItem)); + try_alt_rcvr(&mut err, self.tcx.mk_lang_item(rcvr_t, LangItem::OwnedBox)); + try_alt_rcvr(&mut err, self.tcx.mk_lang_item(rcvr_t, LangItem::Pin)); try_alt_rcvr(&mut err, self.tcx.mk_diagnostic_item(rcvr_t, sym::Arc)); try_alt_rcvr(&mut err, self.tcx.mk_diagnostic_item(rcvr_t, sym::Rc)); } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index e941c844a6d..896bfc07954 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -9,7 +9,7 @@ use rustc_hir::def::{DefKind, Namespace, Res}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::intravisit; -use rustc_hir::lang_items::FnOnceTraitLangItem; +use rustc_hir::lang_items::LangItem; use rustc_hir::{ExprKind, Node, QPath}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::hir::map as hir_map; @@ -36,7 +36,7 @@ fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool { ty::Closure(..) | ty::FnDef(..) | ty::FnPtr(_) => true, // If it's not a simple function, look for things which implement `FnOnce`. _ => { - let fn_once = match tcx.lang_items().require(FnOnceTraitLangItem) { + let fn_once = match tcx.lang_items().require(LangItem::FnOnce) { Ok(fn_once) => fn_once, Err(..) => return false, }; diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 824e81a974c..031d48f8a60 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -100,9 +100,7 @@ use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::itemlikevisit::ItemLikeVisitor; -use rustc_hir::lang_items::{ - FutureTraitLangItem, PinTypeLangItem, SizedTraitLangItem, VaListTypeLangItem, -}; +use rustc_hir::lang_items::LangItem; use rustc_hir::{ExprKind, GenericArg, HirIdMap, ItemKind, Node, PatKind, QPath}; use rustc_index::bit_set::BitSet; use rustc_index::vec::Idx; @@ -1339,7 +1337,7 @@ fn check_fn<'a, 'tcx>( // (as it's created inside the body itself, not passed in from outside). let maybe_va_list = if fn_sig.c_variadic { let span = body.params.last().unwrap().span; - let va_list_did = tcx.require_lang_item(VaListTypeLangItem, Some(span)); + let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(span)); let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span)); Some(tcx.type_of(va_list_did).subst(tcx, &[region.into()])) @@ -3493,7 +3491,7 @@ pub fn require_type_is_sized( code: traits::ObligationCauseCode<'tcx>, ) { if !ty.references_error() { - let lang_item = self.tcx.require_lang_item(SizedTraitLangItem, None); + let lang_item = self.tcx.require_lang_item(LangItem::Sized, None); self.require_type_meets(ty, span, code, lang_item); } } @@ -5265,7 +5263,7 @@ fn suggest_calling_boxed_future_when_appropriate( _ => {} } let boxed_found = self.tcx.mk_box(found); - let new_found = self.tcx.mk_lang_item(boxed_found, PinTypeLangItem).unwrap(); + let new_found = self.tcx.mk_lang_item(boxed_found, LangItem::Pin).unwrap(); if let (true, Ok(snippet)) = ( self.can_coerce(new_found, expected), self.sess().source_map().span_to_snippet(expr.span), @@ -5422,7 +5420,7 @@ fn suggest_missing_await( let sp = expr.span; // Check for `Future` implementations by constructing a predicate to // prove: `::Output == U` - let future_trait = self.tcx.require_lang_item(FutureTraitLangItem, Some(sp)); + let future_trait = self.tcx.require_lang_item(LangItem::Future, Some(sp)); let item_def_id = self .tcx .associated_items(future_trait) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 810bf59ea6c..9c692edaa7f 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -9,7 +9,7 @@ use rustc_hir::intravisit as hir_visit; use rustc_hir::intravisit::Visitor; use rustc_hir::itemlikevisit::ParItemLikeVisitor; -use rustc_hir::lang_items; +use rustc_hir::lang_items::LangItem; use rustc_hir::ItemKind; use rustc_middle::hir::map as hir_map; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst}; @@ -495,7 +495,7 @@ fn check_type_defn<'tcx, F>( let last = idx == variant.fields.len() - 1; fcx.register_bound( field.ty, - fcx.tcx.require_lang_item(lang_items::SizedTraitLangItem, None), + fcx.tcx.require_lang_item(LangItem::Sized, None), traits::ObligationCause::new( field.span, fcx.body_id, @@ -718,7 +718,7 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: hir::HirId, ty_span: Span, allow_fo if forbid_unsized { fcx.register_bound( item_ty, - fcx.tcx.require_lang_item(lang_items::SizedTraitLangItem, None), + fcx.tcx.require_lang_item(LangItem::Sized, None), traits::ObligationCause::new(ty_span, fcx.body_id, traits::MiscObligation), ); } @@ -1223,7 +1223,7 @@ fn receiver_is_valid<'fcx, 'tcx>( // The first type is `receiver_ty`, which we know its not equal to `self_ty`; skip it. autoderef.next(); - let receiver_trait_def_id = fcx.tcx.require_lang_item(lang_items::ReceiverTraitLangItem, None); + let receiver_trait_def_id = fcx.tcx.require_lang_item(LangItem::Receiver, None); // Keep dereferencing `receiver_ty` until we get to `self_ty`. loop { diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index 56a737964c0..0d3cac7f7f3 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -4,9 +4,7 @@ use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::lang_items::{ - CoerceUnsizedTraitLangItem, DispatchFromDynTraitLangItem, UnsizeTraitLangItem, -}; +use rustc_hir::lang_items::LangItem; use rustc_hir::ItemKind; use rustc_infer::infer; use rustc_infer::infer::outlives::env::OutlivesEnvironment; @@ -149,7 +147,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did); let span = tcx.hir().span(impl_hir_id); - let dispatch_from_dyn_trait = tcx.require_lang_item(DispatchFromDynTraitLangItem, Some(span)); + let dispatch_from_dyn_trait = tcx.require_lang_item(LangItem::DispatchFromDyn, Some(span)); let source = tcx.type_of(impl_did); assert!(!source.has_escaping_bound_vars()); @@ -318,9 +316,9 @@ pub fn coerce_unsized_info(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUnsizedI let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did.expect_local()); let span = tcx.hir().span(impl_hir_id); - let coerce_unsized_trait = tcx.require_lang_item(CoerceUnsizedTraitLangItem, Some(span)); + let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, Some(span)); - let unsize_trait = tcx.lang_items().require(UnsizeTraitLangItem).unwrap_or_else(|err| { + let unsize_trait = tcx.lang_items().require(LangItem::Unsize).unwrap_or_else(|err| { tcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err)); }); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 7fb4026117b..1b472810ccf 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -14,7 +14,8 @@ //! At present, however, we do run collection across all items in the //! crate as a kind of pass. This should eventually be factored away. -use crate::astconv::{AstConv, Bounds, SizedByDefault}; +use crate::astconv::{AstConv, SizedByDefault}; +use crate::bounds::Bounds; use crate::check::intrinsic::intrinsic_operation_unsafety; use crate::constrained_generic_params as cgp; use crate::middle::resolve_lifetime as rl; @@ -1542,7 +1543,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { } TraitItem(hir::TraitItem { - kind: TraitItemKind::Fn(FnSig { header, decl }, _), + kind: TraitItemKind::Fn(FnSig { header, decl, span: _ }, _), ident, generics, .. diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 42482531725..62f92fe7ffa 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -79,6 +79,7 @@ pub mod expr_use_visitor; mod astconv; +mod bounds; mod check_unused; mod coherence; mod collect; @@ -109,7 +110,8 @@ use std::iter; -use astconv::{AstConv, Bounds}; +use astconv::AstConv; +use bounds::Bounds; fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi, span: Span) { if decl.c_variadic && !(abi == Abi::C || abi == Abi::Cdecl) { diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 9c44d27447d..1ea1a091069 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -1,6 +1,6 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; -use rustc_hir::lang_items; +use rustc_hir::lang_items::LangItem; use rustc_middle::ty::{self, Region, RegionVid, TypeFoldable}; use rustc_trait_selection::traits::auto_trait::{self, AutoTraitResult}; @@ -454,7 +454,7 @@ fn param_env_to_generics( // The `Sized` trait must be handled specially, since we only display it when // it is *not* required (i.e., '?Sized') - let sized_trait = self.cx.tcx.require_lang_item(lang_items::SizedTraitLangItem, None); + let sized_trait = self.cx.tcx.require_lang_item(LangItem::Sized, None); let mut replacer = RegionReplacer { vid_to_region: &vid_to_region, tcx }; @@ -742,9 +742,9 @@ fn unstable_debug_sort(&self, vec: &mut Vec) { fn is_fn_ty(&self, tcx: TyCtxt<'_>, ty: &Type) -> bool { match &ty { &&Type::ResolvedPath { ref did, .. } => { - *did == tcx.require_lang_item(lang_items::FnTraitLangItem, None) - || *did == tcx.require_lang_item(lang_items::FnMutTraitLangItem, None) - || *did == tcx.require_lang_item(lang_items::FnOnceTraitLangItem, None) + *did == tcx.require_lang_item(LangItem::Fn, None) + || *did == tcx.require_lang_item(LangItem::FnMut, None) + || *did == tcx.require_lang_item(LangItem::FnOnce, None) } _ => false, } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 3eac5bbda00..a458cdab303 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -16,11 +16,11 @@ use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; -use rustc_hir::lang_items; +use rustc_hir::lang_items::LangItem; use rustc_hir::Mutability; use rustc_index::vec::IndexVec; use rustc_middle::middle::stability; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{AssocKind, TyCtxt}; use rustc_span::hygiene::MacroKind; use rustc_span::source_map::DUMMY_SP; use rustc_span::symbol::{kw, sym, Ident, Symbol}; @@ -282,12 +282,21 @@ pub enum ItemEnum { } impl ItemEnum { - pub fn is_associated(&self) -> bool { + pub fn is_type_alias(&self) -> bool { match *self { ItemEnum::TypedefItem(_, _) | ItemEnum::AssocTypeItem(_, _) => true, _ => false, } } + + pub fn as_assoc_kind(&self) -> Option { + match *self { + ItemEnum::AssocConstItem(..) => Some(AssocKind::Const), + ItemEnum::AssocTypeItem(..) => Some(AssocKind::Type), + ItemEnum::TyMethodItem(..) | ItemEnum::MethodItem(..) => Some(AssocKind::Fn), + _ => None, + } + } } #[derive(Clone, Debug)] @@ -701,7 +710,7 @@ pub enum GenericBound { impl GenericBound { pub fn maybe_sized(cx: &DocContext<'_>) -> GenericBound { - let did = cx.tcx.require_lang_item(lang_items::SizedTraitLangItem, None); + let did = cx.tcx.require_lang_item(LangItem::Sized, None); let empty = cx.tcx.intern_substs(&[]); let path = external_path(cx, cx.tcx.item_name(did), Some(did), false, vec![], empty); inline::record_extern_fqn(cx, did, TypeKind::Trait); diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 4f751decc80..14df4e7aa8e 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -83,9 +83,9 @@ pub struct Options { /// Codegen options strings to hand to the compiler. pub codegen_options_strs: Vec, /// Debugging (`-Z`) options to pass to the compiler. - pub debugging_options: DebuggingOptions, + pub debugging_opts: DebuggingOptions, /// Debugging (`-Z`) options strings to pass to the compiler. - pub debugging_options_strs: Vec, + pub debugging_opts_strs: Vec, /// The target used to compile the crate against. pub target: TargetTriple, /// Edition used when reading the crate. Defaults to "2015". Also used by default when @@ -318,9 +318,9 @@ fn println_condition(condition: Condition) { let error_format = config::parse_error_format(&matches, color, json_rendered); let codegen_options = build_codegen_options(matches, error_format); - let debugging_options = build_debugging_options(matches, error_format); + let debugging_opts = build_debugging_options(matches, error_format); - let diag = new_handler(error_format, None, &debugging_options); + let diag = new_handler(error_format, None, &debugging_opts); // check for deprecated options check_deprecated_options(&matches, &diag); @@ -365,7 +365,7 @@ fn println_condition(condition: Condition) { .iter() .map(|s| SearchPath::from_cli_opt(s, error_format)) .collect(); - let externs = parse_externs(&matches, &debugging_options, error_format); + let externs = parse_externs(&matches, &debugging_opts, error_format); let extern_html_root_urls = match parse_extern_html_roots(&matches) { Ok(ex) => ex, Err(err) => { @@ -546,7 +546,7 @@ fn println_condition(condition: Condition) { let persist_doctests = matches.opt_str("persist-doctests").map(PathBuf::from); let test_builder = matches.opt_str("test-builder").map(PathBuf::from); let codegen_options_strs = matches.opt_strs("C"); - let debugging_options_strs = matches.opt_strs("Z"); + let debugging_opts_strs = matches.opt_strs("Z"); let lib_strs = matches.opt_strs("L"); let extern_strs = matches.opt_strs("extern"); let runtool = matches.opt_str("runtool"); @@ -569,8 +569,8 @@ fn println_condition(condition: Condition) { cfgs, codegen_options, codegen_options_strs, - debugging_options, - debugging_options_strs, + debugging_opts, + debugging_opts_strs, target, edition, maybe_sysroot, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 5049dbdb1dd..89b217dc7d4 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -32,8 +32,8 @@ use crate::clean; use crate::clean::{AttributesExt, MAX_DEF_ID}; -use crate::config::RenderInfo; use crate::config::{Options as RustdocOptions, RenderOptions}; +use crate::config::{OutputFormat, RenderInfo}; use crate::passes::{self, Condition::*, ConditionalPass}; pub use rustc_session::config::{CodegenOptions, DebuggingOptions, Input, Options}; @@ -69,6 +69,11 @@ pub struct DocContext<'tcx> { pub auto_traits: Vec, /// The options given to rustdoc that could be relevant to a pass. pub render_options: RenderOptions, + /// The traits in scope for a given module. + /// + /// See `collect_intra_doc_links::traits_implemented_by` for more details. + /// `map>` + pub module_trait_cache: RefCell>>, } impl<'tcx> DocContext<'tcx> { @@ -117,13 +122,13 @@ pub fn enter_alias( // def ids, as we'll end up with a panic if we use the DefId Debug impl for fake DefIds pub fn next_def_id(&self, crate_num: CrateNum) -> DefId { let start_def_id = { - let next_id = if crate_num == LOCAL_CRATE { - self.tcx.hir().definitions().def_path_table().next_id() + let num_def_ids = if crate_num == LOCAL_CRATE { + self.tcx.hir().definitions().def_path_table().num_def_ids() } else { - self.enter_resolver(|r| r.cstore().def_path_table(crate_num).next_id()) + self.enter_resolver(|r| r.cstore().num_def_ids(crate_num)) }; - DefId { krate: crate_num, index: next_id } + DefId { krate: crate_num, index: DefIndex::from_usize(num_def_ids) } }; let mut fake_ids = self.fake_def_ids.borrow_mut(); @@ -229,7 +234,7 @@ pub fn new_handler( /// It returns a tuple containing: /// * Vector of tuples of lints' name and their associated "max" level /// * HashMap of lint id with their associated "max" level -pub fn init_lints( +pub(crate) fn init_lints( mut allowed_lints: Vec, lint_opts: Vec<(String, lint::Level)>, filter_call: F, @@ -252,7 +257,7 @@ pub fn init_lints( .filter_map(|lint| { // Permit feature-gated lints to avoid feature errors when trying to // allow all lints. - if lint.name == warnings_lint_name || lint.feature_gate.is_some() { + if lint.feature_gate.is_some() || allowed_lints.iter().any(|l| lint.name == l) { None } else { filter_call(lint) @@ -275,7 +280,9 @@ pub fn init_lints( (lint_opts, lint_caps) } -pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOptions) { +pub fn run_core( + options: RustdocOptions, +) -> (clean::Crate, RenderInfo, RenderOptions, Lrc) { // Parse, resolve, and typecheck the given crate. let RustdocOptions { @@ -287,15 +294,15 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt externs, mut cfgs, codegen_options, - debugging_options, + debugging_opts, target, edition, maybe_sysroot, lint_opts, describe_lints, lint_cap, - mut default_passes, - mut manual_passes, + default_passes, + manual_passes, display_warnings, render_options, output_format, @@ -321,19 +328,23 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt let private_doc_tests = rustc_lint::builtin::PRIVATE_DOC_TESTS.name; let no_crate_level_docs = rustc_lint::builtin::MISSING_CRATE_LEVEL_DOCS.name; let invalid_codeblock_attributes_name = rustc_lint::builtin::INVALID_CODEBLOCK_ATTRIBUTES.name; + let renamed_and_removed_lints = rustc_lint::builtin::RENAMED_AND_REMOVED_LINTS.name; + let unknown_lints = rustc_lint::builtin::UNKNOWN_LINTS.name; // In addition to those specific lints, we also need to allow those given through // command line, otherwise they'll get ignored and we don't want that. - let allowed_lints = vec![ + let lints_to_show = vec![ intra_link_resolution_failure_name.to_owned(), missing_docs.to_owned(), missing_doc_example.to_owned(), private_doc_tests.to_owned(), no_crate_level_docs.to_owned(), invalid_codeblock_attributes_name.to_owned(), + renamed_and_removed_lints.to_owned(), + unknown_lints.to_owned(), ]; - let (lint_opts, lint_caps) = init_lints(allowed_lints, lint_opts, |lint| { + let (lint_opts, lint_caps) = init_lints(lints_to_show, lint_opts, |lint| { if lint.name == intra_link_resolution_failure_name || lint.name == invalid_codeblock_attributes_name { @@ -351,13 +362,13 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt search_paths: libs, crate_types, lint_opts: if !display_warnings { lint_opts } else { vec![] }, - lint_cap: Some(lint_cap.unwrap_or_else(|| lint::Forbid)), + lint_cap, cg: codegen_options, externs, target_triple: target, unstable_features: UnstableFeatures::from_environment(), actually_rustdoc: true, - debugging_opts: debugging_options, + debugging_opts, error_format, edition, describe_lints, @@ -402,7 +413,9 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt let hir = tcx.hir(); let body = hir.body(hir.body_owned_by(hir.local_def_id_to_hir_id(def_id))); debug!("visiting body for {:?}", def_id); - EmitIgnoredResolutionErrors::new(tcx).visit_body(body); + tcx.sess.time("emit_ignored_resolution_errors", || { + EmitIgnoredResolutionErrors::new(tcx).visit_body(body); + }); (rustc_interface::DEFAULT_QUERY_PROVIDERS.typeck)(tcx, def_id) }; }), @@ -424,18 +437,20 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt // actually be loaded, just in case they're only referred to inside // intra-doc-links resolver.borrow_mut().access(|resolver| { - for extern_name in &extern_names { - resolver - .resolve_str_path_error( - DUMMY_SP, - extern_name, - TypeNS, - LocalDefId { local_def_index: CRATE_DEF_INDEX }.to_def_id(), - ) - .unwrap_or_else(|()| { - panic!("Unable to resolve external crate {}", extern_name) - }); - } + sess.time("load_extern_crates", || { + for extern_name in &extern_names { + resolver + .resolve_str_path_error( + DUMMY_SP, + extern_name, + TypeNS, + LocalDefId { local_def_index: CRATE_DEF_INDEX }.to_def_id(), + ) + .unwrap_or_else(|()| { + panic!("Unable to resolve external crate {}", extern_name) + }); + } + }); }); // Now we're good to clone the resolver because everything should be loaded @@ -448,180 +463,201 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt let mut global_ctxt = abort_on_err(queries.global_ctxt(), sess).take(); - global_ctxt.enter(|tcx| { - // Certain queries assume that some checks were run elsewhere - // (see https://github.com/rust-lang/rust/pull/73566#issuecomment-656954425), - // so type-check everything other than function bodies in this crate before running lints. + let (krate, render_info, opts) = sess.time("run_global_ctxt", || { + global_ctxt.enter(|tcx| { + run_global_ctxt( + tcx, + resolver, + default_passes, + manual_passes, + render_options, + output_format, + ) + }) + }); + (krate, render_info, opts, Lrc::clone(sess)) + }) + }) +} - // NOTE: this does not call `tcx.analysis()` so that we won't - // typeck function bodies or run the default rustc lints. - // (see `override_queries` in the `config`) +fn run_global_ctxt( + tcx: TyCtxt<'_>, + resolver: Rc>, + mut default_passes: passes::DefaultPassOption, + mut manual_passes: Vec, + render_options: RenderOptions, + output_format: Option, +) -> (clean::Crate, RenderInfo, RenderOptions) { + // Certain queries assume that some checks were run elsewhere + // (see https://github.com/rust-lang/rust/pull/73566#issuecomment-656954425), + // so type-check everything other than function bodies in this crate before running lints. + + // NOTE: this does not call `tcx.analysis()` so that we won't + // typeck function bodies or run the default rustc lints. + // (see `override_queries` in the `config`) + + // HACK(jynelson) this calls an _extremely_ limited subset of `typeck` + // and might break if queries change their assumptions in the future. + + // NOTE: This is copy/pasted from typeck/lib.rs and should be kept in sync with those changes. + tcx.sess.time("item_types_checking", || { + for &module in tcx.hir().krate().modules.keys() { + tcx.ensure().check_mod_item_types(tcx.hir().local_def_id(module)); + } + }); + tcx.sess.abort_if_errors(); + tcx.sess.time("missing_docs", || { + rustc_lint::check_crate(tcx, rustc_lint::builtin::MissingDoc::new); + }); + tcx.sess.time("check_mod_attrs", || { + for &module in tcx.hir().krate().modules.keys() { + let local_def_id = tcx.hir().local_def_id(module); + tcx.ensure().check_mod_attrs(local_def_id); + } + }); - // HACK(jynelson) this calls an _extremely_ limited subset of `typeck` - // and might break if queries change their assumptions in the future. + let access_levels = tcx.privacy_access_levels(LOCAL_CRATE); + // Convert from a HirId set to a DefId set since we don't always have easy access + // to the map from defid -> hirid + let access_levels = AccessLevels { + map: access_levels + .map + .iter() + .map(|(&k, &v)| (tcx.hir().local_def_id(k).to_def_id(), v)) + .collect(), + }; - // NOTE: This is copy/pasted from typeck/lib.rs and should be kept in sync with those changes. - tcx.sess.time("item_types_checking", || { - for &module in tcx.hir().krate().modules.keys() { - tcx.ensure().check_mod_item_types(tcx.hir().local_def_id(module)); - } - }); - tcx.sess.abort_if_errors(); - sess.time("missing_docs", || { - rustc_lint::check_crate(tcx, rustc_lint::builtin::MissingDoc::new); - }); - for &module in tcx.hir().krate().modules.keys() { - let local_def_id = tcx.hir().local_def_id(module); - tcx.ensure().check_mod_attrs(local_def_id); - } + let mut renderinfo = RenderInfo::default(); + renderinfo.access_levels = access_levels; + renderinfo.output_format = output_format; + + let mut ctxt = DocContext { + tcx, + resolver, + external_traits: Default::default(), + active_extern_traits: Default::default(), + renderinfo: RefCell::new(renderinfo), + ty_substs: Default::default(), + lt_substs: Default::default(), + ct_substs: Default::default(), + impl_trait_bounds: Default::default(), + fake_def_ids: Default::default(), + all_fake_def_ids: Default::default(), + generated_synthetics: Default::default(), + auto_traits: tcx + .all_traits(LOCAL_CRATE) + .iter() + .cloned() + .filter(|trait_def_id| tcx.trait_is_auto(*trait_def_id)) + .collect(), + render_options, + module_trait_cache: RefCell::new(FxHashMap::default()), + }; + debug!("crate: {:?}", tcx.hir().krate()); + + let mut krate = tcx.sess.time("clean_crate", || clean::krate(&mut ctxt)); + + if let Some(ref m) = krate.module { + if let None | Some("") = m.doc_value() { + let help = "The following guide may be of use:\n\ + https://doc.rust-lang.org/nightly/rustdoc/how-to-write-documentation\ + .html"; + tcx.struct_lint_node( + rustc_lint::builtin::MISSING_CRATE_LEVEL_DOCS, + ctxt.as_local_hir_id(m.def_id).unwrap(), + |lint| { + let mut diag = + lint.build("no documentation found for this crate's top-level module"); + diag.help(help); + diag.emit(); + }, + ); + } + } - let access_levels = tcx.privacy_access_levels(LOCAL_CRATE); - // Convert from a HirId set to a DefId set since we don't always have easy access - // to the map from defid -> hirid - let access_levels = AccessLevels { - map: access_levels - .map - .iter() - .map(|(&k, &v)| (tcx.hir().local_def_id(k).to_def_id(), v)) - .collect(), - }; - - let mut renderinfo = RenderInfo::default(); - renderinfo.access_levels = access_levels; - renderinfo.output_format = output_format; - - let mut ctxt = DocContext { - tcx, - resolver, - external_traits: Default::default(), - active_extern_traits: Default::default(), - renderinfo: RefCell::new(renderinfo), - ty_substs: Default::default(), - lt_substs: Default::default(), - ct_substs: Default::default(), - impl_trait_bounds: Default::default(), - fake_def_ids: Default::default(), - all_fake_def_ids: Default::default(), - generated_synthetics: Default::default(), - auto_traits: tcx - .all_traits(LOCAL_CRATE) - .iter() - .cloned() - .filter(|trait_def_id| tcx.trait_is_auto(*trait_def_id)) - .collect(), - render_options, - }; - debug!("crate: {:?}", tcx.hir().krate()); - - let mut krate = clean::krate(&mut ctxt); - - if let Some(ref m) = krate.module { - if let None | Some("") = m.doc_value() { - let help = "The following guide may be of use:\n\ - https://doc.rust-lang.org/nightly/rustdoc/how-to-write-documentation\ - .html"; - tcx.struct_lint_node( - rustc_lint::builtin::MISSING_CRATE_LEVEL_DOCS, - ctxt.as_local_hir_id(m.def_id).unwrap(), - |lint| { - let mut diag = lint.build( - "no documentation found for this crate's top-level module", - ); - diag.help(help); - diag.emit(); - }, - ); - } - } + fn report_deprecated_attr(name: &str, diag: &rustc_errors::Handler) { + let mut msg = diag + .struct_warn(&format!("the `#![doc({})]` attribute is considered deprecated", name)); + msg.warn( + "see issue #44136 \ + for more information", + ); - fn report_deprecated_attr(name: &str, diag: &rustc_errors::Handler) { - let mut msg = diag.struct_warn(&format!( - "the `#![doc({})]` attribute is considered deprecated", - name - )); - msg.warn( - "see issue #44136 \ - for more information", - ); + if name == "no_default_passes" { + msg.help("you may want to use `#![doc(document_private_items)]`"); + } - if name == "no_default_passes" { - msg.help("you may want to use `#![doc(document_private_items)]`"); - } + msg.emit(); + } - msg.emit(); + // Process all of the crate attributes, extracting plugin metadata along + // with the passes which we are supposed to run. + for attr in krate.module.as_ref().unwrap().attrs.lists(sym::doc) { + let diag = ctxt.sess().diagnostic(); + + let name = attr.name_or_empty(); + if attr.is_word() { + if name == sym::no_default_passes { + report_deprecated_attr("no_default_passes", diag); + if default_passes == passes::DefaultPassOption::Default { + default_passes = passes::DefaultPassOption::None; + } + } + } else if let Some(value) = attr.value_str() { + let sink = match name { + sym::passes => { + report_deprecated_attr("passes = \"...\"", diag); + &mut manual_passes } + sym::plugins => { + report_deprecated_attr("plugins = \"...\"", diag); + eprintln!( + "WARNING: `#![doc(plugins = \"...\")]` \ + no longer functions; see CVE-2018-1000622" + ); + continue; + } + _ => continue, + }; + for name in value.as_str().split_whitespace() { + sink.push(name.to_string()); + } + } - // Process all of the crate attributes, extracting plugin metadata along - // with the passes which we are supposed to run. - for attr in krate.module.as_ref().unwrap().attrs.lists(sym::doc) { - let diag = ctxt.sess().diagnostic(); - - let name = attr.name_or_empty(); - if attr.is_word() { - if name == sym::no_default_passes { - report_deprecated_attr("no_default_passes", diag); - if default_passes == passes::DefaultPassOption::Default { - default_passes = passes::DefaultPassOption::None; - } - } - } else if let Some(value) = attr.value_str() { - let sink = match name { - sym::passes => { - report_deprecated_attr("passes = \"...\"", diag); - &mut manual_passes - } - sym::plugins => { - report_deprecated_attr("plugins = \"...\"", diag); - eprintln!( - "WARNING: `#![doc(plugins = \"...\")]` \ - no longer functions; see CVE-2018-1000622" - ); - continue; - } - _ => continue, - }; - for name in value.as_str().split_whitespace() { - sink.push(name.to_string()); - } - } + if attr.is_word() && name == sym::document_private_items { + ctxt.render_options.document_private = true; + } + } - if attr.is_word() && name == sym::document_private_items { - ctxt.render_options.document_private = true; - } - } + let passes = passes::defaults(default_passes).iter().copied().chain( + manual_passes.into_iter().flat_map(|name| { + if let Some(pass) = passes::find_pass(&name) { + Some(ConditionalPass::always(pass)) + } else { + error!("unknown pass {}, skipping", name); + None + } + }), + ); - let passes = passes::defaults(default_passes).iter().copied().chain( - manual_passes.into_iter().flat_map(|name| { - if let Some(pass) = passes::find_pass(&name) { - Some(ConditionalPass::always(pass)) - } else { - error!("unknown pass {}, skipping", name); - None - } - }), - ); - - info!("Executing passes"); - - for p in passes { - let run = match p.condition { - Always => true, - WhenDocumentPrivate => ctxt.render_options.document_private, - WhenNotDocumentPrivate => !ctxt.render_options.document_private, - WhenNotDocumentHidden => !ctxt.render_options.document_hidden, - }; - if run { - debug!("running pass {}", p.pass.name); - krate = (p.pass.run)(krate, &ctxt); - } - } + info!("Executing passes"); - ctxt.sess().abort_if_errors(); + for p in passes { + let run = match p.condition { + Always => true, + WhenDocumentPrivate => ctxt.render_options.document_private, + WhenNotDocumentPrivate => !ctxt.render_options.document_private, + WhenNotDocumentHidden => !ctxt.render_options.document_hidden, + }; + if run { + debug!("running pass {}", p.pass.name); + krate = ctxt.tcx.sess.time(p.pass.name, || (p.pass.run)(krate, &ctxt)); + } + } - (krate, ctxt.renderinfo.into_inner(), ctxt.render_options) - }) - }) - }) + ctxt.sess().abort_if_errors(); + + (krate, ctxt.renderinfo.into_inner(), ctxt.render_options) } /// Due to https://github.com/rust-lang/rust/pull/73566, diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index bd919205dd1..d17961521c8 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -3612,7 +3612,7 @@ fn doc_impl_item( }; let (is_hidden, extra_class) = - if (trait_.is_none() || item.doc_value().is_some() || item.inner.is_associated()) + if (trait_.is_none() || item.doc_value().is_some() || item.inner.is_type_alias()) && !is_default_item { (false, "") diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 462a696dee6..57c8d5bff76 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -1576,14 +1576,21 @@ function defocusSearchBar() { } function showResults(results) { - if (results.others.length === 1 && - getCurrentValue("rustdoc-go-to-only-result") === "true") { + var search = getSearchElement(); + if (results.others.length === 1 + && getCurrentValue("rustdoc-go-to-only-result") === "true" + // By default, the search DOM element is "empty" (meaning it has no children not + // text content). Once a search has been run, it won't be empty, even if you press + // ESC or empty the search input (which also "cancels" the search). + && (!search.firstChild || search.firstChild.innerText !== getSearchLoadingText())) + { var elem = document.createElement("a"); elem.href = results.others[0].href; elem.style.display = "none"; // For firefox, we need the element to be in the DOM so it can be clicked. document.body.appendChild(elem); elem.click(); + return; } var query = getQuery(search_input.value); @@ -1602,7 +1609,6 @@ function defocusSearchBar() { "

"; - var search = getSearchElement(); search.innerHTML = output; showSearchResults(search); var tds = search.getElementsByTagName("td"); @@ -2679,6 +2685,10 @@ function defocusSearchBar() { } } + function getSearchLoadingText() { + return "Loading search results..."; + } + if (search_input) { search_input.onfocus = function() { putBackSearch(this); @@ -2688,7 +2698,7 @@ function defocusSearchBar() { var params = getQueryStringParams(); if (params && params.search) { var search = getSearchElement(); - search.innerHTML = "

Loading search results...

"; + search.innerHTML = "

" + getSearchLoadingText() + "

"; showSearchResults(search); } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 3dfa7b529e3..b5e246b5d17 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -9,7 +9,6 @@ #![feature(nll)] #![feature(or_patterns)] #![feature(test)] -#![feature(ptr_offset_from)] #![feature(crate_visibility_modifier)] #![feature(never_type)] #![feature(once_cell)] @@ -473,7 +472,7 @@ fn run_renderer( } fn main_options(options: config::Options) -> MainResult { - let diag = core::new_handler(options.error_format, None, &options.debugging_options); + let diag = core::new_handler(options.error_format, None, &options.debugging_opts); match (options.should_test, options.markdown_input()) { (true, true) => return wrap_return(&diag, markdown::test(options)), @@ -489,7 +488,7 @@ fn main_options(options: config::Options) -> MainResult { // need to move these items separately because we lose them by the time the closure is called, // but we can't crates the Handler ahead of time because it's not Send - let diag_opts = (options.error_format, options.edition, options.debugging_options.clone()); + let diag_opts = (options.error_format, options.edition, options.debugging_opts.clone()); let show_coverage = options.show_coverage; // First, parse the crate and extract all relevant information. @@ -502,7 +501,7 @@ fn main_options(options: config::Options) -> MainResult { let crate_name = options.crate_name.clone(); let crate_version = options.crate_version.clone(); let output_format = options.output_format; - let (mut krate, renderinfo, renderopts) = core::run_core(options); + let (mut krate, renderinfo, renderopts, sess) = core::run_core(options); info!("finished with rustc"); @@ -525,11 +524,11 @@ fn main_options(options: config::Options) -> MainResult { let (error_format, edition, debugging_options) = diag_opts; let diag = core::new_handler(error_format, None, &debugging_options); match output_format { - None | Some(config::OutputFormat::Html) => { + None | Some(config::OutputFormat::Html) => sess.time("render_html", || { run_renderer::(krate, renderopts, renderinfo, &diag, edition) - } - Some(config::OutputFormat::Json) => { + }), + Some(config::OutputFormat::Json) => sess.time("render_json", || { run_renderer::(krate, renderopts, renderinfo, &diag, edition) - } + }), } } diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index 0a836f46c0e..671e0825567 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -3,7 +3,7 @@ use crate::core::DocContext; use crate::fold::{self, DocFolder}; use crate::html::markdown::{find_testable_code, ErrorCodes}; -use crate::passes::doc_test_lints::Tests; +use crate::passes::doc_test_lints::{should_have_doc_example, Tests}; use crate::passes::Pass; use rustc_span::symbol::sym; use rustc_span::FileName; @@ -27,20 +27,29 @@ fn calculate_doc_coverage(krate: clean::Crate, ctx: &DocContext<'_>) -> clean::C krate } -#[derive(Default, Copy, Clone, Serialize)] +#[derive(Default, Copy, Clone, Serialize, Debug)] struct ItemCount { total: u64, with_docs: u64, + total_examples: u64, with_examples: u64, } impl ItemCount { - fn count_item(&mut self, has_docs: bool, has_doc_example: bool) { + fn count_item( + &mut self, + has_docs: bool, + has_doc_example: bool, + should_have_doc_examples: bool, + ) { self.total += 1; if has_docs { self.with_docs += 1; } + if should_have_doc_examples || has_doc_example { + self.total_examples += 1; + } if has_doc_example { self.with_examples += 1; } @@ -55,8 +64,8 @@ fn percentage(&self) -> Option { } fn examples_percentage(&self) -> Option { - if self.total > 0 { - Some((self.with_examples as f64 * 100.0) / self.total as f64) + if self.total_examples > 0 { + Some((self.with_examples as f64 * 100.0) / self.total_examples as f64) } else { None } @@ -70,6 +79,7 @@ fn sub(self, rhs: Self) -> Self { ItemCount { total: self.total - rhs.total, with_docs: self.with_docs - rhs.with_docs, + total_examples: self.total_examples - rhs.total_examples, with_examples: self.with_examples - rhs.with_examples, } } @@ -79,6 +89,7 @@ impl ops::AddAssign for ItemCount { fn add_assign(&mut self, rhs: Self) { self.total += rhs.total; self.with_docs += rhs.with_docs; + self.total_examples += rhs.total_examples; self.with_examples += rhs.with_examples; } } @@ -121,7 +132,7 @@ fn print_results(&self, output_format: Option) { let mut total = ItemCount::default(); fn print_table_line() { - println!("+-{0:->35}-+-{0:->10}-+-{0:->10}-+-{0:->10}-+-{0:->10}-+-{0:->10}-+", ""); + println!("+-{0:->35}-+-{0:->10}-+-{0:->10}-+-{0:->10}-+-{0:->10}-+", ""); } fn print_table_record( @@ -131,32 +142,25 @@ fn print_table_record( examples_percentage: f64, ) { println!( - "| {:<35} | {:>10} | {:>10} | {:>9.1}% | {:>10} | {:>9.1}% |", - name, - count.with_docs, - count.total, - percentage, - count.with_examples, - examples_percentage, + "| {:<35} | {:>10} | {:>9.1}% | {:>10} | {:>9.1}% |", + name, count.with_docs, percentage, count.with_examples, examples_percentage, ); } print_table_line(); println!( - "| {:<35} | {:>10} | {:>10} | {:>10} | {:>10} | {:>10} |", - "File", "Documented", "Total", "Percentage", "Examples", "Percentage", + "| {:<35} | {:>10} | {:>10} | {:>10} | {:>10} |", + "File", "Documented", "Percentage", "Examples", "Percentage", ); print_table_line(); for (file, &count) in &self.items { - if let (Some(percentage), Some(examples_percentage)) = - (count.percentage(), count.examples_percentage()) - { + if let Some(percentage) = count.percentage() { print_table_record( &limit_filename_len(file.to_string()), count, percentage, - examples_percentage, + count.examples_percentage().unwrap_or(0.), ); total += count; @@ -176,19 +180,6 @@ fn print_table_record( impl fold::DocFolder for CoverageCalculator { fn fold_item(&mut self, i: clean::Item) -> Option { - let has_docs = !i.attrs.doc_strings.is_empty(); - let mut tests = Tests { found_tests: 0 }; - - find_testable_code( - &i.attrs.doc_strings.iter().map(|d| d.as_str()).collect::>().join("\n"), - &mut tests, - ErrorCodes::No, - false, - None, - ); - - let has_doc_example = tests.found_tests != 0; - match i.inner { _ if !i.def_id.is_local() => { // non-local items are skipped because they can be out of the users control, @@ -237,11 +228,24 @@ fn fold_item(&mut self, i: clean::Item) -> Option { } } _ => { + let has_docs = !i.attrs.doc_strings.is_empty(); + let mut tests = Tests { found_tests: 0 }; + + find_testable_code( + &i.attrs.doc_strings.iter().map(|d| d.as_str()).collect::>().join("\n"), + &mut tests, + ErrorCodes::No, + false, + None, + ); + + let has_doc_example = tests.found_tests != 0; debug!("counting {:?} {:?} in {}", i.type_(), i.name, i.source.filename); - self.items - .entry(i.source.filename.clone()) - .or_default() - .count_item(has_docs, has_doc_example); + self.items.entry(i.source.filename.clone()).or_default().count_item( + has_docs, + has_doc_example, + should_have_doc_example(&i.inner), + ); } } diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 97b9fcce05b..bf091a0a624 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1,4 +1,5 @@ use rustc_ast as ast; +use rustc_data_structures::stable_set::FxHashSet; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_expand::base::SyntaxExtensionKind; use rustc_feature::UnstableFeatures; @@ -180,12 +181,10 @@ fn macro_resolve(&self, path_str: &str, parent_id: Option) -> Option fn resolve( &self, path_str: &str, - disambiguator: Option, ns: Namespace, current_item: &Option, parent_id: Option, extra_fragment: &Option, - item_opt: Option<&Item>, ) -> Result<(Res, Option), ErrorKind> { let cx = self.cx; @@ -218,18 +217,6 @@ fn resolve( return Ok((res, Some(path_str.to_owned()))); } Res::Def(DefKind::Mod, _) => { - // This resolved to a module, but we want primitive types to take precedence instead. - if matches!( - disambiguator, - None | Some(Disambiguator::Namespace(Namespace::TypeNS)) - ) { - if let Some((path, prim)) = is_primitive(path_str, ns) { - if extra_fragment.is_some() { - return Err(ErrorKind::AnchorFailure(AnchorFailure::Primitive)); - } - return Ok((prim, Some(path.to_owned()))); - } - } return Ok((res, extra_fragment.clone())); } _ => { @@ -245,13 +232,6 @@ fn resolve( return Err(ErrorKind::AnchorFailure(AnchorFailure::Primitive)); } return Ok((prim, Some(path.to_owned()))); - } else { - // If resolution failed, it may still be a method - // because methods are not handled by the resolver - // If so, bail when we're not looking for a value. - if ns != ValueNS { - return Err(ErrorKind::ResolutionFailure); - } } // Try looking for methods and associated items. @@ -299,65 +279,56 @@ fn resolve( }) .map_err(|_| ErrorKind::ResolutionFailure)?; if let Res::Err = ty_res { - return self.variant_field(path_str, current_item, module_id); + return if ns == Namespace::ValueNS { + self.variant_field(path_str, current_item, module_id) + } else { + Err(ErrorKind::ResolutionFailure) + }; } let ty_res = ty_res.map_id(|_| panic!("unexpected node_id")); - match ty_res { + let res = match ty_res { Res::Def( DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::TyAlias, did, ) => { + debug!("looking for associated item named {} for item {:?}", item_name, did); // Checks if item_name belongs to `impl SomeItem` - let impl_item = cx + let kind = cx .tcx .inherent_impls(did) .iter() - .flat_map(|imp| cx.tcx.associated_items(*imp).in_definition_order()) - .find(|item| item.ident.name == item_name); - let trait_item = item_opt - .and_then(|item| self.cx.as_local_hir_id(item.def_id)) - .and_then(|item_hir| { - // Checks if item_name belongs to `impl SomeTrait for SomeItem` - let parent_hir = self.cx.tcx.hir().get_parent_item(item_hir); - let item_parent = self.cx.tcx.hir().find(parent_hir); - match item_parent { - Some(hir::Node::Item(hir::Item { - kind: hir::ItemKind::Impl { of_trait: Some(_), self_ty, .. }, - .. - })) => cx - .tcx - .associated_item_def_ids(self_ty.hir_id.owner) - .iter() - .map(|child| { - let associated_item = cx.tcx.associated_item(*child); - associated_item - }) - .find(|child| child.ident.name == item_name), - _ => None, - } + .flat_map(|&imp| { + cx.tcx.associated_items(imp).find_by_name_and_namespace( + cx.tcx, + Ident::with_dummy_span(item_name), + ns, + imp, + ) + }) + .map(|item| item.kind) + // There should only ever be one associated item that matches from any inherent impl + .next() + // Check if item_name belongs to `impl SomeTrait for SomeItem` + // This gives precedence to `impl SomeItem`: + // Although having both would be ambiguous, use impl version for compat. sake. + // To handle that properly resolve() would have to support + // something like [`ambi_fn`](::ambi_fn) + .or_else(|| { + let kind = resolve_associated_trait_item( + did, module_id, item_name, ns, &self.cx, + ); + debug!("got associated item kind {:?}", kind); + kind }); - let item = match (impl_item, trait_item) { - (Some(from_impl), Some(_)) => { - // Although it's ambiguous, return impl version for compat. sake. - // To handle that properly resolve() would have to support - // something like - // [`ambi_fn`](::ambi_fn) - Some(from_impl) - } - (None, Some(from_trait)) => Some(from_trait), - (Some(from_impl), None) => Some(from_impl), - _ => None, - }; - - if let Some(item) = item { - let out = match item.kind { - ty::AssocKind::Fn if ns == ValueNS => "method", - ty::AssocKind::Const if ns == ValueNS => "associatedconstant", - ty::AssocKind::Type if ns == ValueNS => "associatedtype", - _ => return self.variant_field(path_str, current_item, module_id), + + if let Some(kind) = kind { + let out = match kind { + ty::AssocKind::Fn => "method", + ty::AssocKind::Const => "associatedconstant", + ty::AssocKind::Type => "associatedtype", }; - if extra_fragment.is_some() { - Err(ErrorKind::AnchorFailure(if item.kind == ty::AssocKind::Fn { + Some(if extra_fragment.is_some() { + Err(ErrorKind::AnchorFailure(if kind == ty::AssocKind::Fn { AnchorFailure::Method } else { AnchorFailure::AssocConstant @@ -366,20 +337,21 @@ fn resolve( // HACK(jynelson): `clean` expects the type, not the associated item. // but the disambiguator logic expects the associated item. // Store the kind in a side channel so that only the disambiguator logic looks at it. - self.kind_side_channel.replace(Some(item.kind.as_def_kind())); + self.kind_side_channel.set(Some(kind.as_def_kind())); Ok((ty_res, Some(format!("{}.{}", out, item_name)))) - } - } else { + }) + } else if ns == Namespace::ValueNS { match cx.tcx.type_of(did).kind { ty::Adt(def, _) => { - if let Some(item) = if def.is_enum() { + let field = if def.is_enum() { def.all_fields().find(|item| item.ident.name == item_name) } else { def.non_enum_variant() .fields .iter() .find(|item| item.ident.name == item_name) - } { + }; + field.map(|item| { if extra_fragment.is_some() { Err(ErrorKind::AnchorFailure(if def.is_enum() { AnchorFailure::Variant @@ -400,31 +372,31 @@ fn resolve( )), )) } - } else { - self.variant_field(path_str, current_item, module_id) - } + }) } - _ => self.variant_field(path_str, current_item, module_id), + _ => None, } + } else { + // We already know this isn't in ValueNS, so no need to check variant_field + return Err(ErrorKind::ResolutionFailure); } } - Res::Def(DefKind::Trait, did) => { - let item = cx - .tcx - .associated_item_def_ids(did) - .iter() - .map(|item| cx.tcx.associated_item(*item)) - .find(|item| item.ident.name == item_name); - if let Some(item) = item { - let kind = - match item.kind { - ty::AssocKind::Const if ns == ValueNS => "associatedconstant", - ty::AssocKind::Type if ns == TypeNS => "associatedtype", - ty::AssocKind::Fn if ns == ValueNS => { - if item.defaultness.has_value() { "method" } else { "tymethod" } + Res::Def(DefKind::Trait, did) => cx + .tcx + .associated_items(did) + .find_by_name_and_namespace(cx.tcx, Ident::with_dummy_span(item_name), ns, did) + .map(|item| { + let kind = match item.kind { + ty::AssocKind::Const => "associatedconstant", + ty::AssocKind::Type => "associatedtype", + ty::AssocKind::Fn => { + if item.defaultness.has_value() { + "method" + } else { + "tymethod" } - _ => return self.variant_field(path_str, current_item, module_id), - }; + } + }; if extra_fragment.is_some() { Err(ErrorKind::AnchorFailure(if item.kind == ty::AssocKind::Const { @@ -438,12 +410,16 @@ fn resolve( let res = Res::Def(item.kind.as_def_kind(), item.def_id); Ok((res, Some(format!("{}.{}", kind, item_name)))) } - } else { - self.variant_field(path_str, current_item, module_id) - } + }), + _ => None, + }; + res.unwrap_or_else(|| { + if ns == Namespace::ValueNS { + self.variant_field(path_str, current_item, module_id) + } else { + Err(ErrorKind::ResolutionFailure) } - _ => self.variant_field(path_str, current_item, module_id), - } + }) } else { debug!("attempting to resolve item without parent module: {}", path_str); Err(ErrorKind::ResolutionFailure) @@ -451,6 +427,134 @@ fn resolve( } } +fn resolve_associated_trait_item( + did: DefId, + module: DefId, + item_name: Symbol, + ns: Namespace, + cx: &DocContext<'_>, +) -> Option { + let ty = cx.tcx.type_of(did); + // First consider automatic impls: `impl From for T` + let implicit_impls = crate::clean::get_auto_trait_and_blanket_impls(cx, ty, did); + let mut candidates: Vec<_> = implicit_impls + .flat_map(|impl_outer| { + match impl_outer.inner { + ImplItem(impl_) => { + debug!("considering auto or blanket impl for trait {:?}", impl_.trait_); + // Give precedence to methods that were overridden + if !impl_.provided_trait_methods.contains(&*item_name.as_str()) { + let mut items = impl_.items.into_iter().filter_map(|assoc| { + if assoc.name.as_deref() != Some(&*item_name.as_str()) { + return None; + } + let kind = assoc + .inner + .as_assoc_kind() + .expect("inner items for a trait should be associated items"); + if kind.namespace() != ns { + return None; + } + + trace!("considering associated item {:?}", assoc.inner); + // We have a slight issue: normal methods come from `clean` types, + // but provided methods come directly from `tcx`. + // Fortunately, we don't need the whole method, we just need to know + // what kind of associated item it is. + Some((assoc.def_id, kind)) + }); + let assoc = items.next(); + debug_assert_eq!(items.count(), 0); + assoc + } else { + // These are provided methods or default types: + // ``` + // trait T { + // type A = usize; + // fn has_default() -> A { 0 } + // } + // ``` + let trait_ = impl_.trait_.unwrap().def_id().unwrap(); + cx.tcx + .associated_items(trait_) + .find_by_name_and_namespace( + cx.tcx, + Ident::with_dummy_span(item_name), + ns, + trait_, + ) + .map(|assoc| (assoc.def_id, assoc.kind)) + } + } + _ => panic!("get_impls returned something that wasn't an impl"), + } + }) + .collect(); + + // Next consider explicit impls: `impl MyTrait for MyType` + // Give precedence to inherent impls. + if candidates.is_empty() { + let traits = traits_implemented_by(cx, did, module); + debug!("considering traits {:?}", traits); + candidates.extend(traits.iter().filter_map(|&trait_| { + cx.tcx + .associated_items(trait_) + .find_by_name_and_namespace(cx.tcx, Ident::with_dummy_span(item_name), ns, trait_) + .map(|assoc| (assoc.def_id, assoc.kind)) + })); + } + // FIXME: warn about ambiguity + debug!("the candidates were {:?}", candidates); + candidates.pop().map(|(_, kind)| kind) +} + +/// Given a type, return all traits in scope in `module` implemented by that type. +/// +/// NOTE: this cannot be a query because more traits could be available when more crates are compiled! +/// So it is not stable to serialize cross-crate. +fn traits_implemented_by(cx: &DocContext<'_>, type_: DefId, module: DefId) -> FxHashSet { + let mut cache = cx.module_trait_cache.borrow_mut(); + let in_scope_traits = cache.entry(module).or_insert_with(|| { + cx.enter_resolver(|resolver| { + resolver.traits_in_scope(module).into_iter().map(|candidate| candidate.def_id).collect() + }) + }); + + let ty = cx.tcx.type_of(type_); + let iter = in_scope_traits.iter().flat_map(|&trait_| { + trace!("considering explicit impl for trait {:?}", trait_); + let mut saw_impl = false; + // Look at each trait implementation to see if it's an impl for `did` + cx.tcx.for_each_relevant_impl(trait_, ty, |impl_| { + // FIXME: this is inefficient, find a way to short-circuit for_each_* so this doesn't take as long + if saw_impl { + return; + } + + let trait_ref = cx.tcx.impl_trait_ref(impl_).expect("this is not an inherent impl"); + // Check if these are the same type. + let impl_type = trait_ref.self_ty(); + debug!( + "comparing type {} with kind {:?} against type {:?}", + impl_type, impl_type.kind, type_ + ); + // Fast path: if this is a primitive simple `==` will work + saw_impl = impl_type == ty + || match impl_type.kind { + // Check if these are the same def_id + ty::Adt(def, _) => { + debug!("adt def_id: {:?}", def.did); + def.did == type_ + } + ty::Foreign(def_id) => def_id == type_, + _ => false, + }; + }); + if saw_impl { Some(trait_) } else { None } + }); + iter.collect() +} + /// Check for resolve collisions between a trait and its derive /// /// These are common and we should just resolve to the trait in that case @@ -596,7 +700,7 @@ fn fold_item(&mut self, mut item: Item) -> Option { let resolved_self; let mut path_str; let disambiguator; - let (res, fragment) = { + let (mut res, mut fragment) = { path_str = if let Ok((d, path)) = Disambiguator::from_str(&link) { disambiguator = Some(d); path @@ -636,16 +740,9 @@ fn fold_item(&mut self, mut item: Item) -> Option { } match disambiguator.map(Disambiguator::ns) { - Some(ns @ ValueNS) => { - match self.resolve( - path_str, - disambiguator, - ns, - ¤t_item, - base_node, - &extra_fragment, - Some(&item), - ) { + Some(ns @ (ValueNS | TypeNS)) => { + match self.resolve(path_str, ns, ¤t_item, base_node, &extra_fragment) + { Ok(res) => res, Err(ErrorKind::ResolutionFailure) => { resolution_failure(cx, &item, path_str, &dox, link_range); @@ -660,28 +757,6 @@ fn fold_item(&mut self, mut item: Item) -> Option { } } } - Some(ns @ TypeNS) => { - match self.resolve( - path_str, - disambiguator, - ns, - ¤t_item, - base_node, - &extra_fragment, - Some(&item), - ) { - Ok(res) => res, - Err(ErrorKind::ResolutionFailure) => { - resolution_failure(cx, &item, path_str, &dox, link_range); - // This could just be a normal link. - continue; - } - Err(ErrorKind::AnchorFailure(msg)) => { - anchor_failure(cx, &item, &ori_link, &dox, link_range, msg); - continue; - } - } - } None => { // Try everything! let mut candidates = PerNS { @@ -690,33 +765,34 @@ fn fold_item(&mut self, mut item: Item) -> Option { .map(|res| (res, extra_fragment.clone())), type_ns: match self.resolve( path_str, - disambiguator, TypeNS, ¤t_item, base_node, &extra_fragment, - Some(&item), ) { + Ok(res) => { + debug!("got res in TypeNS: {:?}", res); + Some(res) + } Err(ErrorKind::AnchorFailure(msg)) => { anchor_failure(cx, &item, &ori_link, &dox, link_range, msg); continue; } - x => x.ok(), + Err(ErrorKind::ResolutionFailure) => None, }, value_ns: match self.resolve( path_str, - disambiguator, ValueNS, ¤t_item, base_node, &extra_fragment, - Some(&item), ) { + Ok(res) => Some(res), Err(ErrorKind::AnchorFailure(msg)) => { anchor_failure(cx, &item, &ori_link, &dox, link_range, msg); continue; } - x => x.ok(), + Err(ErrorKind::ResolutionFailure) => None, } .and_then(|(res, fragment)| { // Constructors are picked up in the type namespace. @@ -751,13 +827,18 @@ fn fold_item(&mut self, mut item: Item) -> Option { if is_derive_trait_collision(&candidates) { candidates.macro_ns = None; } + let candidates = + candidates.map(|candidate| candidate.map(|(res, _)| res)); + let candidates = [TypeNS, ValueNS, MacroNS] + .iter() + .filter_map(|&ns| candidates[ns].map(|res| (res, ns))); ambiguity_error( cx, &item, path_str, &dox, link_range, - candidates.map(|candidate| candidate.map(|(res, _)| res)), + candidates.collect(), ); continue; } @@ -773,13 +854,81 @@ fn fold_item(&mut self, mut item: Item) -> Option { } }; + // Check for a primitive which might conflict with a module + // Report the ambiguity and require that the user specify which one they meant. + // FIXME: could there ever be a primitive not in the type namespace? + if matches!( + disambiguator, + None | Some(Disambiguator::Namespace(Namespace::TypeNS) | Disambiguator::Primitive) + ) && !matches!(res, Res::PrimTy(_)) + { + if let Some((path, prim)) = is_primitive(path_str, TypeNS) { + // `prim@char` + if matches!(disambiguator, Some(Disambiguator::Primitive)) { + if fragment.is_some() { + anchor_failure( + cx, + &item, + path_str, + &dox, + link_range, + AnchorFailure::Primitive, + ); + continue; + } + res = prim; + fragment = Some(path.to_owned()); + } else { + // `[char]` when a `char` module is in scope + let candidates = vec![(res, TypeNS), (prim, TypeNS)]; + ambiguity_error(cx, &item, path_str, &dox, link_range, candidates); + continue; + } + } + } + + let report_mismatch = |specified: Disambiguator, resolved: Disambiguator| { + // The resolved item did not match the disambiguator; give a better error than 'not found' + let msg = format!("incompatible link kind for `{}`", path_str); + report_diagnostic(cx, &msg, &item, &dox, link_range.clone(), |diag, sp| { + let note = format!( + "this link resolved to {} {}, which is not {} {}", + resolved.article(), + resolved.descr(), + specified.article(), + specified.descr() + ); + let suggestion = resolved.display_for(path_str); + let help_msg = + format!("to link to the {}, use its disambiguator", resolved.descr()); + diag.note(¬e); + if let Some(sp) = sp { + diag.span_suggestion( + sp, + &help_msg, + suggestion, + Applicability::MaybeIncorrect, + ); + } else { + diag.help(&format!("{}: {}", help_msg, suggestion)); + } + }); + }; if let Res::PrimTy(_) = res { - item.attrs.links.push((ori_link, None, fragment)); + match disambiguator { + Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => { + item.attrs.links.push((ori_link, None, fragment)) + } + Some(other) => { + report_mismatch(other, Disambiguator::Primitive); + continue; + } + } } else { debug!("intra-doc link to {} resolved to {:?}", path_str, res); // Disallow e.g. linking to enums with `struct@` - if let Res::Def(kind, id) = res { + if let Res::Def(kind, _) = res { debug!("saw kind {:?} with disambiguator {:?}", kind, disambiguator); match (self.kind_side_channel.take().unwrap_or(kind), disambiguator) { | (DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst, Some(Disambiguator::Kind(DefKind::Const))) @@ -793,22 +942,8 @@ fn fold_item(&mut self, mut item: Item) -> Option { // All of these are valid, so do nothing => {} (actual, Some(Disambiguator::Kind(expected))) if actual == expected => {} - (_, Some(Disambiguator::Kind(expected))) => { - // The resolved item did not match the disambiguator; give a better error than 'not found' - let msg = format!("incompatible link kind for `{}`", path_str); - report_diagnostic(cx, &msg, &item, &dox, link_range, |diag, sp| { - // HACK(jynelson): by looking at the source I saw the DefId we pass - // for `expected.descr()` doesn't matter, since it's not a crate - let note = format!("this link resolved to {} {}, which is not {} {}", kind.article(), kind.descr(id), expected.article(), expected.descr(id)); - let suggestion = Disambiguator::display_for(kind, path_str); - let help_msg = format!("to link to the {}, use its disambiguator", kind.descr(id)); - diag.note(¬e); - if let Some(sp) = sp { - diag.span_suggestion(sp, &help_msg, suggestion, Applicability::MaybeIncorrect); - } else { - diag.help(&format!("{}: {}", help_msg, suggestion)); - } - }); + (_, Some(specified @ Disambiguator::Kind(_) | specified @ Disambiguator::Primitive)) => { + report_mismatch(specified, Disambiguator::Kind(kind)); continue; } } @@ -864,6 +999,7 @@ fn fold_crate(&mut self, mut c: Crate) -> Crate { #[derive(Copy, Clone, Debug, PartialEq, Eq)] enum Disambiguator { + Primitive, Kind(DefKind), Namespace(Namespace), } @@ -871,7 +1007,7 @@ enum Disambiguator { impl Disambiguator { /// (disambiguator, path_str) fn from_str(link: &str) -> Result<(Self, &str), ()> { - use Disambiguator::{Kind, Namespace as NS}; + use Disambiguator::{Kind, Namespace as NS, Primitive}; let find_suffix = || { let suffixes = [ @@ -902,6 +1038,7 @@ fn from_str(link: &str) -> Result<(Self, &str), ()> { "type" => NS(Namespace::TypeNS), "value" => NS(Namespace::ValueNS), "macro" => NS(Namespace::MacroNS), + "prim" | "primitive" => Primitive, _ => return find_suffix(), }; Ok((d, &rest[1..])) @@ -910,7 +1047,12 @@ fn from_str(link: &str) -> Result<(Self, &str), ()> { } } - fn display_for(kind: DefKind, path_str: &str) -> String { + fn display_for(self, path_str: &str) -> String { + let kind = match self { + Disambiguator::Primitive => return format!("prim@{}", path_str), + Disambiguator::Kind(kind) => kind, + Disambiguator::Namespace(_) => panic!("display_for cannot be used on namespaces"), + }; if kind == DefKind::Macro(MacroKind::Bang) { return format!("{}!", path_str); } else if kind == DefKind::Fn || kind == DefKind::AssocFn { @@ -946,6 +1088,25 @@ fn ns(self) -> Namespace { Self::Kind(k) => { k.ns().expect("only DefKinds with a valid namespace can be disambiguators") } + Self::Primitive => TypeNS, + } + } + + fn article(self) -> &'static str { + match self { + Self::Namespace(_) => panic!("article() doesn't make sense for namespaces"), + Self::Kind(k) => k.article(), + Self::Primitive => "a", + } + } + + fn descr(self) -> &'static str { + match self { + Self::Namespace(n) => n.descr(), + // HACK(jynelson): by looking at the source I saw the DefId we pass + // for `expected.descr()` doesn't matter, since it's not a crate + Self::Kind(k) => k.descr(DefId::local(hir::def_id::DefIndex::from_usize(0))), + Self::Primitive => "builtin type", } } } @@ -1086,14 +1247,10 @@ fn ambiguity_error( path_str: &str, dox: &str, link_range: Option>, - candidates: PerNS>, + candidates: Vec<(Res, Namespace)>, ) { let mut msg = format!("`{}` is ", path_str); - let candidates = [TypeNS, ValueNS, MacroNS] - .iter() - .filter_map(|&ns| candidates[ns].map(|res| (res, ns))) - .collect::>(); match candidates.as_slice() { [(first_def, _), (second_def, _)] => { msg += &format!( @@ -1132,6 +1289,7 @@ fn ambiguity_error( } _ => { let type_ = match (res, ns) { + (Res::PrimTy(_), _) => "prim", (Res::Def(DefKind::Const, _), _) => "const", (Res::Def(DefKind::Static, _), _) => "static", (Res::Def(DefKind::Struct, _), _) => "struct", diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 24baff46dcf..b2c4c30d8ff 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -29,7 +29,9 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate { for &cnum in cx.tcx.crates().iter() { for &(did, _) in cx.tcx.all_trait_implementations(cnum).iter() { - inline::build_impl(cx, did, None, &mut new_items); + cx.tcx.sess.time("build_extern_trait_impl", || { + inline::build_impl(cx, did, None, &mut new_items); + }); } } @@ -87,7 +89,9 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate { for &trait_did in cx.tcx.all_traits(LOCAL_CRATE).iter() { for &impl_node in cx.tcx.hir().trait_impls(trait_did) { let impl_did = cx.tcx.hir().local_def_id(impl_node); - inline::build_impl(cx, impl_did.to_def_id(), None, &mut new_items); + cx.tcx.sess.time("build_local_trait_impl", || { + inline::build_impl(cx, impl_did.to_def_id(), None, &mut new_items); + }); } } diff --git a/src/librustdoc/passes/doc_test_lints.rs b/src/librustdoc/passes/doc_test_lints.rs index 1fdc4ee247a..a465a5f681f 100644 --- a/src/librustdoc/passes/doc_test_lints.rs +++ b/src/librustdoc/passes/doc_test_lints.rs @@ -4,6 +4,7 @@ //! - PRIVATE_DOC_TESTS: this looks for private items with doc-tests. use super::{span_of_attrs, Pass}; +use crate::clean; use crate::clean::*; use crate::core::DocContext; use crate::fold::DocFolder; @@ -59,6 +60,22 @@ fn add_test(&mut self, _: String, _: LangString, _: usize) { } } +pub fn should_have_doc_example(item_kind: &clean::ItemEnum) -> bool { + !matches!(item_kind, + clean::StructFieldItem(_) + | clean::VariantItem(_) + | clean::AssocConstItem(_, _) + | clean::AssocTypeItem(_, _) + | clean::TypedefItem(_, _) + | clean::StaticItem(_) + | clean::ConstantItem(_) + | clean::ExternCrateItem(_, _) + | clean::ImportItem(_) + | clean::PrimitiveItem(_) + | clean::KeywordItem(_) + ) +} + pub fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) { let hir_id = match cx.as_local_hir_id(item.def_id) { Some(hir_id) => hir_id, @@ -73,13 +90,7 @@ pub fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) { find_testable_code(&dox, &mut tests, ErrorCodes::No, false, None); if tests.found_tests == 0 { - use ItemEnum::*; - - let should_report = match item.inner { - ExternCrateItem(_, _) | ImportItem(_) | PrimitiveItem(_) | KeywordItem(_) => false, - _ => true, - }; - if should_report { + if should_have_doc_example(&item.inner) { debug!("reporting error for {:?} (hir_id={:?})", item, hir_id); let sp = span_of_attrs(&item.attrs).unwrap_or(item.source.span()); cx.tcx.struct_span_lint_hir( diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 693d5b9fb07..7b7c152d8ab 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -281,7 +281,7 @@ fn run_test( for codegen_options_str in &options.codegen_options_strs { compiler.arg("-C").arg(&codegen_options_str); } - for debugging_option_str in &options.debugging_options_strs { + for debugging_option_str in &options.debugging_opts_strs { compiler.arg("-Z").arg(&debugging_option_str); } if no_run && !compile_fail { diff --git a/src/llvm-project b/src/llvm-project index 86b120e6f30..45790d79496 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 86b120e6f302d39cd6973b6391fb299d7bc22122 +Subproject commit 45790d79496be37fbce6ec57abad5af8fa7a34d7 diff --git a/src/rustllvm/CoverageMappingWrapper.cpp b/src/rustllvm/CoverageMappingWrapper.cpp index 4d15e31df15..81aba0cbf7d 100644 --- a/src/rustllvm/CoverageMappingWrapper.cpp +++ b/src/rustllvm/CoverageMappingWrapper.cpp @@ -3,6 +3,7 @@ #include "llvm/ProfileData/Coverage/CoverageMappingWriter.h" #include "llvm/ProfileData/InstrProf.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/LEB128.h" #include @@ -12,14 +13,15 @@ extern "C" void LLVMRustCoverageWriteFilenamesSectionToBuffer( const char* const Filenames[], size_t FilenamesLen, RustStringRef BufferOut) { - SmallVector FilenameRefs; + // LLVM 11's CoverageFilenamesSectionWriter uses its new `Version4` format, + // so we're manually writing the `Version3` format ourselves. + RawRustStringOstream OS(BufferOut); + encodeULEB128(FilenamesLen, OS); for (size_t i = 0; i < FilenamesLen; i++) { - FilenameRefs.push_back(StringRef(Filenames[i])); + StringRef Filename(Filenames[i]); + encodeULEB128(Filename.size(), OS); + OS << Filename; } - auto FilenamesWriter = coverage::CoverageFilenamesSectionWriter( - makeArrayRef(FilenameRefs)); - RawRustStringOstream OS(BufferOut); - FilenamesWriter.write(OS); } extern "C" void LLVMRustCoverageWriteMappingToBuffer( @@ -64,5 +66,5 @@ extern "C" void LLVMRustCoverageWriteMappingVarNameToString(RustStringRef Str) { } extern "C" uint32_t LLVMRustCoverageMappingVersion() { - return coverage::CovMapVersion::CurrentVersion; + return coverage::CovMapVersion::Version3; } diff --git a/src/test/assembly/asm/aarch64-types.rs b/src/test/assembly/asm/aarch64-types.rs index a8df350ef60..e39f74c916c 100644 --- a/src/test/assembly/asm/aarch64-types.rs +++ b/src/test/assembly/asm/aarch64-types.rs @@ -553,3 +553,8 @@ pub unsafe fn $func(x: $ty) -> $ty { // CHECK: fmov s0, s0 // CHECK: //NO_APP check_reg!(v0_f64x2 f64x2 "s0" "fmov"); + +// Regression test for #75761 +pub unsafe fn issue_75761() { + asm!("", out("v0") _, out("x30") _); +} diff --git a/src/test/assembly/asm/riscv-types.rs b/src/test/assembly/asm/riscv-types.rs index 6b6e582442c..67dda1024fc 100644 --- a/src/test/assembly/asm/riscv-types.rs +++ b/src/test/assembly/asm/riscv-types.rs @@ -55,7 +55,8 @@ pub unsafe fn sym_fn() { // CHECK-LABEL: sym_static: // CHECK: #APP -// CHECK: lb t0, extern_static +// CHECK: auipc t0, %pcrel_hi(extern_static) +// CHECK: lb t0, %pcrel_lo(.Lpcrel_hi0)(t0) // CHECK: #NO_APP #[no_mangle] pub unsafe fn sym_static() { @@ -98,45 +99,45 @@ pub unsafe fn $func(x: $ty) -> $ty { // CHECK-LABEL: reg_i8: // CHECK: #APP -// CHECK: mv {{[a-z0-9]+}}, {{[a-z0-9]+}} +// CHECK: add {{[a-z0-9]+}}, zero, {{[a-z0-9]+}} // CHECK: #NO_APP check!(reg_i8 i8 reg "mv"); // CHECK-LABEL: reg_i16: // CHECK: #APP -// CHECK: mv {{[a-z0-9]+}}, {{[a-z0-9]+}} +// CHECK: add {{[a-z0-9]+}}, zero, {{[a-z0-9]+}} // CHECK: #NO_APP check!(reg_i16 i16 reg "mv"); // CHECK-LABEL: reg_i32: // CHECK: #APP -// CHECK: mv {{[a-z0-9]+}}, {{[a-z0-9]+}} +// CHECK: add {{[a-z0-9]+}}, zero, {{[a-z0-9]+}} // CHECK: #NO_APP check!(reg_i32 i32 reg "mv"); // CHECK-LABEL: reg_f32: // CHECK: #APP -// CHECK: mv {{[a-z0-9]+}}, {{[a-z0-9]+}} +// CHECK: add {{[a-z0-9]+}}, zero, {{[a-z0-9]+}} // CHECK: #NO_APP check!(reg_f32 f32 reg "mv"); // riscv64-LABEL: reg_i64: // riscv64: #APP -// riscv64: mv {{[a-z0-9]+}}, {{[a-z0-9]+}} +// riscv64: add {{[a-z0-9]+}}, zero, {{[a-z0-9]+}} // riscv64: #NO_APP #[cfg(riscv64)] check!(reg_i64 i64 reg "mv"); // riscv64-LABEL: reg_f64: // riscv64: #APP -// riscv64: mv {{[a-z0-9]+}}, {{[a-z0-9]+}} +// riscv64: add {{[a-z0-9]+}}, zero, {{[a-z0-9]+}} // riscv64: #NO_APP #[cfg(riscv64)] check!(reg_f64 f64 reg "mv"); // CHECK-LABEL: reg_ptr: // CHECK: #APP -// CHECK: mv {{[a-z0-9]+}}, {{[a-z0-9]+}} +// CHECK: add {{[a-z0-9]+}}, zero, {{[a-z0-9]+}} // CHECK: #NO_APP check!(reg_ptr ptr reg "mv"); @@ -154,45 +155,45 @@ pub unsafe fn $func(x: $ty) -> $ty { // CHECK-LABEL: a0_i8: // CHECK: #APP -// CHECK: mv a0, a0 +// CHECK: add a0, zero, a0 // CHECK: #NO_APP check_reg!(a0_i8 i8 "a0" "mv"); // CHECK-LABEL: a0_i16: // CHECK: #APP -// CHECK: mv a0, a0 +// CHECK: add a0, zero, a0 // CHECK: #NO_APP check_reg!(a0_i16 i16 "a0" "mv"); // CHECK-LABEL: a0_i32: // CHECK: #APP -// CHECK: mv a0, a0 +// CHECK: add a0, zero, a0 // CHECK: #NO_APP check_reg!(a0_i32 i32 "a0" "mv"); // CHECK-LABEL: a0_f32: // CHECK: #APP -// CHECK: mv a0, a0 +// CHECK: add a0, zero, a0 // CHECK: #NO_APP check_reg!(a0_f32 f32 "a0" "mv"); // riscv64-LABEL: a0_i64: // riscv64: #APP -// riscv64: mv a0, a0 +// riscv64: add a0, zero, a0 // riscv64: #NO_APP #[cfg(riscv64)] check_reg!(a0_i64 i64 "a0" "mv"); // riscv64-LABEL: a0_f64: // riscv64: #APP -// riscv64: mv a0, a0 +// riscv64: add a0, zero, a0 // riscv64: #NO_APP #[cfg(riscv64)] check_reg!(a0_f64 f64 "a0" "mv"); // CHECK-LABEL: a0_ptr: // CHECK: #APP -// CHECK: mv a0, a0 +// CHECK: add a0, zero, a0 // CHECK: #NO_APP check_reg!(a0_ptr ptr "a0" "mv"); diff --git a/src/test/codegen/scalar-pair-bool.rs b/src/test/codegen/scalar-pair-bool.rs index d91ee7f816d..4704c8ad797 100644 --- a/src/test/codegen/scalar-pair-bool.rs +++ b/src/test/codegen/scalar-pair-bool.rs @@ -24,8 +24,9 @@ pub fn pair_i32_bool(pair: (i32, bool)) -> (i32, bool) { #[no_mangle] pub fn pair_and_or((a, b): (bool, bool)) -> (bool, bool) { // Make sure it can operate directly on the unpacked args - // CHECK: and i1 %_1.0, %_1.1 - // CHECK: or i1 %_1.0, %_1.1 + // (but it might not be using simple and/or instructions) + // CHECK-DAG: %_1.0 + // CHECK-DAG: %_1.1 (a && b, a || b) } diff --git a/src/test/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir b/src/test/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir index d9b5094f1e1..a9568112620 100644 --- a/src/test/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir +++ b/src/test/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir @@ -287,12 +287,6 @@ fn address_of_reborrow() -> () { FakeRead(ForLet, _47); // scope 13 at $DIR/address-of.rs:36:9: 36:10 AscribeUserType(_47, o, UserTypeProjection { base: UserType(29), projs: [] }); // scope 13 at $DIR/address-of.rs:36:12: 36:22 _0 = const (); // scope 0 at $DIR/address-of.rs:3:26: 37:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/address-of.rs:3:26: 37:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_47); // scope 13 at $DIR/address-of.rs:37:1: 37:2 StorageDead(_45); // scope 12 at $DIR/address-of.rs:37:1: 37:2 StorageDead(_44); // scope 11 at $DIR/address-of.rs:37:1: 37:2 diff --git a/src/test/mir-opt/address_of.borrow_and_cast.SimplifyCfg-initial.after.mir b/src/test/mir-opt/address_of.borrow_and_cast.SimplifyCfg-initial.after.mir index 4a7e8de29ec..e058b0aaa8f 100644 --- a/src/test/mir-opt/address_of.borrow_and_cast.SimplifyCfg-initial.after.mir +++ b/src/test/mir-opt/address_of.borrow_and_cast.SimplifyCfg-initial.after.mir @@ -39,12 +39,6 @@ fn borrow_and_cast(_1: i32) -> () { FakeRead(ForLet, _6); // scope 2 at $DIR/address-of.rs:44:9: 44:10 StorageDead(_7); // scope 2 at $DIR/address-of.rs:44:31: 44:32 _0 = const (); // scope 0 at $DIR/address-of.rs:41:32: 45:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/address-of.rs:41:32: 45:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_6); // scope 2 at $DIR/address-of.rs:45:1: 45:2 StorageDead(_4); // scope 1 at $DIR/address-of.rs:45:1: 45:2 StorageDead(_2); // scope 0 at $DIR/address-of.rs:45:1: 45:2 diff --git a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir.32bit b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir.32bit index 895824947e9..2216c2bc92a 100644 --- a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir.32bit +++ b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir.32bit @@ -36,10 +36,7 @@ fn main() -> () { StorageLive(_5); // scope 3 at $DIR/array-index-is-temporary.rs:16:12: 16:29 StorageLive(_6); // scope 4 at $DIR/array-index-is-temporary.rs:16:25: 16:26 _6 = _3; // scope 4 at $DIR/array-index-is-temporary.rs:16:25: 16:26 - _5 = const foo(move _6) -> bb1; // scope 4 at $DIR/array-index-is-temporary.rs:16:21: 16:27 - // ty::Const - // + ty: unsafe fn(*mut usize) -> u32 {foo} - // + val: Value(Scalar()) + _5 = foo(move _6) -> bb1; // scope 4 at $DIR/array-index-is-temporary.rs:16:21: 16:27 // mir::Constant // + span: $DIR/array-index-is-temporary.rs:16:21: 16:24 // + literal: Const { ty: unsafe fn(*mut usize) -> u32 {foo}, val: Value(Scalar()) } @@ -59,12 +56,6 @@ fn main() -> () { StorageDead(_5); // scope 3 at $DIR/array-index-is-temporary.rs:16:28: 16:29 StorageDead(_7); // scope 3 at $DIR/array-index-is-temporary.rs:16:29: 16:30 _0 = const (); // scope 0 at $DIR/array-index-is-temporary.rs:12:11: 17:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/array-index-is-temporary.rs:12:11: 17:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_3); // scope 2 at $DIR/array-index-is-temporary.rs:17:1: 17:2 StorageDead(_2); // scope 1 at $DIR/array-index-is-temporary.rs:17:1: 17:2 StorageDead(_1); // scope 0 at $DIR/array-index-is-temporary.rs:17:1: 17:2 diff --git a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir.64bit b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir.64bit index 895824947e9..2216c2bc92a 100644 --- a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir.64bit +++ b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir.64bit @@ -36,10 +36,7 @@ fn main() -> () { StorageLive(_5); // scope 3 at $DIR/array-index-is-temporary.rs:16:12: 16:29 StorageLive(_6); // scope 4 at $DIR/array-index-is-temporary.rs:16:25: 16:26 _6 = _3; // scope 4 at $DIR/array-index-is-temporary.rs:16:25: 16:26 - _5 = const foo(move _6) -> bb1; // scope 4 at $DIR/array-index-is-temporary.rs:16:21: 16:27 - // ty::Const - // + ty: unsafe fn(*mut usize) -> u32 {foo} - // + val: Value(Scalar()) + _5 = foo(move _6) -> bb1; // scope 4 at $DIR/array-index-is-temporary.rs:16:21: 16:27 // mir::Constant // + span: $DIR/array-index-is-temporary.rs:16:21: 16:24 // + literal: Const { ty: unsafe fn(*mut usize) -> u32 {foo}, val: Value(Scalar()) } @@ -59,12 +56,6 @@ fn main() -> () { StorageDead(_5); // scope 3 at $DIR/array-index-is-temporary.rs:16:28: 16:29 StorageDead(_7); // scope 3 at $DIR/array-index-is-temporary.rs:16:29: 16:30 _0 = const (); // scope 0 at $DIR/array-index-is-temporary.rs:12:11: 17:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/array-index-is-temporary.rs:12:11: 17:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_3); // scope 2 at $DIR/array-index-is-temporary.rs:17:1: 17:2 StorageDead(_2); // scope 1 at $DIR/array-index-is-temporary.rs:17:1: 17:2 StorageDead(_1); // scope 0 at $DIR/array-index-is-temporary.rs:17:1: 17:2 diff --git a/src/test/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir b/src/test/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir index 4bb91169cb5..06869735f1e 100644 --- a/src/test/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir +++ b/src/test/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir @@ -67,12 +67,6 @@ fn main() -> () { bb6: { StorageDead(_6); // scope 4 at $DIR/basic_assignment.rs:23:19: 23:20 _0 = const (); // scope 0 at $DIR/basic_assignment.rs:10:11: 24:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/basic_assignment.rs:10:11: 24:2 - // + literal: Const { ty: (), val: Value(Scalar()) } drop(_5) -> [return: bb7, unwind: bb3]; // scope 3 at $DIR/basic_assignment.rs:24:1: 24:2 } diff --git a/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir b/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir index 259501c7de9..46dbb997ef4 100644 --- a/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir +++ b/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir @@ -14,10 +14,7 @@ fn main() -> () { StorageLive(_1); // scope 0 at $DIR/box_expr.rs:7:9: 7:10 StorageLive(_2); // scope 0 at $DIR/box_expr.rs:7:13: 7:25 _2 = Box(S); // scope 0 at $DIR/box_expr.rs:7:13: 7:25 - (*_2) = const S::new() -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/box_expr.rs:7:17: 7:25 - // ty::Const - // + ty: fn() -> S {S::new} - // + val: Value(Scalar()) + (*_2) = S::new() -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/box_expr.rs:7:17: 7:25 // mir::Constant // + span: $DIR/box_expr.rs:7:17: 7:23 // + literal: Const { ty: fn() -> S {S::new}, val: Value(Scalar()) } @@ -41,10 +38,7 @@ fn main() -> () { StorageLive(_3); // scope 1 at $DIR/box_expr.rs:8:5: 8:12 StorageLive(_4); // scope 1 at $DIR/box_expr.rs:8:10: 8:11 _4 = move _1; // scope 1 at $DIR/box_expr.rs:8:10: 8:11 - _3 = const std::mem::drop::>(move _4) -> [return: bb5, unwind: bb7]; // scope 1 at $DIR/box_expr.rs:8:5: 8:12 - // ty::Const - // + ty: fn(std::boxed::Box) {std::mem::drop::>} - // + val: Value(Scalar()) + _3 = std::mem::drop::>(move _4) -> [return: bb5, unwind: bb7]; // scope 1 at $DIR/box_expr.rs:8:5: 8:12 // mir::Constant // + span: $DIR/box_expr.rs:8:5: 8:9 // + literal: Const { ty: fn(std::boxed::Box) {std::mem::drop::>}, val: Value(Scalar()) } @@ -54,12 +48,6 @@ fn main() -> () { StorageDead(_4); // scope 1 at $DIR/box_expr.rs:8:11: 8:12 StorageDead(_3); // scope 1 at $DIR/box_expr.rs:8:12: 8:13 _0 = const (); // scope 0 at $DIR/box_expr.rs:6:11: 9:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/box_expr.rs:6:11: 9:2 - // + literal: Const { ty: (), val: Value(Scalar()) } drop(_1) -> bb8; // scope 0 at $DIR/box_expr.rs:9:1: 9:2 } diff --git a/src/test/mir-opt/byte_slice.main.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/byte_slice.main.SimplifyCfg-elaborate-drops.after.mir index 9e3f6cff4b3..3c56fce3f0a 100644 --- a/src/test/mir-opt/byte_slice.main.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/byte_slice.main.SimplifyCfg-elaborate-drops.after.mir @@ -23,12 +23,6 @@ fn main() -> () { StorageLive(_2); // scope 1 at $DIR/byte_slice.rs:6:9: 6:10 _2 = [const 5_u8, const 120_u8]; // scope 1 at $DIR/byte_slice.rs:6:13: 6:24 _0 = const (); // scope 0 at $DIR/byte_slice.rs:4:11: 7:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/byte_slice.rs:4:11: 7:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_2); // scope 1 at $DIR/byte_slice.rs:7:1: 7:2 StorageDead(_1); // scope 0 at $DIR/byte_slice.rs:7:1: 7:2 return; // scope 0 at $DIR/byte_slice.rs:7:2: 7:2 diff --git a/src/test/mir-opt/const_allocation.main.ConstProp.after.mir.32bit b/src/test/mir-opt/const_allocation.main.ConstProp.after.mir.32bit index 30a383fd162..09a4eca9389 100644 --- a/src/test/mir-opt/const_allocation.main.ConstProp.after.mir.32bit +++ b/src/test/mir-opt/const_allocation.main.ConstProp.after.mir.32bit @@ -19,12 +19,6 @@ fn main() -> () { StorageDead(_2); // scope 0 at $DIR/const_allocation.rs:8:8: 8:9 StorageDead(_1); // scope 0 at $DIR/const_allocation.rs:8:8: 8:9 _0 = const (); // scope 0 at $DIR/const_allocation.rs:7:11: 9:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/const_allocation.rs:7:11: 9:2 - // + literal: Const { ty: (), val: Value(Scalar()) } return; // scope 0 at $DIR/const_allocation.rs:9:2: 9:2 } } diff --git a/src/test/mir-opt/const_allocation.main.ConstProp.after.mir.64bit b/src/test/mir-opt/const_allocation.main.ConstProp.after.mir.64bit index 5fa54ae5a58..b10cc3e0985 100644 --- a/src/test/mir-opt/const_allocation.main.ConstProp.after.mir.64bit +++ b/src/test/mir-opt/const_allocation.main.ConstProp.after.mir.64bit @@ -19,12 +19,6 @@ fn main() -> () { StorageDead(_2); // scope 0 at $DIR/const_allocation.rs:8:8: 8:9 StorageDead(_1); // scope 0 at $DIR/const_allocation.rs:8:8: 8:9 _0 = const (); // scope 0 at $DIR/const_allocation.rs:7:11: 9:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/const_allocation.rs:7:11: 9:2 - // + literal: Const { ty: (), val: Value(Scalar()) } return; // scope 0 at $DIR/const_allocation.rs:9:2: 9:2 } } diff --git a/src/test/mir-opt/const_allocation2.main.ConstProp.after.mir.32bit b/src/test/mir-opt/const_allocation2.main.ConstProp.after.mir.32bit index 71d55dbb96e..19cbab74ab8 100644 --- a/src/test/mir-opt/const_allocation2.main.ConstProp.after.mir.32bit +++ b/src/test/mir-opt/const_allocation2.main.ConstProp.after.mir.32bit @@ -19,12 +19,6 @@ fn main() -> () { StorageDead(_2); // scope 0 at $DIR/const_allocation2.rs:5:8: 5:9 StorageDead(_1); // scope 0 at $DIR/const_allocation2.rs:5:8: 5:9 _0 = const (); // scope 0 at $DIR/const_allocation2.rs:4:11: 6:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/const_allocation2.rs:4:11: 6:2 - // + literal: Const { ty: (), val: Value(Scalar()) } return; // scope 0 at $DIR/const_allocation2.rs:6:2: 6:2 } } diff --git a/src/test/mir-opt/const_allocation2.main.ConstProp.after.mir.64bit b/src/test/mir-opt/const_allocation2.main.ConstProp.after.mir.64bit index 79bad7ea926..4dd960c8ddc 100644 --- a/src/test/mir-opt/const_allocation2.main.ConstProp.after.mir.64bit +++ b/src/test/mir-opt/const_allocation2.main.ConstProp.after.mir.64bit @@ -19,12 +19,6 @@ fn main() -> () { StorageDead(_2); // scope 0 at $DIR/const_allocation2.rs:5:8: 5:9 StorageDead(_1); // scope 0 at $DIR/const_allocation2.rs:5:8: 5:9 _0 = const (); // scope 0 at $DIR/const_allocation2.rs:4:11: 6:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/const_allocation2.rs:4:11: 6:2 - // + literal: Const { ty: (), val: Value(Scalar()) } return; // scope 0 at $DIR/const_allocation2.rs:6:2: 6:2 } } diff --git a/src/test/mir-opt/const_allocation3.main.ConstProp.after.mir.32bit b/src/test/mir-opt/const_allocation3.main.ConstProp.after.mir.32bit index 39c60ad987a..99d3a278d69 100644 --- a/src/test/mir-opt/const_allocation3.main.ConstProp.after.mir.32bit +++ b/src/test/mir-opt/const_allocation3.main.ConstProp.after.mir.32bit @@ -19,12 +19,6 @@ fn main() -> () { StorageDead(_2); // scope 0 at $DIR/const_allocation3.rs:5:8: 5:9 StorageDead(_1); // scope 0 at $DIR/const_allocation3.rs:5:8: 5:9 _0 = const (); // scope 0 at $DIR/const_allocation3.rs:4:11: 6:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/const_allocation3.rs:4:11: 6:2 - // + literal: Const { ty: (), val: Value(Scalar()) } return; // scope 0 at $DIR/const_allocation3.rs:6:2: 6:2 } } diff --git a/src/test/mir-opt/const_allocation3.main.ConstProp.after.mir.64bit b/src/test/mir-opt/const_allocation3.main.ConstProp.after.mir.64bit index 96024f1c82c..d6e49892d4c 100644 --- a/src/test/mir-opt/const_allocation3.main.ConstProp.after.mir.64bit +++ b/src/test/mir-opt/const_allocation3.main.ConstProp.after.mir.64bit @@ -19,12 +19,6 @@ fn main() -> () { StorageDead(_2); // scope 0 at $DIR/const_allocation3.rs:5:8: 5:9 StorageDead(_1); // scope 0 at $DIR/const_allocation3.rs:5:8: 5:9 _0 = const (); // scope 0 at $DIR/const_allocation3.rs:4:11: 6:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/const_allocation3.rs:4:11: 6:2 - // + literal: Const { ty: (), val: Value(Scalar()) } return; // scope 0 at $DIR/const_allocation3.rs:6:2: 6:2 } } diff --git a/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff b/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff index 0e0d8ea9063..6acb8e46e75 100644 --- a/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff +++ b/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff @@ -33,10 +33,7 @@ + // + literal: Const { ty: &[&i32; 1], val: Unevaluated(WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[317d]::BAR[0]), const_param_did: None }, [], Some(promoted[0])) } + _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 - _0 = const core::slice::::as_ptr(move _1) -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 - // ty::Const - // + ty: for<'r> fn(&'r [&i32]) -> *const &i32 {core::slice::::as_ptr} - // + val: Value(Scalar()) + _0 = core::slice::::as_ptr(move _1) -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 // mir::Constant // + span: $DIR/const-promotion-extern-static.rs:9:36: 9:42 // + literal: Const { ty: for<'r> fn(&'r [&i32]) -> *const &i32 {core::slice::::as_ptr}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff b/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff index a885b4d3bae..2f7a2d72884 100644 --- a/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff +++ b/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff @@ -35,10 +35,7 @@ + // + literal: Const { ty: &[&i32; 1], val: Unevaluated(WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[317d]::FOO[0]), const_param_did: None }, [], Some(promoted[0])) } + _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 - _0 = const core::slice::::as_ptr(move _1) -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 - // ty::Const - // + ty: for<'r> fn(&'r [&i32]) -> *const &i32 {core::slice::::as_ptr} - // + val: Value(Scalar()) + _0 = core::slice::::as_ptr(move _1) -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 // mir::Constant // + span: $DIR/const-promotion-extern-static.rs:13:47: 13:53 // + literal: Const { ty: for<'r> fn(&'r [&i32]) -> *const &i32 {core::slice::::as_ptr}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/const_prop/aggregate.main.ConstProp.diff b/src/test/mir-opt/const_prop/aggregate.main.ConstProp.diff index f44025bd523..54877f9f53c 100644 --- a/src/test/mir-opt/const_prop/aggregate.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/aggregate.main.ConstProp.diff @@ -24,12 +24,6 @@ StorageDead(_2); // scope 0 at $DIR/aggregate.rs:5:27: 5:28 StorageDead(_3); // scope 0 at $DIR/aggregate.rs:5:28: 5:29 _0 = const (); // scope 0 at $DIR/aggregate.rs:4:11: 6:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/aggregate.rs:4:11: 6:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_1); // scope 0 at $DIR/aggregate.rs:6:1: 6:2 return; // scope 0 at $DIR/aggregate.rs:6:2: 6:2 } diff --git a/src/test/mir-opt/const_prop/array_index.main.ConstProp.diff.32bit b/src/test/mir-opt/const_prop/array_index.main.ConstProp.diff.32bit index 9b456b6529a..1ccda1c5003 100644 --- a/src/test/mir-opt/const_prop/array_index.main.ConstProp.diff.32bit +++ b/src/test/mir-opt/const_prop/array_index.main.ConstProp.diff.32bit @@ -31,12 +31,6 @@ StorageDead(_3); // scope 0 at $DIR/array_index.rs:5:33: 5:34 StorageDead(_2); // scope 0 at $DIR/array_index.rs:5:33: 5:34 _0 = const (); // scope 0 at $DIR/array_index.rs:4:11: 6:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/array_index.rs:4:11: 6:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_1); // scope 0 at $DIR/array_index.rs:6:1: 6:2 return; // scope 0 at $DIR/array_index.rs:6:2: 6:2 } diff --git a/src/test/mir-opt/const_prop/array_index.main.ConstProp.diff.64bit b/src/test/mir-opt/const_prop/array_index.main.ConstProp.diff.64bit index 9b456b6529a..1ccda1c5003 100644 --- a/src/test/mir-opt/const_prop/array_index.main.ConstProp.diff.64bit +++ b/src/test/mir-opt/const_prop/array_index.main.ConstProp.diff.64bit @@ -31,12 +31,6 @@ StorageDead(_3); // scope 0 at $DIR/array_index.rs:5:33: 5:34 StorageDead(_2); // scope 0 at $DIR/array_index.rs:5:33: 5:34 _0 = const (); // scope 0 at $DIR/array_index.rs:4:11: 6:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/array_index.rs:4:11: 6:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_1); // scope 0 at $DIR/array_index.rs:6:1: 6:2 return; // scope 0 at $DIR/array_index.rs:6:2: 6:2 } diff --git a/src/test/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.diff b/src/test/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.diff index cb3951c1623..30ff6ec8604 100644 --- a/src/test/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.diff @@ -46,12 +46,6 @@ + _2 = Div(const 1_i32, const 0_i32); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 StorageDead(_3); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:18: 5:19 _0 = const (); // scope 0 at $DIR/bad_op_div_by_zero.rs:3:11: 6:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/bad_op_div_by_zero.rs:3:11: 6:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_2); // scope 1 at $DIR/bad_op_div_by_zero.rs:6:1: 6:2 StorageDead(_1); // scope 0 at $DIR/bad_op_div_by_zero.rs:6:1: 6:2 return; // scope 0 at $DIR/bad_op_div_by_zero.rs:6:2: 6:2 diff --git a/src/test/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff b/src/test/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff index d0757aa8a85..6e6ce0a613d 100644 --- a/src/test/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff @@ -46,12 +46,6 @@ + _2 = Rem(const 1_i32, const 0_i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 StorageDead(_3); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:18: 5:19 _0 = const (); // scope 0 at $DIR/bad_op_mod_by_zero.rs:3:11: 6:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/bad_op_mod_by_zero.rs:3:11: 6:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_2); // scope 1 at $DIR/bad_op_mod_by_zero.rs:6:1: 6:2 StorageDead(_1); // scope 0 at $DIR/bad_op_mod_by_zero.rs:6:1: 6:2 return; // scope 0 at $DIR/bad_op_mod_by_zero.rs:6:2: 6:2 diff --git a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.diff.32bit b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.diff.32bit index 6584bcddc47..245a7de5e99 100644 --- a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.diff.32bit +++ b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.diff.32bit @@ -51,12 +51,6 @@ _5 = (*_1)[_6]; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 StorageDead(_6); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:25: 7:26 _0 = const (); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:6:5: 8:6 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:6:5: 8:6 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_5); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:8:5: 8:6 StorageDead(_1); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:9:1: 9:2 return; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:9:2: 9:2 diff --git a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.diff.64bit b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.diff.64bit index 6584bcddc47..245a7de5e99 100644 --- a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.diff.64bit +++ b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.diff.64bit @@ -51,12 +51,6 @@ _5 = (*_1)[_6]; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 StorageDead(_6); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:25: 7:26 _0 = const (); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:6:5: 8:6 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:6:5: 8:6 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_5); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:8:5: 8:6 StorageDead(_1); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:9:1: 9:2 return; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:9:2: 9:2 diff --git a/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff b/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff index aa47c645da5..51255d5ae70 100644 --- a/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff @@ -33,12 +33,6 @@ bb2: { StorageDead(_3); // scope 0 at $DIR/boxes.rs:12:26: 12:27 _0 = const (); // scope 0 at $DIR/boxes.rs:11:11: 13:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/boxes.rs:11:11: 13:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_1); // scope 0 at $DIR/boxes.rs:13:1: 13:2 return; // scope 0 at $DIR/boxes.rs:13:2: 13:2 } diff --git a/src/test/mir-opt/const_prop/cast.main.ConstProp.diff b/src/test/mir-opt/const_prop/cast.main.ConstProp.diff index 895df6ee4cb..1ccc1545822 100644 --- a/src/test/mir-opt/const_prop/cast.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/cast.main.ConstProp.diff @@ -20,12 +20,6 @@ - _2 = const 42_u32 as u8 (Misc); // scope 1 at $DIR/cast.rs:6:13: 6:24 + _2 = const 42_u8; // scope 1 at $DIR/cast.rs:6:13: 6:24 _0 = const (); // scope 0 at $DIR/cast.rs:3:11: 7:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/cast.rs:3:11: 7:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_2); // scope 1 at $DIR/cast.rs:7:1: 7:2 StorageDead(_1); // scope 0 at $DIR/cast.rs:7:1: 7:2 return; // scope 0 at $DIR/cast.rs:7:2: 7:2 diff --git a/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff b/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff index 9510f0dad34..125d150d3d8 100644 --- a/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff @@ -13,7 +13,13 @@ StorageLive(_1); // scope 0 at $DIR/checked_add.rs:5:9: 5:10 - _2 = CheckedAdd(const 1_u32, const 1_u32); // scope 0 at $DIR/checked_add.rs:5:18: 5:23 - assert(!move (_2.1: bool), "attempt to compute `{} + {}` which would overflow", const 1_u32, const 1_u32) -> bb1; // scope 0 at $DIR/checked_add.rs:5:18: 5:23 -+ _2 = (const 2_u32, const false); // scope 0 at $DIR/checked_add.rs:5:18: 5:23 ++ _2 = const (2_u32, false); // scope 0 at $DIR/checked_add.rs:5:18: 5:23 ++ // ty::Const ++ // + ty: (u32, bool) ++ // + val: Value(ByRef { alloc: Allocation { bytes: [2, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) ++ // mir::Constant ++ // + span: $DIR/checked_add.rs:5:18: 5:23 ++ // + literal: Const { ty: (u32, bool), val: Value(ByRef { alloc: Allocation { bytes: [2, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } + assert(!const false, "attempt to compute `{} + {}` which would overflow", const 1_u32, const 1_u32) -> bb1; // scope 0 at $DIR/checked_add.rs:5:18: 5:23 } @@ -21,12 +27,6 @@ - _1 = move (_2.0: u32); // scope 0 at $DIR/checked_add.rs:5:18: 5:23 + _1 = const 2_u32; // scope 0 at $DIR/checked_add.rs:5:18: 5:23 _0 = const (); // scope 0 at $DIR/checked_add.rs:4:11: 6:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/checked_add.rs:4:11: 6:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_1); // scope 0 at $DIR/checked_add.rs:6:1: 6:2 return; // scope 0 at $DIR/checked_add.rs:6:2: 6:2 } diff --git a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff index f3efef387a3..bfc848bbfc9 100644 --- a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff @@ -30,10 +30,7 @@ StorageLive(_4); // scope 1 at $DIR/const_prop_fails_gracefully.rs:8:5: 8:12 StorageLive(_5); // scope 1 at $DIR/const_prop_fails_gracefully.rs:8:10: 8:11 _5 = _1; // scope 1 at $DIR/const_prop_fails_gracefully.rs:8:10: 8:11 - _4 = const read(move _5) -> bb1; // scope 1 at $DIR/const_prop_fails_gracefully.rs:8:5: 8:12 - // ty::Const - // + ty: fn(usize) {read} - // + val: Value(Scalar()) + _4 = read(move _5) -> bb1; // scope 1 at $DIR/const_prop_fails_gracefully.rs:8:5: 8:12 // mir::Constant // + span: $DIR/const_prop_fails_gracefully.rs:8:5: 8:9 // + literal: Const { ty: fn(usize) {read}, val: Value(Scalar()) } @@ -43,12 +40,6 @@ StorageDead(_5); // scope 1 at $DIR/const_prop_fails_gracefully.rs:8:11: 8:12 StorageDead(_4); // scope 1 at $DIR/const_prop_fails_gracefully.rs:8:12: 8:13 _0 = const (); // scope 0 at $DIR/const_prop_fails_gracefully.rs:5:11: 9:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/const_prop_fails_gracefully.rs:5:11: 9:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_1); // scope 0 at $DIR/const_prop_fails_gracefully.rs:9:1: 9:2 return; // scope 0 at $DIR/const_prop_fails_gracefully.rs:9:2: 9:2 } diff --git a/src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff b/src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff index e004b29f504..b55e3a63533 100644 --- a/src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff +++ b/src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff @@ -16,22 +16,13 @@ bb1: { _0 = const (); // scope 0 at $DIR/control-flow-simplification.rs:12:5: 14:6 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/control-flow-simplification.rs:12:5: 14:6 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_1); // scope 0 at $DIR/control-flow-simplification.rs:15:1: 15:2 return; // scope 0 at $DIR/control-flow-simplification.rs:15:2: 15:2 } bb2: { StorageLive(_2); // scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - const std::rt::begin_panic::<&str>(const "explicit panic"); // scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - // ty::Const - // + ty: fn(&str) -> ! {std::rt::begin_panic::<&str>} - // + val: Value(Scalar()) + std::rt::begin_panic::<&str>(const "explicit panic"); // scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL // mir::Constant // + span: $SRC_DIR/std/src/macros.rs:LL:COL // + literal: Const { ty: fn(&str) -> ! {std::rt::begin_panic::<&str>}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/const_prop/control_flow_simplification.hello.PreCodegen.before.mir b/src/test/mir-opt/const_prop/control_flow_simplification.hello.PreCodegen.before.mir index 3569b9897f9..4898f9deb0c 100644 --- a/src/test/mir-opt/const_prop/control_flow_simplification.hello.PreCodegen.before.mir +++ b/src/test/mir-opt/const_prop/control_flow_simplification.hello.PreCodegen.before.mir @@ -5,12 +5,6 @@ fn hello() -> () { bb0: { _0 = const (); // scope 0 at $DIR/control-flow-simplification.rs:12:5: 14:6 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/control-flow-simplification.rs:12:5: 14:6 - // + literal: Const { ty: (), val: Value(Scalar()) } return; // scope 0 at $DIR/control-flow-simplification.rs:15:2: 15:2 } } diff --git a/src/test/mir-opt/const_prop/discriminant.main.ConstProp.diff.32bit b/src/test/mir-opt/const_prop/discriminant.main.ConstProp.diff.32bit index f114eab1e0f..99fa0dcbc90 100644 --- a/src/test/mir-opt/const_prop/discriminant.main.ConstProp.diff.32bit +++ b/src/test/mir-opt/const_prop/discriminant.main.ConstProp.diff.32bit @@ -42,12 +42,6 @@ StorageDead(_2); // scope 0 at $DIR/discriminant.rs:11:67: 11:68 StorageDead(_3); // scope 0 at $DIR/discriminant.rs:11:68: 11:69 _0 = const (); // scope 0 at $DIR/discriminant.rs:10:11: 12:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/discriminant.rs:10:11: 12:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_1); // scope 0 at $DIR/discriminant.rs:12:1: 12:2 return; // scope 0 at $DIR/discriminant.rs:12:2: 12:2 } diff --git a/src/test/mir-opt/const_prop/discriminant.main.ConstProp.diff.64bit b/src/test/mir-opt/const_prop/discriminant.main.ConstProp.diff.64bit index f114eab1e0f..99fa0dcbc90 100644 --- a/src/test/mir-opt/const_prop/discriminant.main.ConstProp.diff.64bit +++ b/src/test/mir-opt/const_prop/discriminant.main.ConstProp.diff.64bit @@ -42,12 +42,6 @@ StorageDead(_2); // scope 0 at $DIR/discriminant.rs:11:67: 11:68 StorageDead(_3); // scope 0 at $DIR/discriminant.rs:11:68: 11:69 _0 = const (); // scope 0 at $DIR/discriminant.rs:10:11: 12:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/discriminant.rs:10:11: 12:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_1); // scope 0 at $DIR/discriminant.rs:12:1: 12:2 return; // scope 0 at $DIR/discriminant.rs:12:2: 12:2 } diff --git a/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff b/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff index fde3c1244ea..e37d0a3ed96 100644 --- a/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff @@ -17,7 +17,13 @@ - _3 = CheckedAdd(_2, const 1_u8); // scope 0 at $DIR/indirect.rs:5:13: 5:29 - assert(!move (_3.1: bool), "attempt to compute `{} + {}` which would overflow", move _2, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:5:13: 5:29 + _2 = const 2_u8; // scope 0 at $DIR/indirect.rs:5:13: 5:25 -+ _3 = (const 3_u8, const false); // scope 0 at $DIR/indirect.rs:5:13: 5:29 ++ _3 = const (3_u8, false); // scope 0 at $DIR/indirect.rs:5:13: 5:29 ++ // ty::Const ++ // + ty: (u8, bool) ++ // + val: Value(ByRef { alloc: Allocation { bytes: [3, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [3], len: Size { raw: 2 } }, size: Size { raw: 2 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) ++ // mir::Constant ++ // + span: $DIR/indirect.rs:5:13: 5:29 ++ // + literal: Const { ty: (u8, bool), val: Value(ByRef { alloc: Allocation { bytes: [3, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [3], len: Size { raw: 2 } }, size: Size { raw: 2 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } + assert(!const false, "attempt to compute `{} + {}` which would overflow", const 2_u8, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:5:13: 5:29 } @@ -26,12 +32,6 @@ + _1 = const 3_u8; // scope 0 at $DIR/indirect.rs:5:13: 5:29 StorageDead(_2); // scope 0 at $DIR/indirect.rs:5:28: 5:29 _0 = const (); // scope 0 at $DIR/indirect.rs:4:11: 6:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/indirect.rs:4:11: 6:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_1); // scope 0 at $DIR/indirect.rs:6:1: 6:2 return; // scope 0 at $DIR/indirect.rs:6:2: 6:2 } diff --git a/src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff b/src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff index 236cbfe6303..6bf553bc580 100644 --- a/src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff @@ -13,19 +13,10 @@ StorageLive(_3); // scope 0 at $DIR/issue-66971.rs:16:13: 16:15 - (_2.0: ()) = move _3; // scope 0 at $DIR/issue-66971.rs:16:12: 16:22 + (_2.0: ()) = const (); // scope 0 at $DIR/issue-66971.rs:16:12: 16:22 -+ // ty::Const -+ // + ty: () -+ // + val: Value(Scalar()) -+ // mir::Constant -+ // + span: $DIR/issue-66971.rs:16:12: 16:22 -+ // + literal: Const { ty: (), val: Value(Scalar()) } (_2.1: u8) = const 0_u8; // scope 0 at $DIR/issue-66971.rs:16:12: 16:22 (_2.2: u8) = const 0_u8; // scope 0 at $DIR/issue-66971.rs:16:12: 16:22 StorageDead(_3); // scope 0 at $DIR/issue-66971.rs:16:21: 16:22 - _1 = const encode(move _2) -> bb1; // scope 0 at $DIR/issue-66971.rs:16:5: 16:23 - // ty::Const - // + ty: fn(((), u8, u8)) {encode} - // + val: Value(Scalar()) + _1 = encode(move _2) -> bb1; // scope 0 at $DIR/issue-66971.rs:16:5: 16:23 // mir::Constant // + span: $DIR/issue-66971.rs:16:5: 16:11 // + literal: Const { ty: fn(((), u8, u8)) {encode}, val: Value(Scalar()) } @@ -35,12 +26,6 @@ StorageDead(_2); // scope 0 at $DIR/issue-66971.rs:16:22: 16:23 StorageDead(_1); // scope 0 at $DIR/issue-66971.rs:16:23: 16:24 _0 = const (); // scope 0 at $DIR/issue-66971.rs:15:11: 17:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/issue-66971.rs:15:11: 17:2 - // + literal: Const { ty: (), val: Value(Scalar()) } return; // scope 0 at $DIR/issue-66971.rs:17:2: 17:2 } } diff --git a/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff b/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff index 8b47f66a117..492938fc206 100644 --- a/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff @@ -14,12 +14,15 @@ (_3.0: u8) = const 1_u8; // scope 0 at $DIR/issue-67019.rs:11:11: 11:17 (_3.1: u8) = const 2_u8; // scope 0 at $DIR/issue-67019.rs:11:11: 11:17 - (_2.0: (u8, u8)) = move _3; // scope 0 at $DIR/issue-67019.rs:11:10: 11:19 -+ (_2.0: (u8, u8)) = (const 1_u8, const 2_u8); // scope 0 at $DIR/issue-67019.rs:11:10: 11:19 ++ (_2.0: (u8, u8)) = const (1_u8, 2_u8); // scope 0 at $DIR/issue-67019.rs:11:10: 11:19 ++ // ty::Const ++ // + ty: (u8, u8) ++ // + val: Value(ByRef { alloc: Allocation { bytes: [1, 2], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [3], len: Size { raw: 2 } }, size: Size { raw: 2 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) ++ // mir::Constant ++ // + span: $DIR/issue-67019.rs:11:10: 11:19 ++ // + literal: Const { ty: (u8, u8), val: Value(ByRef { alloc: Allocation { bytes: [1, 2], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [3], len: Size { raw: 2 } }, size: Size { raw: 2 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } StorageDead(_3); // scope 0 at $DIR/issue-67019.rs:11:18: 11:19 - _1 = const test(move _2) -> bb1; // scope 0 at $DIR/issue-67019.rs:11:5: 11:20 - // ty::Const - // + ty: fn(((u8, u8),)) {test} - // + val: Value(Scalar()) + _1 = test(move _2) -> bb1; // scope 0 at $DIR/issue-67019.rs:11:5: 11:20 // mir::Constant // + span: $DIR/issue-67019.rs:11:5: 11:9 // + literal: Const { ty: fn(((u8, u8),)) {test}, val: Value(Scalar()) } @@ -29,12 +32,6 @@ StorageDead(_2); // scope 0 at $DIR/issue-67019.rs:11:19: 11:20 StorageDead(_1); // scope 0 at $DIR/issue-67019.rs:11:20: 11:21 _0 = const (); // scope 0 at $DIR/issue-67019.rs:10:11: 12:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/issue-67019.rs:10:11: 12:2 - // + literal: Const { ty: (), val: Value(Scalar()) } return; // scope 0 at $DIR/issue-67019.rs:12:2: 12:2 } } diff --git a/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.32bit b/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.32bit index cb55efe2078..b1a9e1cb5d7 100644 --- a/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.32bit +++ b/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.32bit @@ -30,12 +30,6 @@ StorageDead(_3); // scope 0 at $DIR/large_array_index.rs:6:32: 6:33 StorageDead(_2); // scope 0 at $DIR/large_array_index.rs:6:32: 6:33 _0 = const (); // scope 0 at $DIR/large_array_index.rs:4:11: 7:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/large_array_index.rs:4:11: 7:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_1); // scope 0 at $DIR/large_array_index.rs:7:1: 7:2 return; // scope 0 at $DIR/large_array_index.rs:7:2: 7:2 } diff --git a/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.64bit b/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.64bit index cb55efe2078..b1a9e1cb5d7 100644 --- a/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.64bit +++ b/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.64bit @@ -30,12 +30,6 @@ StorageDead(_3); // scope 0 at $DIR/large_array_index.rs:6:32: 6:33 StorageDead(_2); // scope 0 at $DIR/large_array_index.rs:6:32: 6:33 _0 = const (); // scope 0 at $DIR/large_array_index.rs:4:11: 7:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/large_array_index.rs:4:11: 7:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_1); // scope 0 at $DIR/large_array_index.rs:7:1: 7:2 return; // scope 0 at $DIR/large_array_index.rs:7:2: 7:2 } diff --git a/src/test/mir-opt/const_prop/mutable_variable.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable.main.ConstProp.diff index edbb1e57c7d..349f1557a86 100644 --- a/src/test/mir-opt/const_prop/mutable_variable.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/mutable_variable.main.ConstProp.diff @@ -20,12 +20,6 @@ - _2 = _1; // scope 1 at $DIR/mutable_variable.rs:7:13: 7:14 + _2 = const 99_i32; // scope 1 at $DIR/mutable_variable.rs:7:13: 7:14 _0 = const (); // scope 0 at $DIR/mutable_variable.rs:4:11: 8:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/mutable_variable.rs:4:11: 8:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_2); // scope 1 at $DIR/mutable_variable.rs:8:1: 8:2 StorageDead(_1); // scope 0 at $DIR/mutable_variable.rs:8:1: 8:2 return; // scope 0 at $DIR/mutable_variable.rs:8:2: 8:2 diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff index 05c618b3a12..204c1acecf5 100644 --- a/src/test/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff @@ -19,14 +19,14 @@ (_1.1: i32) = const 99_i32; // scope 1 at $DIR/mutable_variable_aggregate.rs:6:5: 6:13 StorageLive(_2); // scope 1 at $DIR/mutable_variable_aggregate.rs:7:9: 7:10 - _2 = _1; // scope 1 at $DIR/mutable_variable_aggregate.rs:7:13: 7:14 -+ _2 = (const 42_i32, const 99_i32); // scope 1 at $DIR/mutable_variable_aggregate.rs:7:13: 7:14 ++ _2 = const (42_i32, 99_i32); // scope 1 at $DIR/mutable_variable_aggregate.rs:7:13: 7:14 ++ // ty::Const ++ // + ty: (i32, i32) ++ // + val: Value(ByRef { alloc: Allocation { bytes: [42, 0, 0, 0, 99, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) ++ // mir::Constant ++ // + span: $DIR/mutable_variable_aggregate.rs:7:13: 7:14 ++ // + literal: Const { ty: (i32, i32), val: Value(ByRef { alloc: Allocation { bytes: [42, 0, 0, 0, 99, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } _0 = const (); // scope 0 at $DIR/mutable_variable_aggregate.rs:4:11: 8:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/mutable_variable_aggregate.rs:4:11: 8:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_2); // scope 1 at $DIR/mutable_variable_aggregate.rs:8:1: 8:2 StorageDead(_1); // scope 0 at $DIR/mutable_variable_aggregate.rs:8:1: 8:2 return; // scope 0 at $DIR/mutable_variable_aggregate.rs:8:2: 8:2 diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.ConstProp.diff index d8f066c7b9b..6dc0e8ab3cf 100644 --- a/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.ConstProp.diff @@ -26,12 +26,6 @@ StorageLive(_3); // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:8:9: 8:10 _3 = _1; // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:8:13: 8:14 _0 = const (); // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:4:11: 9:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:4:11: 9:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_3); // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:9:1: 9:2 StorageDead(_2); // scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:9:1: 9:2 StorageDead(_1); // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:9:1: 9:2 diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.diff index 59a43bda35a..08dd2d4da31 100644 --- a/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.diff @@ -14,10 +14,7 @@ bb0: { StorageLive(_1); // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:5:9: 5:14 - _1 = const foo() -> bb1; // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:5:29: 5:34 - // ty::Const - // + ty: fn() -> (i32, i32) {foo} - // + val: Value(Scalar()) + _1 = foo() -> bb1; // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:5:29: 5:34 // mir::Constant // + span: $DIR/mutable_variable_aggregate_partial_read.rs:5:29: 5:32 // + literal: Const { ty: fn() -> (i32, i32) {foo}, val: Value(Scalar()) } @@ -30,12 +27,6 @@ - _2 = (_1.1: i32); // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:8:13: 8:16 + _2 = const 99_i32; // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:8:13: 8:16 _0 = const (); // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:4:11: 9:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/mutable_variable_aggregate_partial_read.rs:4:11: 9:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_2); // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:9:1: 9:2 StorageDead(_1); // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:9:1: 9:2 return; // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:9:2: 9:2 diff --git a/src/test/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff index 945aeaf1e88..f6e173620ec 100644 --- a/src/test/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff @@ -35,22 +35,10 @@ StorageDead(_3); // scope 2 at $DIR/mutable_variable_no_prop.rs:9:18: 9:19 StorageDead(_4); // scope 2 at $DIR/mutable_variable_no_prop.rs:9:19: 9:20 _2 = const (); // scope 2 at $DIR/mutable_variable_no_prop.rs:8:5: 10:6 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/mutable_variable_no_prop.rs:8:5: 10:6 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_2); // scope 1 at $DIR/mutable_variable_no_prop.rs:10:5: 10:6 StorageLive(_5); // scope 1 at $DIR/mutable_variable_no_prop.rs:11:9: 11:10 _5 = _1; // scope 1 at $DIR/mutable_variable_no_prop.rs:11:13: 11:14 _0 = const (); // scope 0 at $DIR/mutable_variable_no_prop.rs:6:11: 12:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/mutable_variable_no_prop.rs:6:11: 12:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_5); // scope 1 at $DIR/mutable_variable_no_prop.rs:12:1: 12:2 StorageDead(_1); // scope 0 at $DIR/mutable_variable_no_prop.rs:12:1: 12:2 return; // scope 0 at $DIR/mutable_variable_no_prop.rs:12:2: 12:2 diff --git a/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff index 5812814a0ec..63bdcb2bc11 100644 --- a/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff @@ -23,10 +23,7 @@ bb0: { StorageLive(_1); // scope 0 at $DIR/mutable_variable_unprop_assign.rs:5:9: 5:10 - _1 = const foo() -> bb1; // scope 0 at $DIR/mutable_variable_unprop_assign.rs:5:13: 5:18 - // ty::Const - // + ty: fn() -> i32 {foo} - // + val: Value(Scalar()) + _1 = foo() -> bb1; // scope 0 at $DIR/mutable_variable_unprop_assign.rs:5:13: 5:18 // mir::Constant // + span: $DIR/mutable_variable_unprop_assign.rs:5:13: 5:16 // + literal: Const { ty: fn() -> i32 {foo}, val: Value(Scalar()) } @@ -45,12 +42,6 @@ StorageLive(_5); // scope 3 at $DIR/mutable_variable_unprop_assign.rs:9:9: 9:10 _5 = (_2.0: i32); // scope 3 at $DIR/mutable_variable_unprop_assign.rs:9:13: 9:16 _0 = const (); // scope 0 at $DIR/mutable_variable_unprop_assign.rs:4:11: 10:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/mutable_variable_unprop_assign.rs:4:11: 10:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_5); // scope 3 at $DIR/mutable_variable_unprop_assign.rs:10:1: 10:2 StorageDead(_4); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:10:1: 10:2 StorageDead(_2); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:10:1: 10:2 diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.diff.32bit b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.diff.32bit index 3bdf9e753c0..2c8e7ada39b 100644 --- a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.diff.32bit +++ b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.diff.32bit @@ -26,7 +26,13 @@ StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:12:9: 12:10 - _2 = CheckedAdd(const 2_i32, const 2_i32); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 - assert(!move (_2.1: bool), "attempt to compute `{} + {}` which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 -+ _2 = (const 4_i32, const false); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 ++ _2 = const (4_i32, false); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 ++ // ty::Const ++ // + ty: (i32, bool) ++ // + val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) ++ // mir::Constant ++ // + span: $DIR/optimizes_into_variable.rs:12:13: 12:18 ++ // + literal: Const { ty: (i32, bool), val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } + assert(!const false, "attempt to compute `{} + {}` which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 } @@ -58,12 +64,6 @@ + _8 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38 StorageDead(_9); // scope 2 at $DIR/optimizes_into_variable.rs:14:38: 14:39 _0 = const (); // scope 0 at $DIR/optimizes_into_variable.rs:11:11: 15:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/optimizes_into_variable.rs:11:11: 15:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_8); // scope 2 at $DIR/optimizes_into_variable.rs:15:1: 15:2 StorageDead(_3); // scope 1 at $DIR/optimizes_into_variable.rs:15:1: 15:2 StorageDead(_1); // scope 0 at $DIR/optimizes_into_variable.rs:15:1: 15:2 diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.diff.64bit b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.diff.64bit index 3bdf9e753c0..2c8e7ada39b 100644 --- a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.diff.64bit +++ b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.diff.64bit @@ -26,7 +26,13 @@ StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:12:9: 12:10 - _2 = CheckedAdd(const 2_i32, const 2_i32); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 - assert(!move (_2.1: bool), "attempt to compute `{} + {}` which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 -+ _2 = (const 4_i32, const false); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 ++ _2 = const (4_i32, false); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 ++ // ty::Const ++ // + ty: (i32, bool) ++ // + val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) ++ // mir::Constant ++ // + span: $DIR/optimizes_into_variable.rs:12:13: 12:18 ++ // + literal: Const { ty: (i32, bool), val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } + assert(!const false, "attempt to compute `{} + {}` which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 } @@ -58,12 +64,6 @@ + _8 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38 StorageDead(_9); // scope 2 at $DIR/optimizes_into_variable.rs:14:38: 14:39 _0 = const (); // scope 0 at $DIR/optimizes_into_variable.rs:11:11: 15:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/optimizes_into_variable.rs:11:11: 15:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_8); // scope 2 at $DIR/optimizes_into_variable.rs:15:1: 15:2 StorageDead(_3); // scope 1 at $DIR/optimizes_into_variable.rs:15:1: 15:2 StorageDead(_1); // scope 0 at $DIR/optimizes_into_variable.rs:15:1: 15:2 diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.mir.32bit b/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.mir.32bit index 91d9c9aa083..a78a6341c29 100644 --- a/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.mir.32bit +++ b/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.mir.32bit @@ -23,12 +23,6 @@ fn main() -> () { StorageLive(_3); // scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10 _3 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38 _0 = const (); // scope 0 at $DIR/optimizes_into_variable.rs:11:11: 15:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/optimizes_into_variable.rs:11:11: 15:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_3); // scope 2 at $DIR/optimizes_into_variable.rs:15:1: 15:2 StorageDead(_2); // scope 1 at $DIR/optimizes_into_variable.rs:15:1: 15:2 StorageDead(_1); // scope 0 at $DIR/optimizes_into_variable.rs:15:1: 15:2 diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.mir.64bit b/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.mir.64bit index 91d9c9aa083..a78a6341c29 100644 --- a/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.mir.64bit +++ b/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.mir.64bit @@ -23,12 +23,6 @@ fn main() -> () { StorageLive(_3); // scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10 _3 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38 _0 = const (); // scope 0 at $DIR/optimizes_into_variable.rs:11:11: 15:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/optimizes_into_variable.rs:11:11: 15:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_3); // scope 2 at $DIR/optimizes_into_variable.rs:15:1: 15:2 StorageDead(_2); // scope 1 at $DIR/optimizes_into_variable.rs:15:1: 15:2 StorageDead(_1); // scope 0 at $DIR/optimizes_into_variable.rs:15:1: 15:2 diff --git a/src/test/mir-opt/const_prop/read_immutable_static.main.ConstProp.diff b/src/test/mir-opt/const_prop/read_immutable_static.main.ConstProp.diff index 53d10f01eac..07c78be69c0 100644 --- a/src/test/mir-opt/const_prop/read_immutable_static.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/read_immutable_static.main.ConstProp.diff @@ -43,12 +43,6 @@ StorageDead(_5); // scope 0 at $DIR/read_immutable_static.rs:7:22: 7:23 StorageDead(_3); // scope 0 at $DIR/read_immutable_static.rs:7:22: 7:23 _0 = const (); // scope 0 at $DIR/read_immutable_static.rs:6:11: 8:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/read_immutable_static.rs:6:11: 8:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_1); // scope 0 at $DIR/read_immutable_static.rs:8:1: 8:2 return; // scope 0 at $DIR/read_immutable_static.rs:8:2: 8:2 } diff --git a/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff b/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff index f8f9b5ce59c..31061233eee 100644 --- a/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff @@ -24,12 +24,6 @@ StorageDead(_2); // scope 0 at $DIR/ref_deref.rs:5:10: 5:11 StorageDead(_1); // scope 0 at $DIR/ref_deref.rs:5:10: 5:11 _0 = const (); // scope 0 at $DIR/ref_deref.rs:4:11: 6:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/ref_deref.rs:4:11: 6:2 - // + literal: Const { ty: (), val: Value(Scalar()) } return; // scope 0 at $DIR/ref_deref.rs:6:2: 6:2 } } diff --git a/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff b/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff index 019bb63a020..c9caf07a737 100644 --- a/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff +++ b/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff @@ -27,12 +27,6 @@ StorageDead(_2); // scope 0 at $DIR/ref_deref.rs:5:10: 5:11 StorageDead(_1); // scope 0 at $DIR/ref_deref.rs:5:10: 5:11 _0 = const (); // scope 0 at $DIR/ref_deref.rs:4:11: 6:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/ref_deref.rs:4:11: 6:2 - // + literal: Const { ty: (), val: Value(Scalar()) } return; // scope 0 at $DIR/ref_deref.rs:6:2: 6:2 } } diff --git a/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff b/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff index 483e5f1b9a4..e9398df1320 100644 --- a/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff @@ -23,12 +23,6 @@ StorageDead(_2); // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18 StorageDead(_1); // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18 _0 = const (); // scope 0 at $DIR/ref_deref_project.rs:4:11: 6:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/ref_deref_project.rs:4:11: 6:2 - // + literal: Const { ty: (), val: Value(Scalar()) } return; // scope 0 at $DIR/ref_deref_project.rs:6:2: 6:2 } } diff --git a/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff b/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff index d7b3ff7d0c2..43e4b32a6cd 100644 --- a/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff +++ b/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff @@ -27,12 +27,6 @@ StorageDead(_2); // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18 StorageDead(_1); // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18 _0 = const (); // scope 0 at $DIR/ref_deref_project.rs:4:11: 6:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/ref_deref_project.rs:4:11: 6:2 - // + literal: Const { ty: (), val: Value(Scalar()) } return; // scope 0 at $DIR/ref_deref_project.rs:6:2: 6:2 } } diff --git a/src/test/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff b/src/test/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff index 93fe856c8e8..02eb3155be9 100644 --- a/src/test/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff @@ -13,10 +13,7 @@ StorageLive(_1); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:41 StorageLive(_2); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:26 StorageLive(_3); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:17 - _3 = const main as fn() (Pointer(ReifyFnPointer)); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:17 - // ty::Const - // + ty: fn() {main} - // + val: Value(Scalar()) + _3 = main as fn() (Pointer(ReifyFnPointer)); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:17 // mir::Constant // + span: $DIR/reify_fn_ptr.rs:4:13: 4:17 // + literal: Const { ty: fn() {main}, val: Value(Scalar()) } @@ -26,12 +23,6 @@ StorageDead(_2); // scope 0 at $DIR/reify_fn_ptr.rs:4:40: 4:41 StorageDead(_1); // scope 0 at $DIR/reify_fn_ptr.rs:4:41: 4:42 _0 = const (); // scope 0 at $DIR/reify_fn_ptr.rs:3:11: 5:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/reify_fn_ptr.rs:3:11: 5:2 - // + literal: Const { ty: (), val: Value(Scalar()) } return; // scope 0 at $DIR/reify_fn_ptr.rs:5:2: 5:2 } } diff --git a/src/test/mir-opt/const_prop/repeat.main.ConstProp.diff.32bit b/src/test/mir-opt/const_prop/repeat.main.ConstProp.diff.32bit index 61e3606ef83..f14004fc25e 100644 --- a/src/test/mir-opt/const_prop/repeat.main.ConstProp.diff.32bit +++ b/src/test/mir-opt/const_prop/repeat.main.ConstProp.diff.32bit @@ -36,12 +36,6 @@ StorageDead(_4); // scope 0 at $DIR/repeat.rs:6:32: 6:33 StorageDead(_3); // scope 0 at $DIR/repeat.rs:6:32: 6:33 _0 = const (); // scope 0 at $DIR/repeat.rs:5:11: 7:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/repeat.rs:5:11: 7:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_1); // scope 0 at $DIR/repeat.rs:7:1: 7:2 return; // scope 0 at $DIR/repeat.rs:7:2: 7:2 } diff --git a/src/test/mir-opt/const_prop/repeat.main.ConstProp.diff.64bit b/src/test/mir-opt/const_prop/repeat.main.ConstProp.diff.64bit index 61e3606ef83..f14004fc25e 100644 --- a/src/test/mir-opt/const_prop/repeat.main.ConstProp.diff.64bit +++ b/src/test/mir-opt/const_prop/repeat.main.ConstProp.diff.64bit @@ -36,12 +36,6 @@ StorageDead(_4); // scope 0 at $DIR/repeat.rs:6:32: 6:33 StorageDead(_3); // scope 0 at $DIR/repeat.rs:6:32: 6:33 _0 = const (); // scope 0 at $DIR/repeat.rs:5:11: 7:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/repeat.rs:5:11: 7:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_1); // scope 0 at $DIR/repeat.rs:7:1: 7:2 return; // scope 0 at $DIR/repeat.rs:7:2: 7:2 } diff --git a/src/test/mir-opt/const_prop/return_place.add.ConstProp.diff b/src/test/mir-opt/const_prop/return_place.add.ConstProp.diff index 99893aa19cf..d61a04d1e03 100644 --- a/src/test/mir-opt/const_prop/return_place.add.ConstProp.diff +++ b/src/test/mir-opt/const_prop/return_place.add.ConstProp.diff @@ -8,7 +8,13 @@ bb0: { - _1 = CheckedAdd(const 2_u32, const 2_u32); // scope 0 at $DIR/return_place.rs:6:5: 6:10 - assert(!move (_1.1: bool), "attempt to compute `{} + {}` which would overflow", const 2_u32, const 2_u32) -> bb1; // scope 0 at $DIR/return_place.rs:6:5: 6:10 -+ _1 = (const 4_u32, const false); // scope 0 at $DIR/return_place.rs:6:5: 6:10 ++ _1 = const (4_u32, false); // scope 0 at $DIR/return_place.rs:6:5: 6:10 ++ // ty::Const ++ // + ty: (u32, bool) ++ // + val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) ++ // mir::Constant ++ // + span: $DIR/return_place.rs:6:5: 6:10 ++ // + literal: Const { ty: (u32, bool), val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } + assert(!const false, "attempt to compute `{} + {}` which would overflow", const 2_u32, const 2_u32) -> bb1; // scope 0 at $DIR/return_place.rs:6:5: 6:10 } diff --git a/src/test/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff b/src/test/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff index 569e2f8ec2e..a4232d178a3 100644 --- a/src/test/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff @@ -16,12 +16,9 @@ StorageLive(_2); // scope 1 at $DIR/scalar_literal_propagation.rs:4:5: 4:15 StorageLive(_3); // scope 1 at $DIR/scalar_literal_propagation.rs:4:13: 4:14 - _3 = _1; // scope 1 at $DIR/scalar_literal_propagation.rs:4:13: 4:14 -- _2 = const consume(move _3) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:4:5: 4:15 +- _2 = consume(move _3) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:4:5: 4:15 + _3 = const 1_u32; // scope 1 at $DIR/scalar_literal_propagation.rs:4:13: 4:14 -+ _2 = const consume(const 1_u32) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:4:5: 4:15 - // ty::Const - // + ty: fn(u32) {consume} - // + val: Value(Scalar()) ++ _2 = consume(const 1_u32) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:4:5: 4:15 // mir::Constant // + span: $DIR/scalar_literal_propagation.rs:4:5: 4:12 // + literal: Const { ty: fn(u32) {consume}, val: Value(Scalar()) } @@ -31,12 +28,6 @@ StorageDead(_3); // scope 1 at $DIR/scalar_literal_propagation.rs:4:14: 4:15 StorageDead(_2); // scope 1 at $DIR/scalar_literal_propagation.rs:4:15: 4:16 _0 = const (); // scope 0 at $DIR/scalar_literal_propagation.rs:2:11: 5:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/scalar_literal_propagation.rs:2:11: 5:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_1); // scope 0 at $DIR/scalar_literal_propagation.rs:5:1: 5:2 return; // scope 0 at $DIR/scalar_literal_propagation.rs:5:2: 5:2 } diff --git a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.diff.32bit b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.diff.32bit index 100e37d3681..02c4391baf5 100644 --- a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.diff.32bit +++ b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.diff.32bit @@ -47,12 +47,6 @@ StorageDead(_2); // scope 0 at $DIR/slice_len.rs:5:33: 5:34 StorageDead(_1); // scope 0 at $DIR/slice_len.rs:5:33: 5:34 _0 = const (); // scope 0 at $DIR/slice_len.rs:4:11: 6:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/slice_len.rs:4:11: 6:2 - // + literal: Const { ty: (), val: Value(Scalar()) } return; // scope 0 at $DIR/slice_len.rs:6:2: 6:2 } } diff --git a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.diff.64bit b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.diff.64bit index 100e37d3681..02c4391baf5 100644 --- a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.diff.64bit +++ b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.diff.64bit @@ -47,12 +47,6 @@ StorageDead(_2); // scope 0 at $DIR/slice_len.rs:5:33: 5:34 StorageDead(_1); // scope 0 at $DIR/slice_len.rs:5:33: 5:34 _0 = const (); // scope 0 at $DIR/slice_len.rs:4:11: 6:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/slice_len.rs:4:11: 6:2 - // + literal: Const { ty: (), val: Value(Scalar()) } return; // scope 0 at $DIR/slice_len.rs:6:2: 6:2 } } diff --git a/src/test/mir-opt/const_prop/switch_int.main.ConstProp.diff b/src/test/mir-opt/const_prop/switch_int.main.ConstProp.diff index 5fcf830479e..f51df7ae821 100644 --- a/src/test/mir-opt/const_prop/switch_int.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/switch_int.main.ConstProp.diff @@ -13,20 +13,14 @@ } bb1: { - _0 = const foo(const -1_i32) -> bb3; // scope 0 at $DIR/switch_int.rs:9:14: 9:21 - // ty::Const - // + ty: fn(i32) {foo} - // + val: Value(Scalar()) + _0 = foo(const -1_i32) -> bb3; // scope 0 at $DIR/switch_int.rs:9:14: 9:21 // mir::Constant // + span: $DIR/switch_int.rs:9:14: 9:17 // + literal: Const { ty: fn(i32) {foo}, val: Value(Scalar()) } } bb2: { - _0 = const foo(const 0_i32) -> bb3; // scope 0 at $DIR/switch_int.rs:8:14: 8:20 - // ty::Const - // + ty: fn(i32) {foo} - // + val: Value(Scalar()) + _0 = foo(const 0_i32) -> bb3; // scope 0 at $DIR/switch_int.rs:8:14: 8:20 // mir::Constant // + span: $DIR/switch_int.rs:8:14: 8:17 // + literal: Const { ty: fn(i32) {foo}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/const_prop/switch_int.main.SimplifyBranches-after-const-prop.diff b/src/test/mir-opt/const_prop/switch_int.main.SimplifyBranches-after-const-prop.diff index 0337d0e061b..a444956ad1d 100644 --- a/src/test/mir-opt/const_prop/switch_int.main.SimplifyBranches-after-const-prop.diff +++ b/src/test/mir-opt/const_prop/switch_int.main.SimplifyBranches-after-const-prop.diff @@ -13,20 +13,14 @@ } bb1: { - _0 = const foo(const -1_i32) -> bb3; // scope 0 at $DIR/switch_int.rs:9:14: 9:21 - // ty::Const - // + ty: fn(i32) {foo} - // + val: Value(Scalar()) + _0 = foo(const -1_i32) -> bb3; // scope 0 at $DIR/switch_int.rs:9:14: 9:21 // mir::Constant // + span: $DIR/switch_int.rs:9:14: 9:17 // + literal: Const { ty: fn(i32) {foo}, val: Value(Scalar()) } } bb2: { - _0 = const foo(const 0_i32) -> bb3; // scope 0 at $DIR/switch_int.rs:8:14: 8:20 - // ty::Const - // + ty: fn(i32) {foo} - // + val: Value(Scalar()) + _0 = foo(const 0_i32) -> bb3; // scope 0 at $DIR/switch_int.rs:8:14: 8:20 // mir::Constant // + span: $DIR/switch_int.rs:8:14: 8:17 // + literal: Const { ty: fn(i32) {foo}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff b/src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff index 83cdd6b5836..2de1ab19b7c 100644 --- a/src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff @@ -17,11 +17,14 @@ StorageLive(_2); // scope 1 at $DIR/tuple_literal_propagation.rs:5:5: 5:15 StorageLive(_3); // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14 - _3 = _1; // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14 -+ _3 = (const 1_u32, const 2_u32); // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14 - _2 = const consume(move _3) -> bb1; // scope 1 at $DIR/tuple_literal_propagation.rs:5:5: 5:15 - // ty::Const - // + ty: fn((u32, u32)) {consume} - // + val: Value(Scalar()) ++ _3 = const (1_u32, 2_u32); // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14 ++ // ty::Const ++ // + ty: (u32, u32) ++ // + val: Value(ByRef { alloc: Allocation { bytes: [1, 0, 0, 0, 2, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) ++ // mir::Constant ++ // + span: $DIR/tuple_literal_propagation.rs:5:13: 5:14 ++ // + literal: Const { ty: (u32, u32), val: Value(ByRef { alloc: Allocation { bytes: [1, 0, 0, 0, 2, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } + _2 = consume(move _3) -> bb1; // scope 1 at $DIR/tuple_literal_propagation.rs:5:5: 5:15 // mir::Constant // + span: $DIR/tuple_literal_propagation.rs:5:5: 5:12 // + literal: Const { ty: fn((u32, u32)) {consume}, val: Value(Scalar()) } @@ -31,12 +34,6 @@ StorageDead(_3); // scope 1 at $DIR/tuple_literal_propagation.rs:5:14: 5:15 StorageDead(_2); // scope 1 at $DIR/tuple_literal_propagation.rs:5:15: 5:16 _0 = const (); // scope 0 at $DIR/tuple_literal_propagation.rs:2:11: 6:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/tuple_literal_propagation.rs:2:11: 6:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_1); // scope 0 at $DIR/tuple_literal_propagation.rs:6:1: 6:2 return; // scope 0 at $DIR/tuple_literal_propagation.rs:6:2: 6:2 } diff --git a/src/test/mir-opt/const_prop_miscompile.bar.ConstProp.diff b/src/test/mir-opt/const_prop_miscompile.bar.ConstProp.diff index 666ab74e72f..5a3a99e4931 100644 --- a/src/test/mir-opt/const_prop_miscompile.bar.ConstProp.diff +++ b/src/test/mir-opt/const_prop_miscompile.bar.ConstProp.diff @@ -26,12 +26,6 @@ (*_3) = const 5_i32; // scope 2 at $DIR/const_prop_miscompile.rs:14:9: 14:26 StorageDead(_3); // scope 2 at $DIR/const_prop_miscompile.rs:14:26: 14:27 _2 = const (); // scope 2 at $DIR/const_prop_miscompile.rs:13:5: 15:6 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/const_prop_miscompile.rs:13:5: 15:6 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_2); // scope 1 at $DIR/const_prop_miscompile.rs:15:5: 15:6 StorageLive(_4); // scope 1 at $DIR/const_prop_miscompile.rs:16:9: 16:10 StorageLive(_5); // scope 1 at $DIR/const_prop_miscompile.rs:16:13: 16:20 @@ -39,12 +33,6 @@ _4 = Eq(move _5, const 5_i32); // scope 1 at $DIR/const_prop_miscompile.rs:16:13: 16:25 StorageDead(_5); // scope 1 at $DIR/const_prop_miscompile.rs:16:24: 16:25 _0 = const (); // scope 0 at $DIR/const_prop_miscompile.rs:11:10: 17:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/const_prop_miscompile.rs:11:10: 17:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_4); // scope 1 at $DIR/const_prop_miscompile.rs:17:1: 17:2 StorageDead(_1); // scope 0 at $DIR/const_prop_miscompile.rs:17:1: 17:2 return; // scope 0 at $DIR/const_prop_miscompile.rs:17:2: 17:2 diff --git a/src/test/mir-opt/const_prop_miscompile.foo.ConstProp.diff b/src/test/mir-opt/const_prop_miscompile.foo.ConstProp.diff index ef458c50741..648260c7c20 100644 --- a/src/test/mir-opt/const_prop_miscompile.foo.ConstProp.diff +++ b/src/test/mir-opt/const_prop_miscompile.foo.ConstProp.diff @@ -27,12 +27,6 @@ _3 = Eq(move _4, const 5_i32); // scope 1 at $DIR/const_prop_miscompile.rs:7:13: 7:25 StorageDead(_4); // scope 1 at $DIR/const_prop_miscompile.rs:7:24: 7:25 _0 = const (); // scope 0 at $DIR/const_prop_miscompile.rs:4:10: 8:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/const_prop_miscompile.rs:4:10: 8:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_3); // scope 1 at $DIR/const_prop_miscompile.rs:8:1: 8:2 StorageDead(_1); // scope 0 at $DIR/const_prop_miscompile.rs:8:1: 8:2 return; // scope 0 at $DIR/const_prop_miscompile.rs:8:2: 8:2 diff --git a/src/test/mir-opt/copy_propagation_arg.bar.CopyPropagation.diff b/src/test/mir-opt/copy_propagation_arg.bar.CopyPropagation.diff index fccb5bb16c0..fb793e53ea8 100644 --- a/src/test/mir-opt/copy_propagation_arg.bar.CopyPropagation.diff +++ b/src/test/mir-opt/copy_propagation_arg.bar.CopyPropagation.diff @@ -11,10 +11,7 @@ StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:16:5: 16:13 StorageLive(_3); // scope 0 at $DIR/copy_propagation_arg.rs:16:11: 16:12 _3 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:16:11: 16:12 - _2 = const dummy(move _3) -> bb1; // scope 0 at $DIR/copy_propagation_arg.rs:16:5: 16:13 - // ty::Const - // + ty: fn(u8) -> u8 {dummy} - // + val: Value(Scalar()) + _2 = dummy(move _3) -> bb1; // scope 0 at $DIR/copy_propagation_arg.rs:16:5: 16:13 // mir::Constant // + span: $DIR/copy_propagation_arg.rs:16:5: 16:10 // + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value(Scalar()) } @@ -25,12 +22,6 @@ StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:16:13: 16:14 _1 = const 5_u8; // scope 0 at $DIR/copy_propagation_arg.rs:17:5: 17:10 _0 = const (); // scope 0 at $DIR/copy_propagation_arg.rs:15:19: 18:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/copy_propagation_arg.rs:15:19: 18:2 - // + literal: Const { ty: (), val: Value(Scalar()) } return; // scope 0 at $DIR/copy_propagation_arg.rs:18:2: 18:2 } } diff --git a/src/test/mir-opt/copy_propagation_arg.baz.CopyPropagation.diff b/src/test/mir-opt/copy_propagation_arg.baz.CopyPropagation.diff index ee20553f7cc..b20003bd7c6 100644 --- a/src/test/mir-opt/copy_propagation_arg.baz.CopyPropagation.diff +++ b/src/test/mir-opt/copy_propagation_arg.baz.CopyPropagation.diff @@ -12,12 +12,6 @@ _1 = move _2; // scope 0 at $DIR/copy_propagation_arg.rs:23:5: 23:10 StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 _0 = const (); // scope 0 at $DIR/copy_propagation_arg.rs:21:20: 24:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/copy_propagation_arg.rs:21:20: 24:2 - // + literal: Const { ty: (), val: Value(Scalar()) } return; // scope 0 at $DIR/copy_propagation_arg.rs:24:2: 24:2 } } diff --git a/src/test/mir-opt/copy_propagation_arg.foo.CopyPropagation.diff b/src/test/mir-opt/copy_propagation_arg.foo.CopyPropagation.diff index 33aaa748678..d07a4c0541e 100644 --- a/src/test/mir-opt/copy_propagation_arg.foo.CopyPropagation.diff +++ b/src/test/mir-opt/copy_propagation_arg.foo.CopyPropagation.diff @@ -11,10 +11,7 @@ StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17 StorageLive(_3); // scope 0 at $DIR/copy_propagation_arg.rs:11:15: 11:16 _3 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:11:15: 11:16 - _2 = const dummy(move _3) -> bb1; // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17 - // ty::Const - // + ty: fn(u8) -> u8 {dummy} - // + val: Value(Scalar()) + _2 = dummy(move _3) -> bb1; // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17 // mir::Constant // + span: $DIR/copy_propagation_arg.rs:11:9: 11:14 // + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value(Scalar()) } @@ -25,12 +22,6 @@ _1 = move _2; // scope 0 at $DIR/copy_propagation_arg.rs:11:5: 11:17 StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:11:16: 11:17 _0 = const (); // scope 0 at $DIR/copy_propagation_arg.rs:9:19: 12:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/copy_propagation_arg.rs:9:19: 12:2 - // + literal: Const { ty: (), val: Value(Scalar()) } return; // scope 0 at $DIR/copy_propagation_arg.rs:12:2: 12:2 } } diff --git a/src/test/mir-opt/deaggregator_test.bar.Deaggregator.diff b/src/test/mir-opt/deaggregator_test.bar.Deaggregator.diff index ebe76e8e270..e60a1f3e75f 100644 --- a/src/test/mir-opt/deaggregator_test.bar.Deaggregator.diff +++ b/src/test/mir-opt/deaggregator_test.bar.Deaggregator.diff @@ -12,9 +12,6 @@ - _0 = Baz { x: move _2, y: const 0f32, z: const false }; // scope 0 at $DIR/deaggregator_test.rs:9:5: 9:35 + (_0.0: usize) = move _2; // scope 0 at $DIR/deaggregator_test.rs:9:5: 9:35 + (_0.1: f32) = const 0f32; // scope 0 at $DIR/deaggregator_test.rs:9:5: 9:35 - // ty::Const - // + ty: f32 - // + val: Value(Scalar(0x00000000)) // mir::Constant // + span: $DIR/deaggregator_test.rs:9:20: 9:23 // + literal: Const { ty: f32, val: Value(Scalar(0x00000000)) } diff --git a/src/test/mir-opt/fn-ptr-shim.rs b/src/test/mir-opt/fn-ptr-shim.rs index 796bec0be1e..64fbdc9ded1 100644 --- a/src/test/mir-opt/fn-ptr-shim.rs +++ b/src/test/mir-opt/fn-ptr-shim.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmir-opt-level=0 -Zvalidate-mir +// compile-flags: -Zmir-opt-level=0 // Tests that the `` shim does not create a `Call` terminator with a `Self` callee // (as only `FnDef` and `FnPtr` callees are allowed in MIR). diff --git a/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff b/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff index 4291e580bbf..9bf666bc761 100644 --- a/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff +++ b/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff @@ -38,10 +38,7 @@ StorageLive(_4); // scope 0 at $DIR/funky_arms.rs:15:9: 15:19 StorageLive(_5); // scope 0 at $DIR/funky_arms.rs:15:22: 15:25 _5 = &(*_1); // scope 0 at $DIR/funky_arms.rs:15:22: 15:25 - _4 = const std::fmt::Formatter::sign_plus(move _5) -> bb1; // scope 0 at $DIR/funky_arms.rs:15:22: 15:37 - // ty::Const - // + ty: for<'r> fn(&'r std::fmt::Formatter) -> bool {std::fmt::Formatter::sign_plus} - // + val: Value(Scalar()) + _4 = std::fmt::Formatter::sign_plus(move _5) -> bb1; // scope 0 at $DIR/funky_arms.rs:15:22: 15:37 // mir::Constant // + span: $DIR/funky_arms.rs:15:26: 15:35 // + literal: Const { ty: for<'r> fn(&'r std::fmt::Formatter) -> bool {std::fmt::Formatter::sign_plus}, val: Value(Scalar()) } @@ -67,10 +64,7 @@ StorageLive(_7); // scope 2 at $DIR/funky_arms.rs:24:30: 24:45 StorageLive(_8); // scope 2 at $DIR/funky_arms.rs:24:30: 24:33 _8 = &(*_1); // scope 2 at $DIR/funky_arms.rs:24:30: 24:33 - _7 = const std::fmt::Formatter::precision(move _8) -> bb5; // scope 2 at $DIR/funky_arms.rs:24:30: 24:45 - // ty::Const - // + ty: for<'r> fn(&'r std::fmt::Formatter) -> std::option::Option {std::fmt::Formatter::precision} - // + val: Value(Scalar()) + _7 = std::fmt::Formatter::precision(move _8) -> bb5; // scope 2 at $DIR/funky_arms.rs:24:30: 24:45 // mir::Constant // + span: $DIR/funky_arms.rs:24:34: 24:43 // + literal: Const { ty: for<'r> fn(&'r std::fmt::Formatter) -> std::option::Option {std::fmt::Formatter::precision}, val: Value(Scalar()) } @@ -91,10 +85,7 @@ _20 = _6; // scope 2 at $DIR/funky_arms.rs:28:56: 28:60 StorageLive(_21); // scope 2 at $DIR/funky_arms.rs:28:62: 28:67 _21 = _3; // scope 2 at $DIR/funky_arms.rs:28:62: 28:67 - _0 = const float_to_exponential_common_shortest::(move _18, move _19, move _20, move _21) -> bb9; // scope 2 at $DIR/funky_arms.rs:28:9: 28:68 - // ty::Const - // + ty: for<'r, 's, 't0> fn(&'r mut std::fmt::Formatter<'s>, &'t0 T, core::num::flt2dec::Sign, bool) -> std::result::Result<(), std::fmt::Error> {float_to_exponential_common_shortest::} - // + val: Value(Scalar()) + _0 = float_to_exponential_common_shortest::(move _18, move _19, move _20, move _21) -> bb9; // scope 2 at $DIR/funky_arms.rs:28:9: 28:68 // mir::Constant // + span: $DIR/funky_arms.rs:28:9: 28:45 // + literal: Const { ty: for<'r, 's, 't0> fn(&'r mut std::fmt::Formatter<'s>, &'t0 T, core::num::flt2dec::Sign, bool) -> std::result::Result<(), std::fmt::Error> {float_to_exponential_common_shortest::}, val: Value(Scalar()) } @@ -119,10 +110,7 @@ StorageDead(_15); // scope 3 at $DIR/funky_arms.rs:26:78: 26:79 StorageLive(_17); // scope 3 at $DIR/funky_arms.rs:26:81: 26:86 _17 = _3; // scope 3 at $DIR/funky_arms.rs:26:81: 26:86 - _0 = const float_to_exponential_common_exact::(move _11, move _12, move _13, move _14, move _17) -> bb8; // scope 3 at $DIR/funky_arms.rs:26:9: 26:87 - // ty::Const - // + ty: for<'r, 's, 't0> fn(&'r mut std::fmt::Formatter<'s>, &'t0 T, core::num::flt2dec::Sign, u32, bool) -> std::result::Result<(), std::fmt::Error> {float_to_exponential_common_exact::} - // + val: Value(Scalar()) + _0 = float_to_exponential_common_exact::(move _11, move _12, move _13, move _14, move _17) -> bb8; // scope 3 at $DIR/funky_arms.rs:26:9: 26:87 // mir::Constant // + span: $DIR/funky_arms.rs:26:9: 26:42 // + literal: Const { ty: for<'r, 's, 't0> fn(&'r mut std::fmt::Formatter<'s>, &'t0 T, core::num::flt2dec::Sign, u32, bool) -> std::result::Result<(), std::fmt::Error> {float_to_exponential_common_exact::}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/generator_storage_dead_unwind.main-{{closure}}.StateTransform.before.mir b/src/test/mir-opt/generator_storage_dead_unwind.main-{{closure}}.StateTransform.before.mir index 6d7e7b6a627..b6cda806831 100644 --- a/src/test/mir-opt/generator_storage_dead_unwind.main-{{closure}}.StateTransform.before.mir +++ b/src/test/mir-opt/generator_storage_dead_unwind.main-{{closure}}.StateTransform.before.mir @@ -39,10 +39,7 @@ yields () StorageLive(_7); // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:9: 26:16 StorageLive(_8); // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:14: 26:15 _8 = move _3; // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:14: 26:15 - _7 = const take::(move _8) -> [return: bb7, unwind: bb9]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:9: 26:16 - // ty::Const - // + ty: fn(Foo) {take::} - // + val: Value(Scalar()) + _7 = take::(move _8) -> [return: bb7, unwind: bb9]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:9: 26:16 // mir::Constant // + span: $DIR/generator-storage-dead-unwind.rs:26:9: 26:13 // + literal: Const { ty: fn(Foo) {take::}, val: Value(Scalar()) } @@ -75,10 +72,7 @@ yields () StorageLive(_9); // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:9: 27:16 StorageLive(_10); // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:14: 27:15 _10 = move _4; // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:14: 27:15 - _9 = const take::(move _10) -> [return: bb10, unwind: bb11]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:9: 27:16 - // ty::Const - // + ty: fn(Bar) {take::} - // + val: Value(Scalar()) + _9 = take::(move _10) -> [return: bb10, unwind: bb11]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:9: 27:16 // mir::Constant // + span: $DIR/generator-storage-dead-unwind.rs:27:9: 27:13 // + literal: Const { ty: fn(Bar) {take::}, val: Value(Scalar()) } @@ -100,12 +94,6 @@ yields () StorageDead(_10); // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:15: 27:16 StorageDead(_9); // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:16: 27:17 _0 = const (); // scope 0 at $DIR/generator-storage-dead-unwind.rs:22:19: 28:6 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/generator-storage-dead-unwind.rs:22:19: 28:6 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_4); // scope 1 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6 StorageDead(_3); // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6 drop(_1) -> [return: bb12, unwind: bb1]; // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6 diff --git a/src/test/mir-opt/generator_tiny.main-{{closure}}.generator_resume.0.mir b/src/test/mir-opt/generator_tiny.main-{{closure}}.generator_resume.0.mir index 41fc04774db..691f5eedad8 100644 --- a/src/test/mir-opt/generator_tiny.main-{{closure}}.generator_resume.0.mir +++ b/src/test/mir-opt/generator_tiny.main-{{closure}}.generator_resume.0.mir @@ -41,7 +41,8 @@ fn main::{{closure}}#0(_1: std::pin::Pin<&mut [generator@$DIR/generator-tiny.rs: bb2: { StorageLive(_6); // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18 StorageLive(_7); // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18 - _0 = std::ops::GeneratorState::<(), ()>::Yielded(move _7); // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18 + ((_0 as Yielded).0: ()) = move _7; // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18 + discriminant(_0) = 0; // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18 discriminant((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 25:6 {u8, HasDrop, ()}]))) = 3; // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18 return; // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18 } @@ -50,10 +51,7 @@ fn main::{{closure}}#0(_1: std::pin::Pin<&mut [generator@$DIR/generator-tiny.rs: StorageDead(_7); // scope 1 at $DIR/generator-tiny.rs:22:17: 22:18 StorageDead(_6); // scope 1 at $DIR/generator-tiny.rs:22:18: 22:19 StorageLive(_8); // scope 1 at $DIR/generator-tiny.rs:23:13: 23:21 - _8 = const callee() -> bb4; // scope 1 at $DIR/generator-tiny.rs:23:13: 23:21 - // ty::Const - // + ty: fn() {callee} - // + val: Value(Scalar()) + _8 = callee() -> bb4; // scope 1 at $DIR/generator-tiny.rs:23:13: 23:21 // mir::Constant // + span: $DIR/generator-tiny.rs:23:13: 23:19 // + literal: Const { ty: fn() {callee}, val: Value(Scalar()) } @@ -62,12 +60,6 @@ fn main::{{closure}}#0(_1: std::pin::Pin<&mut [generator@$DIR/generator-tiny.rs: bb4: { StorageDead(_8); // scope 1 at $DIR/generator-tiny.rs:23:21: 23:22 _5 = const (); // scope 1 at $DIR/generator-tiny.rs:21:14: 24:10 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/generator-tiny.rs:21:14: 24:10 - // + literal: Const { ty: (), val: Value(Scalar()) } goto -> bb2; // scope 1 at $DIR/generator-tiny.rs:21:9: 24:10 } diff --git a/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir b/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir index a31e7aaf272..9d490f047f7 100644 --- a/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir @@ -16,10 +16,7 @@ fn bar() -> bool { bb0: { StorageLive(_1); // scope 0 at $DIR/inline-any-operand.rs:11:9: 11:10 - _1 = const foo; // scope 0 at $DIR/inline-any-operand.rs:11:13: 11:16 - // ty::Const - // + ty: fn(i32, i32) -> bool {foo} - // + val: Value(Scalar()) + _1 = foo; // scope 0 at $DIR/inline-any-operand.rs:11:13: 11:16 // mir::Constant // + span: $DIR/inline-any-operand.rs:11:13: 11:16 // + literal: Const { ty: fn(i32, i32) -> bool {foo}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.diff.32bit b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.diff.32bit index 73ce7999220..0957698820f 100644 --- a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.diff.32bit +++ b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.diff.32bit @@ -17,60 +17,47 @@ StorageLive(_1); // scope 0 at $DIR/inline-into-box-place.rs:8:9: 8:11 StorageLive(_2); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 _2 = Box(std::vec::Vec); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 -- (*_2) = const std::vec::Vec::::new() -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 +- (*_2) = std::vec::Vec::::new() -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 + _4 = &mut (*_2); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 + ((*_4).0: alloc::raw_vec::RawVec) = const alloc::raw_vec::RawVec:: { ptr: std::ptr::Unique:: { pointer: {0x4 as *const u32}, _marker: std::marker::PhantomData:: }, cap: 0_usize, alloc: std::alloc::Global }; // scope 2 at $SRC_DIR/alloc/src/vec.rs:LL:COL - // ty::Const -- // + ty: fn() -> std::vec::Vec {std::vec::Vec::::new} -- // + val: Value(Scalar()) ++ // ty::Const + // + ty: alloc::raw_vec::RawVec + // + val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) // mir::Constant - // + span: $DIR/inline-into-box-place.rs:8:33: 8:41 - // + user_ty: UserType(1) - // + literal: Const { ty: fn() -> std::vec::Vec {std::vec::Vec::::new}, val: Value(Scalar()) } -- } -- -- bb1 (cleanup): { -- resume; // scope 0 at $DIR/inline-into-box-place.rs:7:1: 9:2 -- } -- -- bb2: { + // + span: $SRC_DIR/alloc/src/vec.rs:LL:COL + // + user_ty: UserType(0) + // + literal: Const { ty: alloc::raw_vec::RawVec, val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } + ((*_4).1: usize) = const 0_usize; // scope 2 at $SRC_DIR/alloc/src/vec.rs:LL:COL - _1 = move _2; // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 - StorageDead(_2); // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 - _0 = const (); // scope 0 at $DIR/inline-into-box-place.rs:7:11: 9:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/inline-into-box-place.rs:7:11: 9:2 - // + literal: Const { ty: (), val: Value(Scalar()) } -- drop(_1) -> [return: bb3, unwind: bb1]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 ++ _1 = move _2; // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 ++ StorageDead(_2); // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 ++ _0 = const (); // scope 0 at $DIR/inline-into-box-place.rs:7:11: 9:2 + drop(_1) -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 } -- bb3: { -- StorageDead(_1); // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 -- return; // scope 0 at $DIR/inline-into-box-place.rs:9:2: 9:2 -+ bb1 (cleanup): { -+ resume; // scope 0 at $DIR/inline-into-box-place.rs:7:1: 9:2 + bb1 (cleanup): { + resume; // scope 0 at $DIR/inline-into-box-place.rs:7:1: 9:2 } + bb2: { +- _1 = move _2; // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 +- StorageDead(_2); // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 +- _0 = const (); // scope 0 at $DIR/inline-into-box-place.rs:7:11: 9:2 +- drop(_1) -> [return: bb3, unwind: bb1]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 +- } +- +- bb3: { + StorageDead(_1); // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 + return; // scope 0 at $DIR/inline-into-box-place.rs:9:2: 9:2 +- } +- - bb4 (cleanup): { -- _3 = const alloc::alloc::box_free::>(move (_2.0: std::ptr::Unique>)) -> bb1; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 -- // ty::Const -- // + ty: unsafe fn(std::ptr::Unique>) {alloc::alloc::box_free::>} -- // + val: Value(Scalar()) +- _3 = alloc::alloc::box_free::>(move (_2.0: std::ptr::Unique>)) -> bb1; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 - // mir::Constant - // + span: $DIR/inline-into-box-place.rs:8:42: 8:43 - // + literal: Const { ty: unsafe fn(std::ptr::Unique>) {alloc::alloc::box_free::>}, val: Value(Scalar()) } -+ bb2: { -+ StorageDead(_1); // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 -+ return; // scope 0 at $DIR/inline-into-box-place.rs:9:2: 9:2 } } diff --git a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.diff.64bit b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.diff.64bit index 27ecaefd875..ab065fc3d25 100644 --- a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.diff.64bit +++ b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.diff.64bit @@ -17,60 +17,47 @@ StorageLive(_1); // scope 0 at $DIR/inline-into-box-place.rs:8:9: 8:11 StorageLive(_2); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 _2 = Box(std::vec::Vec); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 -- (*_2) = const std::vec::Vec::::new() -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 +- (*_2) = std::vec::Vec::::new() -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 + _4 = &mut (*_2); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 + ((*_4).0: alloc::raw_vec::RawVec) = const alloc::raw_vec::RawVec:: { ptr: std::ptr::Unique:: { pointer: {0x4 as *const u32}, _marker: std::marker::PhantomData:: }, cap: 0_usize, alloc: std::alloc::Global }; // scope 2 at $SRC_DIR/alloc/src/vec.rs:LL:COL - // ty::Const -- // + ty: fn() -> std::vec::Vec {std::vec::Vec::::new} -- // + val: Value(Scalar()) ++ // ty::Const + // + ty: alloc::raw_vec::RawVec + // + val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [65535], len: Size { raw: 16 } }, size: Size { raw: 16 }, align: Align { pow2: 3 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) // mir::Constant - // + span: $DIR/inline-into-box-place.rs:8:33: 8:41 - // + user_ty: UserType(1) - // + literal: Const { ty: fn() -> std::vec::Vec {std::vec::Vec::::new}, val: Value(Scalar()) } -- } -- -- bb1 (cleanup): { -- resume; // scope 0 at $DIR/inline-into-box-place.rs:7:1: 9:2 -- } -- -- bb2: { + // + span: $SRC_DIR/alloc/src/vec.rs:LL:COL + // + user_ty: UserType(0) + // + literal: Const { ty: alloc::raw_vec::RawVec, val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [65535], len: Size { raw: 16 } }, size: Size { raw: 16 }, align: Align { pow2: 3 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } + ((*_4).1: usize) = const 0_usize; // scope 2 at $SRC_DIR/alloc/src/vec.rs:LL:COL - _1 = move _2; // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 - StorageDead(_2); // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 - _0 = const (); // scope 0 at $DIR/inline-into-box-place.rs:7:11: 9:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/inline-into-box-place.rs:7:11: 9:2 - // + literal: Const { ty: (), val: Value(Scalar()) } -- drop(_1) -> [return: bb3, unwind: bb1]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 ++ _1 = move _2; // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 ++ StorageDead(_2); // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 ++ _0 = const (); // scope 0 at $DIR/inline-into-box-place.rs:7:11: 9:2 + drop(_1) -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 } -- bb3: { -- StorageDead(_1); // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 -- return; // scope 0 at $DIR/inline-into-box-place.rs:9:2: 9:2 -+ bb1 (cleanup): { -+ resume; // scope 0 at $DIR/inline-into-box-place.rs:7:1: 9:2 + bb1 (cleanup): { + resume; // scope 0 at $DIR/inline-into-box-place.rs:7:1: 9:2 } + bb2: { +- _1 = move _2; // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 +- StorageDead(_2); // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 +- _0 = const (); // scope 0 at $DIR/inline-into-box-place.rs:7:11: 9:2 +- drop(_1) -> [return: bb3, unwind: bb1]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 +- } +- +- bb3: { + StorageDead(_1); // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 + return; // scope 0 at $DIR/inline-into-box-place.rs:9:2: 9:2 +- } +- - bb4 (cleanup): { -- _3 = const alloc::alloc::box_free::>(move (_2.0: std::ptr::Unique>)) -> bb1; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 -- // ty::Const -- // + ty: unsafe fn(std::ptr::Unique>) {alloc::alloc::box_free::>} -- // + val: Value(Scalar()) +- _3 = alloc::alloc::box_free::>(move (_2.0: std::ptr::Unique>)) -> bb1; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 - // mir::Constant - // + span: $DIR/inline-into-box-place.rs:8:42: 8:43 - // + literal: Const { ty: unsafe fn(std::ptr::Unique>) {alloc::alloc::box_free::>}, val: Value(Scalar()) } -+ bb2: { -+ StorageDead(_1); // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 -+ return; // scope 0 at $DIR/inline-into-box-place.rs:9:2: 9:2 } } diff --git a/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir b/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir index d6ac1c57a63..29327108f3e 100644 --- a/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir @@ -24,10 +24,7 @@ fn bar() -> bool { bb0: { StorageLive(_1); // scope 0 at $DIR/inline-retag.rs:11:9: 11:10 - _1 = const foo; // scope 0 at $DIR/inline-retag.rs:11:13: 11:16 - // ty::Const - // + ty: for<'r, 's> fn(&'r i32, &'s i32) -> bool {foo} - // + val: Value(Scalar()) + _1 = foo; // scope 0 at $DIR/inline-retag.rs:11:13: 11:16 // mir::Constant // + span: $DIR/inline-retag.rs:11:13: 11:16 // + literal: Const { ty: for<'r, 's> fn(&'r i32, &'s i32) -> bool {foo}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/inline/inline_specialization.main.Inline.diff b/src/test/mir-opt/inline/inline_specialization.main.Inline.diff index fc0b40a8451..e97191b53e5 100644 --- a/src/test/mir-opt/inline/inline_specialization.main.Inline.diff +++ b/src/test/mir-opt/inline/inline_specialization.main.Inline.diff @@ -12,10 +12,7 @@ bb0: { StorageLive(_1); // scope 0 at $DIR/inline-specialization.rs:5:9: 5:10 -- _1 = const as Foo>::bar() -> bb1; // scope 0 at $DIR/inline-specialization.rs:5:13: 5:38 -- // ty::Const -- // + ty: fn() -> u32 { as Foo>::bar} -- // + val: Value(Scalar()) +- _1 = as Foo>::bar() -> bb1; // scope 0 at $DIR/inline-specialization.rs:5:13: 5:38 - // mir::Constant - // + span: $DIR/inline-specialization.rs:5:13: 5:36 - // + literal: Const { ty: fn() -> u32 { as Foo>::bar}, val: Value(Scalar()) } @@ -24,12 +21,6 @@ - bb1: { + _1 = const 123_u32; // scope 2 at $DIR/inline-specialization.rs:14:31: 14:34 _0 = const (); // scope 0 at $DIR/inline-specialization.rs:4:11: 6:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/inline-specialization.rs:4:11: 6:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_1); // scope 0 at $DIR/inline-specialization.rs:6:1: 6:2 return; // scope 0 at $DIR/inline-specialization.rs:6:2: 6:2 } diff --git a/src/test/mir-opt/inline/inline_trait_method.test.Inline.after.mir b/src/test/mir-opt/inline/inline_trait_method.test.Inline.after.mir index 8acc5ad5c09..eada5ac1347 100644 --- a/src/test/mir-opt/inline/inline_trait_method.test.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_trait_method.test.Inline.after.mir @@ -8,10 +8,7 @@ fn test(_1: &dyn X) -> u32 { bb0: { StorageLive(_2); // scope 0 at $DIR/inline-trait-method.rs:9:5: 9:6 _2 = &(*_1); // scope 0 at $DIR/inline-trait-method.rs:9:5: 9:6 - _0 = const ::y(move _2) -> bb1; // scope 0 at $DIR/inline-trait-method.rs:9:5: 9:10 - // ty::Const - // + ty: for<'r> fn(&'r dyn X) -> u32 {::y} - // + val: Value(Scalar()) + _0 = ::y(move _2) -> bb1; // scope 0 at $DIR/inline-trait-method.rs:9:5: 9:10 // mir::Constant // + span: $DIR/inline-trait-method.rs:9:7: 9:8 // + literal: Const { ty: for<'r> fn(&'r dyn X) -> u32 {::y}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir b/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir index afea1d5ebff..00e3ef06a49 100644 --- a/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir @@ -15,10 +15,7 @@ fn test2(_1: &dyn X) -> bool { _3 = &(*_1); // scope 0 at $DIR/inline-trait-method_2.rs:5:10: 5:11 _2 = move _3 as &dyn X (Pointer(Unsize)); // scope 0 at $DIR/inline-trait-method_2.rs:5:10: 5:11 StorageDead(_3); // scope 0 at $DIR/inline-trait-method_2.rs:5:10: 5:11 - _0 = const ::y(move _2) -> bb1; // scope 1 at $DIR/inline-trait-method_2.rs:10:5: 10:10 - // ty::Const - // + ty: for<'r> fn(&'r dyn X) -> bool {::y} - // + val: Value(Scalar()) + _0 = ::y(move _2) -> bb1; // scope 1 at $DIR/inline-trait-method_2.rs:10:5: 10:10 // mir::Constant // + span: $DIR/inline-trait-method_2.rs:10:7: 10:8 // + literal: Const { ty: for<'r> fn(&'r dyn X) -> bool {::y}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff b/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff index c3831cb2bb4..43c8be8f45d 100644 --- a/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff +++ b/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff @@ -14,10 +14,7 @@ bb1: { StorageLive(_2); // scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17 - _2 = const bar() -> [return: bb3, unwind: bb2]; // scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17 - // ty::Const - // + ty: fn() -> bool {bar} - // + val: Value(Scalar()) + _2 = bar() -> [return: bb3, unwind: bb2]; // scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17 // mir::Constant // + span: /the/src/instrument_coverage.rs:12:12: 12:15 // + literal: Const { ty: fn() -> bool {bar}, val: Value(Scalar()) } @@ -38,24 +35,12 @@ bb5: { _1 = const (); // scope 0 at /the/src/instrument_coverage.rs:12:9: 14:10 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: /the/src/instrument_coverage.rs:12:9: 14:10 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_2); // scope 0 at /the/src/instrument_coverage.rs:15:5: 15:6 goto -> bb0; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 } bb6: { _0 = const (); // scope 0 at /the/src/instrument_coverage.rs:13:13: 13:18 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: /the/src/instrument_coverage.rs:13:13: 13:18 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_2); // scope 0 at /the/src/instrument_coverage.rs:15:5: 15:6 return; // scope 0 at /the/src/instrument_coverage.rs:16:2: 16:2 } diff --git a/src/test/mir-opt/issue_38669.main.SimplifyCfg-initial.after.mir b/src/test/mir-opt/issue_38669.main.SimplifyCfg-initial.after.mir index 3dabc41f195..6bde4da2ecf 100644 --- a/src/test/mir-opt/issue_38669.main.SimplifyCfg-initial.after.mir +++ b/src/test/mir-opt/issue_38669.main.SimplifyCfg-initial.after.mir @@ -40,33 +40,15 @@ fn main() -> () { bb5: { _3 = const (); // scope 1 at $DIR/issue-38669.rs:7:9: 9:10 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/issue-38669.rs:7:9: 9:10 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_4); // scope 1 at $DIR/issue-38669.rs:9:9: 9:10 StorageDead(_3); // scope 1 at $DIR/issue-38669.rs:9:9: 9:10 _1 = const true; // scope 1 at $DIR/issue-38669.rs:10:9: 10:28 _2 = const (); // scope 1 at $DIR/issue-38669.rs:6:10: 11:6 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/issue-38669.rs:6:10: 11:6 - // + literal: Const { ty: (), val: Value(Scalar()) } goto -> bb2; // scope 1 at $DIR/issue-38669.rs:6:5: 11:6 } bb6: { _0 = const (); // scope 1 at $DIR/issue-38669.rs:8:13: 8:18 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/issue-38669.rs:8:13: 8:18 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_4); // scope 1 at $DIR/issue-38669.rs:9:9: 9:10 StorageDead(_3); // scope 1 at $DIR/issue-38669.rs:9:9: 9:10 StorageDead(_1); // scope 0 at $DIR/issue-38669.rs:12:1: 12:2 diff --git a/src/test/mir-opt/issue_41110.main.ElaborateDrops.after.mir b/src/test/mir-opt/issue_41110.main.ElaborateDrops.after.mir index 70eaf817021..04dea1672b3 100644 --- a/src/test/mir-opt/issue_41110.main.ElaborateDrops.after.mir +++ b/src/test/mir-opt/issue_41110.main.ElaborateDrops.after.mir @@ -20,10 +20,7 @@ fn main() -> () { StorageLive(_3); // scope 0 at $DIR/issue-41110.rs:8:21: 8:27 StorageLive(_4); // scope 0 at $DIR/issue-41110.rs:8:21: 8:22 _4 = S; // scope 0 at $DIR/issue-41110.rs:8:21: 8:22 - _3 = const S::id(move _4) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-41110.rs:8:21: 8:27 - // ty::Const - // + ty: fn(S) -> S {S::id} - // + val: Value(Scalar()) + _3 = S::id(move _4) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-41110.rs:8:21: 8:27 // mir::Constant // + span: $DIR/issue-41110.rs:8:23: 8:25 // + literal: Const { ty: fn(S) -> S {S::id}, val: Value(Scalar()) } @@ -36,10 +33,7 @@ fn main() -> () { bb2: { StorageDead(_4); // scope 0 at $DIR/issue-41110.rs:8:26: 8:27 _5 = const false; // scope 0 at $DIR/issue-41110.rs:8:13: 8:28 - _1 = const S::other(move _2, move _3) -> [return: bb6, unwind: bb5]; // scope 0 at $DIR/issue-41110.rs:8:13: 8:28 - // ty::Const - // + ty: fn(S, S) {S::other} - // + val: Value(Scalar()) + _1 = S::other(move _2, move _3) -> [return: bb6, unwind: bb5]; // scope 0 at $DIR/issue-41110.rs:8:13: 8:28 // mir::Constant // + span: $DIR/issue-41110.rs:8:15: 8:20 // + literal: Const { ty: fn(S, S) {S::other}, val: Value(Scalar()) } @@ -62,12 +56,6 @@ fn main() -> () { _5 = const false; // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 StorageDead(_2); // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 _0 = const (); // scope 0 at $DIR/issue-41110.rs:7:11: 9:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/issue-41110.rs:7:11: 9:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_1); // scope 0 at $DIR/issue-41110.rs:9:1: 9:2 return; // scope 0 at $DIR/issue-41110.rs:9:2: 9:2 } diff --git a/src/test/mir-opt/issue_41110.test.ElaborateDrops.after.mir b/src/test/mir-opt/issue_41110.test.ElaborateDrops.after.mir index 6b4f641b1f0..c4a2e7a0ae3 100644 --- a/src/test/mir-opt/issue_41110.test.ElaborateDrops.after.mir +++ b/src/test/mir-opt/issue_41110.test.ElaborateDrops.after.mir @@ -25,10 +25,7 @@ fn test() -> () { StorageLive(_3); // scope 2 at $DIR/issue-41110.rs:17:5: 17:12 StorageLive(_4); // scope 2 at $DIR/issue-41110.rs:17:10: 17:11 _4 = move _2; // scope 2 at $DIR/issue-41110.rs:17:10: 17:11 - _3 = const std::mem::drop::(move _4) -> [return: bb2, unwind: bb5]; // scope 2 at $DIR/issue-41110.rs:17:5: 17:12 - // ty::Const - // + ty: fn(S) {std::mem::drop::} - // + val: Value(Scalar()) + _3 = std::mem::drop::(move _4) -> [return: bb2, unwind: bb5]; // scope 2 at $DIR/issue-41110.rs:17:5: 17:12 // mir::Constant // + span: $DIR/issue-41110.rs:17:5: 17:9 // + literal: Const { ty: fn(S) {std::mem::drop::}, val: Value(Scalar()) } @@ -70,12 +67,6 @@ fn test() -> () { bb8: { StorageDead(_5); // scope 2 at $DIR/issue-41110.rs:18:9: 18:10 _0 = const (); // scope 0 at $DIR/issue-41110.rs:14:15: 19:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/issue-41110.rs:14:15: 19:2 - // + literal: Const { ty: (), val: Value(Scalar()) } drop(_2) -> [return: bb9, unwind: bb3]; // scope 1 at $DIR/issue-41110.rs:19:1: 19:2 } diff --git a/src/test/mir-opt/issue_41888.main.ElaborateDrops.after.mir b/src/test/mir-opt/issue_41888.main.ElaborateDrops.after.mir index cb8057eb75b..84ba4d78ba0 100644 --- a/src/test/mir-opt/issue_41888.main.ElaborateDrops.after.mir +++ b/src/test/mir-opt/issue_41888.main.ElaborateDrops.after.mir @@ -26,10 +26,7 @@ fn main() -> () { _8 = const false; // scope 0 at $DIR/issue-41888.rs:7:9: 7:10 StorageLive(_1); // scope 0 at $DIR/issue-41888.rs:7:9: 7:10 StorageLive(_2); // scope 1 at $DIR/issue-41888.rs:8:8: 8:14 - _2 = const cond() -> [return: bb2, unwind: bb3]; // scope 1 at $DIR/issue-41888.rs:8:8: 8:14 - // ty::Const - // + ty: fn() -> bool {cond} - // + val: Value(Scalar()) + _2 = cond() -> [return: bb2, unwind: bb3]; // scope 1 at $DIR/issue-41888.rs:8:8: 8:14 // mir::Constant // + span: $DIR/issue-41888.rs:8:8: 8:12 // + literal: Const { ty: fn() -> bool {cond}, val: Value(Scalar()) } @@ -49,12 +46,6 @@ fn main() -> () { bb4: { _0 = const (); // scope 1 at $DIR/issue-41888.rs:8:5: 14:6 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/issue-41888.rs:8:5: 14:6 - // + literal: Const { ty: (), val: Value(Scalar()) } goto -> bb11; // scope 1 at $DIR/issue-41888.rs:8:5: 14:6 } @@ -83,12 +74,6 @@ fn main() -> () { bb9: { _0 = const (); // scope 1 at $DIR/issue-41888.rs:10:9: 13:10 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/issue-41888.rs:10:9: 13:10 - // + literal: Const { ty: (), val: Value(Scalar()) } goto -> bb11; // scope 1 at $DIR/issue-41888.rs:10:9: 13:10 } @@ -97,12 +82,6 @@ fn main() -> () { _9 = const false; // scope 1 at $DIR/issue-41888.rs:10:21: 10:23 _6 = move ((_1 as F).0: K); // scope 1 at $DIR/issue-41888.rs:10:21: 10:23 _0 = const (); // scope 2 at $DIR/issue-41888.rs:10:29: 13:10 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/issue-41888.rs:10:29: 13:10 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_6); // scope 1 at $DIR/issue-41888.rs:13:9: 13:10 goto -> bb11; // scope 1 at $DIR/issue-41888.rs:10:9: 13:10 } diff --git a/src/test/mir-opt/issue_49232.main.mir_map.0.mir b/src/test/mir-opt/issue_49232.main.mir_map.0.mir index 4b6cdbf2644..8d76835c636 100644 --- a/src/test/mir-opt/issue_49232.main.mir_map.0.mir +++ b/src/test/mir-opt/issue_49232.main.mir_map.0.mir @@ -42,12 +42,6 @@ fn main() -> () { bb6: { _0 = const (); // scope 0 at $DIR/issue-49232.rs:10:25: 10:30 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/issue-49232.rs:10:25: 10:30 - // + literal: Const { ty: (), val: Value(Scalar()) } goto -> bb8; // scope 0 at $DIR/issue-49232.rs:10:25: 10:30 } @@ -80,10 +74,7 @@ fn main() -> () { StorageLive(_5); // scope 1 at $DIR/issue-49232.rs:13:9: 13:22 StorageLive(_6); // scope 1 at $DIR/issue-49232.rs:13:14: 13:21 _6 = &_2; // scope 1 at $DIR/issue-49232.rs:13:14: 13:21 - _5 = const std::mem::drop::<&i32>(move _6) -> [return: bb13, unwind: bb4]; // scope 1 at $DIR/issue-49232.rs:13:9: 13:22 - // ty::Const - // + ty: fn(&i32) {std::mem::drop::<&i32>} - // + val: Value(Scalar()) + _5 = std::mem::drop::<&i32>(move _6) -> [return: bb13, unwind: bb4]; // scope 1 at $DIR/issue-49232.rs:13:9: 13:22 // mir::Constant // + span: $DIR/issue-49232.rs:13:9: 13:13 // + literal: Const { ty: fn(&i32) {std::mem::drop::<&i32>}, val: Value(Scalar()) } @@ -93,12 +84,6 @@ fn main() -> () { StorageDead(_6); // scope 1 at $DIR/issue-49232.rs:13:21: 13:22 StorageDead(_5); // scope 1 at $DIR/issue-49232.rs:13:22: 13:23 _1 = const (); // scope 0 at $DIR/issue-49232.rs:6:10: 14:6 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/issue-49232.rs:6:10: 14:6 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_2); // scope 0 at $DIR/issue-49232.rs:14:5: 14:6 goto -> bb1; // scope 0 at $DIR/issue-49232.rs:6:5: 14:6 } diff --git a/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir b/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir index 56916d676ed..c71ae934622 100644 --- a/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir +++ b/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir @@ -30,10 +30,7 @@ fn test() -> std::option::Option> { StorageLive(_3); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 StorageLive(_4); // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 _4 = std::option::Option::::None; // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 - _3 = const as std::ops::Try>::into_result(move _4) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 - // ty::Const - // + ty: fn(std::option::Option) -> std::result::Result< as std::ops::Try>::Ok, as std::ops::Try>::Error> { as std::ops::Try>::into_result} - // + val: Value(Scalar()) + _3 = as std::ops::Try>::into_result(move _4) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 // mir::Constant // + span: $DIR/issue-62289.rs:9:15: 9:20 // + literal: Const { ty: fn(std::option::Option) -> std::result::Result< as std::ops::Try>::Ok, as std::ops::Try>::Error> { as std::ops::Try>::into_result}, val: Value(Scalar()) } @@ -72,10 +69,7 @@ fn test() -> std::option::Option> { StorageLive(_8); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 StorageLive(_9); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 _9 = _6; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - _8 = const >::from(move _9) -> [return: bb8, unwind: bb3]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - // ty::Const - // + ty: fn(std::option::NoneError) -> std::option::NoneError {>::from} - // + val: Value(Scalar()) + _8 = >::from(move _9) -> [return: bb8, unwind: bb3]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 // mir::Constant // + span: $DIR/issue-62289.rs:9:19: 9:20 // + literal: Const { ty: fn(std::option::NoneError) -> std::option::NoneError {>::from}, val: Value(Scalar()) } @@ -87,10 +81,7 @@ fn test() -> std::option::Option> { bb8: { StorageDead(_9); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - _0 = const > as std::ops::Try>::from_error(move _8) -> [return: bb9, unwind: bb3]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - // ty::Const - // + ty: fn(> as std::ops::Try>::Error) -> std::option::Option> {> as std::ops::Try>::from_error} - // + val: Value(Scalar()) + _0 = > as std::ops::Try>::from_error(move _8) -> [return: bb9, unwind: bb3]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 // mir::Constant // + span: $DIR/issue-62289.rs:9:15: 9:20 // + literal: Const { ty: fn(> as std::ops::Try>::Error) -> std::option::Option> {> as std::ops::Try>::from_error}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/issue_72181.main.mir_map.0.mir.32bit b/src/test/mir-opt/issue_72181.main.mir_map.0.mir.32bit index 71a70d2d211..89b60121496 100644 --- a/src/test/mir-opt/issue_72181.main.mir_map.0.mir.32bit +++ b/src/test/mir-opt/issue_72181.main.mir_map.0.mir.32bit @@ -22,10 +22,7 @@ fn main() -> () { bb0: { StorageLive(_1); // scope 0 at $DIR/issue-72181.rs:24:13: 24:34 - _1 = const std::mem::size_of::() -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:24:13: 24:34 - // ty::Const - // + ty: fn() -> usize {std::mem::size_of::} - // + val: Value(Scalar()) + _1 = std::mem::size_of::() -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:24:13: 24:34 // mir::Constant // + span: $DIR/issue-72181.rs:24:13: 24:32 // + literal: Const { ty: fn() -> usize {std::mem::size_of::}, val: Value(Scalar()) } @@ -59,12 +56,6 @@ fn main() -> () { StorageDead(_6); // scope 2 at $DIR/issue-72181.rs:27:30: 27:31 StorageDead(_5); // scope 2 at $DIR/issue-72181.rs:27:30: 27:31 _0 = const (); // scope 0 at $DIR/issue-72181.rs:23:11: 28:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/issue-72181.rs:23:11: 28:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_2); // scope 1 at $DIR/issue-72181.rs:28:1: 28:2 goto -> bb4; // scope 0 at $DIR/issue-72181.rs:28:2: 28:2 } diff --git a/src/test/mir-opt/issue_72181.main.mir_map.0.mir.64bit b/src/test/mir-opt/issue_72181.main.mir_map.0.mir.64bit index 71a70d2d211..89b60121496 100644 --- a/src/test/mir-opt/issue_72181.main.mir_map.0.mir.64bit +++ b/src/test/mir-opt/issue_72181.main.mir_map.0.mir.64bit @@ -22,10 +22,7 @@ fn main() -> () { bb0: { StorageLive(_1); // scope 0 at $DIR/issue-72181.rs:24:13: 24:34 - _1 = const std::mem::size_of::() -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:24:13: 24:34 - // ty::Const - // + ty: fn() -> usize {std::mem::size_of::} - // + val: Value(Scalar()) + _1 = std::mem::size_of::() -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:24:13: 24:34 // mir::Constant // + span: $DIR/issue-72181.rs:24:13: 24:32 // + literal: Const { ty: fn() -> usize {std::mem::size_of::}, val: Value(Scalar()) } @@ -59,12 +56,6 @@ fn main() -> () { StorageDead(_6); // scope 2 at $DIR/issue-72181.rs:27:30: 27:31 StorageDead(_5); // scope 2 at $DIR/issue-72181.rs:27:30: 27:31 _0 = const (); // scope 0 at $DIR/issue-72181.rs:23:11: 28:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/issue-72181.rs:23:11: 28:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_2); // scope 1 at $DIR/issue-72181.rs:28:1: 28:2 goto -> bb4; // scope 0 at $DIR/issue-72181.rs:28:2: 28:2 } diff --git a/src/test/mir-opt/issue_72181_1.main.mir_map.0.mir b/src/test/mir-opt/issue_72181_1.main.mir_map.0.mir index b87d0294fb8..b3aea29f13c 100644 --- a/src/test/mir-opt/issue_72181_1.main.mir_map.0.mir +++ b/src/test/mir-opt/issue_72181_1.main.mir_map.0.mir @@ -21,10 +21,7 @@ fn main() -> () { StorageLive(_2); // scope 0 at $DIR/issue-72181-1.rs:16:9: 16:10 StorageLive(_3); // scope 2 at $DIR/issue-72181-1.rs:17:41: 17:43 _3 = (); // scope 2 at $DIR/issue-72181-1.rs:17:41: 17:43 - _2 = const std::intrinsics::transmute::<(), Void>(move _3) -> [return: bb2, unwind: bb1]; // scope 2 at $DIR/issue-72181-1.rs:17:9: 17:44 - // ty::Const - // + ty: unsafe extern "rust-intrinsic" fn(()) -> Void {std::intrinsics::transmute::<(), Void>} - // + val: Value(Scalar()) + _2 = std::intrinsics::transmute::<(), Void>(move _3) -> [return: bb2, unwind: bb1]; // scope 2 at $DIR/issue-72181-1.rs:17:9: 17:44 // mir::Constant // + span: $DIR/issue-72181-1.rs:17:9: 17:40 // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(()) -> Void {std::intrinsics::transmute::<(), Void>}, val: Value(Scalar()) } @@ -41,10 +38,7 @@ fn main() -> () { StorageLive(_4); // scope 1 at $DIR/issue-72181-1.rs:20:5: 20:9 StorageLive(_5); // scope 1 at $DIR/issue-72181-1.rs:20:7: 20:8 _5 = move _2; // scope 1 at $DIR/issue-72181-1.rs:20:7: 20:8 - const f(move _5) -> bb1; // scope 1 at $DIR/issue-72181-1.rs:20:5: 20:9 - // ty::Const - // + ty: fn(Void) -> ! {f} - // + val: Value(Scalar()) + f(move _5) -> bb1; // scope 1 at $DIR/issue-72181-1.rs:20:5: 20:9 // mir::Constant // + span: $DIR/issue-72181-1.rs:20:5: 20:6 // + literal: Const { ty: fn(Void) -> ! {f}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.diff.32bit b/src/test/mir-opt/issue_73223.main.PreCodegen.diff.32bit index f7db1626016..b940f1a929d 100644 --- a/src/test/mir-opt/issue_73223.main.PreCodegen.diff.32bit +++ b/src/test/mir-opt/issue_73223.main.PreCodegen.diff.32bit @@ -112,12 +112,6 @@ StorageDead(_7); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _0 = const (); // scope 0 at $DIR/issue-73223.rs:1:11: 9:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/issue-73223.rs:1:11: 9:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_3); // scope 1 at $DIR/issue-73223.rs:9:1: 9:2 return; // scope 0 at $DIR/issue-73223.rs:9:2: 9:2 } @@ -146,18 +140,12 @@ _22 = (_18.0: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _23 = (_18.1: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_24); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL - _25 = const <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - // ty::Const - // + ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt} - // + val: Value(Scalar()) + _25 = <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL // + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar()) } StorageLive(_28); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _28 = const std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _25) -> bb3; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - // ty::Const - // + ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>} - // + val: Value(Scalar()) + _28 = std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _25) -> bb3; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar()) } @@ -165,10 +153,7 @@ bb3: { StorageLive(_29); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _29 = const std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _22) -> bb4; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - // ty::Const - // + ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>} - // + val: Value(Scalar()) + _29 = std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _22) -> bb4; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar()) } @@ -180,18 +165,12 @@ StorageDead(_29); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageDead(_28); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageLive(_26); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL - _27 = const <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - // ty::Const - // + ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt} - // + val: Value(Scalar()) + _27 = <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL // + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar()) } StorageLive(_30); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _30 = const std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _27) -> bb5; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - // ty::Const - // + ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>} - // + val: Value(Scalar()) + _30 = std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _27) -> bb5; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar()) } @@ -199,10 +178,7 @@ bb5: { StorageLive(_31); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _31 = const std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _23) -> bb6; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - // ty::Const - // + ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>} - // + val: Value(Scalar()) + _31 = std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _23) -> bb6; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar()) } @@ -225,10 +201,7 @@ (_13.2: &[std::fmt::ArgumentV1]) = move _15; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageDead(_32); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL _12 = &_13; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - const std::rt::begin_panic_fmt(move _12); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - // ty::Const - // + ty: for<'r, 's> fn(&'r std::fmt::Arguments<'s>) -> ! {std::rt::begin_panic_fmt} - // + val: Value(Scalar()) + std::rt::begin_panic_fmt(move _12); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL // mir::Constant // + span: $SRC_DIR/std/src/macros.rs:LL:COL // + literal: Const { ty: for<'r, 's> fn(&'r std::fmt::Arguments<'s>) -> ! {std::rt::begin_panic_fmt}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.diff.64bit b/src/test/mir-opt/issue_73223.main.PreCodegen.diff.64bit index f7db1626016..b940f1a929d 100644 --- a/src/test/mir-opt/issue_73223.main.PreCodegen.diff.64bit +++ b/src/test/mir-opt/issue_73223.main.PreCodegen.diff.64bit @@ -112,12 +112,6 @@ StorageDead(_7); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _0 = const (); // scope 0 at $DIR/issue-73223.rs:1:11: 9:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/issue-73223.rs:1:11: 9:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_3); // scope 1 at $DIR/issue-73223.rs:9:1: 9:2 return; // scope 0 at $DIR/issue-73223.rs:9:2: 9:2 } @@ -146,18 +140,12 @@ _22 = (_18.0: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _23 = (_18.1: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_24); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL - _25 = const <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - // ty::Const - // + ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt} - // + val: Value(Scalar()) + _25 = <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL // + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar()) } StorageLive(_28); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _28 = const std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _25) -> bb3; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - // ty::Const - // + ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>} - // + val: Value(Scalar()) + _28 = std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _25) -> bb3; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar()) } @@ -165,10 +153,7 @@ bb3: { StorageLive(_29); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _29 = const std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _22) -> bb4; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - // ty::Const - // + ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>} - // + val: Value(Scalar()) + _29 = std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _22) -> bb4; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar()) } @@ -180,18 +165,12 @@ StorageDead(_29); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageDead(_28); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageLive(_26); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL - _27 = const <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - // ty::Const - // + ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt} - // + val: Value(Scalar()) + _27 = <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL // + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar()) } StorageLive(_30); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _30 = const std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _27) -> bb5; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - // ty::Const - // + ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>} - // + val: Value(Scalar()) + _30 = std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _27) -> bb5; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar()) } @@ -199,10 +178,7 @@ bb5: { StorageLive(_31); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _31 = const std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _23) -> bb6; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - // ty::Const - // + ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>} - // + val: Value(Scalar()) + _31 = std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _23) -> bb6; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar()) } @@ -225,10 +201,7 @@ (_13.2: &[std::fmt::ArgumentV1]) = move _15; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageDead(_32); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL _12 = &_13; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - const std::rt::begin_panic_fmt(move _12); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - // ty::Const - // + ty: for<'r, 's> fn(&'r std::fmt::Arguments<'s>) -> ! {std::rt::begin_panic_fmt} - // + val: Value(Scalar()) + std::rt::begin_panic_fmt(move _12); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL // mir::Constant // + span: $SRC_DIR/std/src/macros.rs:LL:COL // + literal: Const { ty: for<'r, 's> fn(&'r std::fmt::Arguments<'s>) -> ! {std::rt::begin_panic_fmt}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff.32bit b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff.32bit index 957d33e2461..586a9f7624c 100644 --- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff.32bit +++ b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff.32bit @@ -104,12 +104,6 @@ bb1: { _0 = const (); // scope 0 at $DIR/issue-73223.rs:4:17: 4:23 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/issue-73223.rs:4:17: 4:23 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:5:6: 5:7 StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:9:1: 9:2 goto -> bb3; // scope 0 at $DIR/issue-73223.rs:4:17: 4:23 @@ -168,24 +162,12 @@ bb4: { _8 = const (); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_15); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_14); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_13); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _0 = const (); // scope 0 at $DIR/issue-73223.rs:1:11: 9:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/issue-73223.rs:1:11: 9:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_6); // scope 1 at $DIR/issue-73223.rs:9:1: 9:2 StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:9:1: 9:2 goto -> bb3; // scope 0 at $DIR/issue-73223.rs:9:2: 9:2 @@ -235,20 +217,14 @@ StorageLive(_39); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _39 = _36; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_40); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _40 = const <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - // ty::Const - // + ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt} - // + val: Value(Scalar()) + _40 = <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL // + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar()) } StorageLive(_46); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageLive(_47); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL _47 = _40; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _46 = const std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _47) -> bb6; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - // ty::Const - // + ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>} - // + val: Value(Scalar()) + _46 = std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _47) -> bb6; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar()) } @@ -259,10 +235,7 @@ StorageLive(_48); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageLive(_49); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL _49 = _39; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _48 = const std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _49) -> bb7; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - // ty::Const - // + ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>} - // + val: Value(Scalar()) + _48 = std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _49) -> bb7; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar()) } @@ -280,20 +253,14 @@ StorageLive(_42); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _42 = _37; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_43); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _43 = const <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - // ty::Const - // + ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt} - // + val: Value(Scalar()) + _43 = <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL // + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar()) } StorageLive(_50); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageLive(_51); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL _51 = _43; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _50 = const std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _51) -> bb8; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - // ty::Const - // + ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>} - // + val: Value(Scalar()) + _50 = std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _51) -> bb8; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar()) } @@ -304,10 +271,7 @@ StorageLive(_52); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageLive(_53); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL _53 = _42; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _52 = const std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _53) -> bb9; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - // ty::Const - // + ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>} - // + val: Value(Scalar()) + _52 = std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _53) -> bb9; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar()) } @@ -346,10 +310,7 @@ StorageDead(_23); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL _21 = &_22; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL _20 = _21; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - const std::rt::begin_panic_fmt(move _20); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - // ty::Const - // + ty: for<'r, 's> fn(&'r std::fmt::Arguments<'s>) -> ! {std::rt::begin_panic_fmt} - // + val: Value(Scalar()) + std::rt::begin_panic_fmt(move _20); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL // mir::Constant // + span: $SRC_DIR/std/src/macros.rs:LL:COL // + literal: Const { ty: for<'r, 's> fn(&'r std::fmt::Arguments<'s>) -> ! {std::rt::begin_panic_fmt}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff.64bit b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff.64bit index 957d33e2461..586a9f7624c 100644 --- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff.64bit +++ b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff.64bit @@ -104,12 +104,6 @@ bb1: { _0 = const (); // scope 0 at $DIR/issue-73223.rs:4:17: 4:23 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/issue-73223.rs:4:17: 4:23 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:5:6: 5:7 StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:9:1: 9:2 goto -> bb3; // scope 0 at $DIR/issue-73223.rs:4:17: 4:23 @@ -168,24 +162,12 @@ bb4: { _8 = const (); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_15); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_14); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_13); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _0 = const (); // scope 0 at $DIR/issue-73223.rs:1:11: 9:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/issue-73223.rs:1:11: 9:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_6); // scope 1 at $DIR/issue-73223.rs:9:1: 9:2 StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:9:1: 9:2 goto -> bb3; // scope 0 at $DIR/issue-73223.rs:9:2: 9:2 @@ -235,20 +217,14 @@ StorageLive(_39); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _39 = _36; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_40); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _40 = const <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - // ty::Const - // + ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt} - // + val: Value(Scalar()) + _40 = <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL // + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar()) } StorageLive(_46); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageLive(_47); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL _47 = _40; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _46 = const std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _47) -> bb6; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - // ty::Const - // + ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>} - // + val: Value(Scalar()) + _46 = std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _47) -> bb6; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar()) } @@ -259,10 +235,7 @@ StorageLive(_48); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageLive(_49); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL _49 = _39; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _48 = const std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _49) -> bb7; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - // ty::Const - // + ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>} - // + val: Value(Scalar()) + _48 = std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _49) -> bb7; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar()) } @@ -280,20 +253,14 @@ StorageLive(_42); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _42 = _37; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_43); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _43 = const <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - // ty::Const - // + ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt} - // + val: Value(Scalar()) + _43 = <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL // + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar()) } StorageLive(_50); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageLive(_51); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL _51 = _43; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _50 = const std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _51) -> bb8; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - // ty::Const - // + ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>} - // + val: Value(Scalar()) + _50 = std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _51) -> bb8; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar()) } @@ -304,10 +271,7 @@ StorageLive(_52); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageLive(_53); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL _53 = _42; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _52 = const std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _53) -> bb9; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - // ty::Const - // + ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>} - // + val: Value(Scalar()) + _52 = std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _53) -> bb9; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar()) } @@ -346,10 +310,7 @@ StorageDead(_23); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL _21 = &_22; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL _20 = _21; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - const std::rt::begin_panic_fmt(move _20); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - // ty::Const - // + ty: for<'r, 's> fn(&'r std::fmt::Arguments<'s>) -> ! {std::rt::begin_panic_fmt} - // + val: Value(Scalar()) + std::rt::begin_panic_fmt(move _20); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL // mir::Constant // + span: $SRC_DIR/std/src/macros.rs:LL:COL // + literal: Const { ty: for<'r, 's> fn(&'r std::fmt::Arguments<'s>) -> ! {std::rt::begin_panic_fmt}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/loop_test.main.SimplifyCfg-promote-consts.after.mir b/src/test/mir-opt/loop_test.main.SimplifyCfg-promote-consts.after.mir index b95e73854e3..9f9904b40c7 100644 --- a/src/test/mir-opt/loop_test.main.SimplifyCfg-promote-consts.after.mir +++ b/src/test/mir-opt/loop_test.main.SimplifyCfg-promote-consts.after.mir @@ -30,12 +30,6 @@ fn main() -> () { bb3: { _1 = const (); // scope 0 at $DIR/loop_test.rs:10:5: 12:6 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/loop_test.rs:10:5: 12:6 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_2); // scope 0 at $DIR/loop_test.rs:12:5: 12:6 StorageDead(_1); // scope 0 at $DIR/loop_test.rs:12:5: 12:6 StorageLive(_4); // scope 0 at $DIR/loop_test.rs:13:5: 16:6 @@ -44,12 +38,6 @@ fn main() -> () { bb4: { _0 = const (); // scope 0 at $DIR/loop_test.rs:11:9: 11:15 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/loop_test.rs:11:9: 11:15 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_2); // scope 0 at $DIR/loop_test.rs:12:5: 12:6 StorageDead(_1); // scope 0 at $DIR/loop_test.rs:12:5: 12:6 return; // scope 0 at $DIR/loop_test.rs:17:2: 17:2 diff --git a/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir b/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir index dbf1f1ead2c..c0249d134f2 100644 --- a/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir +++ b/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir @@ -65,10 +65,7 @@ fn full_tested_match() -> () { _6 = &(((*_11) as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:16:14: 16:15 _4 = &shallow _2; // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27 StorageLive(_7); // scope 0 at $DIR/match_false_edges.rs:16:20: 16:27 - _7 = const guard() -> [return: bb7, unwind: bb1]; // scope 0 at $DIR/match_false_edges.rs:16:20: 16:27 - // ty::Const - // + ty: fn() -> bool {guard} - // + val: Value(Scalar()) + _7 = guard() -> [return: bb7, unwind: bb1]; // scope 0 at $DIR/match_false_edges.rs:16:20: 16:27 // mir::Constant // + span: $DIR/match_false_edges.rs:16:20: 16:25 // + literal: Const { ty: fn() -> bool {guard}, val: Value(Scalar()) } @@ -114,12 +111,6 @@ fn full_tested_match() -> () { StorageDead(_2); // scope 0 at $DIR/match_false_edges.rs:19:6: 19:7 StorageDead(_1); // scope 0 at $DIR/match_false_edges.rs:19:6: 19:7 _0 = const (); // scope 0 at $DIR/match_false_edges.rs:14:28: 20:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/match_false_edges.rs:14:28: 20:2 - // + literal: Const { ty: (), val: Value(Scalar()) } return; // scope 0 at $DIR/match_false_edges.rs:20:2: 20:2 } } diff --git a/src/test/mir-opt/match_false_edges.full_tested_match2.PromoteTemps.before.mir b/src/test/mir-opt/match_false_edges.full_tested_match2.PromoteTemps.before.mir index c2805968029..a2ad5be265d 100644 --- a/src/test/mir-opt/match_false_edges.full_tested_match2.PromoteTemps.before.mir +++ b/src/test/mir-opt/match_false_edges.full_tested_match2.PromoteTemps.before.mir @@ -63,10 +63,7 @@ fn full_tested_match2() -> () { _6 = &((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:27:14: 27:15 _4 = &shallow _2; // scope 0 at $DIR/match_false_edges.rs:26:19: 26:27 StorageLive(_7); // scope 0 at $DIR/match_false_edges.rs:27:20: 27:27 - _7 = const guard() -> [return: bb7, unwind: bb1]; // scope 0 at $DIR/match_false_edges.rs:27:20: 27:27 - // ty::Const - // + ty: fn() -> bool {guard} - // + val: Value(Scalar()) + _7 = guard() -> [return: bb7, unwind: bb1]; // scope 0 at $DIR/match_false_edges.rs:27:20: 27:27 // mir::Constant // + span: $DIR/match_false_edges.rs:27:20: 27:25 // + literal: Const { ty: fn() -> bool {guard}, val: Value(Scalar()) } @@ -106,12 +103,6 @@ fn full_tested_match2() -> () { StorageDead(_2); // scope 0 at $DIR/match_false_edges.rs:30:6: 30:7 StorageDead(_1); // scope 0 at $DIR/match_false_edges.rs:30:6: 30:7 _0 = const (); // scope 0 at $DIR/match_false_edges.rs:25:29: 31:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/match_false_edges.rs:25:29: 31:2 - // + literal: Const { ty: (), val: Value(Scalar()) } return; // scope 0 at $DIR/match_false_edges.rs:31:2: 31:2 } } diff --git a/src/test/mir-opt/match_false_edges.main.PromoteTemps.before.mir b/src/test/mir-opt/match_false_edges.main.PromoteTemps.before.mir index 66cac95b7e8..b7322e7da0f 100644 --- a/src/test/mir-opt/match_false_edges.main.PromoteTemps.before.mir +++ b/src/test/mir-opt/match_false_edges.main.PromoteTemps.before.mir @@ -71,10 +71,7 @@ fn main() -> () { _7 = &((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:36:14: 36:16 _5 = &shallow _2; // scope 0 at $DIR/match_false_edges.rs:35:19: 35:26 StorageLive(_8); // scope 0 at $DIR/match_false_edges.rs:36:21: 36:28 - _8 = const guard() -> [return: bb7, unwind: bb1]; // scope 0 at $DIR/match_false_edges.rs:36:21: 36:28 - // ty::Const - // + ty: fn() -> bool {guard} - // + val: Value(Scalar()) + _8 = guard() -> [return: bb7, unwind: bb1]; // scope 0 at $DIR/match_false_edges.rs:36:21: 36:28 // mir::Constant // + span: $DIR/match_false_edges.rs:36:21: 36:26 // + literal: Const { ty: fn() -> bool {guard}, val: Value(Scalar()) } @@ -117,10 +114,7 @@ fn main() -> () { StorageLive(_12); // scope 0 at $DIR/match_false_edges.rs:38:20: 38:29 StorageLive(_13); // scope 0 at $DIR/match_false_edges.rs:38:27: 38:28 _13 = (*_11); // scope 0 at $DIR/match_false_edges.rs:38:27: 38:28 - _12 = const guard2(move _13) -> [return: bb12, unwind: bb1]; // scope 0 at $DIR/match_false_edges.rs:38:20: 38:29 - // ty::Const - // + ty: fn(i32) -> bool {guard2} - // + val: Value(Scalar()) + _12 = guard2(move _13) -> [return: bb12, unwind: bb1]; // scope 0 at $DIR/match_false_edges.rs:38:20: 38:29 // mir::Constant // + span: $DIR/match_false_edges.rs:38:20: 38:26 // + literal: Const { ty: fn(i32) -> bool {guard2}, val: Value(Scalar()) } @@ -153,12 +147,6 @@ fn main() -> () { StorageDead(_2); // scope 0 at $DIR/match_false_edges.rs:40:6: 40:7 StorageDead(_1); // scope 0 at $DIR/match_false_edges.rs:40:6: 40:7 _0 = const (); // scope 0 at $DIR/match_false_edges.rs:34:11: 41:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/match_false_edges.rs:34:11: 41:2 - // + literal: Const { ty: (), val: Value(Scalar()) } return; // scope 0 at $DIR/match_false_edges.rs:41:2: 41:2 } } diff --git a/src/test/mir-opt/match_test.main.SimplifyCfg-initial.after.mir b/src/test/mir-opt/match_test.main.SimplifyCfg-initial.after.mir index c72e6542470..e3bc4f80f27 100644 --- a/src/test/mir-opt/match_test.main.SimplifyCfg-initial.after.mir +++ b/src/test/mir-opt/match_test.main.SimplifyCfg-initial.after.mir @@ -99,12 +99,6 @@ fn main() -> () { bb14: { StorageDead(_3); // scope 2 at $DIR/match_test.rs:17:6: 17:7 _0 = const (); // scope 0 at $DIR/match_test.rs:6:11: 18:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/match_test.rs:6:11: 18:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_2); // scope 1 at $DIR/match_test.rs:18:1: 18:2 StorageDead(_1); // scope 0 at $DIR/match_test.rs:18:1: 18:2 return; // scope 0 at $DIR/match_test.rs:18:2: 18:2 diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.32bit b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.32bit index cff899bcb56..883a4e1470b 100644 --- a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.32bit +++ b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.32bit @@ -31,12 +31,6 @@ bb4: { _0 = const (); // scope 0 at $DIR/matches_reduce_branches.rs:6:5: 8:6 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/matches_reduce_branches.rs:6:5: 8:6 - // + literal: Const { ty: (), val: Value(Scalar()) } goto -> bb5; // scope 0 at $DIR/matches_reduce_branches.rs:6:5: 8:6 } diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.64bit b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.64bit index cff899bcb56..883a4e1470b 100644 --- a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.64bit +++ b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.64bit @@ -31,12 +31,6 @@ bb4: { _0 = const (); // scope 0 at $DIR/matches_reduce_branches.rs:6:5: 8:6 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/matches_reduce_branches.rs:6:5: 8:6 - // + literal: Const { ty: (), val: Value(Scalar()) } goto -> bb5; // scope 0 at $DIR/matches_reduce_branches.rs:6:5: 8:6 } diff --git a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.mir.32bit b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.mir.32bit index 3a8426a41a3..2885dd8eb78 100644 --- a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.mir.32bit +++ b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.mir.32bit @@ -77,10 +77,7 @@ fn main() -> () { bb4: { StorageLive(_10); // bb4[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18 - _10 = const Const(Value(Scalar()): fn(usize) -> bool {use_x})(const Const(Value(Scalar(0x00000016)): usize)) -> [return: bb7, unwind: bb1]; // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18 - // ty::Const - // + ty: fn(usize) -> bool {use_x} - // + val: Value(Scalar()) + _10 = Const(Value(Scalar()): fn(usize) -> bool {use_x})(const Const(Value(Scalar(0x00000016)): usize)) -> [return: bb7, unwind: bb1]; // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18 // mir::Constant // + span: $DIR/region-subtyping-basic.rs:23:9: 23:14 // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(Scalar()) } @@ -90,10 +87,7 @@ fn main() -> () { StorageLive(_8); // bb5[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18 StorageLive(_9); // bb5[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17 _9 = (*_6); // bb5[2]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17 - _8 = const Const(Value(Scalar()): fn(usize) -> bool {use_x})(move _9) -> [return: bb6, unwind: bb1]; // bb5[3]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18 - // ty::Const - // + ty: fn(usize) -> bool {use_x} - // + val: Value(Scalar()) + _8 = Const(Value(Scalar()): fn(usize) -> bool {use_x})(move _9) -> [return: bb6, unwind: bb1]; // bb5[3]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18 // mir::Constant // + span: $DIR/region-subtyping-basic.rs:21:9: 21:14 // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(Scalar()) } @@ -103,24 +97,12 @@ fn main() -> () { StorageDead(_9); // bb6[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:17: 21:18 StorageDead(_8); // bb6[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:18: 21:19 _0 = const Const(Value(Scalar()): ()); // bb6[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:13: 22:6 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/region-subtyping-basic.rs:20:13: 22:6 - // + literal: Const { ty: (), val: Value(Scalar()) } goto -> bb8; // bb6[3]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6 } bb7: { StorageDead(_10); // bb7[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:18: 23:19 _0 = const Const(Value(Scalar()): ()); // bb7[1]: scope 3 at $DIR/region-subtyping-basic.rs:22:12: 24:6 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/region-subtyping-basic.rs:22:12: 24:6 - // + literal: Const { ty: (), val: Value(Scalar()) } goto -> bb8; // bb7[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6 } diff --git a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.mir.64bit b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.mir.64bit index 5220ab4cae8..3820f70d515 100644 --- a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.mir.64bit +++ b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.mir.64bit @@ -77,10 +77,7 @@ fn main() -> () { bb4: { StorageLive(_10); // bb4[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18 - _10 = const Const(Value(Scalar()): fn(usize) -> bool {use_x})(const Const(Value(Scalar(0x0000000000000016)): usize)) -> [return: bb7, unwind: bb1]; // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18 - // ty::Const - // + ty: fn(usize) -> bool {use_x} - // + val: Value(Scalar()) + _10 = Const(Value(Scalar()): fn(usize) -> bool {use_x})(const Const(Value(Scalar(0x0000000000000016)): usize)) -> [return: bb7, unwind: bb1]; // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18 // mir::Constant // + span: $DIR/region-subtyping-basic.rs:23:9: 23:14 // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(Scalar()) } @@ -90,10 +87,7 @@ fn main() -> () { StorageLive(_8); // bb5[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18 StorageLive(_9); // bb5[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17 _9 = (*_6); // bb5[2]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17 - _8 = const Const(Value(Scalar()): fn(usize) -> bool {use_x})(move _9) -> [return: bb6, unwind: bb1]; // bb5[3]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18 - // ty::Const - // + ty: fn(usize) -> bool {use_x} - // + val: Value(Scalar()) + _8 = Const(Value(Scalar()): fn(usize) -> bool {use_x})(move _9) -> [return: bb6, unwind: bb1]; // bb5[3]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18 // mir::Constant // + span: $DIR/region-subtyping-basic.rs:21:9: 21:14 // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(Scalar()) } @@ -103,24 +97,12 @@ fn main() -> () { StorageDead(_9); // bb6[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:17: 21:18 StorageDead(_8); // bb6[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:18: 21:19 _0 = const Const(Value(Scalar()): ()); // bb6[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:13: 22:6 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/region-subtyping-basic.rs:20:13: 22:6 - // + literal: Const { ty: (), val: Value(Scalar()) } goto -> bb8; // bb6[3]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6 } bb7: { StorageDead(_10); // bb7[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:18: 23:19 _0 = const Const(Value(Scalar()): ()); // bb7[1]: scope 3 at $DIR/region-subtyping-basic.rs:22:12: 24:6 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/region-subtyping-basic.rs:22:12: 24:6 - // + literal: Const { ty: (), val: Value(Scalar()) } goto -> bb8; // bb7[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6 } diff --git a/src/test/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-elaborate-drops.after.mir index f59390ba84e..e90364c1ccf 100644 --- a/src/test/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-elaborate-drops.after.mir @@ -20,10 +20,7 @@ fn unwrap(_1: std::option::Option) -> T { bb1: { StorageLive(_4); // scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - const std::rt::begin_panic::<&str>(const "explicit panic") -> bb4; // scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - // ty::Const - // + ty: fn(&str) -> ! {std::rt::begin_panic::<&str>} - // + val: Value(Scalar()) + std::rt::begin_panic::<&str>(const "explicit panic") -> bb4; // scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL // mir::Constant // + span: $SRC_DIR/std/src/macros.rs:LL:COL // + literal: Const { ty: fn(&str) -> ! {std::rt::begin_panic::<&str>}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir b/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir index 0af213e425f..5e1866fbc53 100644 --- a/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir +++ b/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir @@ -20,10 +20,7 @@ fn main() -> () { // + span: $DIR/no-spurious-drop-after-call.rs:9:20: 9:22 // + literal: Const { ty: &str, val: Value(Slice { data: Allocation { bytes: [], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [], len: Size { raw: 0 } }, size: Size { raw: 0 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 0 }) } _3 = &(*_4); // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:22 - _2 = const ::to_string(move _3) -> bb2; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:34 - // ty::Const - // + ty: for<'r> fn(&'r str) -> std::string::String {::to_string} - // + val: Value(Scalar()) + _2 = ::to_string(move _3) -> bb2; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:34 // mir::Constant // + span: $DIR/no-spurious-drop-after-call.rs:9:23: 9:32 // + literal: Const { ty: for<'r> fn(&'r str) -> std::string::String {::to_string}, val: Value(Scalar()) } @@ -35,10 +32,7 @@ fn main() -> () { bb2: { StorageDead(_3); // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:33: 9:34 - _1 = const std::mem::drop::(move _2) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:5: 9:35 - // ty::Const - // + ty: fn(std::string::String) {std::mem::drop::} - // + val: Value(Scalar()) + _1 = std::mem::drop::(move _2) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:5: 9:35 // mir::Constant // + span: $DIR/no-spurious-drop-after-call.rs:9:5: 9:19 // + literal: Const { ty: fn(std::string::String) {std::mem::drop::}, val: Value(Scalar()) } @@ -49,12 +43,6 @@ fn main() -> () { StorageDead(_4); // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:35: 9:36 StorageDead(_1); // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:35: 9:36 _0 = const (); // scope 0 at $DIR/no-spurious-drop-after-call.rs:8:11: 10:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/no-spurious-drop-after-call.rs:8:11: 10:2 - // + literal: Const { ty: (), val: Value(Scalar()) } return; // scope 0 at $DIR/no-spurious-drop-after-call.rs:10:2: 10:2 } diff --git a/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir.32bit b/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir.32bit index a0214e5b9c5..4641344f01a 100644 --- a/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir.32bit +++ b/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir.32bit @@ -50,12 +50,6 @@ fn main() -> () { (_1.0: Aligned) = move _4; // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:5: 7:8 StorageDead(_4); // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:28: 7:29 _0 = const (); // scope 0 at $DIR/packed-struct-drop-aligned.rs:5:11: 8:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/packed-struct-drop-aligned.rs:5:11: 8:2 - // + literal: Const { ty: (), val: Value(Scalar()) } drop(_1) -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/packed-struct-drop-aligned.rs:8:1: 8:2 } } diff --git a/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir.64bit b/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir.64bit index a0214e5b9c5..4641344f01a 100644 --- a/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir.64bit +++ b/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir.64bit @@ -50,12 +50,6 @@ fn main() -> () { (_1.0: Aligned) = move _4; // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:5: 7:8 StorageDead(_4); // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:28: 7:29 _0 = const (); // scope 0 at $DIR/packed-struct-drop-aligned.rs:5:11: 8:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/packed-struct-drop-aligned.rs:5:11: 8:2 - // + literal: Const { ty: (), val: Value(Scalar()) } drop(_1) -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/packed-struct-drop-aligned.rs:8:1: 8:2 } } diff --git a/src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir b/src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir index 694c387986f..b10ca218314 100644 --- a/src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir +++ b/src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir @@ -8,10 +8,7 @@ fn std::intrinsics::drop_in_place(_1: *mut Test) -> () { bb0: { Retag([raw] _1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL _2 = &mut (*_1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - _3 = const ::drop(move _2) -> bb1; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - // ty::Const - // + ty: for<'r> fn(&'r mut Test) {::drop} - // + val: Value(Scalar()) + _3 = ::drop(move _2) -> bb1; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/ptr/mod.rs:LL:COL // + literal: Const { ty: for<'r> fn(&'r mut Test) {::drop}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir index 5521ead29db..5a79466ede5 100644 --- a/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir @@ -70,10 +70,7 @@ fn main() -> () { Retag(_7); // scope 1 at $DIR/retag.rs:32:29: 32:35 _6 = &mut (*_7); // scope 1 at $DIR/retag.rs:32:29: 32:35 Retag([2phase] _6); // scope 1 at $DIR/retag.rs:32:29: 32:35 - _3 = const Test::foo(move _4, move _6) -> [return: bb2, unwind: bb3]; // scope 1 at $DIR/retag.rs:32:17: 32:36 - // ty::Const - // + ty: for<'r, 'x> fn(&'r Test, &'x mut i32) -> &'x mut i32 {Test::foo} - // + val: Value(Scalar()) + _3 = Test::foo(move _4, move _6) -> [return: bb2, unwind: bb3]; // scope 1 at $DIR/retag.rs:32:17: 32:36 // mir::Constant // + span: $DIR/retag.rs:32:25: 32:28 // + literal: Const { ty: for<'r, 'x> fn(&'r Test, &'x mut i32) -> &'x mut i32 {Test::foo}, val: Value(Scalar()) } @@ -114,12 +111,6 @@ fn main() -> () { _11 = _12; // scope 4 at $DIR/retag.rs:36:18: 36:29 StorageDead(_12); // scope 4 at $DIR/retag.rs:36:29: 36:30 _2 = const (); // scope 1 at $DIR/retag.rs:31:5: 37:6 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/retag.rs:31:5: 37:6 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_11); // scope 4 at $DIR/retag.rs:37:5: 37:6 StorageDead(_10); // scope 3 at $DIR/retag.rs:37:5: 37:6 StorageDead(_8); // scope 2 at $DIR/retag.rs:37:5: 37:6 @@ -175,10 +166,7 @@ fn main() -> () { Retag(_23); // scope 7 at $DIR/retag.rs:47:21: 47:23 _22 = &(*_23); // scope 7 at $DIR/retag.rs:47:21: 47:23 Retag(_22); // scope 7 at $DIR/retag.rs:47:21: 47:23 - _19 = const Test::foo_shr(move _20, move _22) -> [return: bb6, unwind: bb7]; // scope 7 at $DIR/retag.rs:47:5: 47:24 - // ty::Const - // + ty: for<'r, 'x> fn(&'r Test, &'x i32) -> &'x i32 {Test::foo_shr} - // + val: Value(Scalar()) + _19 = Test::foo_shr(move _20, move _22) -> [return: bb6, unwind: bb7]; // scope 7 at $DIR/retag.rs:47:5: 47:24 // mir::Constant // + span: $DIR/retag.rs:47:13: 47:20 // + literal: Const { ty: for<'r, 'x> fn(&'r Test, &'x i32) -> &'x i32 {Test::foo_shr}, val: Value(Scalar()) } @@ -206,12 +194,6 @@ fn main() -> () { _25 = _26; // scope 7 at $DIR/retag.rs:50:14: 50:28 StorageDead(_26); // scope 7 at $DIR/retag.rs:50:28: 50:29 _0 = const (); // scope 0 at $DIR/retag.rs:29:11: 51:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/retag.rs:29:11: 51:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_25); // scope 7 at $DIR/retag.rs:51:1: 51:2 StorageDead(_15); // scope 6 at $DIR/retag.rs:51:1: 51:2 StorageDead(_13); // scope 1 at $DIR/retag.rs:51:1: 51:2 diff --git a/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.diff.32bit b/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.diff.32bit index db42c5ad8ba..adcda7fcde0 100644 --- a/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.diff.32bit +++ b/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.diff.32bit @@ -51,12 +51,6 @@ bb4: { StorageDead(_2); // scope 1 at $DIR/simplify-arm-identity.rs:22:6: 22:7 _0 = const (); // scope 0 at $DIR/simplify-arm-identity.rs:17:11: 23:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/simplify-arm-identity.rs:17:11: 23:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_1); // scope 0 at $DIR/simplify-arm-identity.rs:23:1: 23:2 return; // scope 0 at $DIR/simplify-arm-identity.rs:23:2: 23:2 } diff --git a/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.diff.64bit b/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.diff.64bit index db42c5ad8ba..adcda7fcde0 100644 --- a/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.diff.64bit +++ b/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.diff.64bit @@ -51,12 +51,6 @@ bb4: { StorageDead(_2); // scope 1 at $DIR/simplify-arm-identity.rs:22:6: 22:7 _0 = const (); // scope 0 at $DIR/simplify-arm-identity.rs:17:11: 23:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/simplify-arm-identity.rs:17:11: 23:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_1); // scope 0 at $DIR/simplify-arm-identity.rs:23:1: 23:2 return; // scope 0 at $DIR/simplify-arm-identity.rs:23:2: 23:2 } diff --git a/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-early-opt.diff b/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-early-opt.diff index 3b472ed3a03..ede081f85de 100644 --- a/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-early-opt.diff +++ b/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-early-opt.diff @@ -13,11 +13,8 @@ - - bb1: { StorageLive(_2); // scope 0 at $DIR/simplify_cfg.rs:7:12: 7:17 -- _2 = const bar() -> bb3; // scope 0 at $DIR/simplify_cfg.rs:7:12: 7:17 -+ _2 = const bar() -> bb1; // scope 0 at $DIR/simplify_cfg.rs:7:12: 7:17 - // ty::Const - // + ty: fn() -> bool {bar} - // + val: Value(Scalar()) +- _2 = bar() -> bb3; // scope 0 at $DIR/simplify_cfg.rs:7:12: 7:17 ++ _2 = bar() -> bb1; // scope 0 at $DIR/simplify_cfg.rs:7:12: 7:17 // mir::Constant // + span: $DIR/simplify_cfg.rs:7:12: 7:15 // + literal: Const { ty: fn() -> bool {bar}, val: Value(Scalar()) } @@ -41,12 +38,6 @@ - bb5: { + bb2: { _1 = const (); // scope 0 at $DIR/simplify_cfg.rs:7:9: 9:10 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/simplify_cfg.rs:7:9: 9:10 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_2); // scope 0 at $DIR/simplify_cfg.rs:10:5: 10:6 goto -> bb0; // scope 0 at $DIR/simplify_cfg.rs:6:5: 10:6 } @@ -54,12 +45,6 @@ - bb6: { + bb3: { _0 = const (); // scope 0 at $DIR/simplify_cfg.rs:8:13: 8:18 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/simplify_cfg.rs:8:13: 8:18 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_2); // scope 0 at $DIR/simplify_cfg.rs:10:5: 10:6 return; // scope 0 at $DIR/simplify_cfg.rs:11:2: 11:2 } diff --git a/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff b/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff index 1ba05b1cb38..e8cdd390ff8 100644 --- a/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff +++ b/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff @@ -22,11 +22,8 @@ - - bb3: { StorageLive(_2); // scope 0 at $DIR/simplify_cfg.rs:7:12: 7:17 -- _2 = const bar() -> [return: bb5, unwind: bb4]; // scope 0 at $DIR/simplify_cfg.rs:7:12: 7:17 -+ _2 = const bar() -> [return: bb3, unwind: bb2]; // scope 0 at $DIR/simplify_cfg.rs:7:12: 7:17 - // ty::Const - // + ty: fn() -> bool {bar} - // + val: Value(Scalar()) +- _2 = bar() -> [return: bb5, unwind: bb4]; // scope 0 at $DIR/simplify_cfg.rs:7:12: 7:17 ++ _2 = bar() -> [return: bb3, unwind: bb2]; // scope 0 at $DIR/simplify_cfg.rs:7:12: 7:17 // mir::Constant // + span: $DIR/simplify_cfg.rs:7:12: 7:15 // + literal: Const { ty: fn() -> bool {bar}, val: Value(Scalar()) } @@ -53,12 +50,6 @@ - bb7: { + bb5: { _1 = const (); // scope 0 at $DIR/simplify_cfg.rs:7:9: 9:10 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/simplify_cfg.rs:7:9: 9:10 - // + literal: Const { ty: (), val: Value(Scalar()) } - goto -> bb12; // scope 0 at $DIR/simplify_cfg.rs:7:9: 9:10 + StorageDead(_2); // scope 0 at $DIR/simplify_cfg.rs:10:5: 10:6 + goto -> bb0; // scope 0 at $DIR/simplify_cfg.rs:6:5: 10:6 @@ -67,12 +58,6 @@ - bb8: { + bb6: { _0 = const (); // scope 0 at $DIR/simplify_cfg.rs:8:13: 8:18 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/simplify_cfg.rs:8:13: 8:18 - // + literal: Const { ty: (), val: Value(Scalar()) } - goto -> bb9; // scope 0 at $DIR/simplify_cfg.rs:8:13: 8:18 - } - diff --git a/src/test/mir-opt/simplify_if.main.SimplifyBranches-after-const-prop.diff b/src/test/mir-opt/simplify_if.main.SimplifyBranches-after-const-prop.diff index 44bf4400e15..aeb319a4904 100644 --- a/src/test/mir-opt/simplify_if.main.SimplifyBranches-after-const-prop.diff +++ b/src/test/mir-opt/simplify_if.main.SimplifyBranches-after-const-prop.diff @@ -15,21 +15,12 @@ bb1: { _0 = const (); // scope 0 at $DIR/simplify_if.rs:6:5: 8:6 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/simplify_if.rs:6:5: 8:6 - // + literal: Const { ty: (), val: Value(Scalar()) } goto -> bb4; // scope 0 at $DIR/simplify_if.rs:6:5: 8:6 } bb2: { StorageLive(_2); // scope 0 at $DIR/simplify_if.rs:7:9: 7:15 - _2 = const noop() -> bb3; // scope 0 at $DIR/simplify_if.rs:7:9: 7:15 - // ty::Const - // + ty: fn() {noop} - // + val: Value(Scalar()) + _2 = noop() -> bb3; // scope 0 at $DIR/simplify_if.rs:7:9: 7:15 // mir::Constant // + span: $DIR/simplify_if.rs:7:9: 7:13 // + literal: Const { ty: fn() {noop}, val: Value(Scalar()) } @@ -38,12 +29,6 @@ bb3: { StorageDead(_2); // scope 0 at $DIR/simplify_if.rs:7:15: 7:16 _0 = const (); // scope 0 at $DIR/simplify_if.rs:6:14: 8:6 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/simplify_if.rs:6:14: 8:6 - // + literal: Const { ty: (), val: Value(Scalar()) } goto -> bb4; // scope 0 at $DIR/simplify_if.rs:6:5: 8:6 } diff --git a/src/test/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals.diff index 8a3fd7d9709..45808962bb5 100644 --- a/src/test/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals.diff +++ b/src/test/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals.diff @@ -31,12 +31,6 @@ bb1: { _0 = const (); // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:5: 8:6 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/simplify-locals-fixedpoint.rs:4:5: 8:6 - // + literal: Const { ty: (), val: Value(Scalar()) } goto -> bb7; // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:5: 8:6 } @@ -58,23 +52,11 @@ bb4: { _0 = const (); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:9: 7:10 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/simplify-locals-fixedpoint.rs:5:9: 7:10 - // + literal: Const { ty: (), val: Value(Scalar()) } goto -> bb6; // scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:9: 7:10 } bb5: { _0 = const (); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:21: 7:10 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/simplify-locals-fixedpoint.rs:5:21: 7:10 - // + literal: Const { ty: (), val: Value(Scalar()) } goto -> bb6; // scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:9: 7:10 } diff --git a/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff index 99b38f3c57a..3064e92f900 100644 --- a/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff +++ b/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff @@ -24,21 +24,7 @@ - StorageLive(_2); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:13:21: 13:23 - StorageLive(_3); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:13:25: 13:27 - (_1.0: ()) = const (); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:13:20: 13:28 -+ StorageLive(_1); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22 -+ _1 = const use_zst(const ((), ())) -> bb1; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22 - // ty::Const -- // + ty: () -- // + val: Value(Scalar()) -- // mir::Constant -- // + span: $DIR/simplify-locals-removes-unused-consts.rs:13:20: 13:28 -- // + literal: Const { ty: (), val: Value(Scalar()) } - (_1.1: ()) = const (); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:13:20: 13:28 -- // ty::Const -- // + ty: () -- // + val: Value(Scalar()) -- // mir::Constant -- // + span: $DIR/simplify-locals-removes-unused-consts.rs:13:20: 13:28 -- // + literal: Const { ty: (), val: Value(Scalar()) } - StorageDead(_3); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:13:27: 13:28 - StorageDead(_2); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:13:27: 13:28 - StorageDead(_1); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:13:28: 13:29 @@ -47,25 +33,12 @@ - StorageLive(_6); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:14: 14:16 - StorageLive(_7); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:18: 14:20 - (_5.0: ()) = const (); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:13: 14:21 -- // ty::Const -- // + ty: () -- // + val: Value(Scalar()) -- // mir::Constant -- // + span: $DIR/simplify-locals-removes-unused-consts.rs:14:13: 14:21 -- // + literal: Const { ty: (), val: Value(Scalar()) } - (_5.1: ()) = const (); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:13: 14:21 -- // ty::Const -- // + ty: () -- // + val: Value(Scalar()) -- // mir::Constant -- // + span: $DIR/simplify-locals-removes-unused-consts.rs:14:13: 14:21 -- // + literal: Const { ty: (), val: Value(Scalar()) } - StorageDead(_7); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:20: 14:21 - StorageDead(_6); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:20: 14:21 -- _4 = const use_zst(const ((), ())) -> bb1; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22 -- // ty::Const - // + ty: fn(((), ())) {use_zst} - // + val: Value(Scalar()) +- _4 = use_zst(const ((), ())) -> bb1; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22 ++ StorageLive(_1); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22 ++ _1 = use_zst(const ((), ())) -> bb1; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22 // mir::Constant // + span: $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:12 // + literal: Const { ty: fn(((), ())) {use_zst}, val: Value(Scalar()) } @@ -88,13 +61,10 @@ - _10 = const 40_u8; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:30 - _9 = const 42_u8; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:34 - StorageDead(_10); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:33: 16:34 -- _8 = const use_u8(const 42_u8) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35 +- _8 = use_u8(const 42_u8) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35 + StorageDead(_1); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:22: 14:23 + StorageLive(_2); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35 -+ _2 = const use_u8(const 42_u8) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35 - // ty::Const - // + ty: fn(u8) {use_u8} - // + val: Value(Scalar()) ++ _2 = use_u8(const 42_u8) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35 // mir::Constant // + span: $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:11 // + literal: Const { ty: fn(u8) {use_u8}, val: Value(Scalar()) } @@ -106,12 +76,6 @@ - StorageDead(_8); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:35: 16:36 + StorageDead(_2); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:35: 16:36 _0 = const (); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:12:11: 17:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/simplify-locals-removes-unused-consts.rs:12:11: 17:2 - // + literal: Const { ty: (), val: Value(Scalar()) } return; // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:17:2: 17:2 } } diff --git a/src/test/mir-opt/simplify_match.main.ConstProp.diff b/src/test/mir-opt/simplify_match.main.ConstProp.diff index aba5fafa3a4..0fdc364514b 100644 --- a/src/test/mir-opt/simplify_match.main.ConstProp.diff +++ b/src/test/mir-opt/simplify_match.main.ConstProp.diff @@ -22,20 +22,11 @@ bb1: { _0 = const (); // scope 0 at $DIR/simplify_match.rs:8:18: 8:20 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/simplify_match.rs:8:18: 8:20 - // + literal: Const { ty: (), val: Value(Scalar()) } goto -> bb3; // scope 0 at $DIR/simplify_match.rs:6:5: 9:6 } bb2: { - _0 = const noop() -> bb3; // scope 0 at $DIR/simplify_match.rs:7:17: 7:23 - // ty::Const - // + ty: fn() {noop} - // + val: Value(Scalar()) + _0 = noop() -> bb3; // scope 0 at $DIR/simplify_match.rs:7:17: 7:23 // mir::Constant // + span: $DIR/simplify_match.rs:7:17: 7:21 // + literal: Const { ty: fn() {noop}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/simplify_try_if_let.{{impl}}-append.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_try_if_let.{{impl}}-append.SimplifyArmIdentity.diff index 4471f4d206c..51a1e6ba4c3 100644 --- a/src/test/mir-opt/simplify_try_if_let.{{impl}}-append.SimplifyArmIdentity.diff +++ b/src/test/mir-opt/simplify_try_if_let.{{impl}}-append.SimplifyArmIdentity.diff @@ -35,10 +35,7 @@ StorageLive(_5); // scope 1 at $DIR/simplify_try_if_let.rs:26:43: 26:60 StorageLive(_6); // scope 1 at $DIR/simplify_try_if_let.rs:26:43: 26:53 _6 = &mut ((*_2).0: std::option::Option>); // scope 1 at $DIR/simplify_try_if_let.rs:26:43: 26:53 - _5 = const std::option::Option::>::take(move _6) -> bb4; // scope 1 at $DIR/simplify_try_if_let.rs:26:43: 26:60 - // ty::Const - // + ty: for<'r> fn(&'r mut std::option::Option>) -> std::option::Option> {std::option::Option::>::take} - // + val: Value(Scalar()) + _5 = std::option::Option::>::take(move _6) -> bb4; // scope 1 at $DIR/simplify_try_if_let.rs:26:43: 26:60 // mir::Constant // + span: $DIR/simplify_try_if_let.rs:26:54: 26:58 // + literal: Const { ty: for<'r> fn(&'r mut std::option::Option>) -> std::option::Option> {std::option::Option::>::take}, val: Value(Scalar()) } @@ -50,12 +47,6 @@ bb3: { _0 = const (); // scope 0 at $DIR/simplify_try_if_let.rs:22:21: 22:24 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/simplify_try_if_let.rs:22:21: 22:24 - // + literal: Const { ty: (), val: Value(Scalar()) } goto -> bb9; // scope 0 at $DIR/simplify_try_if_let.rs:21:9: 32:10 } @@ -67,12 +58,6 @@ bb5: { _0 = const (); // scope 1 at $DIR/simplify_try_if_let.rs:26:17: 30:18 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/simplify_try_if_let.rs:26:17: 30:18 - // + literal: Const { ty: (), val: Value(Scalar()) } goto -> bb8; // scope 1 at $DIR/simplify_try_if_let.rs:26:17: 30:18 } @@ -88,10 +73,7 @@ StorageLive(_11); // scope 3 at $DIR/simplify_try_if_let.rs:28:25: 28:38 StorageLive(_12); // scope 3 at $DIR/simplify_try_if_let.rs:28:25: 28:29 _12 = &mut _4; // scope 3 at $DIR/simplify_try_if_let.rs:28:25: 28:29 - _11 = const std::ptr::NonNull::::as_mut(move _12) -> bb7; // scope 3 at $DIR/simplify_try_if_let.rs:28:25: 28:38 - // ty::Const - // + ty: for<'r> unsafe fn(&'r mut std::ptr::NonNull) -> &'r mut Node {std::ptr::NonNull::::as_mut} - // + val: Value(Scalar()) + _11 = std::ptr::NonNull::::as_mut(move _12) -> bb7; // scope 3 at $DIR/simplify_try_if_let.rs:28:25: 28:38 // mir::Constant // + span: $DIR/simplify_try_if_let.rs:28:30: 28:36 // + literal: Const { ty: for<'r> unsafe fn(&'r mut std::ptr::NonNull) -> &'r mut Node {std::ptr::NonNull::::as_mut}, val: Value(Scalar()) } @@ -103,12 +85,6 @@ StorageDead(_9); // scope 3 at $DIR/simplify_try_if_let.rs:28:61: 28:62 StorageDead(_11); // scope 3 at $DIR/simplify_try_if_let.rs:28:62: 28:63 _0 = const (); // scope 3 at $DIR/simplify_try_if_let.rs:27:21: 29:22 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/simplify_try_if_let.rs:27:21: 29:22 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_8); // scope 1 at $DIR/simplify_try_if_let.rs:30:17: 30:18 goto -> bb8; // scope 1 at $DIR/simplify_try_if_let.rs:26:17: 30:18 } diff --git a/src/test/mir-opt/storage_ranges.main.nll.0.mir b/src/test/mir-opt/storage_ranges.main.nll.0.mir index d51afe3d903..707caf57c60 100644 --- a/src/test/mir-opt/storage_ranges.main.nll.0.mir +++ b/src/test/mir-opt/storage_ranges.main.nll.0.mir @@ -50,12 +50,6 @@ fn main() -> () { _3 = &_4; // scope 1 at $DIR/storage_ranges.rs:6:17: 6:25 FakeRead(ForLet, _3); // scope 1 at $DIR/storage_ranges.rs:6:13: 6:14 _2 = const (); // scope 1 at $DIR/storage_ranges.rs:5:5: 7:6 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/storage_ranges.rs:5:5: 7:6 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_4); // scope 1 at $DIR/storage_ranges.rs:7:5: 7:6 StorageDead(_3); // scope 1 at $DIR/storage_ranges.rs:7:5: 7:6 StorageDead(_2); // scope 1 at $DIR/storage_ranges.rs:7:5: 7:6 @@ -63,12 +57,6 @@ fn main() -> () { _6 = const 1_i32; // scope 1 at $DIR/storage_ranges.rs:8:13: 8:14 FakeRead(ForLet, _6); // scope 1 at $DIR/storage_ranges.rs:8:9: 8:10 _0 = const (); // scope 0 at $DIR/storage_ranges.rs:3:11: 9:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/storage_ranges.rs:3:11: 9:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_6); // scope 1 at $DIR/storage_ranges.rs:9:1: 9:2 StorageDead(_1); // scope 0 at $DIR/storage_ranges.rs:9:1: 9:2 return; // scope 0 at $DIR/storage_ranges.rs:9:2: 9:2 diff --git a/src/test/mir-opt/tls_access.main.SimplifyCfg-final.after.mir b/src/test/mir-opt/tls_access.main.SimplifyCfg-final.after.mir index 6591328423f..06161373be2 100644 --- a/src/test/mir-opt/tls_access.main.SimplifyCfg-final.after.mir +++ b/src/test/mir-opt/tls_access.main.SimplifyCfg-final.after.mir @@ -21,12 +21,6 @@ fn main() -> () { (*_3) = const 42_u8; // scope 2 at $DIR/tls-access.rs:9:9: 9:17 StorageDead(_3); // scope 2 at $DIR/tls-access.rs:9:17: 9:18 _0 = const (); // scope 1 at $DIR/tls-access.rs:7:5: 10:6 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/tls-access.rs:7:5: 10:6 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_2); // scope 1 at $DIR/tls-access.rs:10:5: 10:6 StorageDead(_1); // scope 1 at $DIR/tls-access.rs:10:5: 10:6 return; // scope 0 at $DIR/tls-access.rs:11:2: 11:2 diff --git a/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir b/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir index 41d4f75bd3a..dece3dc2325 100644 --- a/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir +++ b/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir @@ -72,12 +72,6 @@ fn move_out_by_subslice() -> () { StorageLive(_6); // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17 _6 = move _1[0..2]; // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17 _0 = const (); // scope 0 at $DIR/uniform_array_move_out.rs:10:27: 13:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/uniform_array_move_out.rs:10:27: 13:2 - // + literal: Const { ty: (), val: Value(Scalar()) } drop(_6) -> [return: bb12, unwind: bb10]; // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2 } diff --git a/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir b/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir index 1f29ea152b0..b182be51125 100644 --- a/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir +++ b/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir @@ -72,12 +72,6 @@ fn move_out_from_end() -> () { StorageLive(_6); // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16 _6 = move _1[1 of 2]; // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16 _0 = const (); // scope 0 at $DIR/uniform_array_move_out.rs:4:24: 7:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/uniform_array_move_out.rs:4:24: 7:2 - // + literal: Const { ty: (), val: Value(Scalar()) } drop(_6) -> [return: bb12, unwind: bb10]; // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2 } diff --git a/src/test/mir-opt/uninhabited_enum.process_void.SimplifyLocals.after.mir b/src/test/mir-opt/uninhabited_enum.process_void.SimplifyLocals.after.mir index 8cfcd64a70f..539ed710719 100644 --- a/src/test/mir-opt/uninhabited_enum.process_void.SimplifyLocals.after.mir +++ b/src/test/mir-opt/uninhabited_enum.process_void.SimplifyLocals.after.mir @@ -14,12 +14,6 @@ fn process_void(_1: *const Void) -> () { StorageLive(_2); // scope 0 at $DIR/uninhabited-enum.rs:14:8: 14:14 _2 = &(*_1); // scope 2 at $DIR/uninhabited-enum.rs:14:26: 14:33 _0 = const (); // scope 0 at $DIR/uninhabited-enum.rs:13:41: 17:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/uninhabited-enum.rs:13:41: 17:2 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_2); // scope 0 at $DIR/uninhabited-enum.rs:17:1: 17:2 return; // scope 0 at $DIR/uninhabited-enum.rs:17:2: 17:2 } diff --git a/src/test/mir-opt/uninhabited_enum_branching.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir b/src/test/mir-opt/uninhabited_enum_branching.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir index 24fd26591bd..0c6378cf92d 100644 --- a/src/test/mir-opt/uninhabited_enum_branching.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir +++ b/src/test/mir-opt/uninhabited_enum_branching.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir @@ -65,12 +65,6 @@ fn main() -> () { StorageDead(_7); // scope 0 at $DIR/uninhabited_enum_branching.rs:29:6: 29:7 StorageDead(_6); // scope 0 at $DIR/uninhabited_enum_branching.rs:29:6: 29:7 _0 = const (); // scope 0 at $DIR/uninhabited_enum_branching.rs:19:11: 30:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/uninhabited_enum_branching.rs:19:11: 30:2 - // + literal: Const { ty: (), val: Value(Scalar()) } return; // scope 0 at $DIR/uninhabited_enum_branching.rs:30:2: 30:2 } } diff --git a/src/test/mir-opt/uninhabited_enum_branching.main.UninhabitedEnumBranching.diff b/src/test/mir-opt/uninhabited_enum_branching.main.UninhabitedEnumBranching.diff index 7e0a95edf3e..d66f81b8098 100644 --- a/src/test/mir-opt/uninhabited_enum_branching.main.UninhabitedEnumBranching.diff +++ b/src/test/mir-opt/uninhabited_enum_branching.main.UninhabitedEnumBranching.diff @@ -100,12 +100,6 @@ StorageDead(_7); // scope 0 at $DIR/uninhabited_enum_branching.rs:29:6: 29:7 StorageDead(_6); // scope 0 at $DIR/uninhabited_enum_branching.rs:29:6: 29:7 _0 = const (); // scope 0 at $DIR/uninhabited_enum_branching.rs:19:11: 30:2 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/uninhabited_enum_branching.rs:19:11: 30:2 - // + literal: Const { ty: (), val: Value(Scalar()) } return; // scope 0 at $DIR/uninhabited_enum_branching.rs:30:2: 30:2 } } diff --git a/src/test/mir-opt/unreachable.main.UnreachablePropagation.diff b/src/test/mir-opt/unreachable.main.UnreachablePropagation.diff index 16c27fff7e6..37ff5c6ee3b 100644 --- a/src/test/mir-opt/unreachable.main.UnreachablePropagation.diff +++ b/src/test/mir-opt/unreachable.main.UnreachablePropagation.diff @@ -19,10 +19,7 @@ bb0: { StorageLive(_1); // scope 0 at $DIR/unreachable.rs:9:23: 9:30 - _1 = const empty() -> bb1; // scope 0 at $DIR/unreachable.rs:9:23: 9:30 - // ty::Const - // + ty: fn() -> std::option::Option {empty} - // + val: Value(Scalar()) + _1 = empty() -> bb1; // scope 0 at $DIR/unreachable.rs:9:23: 9:30 // mir::Constant // + span: $DIR/unreachable.rs:9:23: 9:28 // + literal: Const { ty: fn() -> std::option::Option {empty}, val: Value(Scalar()) } @@ -36,12 +33,6 @@ bb2: { _0 = const (); // scope 0 at $DIR/unreachable.rs:9:5: 19:6 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/unreachable.rs:9:5: 19:6 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_1); // scope 0 at $DIR/unreachable.rs:20:1: 20:2 return; // scope 0 at $DIR/unreachable.rs:20:2: 20:2 - } @@ -59,24 +50,12 @@ - bb4: { - _4 = const 42_i32; // scope 2 at $DIR/unreachable.rs:15:13: 15:20 - _5 = const (); // scope 2 at $DIR/unreachable.rs:14:16: 16:10 -- // ty::Const -- // + ty: () -- // + val: Value(Scalar()) -- // mir::Constant -- // + span: $DIR/unreachable.rs:14:16: 16:10 -- // + literal: Const { ty: (), val: Value(Scalar()) } - goto -> bb6; // scope 2 at $DIR/unreachable.rs:12:9: 16:10 - } - - bb5: { - _4 = const 21_i32; // scope 2 at $DIR/unreachable.rs:13:13: 13:20 - _5 = const (); // scope 2 at $DIR/unreachable.rs:12:17: 14:10 -- // ty::Const -- // + ty: () -- // + val: Value(Scalar()) -- // mir::Constant -- // + span: $DIR/unreachable.rs:12:17: 14:10 -- // + literal: Const { ty: (), val: Value(Scalar()) } - goto -> bb6; // scope 2 at $DIR/unreachable.rs:12:9: 16:10 - } - diff --git a/src/test/mir-opt/unreachable_asm.main.UnreachablePropagation.diff b/src/test/mir-opt/unreachable_asm.main.UnreachablePropagation.diff index bd5346f663f..5caacf84ca6 100644 --- a/src/test/mir-opt/unreachable_asm.main.UnreachablePropagation.diff +++ b/src/test/mir-opt/unreachable_asm.main.UnreachablePropagation.diff @@ -22,10 +22,7 @@ bb0: { StorageLive(_1); // scope 0 at $DIR/unreachable_asm.rs:11:23: 11:30 - _1 = const empty() -> bb1; // scope 0 at $DIR/unreachable_asm.rs:11:23: 11:30 - // ty::Const - // + ty: fn() -> std::option::Option {empty} - // + val: Value(Scalar()) + _1 = empty() -> bb1; // scope 0 at $DIR/unreachable_asm.rs:11:23: 11:30 // mir::Constant // + span: $DIR/unreachable_asm.rs:11:23: 11:28 // + literal: Const { ty: fn() -> std::option::Option {empty}, val: Value(Scalar()) } @@ -38,12 +35,6 @@ bb2: { _0 = const (); // scope 0 at $DIR/unreachable_asm.rs:11:5: 23:6 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/unreachable_asm.rs:11:5: 23:6 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_1); // scope 0 at $DIR/unreachable_asm.rs:24:1: 24:2 return; // scope 0 at $DIR/unreachable_asm.rs:24:2: 24:2 } @@ -61,24 +52,12 @@ bb4: { _4 = const 42_i32; // scope 2 at $DIR/unreachable_asm.rs:17:13: 17:20 _5 = const (); // scope 2 at $DIR/unreachable_asm.rs:16:16: 18:10 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/unreachable_asm.rs:16:16: 18:10 - // + literal: Const { ty: (), val: Value(Scalar()) } goto -> bb6; // scope 2 at $DIR/unreachable_asm.rs:14:9: 18:10 } bb5: { _4 = const 21_i32; // scope 2 at $DIR/unreachable_asm.rs:15:13: 15:20 _5 = const (); // scope 2 at $DIR/unreachable_asm.rs:14:17: 16:10 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/unreachable_asm.rs:14:17: 16:10 - // + literal: Const { ty: (), val: Value(Scalar()) } goto -> bb6; // scope 2 at $DIR/unreachable_asm.rs:14:9: 18:10 } @@ -88,12 +67,6 @@ StorageLive(_7); // scope 2 at $DIR/unreachable_asm.rs:21:9: 21:37 llvm_asm!(LlvmInlineAsmInner { asm: "NOP", asm_str_style: Cooked, outputs: [], inputs: [], clobbers: [], volatile: true, alignstack: false, dialect: Att } : [] : []); // scope 3 at $DIR/unreachable_asm.rs:21:18: 21:35 _7 = const (); // scope 3 at $DIR/unreachable_asm.rs:21:9: 21:37 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/unreachable_asm.rs:21:9: 21:37 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_7); // scope 2 at $DIR/unreachable_asm.rs:21:36: 21:37 StorageLive(_8); // scope 2 at $DIR/unreachable_asm.rs:22:9: 22:21 unreachable; // scope 2 at $DIR/unreachable_asm.rs:22:15: 22:17 diff --git a/src/test/mir-opt/unreachable_asm_2.main.UnreachablePropagation.diff b/src/test/mir-opt/unreachable_asm_2.main.UnreachablePropagation.diff index 41c60b9c957..07ed81b35f5 100644 --- a/src/test/mir-opt/unreachable_asm_2.main.UnreachablePropagation.diff +++ b/src/test/mir-opt/unreachable_asm_2.main.UnreachablePropagation.diff @@ -25,10 +25,7 @@ bb0: { StorageLive(_1); // scope 0 at $DIR/unreachable_asm_2.rs:11:23: 11:30 - _1 = const empty() -> bb1; // scope 0 at $DIR/unreachable_asm_2.rs:11:23: 11:30 - // ty::Const - // + ty: fn() -> std::option::Option {empty} - // + val: Value(Scalar()) + _1 = empty() -> bb1; // scope 0 at $DIR/unreachable_asm_2.rs:11:23: 11:30 // mir::Constant // + span: $DIR/unreachable_asm_2.rs:11:23: 11:28 // + literal: Const { ty: fn() -> std::option::Option {empty}, val: Value(Scalar()) } @@ -41,12 +38,6 @@ bb2: { _0 = const (); // scope 0 at $DIR/unreachable_asm_2.rs:11:5: 25:6 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/unreachable_asm_2.rs:11:5: 25:6 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_1); // scope 0 at $DIR/unreachable_asm_2.rs:26:1: 26:2 return; // scope 0 at $DIR/unreachable_asm_2.rs:26:2: 26:2 } @@ -65,21 +56,9 @@ StorageLive(_8); // scope 2 at $DIR/unreachable_asm_2.rs:20:13: 20:41 llvm_asm!(LlvmInlineAsmInner { asm: "NOP", asm_str_style: Cooked, outputs: [], inputs: [], clobbers: [], volatile: true, alignstack: false, dialect: Att } : [] : []); // scope 4 at $DIR/unreachable_asm_2.rs:20:22: 20:39 _8 = const (); // scope 4 at $DIR/unreachable_asm_2.rs:20:13: 20:41 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/unreachable_asm_2.rs:20:13: 20:41 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_8); // scope 2 at $DIR/unreachable_asm_2.rs:20:40: 20:41 _4 = const 42_i32; // scope 2 at $DIR/unreachable_asm_2.rs:21:13: 21:20 _5 = const (); // scope 2 at $DIR/unreachable_asm_2.rs:18:16: 22:10 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/unreachable_asm_2.rs:18:16: 22:10 - // + literal: Const { ty: (), val: Value(Scalar()) } - goto -> bb6; // scope 2 at $DIR/unreachable_asm_2.rs:14:9: 22:10 + unreachable; // scope 2 at $DIR/unreachable_asm_2.rs:14:9: 22:10 } @@ -88,21 +67,9 @@ StorageLive(_7); // scope 2 at $DIR/unreachable_asm_2.rs:16:13: 16:41 llvm_asm!(LlvmInlineAsmInner { asm: "NOP", asm_str_style: Cooked, outputs: [], inputs: [], clobbers: [], volatile: true, alignstack: false, dialect: Att } : [] : []); // scope 3 at $DIR/unreachable_asm_2.rs:16:22: 16:39 _7 = const (); // scope 3 at $DIR/unreachable_asm_2.rs:16:13: 16:41 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/unreachable_asm_2.rs:16:13: 16:41 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_7); // scope 2 at $DIR/unreachable_asm_2.rs:16:40: 16:41 _4 = const 21_i32; // scope 2 at $DIR/unreachable_asm_2.rs:17:13: 17:20 _5 = const (); // scope 2 at $DIR/unreachable_asm_2.rs:14:17: 18:10 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/unreachable_asm_2.rs:14:17: 18:10 - // + literal: Const { ty: (), val: Value(Scalar()) } - goto -> bb6; // scope 2 at $DIR/unreachable_asm_2.rs:14:9: 22:10 - } - diff --git a/src/test/mir-opt/unreachable_diverging.main.UnreachablePropagation.diff b/src/test/mir-opt/unreachable_diverging.main.UnreachablePropagation.diff index e1c195ad303..c809483d8c2 100644 --- a/src/test/mir-opt/unreachable_diverging.main.UnreachablePropagation.diff +++ b/src/test/mir-opt/unreachable_diverging.main.UnreachablePropagation.diff @@ -21,10 +21,7 @@ StorageLive(_1); // scope 0 at $DIR/unreachable_diverging.rs:13:9: 13:10 _1 = const true; // scope 0 at $DIR/unreachable_diverging.rs:13:13: 13:17 StorageLive(_2); // scope 1 at $DIR/unreachable_diverging.rs:14:25: 14:32 - _2 = const empty() -> bb1; // scope 1 at $DIR/unreachable_diverging.rs:14:25: 14:32 - // ty::Const - // + ty: fn() -> std::option::Option {empty} - // + val: Value(Scalar()) + _2 = empty() -> bb1; // scope 1 at $DIR/unreachable_diverging.rs:14:25: 14:32 // mir::Constant // + span: $DIR/unreachable_diverging.rs:14:25: 14:30 // + literal: Const { ty: fn() -> std::option::Option {empty}, val: Value(Scalar()) } @@ -37,12 +34,6 @@ bb2: { _0 = const (); // scope 1 at $DIR/unreachable_diverging.rs:14:5: 19:6 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/unreachable_diverging.rs:14:5: 19:6 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_1); // scope 0 at $DIR/unreachable_diverging.rs:20:1: 20:2 StorageDead(_2); // scope 0 at $DIR/unreachable_diverging.rs:20:1: 20:2 return; // scope 0 at $DIR/unreachable_diverging.rs:20:2: 20:2 @@ -60,21 +51,12 @@ bb4: { - _5 = const (); // scope 2 at $DIR/unreachable_diverging.rs:15:9: 17:10 -+ _5 = const loop_forever() -> bb5; // scope 2 at $DIR/unreachable_diverging.rs:16:13: 16:27 - // ty::Const -- // + ty: () -- // + val: Value(Scalar()) -- // mir::Constant -- // + span: $DIR/unreachable_diverging.rs:15:9: 17:10 -- // + literal: Const { ty: (), val: Value(Scalar()) } - goto -> bb6; // scope 2 at $DIR/unreachable_diverging.rs:15:9: 17:10 - } - - bb5: { -- _5 = const loop_forever() -> bb6; // scope 2 at $DIR/unreachable_diverging.rs:16:13: 16:27 -- // ty::Const - // + ty: fn() {loop_forever} - // + val: Value(Scalar()) +- _5 = loop_forever() -> bb6; // scope 2 at $DIR/unreachable_diverging.rs:16:13: 16:27 ++ _5 = loop_forever() -> bb5; // scope 2 at $DIR/unreachable_diverging.rs:16:13: 16:27 // mir::Constant // + span: $DIR/unreachable_diverging.rs:16:13: 16:25 // + literal: Const { ty: fn() {loop_forever}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.std__vec__Vec_i32_.AddMovesForPackedDrops.before.mir.32bit b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.std__vec__Vec_i32_.AddMovesForPackedDrops.before.mir.32bit index 321f13b4927..1f5804e0b2c 100644 --- a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.std__vec__Vec_i32_.AddMovesForPackedDrops.before.mir.32bit +++ b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.std__vec__Vec_i32_.AddMovesForPackedDrops.before.mir.32bit @@ -35,10 +35,7 @@ fn std::intrinsics::drop_in_place(_1: *mut std::vec::Vec) -> () { bb7: { _2 = &mut (*_1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - _3 = const as std::ops::Drop>::drop(move _2) -> [return: bb6, unwind: bb5]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - // ty::Const - // + ty: for<'r> fn(&'r mut std::vec::Vec) { as std::ops::Drop>::drop} - // + val: Value(Scalar()) + _3 = as std::ops::Drop>::drop(move _2) -> [return: bb6, unwind: bb5]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/ptr/mod.rs:LL:COL // + literal: Const { ty: for<'r> fn(&'r mut std::vec::Vec) { as std::ops::Drop>::drop}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.std__vec__Vec_i32_.AddMovesForPackedDrops.before.mir.64bit b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.std__vec__Vec_i32_.AddMovesForPackedDrops.before.mir.64bit index 321f13b4927..1f5804e0b2c 100644 --- a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.std__vec__Vec_i32_.AddMovesForPackedDrops.before.mir.64bit +++ b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.std__vec__Vec_i32_.AddMovesForPackedDrops.before.mir.64bit @@ -35,10 +35,7 @@ fn std::intrinsics::drop_in_place(_1: *mut std::vec::Vec) -> () { bb7: { _2 = &mut (*_1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - _3 = const as std::ops::Drop>::drop(move _2) -> [return: bb6, unwind: bb5]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - // ty::Const - // + ty: for<'r> fn(&'r mut std::vec::Vec) { as std::ops::Drop>::drop} - // + val: Value(Scalar()) + _3 = as std::ops::Drop>::drop(move _2) -> [return: bb6, unwind: bb5]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/ptr/mod.rs:LL:COL // + literal: Const { ty: for<'r> fn(&'r mut std::vec::Vec) { as std::ops::Drop>::drop}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff.32bit b/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff.32bit index 4705309e746..2d53fefca55 100644 --- a/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff.32bit +++ b/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff.32bit @@ -26,12 +26,6 @@ bb1: { _0 = const (); // scope 1 at $DIR/while_let_loops.rs:7:5: 10:6 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/while_let_loops.rs:7:5: 10:6 - // + literal: Const { ty: (), val: Value(Scalar()) } goto -> bb4; // scope 1 at $DIR/while_let_loops.rs:7:5: 10:6 } @@ -42,12 +36,6 @@ bb3: { _1 = const 1_i32; // scope 1 at $DIR/while_let_loops.rs:8:9: 8:15 _0 = const (); // scope 1 at $DIR/while_let_loops.rs:9:9: 9:14 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/while_let_loops.rs:9:9: 9:14 - // + literal: Const { ty: (), val: Value(Scalar()) } goto -> bb4; // scope 1 at $DIR/while_let_loops.rs:9:9: 9:14 } diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff.64bit b/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff.64bit index 4705309e746..2d53fefca55 100644 --- a/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff.64bit +++ b/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff.64bit @@ -26,12 +26,6 @@ bb1: { _0 = const (); // scope 1 at $DIR/while_let_loops.rs:7:5: 10:6 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/while_let_loops.rs:7:5: 10:6 - // + literal: Const { ty: (), val: Value(Scalar()) } goto -> bb4; // scope 1 at $DIR/while_let_loops.rs:7:5: 10:6 } @@ -42,12 +36,6 @@ bb3: { _1 = const 1_i32; // scope 1 at $DIR/while_let_loops.rs:8:9: 8:15 _0 = const (); // scope 1 at $DIR/while_let_loops.rs:9:9: 9:14 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/while_let_loops.rs:9:9: 9:14 - // + literal: Const { ty: (), val: Value(Scalar()) } goto -> bb4; // scope 1 at $DIR/while_let_loops.rs:9:9: 9:14 } diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir.32bit b/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir.32bit index 5c4b18e6f52..523ecb5ec1a 100644 --- a/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir.32bit +++ b/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir.32bit @@ -14,12 +14,6 @@ fn change_loop_body() -> () { StorageLive(_2); // scope 1 at $DIR/while_let_loops.rs:7:28: 7:32 discriminant(_2) = 0; // scope 1 at $DIR/while_let_loops.rs:7:28: 7:32 _0 = const (); // scope 1 at $DIR/while_let_loops.rs:7:5: 10:6 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/while_let_loops.rs:7:5: 10:6 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_2); // scope 1 at $DIR/while_let_loops.rs:10:5: 10:6 StorageDead(_1); // scope 0 at $DIR/while_let_loops.rs:11:1: 11:2 return; // scope 0 at $DIR/while_let_loops.rs:11:2: 11:2 diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir.64bit b/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir.64bit index 5c4b18e6f52..523ecb5ec1a 100644 --- a/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir.64bit +++ b/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir.64bit @@ -14,12 +14,6 @@ fn change_loop_body() -> () { StorageLive(_2); // scope 1 at $DIR/while_let_loops.rs:7:28: 7:32 discriminant(_2) = 0; // scope 1 at $DIR/while_let_loops.rs:7:28: 7:32 _0 = const (); // scope 1 at $DIR/while_let_loops.rs:7:5: 10:6 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/while_let_loops.rs:7:5: 10:6 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_2); // scope 1 at $DIR/while_let_loops.rs:10:5: 10:6 StorageDead(_1); // scope 0 at $DIR/while_let_loops.rs:11:1: 11:2 return; // scope 0 at $DIR/while_let_loops.rs:11:2: 11:2 diff --git a/src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir b/src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir index 3ddf82c2fb2..f4a7ffe50b3 100644 --- a/src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir +++ b/src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir @@ -12,10 +12,7 @@ fn while_loop(_1: bool) -> () { StorageLive(_2); // scope 0 at $DIR/while-storage.rs:10:11: 10:22 StorageLive(_3); // scope 0 at $DIR/while-storage.rs:10:20: 10:21 _3 = _1; // scope 0 at $DIR/while-storage.rs:10:20: 10:21 - _2 = const get_bool(move _3) -> bb1; // scope 0 at $DIR/while-storage.rs:10:11: 10:22 - // ty::Const - // + ty: fn(bool) -> bool {get_bool} - // + val: Value(Scalar()) + _2 = get_bool(move _3) -> bb1; // scope 0 at $DIR/while-storage.rs:10:11: 10:22 // mir::Constant // + span: $DIR/while-storage.rs:10:11: 10:19 // + literal: Const { ty: fn(bool) -> bool {get_bool}, val: Value(Scalar()) } @@ -28,12 +25,6 @@ fn while_loop(_1: bool) -> () { bb2: { _0 = const (); // scope 0 at $DIR/while-storage.rs:10:5: 14:6 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/while-storage.rs:10:5: 14:6 - // + literal: Const { ty: (), val: Value(Scalar()) } goto -> bb7; // scope 0 at $DIR/while-storage.rs:10:5: 14:6 } @@ -41,10 +32,7 @@ fn while_loop(_1: bool) -> () { StorageLive(_4); // scope 0 at $DIR/while-storage.rs:11:12: 11:23 StorageLive(_5); // scope 0 at $DIR/while-storage.rs:11:21: 11:22 _5 = _1; // scope 0 at $DIR/while-storage.rs:11:21: 11:22 - _4 = const get_bool(move _5) -> bb4; // scope 0 at $DIR/while-storage.rs:11:12: 11:23 - // ty::Const - // + ty: fn(bool) -> bool {get_bool} - // + val: Value(Scalar()) + _4 = get_bool(move _5) -> bb4; // scope 0 at $DIR/while-storage.rs:11:12: 11:23 // mir::Constant // + span: $DIR/while-storage.rs:11:12: 11:20 // + literal: Const { ty: fn(bool) -> bool {get_bool}, val: Value(Scalar()) } @@ -63,12 +51,6 @@ fn while_loop(_1: bool) -> () { bb6: { _0 = const (); // scope 0 at $DIR/while-storage.rs:12:13: 12:18 - // ty::Const - // + ty: () - // + val: Value(Scalar()) - // mir::Constant - // + span: $DIR/while-storage.rs:12:13: 12:18 - // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_4); // scope 0 at $DIR/while-storage.rs:14:5: 14:6 goto -> bb7; // scope 0 at $DIR/while-storage.rs:12:13: 12:18 } diff --git a/src/test/run-make-fulldeps/instrument-coverage/expected_export_coverage.json b/src/test/run-make-fulldeps/instrument-coverage/expected_export_coverage.json index 5881cf4b7db..75bec80bdf8 100644 --- a/src/test/run-make-fulldeps/instrument-coverage/expected_export_coverage.json +++ b/src/test/run-make-fulldeps/instrument-coverage/expected_export_coverage.json @@ -55,5 +55,5 @@ } ], "type": "llvm.coverage.json.export", - "version": "2.0.0" + "version": "2.0.1" } diff --git a/src/test/rustdoc-ui/assoc-item-not-in-scope.rs b/src/test/rustdoc-ui/assoc-item-not-in-scope.rs new file mode 100644 index 00000000000..c5bb4305db7 --- /dev/null +++ b/src/test/rustdoc-ui/assoc-item-not-in-scope.rs @@ -0,0 +1,22 @@ +#![deny(broken_intra_doc_links)] + +#[derive(Debug)] +/// Link to [`S::fmt`] +//~^ ERROR unresolved link +pub struct S; + +pub mod inner { + use std::fmt::Debug; + use super::S; + + /// Link to [`S::fmt`] + pub fn f() {} +} + +pub mod ambiguous { + use std::fmt::{Display, Debug}; + use super::S; + + /// Link to [`S::fmt`] + pub fn f() {} +} diff --git a/src/test/rustdoc-ui/assoc-item-not-in-scope.stderr b/src/test/rustdoc-ui/assoc-item-not-in-scope.stderr new file mode 100644 index 00000000000..8827c9351a6 --- /dev/null +++ b/src/test/rustdoc-ui/assoc-item-not-in-scope.stderr @@ -0,0 +1,15 @@ +error: unresolved link to `S::fmt` + --> $DIR/assoc-item-not-in-scope.rs:4:14 + | +LL | /// Link to [`S::fmt`] + | ^^^^^^^^ unresolved link + | +note: the lint level is defined here + --> $DIR/assoc-item-not-in-scope.rs:1:9 + | +LL | #![deny(broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^ + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: aborting due to previous error + diff --git a/src/test/rustdoc-ui/coverage/basic.stdout b/src/test/rustdoc-ui/coverage/basic.stdout index 7e795acc575..3c602b3da4c 100644 --- a/src/test/rustdoc-ui/coverage/basic.stdout +++ b/src/test/rustdoc-ui/coverage/basic.stdout @@ -1,7 +1,7 @@ -+-------------------------------------+------------+------------+------------+------------+------------+ -| File | Documented | Total | Percentage | Examples | Percentage | -+-------------------------------------+------------+------------+------------+------------+------------+ -| ...est/rustdoc-ui/coverage/basic.rs | 7 | 14 | 50.0% | 0 | 0.0% | -+-------------------------------------+------------+------------+------------+------------+------------+ -| Total | 7 | 14 | 50.0% | 0 | 0.0% | -+-------------------------------------+------------+------------+------------+------------+------------+ ++-------------------------------------+------------+------------+------------+------------+ +| File | Documented | Percentage | Examples | Percentage | ++-------------------------------------+------------+------------+------------+------------+ +| ...est/rustdoc-ui/coverage/basic.rs | 7 | 50.0% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ +| Total | 7 | 50.0% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/coverage/doc-examples-json.rs b/src/test/rustdoc-ui/coverage/doc-examples-json.rs new file mode 100644 index 00000000000..1da1813790e --- /dev/null +++ b/src/test/rustdoc-ui/coverage/doc-examples-json.rs @@ -0,0 +1,13 @@ +// check-pass +// compile-flags:-Z unstable-options --output-format json --show-coverage + +// This check ensures that only one doc example is counted since they're "optional" on +// certain items. + +/// ``` +/// let x = 12; +/// ``` +pub const Foo: u32 = 0; + +/// doc +pub const Bar: u32 = 0; diff --git a/src/test/rustdoc-ui/coverage/doc-examples-json.stdout b/src/test/rustdoc-ui/coverage/doc-examples-json.stdout new file mode 100644 index 00000000000..92f58556975 --- /dev/null +++ b/src/test/rustdoc-ui/coverage/doc-examples-json.stdout @@ -0,0 +1 @@ +{"$DIR/doc-examples-json.rs":{"total":3,"with_docs":2,"total_examples":2,"with_examples":1}} diff --git a/src/test/rustdoc-ui/coverage/doc-examples.stdout b/src/test/rustdoc-ui/coverage/doc-examples.stdout index f25cf79a3f3..10ed13c9ff5 100644 --- a/src/test/rustdoc-ui/coverage/doc-examples.stdout +++ b/src/test/rustdoc-ui/coverage/doc-examples.stdout @@ -1,7 +1,7 @@ -+-------------------------------------+------------+------------+------------+------------+------------+ -| File | Documented | Total | Percentage | Examples | Percentage | -+-------------------------------------+------------+------------+------------+------------+------------+ -| ...tdoc-ui/coverage/doc-examples.rs | 4 | 4 | 100.0% | 2 | 50.0% | -+-------------------------------------+------------+------------+------------+------------+------------+ -| Total | 4 | 4 | 100.0% | 2 | 50.0% | -+-------------------------------------+------------+------------+------------+------------+------------+ ++-------------------------------------+------------+------------+------------+------------+ +| File | Documented | Percentage | Examples | Percentage | ++-------------------------------------+------------+------------+------------+------------+ +| ...tdoc-ui/coverage/doc-examples.rs | 4 | 100.0% | 2 | 50.0% | ++-------------------------------------+------------+------------+------------+------------+ +| Total | 4 | 100.0% | 2 | 50.0% | ++-------------------------------------+------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/coverage/empty.stdout b/src/test/rustdoc-ui/coverage/empty.stdout index 2a6a2231e5b..890a7d56e16 100644 --- a/src/test/rustdoc-ui/coverage/empty.stdout +++ b/src/test/rustdoc-ui/coverage/empty.stdout @@ -1,7 +1,7 @@ -+-------------------------------------+------------+------------+------------+------------+------------+ -| File | Documented | Total | Percentage | Examples | Percentage | -+-------------------------------------+------------+------------+------------+------------+------------+ -| ...est/rustdoc-ui/coverage/empty.rs | 0 | 1 | 0.0% | 0 | 0.0% | -+-------------------------------------+------------+------------+------------+------------+------------+ -| Total | 0 | 1 | 0.0% | 0 | 0.0% | -+-------------------------------------+------------+------------+------------+------------+------------+ ++-------------------------------------+------------+------------+------------+------------+ +| File | Documented | Percentage | Examples | Percentage | ++-------------------------------------+------------+------------+------------+------------+ +| ...est/rustdoc-ui/coverage/empty.rs | 0 | 0.0% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ +| Total | 0 | 0.0% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/coverage/enums.stdout b/src/test/rustdoc-ui/coverage/enums.stdout index dd86f61f8d5..64c012c1f66 100644 --- a/src/test/rustdoc-ui/coverage/enums.stdout +++ b/src/test/rustdoc-ui/coverage/enums.stdout @@ -1,7 +1,7 @@ -+-------------------------------------+------------+------------+------------+------------+------------+ -| File | Documented | Total | Percentage | Examples | Percentage | -+-------------------------------------+------------+------------+------------+------------+------------+ -| ...est/rustdoc-ui/coverage/enums.rs | 6 | 8 | 75.0% | 0 | 0.0% | -+-------------------------------------+------------+------------+------------+------------+------------+ -| Total | 6 | 8 | 75.0% | 0 | 0.0% | -+-------------------------------------+------------+------------+------------+------------+------------+ ++-------------------------------------+------------+------------+------------+------------+ +| File | Documented | Percentage | Examples | Percentage | ++-------------------------------------+------------+------------+------------+------------+ +| ...est/rustdoc-ui/coverage/enums.rs | 6 | 75.0% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ +| Total | 6 | 75.0% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/coverage/exotic.stdout b/src/test/rustdoc-ui/coverage/exotic.stdout index f920a3abd36..e282ff12843 100644 --- a/src/test/rustdoc-ui/coverage/exotic.stdout +++ b/src/test/rustdoc-ui/coverage/exotic.stdout @@ -1,8 +1,8 @@ -+-------------------------------------+------------+------------+------------+------------+------------+ -| File | Documented | Total | Percentage | Examples | Percentage | -+-------------------------------------+------------+------------+------------+------------+------------+ -| ...st/rustdoc-ui/coverage/exotic.rs | 1 | 1 | 100.0% | 0 | 0.0% | -| | 2 | 2 | 100.0% | 0 | 0.0% | -+-------------------------------------+------------+------------+------------+------------+------------+ -| Total | 3 | 3 | 100.0% | 0 | 0.0% | -+-------------------------------------+------------+------------+------------+------------+------------+ ++-------------------------------------+------------+------------+------------+------------+ +| File | Documented | Percentage | Examples | Percentage | ++-------------------------------------+------------+------------+------------+------------+ +| ...st/rustdoc-ui/coverage/exotic.rs | 1 | 100.0% | 0 | 0.0% | +| | 2 | 100.0% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ +| Total | 3 | 100.0% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/coverage/json.rs b/src/test/rustdoc-ui/coverage/json.rs index 2bd6a312ab5..a591cd5dba4 100644 --- a/src/test/rustdoc-ui/coverage/json.rs +++ b/src/test/rustdoc-ui/coverage/json.rs @@ -12,16 +12,54 @@ pub enum Bar { A } pub struct X; /// Bar +/// +/// ``` +/// let x = 12; +/// ``` pub mod bar { /// bar pub struct Bar; /// X - pub enum X { Y } + pub enum X { + /// ``` + /// let x = "should be ignored!"; + /// ``` + Y + } } /// yolo +/// +/// ```text +/// should not be counted as a code example! +/// ``` pub enum Yolo { X } +impl Yolo { + /// ``` + /// let x = "should be ignored!"; + /// ``` + pub const Const: u32 = 0; +} + pub struct Xo { + /// ``` + /// let x = "should be ignored!"; + /// ``` x: T, } + +/// ``` +/// let x = "should be ignored!"; +/// ``` +pub static StaticFoo: u32 = 0; + +/// ``` +/// let x = "should be ignored!"; +/// ``` +pub const ConstFoo: u32 = 0; + +/// ``` +/// let x = "should be ignored!"; +/// ``` +pub type TypeFoo = u32; diff --git a/src/test/rustdoc-ui/coverage/json.stdout b/src/test/rustdoc-ui/coverage/json.stdout index 7b5b083e158..c2be73ce3ed 100644 --- a/src/test/rustdoc-ui/coverage/json.stdout +++ b/src/test/rustdoc-ui/coverage/json.stdout @@ -1 +1 @@ -{"$DIR/json.rs":{"total":13,"with_docs":7,"with_examples":0}} +{"$DIR/json.rs":{"total":17,"with_docs":12,"total_examples":15,"with_examples":6}} diff --git a/src/test/rustdoc-ui/coverage/private.stdout b/src/test/rustdoc-ui/coverage/private.stdout index bca3d51da59..37a0f5187b5 100644 --- a/src/test/rustdoc-ui/coverage/private.stdout +++ b/src/test/rustdoc-ui/coverage/private.stdout @@ -1,7 +1,7 @@ -+-------------------------------------+------------+------------+------------+------------+------------+ -| File | Documented | Total | Percentage | Examples | Percentage | -+-------------------------------------+------------+------------+------------+------------+------------+ -| ...t/rustdoc-ui/coverage/private.rs | 4 | 7 | 57.1% | 0 | 0.0% | -+-------------------------------------+------------+------------+------------+------------+------------+ -| Total | 4 | 7 | 57.1% | 0 | 0.0% | -+-------------------------------------+------------+------------+------------+------------+------------+ ++-------------------------------------+------------+------------+------------+------------+ +| File | Documented | Percentage | Examples | Percentage | ++-------------------------------------+------------+------------+------------+------------+ +| ...t/rustdoc-ui/coverage/private.rs | 4 | 57.1% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ +| Total | 4 | 57.1% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/coverage/statics-consts.stdout b/src/test/rustdoc-ui/coverage/statics-consts.stdout index 31b48cc602a..dbea3a3ea23 100644 --- a/src/test/rustdoc-ui/coverage/statics-consts.stdout +++ b/src/test/rustdoc-ui/coverage/statics-consts.stdout @@ -1,7 +1,7 @@ -+-------------------------------------+------------+------------+------------+------------+------------+ -| File | Documented | Total | Percentage | Examples | Percentage | -+-------------------------------------+------------+------------+------------+------------+------------+ -| ...oc-ui/coverage/statics-consts.rs | 6 | 7 | 85.7% | 0 | 0.0% | -+-------------------------------------+------------+------------+------------+------------+------------+ -| Total | 6 | 7 | 85.7% | 0 | 0.0% | -+-------------------------------------+------------+------------+------------+------------+------------+ ++-------------------------------------+------------+------------+------------+------------+ +| File | Documented | Percentage | Examples | Percentage | ++-------------------------------------+------------+------------+------------+------------+ +| ...oc-ui/coverage/statics-consts.rs | 6 | 85.7% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ +| Total | 6 | 85.7% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/coverage/traits.stdout b/src/test/rustdoc-ui/coverage/traits.stdout index ac63b65023d..e04d48b4980 100644 --- a/src/test/rustdoc-ui/coverage/traits.stdout +++ b/src/test/rustdoc-ui/coverage/traits.stdout @@ -1,7 +1,7 @@ -+-------------------------------------+------------+------------+------------+------------+------------+ -| File | Documented | Total | Percentage | Examples | Percentage | -+-------------------------------------+------------+------------+------------+------------+------------+ -| ...st/rustdoc-ui/coverage/traits.rs | 6 | 7 | 85.7% | 0 | 0.0% | -+-------------------------------------+------------+------------+------------+------------+------------+ -| Total | 6 | 7 | 85.7% | 0 | 0.0% | -+-------------------------------------+------------+------------+------------+------------+------------+ ++-------------------------------------+------------+------------+------------+------------+ +| File | Documented | Percentage | Examples | Percentage | ++-------------------------------------+------------+------------+------------+------------+ +| ...st/rustdoc-ui/coverage/traits.rs | 6 | 85.7% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ +| Total | 6 | 85.7% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/intra-link-prim-conflict.rs b/src/test/rustdoc-ui/intra-link-prim-conflict.rs new file mode 100644 index 00000000000..34276fbcf20 --- /dev/null +++ b/src/test/rustdoc-ui/intra-link-prim-conflict.rs @@ -0,0 +1,30 @@ +#![deny(broken_intra_doc_links)] +//~^ NOTE lint level is defined + +/// [char] +//~^ ERROR both a module and a builtin type +//~| NOTE ambiguous link +//~| HELP to link to the module +//~| HELP to link to the builtin type + +/// [type@char] +//~^ ERROR both a module and a builtin type +//~| NOTE ambiguous link +//~| HELP to link to the module +//~| HELP to link to the builtin type + +/// [mod@char] // ok +/// [prim@char] // ok + +/// [struct@char] +//~^ ERROR incompatible link +//~| HELP use its disambiguator +//~| NOTE resolved to a module +pub mod char {} + +pub mod inner { + //! [struct@char] + //~^ ERROR incompatible link + //~| HELP use its disambiguator + //~| NOTE resolved to a builtin type +} diff --git a/src/test/rustdoc-ui/intra-link-prim-conflict.stderr b/src/test/rustdoc-ui/intra-link-prim-conflict.stderr new file mode 100644 index 00000000000..b28a4426666 --- /dev/null +++ b/src/test/rustdoc-ui/intra-link-prim-conflict.stderr @@ -0,0 +1,53 @@ +error: `char` is both a module and a builtin type + --> $DIR/intra-link-prim-conflict.rs:4:6 + | +LL | /// [char] + | ^^^^ ambiguous link + | +note: the lint level is defined here + --> $DIR/intra-link-prim-conflict.rs:1:9 + | +LL | #![deny(broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^ +help: to link to the module, prefix with the item type + | +LL | /// [module@char] + | ^^^^^^^^^^^ +help: to link to the builtin type, prefix with the item type + | +LL | /// [prim@char] + | ^^^^^^^^^ + +error: `char` is both a module and a builtin type + --> $DIR/intra-link-prim-conflict.rs:10:6 + | +LL | /// [type@char] + | ^^^^^^^^^ ambiguous link + | +help: to link to the module, prefix with the item type + | +LL | /// [module@char] + | ^^^^^^^^^^^ +help: to link to the builtin type, prefix with the item type + | +LL | /// [prim@char] + | ^^^^^^^^^ + +error: incompatible link kind for `char` + --> $DIR/intra-link-prim-conflict.rs:19:6 + | +LL | /// [struct@char] + | ^^^^^^^^^^^ help: to link to the module, use its disambiguator: `mod@char` + | + = note: this link resolved to a module, which is not a struct + +error: incompatible link kind for `char` + --> $DIR/intra-link-prim-conflict.rs:26:10 + | +LL | //! [struct@char] + | ^^^^^^^^^^^ help: to link to the builtin type, use its disambiguator: `prim@char` + | + = note: this link resolved to a builtin type, which is not a struct + +error: aborting due to 4 previous errors + diff --git a/src/test/rustdoc-ui/lint-missing-doc-code-example.rs b/src/test/rustdoc-ui/lint-missing-doc-code-example.rs index ffe0ddcd8c9..ebe7a242211 100644 --- a/src/test/rustdoc-ui/lint-missing-doc-code-example.rs +++ b/src/test/rustdoc-ui/lint-missing-doc-code-example.rs @@ -38,3 +38,34 @@ pub mod module3 { //~^ ERROR pub fn test() {} } + +/// Doc, but no code example and it's fine! +pub const Const: u32 = 0; +/// Doc, but no code example and it's fine! +pub static Static: u32 = 0; +/// Doc, but no code example and it's fine! +pub type Type = u32; + +/// Doc +//~^ ERROR +pub struct Struct { + /// Doc, but no code example and it's fine! + pub field: u32, +} + +/// Doc +//~^ ERROR +pub enum Enum { + /// Doc, but no code example and it's fine! + X, +} + +/// Doc +//~^ ERROR +#[repr(C)] +union Union { + /// Doc, but no code example and it's fine! + a: i32, + /// Doc, but no code example and it's fine! + b: f32, +} diff --git a/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr b/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr index 3fcfc1808e0..32756c99e7f 100644 --- a/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr +++ b/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr @@ -1,9 +1,8 @@ error: missing code example in this documentation - --> $DIR/lint-missing-doc-code-example.rs:19:1 + --> $DIR/lint-missing-doc-code-example.rs:49:1 | -LL | / mod module1 { -LL | | } - | |_^ +LL | /// Doc + | ^^^^^^^ | note: the lint level is defined here --> $DIR/lint-missing-doc-code-example.rs:2:9 @@ -11,11 +10,30 @@ note: the lint level is defined here LL | #![deny(missing_doc_code_examples)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ +error: missing code example in this documentation + --> $DIR/lint-missing-doc-code-example.rs:63:1 + | +LL | /// Doc + | ^^^^^^^ + +error: missing code example in this documentation + --> $DIR/lint-missing-doc-code-example.rs:56:1 + | +LL | /// Doc + | ^^^^^^^ + +error: missing code example in this documentation + --> $DIR/lint-missing-doc-code-example.rs:19:1 + | +LL | / mod module1 { +LL | | } + | |_^ + error: missing code example in this documentation --> $DIR/lint-missing-doc-code-example.rs:37:3 | LL | /// doc | ^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 5 previous errors diff --git a/src/test/rustdoc-ui/unknown-renamed-lints.rs b/src/test/rustdoc-ui/unknown-renamed-lints.rs new file mode 100644 index 00000000000..7faa82ea429 --- /dev/null +++ b/src/test/rustdoc-ui/unknown-renamed-lints.rs @@ -0,0 +1,8 @@ +#![deny(unknown_lints)] +//~^ NOTE lint level is defined +#![deny(renamed_and_removed_lints)] +//~^ NOTE lint level is defined +#![deny(x)] +//~^ ERROR unknown lint +#![deny(intra_doc_link_resolution_failure)] +//~^ ERROR lint `intra_doc_link_resolution_failure` has been renamed diff --git a/src/test/rustdoc-ui/unknown-renamed-lints.stderr b/src/test/rustdoc-ui/unknown-renamed-lints.stderr new file mode 100644 index 00000000000..f0917f194bb --- /dev/null +++ b/src/test/rustdoc-ui/unknown-renamed-lints.stderr @@ -0,0 +1,28 @@ +error: unknown lint: `x` + --> $DIR/unknown-renamed-lints.rs:5:9 + | +LL | #![deny(x)] + | ^ + | +note: the lint level is defined here + --> $DIR/unknown-renamed-lints.rs:1:9 + | +LL | #![deny(unknown_lints)] + | ^^^^^^^^^^^^^ + +error: lint `intra_doc_link_resolution_failure` has been renamed to `broken_intra_doc_links` + --> $DIR/unknown-renamed-lints.rs:7:9 + | +LL | #![deny(intra_doc_link_resolution_failure)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `broken_intra_doc_links` + | +note: the lint level is defined here + --> $DIR/unknown-renamed-lints.rs:3:9 + | +LL | #![deny(renamed_and_removed_lints)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: Compilation failed, aborting rustdoc + +error: aborting due to 3 previous errors + diff --git a/src/test/rustdoc/intra-link-associated-defaults.rs b/src/test/rustdoc/intra-link-associated-defaults.rs new file mode 100644 index 00000000000..2051129b948 --- /dev/null +++ b/src/test/rustdoc/intra-link-associated-defaults.rs @@ -0,0 +1,27 @@ +// ignore-tidy-linelength +#![deny(intra_doc_link_resolution_failure)] +#![feature(associated_type_defaults)] + +pub trait TraitWithDefault { + type T = usize; + fn f() -> Self::T { + 0 + } +} + +/// Link to [UsesDefaults::T] and [UsesDefaults::f] +// @has 'intra_link_associated_defaults/struct.UsesDefaults.html' '//a[@href="../intra_link_associated_defaults/struct.UsesDefaults.html#associatedtype.T"]' 'UsesDefaults::T' +// @has 'intra_link_associated_defaults/struct.UsesDefaults.html' '//a[@href="../intra_link_associated_defaults/struct.UsesDefaults.html#method.f"]' 'UsesDefaults::f' +pub struct UsesDefaults; +impl TraitWithDefault for UsesDefaults {} + +/// Link to [OverridesDefaults::T] and [OverridesDefaults::f] +// @has 'intra_link_associated_defaults/struct.OverridesDefaults.html' '//a[@href="../intra_link_associated_defaults/struct.OverridesDefaults.html#associatedtype.T"]' 'OverridesDefaults::T' +// @has 'intra_link_associated_defaults/struct.OverridesDefaults.html' '//a[@href="../intra_link_associated_defaults/struct.OverridesDefaults.html#method.f"]' 'OverridesDefaults::f' +pub struct OverridesDefaults; +impl TraitWithDefault for OverridesDefaults { + type T = bool; + fn f() -> bool { + true + } +} diff --git a/src/test/rustdoc/intra-link-associated-items.rs b/src/test/rustdoc/intra-link-associated-items.rs new file mode 100644 index 00000000000..16a21e33748 --- /dev/null +++ b/src/test/rustdoc/intra-link-associated-items.rs @@ -0,0 +1,59 @@ +// ignore-tidy-linelength +#![deny(intra_doc_link_resolution_failure)] + +/// [`std::collections::BTreeMap::into_iter`] +/// [`String::from`] is ambiguous as to which `From` impl +// @has 'intra_link_associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/collections/btree/map/struct.BTreeMap.html#method.into_iter"]' 'std::collections::BTreeMap::into_iter' +// @has 'intra_link_associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/string/struct.String.html#method.from"]' 'String::from' +pub fn foo() {} + +/// Link to [MyStruct], [link from struct][MyStruct::method], [MyStruct::clone], [MyStruct::Input] +// @has 'intra_link_associated_items/struct.MyStruct.html' '//a[@href="../intra_link_associated_items/struct.MyStruct.html"]' 'MyStruct' +// @has 'intra_link_associated_items/struct.MyStruct.html' '//a[@href="../intra_link_associated_items/struct.MyStruct.html#method.method"]' 'link from struct' +// @has 'intra_link_associated_items/struct.MyStruct.html' '//a[@href="../intra_link_associated_items/struct.MyStruct.html#method.clone"]' 'MyStruct::clone' +// @has 'intra_link_associated_items/struct.MyStruct.html' '//a[@href="../intra_link_associated_items/struct.MyStruct.html#associatedtype.Input"]' 'MyStruct::Input' +pub struct MyStruct { foo: () } + +impl Clone for MyStruct { + fn clone(&self) -> Self { + MyStruct + } +} + +pub trait T { + type Input; + fn method(i: Self::Input); +} + +impl T for MyStruct { + type Input = usize; + + /// [link from method][MyStruct::method] on method + // @has 'intra_link_associated_items/struct.MyStruct.html' '//a[@href="../intra_link_associated_items/struct.MyStruct.html#method.method"]' 'link from method' + fn method(i: usize) { + } +} + +/// Ambiguity between which trait to use +pub trait T1 { + fn ambiguous_method(); +} + +pub trait T2 { + fn ambiguous_method(); +} + +/// Link to [S::ambiguous_method] +// FIXME: there is no way to disambiguate these. +// Since we have `#[deny(intra_doc_failure)]`, we still know it was one or the other. +pub struct S; + +impl T1 for S { + fn ambiguous_method() {} +} + +impl T2 for S { + fn ambiguous_method() {} +} + +fn main() {} diff --git a/src/test/rustdoc/intra-link-prim-precedence.rs b/src/test/rustdoc/intra-link-prim-precedence.rs index 15ea1232fd6..0a4e57ef643 100644 --- a/src/test/rustdoc/intra-link-prim-precedence.rs +++ b/src/test/rustdoc/intra-link-prim-precedence.rs @@ -1,17 +1,17 @@ // ignore-tidy-linelength #![deny(broken_intra_doc_links)] -pub mod char {} +pub mod char { + /// [char] + // @has intra_link_prim_precedence/char/struct.Inner.html '//a/@href' 'https://doc.rust-lang.org/nightly/std/primitive.char.html' + pub struct Inner; +} -/// See also [type@char] +/// See [prim@char] // @has intra_link_prim_precedence/struct.MyString.html '//a/@href' 'https://doc.rust-lang.org/nightly/std/primitive.char.html' pub struct MyString; -/// See also [char] -// @has intra_link_prim_precedence/struct.MyString2.html '//a/@href' 'https://doc.rust-lang.org/nightly/std/primitive.char.html' -pub struct MyString2; - /// See also [crate::char] and [mod@char] -// @has intra_link_prim_precedence/struct.MyString3.html '//*[@href="../intra_link_prim_precedence/char/index.html"]' 'crate::char' +// @has intra_link_prim_precedence/struct.MyString2.html '//*[@href="../intra_link_prim_precedence/char/index.html"]' 'crate::char' // @has - '//*[@href="../intra_link_prim_precedence/char/index.html"]' 'mod@char' -pub struct MyString3; +pub struct MyString2; diff --git a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs index 8d4101b6526..633d153e391 100644 --- a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs +++ b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs @@ -164,6 +164,7 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P)) { id: DUMMY_NODE_ID, kind: PatKind::Wild, span: DUMMY_SP, + tokens: None, }); iter_exprs(depth - 1, &mut |e| g(ExprKind::Let(pat.clone(), e))) }, diff --git a/src/test/ui/abi/stack-probes.rs b/src/test/ui/abi/stack-probes.rs index 1d5b362e29d..a52c285f9f0 100644 --- a/src/test/ui/abi/stack-probes.rs +++ b/src/test/ui/abi/stack-probes.rs @@ -11,7 +11,6 @@ // ignore-cloudabi no processes // ignore-emscripten no processes // ignore-sgx no processes -// ignore-musl FIXME #31506 use std::mem::MaybeUninit; use std::process::Command; diff --git a/src/test/ui/associated-const/defaults-cyclic-fail.stderr b/src/test/ui/associated-const/defaults-cyclic-fail.stderr index 6b2fbe5be4e..e6075f74577 100644 --- a/src/test/ui/associated-const/defaults-cyclic-fail.stderr +++ b/src/test/ui/associated-const/defaults-cyclic-fail.stderr @@ -32,7 +32,7 @@ note: ...which requires const-evaluating `Tr::B`... LL | const B: u8 = Self::A; | ^^^^^^^^^^^^^^^^^^^^^^ = note: ...which again requires normalizing `<() as Tr>::A`, completing the cycle -note: cycle used when const-evaluating `main` +note: cycle used when const-evaluating `main::promoted[2]` --> $DIR/defaults-cyclic-fail.rs:14:1 | LL | fn main() { diff --git a/src/test/ui/associated-types/bound-lifetime-in-binding-only.ok.stderr b/src/test/ui/associated-types/bound-lifetime-in-binding-only.ok.stderr index 5ece425196c..b709fae5a8e 100644 --- a/src/test/ui/associated-types/bound-lifetime-in-binding-only.ok.stderr +++ b/src/test/ui/associated-types/bound-lifetime-in-binding-only.ok.stderr @@ -2,7 +2,7 @@ error: fatal error triggered by #[rustc_error] --> $DIR/bound-lifetime-in-binding-only.rs:71:1 | LL | fn main() { } - | ^^^^^^^^^^^^^ + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/associated-types/bound-lifetime-in-return-only.ok.stderr b/src/test/ui/associated-types/bound-lifetime-in-return-only.ok.stderr index 8c098098311..1c0d3ac1058 100644 --- a/src/test/ui/associated-types/bound-lifetime-in-return-only.ok.stderr +++ b/src/test/ui/associated-types/bound-lifetime-in-return-only.ok.stderr @@ -2,7 +2,7 @@ error: fatal error triggered by #[rustc_error] --> $DIR/bound-lifetime-in-return-only.rs:49:1 | LL | fn main() { } - | ^^^^^^^^^^^^^ + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.ok.stderr b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.ok.stderr index baa8e6f82f6..ed900079cfc 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.ok.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.ok.stderr @@ -2,7 +2,7 @@ error: fatal error triggered by #[rustc_error] --> $DIR/project-fn-ret-contravariant.rs:50:1 | LL | fn main() { } - | ^^^^^^^^^^^^^ + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.oneuse.stderr b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.oneuse.stderr index baa8e6f82f6..ed900079cfc 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.oneuse.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.oneuse.stderr @@ -2,7 +2,7 @@ error: fatal error triggered by #[rustc_error] --> $DIR/project-fn-ret-contravariant.rs:50:1 | LL | fn main() { } - | ^^^^^^^^^^^^^ + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.ok.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.ok.stderr index 2156ecb1739..c3408500948 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.ok.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.ok.stderr @@ -2,7 +2,7 @@ error: fatal error triggered by #[rustc_error] --> $DIR/project-fn-ret-invariant.rs:60:1 | LL | fn main() {} - | ^^^^^^^^^^^^ + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/associated-types/defaults-cyclic-fail-1.rs b/src/test/ui/associated-types/defaults-cyclic-fail-1.rs index 71ac914ef57..fa75f6bc152 100644 --- a/src/test/ui/associated-types/defaults-cyclic-fail-1.rs +++ b/src/test/ui/associated-types/defaults-cyclic-fail-1.rs @@ -26,16 +26,16 @@ impl Tr for u32 { // ...but only if this actually breaks the cycle impl Tr for bool { -//~^ ERROR overflow evaluating the requirement + //~^ ERROR type mismatch resolving `::B == _` type A = Box; - //~^ ERROR overflow evaluating the requirement + //~^ ERROR type mismatch resolving `::B == _` } // (the error is shown twice for some reason) impl Tr for usize { -//~^ ERROR overflow evaluating the requirement + //~^ ERROR type mismatch resolving `::B == _` type B = &'static Self::A; - //~^ ERROR overflow evaluating the requirement + //~^ ERROR type mismatch resolving `::A == _` } fn main() { diff --git a/src/test/ui/associated-types/defaults-cyclic-fail-1.stderr b/src/test/ui/associated-types/defaults-cyclic-fail-1.stderr index 6a8526f6aad..0aea30b1112 100644 --- a/src/test/ui/associated-types/defaults-cyclic-fail-1.stderr +++ b/src/test/ui/associated-types/defaults-cyclic-fail-1.stderr @@ -1,33 +1,34 @@ -error[E0275]: overflow evaluating the requirement `<() as Tr>::B` +error[E0275]: overflow evaluating the requirement `<() as Tr>::B == _` --> $DIR/defaults-cyclic-fail-1.rs:10:6 | LL | impl Tr for () {} | ^^ -error[E0275]: overflow evaluating the requirement `::B` +error[E0271]: type mismatch resolving `::B == _` --> $DIR/defaults-cyclic-fail-1.rs:28:6 | LL | impl Tr for bool { - | ^^ + | ^^ cyclic type of infinite size -error[E0275]: overflow evaluating the requirement `::B` +error[E0271]: type mismatch resolving `::B == _` --> $DIR/defaults-cyclic-fail-1.rs:35:6 | LL | impl Tr for usize { - | ^^ + | ^^ cyclic type of infinite size -error[E0275]: overflow evaluating the requirement `::B` +error[E0271]: type mismatch resolving `::B == _` --> $DIR/defaults-cyclic-fail-1.rs:30:5 | LL | type A = Box; - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size -error[E0275]: overflow evaluating the requirement `::A` +error[E0271]: type mismatch resolving `::A == _` --> $DIR/defaults-cyclic-fail-1.rs:37:5 | LL | type B = &'static Self::A; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0275`. +Some errors have detailed explanations: E0271, E0275. +For more information about an error, try `rustc --explain E0271`. diff --git a/src/test/ui/associated-types/defaults-cyclic-fail-2.rs b/src/test/ui/associated-types/defaults-cyclic-fail-2.rs index 05091e3f498..edcd310908a 100644 --- a/src/test/ui/associated-types/defaults-cyclic-fail-2.rs +++ b/src/test/ui/associated-types/defaults-cyclic-fail-2.rs @@ -10,7 +10,7 @@ trait Tr { // ...but is an error in any impl that doesn't override at least one of the defaults impl Tr for () {} -//~^ ERROR overflow evaluating the requirement +//~^ ERROR type mismatch resolving `<() as Tr>::B == _` // As soon as at least one is redefined, it works: impl Tr for u8 { @@ -28,16 +28,16 @@ impl Tr for u32 { // ...but only if this actually breaks the cycle impl Tr for bool { -//~^ ERROR overflow evaluating the requirement + //~^ ERROR type mismatch resolving `::B == _` type A = Box; - //~^ ERROR overflow evaluating the requirement + //~^ ERROR type mismatch resolving `::B == _` } // (the error is shown twice for some reason) impl Tr for usize { -//~^ ERROR overflow evaluating the requirement + //~^ ERROR type mismatch resolving `::B == _` type B = &'static Self::A; - //~^ ERROR overflow evaluating the requirement + //~^ ERROR type mismatch resolving `::A == _` } fn main() { diff --git a/src/test/ui/associated-types/defaults-cyclic-fail-2.stderr b/src/test/ui/associated-types/defaults-cyclic-fail-2.stderr index 78772df9638..f39021c30ed 100644 --- a/src/test/ui/associated-types/defaults-cyclic-fail-2.stderr +++ b/src/test/ui/associated-types/defaults-cyclic-fail-2.stderr @@ -1,33 +1,33 @@ -error[E0275]: overflow evaluating the requirement `<() as Tr>::B` +error[E0271]: type mismatch resolving `<() as Tr>::B == _` --> $DIR/defaults-cyclic-fail-2.rs:12:6 | LL | impl Tr for () {} - | ^^ + | ^^ cyclic type of infinite size -error[E0275]: overflow evaluating the requirement `::B` +error[E0271]: type mismatch resolving `::B == _` --> $DIR/defaults-cyclic-fail-2.rs:30:6 | LL | impl Tr for bool { - | ^^ + | ^^ cyclic type of infinite size -error[E0275]: overflow evaluating the requirement `::B` +error[E0271]: type mismatch resolving `::B == _` --> $DIR/defaults-cyclic-fail-2.rs:37:6 | LL | impl Tr for usize { - | ^^ + | ^^ cyclic type of infinite size -error[E0275]: overflow evaluating the requirement `::B` +error[E0271]: type mismatch resolving `::B == _` --> $DIR/defaults-cyclic-fail-2.rs:32:5 | LL | type A = Box; - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size -error[E0275]: overflow evaluating the requirement `::A` +error[E0271]: type mismatch resolving `::A == _` --> $DIR/defaults-cyclic-fail-2.rs:39:5 | LL | type B = &'static Self::A; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0275`. +For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/associated-types/higher-ranked-projection.good.stderr b/src/test/ui/associated-types/higher-ranked-projection.good.stderr index 63d88543607..1dc41a2165f 100644 --- a/src/test/ui/associated-types/higher-ranked-projection.good.stderr +++ b/src/test/ui/associated-types/higher-ranked-projection.good.stderr @@ -1,11 +1,8 @@ error: fatal error triggered by #[rustc_error] --> $DIR/higher-ranked-projection.rs:24:1 | -LL | / fn main() { -LL | | foo(()); -LL | | -LL | | } - | |_^ +LL | fn main() { + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/associated-types/normalize-cycle-in-eval-no-region.rs b/src/test/ui/associated-types/normalize-cycle-in-eval-no-region.rs new file mode 100644 index 00000000000..0fd2c707938 --- /dev/null +++ b/src/test/ui/associated-types/normalize-cycle-in-eval-no-region.rs @@ -0,0 +1,20 @@ +// Case that the fix for #74868 also allowed to compile + +// check-pass + +trait BoxedDsl { + type Output; +} + +impl BoxedDsl for T +where + T: BoxedDsl, +{ + type Output = ::Output; +} + +trait HandleUpdate {} + +impl HandleUpdate for T where T: BoxedDsl {} + +fn main() {} diff --git a/src/test/ui/associated-types/normalize-cycle-in-eval.rs b/src/test/ui/associated-types/normalize-cycle-in-eval.rs new file mode 100644 index 00000000000..dff4c9051f4 --- /dev/null +++ b/src/test/ui/associated-types/normalize-cycle-in-eval.rs @@ -0,0 +1,43 @@ +// regression test for #74868 + +// check-pass + +trait BoxedDsl<'a> { + type Output; +} + +impl<'a, T> BoxedDsl<'a> for T +where + T: BoxedDsl<'a>, +{ + type Output = >::Output; +} + +// Showing this trait is wf requires proving +// Self: HandleUpdate +// +// The impl below is a candidate for this projection, as well as the `Self: +// HandleUpdate` bound in the environment. +// We evaluate both candidates to see if we need to consider both applicable. +// Evaluating the impl candidate requires evaluating +// >::Output == () +// The above impl cause normalizing the above type normalize to itself. +// +// This previously compiled because we would generate a new region +// variable each time around the cycle, and evaluation would eventually return +// `EvaluatedToErr` from the `Self: Sized` in the impl, which would in turn +// leave the bound as the only candidate. +// +// #73452 changed this so that region variables are canonicalized when we +// normalize, which means that the projection cycle is detected before +// evaluation returns EvaluatedToErr. The cycle resulted in an error being +// emitted immediately, causing this to fail to compile. +// +// To fix this, normalization doesn't directly emit errors when it finds a +// cycle, instead letting the caller handle it. This restores the original +// behavior. +trait HandleUpdate {} + +impl HandleUpdate for T where T: BoxedDsl<'static, Output = ()> {} + +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.rs b/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.rs index c8c2702ec44..b7a976a0af6 100644 --- a/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.rs +++ b/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.rs @@ -8,7 +8,7 @@ fn full(self) {} async fn crash(self) { Self::partial(self.0); - Self::full(self); //~ ERROR use of moved value: `self` + Self::full(self); //~ ERROR use of partially moved value: `self` } } diff --git a/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.stderr b/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.stderr index 9177b83dd48..e2a73539874 100644 --- a/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.stderr +++ b/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.stderr @@ -1,12 +1,12 @@ -error[E0382]: use of moved value: `self` +error[E0382]: use of partially moved value: `self` --> $DIR/issue-66958-non-copy-infered-type-arg.rs:11:20 | LL | Self::partial(self.0); - | ------ value moved here + | ------ value partially moved here LL | Self::full(self); | ^^^^ value used here after partial move | - = note: move occurs because `self.0` has type `S`, which does not implement the `Copy` trait + = note: partial move occurs because `self.0` has type `S`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.stderr b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.stderr index da584e8ad4e..f65bbeaa31a 100644 --- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.stderr +++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.stderr @@ -25,28 +25,16 @@ LL | async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<' error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds --> $DIR/ret-impl-trait-no-fg.rs:9:1 | -LL | / async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> { -LL | | -LL | | -LL | | -... | -LL | | (a, b) -LL | | } - | |_^ +LL | async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: hidden type `(&u8, &u8)` captures lifetime '_#5r error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds --> $DIR/ret-impl-trait-no-fg.rs:9:1 | -LL | / async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> { -LL | | -LL | | -LL | | -... | -LL | | (a, b) -LL | | } - | |_^ +LL | async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: hidden type `(&u8, &u8)` captures lifetime '_#6r diff --git a/src/test/ui/auto-traits/issue-23080-2.rs b/src/test/ui/auto-traits/issue-23080-2.rs index 7f6b9e3fba7..867f24f8cb4 100644 --- a/src/test/ui/auto-traits/issue-23080-2.rs +++ b/src/test/ui/auto-traits/issue-23080-2.rs @@ -1,5 +1,3 @@ -//~ ERROR - #![feature(optin_builtin_traits)] #![feature(negative_impls)] diff --git a/src/test/ui/auto-traits/issue-23080-2.stderr b/src/test/ui/auto-traits/issue-23080-2.stderr index 48ce09aaa34..efeceafdd2a 100644 --- a/src/test/ui/auto-traits/issue-23080-2.stderr +++ b/src/test/ui/auto-traits/issue-23080-2.stderr @@ -1,17 +1,11 @@ error[E0380]: auto traits cannot have methods or associated items - --> $DIR/issue-23080-2.rs:7:10 + --> $DIR/issue-23080-2.rs:5:10 | LL | unsafe auto trait Trait { | ----- auto trait cannot have items LL | type Output; | ^^^^^^ -error[E0275]: overflow evaluating the requirement `<() as Trait>::Output` - | - = note: required because of the requirements on the impl of `Trait` for `()` - = note: required because of the requirements on the impl of `Trait` for `()` - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0275, E0380. -For more information about an error, try `rustc --explain E0275`. +For more information about this error, try `rustc --explain E0380`. diff --git a/src/test/ui/binding/issue-53114-borrow-checks.stderr b/src/test/ui/binding/issue-53114-borrow-checks.stderr index 2a7a721324d..489bf70d920 100644 --- a/src/test/ui/binding/issue-53114-borrow-checks.stderr +++ b/src/test/ui/binding/issue-53114-borrow-checks.stderr @@ -8,26 +8,26 @@ LL | drop(m); LL | match m { _ => { } } // #53114: should eventually be accepted too | ^ value used here after move -error[E0382]: use of moved value: `mm` +error[E0382]: use of partially moved value: `mm` --> $DIR/issue-53114-borrow-checks.rs:27:11 | LL | match mm { (_x, _) => { } } - | -- value moved here + | -- value partially moved here LL | match mm { (_, _y) => { } } | ^^ value used here after partial move | - = note: move occurs because `mm.0` has type `M`, which does not implement the `Copy` trait + = note: partial move occurs because `mm.0` has type `M`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `mm` +error[E0382]: use of partially moved value: `mm` --> $DIR/issue-53114-borrow-checks.rs:29:11 | LL | match mm { (_, _y) => { } } - | -- value moved here + | -- value partially moved here LL | LL | match mm { (_, _) => { } } | ^^ value used here after partial move | - = note: move occurs because `mm.1` has type `M`, which does not implement the `Copy` trait + = note: partial move occurs because `mm.1` has type `M`, which does not implement the `Copy` trait error[E0382]: use of moved value: `m` --> $DIR/issue-53114-borrow-checks.rs:36:16 @@ -39,26 +39,26 @@ LL | drop(m); LL | if let _ = m { } // #53114: should eventually be accepted too | ^ value used here after move -error[E0382]: use of moved value: `mm` +error[E0382]: use of partially moved value: `mm` --> $DIR/issue-53114-borrow-checks.rs:41:22 | LL | if let (_x, _) = mm { } - | -- value moved here + | -- value partially moved here LL | if let (_, _y) = mm { } | ^^ value used here after partial move | - = note: move occurs because `mm.0` has type `M`, which does not implement the `Copy` trait + = note: partial move occurs because `mm.0` has type `M`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `mm` +error[E0382]: use of partially moved value: `mm` --> $DIR/issue-53114-borrow-checks.rs:43:21 | LL | if let (_, _y) = mm { } - | -- value moved here + | -- value partially moved here LL | LL | if let (_, _) = mm { } | ^^ value used here after partial move | - = note: move occurs because `mm.1` has type `M`, which does not implement the `Copy` trait + = note: partial move occurs because `mm.1` has type `M`, which does not implement the `Copy` trait error: aborting due to 6 previous errors diff --git a/src/test/ui/block-result/issue-20862.stderr b/src/test/ui/block-result/issue-20862.stderr index f9c890b0ed8..560c9c2fbef 100644 --- a/src/test/ui/block-result/issue-20862.stderr +++ b/src/test/ui/block-result/issue-20862.stderr @@ -12,16 +12,13 @@ LL | |y| x + y error[E0618]: expected function, found `()` --> $DIR/issue-20862.rs:7:13 | -LL | / fn foo(x: i32) { -LL | | |y| x + y -LL | | -LL | | } - | |_- `foo` defined here returns `()` +LL | fn foo(x: i32) { + | -------------- `foo` defined here returns `()` ... -LL | let x = foo(5)(2); - | ^^^^^^--- - | | - | call expression requires function +LL | let x = foo(5)(2); + | ^^^^^^--- + | | + | call expression requires function error: aborting due to 2 previous errors diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-match.rs b/src/test/ui/borrowck/borrowck-move-out-from-array-match.rs index c1513fcba8a..ced4d002b38 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array-match.rs +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-match.rs @@ -20,7 +20,7 @@ fn move_out_from_begin_field_and_end() { [_, _, (_x, _)] => {} } match a { - [.., _y] => {} //~ ERROR use of moved value + [.., _y] => {} //~ ERROR use of partially moved value } } @@ -42,7 +42,7 @@ fn move_out_by_const_index_and_subslice() { [_x, _, _] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_y @ .., _, _] => {} } } @@ -53,7 +53,7 @@ fn move_out_by_const_index_end_and_subslice() { [.., _x] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_, _, _y @ ..] => {} } } @@ -64,7 +64,7 @@ fn move_out_by_const_index_field_and_subslice() { [(_x, _), _, _] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_y @ .., _, _] => {} } } @@ -75,7 +75,7 @@ fn move_out_by_const_index_end_field_and_subslice() { [.., (_x, _)] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_, _, _y @ ..] => {} } } @@ -108,7 +108,7 @@ fn move_out_by_subslice_and_subslice() { [x @ .., _] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_, _y @ ..] => {} } } diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr index 84930b000cc..d63f03a71db 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr @@ -9,16 +9,16 @@ LL | [.., _y] => {} | = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a[..]` +error[E0382]: use of partially moved value: `a[..]` --> $DIR/borrowck-move-out-from-array-match.rs:23:14 | LL | [_, _, (_x, _)] => {} - | -- value moved here + | -- value partially moved here ... LL | [.., _y] => {} | ^^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait error[E0382]: use of moved value: `a[..].0` --> $DIR/borrowck-move-out-from-array-match.rs:33:15 @@ -31,49 +31,49 @@ LL | [.., (_y, _)] => {} | = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-match.rs:44:11 | LL | [_x, _, _] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-match.rs:55:11 | LL | [.., _x] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-match.rs:66:11 | LL | [(_x, _), _, _] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-match.rs:77:11 | LL | [.., (_x, _)] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait error[E0382]: use of moved value: `a[..].0` --> $DIR/borrowck-move-out-from-array-match.rs:89:11 @@ -97,16 +97,16 @@ LL | [.., (_x, _)] => {} | = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-match.rs:110:11 | LL | [x @ .., _] => {} - | ------ value moved here + | ------ value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait error: aborting due to 10 previous errors diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.rs b/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.rs index 056b8e672bd..97db70f34cc 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.rs +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.rs @@ -15,7 +15,7 @@ fn move_out_from_begin_and_one_from_end() { [_, _, _x] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [.., _y, _] => {} } } @@ -26,7 +26,7 @@ fn move_out_from_begin_field_and_end_field() { [_, _, (_x, _)] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [.., (_, _y)] => {} } } @@ -39,7 +39,7 @@ fn move_out_by_const_index_and_subslice() { [_x, _, _] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_, _y @ ..] => {} } } @@ -50,7 +50,7 @@ fn move_out_by_const_index_end_and_subslice() { [.., _x] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_y @ .., _] => {} } } @@ -61,7 +61,7 @@ fn move_out_by_const_index_field_and_subslice() { [(_x, _), _, _] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_, _y @ ..] => {} } } @@ -72,7 +72,7 @@ fn move_out_by_const_index_end_field_and_subslice() { [.., (_x, _)] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_y @ .., _] => {} } } @@ -83,7 +83,7 @@ fn move_out_by_const_subslice_and_index_field() { [_, _y @ ..] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [(_x, _), _, _] => {} } } @@ -94,7 +94,7 @@ fn move_out_by_const_subslice_and_end_index_field() { [_y @ .., _] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [.., (_x, _)] => {} } } @@ -107,7 +107,7 @@ fn move_out_by_subslice_and_subslice() { [x @ .., _, _] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_, _y @ ..] => {} } } diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr index ff5eab2442c..7c675149894 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr @@ -1,101 +1,101 @@ -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:17:11 | LL | [_, _, _x] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:28:11 | LL | [_, _, (_x, _)] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:41:11 | LL | [_x, _, _] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:52:11 | LL | [.., _x] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:63:11 | LL | [(_x, _), _, _] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:74:11 | LL | [.., (_x, _)] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:85:11 | LL | [_, _y @ ..] => {} - | ------- value moved here + | ------- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:96:11 | LL | [_y @ .., _] => {} - | ------- value moved here + | ------- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:109:11 | LL | [x @ .., _, _] => {} - | ------ value moved here + | ------ value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait error: aborting due to 9 previous errors diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr index 0ef63105cfb..806354b0116 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr @@ -9,16 +9,16 @@ LL | [.., ref _y] => {} | = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait -error[E0382]: borrow of moved value: `a[..]` +error[E0382]: borrow of partially moved value: `a[..]` --> $DIR/borrowck-move-out-from-array-use-match.rs:23:14 | LL | [_, _, (_x, _)] => {} - | -- value moved here + | -- value partially moved here ... LL | [.., ref _y] => {} | ^^^^^^ value borrowed here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait error[E0382]: borrow of moved value: `a[..].0` --> $DIR/borrowck-move-out-from-array-use-match.rs:33:15 @@ -31,49 +31,49 @@ LL | [.., (ref _y, _)] => {} | = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:44:11 | LL | [_x, _, _] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:55:11 | LL | [.., _x] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:66:11 | LL | [(_x, _), _, _] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:77:11 | LL | [.., (_x, _)] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait error[E0382]: borrow of moved value: `a[..]` --> $DIR/borrowck-move-out-from-array-use-match.rs:89:11 @@ -97,60 +97,60 @@ LL | [.., (ref _x, _)] => {} | = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:110:11 | LL | [x @ .., _] => {} - | ------ value moved here + | ------ value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:123:5 | LL | [_, _, _x] => {} - | -- value moved here + | -- value partially moved here LL | } LL | a[2] = Default::default(); | ^^^^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:131:5 | LL | [_, _, (_x, _)] => {} - | -- value moved here + | -- value partially moved here LL | } LL | a[2].1 = Default::default(); | ^^^^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:139:5 | LL | [_, _, _x @ ..] => {} - | ------- value moved here + | ------- value partially moved here LL | } LL | a[0] = Default::default(); | ^^^^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:147:5 | LL | [_, _, _x @ ..] => {} - | ------- value moved here + | ------- value partially moved here LL | } LL | a[0].1 = Default::default(); | ^^^^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait error: aborting due to 14 previous errors diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.rs b/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.rs index 5afd6835dcf..017ca90b81a 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.rs +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.rs @@ -15,7 +15,7 @@ fn move_out_from_begin_and_one_from_end() { [_, _, _x] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [.., ref _y, _] => {} } } @@ -26,7 +26,7 @@ fn move_out_from_begin_field_and_end_field() { [_, _, (_x, _)] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [.., (_, ref _y)] => {} } } @@ -39,7 +39,7 @@ fn move_out_by_const_index_and_subslice() { [_x, _, _] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_, ref _y @ ..] => {} } } @@ -50,7 +50,7 @@ fn move_out_by_const_index_end_and_subslice() { [.., _x] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [ref _y @ .., _] => {} } } @@ -61,7 +61,7 @@ fn move_out_by_const_index_field_and_subslice() { [(_x, _), _, _] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_, ref _y @ ..] => {} } } @@ -72,7 +72,7 @@ fn move_out_by_const_index_end_field_and_subslice() { [.., (_x, _)] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [ref _y @ .., _] => {} } } @@ -83,7 +83,7 @@ fn move_out_by_const_subslice_and_index_field() { [_, _y @ ..] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [(ref _x, _), _, _] => {} } } @@ -94,7 +94,7 @@ fn move_out_by_const_subslice_and_end_index_field() { [_y @ .., _] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [.., (ref _x, _)] => {} } } @@ -107,7 +107,7 @@ fn move_out_by_subslice_and_subslice() { [x @ .., _, _] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_, ref _y @ ..] => {} } } diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr index a4042ce7db3..53f815db140 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr @@ -1,101 +1,101 @@ -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:17:11 | LL | [_, _, _x] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:28:11 | LL | [_, _, (_x, _)] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:41:11 | LL | [_x, _, _] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:52:11 | LL | [.., _x] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:63:11 | LL | [(_x, _), _, _] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:74:11 | LL | [.., (_x, _)] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:85:11 | LL | [_, _y @ ..] => {} - | ------- value moved here + | ------- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:96:11 | LL | [_y @ .., _] => {} - | ------- value moved here + | ------- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:109:11 | LL | [x @ .., _, _] => {} - | ------ value moved here + | ------ value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait error: aborting due to 9 previous errors diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr index 7ad4116645e..004cc433b34 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr @@ -8,15 +8,15 @@ LL | let [.., ref _y] = a; | = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait -error[E0382]: borrow of moved value: `a[..]` +error[E0382]: borrow of partially moved value: `a[..]` --> $DIR/borrowck-move-out-from-array-use.rs:16:14 | LL | let [_, _, (_x, _)] = a; - | -- value moved here + | -- value partially moved here LL | let [.., ref _y] = a; | ^^^^^^ value borrowed here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait error[E0382]: borrow of moved value: `a[..].0` --> $DIR/borrowck-move-out-from-array-use.rs:22:15 @@ -28,45 +28,45 @@ LL | let [.., (ref _y, _)] = a; | = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait -error[E0382]: borrow of moved value: `a` +error[E0382]: borrow of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:30:10 | LL | let [_x, _, _] = a; - | -- value moved here + | -- value partially moved here LL | let [ref _y @ .., _, _] = a; | ^^^^^^^^^^^ value borrowed here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait -error[E0382]: borrow of moved value: `a` +error[E0382]: borrow of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:36:16 | LL | let [.., _x] = a; - | -- value moved here + | -- value partially moved here LL | let [_, _, ref _y @ ..] = a; | ^^^^^^^^^^^ value borrowed here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait -error[E0382]: borrow of moved value: `a` +error[E0382]: borrow of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:42:10 | LL | let [(_x, _), _, _] = a; - | -- value moved here + | -- value partially moved here LL | let [ref _y @ .., _, _] = a; | ^^^^^^^^^^^ value borrowed here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait -error[E0382]: borrow of moved value: `a` +error[E0382]: borrow of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:48:16 | LL | let [.., (_x, _)] = a; - | -- value moved here + | -- value partially moved here LL | let [_, _, ref _y @ ..] = a; | ^^^^^^^^^^^ value borrowed here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait error[E0382]: borrow of moved value: `a[..]` --> $DIR/borrowck-move-out-from-array-use.rs:54:11 @@ -88,55 +88,55 @@ LL | let [.., (ref _x, _)] = a; | = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait -error[E0382]: borrow of moved value: `a` +error[E0382]: borrow of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:68:13 | LL | let [x @ .., _] = a; - | ------ value moved here + | ------ value partially moved here LL | let [_, ref _y @ ..] = a; | ^^^^^^^^^^^ value borrowed here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:76:5 | LL | let [_, _, _x] = a; - | -- value moved here + | -- value partially moved here LL | a[2] = Default::default(); | ^^^^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:82:5 | LL | let [_, _, (_x, _)] = a; - | -- value moved here + | -- value partially moved here LL | a[2].1 = Default::default(); | ^^^^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:88:5 | LL | let [_, _, _x @ ..] = a; - | ------- value moved here + | ------- value partially moved here LL | a[0] = Default::default(); | ^^^^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:94:5 | LL | let [_, _, _x @ ..] = a; - | ------- value moved here + | ------- value partially moved here LL | a[0].1 = Default::default(); | ^^^^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait error: aborting due to 14 previous errors diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array.stderr index b7babd93ed7..d3eb3e9f761 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-from-array.stderr @@ -8,15 +8,15 @@ LL | let [.., _y] = a; | = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a[..]` +error[E0382]: use of partially moved value: `a[..]` --> $DIR/borrowck-move-out-from-array.rs:16:14 | LL | let [_, _, (_x, _)] = a; - | -- value moved here + | -- value partially moved here LL | let [.., _y] = a; | ^^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait error[E0382]: use of moved value: `a[..].0` --> $DIR/borrowck-move-out-from-array.rs:22:15 @@ -28,45 +28,45 @@ LL | let [.., (_y, _)] = a; | = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array.rs:30:10 | LL | let [_x, _, _] = a; - | -- value moved here + | -- value partially moved here LL | let [_y @ .., _, _] = a; | ^^^^^^^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array.rs:36:16 | LL | let [.., _x] = a; - | -- value moved here + | -- value partially moved here LL | let [_, _, _y @ ..] = a; | ^^^^^^^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array.rs:42:10 | LL | let [(_x, _), _, _] = a; - | -- value moved here + | -- value partially moved here LL | let [_y @ .., _, _] = a; | ^^^^^^^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array.rs:48:16 | LL | let [.., (_x, _)] = a; - | -- value moved here + | -- value partially moved here LL | let [_, _, _y @ ..] = a; | ^^^^^^^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait error[E0382]: use of moved value: `a[..].0` --> $DIR/borrowck-move-out-from-array.rs:54:11 @@ -88,15 +88,15 @@ LL | let [.., (_x, _)] = a; | = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array.rs:68:13 | LL | let [x @ .., _] = a; - | ------ value moved here + | ------ value partially moved here LL | let [_, _y @ ..] = a; | ^^^^^^^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait error: aborting due to 10 previous errors diff --git a/src/test/ui/borrowck/borrowck-uninit-field-access.stderr b/src/test/ui/borrowck/borrowck-uninit-field-access.stderr index 9f35a4a8d83..7951a5b1b5d 100644 --- a/src/test/ui/borrowck/borrowck-uninit-field-access.stderr +++ b/src/test/ui/borrowck/borrowck-uninit-field-access.stderr @@ -14,15 +14,15 @@ LL | let _ = line1.origin.x + 1; | = note: move occurs because `line1.origin` has type `Point`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `line2` +error[E0382]: use of partially moved value: `line2` --> $DIR/borrowck-uninit-field-access.rs:29:5 | LL | let _moved = (line2.origin, line2.middle); - | ------------ value moved here + | ------------ value partially moved here LL | line2.consume(); | ^^^^^ value used here after partial move | - = note: move occurs because `line2.middle` has type `Point`, which does not implement the `Copy` trait + = note: partial move occurs because `line2.middle` has type `Point`, which does not implement the `Copy` trait error: aborting due to 3 previous errors diff --git a/src/test/ui/borrowck/move-in-pattern-mut.rs b/src/test/ui/borrowck/move-in-pattern-mut.rs index 175eb3b7a04..b5c275bf28c 100644 --- a/src/test/ui/borrowck/move-in-pattern-mut.rs +++ b/src/test/ui/borrowck/move-in-pattern-mut.rs @@ -15,9 +15,9 @@ fn main() { if let Some(mut x) = s { x = S; } - foo(s); //~ ERROR use of moved value: `s` + foo(s); //~ ERROR use of partially moved value: `s` let mut e = E::V { s: S }; let E::V { s: mut x } = e; x = S; - bar(e); //~ ERROR use of moved value: `e` + bar(e); //~ ERROR use of partially moved value: `e` } diff --git a/src/test/ui/borrowck/move-in-pattern-mut.stderr b/src/test/ui/borrowck/move-in-pattern-mut.stderr index 391638444c3..17bc5492756 100644 --- a/src/test/ui/borrowck/move-in-pattern-mut.stderr +++ b/src/test/ui/borrowck/move-in-pattern-mut.stderr @@ -1,28 +1,28 @@ -error[E0382]: use of moved value: `s` +error[E0382]: use of partially moved value: `s` --> $DIR/move-in-pattern-mut.rs:18:9 | LL | if let Some(mut x) = s { - | ----- value moved here + | ----- value partially moved here ... LL | foo(s); | ^ value used here after partial move | - = note: move occurs because value has type `S`, which does not implement the `Copy` trait + = note: partial move occurs because value has type `S`, which does not implement the `Copy` trait help: borrow this field in the pattern to avoid moving `s.0` | LL | if let Some(ref mut x) = s { | ^^^ -error[E0382]: use of moved value: `e` +error[E0382]: use of partially moved value: `e` --> $DIR/move-in-pattern-mut.rs:22:9 | LL | let E::V { s: mut x } = e; - | ----- value moved here + | ----- value partially moved here LL | x = S; LL | bar(e); | ^ value used here after partial move | - = note: move occurs because value has type `S`, which does not implement the `Copy` trait + = note: partial move occurs because value has type `S`, which does not implement the `Copy` trait help: borrow this field in the pattern to avoid moving `e.s` | LL | let E::V { s: ref mut x } = e; diff --git a/src/test/ui/borrowck/move-in-pattern.fixed b/src/test/ui/borrowck/move-in-pattern.fixed index f55fdcc5f90..145893d3343 100644 --- a/src/test/ui/borrowck/move-in-pattern.fixed +++ b/src/test/ui/borrowck/move-in-pattern.fixed @@ -16,9 +16,9 @@ fn main() { if let Some(ref x) = s { let _ = x; } - foo(s); //~ ERROR use of moved value: `s` + foo(s); //~ ERROR use of partially moved value: `s` let e = E::V { s: S }; let E::V { s: ref x } = e; let _ = x; - bar(e); //~ ERROR use of moved value: `e` + bar(e); //~ ERROR use of partially moved value: `e` } diff --git a/src/test/ui/borrowck/move-in-pattern.rs b/src/test/ui/borrowck/move-in-pattern.rs index 7ad04b9490c..14851d0f6fc 100644 --- a/src/test/ui/borrowck/move-in-pattern.rs +++ b/src/test/ui/borrowck/move-in-pattern.rs @@ -16,9 +16,9 @@ fn main() { if let Some(x) = s { let _ = x; } - foo(s); //~ ERROR use of moved value: `s` + foo(s); //~ ERROR use of partially moved value: `s` let e = E::V { s: S }; let E::V { s: x } = e; let _ = x; - bar(e); //~ ERROR use of moved value: `e` + bar(e); //~ ERROR use of partially moved value: `e` } diff --git a/src/test/ui/borrowck/move-in-pattern.stderr b/src/test/ui/borrowck/move-in-pattern.stderr index c5cb24455eb..21ba92f1fc4 100644 --- a/src/test/ui/borrowck/move-in-pattern.stderr +++ b/src/test/ui/borrowck/move-in-pattern.stderr @@ -1,28 +1,28 @@ -error[E0382]: use of moved value: `s` +error[E0382]: use of partially moved value: `s` --> $DIR/move-in-pattern.rs:19:9 | LL | if let Some(x) = s { - | - value moved here + | - value partially moved here ... LL | foo(s); | ^ value used here after partial move | - = note: move occurs because value has type `S`, which does not implement the `Copy` trait + = note: partial move occurs because value has type `S`, which does not implement the `Copy` trait help: borrow this field in the pattern to avoid moving `s.0` | LL | if let Some(ref x) = s { | ^^^ -error[E0382]: use of moved value: `e` +error[E0382]: use of partially moved value: `e` --> $DIR/move-in-pattern.rs:23:9 | LL | let E::V { s: x } = e; - | - value moved here + | - value partially moved here LL | let _ = x; LL | bar(e); | ^ value used here after partial move | - = note: move occurs because value has type `S`, which does not implement the `Copy` trait + = note: partial move occurs because value has type `S`, which does not implement the `Copy` trait help: borrow this field in the pattern to avoid moving `e.s` | LL | let E::V { s: ref x } = e; diff --git a/src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.stderr b/src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.stderr index a60be6f23c4..2c1c3c2dc96 100644 --- a/src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.stderr +++ b/src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.stderr @@ -2,9 +2,9 @@ error[E0592]: duplicate definitions with name `f` --> $DIR/coherence-overlapping-inherent-impl-trait.rs:4:14 | LL | impl dyn C { fn f() {} } - | ^^^^^^^^^ duplicate definitions for `f` + | ^^^^^^ duplicate definitions for `f` LL | impl dyn C { fn f() {} } - | --------- other definition for `f` + | ------ other definition for `f` error: aborting due to previous error diff --git a/src/test/ui/codemap_tests/overlapping_inherent_impls.stderr b/src/test/ui/codemap_tests/overlapping_inherent_impls.stderr index 8fe24bae7c6..6fca12e1823 100644 --- a/src/test/ui/codemap_tests/overlapping_inherent_impls.stderr +++ b/src/test/ui/codemap_tests/overlapping_inherent_impls.stderr @@ -2,28 +2,28 @@ error[E0592]: duplicate definitions with name `id` --> $DIR/overlapping_inherent_impls.rs:9:5 | LL | fn id() {} - | ^^^^^^^^^^ duplicate definitions for `id` + | ^^^^^^^ duplicate definitions for `id` ... LL | fn id() {} - | ---------- other definition for `id` + | ------- other definition for `id` error[E0592]: duplicate definitions with name `bar` --> $DIR/overlapping_inherent_impls.rs:19:5 | LL | fn bar(&self) {} - | ^^^^^^^^^^^^^^^^ duplicate definitions for `bar` + | ^^^^^^^^^^^^^ duplicate definitions for `bar` ... LL | fn bar(&self) {} - | ---------------- other definition for `bar` + | ------------- other definition for `bar` error[E0592]: duplicate definitions with name `baz` --> $DIR/overlapping_inherent_impls.rs:29:5 | LL | fn baz(&self) {} - | ^^^^^^^^^^^^^^^^ duplicate definitions for `baz` + | ^^^^^^^^^^^^^ duplicate definitions for `baz` ... LL | fn baz(&self) {} - | ---------------- other definition for `baz` + | ------------- other definition for `baz` | = note: upstream crates may add a new impl of trait `std::marker::Copy` for type `std::vec::Vec<_>` in future versions diff --git a/src/test/ui/coherence/coherence-inherited-subtyping.old.stderr b/src/test/ui/coherence/coherence-inherited-subtyping.old.stderr index 6ea0b89be74..4701bc0b139 100644 --- a/src/test/ui/coherence/coherence-inherited-subtyping.old.stderr +++ b/src/test/ui/coherence/coherence-inherited-subtyping.old.stderr @@ -2,10 +2,10 @@ error[E0592]: duplicate definitions with name `method1` --> $DIR/coherence-inherited-subtyping.rs:14:5 | LL | fn method1(&self) {} - | ^^^^^^^^^^^^^^^^^^^^ duplicate definitions for `method1` + | ^^^^^^^^^^^^^^^^^ duplicate definitions for `method1` ... LL | fn method1(&self) {} - | -------------------- other definition for `method1` + | ----------------- other definition for `method1` | = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details diff --git a/src/test/ui/coherence/coherence-inherited-subtyping.re.stderr b/src/test/ui/coherence/coherence-inherited-subtyping.re.stderr index 6ea0b89be74..4701bc0b139 100644 --- a/src/test/ui/coherence/coherence-inherited-subtyping.re.stderr +++ b/src/test/ui/coherence/coherence-inherited-subtyping.re.stderr @@ -2,10 +2,10 @@ error[E0592]: duplicate definitions with name `method1` --> $DIR/coherence-inherited-subtyping.rs:14:5 | LL | fn method1(&self) {} - | ^^^^^^^^^^^^^^^^^^^^ duplicate definitions for `method1` + | ^^^^^^^^^^^^^^^^^ duplicate definitions for `method1` ... LL | fn method1(&self) {} - | -------------------- other definition for `method1` + | ----------------- other definition for `method1` | = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details diff --git a/src/test/ui/coherence/coherence-overlap-downstream-inherent.stderr b/src/test/ui/coherence/coherence-overlap-downstream-inherent.stderr index 4cb7390453c..bbce4b530b4 100644 --- a/src/test/ui/coherence/coherence-overlap-downstream-inherent.stderr +++ b/src/test/ui/coherence/coherence-overlap-downstream-inherent.stderr @@ -2,19 +2,19 @@ error[E0592]: duplicate definitions with name `dummy` --> $DIR/coherence-overlap-downstream-inherent.rs:7:26 | LL | impl Sweet { fn dummy(&self) { } } - | ^^^^^^^^^^^^^^^^^^^ duplicate definitions for `dummy` + | ^^^^^^^^^^^^^^^ duplicate definitions for `dummy` LL | LL | impl Sweet { fn dummy(&self) { } } - | ------------------- other definition for `dummy` + | --------------- other definition for `dummy` error[E0592]: duplicate definitions with name `f` --> $DIR/coherence-overlap-downstream-inherent.rs:13:38 | LL | impl A where T: Bar { fn f(&self) {} } - | ^^^^^^^^^^^^^^ duplicate definitions for `f` + | ^^^^^^^^^^^ duplicate definitions for `f` LL | LL | impl A { fn f(&self) {} } - | -------------- other definition for `f` + | ----------- other definition for `f` | = note: downstream crates may implement trait `Bar<_>` for type `i32` diff --git a/src/test/ui/coherence/coherence-overlap-issue-23516-inherent.stderr b/src/test/ui/coherence/coherence-overlap-issue-23516-inherent.stderr index e63f8a997af..3ad818cbc36 100644 --- a/src/test/ui/coherence/coherence-overlap-issue-23516-inherent.stderr +++ b/src/test/ui/coherence/coherence-overlap-issue-23516-inherent.stderr @@ -2,10 +2,10 @@ error[E0592]: duplicate definitions with name `dummy` --> $DIR/coherence-overlap-issue-23516-inherent.rs:9:25 | LL | impl Cake { fn dummy(&self) { } } - | ^^^^^^^^^^^^^^^^^^^ duplicate definitions for `dummy` + | ^^^^^^^^^^^^^^^ duplicate definitions for `dummy` LL | LL | impl Cake> { fn dummy(&self) { } } - | ------------------- other definition for `dummy` + | --------------- other definition for `dummy` | = note: downstream crates may implement trait `Sugar` for type `std::boxed::Box<_>` diff --git a/src/test/ui/coherence/coherence-overlap-upstream-inherent.stderr b/src/test/ui/coherence/coherence-overlap-upstream-inherent.stderr index 51316f24975..f355c6e855c 100644 --- a/src/test/ui/coherence/coherence-overlap-upstream-inherent.stderr +++ b/src/test/ui/coherence/coherence-overlap-upstream-inherent.stderr @@ -2,10 +2,10 @@ error[E0592]: duplicate definitions with name `dummy` --> $DIR/coherence-overlap-upstream-inherent.rs:12:32 | LL | impl A where T: Remote { fn dummy(&self) { } } - | ^^^^^^^^^^^^^^^^^^^ duplicate definitions for `dummy` + | ^^^^^^^^^^^^^^^ duplicate definitions for `dummy` LL | LL | impl A { fn dummy(&self) { } } - | ------------------- other definition for `dummy` + | --------------- other definition for `dummy` | = note: upstream crates may add a new impl of trait `coherence_lib::Remote` for type `i16` in future versions diff --git a/src/test/ui/consts/const-eval/const-eval-query-stack.rs b/src/test/ui/consts/const-eval/const-eval-query-stack.rs new file mode 100644 index 00000000000..8a6f7de1c9f --- /dev/null +++ b/src/test/ui/consts/const-eval/const-eval-query-stack.rs @@ -0,0 +1,22 @@ +// compile-flags: -Ztreat-err-as-bug +// build-fail +// failure-status: 101 +// rustc-env:RUST_BACKTRACE=1 +// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> "" +// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> "" +// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> "" +// normalize-stderr-test "note: compiler flags.*\n\n" -> "" +// normalize-stderr-test "note: rustc.*running on.*\n\n" -> "" +// normalize-stderr-test "thread.*panicked.*\n" -> "" +// normalize-stderr-test "stack backtrace:\n" -> "" +// normalize-stderr-test "\s\d{1,}: .*\n" -> "" +// normalize-stderr-test "\s at .*\n" -> "" +// normalize-stderr-test ".*note: Some details.*\n" -> "" + +#![allow(unconditional_panic)] + +fn main() { + let x: &'static i32 = &(1 / 0); + //~^ ERROR reaching this expression at runtime will panic or abort [const_err] + println!("x={}", x); +} diff --git a/src/test/ui/consts/const-eval/const-eval-query-stack.stderr b/src/test/ui/consts/const-eval/const-eval-query-stack.stderr new file mode 100644 index 00000000000..dc2661ee796 --- /dev/null +++ b/src/test/ui/consts/const-eval/const-eval-query-stack.stderr @@ -0,0 +1,18 @@ +error: reaching this expression at runtime will panic or abort + --> $DIR/const-eval-query-stack.rs:19:28 + | +LL | let x: &'static i32 = &(1 / 0); + | -^^^^^^^ + | | + | dividing by zero + | + = note: `#[deny(const_err)]` on by default + +query stack during panic: +#0 [const_eval_raw] const-evaluating `main::promoted[1]` +#1 [const_eval_validated] const-evaluating + checking `main::promoted[1]` +#2 [const_eval_validated] const-evaluating + checking `main::promoted[1]` +#3 [normalize_generic_arg_after_erasing_regions] normalizing `main::promoted[1]` +#4 [optimized_mir] optimizing MIR for `main` +#5 [collect_and_partition_mono_items] collect_and_partition_mono_items +end of query stack diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr index 7f6af051e17..a9e2bcdbdd1 100644 --- a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr @@ -1,4 +1,4 @@ -error[E0723]: can only call other `const fn` within a `const fn`, but `const regular_in_block` is not stable as `const fn` +error[E0723]: can only call other `const fn` within a `const fn`, but `regular_in_block` is not stable as `const fn` --> $DIR/const-extern-fn-call-extern-fn.rs:9:9 | LL | regular_in_block(); @@ -7,7 +7,7 @@ LL | regular_in_block(); = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: can only call other `const fn` within a `const fn`, but `const regular` is not stable as `const fn` +error[E0723]: can only call other `const fn` within a `const fn`, but `regular` is not stable as `const fn` --> $DIR/const-extern-fn-call-extern-fn.rs:18:9 | LL | regular(); diff --git a/src/test/ui/consts/const-float-bits-conv.rs b/src/test/ui/consts/const-float-bits-conv.rs new file mode 100644 index 00000000000..2dfc6de8597 --- /dev/null +++ b/src/test/ui/consts/const-float-bits-conv.rs @@ -0,0 +1,93 @@ +// compile-flags: -Zmir-opt-level=0 +// run-pass + +#![feature(const_panic)] +#![feature(const_float_bits_conv)] +#![feature(const_float_classify)] + +// Don't promote +const fn nop(x: T) -> T { x } + +macro_rules! const_assert { + ($a:expr) => { + { + const _: () = assert!($a); + assert!(nop($a)); + } + }; + ($a:expr, $b:expr) => { + { + const _: () = assert!($a == $b); + assert_eq!(nop($a), nop($b)); + } + }; +} + +fn f32() { + const_assert!((1f32).to_bits(), 0x3f800000); + const_assert!(u32::from_be_bytes(1f32.to_be_bytes()), 0x3f800000); + const_assert!((12.5f32).to_bits(), 0x41480000); + const_assert!(u32::from_le_bytes(12.5f32.to_le_bytes()), 0x41480000); + const_assert!((1337f32).to_bits(), 0x44a72000); + const_assert!(u32::from_ne_bytes(1337f32.to_ne_bytes()), 0x44a72000); + const_assert!((-14.25f32).to_bits(), 0xc1640000); + const_assert!(f32::from_bits(0x3f800000), 1.0); + const_assert!(f32::from_be_bytes(0x3f800000u32.to_be_bytes()), 1.0); + const_assert!(f32::from_bits(0x41480000), 12.5); + const_assert!(f32::from_le_bytes(0x41480000u32.to_le_bytes()), 12.5); + const_assert!(f32::from_bits(0x44a72000), 1337.0); + const_assert!(f32::from_ne_bytes(0x44a72000u32.to_ne_bytes()), 1337.0); + const_assert!(f32::from_bits(0xc1640000), -14.25); + + // Check that NaNs roundtrip their bits regardless of signalingness + // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits + const MASKED_NAN1: u32 = f32::NAN.to_bits() ^ 0x002A_AAAA; + const MASKED_NAN2: u32 = f32::NAN.to_bits() ^ 0x0055_5555; + + const_assert!(f32::from_bits(MASKED_NAN1).is_nan()); + const_assert!(f32::from_bits(MASKED_NAN1).is_nan()); + + // LLVM does not guarantee that loads and stores of NaNs preserve their exact bit pattern. + // In practice, this seems to only cause a problem on x86, since the most widely used calling + // convention mandates that floating point values are returned on the x87 FPU stack. See #73328. + if !cfg!(target_arch = "x86") { + const_assert!(f32::from_bits(MASKED_NAN1).to_bits(), MASKED_NAN1); + const_assert!(f32::from_bits(MASKED_NAN2).to_bits(), MASKED_NAN2); + } +} + +fn f64() { + const_assert!((1f64).to_bits(), 0x3ff0000000000000); + const_assert!(u64::from_be_bytes(1f64.to_be_bytes()), 0x3ff0000000000000); + const_assert!((12.5f64).to_bits(), 0x4029000000000000); + const_assert!(u64::from_le_bytes(12.5f64.to_le_bytes()), 0x4029000000000000); + const_assert!((1337f64).to_bits(), 0x4094e40000000000); + const_assert!(u64::from_ne_bytes(1337f64.to_ne_bytes()), 0x4094e40000000000); + const_assert!((-14.25f64).to_bits(), 0xc02c800000000000); + const_assert!(f64::from_bits(0x3ff0000000000000), 1.0); + const_assert!(f64::from_be_bytes(0x3ff0000000000000u64.to_be_bytes()), 1.0); + const_assert!(f64::from_bits(0x4029000000000000), 12.5); + const_assert!(f64::from_le_bytes(0x4029000000000000u64.to_le_bytes()), 12.5); + const_assert!(f64::from_bits(0x4094e40000000000), 1337.0); + const_assert!(f64::from_ne_bytes(0x4094e40000000000u64.to_ne_bytes()), 1337.0); + const_assert!(f64::from_bits(0xc02c800000000000), -14.25); + + // Check that NaNs roundtrip their bits regardless of signalingness + // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits + const MASKED_NAN1: u64 = f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA; + const MASKED_NAN2: u64 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555; + + const_assert!(f64::from_bits(MASKED_NAN1).is_nan()); + const_assert!(f64::from_bits(MASKED_NAN1).is_nan()); + + // See comment above. + if !cfg!(target_arch = "x86") { + const_assert!(f64::from_bits(MASKED_NAN1).to_bits(), MASKED_NAN1); + const_assert!(f64::from_bits(MASKED_NAN2).to_bits(), MASKED_NAN2); + } +} + +fn main() { + f32(); + f64(); +} diff --git a/src/test/ui/consts/const-float-classify.rs b/src/test/ui/consts/const-float-classify.rs new file mode 100644 index 00000000000..36fec9976be --- /dev/null +++ b/src/test/ui/consts/const-float-classify.rs @@ -0,0 +1,77 @@ +// compile-flags: -Zmir-opt-level=0 +// run-pass + +#![feature(const_panic)] +#![feature(const_float_bits_conv)] +#![feature(const_float_classify)] +#![feature(const_trait_impl)] +#![allow(incomplete_features)] + +// Don't promote +const fn nop(x: T) -> T { x } + +macro_rules! const_assert { + ($a:expr, $b:expr) => { + { + const _: () = assert!($a == $b); + assert_eq!(nop($a), nop($b)); + } + }; +} + +macro_rules! suite { + ( $( $tt:tt )* ) => { + fn f32() { + suite_inner!(f32 $($tt)*); + } + + fn f64() { + suite_inner!(f64 $($tt)*); + } + } + +} + +macro_rules! suite_inner { + ( + $ty:ident [$( $fn:ident ),*] + $val:expr => [$($out:ident),*] + + $( $tail:tt )* + ) => { + $( const_assert!($ty::$fn($val), $out); )* + suite_inner!($ty [$($fn),*] $($tail)*) + }; + + ( $ty:ident [$( $fn:ident ),*]) => {}; +} + +#[derive(Debug)] +struct NonDet; + +impl const PartialEq for bool { + fn eq(&self, _: &NonDet) -> bool { + true + } +} + +// The result of the `is_sign` methods are not checked for correctness, since LLVM does not +// guarantee anything about the signedness of NaNs. See +// https://github.com/rust-lang/rust/issues/55131. + +suite! { + [is_nan, is_infinite, is_finite, is_normal, is_sign_positive, is_sign_negative] + -0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] + 0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] + 1.0 => [ false, false, true, true, true, false] + -1.0 => [ false, false, true, true, false, true] + 0.0 => [ false, false, true, false, true, false] + -0.0 => [ false, false, true, false, false, true] + 1.0 / 0.0 => [ false, true, false, false, true, false] + -1.0 / 0.0 => [ false, true, false, false, false, true] +} + +fn main() { + f32(); + f64(); +} diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr index b82ae40d687..bef4f240eeb 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr @@ -1,4 +1,4 @@ -error[E0723]: can only call other `const fn` within a `const fn`, but `const foo` is not stable as `const fn` +error[E0723]: can only call other `const fn` within a `const fn`, but `foo` is not stable as `const fn` --> $DIR/min_const_fn_libstd_stability.rs:16:25 | LL | const fn bar() -> u32 { foo() } @@ -7,7 +7,7 @@ LL | const fn bar() -> u32 { foo() } = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: can only call other `const fn` within a `const fn`, but `const foo2` is not stable as `const fn` +error[E0723]: can only call other `const fn` within a `const fn`, but `foo2` is not stable as `const fn` --> $DIR/min_const_fn_libstd_stability.rs:24:26 | LL | const fn bar2() -> u32 { foo2() } @@ -25,7 +25,7 @@ LL | const fn bar3() -> u32 { (5f32 + 6f32) as u32 } = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: can only call other `const fn` within a `const fn`, but `const foo2_gated` is not stable as `const fn` +error[E0723]: can only call other `const fn` within a `const fn`, but `foo2_gated` is not stable as `const fn` --> $DIR/min_const_fn_libstd_stability.rs:38:32 | LL | const fn bar2_gated() -> u32 { foo2_gated() } diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr index 00975a80b22..c5ff340dfc6 100644 --- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr @@ -1,4 +1,4 @@ -error[E0723]: can only call other `const fn` within a `const fn`, but `const foo` is not stable as `const fn` +error[E0723]: can only call other `const fn` within a `const fn`, but `foo` is not stable as `const fn` --> $DIR/min_const_unsafe_fn_libstd_stability.rs:16:41 | LL | const unsafe fn bar() -> u32 { unsafe { foo() } } @@ -7,7 +7,7 @@ LL | const unsafe fn bar() -> u32 { unsafe { foo() } } = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: can only call other `const fn` within a `const fn`, but `const foo2` is not stable as `const fn` +error[E0723]: can only call other `const fn` within a `const fn`, but `foo2` is not stable as `const fn` --> $DIR/min_const_unsafe_fn_libstd_stability.rs:24:42 | LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } } @@ -25,7 +25,7 @@ LL | const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: can only call other `const fn` within a `const fn`, but `const foo2_gated` is not stable as `const fn` +error[E0723]: can only call other `const fn` within a `const fn`, but `foo2_gated` is not stable as `const fn` --> $DIR/min_const_unsafe_fn_libstd_stability.rs:38:48 | LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr index 5014eed06fa..31ad12c9551 100644 --- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr @@ -1,4 +1,4 @@ -error[E0723]: can only call other `const fn` within a `const fn`, but `const foo` is not stable as `const fn` +error[E0723]: can only call other `const fn` within a `const fn`, but `foo` is not stable as `const fn` --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:16:32 | LL | const unsafe fn bar() -> u32 { foo() } @@ -7,7 +7,7 @@ LL | const unsafe fn bar() -> u32 { foo() } = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: can only call other `const fn` within a `const fn`, but `const foo2` is not stable as `const fn` +error[E0723]: can only call other `const fn` within a `const fn`, but `foo2` is not stable as `const fn` --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:24:33 | LL | const unsafe fn bar2() -> u32 { foo2() } @@ -16,7 +16,7 @@ LL | const unsafe fn bar2() -> u32 { foo2() } = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: can only call other `const fn` within a `const fn`, but `const foo2_gated` is not stable as `const fn` +error[E0723]: can only call other `const fn` within a `const fn`, but `foo2_gated` is not stable as `const fn` --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:33:39 | LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() } diff --git a/src/test/ui/consts/offset.rs b/src/test/ui/consts/offset.rs index f64242d568e..a491f1c92d3 100644 --- a/src/test/ui/consts/offset.rs +++ b/src/test/ui/consts/offset.rs @@ -1,7 +1,6 @@ // run-pass #![feature(const_ptr_offset)] #![feature(const_ptr_offset_from)] -#![feature(ptr_offset_from)] use std::ptr; #[repr(C)] diff --git a/src/test/ui/consts/offset_from.rs b/src/test/ui/consts/offset_from.rs index 8c1b2784262..8d501e0d953 100644 --- a/src/test/ui/consts/offset_from.rs +++ b/src/test/ui/consts/offset_from.rs @@ -2,7 +2,6 @@ #![feature(const_raw_ptr_deref)] #![feature(const_ptr_offset_from)] -#![feature(ptr_offset_from)] struct Struct { field: (), diff --git a/src/test/ui/consts/offset_from_ub.rs b/src/test/ui/consts/offset_from_ub.rs index a7902f20467..b73191d56a6 100644 --- a/src/test/ui/consts/offset_from_ub.rs +++ b/src/test/ui/consts/offset_from_ub.rs @@ -1,6 +1,5 @@ #![feature(const_raw_ptr_deref)] #![feature(const_ptr_offset_from)] -#![feature(ptr_offset_from)] #[repr(C)] struct Struct { diff --git a/src/test/ui/consts/offset_from_ub.stderr b/src/test/ui/consts/offset_from_ub.stderr index bd57e68e137..a89dcefd839 100644 --- a/src/test/ui/consts/offset_from_ub.stderr +++ b/src/test/ui/consts/offset_from_ub.stderr @@ -6,9 +6,9 @@ LL | unsafe { intrinsics::ptr_offset_from(self, origin) } | | | ptr_offset_from cannot compute offset of pointers into different allocations. | inside `std::ptr::const_ptr::::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL - | inside `DIFFERENT_ALLOC` at $DIR/offset_from_ub.rs:17:27 + | inside `DIFFERENT_ALLOC` at $DIR/offset_from_ub.rs:16:27 | - ::: $DIR/offset_from_ub.rs:11:1 + ::: $DIR/offset_from_ub.rs:10:1 | LL | / pub const DIFFERENT_ALLOC: usize = { LL | | @@ -29,9 +29,9 @@ LL | unsafe { intrinsics::ptr_offset_from(self, origin) } | | | unable to turn bytes into a pointer | inside `std::ptr::const_ptr::::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL - | inside `NOT_PTR` at $DIR/offset_from_ub.rs:23:14 + | inside `NOT_PTR` at $DIR/offset_from_ub.rs:22:14 | - ::: $DIR/offset_from_ub.rs:21:1 + ::: $DIR/offset_from_ub.rs:20:1 | LL | / pub const NOT_PTR: usize = { LL | | @@ -47,9 +47,9 @@ LL | unsafe { intrinsics::ptr_offset_from(self, origin) } | | | exact_div: 1_isize cannot be divided by 2_isize without remainder | inside `std::ptr::const_ptr::::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL - | inside `NOT_MULTIPLE_OF_SIZE` at $DIR/offset_from_ub.rs:31:14 + | inside `NOT_MULTIPLE_OF_SIZE` at $DIR/offset_from_ub.rs:30:14 | - ::: $DIR/offset_from_ub.rs:26:1 + ::: $DIR/offset_from_ub.rs:25:1 | LL | / pub const NOT_MULTIPLE_OF_SIZE: isize = { LL | | @@ -68,9 +68,9 @@ LL | unsafe { intrinsics::ptr_offset_from(self, origin) } | | | inbounds test failed: 0x0 is not a valid pointer | inside `std::ptr::const_ptr::::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL - | inside `OFFSET_FROM_NULL` at $DIR/offset_from_ub.rs:37:14 + | inside `OFFSET_FROM_NULL` at $DIR/offset_from_ub.rs:36:14 | - ::: $DIR/offset_from_ub.rs:34:1 + ::: $DIR/offset_from_ub.rs:33:1 | LL | / pub const OFFSET_FROM_NULL: isize = { LL | | @@ -87,9 +87,9 @@ LL | unsafe { intrinsics::ptr_offset_from(self, origin) } | | | unable to turn bytes into a pointer | inside `std::ptr::const_ptr::::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL - | inside `DIFFERENT_INT` at $DIR/offset_from_ub.rs:44:14 + | inside `DIFFERENT_INT` at $DIR/offset_from_ub.rs:43:14 | - ::: $DIR/offset_from_ub.rs:40:1 + ::: $DIR/offset_from_ub.rs:39:1 | LL | / pub const DIFFERENT_INT: isize = { // offset_from with two different integers: like DIFFERENT_ALLOC LL | | diff --git a/src/test/ui/duplicate/dupe-symbols-1.stderr b/src/test/ui/duplicate/dupe-symbols-1.stderr index cca8b4d25da..933ed5e89e5 100644 --- a/src/test/ui/duplicate/dupe-symbols-1.stderr +++ b/src/test/ui/duplicate/dupe-symbols-1.stderr @@ -1,10 +1,8 @@ error: symbol `fail` is already defined --> $DIR/dupe-symbols-1.rs:12:1 | -LL | / pub fn b() { -LL | | -LL | | } - | |_^ +LL | pub fn b() { + | ^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/duplicate/dupe-symbols-2.stderr b/src/test/ui/duplicate/dupe-symbols-2.stderr index 017aade3129..1b29edfb655 100644 --- a/src/test/ui/duplicate/dupe-symbols-2.stderr +++ b/src/test/ui/duplicate/dupe-symbols-2.stderr @@ -1,10 +1,8 @@ error: symbol `fail` is already defined --> $DIR/dupe-symbols-2.rs:15:5 | -LL | / pub extern fn fail() { -LL | | -LL | | } - | |_____^ +LL | pub extern fn fail() { + | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/duplicate/dupe-symbols-3.stderr b/src/test/ui/duplicate/dupe-symbols-3.stderr index 2e2ac3a98b8..6300b4908d1 100644 --- a/src/test/ui/duplicate/dupe-symbols-3.stderr +++ b/src/test/ui/duplicate/dupe-symbols-3.stderr @@ -1,10 +1,8 @@ error: symbol `fail` is already defined --> $DIR/dupe-symbols-3.rs:12:1 | -LL | / pub fn fail() { -LL | | -LL | | } - | |_^ +LL | pub fn fail() { + | ^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/duplicate/dupe-symbols-4.stderr b/src/test/ui/duplicate/dupe-symbols-4.stderr index 10b93891b66..1407a4883e1 100644 --- a/src/test/ui/duplicate/dupe-symbols-4.stderr +++ b/src/test/ui/duplicate/dupe-symbols-4.stderr @@ -2,7 +2,7 @@ error: symbol `fail` is already defined --> $DIR/dupe-symbols-4.rs:23:5 | LL | fn fail(self) {} - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/duplicate/dupe-symbols-5.stderr b/src/test/ui/duplicate/dupe-symbols-5.stderr index ebeb19f94f6..558f868a0c6 100644 --- a/src/test/ui/duplicate/dupe-symbols-5.stderr +++ b/src/test/ui/duplicate/dupe-symbols-5.stderr @@ -1,10 +1,8 @@ error: symbol `fail` is already defined --> $DIR/dupe-symbols-5.rs:11:1 | -LL | / pub fn b() { -LL | | -LL | | } - | |_^ +LL | pub fn b() { + | ^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/duplicate/dupe-symbols-7.stderr b/src/test/ui/duplicate/dupe-symbols-7.stderr index 2ea5521e095..1455f0e75ab 100644 --- a/src/test/ui/duplicate/dupe-symbols-7.stderr +++ b/src/test/ui/duplicate/dupe-symbols-7.stderr @@ -2,7 +2,7 @@ error: entry symbol `main` declared multiple times --> $DIR/dupe-symbols-7.rs:12:1 | LL | fn main(){} - | ^^^^^^^^^^^ + | ^^^^^^^^^ | = help: did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead diff --git a/src/test/ui/duplicate/dupe-symbols-8.stderr b/src/test/ui/duplicate/dupe-symbols-8.stderr index f001201b8d0..8d6a79e12d9 100644 --- a/src/test/ui/duplicate/dupe-symbols-8.stderr +++ b/src/test/ui/duplicate/dupe-symbols-8.stderr @@ -1,13 +1,8 @@ error: entry symbol `main` declared multiple times --> $DIR/dupe-symbols-8.rs:7:1 | -LL | / fn main() { -LL | | extern "Rust" { -LL | | fn main(); -LL | | } -LL | | unsafe { main(); } -LL | | } - | |_^ +LL | fn main() { + | ^^^^^^^^^ | = help: did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead diff --git a/src/test/ui/duplicate_entry_error.stderr b/src/test/ui/duplicate_entry_error.stderr index 61cccf40ed8..6d078dfbd20 100644 --- a/src/test/ui/duplicate_entry_error.stderr +++ b/src/test/ui/duplicate_entry_error.stderr @@ -1,11 +1,8 @@ error[E0152]: found duplicate lang item `panic_impl` --> $DIR/duplicate_entry_error.rs:11:1 | -LL | / fn panic_impl(info: &PanicInfo) -> ! { -LL | | -LL | | loop {} -LL | | } - | |_^ +LL | fn panic_impl(info: &PanicInfo) -> ! { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the lang item is first defined in crate `std` (which `duplicate_entry_error` depends on) = note: first definition in `std` loaded from SYSROOT/libstd-*.rlib diff --git a/src/test/ui/error-codes/E0445.stderr b/src/test/ui/error-codes/E0445.stderr index d0d6ebe16c7..953a626bf95 100644 --- a/src/test/ui/error-codes/E0445.stderr +++ b/src/test/ui/error-codes/E0445.stderr @@ -14,7 +14,7 @@ error[E0445]: private trait `Foo` in public interface --> $DIR/E0445.rs:9:1 | LL | pub fn foo (t: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait + | ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait error: aborting due to 3 previous errors diff --git a/src/test/ui/error-codes/E0446.stderr b/src/test/ui/error-codes/E0446.stderr index a0f5f7079b3..bb009260979 100644 --- a/src/test/ui/error-codes/E0446.stderr +++ b/src/test/ui/error-codes/E0446.stderr @@ -1,13 +1,11 @@ error[E0446]: private type `foo::Bar` in public interface --> $DIR/E0446.rs:4:5 | -LL | struct Bar(u32); - | - `foo::Bar` declared as private +LL | struct Bar(u32); + | - `foo::Bar` declared as private LL | -LL | / pub fn bar() -> Bar { -LL | | Bar(0) -LL | | } - | |_____^ can't leak private type +LL | pub fn bar() -> Bar { + | ^^^^^^^^^^^^^^^^^^^ can't leak private type error: aborting due to previous error diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr index 94837556610..2bf78d12290 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr @@ -1,14 +1,8 @@ error: fatal error triggered by #[rustc_error] --> $DIR/hr-subtype.rs:102:1 | -LL | / fn main() { -LL | | -LL | | -LL | | -... | -LL | | -LL | | } - | |_^ +LL | fn main() { + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr index 94837556610..2bf78d12290 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr @@ -1,14 +1,8 @@ error: fatal error triggered by #[rustc_error] --> $DIR/hr-subtype.rs:102:1 | -LL | / fn main() { -LL | | -LL | | -LL | | -... | -LL | | -LL | | } - | |_^ +LL | fn main() { + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr index 94837556610..2bf78d12290 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr @@ -1,14 +1,8 @@ error: fatal error triggered by #[rustc_error] --> $DIR/hr-subtype.rs:102:1 | -LL | / fn main() { -LL | | -LL | | -LL | | -... | -LL | | -LL | | } - | |_^ +LL | fn main() { + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr index 94837556610..2bf78d12290 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr @@ -1,14 +1,8 @@ error: fatal error triggered by #[rustc_error] --> $DIR/hr-subtype.rs:102:1 | -LL | / fn main() { -LL | | -LL | | -LL | | -... | -LL | | -LL | | } - | |_^ +LL | fn main() { + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr index 94837556610..2bf78d12290 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr @@ -1,14 +1,8 @@ error: fatal error triggered by #[rustc_error] --> $DIR/hr-subtype.rs:102:1 | -LL | / fn main() { -LL | | -LL | | -LL | | -... | -LL | | -LL | | } - | |_^ +LL | fn main() { + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr index 94837556610..2bf78d12290 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr @@ -1,14 +1,8 @@ error: fatal error triggered by #[rustc_error] --> $DIR/hr-subtype.rs:102:1 | -LL | / fn main() { -LL | | -LL | | -LL | | -... | -LL | | -LL | | } - | |_^ +LL | fn main() { + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr index 94837556610..2bf78d12290 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr @@ -1,14 +1,8 @@ error: fatal error triggered by #[rustc_error] --> $DIR/hr-subtype.rs:102:1 | -LL | / fn main() { -LL | | -LL | | -LL | | -... | -LL | | -LL | | } - | |_^ +LL | fn main() { + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr index 94837556610..2bf78d12290 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr @@ -1,14 +1,8 @@ error: fatal error triggered by #[rustc_error] --> $DIR/hr-subtype.rs:102:1 | -LL | / fn main() { -LL | | -LL | | -LL | | -... | -LL | | -LL | | } - | |_^ +LL | fn main() { + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr index 94837556610..2bf78d12290 100644 --- a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr @@ -1,14 +1,8 @@ error: fatal error triggered by #[rustc_error] --> $DIR/hr-subtype.rs:102:1 | -LL | / fn main() { -LL | | -LL | | -LL | | -... | -LL | | -LL | | } - | |_^ +LL | fn main() { + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/hrtb/issue-58451.stderr b/src/test/ui/hrtb/issue-58451.stderr index c0915808bf5..bd08fc1bfae 100644 --- a/src/test/ui/hrtb/issue-58451.stderr +++ b/src/test/ui/hrtb/issue-58451.stderr @@ -5,8 +5,7 @@ LL | / fn f(i: I) LL | | where LL | | I: IntoIterator, LL | | I::Item: for<'a> Into<&'a ()>, -LL | | {} - | |__- defined here + | |__________________________________- defined here ... LL | f(&[f()]); | ^-- supplied 0 arguments diff --git a/src/test/ui/infinite/infinite-instantiation.stderr b/src/test/ui/infinite/infinite-instantiation.stderr index 7b22393ee7c..eb07d8905d6 100644 --- a/src/test/ui/infinite/infinite-instantiation.stderr +++ b/src/test/ui/infinite/infinite-instantiation.stderr @@ -7,13 +7,8 @@ LL | function(counter - 1, t.to_option()); note: `function` defined here --> $DIR/infinite-instantiation.rs:19:1 | -LL | / fn function(counter: usize, t: T) { -LL | | if counter > 0 { -LL | | function(counter - 1, t.to_option()); -LL | | -LL | | } -LL | | } - | |_^ +LL | fn function(counter: usize, t: T) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-16683.stderr b/src/test/ui/issues/issue-16683.stderr index 4f658330758..6efc12df8fa 100644 --- a/src/test/ui/issues/issue-16683.stderr +++ b/src/test/ui/issues/issue-16683.stderr @@ -7,10 +7,8 @@ LL | self.a(); note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 3:5... --> $DIR/issue-16683.rs:3:5 | -LL | / fn b(&self) { -LL | | self.a(); -LL | | } - | |_____^ +LL | fn b(&self) { + | ^^^^^^^^^^^ note: ...so that reference does not outlive borrowed content --> $DIR/issue-16683.rs:4:9 | diff --git a/src/test/ui/issues/issue-17740.stderr b/src/test/ui/issues/issue-17740.stderr index cd1d7f821c7..9fe80232a14 100644 --- a/src/test/ui/issues/issue-17740.stderr +++ b/src/test/ui/issues/issue-17740.stderr @@ -9,14 +9,8 @@ LL | fn bar(self: &mut Foo) { note: the anonymous lifetime #2 defined on the method body at 6:5... --> $DIR/issue-17740.rs:6:5 | -LL | / fn bar(self: &mut Foo) { -LL | | -LL | | -LL | | -... | -LL | | -LL | | } - | |_____^ +LL | fn bar(self: &mut Foo) { + | ^^^^^^^^^^^^^^^^^^^^^^ note: ...does not necessarily outlive the lifetime `'a` as defined on the impl at 5:7 --> $DIR/issue-17740.rs:5:7 | @@ -39,14 +33,8 @@ LL | impl <'a> Foo<'a>{ note: ...does not necessarily outlive the anonymous lifetime #2 defined on the method body at 6:5 --> $DIR/issue-17740.rs:6:5 | -LL | / fn bar(self: &mut Foo) { -LL | | -LL | | -LL | | -... | -LL | | -LL | | } - | |_____^ +LL | fn bar(self: &mut Foo) { + | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-17758.stderr b/src/test/ui/issues/issue-17758.stderr index 31788cfa61c..f82e0f53a23 100644 --- a/src/test/ui/issues/issue-17758.stderr +++ b/src/test/ui/issues/issue-17758.stderr @@ -7,11 +7,8 @@ LL | self.foo(); note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 6:5... --> $DIR/issue-17758.rs:6:5 | -LL | / fn bar(&self) { -LL | | self.foo(); -LL | | -LL | | } - | |_____^ +LL | fn bar(&self) { + | ^^^^^^^^^^^^^ note: ...so that reference does not outlive borrowed content --> $DIR/issue-17758.rs:7:9 | diff --git a/src/test/ui/issues/issue-17905-2.stderr b/src/test/ui/issues/issue-17905-2.stderr index f347c26f066..c762a4ab496 100644 --- a/src/test/ui/issues/issue-17905-2.stderr +++ b/src/test/ui/issues/issue-17905-2.stderr @@ -9,12 +9,8 @@ LL | fn say(self: &Pair<&str, isize>) { note: the anonymous lifetime #2 defined on the method body at 8:5... --> $DIR/issue-17905-2.rs:8:5 | -LL | / fn say(self: &Pair<&str, isize>) { -LL | | -LL | | -LL | | println!("{:?}", self); -LL | | } - | |_____^ +LL | fn say(self: &Pair<&str, isize>) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...does not necessarily outlive the lifetime `'_` as defined on the impl at 5:5 --> $DIR/issue-17905-2.rs:5:5 | @@ -37,12 +33,8 @@ LL | &str, note: ...does not necessarily outlive the anonymous lifetime #2 defined on the method body at 8:5 --> $DIR/issue-17905-2.rs:8:5 | -LL | / fn say(self: &Pair<&str, isize>) { -LL | | -LL | | -LL | | println!("{:?}", self); -LL | | } - | |_____^ +LL | fn say(self: &Pair<&str, isize>) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-20831-debruijn.stderr b/src/test/ui/issues/issue-20831-debruijn.stderr index e7c1dcc5d69..1ab89e818e3 100644 --- a/src/test/ui/issues/issue-20831-debruijn.stderr +++ b/src/test/ui/issues/issue-20831-debruijn.stderr @@ -15,14 +15,8 @@ LL | | } note: the anonymous lifetime #2 defined on the method body at 28:5... --> $DIR/issue-20831-debruijn.rs:28:5 | -LL | / fn subscribe(&mut self, t : Box::Output> + 'a>) { -LL | | // Not obvious, but there is an implicit lifetime here -------^ -LL | | -LL | | -... | -LL | | self.sub = t; -LL | | } - | |_____^ +LL | fn subscribe(&mut self, t : Box::Output> + 'a>) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...does not necessarily outlive the lifetime `'a` as defined on the impl at 26:6 --> $DIR/issue-20831-debruijn.rs:26:6 | @@ -51,14 +45,8 @@ LL | impl<'a> Publisher<'a> for MyStruct<'a> { note: ...does not necessarily outlive the anonymous lifetime #2 defined on the method body at 28:5 --> $DIR/issue-20831-debruijn.rs:28:5 | -LL | / fn subscribe(&mut self, t : Box::Output> + 'a>) { -LL | | // Not obvious, but there is an implicit lifetime here -------^ -LL | | -LL | | -... | -LL | | self.sub = t; -LL | | } - | |_____^ +LL | fn subscribe(&mut self, t : Box::Output> + 'a>) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements --> $DIR/issue-20831-debruijn.rs:28:33 @@ -69,14 +57,8 @@ LL | fn subscribe(&mut self, t : Box $DIR/issue-20831-debruijn.rs:28:5 | -LL | / fn subscribe(&mut self, t : Box::Output> + 'a>) { -LL | | // Not obvious, but there is an implicit lifetime here -------^ -LL | | -LL | | -... | -LL | | self.sub = t; -LL | | } - | |_____^ +LL | fn subscribe(&mut self, t : Box::Output> + 'a>) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...but the lifetime must also be valid for the lifetime `'a` as defined on the impl at 26:6... --> $DIR/issue-20831-debruijn.rs:26:6 | @@ -99,14 +81,8 @@ LL | fn subscribe(&mut self, t : Box $DIR/issue-20831-debruijn.rs:28:5 | -LL | / fn subscribe(&mut self, t : Box::Output> + 'a>) { -LL | | // Not obvious, but there is an implicit lifetime here -------^ -LL | | -LL | | -... | -LL | | self.sub = t; -LL | | } - | |_____^ +LL | fn subscribe(&mut self, t : Box::Output> + 'a>) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...but the lifetime must also be valid for the lifetime `'a` as defined on the impl at 26:6... --> $DIR/issue-20831-debruijn.rs:26:6 | diff --git a/src/test/ui/issues/issue-21946.rs b/src/test/ui/issues/issue-21946.rs index 2d99769cfa3..0a9f8f50bdc 100644 --- a/src/test/ui/issues/issue-21946.rs +++ b/src/test/ui/issues/issue-21946.rs @@ -5,9 +5,9 @@ trait Foo { struct FooStruct; impl Foo for FooStruct { -//~^ ERROR overflow evaluating the requirement `::A` + //~^ ERROR overflow evaluating the requirement `::A == _` type A = ::A; - //~^ ERROR overflow evaluating the requirement `::A` + //~^ ERROR overflow evaluating the requirement `::A == _` } fn main() {} diff --git a/src/test/ui/issues/issue-21946.stderr b/src/test/ui/issues/issue-21946.stderr index 5ac49f61543..582ce393d7f 100644 --- a/src/test/ui/issues/issue-21946.stderr +++ b/src/test/ui/issues/issue-21946.stderr @@ -1,10 +1,10 @@ -error[E0275]: overflow evaluating the requirement `::A` +error[E0275]: overflow evaluating the requirement `::A == _` --> $DIR/issue-21946.rs:7:6 | LL | impl Foo for FooStruct { | ^^^ -error[E0275]: overflow evaluating the requirement `::A` +error[E0275]: overflow evaluating the requirement `::A == _` --> $DIR/issue-21946.rs:9:5 | LL | type A = ::A; diff --git a/src/test/ui/issues/issue-22638.stderr b/src/test/ui/issues/issue-22638.stderr index 41965d6b355..b0df46b11fa 100644 --- a/src/test/ui/issues/issue-22638.stderr +++ b/src/test/ui/issues/issue-22638.stderr @@ -1,12 +1,8 @@ error: reached the type-length limit while instantiating `D::matches::$CLOSURE` --> $DIR/issue-22638.rs:53:5 | -LL | / pub fn matches(&self, f: &F) { -LL | | -LL | | let &D(ref a) = self; -LL | | a.matches(f) -LL | | } - | |_____^ +LL | pub fn matches(&self, f: &F) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: consider adding a `#![type_length_limit="30408681"]` attribute to your crate diff --git a/src/test/ui/issues/issue-23122-1.stderr b/src/test/ui/issues/issue-23122-1.stderr index 1b752b7afe2..4e2e837c07c 100644 --- a/src/test/ui/issues/issue-23122-1.stderr +++ b/src/test/ui/issues/issue-23122-1.stderr @@ -1,10 +1,10 @@ -error[E0275]: overflow evaluating the requirement ` as Next>::Next` +error[E0275]: overflow evaluating the requirement ` as Next>::Next == _` --> $DIR/issue-23122-1.rs:7:15 | LL | impl Next for GetNext { | ^^^^ -error[E0275]: overflow evaluating the requirement ` as Next>::Next` +error[E0275]: overflow evaluating the requirement ` as Next>::Next == _` --> $DIR/issue-23122-1.rs:9:5 | LL | type Next = as Next>::Next; diff --git a/src/test/ui/issues/issue-30079.stderr b/src/test/ui/issues/issue-30079.stderr index f4a530124ff..e67f297ffa7 100644 --- a/src/test/ui/issues/issue-30079.stderr +++ b/src/test/ui/issues/issue-30079.stderr @@ -2,7 +2,7 @@ warning: private type `m1::Priv` in public interface (error E0446) --> $DIR/issue-30079.rs:6:9 | LL | pub fn f(_: Priv) {} - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ | = note: `#[warn(private_in_public)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! diff --git a/src/test/ui/issues/issue-33140.stderr b/src/test/ui/issues/issue-33140.stderr index 6c3ba63e6f6..9a900d2fc94 100644 --- a/src/test/ui/issues/issue-33140.stderr +++ b/src/test/ui/issues/issue-33140.stderr @@ -19,15 +19,11 @@ LL | impl Trait2 for dyn Sync + Send + Sync { error[E0592]: duplicate definitions with name `abc` --> $DIR/issue-33140.rs:29:5 | -LL | / fn abc() -> bool { -LL | | false -LL | | } - | |_____^ duplicate definitions for `abc` +LL | fn abc() -> bool { + | ^^^^^^^^^^^^^^^^ duplicate definitions for `abc` ... -LL | / fn abc() -> bool { -LL | | true -LL | | } - | |_____- other definition for `abc` +LL | fn abc() -> bool { + | ---------------- other definition for `abc` error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.stderr b/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.stderr index 7a4b59b5633..6229d90d4b4 100644 --- a/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.stderr +++ b/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.stderr @@ -1,10 +1,8 @@ error: reached the type-length limit while instantiating `<(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(...))))))))))))))) as Foo>::recurse` --> $DIR/issue-37311.rs:15:5 | -LL | / fn recurse(&self) { -LL | | (self, self).recurse(); -LL | | } - | |_____^ +LL | fn recurse(&self) { + | ^^^^^^^^^^^^^^^^^ | = note: consider adding a `#![type_length_limit="2097149"]` attribute to your crate diff --git a/src/test/ui/issues/issue-37884.stderr b/src/test/ui/issues/issue-37884.stderr index 703cdf08548..5baa245b3cc 100644 --- a/src/test/ui/issues/issue-37884.stderr +++ b/src/test/ui/issues/issue-37884.stderr @@ -14,13 +14,8 @@ LL | | } note: the anonymous lifetime #1 defined on the method body at 6:5... --> $DIR/issue-37884.rs:6:5 | -LL | / fn next(&'a mut self) -> Option -LL | | -LL | | -LL | | { -LL | | Some(&mut self.0) -LL | | } - | |_____^ +LL | fn next(&'a mut self) -> Option + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...does not necessarily outlive the lifetime `'a` as defined on the impl at 3:6 --> $DIR/issue-37884.rs:3:6 | diff --git a/src/test/ui/issues/issue-67552.stderr b/src/test/ui/issues/issue-67552.stderr index 3bb2016f07d..8243e52039d 100644 --- a/src/test/ui/issues/issue-67552.stderr +++ b/src/test/ui/issues/issue-67552.stderr @@ -10,11 +10,7 @@ note: `rec` defined here LL | / fn rec(mut it: T) LL | | where LL | | T: Iterator, -LL | | { -... | -LL | | } -LL | | } - | |_^ + | |________________^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-8727.stderr b/src/test/ui/issues/issue-8727.stderr index 70709fd33ac..59008151f1a 100644 --- a/src/test/ui/issues/issue-8727.stderr +++ b/src/test/ui/issues/issue-8727.stderr @@ -18,10 +18,8 @@ LL | generic::>(); note: `generic` defined here --> $DIR/issue-8727.rs:6:1 | -LL | / fn generic() { -LL | | generic::>(); -LL | | } - | |_^ +LL | fn generic() { + | ^^^^^^^^^^^^^^^ error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/lint/clashing-extern-fn.rs b/src/test/ui/lint/clashing-extern-fn.rs index d6ac7ccccc7..44cef19b0d3 100644 --- a/src/test/ui/lint/clashing-extern-fn.rs +++ b/src/test/ui/lint/clashing-extern-fn.rs @@ -285,3 +285,26 @@ mod b { } } } + +#[allow(improper_ctypes)] +mod unknown_layout { + mod a { + extern "C" { + pub fn generic(l: Link); + } + pub struct Link { + pub item: T, + pub next: *const Link, + } + } + + mod b { + extern "C" { + pub fn generic(l: Link); + } + pub struct Link { + pub item: T, + pub next: *const Link, + } + } +} diff --git a/src/test/ui/marker_trait_attr/marker-trait-with-associated-items.stderr b/src/test/ui/marker_trait_attr/marker-trait-with-associated-items.stderr index 68434c13110..ae7d5a98b08 100644 --- a/src/test/ui/marker_trait_attr/marker-trait-with-associated-items.stderr +++ b/src/test/ui/marker_trait_attr/marker-trait-with-associated-items.stderr @@ -32,7 +32,7 @@ error[E0714]: marker traits cannot have associated items --> $DIR/marker-trait-with-associated-items.rs:36:5 | LL | fn foo() {} - | ^^^^^^^^^^^ + | ^^^^^^^^ error: aborting due to 6 previous errors diff --git a/src/test/ui/match/match-incompat-type-semi.rs b/src/test/ui/match/match-incompat-type-semi.rs new file mode 100644 index 00000000000..9ab40fa3cce --- /dev/null +++ b/src/test/ui/match/match-incompat-type-semi.rs @@ -0,0 +1,42 @@ +// Diagnostic enhancement explained in issue #75418. +// Point at the last statement in the block if there's no tail expression, +// and suggest removing the semicolon if appropriate. + +fn main() { + let _ = match Some(42) { + Some(x) => { + x + }, + None => { + 0; + //~^ ERROR incompatible types + //~| HELP consider removing this semicolon + }, + }; + + let _ = if let Some(x) = Some(42) { + x + } else { + 0; + //~^ ERROR incompatible types + //~| HELP consider removing this semicolon + }; + + let _ = match Some(42) { + Some(x) => { + x + }, + None => { + (); + //~^ ERROR incompatible types + }, + }; + + let _ = match Some(42) { + Some(x) => { + x + }, + None => { //~ ERROR incompatible types + }, + }; +} diff --git a/src/test/ui/match/match-incompat-type-semi.stderr b/src/test/ui/match/match-incompat-type-semi.stderr new file mode 100644 index 00000000000..701f15fdc4b --- /dev/null +++ b/src/test/ui/match/match-incompat-type-semi.stderr @@ -0,0 +1,74 @@ +error[E0308]: `match` arms have incompatible types + --> $DIR/match-incompat-type-semi.rs:11:13 + | +LL | let _ = match Some(42) { + | _____________- +LL | | Some(x) => { +LL | | x + | | - this is found to be of type `{integer}` +LL | | }, +LL | | None => { +LL | | 0; + | | ^- + | | || + | | |help: consider removing this semicolon + | | expected integer, found `()` +... | +LL | | }, +LL | | }; + | |_____- `match` arms have incompatible types + +error[E0308]: `if` and `else` have incompatible types + --> $DIR/match-incompat-type-semi.rs:20:9 + | +LL | let _ = if let Some(x) = Some(42) { + | _____________- +LL | | x + | | - expected because of this +LL | | } else { +LL | | 0; + | | ^- + | | || + | | |help: consider removing this semicolon + | | expected integer, found `()` +LL | | +LL | | +LL | | }; + | |_____- `if` and `else` have incompatible types + +error[E0308]: `match` arms have incompatible types + --> $DIR/match-incompat-type-semi.rs:30:13 + | +LL | let _ = match Some(42) { + | _____________- +LL | | Some(x) => { +LL | | x + | | - this is found to be of type `{integer}` +LL | | }, +LL | | None => { +LL | | (); + | | ^^^ expected integer, found `()` +LL | | +LL | | }, +LL | | }; + | |_____- `match` arms have incompatible types + +error[E0308]: `match` arms have incompatible types + --> $DIR/match-incompat-type-semi.rs:39:17 + | +LL | let _ = match Some(42) { + | _____________- +LL | | Some(x) => { +LL | | x + | | - this is found to be of type `{integer}` +LL | | }, +LL | | None => { + | |_________________^ +LL | || }, + | ||_________^ expected integer, found `()` +LL | | }; + | |_____- `match` arms have incompatible types + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.rs b/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.rs index b070671cb25..4417fb926d9 100644 --- a/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.rs +++ b/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.rs @@ -10,7 +10,7 @@ fn foo(node: Box) -> isize { Some(right) => consume(right), None => 0 }; - consume(node) + r //~ ERROR use of moved value: `node` + consume(node) + r //~ ERROR use of partially moved value: `node` } fn consume(v: Box) -> isize { diff --git a/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr b/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr index 952985fcdde..49964e2a947 100644 --- a/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr +++ b/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr @@ -1,13 +1,13 @@ -error[E0382]: use of moved value: `node` +error[E0382]: use of partially moved value: `node` --> $DIR/moves-based-on-type-cyclic-types-issue-4821.rs:13:13 | LL | Some(right) => consume(right), - | ----- value moved here + | ----- value partially moved here ... LL | consume(node) + r | ^^^^ value used here after partial move | - = note: move occurs because value has type `std::boxed::Box`, which does not implement the `Copy` trait + = note: partial move occurs because value has type `std::boxed::Box`, which does not implement the `Copy` trait help: borrow this field in the pattern to avoid moving `node.next.0` | LL | Some(ref right) => consume(right), diff --git a/src/test/ui/moves/moves-based-on-type-match-bindings.rs b/src/test/ui/moves/moves-based-on-type-match-bindings.rs index 1290d4a25ab..75fc6085f0a 100644 --- a/src/test/ui/moves/moves-based-on-type-match-bindings.rs +++ b/src/test/ui/moves/moves-based-on-type-match-bindings.rs @@ -13,9 +13,9 @@ fn f10() { Foo {f} => {} }; - touch(&x); //~ ERROR borrow of moved value: `x` + touch(&x); //~ ERROR borrow of partially moved value: `x` //~^ value borrowed here after partial move - //~| move occurs because `x.f` has type `std::string::String` + //~| partial move occurs because `x.f` has type `std::string::String` } fn main() {} diff --git a/src/test/ui/moves/moves-based-on-type-match-bindings.stderr b/src/test/ui/moves/moves-based-on-type-match-bindings.stderr index 322999a1f0f..2ee8d8d0b75 100644 --- a/src/test/ui/moves/moves-based-on-type-match-bindings.stderr +++ b/src/test/ui/moves/moves-based-on-type-match-bindings.stderr @@ -1,13 +1,13 @@ -error[E0382]: borrow of moved value: `x` +error[E0382]: borrow of partially moved value: `x` --> $DIR/moves-based-on-type-match-bindings.rs:16:11 | LL | Foo {f} => {} - | - value moved here + | - value partially moved here ... LL | touch(&x); | ^^ value borrowed here after partial move | - = note: move occurs because `x.f` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `x.f` has type `std::string::String`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/nll/issue-52742.stderr b/src/test/ui/nll/issue-52742.stderr index 0cdc2d94439..7631ca61e5e 100644 --- a/src/test/ui/nll/issue-52742.stderr +++ b/src/test/ui/nll/issue-52742.stderr @@ -12,11 +12,8 @@ LL | impl Foo<'_, '_> { note: ...but the borrowed content is only valid for the anonymous lifetime #2 defined on the method body at 13:5 --> $DIR/issue-52742.rs:13:5 | -LL | / fn take_bar(&mut self, b: Bar<'_>) { -LL | | self.y = b.z -LL | | -LL | | } - | |_____^ +LL | fn take_bar(&mut self, b: Bar<'_>) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/nll/issue-55394.stderr b/src/test/ui/nll/issue-55394.stderr index ba8d91b8455..e24ef176db0 100644 --- a/src/test/ui/nll/issue-55394.stderr +++ b/src/test/ui/nll/issue-55394.stderr @@ -7,10 +7,8 @@ LL | Foo { bar } note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 8:5... --> $DIR/issue-55394.rs:8:5 | -LL | / fn new(bar: &mut Bar) -> Self { -LL | | Foo { bar } -LL | | } - | |_____^ +LL | fn new(bar: &mut Bar) -> Self { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...so that reference does not outlive borrowed content --> $DIR/issue-55394.rs:9:15 | diff --git a/src/test/ui/nll/move-subpaths-moves-root.rs b/src/test/ui/nll/move-subpaths-moves-root.rs index e7caf89e783..d266c6bb658 100644 --- a/src/test/ui/nll/move-subpaths-moves-root.rs +++ b/src/test/ui/nll/move-subpaths-moves-root.rs @@ -1,5 +1,5 @@ fn main() { let x = (vec![1, 2, 3], ); drop(x.0); - drop(x); //~ ERROR use of moved value + drop(x); //~ ERROR use of partially moved value } diff --git a/src/test/ui/nll/move-subpaths-moves-root.stderr b/src/test/ui/nll/move-subpaths-moves-root.stderr index 7030d5b3305..d86801cf296 100644 --- a/src/test/ui/nll/move-subpaths-moves-root.stderr +++ b/src/test/ui/nll/move-subpaths-moves-root.stderr @@ -1,12 +1,12 @@ -error[E0382]: use of moved value: `x` +error[E0382]: use of partially moved value: `x` --> $DIR/move-subpaths-moves-root.rs:4:10 | LL | drop(x.0); - | --- value moved here + | --- value partially moved here LL | drop(x); | ^ value used here after partial move | - = note: move occurs because `x.0` has type `std::vec::Vec`, which does not implement the `Copy` trait + = note: partial move occurs because `x.0` has type `std::vec::Vec`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/nll/type-alias-free-regions.stderr b/src/test/ui/nll/type-alias-free-regions.stderr index 3317aae83bb..65ce0581121 100644 --- a/src/test/ui/nll/type-alias-free-regions.stderr +++ b/src/test/ui/nll/type-alias-free-regions.stderr @@ -7,10 +7,8 @@ LL | C { f: b } note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 16:5... --> $DIR/type-alias-free-regions.rs:16:5 | -LL | / fn from_box(b: Box) -> Self { -LL | | C { f: b } -LL | | } - | |_____^ +LL | fn from_box(b: Box) -> Self { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...so that the expression is assignable --> $DIR/type-alias-free-regions.rs:17:16 | @@ -40,10 +38,8 @@ LL | C { f: Box::new(b.0) } note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 26:5... --> $DIR/type-alias-free-regions.rs:26:5 | -LL | / fn from_tuple(b: (B,)) -> Self { -LL | | C { f: Box::new(b.0) } -LL | | } - | |_____^ +LL | fn from_tuple(b: (B,)) -> Self { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...so that the expression is assignable --> $DIR/type-alias-free-regions.rs:27:25 | diff --git a/src/test/ui/offset_from.rs b/src/test/ui/offset_from.rs index cbbb2adf15f..aa59c119706 100644 --- a/src/test/ui/offset_from.rs +++ b/src/test/ui/offset_from.rs @@ -1,7 +1,5 @@ // run-pass -#![feature(ptr_offset_from)] - fn main() { let mut a = [0; 5]; let ptr1: *mut i32 = &mut a[1]; diff --git a/src/test/ui/out-of-stack.rs b/src/test/ui/out-of-stack.rs index d04b0c1a630..6beafc0732b 100644 --- a/src/test/ui/out-of-stack.rs +++ b/src/test/ui/out-of-stack.rs @@ -3,7 +3,6 @@ #![allow(unused_must_use)] #![allow(unconditional_recursion)] // ignore-android: FIXME (#20004) -// ignore-musl // ignore-cloudabi no processes // ignore-emscripten no processes // ignore-sgx no processes diff --git a/src/test/ui/panic-handler/panic-handler-bad-signature-4.stderr b/src/test/ui/panic-handler/panic-handler-bad-signature-4.stderr index 3a5fc76efbb..5e46da12142 100644 --- a/src/test/ui/panic-handler/panic-handler-bad-signature-4.stderr +++ b/src/test/ui/panic-handler/panic-handler-bad-signature-4.stderr @@ -1,11 +1,8 @@ error: should have no type parameters --> $DIR/panic-handler-bad-signature-4.rs:9:1 | -LL | / fn panic(pi: &PanicInfo) -> ! { -LL | | -LL | | loop {} -LL | | } - | |_^ +LL | fn panic(pi: &PanicInfo) -> ! { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/panic-handler/panic-handler-duplicate.stderr b/src/test/ui/panic-handler/panic-handler-duplicate.stderr index 8603ef91bef..8cdc4888d02 100644 --- a/src/test/ui/panic-handler/panic-handler-duplicate.stderr +++ b/src/test/ui/panic-handler/panic-handler-duplicate.stderr @@ -1,18 +1,14 @@ error[E0152]: found duplicate lang item `panic_impl` --> $DIR/panic-handler-duplicate.rs:15:1 | -LL | / fn panic2(info: &PanicInfo) -> ! { -LL | | loop {} -LL | | } - | |_^ +LL | fn panic2(info: &PanicInfo) -> ! { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: the lang item is first defined here --> $DIR/panic-handler-duplicate.rs:10:1 | -LL | / fn panic(info: &PanicInfo) -> ! { -LL | | loop {} -LL | | } - | |_^ +LL | fn panic(info: &PanicInfo) -> ! { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/panic-handler/panic-handler-std.stderr b/src/test/ui/panic-handler/panic-handler-std.stderr index bb656089bca..e4069b196ff 100644 --- a/src/test/ui/panic-handler/panic-handler-std.stderr +++ b/src/test/ui/panic-handler/panic-handler-std.stderr @@ -1,10 +1,8 @@ error[E0152]: found duplicate lang item `panic_impl` --> $DIR/panic-handler-std.rs:8:1 | -LL | / fn panic(info: PanicInfo) -> ! { -LL | | loop {} -LL | | } - | |_^ +LL | fn panic(info: PanicInfo) -> ! { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the lang item is first defined in crate `std` (which `panic_handler_std` depends on) = note: first definition in `std` loaded from SYSROOT/libstd-*.rlib diff --git a/src/test/ui/parser/struct-literal-in-match-guard.rs b/src/test/ui/parser/struct-literal-in-match-guard.rs new file mode 100644 index 00000000000..bf0551b5c97 --- /dev/null +++ b/src/test/ui/parser/struct-literal-in-match-guard.rs @@ -0,0 +1,18 @@ +// check-pass + +// Unlike `if` condition, `match` guards accept struct literals. +// This is detected in . + +#[derive(PartialEq)] +struct Foo { + x: isize, +} + +fn foo(f: Foo) { + match () { + () if f == Foo { x: 42 } => {} + _ => {} + } +} + +fn main() {} diff --git a/src/test/ui/privacy/private-in-public-lint.stderr b/src/test/ui/privacy/private-in-public-lint.stderr index 441a4d5cffd..377bd58b54c 100644 --- a/src/test/ui/privacy/private-in-public-lint.stderr +++ b/src/test/ui/privacy/private-in-public-lint.stderr @@ -5,7 +5,7 @@ LL | struct Priv; | - `m1::Priv` declared as private ... LL | pub fn f() -> Priv {Priv} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `m2::Priv` in public interface --> $DIR/private-in-public-lint.rs:15:9 @@ -14,7 +14,7 @@ LL | struct Priv; | - `m2::Priv` declared as private ... LL | pub fn f() -> Priv {Priv} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^^^^^^^^^ can't leak private type error: aborting due to 2 previous errors diff --git a/src/test/ui/privacy/private-in-public-non-principal.stderr b/src/test/ui/privacy/private-in-public-non-principal.stderr index 43469f74538..5b4123ea82a 100644 --- a/src/test/ui/privacy/private-in-public-non-principal.stderr +++ b/src/test/ui/privacy/private-in-public-non-principal.stderr @@ -2,7 +2,7 @@ warning: private trait `PrivNonPrincipal` in public interface (error E0445) --> $DIR/private-in-public-non-principal.rs:7:1 | LL | pub fn leak_dyn_nonprincipal() -> Box { loop {} } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `#[warn(private_in_public)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! diff --git a/src/test/ui/privacy/private-in-public-warn.stderr b/src/test/ui/privacy/private-in-public-warn.stderr index 38081295e7e..4905e295195 100644 --- a/src/test/ui/privacy/private-in-public-warn.stderr +++ b/src/test/ui/privacy/private-in-public-warn.stderr @@ -52,7 +52,7 @@ error: private type `types::Priv` in public interface (error E0446) --> $DIR/private-in-public-warn.rs:27:9 | LL | fn f1(arg: Priv) {} - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 @@ -61,7 +61,7 @@ error: private type `types::Priv` in public interface (error E0446) --> $DIR/private-in-public-warn.rs:29:9 | LL | fn f2() -> Priv { panic!() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 @@ -148,7 +148,7 @@ error: private trait `traits::PrivTr` in public interface (error E0445) --> $DIR/private-in-public-warn.rs:61:9 | LL | fn f(arg: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 @@ -193,7 +193,7 @@ error: private trait `traits_where::PrivTr` in public interface (error E0445) --> $DIR/private-in-public-warn.rs:83:9 | LL | fn f(arg: T) where T: PrivTr {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 @@ -265,7 +265,7 @@ error: private type `aliases_pub::Priv` in public interface (error E0446) --> $DIR/private-in-public-warn.rs:206:9 | LL | pub fn f(arg: Priv) {} - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 diff --git a/src/test/ui/privacy/private-in-public.stderr b/src/test/ui/privacy/private-in-public.stderr index e3fa4c145c3..4750fe8687e 100644 --- a/src/test/ui/privacy/private-in-public.stderr +++ b/src/test/ui/privacy/private-in-public.stderr @@ -23,7 +23,7 @@ LL | struct Priv; | - `types::Priv` declared as private ... LL | pub fn f1(arg: Priv) {} - | ^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `types::Priv` in public interface --> $DIR/private-in-public.rs:16:5 @@ -32,7 +32,7 @@ LL | struct Priv; | - `types::Priv` declared as private ... LL | pub fn f2() -> Priv { panic!() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `types::Priv` in public interface --> $DIR/private-in-public.rs:17:19 @@ -68,7 +68,7 @@ LL | struct Priv; | - `types::Priv` declared as private ... LL | pub fn f1(arg: Priv) {} - | ^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `types::Priv` in public interface --> $DIR/private-in-public.rs:22:9 @@ -77,7 +77,7 @@ LL | struct Priv; | - `types::Priv` declared as private ... LL | pub fn f2() -> Priv { panic!() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0445]: private trait `traits::PrivTr` in public interface --> $DIR/private-in-public.rs:31:5 @@ -95,7 +95,7 @@ LL | trait PrivTr {} | - `traits::PrivTr` declared as private ... LL | pub fn f(arg: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait error[E0445]: private trait `traits::PrivTr` in public interface --> $DIR/private-in-public.rs:33:5 @@ -124,7 +124,7 @@ LL | trait PrivTr {} | - `traits::PrivTr` declared as private ... LL | pub fn f(arg: U) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait error[E0445]: private trait `traits_where::PrivTr` in public interface --> $DIR/private-in-public.rs:44:5 @@ -142,7 +142,7 @@ LL | trait PrivTr {} | - `traits_where::PrivTr` declared as private ... LL | pub fn f(arg: T) where T: PrivTr {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait error[E0445]: private trait `traits_where::PrivTr` in public interface --> $DIR/private-in-public.rs:48:5 @@ -173,7 +173,7 @@ LL | trait PrivTr {} | - `traits_where::PrivTr` declared as private ... LL | pub fn f(arg: U) where U: PrivTr {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait error[E0446]: private type `generics::Priv` in public interface --> $DIR/private-in-public.rs:63:5 @@ -182,7 +182,7 @@ LL | struct Priv(T); | - `generics::Priv` declared as private ... LL | pub fn f1(arg: [Priv; 1]) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `generics::Priv` in public interface --> $DIR/private-in-public.rs:64:5 @@ -191,7 +191,7 @@ LL | struct Priv(T); | - `generics::Priv` declared as private ... LL | pub fn f2(arg: Pub) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `generics::Priv` in public interface --> $DIR/private-in-public.rs:65:5 @@ -200,7 +200,7 @@ LL | struct Priv(T); | - `generics::Priv` declared as private ... LL | pub fn f3(arg: Priv) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `impls::Priv` in public interface --> $DIR/private-in-public.rs:80:9 @@ -209,7 +209,7 @@ LL | struct Priv; | - `impls::Priv` declared as private ... LL | pub fn f(arg: Priv) {} - | ^^^^^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0445]: private trait `aliases_pub::PrivTr` in public interface --> $DIR/private-in-public.rs:104:5 @@ -218,7 +218,7 @@ LL | trait PrivTr { | - `aliases_pub::PrivTr` declared as private ... LL | pub fn f3(arg: ::Assoc) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait error[E0446]: private type `aliases_pub::Priv` in public interface --> $DIR/private-in-public.rs:104:5 @@ -227,7 +227,7 @@ LL | struct Priv; | - `aliases_pub::Priv` declared as private ... LL | pub fn f3(arg: ::Assoc) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `aliases_pub::Priv` in public interface --> $DIR/private-in-public.rs:109:9 @@ -236,7 +236,7 @@ LL | struct Priv; | - `aliases_pub::Priv` declared as private ... LL | pub fn f(arg: Priv) {} - | ^^^^^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `aliases_priv::Priv1` in public interface --> $DIR/private-in-public.rs:131:5 @@ -245,7 +245,7 @@ LL | struct Priv1; | - `aliases_priv::Priv1` declared as private ... LL | pub fn f1(arg: PrivUseAlias) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `aliases_priv::Priv2` in public interface --> $DIR/private-in-public.rs:132:5 @@ -254,7 +254,7 @@ LL | struct Priv2; | - `aliases_priv::Priv2` declared as private ... LL | pub fn f2(arg: PrivAlias) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0445]: private trait `aliases_priv::PrivTr` in public interface --> $DIR/private-in-public.rs:133:5 @@ -263,7 +263,7 @@ LL | trait PrivTr { | - `aliases_priv::PrivTr` declared as private ... LL | pub fn f3(arg: ::Assoc) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait error[E0446]: private type `aliases_priv::Priv` in public interface --> $DIR/private-in-public.rs:133:5 @@ -272,7 +272,7 @@ LL | struct Priv; | - `aliases_priv::Priv` declared as private ... LL | pub fn f3(arg: ::Assoc) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `aliases_params::Priv` in public interface --> $DIR/private-in-public.rs:143:5 @@ -281,7 +281,7 @@ LL | struct Priv; | - `aliases_params::Priv` declared as private ... LL | pub fn f2(arg: PrivAliasGeneric) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `aliases_params::Priv` in public interface --> $DIR/private-in-public.rs:145:5 @@ -290,7 +290,7 @@ LL | struct Priv; | - `aliases_params::Priv` declared as private ... LL | pub fn f3(arg: Result) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type error: aborting due to 32 previous errors diff --git a/src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr b/src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr index 010969c03af..727134bd51d 100644 --- a/src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr +++ b/src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr @@ -14,7 +14,7 @@ error: type `priv_dep::OtherType` from private dependency 'priv_dep' in public i --> $DIR/pub-priv1.rs:27:5 | LL | pub fn pub_fn(param: OtherType) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: trait `priv_dep::OtherTrait` from private dependency 'priv_dep' in public interface --> $DIR/pub-priv1.rs:33:1 diff --git a/src/test/ui/privacy/restricted/private-in-public.stderr b/src/test/ui/privacy/restricted/private-in-public.stderr index 87c96d31f09..c597935e7f0 100644 --- a/src/test/ui/privacy/restricted/private-in-public.stderr +++ b/src/test/ui/privacy/restricted/private-in-public.stderr @@ -5,7 +5,7 @@ LL | struct Priv; | - `foo::Priv` declared as private ... LL | pub(crate) fn g(_: Priv) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `foo::Priv` in public interface --> $DIR/private-in-public.rs:9:9 @@ -14,7 +14,7 @@ LL | struct Priv; | - `foo::Priv` declared as private ... LL | crate fn h(_: Priv) {} - | ^^^^^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^^^^^^^^^^ can't leak private type error: aborting due to 2 previous errors diff --git a/src/test/ui/proc-macro/capture-macro-rules-invoke.rs b/src/test/ui/proc-macro/capture-macro-rules-invoke.rs index a404ddace9b..2ff6ad6d68f 100644 --- a/src/test/ui/proc-macro/capture-macro-rules-invoke.rs +++ b/src/test/ui/proc-macro/capture-macro-rules-invoke.rs @@ -1,12 +1,20 @@ // aux-build:test-macros.rs // check-pass +// compile-flags: -Z span-debug +// normalize-stdout-test "#\d+" -> "#CTXT" extern crate test_macros; -use test_macros::recollect; +use test_macros::print_bang; macro_rules! use_expr { ($expr:expr) => { - recollect!($expr) + print_bang!($expr) + } +} + +macro_rules! use_pat { + ($pat:pat) => { + print_bang!($pat) } } @@ -17,6 +25,10 @@ impl Foo { fn use_self(self) { drop(use_expr!(self)); } + + fn with_pat(use_pat!((a, b)): (u32, u32)) { + println!("Args: {} {}", a, b); + } } fn main() {} diff --git a/src/test/ui/proc-macro/capture-macro-rules-invoke.stdout b/src/test/ui/proc-macro/capture-macro-rules-invoke.stdout new file mode 100644 index 00000000000..28812e20548 --- /dev/null +++ b/src/test/ui/proc-macro/capture-macro-rules-invoke.stdout @@ -0,0 +1,41 @@ +PRINT-BANG INPUT (DISPLAY): self +PRINT-BANG INPUT (DEBUG): TokenStream [ + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "self", + span: $DIR/capture-macro-rules-invoke.rs:26:24: 26:28 (#CTXT), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:11:21: 11:26 (#CTXT), + }, +] +PRINT-BANG INPUT (DISPLAY): (a, b) +PRINT-BANG INPUT (DEBUG): TokenStream [ + Group { + delimiter: None, + stream: TokenStream [ + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "a", + span: $DIR/capture-macro-rules-invoke.rs:29:27: 29:28 (#CTXT), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:29:28: 29:29 (#CTXT), + }, + Ident { + ident: "b", + span: $DIR/capture-macro-rules-invoke.rs:29:30: 29:31 (#CTXT), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:29:26: 29:32 (#CTXT), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:17:21: 17:25 (#CTXT), + }, +] diff --git a/src/test/ui/proc-macro/group-compat-hack/auxiliary/group-compat-hack.rs b/src/test/ui/proc-macro/group-compat-hack/auxiliary/group-compat-hack.rs new file mode 100644 index 00000000000..5cd3b40a2e4 --- /dev/null +++ b/src/test/ui/proc-macro/group-compat-hack/auxiliary/group-compat-hack.rs @@ -0,0 +1,13 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn my_macro(_attr: TokenStream, input: TokenStream) -> TokenStream { + println!("Called proc_macro_hack with {:?}", input); + input +} diff --git a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.rs b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.rs new file mode 100644 index 00000000000..35c101587de --- /dev/null +++ b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.rs @@ -0,0 +1,30 @@ +// check-pass +// aux-build:group-compat-hack.rs +// compile-flags: -Z span-debug + +#![no_std] // Don't load unnecessary hygiene information from std +extern crate std; + +#[macro_use] extern crate group_compat_hack; + +// Tests the backwards compatibility hack added for certain macros +// When an attribute macro named `proc_macro_hack` or `wasm_bindgen` +// has an `NtIdent` named `$name`, we pass a plain `Ident` token in +// place of a `None`-delimited group. This allows us to maintain +// backwards compatibility for older versions of these crates. + +include!("js-sys/src/lib.rs"); +include!("time-macros-impl/src/lib.rs"); + +macro_rules! other { + ($name:ident) => { + #[my_macro] struct Three($name); + } +} + +fn main() { + struct Foo; + impl_macros!(Foo); + arrays!(Foo); + other!(Foo); +} diff --git a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout new file mode 100644 index 00000000000..d519daab1f2 --- /dev/null +++ b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout @@ -0,0 +1,3 @@ +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl/src/lib.rs:5:21: 5:27 (#5) }, Ident { ident: "One", span: $DIR/time-macros-impl/src/lib.rs:5:28: 5:31 (#5) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:27:18: 27:21 (#0) }], span: $DIR/time-macros-impl/src/lib.rs:5:31: 5:38 (#5) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl/src/lib.rs:5:38: 5:39 (#5) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys/src/lib.rs:5:21: 5:27 (#9) }, Ident { ident: "Two", span: $DIR/js-sys/src/lib.rs:5:28: 5:31 (#9) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:28:13: 28:16 (#0) }], span: $DIR/js-sys/src/lib.rs:5:31: 5:38 (#9) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys/src/lib.rs:5:38: 5:39 (#9) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:21:21: 21:27 (#13) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:21:28: 21:33 (#13) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:29:12: 29:15 (#0) }], span: $DIR/group-compat-hack.rs:21:34: 21:39 (#13) }], span: $DIR/group-compat-hack.rs:21:33: 21:40 (#13) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:21:40: 21:41 (#13) }] diff --git a/src/test/ui/proc-macro/group-compat-hack/js-sys/src/lib.rs b/src/test/ui/proc-macro/group-compat-hack/js-sys/src/lib.rs new file mode 100644 index 00000000000..d1a66940ebf --- /dev/null +++ b/src/test/ui/proc-macro/group-compat-hack/js-sys/src/lib.rs @@ -0,0 +1,7 @@ +// ignore-test this is not a test + +macro_rules! arrays { + ($name:ident) => { + #[my_macro] struct Two($name); + } +} diff --git a/src/test/ui/proc-macro/group-compat-hack/time-macros-impl/src/lib.rs b/src/test/ui/proc-macro/group-compat-hack/time-macros-impl/src/lib.rs new file mode 100644 index 00000000000..c94c3579209 --- /dev/null +++ b/src/test/ui/proc-macro/group-compat-hack/time-macros-impl/src/lib.rs @@ -0,0 +1,7 @@ +// ignore-test this is not a test + +macro_rules! impl_macros { + ($name:ident) => { + #[my_macro] struct One($name); + } +} diff --git a/src/test/ui/proc-macro/input-interpolated.stdout b/src/test/ui/proc-macro/input-interpolated.stdout index 9cf33ba4a9d..a9636cfef82 100644 --- a/src/test/ui/proc-macro/input-interpolated.stdout +++ b/src/test/ui/proc-macro/input-interpolated.stdout @@ -15,51 +15,63 @@ PRINT-ATTR INPUT (DISPLAY): const A : u8 = 0 ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "const", - span: #0 bytes(0..0), + span: #3 bytes(416..421), }, - Ident { - ident: "A", - span: #0 bytes(0..0), + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "A", + span: #0 bytes(503..504), + }, + ], + span: #3 bytes(422..424), }, Punct { ch: ':', spacing: Alone, - span: #0 bytes(0..0), + span: #3 bytes(424..425), }, Ident { ident: "u8", - span: #0 bytes(0..0), + span: #3 bytes(426..428), }, Punct { ch: '=', spacing: Alone, - span: #0 bytes(0..0), + span: #3 bytes(429..430), }, Literal { kind: Integer, symbol: "0", suffix: None, - span: #0 bytes(0..0), + span: #3 bytes(431..432), }, Punct { ch: ';', spacing: Alone, - span: #0 bytes(0..0), + span: #3 bytes(432..433), }, ] PRINT-DERIVE INPUT (DISPLAY): struct A { } PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: #0 bytes(0..0), + span: #3 bytes(468..474), }, - Ident { - ident: "A", - span: #0 bytes(0..0), + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "A", + span: #0 bytes(503..504), + }, + ], + span: #3 bytes(475..477), }, Group { delimiter: Brace, stream: TokenStream [], - span: #0 bytes(0..0), + span: #3 bytes(478..480), }, ] diff --git a/src/test/ui/proc-macro/macro-rules-derive.rs b/src/test/ui/proc-macro/macro-rules-derive.rs index 5b4d577a1ac..e0c40bbc734 100644 --- a/src/test/ui/proc-macro/macro-rules-derive.rs +++ b/src/test/ui/proc-macro/macro-rules-derive.rs @@ -1,14 +1,13 @@ // aux-build:first-second.rs -// FIXME: The spans here are bad, see PR #73084 extern crate first_second; use first_second::*; macro_rules! produce_it { ($name:ident) => { - #[first] //~ ERROR cannot find type + #[first] struct $name { - field: MissingType + field: MissingType //~ ERROR cannot find type } } } diff --git a/src/test/ui/proc-macro/macro-rules-derive.stderr b/src/test/ui/proc-macro/macro-rules-derive.stderr index 4b72d29fe8a..54a079e4e73 100644 --- a/src/test/ui/proc-macro/macro-rules-derive.stderr +++ b/src/test/ui/proc-macro/macro-rules-derive.stderr @@ -1,8 +1,13 @@ error[E0412]: cannot find type `MissingType` in this scope - --> $DIR/macro-rules-derive.rs:9:9 + --> $DIR/macro-rules-derive.rs:10:20 | -LL | #[first] - | ^^^^^^^^ not found in this scope +LL | field: MissingType + | ^^^^^^^^^^^ not found in this scope +... +LL | produce_it!(MyName); + | -------------------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/proc-macro/no-macro-use-attr.stderr b/src/test/ui/proc-macro/no-macro-use-attr.stderr index 1831300a0d9..a9e5256a0a9 100644 --- a/src/test/ui/proc-macro/no-macro-use-attr.stderr +++ b/src/test/ui/proc-macro/no-macro-use-attr.stderr @@ -14,7 +14,7 @@ error: fatal error triggered by #[rustc_error] --> $DIR/no-macro-use-attr.rs:10:1 | LL | fn main() {} - | ^^^^^^^^^^^^ + | ^^^^^^^^^ error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/proc-macro/nodelim-groups.stdout b/src/test/ui/proc-macro/nodelim-groups.stdout index 2fcd41f6da0..cdf851b535a 100644 --- a/src/test/ui/proc-macro/nodelim-groups.stdout +++ b/src/test/ui/proc-macro/nodelim-groups.stdout @@ -71,7 +71,6 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ }, ] PRINT-BANG INPUT (DISPLAY): "hi" "hello".len() + "world".len() (1 + 1) -PRINT-BANG RE-COLLECTED (DISPLAY): "hi" "hello" . len() + "world" . len() (1 + 1) PRINT-BANG INPUT (DEBUG): TokenStream [ Literal { kind: Str, @@ -82,50 +81,62 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ Group { delimiter: None, stream: TokenStream [ - Literal { - kind: Str, - symbol: "hello", - suffix: None, - span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8), - }, - Punct { - ch: '.', - spacing: Alone, - span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8), - }, - Ident { - ident: "len", - span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8), - }, Group { - delimiter: Parenthesis, - stream: TokenStream [], - span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8), + delimiter: None, + stream: TokenStream [ + Literal { + kind: Str, + symbol: "hello", + suffix: None, + span: $DIR/nodelim-groups.rs:21:17: 21:24 (#0), + }, + Punct { + ch: '.', + spacing: Alone, + span: $DIR/nodelim-groups.rs:21:24: 21:25 (#0), + }, + Ident { + ident: "len", + span: $DIR/nodelim-groups.rs:21:25: 21:28 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/nodelim-groups.rs:21:28: 21:30 (#0), + }, + ], + span: $DIR/nodelim-groups.rs:15:49: 15:54 (#7), }, Punct { ch: '+', spacing: Alone, - span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8), - }, - Literal { - kind: Str, - symbol: "world", - suffix: None, - span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8), - }, - Punct { - ch: '.', - spacing: Alone, - span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8), - }, - Ident { - ident: "len", - span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8), + span: $DIR/nodelim-groups.rs:15:55: 15:56 (#7), }, Group { - delimiter: Parenthesis, - stream: TokenStream [], - span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8), + delimiter: None, + stream: TokenStream [ + Literal { + kind: Str, + symbol: "world", + suffix: None, + span: $DIR/nodelim-groups.rs:21:33: 21:40 (#0), + }, + Punct { + ch: '.', + spacing: Alone, + span: $DIR/nodelim-groups.rs:21:40: 21:41 (#0), + }, + Ident { + ident: "len", + span: $DIR/nodelim-groups.rs:21:41: 21:44 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/nodelim-groups.rs:21:44: 21:46 (#0), + }, + ], + span: $DIR/nodelim-groups.rs:15:57: 15:62 (#7), }, ], span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8), diff --git a/src/test/ui/proc-macro/weird-hygiene.rs b/src/test/ui/proc-macro/weird-hygiene.rs index 3f48191b5b2..7ba3f98a7a9 100644 --- a/src/test/ui/proc-macro/weird-hygiene.rs +++ b/src/test/ui/proc-macro/weird-hygiene.rs @@ -1,6 +1,4 @@ // aux-build:weird-hygiene.rs -// check-pass -// FIXME: This should actually error, see PR #73084 #![feature(stmt_expr_attributes)] #![feature(proc_macro_hygiene)] @@ -22,7 +20,7 @@ macro_rules! inner { #[derive(WeirdDerive)] enum MyEnum { - Value = (stringify!($tokens + hidden_ident), 1).1 + Value = (stringify!($tokens + hidden_ident), 1).1 //~ ERROR cannot find } inner!(); @@ -33,7 +31,7 @@ macro_rules! invoke_it { ($token:expr) => { #[recollect_attr] { $token; - hidden_ident + hidden_ident //~ ERROR cannot find } } } diff --git a/src/test/ui/proc-macro/weird-hygiene.stderr b/src/test/ui/proc-macro/weird-hygiene.stderr new file mode 100644 index 00000000000..b17dc28f840 --- /dev/null +++ b/src/test/ui/proc-macro/weird-hygiene.stderr @@ -0,0 +1,25 @@ +error[E0425]: cannot find value `hidden_ident` in this scope + --> $DIR/weird-hygiene.rs:23:43 + | +LL | Value = (stringify!($tokens + hidden_ident), 1).1 + | ^^^^^^^^^^^^ not found in this scope +... +LL | other!(50); + | ----------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0425]: cannot find value `hidden_ident` in this scope + --> $DIR/weird-hygiene.rs:34:13 + | +LL | hidden_ident + | ^^^^^^^^^^^^ not found in this scope +... +LL | invoke_it!(25); + | --------------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/range_inclusive.rs b/src/test/ui/range_inclusive.rs index 540b35e0392..7e7a15924b7 100644 --- a/src/test/ui/range_inclusive.rs +++ b/src/test/ui/range_inclusive.rs @@ -1,6 +1,5 @@ // run-pass // Test inclusive range syntax. -#![feature(range_is_empty)] #![allow(unused_braces)] #![allow(unused_comparisons)] diff --git a/src/test/ui/realloc-16687.rs b/src/test/ui/realloc-16687.rs index bdcd47a7260..2e07fdcbe83 100644 --- a/src/test/ui/realloc-16687.rs +++ b/src/test/ui/realloc-16687.rs @@ -48,7 +48,7 @@ unsafe fn allocate(layout: Layout) -> *mut u8 { println!("allocate({:?}) = {:?}", layout, ptr); } - ptr.as_non_null_ptr().as_ptr() + ptr.as_mut_ptr() } unsafe fn deallocate(ptr: *mut u8, layout: Layout) { @@ -65,23 +65,17 @@ unsafe fn reallocate(ptr: *mut u8, old: Layout, new: Layout) -> *mut u8 { } let memory = if new.size() > old.size() { - Global.grow( - NonNull::new_unchecked(ptr), - old, - new.size(), - ) + Global.grow(NonNull::new_unchecked(ptr), old, new) } else { - Global.shrink(NonNull::new_unchecked(ptr), old, new.size()) + Global.shrink(NonNull::new_unchecked(ptr), old, new) }; - let ptr = memory.unwrap_or_else(|_| { - handle_alloc_error(Layout::from_size_align_unchecked(new.size(), old.align())) - }); + let ptr = memory.unwrap_or_else(|_| handle_alloc_error(new)); if PRINT { println!("reallocate({:?}, old={:?}, new={:?}) = {:?}", ptr, old, new, ptr); } - ptr.as_non_null_ptr().as_ptr() + ptr.as_mut_ptr() } fn idx_to_size(i: usize) -> usize { diff --git a/src/test/ui/recursion/recursion.stderr b/src/test/ui/recursion/recursion.stderr index 0c0eba68c83..db4c99eeb8b 100644 --- a/src/test/ui/recursion/recursion.stderr +++ b/src/test/ui/recursion/recursion.stderr @@ -7,13 +7,8 @@ LL | _ => {test (n-1, i+1, Cons {head:2*i+1, tail:first}, Cons{head:i*i, tai note: `test` defined here --> $DIR/recursion.rs:15:1 | -LL | / fn test (n:isize, i:isize, first:T, second:T) ->isize { -LL | | match n { 0 => {first.dot(second)} -LL | | _ => {test (n-1, i+1, Cons {head:2*i+1, tail:first}, Cons{head:i*i, tail:second})} -LL | | -LL | | } -LL | | } - | |_^ +LL | fn test (n:isize, i:isize, first:T, second:T) ->isize { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/ref-suggestion.rs b/src/test/ui/ref-suggestion.rs index 49d199cd9e7..346d118f0f9 100644 --- a/src/test/ui/ref-suggestion.rs +++ b/src/test/ui/ref-suggestion.rs @@ -13,5 +13,5 @@ fn main() { (Some(y), ()) => {}, _ => {}, } - x; //~ ERROR use of moved value + x; //~ ERROR use of partially moved value } diff --git a/src/test/ui/ref-suggestion.stderr b/src/test/ui/ref-suggestion.stderr index 97d2c174d9a..313ad087c34 100644 --- a/src/test/ui/ref-suggestion.stderr +++ b/src/test/ui/ref-suggestion.stderr @@ -18,16 +18,16 @@ LL | let mut y = x; LL | x; | ^ value used here after move -error[E0382]: use of moved value: `x` +error[E0382]: use of partially moved value: `x` --> $DIR/ref-suggestion.rs:16:5 | LL | (Some(y), ()) => {}, - | - value moved here + | - value partially moved here ... LL | x; | ^ value used here after partial move | - = note: move occurs because value has type `std::vec::Vec`, which does not implement the `Copy` trait + = note: partial move occurs because value has type `std::vec::Vec`, which does not implement the `Copy` trait help: borrow this field in the pattern to avoid moving `x.0.0` | LL | (Some(ref y), ()) => {}, diff --git a/src/test/ui/regions/regions-infer-paramd-indirect.stderr b/src/test/ui/regions/regions-infer-paramd-indirect.stderr index 1497c3ed925..3e196cf8f12 100644 --- a/src/test/ui/regions/regions-infer-paramd-indirect.stderr +++ b/src/test/ui/regions/regions-infer-paramd-indirect.stderr @@ -9,14 +9,8 @@ LL | self.f = b; note: the anonymous lifetime #2 defined on the method body at 21:5... --> $DIR/regions-infer-paramd-indirect.rs:21:5 | -LL | / fn set_f_bad(&mut self, b: Box) { -LL | | self.f = b; -LL | | -LL | | -LL | | -LL | | -LL | | } - | |_____^ +LL | fn set_f_bad(&mut self, b: Box) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...does not necessarily outlive the lifetime `'a` as defined on the impl at 16:6 --> $DIR/regions-infer-paramd-indirect.rs:16:6 | diff --git a/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr b/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr index dc93d620ca6..10ecb8d5262 100644 --- a/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr +++ b/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr @@ -5,9 +5,7 @@ LL | / fn bar<'a, 'b>() LL | | LL | | LL | | where <() as Project<'a, 'b>>::Item : Eq -LL | | { -LL | | } - | |_^ + | |____________________________________________^ | note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 22:8... --> $DIR/regions-normalize-in-where-clause-list.rs:22:8 @@ -26,9 +24,7 @@ LL | / fn bar<'a, 'b>() LL | | LL | | LL | | where <() as Project<'a, 'b>>::Item : Eq -LL | | { -LL | | } - | |_^ + | |____________________________________________^ = note: expected `Project<'a, 'b>` found `Project<'_, '_>` @@ -39,9 +35,7 @@ LL | / fn bar<'a, 'b>() LL | | LL | | LL | | where <() as Project<'a, 'b>>::Item : Eq -LL | | { -LL | | } - | |_^ + | |____________________________________________^ | note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 22:8... --> $DIR/regions-normalize-in-where-clause-list.rs:22:8 @@ -60,9 +54,7 @@ LL | / fn bar<'a, 'b>() LL | | LL | | LL | | where <() as Project<'a, 'b>>::Item : Eq -LL | | { -LL | | } - | |_^ + | |____________________________________________^ = note: expected `Project<'a, 'b>` found `Project<'_, '_>` diff --git a/src/test/ui/regions/regions-trait-1.stderr b/src/test/ui/regions/regions-trait-1.stderr index 60ac7c09f04..92d96a722d4 100644 --- a/src/test/ui/regions/regions-trait-1.stderr +++ b/src/test/ui/regions/regions-trait-1.stderr @@ -14,10 +14,8 @@ LL | impl<'a> GetCtxt for HasCtxt<'a> { note: ...does not necessarily outlive the anonymous lifetime #1 defined on the method body at 16:5 --> $DIR/regions-trait-1.rs:16:5 | -LL | / fn get_ctxt(&self) -> &'a Ctxt { -LL | | self.c -LL | | } - | |_____^ +LL | fn get_ctxt(&self) -> &'a Ctxt { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/rfc-2091-track-caller/error-with-main.stderr b/src/test/ui/rfc-2091-track-caller/error-with-main.stderr index f05f88e7d71..7e2ec352414 100644 --- a/src/test/ui/rfc-2091-track-caller/error-with-main.stderr +++ b/src/test/ui/rfc-2091-track-caller/error-with-main.stderr @@ -1,12 +1,10 @@ error: `main` function is not allowed to be `#[track_caller]` --> $DIR/error-with-main.rs:1:1 | -LL | #[track_caller] - | ^^^^^^^^^^^^^^^ -LL | / fn main() { -LL | | panic!("{}: oh no", std::panic::Location::caller()); -LL | | } - | |_- `main` function is not allowed to be `#[track_caller]` +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ +LL | fn main() { + | --------- `main` function is not allowed to be `#[track_caller]` error: aborting due to previous error diff --git a/src/test/ui/rfc-2091-track-caller/error-with-start.stderr b/src/test/ui/rfc-2091-track-caller/error-with-start.stderr index 1a1f3e04491..454c98ff934 100644 --- a/src/test/ui/rfc-2091-track-caller/error-with-start.stderr +++ b/src/test/ui/rfc-2091-track-caller/error-with-start.stderr @@ -1,12 +1,10 @@ error: `start` is not allowed to be `#[track_caller]` --> $DIR/error-with-start.rs:4:1 | -LL | #[track_caller] - | ^^^^^^^^^^^^^^^ -LL | / fn start(_argc: isize, _argv: *const *const u8) -> isize { -LL | | panic!("{}: oh no", std::panic::Location::caller()); -LL | | } - | |_- `start` is not allowed to be `#[track_caller]` +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ +LL | fn start(_argc: isize, _argv: *const *const u8) -> isize { + | -------------------------------------------------------- `start` is not allowed to be `#[track_caller]` error: aborting due to previous error diff --git a/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs b/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs new file mode 100644 index 00000000000..c0a9bbc36b2 --- /dev/null +++ b/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs @@ -0,0 +1,85 @@ +// gate-test-if_let_guard + +use std::ops::Range; + +fn _if_let_guard() { + match () { + () if let 0 = 1 => {} + //~^ ERROR `if let` guard is not implemented + //~| ERROR `let` expressions are not supported here + + () if (let 0 = 1) => {} + //~^ ERROR `let` expressions in this position are experimental + //~| ERROR `let` expressions are not supported here + + () if (((let 0 = 1))) => {} + //~^ ERROR `let` expressions in this position are experimental + //~| ERROR `let` expressions are not supported here + + () if true && let 0 = 1 => {} + //~^ ERROR `let` expressions in this position are experimental + //~| ERROR `let` expressions are not supported here + + () if let 0 = 1 && true => {} + //~^ ERROR `let` expressions in this position are experimental + //~| ERROR `let` expressions are not supported here + + () if (let 0 = 1) && true => {} + //~^ ERROR `let` expressions in this position are experimental + //~| ERROR `let` expressions are not supported here + + () if true && (let 0 = 1) => {} + //~^ ERROR `let` expressions in this position are experimental + //~| ERROR `let` expressions are not supported here + + () if (let 0 = 1) && (let 0 = 1) => {} + //~^ ERROR `let` expressions in this position are experimental + //~| ERROR `let` expressions in this position are experimental + //~| ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + + () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + //~^ ERROR `let` expressions in this position are experimental + //~| ERROR `let` expressions in this position are experimental + //~| ERROR `let` expressions in this position are experimental + //~| ERROR `let` expressions in this position are experimental + //~| ERROR `let` expressions in this position are experimental + //~| ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + + () if let Range { start: _, end: _ } = (true..true) && false => {} + //~^ ERROR `let` expressions in this position are experimental + //~| ERROR `let` expressions are not supported here + _ => {} + } +} + +fn _macros() { + macro_rules! use_expr { + ($e:expr) => { + match () { + () if $e => {} + _ => {} + } + } + } + use_expr!((let 0 = 1 && 0 == 0)); + //~^ ERROR `let` expressions in this position are experimental + //~| ERROR `let` expressions are not supported here + use_expr!((let 0 = 1)); + //~^ ERROR `let` expressions in this position are experimental + //~| ERROR `let` expressions are not supported here + match () { + #[cfg(FALSE)] + () if let 0 = 1 => {} + //~^ ERROR `if let` guard is not implemented + _ => {} + } + use_expr!(let 0 = 1); + //~^ ERROR no rules expected the token `let` +} + +fn main() {} diff --git a/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr b/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr new file mode 100644 index 00000000000..5c7f8190dd6 --- /dev/null +++ b/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr @@ -0,0 +1,327 @@ +error: no rules expected the token `let` + --> $DIR/feature-gate.rs:81:15 + | +LL | macro_rules! use_expr { + | --------------------- when calling this macro +... +LL | use_expr!(let 0 = 1); + | ^^^ no rules expected this token in macro call + +error[E0658]: `if let` guard is not implemented + --> $DIR/feature-gate.rs:7:12 + | +LL | () if let 0 = 1 => {} + | ^^^^^^^^^^^^ + | + = note: see issue #51114 for more information + = help: add `#![feature(if_let_guard)]` to the crate attributes to enable + +error[E0658]: `if let` guard is not implemented + --> $DIR/feature-gate.rs:77:12 + | +LL | () if let 0 = 1 => {} + | ^^^^^^^^^^^^ + | + = note: see issue #51114 for more information + = help: add `#![feature(if_let_guard)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:11:16 + | +LL | () if (let 0 = 1) => {} + | ^^^^^^^^^ + | + = note: see issue #53667 for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:15:18 + | +LL | () if (((let 0 = 1))) => {} + | ^^^^^^^^^ + | + = note: see issue #53667 for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:19:23 + | +LL | () if true && let 0 = 1 => {} + | ^^^^^^^^^ + | + = note: see issue #53667 for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:23:15 + | +LL | () if let 0 = 1 && true => {} + | ^^^^^^^^^ + | + = note: see issue #53667 for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:27:16 + | +LL | () if (let 0 = 1) && true => {} + | ^^^^^^^^^ + | + = note: see issue #53667 for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:31:24 + | +LL | () if true && (let 0 = 1) => {} + | ^^^^^^^^^ + | + = note: see issue #53667 for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:35:16 + | +LL | () if (let 0 = 1) && (let 0 = 1) => {} + | ^^^^^^^^^ + | + = note: see issue #53667 for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:35:31 + | +LL | () if (let 0 = 1) && (let 0 = 1) => {} + | ^^^^^^^^^ + | + = note: see issue #53667 for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:41:15 + | +LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + | ^^^^^^^^^ + | + = note: see issue #53667 for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:41:28 + | +LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + | ^^^^^^^^^ + | + = note: see issue #53667 for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:41:42 + | +LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + | ^^^^^^^^^ + | + = note: see issue #53667 for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:41:55 + | +LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + | ^^^^^^^^^ + | + = note: see issue #53667 for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:41:68 + | +LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + | ^^^^^^^^^ + | + = note: see issue #53667 for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:53:15 + | +LL | () if let Range { start: _, end: _ } = (true..true) && false => {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #53667 for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:69:16 + | +LL | use_expr!((let 0 = 1 && 0 == 0)); + | ^^^^^^^^^ + | + = note: see issue #53667 for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:72:16 + | +LL | use_expr!((let 0 = 1)); + | ^^^^^^^^^ + | + = note: see issue #53667 for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:7:15 + | +LL | () if let 0 = 1 => {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:11:16 + | +LL | () if (let 0 = 1) => {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:15:18 + | +LL | () if (((let 0 = 1))) => {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:19:23 + | +LL | () if true && let 0 = 1 => {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:23:15 + | +LL | () if let 0 = 1 && true => {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:27:16 + | +LL | () if (let 0 = 1) && true => {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:31:24 + | +LL | () if true && (let 0 = 1) => {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:35:16 + | +LL | () if (let 0 = 1) && (let 0 = 1) => {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:35:31 + | +LL | () if (let 0 = 1) && (let 0 = 1) => {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:41:15 + | +LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:41:28 + | +LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:41:42 + | +LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:41:55 + | +LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:41:68 + | +LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:53:15 + | +LL | () if let Range { start: _, end: _ } = (true..true) && false => {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:69:16 + | +LL | use_expr!((let 0 = 1 && 0 == 0)); + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:72:16 + | +LL | use_expr!((let 0 = 1)); + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: aborting due to 36 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr index 7fe3a9fd852..b50dd03a861 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr @@ -1,4 +1,4 @@ -error[E0723]: can only call other `const fn` within a `const fn`, but `const non_const` is not stable as `const fn` +error[E0723]: can only call other `const fn` within a `const fn`, but `non_const` is not stable as `const fn` --> $DIR/const-check-fns-in-const-impl.rs:12:16 | LL | fn foo() { non_const() } diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr index e4f4d4262b6..3994bd97c30 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr @@ -2,7 +2,7 @@ error: fatal error triggered by #[rustc_error] --> $DIR/feature-gate.rs:16:1 | LL | fn main() {} - | ^^^^^^^^^^^^ + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/rfc-2632-const-trait-impl/feature-gate.gated.stderr b/src/test/ui/rfc-2632-const-trait-impl/feature-gate.gated.stderr index d1ab99e33e9..4c630d33c55 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/feature-gate.gated.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/feature-gate.gated.stderr @@ -2,7 +2,7 @@ error: fatal error triggered by #[rustc_error] --> $DIR/feature-gate.rs:14:1 | LL | fn main() {} - | ^^^^^^^^^^^^ + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/rfc-2632-const-trait-impl/stability.stderr b/src/test/ui/rfc-2632-const-trait-impl/stability.stderr index 1ecff62955b..e7002a1a045 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/stability.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/stability.stderr @@ -10,7 +10,7 @@ LL | | } = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: can only call other `const fn` within a `const fn`, but `const ::add` is not stable as `const fn` +error[E0723]: can only call other `const fn` within a `const fn`, but `::add` is not stable as `const fn` --> $DIR/stability.rs:32:5 | LL | Int(1i32) + Int(2i32) diff --git a/src/test/ui/rfc1445/feature-gate.with_gate.stderr b/src/test/ui/rfc1445/feature-gate.with_gate.stderr index fabbfd5c70b..623fd585acc 100644 --- a/src/test/ui/rfc1445/feature-gate.with_gate.stderr +++ b/src/test/ui/rfc1445/feature-gate.with_gate.stderr @@ -1,14 +1,8 @@ error: fatal error triggered by #[rustc_error] --> $DIR/feature-gate.rs:21:1 | -LL | / fn main() { -LL | | let y = Foo { x: 1 }; -LL | | match y { -LL | | FOO => { } -LL | | _ => { } -LL | | } -LL | | } - | |_^ +LL | fn main() { + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/rfcs/rfc-1014-2.rs b/src/test/ui/rfcs/rfc-1014-2.rs index 5be092204d7..7dd65701f12 100644 --- a/src/test/ui/rfcs/rfc-1014-2.rs +++ b/src/test/ui/rfcs/rfc-1014-2.rs @@ -23,7 +23,8 @@ fn close_stdout() { #[cfg(windows)] fn main() { close_stdout(); - println!("hello world"); + println!("hello"); + println!("world"); } #[cfg(not(windows))] diff --git a/src/test/ui/rfcs/rfc-1014.rs b/src/test/ui/rfcs/rfc-1014.rs index 41a036958bf..53b8fddcf31 100644 --- a/src/test/ui/rfcs/rfc-1014.rs +++ b/src/test/ui/rfcs/rfc-1014.rs @@ -30,5 +30,6 @@ fn close_stdout() { fn main() { close_stdout(); - println!("hello world"); + println!("hello"); + println!("world"); } diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/feature-gate-target_feature_11.stderr b/src/test/ui/rfcs/rfc-2396-target_feature-11/feature-gate-target_feature_11.stderr index 413890f436d..18917fd2556 100644 --- a/src/test/ui/rfcs/rfc-2396-target_feature-11/feature-gate-target_feature_11.stderr +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/feature-gate-target_feature_11.stderr @@ -4,7 +4,7 @@ error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | fn foo() {} - | ----------- not an `unsafe` function + | -------- not an `unsafe` function | = note: see issue #69098 for more information = help: add `#![feature(target_feature_11)]` to the crate attributes to enable diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/trait-impl.stderr b/src/test/ui/rfcs/rfc-2396-target_feature-11/trait-impl.stderr index 3c56e0fc5c6..07d6e090059 100644 --- a/src/test/ui/rfcs/rfc-2396-target_feature-11/trait-impl.stderr +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/trait-impl.stderr @@ -5,7 +5,7 @@ LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot be applied to safe trait method LL | LL | fn foo(&self) {} - | ---------------- not an `unsafe` function + | ------------- not an `unsafe` function error: aborting due to previous error diff --git a/src/test/ui/rustc-error.stderr b/src/test/ui/rustc-error.stderr index 7dfc4449295..de27e9b8f08 100644 --- a/src/test/ui/rustc-error.stderr +++ b/src/test/ui/rustc-error.stderr @@ -1,10 +1,8 @@ error: fatal error triggered by #[rustc_error] --> $DIR/rustc-error.rs:4:1 | -LL | / fn main() { -LL | | -LL | | } - | |_^ +LL | fn main() { + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/specialization/specialization-overlap-hygiene.stderr b/src/test/ui/specialization/specialization-overlap-hygiene.stderr index 6adf16de462..81efd46cc7f 100644 --- a/src/test/ui/specialization/specialization-overlap-hygiene.stderr +++ b/src/test/ui/specialization/specialization-overlap-hygiene.stderr @@ -2,10 +2,10 @@ error[E0592]: duplicate definitions with name `f` --> $DIR/specialization-overlap-hygiene.rs:13:4 | LL | fn f() {} - | --------- other definition for `f` + | ------ other definition for `f` ... LL | fn f() {} - | ^^^^^^^^^ duplicate definitions for `f` + | ^^^^^^ duplicate definitions for `f` error: aborting due to previous error diff --git a/src/test/ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.stderr b/src/test/ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.stderr index f81c45e2f8d..6e4cee18c16 100644 --- a/src/test/ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.stderr +++ b/src/test/ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.stderr @@ -2,7 +2,7 @@ error[E0618]: expected function, found `bool` --> $DIR/issue-51055-missing-semicolon-between-call-and-tuple.rs:4:5 | LL | fn vindictive() -> bool { true } - | -------------------------------- `vindictive` defined here returns `bool` + | ----------------------- `vindictive` defined here returns `bool` ... LL | vindictive() | -^^^^^^^^^^^- help: try adding a semicolon: `;` diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr index 2072b00f7b2..1bfcdab5d86 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr @@ -32,10 +32,7 @@ LL | / fn bar(g: G, dest: &mut T) -> impl FnOnce() + '_ LL | | LL | | where LL | | G: Get -... | -LL | | } -LL | | } - | |_^ + | |_____________^ error[E0311]: the parameter type `G` may not live long enough --> $DIR/missing-lifetimes-in-signature.rs:47:45 @@ -50,10 +47,7 @@ LL | / fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ LL | | LL | | where LL | | G: Get -... | -LL | | } -LL | | } - | |_^ + | |_____________^ error[E0311]: the parameter type `G` may not live long enough --> $DIR/missing-lifetimes-in-signature.rs:59:58 @@ -64,13 +58,8 @@ LL | fn qux<'b, G: Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ note: the parameter type `G` must be valid for the anonymous lifetime #1 defined on the method body at 59:5... --> $DIR/missing-lifetimes-in-signature.rs:59:5 | -LL | / fn qux<'b, G: Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { -LL | | -LL | | move || { -LL | | *dest = g.get(); -LL | | } -LL | | } - | |_____^ +LL | fn qux<'b, G: Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0311]: the parameter type `G` may not live long enough --> $DIR/missing-lifetimes-in-signature.rs:68:45 @@ -85,10 +74,7 @@ LL | / fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a LL | | LL | | where LL | | G: Get -... | -LL | | } -LL | | } - | |_^ + | |_____________^ error[E0621]: explicit lifetime required in the type of `dest` --> $DIR/missing-lifetimes-in-signature.rs:73:5 diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr index d7051515f11..cec01fefca8 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr @@ -40,10 +40,7 @@ LL | / fn bar(g: G, dest: &mut T) -> impl FnOnce() + '_ LL | | LL | | where LL | | G: Get -... | -LL | | } -LL | | } - | |_^ + | |_____________^ note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:30:5: 32:6 g:G, dest:&mut T]` will meet its required lifetime bounds --> $DIR/missing-lifetimes-in-signature.rs:25:37 | @@ -67,10 +64,7 @@ LL | / fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ LL | | LL | | where LL | | G: Get -... | -LL | | } -LL | | } - | |_^ + | |_____________^ note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:52:5: 54:6 g:G, dest:&mut T]` will meet its required lifetime bounds --> $DIR/missing-lifetimes-in-signature.rs:47:45 | @@ -90,13 +84,8 @@ LL | fn qux<'b, G: Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ note: the parameter type `G` must be valid for the anonymous lifetime #1 defined on the method body at 59:5... --> $DIR/missing-lifetimes-in-signature.rs:59:5 | -LL | / fn qux<'b, G: Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { -LL | | -LL | | move || { -LL | | *dest = g.get(); -LL | | } -LL | | } - | |_____^ +LL | fn qux<'b, G: Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:61:9: 63:10 g:G, dest:&mut T]` will meet its required lifetime bounds --> $DIR/missing-lifetimes-in-signature.rs:59:58 | diff --git a/src/test/ui/target-feature/invalid-attribute.stderr b/src/test/ui/target-feature/invalid-attribute.stderr index f3995f118d3..3d629afb9a6 100644 --- a/src/test/ui/target-feature/invalid-attribute.stderr +++ b/src/test/ui/target-feature/invalid-attribute.stderr @@ -29,7 +29,7 @@ LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | fn bar() {} - | ----------- not an `unsafe` function + | -------- not an `unsafe` function | = note: see issue #69098 for more information = help: add `#![feature(target_feature_11)]` to the crate attributes to enable @@ -113,7 +113,7 @@ LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | fn foo() {} - | ----------- not an `unsafe` function + | -------- not an `unsafe` function | = note: see issue #69098 for more information = help: add `#![feature(target_feature_11)]` to the crate attributes to enable diff --git a/src/test/ui/traits/trait-object-auto-dedup-in-impl.stderr b/src/test/ui/traits/trait-object-auto-dedup-in-impl.stderr index 2570db0212a..d10e58629cc 100644 --- a/src/test/ui/traits/trait-object-auto-dedup-in-impl.stderr +++ b/src/test/ui/traits/trait-object-auto-dedup-in-impl.stderr @@ -2,10 +2,10 @@ error[E0592]: duplicate definitions with name `test` --> $DIR/trait-object-auto-dedup-in-impl.rs:14:5 | LL | fn test(&self) { println!("one"); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definitions for `test` + | ^^^^^^^^^^^^^^ duplicate definitions for `test` ... LL | fn test(&self) { println!("two"); } - | ----------------------------------- other definition for `test` + | -------------- other definition for `test` error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/different_defining_uses.stderr b/src/test/ui/type-alias-impl-trait/different_defining_uses.stderr index 87ed997ec59..eaa716bc71c 100644 --- a/src/test/ui/type-alias-impl-trait/different_defining_uses.stderr +++ b/src/test/ui/type-alias-impl-trait/different_defining_uses.stderr @@ -1,18 +1,14 @@ error: concrete type differs from previous defining opaque type use --> $DIR/different_defining_uses.rs:12:1 | -LL | / fn bar() -> Foo { -LL | | 42i32 -LL | | } - | |_^ expected `&'static str`, got `i32` +LL | fn bar() -> Foo { + | ^^^^^^^^^^^^^^^ expected `&'static str`, got `i32` | note: previous use here --> $DIR/different_defining_uses.rs:8:1 | -LL | / fn foo() -> Foo { -LL | | "" -LL | | } - | |_^ +LL | fn foo() -> Foo { + | ^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.stderr b/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.stderr index 5be656e8f44..9a587e4f06e 100644 --- a/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.stderr +++ b/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.stderr @@ -1,34 +1,26 @@ error: concrete type differs from previous defining opaque type use --> $DIR/different_defining_uses_never_type.rs:12:1 | -LL | / fn bar() -> Foo { -LL | | panic!() -LL | | } - | |_^ expected `&'static str`, got `()` +LL | fn bar() -> Foo { + | ^^^^^^^^^^^^^^^ expected `&'static str`, got `()` | note: previous use here --> $DIR/different_defining_uses_never_type.rs:8:1 | -LL | / fn foo() -> Foo { -LL | | "" -LL | | } - | |_^ +LL | fn foo() -> Foo { + | ^^^^^^^^^^^^^^^ error: concrete type differs from previous defining opaque type use --> $DIR/different_defining_uses_never_type.rs:16:1 | -LL | / fn boo() -> Foo { -LL | | loop {} -LL | | } - | |_^ expected `&'static str`, got `()` +LL | fn boo() -> Foo { + | ^^^^^^^^^^^^^^^ expected `&'static str`, got `()` | note: previous use here --> $DIR/different_defining_uses_never_type.rs:8:1 | -LL | / fn foo() -> Foo { -LL | | "" -LL | | } - | |_^ +LL | fn foo() -> Foo { + | ^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/type-alias-impl-trait/generic_different_defining_uses.stderr b/src/test/ui/type-alias-impl-trait/generic_different_defining_uses.stderr index 4bcd2e1cb12..f8a058170e3 100644 --- a/src/test/ui/type-alias-impl-trait/generic_different_defining_uses.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_different_defining_uses.stderr @@ -1,18 +1,14 @@ error: concrete type differs from previous defining opaque type use --> $DIR/generic_different_defining_uses.rs:11:1 | -LL | / fn my_iter2(t: T) -> MyIter { -LL | | Some(t).into_iter() -LL | | } - | |_^ expected `std::iter::Once`, got `std::option::IntoIter` +LL | fn my_iter2(t: T) -> MyIter { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `std::iter::Once`, got `std::option::IntoIter` | note: previous use here --> $DIR/generic_different_defining_uses.rs:7:1 | -LL | / fn my_iter(t: T) -> MyIter { -LL | | std::iter::once(t) -LL | | } - | |_^ +LL | fn my_iter(t: T) -> MyIter { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr index 8170c671f68..7900da47ca2 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr @@ -1,19 +1,14 @@ error: concrete type differs from previous defining opaque type use --> $DIR/generic_duplicate_param_use2.rs:14:1 | -LL | / fn two(t: T, _: U) -> Two { -LL | | -LL | | t -LL | | } - | |_^ expected `U`, got `T` +LL | fn two(t: T, _: U) -> Two { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `U`, got `T` | note: previous use here --> $DIR/generic_duplicate_param_use2.rs:10:1 | -LL | / fn one(t: T) -> Two { -LL | | t -LL | | } - | |_^ +LL | fn one(t: T) -> Two { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr index 86dd3368400..ac5f7947d51 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr @@ -1,19 +1,14 @@ error: concrete type differs from previous defining opaque type use --> $DIR/generic_duplicate_param_use3.rs:14:1 | -LL | / fn two(t: T, _: U) -> Two { -LL | | -LL | | t -LL | | } - | |_^ expected `U`, got `T` +LL | fn two(t: T, _: U) -> Two { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `U`, got `T` | note: previous use here --> $DIR/generic_duplicate_param_use3.rs:10:1 | -LL | / fn one(t: T) -> Two { -LL | | t -LL | | } - | |_^ +LL | fn one(t: T) -> Two { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use5.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use5.stderr index 589ea749319..1ddbc0c8d6a 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use5.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use5.stderr @@ -1,19 +1,14 @@ error: concrete type differs from previous defining opaque type use --> $DIR/generic_duplicate_param_use5.rs:14:1 | -LL | / fn three(t: T, u: U) -> Two { -LL | | -LL | | (u, t) -LL | | } - | |_^ expected `(T, U)`, got `(U, T)` +LL | fn three(t: T, u: U) -> Two { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `(T, U)`, got `(U, T)` | note: previous use here --> $DIR/generic_duplicate_param_use5.rs:10:1 | -LL | / fn two(t: T, u: U) -> Two { -LL | | (t, u) -LL | | } - | |_^ +LL | fn two(t: T, u: U) -> Two { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.stderr index 7e81d362661..ebd07b7c300 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.stderr @@ -1,19 +1,14 @@ error: concrete type differs from previous defining opaque type use --> $DIR/generic_duplicate_param_use6.rs:14:1 | -LL | / fn three(t: T, u: U) -> Two { -LL | | -LL | | (u, t) -LL | | } - | |_^ expected `(T, T)`, got `(U, T)` +LL | fn three(t: T, u: U) -> Two { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `(T, T)`, got `(U, T)` | note: previous use here --> $DIR/generic_duplicate_param_use6.rs:10:1 | -LL | / fn two(t: T, u: U) -> Two { -LL | | (t, t) -LL | | } - | |_^ +LL | fn two(t: T, u: U) -> Two { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use8.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use8.stderr index 8f4cf4c6084..4778ee5155c 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use8.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use8.stderr @@ -1,19 +1,14 @@ error: concrete type differs from previous defining opaque type use --> $DIR/generic_duplicate_param_use8.rs:13:1 | -LL | / fn three(_: T, u: U) -> Two { -LL | | -LL | | (u, 4u32) -LL | | } - | |_^ expected `(T, u32)`, got `(U, u32)` +LL | fn three(_: T, u: U) -> Two { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `(T, u32)`, got `(U, u32)` | note: previous use here --> $DIR/generic_duplicate_param_use8.rs:9:1 | -LL | / fn two(t: T, _: U) -> Two { -LL | | (t, 4u32) -LL | | } - | |_^ +LL | fn two(t: T, _: U) -> Two { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.stderr index 4d0b03ba5ed..247b042f61e 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.stderr @@ -1,18 +1,14 @@ error: concrete type differs from previous defining opaque type use --> $DIR/generic_duplicate_param_use9.rs:18:1 | -LL | / fn three(t: T, u: U) -> Two { -LL | | (t, u, 42) -LL | | } - | |_^ expected `(A, B,
::Bar)`, got `(A, B, i32)` +LL | fn three(t: T, u: U) -> Two { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `(A, B, ::Bar)`, got `(A, B, i32)` | note: previous use here --> $DIR/generic_duplicate_param_use9.rs:14:1 | -LL | / fn two(t: T, u: U) -> Two { -LL | | (t, u, T::BAR) -LL | | } - | |_^ +LL | fn two(t: T, u: U) -> Two { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/issue-52843-closure-constrain.stderr b/src/test/ui/type-alias-impl-trait/issue-52843-closure-constrain.stderr index 1333b4c63d1..13069126bab 100644 --- a/src/test/ui/type-alias-impl-trait/issue-52843-closure-constrain.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-52843-closure-constrain.stderr @@ -8,7 +8,7 @@ note: previous use here --> $DIR/issue-52843-closure-constrain.rs:9:5 | LL | fn _unused() -> Opaque { String::new() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/not_a_defining_use.stderr b/src/test/ui/type-alias-impl-trait/not_a_defining_use.stderr index cce861b76c9..9ce07a879f0 100644 --- a/src/test/ui/type-alias-impl-trait/not_a_defining_use.stderr +++ b/src/test/ui/type-alias-impl-trait/not_a_defining_use.stderr @@ -1,18 +1,14 @@ error: concrete type differs from previous defining opaque type use --> $DIR/not_a_defining_use.rs:29:1 | -LL | / fn four(t: T) -> Two { -LL | | (t, ::FOO) -LL | | } - | |_^ expected `(T, i8)`, got `(T, ::Blub)` +LL | fn four(t: T) -> Two { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `(T, i8)`, got `(T, ::Blub)` | note: previous use here --> $DIR/not_a_defining_use.rs:9:1 | -LL | / fn two(t: T) -> Two { -LL | | (t, 4i8) -LL | | } - | |_^ +LL | fn two(t: T) -> Two { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/ufcs/ufcs-explicit-self-bad.stderr b/src/test/ui/ufcs/ufcs-explicit-self-bad.stderr index d1232ad3f32..d7c48173571 100644 --- a/src/test/ui/ufcs/ufcs-explicit-self-bad.stderr +++ b/src/test/ui/ufcs/ufcs-explicit-self-bad.stderr @@ -37,7 +37,7 @@ note: the anonymous lifetime #1 defined on the method body at 37:5... --> $DIR/ufcs-explicit-self-bad.rs:37:5 | LL | fn dummy2(self: &Bar) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ note: ...does not necessarily outlive the lifetime `'a` as defined on the impl at 35:6 --> $DIR/ufcs-explicit-self-bad.rs:35:6 | @@ -61,7 +61,7 @@ note: ...does not necessarily outlive the anonymous lifetime #1 defined on the m --> $DIR/ufcs-explicit-self-bad.rs:37:5 | LL | fn dummy2(self: &Bar) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched `self` parameter type --> $DIR/ufcs-explicit-self-bad.rs:39:21 @@ -75,7 +75,7 @@ note: the anonymous lifetime #2 defined on the method body at 39:5... --> $DIR/ufcs-explicit-self-bad.rs:39:5 | LL | fn dummy3(self: &&Bar) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...does not necessarily outlive the lifetime `'a` as defined on the impl at 35:6 --> $DIR/ufcs-explicit-self-bad.rs:35:6 | @@ -99,7 +99,7 @@ note: ...does not necessarily outlive the anonymous lifetime #2 defined on the m --> $DIR/ufcs-explicit-self-bad.rs:39:5 | LL | fn dummy3(self: &&Bar) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 7 previous errors diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-recursive-fn.rs b/src/test/ui/unboxed-closures/unboxed-closures-infer-recursive-fn.rs index 86834f49407..a0fbbafe25f 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-infer-recursive-fn.rs +++ b/src/test/ui/unboxed-closures/unboxed-closures-infer-recursive-fn.rs @@ -7,7 +7,7 @@ // closure. As far as I can tell, coding up a recursive closure // requires the good ol' [Y Combinator]. // -// [Y Combinator]: http://en.wikipedia.org/wiki/Fixed-point_combinator#Y_combinator +// [Y Combinator]: https://en.wikipedia.org/wiki/Fixed-point_combinator#Y_combinator struct YCombinator { func: F, diff --git a/src/test/ui/unsized-locals/borrow-after-move.stderr b/src/test/ui/unsized-locals/borrow-after-move.stderr index 906b543e421..13f9507d8db 100644 --- a/src/test/ui/unsized-locals/borrow-after-move.stderr +++ b/src/test/ui/unsized-locals/borrow-after-move.stderr @@ -5,7 +5,7 @@ LL | let y = *x; | -- value moved here LL | drop_unsized(y); LL | println!("{}", &x); - | ^^ value borrowed here after partial move + | ^^ value borrowed here after move | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait @@ -27,7 +27,7 @@ LL | let y = *x; | -- value moved here LL | y.foo(); LL | println!("{}", &x); - | ^^ value borrowed here after partial move + | ^^ value borrowed here after move | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait diff --git a/src/test/ui/unsized-locals/double-move.stderr b/src/test/ui/unsized-locals/double-move.stderr index 49b2031c6b9..5b29314ad55 100644 --- a/src/test/ui/unsized-locals/double-move.stderr +++ b/src/test/ui/unsized-locals/double-move.stderr @@ -14,7 +14,7 @@ error[E0382]: use of moved value: `x` LL | let _y = *x; | -- value moved here LL | drop_unsized(x); - | ^ value used here after partial move + | ^ value used here after move | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait @@ -50,7 +50,7 @@ error[E0382]: use of moved value: `x` LL | let _y = *x; | -- value moved here LL | x.foo(); - | ^ value used here after partial move + | ^ value used here after move | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait diff --git a/src/tools/cargotest/main.rs b/src/tools/cargotest/main.rs index 269ab8042c0..b65163a3bc9 100644 --- a/src/tools/cargotest/main.rs +++ b/src/tools/cargotest/main.rs @@ -11,7 +11,7 @@ struct Test { packages: &'static [&'static str], } -const TEST_REPOS: &'static [Test] = &[ +const TEST_REPOS: &[Test] = &[ Test { name: "iron", repo: "https://github.com/iron/iron", @@ -53,9 +53,9 @@ struct Test { fn main() { let args = env::args().collect::>(); - let ref cargo = args[1]; + let cargo = &args[1]; let out_dir = Path::new(&args[2]); - let ref cargo = Path::new(cargo); + let cargo = &Path::new(cargo); for test in TEST_REPOS.iter().rev() { test_repo(cargo, out_dir, test); @@ -77,7 +77,7 @@ fn clone_repo(test: &Test, out_dir: &Path) -> PathBuf { let out_dir = out_dir.join(test.name); if !out_dir.join(".git").is_dir() { - let status = Command::new("git").arg("init").arg(&out_dir).status().expect(""); + let status = Command::new("git").arg("init").arg(&out_dir).status().unwrap(); assert!(status.success()); } @@ -92,7 +92,7 @@ fn clone_repo(test: &Test, out_dir: &Path) -> PathBuf { .arg(&format!("--depth={}", depth)) .current_dir(&out_dir) .status() - .expect(""); + .unwrap(); assert!(status.success()); } @@ -102,7 +102,7 @@ fn clone_repo(test: &Test, out_dir: &Path) -> PathBuf { .arg("--hard") .current_dir(&out_dir) .status() - .expect(""); + .unwrap(); if status.success() { found = true; @@ -133,7 +133,7 @@ fn run_cargo_test(cargo_path: &Path, crate_path: &Path, packages: &[&str]) -> bo .env("RUSTFLAGS", "--cap-lints warn") .current_dir(crate_path) .status() - .expect(""); + .unwrap(); status.success() } diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs index b7e2eba0a81..9fe771cef45 100644 --- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs @@ -340,6 +340,7 @@ fn take_pat(from: &mut Pat) -> Pat { id: DUMMY_NODE_ID, kind: Wild, span: DUMMY_SP, + tokens: None }; mem::replace(from, dummy) } diff --git a/src/tools/clippy/tests/ui/len_zero_ranges.fixed b/src/tools/clippy/tests/ui/len_zero_ranges.fixed index 7da26f8ff4d..eee3db9b7d4 100644 --- a/src/tools/clippy/tests/ui/len_zero_ranges.fixed +++ b/src/tools/clippy/tests/ui/len_zero_ranges.fixed @@ -3,6 +3,7 @@ #![feature(range_is_empty)] #![warn(clippy::len_zero)] #![allow(unused)] +#![allow(stable_features)] // TODO: https://github.com/rust-lang/rust-clippy/issues/5956 mod issue_3807 { // With the feature enabled, `is_empty` should be suggested diff --git a/src/tools/clippy/tests/ui/len_zero_ranges.rs b/src/tools/clippy/tests/ui/len_zero_ranges.rs index be7b4244bc0..be2e0f38fd1 100644 --- a/src/tools/clippy/tests/ui/len_zero_ranges.rs +++ b/src/tools/clippy/tests/ui/len_zero_ranges.rs @@ -3,6 +3,7 @@ #![feature(range_is_empty)] #![warn(clippy::len_zero)] #![allow(unused)] +#![allow(stable_features)] // TODO: https://github.com/rust-lang/rust-clippy/issues/5956 mod issue_3807 { // With the feature enabled, `is_empty` should be suggested diff --git a/src/tools/clippy/tests/ui/len_zero_ranges.stderr b/src/tools/clippy/tests/ui/len_zero_ranges.stderr index 6e5fa41fb08..acb85f7100a 100644 --- a/src/tools/clippy/tests/ui/len_zero_ranges.stderr +++ b/src/tools/clippy/tests/ui/len_zero_ranges.stderr @@ -1,5 +1,5 @@ error: length comparison to zero - --> $DIR/len_zero_ranges.rs:10:17 + --> $DIR/len_zero_ranges.rs:11:17 | LL | let _ = (0..42).len() == 0; | ^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(0..42).is_empty()` diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs index 8edc9c9cd03..054235ec16d 100644 --- a/src/tools/compiletest/src/errors.rs +++ b/src/tools/compiletest/src/errors.rs @@ -148,7 +148,7 @@ fn parse_expected( // If we find `//~ ERROR foo` or something like that, skip the first word. let kind = first_word.parse::().ok(); - if let Some(_) = kind { + if kind.is_some() { msg = &msg.trim_start().split_at(first_word.len()).1; } diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 90a0d8926ad..0efa668ecc8 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -173,10 +173,8 @@ fn ignore_lldb(config: &Config, line: &str) -> bool { // Ignore if actual version is smaller the minimum required // version actual_version < min_version - } else if line.starts_with("rust-lldb") && !config.lldb_native_rust { - true } else { - false + line.starts_with("rust-lldb") && !config.lldb_native_rust } } else { false @@ -657,7 +655,6 @@ fn iter_header(testfile: &Path, cfg: Option<&str>, rdr: R, it: &mut dyn it(ln[comment.len()..].trim_start()); } } - return; } impl Config { @@ -819,7 +816,7 @@ fn parse_cfg_name_directive(&self, line: &str, prefix: &str) -> ParsedNameDirect let name = line[prefix.len() + 1..].split(&[':', ' '][..]).next().unwrap(); let is_match = name == "test" || - &self.target == name || // triple + self.target == name || // triple util::matches_os(&self.target, name) || // target util::matches_env(&self.target, name) || // env self.target.ends_with(name) || // target and env @@ -857,10 +854,7 @@ fn parse_name_directive(&self, line: &str, directive: &str) -> bool { // Ensure the directive is a whole word. Do not match "ignore-x86" when // the line says "ignore-x86_64". line.starts_with(directive) - && match line.as_bytes().get(directive.len()) { - None | Some(&b' ') | Some(&b':') => true, - _ => false, - } + && matches!(line.as_bytes().get(directive.len()), None | Some(&b' ') | Some(&b':')) } pub fn parse_name_value_directive(&self, line: &str, directive: &str) -> Option { @@ -901,9 +895,9 @@ fn parse_edition(&self, line: &str) -> Option { } fn expand_variables(mut value: String, config: &Config) -> String { - const CWD: &'static str = "{{cwd}}"; - const SRC_BASE: &'static str = "{{src-base}}"; - const BUILD_BASE: &'static str = "{{build-base}}"; + const CWD: &str = "{{cwd}}"; + const SRC_BASE: &str = "{{src-base}}"; + const BUILD_BASE: &str = "{{build-base}}"; if value.contains(CWD) { let cwd = env::current_dir().unwrap(); diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs index 6ac7c3b9b47..6a03a76c566 100644 --- a/src/tools/compiletest/src/json.rs +++ b/src/tools/compiletest/src/json.rs @@ -75,7 +75,7 @@ pub fn extract_rendered(output: &str) -> String { if line.starts_with('{') { if let Ok(diagnostic) = serde_json::from_str::(line) { diagnostic.rendered - } else if let Ok(_) = serde_json::from_str::(line) { + } else if serde_json::from_str::(line).is_ok() { // Ignore the notification. None } else { diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 46e16393a24..adf2fa7fd8e 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -240,7 +240,7 @@ fn make_absolute(path: PathBuf) -> PathBuf { cc: matches.opt_str("cc").unwrap(), cxx: matches.opt_str("cxx").unwrap(), cflags: matches.opt_str("cflags").unwrap(), - ar: matches.opt_str("ar").unwrap_or("ar".into()), + ar: matches.opt_str("ar").unwrap_or_else(|| String::from("ar")), linker: matches.opt_str("linker"), llvm_components: matches.opt_str("llvm-components").unwrap(), nodejs: matches.opt_str("nodejs"), @@ -361,17 +361,13 @@ pub fn run_tests(config: Config) { } fn configure_cdb(config: &Config) -> Option { - if config.cdb.is_none() { - return None; - } + config.cdb.as_ref()?; Some(Config { debugger: Some(Debugger::Cdb), ..config.clone() }) } fn configure_gdb(config: &Config) -> Option { - if config.gdb_version.is_none() { - return None; - } + config.gdb_version?; if util::matches_env(&config.target, "msvc") { return None; @@ -405,9 +401,7 @@ fn configure_gdb(config: &Config) -> Option { } fn configure_lldb(config: &Config) -> Option { - if config.lldb_python_dir.is_none() { - return None; - } + config.lldb_python_dir.as_ref()?; if let Some(350) = config.lldb_version { println!( @@ -455,7 +449,7 @@ pub fn make_tests(config: &Config, tests: &mut Vec) { debug!("making tests from {:?}", config.src_base.display()); let inputs = common_inputs_stamp(config); collect_tests_from_dir(config, &config.src_base, &PathBuf::new(), &inputs, tests) - .expect(&format!("Could not read tests from {}", config.src_base.display())); + .unwrap_or_else(|_| panic!("Could not read tests from {}", config.src_base.display())); } /// Returns a stamp constructed from input files common to all test cases. @@ -588,7 +582,7 @@ fn make_test(config: &Config, testpaths: &TestPaths, inputs: &Stamp) -> Vec bool { - match &target[..] { - "arm-linux-androideabi" | "armv7-linux-androideabi" | "aarch64-linux-android" => true, - _ => false, - } +fn is_android_gdb_target(target: &str) -> bool { + matches!( + &target[..], + "arm-linux-androideabi" | "armv7-linux-androideabi" | "aarch64-linux-android" + ) } /// Returns `true` if the given target is a MSVC target for the purpouses of CDB testing. -fn is_pc_windows_msvc_target(target: &String) -> bool { +fn is_pc_windows_msvc_target(target: &str) -> bool { target.ends_with("-pc-windows-msvc") } -fn find_cdb(target: &String) -> Option { +fn find_cdb(target: &str) -> Option { if !(cfg!(windows) && is_pc_windows_msvc_target(target)) { return None; } - let pf86 = env::var_os("ProgramFiles(x86)").or(env::var_os("ProgramFiles"))?; + let pf86 = env::var_os("ProgramFiles(x86)").or_else(|| env::var_os("ProgramFiles"))?; let cdb_arch = if cfg!(target_arch = "x86") { "x86" } else if cfg!(target_arch = "x86_64") { @@ -779,14 +773,14 @@ fn find_cdb(target: &String) -> Option { } /// Returns Path to CDB -fn analyze_cdb(cdb: Option, target: &String) -> Option { - cdb.map(|s| OsString::from(s)).or(find_cdb(target)) +fn analyze_cdb(cdb: Option, target: &str) -> Option { + cdb.map(OsString::from).or_else(|| find_cdb(target)) } /// Returns (Path to GDB, GDB Version, GDB has Rust Support) fn analyze_gdb( gdb: Option, - target: &String, + target: &str, android_cross_path: &PathBuf, ) -> (Option, Option, bool) { #[cfg(not(windows))] diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 03136921ad6..124a9adcab9 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -114,7 +114,7 @@ pub struct Mismatch { impl Mismatch { fn new(line_number: u32) -> Mismatch { - Mismatch { line_number: line_number, lines: Vec::new() } + Mismatch { line_number, lines: Vec::new() } } } @@ -199,7 +199,7 @@ fn write_diff(expected: &str, actual: &str, context_size: usize) -> String { } } } - writeln!(output, "").unwrap(); + writeln!(output).unwrap(); } output } @@ -230,7 +230,7 @@ pub fn run(config: Config, testpaths: &TestPaths, revision: Option<&str>) { debug!("running {:?}", testpaths.file.display()); let props = TestProps::from_file(&testpaths.file, revision, &config); - let cx = TestCx { config: &config, props: &props, testpaths, revision: revision }; + let cx = TestCx { config: &config, props: &props, testpaths, revision }; create_dir_all(&cx.output_base_dir()).unwrap(); if config.mode == Incremental { @@ -578,8 +578,8 @@ fn run_pretty_test(&self) { if self.props.pp_exact.is_some() { // Now we have to care about line endings let cr = "\r".to_owned(); - actual = actual.replace(&cr, "").to_owned(); - expected = expected.replace(&cr, "").to_owned(); + actual = actual.replace(&cr, ""); + expected = expected.replace(&cr, ""); } self.compare_source(&expected, &actual); @@ -740,7 +740,7 @@ fn run_debuginfo_cdb_test_no_opt(&self) { let exe_file = self.make_exe_name(); let prefixes = { - static PREFIXES: &'static [&'static str] = &["cdb", "cdbg"]; + static PREFIXES: &[&str] = &["cdb", "cdbg"]; // No "native rust support" variation for CDB yet. PREFIXES }; @@ -811,12 +811,12 @@ fn run_debuginfo_gdb_test(&self) { fn run_debuginfo_gdb_test_no_opt(&self) { let prefixes = if self.config.gdb_native_rust { // GDB with Rust - static PREFIXES: &'static [&'static str] = &["gdb", "gdbr"]; + static PREFIXES: &[&str] = &["gdb", "gdbr"]; println!("NOTE: compiletest thinks it is using GDB with native rust support"); PREFIXES } else { // Generic GDB - static PREFIXES: &'static [&'static str] = &["gdb", "gdbg"]; + static PREFIXES: &[&str] = &["gdb", "gdbg"]; println!("NOTE: compiletest thinks it is using GDB without native rust support"); PREFIXES }; @@ -875,12 +875,12 @@ fn run_debuginfo_gdb_test_no_opt(&self) { .arg(&exe_file) .arg(&self.config.adb_test_dir) .status() - .expect(&format!("failed to exec `{:?}`", adb_path)); + .unwrap_or_else(|_| panic!("failed to exec `{:?}`", adb_path)); Command::new(adb_path) .args(&["forward", "tcp:5039", "tcp:5039"]) .status() - .expect(&format!("failed to exec `{:?}`", adb_path)); + .unwrap_or_else(|_| panic!("failed to exec `{:?}`", adb_path)); let adb_arg = format!( "export LD_LIBRARY_PATH={}; \ @@ -897,7 +897,7 @@ fn run_debuginfo_gdb_test_no_opt(&self) { .stdout(Stdio::piped()) .stderr(Stdio::inherit()) .spawn() - .expect(&format!("failed to exec `{:?}`", adb_path)); + .unwrap_or_else(|_| panic!("failed to exec `{:?}`", adb_path)); // Wait for the gdbserver to print out "Listening on port ..." // at which point we know that it's started and then we can @@ -922,7 +922,7 @@ fn run_debuginfo_gdb_test_no_opt(&self) { let Output { status, stdout, stderr } = Command::new(&gdb_path) .args(debugger_opts) .output() - .expect(&format!("failed to exec `{:?}`", gdb_path)); + .unwrap_or_else(|_| panic!("failed to exec `{:?}`", gdb_path)); let cmdline = { let mut gdb = Command::new(&format!("{}-gdb", self.config.target)); gdb.args(debugger_opts); @@ -1063,11 +1063,11 @@ fn run_debuginfo_lldb_test_no_opt(&self) { } let prefixes = if self.config.lldb_native_rust { - static PREFIXES: &'static [&'static str] = &["lldb", "lldbr"]; + static PREFIXES: &[&str] = &["lldb", "lldbr"]; println!("NOTE: compiletest thinks it is using LLDB with native rust support"); PREFIXES } else { - static PREFIXES: &'static [&'static str] = &["lldb", "lldbg"]; + static PREFIXES: &[&str] = &["lldb", "lldbg"]; println!("NOTE: compiletest thinks it is using LLDB without native rust support"); PREFIXES }; @@ -1842,8 +1842,8 @@ fn compose_and_run( // Need to be sure to put both the lib_path and the aux path in the dylib // search path for the child. - let mut path = env::split_paths(&env::var_os(dylib_env_var()).unwrap_or(OsString::new())) - .collect::>(); + let mut path = + env::split_paths(&env::var_os(dylib_env_var()).unwrap_or_default()).collect::>(); if let Some(p) = aux_path { path.insert(0, PathBuf::from(p)) } @@ -1854,7 +1854,7 @@ fn compose_and_run( command.env(dylib_env_var(), newpath); let mut child = disable_error_reporting(|| command.spawn()) - .expect(&format!("failed to exec `{:?}`", &command)); + .unwrap_or_else(|_| panic!("failed to exec `{:?}`", &command)); if let Some(input) = input { child.stdin.as_mut().unwrap().write_all(input.as_bytes()).unwrap(); } @@ -1942,6 +1942,7 @@ fn make_compile_args( rustc.args(&[ "-Zdump-mir=all", "-Zmir-opt-level=3", + "-Zvalidate-mir", "-Zdump-mir-exclude-pass-number", ]); @@ -2445,8 +2446,8 @@ fn run_codegen_units_test(&self) { self.check_no_compiler_crash(&proc_res, self.props.should_ice); - const PREFIX: &'static str = "MONO_ITEM "; - const CGU_MARKER: &'static str = "@@"; + const PREFIX: &str = "MONO_ITEM "; + const CGU_MARKER: &str = "@@"; let actual: Vec = proc_res .stdout @@ -2975,7 +2976,7 @@ fn run_ui_test(&self) { Filter::MachineApplicableOnly, ) .unwrap_or_default(); - if suggestions.len() > 0 + if !suggestions.is_empty() && !self.props.run_rustfix && !self.props.rustfix_only_machine_applicable { @@ -2989,7 +2990,7 @@ fn run_ui_test(&self) { .open(coverage_file_path.as_path()) .expect("could not create or open file"); - if let Err(_) = writeln!(file, "{}", self.testpaths.file.display()) { + if writeln!(file, "{}", self.testpaths.file.display()).is_err() { panic!("couldn't write to {}", coverage_file_path.display()); } } @@ -3006,10 +3007,9 @@ fn run_ui_test(&self) { }, ) .unwrap(); - let fixed_code = apply_suggestions(&unfixed_code, &suggestions).expect(&format!( - "failed to apply suggestions for {:?} with rustfix", - self.testpaths.file - )); + let fixed_code = apply_suggestions(&unfixed_code, &suggestions).unwrap_or_else(|_| { + panic!("failed to apply suggestions for {:?} with rustfix", self.testpaths.file) + }); errors += self.compare_output("fixed", &fixed_code, &expected_fixed); } else if !expected_fixed.is_empty() { @@ -3518,7 +3518,7 @@ fn prune_duplicate_output(&self, mode: CompareMode, kind: &str, canon_content: & let examined_content = self.load_expected_output_from_path(&examined_path).unwrap_or_else(|_| String::new()); - if canon_content == &examined_content { + if canon_content == examined_content { self.delete_file(&examined_path); } } diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index cc4b21f9efb..1a727fc2b82 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -9,7 +9,7 @@ mod tests; /// Conversion table from triple OS name to Rust SYSNAME -const OS_TABLE: &'static [(&'static str, &'static str)] = &[ +const OS_TABLE: &[(&str, &str)] = &[ ("android", "android"), ("androideabi", "android"), ("cloudabi", "cloudabi"), @@ -37,7 +37,7 @@ ("vxworks", "vxworks"), ]; -const ARCH_TABLE: &'static [(&'static str, &'static str)] = &[ +const ARCH_TABLE: &[(&str, &str)] = &[ ("aarch64", "aarch64"), ("amd64", "x86_64"), ("arm", "arm"), @@ -82,7 +82,7 @@ ("xcore", "xcore"), ]; -pub const ASAN_SUPPORTED_TARGETS: &'static [&'static str] = &[ +pub const ASAN_SUPPORTED_TARGETS: &[&str] = &[ "aarch64-fuchsia", "aarch64-unknown-linux-gnu", "x86_64-apple-darwin", @@ -91,20 +91,20 @@ "x86_64-unknown-linux-gnu", ]; -pub const LSAN_SUPPORTED_TARGETS: &'static [&'static str] = +pub const LSAN_SUPPORTED_TARGETS: &[&str] = &["aarch64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu"]; -pub const MSAN_SUPPORTED_TARGETS: &'static [&'static str] = +pub const MSAN_SUPPORTED_TARGETS: &[&str] = &["aarch64-unknown-linux-gnu", "x86_64-unknown-freebsd", "x86_64-unknown-linux-gnu"]; -pub const TSAN_SUPPORTED_TARGETS: &'static [&'static str] = &[ +pub const TSAN_SUPPORTED_TARGETS: &[&str] = &[ "aarch64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-unknown-freebsd", "x86_64-unknown-linux-gnu", ]; -const BIG_ENDIAN: &'static [&'static str] = &[ +const BIG_ENDIAN: &[&str] = &[ "armebv7r", "mips", "mips64", @@ -195,11 +195,11 @@ pub trait PathBufExt { impl PathBufExt for PathBuf { fn with_extra_extension>(&self, extension: S) -> PathBuf { - if extension.as_ref().len() == 0 { + if extension.as_ref().is_empty() { self.clone() } else { let mut fname = self.file_name().unwrap().to_os_string(); - if !extension.as_ref().to_str().unwrap().starts_with(".") { + if !extension.as_ref().to_str().unwrap().starts_with('.') { fname.push("."); } fname.push(extension); diff --git a/src/tools/expand-yaml-anchors/src/main.rs b/src/tools/expand-yaml-anchors/src/main.rs index d8dad8fc789..f7ff64036a1 100644 --- a/src/tools/expand-yaml-anchors/src/main.rs +++ b/src/tools/expand-yaml-anchors/src/main.rs @@ -48,8 +48,8 @@ fn from_args() -> Result> { // Parse CLI arguments let args = std::env::args().skip(1).collect::>(); let (mode, base) = match args.iter().map(|s| s.as_str()).collect::>().as_slice() { - &["generate", ref base] => (Mode::Generate, PathBuf::from(base)), - &["check", ref base] => (Mode::Check, PathBuf::from(base)), + ["generate", ref base] => (Mode::Generate, PathBuf::from(base)), + ["check", ref base] => (Mode::Check, PathBuf::from(base)), _ => { eprintln!("usage: expand-yaml-anchors "); std::process::exit(1); @@ -138,9 +138,7 @@ fn filter_document(document: Yaml) -> Yaml { .map(|(key, value)| (filter_document(key), filter_document(value))) .collect(), ), - Yaml::Array(vec) => { - Yaml::Array(vec.into_iter().map(|item| filter_document(item)).collect()) - } + Yaml::Array(vec) => Yaml::Array(vec.into_iter().map(filter_document).collect()), other => other, } } diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index 194318d7a59..b7ceba1e282 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -172,10 +172,10 @@ fn check(cache: &mut Cache, root: &Path, file: &Path, errors: &mut bool) -> Opti { return; } - let mut parts = url.splitn(2, "#"); + let mut parts = url.splitn(2, '#'); let url = parts.next().unwrap(); let fragment = parts.next(); - let mut parts = url.splitn(2, "?"); + let mut parts = url.splitn(2, '?'); let url = parts.next().unwrap(); // Once we've plucked out the URL, parse it using our base url and @@ -258,7 +258,7 @@ fn check(cache: &mut Cache, root: &Path, file: &Path, errors: &mut bool) -> Opti } // These appear to be broken in mdbook right now? - if fragment.starts_with("-") { + if fragment.starts_with('-') { return; } @@ -324,7 +324,7 @@ fn load_file( } fn maybe_redirect(source: &str) -> Option { - const REDIRECT: &'static str = "

Redirecting to Redirecting to (contents: &str, attr: &str, }; let quote_delim = rest.as_bytes()[pos_quote] as char; - if rest[..pos_quote].trim_start_matches(" ") != "" { + if rest[..pos_quote].trim_start_matches(' ') != "" { continue; } let rest = &rest[pos_quote + 1..]; diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index 72b3df8377a..51416c8ce63 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -275,7 +275,7 @@ def update_latest( return message -if __name__ == '__main__': +def main(): repo = os.environ.get('TOOLSTATE_VALIDATE_MAINTAINERS_REPO') if repo: github_token = os.environ.get('TOOLSTATE_REPO_ACCESS_TOKEN') @@ -342,3 +342,11 @@ if __name__ == '__main__': } )) response.read() + + +if __name__ == '__main__': + try: + main() + except urllib2.HTTPError as e: + print("HTTPError: %s\n%s" % (e, e.read())) + raise diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer index 0b2b9a55081..e65d48d1fb3 160000 --- a/src/tools/rust-analyzer +++ b/src/tools/rust-analyzer @@ -1 +1 @@ -Subproject commit 0b2b9a5508186c16a2e782f47ce7e0e1c5fb8d33 +Subproject commit e65d48d1fb3d4d91d9dc1148a7a836ff5c9a3c87 diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml index f984e5b61a5..ccdb4524d5c 100644 --- a/src/tools/tidy/Cargo.toml +++ b/src/tools/tidy/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Alex Crichton "] edition = "2018" [dependencies] -cargo_metadata = "0.9.1" +cargo_metadata = "0.11" regex = "1" lazy_static = "1" walkdir = "2" diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 4f98944e4c8..af3fb403703 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -85,11 +85,13 @@ "crossbeam-queue", "crossbeam-utils", "datafrog", + "difference", "digest", "dlmalloc", "either", "ena", "env_logger", + "expect-test", "fake-simd", "filetime", "flate2", diff --git a/src/tools/tidy/src/error_codes_check.rs b/src/tools/tidy/src/error_codes_check.rs index 2fa0f12d7e8..82a5234ac5b 100644 --- a/src/tools/tidy/src/error_codes_check.rs +++ b/src/tools/tidy/src/error_codes_check.rs @@ -47,9 +47,7 @@ fn check_error_code_explanation( invalid_compile_fail_format } -fn check_if_error_code_is_test_in_explanation(f: &str, err_code: &String) -> bool { - let mut can_be_ignored = false; - +fn check_if_error_code_is_test_in_explanation(f: &str, err_code: &str) -> bool { for line in f.lines() { let s = line.trim(); if s.starts_with("#### Note: this error code is no longer emitted by the compiler") { @@ -58,13 +56,13 @@ fn check_if_error_code_is_test_in_explanation(f: &str, err_code: &String) -> boo if s.starts_with("```") { if s.contains("compile_fail") && s.contains(err_code) { return true; - } else if s.contains("(") { + } else if s.contains('(') { // It's very likely that we can't actually make it fail compilation... - can_be_ignored = true; + return true; } } } - can_be_ignored + false } macro_rules! some_or_continue { diff --git a/src/tools/unicode-table-generator/src/main.rs b/src/tools/unicode-table-generator/src/main.rs index d2d1807b3bb..218e9668df4 100644 --- a/src/tools/unicode-table-generator/src/main.rs +++ b/src/tools/unicode-table-generator/src/main.rs @@ -315,7 +315,7 @@ fn version() -> String { fn fmt_list(values: impl IntoIterator) -> String { let pieces = values.into_iter().map(|b| format!("{:?}, ", b)).collect::>(); let mut out = String::new(); - let mut line = format!("\n "); + let mut line = String::from("\n "); for piece in pieces { if line.len() + piece.len() < 98 { line.push_str(&piece); diff --git a/src/tools/unicode-table-generator/src/raw_emitter.rs b/src/tools/unicode-table-generator/src/raw_emitter.rs index 63cc29b670f..42e7e5fb406 100644 --- a/src/tools/unicode-table-generator/src/raw_emitter.rs +++ b/src/tools/unicode-table-generator/src/raw_emitter.rs @@ -20,7 +20,7 @@ fn blank_line(&mut self) { if self.file.is_empty() || self.file.ends_with("\n\n") { return; } - writeln!(&mut self.file, "").unwrap(); + writeln!(&mut self.file).unwrap(); } fn emit_bitset(&mut self, ranges: &[Range]) { @@ -161,10 +161,10 @@ pub fn emit_codepoints(emitter: &mut RawEmitter, ranges: &[Range]) { if bitset.bytes_used <= skiplist.bytes_used { *emitter = bitset; - emitter.desc = format!("bitset"); + emitter.desc = String::from("bitset"); } else { *emitter = skiplist; - emitter.desc = format!("skiplist"); + emitter.desc = String::from("skiplist"); } } @@ -289,7 +289,7 @@ enum UniqueMapping { // Remove the now-canonicalized word from other mappings, // to ensure that we deprioritize them in the next iteration of // the while loop. - for (_, mapped) in &mut mappings { + for mapped in mappings.values_mut() { let mut i = 0; while i != mapped.len() { if mapped[i].0 == *from { @@ -309,7 +309,7 @@ enum UniqueMapping { // Remove the now-canonical word from other mappings, to ensure that // we deprioritize them in the next iteration of the while loop. - for (_, mapped) in &mut mappings { + for mapped in mappings.values_mut() { let mut i = 0; while i != mapped.len() { if mapped[i].0 == to { diff --git a/src/tools/unstable-book-gen/src/main.rs b/src/tools/unstable-book-gen/src/main.rs index 11617911446..5d277e1c41f 100644 --- a/src/tools/unstable-book-gen/src/main.rs +++ b/src/tools/unstable-book-gen/src/main.rs @@ -94,9 +94,9 @@ fn copy_recursive(from: &Path, to: &Path) { } fn main() { - let library_path_str = env::args_os().skip(1).next().expect("library path required"); - let src_path_str = env::args_os().skip(2).next().expect("source path required"); - let dest_path_str = env::args_os().skip(3).next().expect("destination path required"); + let library_path_str = env::args_os().nth(1).expect("library path required"); + let src_path_str = env::args_os().nth(2).expect("source path required"); + let dest_path_str = env::args_os().nth(3).expect("destination path required"); let library_path = Path::new(&library_path_str); let src_path = Path::new(&src_path_str); let dest_path = Path::new(&dest_path_str);