fn replace(&mut self, key: K) -> Option<K> {
let root = Self::ensure_is_owned(&mut self.root);
match search::search_tree::<marker::Mut<'_>, K, (), K>(root.node_as_mut(), &key) {
- Found(handle) => Some(mem::replace(handle.into_kv_mut().0, key)),
+ Found(handle) => Some(mem::replace(handle.into_key_mut(), key)),
GoDown(handle) => {
VacantEntry { key, handle, length: &mut self.length, _marker: PhantomData }
.insert(());
{
let root_node = self.root.as_mut()?.node_as_mut();
match search::search_tree(root_node, key) {
- Found(handle) => Some(handle.into_kv_mut().1),
+ Found(handle) => Some(handle.into_val_mut()),
GoDown(_) => None,
}
}
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn into_mut(self) -> &'a mut V {
- self.handle.into_kv_mut().1
+ self.handle.into_val_mut()
}
/// Sets the value of the entry with the `OccupiedEntry`'s key,
impl<'a, K, V, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
/// Unsafely asserts to the compiler some static information about whether this
/// node is a `Leaf` or an `Internal`.
- unsafe fn cast_unchecked<NewType>(&mut self) -> NodeRef<marker::Mut<'_>, K, V, NewType> {
+ unsafe fn cast_unchecked<NewType>(self) -> NodeRef<marker::Mut<'a>, K, V, NewType> {
NodeRef { height: self.height, node: self.node, root: self.root, _marker: PhantomData }
}
}
impl<Node, Type> Handle<Node, Type> {
- /// Retrieves the node that contains the edge of key/value pair this handle points to.
+ /// Retrieves the node that contains the edge or key/value pair this handle points to.
pub fn into_node(self) -> Node {
self.node
}
}
impl<'a, K: 'a, V: 'a, NodeType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, marker::KV> {
+ pub fn into_key_mut(self) -> &'a mut K {
+ let keys = self.node.into_key_slice_mut();
+ unsafe { keys.get_unchecked_mut(self.idx) }
+ }
+
+ pub fn into_val_mut(self) -> &'a mut V {
+ let vals = self.node.into_val_slice_mut();
+ unsafe { vals.get_unchecked_mut(self.idx) }
+ }
+
pub fn into_kv_mut(self) -> (&'a mut K, &'a mut V) {
unsafe {
let (keys, vals) = self.node.into_slices_mut();
}
/// Removes the key/value pair pointed to by this handle and returns it, along with the edge
- /// between the now adjacent key/value pairs (if any) to the left and right of this handle.
+ /// that the key/value pair collapsed into.
pub fn remove(
mut self,
) -> ((K, V), Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>) {
/// to by this handle, and the node immediately to the right of this handle into one new
/// child of the underlying node, returning an edge referencing that new child.
///
- /// Assumes that this edge `.can_merge()`.
+ /// Panics unless this edge `.can_merge()`.
pub fn merge(
mut self,
) -> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::Edge> {
let self2 = unsafe { ptr::read(&self) };
let mut left_node = self1.left_edge().descend();
let left_len = left_node.len();
- let mut right_node = self2.right_edge().descend();
+ let right_node = self2.right_edge().descend();
let right_len = right_node.len();
- // necessary for correctness, but in a private module
assert!(left_len + right_len < CAPACITY);
unsafe {
(*left_node.as_leaf_mut()).len += right_len as u16 + 1;
- let layout = if self.node.height > 1 {
+ if self.node.height > 1 {
+ // SAFETY: the height of the nodes being merged is one below the height
+ // of the node of this edge, thus above zero, so they are internal.
+ let mut left_node = left_node.cast_unchecked();
+ let right_node = right_node.cast_unchecked();
ptr::copy_nonoverlapping(
- right_node.cast_unchecked().as_internal().edges.as_ptr(),
- left_node
- .cast_unchecked()
- .as_internal_mut()
- .edges
- .as_mut_ptr()
- .add(left_len + 1),
+ right_node.reborrow().as_internal().edges.as_ptr(),
+ left_node.reborrow_mut().as_internal_mut().edges.as_mut_ptr().add(left_len + 1),
right_len + 1,
);
for i in left_len + 1..left_len + right_len + 2 {
- Handle::new_edge(left_node.cast_unchecked().reborrow_mut(), i)
- .correct_parent_link();
+ Handle::new_edge(left_node.reborrow_mut(), i).correct_parent_link();
}
- Layout::new::<InternalNode<K, V>>()
+ Global.dealloc(right_node.node.cast(), Layout::new::<InternalNode<K, V>>());
} else {
- Layout::new::<LeafNode<K, V>>()
- };
- Global.dealloc(right_node.node.cast(), layout);
+ Global.dealloc(right_node.node.cast(), Layout::new::<LeafNode<K, V>>());
+ }
Handle::new_edge(self.node, self.idx)
}
unsafe {
let (k, v, edge) = self.reborrow_mut().left_edge().descend().pop();
- let k = mem::replace(self.reborrow_mut().into_kv_mut().0, k);
- let v = mem::replace(self.reborrow_mut().into_kv_mut().1, v);
+ let k = mem::replace(self.kv_mut().0, k);
+ let v = mem::replace(self.kv_mut().1, v);
match self.reborrow_mut().right_edge().descend().force() {
ForceResult::Leaf(mut leaf) => leaf.push_front(k, v),
unsafe {
let (k, v, edge) = self.reborrow_mut().right_edge().descend().pop_front();
- let k = mem::replace(self.reborrow_mut().into_kv_mut().0, k);
- let v = mem::replace(self.reborrow_mut().into_kv_mut().1, v);
+ let k = mem::replace(self.kv_mut().0, k);
+ let v = mem::replace(self.kv_mut().1, v);
match self.reborrow_mut().left_edge().descend().force() {
ForceResult::Leaf(mut leaf) => leaf.push(k, v),
let left_kv = left_node.reborrow_mut().into_kv_pointers_mut();
let right_kv = right_node.reborrow_mut().into_kv_pointers_mut();
let parent_kv = {
- let kv = self.reborrow_mut().into_kv_mut();
+ let kv = self.kv_mut();
(kv.0 as *mut K, kv.1 as *mut V)
};
let left_kv = left_node.reborrow_mut().into_kv_pointers_mut();
let right_kv = right_node.reborrow_mut().into_kv_pointers_mut();
let parent_kv = {
- let kv = self.reborrow_mut().into_kv_mut();
+ let kv = self.kv_mut();
(kv.0 as *mut K, kv.1 as *mut V)
};
///
/// This `struct` is created by the `into_iter` method on [`Vec`] (provided
/// by the [`IntoIterator`] trait).
-///
-/// [`Vec`]: struct.Vec.html
-/// [`IntoIterator`]: ../../std/iter/trait.IntoIterator.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct IntoIter<T> {
buf: NonNull<T>,
/// A draining iterator for `Vec<T>`.
///
-/// This `struct` is created by the [`drain`] method on [`Vec`].
-///
-/// [`drain`]: struct.Vec.html#method.drain
-/// [`Vec`]: struct.Vec.html
+/// This `struct` is created by [`Vec::drain`].
#[stable(feature = "drain", since = "1.6.0")]
pub struct Drain<'a, T: 'a> {
/// Index of tail to preserve
/// A splicing iterator for `Vec`.
///
-/// This struct is created by the [`splice()`] method on [`Vec`]. See its
-/// documentation for more.
-///
-/// [`splice()`]: struct.Vec.html#method.splice
-/// [`Vec`]: struct.Vec.html
+/// This struct is created by [`Vec::splice()`].
+/// See its documentation for more.
#[derive(Debug)]
#[stable(feature = "vec_splice", since = "1.21.0")]
pub struct Splice<'a, I: Iterator + 'a> {
/// working with [pinned] data, where reusing the memory without calling the destructor could lead
/// to Undefined Behaviour.
///
-/// [`mem::zeroed`]: fn.zeroed.html
-/// [`MaybeUninit<T>`]: union.MaybeUninit.html
-/// [pinned]: ../pin/index.html
+/// [`mem::zeroed`]: crate::mem::zeroed
+/// [`MaybeUninit<T>`]: crate::mem::MaybeUninit
+/// [pinned]: crate::pin
#[stable(feature = "manually_drop", since = "1.20.0")]
#[lang = "manually_drop"]
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
/// leaving the state of this container unchanged.
/// It is your responsibility to ensure that this `ManuallyDrop` is not used again.
///
- /// [`ManuallyDrop::drop`]: #method.drop
- /// [`ManuallyDrop::into_inner`]: #method.into_inner
#[must_use = "if you don't need the value, you can use `ManuallyDrop::drop` instead"]
#[stable(feature = "manually_drop_take", since = "1.42.0")]
#[inline]
/// This is normally prevented by the type system, but users of `ManuallyDrop` must
/// uphold those guarantees without assistance from the compiler.
///
- /// [`ManuallyDrop::into_inner`]: #method.into_inner
- /// [`ptr::drop_in_place`]: ../ptr/fn.drop_in_place.html
- /// [pinned]: ../pin/index.html
+ /// [pinned]: crate::pin
#[stable(feature = "manually_drop", since = "1.20.0")]
#[inline]
pub unsafe fn drop(slot: &mut ManuallyDrop<T>) {
/// Note that dropping a `MaybeUninit<T>` will never call `T`'s drop code.
/// It is your responsibility to make sure `T` gets dropped if it got initialized.
///
- /// [`assume_init`]: #method.assume_init
+ /// [`assume_init`]: MaybeUninit::assume_init
#[stable(feature = "maybe_uninit", since = "1.36.0")]
#[rustc_const_stable(feature = "const_maybe_uninit", since = "1.36.0")]
#[inline(always)]
/// to ensure that that data may indeed be duplicated.
///
/// [inv]: #initialization-invariant
- /// [`assume_init`]: #method.assume_init
+ /// [`assume_init`]: MaybeUninit::assume_init
///
/// # Examples
///
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
-pub unsafe fn from_utf8_unchecked(v: &[u8]) -> &str {
- // SAFETY: the caller must guarantee that the bytes `v`
- // are valid UTF-8, thus the cast to `*const str` is safe.
- // Also, the pointer dereference is safe because that pointer
- // comes from a reference which is guaranteed to be valid for reads.
- unsafe { &*(v as *const [u8] as *const str) }
+#[rustc_const_unstable(feature = "const_str_from_utf8_unchecked", issue = "75196")]
+#[allow(unused_attributes)]
+#[allow_internal_unstable(const_fn_transmute)]
+pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str {
+ // SAFETY: the caller must guarantee that the bytes `v` are valid UTF-8.
+ // Also relies on `&str` and `&[u8]` having the same layout.
+ unsafe { mem::transmute(v) }
}
/// Converts a slice of bytes to a string slice without checking
#[rustc_const_stable(feature = "str_as_bytes", since = "1.32.0")]
#[inline(always)]
#[allow(unused_attributes)]
- #[allow_internal_unstable(const_fn_union)]
+ #[allow_internal_unstable(const_fn_transmute)]
pub const fn as_bytes(&self) -> &[u8] {
- #[repr(C)]
- union Slices<'a> {
- str: &'a str,
- slice: &'a [u8],
- }
// SAFETY: const sound because we transmute two types with the same layout
- unsafe { Slices { str: self }.slice }
+ unsafe { mem::transmute(self) }
}
/// Converts a mutable string slice to a mutable byte slice.
panic_unwind = { path = "../panic_unwind", optional = true }
panic_abort = { path = "../panic_abort" }
core = { path = "../core" }
-libc = { version = "0.2.51", default-features = false, features = ['rustc-dep-of-std'] }
+libc = { version = "0.2.74", default-features = false, features = ['rustc-dep-of-std'] }
compiler_builtins = { version = "0.1.32" }
profiler_builtins = { path = "../profiler_builtins", optional = true }
unwind = { path = "../unwind" }
+#![deny(unsafe_op_in_unsafe_fn)]
use crate::ascii;
use crate::borrow::{Borrow, Cow};
use crate::cmp::Ordering;
/// example, you can build a `CString` straight out of a [`String`] or
/// a [`&str`], since both implement that trait).
///
-/// The [`new`] method will actually check that the provided `&[u8]`
+/// The [`CString::new`] method will actually check that the provided `&[u8]`
/// does not have 0 bytes in the middle, and return an error if it
/// finds one.
///
/// # Extracting a raw pointer to the whole C string
///
-/// `CString` implements a [`as_ptr`] method through the [`Deref`]
+/// `CString` implements a [`as_ptr`][`CStr::as_ptr`] method through the [`Deref`]
/// trait. This method will give you a `*const c_char` which you can
/// feed directly to extern functions that expect a nul-terminated
-/// string, like C's `strdup()`. Notice that [`as_ptr`] returns a
+/// string, like C's `strdup()`. Notice that [`as_ptr`][`CStr::as_ptr`] returns a
/// read-only pointer; if the C code writes to it, that causes
/// undefined behavior.
///
/// # Extracting a slice of the whole C string
///
/// Alternatively, you can obtain a `&[`[`u8`]`]` slice from a
-/// `CString` with the [`as_bytes`] method. Slices produced in this
+/// `CString` with the [`CString::as_bytes`] method. Slices produced in this
/// way do *not* contain the trailing nul terminator. This is useful
/// when you will be calling an extern function that takes a `*const
/// u8` argument which is not necessarily nul-terminated, plus another
/// [`len`][slice.len] method.
///
/// If you need a `&[`[`u8`]`]` slice *with* the nul terminator, you
-/// can use [`as_bytes_with_nul`] instead.
+/// can use [`CString::as_bytes_with_nul`] instead.
///
/// Once you have the kind of slice you need (with or without a nul
/// terminator), you can call the slice's own
/// extern functions. See the documentation for that function for a
/// discussion on ensuring the lifetime of the raw pointer.
///
-/// [`Into`]: ../convert/trait.Into.html
-/// [`Vec`]: ../vec/struct.Vec.html
-/// [`String`]: ../string/struct.String.html
-/// [`&str`]: ../primitive.str.html
-/// [`u8`]: ../primitive.u8.html
-/// [`new`]: #method.new
-/// [`as_bytes`]: #method.as_bytes
-/// [`as_bytes_with_nul`]: #method.as_bytes_with_nul
-/// [`as_ptr`]: #method.as_ptr
+/// [`&str`]: str
/// [slice.as_ptr]: ../primitive.slice.html#method.as_ptr
/// [slice.len]: ../primitive.slice.html#method.len
-/// [`Deref`]: ../ops/trait.Deref.html
-/// [`CStr`]: struct.CStr.html
-/// [`&CStr`]: struct.CStr.html
+/// [`Deref`]: ops::Deref
+/// [`&CStr`]: CStr
///
/// # Examples
///
/// documentation of `CString` before use, as improper ownership management
/// of `CString` instances can lead to invalid memory accesses, memory leaks,
/// and other memory errors.
-
#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct CString {
///
/// Note that this structure is **not** `repr(C)` and is not recommended to be
/// placed in the signatures of FFI functions. Instead, safe wrappers of FFI
-/// functions may leverage the unsafe [`from_ptr`] constructor to provide a safe
-/// interface to other consumers.
+/// functions may leverage the unsafe [`CStr::from_ptr`] constructor to provide
+/// a safe interface to other consumers.
///
/// # Examples
///
/// println!("string: {}", my_string_safe());
/// ```
///
-/// [`u8`]: ../primitive.u8.html
-/// [`&str`]: ../primitive.str.html
-/// [`String`]: ../string/struct.String.html
-/// [`CString`]: struct.CString.html
-/// [`from_ptr`]: #method.from_ptr
+/// [`&str`]: str
#[derive(Hash)]
#[stable(feature = "rust1", since = "1.0.0")]
// FIXME:
/// This error is created by the [`new`][`CString::new`] method on
/// [`CString`]. See its documentation for more.
///
-/// [`CString`]: struct.CString.html
-/// [`CString::new`]: struct.CString.html#method.new
-///
/// # Examples
///
/// ```
/// The slice used to create a [`CStr`] must have one and only one nul byte,
/// positioned at the end.
///
-/// This error is created by the [`from_bytes_with_nul`] method on [`CStr`].
+/// This error is created by the [`CStr::from_bytes_with_nul`] method.
/// See its documentation for more.
///
-/// [`CStr`]: struct.CStr.html
-/// [`from_bytes_with_nul`]: struct.CStr.html#method.from_bytes_with_nul
-///
/// # Examples
///
/// ```
/// The vector used to create a [`CString`] must have one and only one nul byte,
/// positioned at the end.
///
-/// This error is created by the [`from_vec_with_nul`] method on [`CString`].
+/// This error is created by the [`CString::from_vec_with_nul`] method.
/// See its documentation for more.
///
-/// [`CString`]: struct.CString.html
-/// [`from_vec_with_nul`]: struct.CString.html#method.from_vec_with_nul
-///
/// # Examples
///
/// ```
///
/// assert_eq!(&bytes[..], value.unwrap_err().as_bytes());
/// ```
- ///
- /// [`CString`]: struct.CString.html
pub fn as_bytes(&self) -> &[u8] {
&self.bytes[..]
}
///
/// assert_eq!(bytes, value.unwrap_err().into_bytes());
/// ```
- ///
- /// [`CString`]: struct.CString.html
pub fn into_bytes(self) -> Vec<u8> {
self.bytes
}
/// An error indicating invalid UTF-8 when converting a [`CString`] into a [`String`].
///
-/// `CString` is just a wrapper over a buffer of bytes with a nul
-/// terminator; [`into_string`][`CString::into_string`] performs UTF-8
-/// validation on those bytes and may return this error.
+/// `CString` is just a wrapper over a buffer of bytes with a nul terminator;
+/// [`CString::into_string`] performs UTF-8 validation on those bytes and may
+/// return this error.
///
-/// This `struct` is created by the
-/// [`into_string`][`CString::into_string`] method on [`CString`]. See
+/// This `struct` is created by [`CString::into_string()`]. See
/// its documentation for more.
-///
-/// [`String`]: ../string/struct.String.html
-/// [`CString`]: struct.CString.html
-/// [`CString::into_string`]: struct.CString.html#method.into_string
#[derive(Clone, PartialEq, Eq, Debug)]
#[stable(feature = "cstring_into", since = "1.7.0")]
pub struct IntoStringError {
/// This function will return an error if the supplied bytes contain an
/// internal 0 byte. The [`NulError`] returned will contain the bytes as well as
/// the position of the nul byte.
- ///
- /// [`NulError`]: struct.NulError.html
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new<T: Into<Vec<u8>>>(t: T) -> Result<CString, NulError> {
trait SpecIntoVec {
/// Creates a C-compatible string by consuming a byte vector,
/// without checking for interior 0 bytes.
///
- /// This method is equivalent to [`new`] except that no runtime assertion
- /// is made that `v` contains no 0 bytes, and it requires an actual
- /// byte vector, not anything that can be converted to one with Into.
- ///
- /// [`new`]: #method.new
+ /// This method is equivalent to [`CString::new`] except that no runtime
+ /// assertion is made that `v` contains no 0 bytes, and it requires an
+ /// actual byte vector, not anything that can be converted to one with Into.
///
/// # Examples
///
CString { inner: v.into_boxed_slice() }
}
- /// Retakes ownership of a `CString` that was transferred to C via [`into_raw`].
+ /// Retakes ownership of a `CString` that was transferred to C via
+ /// [`CString::into_raw`].
///
/// Additionally, the length of the string will be recalculated from the pointer.
///
/// # Safety
///
/// This should only ever be called with a pointer that was earlier
- /// obtained by calling [`into_raw`] on a `CString`. Other usage (e.g., trying to take
+ /// obtained by calling [`CString::into_raw`]. Other usage (e.g., trying to take
/// ownership of a string that was allocated by foreign code) is likely to lead
/// to undefined behavior or allocator corruption.
///
/// It should be noted that the length isn't just "recomputed," but that
/// the recomputed length must match the original length from the
- /// [`into_raw`] call. This means the [`into_raw`]/`from_raw` methods
- /// should not be used when passing the string to C functions that can
+ /// [`CString::into_raw`] call. This means the [`CString::into_raw`]/`from_raw`
+ /// methods should not be used when passing the string to C functions that can
/// modify the string's length.
///
/// > **Note:** If you need to borrow a string that was allocated by
/// > make your own provisions for freeing it appropriately, likely
/// > with the foreign code's API to do that.
///
- /// [`into_raw`]: #method.into_raw
- /// [`CStr`]: struct.CStr.html
- ///
/// # Examples
///
/// Creates a `CString`, pass ownership to an `extern` function (via raw pointer), then retake
/// ```
#[stable(feature = "cstr_memory", since = "1.4.0")]
pub unsafe fn from_raw(ptr: *mut c_char) -> CString {
- let len = sys::strlen(ptr) + 1; // Including the NUL byte
- let slice = slice::from_raw_parts_mut(ptr, len as usize);
- CString { inner: Box::from_raw(slice as *mut [c_char] as *mut [u8]) }
+ // SAFETY: This is called with a pointer that was obtained from a call
+ // to `CString::into_raw` and the length has not been modified. As such,
+ // we know there is a NUL byte (and only one) at the end and that the
+ // information about the size of the allocation is correct on Rust's
+ // side.
+ unsafe {
+ let len = sys::strlen(ptr) + 1; // Including the NUL byte
+ let slice = slice::from_raw_parts_mut(ptr, len as usize);
+ CString { inner: Box::from_raw(slice as *mut [c_char] as *mut [u8]) }
+ }
}
/// Consumes the `CString` and transfers ownership of the string to a C caller.
///
/// The pointer which this function returns must be returned to Rust and reconstituted using
- /// [`from_raw`] to be properly deallocated. Specifically, one
+ /// [`CString::from_raw`] to be properly deallocated. Specifically, one
/// should *not* use the standard C `free()` function to deallocate
/// this string.
///
- /// Failure to call [`from_raw`] will lead to a memory leak.
+ /// Failure to call [`CString::from_raw`] will lead to a memory leak.
///
/// The C side must **not** modify the length of the string (by writing a
/// `NULL` somewhere inside the string or removing the final one) before
- /// it makes it back into Rust using [`from_raw`]. See the safety section
- /// in [`from_raw`].
- ///
- /// [`from_raw`]: #method.from_raw
+ /// it makes it back into Rust using [`CString::from_raw`]. See the safety section
+ /// in [`CString::from_raw`].
///
/// # Examples
///
///
/// On failure, ownership of the original `CString` is returned.
///
- /// [`String`]: ../string/struct.String.html
- ///
/// # Examples
///
/// ```
vec
}
- /// Equivalent to the [`into_bytes`] function except that the returned vector
- /// includes the trailing nul terminator.
- ///
- /// [`into_bytes`]: #method.into_bytes
+ /// Equivalent to [`CString::into_bytes()`] except that the
+ /// returned vector includes the trailing nul terminator.
///
/// # Examples
///
/// The returned slice does **not** contain the trailing nul
/// terminator, and it is guaranteed to not have any interior nul
/// bytes. If you need the nul terminator, use
- /// [`as_bytes_with_nul`] instead.
- ///
- /// [`as_bytes_with_nul`]: #method.as_bytes_with_nul
+ /// [`CString::as_bytes_with_nul`] instead.
///
/// # Examples
///
&self.inner[..self.inner.len() - 1]
}
- /// Equivalent to the [`as_bytes`] function except that the returned slice
- /// includes the trailing nul terminator.
- ///
- /// [`as_bytes`]: #method.as_bytes
+ /// Equivalent to [`CString::as_bytes()`] except that the
+ /// returned slice includes the trailing nul terminator.
///
/// # Examples
///
/// Extracts a [`CStr`] slice containing the entire string.
///
- /// [`CStr`]: struct.CStr.html
- ///
/// # Examples
///
/// ```
/// Converts this `CString` into a boxed [`CStr`].
///
- /// [`CStr`]: struct.CStr.html
- ///
/// # Examples
///
/// ```
}
/// Bypass "move out of struct which implements [`Drop`] trait" restriction.
- ///
- /// [`Drop`]: ../ops/trait.Drop.html
fn into_inner(self) -> Box<[u8]> {
// Rationale: `mem::forget(self)` invalidates the previous call to `ptr::read(&self.inner)`
// so we use `ManuallyDrop` to ensure `self` is not dropped.
unsafe { ptr::read(&this.inner) }
}
- /// Converts a `Vec` of `u8` to a `CString` without checking the invariants
- /// on the given `Vec`.
+ /// Converts a [`Vec`]`<u8>` to a [`CString`] without checking the
+ /// invariants on the given [`Vec`].
///
/// # Safety
///
- /// The given `Vec` **must** have one nul byte as its last element.
+ /// The given [`Vec`] **must** have one nul byte as its last element.
/// This means it cannot be empty nor have any other nul byte anywhere else.
///
/// # Example
Self { inner: v.into_boxed_slice() }
}
- /// Attempts to converts a `Vec` of `u8` to a `CString`.
+ /// Attempts to converts a [`Vec`]`<u8>` to a [`CString`].
///
/// Runtime checks are present to ensure there is only one nul byte in the
- /// `Vec`, its last element.
+ /// [`Vec`], its last element.
///
/// # Errors
///
///
/// # Examples
///
- /// A successful conversion will produce the same result as [`new`] when
- /// called without the ending nul byte.
+ /// A successful conversion will produce the same result as [`CString::new`]
+ /// when called without the ending nul byte.
///
/// ```
/// #![feature(cstring_from_vec_with_nul)]
/// );
/// ```
///
- /// A incorrectly formatted vector will produce an error.
+ /// A incorrectly formatted [`Vec`] will produce an error.
///
/// ```
/// #![feature(cstring_from_vec_with_nul)]
/// // No nul byte
/// let _: FromVecWithNulError = CString::from_vec_with_nul(b"abc".to_vec()).unwrap_err();
/// ```
- ///
- /// [`new`]: #method.new
#[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")]
pub fn from_vec_with_nul(v: Vec<u8>) -> Result<Self, FromVecWithNulError> {
let nul_pos = memchr::memchr(0, &v);
/// Converts a [`CString`] into a [`Vec`]`<u8>`.
///
/// The conversion consumes the [`CString`], and removes the terminating NUL byte.
- ///
- /// [`Vec`]: ../vec/struct.Vec.html
- /// [`CString`]: ../ffi/struct.CString.html
#[inline]
fn from(s: CString) -> Vec<u8> {
s.into_bytes()
#[stable(feature = "c_string_from_box", since = "1.18.0")]
impl From<Box<CStr>> for CString {
/// Converts a [`Box`]`<CStr>` into a [`CString`] without copying or allocating.
- ///
- /// [`Box`]: ../boxed/struct.Box.html
- /// [`CString`]: ../ffi/struct.CString.html
#[inline]
fn from(s: Box<CStr>) -> CString {
s.into_c_string()
impl From<Vec<NonZeroU8>> for CString {
/// Converts a [`Vec`]`<`[`NonZeroU8`]`>` into a [`CString`] without
/// copying nor checking for inner null bytes.
- ///
- /// [`CString`]: ../ffi/struct.CString.html
- /// [`NonZeroU8`]: ../num/struct.NonZeroU8.html
- /// [`Vec`]: ../vec/struct.Vec.html
#[inline]
fn from(v: Vec<NonZeroU8>) -> CString {
unsafe {
#[stable(feature = "box_from_c_string", since = "1.20.0")]
impl From<CString> for Box<CStr> {
/// Converts a [`CString`] into a [`Box`]`<CStr>` without copying or allocating.
- ///
- /// [`CString`]: ../ffi/struct.CString.html
- /// [`Box`]: ../boxed/struct.Box.html
#[inline]
fn from(s: CString) -> Box<CStr> {
s.into_boxed_c_str()
#[stable(feature = "shared_from_slice2", since = "1.24.0")]
impl From<CString> for Arc<CStr> {
/// Converts a [`CString`] into a [`Arc`]`<CStr>` without copying or allocating.
- ///
- /// [`CString`]: ../ffi/struct.CString.html
- /// [`Arc`]: ../sync/struct.Arc.html
#[inline]
fn from(s: CString) -> Arc<CStr> {
let arc: Arc<[u8]> = Arc::from(s.into_inner());
#[stable(feature = "shared_from_slice2", since = "1.24.0")]
impl From<CString> for Rc<CStr> {
/// Converts a [`CString`] into a [`Rc`]`<CStr>` without copying or allocating.
- ///
- /// [`CString`]: ../ffi/struct.CString.html
- /// [`Rc`]: ../rc/struct.Rc.html
#[inline]
fn from(s: CString) -> Rc<CStr> {
let rc: Rc<[u8]> = Rc::from(s.into_inner());
/// Returns the position of the nul byte in the slice that caused
/// [`CString::new`] to fail.
///
- /// [`CString::new`]: struct.CString.html#method.new
- ///
/// # Examples
///
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
impl From<NulError> for io::Error {
/// Converts a [`NulError`] into a [`io::Error`].
- ///
- /// [`NulError`]: ../ffi/struct.NulError.html
- /// [`io::Error`]: ../io/struct.Error.html
fn from(_: NulError) -> io::Error {
io::Error::new(io::ErrorKind::InvalidInput, "data provided contains a nul byte")
}
impl IntoStringError {
/// Consumes this error, returning original [`CString`] which generated the
/// error.
- ///
- /// [`CString`]: struct.CString.html
#[stable(feature = "cstring_into", since = "1.7.0")]
pub fn into_cstring(self) -> CString {
self.inner
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
- let len = sys::strlen(ptr);
- let ptr = ptr as *const u8;
- CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len as usize + 1))
+ // SAFETY: The caller has provided a pointer that points to a valid C
+ // string with a NUL terminator of size less than `isize::MAX`, whose
+ // content remain valid and doesn't change for the lifetime of the
+ // returned `CStr`.
+ //
+ // Thus computing the length is fine (a NUL byte exists), the call to
+ // from_raw_parts is safe because we know the length is at most `isize::MAX`, meaning
+ // the call to `from_bytes_with_nul_unchecked` is correct.
+ //
+ // The cast from c_char to u8 is ok because a c_char is always one byte.
+ unsafe {
+ let len = sys::strlen(ptr);
+ let ptr = ptr as *const u8;
+ CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len as usize + 1))
+ }
}
/// Creates a C string wrapper from a byte slice.
#[stable(feature = "cstr_from_bytes", since = "1.10.0")]
#[rustc_const_unstable(feature = "const_cstr_unchecked", issue = "none")]
pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
- &*(bytes as *const [u8] as *const CStr)
+ // SAFETY: Casting to CStr is safe because its internal representation
+ // is a [u8] too (safe only inside std).
+ // Dereferencing the obtained pointer is safe because it comes from a
+ // reference. Making a reference is then safe because its lifetime
+ // is bound by the lifetime of the given `bytes`.
+ unsafe { &*(bytes as *const [u8] as *const CStr) }
}
/// Returns the inner pointer to this C string.
///
/// This happens because the pointer returned by `as_ptr` does not carry any
/// lifetime information and the [`CString`] is deallocated immediately after
- /// the `CString::new("Hello").expect("CString::new failed").as_ptr()` expression is evaluated.
+ /// the `CString::new("Hello").expect("CString::new failed").as_ptr()`
+ /// expression is evaluated.
/// To fix the problem, bind the `CString` to a local variable:
///
/// ```no_run
/// }
/// ```
///
- /// This way, the lifetime of the `CString` in `hello` encompasses
+ /// This way, the lifetime of the [`CString`] in `hello` encompasses
/// the lifetime of `ptr` and the `unsafe` block.
- ///
- /// [`CString`]: struct.CString.html
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_str_as_ptr", since = "1.32.0")]
/// Converts this C string to a byte slice containing the trailing 0 byte.
///
- /// This function is the equivalent of [`to_bytes`] except that it will retain
- /// the trailing nul terminator instead of chopping it off.
+ /// This function is the equivalent of [`CStr::to_bytes`] except that it
+ /// will retain the trailing nul terminator instead of chopping it off.
///
/// > **Note**: This method is currently implemented as a 0-cost cast, but
/// > it is planned to alter its definition in the future to perform the
/// > length calculation whenever this method is called.
///
- /// [`to_bytes`]: #method.to_bytes
- ///
/// # Examples
///
/// ```
/// function will return the corresponding [`&str`] slice. Otherwise,
/// it will return an error with details of where UTF-8 validation failed.
///
- /// [`&str`]: ../primitive.str.html
+ /// [`&str`]: str
///
/// # Examples
///
/// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD] and return a
/// [`Cow`]`::`[`Owned`]`(`[`String`]`)` with the result.
///
- /// [`Cow`]: ../borrow/enum.Cow.html
- /// [`Borrowed`]: ../borrow/enum.Cow.html#variant.Borrowed
- /// [`Owned`]: ../borrow/enum.Cow.html#variant.Owned
- /// [`str`]: ../primitive.str.html
- /// [`String`]: ../string/struct.String.html
- /// [U+FFFD]: ../char/constant.REPLACEMENT_CHARACTER.html
+ /// [`Borrowed`]: Cow::Borrowed
+ /// [`Owned`]: Cow::Owned
+ /// [U+FFFD]: crate::char::REPLACEMENT_CHARACTER
///
/// # Examples
///
/// Converts a [`Box`]`<CStr>` into a [`CString`] without copying or allocating.
///
- /// [`Box`]: ../boxed/struct.Box.html
- /// [`CString`]: struct.CString.html
- ///
/// # Examples
///
/// ```
//! [`env::var_os()`] is used to query environment variables; it
//! returns an [`Option`]`<`[`OsString`]`>`. If the environment variable
//! exists you will get a [`Some`]`(os_string)`, which you can *then* try to
-//! convert to a Rust string. This yields a [`Result<>`], so that
+//! convert to a Rust string. This yields a [`Result`], so that
//! your code can detect errors in case the environment variable did
//! not in fact contain valid Unicode data.
//!
//! method is an [`OsString`] which can be round-tripped to a Windows
//! string losslessly.
//!
-//! [`String`]: ../string/struct.String.html
-//! [`str`]: ../primitive.str.html
-//! [`char`]: ../primitive.char.html
-//! [`u8`]: ../primitive.u8.html
-//! [`u16`]: ../primitive.u16.html
//! [Unicode scalar value]: http://www.unicode.org/glossary/#unicode_scalar_value
//! [Unicode code point]: http://www.unicode.org/glossary/#code_point
-//! [`CString`]: struct.CString.html
-//! [`CStr`]: struct.CStr.html
-//! [`OsString`]: struct.OsString.html
-//! [`OsStr`]: struct.OsStr.html
-//! [`env::set_var()`]: ../env/fn.set_var.html
-//! [`env::var_os()`]: ../env/fn.var_os.html
-//! [`Result<>`]: ../result/enum.Result.html
-//! [unix.OsStringExt]: ../os/unix/ffi/trait.OsStringExt.html
-//! [`from_vec`]: ../os/unix/ffi/trait.OsStringExt.html#tymethod.from_vec
-//! [`into_vec`]: ../os/unix/ffi/trait.OsStringExt.html#tymethod.into_vec
-//! [unix.OsStrExt]: ../os/unix/ffi/trait.OsStrExt.html
-//! [`from_bytes`]: ../os/unix/ffi/trait.OsStrExt.html#tymethod.from_bytes
-//! [`as_bytes`]: ../os/unix/ffi/trait.OsStrExt.html#tymethod.as_bytes
-//! [`OsStrExt`]: ../os/unix/ffi/trait.OsStrExt.html
-//! [windows.OsStrExt]: ../os/windows/ffi/trait.OsStrExt.html
-//! [`encode_wide`]: ../os/windows/ffi/trait.OsStrExt.html#tymethod.encode_wide
-//! [`collect`]: ../iter/trait.Iterator.html#method.collect
-//! [windows.OsStringExt]: ../os/windows/ffi/trait.OsStringExt.html
-//! [`from_wide`]: ../os/windows/ffi/trait.OsStringExt.html#tymethod.from_wide
-//! [`Option`]: ../option/enum.Option.html
-//! [`Some`]: ../option/enum.Option.html#variant.Some
+//! [`env::set_var()`]: crate::env::set_var
+//! [`env::var_os()`]: crate::env::var_os
+//! [unix.OsStringExt]: crate::os::unix::ffi::OsStringExt
+//! [`from_vec`]: crate::os::unix::ffi::OsStringExt::from_vec
+//! [`into_vec`]: crate::os::unix::ffi::OsStringExt::into_vec
+//! [unix.OsStrExt]: crate::os::unix::ffi::OsStrExt
+//! [`from_bytes`]: crate::os::unix::ffi::OsStrExt::from_bytes
+//! [`as_bytes`]: crate::os::unix::ffi::OsStrExt::as_bytes
+//! [`OsStrExt`]: crate::os::unix::ffi::OsStrExt
+//! [windows.OsStrExt]: crate::os::windows::ffi::OsStrExt
+//! [`encode_wide`]: crate::os::windows::ffi::OsStrExt::encode_wide
+//! [`collect`]: crate::iter::Iterator::collect
+//! [windows.OsStringExt]: crate::os::windows::ffi::OsStringExt
+//! [`from_wide`]: crate::os::windows::ffi::OsStringExt::from_wide
#![stable(feature = "rust1", since = "1.0.0")]
/// create an `OsString` from a normal Rust string.
///
/// **From slices:** Just like you can start with an empty Rust
-/// [`String`] and then [`push_str`][String.push_str] `&str`
+/// [`String`] and then [`String::push_str`] `&str`
/// sub-string slices into it, you can create an empty `OsString` with
-/// the [`new`] method and then push string slices into it with the
-/// [`push`] method.
+/// the [`OsString::new`] method and then push string slices into it with the
+/// [`OsString::push`] method.
///
/// # Extracting a borrowed reference to the whole OS string
///
-/// You can use the [`as_os_str`] method to get an `&`[`OsStr`] from
+/// You can use the [`OsString::as_os_str`] method to get an `&`[`OsStr`] from
/// an `OsString`; this is effectively a borrowed reference to the
/// whole string.
///
/// See the [module's toplevel documentation about conversions][conversions] for a discussion on
/// the traits which `OsString` implements for [conversions] from/to native representations.
///
-/// [`OsStr`]: struct.OsStr.html
-/// [`&OsStr`]: struct.OsStr.html
-/// [`CStr`]: struct.CStr.html
-/// [`From`]: ../convert/trait.From.html
-/// [`String`]: ../string/struct.String.html
-/// [`&str`]: ../primitive.str.html
-/// [`u8`]: ../primitive.u8.html
-/// [`u16`]: ../primitive.u16.html
-/// [String.push_str]: ../string/struct.String.html#method.push_str
-/// [`new`]: #method.new
-/// [`push`]: #method.push
-/// [`as_os_str`]: #method.as_os_str
+/// [`&OsStr`]: OsStr
+/// [`&str`]: str
+/// [`CStr`]: crate::ffi::CStr
/// [conversions]: index.html#conversions
#[derive(Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
/// See the [module's toplevel documentation about conversions][conversions] for a discussion on
/// the traits which `OsStr` implements for [conversions] from/to native representations.
///
-/// [`OsString`]: struct.OsString.html
-/// [`&str`]: ../primitive.str.html
-/// [`String`]: ../string/struct.String.html
+/// [`&str`]: str
/// [conversions]: index.html#conversions
#[stable(feature = "rust1", since = "1.0.0")]
// FIXME:
/// Converts to an [`OsStr`] slice.
///
- /// [`OsStr`]: struct.OsStr.html
- ///
/// # Examples
///
/// ```
///
/// On failure, ownership of the original `OsString` is returned.
///
- /// [`String`]: ../../std/string/struct.String.html
- ///
/// # Examples
///
/// ```
/// Extends the string with the given [`&OsStr`] slice.
///
- /// [`&OsStr`]: struct.OsStr.html
+ /// [`&OsStr`]: OsStr
///
/// # Examples
///
/// Converts this `OsString` into a boxed [`OsStr`].
///
- /// [`OsStr`]: struct.OsStr.html
- ///
/// # Examples
///
/// ```
/// Converts a [`String`] into a [`OsString`].
///
/// The conversion copies the data, and includes an allocation on the heap.
- ///
- /// [`OsString`]: ../../std/ffi/struct.OsString.html
fn from(s: String) -> OsString {
OsString { inner: Buf::from_string(s) }
}
///
/// This conversion may entail doing a check for UTF-8 validity.
///
- /// [`&str`]: ../../std/primitive.str.html
+ /// [`&str`]: str
///
/// # Examples
///
/// Any non-Unicode sequences are replaced with
/// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD].
///
- /// [`Cow`]: ../../std/borrow/enum.Cow.html
- /// [`str`]: ../../std/primitive.str.html
- /// [U+FFFD]: ../../std/char/constant.REPLACEMENT_CHARACTER.html
+ /// [U+FFFD]: crate::char::REPLACEMENT_CHARACTER
///
/// # Examples
///
/// Copies the slice into an owned [`OsString`].
///
- /// [`OsString`]: struct.OsString.html
- ///
/// # Examples
///
/// ```
/// This number is simply useful for passing to other methods, like
/// [`OsString::with_capacity`] to avoid reallocations.
///
- /// [`OsString`]: struct.OsString.html
- /// [`OsString::with_capacity`]: struct.OsString.html#method.with_capacity
- ///
/// # Examples
///
/// ```
}
/// Converts a [`Box`]`<OsStr>` into an [`OsString`] without copying or allocating.
- ///
- /// [`Box`]: ../boxed/struct.Box.html
- /// [`OsString`]: struct.OsString.html
#[stable(feature = "into_boxed_os_str", since = "1.20.0")]
pub fn into_os_string(self: Box<OsStr>) -> OsString {
let boxed = unsafe { Box::from_raw(Box::into_raw(self) as *mut Slice) };
/// but non-ASCII letters are unchanged.
///
/// To return a new lowercased value without modifying the existing one, use
- /// [`to_ascii_lowercase`].
- ///
- /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase
+ /// [`OsStr::to_ascii_lowercase`].
///
/// # Examples
///
/// but non-ASCII letters are unchanged.
///
/// To return a new uppercased value without modifying the existing one, use
- /// [`to_ascii_uppercase`].
- ///
- /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase
+ /// [`OsStr::to_ascii_uppercase`].
///
/// # Examples
///
/// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
/// but non-ASCII letters are unchanged.
///
- /// To lowercase the value in-place, use [`make_ascii_lowercase`].
- ///
- /// [`make_ascii_lowercase`]: #method.make_ascii_lowercase
+ /// To lowercase the value in-place, use [`OsStr::make_ascii_lowercase`].
///
/// # Examples
///
/// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
/// but non-ASCII letters are unchanged.
///
- /// To uppercase the value in-place, use [`make_ascii_uppercase`].
- ///
- /// [`make_ascii_uppercase`]: #method.make_ascii_uppercase
+ /// To uppercase the value in-place, use [`OsStr::make_ascii_uppercase`].
///
/// # Examples
///
impl From<Box<OsStr>> for OsString {
/// Converts a [`Box`]`<`[`OsStr`]`>` into a `OsString` without copying or
/// allocating.
- ///
- /// [`Box`]: ../boxed/struct.Box.html
- /// [`OsStr`]: ../ffi/struct.OsStr.html
fn from(boxed: Box<OsStr>) -> OsString {
boxed.into_os_string()
}
#[stable(feature = "box_from_os_string", since = "1.20.0")]
impl From<OsString> for Box<OsStr> {
/// Converts a [`OsString`] into a [`Box`]`<OsStr>` without copying or allocating.
- ///
- /// [`Box`]: ../boxed/struct.Box.html
- /// [`OsString`]: ../ffi/struct.OsString.html
fn from(s: OsString) -> Box<OsStr> {
s.into_boxed_os_str()
}
#[stable(feature = "shared_from_slice2", since = "1.24.0")]
impl From<OsString> for Arc<OsStr> {
/// Converts a [`OsString`] into a [`Arc`]`<OsStr>` without copying or allocating.
- ///
- /// [`Arc`]: ../sync/struct.Arc.html
- /// [`OsString`]: ../ffi/struct.OsString.html
#[inline]
fn from(s: OsString) -> Arc<OsStr> {
let arc = s.inner.into_arc();
#[stable(feature = "shared_from_slice2", since = "1.24.0")]
impl From<OsString> for Rc<OsStr> {
/// Converts a [`OsString`] into a [`Rc`]`<OsStr>` without copying or allocating.
- ///
- /// [`Rc`]: ../rc/struct.Rc.html
- /// [`OsString`]: ../ffi/struct.OsString.html
#[inline]
fn from(s: OsString) -> Rc<OsStr> {
let rc = s.inner.into_rc();
#[doc(keyword = "unsafe")]
//
-/// Code or interfaces whose [memory safety] cannot be verified by the type system.
+/// Code or interfaces whose [memory safety] cannot be verified by the type
+/// system.
+///
+/// The `unsafe` keyword has two uses: to declare the existence of contracts the
+/// compiler can't check (`unsafe fn` and `unsafe trait`), and to declare that a
+/// programmer has checked that these contracts have been upheld (`unsafe {}`
+/// and `unsafe impl`, but also `unsafe fn` -- see below). They are not mutually
+/// exclusive, as can be seen in `unsafe fn`.
+///
+/// # Unsafe abilities
+///
+/// **No matter what, Safe Rust can't cause Undefined Behavior**. This is
+/// referred to as [soundness]: a well-typed program actually has the desired
+/// properties. The [Nomicon][nomicon-soundness] has a more detailed explanation
+/// on the subject.
+///
+/// To ensure soundness, Safe Rust is restricted enough that it can be
+/// automatically checked. Sometimes, however, it is necessary to write code
+/// that is correct for reasons which are too clever for the compiler to
+/// understand. In those cases, you need to use Unsafe Rust.
+///
+/// Here are the abilities Unsafe Rust has in addition to Safe Rust:
+///
+/// - Dereference [raw pointers]
+/// - Implement `unsafe` [`trait`]s
+/// - Call `unsafe` functions
+/// - Mutate [`static`]s (including [`extern`]al ones)
+/// - Access fields of [`union`]s
+///
+/// However, this extra power comes with extra responsibilities: it is now up to
+/// you to ensure soundness. The `unsafe` keyword helps by clearly marking the
+/// pieces of code that need to worry about this.
+///
+/// ## The different meanings of `unsafe`
+///
+/// Not all uses of `unsafe` are equivalent: some are here to mark the existence
+/// of a contract the programmer must check, others are to say "I have checked
+/// the contract, go ahead and do this". The following
+/// [discussion on Rust Internals] has more in-depth explanations about this but
+/// here is a summary of the main points:
+///
+/// - `unsafe fn`: calling this function means abiding by a contract the
+/// compiler cannot enforce.
+/// - `unsafe trait`: implementing the [`trait`] means abiding by a
+/// contract the compiler cannot enforce.
+/// - `unsafe {}`: the contract necessary to call the operations inside the
+/// block has been checked by the programmer and is guaranteed to be respected.
+/// - `unsafe impl`: the contract necessary to implement the trait has been
+/// checked by the programmer and is guaranteed to be respected.
+///
+/// `unsafe fn` also acts like an `unsafe {}` block
+/// around the code inside the function. This means it is not just a signal to
+/// the caller, but also promises that the preconditions for the operations
+/// inside the function are upheld. Mixing these two meanings can be confusing
+/// and [proposal]s exist to use `unsafe {}` blocks inside such functions when
+/// making `unsafe` operations.
+///
+/// See the [Rustnomicon] and the [Reference] for more informations.
///
-/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+/// # Examples
+///
+/// ## Marking elements as `unsafe`
+///
+/// `unsafe` can be used on functions. Note that functions and statics declared
+/// in [`extern`] blocks are implicitly marked as `unsafe` (but not functions
+/// declared as `extern "something" fn ...`). Mutable statics are always unsafe,
+/// wherever they are declared. Methods can also be declared as `unsafe`:
+///
+/// ```rust
+/// # #![allow(dead_code)]
+/// static mut FOO: &str = "hello";
+///
+/// unsafe fn unsafe_fn() {}
+///
+/// extern "C" {
+/// fn unsafe_extern_fn();
+/// static BAR: *mut u32;
+/// }
+///
+/// trait SafeTraitWithUnsafeMethod {
+/// unsafe fn unsafe_method(&self);
+/// }
+///
+/// struct S;
+///
+/// impl S {
+/// unsafe fn unsafe_method_on_struct() {}
+/// }
+/// ```
+///
+/// Traits can also be declared as `unsafe`:
+///
+/// ```rust
+/// unsafe trait UnsafeTrait {}
+/// ```
///
+/// Since `unsafe fn` and `unsafe trait` indicate that there is a safety
+/// contract that the compiler cannot enforce, documenting it is important. The
+/// standard library has many examples of this, like the following which is an
+/// extract from [`Vec::set_len`]. The `# Safety` section explains the contract
+/// that must be fulfilled to safely call the function.
+///
+/// ```rust,ignore (stub-to-show-doc-example)
+/// /// Forces the length of the vector to `new_len`.
+/// ///
+/// /// This is a low-level operation that maintains none of the normal
+/// /// invariants of the type. Normally changing the length of a vector
+/// /// is done using one of the safe operations instead, such as
+/// /// `truncate`, `resize`, `extend`, or `clear`.
+/// ///
+/// /// # Safety
+/// ///
+/// /// - `new_len` must be less than or equal to `capacity()`.
+/// /// - The elements at `old_len..new_len` must be initialized.
+/// pub unsafe fn set_len(&mut self, new_len: usize)
+/// ```
+///
+/// ## Using `unsafe {}` blocks and `impl`s
+///
+/// Performing `unsafe` operations requires an `unsafe {}` block:
+///
+/// ```rust
+/// # #![allow(dead_code)]
+/// /// Dereference the given pointer.
+/// ///
+/// /// # Safety
+/// ///
+/// /// `ptr` must be aligned and must not be dangling.
+/// unsafe fn deref_unchecked(ptr: *const i32) -> i32 {
+/// *ptr
+/// }
+///
+/// let a = 3;
+/// let b = &a as *const _;
+/// // SAFETY: `a` has not been dropped and references are always aligned,
+/// // so `b` is a valid address.
+/// unsafe { assert_eq!(*b, deref_unchecked(b)); };
+/// ```
+///
+/// Traits marked as `unsafe` must be [`impl`]emented using `unsafe impl`. This
+/// makes a guarantee to other `unsafe` code that the implementation satisfies
+/// the trait's safety contract. The [Send] and [Sync] traits are examples of
+/// this behaviour in the standard library.
+///
+/// ```rust
+/// /// Implementors of this trait must guarantee an element is always
+/// /// accessible with index 3.
+/// unsafe trait ThreeIndexable<T> {
+/// /// Returns a reference to the element with index 3 in `&self`.
+/// fn three(&self) -> &T;
+/// }
+///
+/// // The implementation of `ThreeIndexable` for `[T; 4]` is `unsafe`
+/// // because the implementor must abide by a contract the compiler cannot
+/// // check but as a programmer we know there will always be a valid element
+/// // at index 3 to access.
+/// unsafe impl<T> ThreeIndexable<T> for [T; 4] {
+/// fn three(&self) -> &T {
+/// // SAFETY: implementing the trait means there always is an element
+/// // with index 3 accessible.
+/// unsafe { self.get_unchecked(3) }
+/// }
+/// }
+///
+/// let a = [1, 2, 4, 8];
+/// assert_eq!(a.three(), &8);
+/// ```
+///
+/// [`extern`]: keyword.extern.html
+/// [`trait`]: keyword.trait.html
+/// [`static`]: keyword.static.html
+/// [`union`]: keyword.union.html
+/// [`impl`]: keyword.impl.html
+/// [Send]: marker/trait.Send.html
+/// [Sync]: marker/trait.Sync.html
+/// [`Vec::set_len`]: vec/struct.Vec.html#method.set_len
+/// [raw pointers]: ../reference/types/pointer.html
/// [memory safety]: ../book/ch19-01-unsafe-rust.html
-/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+/// [Rustnomicon]: ../nomicon/index.html
+/// [nomicon-soundness]: ../nomicon/safe-unsafe-meaning.html
+/// [soundness]: https://rust-lang.github.io/unsafe-code-guidelines/glossary.html#soundness-of-code--of-a-library
+/// [Reference]: ../reference/unsafety.html
+/// [proposal]: https://github.com/rust-lang/rfcs/pull/2585
+/// [discussion on Rust Internals]: https://internals.rust-lang.org/t/what-does-unsafe-mean/6696
mod unsafe_keyword {}
#[doc(keyword = "use")]
/// assert_eq!(socket.port(), 8080);
/// assert_eq!(socket.is_ipv4(), true);
/// ```
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[stable(feature = "rust1", since = "1.0.0")]
pub enum SocketAddr {
/// An IPv4 socket address.
}
}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for SocketAddr {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(self, fmt)
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Display for SocketAddrV4 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
/// assert_eq!(localhost_v4.is_ipv4(), true);
/// ```
#[stable(feature = "ip_addr", since = "1.7.0")]
-#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, PartialOrd, Ord)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
pub enum IpAddr {
/// An IPv4 address.
#[stable(feature = "ip_addr", since = "1.7.0")]
}
}
+#[stable(feature = "ip_addr", since = "1.7.0")]
+impl fmt::Debug for IpAddr {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(self, fmt)
+ }
+}
+
#[stable(feature = "ip_from_ip", since = "1.16.0")]
impl From<Ipv4Addr> for IpAddr {
/// Copies this address to a new `IpAddr::V4`.
//! assert_eq!(b"test", output.stdout.as_slice());
//! ```
//!
-//! [`abort`]: fn.abort.html
-//! [`exit`]: fn.exit.html
+//! [`spawn`]: Command::spawn
+//! [`output`]: Command::output
//!
-//! [`Command`]: struct.Command.html
-//! [`spawn`]: struct.Command.html#method.spawn
-//! [`output`]: struct.Command.html#method.output
+//! [`stdout`]: Command::stdout
+//! [`stdin`]: Command::stdin
+//! [`stderr`]: Command::stderr
//!
-//! [`Child`]: struct.Child.html
-//! [`ChildStdin`]: struct.ChildStdin.html
-//! [`ChildStdout`]: struct.ChildStdout.html
-//! [`ChildStderr`]: struct.ChildStderr.html
-//! [`Stdio`]: struct.Stdio.html
-//!
-//! [`stdout`]: struct.Command.html#method.stdout
-//! [`stdin`]: struct.Command.html#method.stdin
-//! [`stderr`]: struct.Command.html#method.stderr
-//!
-//! [`Write`]: ../io/trait.Write.html
-//! [`Read`]: ../io/trait.Read.html
+//! [`Write`]: io::Write
+//! [`Read`]: io::Read
#![stable(feature = "process", since = "1.0.0")]
/// run, even after the `Child` handle to the child process has gone out of
/// scope.
///
-/// Calling [`wait`](#method.wait) (or other functions that wrap around it) will make
+/// Calling [`wait`] (or other functions that wrap around it) will make
/// the parent process wait until the child has actually exited before
/// continuing.
///
/// assert!(ecode.success());
/// ```
///
-/// [`Command`]: struct.Command.html
-/// [`Drop`]: ../../core/ops/trait.Drop.html
-/// [`wait`]: #method.wait
+/// [`wait`]: Child::wait
#[stable(feature = "process", since = "1.0.0")]
pub struct Child {
handle: imp::Process,
/// The handle for writing to the child's standard input (stdin), if it has
- /// been captured.
+ /// been captured. To avoid partially moving
+ /// the `child` and thus blocking yourself from calling
+ /// functions on `child` while using `stdin`,
+ /// you might find it helpful:
+ ///
+ /// ```compile_fail,E0425
+ /// let stdin = child.stdin.take().unwrap();
+ /// ```
#[stable(feature = "process", since = "1.0.0")]
pub stdin: Option<ChildStdin>,
/// The handle for reading from the child's standard output (stdout), if it
- /// has been captured.
+ /// has been captured. You might find it helpful to do
+ ///
+ /// ```compile_fail,E0425
+ /// let stdout = child.stdout.take().unwrap();
+ /// ```
+ ///
+ /// to avoid partially moving the `child` and thus blocking yourself from calling
+ /// functions on `child` while using `stdout`.
#[stable(feature = "process", since = "1.0.0")]
pub stdout: Option<ChildStdout>,
/// The handle for reading from the child's standard error (stderr), if it
- /// has been captured.
+ /// has been captured. You might find it helpful to do
+ ///
+ /// ```compile_fail,E0425
+ /// let stderr = child.stderr.take().unwrap();
+ /// ```
+ ///
+ /// to avoid partially moving the `child` and thus blocking yourself from calling
+ /// functions on `child` while using `stderr`.
#[stable(feature = "process", since = "1.0.0")]
pub stderr: Option<ChildStderr>,
}
/// file handle will be closed. If the child process was blocked on input prior
/// to being dropped, it will become unblocked after dropping.
///
-/// [`Child`]: struct.Child.html
-/// [`stdin`]: struct.Child.html#structfield.stdin
-/// [dropped]: ../ops/trait.Drop.html
+/// [`stdin`]: Child::stdin
+/// [dropped]: Drop
#[stable(feature = "process", since = "1.0.0")]
pub struct ChildStdin {
inner: AnonPipe,
/// When an instance of `ChildStdout` is [dropped], the `ChildStdout`'s
/// underlying file handle will be closed.
///
-/// [`Child`]: struct.Child.html
-/// [`stdout`]: struct.Child.html#structfield.stdout
-/// [dropped]: ../ops/trait.Drop.html
+/// [`stdout`]: Child::stdout
+/// [dropped]: Drop
#[stable(feature = "process", since = "1.0.0")]
pub struct ChildStdout {
inner: AnonPipe,
/// When an instance of `ChildStderr` is [dropped], the `ChildStderr`'s
/// underlying file handle will be closed.
///
-/// [`Child`]: struct.Child.html
-/// [`stderr`]: struct.Child.html#structfield.stderr
-/// [dropped]: ../ops/trait.Drop.html
+/// [`stderr`]: Child::stderr
+/// [dropped]: Drop
#[stable(feature = "process", since = "1.0.0")]
pub struct ChildStderr {
inner: AnonPipe,
///
/// To pass multiple arguments see [`args`].
///
- /// [`args`]: #method.args
+ /// [`args`]: Command::args
///
/// # Examples
///
///
/// To pass a single argument see [`arg`].
///
- /// [`arg`]: #method.arg
+ /// [`arg`]: Command::arg
///
/// # Examples
///
/// .expect("ls command failed to start");
/// ```
///
- /// [`canonicalize`]: ../fs/fn.canonicalize.html
+ /// [`canonicalize`]: crate::fs::canonicalize
#[stable(feature = "process", since = "1.0.0")]
pub fn current_dir<P: AsRef<Path>>(&mut self, dir: P) -> &mut Command {
self.inner.cwd(dir.as_ref().as_ref());
/// Defaults to [`inherit`] when used with `spawn` or `status`, and
/// defaults to [`piped`] when used with `output`.
///
- /// [`inherit`]: struct.Stdio.html#method.inherit
- /// [`piped`]: struct.Stdio.html#method.piped
+ /// [`inherit`]: Stdio::inherit
+ /// [`piped`]: Stdio::piped
///
/// # Examples
///
/// Defaults to [`inherit`] when used with `spawn` or `status`, and
/// defaults to [`piped`] when used with `output`.
///
- /// [`inherit`]: struct.Stdio.html#method.inherit
- /// [`piped`]: struct.Stdio.html#method.piped
+ /// [`inherit`]: Stdio::inherit
+ /// [`piped`]: Stdio::piped
///
/// # Examples
///
/// Defaults to [`inherit`] when used with `spawn` or `status`, and
/// defaults to [`piped`] when used with `output`.
///
- /// [`inherit`]: struct.Stdio.html#method.inherit
- /// [`piped`]: struct.Stdio.html#method.piped
+ /// [`inherit`]: Stdio::inherit
+ /// [`piped`]: Stdio::piped
///
/// # Examples
///
/// [`Command`], or the [`wait_with_output`] method of a [`Child`]
/// process.
///
-/// [`Command`]: struct.Command.html
-/// [`Child`]: struct.Child.html
-/// [`output`]: struct.Command.html#method.output
-/// [`wait_with_output`]: struct.Child.html#method.wait_with_output
+/// [`output`]: Command::output
+/// [`wait_with_output`]: Child::wait_with_output
#[derive(PartialEq, Eq, Clone)]
#[stable(feature = "process", since = "1.0.0")]
pub struct Output {
/// Describes what to do with a standard I/O stream for a child process when
/// passed to the [`stdin`], [`stdout`], and [`stderr`] methods of [`Command`].
///
-/// [`stdin`]: struct.Command.html#method.stdin
-/// [`stdout`]: struct.Command.html#method.stdout
-/// [`stderr`]: struct.Command.html#method.stderr
-/// [`Command`]: struct.Command.html
+/// [`stdin`]: Command::stdin
+/// [`stdout`]: Command::stdout
+/// [`stderr`]: Command::stderr
#[stable(feature = "process", since = "1.0.0")]
pub struct Stdio(imp::Stdio);
/// status is exposed through the [`status`] method, or the [`wait`] method
/// of a [`Child`] process.
///
-/// [`Command`]: struct.Command.html
-/// [`Child`]: struct.Child.html
-/// [`status`]: struct.Command.html#method.status
-/// [`wait`]: struct.Child.html#method.wait
+/// [`status`]: Command::status
+/// [`wait`]: Child::wait
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
#[stable(feature = "process", since = "1.0.0")]
pub struct ExitStatus(imp::ExitStatus);
/// For the platform's canonical successful and unsuccessful codes, see
/// the [`SUCCESS`] and [`FAILURE`] associated items.
///
-/// [`SUCCESS`]: #associatedconstant.SUCCESS
-/// [`FAILURE`]: #associatedconstant.FAILURE
+/// [`SUCCESS`]: ExitCode::SUCCESS
+/// [`FAILURE`]: ExitCode::FAILURE
///
/// **Warning**: While various forms of this were discussed in [RFC #1937],
/// it was ultimately cut from that RFC, and thus this type is more subject
/// }
/// ```
///
- /// [`ErrorKind`]: ../io/enum.ErrorKind.html
- /// [`InvalidInput`]: ../io/enum.ErrorKind.html#variant.InvalidInput
- /// [`Other`]: ../io/enum.ErrorKind.html#variant.Other
+ /// [`ErrorKind`]: io::ErrorKind
+ /// [`InvalidInput`]: io::ErrorKind::InvalidInput
+ /// [`Other`]: io::ErrorKind::Other
#[stable(feature = "process", since = "1.0.0")]
pub fn kill(&mut self) -> io::Result<()> {
self.handle.kill()
/// }
/// ```
///
-/// [`panic!`]: ../../std/macro.panic.html
-/// [panic hook]: ../../std/panic/fn.set_hook.html
+/// [panic hook]: crate::panic::set_hook
#[stable(feature = "process_abort", since = "1.17.0")]
pub fn abort() -> ! {
crate::sys::abort_internal();
}
}
+ pub fn ident(&self) -> Option<&Ident> {
+ match self {
+ FnKind::Fn(_, ident, ..) => Some(ident),
+ _ => None,
+ }
+ }
+
pub fn decl(&self) -> &'a FnDecl {
match self {
FnKind::Fn(_, _, sig, _, _) => &sig.decl,
use log::debug;
use rustc_codegen_ssa::coverageinfo::map::{CounterExpression, ExprKind, FunctionCoverage, Region};
use rustc_codegen_ssa::traits::{
- BaseTypeMethods, CoverageInfoBuilderMethods, CoverageInfoMethods, StaticMethods,
+ BaseTypeMethods, CoverageInfoBuilderMethods, CoverageInfoMethods, MiscMethods, StaticMethods,
};
use rustc_data_structures::fx::FxHashMap;
use rustc_llvm::RustString;
}
impl CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
+ /// Calls llvm::createPGOFuncNameVar() with the given function instance's mangled function name.
+ /// The LLVM API returns an llvm::GlobalVariable containing the function name, with the specific
+ /// variable name and linkage required by LLVM InstrProf source-based coverage instrumentation.
+ fn create_pgo_func_name_var(&self, instance: Instance<'tcx>) -> Self::Value {
+ let llfn = self.cx.get_fn(instance);
+ let mangled_fn_name = CString::new(self.tcx.symbol_name(instance).name)
+ .expect("error converting function name to C string");
+ unsafe { llvm::LLVMRustCoverageCreatePGOFuncNameVar(llfn, mangled_fn_name.as_ptr()) }
+ }
+
fn add_counter_region(
&mut self,
instance: Instance<'tcx>,
self.call(llfn, &[], None)
}
sym::count_code_region => {
- let coverageinfo = tcx.coverageinfo(caller_instance.def_id());
- let mangled_fn = tcx.symbol_name(caller_instance);
- let (mangled_fn_name, _len_val) = self.const_str(Symbol::intern(mangled_fn.name));
- let num_counters = self.const_u32(coverageinfo.num_counters);
use coverage::count_code_region_args::*;
+ let coverageinfo = tcx.coverageinfo(caller_instance.def_id());
+
+ let fn_name = self.create_pgo_func_name_var(caller_instance);
let hash = args[FUNCTION_SOURCE_HASH].immediate();
+ let num_counters = self.const_u32(coverageinfo.num_counters);
let index = args[COUNTER_ID].immediate();
debug!(
"translating Rust intrinsic `count_code_region()` to LLVM intrinsic: \
- instrprof.increment(fn_name={}, hash={:?}, num_counters={:?}, index={:?})",
- mangled_fn.name, hash, num_counters, index,
+ instrprof.increment(fn_name={:?}, hash={:?}, num_counters={:?}, index={:?})",
+ fn_name, hash, num_counters, index,
);
- self.instrprof_increment(mangled_fn_name, hash, num_counters, index)
+ self.instrprof_increment(fn_name, hash, num_counters, index)
}
sym::va_start => self.va_start(args[0].immediate()),
sym::va_end => self.va_end(args[0].immediate()),
BufferOut: &RustString,
);
+ pub fn LLVMRustCoverageCreatePGOFuncNameVar(F: &'a Value, FuncName: *const c_char)
+ -> &'a Value;
pub fn LLVMRustCoverageComputeHash(Name: *const c_char) -> u64;
#[allow(improper_ctypes)]
}
}
- if tcx.sess.opts.cg.profile_generate.enabled() {
+ if tcx.sess.opts.debugging_opts.instrument_coverage
+ || tcx.sess.opts.cg.profile_generate.enabled()
+ {
// These are weak symbols that point to the profile version and the
// profile name, which need to be treated as exported so LTO doesn't nix
// them.
}));
}
- if tcx.sess.opts.debugging_opts.instrument_coverage {
- // Similar to PGO profiling, preserve symbols used by LLVM InstrProf coverage profiling.
- const COVERAGE_WEAK_SYMBOLS: [&str; 3] =
- ["__llvm_profile_filename", "__llvm_coverage_mapping", "__llvm_covmap"];
-
- symbols.extend(COVERAGE_WEAK_SYMBOLS.iter().map(|sym| {
- let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, sym));
- (exported_symbol, SymbolExportLevel::C)
- }));
- }
-
if tcx.sess.opts.debugging_opts.sanitizer.contains(SanitizerSet::MEMORY) {
// Similar to profiling, preserve weak msan symbol during LTO.
const MSAN_WEAK_SYMBOLS: [&str; 2] = ["__msan_track_origins", "__msan_keep_going"];
}
pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes {
+ fn create_pgo_func_name_var(&self, instance: Instance<'tcx>) -> Self::Value;
+
fn add_counter_region(
&mut self,
instance: Instance<'tcx>,
-`fn main()` or the specified start function is not allowed to be
-async. You might be seeing this error because your async runtime
-library is not set up correctly.
+The entry point of the program was marked as `async`.
Erroneous code example:
```compile_fail,E0752
-async fn main() -> Result<i32, ()> {
- Ok(1)
+async fn main() -> Result<(), ()> { // error!
+ Ok(())
+}
+```
+
+`fn main()` or the specified start function is not allowed to be `async`. Not
+having a correct async runtime library setup may cause this error. To fix it,
+declare the entry point without `async`:
+
+```
+fn main() -> Result<(), ()> { // ok!
+ Ok(())
}
```
ecx.run()?;
// Intern the result
+ // FIXME: since the DefId of a promoted is the DefId of its owner, this
+ // means that promoteds in statics are actually interned like statics!
+ // However, this is also currently crucial because we promote mutable
+ // non-empty slices in statics to extend their lifetime, and this
+ // ensures that they are put into a mutable allocation.
+ // For other kinds of promoteds in statics (like array initializers), this is rather silly.
let intern_kind = match tcx.static_mutability(cid.instance.def_id()) {
Some(m) => InternKind::Static(m),
None if cid.promoted.is_some() => InternKind::Promoted,
let tcx = ecx.tcx;
let base_intern_mode = match intern_kind {
InternKind::Static(mutbl) => InternMode::Static(mutbl),
- // FIXME: what about array lengths, array initializers?
+ // `Constant` includes array lengths.
+ // `Promoted` includes non-`Copy` array initializers and `rustc_args_required_const` arguments.
InternKind::Constant | InternKind::Promoted => InternMode::ConstBase,
};
.skip(1)
.take(arg_count)
.map(|(local, _)| Place::from(local))
- .filter(needs_retag)
- .collect::<Vec<_>>();
+ .filter(needs_retag);
// Emit their retags.
basic_blocks[START_BLOCK].statements.splice(
0..0,
- places.into_iter().map(|place| Statement {
+ places.map(|place| Statement {
source_info,
kind: StatementKind::Retag(RetagKind::FnEntry, box (place)),
}),
// PART 2
// Retag return values of functions. Also escape-to-raw the argument of `drop`.
// We collect the return destinations because we cannot mutate while iterating.
- let mut returns: Vec<(SourceInfo, Place<'tcx>, BasicBlock)> = Vec::new();
- for block_data in basic_blocks.iter_mut() {
- match block_data.terminator().kind {
- TerminatorKind::Call { ref destination, .. } => {
- // Remember the return destination for later
- if let Some(ref destination) = destination {
- if needs_retag(&destination.0) {
- returns.push((
- block_data.terminator().source_info,
- destination.0,
- destination.1,
- ));
- }
+ let returns = basic_blocks
+ .iter_mut()
+ .filter_map(|block_data| {
+ match block_data.terminator().kind {
+ TerminatorKind::Call { destination: Some(ref destination), .. }
+ if needs_retag(&destination.0) =>
+ {
+ // Remember the return destination for later
+ Some((block_data.terminator().source_info, destination.0, destination.1))
}
- }
- TerminatorKind::Drop { .. } | TerminatorKind::DropAndReplace { .. } => {
+
// `Drop` is also a call, but it doesn't return anything so we are good.
- }
- _ => {
+ TerminatorKind::Drop { .. } | TerminatorKind::DropAndReplace { .. } => None,
// Not a block ending in a Call -> ignore.
+ _ => None,
}
- }
- }
+ })
+ .collect::<Vec<_>>();
// Now we go over the returns we collected to retag the return values.
for (source_info, dest_place, dest_block) in returns {
basic_blocks[dest_block].statements.insert(
for bb in basic_blocks {
bb.expand_statements(|stmt| {
// FIXME(eddyb) don't match twice on `stmt.kind` (post-NLL).
- if let StatementKind::Assign(box (_, ref rhs)) = stmt.kind {
- if let Rvalue::Aggregate(ref kind, _) = *rhs {
- // FIXME(#48193) Deaggregate arrays when it's cheaper to do so.
- if let AggregateKind::Array(_) = **kind {
- return None;
- }
- } else {
+ match stmt.kind {
+ // FIXME(#48193) Deaggregate arrays when it's cheaper to do so.
+ StatementKind::Assign(box (
+ _,
+ Rvalue::Aggregate(box AggregateKind::Array(_), _),
+ )) => {
return None;
}
- } else {
- return None;
+ StatementKind::Assign(box (_, Rvalue::Aggregate(_, _))) => {}
+ _ => return None,
}
let stmt = stmt.replace_nop();
let source_info = stmt.source_info;
let (lhs, kind, operands) = match stmt.kind {
- StatementKind::Assign(box (lhs, rvalue)) => match rvalue {
- Rvalue::Aggregate(kind, operands) => (lhs, kind, operands),
- _ => bug!(),
- },
+ StatementKind::Assign(box (lhs, Rvalue::Aggregate(kind, operands))) => {
+ (lhs, kind, operands)
+ }
_ => bug!(),
};
let (file_name, start_line, start_col, end_line, end_col) = self.code_region(&span);
+ // FIXME(richkadel): Note that `const_str()` results in the creation of an `Allocation` to
+ // hold one copy of each unique filename. It looks like that `Allocation` may translate into
+ // the creation of an `@alloc` in LLVM IR that is never actually used by runtime code.
+ //
+ // Example LLVM IR:
+ //
+ // @alloc4 = private unnamed_addr constant <{ [43 x i8] }> \
+ // <{ [43 x i8] c"C:\\msys64\\home\\richkadel\\rust\\rust_basic.rs" }>, align 1
+ //
+ // Can I flag the alloc as something not to be added to codegen? Or somehow remove it before
+ // it gets added to the LLVM IR? Do we need some kind of reference counting to know it's
+ // not used by any runtime code?
+ //
+ // This question is moot if I convert the Call Terminators to Statements, I believe:
+ // https://rust-lang.zulipchat.com/#narrow/stream/233931-t-compiler.2Fmajor-changes/topic/Implement.20LLVM-compatible.20source-based.20cod.20compiler-team.23278/near/206731748
args.push(self.const_str(&file_name, inject_at));
args.push(self.const_u32(start_line, inject_at));
args.push(self.const_u32(start_col, inject_at));
/// of a larger candidate.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Candidate {
- /// Borrow of a constant temporary.
+ /// Borrow of a constant temporary, candidate for lifetime extension.
Ref(Location),
/// Promotion of the `x` in `[x; 32]`.
tmp_assigned_vars.insert(*r);
}
- let mut dbg_info_to_adjust = Vec::new();
- for (i, var_info) in debug_info.iter().enumerate() {
- if tmp_assigned_vars.contains(var_info.place.local) {
- dbg_info_to_adjust.push(i);
- }
- }
+ let dbg_info_to_adjust: Vec<_> =
+ debug_info
+ .iter()
+ .enumerate()
+ .filter_map(|(i, var_info)| {
+ if tmp_assigned_vars.contains(var_info.place.local) { Some(i) } else { None }
+ })
+ .collect();
Some(ArmIdentityInfo {
local_temp_0: local_tmp_s0,
stmt: &Statement<'tcx>,
) -> Option<(Local, Local, VarField<'tcx>, &'tcx List<PlaceElem<'tcx>>)> {
match &stmt.kind {
- StatementKind::Assign(box (place_into, rvalue_from)) => match rvalue_from {
- Rvalue::Use(Operand::Copy(pf) | Operand::Move(pf)) => {
- let local_into = place_into.as_local()?;
- let (local_from, vf) = match_variant_field_place(*pf)?;
- Some((local_into, local_from, vf, pf.projection))
- }
- _ => None,
- },
+ StatementKind::Assign(box (
+ place_into,
+ Rvalue::Use(Operand::Copy(pf) | Operand::Move(pf)),
+ )) => {
+ let local_into = place_into.as_local()?;
+ let (local_from, vf) = match_variant_field_place(*pf)?;
+ Some((local_into, local_from, vf, pf.projection))
+ }
_ => None,
}
}
/// ```
fn match_set_variant_field<'tcx>(stmt: &Statement<'tcx>) -> Option<(Local, Local, VarField<'tcx>)> {
match &stmt.kind {
- StatementKind::Assign(box (place_from, rvalue_into)) => match rvalue_into {
- Rvalue::Use(Operand::Move(place_into)) => {
- let local_into = place_into.as_local()?;
- let (local_from, vf) = match_variant_field_place(*place_from)?;
- Some((local_into, local_from, vf))
- }
- _ => None,
- },
+ StatementKind::Assign(box (place_from, Rvalue::Use(Operand::Move(place_into)))) => {
+ let local_into = place_into.as_local()?;
+ let (local_from, vf) = match_variant_field_place(*place_from)?;
+ Some((local_into, local_from, vf))
+ }
_ => None,
}
}
if let TerminatorKind::SwitchInt { values, targets, .. } =
&mut body.basic_blocks_mut()[bb].terminator_mut().kind
{
- let vals = &*values;
- let zipped = vals.iter().zip(targets.iter());
-
- let mut matched_values = Vec::with_capacity(allowed_variants.len());
- let mut matched_targets = Vec::with_capacity(allowed_variants.len() + 1);
-
- for (val, target) in zipped {
- if allowed_variants.contains(val) {
- matched_values.push(*val);
- matched_targets.push(*target);
- } else {
- trace!("eliminating {:?} -> {:?}", val, target);
- }
- }
-
- // handle the "otherwise" branch
- matched_targets.push(targets.pop().unwrap());
-
- *values = matched_values.into();
- *targets = matched_targets;
+ // take otherwise out early
+ let otherwise = targets.pop().unwrap();
+ assert_eq!(targets.len(), values.len());
+ let mut i = 0;
+ targets.retain(|_| {
+ let keep = allowed_variants.contains(&values[i]);
+ i += 1;
+ keep
+ });
+ targets.push(otherwise);
+
+ values.to_mut().retain(|var| allowed_variants.contains(var));
} else {
unreachable!()
}
where
F: Fn(BasicBlock) -> bool,
{
- match *terminator_kind {
- TerminatorKind::Goto { target } if predicate(target) => Some(TerminatorKind::Unreachable),
+ let terminator = match *terminator_kind {
+ TerminatorKind::Goto { target } if predicate(target) => TerminatorKind::Unreachable,
TerminatorKind::SwitchInt { ref discr, switch_ty, ref values, ref targets } => {
let original_targets_len = targets.len();
let (otherwise, targets) = targets.split_last().unwrap();
- let retained = values
- .iter()
- .zip(targets.iter())
- .filter(|(_, &t)| !predicate(t))
- .collect::<Vec<_>>();
- let mut values = retained.iter().map(|&(v, _)| *v).collect::<Vec<_>>();
- let mut targets = retained.iter().map(|&(_, d)| *d).collect::<Vec<_>>();
+ let (mut values, mut targets): (Vec<_>, Vec<_>) =
+ values.iter().zip(targets.iter()).filter(|(_, &t)| !predicate(t)).unzip();
if !predicate(*otherwise) {
targets.push(*otherwise);
let retained_targets_len = targets.len();
if targets.is_empty() {
- Some(TerminatorKind::Unreachable)
+ TerminatorKind::Unreachable
} else if targets.len() == 1 {
- Some(TerminatorKind::Goto { target: targets[0] })
+ TerminatorKind::Goto { target: targets[0] }
} else if original_targets_len != retained_targets_len {
- Some(TerminatorKind::SwitchInt {
+ TerminatorKind::SwitchInt {
discr: discr.clone(),
switch_ty,
values: Cow::from(values),
targets,
- })
+ }
} else {
- None
+ return None;
}
}
- _ => None,
- }
+ _ => return None,
+ };
+ Some(terminator)
}
use rustc_ast::ast::{self, Expr, ExprKind, Item, ItemKind, NodeId, Path, Ty, TyKind};
use rustc_ast::util::lev_distance::find_best_match_for_name;
+use rustc_ast::visit::FnKind;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
use rustc_hir as hir;
let code = source.error_code(res.is_some());
let mut err = self.r.session.struct_span_err_with_code(base_span, &base_msg, code);
+ let is_assoc_fn = self.self_type_is_available(span);
// Emit help message for fake-self from other languages (e.g., `this` in Javascript).
- if ["this", "my"].contains(&&*item_str.as_str())
- && self.self_value_is_available(path[0].ident.span, span)
- {
+ if ["this", "my"].contains(&&*item_str.as_str()) && is_assoc_fn {
err.span_suggestion_short(
span,
"you might have meant to use `self` here instead",
"self".to_string(),
Applicability::MaybeIncorrect,
);
+ if !self.self_value_is_available(path[0].ident.span, span) {
+ if let Some((FnKind::Fn(_, _, sig, ..), fn_span)) =
+ &self.diagnostic_metadata.current_function
+ {
+ let (span, sugg) = if let Some(param) = sig.decl.inputs.get(0) {
+ (param.span.shrink_to_lo(), "&self, ")
+ } else {
+ (
+ self.r
+ .session
+ .source_map()
+ .span_through_char(*fn_span, '(')
+ .shrink_to_hi(),
+ "&self",
+ )
+ };
+ err.span_suggestion_verbose(
+ span,
+ "if you meant to use `self`, you are also missing a `self` receiver \
+ argument",
+ sugg.to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
}
// Emit special messages for unresolved `Self` and `self`.
if fn_kind.decl().inputs.get(0).map(|p| p.is_self()).unwrap_or(false) {
err.span_label(*span, "this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters");
} else {
- err.span_label(*span, "this function doesn't have a `self` parameter");
+ let doesnt = if is_assoc_fn {
+ let (span, sugg) = fn_kind
+ .decl()
+ .inputs
+ .get(0)
+ .map(|p| (p.span.shrink_to_lo(), "&self, "))
+ .unwrap_or_else(|| {
+ (
+ self.r
+ .session
+ .source_map()
+ .span_through_char(*span, '(')
+ .shrink_to_hi(),
+ "&self",
+ )
+ });
+ err.span_suggestion_verbose(
+ span,
+ "add a `self` receiver parameter to make the associated `fn` a method",
+ sugg.to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ "doesn't"
+ } else {
+ "can't"
+ };
+ if let Some(ident) = fn_kind.ident() {
+ err.span_label(
+ ident.span,
+ &format!("this function {} have a `self` parameter", doesnt),
+ );
+ }
}
}
return (err, Vec::new());
span: Span,
trait_bounds: &[hir::PolyTraitRef<'_>],
lifetime: &hir::Lifetime,
+ borrowed: bool,
) -> Ty<'tcx> {
let tcx = self.tcx();
self.ast_region_to_region(lifetime, None)
} else {
self.re_infer(None, span).unwrap_or_else(|| {
- // FIXME: these can be redundant with E0106, but not always.
- struct_span_err!(
+ 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"
- )
- .emit();
+ );
+ 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
})
}
/// 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();
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(&mt.ty);
+ 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::TraitObject(ref bounds, ref lifetime) => {
- self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, 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);
CoverageMappingWriter.write(OS);
}
+extern "C" LLVMValueRef LLVMRustCoverageCreatePGOFuncNameVar(LLVMValueRef F, const char *FuncName) {
+ StringRef FuncNameRef(FuncName);
+ return wrap(createPGOFuncNameVar(*cast<Function>(unwrap(F)), FuncNameRef));
+}
+
extern "C" uint64_t LLVMRustCoverageComputeHash(const char *Name) {
StringRef NameRef(Name);
return IndexedInstrProf::ComputeHash(NameRef);
# FIXME(richkadel): Debug the following problem, and reenable on Windows (by
# removing the `# ignore-msvc` directive above). The current implementation
-# generates a segfault when running the instrumented `main` executable,
-# after the `main` program code executes, but before the process terminates.
-# This most likely points to a problem generating the LLVM "main.profraw"
+# generates a segfault when running the instrumented `testprog` executable,
+# after the `main()` function completes, but before the process terminates.
+# This most likely points to a problem generating the LLVM "testprog.profraw"
# file.
-include ../tools.mk
+UNAME = $(shell uname)
+
+ifeq ($(UNAME),Darwin)
+ INSTR_PROF_DATA_SUFFIX=,regular,live_support
+ DATA_SECTION_PREFIX=__DATA,
+ LLVM_COV_SECTION_PREFIX=__LLVM_COV,
+else
+ INSTR_PROF_DATA_SUFFIX=
+ DATA_SECTION_PREFIX=
+ LLVM_COV_SECTION_PREFIX=
+endif
+
# This test makes sure that LLVM coverage maps are genereated in LLVM IR.
COMMON_FLAGS=-Zinstrument-coverage
all:
# Compile the test program with instrumentation, and also generate LLVM IR
- $(RUSTC) $(COMMON_FLAGS) main.rs
+ $(RUSTC) $(COMMON_FLAGS) testprog.rs \
+ --emit=link,llvm-ir
+
+ # check the LLVM IR
+ifdef IS_WIN32
+ cat "$(TMPDIR)"/testprog.ll | "$(LLVM_FILECHECK)" filecheck-patterns.txt \
+ -check-prefixes=CHECK,WIN32 \
+ -DPRIVATE_GLOBAL="internal global" \
+ -DINSTR_PROF_DATA=".lprfd$$M" \
+ -DINSTR_PROF_NAME=".lprfn$$M" \
+ -DINSTR_PROF_CNTS=".lprfc$$M" \
+ -DINSTR_PROF_VALS=".lprfv$$M" \
+ -DINSTR_PROF_VNODES=".lprfnd$$M" \
+ -DINSTR_PROF_COVMAP=".lcovmap$$M" \
+ -DINSTR_PROF_ORDERFILE=".lorderfile$$M"
+else
+ cat "$(TMPDIR)"/testprog.ll | "$(LLVM_FILECHECK)" filecheck-patterns.txt \
+ -check-prefixes=CHECK \
+ -DPRIVATE_GLOBAL="private global" \
+ -DINSTR_PROF_DATA="$(DATA_SECTION_PREFIX)__llvm_prf_data$(INSTR_PROF_DATA_SUFFIX)" \
+ -DINSTR_PROF_NAME="$(DATA_SECTION_PREFIX)__llvm_prf_names" \
+ -DINSTR_PROF_CNTS="$(DATA_SECTION_PREFIX)__llvm_prf_cnts" \
+ -DINSTR_PROF_VALS="$(DATA_SECTION_PREFIX)__llvm_prf_vals" \
+ -DINSTR_PROF_VNODES="$(DATA_SECTION_PREFIX)__llvm_prf_vnds" \
+ -DINSTR_PROF_COVMAP="$(LLVM_COV_SECTION_PREFIX)__llvm_covmap" \
+ -DINSTR_PROF_ORDERFILE="$(DATA_SECTION_PREFIX)__llvm_orderfile"
+endif
# Run it in order to generate some profiling data,
# with `LLVM_PROFILE_FILE=<profdata_file>` environment variable set to
# output the coverage stats for this run.
- LLVM_PROFILE_FILE="$(TMPDIR)"/main.profraw \
- $(call RUN,main)
+ LLVM_PROFILE_FILE="$(TMPDIR)"/testprog.profraw \
+ $(call RUN,testprog)
# Postprocess the profiling data so it can be used by the llvm-cov tool
"$(LLVM_BIN_DIR)"/llvm-profdata merge --sparse \
- "$(TMPDIR)"/main.profraw \
- -o "$(TMPDIR)"/main.profdata
+ "$(TMPDIR)"/testprog.profraw \
+ -o "$(TMPDIR)"/testprog.profdata
# Generate a coverage report using `llvm-cov show`. The output ordering
# can be non-deterministic, so ignore the return status. If the test fails
# when comparing the JSON `export`, the `show` output may be useful when
# debugging.
"$(LLVM_BIN_DIR)"/llvm-cov show \
- --Xdemangler="$(RUST_DEMANGLER)" \
- --show-line-counts-or-regions \
- --instr-profile="$(TMPDIR)"/main.profdata \
- $(call BIN,"$(TMPDIR)"/main) \
+ --Xdemangler="$(RUST_DEMANGLER)" \
+ --show-line-counts-or-regions \
+ --instr-profile="$(TMPDIR)"/testprog.profdata \
+ $(call BIN,"$(TMPDIR)"/testprog) \
> "$(TMPDIR)"/actual_show_coverage.txt
+ifdef RUSTC_BLESS_TEST
+ cp "$(TMPDIR)"/actual_show_coverage.txt typical_show_coverage.txt
+else
# Compare the show coverage output
$(DIFF) typical_show_coverage.txt "$(TMPDIR)"/actual_show_coverage.txt || \
- >&2 echo 'diff failed for `llvm-cov show` (might not be an error)'
+ >&2 echo 'diff failed for `llvm-cov show` (might not be an error)'
+endif
# Generate a coverage report in JSON, using `llvm-cov export`, and fail if
# there are differences from the expected output.
"$(LLVM_BIN_DIR)"/llvm-cov export \
- --summary-only \
- --instr-profile="$(TMPDIR)"/main.profdata \
- $(call BIN,"$(TMPDIR)"/main) \
+ --summary-only \
+ --instr-profile="$(TMPDIR)"/testprog.profdata \
+ $(call BIN,"$(TMPDIR)"/testprog) \
| "$(PYTHON)" prettify_json.py \
> "$(TMPDIR)"/actual_export_coverage.json
+ifdef RUSTC_BLESS_TEST
+ cp "$(TMPDIR)"/actual_export_coverage.json expected_export_coverage.json
+else
# Check that the exported JSON coverage data matches what we expect
$(DIFF) expected_export_coverage.json "$(TMPDIR)"/actual_export_coverage.json
+endif
{
"files": [
{
- "filename": "main.rs",
+ "filename": "testprog.rs",
"summary": {
"functions": {
"count": 7,
--- /dev/null
+# Check for metadata, variables, declarations, and function definitions injected
+# into LLVM IR when compiling with -Zinstrument-coverage.
+
+WIN32: $__llvm_profile_runtime_user = comdat any
+
+CHECK: @__llvm_coverage_mapping = internal constant
+CHECK-SAME: section "[[INSTR_PROF_COVMAP]]", align 8
+
+WIN32: @__llvm_profile_runtime = external global i32
+
+CHECK: @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = [[PRIVATE_GLOBAL]]
+CHECK-SAME: section "[[INSTR_PROF_CNTS]]", align 8
+
+CHECK: @__profd__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = [[PRIVATE_GLOBAL]]
+CHECK-SAME: @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called,
+CHECK-SAME: ()* @_R{{[a-zA-Z0-9_]+}}testprog14will_be_called to i8*),
+CHECK-SAME: section "[[INSTR_PROF_DATA]]", align 8
+
+CHECK: @__profc__R{{[a-zA-Z0-9_]+}}testprog4main = [[PRIVATE_GLOBAL]]
+CHECK-SAME: section "[[INSTR_PROF_CNTS]]", align 8
+
+CHECK: @__profd__R{{[a-zA-Z0-9_]+}}testprog4main = [[PRIVATE_GLOBAL]]
+CHECK-SAME: @__profc__R{{[a-zA-Z0-9_]+}}testprog4main,
+CHECK-SAME: ()* @_R{{[a-zA-Z0-9_]+}}testprog4main to i8*),
+CHECK-SAME: section "[[INSTR_PROF_DATA]]", align 8
+
+CHECK: @__llvm_prf_nm = private constant
+CHECK-SAME: section "[[INSTR_PROF_NAME]]", align 1
+
+CHECK: @llvm.used = appending global
+CHECK-SAME: i8* bitcast ({ {{.*}} }* @__llvm_coverage_mapping to i8*)
+WIN32-SAME: i8* bitcast (i32 ()* @__llvm_profile_runtime_user to i8*)
+CHECK-SAME: i8* bitcast ({ {{.*}} }* @__profd__R{{[a-zA-Z0-9_]*}}testprog4main to i8*)
+CHECK-SAME: i8* getelementptr inbounds ({{.*}}* @__llvm_prf_nm, i32 0, i32 0)
+CHECK-SAME: section "llvm.metadata"
+
+CHECK: define hidden { {{.*}} } @_R{{[a-zA-Z0-9_]+}}testprog14will_be_called() unnamed_addr #{{[0-9]+}} {
+CHECK-NEXT: start:
+CHECK-NOT: bb{{[0-9]+}}:
+CHECK: %pgocount = load i64, i64* getelementptr inbounds
+CHECK-SAME: * @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called,
+
+CHECK: declare void @llvm.instrprof.increment(i8*, i64, i32, i32) #[[LLVM_INSTRPROF_INCREMENT_ATTR:[0-9]+]]
+
+WIN32: define linkonce_odr hidden i32 @__llvm_profile_runtime_user() #[[LLVM_PROFILE_RUNTIME_USER_ATTR:[0-9]+]] comdat {
+WIN32-NEXT: %1 = load i32, i32* @__llvm_profile_runtime
+WIN32-NEXT: ret i32 %1
+WIN32-NEXT: }
+
+CHECK: attributes #[[LLVM_INSTRPROF_INCREMENT_ATTR]] = { nounwind }
+WIN32: attributes #[[LLVM_PROFILE_RUNTIME_USER_ATTR]] = { noinline }
\ No newline at end of file
+++ /dev/null
-pub fn will_be_called() -> &'static str {
- let val = "called";
- println!("{}", val);
- val
-}
-
-pub fn will_not_be_called() -> bool {
- println!("should not have been called");
- false
-}
-
-pub fn print<T>(left: &str, value: T, right: &str)
-where
- T: std::fmt::Display,
-{
- println!("{}{}{}", left, value, right);
-}
-
-pub fn wrap_with<F, T>(inner: T, should_wrap: bool, wrapper: F)
-where
- F: FnOnce(&T)
-{
- if should_wrap {
- wrapper(&inner)
- }
-}
-
-fn main() {
- let less = 1;
- let more = 100;
-
- if less < more {
- wrap_with(will_be_called(), less < more, |inner| print(" ***", inner, "*** "));
- wrap_with(will_be_called(), more < less, |inner| print(" ***", inner, "*** "));
- } else {
- wrap_with(will_not_be_called(), true, |inner| print("wrapped result is: ", inner, ""));
- }
-}
--- /dev/null
+pub fn will_be_called() -> &'static str {
+ let val = "called";
+ println!("{}", val);
+ val
+}
+
+pub fn will_not_be_called() -> bool {
+ println!("should not have been called");
+ false
+}
+
+pub fn print<T>(left: &str, value: T, right: &str)
+where
+ T: std::fmt::Display,
+{
+ println!("{}{}{}", left, value, right);
+}
+
+pub fn wrap_with<F, T>(inner: T, should_wrap: bool, wrapper: F)
+where
+ F: FnOnce(&T)
+{
+ if should_wrap {
+ wrapper(&inner)
+ }
+}
+
+fn main() {
+ let less = 1;
+ let more = 100;
+
+ if less < more {
+ wrap_with(will_be_called(), less < more, |inner| print(" ***", inner, "*** "));
+ wrap_with(will_be_called(), more < less, |inner| print(" ***", inner, "*** "));
+ } else {
+ wrap_with(will_not_be_called(), true, |inner| print("wrapped result is: ", inner, ""));
+ }
+}
25| 2| }
26| 2|}
------------------
- | main[317d481089b8c8fe]::wrap_with::<main[317d481089b8c8fe]::main::{closure#0}, &str>:
+ | testprog[317d481089b8c8fe]::wrap_with::<testprog[317d481089b8c8fe]::main::{closure#0}, &str>:
| 22| 1|{
| 23| 1| if should_wrap {
| 24| 1| wrapper(&inner)
| 25| 1| }
| 26| 1|}
------------------
- | main[317d481089b8c8fe]::wrap_with::<main[317d481089b8c8fe]::main::{closure#1}, &str>:
+ | testprog[317d481089b8c8fe]::wrap_with::<testprog[317d481089b8c8fe]::main::{closure#1}, &str>:
| 22| 1|{
| 23| 1| if should_wrap {
| 24| 1| wrapper(&inner)
fn foo() {
self.bar(); //~ ERROR E0424
}
+
+ fn baz(_: i32) {
+ self.bar(); //~ ERROR E0424
+ }
}
fn main () {
error[E0424]: expected value, found module `self`
--> $DIR/E0424.rs:7:9
|
-LL | / fn foo() {
-LL | | self.bar();
- | | ^^^^ `self` value is a keyword only available in methods with a `self` parameter
-LL | | }
- | |_____- this function doesn't have a `self` parameter
+LL | fn foo() {
+ | --- this function doesn't have a `self` parameter
+LL | self.bar();
+ | ^^^^ `self` value is a keyword only available in methods with a `self` parameter
+ |
+help: add a `self` receiver parameter to make the associated `fn` a method
+ |
+LL | fn foo(&self) {
+ | ^^^^^
+
+error[E0424]: expected value, found module `self`
+ --> $DIR/E0424.rs:11:9
+ |
+LL | fn baz(_: i32) {
+ | --- this function doesn't have a `self` parameter
+LL | self.bar();
+ | ^^^^ `self` value is a keyword only available in methods with a `self` parameter
+ |
+help: add a `self` receiver parameter to make the associated `fn` a method
+ |
+LL | fn baz(&self, _: i32) {
+ | ^^^^^^
error[E0424]: expected unit struct, unit variant or constant, found module `self`
- --> $DIR/E0424.rs:12:9
+ --> $DIR/E0424.rs:16:9
|
-LL | / fn main () {
-LL | | let self = "self";
- | | ^^^^ `self` value is a keyword and may not be bound to variables or shadowed
-LL | | }
- | |_- this function doesn't have a `self` parameter
+LL | fn main () {
+ | ---- this function can't have a `self` parameter
+LL | let self = "self";
+ | ^^^^ `self` value is a keyword and may not be bound to variables or shadowed
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0424`.
-trait B < A > { fn a() -> A { this.a } } //~ ERROR cannot find value `this` in this scope
+trait B <A> {
+ fn a() -> A {
+ this.a //~ ERROR cannot find value `this` in this scope
+ }
+ fn b(x: i32) {
+ this.b(x); //~ ERROR cannot find value `this` in this scope
+ }
+}
fn main() {}
error[E0425]: cannot find value `this` in this scope
- --> $DIR/issue-5099.rs:1:31
+ --> $DIR/issue-5099.rs:3:9
|
-LL | trait B < A > { fn a() -> A { this.a } }
- | ^^^^ not found in this scope
+LL | this.a
+ | ^^^^ not found in this scope
+ |
+help: you might have meant to use `self` here instead
+ |
+LL | self.a
+ | ^^^^
+help: if you meant to use `self`, you are also missing a `self` receiver argument
+ |
+LL | fn a(&self) -> A {
+ | ^^^^^
+
+error[E0425]: cannot find value `this` in this scope
+ --> $DIR/issue-5099.rs:6:9
+ |
+LL | this.b(x);
+ | ^^^^ not found in this scope
+ |
+help: you might have meant to use `self` here instead
+ |
+LL | self.b(x);
+ | ^^^^
+help: if you meant to use `self`, you are also missing a `self` receiver argument
+ |
+LL | fn b(&self, x: i32) {
+ | ^^^^^^
-error: aborting due to previous error
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0425`.
error[E0424]: expected value, found module `self`
--> $DIR/issue-2356.rs:65:8
|
-LL | / fn meow() {
-LL | | if self.whiskers > 3 {
- | | ^^^^ `self` value is a keyword only available in methods with a `self` parameter
-LL | |
-LL | | println!("MEOW");
-LL | | }
-LL | | }
- | |___- this function doesn't have a `self` parameter
+LL | fn meow() {
+ | ---- this function doesn't have a `self` parameter
+LL | if self.whiskers > 3 {
+ | ^^^^ `self` value is a keyword only available in methods with a `self` parameter
+ |
+help: add a `self` receiver parameter to make the associated `fn` a method
+ |
+LL | fn meow(&self) {
+ | ^^^^^
error[E0425]: cannot find function `grow_older` in this scope
--> $DIR/issue-2356.rs:72:5
error[E0424]: expected value, found module `self`
--> $DIR/issue-2356.rs:92:5
|
-LL | / fn main() {
-LL | | self += 1;
- | | ^^^^ `self` value is a keyword only available in methods with a `self` parameter
-LL | |
-LL | | }
- | |_- this function doesn't have a `self` parameter
+LL | fn main() {
+ | ---- this function can't have a `self` parameter
+LL | self += 1;
+ | ^^^^ `self` value is a keyword only available in methods with a `self` parameter
error: aborting due to 17 previous errors
//~| ERROR missing lifetime specifier
//~| ERROR missing lifetime specifier
//~| ERROR missing lifetime specifier
- //~| ERROR the lifetime bound for this object type cannot be deduced from context
- //~| ERROR the lifetime bound for this object type cannot be deduced from context
}
thread_local! {
static c: RefCell<HashMap<i32, Vec<Vec<Qux<i32>>>>> = RefCell::new(HashMap::new());
//~| ERROR missing lifetime specifier
//~| ERROR missing lifetime specifier
//~| ERROR missing lifetime specifier
- //~| ERROR the lifetime bound for this object type cannot be deduced from context
- //~| ERROR the lifetime bound for this object type cannot be deduced from context
}
thread_local! {
}
thread_local! {
static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
- //~^ ERROR the lifetime bound for this object type cannot be deduced from context
- //~| ERROR the lifetime bound for this object type cannot be deduced from context
- //~| ERROR wrong number of lifetime arguments: expected 2, found 1
+ //~^ ERROR wrong number of lifetime arguments: expected 2, found 1
//~| ERROR wrong number of lifetime arguments: expected 2, found 1
//~| ERROR wrong number of lifetime arguments: expected 2, found 1
//~| ERROR wrong number of lifetime arguments: expected 2, found 1
| ^^^^^^^^^^^^^^^^^^^^^
error[E0106]: missing lifetime specifiers
- --> $DIR/missing-lifetime-specifier.rs:32:48
+ --> $DIR/missing-lifetime-specifier.rs:30:48
|
LL | static c: RefCell<HashMap<i32, Vec<Vec<Qux<i32>>>>> = RefCell::new(HashMap::new());
| ^ expected 2 lifetime parameters
| ^^^^^^^^^^^^^^^^^
error[E0106]: missing lifetime specifiers
- --> $DIR/missing-lifetime-specifier.rs:32:48
+ --> $DIR/missing-lifetime-specifier.rs:30:48
|
LL | static c: RefCell<HashMap<i32, Vec<Vec<Qux<i32>>>>> = RefCell::new(HashMap::new());
| ^ expected 2 lifetime parameters
| ^^^^^^^^^^^^^^^^^
error[E0106]: missing lifetime specifier
- --> $DIR/missing-lifetime-specifier.rs:37:44
+ --> $DIR/missing-lifetime-specifier.rs:35:44
|
LL | static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
| ^ expected named lifetime parameter
| ^^^^^^^^
error[E0106]: missing lifetime specifiers
- --> $DIR/missing-lifetime-specifier.rs:37:49
+ --> $DIR/missing-lifetime-specifier.rs:35:49
|
LL | static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
| ^ expected 2 lifetime parameters
| ^^^^^^^^^^^^^^^^^
error[E0106]: missing lifetime specifier
- --> $DIR/missing-lifetime-specifier.rs:37:44
+ --> $DIR/missing-lifetime-specifier.rs:35:44
|
LL | static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
| ^ expected named lifetime parameter
| ^^^^^^^^
error[E0106]: missing lifetime specifiers
- --> $DIR/missing-lifetime-specifier.rs:37:49
+ --> $DIR/missing-lifetime-specifier.rs:35:49
|
LL | static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
| ^ expected 2 lifetime parameters
| ^^^^^^^^^^^^^^^^^
error[E0106]: missing lifetime specifier
- --> $DIR/missing-lifetime-specifier.rs:54:44
+ --> $DIR/missing-lifetime-specifier.rs:50:44
|
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
| ^ expected named lifetime parameter
| ^^^^^^^^
error[E0106]: missing lifetime specifier
- --> $DIR/missing-lifetime-specifier.rs:54:44
+ --> $DIR/missing-lifetime-specifier.rs:50:44
|
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
| ^ expected named lifetime parameter
LL | static f: RefCell<HashMap<i32, Vec<Vec<&'static Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
| ^^^^^^^^
-error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
- --> $DIR/missing-lifetime-specifier.rs:23:45
- |
-LL | static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new());
- | ^^^
-
-error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
- --> $DIR/missing-lifetime-specifier.rs:23:45
- |
-LL | static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new());
- | ^^^
-
-error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
- --> $DIR/missing-lifetime-specifier.rs:37:45
- |
-LL | static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
- | ^^^^^^^^
-
-error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
- --> $DIR/missing-lifetime-specifier.rs:37:45
- |
-LL | static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
- | ^^^^^^^^
-
error[E0107]: wrong number of lifetime arguments: expected 2, found 1
- --> $DIR/missing-lifetime-specifier.rs:47:44
+ --> $DIR/missing-lifetime-specifier.rs:43:44
|
LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell::new(HashMap::new());
| ^^^^^^^^^^^^^^^^^ expected 2 lifetime arguments
error[E0107]: wrong number of lifetime arguments: expected 2, found 1
- --> $DIR/missing-lifetime-specifier.rs:47:44
+ --> $DIR/missing-lifetime-specifier.rs:43:44
|
LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell::new(HashMap::new());
| ^^^^^^^^^^^^^^^^^ expected 2 lifetime arguments
error[E0107]: wrong number of lifetime arguments: expected 2, found 1
- --> $DIR/missing-lifetime-specifier.rs:47:44
+ --> $DIR/missing-lifetime-specifier.rs:43:44
|
LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell::new(HashMap::new());
| ^^^^^^^^^^^^^^^^^ expected 2 lifetime arguments
error[E0107]: wrong number of lifetime arguments: expected 2, found 1
- --> $DIR/missing-lifetime-specifier.rs:47:44
+ --> $DIR/missing-lifetime-specifier.rs:43:44
|
LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell::new(HashMap::new());
| ^^^^^^^^^^^^^^^^^ expected 2 lifetime arguments
error[E0107]: wrong number of lifetime arguments: expected 2, found 1
- --> $DIR/missing-lifetime-specifier.rs:54:45
+ --> $DIR/missing-lifetime-specifier.rs:50:45
|
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
| ^^^^^^^^^^^^^^^^^ expected 2 lifetime arguments
error[E0107]: wrong number of lifetime arguments: expected 2, found 1
- --> $DIR/missing-lifetime-specifier.rs:54:45
+ --> $DIR/missing-lifetime-specifier.rs:50:45
|
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
| ^^^^^^^^^^^^^^^^^ expected 2 lifetime arguments
-error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
- --> $DIR/missing-lifetime-specifier.rs:54:45
- |
-LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
- | ^^^^^^^^^^^^^^^^^
-
error[E0107]: wrong number of lifetime arguments: expected 2, found 1
- --> $DIR/missing-lifetime-specifier.rs:54:45
+ --> $DIR/missing-lifetime-specifier.rs:50:45
|
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
| ^^^^^^^^^^^^^^^^^ expected 2 lifetime arguments
-error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
- --> $DIR/missing-lifetime-specifier.rs:54:45
- |
-LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
- | ^^^^^^^^^^^^^^^^^
-
error[E0107]: wrong number of lifetime arguments: expected 2, found 1
- --> $DIR/missing-lifetime-specifier.rs:54:45
+ --> $DIR/missing-lifetime-specifier.rs:50:45
|
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
| ^^^^^^^^^^^^^^^^^ expected 2 lifetime arguments
-error: aborting due to 28 previous errors
+error: aborting due to 22 previous errors
-Some errors have detailed explanations: E0106, E0107, E0228.
+Some errors have detailed explanations: E0106, E0107.
For more information about an error, try `rustc --explain E0106`.