- 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
[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
Markus Westerlind <marwes91@gmail.com> Markus <marwes91@gmail.com>
Martin Hafskjold Thoresen <martinhath@gmail.com>
Matej Lach <matej.lach@gmail.com> Matej Ľach <matej.lach@gmail.com>
-Mateusz Mikuła <matti@marinelayer.io> <mati865@gmail.com>
-Mateusz Mikuła <matti@marinelayer.io> <mati865@users.noreply.github.com>
+Mateusz Mikuła <mati865@gmail.com> <mati865@users.noreply.github.com>
+Mateusz Mikuła <mati865@gmail.com> <matti@marinelayer.io>
Matt Brubeck <mbrubeck@limpet.net> <mbrubeck@cs.hmc.edu>
Matthew Auld <matthew.auld@intel.com>
Matthew Kraai <kraai@ftbfs.org>
"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"
"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"
name = "rustc_lexer"
version = "0.1.0"
dependencies = [
+ "expect-test",
"unicode-xid",
]
name = "tidy"
version = "0.1.0"
dependencies = [
- "cargo_metadata 0.9.1",
+ "cargo_metadata 0.11.1",
"lazy_static",
"regex",
"walkdir",
#![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)]
///
/// 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;
///
/// See [`GlobalAlloc::alloc`].
///
-/// [`Global`]: struct.Global.html
-/// [`AllocRef`]: trait.AllocRef.html
-/// [`GlobalAlloc::alloc`]: trait.GlobalAlloc.html#tymethod.alloc
-///
/// # Examples
///
/// ```
/// # 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) {
/// # 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 {
///
/// See [`GlobalAlloc::alloc_zeroed`].
///
-/// [`Global`]: struct.Global.html
-/// [`AllocRef`]: trait.AllocRef.html
-/// [`GlobalAlloc::alloc_zeroed`]: trait.GlobalAlloc.html#method.alloc_zeroed
-///
/// # Examples
///
/// ```
unsafe fn grow_impl(
&mut self,
ptr: NonNull<u8>,
- layout: Layout,
- new_size: usize,
+ old_layout: Layout,
+ new_layout: Layout,
zeroed: bool,
) -> Result<NonNull<[u8]>, 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)
+ },
}
}
}
unsafe fn grow(
&mut self,
ptr: NonNull<u8>,
- layout: Layout,
- new_size: usize,
+ old_layout: Layout,
+ new_layout: Layout,
) -> Result<NonNull<[u8]>, 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<u8>,
- layout: Layout,
- new_size: usize,
+ old_layout: Layout,
+ new_layout: Layout,
) -> Result<NonNull<[u8]>, 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<u8>,
- layout: Layout,
- new_size: usize,
+ old_layout: Layout,
+ new_layout: Layout,
) -> Result<NonNull<[u8]>, 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)
+ },
}
}
}
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),
}
}
//! 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<T>`]: struct.Box.html
-//! [`Box::<T>::from_raw(value)`]: struct.Box.html#method.from_raw
-//! [`Box::<T>::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<T>`]: Box
+//! [`Box::<T>::from_raw(value)`]: Box::from_raw
+//! [`Box::<T>::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")]
/// Converts a `Box<T>` 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<T>) -> Box<[T]> {
// *mut T and *mut [T; 1] have the same size and alignment
pub fn new_uninit_slice(len: usize) -> Box<[mem::MaybeUninit<T>]> {
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<T>]> {
+ unsafe { RawVec::with_capacity_zeroed(len).into_box(len) }
+ }
}
impl<T> Box<mem::MaybeUninit<T>> {
/// }
/// ```
///
- /// [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 {
/// }
/// ```
///
- /// [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<T>) -> *mut T {
/// 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:
//! 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
//!
//! ```
//! 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")]
/// 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<NonNull<Node<T>>>,
/// 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`
/// (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<T> {
//! 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")]
/// 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();
//! 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")]
#![feature(or_patterns)]
#![feature(pattern)]
#![feature(ptr_internals)]
-#![feature(ptr_offset_from)]
#![feature(raw_ref_op)]
#![feature(rustc_attrs)]
#![feature(receiver_trait)]
#![feature(alloc_layout_extra)]
#![feature(try_trait)]
#![feature(associated_type_bounds)]
-
// Allow testing this library
#[cfg(test)]
/// 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")]
/// 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
///
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};
let new_size = amount * mem::size_of::<T>();
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: (),
})?
};
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<T, A> {
//! }
//! ```
//!
-//! [`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")]
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;
#[unstable(feature = "new_uninit", issue = "63291")]
pub fn new_uninit() -> Rc<mem::MaybeUninit<T>> {
unsafe {
- Rc::from_ptr(Rc::allocate_for_layout(Layout::new::<T>(), |mem| {
- mem as *mut RcBox<mem::MaybeUninit<T>>
- }))
+ Rc::from_ptr(Rc::allocate_for_layout(
+ Layout::new::<T>(),
+ |layout| Global.alloc(layout),
+ |mem| mem as *mut RcBox<mem::MaybeUninit<T>>,
+ ))
}
}
#[unstable(feature = "new_uninit", issue = "63291")]
pub fn new_zeroed() -> Rc<mem::MaybeUninit<T>> {
unsafe {
- let mut uninit = Self::new_uninit();
- ptr::write_bytes::<T>(Rc::get_mut_unchecked(&mut uninit).as_mut_ptr(), 0, 1);
- uninit
+ Rc::from_ptr(Rc::allocate_for_layout(
+ Layout::new::<T>(),
+ |layout| Global.alloc_zeroed(layout),
+ |mem| mem as *mut RcBox<mem::MaybeUninit<T>>,
+ ))
}
}
/// 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
///
/// ```
pub fn new_uninit_slice(len: usize) -> Rc<[mem::MaybeUninit<T>]> {
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<T>]> {
+ unsafe {
+ Rc::from_ptr(Rc::allocate_for_layout(
+ Layout::array::<T>(len).unwrap(),
+ |layout| Global.alloc_zeroed(layout),
+ |mem| {
+ ptr::slice_from_raw_parts_mut(mem as *mut T, len)
+ as *mut RcBox<[mem::MaybeUninit<T>]>
+ },
+ ))
+ }
+ }
}
impl<T> Rc<mem::MaybeUninit<T>> {
/// 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
///
/// This function is unsafe because improper use may lead to memory unsafety,
/// even if the returned `Rc<T>` 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
///
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
///
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
///
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.
/// 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
///
///
/// 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
///
/// 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()
}
///
/// 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
///
/// and must return back a (potentially fat)-pointer for the `RcBox<T>`.
unsafe fn allocate_for_layout(
value_layout: Layout,
+ allocate: impl FnOnce(Layout) -> Result<NonNull<[u8]>, AllocErr>,
mem_to_rcbox: impl FnOnce(*mut u8) -> *mut RcBox<T>,
) -> *mut RcBox<T> {
// Calculate layout using the given value layout.
let layout = Layout::new::<RcBox<()>>().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());
unsafe fn allocate_for_ptr(ptr: *const T) -> *mut RcBox<T> {
// Allocate for the `RcBox<T>` 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<T>
- })
+ Self::allocate_for_layout(
+ Layout::for_value(&*ptr),
+ |layout| Global.alloc(layout),
+ |mem| set_data_ptr(ptr as *mut T, mem) as *mut RcBox<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::<T>(len).unwrap(), |mem| {
- ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut RcBox<[T]>
- })
+ Self::allocate_for_layout(
+ Layout::array::<T>(len).unwrap(),
+ |layout| Global.alloc(layout),
+ |mem| ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut RcBox<[T]>,
+ )
}
}
}
/// drop(foo); // Doesn't print anything
/// drop(foo2); // Prints "dropped!"
/// ```
- ///
- /// [`Weak`]: ../../std/rc/struct.Weak.html
fn drop(&mut self) {
unsafe {
self.dec_strong();
///
/// 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<T: ?Sized> {
// This is a `NonNull` to allow optimizing the size of this type in enums,
/// Constructs a new `Weak<T>`, 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
///
/// // 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<T> = NonNull::as_ptr(self.ptr);
/// 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();
/// 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() {
///
/// Returns [`None`] if the inner value has since been dropped.
///
- /// [`Rc`]: struct.Rc.html
- /// [`None`]: ../../std/option/enum.Option.html
- ///
/// # Examples
///
/// ```
/// 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 }
/// 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 {
/// Constructs a new `Weak<T>`, 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
///
#[stable(feature = "pin", since = "1.33.0")]
impl<T: ?Sized> Unpin for Rc<T> {}
-/// Get the offset within an `ArcInner` for
+/// Get the offset within an `RcBox` for
/// a payload of type described by a pointer.
///
/// # Safety
//! * 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
///
/// 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<u8> {
///
/// 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<u8> {
///
/// 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)]
///
/// [`Utf8Error`]: core::str::Utf8Error
/// [`std::str`]: core::str
-/// [`&str`]: str
+/// [`&str`]: prim@str
/// [`utf8_error`]: Self::utf8_error
///
/// # Examples
///
/// [`from_utf8_unchecked`]: String::from_utf8_unchecked
/// [`Vec<u8>`]: crate::vec::Vec
- /// [`&str`]: str
+ /// [`&str`]: prim@str
/// [`into_bytes`]: String::into_bytes
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
///
/// This will drop any excess capacity.
///
+ /// [`str`]: prim@str
+ ///
/// # Examples
///
/// Basic usage:
/// on using it.
///
/// [`std::str`]: core::str
- /// [`&str`]: str
+ /// [`&str`]: prim@str
///
/// # Examples
///
//! Thread-safe reference-counting pointers.
//!
-//! See the [`Arc<T>`][arc] documentation for more details.
-//!
-//! [arc]: struct.Arc.html
+//! See the [`Arc<T>`][Arc] documentation for more details.
use core::any::Any;
use core::borrow;
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;
/// ## 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<T>`][arc] and [`Weak<T>`][weak].
+/// `Clone` trait implemented for [`Arc<T>`][Arc] and [`Weak<T>`][Weak].
///
/// ```
/// use std::sync::Arc;
/// Arc::downgrade(&my_arc);
/// ```
///
-/// [`Weak<T>`][weak] does not auto-dereference to `T`, because the inner value may have
+/// [`Weak<T>`][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<T>`]: ../../std/rc/struct.Rc.html
-/// [clone]: ../../std/clone/trait.Clone.html#tymethod.clone
+/// [`Rc<T>`]: 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<T>`]: ../../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<T>`]: core::cell::RefCell
/// [`std::sync`]: ../../std/sync/index.html
/// [`Arc::clone(&from)`]: #method.clone
///
///
/// Sharing a mutable [`AtomicUsize`]:
///
-/// [`AtomicUsize`]: ../../std/sync/atomic/struct.AtomicUsize.html
+/// [`AtomicUsize`]: core::sync::atomic::AtomicUsize
///
/// ```no_run
/// use std::sync::Arc;
///
/// 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<T: ?Sized> {
// This is a `NonNull` to allow optimizing the size of this type in enums,
Self::from_inner(Box::leak(x).into())
}
+ /// Constructs a new `Arc<T>` 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<Foo>,
+ /// }
+ ///
+ /// 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>) -> T) -> Arc<T> {
+ // 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::<T>::uninit(),
+ })
+ .into();
+ let init_ptr: NonNull<ArcInner<T>> = 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
#[unstable(feature = "new_uninit", issue = "63291")]
pub fn new_uninit() -> Arc<mem::MaybeUninit<T>> {
unsafe {
- Arc::from_ptr(Arc::allocate_for_layout(Layout::new::<T>(), |mem| {
- mem as *mut ArcInner<mem::MaybeUninit<T>>
- }))
+ Arc::from_ptr(Arc::allocate_for_layout(
+ Layout::new::<T>(),
+ |layout| Global.alloc(layout),
+ |mem| mem as *mut ArcInner<mem::MaybeUninit<T>>,
+ ))
}
}
#[unstable(feature = "new_uninit", issue = "63291")]
pub fn new_zeroed() -> Arc<mem::MaybeUninit<T>> {
unsafe {
- let mut uninit = Self::new_uninit();
- ptr::write_bytes::<T>(Arc::get_mut_unchecked(&mut uninit).as_mut_ptr(), 0, 1);
- uninit
+ Arc::from_ptr(Arc::allocate_for_layout(
+ Layout::new::<T>(),
+ |layout| Global.alloc_zeroed(layout),
+ |mem| mem as *mut ArcInner<mem::MaybeUninit<T>>,
+ ))
}
}
/// 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
///
/// ```
}
impl<T> Arc<[T]> {
- /// Constructs a new reference-counted slice with uninitialized contents.
+ /// Constructs a new atomically reference-counted slice with uninitialized contents.
///
/// # Examples
///
pub fn new_uninit_slice(len: usize) -> Arc<[mem::MaybeUninit<T>]> {
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<T>]> {
+ unsafe {
+ Arc::from_ptr(Arc::allocate_for_layout(
+ Layout::array::<T>(len).unwrap(),
+ |layout| Global.alloc_zeroed(layout),
+ |mem| {
+ ptr::slice_from_raw_parts_mut(mem as *mut T, len)
+ as *mut ArcInner<[mem::MaybeUninit<T>]>
+ },
+ ))
+ }
+ }
}
impl<T> Arc<mem::MaybeUninit<T>> {
/// 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
///
/// This function is unsafe because improper use may lead to memory unsafety,
/// even if the returned `Arc<T>` 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
///
}
}
- /// Creates a new [`Weak`][weak] pointer to this allocation.
- ///
- /// [weak]: struct.Weak.html
+ /// Creates a new [`Weak`] pointer to this allocation.
///
/// # Examples
///
}
}
- /// Gets the number of [`Weak`][weak] pointers to this allocation.
- ///
- /// [weak]: struct.Weak.html
+ /// Gets the number of [`Weak`] pointers to this allocation.
///
/// # Safety
///
/// 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()
}
/// and must return back a (potentially fat)-pointer for the `ArcInner<T>`.
unsafe fn allocate_for_layout(
value_layout: Layout,
+ allocate: impl FnOnce(Layout) -> Result<NonNull<[u8]>, AllocErr>,
mem_to_arcinner: impl FnOnce(*mut u8) -> *mut ArcInner<T>,
) -> *mut ArcInner<T> {
// Calculate layout using the given value layout.
// reference (see #54908).
let layout = Layout::new::<ArcInner<()>>().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());
unsafe fn allocate_for_ptr(ptr: *const T) -> *mut ArcInner<T> {
// Allocate for the `ArcInner<T>` 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<T>
- })
+ Self::allocate_for_layout(
+ Layout::for_value(&*ptr),
+ |layout| Global.alloc(layout),
+ |mem| set_data_ptr(ptr as *mut T, mem) as *mut ArcInner<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::<T>(len).unwrap(), |mem| {
- ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut ArcInner<[T]>
- })
+ Self::allocate_for_layout(
+ Layout::array::<T>(len).unwrap(),
+ |layout| Global.alloc(layout),
+ |mem| ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut ArcInner<[T]>,
+ )
}
}
}
impl<T: Clone> Arc<T> {
/// 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.
///
///
/// 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
///
impl<T: ?Sized> Arc<T> {
/// 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
///
///
/// 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
///
/// 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
/// Constructs a new `Weak<T>`, 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
///
/// // 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<T> = NonNull::as_ptr(self.ptr);
/// 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();
/// 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() {
///
/// Returns [`None`] if the inner value has since been dropped.
///
- /// [`Arc`]: struct.Arc.html
- /// [`None`]: ../../std/option/enum.Option.html#variant.None
- ///
/// # Examples
///
/// ```
#[stable(feature = "arc_weak", since = "1.4.0")]
pub fn upgrade(&self) -> Option<Arc<T>> {
// 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
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,
}
/// 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 }
/// 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()
/// 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 {
/// 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
///
let a: Result<Arc<[u32; 2]>, _> = r.clone().try_into();
assert!(a.is_err());
}
+
+#[test]
+fn test_arc_cyclic_with_zero_refs() {
+ struct ZeroRefs {
+ inner: Weak<ZeroRefs>,
+ }
+ 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<OneRef>,
+ }
+ 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<TwoRefs>,
+ inner2: Weak<TwoRefs>,
+ }
+ 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);
+}
/// # Safety
///
/// This function is unsafe as it does not verify the preconditions from
- /// [`Layout::from_size_align`](#method.from_size_align).
+ /// [`Layout::from_size_align`].
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[rustc_const_stable(feature = "alloc_layout", since = "1.28.0")]
#[inline]
/// 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<Self, LayoutErr> {
/// 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
///
/// # 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
unsafe fn grow(
&mut self,
ptr: NonNull<u8>,
- layout: Layout,
- new_size: usize,
+ old_layout: Layout,
+ new_layout: Layout,
) -> Result<NonNull<[u8]>, 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)
///
/// 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
unsafe fn grow_zeroed(
&mut self,
ptr: NonNull<u8>,
- layout: Layout,
- new_size: usize,
+ old_layout: Layout,
+ new_layout: Layout,
) -> Result<NonNull<[u8]>, 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)
/// 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
///
/// # 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
unsafe fn shrink(
&mut self,
ptr: NonNull<u8>,
- layout: Layout,
- new_size: usize,
+ old_layout: Layout,
+ new_layout: Layout,
) -> Result<NonNull<[u8]>, 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)
unsafe fn grow(
&mut self,
ptr: NonNull<u8>,
- layout: Layout,
- new_size: usize,
+ old_layout: Layout,
+ new_layout: Layout,
) -> Result<NonNull<[u8]>, 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<u8>,
- layout: Layout,
- new_size: usize,
+ old_layout: Layout,
+ new_layout: Layout,
) -> Result<NonNull<[u8]>, 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<u8>,
- layout: Layout,
- new_size: usize,
+ old_layout: Layout,
+ new_layout: Layout,
) -> Result<NonNull<[u8]>, 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) }
}
}
/// 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<T> {
/// Converts the array to immutable slice
/// 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")]
/// 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 {
/// 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 {
/// 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);
/// 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);
/// 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);
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`,
///
/// 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`?
///
///
/// 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`?
///
// 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 \
///
/// This function will return an instance of [`Error`] on error.
///
- /// [`Error`]: struct.Error.html
- ///
/// # Examples
///
/// ```
///
/// This function will return an instance of [`Error`] on error.
///
- /// [`char`]: ../../std/primitive.char.html
- /// [`Error`]: struct.Error.html
- ///
/// # Examples
///
/// ```
/// 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> {
///
/// 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`
/// 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> {
///
/// 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
/// `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 `#?`:
///
/// 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
///
///
/// 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
///
///
/// 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
///
/// "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.
///
/// 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
///
///
/// 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
///
/// 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
///
///
/// 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
///
///
/// 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
///
/// 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
///
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",
/// 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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(src: *const T) -> T;
pub fn atomic_load_unordered<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(dst: *mut T, val: T);
pub fn atomic_store_unordered<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(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<T: Copy>(dst: *mut T, src: T) -> T;
/// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction
/// 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();
/// 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.
/// 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.
/// 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.
/// 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();
/// 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() -> !;
/// 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<T>() -> usize;
///
/// 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<T>(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<T>() -> usize;
/// The preferred alignment of a type.
/// 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<T: ?Sized>(_: *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<T: ?Sized>(_: *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<T: ?Sized>() -> &'static str;
/// 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<T: ?Sized + 'static>() -> u64;
/// 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: ?Sized>(_: T);
/// Reinterprets the bits of a value of one type as another type.
/// 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<T>() -> bool;
/// 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<T>(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<T>(dst: *mut T, val: T);
/// Performs a volatile load from the `src` pointer
/// 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.
/// Convert with LLVM’s fptoui/fptosi, which may return undef for values out of range
/// (<https://github.com/rust-lang/rust/issues/10184>)
///
- /// 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<Float: Copy, Int: Copy>(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<T: Copy>(x: T) -> T;
///
/// 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
///
///
/// 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
///
///
/// 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<T: Copy>(x: T) -> T;
///
/// 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<T: Copy>(x: T) -> T;
///
/// 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<T: Copy>(x: T, y: T) -> (T, bool);
///
/// 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<T: Copy>(x: T, y: T) -> (T, bool);
///
/// 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<T: Copy>(x: T, y: T) -> (T, bool);
///
/// 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<T: Copy>(x: T, y: T) -> T;
/// Returns the remainder of an unchecked division, resulting in
///
/// 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<T: Copy>(x: T, y: T) -> T;
///
/// 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<T: Copy>(x: T, y: T) -> T;
/// Performs an unchecked right shift, resulting in undefined behavior when
///
/// 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<T: Copy>(x: T, y: T) -> T;
///
/// 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<T: Copy>(x: T, y: T) -> T;
///
/// 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<T: Copy>(x: T, y: T) -> T;
///
/// 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<T: Copy>(a: T, b: T) -> T;
/// Returns (a - b) mod 2<sup>N</sup>, 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<T: Copy>(a: T, b: T) -> T;
/// Returns (a * b) mod 2<sup>N</sup>, 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<T: Copy>(a: T, b: T) -> T;
///
/// 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<T: Copy>(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<T: Copy>(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<T>(v: &T) -> <T as DiscriminantKind>::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<T>() -> 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
/// Note that even if the effectively copied size (`count * size_of::<T>()`) 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
///
/// 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
/// Note that even if the effectively copied size (`count * size_of::<T>()`) 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
///
/// Note that even if the effectively copied size (`count * size_of::<T>()`) is
/// `0`, the pointer must be non-NULL and properly aligned.
///
-/// [valid]: ../ptr/index.html#safety
+/// [valid]: crate::ptr#safety
///
/// # Examples
///
#![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)]
/// 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
///
/// ```
/// 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
///
/// ```
/// 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
///
/// ```
/// 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
///
/// ```
/// 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
///
/// ```
/// Because of the early return, `try!` can only be used in functions that
/// return [`Result`].
///
-/// [`Result`]: ../std/result/enum.Result.html
-///
/// # Examples
///
/// ```
///
/// 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
/// 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
///
/// 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:
/// 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)
/// #[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]
///
/// 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
/// will be emitted. To not emit a compile error, use the [`option_env!`]
/// macro instead.
///
- /// [`option_env!`]: ../std/macro.option_env.html
- ///
/// # Examples
///
/// ```
/// 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<T>`][option] for more information on this type.
+ /// [`Option<T>`][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
///
/// ```
/// but rather the first macro invocation leading up to the invocation
/// of the `line!` macro.
///
- /// [`column!`]: macro.column.html
- /// [`file!`]: macro.file.html
- ///
/// # Examples
///
/// ```
/// but rather the first macro invocation leading up to the invocation
/// of the `column!` macro.
///
- /// [`line!`]: macro.line.html
- /// [`file!`]: macro.file.html
- ///
/// # Examples
///
/// ```
/// 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
///
/// ```
/// 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
///
///
/// ```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)]
#[rustc_const_stable(feature = "const_forget", since = "1.46.0")]
#[stable(feature = "rust1", since = "1.0.0")]
pub const fn forget<T>(t: T) {
- ManuallyDrop::new(t);
+ let _ = ManuallyDrop::new(t);
}
/// Like [`forget`], but also accepts unsized values.
/// 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
}
// 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)
}
/// 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
}
/// 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
/// ```
/// [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
/// 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;
/// 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()
}
/// 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
///
/// ```
#[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) }
}
/// 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) }
/// 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()
}
/// 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()
}
/// );
/// ```
#[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()
}
/// 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))
}
/// 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))
}
/// 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))
}
/// 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
}
// 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)
}
/// 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
}
/// 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
/// ```
/// [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
/// 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;
/// 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()
}
/// 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
}
///
/// ```
#[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) }
}
/// 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) }
/// 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()
}
/// 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()
}
/// );
/// ```
#[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()
}
/// 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))
}
/// 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))
}
/// 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))
}
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
/// [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
/// [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
///
/// 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
///
/// 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 {
///
/// 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.
/// 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);
}
/// 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
///
/// 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
///
/// 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
///
/// [`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`
/// 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
//! // `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")]
/// 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)]
/// # Examples
///
/// ```
- /// #![feature(range_is_empty)]
- ///
/// assert!(!(3..5).is_empty());
/// assert!( (3..3).is_empty());
/// assert!( (3..2).is_empty());
/// 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)
}
/// 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
/// 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)]
/// 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
///
/// 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
///
/// 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
///
/// # Examples
///
/// ```
- /// #![feature(range_is_empty)]
- ///
/// assert!(!(3..=5).is_empty());
/// assert!(!(3..=3).is_empty());
/// assert!( (3..=2).is_empty());
/// 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());
/// 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)
/// 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)]
/// 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"]
//! mutable reference even when you just have [`Pin`]`<&mut Self>` (such as in your own
//! [`poll`] implementation).
//!
-//! [`Pin<P>`]: 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<P>`]: Pin
+//! [`Deref`]: crate::ops::Deref
+//! [`DerefMut`]: crate::ops::DerefMut
+//! [`mem::swap`]: crate::mem::swap
+//! [`mem::forget`]: crate::mem::forget
//! [`Box<T>`]: ../../std/boxed/struct.Box.html
//! [`Vec<T>`]: ../../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<T>`]: ../../std/cell/struct.RefCell.html
-//! [`Drop`]: ../../std/ops/trait.Drop.html
-//! [`drop`]: ../../std/ops/trait.Drop.html#tymethod.drop
+//! [`RefCell<T>`]: crate::cell::RefCell
+//! [`drop`]: Drop::drop
//! [`VecDeque<T>`]: ../../std/collections/struct.VecDeque.html
-//! [`Option<T>`]: ../../std/option/enum.Option.html
-//! [`VecDeque<T>`]: ../../std/collections/struct.VecDeque.html
-//! [`RefCell<T>`]: ../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<T>`]: 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")]
///
/// *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.
///
/// 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<P> {
///
/// 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>) -> P {
/// }
/// ```
///
- /// [`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)]
///
/// 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>) -> P {
/// 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::<T>())`
+ /// 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
/// This function is the inverse of [`offset`].
///
/// [`offset`]: #method.offset
- /// [`wrapping_offset_from`]: #method.wrapping_offset_from
///
/// # Safety
///
/// 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
/// 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").
/// Basic usage:
///
/// ```
- /// #![feature(ptr_offset_from)]
- ///
/// let a = [0; 5];
/// let ptr1: *const i32 = &a[1];
/// let ptr2: *const i32 = &a[3];
/// 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
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::<T>()`.
- ///
- /// If the address different between the two pointers is not a multiple of
- /// `mem::size_of::<T>()` 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::<T>();
- 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
/// 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::<T>())`
+ /// 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
/// This function is the inverse of [`offset`].
///
/// [`offset`]: #method.offset-1
- /// [`wrapping_offset_from`]: #method.wrapping_offset_from-1
///
/// # Safety
///
/// 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
/// 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").
/// 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];
/// 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
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::<T>()`.
- ///
- /// If the address different between the two pointers is not a multiple of
- /// `mem::size_of::<T>()` 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
/// [`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
//! [`?`] 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")]
/// `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"]
/// Returns `true` if the result is [`Ok`].
///
- /// [`Ok`]: enum.Result.html#variant.Ok
- ///
/// # Examples
///
/// Basic usage:
/// Returns `true` if the result is [`Err`].
///
- /// [`Err`]: enum.Result.html#variant.Err
- ///
/// # Examples
///
/// Basic usage:
/// Converts `self` into an [`Option<T>`], consuming `self`,
/// and discarding the error, if any.
///
- /// [`Option<T>`]: ../../std/option/enum.Option.html
+ /// [`Option<T>`]: Option
///
/// # Examples
///
/// Converts `self` into an [`Option<E>`], consuming `self`,
/// and discarding the success value, if any.
///
- /// [`Option<E>`]: ../../std/option/enum.Option.html
+ /// [`Option<E>`]: Option
///
/// # Examples
///
///
/// 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.
/// 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
///
/// 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
///
/// 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
///
/// 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
///
/// 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.
///
/// 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
///
///
/// 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
///
/// 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
///
/// Returns the contained [`Ok`] value or computes it from a closure.
///
- /// [`Ok`]: enum.Result.html#variant.Ok
///
/// # Examples
///
/// 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
///
/// 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
///
/// 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
///
/// 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
/// 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 {
/// 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
///
/// 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> {
/// 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> {
/// 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<T> {
/// 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")]
/// 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")]
/// 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:
/// 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̆";
/// 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";
/// 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
/// 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
/// 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
/// 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
/// 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
/// 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
/// 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
/// 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
/// 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
/// 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
/// 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
/// 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
/// 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
/// 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
/// 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
/// 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
/// 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
/// 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
/// 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
/// 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
/// 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
/// 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
/// 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
//! # 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`.
//!
//! ```
//! 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(
/// 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
/// | `&String` | is substring |
///
/// # Examples
+///
/// ```
/// // &str
/// assert_eq!("abaaa".find("ba"), Some(1));
/// 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>;
// 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
/// 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 {
}
}
- /// 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 {
/// 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 {
}
}
- /// 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 {
}
}
-/// 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
/// # 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
/// `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],
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
///
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
///
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
///
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))]
];
#[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() {
#![feature(try_find)]
#![feature(is_sorted)]
#![feature(pattern)]
-#![feature(range_is_empty)]
#![feature(raw)]
#![feature(sort_internals)]
#![feature(slice_partition_at_index)]
}
#[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.
}
#[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.
}
#[test]
-#[cfg_attr(miri, ignore)] // Miri is too slow
fn align_offset_weird_strides() {
#[repr(packed)]
struct A3(u16, u8);
// 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::<A3>(ptr as *const A3, align);
}
#[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::<u16>() };
}
#[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);
#![feature(panic_runtime)]
#![feature(staged_api)]
#![feature(rustc_attrs)]
+#![feature(llvm_asm)]
use core::any::Any;
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();
}
__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();
/// 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())
// 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"));
unsafe fn grow_impl(
&mut self,
ptr: NonNull<u8>,
- layout: Layout,
- new_size: usize,
+ old_layout: Layout,
+ new_layout: Layout,
zeroed: bool,
) -> Result<NonNull<[u8]>, 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)
+ },
}
}
}
unsafe fn grow(
&mut self,
ptr: NonNull<u8>,
- layout: Layout,
- new_size: usize,
+ old_layout: Layout,
+ new_layout: Layout,
) -> Result<NonNull<[u8]>, 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<u8>,
- layout: Layout,
- new_size: usize,
+ old_layout: Layout,
+ new_layout: Layout,
) -> Result<NonNull<[u8]>, 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<u8>,
- layout: Layout,
- new_size: usize,
+ old_layout: Layout,
+ new_layout: Layout,
) -> Result<NonNull<[u8]>, 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)
+ },
}
}
}
//! 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")]
impl<'a> From<&str> for Box<dyn Error + Send + Sync + 'a> {
/// Converts a [`str`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
///
+ /// [`str`]: prim@str
+ ///
/// # Examples
///
/// ```
impl From<&str> for Box<dyn Error> {
/// Converts a [`str`] into a box of dyn [`Error`].
///
+ /// [`str`]: prim@str
+ ///
/// # Examples
///
/// ```
/// 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
/// println!("string: {}", my_string_safe());
/// ```
///
-/// [`&str`]: str
+/// [`&str`]: prim@str
#[derive(Hash)]
#[stable(feature = "rust1", since = "1.0.0")]
// FIXME:
/// 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
///
/// [`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
DirBuilder::new().recursive(true).create(path.as_ref())
}
-/// Removes an existing, empty directory.
+/// Removes an empty directory.
///
/// # Platform-specific behavior
///
/// 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.
///
/// ```
///
/// [`read()`]: Read::read
-/// [`&str`]: str
+/// [`&str`]: prim@str
/// [`std::io`]: self
/// [`File`]: crate::fs::File
/// [slice]: ../../std/primitive.slice.html
/// 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<StdinRaw> {
- 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.
///
/// The returned handle has no external synchronization or buffering layered on
/// top.
-fn stdout_raw() -> io::Result<StdoutRaw> {
- 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.
///
/// The returned handle has no external synchronization or buffering layered on
/// top.
-fn stderr_raw() -> io::Result<StderrRaw> {
- 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<usize> {
- self.0.read(buf)
+ handle_ebadf(self.0.read(buf), 0)
}
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
- self.0.read_vectored(bufs)
+ handle_ebadf(self.0.read_vectored(bufs), 0)
}
#[inline]
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
- 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<usize> {
- 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<usize> {
- self.0.write(buf)
+ handle_ebadf(self.0.write(buf), buf.len())
}
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
- self.0.write_vectored(bufs)
+ let total = bufs.iter().map(|b| b.len()).sum();
+ handle_ebadf(self.0.write_vectored(bufs), total)
}
#[inline]
}
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<usize> {
- self.0.write(buf)
+ handle_ebadf(self.0.write(buf), buf.len())
}
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
- self.0.write_vectored(bufs)
+ let total = bufs.iter().map(|b| b.len()).sum();
+ handle_ebadf(self.0.write_vectored(bufs), total)
}
#[inline]
}
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<T> {
- Real(T),
- Fake,
-}
-
-impl<W: io::Write> io::Write for Maybe<W> {
- fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- 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<usize> {
- 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<R: io::Read> io::Read for Maybe<R> {
- fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
- 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<usize> {
- 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), ())
}
}
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Stdin {
- inner: Arc<Mutex<BufReader<Maybe<StdinRaw>>>>,
+ inner: Arc<Mutex<BufReader<StdinRaw>>>,
}
/// A locked reference to the `Stdin` handle.
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct StdinLock<'a> {
- inner: MutexGuard<'a, BufReader<Maybe<StdinRaw>>>,
+ inner: MutexGuard<'a, BufReader<StdinRaw>>,
}
/// Constructs a new handle to the standard input of the current process.
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stdin() -> Stdin {
- static INSTANCE: Lazy<Mutex<BufReader<Maybe<StdinRaw>>>> = Lazy::new();
+ static INSTANCE: Lazy<Mutex<BufReader<StdinRaw>>> = Lazy::new();
return Stdin {
inner: unsafe { INSTANCE.get(stdin_init).expect("cannot access stdin during shutdown") },
};
- fn stdin_init() -> Arc<Mutex<BufReader<Maybe<StdinRaw>>>> {
+ fn stdin_init() -> Arc<Mutex<BufReader<StdinRaw>>> {
// 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)))
}
}
// 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<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>>,
+ inner: Arc<ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>>,
}
/// A locked reference to the `Stdout` handle.
/// an error.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct StdoutLock<'a> {
- inner: ReentrantMutexGuard<'a, RefCell<LineWriter<Maybe<StdoutRaw>>>>,
+ inner: ReentrantMutexGuard<'a, RefCell<LineWriter<StdoutRaw>>>,
}
/// Constructs a new handle to the standard output of the current process.
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stdout() -> Stdout {
- static INSTANCE: Lazy<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>> = Lazy::new();
+ static INSTANCE: Lazy<ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>> = Lazy::new();
return Stdout {
inner: unsafe { INSTANCE.get(stdout_init).expect("cannot access stdout during shutdown") },
};
- fn stdout_init() -> Arc<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>> {
+ fn stdout_init() -> Arc<ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>> {
// 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();
/// an error.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Stderr {
- inner: &'static ReentrantMutex<RefCell<Maybe<StderrRaw>>>,
+ inner: &'static ReentrantMutex<RefCell<StderrRaw>>,
}
/// A locked reference to the `Stderr` handle.
/// an error.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct StderrLock<'a> {
- inner: ReentrantMutexGuard<'a, RefCell<Maybe<StderrRaw>>>,
+ inner: ReentrantMutexGuard<'a, RefCell<StderrRaw>>,
}
/// Constructs a new handle to the standard error of the current process.
//
// This has the added benefit of allowing `stderr` to be usable during
// process shutdown as well!
- static INSTANCE: ReentrantMutex<RefCell<Maybe<StderrRaw>>> =
- unsafe { ReentrantMutex::new(RefCell::new(Maybe::Fake)) };
+ static INSTANCE: ReentrantMutex<RefCell<StderrRaw>> =
+ 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 }
}
// 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
}
//! [`Vec<T>`]: 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
#![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
//! 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.
/// 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
///
/// 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
///
/// 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
///
/// 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
///
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() }
},
}
/// ```
#[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) }
}
/// ```
#[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.
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.
///
#[stable(feature = "rust1", since = "1.0.0")]
impl hash::Hash for Ipv4Addr {
fn hash<H: hash::Hasher>(&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)
}
}
#[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<c::in_addr> for Ipv4Addr {
- fn as_inner(&self) -> &c::in_addr {
- &self.inner
+impl IntoInner<c::in_addr> for Ipv4Addr {
+ fn into_inner(self) -> c::in_addr {
+ self.inner
}
}
#[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
#[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],
}
}
/// 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::<Box<[u8]>>());
+/// assert_eq!(2 * pointer_size, std::mem::size_of::<Rc<[u8]>>());
+/// ```
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_slice {}
///
/// # 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).
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();
}
///
/// 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);
/// 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
///
/// poisoned when this thread re-acquires the lock. For more information,
/// see information about [poisoning] on the [`Mutex`] type.
///
- /// [`notify_one`]: #method.notify_one
- /// [`notify_all`]: #method.notify_all
- /// [poisoning]: ../sync/struct.Mutex.html#poisoning
- /// [`Mutex`]: ../sync/struct.Mutex.html
+ /// [`notify_one`]: Self::notify_one
+ /// [`notify_all`]: Self::notify_all
+ /// [poisoning]: super::Mutex#poisoning
+ /// [`Mutex`]: super::Mutex
///
/// # Examples
///
/// 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
///
/// 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
///
/// 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
///
///
/// 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
///
///
/// To wake up only one thread, see [`notify_one`].
///
- /// [`notify_one`]: #method.notify_one
+ /// [`notify_one`]: Self::notify_one
///
/// # Examples
///
-// ignore-tidy-filelength
-
//! Multi-producer, single-consumer FIFO queue communication primitives.
//!
//! This module provides message-based communication over channels, concretely
//! 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
//!
//! 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
//!
///
/// 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
///
/// 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
///
/// 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
///
/// 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
///
///
/// Messages can be sent through this channel with [`send`].
///
-/// [`channel`]: fn.channel.html
-/// [`send`]: struct.Sender.html#method.send
+/// [`send`]: Sender::send
///
/// # Examples
///
///
/// [`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
///
/// 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<T>(#[stable(feature = "rust1", since = "1.0.0")] pub T);
/// [`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;
/// 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 {
/// 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 {
/// 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<T> {
/// 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),
}
/// [`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
///
/// [`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
///
/// 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
/// [`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
/// 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
///
/// 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
///
/// 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
///
/// ```
/// 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`
/// 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:
/// 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
/// 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
/// 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
///
/// 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> {
/// this call will return failure if the mutex would otherwise be
/// acquired.
///
- /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
- ///
/// # Examples
///
/// ```
impl<T> From<T> for Mutex<T> {
/// 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)
}
/// } // 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<T: ?Sized> {
inner: Box<sys::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> {
/// 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> {
impl<T> From<T> for RwLock<T> {
/// Creates a new instance of an `RwLock<T>` 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)
}
pub struct Stderr(());
impl Stdin {
- pub fn new() -> io::Result<Stdin> {
- Ok(Stdin(()))
+ pub const fn new() -> Stdin {
+ Stdin(())
}
}
}
impl Stdout {
- pub fn new() -> io::Result<Stdout> {
- Ok(Stdout(()))
+ pub const fn new() -> Stdout {
+ Stdout(())
}
}
}
impl Stderr {
- pub fn new() -> io::Result<Stderr> {
- Ok(Stderr(()))
+ pub const fn new() -> Stderr {
+ Stderr(())
}
}
pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE;
pub fn panic_output() -> Option<impl io::Write> {
- Stderr::new().ok()
+ Some(Stderr::new())
}
pub struct Stderr;
impl Stdin {
- pub fn new() -> io::Result<Stdin> {
- Ok(Stdin)
+ pub const fn new() -> Stdin {
+ Stdin
}
}
}
impl Stdout {
- pub fn new() -> io::Result<Stdout> {
- Ok(Stdout)
+ pub const fn new() -> Stdout {
+ Stdout
}
}
}
impl Stderr {
- pub fn new() -> io::Result<Stderr> {
- Ok(Stderr)
+ pub const fn new() -> Stderr {
+ Stderr
}
}
}
pub fn panic_output() -> Option<impl io::Write> {
- Stderr::new().ok()
+ Some(Stderr::new())
}
}
impl Stdin {
- pub fn new() -> io::Result<Stdin> {
- Ok(Stdin(()))
+ pub const fn new() -> Stdin {
+ Stdin(())
}
}
}
impl Stdout {
- pub fn new() -> io::Result<Stdout> {
- Ok(Stdout(()))
+ pub const fn new() -> Stdout {
+ Stdout(())
}
}
}
impl Stderr {
- pub fn new() -> io::Result<Stderr> {
- Ok(Stderr(()))
+ pub const fn new() -> Stderr {
+ Stderr(())
}
}
pub struct Stderr(());
impl Stdin {
- pub fn new() -> io::Result<Stdin> {
- Ok(Stdin(()))
+ pub const fn new() -> Stdin {
+ Stdin(())
}
}
}
impl Stdout {
- pub fn new() -> io::Result<Stdout> {
- Ok(Stdout(()))
+ pub const fn new() -> Stdout {
+ Stdout(())
}
}
}
impl Stderr {
- pub fn new() -> io::Result<Stderr> {
- Ok(Stderr(()))
+ pub const fn new() -> Stderr {
+ Stderr(())
}
}
pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE;
pub fn panic_output() -> Option<impl io::Write> {
- Stderr::new().ok()
+ Some(Stderr::new())
}
pub struct Stderr;
impl Stdin {
- pub fn new() -> io::Result<Stdin> {
- Ok(Stdin)
+ pub const fn new() -> Stdin {
+ Stdin
}
}
}
impl Stdout {
- pub fn new() -> io::Result<Stdout> {
- Ok(Stdout)
+ pub const fn new() -> Stdout {
+ Stdout
}
}
}
impl Stderr {
- pub fn new() -> io::Result<Stderr> {
- Ok(Stderr)
+ pub const fn new() -> Stderr {
+ Stderr
}
}
}
#[inline]
- fn is_read_vectored(&self) -> bool {
+ pub fn is_read_vectored(&self) -> bool {
true
}
}
fn exited(&self) -> bool {
- /*unsafe*/
- { libc::WIFEXITED(self.0) }
+ libc::WIFEXITED(self.0)
}
pub fn success(&self) -> bool {
}
pub fn code(&self) -> Option<i32> {
- 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<i32> {
- if !self.exited() {
- Some(/*unsafe*/ { libc::WTERMSIG(self.0) })
- } else {
- None
- }
+ if !self.exited() { Some(libc::WTERMSIG(self.0)) } else { None }
}
}
pub struct Stderr(());
impl Stdin {
- pub fn new() -> io::Result<Stdin> {
- Ok(Stdin(()))
+ pub const fn new() -> Stdin {
+ Stdin(())
}
}
}
impl Stdout {
- pub fn new() -> io::Result<Stdout> {
- Ok(Stdout(()))
+ pub const fn new() -> Stdout {
+ Stdout(())
}
}
}
impl Stderr {
- pub fn new() -> io::Result<Stderr> {
- Ok(Stderr(()))
+ pub const fn new() -> Stderr {
+ Stderr(())
}
}
pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE;
pub fn panic_output() -> Option<impl io::Write> {
- Stderr::new().ok()
+ Some(Stderr::new())
}
#![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);
}
pub struct Stderr;
impl Stdin {
- pub fn new() -> io::Result<Stdin> {
- Ok(Stdin)
+ pub const fn new() -> Stdin {
+ Stdin
}
#[inline]
}
impl Stdout {
- pub fn new() -> io::Result<Stdout> {
- Ok(Stdout)
+ pub const fn new() -> Stdout {
+ Stdout
}
#[inline]
}
impl Stderr {
- pub fn new() -> io::Result<Stderr> {
- Ok(Stderr)
+ pub const fn new() -> Stderr {
+ Stderr
}
#[inline]
}
pub fn panic_output() -> Option<impl io::Write> {
- Stderr::new().ok()
+ Some(Stderr::new())
}
.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"))]
}
impl Stdin {
- pub fn new() -> io::Result<Stdin> {
- Ok(Stdin { surrogate: 0 })
+ pub const fn new() -> Stdin {
+ Stdin { surrogate: 0 }
}
}
}
impl Stdout {
- pub fn new() -> io::Result<Stdout> {
- Ok(Stdout)
+ pub const fn new() -> Stdout {
+ Stdout
}
}
}
impl Stderr {
- pub fn new() -> io::Result<Stderr> {
- Ok(Stderr)
+ pub const fn new() -> Stderr {
+ Stderr
}
}
}
pub fn panic_output() -> Option<impl io::Write> {
- Stderr::new().ok()
+ Some(Stderr::new())
}
}
impl Stdin {
- pub fn new() -> io::Result<Stdin> {
- Ok(Stdin {})
+ pub const fn new() -> Stdin {
+ Stdin {}
}
}
}
impl Stdout {
- pub fn new() -> io::Result<Stdout> {
- Ok(Stdout)
+ pub const fn new() -> Stdout {
+ Stdout
}
}
}
impl Stderr {
- pub fn new() -> io::Result<Stderr> {
- Ok(Stderr)
+ pub const fn new() -> Stderr {
+ Stderr
}
}
}
pub fn panic_output() -> Option<impl io::Write> {
- Stderr::new().ok()
+ Some(Stderr::new())
}
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)
}
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)
}
/// 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<T: 'static> {
// This outer `LocalKey<T>` type is what's going to be stored in statics,
/// # 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)]
//!
//! 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")]
/// 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")]
/// [`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
///
/// 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<JoinHandle<T>>
where
/// 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
/// 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, T>(f: F) -> JoinHandle<T>
where
/// 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()
/// panic!()
/// }
/// ```
-///
-/// [Mutex]: ../../std/sync/struct.Mutex.html
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn panicking() -> bool {
/// 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
/// 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) {
/// 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();
/// 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);
/// 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<Inner>,
}
///
/// 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
/// }
/// ```
///
-/// [`Result`]: ../../std/result/enum.Result.html
+/// [`Result`]: crate::result::Result
#[stable(feature = "rust1", since = "1.0.0")]
pub type Result<T> = crate::result::Result<T, Box<dyn Any + Send + 'static>>;
/// 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<T>(JoinInner<T>);
/// 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
///
/// by the constant `1.4826` to allow its use as a consistent estimator for the standard
/// deviation.
///
- /// See: <http://en.wikipedia.org/wiki/Median_absolute_deviation>
+ /// See: <https://en.wikipedia.org/wiki/Median_absolute_deviation>
fn median_abs_dev(&self) -> f64;
/// Median absolute deviation as a percent of the median. See `median_abs_dev` and `median`.
///
/// Calculated by linear interpolation between closest ranks.
///
- /// See: <http://en.wikipedia.org/wiki/Percentile>
+ /// See: <https://en.wikipedia.org/wiki/Percentile>
fn percentile(&self, pct: f64) -> f64;
/// Quartiles of the sample: three values that divide the sample into four equal groups, each
/// It differs from trimming in that it does not change the number of samples,
/// just changes the values of those that are outliers.
///
-/// See: <http://en.wikipedia.org/wiki/Winsorising>
+/// See: <https://en.wikipedia.org/wiki/Winsorising>
pub fn winsorize(samples: &mut [f64], pct: f64) {
let mut tmp = samples.to_vec();
local_sort(&mut tmp);
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);
}
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);
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);
.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)]
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);
}
}
.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);
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)
}
}
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")
) -> Vec<SanitizerRuntime> {
let darwin_libs = |os: &str, components: &[&str]| -> Vec<SanitizerRuntime> {
components
- .into_iter()
+ .iter()
.map(move |c| SanitizerRuntime {
cmake_target: format!("clang_rt.{}_{}_dynamic", c, os),
path: out_dir
let common_libs = |os: &str, arch: &str, components: &[&str]| -> Vec<SanitizerRuntime> {
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)),
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)),
source shared.sh
-LLVM=llvmorg-9.0.0
+LLVM=llvmorg-10.0.0
mkdir llvm-project
cd llvm-project
# 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 \
+++ /dev/null
-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
- 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
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
#
# 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.
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
}
```
-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)
```
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.
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.
## 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
pub struct FnSig {
pub header: FnHeader,
pub decl: P<FnDecl>,
+ pub span: Span,
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
}
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
-pub fn visit_fn_sig<T: MutVisitor>(FnSig { header, decl }: &mut FnSig, vis: &mut T) {
+pub fn visit_fn_sig<T: MutVisitor>(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`.
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};
}
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 {
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);
)
},
);
- 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)
})
}
)
},
);
- (generics, hir::FnSig { header, decl })
+ (generics, hir::FnSig { header, decl, span: sig.span })
}
fn lower_fn_header(&mut self, h: FnHeader) -> hir::FnHeader {
hir::GenericBound::LangItemTrait(
// ::std::future::Future<future_params>
- hir::LangItem::FutureTraitLangItem,
+ hir::LangItem::Future,
span,
self.next_id(),
future_args,
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");
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;
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(
};
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));
_ => 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())
}
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;
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(),
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};
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])
}
};
// 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);
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};
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));
}
}
-/// 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 {
}
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!(),
/// 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
// -------------------------------------------------------------------------
/// 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,
/// 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<DefIndex, DefKey>,
def_path_hashes: IndexVec<DefIndex, DefPathHash>,
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]
hash
}
- pub fn add_def_path_hashes_to(&self, cnum: CrateNum, out: &mut FxHashMap<DefPathHash, DefId>) {
- 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<Item = (DefIndex, &DefKey, &DefPathHash)> + '_ {
+ 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<Item = (DefPathHash, DefId)> + '_ {
+ self.def_path_hashes
+ .iter_enumerated()
+ .map(move |(index, hash)| (*hash, DefId { krate, index }))
}
}
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
//! * 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};
/// 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<LangItemGroup> {
use LangItemGroup::*;
match self {
- $( $variant => expand_group!($($group)*), )*
+ $( LangItem::$variant => expand_group!($($group)*), )*
}
}
}
fn init_none(_: LangItem) -> Option<DefId> { None }
Self {
- items: vec![$(init_none($variant)),*],
+ items: vec![$(init_none(LangItem::$variant)),*],
missing: Vec::new(),
groups: [vec![]; NUM_GROUPS],
}
/// exists.
#[allow(dead_code)]
pub fn $method(&self) -> Option<DefId> {
- self.items[$variant as usize]
+ self.items[LangItem::$variant as usize]
}
)*
}
/// 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<Symbol, (usize, Target)> = {
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
};
}
}
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;
}
lazy_static! {
pub static ref WEAK_ITEMS_REFS: FxHashMap<Symbol, LangItem> = {
let mut map = FxHashMap::default();
- $(map.insert(sym::$name, lang_items::$item);)*
+ $(map.insert(sym::$name, LangItem::$item);)*
map
};
}
) }
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;
}
err.span_label(span, "expected due to this");
}
ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
+ semi_span,
source,
ref prior_arms,
last_ty,
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 }) => {
#![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
# Note that this crate purposefully does not depend on other rustc crates
[dependencies]
unicode-xid = "0.2.0"
+
+[dev-dependencies]
+expect-test = "0.1"
/// 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,
-#[cfg(test)]
-mod tests {
- use crate::*;
-
- fn check_raw_str(s: &str, expected_hashes: u16, expected_err: Option<RawStrError>) {
- 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<RawStrError>) {
+ 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 }
+ "#]],
+ )
}
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;
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<bool, LayoutError<'tcx>> {
+ 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)]
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, .. }| {
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),
}
})
}
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);
}
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);
#[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<Mutex<Guard>> = SyncLazy::new(|| Mutex::new(Guard { _priv: () }));
+ LOCK.lock().unwrap()
+ }
- fn check_for_errors_in<T, F>(f: F) -> Result<T, String>
- 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) {
#![feature(drain_filter)]
#![feature(in_band_lifetimes)]
#![feature(nll)]
+#![feature(once_cell)]
#![feature(or_patterns)]
#![feature(proc_macro_internals)]
#![feature(min_specialization)]
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};
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;
/// 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.
/// 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<DepNodeIndex>,
+ /// Caches decoded `DefKey`s.
+ def_key_cache: Lock<FxHashMap<DefIndex, DefKey>>,
+ /// Caches decoded `DefPathHash`es.
+ def_path_hash_cache: Lock<FxHashMap<DefIndex, DefPathHash>>,
// --- Other significant crate properties ---
/// ID of this crate, from the current compilation session's point of view.
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(
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"),
}
#[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`.
DefPath::make(self.cnum, id, |parent| self.def_key(parent))
}
+ fn def_path_hash_unlocked(
+ &self,
+ index: DefIndex,
+ def_path_hashes: &mut FxHashMap<DefIndex, DefPathHash>,
+ ) -> 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").
///
private_dep: bool,
host_hash: Option<Svh>,
) -> 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))
CrateMetadata {
blob,
root,
- def_path_table,
trait_impls,
raw_proc_macros,
source_map_import_info: OnceCell::new(),
host_hash,
extern_crate: Lock::new(None),
hygiene_context: Default::default(),
+ def_key_cache: Default::default(),
+ def_path_hash_cache: Default::default(),
}
}
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 }
}
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
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};
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<CrateNum> {
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;
}
}
- fn encode_def_path_table(&mut self) -> Lazy<DefPathTable> {
- 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]> {
// 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.
native_libraries,
foreign_modules,
source_map,
- def_path_table,
impls,
exported_symbols,
interpret_alloc_index,
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;
diagnostic_items: Lazy<[(Symbol, DefIndex)]>,
native_libraries: Lazy<[NativeLib]>,
foreign_modules: Lazy<[ForeignModule]>,
- def_path_table: Lazy<rustc_hir::definitions::DefPathTable>,
impls: Lazy<[TraitImpls]>,
interpret_alloc_index: Lazy<[u32]>,
mir: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, mir::Body<'tcx>>)>,
unused_generic_params: Table<DefIndex, Lazy<FiniteBitSet<u32>>>,
+ // `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<DefIndex, Lazy<DefKey>>,
+ def_path_hashes: Table<DefIndex, Lazy<DefPathHash>>
}
#[derive(Copy, Clone, MetadataEncodable, MetadataDecodable)]
let bytes = &metadata.raw_bytes()[start..start + self.meta];
<Option<T>>::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 / <Option<T>>::BYTE_LEN
+ }
}
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,
}
}
+ /// 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<Span> {
id.as_local().map(|id| self.span(self.local_def_id_to_hir_id(id)))
}
#![feature(nll)]
#![feature(option_expect_none)]
#![feature(or_patterns)]
-#![feature(range_is_empty)]
#![feature(min_specialization)]
#![feature(trusted_len)]
#![feature(stmt_expr_attributes)]
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;
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;
// 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,
}
}
/// ```
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,
/// 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.
// 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`.
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))
}
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
}
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)
}
}
unwind: Option<BasicBlock>,
},
- /// 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>,
#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
pub struct MatchExpressionArmCause<'tcx> {
pub arm_span: Span,
+ pub semi_span: Option<Span>,
pub source: hir::MatchSource,
pub prior_arms: Vec<Span>,
pub last_ty: Ty<'tcx>,
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)]
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)
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;
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::<usize>();
+ 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::<usize>();
-
- 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)
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())),
)
}
#[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<Ty<'tcx>> {
+ pub fn mk_lang_item(self, ty: Ty<'tcx>, item: LangItem) -> Option<Ty<'tcx>> {
let def_id = self.lang_items().require(item).ok()?;
Some(self.mk_generic_adt(def_id, ty))
}
#[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)
}
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;
}
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()
}
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()
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};
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()]);
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;
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),
}
}
/// 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({})",
}
}
- 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;
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 } =
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,
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(
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
}
}
} 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()
+ ),
);
}
}
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
),
);
}
} 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)) =
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
place_desc: &str,
ty: Ty<'tcx>,
span: Option<Span>,
+ 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);
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();
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
&format!("`{}`", self.local_names[*local].unwrap()),
bind_to.ty,
Some(binding_span),
+ "",
);
}
}
};
// 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
desired_action: InitializationRequiringAction,
place_span: (PlaceRef<'tcx>, Span),
maybe_uninits: &BitSet<MovePathIndex>,
- 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;
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;
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, &[]),
};
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");
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(
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, &[]),
}
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, &[]),
};
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()]),
};
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};
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
}
};
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
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};
// 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);
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)?
#![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)]
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};
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));
_ => 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),
};
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;
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,
+++ /dev/null
-//! 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<CodegenUnit<'tcx>>
-where
- I: Iterator<Item = MonoItem<'tcx>>,
-{
- 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<CodegenUnit<'tcx>>,
- roots: FxHashSet<MonoItem<'tcx>>,
- internalization_candidates: FxHashSet<MonoItem<'tcx>>,
-}
-
-/// 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<CodegenUnit<'tcx>>,
- mono_item_placements: FxHashMap<MonoItem<'tcx>, MonoItemPlacement>,
- internalization_candidates: FxHashSet<MonoItem<'tcx>>,
-}
-
-fn place_root_mono_items<'tcx, I>(tcx: TyCtxt<'tcx>, mono_items: I) -> PreInliningPartitioning<'tcx>
-where
- I: Iterator<Item = MonoItem<'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 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<Symbol, Vec<SymbolStr>> =
- 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<Symbol, String> = 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<MonoItem<'tcx>>,
- ) {
- 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<MonoItem<'tcx>, Vec<MonoItem<'tcx>>> = 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<DefId> {
- 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<Item = &'a CodegenUnit<'tcx>>,
- '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("<no hash>");
-
- 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<Item = &'a MonoItem<'tcx>>,
- '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))
- };
-}
--- /dev/null
+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<Item = MonoItem<'tcx>>,
+ ) -> 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<MonoItem<'tcx>>,
+ ) {
+ 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<MonoItem<'tcx>, Vec<MonoItem<'tcx>>> = 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<DefId> {
+ 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,
+ }
+}
--- /dev/null
+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<Symbol, Vec<SymbolStr>> =
+ 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<Symbol, String> = 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))
+}
--- /dev/null
+//! 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<Item = MonoItem<'tcx>>,
+ ) -> 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<dyn Partitioner<'tcx>> {
+ 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<Item = MonoItem<'tcx>>,
+ max_cgu_count: usize,
+ inlining_map: &InliningMap<'tcx>,
+) -> Vec<CodegenUnit<'tcx>> {
+ 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<CodegenUnit<'tcx>>,
+ roots: FxHashSet<MonoItem<'tcx>>,
+ internalization_candidates: FxHashSet<MonoItem<'tcx>>,
+}
+
+/// 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<CodegenUnit<'tcx>>,
+ mono_item_placements: FxHashMap<MonoItem<'tcx>, MonoItemPlacement>,
+ internalization_candidates: FxHashSet<MonoItem<'tcx>>,
+}
+
+fn debug_dump<'a, 'tcx, I>(tcx: TyCtxt<'tcx>, label: &str, cgus: I)
+where
+ I: Iterator<Item = &'a CodegenUnit<'tcx>>,
+ '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("<no hash>");
+
+ 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<Item = &'a MonoItem<'tcx>>,
+ '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))
+ };
+}
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};
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()
fn downcast_subpath(&self, _path: Self::Path, _variant: VariantIdx) -> Option<Self::Path> {
Some(())
}
- fn array_subpath(&self, _path: Self::Path, _index: u32, _size: u32) -> Option<Self::Path> {
+ fn array_subpath(&self, _path: Self::Path, _index: u64, _size: u64) -> Option<Self::Path> {
None
}
}
//! 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};
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);
})
}
- fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option<Self::Path> {
+ fn array_subpath(&self, path: Self::Path, index: u64, size: u64) -> Option<Self::Path> {
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");
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};
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);
};
// Compute GeneratorState<yield_ty, return_ty>
- 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);
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.
.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,
},
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;
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 {
/// 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<Self::Path>;
+ fn array_subpath(&self, path: Self::Path, index: u64, size: u64) -> Option<Self::Path>;
}
#[derive(Debug)]
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, &[]);
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<D::Path>)> = (0..size)
.map(|i| {
(
) -> 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()
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);
}
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;
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);
_ => 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();
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);
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,
},
}
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,
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;
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),
..
| 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 {
// 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 {
return_ty,
return_ty_span,
body,
+ span_with_body
);
mir.yield_ty = yield_ty;
mir
return_ty: Ty<'tcx>,
return_ty_span: Span,
body: &'tcx hir::Body<'tcx>,
+ span_with_body: Span
) -> Body<'tcx>
where
A: Iterator<Item = ArgInfo<'tcx>>,
let mut builder = Builder::new(
hir,
- span,
+ span_with_body,
arguments.len(),
safety,
return_ty,
)
);
// 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);
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");
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;
// 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,
#![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};
// 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!(
//
// 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
}
}
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);
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;
}
}
//
// 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,
}
b == d && (a == c || a == kw::DollarCrate || c == kw::DollarCrate)
}
- (&Interpolated(..), &Interpolated(..)) => false,
+ (&Interpolated(..), &Interpolated(..)) => panic!("Unexpanded Interpolated!"),
_ => panic!("forgot to add a token?"),
}
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;
(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) {
&mut self,
attrs: &mut Vec<Attribute>,
req_name: ReqName,
+ sig_lo: Span,
) -> PResult<'a, (Ident, FnSig, Generics, Option<P<Block>>)> {
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<Attribute>) -> PResult<'a, Option<P<Block>>> {
+ fn parse_fn_body(
+ &mut self,
+ attrs: &mut Vec<Attribute>,
+ sig_hi: &mut Span,
+ ) -> PResult<'a, Option<P<Block>>> {
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() {
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;
// 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);
}
{
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));
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)
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;
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};
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<TraitCandidate>,
- ) {
- 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> {
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;
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};
}
}
+ /// This modifies `self` in place. The traits will be stored in `self.traits`.
+ fn ensure_traits<R>(&'a self, resolver: &mut R)
+ where
+ R: AsMut<Resolver<'a>>,
+ {
+ 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<Res> {
match self.kind {
ModuleKind::Def(kind, def_id, _) => Some(Res::Def(kind, def_id)),
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<TraitCandidate>,
+ 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>,
})
}
+ /// 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<TraitCandidate> {
+ 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,
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 ");
"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<String> = (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<String> = (None, parse_opt_string, [TRACKED],
pub struct PerfStats {
/// The accumulated time spent on computing symbol hashes.
pub symbol_hash_time: Lock<Duration>,
- /// The accumulated time spent decoding def path tables from metadata.
- pub decode_def_path_tables_time: Lock<Duration>,
/// Total number of values canonicalized queries constructed.
pub queries_canonicalized: AtomicUsize,
/// Number of times this query is invoked.
"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)
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),
arith_offset,
arm_target_feature,
array,
+ arrays,
as_str,
asm,
assert,
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,
}
// 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
-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(),
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,
})
}
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()
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()
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;
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
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());
}
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,
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());
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;
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,
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 },
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,
//! [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};
// 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)));
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;
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(),
// 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(),
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;
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(
//! 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);
+++ /dev/null
-// 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<DefId>;
-
- 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<ty::Region<'tcx>>;
-
- /// 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<ErrorReported>,
- /// A list of spans of arguments provided that were not valid.
- pub invalid_args: Vec<Span>,
-}
-
-/// 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::<Vec<_>>();
-
- 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<Span>,
- 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<Span> = 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 `<T as Foo>::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<Ty<'tcx>>,
- 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::<Vec<(ParamKindOrd, GenericParamDef)>>();
- param_types_present.sort_by_key(|(ord, _)| *ord);
- let (mut param_types_present, ordered_params): (
- Vec<ParamKindOrd>,
- Vec<GenericParamDef>,
- ) = 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::<Vec<String>>()
- .join(", then "),
- ordered_params
- .into_iter()
- .filter_map(|param| {
- if param.name == kw::SelfUpper {
- None
- } else {
- Some(param.name.to_string())
- }
- })
- .collect::<Vec<String>>()
- .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<usize, Output = u32>
- /// ^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<ConvertedBinding...>` result.
- ///
- /// Note that the type listing given here is *exactly* what the user provided.
- ///
- /// For (generic) associated types
- ///
- /// ```
- /// <Vec<u8> as Iterable<u8>>::Iter::<'a>
- /// ```
- ///
- /// We have the parent substs are the substs for the parent trait:
- /// `[Vec<u8>, u8]` and `generic_args` are the arguments for the associated
- /// type itself: `['a]`. The returned `SubstsRef` concatenates these two
- /// lists: `[Vec<u8>, 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<Ty<'tcx>>,
- ) -> (SubstsRef<'tcx>, Vec<ConvertedBinding<'a, 'tcx>>, 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<Item = u32>
- //
- // 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 `<T as Iterator>::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<String>,
- 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::<Vec<_>>().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<Type>`.
- 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<T = X>`
- /// 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<Item = u32>
- /// self_ty = Foo
- /// ```
- ///
- /// this would return `Foo: Iterator` and add `<Foo as Iterator>::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::<Result<Vec<_>, _>>()
- .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<ConvertedBinding<'a, 'tcx>>, 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<T: Debug>
- /// ^ ^^^^^ `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<T: Bar + Baz>() { }
- /// ^ ^^^^^^^^^ 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<Item = &'a u32>`, 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<DefId, Span>,
- path_span: Span,
- ) -> Result<(), ErrorReported> {
- let tcx = self.tcx();
-
- if !speculative {
- // Given something like `U: SomeTrait<T = X>`, we want to produce a
- // predicate like `<U as SomeTrait>::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<i32> { }
- // trait SuperTrait<A> { type T; }
- //
- // ... B: SubTrait<T = foo> ...
- // ```
- //
- // We want to produce `<B as SuperTrait<i32>>::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> <T as Iterator>::Item = &'a str // <-- 'a is bad
- // for<'a> <T as FnMut<(&'a u32,)>>::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<F: for<'a> 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<Item = u32>` this to
- // the "projection predicate" for:
- //
- // `<T as Iterator>::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<Item: Debug>` to
- //
- // `<T as Iterator>::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::<Vec<_>>()
- .join(" + "),
- ));
- err.note(
- "auto-traits like `Send` and `Sync` are traits that have special properties; \
- for more information on them, visit \
- <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>",
- );
- 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<Span, BTreeSet<DefId>> = 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() -> <Self as MyTrait>::MyOutput {
- // type MyOutput;
- // }
- // ```
- //
- // Here, the user could theoretically write `dyn MyTrait<Output = X>`,
- // but actually supporting that would "expand" to an infinitely-long type
- // `fix $ τ → dyn MyTrait<MyOutput = X, Output = <τ as MyTrait>::MyOutput`.
- //
- // Instead, we force the user to write
- // `dyn MyTrait<MyOutput = X, Output = X>`, 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::<SmallVec<[_; 8]>>();
- 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<Span, BTreeSet<DefId>>,
- potential_assoc_types: Vec<Span>,
- 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<Span, Vec<_>> = 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<Span> = 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<Output = Type>`
- //
- // 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<Output = Type>`
- [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<isize>` instead of
- // `Iterator<Item = isize>`.
- 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<Item = Type>`.
- 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<ty::PolyTraitRef<'tcx>, 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<I>(
- &self,
- all_candidates: impl Fn() -> I,
- ty_param_name: impl Fn() -> String,
- assoc_name: Ident,
- span: Span,
- is_equality: impl Fn() -> Option<String>,
- ) -> Result<ty::PolyTraitRef<'tcx>, ErrorReported>
- where
- I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
- {
- 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<I>(
- &self,
- all_candidates: impl Fn() -> I,
- ty_param_name: &str,
- assoc_name: Ident,
- span: Span,
- ) where
- I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
- {
- // 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<Ty<'tcx>>,
- 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 `<Self as ..>` 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<Item = &'a hir::PathSegment<'a>>>(
- &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<Ty<'tcx>>,
- kind: DefKind,
- def_id: DefId,
- ) -> Vec<PathSeg> {
- // 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<T>(...)
- //
- // In this case, the parameters are declared in the type space.
- //
- // 2. Reference to a constructor of an enum variant:
- //
- // enum E<T> { 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<T>() { }
- //
- // In this case, the path will again always have the form
- // `a::b::foo::<T>` 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<A> SomeStruct<A> {
- // fn foo<B>(...)
- // }
- //
- // Here we can have a path like
- // `a::b::SomeStruct::<A>::foo::<B>`, in which case parameters
- // may appear in two places. The penultimate segment,
- // `SomeStruct::<A>`, contains parameters in TypeSpace, and the
- // final segment, `foo::<B>` 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<Ty<'tcx>>,
- 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>>) -> 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<Span>,
- ) -> 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<ty::BoundRegion>,
- referenced_regions: FxHashSet<ty::BoundRegion>,
- 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<ty::ExistentialPredicate<'tcx>>>,
- ) -> Option<ty::Region<'tcx>> // 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<T: Bar + Baz>() { }
-/// ^^^^^^^^^ 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<Item = u32>` this would include `<T as
- /// Iterator>::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<Span>,
-}
-
-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()
- }
-}
--- /dev/null
+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<String>,
+ 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::<Vec<_>>().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<Type>`.
+ 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::<Result<Vec<_>, _>>()
+ .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<I>(
+ &self,
+ all_candidates: impl Fn() -> I,
+ ty_param_name: &str,
+ assoc_name: Ident,
+ span: Span,
+ ) where
+ I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
+ {
+ // 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<Span, BTreeSet<DefId>>,
+ potential_assoc_types: Vec<Span>,
+ 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<Span, Vec<_>> = 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<Span> = 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<Output = Type>`
+ //
+ // 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<Output = Type>`
+ [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<isize>` instead of
+ // `Iterator<Item = isize>`.
+ 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<Item = Type>`.
+ 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();
+ }
+}
--- /dev/null
+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 `<T as Foo>::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<Ty<'tcx>>,
+ 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::<Vec<(ParamKindOrd, GenericParamDef)>>();
+ param_types_present.sort_by_key(|(ord, _)| *ord);
+ let (mut param_types_present, ordered_params): (
+ Vec<ParamKindOrd>,
+ Vec<GenericParamDef>,
+ ) = 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::<Vec<String>>()
+ .join(", then "),
+ ordered_params
+ .into_iter()
+ .filter_map(|param| {
+ if param.name == kw::SelfUpper {
+ None
+ } else {
+ Some(param.name.to_string())
+ }
+ })
+ .collect::<Vec<String>>()
+ .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<Span>,
+ 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<Span> = 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::<Vec<_>>();
+
+ 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
+ }
+ }
+}
--- /dev/null
+//! 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<DefId>;
+
+ 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<ty::Region<'tcx>>;
+
+ /// 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<ErrorReported>,
+ /// A list of spans of arguments provided that were not valid.
+ pub invalid_args: Vec<Span>,
+}
+
+/// 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<usize, Output = u32>
+ /// ^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<ConvertedBinding...>` result.
+ ///
+ /// Note that the type listing given here is *exactly* what the user provided.
+ ///
+ /// For (generic) associated types
+ ///
+ /// ```
+ /// <Vec<u8> as Iterable<u8>>::Iter::<'a>
+ /// ```
+ ///
+ /// We have the parent substs are the substs for the parent trait:
+ /// `[Vec<u8>, u8]` and `generic_args` are the arguments for the associated
+ /// type itself: `['a]`. The returned `SubstsRef` concatenates these two
+ /// lists: `[Vec<u8>, 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<Ty<'tcx>>,
+ ) -> (SubstsRef<'tcx>, Vec<ConvertedBinding<'a, 'tcx>>, 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<Item = u32>
+ //
+ // 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 `<T as Iterator>::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<T = X>`
+ /// 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<Item = u32>
+ /// self_ty = Foo
+ /// ```
+ ///
+ /// this would return `Foo: Iterator` and add `<Foo as Iterator>::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<ConvertedBinding<'a, 'tcx>>, 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<T: Debug>
+ /// ^ ^^^^^ `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<T: Bar + Baz>() { }
+ /// ^ ^^^^^^^^^ 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<Item = &'a u32>`, 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<DefId, Span>,
+ path_span: Span,
+ ) -> Result<(), ErrorReported> {
+ let tcx = self.tcx();
+
+ if !speculative {
+ // Given something like `U: SomeTrait<T = X>`, we want to produce a
+ // predicate like `<U as SomeTrait>::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<i32> { }
+ // trait SuperTrait<A> { type T; }
+ //
+ // ... B: SubTrait<T = foo> ...
+ // ```
+ //
+ // We want to produce `<B as SuperTrait<i32>>::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> <T as Iterator>::Item = &'a str // <-- 'a is bad
+ // for<'a> <T as FnMut<(&'a u32,)>>::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<F: for<'a> 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<Item = u32>` this to
+ // the "projection predicate" for:
+ //
+ // `<T as Iterator>::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<Item: Debug>` to
+ //
+ // `<T as Iterator>::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::<Vec<_>>()
+ .join(" + "),
+ ));
+ err.note(
+ "auto-traits like `Send` and `Sync` are traits that have special properties; \
+ for more information on them, visit \
+ <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>",
+ );
+ 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<Span, BTreeSet<DefId>> = 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() -> <Self as MyTrait>::MyOutput {
+ // type MyOutput;
+ // }
+ // ```
+ //
+ // Here, the user could theoretically write `dyn MyTrait<Output = X>`,
+ // but actually supporting that would "expand" to an infinitely-long type
+ // `fix $ τ → dyn MyTrait<MyOutput = X, Output = <τ as MyTrait>::MyOutput`.
+ //
+ // Instead, we force the user to write
+ // `dyn MyTrait<MyOutput = X, Output = X>`, 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::<SmallVec<[_; 8]>>();
+ 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<ty::PolyTraitRef<'tcx>, 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<I>(
+ &self,
+ all_candidates: impl Fn() -> I,
+ ty_param_name: impl Fn() -> String,
+ assoc_name: Ident,
+ span: Span,
+ is_equality: impl Fn() -> Option<String>,
+ ) -> Result<ty::PolyTraitRef<'tcx>, ErrorReported>
+ where
+ I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
+ {
+ 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<Ty<'tcx>>,
+ 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 `<Self as ..>` 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<Item = &'a hir::PathSegment<'a>>>(
+ &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<Ty<'tcx>>,
+ kind: DefKind,
+ def_id: DefId,
+ ) -> Vec<PathSeg> {
+ // 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<T>(...)
+ //
+ // In this case, the parameters are declared in the type space.
+ //
+ // 2. Reference to a constructor of an enum variant:
+ //
+ // enum E<T> { 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<T>() { }
+ //
+ // In this case, the path will again always have the form
+ // `a::b::foo::<T>` 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<A> SomeStruct<A> {
+ // fn foo<B>(...)
+ // }
+ //
+ // Here we can have a path like
+ // `a::b::SomeStruct::<A>::foo::<B>`, in which case parameters
+ // may appear in two places. The penultimate segment,
+ // `SomeStruct::<A>`, contains parameters in TypeSpace, and the
+ // final segment, `foo::<B>` 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<Ty<'tcx>>,
+ 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>>) -> 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<Span>,
+ ) -> 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<ty::BoundRegion>,
+ referenced_regions: FxHashSet<ty::BoundRegion>,
+ 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<ty::ExistentialPredicate<'tcx>>>,
+ ) -> Option<ty::Region<'tcx>> // 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)
+ }
+}
--- /dev/null
+//! 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<T: Bar + Baz>() { }
+/// ^^^^^^^^^ 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<Item = u32>` this would include `<T as
+ /// Iterator>::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<Span>,
+}
+
+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()
+ }
+}
}
}
} 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,
expr.span,
ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
arm_span,
+ semi_span,
source: match_src,
prior_arms: other_arms.clone(),
last_ty: prior_arm_ty.unwrap(),
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 {
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
// 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
scrut_ty
}
}
+
+ fn find_block_span(
+ &self,
+ block: &'tcx hir::Block<'tcx>,
+ expected_ty: Option<Ty<'tcx>>,
+ ) -> (Span, Option<Span>) {
+ 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)
+ }
+ }
}
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;
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)
}
}
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};
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");
// 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;
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};
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(
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};
// 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));
}
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;
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,
};
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;
// (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()]))
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);
}
}
_ => {}
}
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),
let sp = expr.span;
// Check for `Future` implementations by constructing a predicate to
// prove: `<T as Future>::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)
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};
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,
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),
);
}
// 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 {
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;
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());
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));
});
//! 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;
}
TraitItem(hir::TraitItem {
- kind: TraitItemKind::Fn(FnSig { header, decl }, _),
+ kind: TraitItemKind::Fn(FnSig { header, decl, span: _ }, _),
ident,
generics,
..
pub mod expr_use_visitor;
mod astconv;
+mod bounds;
mod check_unused;
mod coherence;
mod collect;
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) {
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};
// 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 };
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,
}
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};
}
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<AssocKind> {
+ match *self {
+ ItemEnum::AssocConstItem(..) => Some(AssocKind::Const),
+ ItemEnum::AssocTypeItem(..) => Some(AssocKind::Type),
+ ItemEnum::TyMethodItem(..) | ItemEnum::MethodItem(..) => Some(AssocKind::Fn),
+ _ => None,
+ }
+ }
}
#[derive(Clone, Debug)]
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);
/// Codegen options strings to hand to the compiler.
pub codegen_options_strs: Vec<String>,
/// 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<String>,
+ pub debugging_opts_strs: Vec<String>,
/// 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
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);
.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) => {
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");
cfgs,
codegen_options,
codegen_options_strs,
- debugging_options,
- debugging_options_strs,
+ debugging_opts,
+ debugging_opts_strs,
target,
edition,
maybe_sysroot,
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};
pub auto_traits: Vec<DefId>,
/// 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<module, set<trait>>`
+ pub module_trait_cache: RefCell<FxHashMap<DefId, FxHashSet<DefId>>>,
}
impl<'tcx> DocContext<'tcx> {
// 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();
/// 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<F>(
+pub(crate) fn init_lints<F>(
mut allowed_lints: Vec<String>,
lint_opts: Vec<(String, lint::Level)>,
filter_call: F,
.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)
(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<Session>) {
// Parse, resolve, and typecheck the given crate.
let RustdocOptions {
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,
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
{
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,
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)
};
}),
// 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
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<RefCell<interface::BoxedResolver>>,
+ mut default_passes: passes::DefaultPassOption,
+ mut manual_passes: Vec<String>,
+ render_options: RenderOptions,
+ output_format: Option<OutputFormat>,
+) -> (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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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,
};
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, "")
#![feature(nll)]
#![feature(or_patterns)]
#![feature(test)]
-#![feature(ptr_offset_from)]
#![feature(crate_visibility_modifier)]
#![feature(never_type)]
#![feature(once_cell)]
}
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)),
// 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.
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");
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::<html::render::Context>(krate, renderopts, renderinfo, &diag, edition)
- }
- Some(config::OutputFormat::Json) => {
+ }),
+ Some(config::OutputFormat::Json) => sess.time("render_json", || {
run_renderer::<json::JsonRenderer>(krate, renderopts, renderinfo, &diag, edition)
- }
+ }),
}
}
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;
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;
}
}
fn examples_percentage(&self) -> Option<f64> {
- 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
}
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,
}
}
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;
}
}
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(
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;
impl fold::DocFolder for CoverageCalculator {
fn fold_item(&mut self, i: clean::Item) -> Option<clean::Item> {
- 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::<Vec<_>>().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,
}
}
_ => {
+ 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::<Vec<_>>().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),
+ );
}
}
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;
fn resolve(
&self,
path_str: &str,
- disambiguator: Option<Disambiguator>,
ns: Namespace,
current_item: &Option<String>,
parent_id: Option<DefId>,
extra_fragment: &Option<String>,
- item_opt: Option<&Item>,
) -> Result<(Res, Option<String>), ErrorKind> {
let cx = self.cx;
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()));
}
_ => {
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.
})
.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`](<SomeStruct as SomeTrait>::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`](<SomeStruct as SomeTrait>::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
// 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
)),
))
}
- } 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 {
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)
}
}
+fn resolve_associated_trait_item(
+ did: DefId,
+ module: DefId,
+ item_name: Symbol,
+ ns: Namespace,
+ cx: &DocContext<'_>,
+) -> Option<ty::AssocKind> {
+ let ty = cx.tcx.type_of(did);
+ // First consider automatic impls: `impl From<T> 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<DefId> {
+ 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
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
}
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);
}
}
}
- 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 {
.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.
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;
}
}
};
+ // 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)))
// 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;
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum Disambiguator {
+ Primitive,
Kind(DefKind),
Namespace(Namespace),
}
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 = [
"type" => NS(Namespace::TypeNS),
"value" => NS(Namespace::ValueNS),
"macro" => NS(Namespace::MacroNS),
+ "prim" | "primitive" => Primitive,
_ => return find_suffix(),
};
Ok((d, &rest[1..]))
}
}
- 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 {
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",
}
}
}
path_str: &str,
dox: &str,
link_range: Option<Range<usize>>,
- candidates: PerNS<Option<Res>>,
+ 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::<Vec<_>>();
match candidates.as_slice() {
[(first_def, _), (second_def, _)] => {
msg += &format!(
}
_ => {
let type_ = match (res, ns) {
+ (Res::PrimTy(_), _) => "prim",
(Res::Def(DefKind::Const, _), _) => "const",
(Res::Def(DefKind::Static, _), _) => "static",
(Res::Def(DefKind::Struct, _), _) => "struct",
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);
+ });
}
}
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);
+ });
}
}
//! - 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;
}
}
+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,
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(
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 {
-Subproject commit 86b120e6f302d39cd6973b6391fb299d7bc22122
+Subproject commit 45790d79496be37fbce6ec57abad5af8fa7a34d7
#include "llvm/ProfileData/Coverage/CoverageMappingWriter.h"
#include "llvm/ProfileData/InstrProf.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/LEB128.h"
#include <iostream>
const char* const Filenames[],
size_t FilenamesLen,
RustStringRef BufferOut) {
- SmallVector<StringRef,32> 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(
}
extern "C" uint32_t LLVMRustCoverageMappingVersion() {
- return coverage::CovMapVersion::CurrentVersion;
+ return coverage::CovMapVersion::Version3;
}
// 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") _);
+}
// 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() {
// 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");
// 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");
#[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)
}
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
+ _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(<ZST>)) }
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
+ _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(<ZST>)) }
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
+ (*_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(<ZST>)) }
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::<std::boxed::Box<S>>(move _4) -> [return: bb5, unwind: bb7]; // scope 1 at $DIR/box_expr.rs:8:5: 8:12
+ _3 = std::mem::drop::<std::boxed::Box<S>>(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<S>) {std::mem::drop::<std::boxed::Box<S>>}, val: Value(Scalar(<ZST>)) }
+ // + 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::<impl [&i32]>::as_ptr(move _1) -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44
+ _0 = core::slice::<impl [&i32]>::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::<impl [&i32]>::as_ptr}, val: Value(Scalar(<ZST>)) }
+ // + 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::<impl [&i32]>::as_ptr(move _1) -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55
+ _0 = core::slice::<impl [&i32]>::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::<impl [&i32]>::as_ptr}, val: Value(Scalar(<ZST>)) }
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
+ _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(<ZST>)) }
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
+ 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(<ZST>)) }
(_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
+ _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(<ZST>)) }
+ // + 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
+ _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(<ZST>)) }
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
+ _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(<ZST>)) }
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
+ _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(<ZST>)) }
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
+ _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(<ZST>)) }
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
++ _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(<ZST>)) }
}
bb1: {
- _0 = const foo(const -1_i32) -> bb3; // scope 0 at $DIR/switch_int.rs:9:14: 9:21
+ _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(<ZST>)) }
}
bb2: {
- _0 = const foo(const 0_i32) -> bb3; // scope 0 at $DIR/switch_int.rs:8:14: 8:20
+ _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(<ZST>)) }
}
bb1: {
- _0 = const foo(const -1_i32) -> bb3; // scope 0 at $DIR/switch_int.rs:9:14: 9:21
+ _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(<ZST>)) }
}
bb2: {
- _0 = const foo(const 0_i32) -> bb3; // scope 0 at $DIR/switch_int.rs:8:14: 8:20
+ _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(<ZST>)) }
+ // 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 = const consume(move _3) -> bb1; // scope 1 at $DIR/tuple_literal_propagation.rs:5:5: 5:15
+ _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(<ZST>)) }
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
+ _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(<ZST>)) }
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
+ _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(<ZST>)) }
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
+ _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(<ZST>)) }
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
+ _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<usize> {std::fmt::Formatter::precision}, val: Value(Scalar(<ZST>)) }
_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::<T>(move _18, move _19, move _20, move _21) -> bb9; // scope 2 at $DIR/funky_arms.rs:28:9: 28:68
+ _0 = float_to_exponential_common_shortest::<T>(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::<T>}, val: Value(Scalar(<ZST>)) }
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::<T>(move _11, move _12, move _13, move _14, move _17) -> bb8; // scope 3 at $DIR/funky_arms.rs:26:9: 26:87
+ _0 = float_to_exponential_common_exact::<T>(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::<T>}, val: Value(Scalar(<ZST>)) }
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::<Foo>(move _8) -> [return: bb7, unwind: bb9]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:9: 26:16
+ _7 = take::<Foo>(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::<Foo>}, val: Value(Scalar(<ZST>)) }
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::<Bar>(move _10) -> [return: bb10, unwind: bb11]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:9: 27:16
+ _9 = take::<Bar>(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::<Bar>}, val: Value(Scalar(<ZST>)) }
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
+ _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(<ZST>)) }
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
+ _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(<ZST>)) }
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<u32>); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
-- (*_2) = const std::vec::Vec::<u32>::new() -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
+- (*_2) = std::vec::Vec::<u32>::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<u32>) = const alloc::raw_vec::RawVec::<u32> { ptr: std::ptr::Unique::<u32> { pointer: {0x4 as *const u32}, _marker: std::marker::PhantomData::<u32> }, cap: 0_usize, alloc: std::alloc::Global }; // scope 2 at $SRC_DIR/alloc/src/vec.rs:LL:COL
+ // ty::Const
- }
-
- bb4 (cleanup): {
-- _3 = const alloc::alloc::box_free::<std::vec::Vec<u32>>(move (_2.0: std::ptr::Unique<std::vec::Vec<u32>>)) -> bb1; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
+- _3 = alloc::alloc::box_free::<std::vec::Vec<u32>>(move (_2.0: std::ptr::Unique<std::vec::Vec<u32>>)) -> 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<std::vec::Vec<u32>>) {alloc::alloc::box_free::<std::vec::Vec<u32>>}, val: Value(Scalar(<ZST>)) }
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<u32>); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
-- (*_2) = const std::vec::Vec::<u32>::new() -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
+- (*_2) = std::vec::Vec::<u32>::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<u32>) = const alloc::raw_vec::RawVec::<u32> { ptr: std::ptr::Unique::<u32> { pointer: {0x4 as *const u32}, _marker: std::marker::PhantomData::<u32> }, cap: 0_usize, alloc: std::alloc::Global }; // scope 2 at $SRC_DIR/alloc/src/vec.rs:LL:COL
+ // ty::Const
- }
-
- bb4 (cleanup): {
-- _3 = const alloc::alloc::box_free::<std::vec::Vec<u32>>(move (_2.0: std::ptr::Unique<std::vec::Vec<u32>>)) -> bb1; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
+- _3 = alloc::alloc::box_free::<std::vec::Vec<u32>>(move (_2.0: std::ptr::Unique<std::vec::Vec<u32>>)) -> 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<std::vec::Vec<u32>>) {alloc::alloc::box_free::<std::vec::Vec<u32>>}, val: Value(Scalar(<ZST>)) }
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
+ _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(<ZST>)) }
bb0: {
StorageLive(_1); // scope 0 at $DIR/inline-specialization.rs:5:9: 5:10
-- _1 = const <std::vec::Vec<()> as Foo>::bar() -> bb1; // scope 0 at $DIR/inline-specialization.rs:5:13: 5:38
+- _1 = <std::vec::Vec<()> 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 {<std::vec::Vec<()> as Foo>::bar}, val: Value(Scalar(<ZST>)) }
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 <dyn X as X>::y(move _2) -> bb1; // scope 0 at $DIR/inline-trait-method.rs:9:5: 9:10
+ _0 = <dyn X as X>::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 {<dyn X as X>::y}, val: Value(Scalar(<ZST>)) }
_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 <dyn X as X>::y(move _2) -> bb1; // scope 1 at $DIR/inline-trait-method_2.rs:10:5: 10:10
+ _0 = <dyn X as X>::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 {<dyn X as X>::y}, val: Value(Scalar(<ZST>)) }
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
+ _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(<ZST>)) }
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
+ _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(<ZST>)) }
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
+ _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(<ZST>)) }
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::<S>(move _4) -> [return: bb2, unwind: bb5]; // scope 2 at $DIR/issue-41110.rs:17:5: 17:12
+ _3 = std::mem::drop::<S>(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::<S>}, val: Value(Scalar(<ZST>)) }
_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
+ _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(<ZST>)) }
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
+ _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(<ZST>)) }
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::<u32>::None; // scope 0 at $DIR/issue-62289.rs:9:15: 9:19
- _3 = const <std::option::Option<u32> as std::ops::Try>::into_result(move _4) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
+ _3 = <std::option::Option<u32> 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<u32>) -> std::result::Result<<std::option::Option<u32> as std::ops::Try>::Ok, <std::option::Option<u32> as std::ops::Try>::Error> {<std::option::Option<u32> as std::ops::Try>::into_result}, val: Value(Scalar(<ZST>)) }
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 <std::option::NoneError as std::convert::From<std::option::NoneError>>::from(move _9) -> [return: bb8, unwind: bb3]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20
+ _8 = <std::option::NoneError as std::convert::From<std::option::NoneError>>::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 {<std::option::NoneError as std::convert::From<std::option::NoneError>>::from}, val: Value(Scalar(<ZST>)) }
bb8: {
StorageDead(_9); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20
- _0 = const <std::option::Option<std::boxed::Box<u32>> as std::ops::Try>::from_error(move _8) -> [return: bb9, unwind: bb3]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20
+ _0 = <std::option::Option<std::boxed::Box<u32>> 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(<std::option::Option<std::boxed::Box<u32>> as std::ops::Try>::Error) -> std::option::Option<std::boxed::Box<u32>> {<std::option::Option<std::boxed::Box<u32>> as std::ops::Try>::from_error}, val: Value(Scalar(<ZST>)) }
bb0: {
StorageLive(_1); // scope 0 at $DIR/issue-72181.rs:24:13: 24:34
- _1 = const std::mem::size_of::<Foo>() -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:24:13: 24:34
+ _1 = std::mem::size_of::<Foo>() -> [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::<Foo>}, val: Value(Scalar(<ZST>)) }
bb0: {
StorageLive(_1); // scope 0 at $DIR/issue-72181.rs:24:13: 24:34
- _1 = const std::mem::size_of::<Foo>() -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:24:13: 24:34
+ _1 = std::mem::size_of::<Foo>() -> [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::<Foo>}, val: Value(Scalar(<ZST>)) }
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
+ _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(<ZST>)) }
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
+ 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(<ZST>)) }
_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
+ _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(<ZST>)) }
StorageLive(_28); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- _28 = const std::intrinsics::transmute::<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>>(move _25) -> bb3; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ _28 = std::intrinsics::transmute::<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>>(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::<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>>}, val: Value(Scalar(<ZST>)) }
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
+ _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(<ZST>)) }
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
+ _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(<ZST>)) }
StorageLive(_30); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- _30 = const std::intrinsics::transmute::<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>>(move _27) -> bb5; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ _30 = std::intrinsics::transmute::<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>>(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::<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>>}, val: Value(Scalar(<ZST>)) }
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
+ _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(<ZST>)) }
(_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
+ 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(<ZST>)) }
_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
+ _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(<ZST>)) }
StorageLive(_28); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- _28 = const std::intrinsics::transmute::<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>>(move _25) -> bb3; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ _28 = std::intrinsics::transmute::<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>>(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::<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>>}, val: Value(Scalar(<ZST>)) }
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
+ _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(<ZST>)) }
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
+ _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(<ZST>)) }
StorageLive(_30); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- _30 = const std::intrinsics::transmute::<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>>(move _27) -> bb5; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ _30 = std::intrinsics::transmute::<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>>(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::<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>>}, val: Value(Scalar(<ZST>)) }
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
+ _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(<ZST>)) }
(_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
+ 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(<ZST>)) }
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
+ _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(<ZST>)) }
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::<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>>(move _47) -> bb6; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ _46 = std::intrinsics::transmute::<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>>(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::<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>>}, val: Value(Scalar(<ZST>)) }
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
+ _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(<ZST>)) }
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
+ _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(<ZST>)) }
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::<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>>(move _51) -> bb8; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ _50 = std::intrinsics::transmute::<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>>(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::<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>>}, val: Value(Scalar(<ZST>)) }
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
+ _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(<ZST>)) }
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
+ 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(<ZST>)) }
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
+ _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(<ZST>)) }
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::<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>>(move _47) -> bb6; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ _46 = std::intrinsics::transmute::<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>>(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::<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>>}, val: Value(Scalar(<ZST>)) }
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
+ _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(<ZST>)) }
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
+ _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(<ZST>)) }
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::<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>>(move _51) -> bb8; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+ _50 = std::intrinsics::transmute::<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>>(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::<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>>}, val: Value(Scalar(<ZST>)) }
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
+ _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(<ZST>)) }
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
+ 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(<ZST>)) }
_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
+ _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(<ZST>)) }
_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
+ _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(<ZST>)) }
_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
+ _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(<ZST>)) }
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
+ _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(<ZST>)) }
bb4: {
StorageLive(_10); // bb4[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18
- _10 = const Const(Value(Scalar(<ZST>)): 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
+ _10 = Const(Value(Scalar(<ZST>)): 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(<ZST>)) }
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(<ZST>)): 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
+ _8 = Const(Value(Scalar(<ZST>)): 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(<ZST>)) }
bb4: {
StorageLive(_10); // bb4[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18
- _10 = const Const(Value(Scalar(<ZST>)): 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
+ _10 = Const(Value(Scalar(<ZST>)): 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(<ZST>)) }
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(<ZST>)): 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
+ _8 = Const(Value(Scalar(<ZST>)): 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(<ZST>)) }
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
+ 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(<ZST>)) }
// + 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 <str as std::string::ToString>::to_string(move _3) -> bb2; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:34
+ _2 = <str as std::string::ToString>::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 {<str as std::string::ToString>::to_string}, val: Value(Scalar(<ZST>)) }
bb2: {
StorageDead(_3); // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:33: 9:34
- _1 = const std::mem::drop::<std::string::String>(move _2) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:5: 9:35
+ _1 = std::mem::drop::<std::string::String>(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::<std::string::String>}, val: Value(Scalar(<ZST>)) }
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 <Test as std::ops::Drop>::drop(move _2) -> bb1; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+ _3 = <Test as std::ops::Drop>::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) {<Test as std::ops::Drop>::drop}, val: Value(Scalar(<ZST>)) }
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
+ _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(<ZST>)) }
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
+ _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(<ZST>)) }
-
- 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
+- _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(<ZST>)) }
-
- 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
+- _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(<ZST>)) }
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
+ _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(<ZST>)) }
- (_5.1: ()) = const (); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:13: 14:21
- 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
+- _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 = const use_zst(const ((), ())) -> bb1; // 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(<ZST>)) }
- _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
++ _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(<ZST>)) }
}
bb2: {
- _0 = const noop() -> bb3; // scope 0 at $DIR/simplify_match.rs:7:17: 7:23
+ _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(<ZST>)) }
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<std::ptr::NonNull<Node>>); // scope 1 at $DIR/simplify_try_if_let.rs:26:43: 26:53
- _5 = const std::option::Option::<std::ptr::NonNull<Node>>::take(move _6) -> bb4; // scope 1 at $DIR/simplify_try_if_let.rs:26:43: 26:60
+ _5 = std::option::Option::<std::ptr::NonNull<Node>>::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::ptr::NonNull<Node>>) -> std::option::Option<std::ptr::NonNull<Node>> {std::option::Option::<std::ptr::NonNull<Node>>::take}, val: Value(Scalar(<ZST>)) }
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::<Node>::as_mut(move _12) -> bb7; // scope 3 at $DIR/simplify_try_if_let.rs:28:25: 28:38
+ _11 = std::ptr::NonNull::<Node>::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<Node>) -> &'r mut Node {std::ptr::NonNull::<Node>::as_mut}, val: Value(Scalar(<ZST>)) }
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
+ _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> {empty}, val: Value(Scalar(<ZST>)) }
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
+ _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> {empty}, val: Value(Scalar(<ZST>)) }
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
+ _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> {empty}, val: Value(Scalar(<ZST>)) }
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
+ _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> {empty}, val: Value(Scalar(<ZST>)) }
- }
-
- bb5: {
-- _5 = const loop_forever() -> bb6; // scope 2 at $DIR/unreachable_diverging.rs:16:13: 16:27
-+ _5 = const loop_forever() -> bb5; // scope 2 at $DIR/unreachable_diverging.rs:16:13: 16:27
+- _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(<ZST>)) }
bb7: {
_2 = &mut (*_1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
- _3 = const <std::vec::Vec<i32> as std::ops::Drop>::drop(move _2) -> [return: bb6, unwind: bb5]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+ _3 = <std::vec::Vec<i32> 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<i32>) {<std::vec::Vec<i32> as std::ops::Drop>::drop}, val: Value(Scalar(<ZST>)) }
bb7: {
_2 = &mut (*_1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
- _3 = const <std::vec::Vec<i32> as std::ops::Drop>::drop(move _2) -> [return: bb6, unwind: bb5]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+ _3 = <std::vec::Vec<i32> 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<i32>) {<std::vec::Vec<i32> as std::ops::Drop>::drop}, val: Value(Scalar(<ZST>)) }
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
+ _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(<ZST>)) }
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
+ _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(<ZST>)) }
}
],
"type": "llvm.coverage.json.export",
- "version": "2.0.0"
+ "version": "2.0.1"
}
--- /dev/null
+#![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() {}
+}
--- /dev/null
+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
+
-+-------------------------------------+------------+------------+------------+------------+------------+
-| 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% |
++-------------------------------------+------------+------------+------------+------------+
--- /dev/null
+// 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;
--- /dev/null
+{"$DIR/doc-examples-json.rs":{"total":3,"with_docs":2,"total_examples":2,"with_examples":1}}
-+-------------------------------------+------------+------------+------------+------------+------------+
-| 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% |
++-------------------------------------+------------+------------+------------+------------+
-+-------------------------------------+------------+------------+------------+------------+------------+
-| 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% |
++-------------------------------------+------------+------------+------------+------------+
-+-------------------------------------+------------+------------+------------+------------+------------+
-| 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% |
++-------------------------------------+------------+------------+------------+------------+
-+-------------------------------------+------------+------------+------------+------------+------------+
-| File | Documented | Total | Percentage | Examples | Percentage |
-+-------------------------------------+------------+------------+------------+------------+------------+
-| ...st/rustdoc-ui/coverage/exotic.rs | 1 | 1 | 100.0% | 0 | 0.0% |
-| <anon> | 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% |
+| <anon> | 2 | 100.0% | 0 | 0.0% |
++-------------------------------------+------------+------------+------------+------------+
+| Total | 3 | 100.0% | 0 | 0.0% |
++-------------------------------------+------------+------------+------------+------------+
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<T: Clone> {
+ /// ```
+ /// 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;
-{"$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}}
-+-------------------------------------+------------+------------+------------+------------+------------+
-| 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% |
++-------------------------------------+------------+------------+------------+------------+
-+-------------------------------------+------------+------------+------------+------------+------------+
-| 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% |
++-------------------------------------+------------+------------+------------+------------+
-+-------------------------------------+------------+------------+------------+------------+------------+
-| 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% |
++-------------------------------------+------------+------------+------------+------------+
--- /dev/null
+#![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
+}
--- /dev/null
+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
+
//~^ 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,
+}
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
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
--- /dev/null
+#![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
--- /dev/null
+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
+
--- /dev/null
+// 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
+ }
+}
--- /dev/null
+// 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() {}
// 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;
--> $DIR/bound-lifetime-in-binding-only.rs:71:1
|
LL | fn main() { }
- | ^^^^^^^^^^^^^
+ | ^^^^^^^^^
error: aborting due to previous error
--> $DIR/bound-lifetime-in-return-only.rs:49:1
|
LL | fn main() { }
- | ^^^^^^^^^^^^^
+ | ^^^^^^^^^
error: aborting due to previous error
--> $DIR/project-fn-ret-contravariant.rs:50:1
|
LL | fn main() { }
- | ^^^^^^^^^^^^^
+ | ^^^^^^^^^
error: aborting due to previous error
--> $DIR/project-fn-ret-contravariant.rs:50:1
|
LL | fn main() { }
- | ^^^^^^^^^^^^^
+ | ^^^^^^^^^
error: aborting due to previous error
--> $DIR/project-fn-ret-invariant.rs:60:1
|
LL | fn main() {}
- | ^^^^^^^^^^^^
+ | ^^^^^^^^^
error: aborting due to previous error
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
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`
}
}
-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
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
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
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
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
[_, _, (_x, _)] => {}
}
match a {
- [.., _y] => {} //~ ERROR use of moved value
+ [.., _y] => {} //~ ERROR use of partially moved value
}
}
[_x, _, _] => {}
}
match a {
- //~^ ERROR use of moved value
+ //~^ ERROR use of partially moved value
[_y @ .., _, _] => {}
}
}
[.., _x] => {}
}
match a {
- //~^ ERROR use of moved value
+ //~^ ERROR use of partially moved value
[_, _, _y @ ..] => {}
}
}
[(_x, _), _, _] => {}
}
match a {
- //~^ ERROR use of moved value
+ //~^ ERROR use of partially moved value
[_y @ .., _, _] => {}
}
}
[.., (_x, _)] => {}
}
match a {
- //~^ ERROR use of moved value
+ //~^ ERROR use of partially moved value
[_, _, _y @ ..] => {}
}
}
[x @ .., _] => {}
}
match a {
- //~^ ERROR use of moved value
+ //~^ ERROR use of partially moved value
[_, _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
|
= 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
|
= 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
[_, _, _x] => {}
}
match a {
- //~^ ERROR use of moved value
+ //~^ ERROR use of partially moved value
[.., _y, _] => {}
}
}
[_, _, (_x, _)] => {}
}
match a {
- //~^ ERROR use of moved value
+ //~^ ERROR use of partially moved value
[.., (_, _y)] => {}
}
}
[_x, _, _] => {}
}
match a {
- //~^ ERROR use of moved value
+ //~^ ERROR use of partially moved value
[_, _y @ ..] => {}
}
}
[.., _x] => {}
}
match a {
- //~^ ERROR use of moved value
+ //~^ ERROR use of partially moved value
[_y @ .., _] => {}
}
}
[(_x, _), _, _] => {}
}
match a {
- //~^ ERROR use of moved value
+ //~^ ERROR use of partially moved value
[_, _y @ ..] => {}
}
}
[.., (_x, _)] => {}
}
match a {
- //~^ ERROR use of moved value
+ //~^ ERROR use of partially moved value
[_y @ .., _] => {}
}
}
[_, _y @ ..] => {}
}
match a {
- //~^ ERROR use of moved value
+ //~^ ERROR use of partially moved value
[(_x, _), _, _] => {}
}
}
[_y @ .., _] => {}
}
match a {
- //~^ ERROR use of moved value
+ //~^ ERROR use of partially moved value
[.., (_x, _)] => {}
}
}
[x @ .., _, _] => {}
}
match a {
- //~^ ERROR use of moved value
+ //~^ ERROR use of partially moved value
[_, _y @ ..] => {}
}
}
-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
|
= 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
|
= 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
|
= 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
[_, _, _x] => {}
}
match a {
- //~^ ERROR use of moved value
+ //~^ ERROR use of partially moved value
[.., ref _y, _] => {}
}
}
[_, _, (_x, _)] => {}
}
match a {
- //~^ ERROR use of moved value
+ //~^ ERROR use of partially moved value
[.., (_, ref _y)] => {}
}
}
[_x, _, _] => {}
}
match a {
- //~^ ERROR use of moved value
+ //~^ ERROR use of partially moved value
[_, ref _y @ ..] => {}
}
}
[.., _x] => {}
}
match a {
- //~^ ERROR use of moved value
+ //~^ ERROR use of partially moved value
[ref _y @ .., _] => {}
}
}
[(_x, _), _, _] => {}
}
match a {
- //~^ ERROR use of moved value
+ //~^ ERROR use of partially moved value
[_, ref _y @ ..] => {}
}
}
[.., (_x, _)] => {}
}
match a {
- //~^ ERROR use of moved value
+ //~^ ERROR use of partially moved value
[ref _y @ .., _] => {}
}
}
[_, _y @ ..] => {}
}
match a {
- //~^ ERROR use of moved value
+ //~^ ERROR use of partially moved value
[(ref _x, _), _, _] => {}
}
}
[_y @ .., _] => {}
}
match a {
- //~^ ERROR use of moved value
+ //~^ ERROR use of partially moved value
[.., (ref _x, _)] => {}
}
}
[x @ .., _, _] => {}
}
match a {
- //~^ ERROR use of moved value
+ //~^ ERROR use of partially moved value
[_, ref _y @ ..] => {}
}
}
-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
|
= 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
|
= 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
|
= 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
|
= 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
|
= 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
|
= 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
|
= 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
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`
}
-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;
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`
}
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`
}
-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;
--> $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
--> $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
--> $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
--> $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
--> $DIR/coherence-overlap-downstream-inherent.rs:7:26
|
LL | impl<T:Sugar> Sweet<T> { fn dummy(&self) { } }
- | ^^^^^^^^^^^^^^^^^^^ duplicate definitions for `dummy`
+ | ^^^^^^^^^^^^^^^ duplicate definitions for `dummy`
LL |
LL | impl<T:Fruit> Sweet<T> { 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<X, T> A<T, X> where T: Bar<X> { fn f(&self) {} }
- | ^^^^^^^^^^^^^^ duplicate definitions for `f`
+ | ^^^^^^^^^^^ duplicate definitions for `f`
LL |
LL | impl<X> A<i32, X> { fn f(&self) {} }
- | -------------- other definition for `f`
+ | ----------- other definition for `f`
|
= note: downstream crates may implement trait `Bar<_>` for type `i32`
--> $DIR/coherence-overlap-issue-23516-inherent.rs:9:25
|
LL | impl<T:Sugar> Cake<T> { fn dummy(&self) { } }
- | ^^^^^^^^^^^^^^^^^^^ duplicate definitions for `dummy`
+ | ^^^^^^^^^^^^^^^ duplicate definitions for `dummy`
LL |
LL | impl<U:Sugar> Cake<Box<U>> { fn dummy(&self) { } }
- | ------------------- other definition for `dummy`
+ | --------------- other definition for `dummy`
|
= note: downstream crates may implement trait `Sugar` for type `std::boxed::Box<_>`
--> $DIR/coherence-overlap-upstream-inherent.rs:12:32
|
LL | impl<T> A<T> where T: Remote { fn dummy(&self) { } }
- | ^^^^^^^^^^^^^^^^^^^ duplicate definitions for `dummy`
+ | ^^^^^^^^^^^^^^^ duplicate definitions for `dummy`
LL |
LL | impl A<i16> { 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
// normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
// normalize-stderr-test "thread.*panicked.*\n" -> ""
// normalize-stderr-test "stack backtrace:\n" -> ""
-// normalize-stderr-test " \d{1,}: .*\n" -> ""
+// normalize-stderr-test "\s\d{1,}: .*\n" -> ""
+// normalize-stderr-test "\s at .*\n" -> ""
// normalize-stderr-test ".*note: Some details.*\n" -> ""
#![allow(unconditional_panic)]
error: reaching this expression at runtime will panic or abort
- --> $DIR/const-eval-query-stack.rs:18:28
+ --> $DIR/const-eval-query-stack.rs:19:28
|
LL | let x: &'static i32 = &(1 / 0);
| -^^^^^^^
-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();
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/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();
--- /dev/null
+// 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<T>(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();
+}
--- /dev/null
+// 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<T>(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<NonDet> 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();
+}
-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() }
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/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() }
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/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() }
-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() } }
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/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() } }
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/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() } }
-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() }
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/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() }
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/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() }
// run-pass
#![feature(const_ptr_offset)]
#![feature(const_ptr_offset_from)]
-#![feature(ptr_offset_from)]
use std::ptr;
#[repr(C)]
#![feature(const_raw_ptr_deref)]
#![feature(const_ptr_offset_from)]
-#![feature(ptr_offset_from)]
struct Struct {
field: (),
#![feature(const_raw_ptr_deref)]
#![feature(const_ptr_offset_from)]
-#![feature(ptr_offset_from)]
#[repr(C)]
struct Struct {
| |
| ptr_offset_from cannot compute offset of pointers into different allocations.
| inside `std::ptr::const_ptr::<impl *const Struct>::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 | |
| |
| unable to turn bytes into a pointer
| inside `std::ptr::const_ptr::<impl *const u8>::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 | |
| |
| exact_div: 1_isize cannot be divided by 2_isize without remainder
| inside `std::ptr::const_ptr::<impl *const u16>::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 | |
| |
| inbounds test failed: 0x0 is not a valid pointer
| inside `std::ptr::const_ptr::<impl *const u8>::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 | |
| |
| unable to turn bytes into a pointer
| inside `std::ptr::const_ptr::<impl *const u8>::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 | |
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
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
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
--> $DIR/dupe-symbols-4.rs:23:5
|
LL | fn fail(self) {}
- | ^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^
error: aborting due to previous error
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
--> $DIR/dupe-symbols-7.rs:12:1
|
LL | fn main(){}
- | ^^^^^^^^^^^
+ | ^^^^^^^^^
|
= help: did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead
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
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
--> $DIR/E0445.rs:9:1
|
LL | pub fn foo<T: Foo> (t: T) {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait
error: aborting due to 3 previous errors
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
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
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
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
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
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
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
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
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
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
LL | | where
LL | | I: IntoIterator,
LL | | I::Item: for<'a> Into<&'a ()>,
-LL | | {}
- | |__- defined here
+ | |__________________________________- defined here
...
LL | f(&[f()]);
| ^-- supplied 0 arguments
note: `function` defined here
--> $DIR/infinite-instantiation.rs:19:1
|
-LL | / fn function<T:ToOpt + Clone>(counter: usize, t: T) {
-LL | | if counter > 0 {
-LL | | function(counter - 1, t.to_option());
-LL | |
-LL | | }
-LL | | }
- | |_^
+LL | fn function<T:ToOpt + Clone>(counter: usize, t: T) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
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
|
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
|
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
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
|
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
|
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
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<dyn Subscriber<Input=<Self as Publisher>::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<dyn Subscriber<Input=<Self as Publisher>::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
|
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<dyn Subscriber<Input=<Self as Publisher>::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<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
--> $DIR/issue-20831-debruijn.rs:28:33
note: first, the lifetime cannot 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<dyn Subscriber<Input=<Self as Publisher>::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<dyn Subscriber<Input=<Self as Publisher>::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
|
note: first, the lifetime cannot 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<dyn Subscriber<Input=<Self as Publisher>::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<dyn Subscriber<Input=<Self as Publisher>::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
|
error: reached the type-length limit while instantiating `D::matches::$CLOSURE`
--> $DIR/issue-22638.rs:53:5
|
-LL | / pub fn matches<F: Fn()>(&self, f: &F) {
-LL | |
-LL | | let &D(ref a) = self;
-LL | | a.matches(f)
-LL | | }
- | |_____^
+LL | pub fn matches<F: Fn()>(&self, f: &F) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: consider adding a `#![type_length_limit="30408681"]` attribute to your crate
--> $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!
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
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
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<Self::Item>
-LL | |
-LL | |
-LL | | {
-LL | | Some(&mut self.0)
-LL | | }
- | |_____^
+LL | fn next(&'a mut self) -> Option<Self::Item>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...does not necessarily outlive the lifetime `'a` as defined on the impl at 3:6
--> $DIR/issue-37884.rs:3:6
|
LL | / fn rec<T>(mut it: T)
LL | | where
LL | | T: Iterator,
-LL | | {
-... |
-LL | | }
-LL | | }
- | |_^
+ | |________________^
error: aborting due to previous error
note: `generic` defined here
--> $DIR/issue-8727.rs:6:1
|
-LL | / fn generic<T>() {
-LL | | generic::<Option<T>>();
-LL | | }
- | |_^
+LL | fn generic<T>() {
+ | ^^^^^^^^^^^^^^^
error: aborting due to previous error; 1 warning emitted
}
}
}
+
+#[allow(improper_ctypes)]
+mod unknown_layout {
+ mod a {
+ extern "C" {
+ pub fn generic(l: Link<u32>);
+ }
+ pub struct Link<T> {
+ pub item: T,
+ pub next: *const Link<T>,
+ }
+ }
+
+ mod b {
+ extern "C" {
+ pub fn generic(l: Link<u32>);
+ }
+ pub struct Link<T> {
+ pub item: T,
+ pub next: *const Link<T>,
+ }
+ }
+}
--> $DIR/marker-trait-with-associated-items.rs:36:5
|
LL | fn foo() {}
- | ^^^^^^^^^^^
+ | ^^^^^^^^
error: aborting due to 6 previous errors
--- /dev/null
+// 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
+ },
+ };
+}
--- /dev/null
+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`.
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<List>) -> isize {
-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<List>`, which does not implement the `Copy` trait
+ = note: partial move occurs because value has type `std::boxed::Box<List>`, 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),
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() {}
-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
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
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
|
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
}
-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<i32>`, which does not implement the `Copy` trait
+ = note: partial move occurs because `x.0` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
error: aborting due to previous error
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<B>) -> Self {
-LL | | C { f: b }
-LL | | }
- | |_____^
+LL | fn from_box(b: Box<B>) -> Self {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that the expression is assignable
--> $DIR/type-alias-free-regions.rs:17:16
|
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
|
// run-pass
-#![feature(ptr_offset_from)]
-
fn main() {
let mut a = [0; 5];
let ptr1: *mut i32 = &mut a[1];
error: should have no type parameters
--> $DIR/panic-handler-bad-signature-4.rs:9:1
|
-LL | / fn panic<T>(pi: &PanicInfo) -> ! {
-LL | |
-LL | | loop {}
-LL | | }
- | |_^
+LL | fn panic<T>(pi: &PanicInfo) -> ! {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
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
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
--- /dev/null
+// check-pass
+
+// Unlike `if` condition, `match` guards accept struct literals.
+// This is detected in <https://github.com/rust-lang/rust/pull/74566#issuecomment-663613705>.
+
+#[derive(PartialEq)]
+struct Foo {
+ x: isize,
+}
+
+fn foo(f: Foo) {
+ match () {
+ () if f == Foo { x: 42 } => {}
+ _ => {}
+ }
+}
+
+fn main() {}
| - `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
| - `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
--> $DIR/private-in-public-non-principal.rs:7:1
|
LL | pub fn leak_dyn_nonprincipal() -> Box<dyn PubPrincipal + PrivNonPrincipal> { 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!
--> $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 <https://github.com/rust-lang/rust/issues/34537>
--> $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 <https://github.com/rust-lang/rust/issues/34537>
--> $DIR/private-in-public-warn.rs:61:9
|
LL | fn f<T: PrivTr>(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 <https://github.com/rust-lang/rust/issues/34537>
--> $DIR/private-in-public-warn.rs:83:9
|
LL | fn f<T>(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 <https://github.com/rust-lang/rust/issues/34537>
--> $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 <https://github.com/rust-lang/rust/issues/34537>
| - `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
| - `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
| - `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
| - `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
| - `traits::PrivTr` declared as private
...
LL | pub fn f<T: PrivTr>(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
| - `traits::PrivTr` declared as private
...
LL | pub fn f<U: PrivTr>(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
| - `traits_where::PrivTr` declared as private
...
LL | pub fn f<T>(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
| - `traits_where::PrivTr` declared as private
...
LL | pub fn f<U>(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
| - `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
| - `generics::Priv` declared as private
...
LL | pub fn f2(arg: Pub<Priv>) {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
error[E0446]: private type `generics::Priv<generics::Pub>` in public interface
--> $DIR/private-in-public.rs:65:5
| - `generics::Priv<generics::Pub>` declared as private
...
LL | pub fn f3(arg: Priv<Pub>) {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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
| - `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
| - `aliases_pub::PrivTr` declared as private
...
LL | pub fn f3(arg: <Priv as PrivTr>::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
| - `aliases_pub::Priv` declared as private
...
LL | pub fn f3(arg: <Priv as PrivTr>::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
| - `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
| - `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
| - `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
| - `aliases_priv::PrivTr` declared as private
...
LL | pub fn f3(arg: <Priv as PrivTr>::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
| - `aliases_priv::Priv` declared as private
...
LL | pub fn f3(arg: <Priv as PrivTr>::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
| - `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
| - `aliases_params::Priv` declared as private
...
LL | pub fn f3(arg: Result<u8>) {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
error: aborting due to 32 previous errors
--> $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
| - `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
| - `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
--- /dev/null
+// 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
+}
--- /dev/null
+// 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);
+}
--- /dev/null
+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) }]
--- /dev/null
+// ignore-test this is not a test
+
+macro_rules! arrays {
+ ($name:ident) => {
+ #[my_macro] struct Two($name);
+ }
+}
--- /dev/null
+// ignore-test this is not a test
+
+macro_rules! impl_macros {
+ ($name:ident) => {
+ #[my_macro] struct One($name);
+ }
+}
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),
},
]
// 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
}
}
}
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
--> $DIR/no-macro-use-attr.rs:10:1
|
LL | fn main() {}
- | ^^^^^^^^^^^^
+ | ^^^^^^^^^
error: aborting due to previous error; 1 warning emitted
},
]
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,
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),
// aux-build:weird-hygiene.rs
-// check-pass
-// FIXME: This should actually error, see PR #73084
#![feature(stmt_expr_attributes)]
#![feature(proc_macro_hygiene)]
#[derive(WeirdDerive)]
enum MyEnum {
- Value = (stringify!($tokens + hidden_ident), 1).1
+ Value = (stringify!($tokens + hidden_ident), 1).1 //~ ERROR cannot find
}
inner!();
($token:expr) => {
#[recollect_attr] {
$token;
- hidden_ident
+ hidden_ident //~ ERROR cannot find
}
}
}
--- /dev/null
+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`.
// run-pass
// Test inclusive range syntax.
-#![feature(range_is_empty)]
#![allow(unused_braces)]
#![allow(unused_comparisons)]
println!("allocate({:?}) = {:?}", layout, ptr);
}
- ptr.as_non_null_ptr().as_ptr()
+ ptr.as_mut_ptr()
}
unsafe fn deallocate(ptr: *mut u8, layout: Layout) {
}
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 {
note: `test` defined here
--> $DIR/recursion.rs:15:1
|
-LL | / fn test<T:Dot> (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<T:Dot> (n:isize, i:isize, first:T, second:T) ->isize {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
(Some(y), ()) => {},
_ => {},
}
- x; //~ ERROR use of moved value
+ x; //~ ERROR use of partially moved value
}
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<i32>`, which does not implement the `Copy` trait
+ = note: partial move occurs because value has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
help: borrow this field in the pattern to avoid moving `x.0.0`
|
LL | (Some(ref y), ()) => {},
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<B>) {
-LL | | self.f = b;
-LL | |
-LL | |
-LL | |
-LL | |
-LL | | }
- | |_____^
+LL | fn set_f_bad(&mut self, b: Box<B>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...does not necessarily outlive the lifetime `'a` as defined on the impl at 16:6
--> $DIR/regions-infer-paramd-indirect.rs:16:6
|
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
LL | |
LL | |
LL | | where <() as Project<'a, 'b>>::Item : Eq
-LL | | {
-LL | | }
- | |_^
+ | |____________________________________________^
= note: expected `Project<'a, 'b>`
found `Project<'_, '_>`
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
LL | |
LL | |
LL | | where <() as Project<'a, 'b>>::Item : Eq
-LL | | {
-LL | | }
- | |_^
+ | |____________________________________________^
= note: expected `Project<'a, 'b>`
found `Project<'_, '_>`
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
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
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
--- /dev/null
+// 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() {}
--- /dev/null
+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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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`.
-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() }
--> $DIR/feature-gate.rs:16:1
|
LL | fn main() {}
- | ^^^^^^^^^^^^
+ | ^^^^^^^^^
error: aborting due to previous error
--> $DIR/feature-gate.rs:14:1
|
LL | fn main() {}
- | ^^^^^^^^^^^^
+ | ^^^^^^^^^
error: aborting due to previous error
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/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 <Int as std::ops::Add>::add` is not stable as `const fn`
+error[E0723]: can only call other `const fn` within a `const fn`, but `<Int as std::ops::Add>::add` is not stable as `const fn`
--> $DIR/stability.rs:32:5
|
LL | Int(1i32) + Int(2i32)
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
#[cfg(windows)]
fn main() {
close_stdout();
- println!("hello world");
+ println!("hello");
+ println!("world");
}
#[cfg(not(windows))]
fn main() {
close_stdout();
- println!("hello world");
+ println!("hello");
+ println!("world");
}
LL | #[target_feature(enable = "sse2")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | fn foo() {}
- | ----------- not an `unsafe` function
+ | -------- not an `unsafe` function
|
= note: see issue #69098 <https://github.com/rust-lang/rust/issues/69098> for more information
= help: add `#![feature(target_feature_11)]` to the crate attributes to enable
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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
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
--> $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
--> $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: `;`
LL | |
LL | | where
LL | | G: Get<T>
-... |
-LL | | }
-LL | | }
- | |_^
+ | |_____________^
error[E0311]: the parameter type `G` may not live long enough
--> $DIR/missing-lifetimes-in-signature.rs:47:45
LL | |
LL | | where
LL | | G: Get<T>
-... |
-LL | | }
-LL | | }
- | |_^
+ | |_____________^
error[E0311]: the parameter type `G` may not live long enough
--> $DIR/missing-lifetimes-in-signature.rs:59:58
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<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
-LL | |
-LL | | move || {
-LL | | *dest = g.get();
-LL | | }
-LL | | }
- | |_____^
+LL | fn qux<'b, G: Get<T> + '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
LL | |
LL | | where
LL | | G: Get<T>
-... |
-LL | | }
-LL | | }
- | |_^
+ | |_____________^
error[E0621]: explicit lifetime required in the type of `dest`
--> $DIR/missing-lifetimes-in-signature.rs:73:5
LL | |
LL | | where
LL | | G: Get<T>
-... |
-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
|
LL | |
LL | | where
LL | | G: Get<T>
-... |
-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
|
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<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
-LL | |
-LL | | move || {
-LL | | *dest = g.get();
-LL | | }
-LL | | }
- | |_____^
+LL | fn qux<'b, G: Get<T> + '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
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
LL | fn bar() {}
- | ----------- not an `unsafe` function
+ | -------- not an `unsafe` function
|
= note: see issue #69098 <https://github.com/rust-lang/rust/issues/69098> for more information
= help: add `#![feature(target_feature_11)]` to the crate attributes to enable
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
LL | fn foo() {}
- | ----------- not an `unsafe` function
+ | -------- not an `unsafe` function
|
= note: see issue #69098 <https://github.com/rust-lang/rust/issues/69098> for more information
= help: add `#![feature(target_feature_11)]` to the crate attributes to enable
--> $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
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
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
error: concrete type differs from previous defining opaque type use
--> $DIR/generic_different_defining_uses.rs:11:1
|
-LL | / fn my_iter2<T>(t: T) -> MyIter<T> {
-LL | | Some(t).into_iter()
-LL | | }
- | |_^ expected `std::iter::Once<T>`, got `std::option::IntoIter<T>`
+LL | fn my_iter2<T>(t: T) -> MyIter<T> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `std::iter::Once<T>`, got `std::option::IntoIter<T>`
|
note: previous use here
--> $DIR/generic_different_defining_uses.rs:7:1
|
-LL | / fn my_iter<T>(t: T) -> MyIter<T> {
-LL | | std::iter::once(t)
-LL | | }
- | |_^
+LL | fn my_iter<T>(t: T) -> MyIter<T> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
error: concrete type differs from previous defining opaque type use
--> $DIR/generic_duplicate_param_use2.rs:14:1
|
-LL | / fn two<T: Debug, U>(t: T, _: U) -> Two<T, U> {
-LL | |
-LL | | t
-LL | | }
- | |_^ expected `U`, got `T`
+LL | fn two<T: Debug, U>(t: T, _: U) -> Two<T, U> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `U`, got `T`
|
note: previous use here
--> $DIR/generic_duplicate_param_use2.rs:10:1
|
-LL | / fn one<T: Debug>(t: T) -> Two<T, T> {
-LL | | t
-LL | | }
- | |_^
+LL | fn one<T: Debug>(t: T) -> Two<T, T> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
error: concrete type differs from previous defining opaque type use
--> $DIR/generic_duplicate_param_use3.rs:14:1
|
-LL | / fn two<T: Debug, U>(t: T, _: U) -> Two<T, U> {
-LL | |
-LL | | t
-LL | | }
- | |_^ expected `U`, got `T`
+LL | fn two<T: Debug, U>(t: T, _: U) -> Two<T, U> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `U`, got `T`
|
note: previous use here
--> $DIR/generic_duplicate_param_use3.rs:10:1
|
-LL | / fn one<T: Debug>(t: T) -> Two<T, T> {
-LL | | t
-LL | | }
- | |_^
+LL | fn one<T: Debug>(t: T) -> Two<T, T> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
error: concrete type differs from previous defining opaque type use
--> $DIR/generic_duplicate_param_use5.rs:14:1
|
-LL | / fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
-LL | |
-LL | | (u, t)
-LL | | }
- | |_^ expected `(T, U)`, got `(U, T)`
+LL | fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `(T, U)`, got `(U, T)`
|
note: previous use here
--> $DIR/generic_duplicate_param_use5.rs:10:1
|
-LL | / fn two<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
-LL | | (t, u)
-LL | | }
- | |_^
+LL | fn two<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
error: concrete type differs from previous defining opaque type use
--> $DIR/generic_duplicate_param_use6.rs:14:1
|
-LL | / fn three<T: Copy + Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
-LL | |
-LL | | (u, t)
-LL | | }
- | |_^ expected `(T, T)`, got `(U, T)`
+LL | fn three<T: Copy + Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `(T, T)`, got `(U, T)`
|
note: previous use here
--> $DIR/generic_duplicate_param_use6.rs:10:1
|
-LL | / fn two<T: Copy + Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
-LL | | (t, t)
-LL | | }
- | |_^
+LL | fn two<T: Copy + Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
error: concrete type differs from previous defining opaque type use
--> $DIR/generic_duplicate_param_use8.rs:13:1
|
-LL | / fn three<T: Debug, U: Debug>(_: T, u: U) -> Two<T, U> {
-LL | |
-LL | | (u, 4u32)
-LL | | }
- | |_^ expected `(T, u32)`, got `(U, u32)`
+LL | fn three<T: Debug, U: Debug>(_: T, u: U) -> Two<T, U> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `(T, u32)`, got `(U, u32)`
|
note: previous use here
--> $DIR/generic_duplicate_param_use8.rs:9:1
|
-LL | / fn two<T: Debug, U: Debug>(t: T, _: U) -> Two<T, U> {
-LL | | (t, 4u32)
-LL | | }
- | |_^
+LL | fn two<T: Debug, U: Debug>(t: T, _: U) -> Two<T, U> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
error: concrete type differs from previous defining opaque type use
--> $DIR/generic_duplicate_param_use9.rs:18:1
|
-LL | / fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
-LL | | (t, u, 42)
-LL | | }
- | |_^ expected `(A, B, <A as Foo>::Bar)`, got `(A, B, i32)`
+LL | fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `(A, B, <A as Foo>::Bar)`, got `(A, B, i32)`
|
note: previous use here
--> $DIR/generic_duplicate_param_use9.rs:14:1
|
-LL | / fn two<T: Debug + Foo, U: Debug>(t: T, u: U) -> Two<T, U> {
-LL | | (t, u, T::BAR)
-LL | | }
- | |_^
+LL | fn two<T: Debug + Foo, U: Debug>(t: T, u: U) -> Two<T, U> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
--> $DIR/issue-52843-closure-constrain.rs:9:5
|
LL | fn _unused() -> Opaque { String::new() }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
error: concrete type differs from previous defining opaque type use
--> $DIR/not_a_defining_use.rs:29:1
|
-LL | / fn four<T: Debug, U: Bar>(t: T) -> Two<T, U> {
-LL | | (t, <U as Bar>::FOO)
-LL | | }
- | |_^ expected `(T, i8)`, got `(T, <U as Bar>::Blub)`
+LL | fn four<T: Debug, U: Bar>(t: T) -> Two<T, U> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `(T, i8)`, got `(T, <U as Bar>::Blub)`
|
note: previous use here
--> $DIR/not_a_defining_use.rs:9:1
|
-LL | / fn two<T: Debug>(t: T) -> Two<T, u32> {
-LL | | (t, 4i8)
-LL | | }
- | |_^
+LL | fn two<T: Debug>(t: T) -> Two<T, u32> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
--> $DIR/ufcs-explicit-self-bad.rs:37:5
|
LL | fn dummy2(self: &Bar<T>) {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
note: ...does not necessarily outlive the lifetime `'a` as defined on the impl at 35:6
--> $DIR/ufcs-explicit-self-bad.rs:35:6
|
--> $DIR/ufcs-explicit-self-bad.rs:37:5
|
LL | fn dummy2(self: &Bar<T>) {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
error[E0308]: mismatched `self` parameter type
--> $DIR/ufcs-explicit-self-bad.rs:39:21
--> $DIR/ufcs-explicit-self-bad.rs:39:5
|
LL | fn dummy3(self: &&Bar<T>) {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...does not necessarily outlive the lifetime `'a` as defined on the impl at 35:6
--> $DIR/ufcs-explicit-self-bad.rs:35:6
|
--> $DIR/ufcs-explicit-self-bad.rs:39:5
|
LL | fn dummy3(self: &&Bar<T>) {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 7 previous errors
// 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<F,A,R> {
func: F,
| -- 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
| -- 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
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
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
packages: &'static [&'static str],
}
-const TEST_REPOS: &'static [Test] = &[
+const TEST_REPOS: &[Test] = &[
Test {
name: "iron",
repo: "https://github.com/iron/iron",
fn main() {
let args = env::args().collect::<Vec<_>>();
- 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);
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());
}
.arg(&format!("--depth={}", depth))
.current_dir(&out_dir)
.status()
- .expect("");
+ .unwrap();
assert!(status.success());
}
.arg("--hard")
.current_dir(&out_dir)
.status()
- .expect("");
+ .unwrap();
if status.success() {
found = true;
.env("RUSTFLAGS", "--cap-lints warn")
.current_dir(crate_path)
.status()
- .expect("");
+ .unwrap();
status.success()
}
#![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
#![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
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()`
// If we find `//~ ERROR foo` or something like that, skip the first word.
let kind = first_word.parse::<ErrorKind>().ok();
- if let Some(_) = kind {
+ if kind.is_some() {
msg = &msg.trim_start().split_at(first_word.len()).1;
}
// 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
it(ln[comment.len()..].trim_start());
}
}
- return;
}
impl Config {
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
// 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<String> {
}
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();
if line.starts_with('{') {
if let Ok(diagnostic) = serde_json::from_str::<Diagnostic>(line) {
diagnostic.rendered
- } else if let Ok(_) = serde_json::from_str::<ArtifactNotification>(line) {
+ } else if serde_json::from_str::<ArtifactNotification>(line).is_ok() {
// Ignore the notification.
None
} else {
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"),
}
fn configure_cdb(config: &Config) -> Option<Config> {
- 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<Config> {
- if config.gdb_version.is_none() {
- return None;
- }
+ config.gdb_version?;
if util::matches_env(&config.target, "msvc") {
return None;
}
fn configure_lldb(config: &Config) -> Option<Config> {
- if config.lldb_python_dir.is_none() {
- return None;
- }
+ config.lldb_python_dir.as_ref()?;
if let Some(350) = config.lldb_version {
println!(
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.
let revisions = if early_props.revisions.is_empty() || config.mode == Mode::Incremental {
vec![None]
} else {
- early_props.revisions.iter().map(|r| Some(r)).collect()
+ early_props.revisions.iter().map(Some).collect()
};
revisions
.into_iter()
/// Returns `true` if the given target is an Android target for the
/// purposes of GDB testing.
-fn is_android_gdb_target(target: &String) -> 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<OsString> {
+fn find_cdb(target: &str) -> Option<OsString> {
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") {
}
/// Returns Path to CDB
-fn analyze_cdb(cdb: Option<String>, target: &String) -> Option<OsString> {
- cdb.map(|s| OsString::from(s)).or(find_cdb(target))
+fn analyze_cdb(cdb: Option<String>, target: &str) -> Option<OsString> {
+ cdb.map(OsString::from).or_else(|| find_cdb(target))
}
/// Returns (Path to GDB, GDB Version, GDB has Rust Support)
fn analyze_gdb(
gdb: Option<String>,
- target: &String,
+ target: &str,
android_cross_path: &PathBuf,
) -> (Option<String>, Option<u32>, bool) {
#[cfg(not(windows))]
impl Mismatch {
fn new(line_number: u32) -> Mismatch {
- Mismatch { line_number: line_number, lines: Vec::new() }
+ Mismatch { line_number, lines: Vec::new() }
}
}
}
}
}
- writeln!(output, "").unwrap();
+ writeln!(output).unwrap();
}
output
}
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 {
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);
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
};
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
};
.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={}; \
.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
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);
}
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
};
// 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::<Vec<_>>();
+ let mut path =
+ env::split_paths(&env::var_os(dylib_env_var()).unwrap_or_default()).collect::<Vec<_>>();
if let Some(p) = aux_path {
path.insert(0, PathBuf::from(p))
}
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();
}
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<MonoItem> = proc_res
.stdout
Filter::MachineApplicableOnly,
)
.unwrap_or_default();
- if suggestions.len() > 0
+ if !suggestions.is_empty()
&& !self.props.run_rustfix
&& !self.props.rustfix_only_machine_applicable
{
.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());
}
}
},
)
.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() {
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);
}
}
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"),
("vxworks", "vxworks"),
];
-const ARCH_TABLE: &'static [(&'static str, &'static str)] = &[
+const ARCH_TABLE: &[(&str, &str)] = &[
("aarch64", "aarch64"),
("amd64", "x86_64"),
("arm", "arm"),
("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",
"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",
impl PathBufExt for PathBuf {
fn with_extra_extension<S: AsRef<OsStr>>(&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);
// Parse CLI arguments
let args = std::env::args().skip(1).collect::<Vec<_>>();
let (mode, base) = match args.iter().map(|s| s.as_str()).collect::<Vec<_>>().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 <source-dir> <dest-dir>");
std::process::exit(1);
.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,
}
}
{
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
}
// These appear to be broken in mdbook right now?
- if fragment.starts_with("-") {
+ if fragment.starts_with('-') {
return;
}
}
fn maybe_redirect(source: &str) -> Option<String> {
- const REDIRECT: &'static str = "<p>Redirecting to <a href=";
+ const REDIRECT: &str = "<p>Redirecting to <a href=";
let mut lines = source.lines();
let redirect_line = lines.nth(6)?;
// we can get away with using one pass.
let is_base = line[..j].ends_with("<base");
line = rest;
- let pos_equals = match rest.find("=") {
+ let pos_equals = match rest.find('=') {
Some(i) => i,
None => continue,
};
- if rest[..pos_equals].trim_start_matches(" ") != "" {
+ if rest[..pos_equals].trim_start_matches(' ') != "" {
continue;
}
};
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..];
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')
}
))
response.read()
+
+
+if __name__ == '__main__':
+ try:
+ main()
+ except urllib2.HTTPError as e:
+ print("HTTPError: %s\n%s" % (e, e.read()))
+ raise
-Subproject commit 0b2b9a5508186c16a2e782f47ce7e0e1c5fb8d33
+Subproject commit e65d48d1fb3d4d91d9dc1148a7a836ff5c9a3c87
edition = "2018"
[dependencies]
-cargo_metadata = "0.9.1"
+cargo_metadata = "0.11"
regex = "1"
lazy_static = "1"
walkdir = "2"
"crossbeam-queue",
"crossbeam-utils",
"datafrog",
+ "difference",
"digest",
"dlmalloc",
"either",
"ena",
"env_logger",
+ "expect-test",
"fake-simd",
"filetime",
"flate2",
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") {
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 {
fn fmt_list<V: std::fmt::Debug>(values: impl IntoIterator<Item = V>) -> String {
let pieces = values.into_iter().map(|b| format!("{:?}, ", b)).collect::<Vec<_>>();
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);
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<u32>]) {
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");
}
}
// 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 {
// 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 {
}
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);