target: self.target,
mode: "ui",
suite: "rustdoc-ui",
- path: None,
+ path: Some("src/test/rustdoc-ui"),
compare_mode: None,
})
}
state = cur[os_name]
new_state = toolstate.get(tool, '')
if verb == 'regressed':
- if tool == 'rls':
- # Temporary override until
- # https://github.com/rust-lang/rust/issues/60848 is fixed.
- updated = False
- else:
- updated = new_state < state
+ updated = new_state < state
elif verb == 'changed':
updated = new_state != state
else:
///
/// Note: while this type is unstable, the functionality it provides can be
/// accessed through the [free functions in `alloc`](index.html#functions).
+///
+/// [`Alloc`]: trait.Alloc.html
#[unstable(feature = "allocator_api", issue = "32838")]
#[derive(Copy, Clone, Default, Debug)]
pub struct Global;
///
/// See [`GlobalAlloc::alloc`].
///
+/// [`Global`]: struct.Global.html
+/// [`Alloc`]: trait.Alloc.html
+/// [`GlobalAlloc::alloc`]: trait.GlobalAlloc.html#tymethod.alloc
+///
/// # Examples
///
/// ```
/// # Safety
///
/// See [`GlobalAlloc::dealloc`].
+///
+/// [`Global`]: struct.Global.html
+/// [`Alloc`]: trait.Alloc.html
+/// [`GlobalAlloc::dealloc`]: trait.GlobalAlloc.html#tymethod.dealloc
#[stable(feature = "global_alloc", since = "1.28.0")]
#[inline]
pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) {
/// # Safety
///
/// See [`GlobalAlloc::realloc`].
+///
+/// [`Global`]: struct.Global.html
+/// [`Alloc`]: trait.Alloc.html
+/// [`GlobalAlloc::realloc`]: trait.GlobalAlloc.html#method.realloc
#[stable(feature = "global_alloc", since = "1.28.0")]
#[inline]
pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
///
/// See [`GlobalAlloc::alloc_zeroed`].
///
+/// [`Global`]: struct.Global.html
+/// [`Alloc`]: trait.Alloc.html
+/// [`GlobalAlloc::alloc_zeroed`]: trait.GlobalAlloc.html#method.alloc_zeroed
+///
/// # Examples
///
/// ```
/// assert_eq!(heap.pop(), Some(Reverse(5)));
/// assert_eq!(heap.pop(), None);
/// ```
+///
+/// # Time complexity
+///
+/// | [push] | [pop] | [peek]/[peek\_mut] |
+/// |--------|----------|--------------------|
+/// | O(1)~ | O(log n) | O(1) |
+///
+/// The value for `push` is an expected cost; the method documentation gives a
+/// more detailed analysis.
+///
+/// [push]: #method.push
+/// [pop]: #method.pop
+/// [peek]: #method.peek
+/// [peek\_mut]: #method.peek_mut
#[stable(feature = "rust1", since = "1.0.0")]
pub struct BinaryHeap<T> {
data: Vec<T>,
/// }
/// assert_eq!(heap.peek(), Some(&2));
/// ```
+ ///
+ /// # Time complexity
+ ///
+ /// Cost is O(1) in the worst case.
#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
pub fn peek_mut(&mut self) -> Option<PeekMut<'_, T>> {
if self.is_empty() {
/// assert_eq!(heap.pop(), Some(1));
/// assert_eq!(heap.pop(), None);
/// ```
+ ///
+ /// # Time complexity
+ ///
+ /// The worst case cost of `pop` on a heap containing *n* elements is O(log
+ /// n).
#[stable(feature = "rust1", since = "1.0.0")]
pub fn pop(&mut self) -> Option<T> {
self.data.pop().map(|mut item| {
/// assert_eq!(heap.len(), 3);
/// assert_eq!(heap.peek(), Some(&5));
/// ```
+ ///
+ /// # Time complexity
+ ///
+ /// The expected cost of `push`, averaged over every possible ordering of
+ /// the elements being pushed, and over a sufficiently large number of
+ /// pushes, is O(1). This is the most meaningful cost metric when pushing
+ /// elements that are *not* already in any sorted pattern.
+ ///
+ /// The time complexity degrades if elements are pushed in predominantly
+ /// ascending order. In the worst case, elements are pushed in ascending
+ /// sorted order and the amortized cost per push is O(log n) against a heap
+ /// containing *n* elements.
+ ///
+ /// The worst case cost of a *single* call to `push` is O(n). The worst case
+ /// occurs when capacity is exhausted and needs a resize. The resize cost
+ /// has been amortized in the previous figures.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn push(&mut self, item: T) {
let old_len = self.len();
/// assert_eq!(heap.peek(), Some(&5));
///
/// ```
+ ///
+ /// # Time complexity
+ ///
+ /// Cost is O(1) in the worst case.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn peek(&self) -> Option<&T> {
self.data.get(0)
/// # Examples
///
/// ```
- /// #![feature(vecdeque_rotate)]
- ///
/// use std::collections::VecDeque;
///
/// let mut buf: VecDeque<_> = (0..10).collect();
/// }
/// assert_eq!(buf, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
/// ```
- #[unstable(feature = "vecdeque_rotate", issue = "56686")]
+ #[stable(feature = "vecdeque_rotate", since = "1.36.0")]
pub fn rotate_left(&mut self, mid: usize) {
assert!(mid <= self.len());
let k = self.len() - mid;
/// # Examples
///
/// ```
- /// #![feature(vecdeque_rotate)]
- ///
/// use std::collections::VecDeque;
///
/// let mut buf: VecDeque<_> = (0..10).collect();
/// }
/// assert_eq!(buf, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
/// ```
- #[unstable(feature = "vecdeque_rotate", issue = "56686")]
+ #[stable(feature = "vecdeque_rotate", since = "1.36.0")]
pub fn rotate_right(&mut self, k: usize) {
assert!(k <= self.len());
let mid = self.len() - k;
#![feature(rustc_const_unstable)]
#![feature(const_vec_new)]
#![feature(slice_partition_dedup)]
-#![feature(maybe_uninit, maybe_uninit_slice, maybe_uninit_array)]
+#![feature(maybe_uninit_extra, maybe_uninit_slice, maybe_uninit_array)]
#![feature(alloc_layout_extra)]
#![feature(try_trait)]
#![feature(iter_nth_back)]
#[test]
// Only tests the simple function definition with respect to intersection
fn test_is_disjoint() {
- let one = [1].into_iter().collect::<BTreeSet<_>>();
- let two = [2].into_iter().collect::<BTreeSet<_>>();
+ let one = [1].iter().collect::<BTreeSet<_>>();
+ let two = [2].iter().collect::<BTreeSet<_>>();
assert!(one.is_disjoint(&two));
}
#![feature(repeat_generic_slice)]
#![feature(try_reserve)]
#![feature(unboxed_closures)]
-#![feature(vecdeque_rotate)]
#![deny(rust_2018_idioms)]
use std::hash::{Hash, Hasher};
/// [`Layout::from_size_align`](#method.from_size_align).
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[inline]
- pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self {
+ pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self {
Layout { size_: size, align_: NonZeroUsize::new_unchecked(align) }
}
/// this allocator,
///
/// * `layout` must be the same layout that was used
- /// to allocated that block of memory,
+ /// to allocate that block of memory,
#[stable(feature = "global_alloc", since = "1.28.0")]
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout);
/// * `ptr` must be currently allocated via this allocator,
///
/// * `layout` must be the same layout that was used
- /// to allocated that block of memory,
+ /// to allocate that block of memory,
///
/// * `new_size` must be greater than zero.
///
///
/// # Examples
///
-/// Basic usage with `i32`:
+/// Basic usage with `f64`:
///
/// ```
/// let x = 42.0; // 42.0 is '4.2e1' in scientific notation
///
/// # Examples
///
-/// Basic usage with `f32`:
+/// Basic usage with `f64`:
///
/// ```
/// let x = 42.0; // 42.0 is '4.2E1' in scientific notation
///
/// ```
/// let a = [0, 1, 2, 3, 4, 5];
- /// let mut iter = a.into_iter().step_by(2);
+ /// let mut iter = a.iter().step_by(2);
///
/// assert_eq!(iter.next(), Some(&0));
/// assert_eq!(iter.next(), Some(&2));
/// ```
/// let a = [1, 2, 3];
///
- /// let mut iter = a.into_iter().map(|x| 2 * x);
+ /// let mut iter = a.iter().map(|x| 2 * x);
///
/// assert_eq!(iter.next(), Some(2));
/// assert_eq!(iter.next(), Some(4));
/// ```
/// let a = [0i32, 1, 2];
///
- /// let mut iter = a.into_iter().filter(|x| x.is_positive());
+ /// let mut iter = a.iter().filter(|x| x.is_positive());
///
/// assert_eq!(iter.next(), Some(&1));
/// assert_eq!(iter.next(), Some(&2));
/// ```
/// let a = [0, 1, 2];
///
- /// let mut iter = a.into_iter().filter(|x| **x > 1); // need two *s!
+ /// let mut iter = a.iter().filter(|x| **x > 1); // need two *s!
///
/// assert_eq!(iter.next(), Some(&2));
/// assert_eq!(iter.next(), None);
/// ```
/// let a = [0, 1, 2];
///
- /// let mut iter = a.into_iter().filter(|&x| *x > 1); // both & and *
+ /// let mut iter = a.iter().filter(|&x| *x > 1); // both & and *
///
/// assert_eq!(iter.next(), Some(&2));
/// assert_eq!(iter.next(), None);
/// ```
/// let a = [0, 1, 2];
///
- /// let mut iter = a.into_iter().filter(|&&x| x > 1); // two &s
+ /// let mut iter = a.iter().filter(|&&x| x > 1); // two &s
///
/// assert_eq!(iter.next(), Some(&2));
/// assert_eq!(iter.next(), None);
/// ```
/// let a = [-1i32, 0, 1];
///
- /// let mut iter = a.into_iter().skip_while(|x| x.is_negative());
+ /// let mut iter = a.iter().skip_while(|x| x.is_negative());
///
/// assert_eq!(iter.next(), Some(&0));
/// assert_eq!(iter.next(), Some(&1));
/// ```
/// let a = [-1, 0, 1];
///
- /// let mut iter = a.into_iter().skip_while(|x| **x < 0); // need two *s!
+ /// let mut iter = a.iter().skip_while(|x| **x < 0); // need two *s!
///
/// assert_eq!(iter.next(), Some(&0));
/// assert_eq!(iter.next(), Some(&1));
/// ```
/// let a = [-1, 0, 1, -2];
///
- /// let mut iter = a.into_iter().skip_while(|x| **x < 0);
+ /// let mut iter = a.iter().skip_while(|x| **x < 0);
///
/// assert_eq!(iter.next(), Some(&0));
/// assert_eq!(iter.next(), Some(&1));
/// ```
/// let a = [-1i32, 0, 1];
///
- /// let mut iter = a.into_iter().take_while(|x| x.is_negative());
+ /// let mut iter = a.iter().take_while(|x| x.is_negative());
///
/// assert_eq!(iter.next(), Some(&-1));
/// assert_eq!(iter.next(), None);
/// ```
/// let a = [-1, 0, 1];
///
- /// let mut iter = a.into_iter().take_while(|x| **x < 0); // need two *s!
+ /// let mut iter = a.iter().take_while(|x| **x < 0); // need two *s!
///
/// assert_eq!(iter.next(), Some(&-1));
/// assert_eq!(iter.next(), None);
/// ```
/// let a = [-1, 0, 1, -2];
///
- /// let mut iter = a.into_iter().take_while(|x| **x < 0);
+ /// let mut iter = a.iter().take_while(|x| **x < 0);
///
/// assert_eq!(iter.next(), Some(&-1));
///
///
/// ```
/// let a = [1, 2, 3, 4];
- /// let mut iter = a.into_iter();
+ /// let mut iter = a.iter();
///
/// let result: Vec<i32> = iter.by_ref()
/// .take_while(|n| **n != 3)
/// ```
/// let a = [1, 2, 3];
///
- /// let iter = a.into_iter();
+ /// let iter = a.iter();
///
/// let sum: i32 = iter.take(5).fold(0, |acc, i| acc + i );
///
/// // let's try that again
/// let a = [1, 2, 3];
///
- /// let mut iter = a.into_iter();
+ /// let mut iter = a.iter();
///
/// // instead, we add in a .by_ref()
/// let sum: i32 = iter.by_ref().take(2).fold(0, |acc, i| acc + i );
/// let a = [1, 2, 3];
///
/// let (even, odd): (Vec<i32>, Vec<i32>) = a
- /// .into_iter()
+ /// .iter()
/// .partition(|&n| n % 2 == 0);
///
/// assert_eq!(even, vec![2]);
#![feature(structural_match)]
#![feature(abi_unadjusted)]
#![feature(adx_target_feature)]
-#![feature(maybe_uninit, maybe_uninit_slice, maybe_uninit_array)]
+#![feature(maybe_uninit_slice, maybe_uninit_array)]
#![feature(external_doc)]
#[prelude_import]
/// The practical use cases for `forget` are rather specialized and mainly come
/// up in unsafe or FFI code.
///
-/// ## Use case 1
-///
-/// You have created an uninitialized value using [`mem::uninitialized`][uninit].
-/// You must either initialize or `forget` it on every computation path before
-/// Rust drops it automatically, like at the end of a scope or after a panic.
-/// Running the destructor on an uninitialized value would be [undefined behavior][ub].
-///
-/// ```
-/// use std::mem;
-/// use std::ptr;
-///
-/// # let some_condition = false;
-/// unsafe {
-/// let mut uninit_vec: Vec<u32> = mem::uninitialized();
-///
-/// if some_condition {
-/// // Initialize the variable.
-/// ptr::write(&mut uninit_vec, Vec::new());
-/// } else {
-/// // Forget the uninitialized value so its destructor doesn't run.
-/// mem::forget(uninit_vec);
-/// }
-/// }
-/// ```
-///
-/// ## Use case 2
-///
-/// You have duplicated the bytes making up a value, without doing a proper
-/// [`Clone`][clone]. You need the value's destructor to run only once,
-/// because a double `free` is undefined behavior.
-///
-/// An example is a possible implementation of [`mem::swap`][swap]:
-///
-/// ```
-/// use std::mem;
-/// use std::ptr;
-///
-/// # #[allow(dead_code)]
-/// fn swap<T>(x: &mut T, y: &mut T) {
-/// unsafe {
-/// // Give ourselves some scratch space to work with
-/// let mut t: T = mem::uninitialized();
-///
-/// // Perform the swap, `&mut` pointers never alias
-/// ptr::copy_nonoverlapping(&*x, &mut t, 1);
-/// ptr::copy_nonoverlapping(&*y, x, 1);
-/// ptr::copy_nonoverlapping(&t, y, 1);
-///
-/// // y and t now point to the same thing, but we need to completely
-/// // forget `t` because we do not want to run the destructor for `T`
-/// // on its value, which is still owned somewhere outside this function.
-/// mem::forget(t);
-/// }
-/// }
-/// ```
-///
/// [drop]: fn.drop.html
/// [uninit]: fn.uninitialized.html
/// [clone]: ../clone/trait.Clone.html
/// Creates a value whose bytes are all zero.
///
-/// This has the same effect as allocating space with
-/// [`mem::uninitialized`][uninit] and then zeroing it out. It is useful for
-/// FFI sometimes, but should generally be avoided.
+/// This has the same effect as [`MaybeUninit::zeroed().assume_init()`][zeroed].
+/// It is useful for FFI sometimes, but should generally be avoided.
///
/// There is no guarantee that an all-zero byte-pattern represents a valid value of
-/// some type `T`. If `T` has a destructor and the value is destroyed (due to
-/// a panic or the end of a scope) before being initialized, then the destructor
-/// will run on zeroed data, likely leading to [undefined behavior][ub].
-///
-/// See also the documentation for [`mem::uninitialized`][uninit], which has
-/// many of the same caveats.
+/// some type `T`. For example, the all-zero byte-pattern is not a valid value
+/// for reference types (`&T` and `&mut T`). Using `zeroed` on such types
+/// causes immediate [undefined behavior][ub] because [the Rust compiler assumes][inv]
+/// that there always is a valid value in a variable it considers initialized.
///
-/// [uninit]: fn.uninitialized.html
+/// [zeroed]: union.MaybeUninit.html#method.zeroed
/// [ub]: ../../reference/behavior-considered-undefined.html
+/// [inv]: union.MaybeUninit.html#initialization-invariant
///
/// # Examples
///
+/// Correct usage of this function: initializing an integer with zero.
+///
/// ```
/// use std::mem;
///
/// let x: i32 = unsafe { mem::zeroed() };
/// assert_eq!(0, x);
/// ```
+///
+/// *Incorrect* usage of this function: initializing a reference with zero.
+///
+/// ```no_run
+/// use std::mem;
+///
+/// let _x: &i32 = unsafe { mem::zeroed() }; // Undefined behavior!
+/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn zeroed<T>() -> T {
/// Bypasses Rust's normal memory-initialization checks by pretending to
/// produce a value of type `T`, while doing nothing at all.
///
-/// **This is incredibly dangerous and should not be done lightly. Deeply
-/// consider initializing your memory with a default value instead.**
-///
-/// This is useful for FFI functions and initializing arrays sometimes,
-/// but should generally be avoided.
-///
-/// # Undefined behavior
-///
-/// It is [undefined behavior][ub] to read uninitialized memory, even just an
-/// uninitialized boolean. For instance, if you branch on the value of such
-/// a boolean, your program may take one, both, or neither of the branches.
-///
-/// Writing to the uninitialized value is similarly dangerous. Rust believes the
-/// value is initialized, and will therefore try to [`Drop`] the uninitialized
-/// value and its fields if you try to overwrite it in a normal manner. The only way
-/// to safely initialize an uninitialized value is with [`ptr::write`][write],
-/// [`ptr::copy`][copy], or [`ptr::copy_nonoverlapping`][copy_no].
-///
-/// If the value does implement [`Drop`], it must be initialized before
-/// it goes out of scope (and therefore would be dropped). Note that this
-/// includes a `panic` occurring and unwinding the stack suddenly.
+/// **This functon is deprecated.** Use [`MaybeUninit<T>`] instead.
///
-/// If you partially initialize an array, you may need to use
-/// [`ptr::drop_in_place`][drop_in_place] to remove the elements you have fully
-/// initialized followed by [`mem::forget`][mem_forget] to prevent drop running
-/// on the array. If a partially allocated array is dropped this will lead to
-/// undefined behaviour.
-///
-/// # Examples
-///
-/// Here's how to safely initialize an array of [`Vec`]s.
-///
-/// ```
-/// use std::mem;
-/// use std::ptr;
-///
-/// // Only declare the array. This safely leaves it
-/// // uninitialized in a way that Rust will track for us.
-/// // However we can't initialize it element-by-element
-/// // safely, and we can't use the `[value; 1000]`
-/// // constructor because it only works with `Copy` data.
-/// let mut data: [Vec<u32>; 1000];
-///
-/// unsafe {
-/// // So we need to do this to initialize it.
-/// data = mem::uninitialized();
-///
-/// // DANGER ZONE: if anything panics or otherwise
-/// // incorrectly reads the array here, we will have
-/// // Undefined Behavior.
-///
-/// // It's ok to mutably iterate the data, since this
-/// // doesn't involve reading it at all.
-/// // (ptr and len are statically known for arrays)
-/// for elem in &mut data[..] {
-/// // *elem = Vec::new() would try to drop the
-/// // uninitialized memory at `elem` -- bad!
-/// //
-/// // Vec::new doesn't allocate or do really
-/// // anything. It's only safe to call here
-/// // because we know it won't panic.
-/// ptr::write(elem, Vec::new());
-/// }
-///
-/// // SAFE ZONE: everything is initialized.
-/// }
-///
-/// println!("{:?}", &data[0]);
-/// ```
-///
-/// This example emphasizes exactly how delicate and dangerous using `mem::uninitialized`
-/// can be. Note that the [`vec!`] macro *does* let you initialize every element with a
-/// value that is only [`Clone`], so the following is semantically equivalent and
-/// vastly less dangerous, as long as you can live with an extra heap
-/// allocation:
-///
-/// ```
-/// let data: Vec<Vec<u32>> = vec![Vec::new(); 1000];
-/// println!("{:?}", &data[0]);
-/// ```
-///
-/// This example shows how to handle partially initialized arrays, which could
-/// be found in low-level datastructures.
-///
-/// ```
-/// use std::mem;
-/// use std::ptr;
-///
-/// // Count the number of elements we have assigned.
-/// let mut data_len: usize = 0;
-/// let mut data: [String; 1000];
-///
-/// unsafe {
-/// data = mem::uninitialized();
-///
-/// for elem in &mut data[0..500] {
-/// ptr::write(elem, String::from("hello"));
-/// data_len += 1;
-/// }
-///
-/// // For each item in the array, drop if we allocated it.
-/// for i in &mut data[0..data_len] {
-/// ptr::drop_in_place(i);
-/// }
-/// }
-/// // Forget the data. If this is allowed to drop, you may see a crash such as:
-/// // 'mem_uninit_test(2457,0x7fffb55dd380) malloc: *** error for object
-/// // 0x7ff3b8402920: pointer being freed was not allocated'
-/// mem::forget(data);
-/// ```
+/// The reason for deprecation is that the function basically cannot be used
+/// correctly: [the Rust compiler assumes][inv] that values are properly initialized.
+/// As a consequence, calling e.g. `mem::uninitialized::<bool>()` causes immediate
+/// undefined behavior for returning a `bool` that is not definitely either `true`
+/// or `false`. Worse, truly uninitialized memory like what gets returned here
+/// is special in that the compiler knows that it does not have a fixed value.
+/// This makes it undefined behavior to have uninitialized data in a variable even
+/// if that variable has an integer type.
+/// (Notice that the rules around uninitialized integers are not finalized yet, but
+/// until they are, it is advisable to avoid them.)
///
-/// [`Vec`]: ../../std/vec/struct.Vec.html
-/// [`vec!`]: ../../std/macro.vec.html
-/// [`Clone`]: ../../std/clone/trait.Clone.html
-/// [ub]: ../../reference/behavior-considered-undefined.html
-/// [write]: ../ptr/fn.write.html
-/// [drop_in_place]: ../ptr/fn.drop_in_place.html
-/// [mem_zeroed]: fn.zeroed.html
-/// [mem_forget]: fn.forget.html
-/// [copy]: ../intrinsics/fn.copy.html
-/// [copy_no]: ../intrinsics/fn.copy_nonoverlapping.html
-/// [`Drop`]: ../ops/trait.Drop.html
+/// [`MaybeUninit<T>`]: union.MaybeUninit.html
+/// [inv]: union.MaybeUninit.html#initialization-invariant
#[inline]
-#[rustc_deprecated(since = "2.0.0", reason = "use `mem::MaybeUninit::uninit` instead")]
+#[rustc_deprecated(since = "1.40.0", reason = "use `mem::MaybeUninit` instead")]
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn uninitialized<T>() -> T {
intrinsics::panic_if_uninhabited::<T>();
}
}
-// FIXME: Reference `MaybeUninit` from these docs, once that is stable.
/// A wrapper to inhibit compiler from automatically calling `T`’s destructor.
///
/// This wrapper is 0-cost.
/// As a consequence, it has *no effect* on the assumptions that the compiler makes
/// about all values being initialized at their type. In particular, initializing
/// a `ManuallyDrop<&mut T>` with [`mem::zeroed`] is undefined behavior.
+/// If you need to handle uninitialized data, use [`MaybeUninit<T>`] instead.
///
/// # Examples
///
/// ```
///
/// [`mem::zeroed`]: fn.zeroed.html
+/// [`MaybeUninit<T>`]: union.MaybeUninit.html
#[stable(feature = "manually_drop", since = "1.20.0")]
#[lang = "manually_drop"]
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
}
}
-/// A wrapper to construct uninitialized instances of `T`.
+/// A wrapper type to construct uninitialized instances of `T`.
+///
+/// # Initialization invariant
///
/// The compiler, in general, assumes that variables are properly initialized
/// at their respective type. For example, a variable of reference type must
/// be aligned and non-NULL. This is an invariant that must *always* be upheld,
/// even in unsafe code. As a consequence, zero-initializing a variable of reference
-/// type causes instantaneous undefined behavior, no matter whether that reference
+/// type causes instantaneous [undefined behavior][ub], no matter whether that reference
/// ever gets used to access memory:
///
/// ```rust,no_run
-/// #![feature(maybe_uninit)]
/// use std::mem::{self, MaybeUninit};
///
/// let x: &i32 = unsafe { mem::zeroed() }; // undefined behavior!
/// always be `true` or `false`. Hence, creating an uninitialized `bool` is undefined behavior:
///
/// ```rust,no_run
-/// #![feature(maybe_uninit)]
/// use std::mem::{self, MaybeUninit};
///
/// let b: bool = unsafe { mem::uninitialized() }; // undefined behavior!
/// Moreover, uninitialized memory is special in that the compiler knows that
/// it does not have a fixed value. This makes it undefined behavior to have
/// uninitialized data in a variable even if that variable has an integer type,
-/// which otherwise can hold any bit pattern:
+/// which otherwise can hold any *fixed* bit pattern:
///
/// ```rust,no_run
-/// #![feature(maybe_uninit)]
/// use std::mem::{self, MaybeUninit};
///
/// let x: i32 = unsafe { mem::uninitialized() }; // undefined behavior!
/// (Notice that the rules around uninitialized integers are not finalized yet, but
/// until they are, it is advisable to avoid them.)
///
+/// On top of that, remember that most types have additional invariants beyond merely
+/// being considered initialized at the type level. For example, a `1`-initialized [`Vec<T>`]
+/// is considered initialized because the only requirement the compiler knows about it
+/// is that the data pointer must be non-null. Creating such a `Vec<T>` does not cause
+/// *immediate* undefined behavior, but will cause undefined behavior with most
+/// safe operations (including dropping it).
+///
+/// [`Vec<T>`]: ../../std/vec/struct.Vec.html
+///
+/// # Examples
+///
/// `MaybeUninit<T>` serves to enable unsafe code to deal with uninitialized data.
/// It is a signal to the compiler indicating that the data here might *not*
/// be initialized:
///
/// ```rust
-/// #![feature(maybe_uninit)]
/// use std::mem::MaybeUninit;
///
/// // Create an explicitly uninitialized reference. The compiler knows that data inside
/// // a `MaybeUninit<T>` may be invalid, and hence this is not UB:
/// let mut x = MaybeUninit::<&i32>::uninit();
/// // Set it to a valid value.
-/// x.write(&0);
+/// unsafe { x.as_mut_ptr().write(&0); }
/// // Extract the initialized data -- this is only allowed *after* properly
/// // initializing `x`!
/// let x = unsafe { x.assume_init() };
/// ```
///
/// The compiler then knows to not make any incorrect assumptions or optimizations on this code.
-//
-// FIXME before stabilizing, explain how to initialize a struct field-by-field.
+///
+/// ## out-pointers
+///
+/// You can use `MaybeUninit<T>` to implement "out-pointers": instead of returning data
+/// from a function, pass it a pointer to some (uninitialized) memory to put the
+/// result into. This can be useful when it is important for the caller to control
+/// how the memory the result is stored in gets allocated, and you want to avoid
+/// unnecessary moves.
+///
+/// ```
+/// use std::mem::MaybeUninit;
+///
+/// unsafe fn make_vec(out: *mut Vec<i32>) {
+/// // `write` does not drop the old contents, which is important.
+/// out.write(vec![1, 2, 3]);
+/// }
+///
+/// let mut v: MaybeUninit<Vec<i32>> = MaybeUninit::uninit();
+/// unsafe { make_vec(v.as_mut_ptr()); }
+/// // Now we know `v` is initialized! This also makes sure the vector gets
+/// // properly dropped.
+/// let v = unsafe { v.assume_init() };
+/// assert_eq!(&v, &[1, 2, 3]);
+/// ```
+///
+/// ## Initializing an array element-by-element
+///
+/// `MaybeUninit<T>` can be used to initialize a large array element-by-element:
+///
+/// ```
+/// use std::mem::{self, MaybeUninit};
+/// use std::ptr;
+///
+/// let data = {
+/// // Create an uninitialized array of `MaybeUninit`. The `assume_init` is
+/// // safe because the type we are claiming to have initialized here is a
+/// // bunch of `MaybeUninit`s, which do not require initialization.
+/// let mut data: [MaybeUninit<Vec<u32>>; 1000] = unsafe {
+/// MaybeUninit::uninit().assume_init()
+/// };
+///
+/// // Dropping a `MaybeUninit` does nothing, so if there is a panic during this loop,
+/// // we have a memory leak, but there is no memory safety issue.
+/// for elem in &mut data[..] {
+/// unsafe { ptr::write(elem.as_mut_ptr(), vec![42]); }
+/// }
+///
+/// // Everything is initialized. Transmute the array to the
+/// // initialized type.
+/// unsafe { mem::transmute::<_, [Vec<u32>; 1000]>(data) }
+/// };
+///
+/// assert_eq!(&data[0], &[42]);
+/// ```
+///
+/// You can also work with partially initialized arrays, which could
+/// be found in low-level datastructures.
+///
+/// ```
+/// use std::mem::MaybeUninit;
+/// use std::ptr;
+///
+/// // Create an uninitialized array of `MaybeUninit`. The `assume_init` is
+/// // safe because the type we are claiming to have initialized here is a
+/// // bunch of `MaybeUninit`s, which do not require initialization.
+/// let mut data: [MaybeUninit<String>; 1000] = unsafe { MaybeUninit::uninit().assume_init() };
+/// // Count the number of elements we have assigned.
+/// let mut data_len: usize = 0;
+///
+/// for elem in &mut data[0..500] {
+/// unsafe { ptr::write(elem.as_mut_ptr(), String::from("hello")); }
+/// data_len += 1;
+/// }
+///
+/// // For each item in the array, drop if we allocated it.
+/// for elem in &mut data[0..data_len] {
+/// unsafe { ptr::drop_in_place(elem.as_mut_ptr()); }
+/// }
+/// ```
+///
+/// ## Initializing a struct field-by-field
+///
+/// There is currently no supported way to create a raw pointer or reference
+/// to a field of a struct inside `MaybeUninit<Struct>`. That means it is not possible
+/// to create a struct by calling `MaybeUninit::uninit::<Struct>()` and then writing
+/// to its fields.
+///
+/// [ub]: ../../reference/behavior-considered-undefined.html
+///
+/// # Layout
+///
+/// `MaybeUninit<T>` is guaranteed to have the same size and alignment as `T`:
+///
+/// ```rust
+/// use std::mem::{MaybeUninit, size_of, align_of};
+/// assert_eq!(size_of::<MaybeUninit<u64>>(), size_of::<u64>());
+/// assert_eq!(align_of::<MaybeUninit<u64>>(), align_of::<u64>());
+/// ```
+///
+/// However remember that a type *containing* a `MaybeUninit<T>` is not necessarily the same
+/// layout; Rust does not in general guarantee that the fields of a `Foo<T>` have the same order as
+/// a `Foo<U>` even if `T` and `U` have the same size and alignment. Furthermore because any bit
+/// value is valid for a `MaybeUninit<T>` the compiler can't apply non-zero/niche-filling
+/// optimizations, potentially resulting in a larger size:
+///
+/// ```rust
+/// # use std::mem::{MaybeUninit, size_of, align_of};
+/// assert_eq!(size_of::<Option<bool>>(), 1);
+/// assert_eq!(size_of::<Option<MaybeUninit<bool>>>(), 2);
+/// ```
#[allow(missing_debug_implementations)]
-#[unstable(feature = "maybe_uninit", issue = "53491")]
+#[stable(feature = "maybe_uninit", since = "1.36.0")]
#[derive(Copy)]
-// NOTE: after stabilizing `MaybeUninit`, proceed to deprecate `mem::uninitialized`.
pub union MaybeUninit<T> {
uninit: (),
value: ManuallyDrop<T>,
}
-#[unstable(feature = "maybe_uninit", issue = "53491")]
+#[stable(feature = "maybe_uninit", since = "1.36.0")]
impl<T: Copy> Clone for MaybeUninit<T> {
#[inline(always)]
fn clone(&self) -> Self {
impl<T> MaybeUninit<T> {
/// Creates a new `MaybeUninit<T>` initialized with the given value.
+ /// It is safe to call [`assume_init`] on the return value of this function.
///
/// 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.
- #[unstable(feature = "maybe_uninit", issue = "53491")]
+ ///
+ /// [`assume_init`]: #method.assume_init
+ #[stable(feature = "maybe_uninit", since = "1.36.0")]
#[inline(always)]
pub const fn new(val: T) -> MaybeUninit<T> {
MaybeUninit { value: ManuallyDrop::new(val) }
///
/// 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.
- #[unstable(feature = "maybe_uninit", issue = "53491")]
+ ///
+ /// See the [type-level documentation][type] for some examples.
+ ///
+ /// [type]: union.MaybeUninit.html
+ #[stable(feature = "maybe_uninit", since = "1.36.0")]
#[inline(always)]
pub const fn uninit() -> MaybeUninit<T> {
MaybeUninit { uninit: () }
/// fields of the struct can hold the bit-pattern 0 as a valid value.
///
/// ```rust
- /// #![feature(maybe_uninit)]
/// use std::mem::MaybeUninit;
///
/// let x = MaybeUninit::<(u8, bool)>::zeroed();
/// cannot hold 0 as a valid value.
///
/// ```rust,no_run
- /// #![feature(maybe_uninit)]
/// use std::mem::MaybeUninit;
///
/// enum NotZero { One = 1, Two = 2 };
/// // Inside a pair, we create a `NotZero` that does not have a valid discriminant.
/// // This is undefined behavior.
/// ```
- #[unstable(feature = "maybe_uninit", issue = "53491")]
+ #[stable(feature = "maybe_uninit", since = "1.36.0")]
#[inline]
pub fn zeroed() -> MaybeUninit<T> {
let mut u = MaybeUninit::<T>::uninit();
/// without dropping it, so be careful not to use this twice unless you want to
/// skip running the destructor. For your convenience, this also returns a mutable
/// reference to the (now safely initialized) contents of `self`.
- #[unstable(feature = "maybe_uninit", issue = "53491")]
+ #[unstable(feature = "maybe_uninit_extra", issue = "53491")]
#[inline(always)]
pub fn write(&mut self, val: T) -> &mut T {
unsafe {
/// Gets a pointer to the contained value. Reading from this pointer or turning it
/// into a reference is undefined behavior unless the `MaybeUninit<T>` is initialized.
+ /// Writing to memory that this pointer (non-transitively) points to is undefined behavior
+ /// (except inside an `UnsafeCell<T>`).
///
/// # Examples
///
/// Correct usage of this method:
///
/// ```rust
- /// #![feature(maybe_uninit)]
/// use std::mem::MaybeUninit;
///
/// let mut x = MaybeUninit::<Vec<u32>>::uninit();
/// *Incorrect* usage of this method:
///
/// ```rust,no_run
- /// #![feature(maybe_uninit)]
/// use std::mem::MaybeUninit;
///
/// let x = MaybeUninit::<Vec<u32>>::uninit();
///
/// (Notice that the rules around references to uninitialized data are not finalized yet, but
/// until they are, it is advisable to avoid them.)
- #[unstable(feature = "maybe_uninit", issue = "53491")]
+ #[stable(feature = "maybe_uninit", since = "1.36.0")]
#[inline(always)]
pub fn as_ptr(&self) -> *const T {
unsafe { &*self.value as *const T }
/// Correct usage of this method:
///
/// ```rust
- /// #![feature(maybe_uninit)]
/// use std::mem::MaybeUninit;
///
/// let mut x = MaybeUninit::<Vec<u32>>::uninit();
/// *Incorrect* usage of this method:
///
/// ```rust,no_run
- /// #![feature(maybe_uninit)]
/// use std::mem::MaybeUninit;
///
/// let mut x = MaybeUninit::<Vec<u32>>::uninit();
///
/// (Notice that the rules around references to uninitialized data are not finalized yet, but
/// until they are, it is advisable to avoid them.)
- #[unstable(feature = "maybe_uninit", issue = "53491")]
+ #[stable(feature = "maybe_uninit", since = "1.36.0")]
#[inline(always)]
pub fn as_mut_ptr(&mut self) -> *mut T {
unsafe { &mut *self.value as *mut T }
/// # Safety
///
/// It is up to the caller to guarantee that the `MaybeUninit<T>` really is in an initialized
- /// state. Calling this when the content is not yet fully initialized causes undefined
- /// behavior.
+ /// state. Calling this when the content is not yet fully initialized causes immediate undefined
+ /// behavior. The [type-level documentation][inv] contains more information about
+ /// this initialization invariant.
+ ///
+ /// [inv]: #initialization-invariant
///
/// # Examples
///
/// Correct usage of this method:
///
/// ```rust
- /// #![feature(maybe_uninit)]
/// use std::mem::MaybeUninit;
///
/// let mut x = MaybeUninit::<bool>::uninit();
/// *Incorrect* usage of this method:
///
/// ```rust,no_run
- /// #![feature(maybe_uninit)]
/// use std::mem::MaybeUninit;
///
/// let x = MaybeUninit::<Vec<u32>>::uninit();
/// let x_init = unsafe { x.assume_init() };
/// // `x` had not been initialized yet, so this last line caused undefined behavior.
/// ```
- #[unstable(feature = "maybe_uninit", issue = "53491")]
+ #[stable(feature = "maybe_uninit", since = "1.36.0")]
#[inline(always)]
pub unsafe fn assume_init(self) -> T {
intrinsics::panic_if_uninhabited::<T>();
///
/// It is up to the caller to guarantee that the `MaybeUninit<T>` really is in an initialized
/// state. Calling this when the content is not yet fully initialized causes undefined
- /// behavior.
+ /// behavior. The [type-level documentation][inv] contains more information about
+ /// this initialization invariant.
///
/// Moreover, this leaves a copy of the same data behind in the `MaybeUninit<T>`. When using
/// multiple copies of the data (by calling `read` multiple times, or first
/// calling `read` and then [`assume_init`]), it is your responsibility
/// to ensure that that data may indeed be duplicated.
///
+ /// [inv]: #initialization-invariant
/// [`assume_init`]: #method.assume_init
///
/// # Examples
/// Correct usage of this method:
///
/// ```rust
- /// #![feature(maybe_uninit)]
+ /// #![feature(maybe_uninit_extra)]
/// use std::mem::MaybeUninit;
///
/// let mut x = MaybeUninit::<u32>::uninit();
/// *Incorrect* usage of this method:
///
/// ```rust,no_run
- /// #![feature(maybe_uninit)]
+ /// #![feature(maybe_uninit_extra)]
/// use std::mem::MaybeUninit;
///
/// let mut x = MaybeUninit::<Option<Vec<u32>>>::uninit();
/// // We now created two copies of the same vector, leading to a double-free when
/// // they both get dropped!
/// ```
- #[unstable(feature = "maybe_uninit", issue = "53491")]
+ #[unstable(feature = "maybe_uninit_extra", issue = "53491")]
#[inline(always)]
pub unsafe fn read(&self) -> T {
intrinsics::panic_if_uninhabited::<T>();
/// location first:
/// ```
/// use std::ptr;
-/// use std::mem;
+/// use std::mem::{self, MaybeUninit};
///
/// unsafe fn drop_after_copy<T>(to_drop: *mut T) {
-/// let mut copy: T = mem::uninitialized();
-/// ptr::copy(to_drop, &mut copy, 1);
-/// drop(copy);
+/// let mut copy: MaybeUninit<T> = MaybeUninit::uninit();
+/// ptr::copy(to_drop, copy.as_mut_ptr(), 1);
+/// drop(copy.assume_init());
/// }
///
/// #[repr(packed, C)]
/// to not be elided or reordered by the compiler across other volatile
/// operations.
///
-/// Memory accessed with `read_volatile` or [`write_volatile`] should not be
-/// accessed with non-volatile operations.
-///
/// [`write_volatile`]: ./fn.write_volatile.html
///
/// # Notes
///
/// * `src` must be properly aligned.
///
-/// Like [`read`], `read_unaligned` creates a bitwise copy of `T`, regardless of
+/// Like [`read`], `read_volatile` creates a bitwise copy of `T`, regardless of
/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the returned
/// value and the value at `*src` can [violate memory safety][read-ownership].
/// However, storing non-[`Copy`] types in volatile memory is almost certainly
/// to not be elided or reordered by the compiler across other volatile
/// operations.
///
-/// Memory accessed with [`read_volatile`] or `write_volatile` should not be
-/// accessed with non-volatile operations.
-///
/// `write_volatile` does not drop the contents of `dst`. This is safe, but it
/// could leak allocations or resources, so care should be taken not to overwrite
/// an object that should be dropped.
///
/// It consists of a data pointer and a [virtual function pointer table (vtable)][vtable] that
/// customizes the behavior of the `RawWaker`.
+///
+/// [`Waker`]: struct.Waker.html
#[derive(PartialEq, Debug)]
#[stable(feature = "futures_api", since = "1.36.0")]
pub struct RawWaker {
/// pointer of a properly constructed [`RawWaker`] object from inside the
/// [`RawWaker`] implementation. Calling one of the contained functions using
/// any other `data` pointer will cause undefined behavior.
+///
+/// [`RawWaker`]: struct.RawWaker.html
#[stable(feature = "futures_api", since = "1.36.0")]
#[derive(PartialEq, Copy, Clone, Debug)]
pub struct RawWakerVTable {
/// required for this additional instance of a [`RawWaker`] and associated
/// task. Calling `wake` on the resulting [`RawWaker`] should result in a wakeup
/// of the same task that would have been awoken by the original [`RawWaker`].
+ ///
+ /// [`Waker`]: struct.Waker.html
+ /// [`RawWaker`]: struct.RawWaker.html
clone: unsafe fn(*const ()) -> RawWaker,
/// This function will be called when `wake` is called on the [`Waker`].
/// The implementation of this function must make sure to release any
/// resources that are associated with this instance of a [`RawWaker`] and
/// associated task.
+ ///
+ /// [`Waker`]: struct.Waker.html
+ /// [`RawWaker`]: struct.RawWaker.html
wake: unsafe fn(*const ()),
/// This function will be called when `wake_by_ref` is called on the [`Waker`].
///
/// This function is similar to `wake`, but must not consume the provided data
/// pointer.
+ ///
+ /// [`Waker`]: struct.Waker.html
+ /// [`RawWaker`]: struct.RawWaker.html
wake_by_ref: unsafe fn(*const ()),
/// This function gets called when a [`RawWaker`] gets dropped.
/// The implementation of this function must make sure to release any
/// resources that are associated with this instance of a [`RawWaker`] and
/// associated task.
+ ///
+ /// [`RawWaker`]: struct.RawWaker.html
drop: unsafe fn(*const ()),
}
/// The implementation of this function must make sure to release any
/// resources that are associated with this instance of a [`RawWaker`] and
/// associated task.
+ ///
+ /// [`Waker`]: struct.Waker.html
+ /// [`RawWaker`]: struct.RawWaker.html
#[rustc_promotable]
#[cfg_attr(stage0, unstable(feature = "futures_api_const_fn_ptr", issue = "50547"))]
#[cfg_attr(not(stage0), stable(feature = "futures_api", since = "1.36.0"))]
/// executor-specific wakeup behavior.
///
/// Implements [`Clone`], [`Send`], and [`Sync`].
+///
+/// [`RawWaker`]: struct.RawWaker.html
#[repr(transparent)]
#[stable(feature = "futures_api", since = "1.36.0")]
pub struct Waker {
/// The behavior of the returned `Waker` is undefined if the contract defined
/// in [`RawWaker`]'s and [`RawWakerVTable`]'s documentation is not upheld.
/// Therefore this method is unsafe.
+ ///
+ /// [`RawWaker`]: struct.RawWaker.html
+ /// [`RawWakerVTable`]: struct.RawWakerVTable.html
#[inline]
#[stable(feature = "futures_api", since = "1.36.0")]
pub unsafe fn from_raw(waker: RawWaker) -> Waker {
--- /dev/null
+use core::alloc::Layout;
+
+#[test]
+fn const_unchecked_layout() {
+ const SIZE: usize = 0x2000;
+ const ALIGN: usize = 0x1000;
+ const LAYOUT: Layout = unsafe { Layout::from_size_align_unchecked(SIZE, ALIGN) };
+ assert_eq!(LAYOUT.size(), SIZE);
+ assert_eq!(LAYOUT.align(), ALIGN);
+}
#![feature(slice_partition_dedup)]
#![feature(copy_within)]
#![feature(int_error_matching)]
+#![feature(const_fn)]
#![warn(rust_2018_idioms)]
extern crate test;
+mod alloc;
mod any;
mod array;
mod ascii;
impl serialize::UseSpecializedEncodable for CrateNum {}
impl serialize::UseSpecializedDecodable for CrateNum {}
-/// A DefIndex is an index into the hir-map for a crate, identifying a
-/// particular definition. It should really be considered an interned
-/// shorthand for a particular DefPath.
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
-pub struct DefIndex(u32);
-
-/// The crate root is always assigned index 0 by the AST Map code,
-/// thanks to `NodeCollector::new`.
-pub const CRATE_DEF_INDEX: DefIndex = DefIndex(0);
+newtype_index! {
+ /// A DefIndex is an index into the hir-map for a crate, identifying a
+ /// particular definition. It should really be considered an interned
+ /// shorthand for a particular DefPath.
+ pub struct DefIndex {
+ DEBUG_FORMAT = "DefIndex({})",
-impl fmt::Debug for DefIndex {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "DefIndex({})", self.as_array_index())
+ /// The crate root is always assigned index 0 by the AST Map code,
+ /// thanks to `NodeCollector::new`.
+ const CRATE_DEF_INDEX = 0,
}
}
impl DefIndex {
- /// Converts this DefIndex into a zero-based array index.
- #[inline]
- pub fn as_array_index(&self) -> usize {
- self.0 as usize
- }
-
- #[inline]
- pub fn from_array_index(i: usize) -> DefIndex {
- DefIndex(i as u32)
- }
-
// Proc macros from a proc-macro crate have a kind of virtual DefIndex. This
// function maps the index of the macro within the crate (which is also the
// index of the macro in the CrateMetadata::proc_macros array) to the
// DefIndex for proc macros start from FIRST_FREE_DEF_INDEX,
// because the first FIRST_FREE_DEF_INDEX indexes are reserved
// for internal use.
- let def_index = DefIndex::from_array_index(
+ let def_index = DefIndex::from(
proc_macro_index.checked_add(FIRST_FREE_DEF_INDEX)
.expect("integer overflow adding `proc_macro_index`"));
assert!(def_index != CRATE_DEF_INDEX);
// This function is the reverse of from_proc_macro_index() above.
pub fn to_proc_macro_index(self: DefIndex) -> usize {
- self.as_array_index().checked_sub(FIRST_FREE_DEF_INDEX)
+ self.index().checked_sub(FIRST_FREE_DEF_INDEX)
.unwrap_or_else(|| {
bug!("using local index {:?} as proc-macro index", self)
})
}
-
- pub fn from_raw_u32(x: u32) -> DefIndex {
- DefIndex(x)
- }
-
- pub fn as_raw_u32(&self) -> u32 {
- self.0
- }
}
impl serialize::UseSpecializedEncodable for DefIndex {}
impl fmt::Debug for DefId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "DefId({}:{}", self.krate, self.index.as_array_index())?;
+ write!(f, "DefId({}:{}", self.krate, self.index.index())?;
ty::tls::with_opt(|opt_tcx| {
if let Some(tcx) = opt_tcx {
self.sess.diagnostic()
}
- fn str_to_ident(&self, s: &'static str) -> Ident {
- Ident::with_empty_ctxt(Symbol::gensym(s))
- }
-
fn with_anonymous_lifetime_mode<R>(
&mut self,
anonymous_lifetime_mode: AnonymousLifetimeMode,
);
head.span = desugared_span;
- let iter = self.str_to_ident("iter");
+ let iter = Ident::with_empty_ctxt(sym::iter);
- let next_ident = self.str_to_ident("__next");
+ let next_ident = Ident::with_empty_ctxt(sym::__next);
let (next_pat, next_pat_hid) = self.pat_ident_binding_mode(
desugared_span,
next_ident,
hir::BindingAnnotation::Mutable,
);
- // `::std::option::Option::Some(val) => next = val`
+ // `::std::option::Option::Some(val) => __next = val`
let pat_arm = {
- let val_ident = self.str_to_ident("val");
+ let val_ident = Ident::with_empty_ctxt(sym::val);
let (val_pat, val_pat_hid) = self.pat_ident(pat.span, val_ident);
let val_expr = P(self.expr_ident(pat.span, val_ident, val_pat_hid));
let next_expr = P(self.expr_ident(pat.span, next_ident, next_pat_hid));
let unstable_span = self.sess.source_map().mark_span_with_reason(
CompilerDesugaringKind::QuestionMark,
e.span,
- Some(vec![
- Symbol::intern("try_trait")
- ].into()),
+ Some(vec![sym::try_trait].into()),
);
let try_span = self.sess.source_map().end_point(e.span);
let try_span = self.sess.source_map().mark_span_with_reason(
CompilerDesugaringKind::QuestionMark,
try_span,
- Some(vec![
- Symbol::intern("try_trait")
- ].into()),
+ Some(vec![sym::try_trait].into()),
);
// `Try::into_result(<expr>)`
// `allow(unreachable_code)`
let allow = {
let allow_ident = Ident::with_empty_ctxt(sym::allow).with_span_pos(e.span);
- let uc_ident = Ident::from_str("unreachable_code").with_span_pos(e.span);
+ let uc_ident = Ident::with_empty_ctxt(sym::unreachable_code)
+ .with_span_pos(e.span);
let uc_nested = attr::mk_nested_word_item(uc_ident);
attr::mk_list_item(e.span, allow_ident, vec![uc_nested])
};
// `Ok(val) => #[allow(unreachable_code)] val,`
let ok_arm = {
- let val_ident = self.str_to_ident("val");
+ let val_ident = Ident::with_empty_ctxt(sym::val);
let (val_pat, val_pat_nid) = self.pat_ident(e.span, val_ident);
let val_expr = P(self.expr_ident_with_attrs(
e.span,
// `Err(err) => #[allow(unreachable_code)]
// return Try::from_error(From::from(err)),`
let err_arm = {
- let err_ident = self.str_to_ident("err");
+ let err_ident = Ident::with_empty_ctxt(sym::err);
let (err_local, err_local_nid) = self.pat_ident(try_span, err_ident);
let from_expr = {
let from_path = &[sym::convert, sym::From, sym::from];
// match ::std::future::poll_with_tls_context(unsafe {
// ::std::pin::Pin::new_unchecked(&mut pinned)
// }) {
- // ::std::task::Poll::Ready(x) => break x,
+ // ::std::task::Poll::Ready(result) => break result,
// ::std::task::Poll::Pending => {},
// }
// yield ();
let gen_future_span = self.sess.source_map().mark_span_with_reason(
CompilerDesugaringKind::Await,
await_span,
- Some(vec![Symbol::intern("gen_future")].into()),
+ Some(vec![sym::gen_future].into()),
);
// let mut pinned = <expr>;
let expr = P(self.lower_expr(expr));
- let pinned_ident = self.str_to_ident("pinned");
+ let pinned_ident = Ident::with_empty_ctxt(sym::pinned);
let (pinned_pat, pinned_pat_hid) = self.pat_ident_binding_mode(
span,
pinned_ident,
))
};
- // `::std::task::Poll::Ready(x) => break x`
+ // `::std::task::Poll::Ready(result) => break result`
let loop_node_id = self.sess.next_node_id();
let loop_hir_id = self.lower_node_id(loop_node_id);
let ready_arm = {
- let x_ident = self.str_to_ident("x");
+ let x_ident = Ident::with_empty_ctxt(sym::result);
let (x_pat, x_pat_hid) = self.pat_ident(span, x_ident);
let x_expr = P(self.expr_ident(span, x_ident, x_pat_hid));
let ready_pat = self.pat_std_enum(
fn insert_entry(&mut self, id: HirId, entry: Entry<'hir>) {
debug!("hir_map: {:?} => {:?}", id, entry);
- let local_map = &mut self.map[id.owner.as_array_index()];
+ let local_map = &mut self.map[id.owner.index()];
let i = id.local_id.as_u32() as usize;
if local_map.is_none() {
*local_map = Some(IndexVec::with_capacity(i + 1));
def_path_hash: DefPathHash)
-> DefIndex {
let index = {
- let index = DefIndex::from_array_index(self.index_to_key.len());
+ let index = DefIndex::from(self.index_to_key.len());
debug!("DefPathTable::insert() - {:?} <-> {:?}", key, index);
self.index_to_key.push(key);
index
}
pub fn next_id(&self) -> DefIndex {
- DefIndex::from_array_index(self.index_to_key.len())
+ DefIndex::from(self.index_to_key.len())
}
#[inline(always)]
pub fn def_key(&self, index: DefIndex) -> DefKey {
- self.index_to_key[index.as_array_index()].clone()
+ self.index_to_key[index.index()].clone()
}
#[inline(always)]
pub fn def_path_hash(&self, index: DefIndex) -> DefPathHash {
- let ret = self.def_path_hashes[index.as_array_index()];
+ let ret = self.def_path_hashes[index.index()];
debug!("def_path_hash({:?}) = {:?}", index, ret);
return ret
}
.map(|(index, &hash)| {
let def_id = DefId {
krate: cnum,
- index: DefIndex::from_array_index(index),
+ index: DefIndex::from(index),
};
(hash, def_id)
})
#[inline]
pub fn as_local_node_id(&self, def_id: DefId) -> Option<ast::NodeId> {
if def_id.krate == LOCAL_CRATE {
- let node_id = self.def_index_to_node[def_id.index.as_array_index()];
+ let node_id = self.def_index_to_node[def_id.index.index()];
if node_id != ast::DUMMY_NODE_ID {
return Some(node_id);
}
#[inline]
pub fn def_index_to_hir_id(&self, def_index: DefIndex) -> hir::HirId {
- let node_id = self.def_index_to_node[def_index.as_array_index()];
+ let node_id = self.def_index_to_node[def_index.index()];
self.node_to_hir_id[node_id]
}
// Create the definition.
let index = self.table.allocate(key, def_path_hash);
- assert_eq!(index.as_array_index(), self.def_index_to_node.len());
+ assert_eq!(index.index(), self.def_index_to_node.len());
self.def_index_to_node.push(node_id);
// Some things for which we allocate DefIndices don't correspond to
.position(|k| *k == def_key)
.unwrap();
- DefIndex::from_array_index(index)
+ DefIndex::from(index)
}
fn name(&self) -> Symbol {
impl<'hir> Map<'hir> {
#[inline]
fn lookup(&self, id: HirId) -> Option<&Entry<'hir>> {
- let local_map = self.map.get(id.owner.as_array_index())?;
+ let local_map = self.map.get(id.owner.index())?;
local_map.as_ref()?.get(id.local_id)?.as_ref()
}
local_map.iter_enumerated().filter_map(move |(i, entry)| entry.map(move |_| {
// Reconstruct the HirId based on the 3 indices we used to find it
HirId {
- owner: DefIndex::from_array_index(array_index),
+ owner: DefIndex::from(array_index),
local_id: i,
}
}))
own_counts
}
- pub fn get_named(&self, name: &InternedString) -> Option<&GenericParam> {
+ pub fn get_named(&self, name: InternedString) -> Option<&GenericParam> {
for param in &self.params {
- if *name == param.name.ident().as_interned_str() {
+ if name == param.name.ident().as_interned_str() {
return Some(param);
}
}
// `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(target_arch = "x86_64")]
-static_assert!(MEM_SIZE_OF_EXPR: std::mem::size_of::<Expr>() == 72);
+static_assert_size!(Expr, 72);
impl Expr {
pub fn precedence(&self) -> ExprPrecedence {
let mut sp = cm.def_span(self.hir().span_by_hir_id(node));
if let Some(param) = self.hir()
.get_generics(scope)
- .and_then(|generics| generics.get_named(&br.name))
+ .and_then(|generics| generics.get_named(br.name))
{
sp = param.span;
}
(format!("the lifetime {} as defined on", br.name), sp)
}
ty::ReFree(ty::FreeRegion {
- bound_region: ty::BoundRegion::BrNamed(_, ref name),
+ bound_region: ty::BoundRegion::BrNamed(_, name),
..
}) => {
let mut sp = cm.def_span(self.hir().span_by_hir_id(node));
if let Some(param) = self.hir()
.get_generics(scope)
- .and_then(|generics| generics.get_named(&name))
+ .and_then(|generics| generics.get_named(name))
{
sp = param.span;
}
) -> Option<AnonymousArgInfo<'_>> {
let (id, bound_region) = match *anon_region {
ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region),
- ty::ReEarlyBound(ref ebr) => (
+ ty::ReEarlyBound(ebr) => (
self.tcx().parent(ebr.def_id).unwrap(),
ty::BoundRegion::BrNamed(ebr.def_id, ebr.name),
),
}
let requested_node = env::var("RUST_REGION_GRAPH_NODE")
- .ok().and_then(|s| s.parse().map(DefIndex::from_raw_u32).ok());
+ .ok().and_then(|s| s.parse().map(DefIndex::from_u32).ok());
if requested_node.is_some() && requested_node != Some(context.index) {
return;
let mut new_str = String::new();
for c in output_template.chars() {
if c == '%' {
- new_str.push_str(&context.index.as_raw_u32().to_string());
+ new_str.push_str(&context.index.as_u32().to_string());
} else {
new_str.push(c);
}
// This shouldn't ever be needed, but just in case:
Ok(vec![match trait_ref {
- Some(trait_ref) => Symbol::intern(&format!("{:?}", trait_ref)).as_str(),
- None => Symbol::intern(&format!("<{}>", self_ty)).as_str(),
+ Some(trait_ref) => LocalInternedString::intern(&format!("{:?}", trait_ref)),
+ None => LocalInternedString::intern(&format!("<{}>", self_ty)),
}])
}
// This shouldn't ever be needed, but just in case:
path.push(match trait_ref {
Some(trait_ref) => {
- Symbol::intern(&format!("<impl {} for {}>", trait_ref, self_ty)).as_str()
+ LocalInternedString::intern(&format!("<impl {} for {}>", trait_ref,
+ self_ty))
},
- None => Symbol::intern(&format!("<impl {}>", self_ty)).as_str(),
+ None => LocalInternedString::intern(&format!("<impl {}>", self_ty)),
});
Ok(path)
let push = builder.levels.push(&krate.attrs);
builder.levels.register_id(hir::CRATE_HIR_ID);
+ for macro_def in &krate.exported_macros {
+ builder.levels.register_id(macro_def.hir_id);
+ }
intravisit::walk_crate(&mut builder, krate);
builder.levels.pop(push);
impl_stable_hash_for!(struct crate::middle::region::FirstStatementIndex { private });
// compilation error if size of `ScopeData` is not the same as a `u32`
-static_assert!(ASSERT_SCOPE_DATA: mem::size_of::<ScopeData>() == 4);
+static_assert_size!(ScopeData, 4);
impl Scope {
/// Returns a item-local ID associated with this scope.
pub tag: Tag,
}
-static_assert!(POINTER_SIZE: ::std::mem::size_of::<Pointer>() == 16);
+static_assert_size!(Pointer, 16);
/// Produces a `Pointer` which points to the beginning of the Allocation
impl From<AllocId> for Pointer {
}
#[cfg(target_arch = "x86_64")]
-static_assert!(CONST_SIZE: ::std::mem::size_of::<ConstValue<'static>>() == 40);
+static_assert_size!(ConstValue<'_>, 40);
impl<'tcx> ConstValue<'tcx> {
#[inline]
}
#[cfg(target_arch = "x86_64")]
-static_assert!(SCALAR_SIZE: ::std::mem::size_of::<Scalar>() == 24);
+static_assert_size!(Scalar, 24);
impl<Tag> fmt::Display for Scalar<Tag> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// `Statement` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(target_arch = "x86_64")]
-static_assert!(MEM_SIZE_OF_STATEMENT: mem::size_of::<Statement<'_>>() == 56);
+static_assert_size!(Statement<'_>, 56);
impl<'tcx> Statement<'tcx> {
/// Changes a statement to a nop. This is both faster than deleting instructions and avoids
/// and the index is a local.
pub type PlaceElem<'tcx> = ProjectionElem<Local, Ty<'tcx>>;
-// at least on 64 bit systems, `PlaceElem` should not be larger than two pointers
-static_assert!(PROJECTION_ELEM_IS_2_PTRS_LARGE:
- mem::size_of::<PlaceElem<'_>>() <= 16
-);
+// At least on 64 bit systems, `PlaceElem` should not be larger than two pointers.
+#[cfg(target_arch = "x86_64")]
+static_assert_size!(PlaceElem<'_>, 16);
/// Alias for projections as they appear in `UserTypeProjection`, where we
/// need neither the `V` parameter for `Index` nor the `T` for `Field`.
use crate::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
use crate::hir::HirId;
-use syntax::symbol::{Symbol, InternedString};
+use syntax::symbol::InternedString;
use crate::ty::{Instance, TyCtxt};
use crate::util::nodemap::FxHashMap;
use rustc_data_structures::base_n;
cgu_name
} else {
let cgu_name = &cgu_name.as_str()[..];
- Symbol::intern(&CodegenUnit::mangle_name(cgu_name)).as_interned_str()
+ InternedString::intern(&CodegenUnit::mangle_name(cgu_name))
}
}
write!(cgu_name, ".{}", special_suffix).unwrap();
}
- Symbol::intern(&cgu_name[..]).as_interned_str()
+ InternedString::intern(&cgu_name[..])
}
}
pub variant_index: Option<VariantIdx>,
}
-static_assert!(PLACE_TY_IS_3_PTRS_LARGE:
- mem::size_of::<PlaceTy<'_>>() <= 24
-);
+// At least on 64 bit systems, `PlaceTy` should not be larger than two or three pointers.
+#[cfg(target_arch = "x86_64")]
+static_assert_size!(PlaceTy<'_>, 16);
impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> {
pub fn from_ty(ty: Ty<'tcx>) -> PlaceTy<'tcx> {
.map(|s| &s == "?")
.unwrap_or(false);
let is_from = format!("{}", trait_ref).starts_with("std::convert::From<");
- let message = if is_try && is_from {
- Some(format!(
+ let (message, note) = if is_try && is_from {
+ (Some(format!(
"`?` couldn't convert the error to `{}`",
trait_ref.self_ty(),
+ )), Some(
+ "the question mark operation (`?`) implicitly performs a \
+ conversion on the error value using the `From` trait".to_owned()
))
} else {
- message
+ (message, note)
};
let mut err = struct_span_err!(
use crate::ty::subst::{Subst, InternalSubsts};
use std::borrow::Cow;
use std::iter::{self};
-use syntax::ast::{self, Name};
+use syntax::ast::{self};
+use syntax::symbol::InternedString;
use syntax_pos::Span;
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
// are implemented
let unsized_self_ty: Ty<'tcx> = self.mk_ty_param(
::std::u32::MAX,
- Name::intern("RustaceansAreAwesome").as_interned_str(),
+ InternedString::intern("RustaceansAreAwesome"),
);
// `Receiver[Self => U]`
// negated `CrateNum` (so remote definitions are visited first) and then
// by a flattened version of the `DefIndex`.
trait_impls.sort_unstable_by_key(|def_id| {
- (-(def_id.krate.as_u32() as i64), def_id.index.as_array_index())
+ (-(def_id.krate.as_u32() as i64), def_id.index.index())
});
for impl_def_id in trait_impls {
}
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
- use syntax::symbol::Symbol;
-
match t.sty {
ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => {
self.types.insert(
bound_ty.var.as_u32(),
match bound_ty.kind {
ty::BoundTyKind::Param(name) => name,
- ty::BoundTyKind::Anon => Symbol::intern(
- &format!("^{}", bound_ty.var.as_u32())
- ).as_interned_str(),
+ ty::BoundTyKind::Anon =>
+ InternedString::intern(&format!("^{}", bound_ty.var.as_u32()),
+ ),
}
);
}
}
fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
- use syntax::symbol::Symbol;
-
match r {
ty::ReLateBound(index, br) if *index == self.binder_index => {
match br {
}
ty::BoundRegion::BrAnon(var) => {
- self.regions.insert(Symbol::intern(
- &format!("'^{}", var)
- ).as_interned_str());
+ self.regions.insert(InternedString::intern(&format!("'^{}", var)));
}
_ => (),
// `TyS` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(target_arch = "x86_64")]
-static_assert!(MEM_SIZE_OF_TY_S: ::std::mem::size_of::<TyS<'_>>() == 32);
+static_assert_size!(TyS<'_>, 32);
impl<'tcx> Ord for TyS<'tcx> {
fn cmp(&self, other: &TyS<'tcx>) -> Ordering {
impl SymbolName {
pub fn new(name: &str) -> SymbolName {
SymbolName {
- name: Symbol::intern(name).as_interned_str()
+ name: InternedString::intern(name)
}
}
use crate::ty::{self, DefIdTree, ParamConst, Ty, TyCtxt, TypeFoldable};
use crate::ty::subst::{Kind, Subst, UnpackedKind};
use crate::mir::interpret::ConstValue;
-use syntax::symbol::{keywords, Symbol};
-
use rustc_target::spec::abi::Abi;
-use syntax::symbol::InternedString;
+use syntax::symbol::{keywords, InternedString};
use std::cell::Cell;
use std::fmt::{self, Write as _};
{
fn name_by_region_index(index: usize) -> InternedString {
match index {
- 0 => Symbol::intern("'r"),
- 1 => Symbol::intern("'s"),
- i => Symbol::intern(&format!("'t{}", i-2)),
- }.as_interned_str()
+ 0 => InternedString::intern("'r"),
+ 1 => InternedString::intern("'s"),
+ i => InternedString::intern(&format!("'t{}", i-2)),
+ }
}
// Replace any anonymous late-bound regions with named
use crate::ty::{self, Ty, TyCtxt, AdtSizedConstraint};
use crate::ty::util::NeedsDrop;
-use syntax::symbol::Symbol;
+use syntax::symbol::InternedString;
pub(super) trait Value<'tcx>: Sized {
fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self;
impl<'tcx> Value<'tcx> for ty::SymbolName {
fn from_cycle_error<'a>(_: TyCtxt<'a, 'tcx, 'tcx>) -> Self {
- ty::SymbolName { name: Symbol::intern("<error>").as_interned_str() }
+ ty::SymbolName { name: InternedString::intern("<error>") }
}
}
// `TyKind` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(target_arch = "x86_64")]
-static_assert!(MEM_SIZE_OF_TY_KIND: ::std::mem::size_of::<TyKind<'_>>() == 24);
+static_assert_size!(TyKind<'_>, 24);
/// A closure can be modeled as a struct that looks like:
///
// FIXME(#50125): Ignoring `Self` with `index != 0` might lead to weird behavior elsewhere,
// but this should only be possible when using `-Z continue-parse-after-error` like
// `compile-fail/issue-36638.rs`.
- self.name == keywords::SelfUpper.name().as_str() && self.index == 0
+ self.name.as_symbol() == keywords::SelfUpper.name() && self.index == 0
}
}
}
#[cfg(target_arch = "x86_64")]
-static_assert!(CONST_SIZE: ::std::mem::size_of::<Const<'static>>() == 48);
+static_assert_size!(Const<'_>, 48);
impl<'tcx> Const<'tcx> {
#[inline]
return
}
// The x86 ABI seems to require that leading underscores are added to symbol
- // names, so we need an extra underscore on 32-bit. There's also a leading
+ // names, so we need an extra underscore on x86. There's also a leading
// '\x01' here which disables LLVM's symbol mangling (e.g., no extra
// underscores added in front).
- let prefix = if cgcx.target_pointer_width == "32" {
+ let prefix = if cgcx.target_arch == "x86" {
"\x01__imp__"
} else {
"\x01__imp_"
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
use rustc::hir;
use syntax::ast::{self, FloatTy};
-use syntax::symbol::Symbol;
+use syntax::symbol::LocalInternedString;
use rustc_codegen_ssa::traits::*;
}
"type_name" => {
let tp_ty = substs.type_at(0);
- let ty_name = Symbol::intern(&tp_ty.to_string()).as_str();
+ let ty_name = LocalInternedString::intern(&tp_ty.to_string());
self.const_str_slice(ty_name)
}
"type_id" => {
pub tm_factory: TargetMachineFactory<B>,
pub msvc_imps_needed: bool,
pub target_pointer_width: String,
+ pub target_arch: String,
pub debuginfo: config::DebugInfo,
// Number of cgus excluding the allocator/metadata modules
total_cgus,
msvc_imps_needed: msvc_imps_needed(tcx),
target_pointer_width: tcx.sess.target.target.target_pointer_width.clone(),
+ target_arch: tcx.sess.target.target.arch.clone(),
debuginfo: tcx.sess.opts.debuginfo,
assembler_cmd,
};
use std::borrow::Cow;
-use syntax::symbol::Symbol;
+use syntax::symbol::LocalInternedString;
use syntax_pos::Pos;
use super::{FunctionCx, LocalRef};
// Get the location information.
let loc = bx.sess().source_map().lookup_char_pos(span.lo());
- let filename = Symbol::intern(&loc.file.name.to_string()).as_str();
+ let filename = LocalInternedString::intern(&loc.file.name.to_string());
let line = bx.const_u32(loc.line as u32);
let col = bx.const_u32(loc.col.to_usize() as u32 + 1);
}
_ => {
let str = msg.description();
- let msg_str = Symbol::intern(str).as_str();
+ let msg_str = LocalInternedString::intern(str);
let msg_file_line_col = bx.static_panic_msg(
Some(msg_str),
filename,
let layout = bx.layout_of(ty);
if layout.abi.is_uninhabited() {
let loc = bx.sess().source_map().lookup_char_pos(span.lo());
- let filename = Symbol::intern(&loc.file.name.to_string()).as_str();
+ let filename = LocalInternedString::intern(&loc.file.name.to_string());
let line = bx.const_u32(loc.line as u32);
let col = bx.const_u32(loc.col.to_usize() as u32 + 1);
"Attempted to instantiate uninhabited type {}",
ty
);
- let msg_str = Symbol::intern(&str).as_str();
+ let msg_str = LocalInternedString::intern(&str);
let msg_file_line_col = bx.static_panic_msg(
Some(msg_str),
filename,
use rustc_mir::monomorphize::item::{InstantiationMode, MonoItem, MonoItemExt};
use rustc_mir::monomorphize::Instance;
-use syntax_pos::symbol::{Symbol, InternedString};
+use syntax_pos::symbol::InternedString;
use log::debug;
if def_id.is_local() {
if tcx.plugin_registrar_fn(LOCAL_CRATE) == Some(def_id) {
let disambiguator = tcx.sess.local_crate_disambiguator();
- return Symbol::intern(&tcx.sess.generate_plugin_registrar_symbol(disambiguator))
- .as_interned_str();
+ return
+ InternedString::intern(&tcx.sess.generate_plugin_registrar_symbol(disambiguator));
}
if tcx.proc_macro_decls_static(LOCAL_CRATE) == Some(def_id) {
let disambiguator = tcx.sess.local_crate_disambiguator();
- return Symbol::intern(&tcx.sess.generate_proc_macro_decls_symbol(disambiguator))
- .as_interned_str();
+ return
+ InternedString::intern(&tcx.sess.generate_proc_macro_decls_symbol(disambiguator));
}
}
let _ = printer.write_str("{{vtable-shim}}");
}
- Symbol::intern(&printer.path.finish(hash)).as_interned_str()
+ InternedString::intern(&printer.path.finish(hash))
}
// Follow C++ namespace-mangling style, see
static $name: () = [()][!($test: bool) as usize];
}
}
+
+/// Type size assertion. The first argument is a type and the second argument is its expected size.
+#[macro_export]
+#[allow_internal_unstable(underscore_const_names)]
+macro_rules! static_assert_size {
+ ($ty:ty, $size:expr) => {
+ const _: [(); $size] = [(); ::std::mem::size_of::<$ty>()];
+ }
+}
/// extended to 64 bits if needed.
pub struct StableHasher<W> {
state: SipHasher128,
- bytes_hashed: u64,
width: PhantomData<W>,
}
pub fn new() -> Self {
StableHasher {
state: SipHasher128::new_with_keys(0, 0),
- bytes_hashed: 0,
width: PhantomData,
}
}
pub fn finalize(self) -> (u64, u64) {
self.state.finish128()
}
-
- #[inline]
- pub fn bytes_hashed(&self) -> u64 {
- self.bytes_hashed
- }
}
impl<W> Hasher for StableHasher<W> {
#[inline]
fn write(&mut self, bytes: &[u8]) {
self.state.write(bytes);
- self.bytes_hashed += bytes.len() as u64;
}
#[inline]
fn write_u8(&mut self, i: u8) {
self.state.write_u8(i);
- self.bytes_hashed += 1;
}
#[inline]
fn write_u16(&mut self, i: u16) {
self.state.write_u16(i.to_le());
- self.bytes_hashed += 2;
}
#[inline]
fn write_u32(&mut self, i: u32) {
self.state.write_u32(i.to_le());
- self.bytes_hashed += 4;
}
#[inline]
fn write_u64(&mut self, i: u64) {
self.state.write_u64(i.to_le());
- self.bytes_hashed += 8;
}
#[inline]
fn write_u128(&mut self, i: u128) {
self.state.write_u128(i.to_le());
- self.bytes_hashed += 16;
}
#[inline]
// platforms. This is important for symbol hashes when cross compiling,
// for example.
self.state.write_u64((i as u64).to_le());
- self.bytes_hashed += 8;
}
#[inline]
fn write_i8(&mut self, i: i8) {
self.state.write_i8(i);
- self.bytes_hashed += 1;
}
#[inline]
fn write_i16(&mut self, i: i16) {
self.state.write_i16(i.to_le());
- self.bytes_hashed += 2;
}
#[inline]
fn write_i32(&mut self, i: i32) {
self.state.write_i32(i.to_le());
- self.bytes_hashed += 4;
}
#[inline]
fn write_i64(&mut self, i: i64) {
self.state.write_i64(i.to_le());
- self.bytes_hashed += 8;
}
#[inline]
fn write_i128(&mut self, i: i128) {
self.state.write_i128(i.to_le());
- self.bytes_hashed += 16;
}
#[inline]
// platforms. This is important for symbol hashes when cross compiling,
// for example.
self.state.write_i64((i as i64).to_le());
- self.bytes_hashed += 8;
}
}
/// Something that implements `HashStable<CTX>` can be hashed in a way that is
/// stable across multiple compilation sessions.
+///
+/// Note that `HashStable` imposes rather more strict requirements than usual
+/// hash functions:
+///
+/// - Stable hashes are sometimes used as identifiers. Therefore they must
+/// conform to the corresponding `PartialEq` implementations:
+///
+/// - `x == y` implies `hash_stable(x) == hash_stable(y)`, and
+/// - `x != y` implies `hash_stable(x) != hash_stable(y)`.
+///
+/// That second condition is usually not required for hash functions
+/// (e.g. `Hash`). In practice this means that `hash_stable` must feed any
+/// information into the hasher that a `PartialEq` comparision takes into
+/// account. See [#49300](https://github.com/rust-lang/rust/issues/49300)
+/// for an example where violating this invariant has caused trouble in the
+/// past.
+///
+/// - `hash_stable()` must be independent of the current
+/// compilation session. E.g. they must not hash memory addresses or other
+/// things that are "randomly" assigned per compilation session.
+///
+/// - `hash_stable()` must be independent of the host architecture. The
+/// `StableHasher` takes care of endianness and `isize`/`usize` platform
+/// differences.
pub trait HashStable<CTX> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut CTX,
// have to be user friendly.
let name = format!(
"hir_id_{}_{}",
- hir_id.owner.as_array_index(),
+ hir_id.owner.index(),
hir_id.local_id.index(),
);
let lcfg = LabelledCFG {
impl<'a> LoadError<'a> {
fn report(self) -> ! {
match self {
- LoadError::LocatorError(mut locate_ctxt) => locate_ctxt.report_errs(),
+ LoadError::LocatorError(locate_ctxt) => locate_ctxt.report_errs(),
}
}
}
span,
ident,
crate_name: name,
- hash: hash.map(|a| &*a),
- extra_filename: extra_filename,
+ hash,
+ extra_filename,
filesearch: self.sess.target_filesearch(path_kind),
target: &self.sess.target.target,
triple: self.sess.opts.target_triple.clone(),
impl<'a, 'tcx> SpecializedDecoder<DefIndex> for DecodeContext<'a, 'tcx> {
#[inline]
fn specialized_decode(&mut self) -> Result<DefIndex, Self::Error> {
- Ok(DefIndex::from_raw_u32(self.read_u32()?))
+ Ok(DefIndex::from_u32(self.read_u32()?))
}
}
impl<'a, 'tcx> SpecializedEncoder<DefIndex> for EncodeContext<'a, 'tcx> {
#[inline]
fn specialized_encode(&mut self, def_index: &DefIndex) -> Result<(), Self::Error> {
- self.emit_u32(def_index.as_raw_u32())
+ self.emit_u32(def_index.as_u32())
}
}
pub fn record_index(&mut self, item: DefIndex, entry: Lazy<Entry<'_>>) {
assert!(entry.position < (u32::MAX as usize));
let position = entry.position as u32;
- let array_index = item.as_array_index();
+ let array_index = item.index();
let positions = &mut self.positions;
assert!(u32::read_from_bytes_at(positions, array_index) == u32::MAX,
def_index,
self.len);
- let position = u32::read_from_bytes_at(bytes, 1 + def_index.as_array_index());
+ let position = u32::read_from_bytes_at(bytes, 1 + def_index.index());
if position == u32::MAX {
debug!("Index::lookup: position=u32::MAX");
None
}
}
- pub fn report_errs(&mut self) -> ! {
+ pub fn report_errs(self) -> ! {
let add = match self.root {
&None => String::new(),
&Some(ref r) => format!(" which `{}` depends on", r.ident),
let mut inflated = Vec::new();
match DeflateDecoder::new(compressed_bytes).read_to_end(&mut inflated) {
Ok(_) => {
- let buf = unsafe { OwningRef::new_assert_stable_address(inflated) };
- rustc_erase_owner!(buf.map_owner_box())
+ rustc_erase_owner!(OwningRef::new(inflated).map_owner_box())
}
Err(_) => {
return Err(format!("failed to decompress metadata: {}", filename.display()));
use rustc::ty::{self, RegionKind, RegionVid, Ty, TyCtxt};
use rustc::ty::print::RegionHighlightMode;
use rustc_errors::DiagnosticBuilder;
-use syntax::ast::Name;
use syntax::symbol::keywords;
use syntax_pos::Span;
use syntax_pos::symbol::InternedString;
}
#[allow(dead_code)]
- crate fn name(&self) -> &InternedString {
- &self.name
+ crate fn name(&self) -> InternedString {
+ self.name
}
crate fn highlight_region_name(
match error_region {
ty::ReEarlyBound(ebr) => {
if ebr.has_name() {
- let span = self.get_named_span(tcx, error_region, &ebr.name);
+ let span = self.get_named_span(tcx, error_region, ebr.name);
Some(RegionName {
name: ebr.name,
source: RegionNameSource::NamedEarlyBoundRegion(span)
ty::ReFree(free_region) => match free_region.bound_region {
ty::BoundRegion::BrNamed(_, name) => {
- let span = self.get_named_span(tcx, error_region, &name);
+ let span = self.get_named_span(tcx, error_region, name);
Some(RegionName {
name,
source: RegionNameSource::NamedFreeRegion(span),
&self,
tcx: TyCtxt<'_, '_, 'tcx>,
error_region: &RegionKind,
- name: &InternedString,
+ name: InternedString,
) -> Span {
let scope = error_region.free_region_binding_scope(tcx);
let node = tcx.hir().as_local_hir_id(scope).unwrap_or(hir::DUMMY_HIR_ID);
let c = *counter;
*counter += 1;
- Name::intern(&format!("'{:?}", c)).as_interned_str()
+ InternedString::intern(&format!("'{:?}", c))
}
}
trace!("{:?} is now live", local);
let local_val = LocalValue::Uninitialized;
- // StorageLive *always* kills the value that's currently stored
+ // StorageLive *always* kills the value that's currently stored.
+ // However, we do not error if the variable already is live;
+ // see <https://github.com/rust-lang/rust/issues/42371>.
Ok(mem::replace(&mut self.frame_mut().locals[local].value, local_val))
}
use std::fmt::{self, Write};
use std::iter;
use rustc::mir::mono::Linkage;
-use syntax_pos::symbol::Symbol;
+use syntax_pos::symbol::InternedString;
use syntax::source_map::Span;
pub use rustc::mir::mono::MonoItem;
MonoItem::GlobalAsm(hir_id) => {
let def_id = tcx.hir().local_def_id_from_hir_id(hir_id);
ty::SymbolName {
- name: Symbol::intern(&format!("global_asm_{:?}", def_id)).as_interned_str()
+ name: InternedString::intern(&format!("global_asm_{:?}", def_id))
}
}
}
use rustc::mir::*;
use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext};
-use syntax::symbol::{Symbol, sym};
+use syntax::symbol::{InternedString, sym};
use std::ops::Bound;
(CastTy::FnPtr, CastTy::Int(_)) => {
self.register_violations(&[UnsafetyViolation {
source_info: self.source_info,
- description: Symbol::intern("cast of pointer to int").as_interned_str(),
- details: Symbol::intern("casting pointers to integers in constants")
- .as_interned_str(),
+ description: InternedString::intern("cast of pointer to int"),
+ details: InternedString::intern(
+ "casting pointers to integers in constants"),
kind: UnsafetyViolationKind::General,
}], &[]);
},
if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.mir, self.tcx).sty {
self.register_violations(&[UnsafetyViolation {
source_info: self.source_info,
- description: Symbol::intern("pointer operation").as_interned_str(),
- details: Symbol::intern("operations on pointers in constants")
- .as_interned_str(),
+ description: InternedString::intern("pointer operation"),
+ details: InternedString::intern("operations on pointers in constants"),
kind: UnsafetyViolationKind::General,
}], &[]);
}
self.source_scope_local_data[source_info.scope].lint_root;
self.register_violations(&[UnsafetyViolation {
source_info,
- description: Symbol::intern("borrow of packed field").as_interned_str(),
- details:
- Symbol::intern("fields of packed structs might be misaligned: \
- dereferencing a misaligned pointer or even just \
- creating a misaligned reference is undefined \
- behavior")
- .as_interned_str(),
+ description: InternedString::intern("borrow of packed field"),
+ details: InternedString::intern(
+ "fields of packed structs might be misaligned: dereferencing a \
+ misaligned pointer or even just creating a misaligned reference \
+ is undefined behavior"),
kind: UnsafetyViolationKind::BorrowPacked(lint_root)
}], &[]);
}
self.source_scope_local_data[source_info.scope].lint_root;
self.register_violations(&[UnsafetyViolation {
source_info,
- description: Symbol::intern("use of extern static").as_interned_str(),
- details:
- Symbol::intern("extern statics are not controlled by the Rust type \
- system: invalid data, aliasing violations or data \
- races will cause undefined behavior")
- .as_interned_str(),
+ description: InternedString::intern("use of extern static"),
+ details: InternedString::intern(
+ "extern statics are not controlled by the Rust type system: invalid \
+ data, aliasing violations or data races will cause undefined behavior"),
kind: UnsafetyViolationKind::ExternStatic(lint_root)
}], &[]);
}
let source_info = self.source_info;
self.register_violations(&[UnsafetyViolation {
source_info,
- description: Symbol::intern(description).as_interned_str(),
- details: Symbol::intern(details).as_interned_str(),
+ description: InternedString::intern(description),
+ details: InternedString::intern(details),
kind,
}], &[]);
}
let source_info = self.source_info;
self.register_violations(&[UnsafetyViolation {
source_info,
- description: Symbol::intern(description).as_interned_str(),
- details: Symbol::intern(details).as_interned_str(),
+ description: InternedString::intern(description),
+ details: InternedString::intern(details),
kind: UnsafetyViolationKind::GeneralAndConstFn,
}], &[]);
}
}
}
}
+
+ fn should_const_prop(&self) -> bool {
+ self.tcx.sess.opts.debugging_opts.mir_opt_level >= 2
+ }
}
fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
assert!(self.places[local].is_none());
self.places[local] = Some(value);
- if self.tcx.sess.opts.debugging_opts.mir_opt_level >= 2 {
+ if self.should_const_prop() {
self.replace_with_const(rval, value, statement.source_info.span);
}
}
location: Location,
) {
self.super_terminator(terminator, location);
- let source_info = terminator.source_info;;
- if let TerminatorKind::Assert { expected, msg, cond, .. } = &terminator.kind {
- if let Some(value) = self.eval_operand(&cond, source_info) {
- trace!("assertion on {:?} should be {:?}", value, expected);
- let expected = ScalarMaybeUndef::from(Scalar::from_bool(*expected));
- if expected != self.ecx.read_scalar(value).unwrap() {
- // poison all places this operand references so that further code
- // doesn't use the invalid value
- match cond {
- Operand::Move(ref place) | Operand::Copy(ref place) => {
- let mut place = place;
- while let Place::Projection(ref proj) = *place {
- place = &proj.base;
- }
- if let Place::Base(PlaceBase::Local(local)) = *place {
- self.places[local] = None;
+ let source_info = terminator.source_info;
+ match &mut terminator.kind {
+ TerminatorKind::Assert { expected, msg, ref mut cond, .. } => {
+ if let Some(value) = self.eval_operand(&cond, source_info) {
+ trace!("assertion on {:?} should be {:?}", value, expected);
+ let expected = ScalarMaybeUndef::from(Scalar::from_bool(*expected));
+ let value_const = self.ecx.read_scalar(value).unwrap();
+ if expected != value_const {
+ // poison all places this operand references so that further code
+ // doesn't use the invalid value
+ match cond {
+ Operand::Move(ref place) | Operand::Copy(ref place) => {
+ let mut place = place;
+ while let Place::Projection(ref proj) = *place {
+ place = &proj.base;
+ }
+ if let Place::Base(PlaceBase::Local(local)) = *place {
+ self.places[local] = None;
+ }
+ },
+ Operand::Constant(_) => {}
+ }
+ let span = terminator.source_info.span;
+ let hir_id = self
+ .tcx
+ .hir()
+ .as_local_hir_id(self.source.def_id())
+ .expect("some part of a failing const eval must be local");
+ use rustc::mir::interpret::InterpError::*;
+ let msg = match msg {
+ Overflow(_) |
+ OverflowNeg |
+ DivisionByZero |
+ RemainderByZero => msg.description().to_owned(),
+ BoundsCheck { ref len, ref index } => {
+ let len = self
+ .eval_operand(len, source_info)
+ .expect("len must be const");
+ let len = match self.ecx.read_scalar(len) {
+ Ok(ScalarMaybeUndef::Scalar(Scalar::Bits {
+ bits, ..
+ })) => bits,
+ other => bug!("const len not primitive: {:?}", other),
+ };
+ let index = self
+ .eval_operand(index, source_info)
+ .expect("index must be const");
+ let index = match self.ecx.read_scalar(index) {
+ Ok(ScalarMaybeUndef::Scalar(Scalar::Bits {
+ bits, ..
+ })) => bits,
+ other => bug!("const index not primitive: {:?}", other),
+ };
+ format!(
+ "index out of bounds: \
+ the len is {} but the index is {}",
+ len,
+ index,
+ )
+ },
+ // Need proper const propagator for these
+ _ => return,
+ };
+ self.tcx.lint_hir(
+ ::rustc::lint::builtin::CONST_ERR,
+ hir_id,
+ span,
+ &msg,
+ );
+ } else {
+ if self.should_const_prop() {
+ if let ScalarMaybeUndef::Scalar(scalar) = value_const {
+ *cond = self.operand_from_scalar(
+ scalar,
+ self.tcx.types.bool,
+ source_info.span,
+ );
}
- },
- Operand::Constant(_) => {}
+ }
}
- let span = terminator.source_info.span;
- let hir_id = self
- .tcx
- .hir()
- .as_local_hir_id(self.source.def_id())
- .expect("some part of a failing const eval must be local");
- use rustc::mir::interpret::InterpError::*;
- let msg = match msg {
- Overflow(_) |
- OverflowNeg |
- DivisionByZero |
- RemainderByZero => msg.description().to_owned(),
- BoundsCheck { ref len, ref index } => {
- let len = self
- .eval_operand(len, source_info)
- .expect("len must be const");
- let len = match self.ecx.read_scalar(len) {
- Ok(ScalarMaybeUndef::Scalar(Scalar::Bits {
- bits, ..
- })) => bits,
- other => bug!("const len not primitive: {:?}", other),
- };
- let index = self
- .eval_operand(index, source_info)
- .expect("index must be const");
- let index = match self.ecx.read_scalar(index) {
- Ok(ScalarMaybeUndef::Scalar(Scalar::Bits {
- bits, ..
- })) => bits,
- other => bug!("const index not primitive: {:?}", other),
- };
- format!(
- "index out of bounds: \
- the len is {} but the index is {}",
- len,
- index,
- )
- },
- // Need proper const propagator for these
- _ => return,
- };
- self.tcx.lint_hir(
- ::rustc::lint::builtin::CONST_ERR,
- hir_id,
- span,
- &msg,
- );
}
- }
+ },
+ TerminatorKind::SwitchInt { ref mut discr, switch_ty, .. } => {
+ if self.should_const_prop() {
+ if let Some(value) = self.eval_operand(&discr, source_info) {
+ if let ScalarMaybeUndef::Scalar(scalar) =
+ self.ecx.read_scalar(value).unwrap() {
+ *discr = self.operand_from_scalar(scalar, switch_ty, source_info.span);
+ }
+ }
+ }
+ },
+ //none of these have Operands to const-propagate
+ TerminatorKind::Goto { .. } |
+ TerminatorKind::Resume |
+ TerminatorKind::Abort |
+ TerminatorKind::Return |
+ TerminatorKind::Unreachable |
+ TerminatorKind::Drop { .. } |
+ TerminatorKind::DropAndReplace { .. } |
+ TerminatorKind::Yield { .. } |
+ TerminatorKind::GeneratorDrop |
+ TerminatorKind::FalseEdges { .. } |
+ TerminatorKind::FalseUnwind { .. } => { }
+ //FIXME(wesleywiser) Call does have Operands that could be const-propagated
+ TerminatorKind::Call { .. } => { }
}
}
}
format!(
"{}_{}",
def_id.krate.index(),
- def_id.index.as_array_index(),
+ def_id.index.index(),
)
}
fn add_builtin(&mut self, ident: ast::Ident, ext: Lrc<SyntaxExtension>) {
let def_id = DefId {
krate: CrateNum::BuiltinMacros,
- index: DefIndex::from_array_index(self.macro_map.len()),
+ index: DefIndex::from(self.macro_map.len()),
};
let kind = ext.kind();
self.macro_map.insert(def_id, ext);
fn id_from_def_id(id: DefId) -> rls_data::Id {
rls_data::Id {
krate: id.krate.as_u32(),
- index: id.index.as_raw_u32(),
+ index: id.index.as_u32(),
}
}
use crate::require_same_types;
use rustc_target::spec::abi::Abi;
-use syntax::symbol::Symbol;
+use syntax::symbol::InternedString;
use rustc::hir;
/// and in libcore/intrinsics.rs
pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
it: &hir::ForeignItem) {
- let param = |n| tcx.mk_ty_param(n, Symbol::intern(&format!("P{}", n)).as_interned_str());
+ let param = |n| tcx.mk_ty_param(n, InternedString::intern(&format!("P{}", n)));
let name = it.ident.as_str();
let mk_va_list_ty = || {
pub fn check_platform_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
it: &hir::ForeignItem) {
let param = |n| {
- let name = Symbol::intern(&format!("P{}", n)).as_interned_str();
+ let name = InternedString::intern(&format!("P{}", n));
tcx.mk_ty_param(n, name)
};
continue;
}
+ // If the extern crate is renamed, then we cannot suggest replacing it with a use as this
+ // would not insert the new name into the prelude, where other imports in the crate may be
+ // expecting it.
+ if extern_crate.orig_name.is_some() {
+ continue;
+ }
+
// If the extern crate has any attributes, they may have funky
// semantics we can't faithfully represent using `use` (most
// notably `#[macro_use]`). Ignore it.
use syntax::attr::{InlineAttr, OptimizeAttr, list_contains_name, mark_used};
use syntax::source_map::Spanned;
use syntax::feature_gate;
-use syntax::symbol::{keywords, Symbol, sym};
+use syntax::symbol::{InternedString, keywords, Symbol, sym};
use syntax_pos::{Span, DUMMY_SP};
use rustc::hir::def::{CtorKind, Res, DefKind};
.enumerate()
.map(|(i, &arg)| ty::GenericParamDef {
index: type_start + i as u32,
- name: Symbol::intern(arg).as_interned_str(),
+ name: InternedString::intern(arg),
def_id,
pure_wrt_drop: false,
kind: ty::GenericParamDefKind::Type {
params.extend(upvars.iter().zip((dummy_args.len() as u32)..).map(|(_, i)| {
ty::GenericParamDef {
index: type_start + i,
- name: Symbol::intern("<upvar>").as_interned_str(),
+ name: InternedString::intern("<upvar>"),
def_id,
pure_wrt_drop: false,
kind: ty::GenericParamDefKind::Type {
fn clean(&self, cx: &DocContext<'_>) -> Constant {
Constant {
type_: self.ty.clean(cx),
- expr: format!("{:?}", self.val), // FIXME(const_generics)
+ expr: match self.val {
+ ConstValue::Param(ty::ParamConst { name, .. }) => format!("{}", name),
+ e => format!("{:?}", e), // FIXME generic consts with expressions
+ },
}
}
}
pub locol: usize,
pub hiline: usize,
pub hicol: usize,
+ pub original: syntax_pos::Span,
}
impl Span {
filename: FileName::Anon(0),
loline: 0, locol: 0,
hiline: 0, hicol: 0,
+ original: syntax_pos::DUMMY_SP,
}
}
+
+ pub fn span(&self) -> syntax_pos::Span {
+ self.original
+ }
}
impl Clean<Span> for syntax_pos::Span {
locol: lo.col.to_usize(),
hiline: hi.line,
hicol: hi.col.to_usize(),
+ original: *self,
}
}
}
use rustc::session::search_paths::SearchPath;
use rustc_driver;
use rustc_target::spec::TargetTriple;
-use syntax::edition::Edition;
+use syntax::edition::{Edition, DEFAULT_EDITION};
use crate::core::new_handler;
use crate::externalfiles::ExternalHtml;
}
}
+ let edition = if let Some(e) = matches.opt_str("edition") {
+ match e.parse() {
+ Ok(e) => e,
+ Err(_) => {
+ diag.struct_err("could not parse edition").emit();
+ return Err(1);
+ }
+ }
+ } else {
+ DEFAULT_EDITION
+ };
+
let mut id_map = html::markdown::IdMap::new();
id_map.populate(html::render::initial_ids());
let external_html = match ExternalHtml::load(
&matches.opt_strs("html-before-content"),
&matches.opt_strs("html-after-content"),
&matches.opt_strs("markdown-before-content"),
- &matches.opt_strs("markdown-after-content"), &diag, &mut id_map) {
+ &matches.opt_strs("markdown-after-content"),
+ &diag, &mut id_map, edition) {
Some(eh) => eh,
None => return Err(3),
};
- let edition = matches.opt_str("edition").unwrap_or("2015".to_string());
- let edition = match edition.parse() {
- Ok(e) => e,
- Err(_) => {
- diag.struct_err("could not parse edition").emit();
- return Err(1);
- }
- };
-
match matches.opt_str("r").as_ref().map(|s| &**s) {
Some("rust") | None => {}
Some(s) => {
"passes",
];
- for flag in deprecated_flags.into_iter() {
+ for flag in deprecated_flags.iter() {
if matches.opt_present(flag) {
let mut err = diag.struct_warn(&format!("the '{}' flag is considered deprecated",
flag));
crate_num,
DefId {
krate: crate_num,
- index: DefIndex::from_array_index(def_id.index.as_array_index() + 1),
+ index: DefIndex::from(def_id.index.index() + 1),
},
);
use std::str;
use errors;
use crate::syntax::feature_gate::UnstableFeatures;
+use crate::syntax::edition::Edition;
use crate::html::markdown::{IdMap, ErrorCodes, Markdown};
use std::cell::RefCell;
impl ExternalHtml {
pub fn load(in_header: &[String], before_content: &[String], after_content: &[String],
md_before_content: &[String], md_after_content: &[String], diag: &errors::Handler,
- id_map: &mut IdMap)
+ id_map: &mut IdMap, edition: Edition)
-> Option<ExternalHtml> {
let codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build());
load_external_files(in_header, diag)
.and_then(|(ih, bc)|
load_external_files(md_before_content, diag)
.map(|m_bc| (ih,
- format!("{}{}", bc, Markdown(&m_bc, &[], RefCell::new(id_map), codes))))
+ format!("{}{}", bc, Markdown(&m_bc, &[], RefCell::new(id_map),
+ codes, edition))))
)
.and_then(|(ih, bc)|
load_external_files(after_content, diag)
.and_then(|(ih, bc, ac)|
load_external_files(md_after_content, diag)
.map(|m_ac| (ih, bc,
- format!("{}{}", ac, Markdown(&m_ac, &[], RefCell::new(id_map), codes))))
+ format!("{}{}", ac, Markdown(&m_ac, &[], RefCell::new(id_map),
+ codes, edition))))
)
.map(|(ih, bc, ac)|
ExternalHtml {
impl fmt::Display for clean::Constant {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::Display::fmt(&self.expr, f)?;
- f.write_str(": ")?;
- fmt::Display::fmt(&self.type_, f)
+ fmt::Display::fmt(&self.expr, f)
}
}
let p = SlashChecker(&p);
if layout.logo.is_empty() {
format!("<a href='{path}index.html'>\
- <img src='{static_root_path}rust-logo{suffix}.png' \
- alt='logo' width='100'></a>",
+ <div class='logo-container'>\
+ <img src='{static_root_path}rust-logo{suffix}.png' alt='logo'></div></a>",
path=p,
static_root_path=static_root_path,
suffix=page.resource_suffix)
} else {
format!("<a href='{}index.html'>\
- <img src='{}' alt='logo' width='100'></a>",
+ <div class='logo-container'><img src='{}' alt='logo'></div></a>",
p,
layout.logo)
}
//! ```
//! #![feature(rustc_private)]
//!
+//! extern crate syntax;
+//!
+//! use syntax::edition::Edition;
//! use rustdoc::html::markdown::{IdMap, Markdown, ErrorCodes};
//! use std::cell::RefCell;
//!
//! let s = "My *markdown* _text_";
//! let mut id_map = IdMap::new();
-//! let html = format!("{}", Markdown(s, &[], RefCell::new(&mut id_map), ErrorCodes::Yes));
+//! let html = format!("{}", Markdown(s, &[], RefCell::new(&mut id_map),
+//! ErrorCodes::Yes, Edition::Edition2015));
//! // ... something using html
//! ```
/// A unit struct which has the `fmt::Display` trait implemented. When
/// formatted, this struct will emit the HTML corresponding to the rendered
/// version of the contained markdown string.
-/// The second parameter is a list of link replacements
+///
+/// The second parameter is a list of link replacements.
+///
+/// The third is the current list of used header IDs.
+///
+/// The fourth is whether to allow the use of explicit error codes in doctest lang strings.
+///
+/// The fifth is what default edition to use when parsing doctests (to add a `fn main`).
pub struct Markdown<'a>(
- pub &'a str, pub &'a [(String, String)], pub RefCell<&'a mut IdMap>, pub ErrorCodes);
+ pub &'a str, pub &'a [(String, String)], pub RefCell<&'a mut IdMap>, pub ErrorCodes, pub Edition);
/// A unit struct like `Markdown`, that renders the markdown with a
/// table of contents.
-pub struct MarkdownWithToc<'a>(pub &'a str, pub RefCell<&'a mut IdMap>, pub ErrorCodes);
+pub struct MarkdownWithToc<'a>(pub &'a str, pub RefCell<&'a mut IdMap>, pub ErrorCodes, pub Edition);
/// A unit struct like `Markdown`, that renders the markdown escaping HTML tags.
-pub struct MarkdownHtml<'a>(pub &'a str, pub RefCell<&'a mut IdMap>, pub ErrorCodes);
+pub struct MarkdownHtml<'a>(pub &'a str, pub RefCell<&'a mut IdMap>, pub ErrorCodes, pub Edition);
/// A unit struct like `Markdown`, that renders only the first paragraph.
pub struct MarkdownSummaryLine<'a>(pub &'a str, pub &'a [(String, String)]);
struct CodeBlocks<'a, I: Iterator<Item = Event<'a>>> {
inner: I,
check_error_codes: ErrorCodes,
+ edition: Edition,
}
impl<'a, I: Iterator<Item = Event<'a>>> CodeBlocks<'a, I> {
- fn new(iter: I, error_codes: ErrorCodes) -> Self {
+ fn new(iter: I, error_codes: ErrorCodes, edition: Edition) -> Self {
CodeBlocks {
inner: iter,
check_error_codes: error_codes,
+ edition,
}
}
}
return event;
}
+ let explicit_edition = edition.is_some();
+ let edition = edition.unwrap_or(self.edition);
+
let mut origtext = String::new();
for event in &mut self.inner {
match event {
.collect::<Vec<Cow<'_, str>>>().join("\n");
let krate = krate.as_ref().map(|s| &**s);
let (test, _) = test::make_test(&test, krate, false,
- &Default::default());
+ &Default::default(), edition);
let channel = if test.contains("#![feature(") {
"&version=nightly"
} else {
""
};
- let edition_string = if let Some(e @ Edition::Edition2018) = edition {
- format!("&edition={}{}", e,
- if channel == "&version=nightly" { "" }
- else { "&version=nightly" })
- } else if let Some(e) = edition {
- format!("&edition={}", e)
- } else {
- "".to_owned()
- };
+ let edition_string = format!("&edition={}", edition);
// These characters don't need to be escaped in a URI.
// FIXME: use a library function for percent encoding.
Some(("This example is not tested".to_owned(), "ignore"))
} else if compile_fail {
Some(("This example deliberately fails to compile".to_owned(), "compile_fail"))
- } else if let Some(e) = edition {
- Some((format!("This code runs with edition {}", e), "edition"))
+ } else if explicit_edition {
+ Some((format!("This code runs with edition {}", edition), "edition"))
} else {
None
};
Some(&format!("rust-example-rendered{}",
if ignore { " ignore" }
else if compile_fail { " compile_fail" }
- else if edition.is_some() { " edition " }
+ else if explicit_edition { " edition " }
else { "" })),
playground_button.as_ref().map(String::as_str),
Some((s1.as_str(), s2))));
Some(&format!("rust-example-rendered{}",
if ignore { " ignore" }
else if compile_fail { " compile_fail" }
- else if edition.is_some() { " edition " }
+ else if explicit_edition { " edition " }
else { "" })),
playground_button.as_ref().map(String::as_str),
None));
impl<'a> fmt::Display for Markdown<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- let Markdown(md, links, ref ids, codes) = *self;
+ let Markdown(md, links, ref ids, codes, edition) = *self;
let mut ids = ids.borrow_mut();
// This is actually common enough to special-case
let p = HeadingLinks::new(p, None, &mut ids);
let p = LinkReplacer::new(p, links);
- let p = CodeBlocks::new(p, codes);
+ let p = CodeBlocks::new(p, codes, edition);
let p = Footnotes::new(p);
html::push_html(&mut s, p);
impl<'a> fmt::Display for MarkdownWithToc<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- let MarkdownWithToc(md, ref ids, codes) = *self;
+ let MarkdownWithToc(md, ref ids, codes, edition) = *self;
let mut ids = ids.borrow_mut();
let p = Parser::new_ext(md, opts());
{
let p = HeadingLinks::new(p, Some(&mut toc), &mut ids);
- let p = CodeBlocks::new(p, codes);
+ let p = CodeBlocks::new(p, codes, edition);
let p = Footnotes::new(p);
html::push_html(&mut s, p);
}
impl<'a> fmt::Display for MarkdownHtml<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- let MarkdownHtml(md, ref ids, codes) = *self;
+ let MarkdownHtml(md, ref ids, codes, edition) = *self;
let mut ids = ids.borrow_mut();
// This is actually common enough to special-case
let mut s = String::with_capacity(md.len() * 3 / 2);
let p = HeadingLinks::new(p, None, &mut ids);
- let p = CodeBlocks::new(p, codes);
+ let p = CodeBlocks::new(p, codes, edition);
let p = Footnotes::new(p);
html::push_html(&mut s, p);
use super::{ErrorCodes, LangString, Markdown, MarkdownHtml, IdMap};
use super::plain_summary_line;
use std::cell::RefCell;
- use syntax::edition::Edition;
+ use syntax::edition::{Edition, DEFAULT_EDITION};
#[test]
fn test_lang_string_parse() {
fn test_header() {
fn t(input: &str, expect: &str) {
let mut map = IdMap::new();
- let output = Markdown(input, &[], RefCell::new(&mut map), ErrorCodes::Yes).to_string();
+ let output = Markdown(input, &[], RefCell::new(&mut map),
+ ErrorCodes::Yes, DEFAULT_EDITION).to_string();
assert_eq!(output, expect, "original: {}", input);
}
fn test_header_ids_multiple_blocks() {
let mut map = IdMap::new();
fn t(map: &mut IdMap, input: &str, expect: &str) {
- let output = Markdown(input, &[], RefCell::new(map), ErrorCodes::Yes).to_string();
+ let output = Markdown(input, &[], RefCell::new(map),
+ ErrorCodes::Yes, DEFAULT_EDITION).to_string();
assert_eq!(output, expect, "original: {}", input);
}
fn test_markdown_html_escape() {
fn t(input: &str, expect: &str) {
let mut idmap = IdMap::new();
- let output = MarkdownHtml(input, RefCell::new(&mut idmap), ErrorCodes::Yes).to_string();
+ let output = MarkdownHtml(input, RefCell::new(&mut idmap),
+ ErrorCodes::Yes, DEFAULT_EDITION).to_string();
assert_eq!(output, expect, "original: {}", input);
}
use errors;
use serialize::json::{ToJson, Json, as_json};
use syntax::ast;
+use syntax::edition::Edition;
use syntax::ext::base::MacroKind;
use syntax::source_map::FileName;
use syntax::feature_gate::UnstableFeatures;
/// publicly reused items to redirect to the right location.
pub render_redirect_pages: bool,
pub codes: ErrorCodes,
+ /// The default edition used to parse doctests.
+ pub edition: Edition,
/// The map used to ensure all generated 'id=' attributes are unique.
id_map: Rc<RefCell<IdMap>>,
pub shared: Arc<SharedContext>,
"methods",
"deref-methods",
"implementations",
- ].into_iter().map(|id| (String::from(*id))).collect()
+ ].iter().map(|id| (String::from(*id))).collect()
}
/// Generates the documentation for `crate` into the directory `dst`
options: RenderOptions,
passes: FxHashSet<String>,
renderinfo: RenderInfo,
- diag: &errors::Handler) -> Result<(), Error> {
+ diag: &errors::Handler,
+ edition: Edition) -> Result<(), Error> {
// need to save a copy of the options for rendering the index page
let md_opts = options.clone();
let RenderOptions {
dst,
render_redirect_pages: false,
codes: ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()),
+ edition,
id_map: Rc::new(RefCell::new(id_map)),
shared: Arc::new(scx),
};
md_opts.output = cx.dst.clone();
md_opts.external_html = (*cx.shared).layout.external_html.clone();
- crate::markdown::render(index_page, md_opts, diag);
+ crate::markdown::render(index_page, md_opts, diag, cx.edition);
} else {
let dst = cx.dst.join("index.html");
let mut w = BufWriter::new(try_err!(File::create(&dst), &dst));
if is_hidden { " hidden" } else { "" },
prefix,
Markdown(md_text, &links, RefCell::new(&mut ids),
- cx.codes))
+ cx.codes, cx.edition))
}
fn document_short(
if let Some(note) = note {
let mut ids = cx.id_map.borrow_mut();
- let html = MarkdownHtml(¬e, RefCell::new(&mut ids), error_codes);
+ let html = MarkdownHtml(¬e, RefCell::new(&mut ids), error_codes, cx.edition);
message.push_str(&format!(": {}", html));
}
stability.push(format!("<div class='stab deprecated'>{}</div>", message));
message = format!(
"<details><summary>{}</summary>{}</details>",
message,
- MarkdownHtml(&unstable_reason, RefCell::new(&mut ids), error_codes)
+ MarkdownHtml(&unstable_reason, RefCell::new(&mut ids), error_codes, cx.edition)
);
}
fn item_constant(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
c: &clean::Constant) -> fmt::Result {
write!(w, "<pre class='rust const'>")?;
- render_attributes(w, it)?;
+ render_attributes(w, it, false)?;
write!(w, "{vis}const \
{name}: {typ}</pre>",
vis = VisSpace(&it.visibility),
fn item_static(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
s: &clean::Static) -> fmt::Result {
write!(w, "<pre class='rust static'>")?;
- render_attributes(w, it)?;
+ render_attributes(w, it, false)?;
write!(w, "{vis}static {mutability}\
{name}: {typ}</pre>",
vis = VisSpace(&it.visibility),
f.generics
).len();
write!(w, "{}<pre class='rust fn'>", render_spotlight_traits(it)?)?;
- render_attributes(w, it)?;
+ render_attributes(w, it, false)?;
write!(w,
"{vis}{constness}{unsafety}{asyncness}{abi}fn \
{name}{generics}{decl}{where_clause}</pre>",
// Output the trait definition
wrap_into_docblock(w, |w| {
write!(w, "<pre class='rust trait'>")?;
- render_attributes(w, it)?;
+ render_attributes(w, it, true)?;
write!(w, "{}{}{}trait {}{}{}",
VisSpace(&it.visibility),
UnsafetySpace(t.unsafety),
it: &clean::Item,
ty: &clean::Type,
_default: Option<&String>,
- link: AssocItemLink<'_>) -> fmt::Result {
- write!(w, "{}const <a href='{}' class=\"constant\"><b>{}</b></a>: {}",
+ link: AssocItemLink<'_>,
+ extra: &str) -> fmt::Result {
+ write!(w, "{}{}const <a href='{}' class=\"constant\"><b>{}</b></a>: {}",
+ extra,
VisSpace(&it.visibility),
naive_assoc_href(it, link),
it.name.as_ref().unwrap(),
fn assoc_type<W: fmt::Write>(w: &mut W, it: &clean::Item,
bounds: &[clean::GenericBound],
default: Option<&clean::Type>,
- link: AssocItemLink<'_>) -> fmt::Result {
- write!(w, "type <a href='{}' class=\"type\">{}</a>",
+ link: AssocItemLink<'_>,
+ extra: &str) -> fmt::Result {
+ write!(w, "{}type <a href='{}' class=\"type\">{}</a>",
+ extra,
naive_assoc_href(it, link),
it.name.as_ref().unwrap())?;
if !bounds.is_empty() {
} else {
(0, true)
};
- render_attributes(w, meth)?;
+ render_attributes(w, meth, false)?;
write!(w, "{}{}{}{}{}{}{}fn <a href='{href}' class='fnname'>{name}</a>\
{generics}{decl}{where_clause}",
if parent == ItemType::Trait { " " } else { "" },
method(w, item, m.header, &m.generics, &m.decl, link, parent)
}
clean::AssociatedConstItem(ref ty, ref default) => {
- assoc_const(w, item, ty, default.as_ref(), link)
+ assoc_const(w, item, ty, default.as_ref(), link,
+ if parent == ItemType::Trait { " " } else { "" })
}
clean::AssociatedTypeItem(ref bounds, ref default) => {
- assoc_type(w, item, bounds, default.as_ref(), link)
+ assoc_type(w, item, bounds, default.as_ref(), link,
+ if parent == ItemType::Trait { " " } else { "" })
}
_ => panic!("render_assoc_item called on non-associated-item")
}
s: &clean::Struct) -> fmt::Result {
wrap_into_docblock(w, |w| {
write!(w, "<pre class='rust struct'>")?;
- render_attributes(w, it)?;
+ render_attributes(w, it, true)?;
render_struct(w,
it,
Some(&s.generics),
s: &clean::Union) -> fmt::Result {
wrap_into_docblock(w, |w| {
write!(w, "<pre class='rust union'>")?;
- render_attributes(w, it)?;
+ render_attributes(w, it, true)?;
render_union(w,
it,
Some(&s.generics),
e: &clean::Enum) -> fmt::Result {
wrap_into_docblock(w, |w| {
write!(w, "<pre class='rust enum'>")?;
- render_attributes(w, it)?;
+ render_attributes(w, it, true)?;
write!(w, "{}enum {}{}{}",
VisSpace(&it.visibility),
it.name.as_ref().unwrap(),
sym::non_exhaustive
];
-fn render_attributes(w: &mut dyn fmt::Write, it: &clean::Item) -> fmt::Result {
+// The `top` parameter is used when generating the item declaration to ensure it doesn't have a
+// left padding. For example:
+//
+// #[foo] <----- "top" attribute
+// struct Foo {
+// #[bar] <---- not "top" attribute
+// bar: usize,
+// }
+fn render_attributes(w: &mut dyn fmt::Write, it: &clean::Item, top: bool) -> fmt::Result {
let mut attrs = String::new();
for attr in &it.attrs.other_attrs {
}
}
if attrs.len() > 0 {
- write!(w, "<div class=\"docblock attributes\">{}</div>", &attrs)?;
+ write!(w, "<div class=\"docblock attributes{}\">{}</div>",
+ if top { " top-attr" } else { "" }, &attrs)?;
}
Ok(())
}
out.push_str("<span class=\"where fmt-newline\"> ");
assoc_type(&mut out, it, &[],
Some(&tydef.type_),
- AssocItemLink::GotoSource(t_did, &FxHashSet::default()))?;
+ AssocItemLink::GotoSource(t_did, &FxHashSet::default()),
+ "")?;
out.push_str(";</span>");
}
}
if let clean::TypedefItem(ref tydef, _) = it.inner {
write!(w, "<span class=\"where fmt-newline\"> ")?;
assoc_type(w, it, &vec![], Some(&tydef.type_),
- AssocItemLink::Anchor(None))?;
+ AssocItemLink::Anchor(None),
+ "")?;
write!(w, ";</span>")?;
}
}
if let Some(ref dox) = cx.shared.maybe_collapsed_doc_value(&i.impl_item) {
let mut ids = cx.id_map.borrow_mut();
write!(w, "<div class='docblock'>{}</div>",
- Markdown(&*dox, &i.impl_item.links(), RefCell::new(&mut ids), cx.codes))?;
+ Markdown(&*dox, &i.impl_item.links(), RefCell::new(&mut ids),
+ cx.codes, cx.edition))?;
}
}
let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class)?;
write!(w, "<code id='{}'>", ns_id)?;
- assoc_type(w, item, &Vec::new(), Some(&tydef.type_), link.anchor(&id))?;
+ assoc_type(w, item, &Vec::new(), Some(&tydef.type_), link.anchor(&id), "")?;
write!(w, "</code></h4>")?;
}
clean::AssociatedConstItem(ref ty, ref default) => {
let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class)?;
write!(w, "<code id='{}'>", ns_id)?;
- assoc_const(w, item, ty, default.as_ref(), link.anchor(&id))?;
+ assoc_const(w, item, ty, default.as_ref(), link.anchor(&id), "")?;
write!(w, "</code>")?;
render_stability_since_raw(w, item.stable_since(), outer_version)?;
if let Some(l) = (Item { cx, item }).src_href() {
let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class)?;
write!(w, "<code id='{}'>", ns_id)?;
- assoc_type(w, item, bounds, default.as_ref(), link.anchor(&id))?;
+ assoc_type(w, item, bounds, default.as_ref(), link.anchor(&id), "")?;
write!(w, "</code></h4>")?;
}
clean::StrippedItem(..) => return Ok(()),
t: &clean::Existential,
) -> fmt::Result {
write!(w, "<pre class='rust existential'>")?;
- render_attributes(w, it)?;
+ render_attributes(w, it, false)?;
write!(w, "existential type {}{}{where_clause}: {bounds};</pre>",
it.name.as_ref().unwrap(),
t.generics,
fn item_trait_alias(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
t: &clean::TraitAlias) -> fmt::Result {
write!(w, "<pre class='rust trait-alias'>")?;
- render_attributes(w, it)?;
+ render_attributes(w, it, false)?;
write!(w, "trait {}{}{} = {};</pre>",
it.name.as_ref().unwrap(),
t.generics,
fn item_typedef(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
t: &clean::Typedef) -> fmt::Result {
write!(w, "<pre class='rust typedef'>")?;
- render_attributes(w, it)?;
+ render_attributes(w, it, false)?;
write!(w, "type {}{}{where_clause} = {type_};</pre>",
it.name.as_ref().unwrap(),
t.generics,
fn item_foreign_type(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item) -> fmt::Result {
writeln!(w, "<pre class='rust foreigntype'>extern {{")?;
- render_attributes(w, it)?;
+ render_attributes(w, it, false)?;
write!(
w,
" {}type {};\n}}</pre>",
}
var attributesToggle = createToggleWrapper(createSimpleToggle(false));
onEachLazy(main.getElementsByClassName("attributes"), function(i_e) {
- i_e.parentNode.insertBefore(attributesToggle.cloneNode(true), i_e);
+ var attr_tog = attributesToggle.cloneNode(true);
+ if (hasClass(i_e, "top-attr") === true) {
+ addClass(attr_tog, "top-attr");
+ }
+ i_e.parentNode.insertBefore(attr_tog, i_e);
itemAttributesFunc(i_e);
});
display: none !important;
}
-.sidebar img {
+.logo-container {
+ height: 100px;
+ width: 100px;
+ position: relative;
margin: 20px auto;
display: block;
margin-top: 10px;
}
+.logo-container > img {
+ max-width: 100px;
+ max-height: 100px;
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ transform: translate(-50%, -50%);
+ display: block;
+}
+
.sidebar .location {
border: 1px solid;
font-size: 17px;
transition: border-color 300ms ease;
transition: border-radius 300ms ease-in-out;
transition: box-shadow 300ms ease-in-out;
- width: calc(100% - 32px);
+ width: 100%;
}
#crate-search + .search-input {
border-radius: 0 1px 1px 0;
+ width: calc(100% - 32px);
}
.search-input:focus {
border-radius: 2px;
border: 0;
outline: 0;
- box-shadow: 0 0 8px #078dd8;
}
.search-results .desc {
opacity: 1;
}
+.information {
+ position: absolute;
+ left: -20px;
+ margin-top: 7px;
+ z-index: 1;
+}
+
+.tooltip {
+ position: relative;
+ display: inline-block;
+ cursor: pointer;
+}
+
+.tooltip .tooltiptext {
+ width: 120px;
+ display: none;
+ text-align: center;
+ padding: 5px 3px;
+ border-radius: 6px;
+ margin-left: 5px;
+ top: -5px;
+ left: 105%;
+ z-index: 10;
+}
+
+.tooltip:hover .tooltiptext {
+ display: inline;
+}
+
+.tooltip .tooltiptext::after {
+ content: " ";
+ position: absolute;
+ top: 50%;
+ left: 11px;
+ margin-top: -5px;
+ border-width: 5px;
+ border-style: solid;
+}
+
+.important-traits .tooltip .tooltiptext {
+ border: 1px solid;
+}
+
+pre.rust {
+ position: relative;
+ tab-width: 4;
+ -moz-tab-width: 4;
+}
+
+.search-failed {
+ text-align: center;
+ margin-top: 20px;
+}
+
+.search-failed > ul {
+ text-align: left;
+ max-width: 570px;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+#titles {
+ height: 35px;
+}
+
+#titles > div {
+ float: left;
+ width: 33.3%;
+ text-align: center;
+ font-size: 18px;
+ cursor: pointer;
+ border-top: 2px solid;
+}
+
+#titles > div:not(:last-child) {
+ margin-right: 1px;
+ width: calc(33.3% - 1px);
+}
+
+#titles > div > div.count {
+ display: inline-block;
+ font-size: 16px;
+}
+
+.important-traits {
+ cursor: pointer;
+ z-index: 2;
+}
+
+h4 > .important-traits {
+ position: absolute;
+ left: -44px;
+ top: 2px;
+}
+
+#all-types {
+ text-align: center;
+ border: 1px solid;
+ margin: 0 10px;
+ margin-bottom: 10px;
+ display: block;
+ border-radius: 7px;
+}
+#all-types > p {
+ margin: 5px 0;
+}
+
+#sidebar-toggle {
+ position: fixed;
+ top: 30px;
+ left: 300px;
+ z-index: 10;
+ padding: 3px;
+ border-top-right-radius: 3px;
+ border-bottom-right-radius: 3px;
+ cursor: pointer;
+ font-weight: bold;
+ transition: left .5s;
+ font-size: 1.2em;
+ border: 1px solid;
+ border-left: 0;
+}
+#source-sidebar {
+ position: fixed;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ width: 300px;
+ z-index: 1;
+ overflow: auto;
+ transition: left .5s;
+ border-right: 1px solid;
+}
+#source-sidebar > .title {
+ font-size: 1.5em;
+ text-align: center;
+ border-bottom: 1px solid;
+ margin-bottom: 6px;
+}
+
+.theme-picker {
+ position: absolute;
+ left: 211px;
+ top: 19px;
+}
+
+.theme-picker button {
+ outline: none;
+}
+
+#settings-menu {
+ position: absolute;
+ right: 0;
+ top: 10px;
+ outline: none;
+}
+
+#theme-picker, #settings-menu {
+ padding: 4px;
+ width: 27px;
+ height: 29px;
+ border: 1px solid;
+ border-radius: 3px;
+ cursor: pointer;
+}
+
+#theme-choices {
+ display: none;
+ position: absolute;
+ left: 0;
+ top: 28px;
+ border: 1px solid;
+ border-radius: 3px;
+ z-index: 1;
+ cursor: pointer;
+}
+
+#theme-choices > button {
+ border: none;
+ width: 100%;
+ padding: 4px;
+ text-align: center;
+ background: rgba(0,0,0,0);
+}
+
+#theme-choices > button:not(:first-child) {
+ border-top: 1px solid;
+}
+
/* Media Queries */
@media (max-width: 700px) {
padding: 0;
}
- .sidebar img {
+ .sidebar .logo-container {
width: 35px;
+ height: 35px;
margin-top: 5px;
margin-bottom: 5px;
float: left;
margin-left: 50px;
}
+ .sidebar .logo-container > img {
+ max-width: 35px;
+ max-height: 35px;
+ }
+
.sidebar-menu {
position: fixed;
z-index: 10;
overflow: initial;
}
- #main > .line-numbers {
- margin-top: 0;
- }
-}
-
-@media print {
- nav.sub, .content .out-of-band, .collapse-toggle {
- display: none;
+ .theme-picker {
+ left: 10px;
+ top: 54px;
+ z-index: 1;
}
-}
-.information {
- position: absolute;
- left: -20px;
- margin-top: 7px;
- z-index: 1;
-}
-
-.tooltip {
- position: relative;
- display: inline-block;
- cursor: pointer;
-}
-
-.tooltip .tooltiptext {
- width: 120px;
- display: none;
- text-align: center;
- padding: 5px 3px;
- border-radius: 6px;
- margin-left: 5px;
- top: -5px;
- left: 105%;
- z-index: 10;
-}
-
-.tooltip:hover .tooltiptext {
- display: inline;
-}
-
-.tooltip .tooltiptext::after {
- content: " ";
- position: absolute;
- top: 50%;
- left: 11px;
- margin-top: -5px;
- border-width: 5px;
- border-style: solid;
-}
-
-.important-traits .tooltip .tooltiptext {
- border: 1px solid;
-}
-
-pre.rust {
- position: relative;
- tab-width: 4;
- -moz-tab-width: 4;
-}
-
-.search-failed {
- text-align: center;
- margin-top: 20px;
-}
-
-.search-failed > ul {
- text-align: left;
- max-width: 570px;
- margin-left: auto;
- margin-right: auto;
-}
-
-#titles {
- height: 35px;
-}
-
-#titles > div {
- float: left;
- width: 33.3%;
- text-align: center;
- font-size: 18px;
- cursor: pointer;
- border-top: 2px solid;
-}
-
-#titles > div:not(:last-child) {
- margin-right: 1px;
- width: calc(33.3% - 1px);
-}
-
-#titles > div > div.count {
- display: inline-block;
- font-size: 16px;
-}
-
-.important-traits {
- cursor: pointer;
- z-index: 2;
-}
-
-h4 > .important-traits {
- position: absolute;
- left: -44px;
- top: 2px;
-}
-
-#all-types {
- text-align: center;
- border: 1px solid;
- margin: 0 10px;
- margin-bottom: 10px;
- display: block;
- border-radius: 7px;
-}
-#all-types > p {
- margin: 5px 0;
-}
-
-@media (max-width: 700px) {
h4 > .important-traits {
position: absolute;
left: -22px;
#all-types {
margin: 10px;
}
+
+ #sidebar-toggle {
+ top: 100px;
+ width: 30px;
+ font-size: 1.5rem;
+ text-align: center;
+ padding: 0;
+ }
+
+ #source-sidebar {
+ z-index: 11;
+ }
+
+ #main > .line-numbers {
+ margin-top: 0;
+ }
}
+@media print {
+ nav.sub, .content .out-of-band, .collapse-toggle {
+ display: none;
+ }
+}
@media (max-width: 416px) {
#titles {
cursor: default;
}
-.theme-picker {
- position: absolute;
- left: 211px;
- top: 19px;
-}
-
-.theme-picker button {
- outline: none;
-}
-
-#settings-menu {
- position: absolute;
- right: 0;
- top: 10px;
- outline: none;
-}
-
-#theme-picker, #settings-menu {
- padding: 4px;
- width: 27px;
- height: 29px;
- border: 1px solid;
- border-radius: 3px;
- cursor: pointer;
-}
-
-#theme-choices {
- display: none;
- position: absolute;
- left: 0;
- top: 28px;
- border: 1px solid;
- border-radius: 3px;
- z-index: 1;
- cursor: pointer;
-}
-
-#theme-choices > button {
- border: none;
- width: 100%;
- padding: 4px;
- text-align: center;
- background: rgba(0,0,0,0);
-}
-
-#theme-choices > button:not(:first-child) {
- border-top: 1px solid;
-}
-
-@media (max-width: 700px) {
- .theme-picker {
- left: 10px;
- top: 54px;
- z-index: 1;
- }
-}
-
.hidden-by-impl-hider,
.hidden-by-usual-hider {
/* important because of conflicting rule for small screens */
margin-bottom: 1em;
}
-#sidebar-toggle {
- position: fixed;
- top: 30px;
- left: 300px;
- z-index: 10;
- padding: 3px;
- border-top-right-radius: 3px;
- border-bottom-right-radius: 3px;
- cursor: pointer;
- font-weight: bold;
- transition: left .5s;
- font-size: 1.2em;
- border: 1px solid;
- border-left: 0;
-}
-#source-sidebar {
- position: fixed;
- top: 0;
- bottom: 0;
- left: 0;
- width: 300px;
- z-index: 1;
- overflow: auto;
- transition: left .5s;
- border-right: 1px solid;
-}
-#source-sidebar > .title {
- font-size: 1.5em;
- text-align: center;
- border-bottom: 1px solid;
- margin-bottom: 6px;
-}
-
div.children {
padding-left: 27px;
display: none;
}
/* This part is to fix the "Expand attributes" part in the type declaration. */
-.type-decl > pre > :first-child {
+.type-decl > pre > .toggle-wrapper.toggle-attributes.top-attr {
margin-left: 0 !important;
}
-.type-decl > pre > :nth-child(2) {
+.type-decl > pre > .docblock.attributes.top-attr {
margin-left: 1.8em !important;
}
.type-decl > pre > .toggle-attributes {
color: #111;
background-color: #f0f0f0;
border-color: #000;
+ box-shadow: 0 0 0 1px #000, 0 0 0 2px transparent;
}
.search-input {
color: #111;
- box-shadow: 0 0 0 1px #000, 0 0 0 2px transparent;
background-color: #f0f0f0;
+ box-shadow: 0 0 0 1px #000, 0 0 0 2px transparent;
}
.search-input:focus {
border-color: #008dfd;
}
-#crate-search + .search-input {
- box-shadow: 1px 0 0 1px #000, 0 0 0 2px transparent;
+#crate-search + .search-input:focus {
+ box-shadow: 0 0 8px 4px #078dd8;
}
.module-item .stab {
color: #555;
background-color: white;
border-color: #e0e0e0;
- box-shadow: 0px 0 0 1px #e0e0e0, 0 0 0 2px transparent;
+ box-shadow: 0 0 0 1px #e0e0e0, 0 0 0 2px transparent;
}
.search-input {
color: #555;
- box-shadow: 0 0 0 1px #e0e0e0, 0 0 0 2px transparent;
background-color: white;
+ box-shadow: 0 0 0 1px #e0e0e0, 0 0 0 2px transparent;
}
.search-input:focus {
border-color: #66afe9;
}
-#crate-search + .search-input {
- box-shadow: 1px 0 0 1px #e0e0e0, 0 0 0 2px transparent;
+#crate-search + .search-input:focus {
+ box-shadow: 0 0 8px #078dd8;
}
.module-item .stab {
match (options.should_test, options.markdown_input()) {
(true, true) => return markdown::test(options, &diag),
(true, false) => return test::run(options),
- (false, true) => return markdown::render(options.input, options.render_options, &diag),
+ (false, true) => return markdown::render(options.input,
+ options.render_options,
+ &diag,
+ options.edition),
(false, false) => {}
}
// but we can't crates the Handler ahead of time because it's not Send
let diag_opts = (options.error_format,
options.debugging_options.treat_err_as_bug,
- options.debugging_options.ui_testing);
+ options.debugging_options.ui_testing,
+ options.edition);
let show_coverage = options.show_coverage;
rust_input(options, move |out| {
if show_coverage {
let Output { krate, passes, renderinfo, renderopts } = out;
info!("going to format");
- let (error_format, treat_err_as_bug, ui_testing) = diag_opts;
+ let (error_format, treat_err_as_bug, ui_testing, edition) = diag_opts;
let diag = core::new_handler(error_format, None, treat_err_as_bug, ui_testing);
match html::render::run(
krate,
passes.into_iter().collect(),
renderinfo,
&diag,
+ edition,
) {
Ok(_) => rustc_driver::EXIT_SUCCESS,
Err(e) => {
use errors;
use testing;
+use syntax::edition::Edition;
use syntax::source_map::DUMMY_SP;
use syntax::feature_gate::UnstableFeatures;
/// Render `input` (e.g., "foo.md") into an HTML file in `output`
/// (e.g., output = "bar" => "bar/foo.html").
-pub fn render(input: PathBuf, options: RenderOptions, diag: &errors::Handler) -> i32 {
+pub fn render(
+ input: PathBuf,
+ options: RenderOptions,
+ diag: &errors::Handler,
+ edition: Edition
+) -> i32 {
let mut output = options.output;
output.push(input.file_stem().unwrap());
output.set_extension("html");
let mut ids = IdMap::new();
let error_codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build());
let text = if !options.markdown_no_toc {
- MarkdownWithToc(text, RefCell::new(&mut ids), error_codes).to_string()
+ MarkdownWithToc(text, RefCell::new(&mut ids), error_codes, edition).to_string()
} else {
- Markdown(text, &[], RefCell::new(&mut ids), error_codes).to_string()
+ Markdown(text, &[], RefCell::new(&mut ids), error_codes, edition).to_string()
};
let err = write!(
if let Ok(res) = self.resolve(path_str, ns, ¤t_item, parent_node) {
res
} else {
- resolution_failure(cx, &item.attrs, path_str, &dox, link_range);
+ resolution_failure(cx, &item, path_str, &dox, link_range);
// This could just be a normal link or a broken link
// we could potentially check if something is
// "intra-doc-link-like" and warn in that case.
if let Ok(res) = self.resolve(path_str, ns, ¤t_item, parent_node) {
res
} else {
- resolution_failure(cx, &item.attrs, path_str, &dox, link_range);
+ resolution_failure(cx, &item, path_str, &dox, link_range);
// This could just be a normal link.
continue;
}
};
if candidates.is_empty() {
- resolution_failure(cx, &item.attrs, path_str, &dox, link_range);
+ resolution_failure(cx, &item, path_str, &dox, link_range);
// this could just be a normal link
continue;
}
} else {
ambiguity_error(
cx,
- &item.attrs,
+ &item,
path_str,
&dox,
link_range,
if let Some(res) = macro_resolve(cx, path_str) {
(res, None)
} else {
- resolution_failure(cx, &item.attrs, path_str, &dox, link_range);
+ resolution_failure(cx, &item, path_str, &dox, link_range);
continue
}
}
/// line containing the failure as a note as well.
fn resolution_failure(
cx: &DocContext<'_>,
- attrs: &Attributes,
+ item: &Item,
path_str: &str,
dox: &str,
link_range: Option<Range<usize>>,
) {
+ let hir_id = match cx.as_local_hir_id(item.def_id) {
+ Some(hir_id) => hir_id,
+ None => {
+ // If non-local, no need to check anything.
+ return;
+ }
+ };
+ let attrs = &item.attrs;
let sp = span_of_attrs(attrs);
let mut diag = cx.tcx.struct_span_lint_hir(
lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE,
- hir::CRATE_HIR_ID,
+ hir_id,
sp,
&format!("`[{}]` cannot be resolved, ignoring it...", path_str),
);
fn ambiguity_error(
cx: &DocContext<'_>,
- attrs: &Attributes,
+ item: &Item,
path_str: &str,
dox: &str,
link_range: Option<Range<usize>>,
candidates: PerNS<Option<Res>>,
) {
+ let hir_id = match cx.as_local_hir_id(item.def_id) {
+ Some(hir_id) => hir_id,
+ None => {
+ // If non-local, no need to check anything.
+ return;
+ }
+ };
+ let attrs = &item.attrs;
let sp = span_of_attrs(attrs);
let mut msg = format!("`{}` is ", path_str);
let mut diag = cx.tcx.struct_span_lint_hir(
lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE,
- hir::CRATE_HIR_ID,
+ hir_id,
sp,
&msg,
);
//! Contains information about "passes", used to modify crate information during the documentation
//! process.
-use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::lint as lint;
use rustc::middle::privacy::AccessLevels;
item: &Item,
check_missing_code: bool,
) {
- if cx.as_local_hir_id(item.def_id).is_none() {
- // If non-local, no need to check anything.
- return;
- }
+ let hir_id = match cx.as_local_hir_id(item.def_id) {
+ Some(hir_id) => hir_id,
+ None => {
+ // If non-local, no need to check anything.
+ return;
+ }
+ };
struct Tests {
found_tests: usize,
find_testable_code(&dox, &mut tests, ErrorCodes::No);
if check_missing_code == true && tests.found_tests == 0 {
+ let sp = span_of_attrs(&item.attrs).substitute_dummy(item.source.span());
let mut diag = cx.tcx.struct_span_lint_hir(
lint::builtin::MISSING_DOC_CODE_EXAMPLES,
- hir::CRATE_HIR_ID,
- span_of_attrs(&item.attrs),
+ hir_id,
+ sp,
"Missing code example in this documentation");
diag.emit();
} else if check_missing_code == false &&
!cx.renderinfo.borrow().access_levels.is_doc_reachable(item.def_id) {
let mut diag = cx.tcx.struct_span_lint_hir(
lint::builtin::PRIVATE_DOC_TESTS,
- hir::CRATE_HIR_ID,
+ hir_id,
span_of_attrs(&item.attrs),
"Documentation test in private item");
diag.emit();
maybe_sysroot: Option<PathBuf>, linker: Option<PathBuf>, edition: Edition,
persist_doctests: Option<PathBuf>) {
let (test, line_offset) = match panic::catch_unwind(|| {
- make_test(test, Some(cratename), as_test_harness, opts)
+ make_test(test, Some(cratename), as_test_harness, opts, edition)
}) {
Ok((test, line_offset)) => (test, line_offset),
Err(cause) if cause.is::<errors::FatalErrorMarker>() => {
pub fn make_test(s: &str,
cratename: Option<&str>,
dont_insert_main: bool,
- opts: &TestOptions)
+ opts: &TestOptions,
+ edition: Edition)
-> (String, usize) {
let (crate_attrs, everything_else, crates) = partition_source(s);
let everything_else = everything_else.trim();
use errors::emitter::EmitterWriter;
use errors::Handler;
+ syntax::ext::hygiene::set_default_edition(edition);
+
let filename = FileName::anon_source_code(s);
let source = crates + &everything_else;
// send all the errors that libsyntax emits directly into a `Sink` instead of stderr.
let cm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
let emitter = EmitterWriter::new(box io::sink(), None, false, false, false);
+ // FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser
let handler = Handler::with_emitter(false, None, box emitter);
let sess = ParseSess::with_span_handler(handler, cm);
#[cfg(test)]
mod tests {
use super::{TestOptions, make_test};
+ use syntax::edition::DEFAULT_EDITION;
#[test]
fn make_test_basic() {
fn main() {
assert_eq!(2+2, 4);
}".to_string();
- let output = make_test(input, None, false, &opts);
+ let output = make_test(input, None, false, &opts, DEFAULT_EDITION);
assert_eq!(output, (expected, 2));
}
fn main() {
assert_eq!(2+2, 4);
}".to_string();
- let output = make_test(input, Some("asdf"), false, &opts);
+ let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
assert_eq!(output, (expected, 2));
}
use asdf::qwop;
assert_eq!(2+2, 4);
}".to_string();
- let output = make_test(input, Some("asdf"), false, &opts);
+ let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
assert_eq!(output, (expected, 3));
}
use asdf::qwop;
assert_eq!(2+2, 4);
}".to_string();
- let output = make_test(input, Some("asdf"), false, &opts);
+ let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
assert_eq!(output, (expected, 2));
}
use std::*;
assert_eq!(2+2, 4);
}".to_string();
- let output = make_test(input, Some("std"), false, &opts);
+ let output = make_test(input, Some("std"), false, &opts, DEFAULT_EDITION);
assert_eq!(output, (expected, 2));
}
use asdf::qwop;
assert_eq!(2+2, 4);
}".to_string();
- let output = make_test(input, Some("asdf"), false, &opts);
+ let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
assert_eq!(output, (expected, 2));
}
use asdf::qwop;
assert_eq!(2+2, 4);
}".to_string();
- let output = make_test(input, Some("asdf"), false, &opts);
+ let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
assert_eq!(output, (expected, 2));
}
use asdf::qwop;
assert_eq!(2+2, 4);
}".to_string();
- let output = make_test(input, Some("asdf"), false, &opts);
+ let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
assert_eq!(output, (expected, 3));
// Adding more will also bump the returned line offset.
use asdf::qwop;
assert_eq!(2+2, 4);
}".to_string();
- let output = make_test(input, Some("asdf"), false, &opts);
+ let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
assert_eq!(output, (expected, 4));
}
fn main() {
assert_eq!(2+2, 4);
}".to_string();
- let output = make_test(input, None, false, &opts);
+ let output = make_test(input, None, false, &opts, DEFAULT_EDITION);
assert_eq!(output, (expected, 2));
}
fn main() {
assert_eq!(2+2, 4);
}".to_string();
- let output = make_test(input, None, false, &opts);
+ let output = make_test(input, None, false, &opts, DEFAULT_EDITION);
assert_eq!(output, (expected, 1));
}
fn main() {
assert_eq!(2+2, 4);
}".to_string();
- let output = make_test(input, None, false, &opts);
+ let output = make_test(input, None, false, &opts, DEFAULT_EDITION);
assert_eq!(output, (expected, 2));
}
"#![allow(unused)]
//Ceci n'est pas une `fn main`
assert_eq!(2+2, 4);".to_string();
- let output = make_test(input, None, true, &opts);
+ let output = make_test(input, None, true, &opts, DEFAULT_EDITION);
assert_eq!(output, (expected, 1));
}
"fn main() {
assert_eq!(2+2, 4);
}".to_string();
- let output = make_test(input, None, false, &opts);
+ let output = make_test(input, None, false, &opts, DEFAULT_EDITION);
assert_eq!(output, (expected, 1));
}
assert_eq!(2+2, 4);
}".to_string();
- let output = make_test(input, None, false, &opts);
+ let output = make_test(input, None, false, &opts, DEFAULT_EDITION);
assert_eq!(output, (expected, 2));
let input =
assert_eq!(asdf::foo, 4);
}".to_string();
- let output = make_test(input, Some("asdf"), false, &opts);
+ let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
assert_eq!(output, (expected, 3));
}
fn main() {}
}".to_string();
- let output = make_test(input, Some("my_crate"), false, &opts);
+ let output = make_test(input, Some("my_crate"), false, &opts, DEFAULT_EDITION);
assert_eq!(output, (expected, 1));
}
}
/// about the allocation that failed.
///
/// The allocation error hook is a global resource.
+///
+/// [`set_alloc_error_hook`]: fn.set_alloc_error_hook.html
+/// [`take_alloc_error_hook`]: fn.take_alloc_error_hook.html
#[unstable(feature = "alloc_error_hook", issue = "51245")]
pub fn set_alloc_error_hook(hook: fn(Layout)) {
HOOK.store(hook as *mut (), Ordering::SeqCst);
/// *See also the function [`set_alloc_error_hook`].*
///
/// If no custom hook is registered, the default hook will be returned.
+///
+/// [`set_alloc_error_hook`]: fn.set_alloc_error_hook.html
#[unstable(feature = "alloc_error_hook", issue = "51245")]
pub fn take_alloc_error_hook() -> fn(Layout) {
let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst);
#[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
impl Default for DefaultHasher {
- /// Creates a new `DefaultHasher` using [`new`][DefaultHasher::new].
+ // FIXME: here should link `new` to [DefaultHasher::new], but it occurs intra-doc link
+ // resolution failure when re-exporting libstd items. When #56922 fixed,
+ // link `new` to [DefaultHasher::new] again.
+ /// Creates a new `DefaultHasher` using `new`.
/// See its documentation for more.
fn default() -> DefaultHasher {
DefaultHasher::new()
impl<'a, E: Error + 'a> From<E> for Box<dyn Error + 'a> {
/// Converts a type of [`Error`] into a box of dyn [`Error`].
///
+ /// [`Error`]: ../error/trait.Error.html
+ ///
/// # Examples
///
/// ```
/// Converts a type of [`Error`] + [`Send`] + [`Sync`] into a box of dyn [`Error`] +
/// [`Send`] + [`Sync`].
///
+ /// [`Error`]: ../error/trait.Error.html
+ ///
/// # Examples
///
/// ```
impl From<String> for Box<dyn Error + Send + Sync> {
/// Converts a [`String`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
///
+ /// [`Error`]: ../error/trait.Error.html
+ ///
/// # Examples
///
/// ```
impl From<String> for Box<dyn Error> {
/// Converts a [`String`] into a box of dyn [`Error`].
///
+ /// [`Error`]: ../error/trait.Error.html
+ ///
/// # Examples
///
/// ```
impl<'a> From<&str> for Box<dyn Error + Send + Sync + 'a> {
/// Converts a [`str`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
///
+ /// [`Error`]: ../error/trait.Error.html
+ ///
/// # Examples
///
/// ```
impl From<&str> for Box<dyn Error> {
/// Converts a [`str`] into a box of dyn [`Error`].
///
+ /// [`Error`]: ../error/trait.Error.html
+ ///
/// # Examples
///
/// ```
impl<'a, 'b> From<Cow<'b, str>> for Box<dyn Error + Send + Sync + 'a> {
/// Converts a [`Cow`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
///
+ /// [`Cow`]: ../borrow/enum.Cow.html
+ /// [`Error`]: ../error/trait.Error.html
+ ///
/// # Examples
///
/// ```
impl<'a> From<Cow<'a, str>> for Box<dyn Error> {
/// Converts a [`Cow`] into a box of dyn [`Error`].
///
+ /// [`Cow`]: ../borrow/enum.Cow.html
+ /// [`Error`]: ../error/trait.Error.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) }
}
/// function.)
/// * `path` already exists.
///
+/// [`create_dir_all`]: fn.create_dir_all.html
+///
/// # Examples
///
/// ```no_run
/// completed, rather than the entire buffer at once. Enter `LineWriter`. It
/// does exactly that.
///
-/// Like [`BufWriter`], a `LineWriter`’s buffer will also be flushed when the
+/// Like [`BufWriter`][bufwriter], a `LineWriter`’s buffer will also be flushed when the
/// `LineWriter` goes out of scope or when its internal buffer is full.
///
/// [bufwriter]: struct.BufWriter.html
/// let stdin = io::stdin();
/// let mut stdin = stdin.lock();
///
- /// // we can't have two `&mut` references to `stdin`, so use a block
- /// // to end the borrow early.
- /// let length = {
- /// let buffer = stdin.fill_buf().unwrap();
+ /// let buffer = stdin.fill_buf().unwrap();
///
- /// // work with buffer
- /// println!("{:?}", buffer);
- ///
- /// buffer.len()
- /// };
+ /// // work with buffer
+ /// println!("{:?}", buffer);
///
/// // ensure the bytes we worked with aren't returned again later
+ /// let length = buffer.len();
/// stdin.consume(length);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#![feature(libc)]
#![feature(link_args)]
#![feature(linkage)]
-#![feature(maybe_uninit)]
#![feature(needs_panic_runtime)]
#![feature(never_type)]
#![feature(nll)]
};
}
-/// Selects the first successful receive event from a number of receivers.
-///
-/// This macro is used to wait for the first event to occur on a number of
-/// receivers. It places no restrictions on the types of receivers given to
-/// this macro, this can be viewed as a heterogeneous select.
-///
-/// # Examples
-///
-/// ```
-/// #![feature(mpsc_select)]
-///
-/// use std::thread;
-/// use std::sync::mpsc;
-///
-/// // two placeholder functions for now
-/// fn long_running_thread() {}
-/// fn calculate_the_answer() -> u32 { 42 }
-///
-/// let (tx1, rx1) = mpsc::channel();
-/// let (tx2, rx2) = mpsc::channel();
-///
-/// thread::spawn(move|| { long_running_thread(); tx1.send(()).unwrap(); });
-/// thread::spawn(move|| { tx2.send(calculate_the_answer()).unwrap(); });
-///
-/// select! {
-/// _ = rx1.recv() => println!("the long running thread finished first"),
-/// answer = rx2.recv() => {
-/// println!("the answer was: {}", answer.unwrap());
-/// }
-/// }
-/// # drop(rx1.recv());
-/// # drop(rx2.recv());
-/// ```
-///
-/// For more information about select, see the `std::sync::mpsc::Select` structure.
-#[macro_export]
-#[unstable(feature = "mpsc_select", issue = "27800")]
-#[rustc_deprecated(since = "1.32.0",
- reason = "channel selection will be removed in a future release")]
-macro_rules! select {
- (
- $($name:pat = $rx:ident.$meth:ident() => $code:expr),+
- ) => ({
- use $crate::sync::mpsc::Select;
- let sel = Select::new();
- $( let mut $rx = sel.handle(&$rx); )+
- unsafe {
- $( $rx.add(); )+
- }
- let ret = sel.wait();
- $( if ret == $rx.id() { let $name = $rx.$meth(); $code } else )+
- { unreachable!() }
- })
-}
-
#[cfg(test)]
macro_rules! assert_approx_eq {
($a:expr, $b:expr) => ({
#[stable(feature = "ip_from_ip", since = "1.16.0")]
impl From<SocketAddrV4> for SocketAddr {
/// Converts a [`SocketAddrV4`] into a [`SocketAddr::V4`].
+ ///
+ /// [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html
+ /// [`SocketAddr::V4`]: ../../std/net/enum.SocketAddr.html#variant.V4
fn from(sock4: SocketAddrV4) -> SocketAddr {
SocketAddr::V4(sock4)
}
#[stable(feature = "ip_from_ip", since = "1.16.0")]
impl From<SocketAddrV6> for SocketAddr {
/// Converts a [`SocketAddrV6`] into a [`SocketAddr::V6`].
+ ///
+ /// [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html
+ /// [`SocketAddr::V6`]: ../../std/net/enum.SocketAddr.html#variant.V6
fn from(sock6: SocketAddrV6) -> SocketAddr {
SocketAddr::V6(sock6)
}
/// and creates a [`SocketAddr::V6`] for a [`IpAddr::V6`].
///
/// `u16` is treated as port of the newly created [`SocketAddr`].
+ ///
+ /// [`IpAddr`]: ../../std/net/enum.IpAddr.html
+ /// [`IpAddr::V4`]: ../../std/net/enum.IpAddr.html#variant.V4
+ /// [`IpAddr::V6`]: ../../std/net/enum.IpAddr.html#variant.V6
+ /// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html
+ /// [`SocketAddr::V4`]: ../../std/net/enum.SocketAddr.html#variant.V4
+ /// [`SocketAddr::V6`]: ../../std/net/enum.SocketAddr.html#variant.V6
fn from(pieces: (I, u16)) -> SocketAddr {
SocketAddr::new(pieces.0.into(), pieces.1)
}
//! ```
#![stable(feature = "rust1", since = "1.0.0")]
-#![allow(deprecated)] // for mpsc_select
// A description of how Rust's channel implementation works
//
// believe that there is anything fundamental that needs to change about these
// channels, however, in order to support a more efficient select().
//
+// FIXME: Select is now removed, so these factors are ready to be cleaned up!
+//
// # Conclusion
//
// And now that you've seen all the races that I found and attempted to fix,
use crate::cell::UnsafeCell;
use crate::time::{Duration, Instant};
-#[unstable(feature = "mpsc_select", issue = "27800")]
-pub use self::select::{Select, Handle};
-use self::select::StartResult;
-use self::select::StartResult::*;
-use self::blocking::SignalToken;
-
-#[cfg(all(test, not(target_os = "emscripten")))]
-mod select_tests;
-
mod blocking;
mod oneshot;
-mod select;
mod shared;
mod stream;
mod sync;
}
-impl<T> select::Packet for Receiver<T> {
- fn can_recv(&self) -> bool {
- loop {
- let new_port = match *unsafe { self.inner() } {
- Flavor::Oneshot(ref p) => {
- match p.can_recv() {
- Ok(ret) => return ret,
- Err(upgrade) => upgrade,
- }
- }
- Flavor::Stream(ref p) => {
- match p.can_recv() {
- Ok(ret) => return ret,
- Err(upgrade) => upgrade,
- }
- }
- Flavor::Shared(ref p) => return p.can_recv(),
- Flavor::Sync(ref p) => return p.can_recv(),
- };
- unsafe {
- mem::swap(self.inner_mut(),
- new_port.inner_mut());
- }
- }
- }
-
- fn start_selection(&self, mut token: SignalToken) -> StartResult {
- loop {
- let (t, new_port) = match *unsafe { self.inner() } {
- Flavor::Oneshot(ref p) => {
- match p.start_selection(token) {
- oneshot::SelSuccess => return Installed,
- oneshot::SelCanceled => return Abort,
- oneshot::SelUpgraded(t, rx) => (t, rx),
- }
- }
- Flavor::Stream(ref p) => {
- match p.start_selection(token) {
- stream::SelSuccess => return Installed,
- stream::SelCanceled => return Abort,
- stream::SelUpgraded(t, rx) => (t, rx),
- }
- }
- Flavor::Shared(ref p) => return p.start_selection(token),
- Flavor::Sync(ref p) => return p.start_selection(token),
- };
- token = t;
- unsafe {
- mem::swap(self.inner_mut(), new_port.inner_mut());
- }
- }
- }
-
- fn abort_selection(&self) -> bool {
- let mut was_upgrade = false;
- loop {
- let result = match *unsafe { self.inner() } {
- Flavor::Oneshot(ref p) => p.abort_selection(),
- Flavor::Stream(ref p) => p.abort_selection(was_upgrade),
- Flavor::Shared(ref p) => return p.abort_selection(was_upgrade),
- Flavor::Sync(ref p) => return p.abort_selection(),
- };
- let new_port = match result { Ok(b) => return b, Err(p) => p };
- was_upgrade = true;
- unsafe {
- mem::swap(self.inner_mut(),
- new_port.inner_mut());
- }
- }
- }
-}
-
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> Iterator for Iter<'a, T> {
type Item = T;
pub use self::Failure::*;
pub use self::UpgradeResult::*;
-pub use self::SelectionResult::*;
use self::MyUpgrade::*;
use crate::sync::mpsc::Receiver;
UpWoke(SignalToken),
}
-pub enum SelectionResult<T> {
- SelCanceled,
- SelUpgraded(SignalToken, Receiver<T>),
- SelSuccess,
-}
-
enum MyUpgrade<T> {
NothingSent,
SendUsed,
// select implementation
////////////////////////////////////////////////////////////////////////////
- // If Ok, the value is whether this port has data, if Err, then the upgraded
- // port needs to be checked instead of this one.
- pub fn can_recv(&self) -> Result<bool, Receiver<T>> {
- unsafe {
- match self.state.load(Ordering::SeqCst) {
- EMPTY => Ok(false), // Welp, we tried
- DATA => Ok(true), // we have some un-acquired data
- DISCONNECTED if (*self.data.get()).is_some() => Ok(true), // we have data
- DISCONNECTED => {
- match ptr::replace(self.upgrade.get(), SendUsed) {
- // The other end sent us an upgrade, so we need to
- // propagate upwards whether the upgrade can receive
- // data
- GoUp(upgrade) => Err(upgrade),
-
- // If the other end disconnected without sending an
- // upgrade, then we have data to receive (the channel is
- // disconnected).
- up => { ptr::write(self.upgrade.get(), up); Ok(true) }
- }
- }
- _ => unreachable!(), // we're the "one blocker"
- }
- }
- }
-
- // Attempts to start selection on this port. This can either succeed, fail
- // because there is data, or fail because there is an upgrade pending.
- pub fn start_selection(&self, token: SignalToken) -> SelectionResult<T> {
- unsafe {
- let ptr = token.cast_to_usize();
- match self.state.compare_and_swap(EMPTY, ptr, Ordering::SeqCst) {
- EMPTY => SelSuccess,
- DATA => {
- drop(SignalToken::cast_from_usize(ptr));
- SelCanceled
- }
- DISCONNECTED if (*self.data.get()).is_some() => {
- drop(SignalToken::cast_from_usize(ptr));
- SelCanceled
- }
- DISCONNECTED => {
- match ptr::replace(self.upgrade.get(), SendUsed) {
- // The other end sent us an upgrade, so we need to
- // propagate upwards whether the upgrade can receive
- // data
- GoUp(upgrade) => {
- SelUpgraded(SignalToken::cast_from_usize(ptr), upgrade)
- }
-
- // If the other end disconnected without sending an
- // upgrade, then we have data to receive (the channel is
- // disconnected).
- up => {
- ptr::write(self.upgrade.get(), up);
- drop(SignalToken::cast_from_usize(ptr));
- SelCanceled
- }
- }
- }
- _ => unreachable!(), // we're the "one blocker"
- }
- }
- }
-
// Remove a previous selecting thread from this port. This ensures that the
// blocked thread will no longer be visible to any other threads.
//
+++ /dev/null
-//! Selection over an array of receivers
-//!
-//! This module contains the implementation machinery necessary for selecting
-//! over a number of receivers. One large goal of this module is to provide an
-//! efficient interface to selecting over any receiver of any type.
-//!
-//! This is achieved through an architecture of a "receiver set" in which
-//! receivers are added to a set and then the entire set is waited on at once.
-//! The set can be waited on multiple times to prevent re-adding each receiver
-//! to the set.
-//!
-//! Usage of this module is currently encouraged to go through the use of the
-//! `select!` macro. This macro allows naturally binding of variables to the
-//! received values of receivers in a much more natural syntax then usage of the
-//! `Select` structure directly.
-//!
-//! # Examples
-//!
-//! ```rust
-//! #![feature(mpsc_select)]
-//!
-//! use std::sync::mpsc::channel;
-//!
-//! let (tx1, rx1) = channel();
-//! let (tx2, rx2) = channel();
-//!
-//! tx1.send(1).unwrap();
-//! tx2.send(2).unwrap();
-//!
-//! select! {
-//! val = rx1.recv() => {
-//! assert_eq!(val.unwrap(), 1);
-//! },
-//! val = rx2.recv() => {
-//! assert_eq!(val.unwrap(), 2);
-//! }
-//! }
-//! ```
-
-#![allow(dead_code)]
-#![unstable(feature = "mpsc_select",
- reason = "This implementation, while likely sufficient, is unsafe and \
- likely to be error prone. At some point in the future this \
- module will be removed.",
- issue = "27800")]
-#![rustc_deprecated(since = "1.32.0",
- reason = "channel selection will be removed in a future release")]
-
-use core::cell::{Cell, UnsafeCell};
-use core::marker;
-use core::ptr;
-use core::usize;
-
-use crate::fmt;
-use crate::sync::mpsc::{Receiver, RecvError};
-use crate::sync::mpsc::blocking::{self, SignalToken};
-
-/// The "receiver set" of the select interface. This structure is used to manage
-/// a set of receivers which are being selected over.
-pub struct Select {
- inner: UnsafeCell<SelectInner>,
- next_id: Cell<usize>,
-}
-
-struct SelectInner {
- head: *mut Handle<'static, ()>,
- tail: *mut Handle<'static, ()>,
-}
-
-impl !marker::Send for Select {}
-
-/// A handle to a receiver which is currently a member of a `Select` set of
-/// receivers. This handle is used to keep the receiver in the set as well as
-/// interact with the underlying receiver.
-pub struct Handle<'rx, T:Send+'rx> {
- /// The ID of this handle, used to compare against the return value of
- /// `Select::wait()`.
- id: usize,
- selector: *mut SelectInner,
- next: *mut Handle<'static, ()>,
- prev: *mut Handle<'static, ()>,
- added: bool,
- packet: &'rx (dyn Packet+'rx),
-
- // due to our fun transmutes, we be sure to place this at the end. (nothing
- // previous relies on T)
- rx: &'rx Receiver<T>,
-}
-
-struct Packets { cur: *mut Handle<'static, ()> }
-
-#[doc(hidden)]
-#[derive(PartialEq, Eq)]
-pub enum StartResult {
- Installed,
- Abort,
-}
-
-#[doc(hidden)]
-pub trait Packet {
- fn can_recv(&self) -> bool;
- fn start_selection(&self, token: SignalToken) -> StartResult;
- fn abort_selection(&self) -> bool;
-}
-
-impl Select {
- /// Creates a new selection structure. This set is initially empty.
- ///
- /// Usage of this struct directly can sometimes be burdensome, and usage is much easier through
- /// the `select!` macro.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(mpsc_select)]
- ///
- /// use std::sync::mpsc::Select;
- ///
- /// let select = Select::new();
- /// ```
- pub fn new() -> Select {
- Select {
- inner: UnsafeCell::new(SelectInner {
- head: ptr::null_mut(),
- tail: ptr::null_mut(),
- }),
- next_id: Cell::new(1),
- }
- }
-
- /// Creates a new handle into this receiver set for a new receiver. Note
- /// that this does *not* add the receiver to the receiver set, for that you
- /// must call the `add` method on the handle itself.
- pub fn handle<'a, T: Send>(&'a self, rx: &'a Receiver<T>) -> Handle<'a, T> {
- let id = self.next_id.get();
- self.next_id.set(id + 1);
- Handle {
- id,
- selector: self.inner.get(),
- next: ptr::null_mut(),
- prev: ptr::null_mut(),
- added: false,
- rx,
- packet: rx,
- }
- }
-
- /// Waits for an event on this receiver set. The returned value is *not* an
- /// index, but rather an ID. This ID can be queried against any active
- /// `Handle` structures (each one has an `id` method). The handle with
- /// the matching `id` will have some sort of event available on it. The
- /// event could either be that data is available or the corresponding
- /// channel has been closed.
- pub fn wait(&self) -> usize {
- self.wait2(true)
- }
-
- /// Helper method for skipping the preflight checks during testing
- pub(super) fn wait2(&self, do_preflight_checks: bool) -> usize {
- // Note that this is currently an inefficient implementation. We in
- // theory have knowledge about all receivers in the set ahead of time,
- // so this method shouldn't really have to iterate over all of them yet
- // again. The idea with this "receiver set" interface is to get the
- // interface right this time around, and later this implementation can
- // be optimized.
- //
- // This implementation can be summarized by:
- //
- // fn select(receivers) {
- // if any receiver ready { return ready index }
- // deschedule {
- // block on all receivers
- // }
- // unblock on all receivers
- // return ready index
- // }
- //
- // Most notably, the iterations over all of the receivers shouldn't be
- // necessary.
- unsafe {
- // Stage 1: preflight checks. Look for any packets ready to receive
- if do_preflight_checks {
- for handle in self.iter() {
- if (*handle).packet.can_recv() {
- return (*handle).id();
- }
- }
- }
-
- // Stage 2: begin the blocking process
- //
- // Create a number of signal tokens, and install each one
- // sequentially until one fails. If one fails, then abort the
- // selection on the already-installed tokens.
- let (wait_token, signal_token) = blocking::tokens();
- for (i, handle) in self.iter().enumerate() {
- match (*handle).packet.start_selection(signal_token.clone()) {
- StartResult::Installed => {}
- StartResult::Abort => {
- // Go back and abort the already-begun selections
- for handle in self.iter().take(i) {
- (*handle).packet.abort_selection();
- }
- return (*handle).id;
- }
- }
- }
-
- // Stage 3: no messages available, actually block
- wait_token.wait();
-
- // Stage 4: there *must* be message available; find it.
- //
- // Abort the selection process on each receiver. If the abort
- // process returns `true`, then that means that the receiver is
- // ready to receive some data. Note that this also means that the
- // receiver may have yet to have fully read the `to_wake` field and
- // woken us up (although the wakeup is guaranteed to fail).
- //
- // This situation happens in the window of where a sender invokes
- // increment(), sees -1, and then decides to wake up the thread. After
- // all this is done, the sending thread will set `selecting` to
- // `false`. Until this is done, we cannot return. If we were to
- // return, then a sender could wake up a receiver which has gone
- // back to sleep after this call to `select`.
- //
- // Note that it is a "fairly small window" in which an increment()
- // views that it should wake a thread up until the `selecting` bit
- // is set to false. For now, the implementation currently just spins
- // in a yield loop. This is very distasteful, but this
- // implementation is already nowhere near what it should ideally be.
- // A rewrite should focus on avoiding a yield loop, and for now this
- // implementation is tying us over to a more efficient "don't
- // iterate over everything every time" implementation.
- let mut ready_id = usize::MAX;
- for handle in self.iter() {
- if (*handle).packet.abort_selection() {
- ready_id = (*handle).id;
- }
- }
-
- // We must have found a ready receiver
- assert!(ready_id != usize::MAX);
- return ready_id;
- }
- }
-
- fn iter(&self) -> Packets { Packets { cur: unsafe { &*self.inner.get() }.head } }
-}
-
-impl<'rx, T: Send> Handle<'rx, T> {
- /// Retrieves the ID of this handle.
- #[inline]
- pub fn id(&self) -> usize { self.id }
-
- /// Blocks to receive a value on the underlying receiver, returning `Some` on
- /// success or `None` if the channel disconnects. This function has the same
- /// semantics as `Receiver.recv`
- pub fn recv(&mut self) -> Result<T, RecvError> { self.rx.recv() }
-
- /// Adds this handle to the receiver set that the handle was created from. This
- /// method can be called multiple times, but it has no effect if `add` was
- /// called previously.
- ///
- /// This method is unsafe because it requires that the `Handle` is not moved
- /// while it is added to the `Select` set.
- pub unsafe fn add(&mut self) {
- if self.added { return }
- let selector = &mut *self.selector;
- let me = self as *mut Handle<'rx, T> as *mut Handle<'static, ()>;
-
- if selector.head.is_null() {
- selector.head = me;
- selector.tail = me;
- } else {
- (*me).prev = selector.tail;
- assert!((*me).next.is_null());
- (*selector.tail).next = me;
- selector.tail = me;
- }
- self.added = true;
- }
-
- /// Removes this handle from the `Select` set. This method is unsafe because
- /// it has no guarantee that the `Handle` was not moved since `add` was
- /// called.
- pub unsafe fn remove(&mut self) {
- if !self.added { return }
-
- let selector = &mut *self.selector;
- let me = self as *mut Handle<'rx, T> as *mut Handle<'static, ()>;
-
- if self.prev.is_null() {
- assert_eq!(selector.head, me);
- selector.head = self.next;
- } else {
- (*self.prev).next = self.next;
- }
- if self.next.is_null() {
- assert_eq!(selector.tail, me);
- selector.tail = self.prev;
- } else {
- (*self.next).prev = self.prev;
- }
-
- self.next = ptr::null_mut();
- self.prev = ptr::null_mut();
-
- self.added = false;
- }
-}
-
-impl Drop for Select {
- fn drop(&mut self) {
- unsafe {
- assert!((&*self.inner.get()).head.is_null());
- assert!((&*self.inner.get()).tail.is_null());
- }
- }
-}
-
-impl<T: Send> Drop for Handle<'_, T> {
- fn drop(&mut self) {
- unsafe { self.remove() }
- }
-}
-
-impl Iterator for Packets {
- type Item = *mut Handle<'static, ()>;
-
- fn next(&mut self) -> Option<*mut Handle<'static, ()>> {
- if self.cur.is_null() {
- None
- } else {
- let ret = Some(self.cur);
- unsafe { self.cur = (*self.cur).next; }
- ret
- }
- }
-}
-
-impl fmt::Debug for Select {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("Select").finish()
- }
-}
-
-impl<T: Send> fmt::Debug for Handle<'_, T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("Handle").finish()
- }
-}
+++ /dev/null
-#![allow(unused_imports)]
-
-/// This file exists to hack around https://github.com/rust-lang/rust/issues/47238
-
-use crate::thread;
-use crate::sync::mpsc::*;
-
-// Don't use the libstd version so we can pull in the right Select structure
-// (std::comm points at the wrong one)
-macro_rules! select {
- (
- $($name:pat = $rx:ident.$meth:ident() => $code:expr),+
- ) => ({
- let sel = Select::new();
- $( let mut $rx = sel.handle(&$rx); )+
- unsafe {
- $( $rx.add(); )+
- }
- let ret = sel.wait();
- $( if ret == $rx.id() { let $name = $rx.$meth(); $code } else )+
- { unreachable!() }
- })
-}
-
-#[test]
-fn smoke() {
- let (tx1, rx1) = channel::<i32>();
- let (tx2, rx2) = channel::<i32>();
- tx1.send(1).unwrap();
- select! {
- foo = rx1.recv() => { assert_eq!(foo.unwrap(), 1); },
- _bar = rx2.recv() => { panic!() }
- }
- tx2.send(2).unwrap();
- select! {
- _foo = rx1.recv() => { panic!() },
- bar = rx2.recv() => { assert_eq!(bar.unwrap(), 2) }
- }
- drop(tx1);
- select! {
- foo = rx1.recv() => { assert!(foo.is_err()); },
- _bar = rx2.recv() => { panic!() }
- }
- drop(tx2);
- select! {
- bar = rx2.recv() => { assert!(bar.is_err()); }
- }
-}
-
-#[test]
-fn smoke2() {
- let (_tx1, rx1) = channel::<i32>();
- let (_tx2, rx2) = channel::<i32>();
- let (_tx3, rx3) = channel::<i32>();
- let (_tx4, rx4) = channel::<i32>();
- let (tx5, rx5) = channel::<i32>();
- tx5.send(4).unwrap();
- select! {
- _foo = rx1.recv() => { panic!("1") },
- _foo = rx2.recv() => { panic!("2") },
- _foo = rx3.recv() => { panic!("3") },
- _foo = rx4.recv() => { panic!("4") },
- foo = rx5.recv() => { assert_eq!(foo.unwrap(), 4); }
- }
-}
-
-#[test]
-fn closed() {
- let (_tx1, rx1) = channel::<i32>();
- let (tx2, rx2) = channel::<i32>();
- drop(tx2);
-
- select! {
- _a1 = rx1.recv() => { panic!() },
- a2 = rx2.recv() => { assert!(a2.is_err()); }
- }
-}
-
-#[test]
-fn unblocks() {
- let (tx1, rx1) = channel::<i32>();
- let (_tx2, rx2) = channel::<i32>();
- let (tx3, rx3) = channel::<i32>();
-
- let _t = thread::spawn(move|| {
- for _ in 0..20 { thread::yield_now(); }
- tx1.send(1).unwrap();
- rx3.recv().unwrap();
- for _ in 0..20 { thread::yield_now(); }
- });
-
- select! {
- a = rx1.recv() => { assert_eq!(a.unwrap(), 1); },
- _b = rx2.recv() => { panic!() }
- }
- tx3.send(1).unwrap();
- select! {
- a = rx1.recv() => { assert!(a.is_err()) },
- _b = rx2.recv() => { panic!() }
- }
-}
-
-#[test]
-fn both_ready() {
- let (tx1, rx1) = channel::<i32>();
- let (tx2, rx2) = channel::<i32>();
- let (tx3, rx3) = channel::<()>();
-
- let _t = thread::spawn(move|| {
- for _ in 0..20 { thread::yield_now(); }
- tx1.send(1).unwrap();
- tx2.send(2).unwrap();
- rx3.recv().unwrap();
- });
-
- select! {
- a = rx1.recv() => { assert_eq!(a.unwrap(), 1); },
- a = rx2.recv() => { assert_eq!(a.unwrap(), 2); }
- }
- select! {
- a = rx1.recv() => { assert_eq!(a.unwrap(), 1); },
- a = rx2.recv() => { assert_eq!(a.unwrap(), 2); }
- }
- assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty));
- assert_eq!(rx2.try_recv(), Err(TryRecvError::Empty));
- tx3.send(()).unwrap();
-}
-
-#[test]
-fn stress() {
- const AMT: i32 = 10000;
- let (tx1, rx1) = channel::<i32>();
- let (tx2, rx2) = channel::<i32>();
- let (tx3, rx3) = channel::<()>();
-
- let _t = thread::spawn(move|| {
- for i in 0..AMT {
- if i % 2 == 0 {
- tx1.send(i).unwrap();
- } else {
- tx2.send(i).unwrap();
- }
- rx3.recv().unwrap();
- }
- });
-
- for i in 0..AMT {
- select! {
- i1 = rx1.recv() => { assert!(i % 2 == 0 && i == i1.unwrap()); },
- i2 = rx2.recv() => { assert!(i % 2 == 1 && i == i2.unwrap()); }
- }
- tx3.send(()).unwrap();
- }
-}
-
-#[allow(unused_must_use)]
-#[test]
-fn cloning() {
- let (tx1, rx1) = channel::<i32>();
- let (_tx2, rx2) = channel::<i32>();
- let (tx3, rx3) = channel::<()>();
-
- let _t = thread::spawn(move|| {
- rx3.recv().unwrap();
- tx1.clone();
- assert_eq!(rx3.try_recv(), Err(TryRecvError::Empty));
- tx1.send(2).unwrap();
- rx3.recv().unwrap();
- });
-
- tx3.send(()).unwrap();
- select! {
- _i1 = rx1.recv() => {},
- _i2 = rx2.recv() => panic!()
- }
- tx3.send(()).unwrap();
-}
-
-#[allow(unused_must_use)]
-#[test]
-fn cloning2() {
- let (tx1, rx1) = channel::<i32>();
- let (_tx2, rx2) = channel::<i32>();
- let (tx3, rx3) = channel::<()>();
-
- let _t = thread::spawn(move|| {
- rx3.recv().unwrap();
- tx1.clone();
- assert_eq!(rx3.try_recv(), Err(TryRecvError::Empty));
- tx1.send(2).unwrap();
- rx3.recv().unwrap();
- });
-
- tx3.send(()).unwrap();
- select! {
- _i1 = rx1.recv() => {},
- _i2 = rx2.recv() => panic!()
- }
- tx3.send(()).unwrap();
-}
-
-#[test]
-fn cloning3() {
- let (tx1, rx1) = channel::<()>();
- let (tx2, rx2) = channel::<()>();
- let (tx3, rx3) = channel::<()>();
- let _t = thread::spawn(move|| {
- let s = Select::new();
- let mut h1 = s.handle(&rx1);
- let mut h2 = s.handle(&rx2);
- unsafe { h2.add(); }
- unsafe { h1.add(); }
- assert_eq!(s.wait(), h2.id());
- tx3.send(()).unwrap();
- });
-
- for _ in 0..1000 { thread::yield_now(); }
- drop(tx1.clone());
- tx2.send(()).unwrap();
- rx3.recv().unwrap();
-}
-
-#[test]
-fn preflight1() {
- let (tx, rx) = channel();
- tx.send(()).unwrap();
- select! {
- _n = rx.recv() => {}
- }
-}
-
-#[test]
-fn preflight2() {
- let (tx, rx) = channel();
- tx.send(()).unwrap();
- tx.send(()).unwrap();
- select! {
- _n = rx.recv() => {}
- }
-}
-
-#[test]
-fn preflight3() {
- let (tx, rx) = channel();
- drop(tx.clone());
- tx.send(()).unwrap();
- select! {
- _n = rx.recv() => {}
- }
-}
-
-#[test]
-fn preflight4() {
- let (tx, rx) = channel();
- tx.send(()).unwrap();
- let s = Select::new();
- let mut h = s.handle(&rx);
- unsafe { h.add(); }
- assert_eq!(s.wait2(false), h.id());
-}
-
-#[test]
-fn preflight5() {
- let (tx, rx) = channel();
- tx.send(()).unwrap();
- tx.send(()).unwrap();
- let s = Select::new();
- let mut h = s.handle(&rx);
- unsafe { h.add(); }
- assert_eq!(s.wait2(false), h.id());
-}
-
-#[test]
-fn preflight6() {
- let (tx, rx) = channel();
- drop(tx.clone());
- tx.send(()).unwrap();
- let s = Select::new();
- let mut h = s.handle(&rx);
- unsafe { h.add(); }
- assert_eq!(s.wait2(false), h.id());
-}
-
-#[test]
-fn preflight7() {
- let (tx, rx) = channel::<()>();
- drop(tx);
- let s = Select::new();
- let mut h = s.handle(&rx);
- unsafe { h.add(); }
- assert_eq!(s.wait2(false), h.id());
-}
-
-#[test]
-fn preflight8() {
- let (tx, rx) = channel();
- tx.send(()).unwrap();
- drop(tx);
- rx.recv().unwrap();
- let s = Select::new();
- let mut h = s.handle(&rx);
- unsafe { h.add(); }
- assert_eq!(s.wait2(false), h.id());
-}
-
-#[test]
-fn preflight9() {
- let (tx, rx) = channel();
- drop(tx.clone());
- tx.send(()).unwrap();
- drop(tx);
- rx.recv().unwrap();
- let s = Select::new();
- let mut h = s.handle(&rx);
- unsafe { h.add(); }
- assert_eq!(s.wait2(false), h.id());
-}
-
-#[test]
-fn oneshot_data_waiting() {
- let (tx1, rx1) = channel();
- let (tx2, rx2) = channel();
- let _t = thread::spawn(move|| {
- select! {
- _n = rx1.recv() => {}
- }
- tx2.send(()).unwrap();
- });
-
- for _ in 0..100 { thread::yield_now() }
- tx1.send(()).unwrap();
- rx2.recv().unwrap();
-}
-
-#[test]
-fn stream_data_waiting() {
- let (tx1, rx1) = channel();
- let (tx2, rx2) = channel();
- tx1.send(()).unwrap();
- tx1.send(()).unwrap();
- rx1.recv().unwrap();
- rx1.recv().unwrap();
- let _t = thread::spawn(move|| {
- select! {
- _n = rx1.recv() => {}
- }
- tx2.send(()).unwrap();
- });
-
- for _ in 0..100 { thread::yield_now() }
- tx1.send(()).unwrap();
- rx2.recv().unwrap();
-}
-
-#[test]
-fn shared_data_waiting() {
- let (tx1, rx1) = channel();
- let (tx2, rx2) = channel();
- drop(tx1.clone());
- tx1.send(()).unwrap();
- rx1.recv().unwrap();
- let _t = thread::spawn(move|| {
- select! {
- _n = rx1.recv() => {}
- }
- tx2.send(()).unwrap();
- });
-
- for _ in 0..100 { thread::yield_now() }
- tx1.send(()).unwrap();
- rx2.recv().unwrap();
-}
-
-#[test]
-fn sync1() {
- let (tx, rx) = sync_channel::<i32>(1);
- tx.send(1).unwrap();
- select! {
- n = rx.recv() => { assert_eq!(n.unwrap(), 1); }
- }
-}
-
-#[test]
-fn sync2() {
- let (tx, rx) = sync_channel::<i32>(0);
- let _t = thread::spawn(move|| {
- for _ in 0..100 { thread::yield_now() }
- tx.send(1).unwrap();
- });
- select! {
- n = rx.recv() => { assert_eq!(n.unwrap(), 1); }
- }
-}
-
-#[test]
-fn sync3() {
- let (tx1, rx1) = sync_channel::<i32>(0);
- let (tx2, rx2): (Sender<i32>, Receiver<i32>) = channel();
- let _t = thread::spawn(move|| { tx1.send(1).unwrap(); });
- let _t = thread::spawn(move|| { tx2.send(2).unwrap(); });
- select! {
- n = rx1.recv() => {
- let n = n.unwrap();
- assert_eq!(n, 1);
- assert_eq!(rx2.recv().unwrap(), 2);
- },
- n = rx2.recv() => {
- let n = n.unwrap();
- assert_eq!(n, 2);
- assert_eq!(rx1.recv().unwrap(), 1);
- }
- }
-}
/// channels are quite similar, and this is no coincidence!
pub use self::Failure::*;
+use self::StartResult::*;
use core::cmp;
use core::intrinsics::abort;
use crate::sync::atomic::{AtomicUsize, AtomicIsize, AtomicBool, Ordering};
use crate::sync::mpsc::blocking::{self, SignalToken};
use crate::sync::mpsc::mpsc_queue as mpsc;
-use crate::sync::mpsc::select::StartResult::*;
-use crate::sync::mpsc::select::StartResult;
use crate::sync::{Mutex, MutexGuard};
use crate::thread;
use crate::time::Instant;
Disconnected,
}
+#[derive(PartialEq, Eq)]
+enum StartResult {
+ Installed,
+ Abort,
+}
+
impl<T> Packet<T> {
// Creation of a packet *must* be followed by a call to postinit_lock
// and later by inherit_blocker
// select implementation
////////////////////////////////////////////////////////////////////////////
- // Helper function for select, tests whether this port can receive without
- // blocking (obviously not an atomic decision).
- //
- // This is different than the stream version because there's no need to peek
- // at the queue, we can just look at the local count.
- pub fn can_recv(&self) -> bool {
- let cnt = self.cnt.load(Ordering::SeqCst);
- cnt == DISCONNECTED || cnt - unsafe { *self.steals.get() } > 0
- }
-
// increment the count on the channel (used for selection)
fn bump(&self, amt: isize) -> isize {
match self.cnt.fetch_add(amt, Ordering::SeqCst) {
}
}
- // Inserts the signal token for selection on this port, returning true if
- // blocking should proceed.
- //
- // The code here is the same as in stream.rs, except that it doesn't need to
- // peek at the channel to see if an upgrade is pending.
- pub fn start_selection(&self, token: SignalToken) -> StartResult {
- match self.decrement(token) {
- Installed => Installed,
- Abort => {
- let prev = self.bump(1);
- assert!(prev == DISCONNECTED || prev >= 0);
- Abort
- }
- }
- }
-
// Cancels a previous thread waiting on this port, returning whether there's
// data on the port.
//
pub use self::Failure::*;
pub use self::UpgradeResult::*;
-pub use self::SelectionResult::*;
use self::Message::*;
use core::cmp;
UpWoke(SignalToken),
}
-pub enum SelectionResult<T> {
- SelSuccess,
- SelCanceled,
- SelUpgraded(SignalToken, Receiver<T>),
-}
-
// Any message could contain an "upgrade request" to a new shared port, so the
// internal queue it's a queue of T, but rather Message<T>
enum Message<T> {
// select implementation
////////////////////////////////////////////////////////////////////////////
- // Tests to see whether this port can receive without blocking. If Ok is
- // returned, then that's the answer. If Err is returned, then the returned
- // port needs to be queried instead (an upgrade happened)
- pub fn can_recv(&self) -> Result<bool, Receiver<T>> {
- // We peek at the queue to see if there's anything on it, and we use
- // this return value to determine if we should pop from the queue and
- // upgrade this channel immediately. If it looks like we've got an
- // upgrade pending, then go through the whole recv rigamarole to update
- // the internal state.
- match self.queue.peek() {
- Some(&mut GoUp(..)) => {
- match self.recv(None) {
- Err(Upgraded(port)) => Err(port),
- _ => unreachable!(),
- }
- }
- Some(..) => Ok(true),
- None => Ok(false)
- }
- }
-
// increment the count on the channel (used for selection)
fn bump(&self, amt: isize) -> isize {
match self.queue.producer_addition().cnt.fetch_add(amt, Ordering::SeqCst) {
}
}
- // Attempts to start selecting on this port. Like a oneshot, this can fail
- // immediately because of an upgrade.
- pub fn start_selection(&self, token: SignalToken) -> SelectionResult<T> {
- match self.decrement(token) {
- Ok(()) => SelSuccess,
- Err(token) => {
- let ret = match self.queue.peek() {
- Some(&mut GoUp(..)) => {
- match self.queue.pop() {
- Some(GoUp(port)) => SelUpgraded(token, port),
- _ => unreachable!(),
- }
- }
- Some(..) => SelCanceled,
- None => SelCanceled,
- };
- // Undo our decrement above, and we should be guaranteed that the
- // previous value is positive because we're not going to sleep
- let prev = self.bump(1);
- assert!(prev == DISCONNECTED || prev >= 0);
- ret
- }
- }
- }
-
// Removes a previous thread from being blocked in this port
pub fn abort_selection(&self,
was_upgrade: bool) -> Result<bool, Receiver<T>> {
use crate::sync::atomic::{Ordering, AtomicUsize};
use crate::sync::mpsc::blocking::{self, WaitToken, SignalToken};
-use crate::sync::mpsc::select::StartResult::{self, Installed, Abort};
use crate::sync::{Mutex, MutexGuard};
use crate::time::Instant;
while let Some(token) = queue.dequeue() { token.signal(); }
waiter.map(|t| t.signal());
}
-
- ////////////////////////////////////////////////////////////////////////////
- // select implementation
- ////////////////////////////////////////////////////////////////////////////
-
- // If Ok, the value is whether this port has data, if Err, then the upgraded
- // port needs to be checked instead of this one.
- pub fn can_recv(&self) -> bool {
- let guard = self.lock.lock().unwrap();
- guard.disconnected || guard.buf.size() > 0
- }
-
- // Attempts to start selection on this port. This can either succeed or fail
- // because there is data waiting.
- pub fn start_selection(&self, token: SignalToken) -> StartResult {
- let mut guard = self.lock.lock().unwrap();
- if guard.disconnected || guard.buf.size() > 0 {
- Abort
- } else {
- match mem::replace(&mut guard.blocker, BlockedReceiver(token)) {
- NoneBlocked => {}
- BlockedSender(..) => unreachable!(),
- BlockedReceiver(..) => unreachable!(),
- }
- Installed
- }
- }
-
- // Remove a previous selecting thread from this port. This ensures that the
- // blocked thread will no longer be visible to any other threads.
- //
- // The return value indicates whether there's data on this port.
- pub fn abort_selection(&self) -> bool {
- let mut guard = self.lock.lock().unwrap();
- abort_selection(&mut guard)
- }
}
impl<T> Drop for Packet<T> {
impl<T> From<T> for Mutex<T> {
/// Creates a new mutex in an unlocked state ready for use.
/// This is equivalent to [`Mutex::new`].
+ ///
+ /// [`Mutex::new`]: ../../std/sync/struct.Mutex.html#method.new
fn from(t: T) -> Self {
Mutex::new(t)
}
impl<T> From<T> for RwLock<T> {
/// Creates a new instance of an `RwLock<T>` which is unlocked.
/// This is equivalent to [`RwLock::new`].
+ ///
+ /// [`RwLock::new`]: ../../std/sync/struct.RwLock.html#method.new
fn from(t: T) -> Self {
RwLock::new(t)
}
let err = errno() as libc::c_int;
if err == libc::EINTR {
continue;
- } else if err == libc::ENOSYS {
+ } else if err == libc::ENOSYS || err == libc::EPERM {
+ // Fall back to reading /dev/urandom if `getrandom` is not
+ // supported on the current kernel.
+ //
+ // Also fall back in case it is disabled by something like
+ // seccomp or inside of virtual machines.
GETRANDOM_UNAVAILABLE.store(true, Ordering::Relaxed);
return false;
} else if err == libc::EAGAIN {
/// [`Builder::spawn`]: ../../std/thread/struct.Builder.html#method.spawn
/// [`io::Result`]: ../../std/io/type.Result.html
/// [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html
+ /// [`JoinHandle::join`]: ../../std/thread/struct.JoinHandle.html#method.join
#[unstable(feature = "thread_spawn_unchecked", issue = "55132")]
pub unsafe fn spawn_unchecked<'a, F, T>(self, f: F) -> io::Result<JoinHandle<T>> where
F: FnOnce() -> T, F: Send + 'a, T: Send + 'a
use rustc_data_structures::indexed_vec::Idx;
#[cfg(target_arch = "x86_64")]
-use rustc_data_structures::static_assert;
+use rustc_data_structures::static_assert_size;
use rustc_target::spec::abi::Abi;
use syntax_pos::{Span, DUMMY_SP};
// `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(target_arch = "x86_64")]
-static_assert!(MEM_SIZE_OF_EXPR: std::mem::size_of::<Expr>() == 96);
+static_assert_size!(Expr, 96);
impl Expr {
/// Whether this expression would be valid somewhere that expects a value; for example, an `if`
(sym::repr, Normal, template!(List: "C, packed, ..."), Ungated),
(sym::path, Normal, template!(NameValueStr: "file"), Ungated),
(sym::automatically_derived, Normal, template!(Word), Ungated),
- (sym::no_mangle, Normal, template!(Word), Ungated),
+ (sym::no_mangle, Whitelisted, template!(Word), Ungated),
(sym::no_link, Normal, template!(Word), Ungated),
(sym::derive, Normal, template!(List: "Trait1, Trait2, ..."), Ungated),
(
use std::fmt;
use std::mem;
#[cfg(target_arch = "x86_64")]
-use rustc_data_structures::static_assert;
+use rustc_data_structures::static_assert_size;
use rustc_data_structures::sync::Lrc;
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
}
#[cfg(target_arch = "x86_64")]
-static_assert!(MEM_SIZE_OF_LIT: mem::size_of::<Lit>() == 8);
+static_assert_size!(Lit, 8);
impl Lit {
crate fn literal_name(&self) -> &'static str {
// `Token` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(target_arch = "x86_64")]
-static_assert!(MEM_SIZE_OF_STATEMENT: mem::size_of::<Token>() == 16);
+static_assert_size!(Token, 16);
impl Token {
/// Recovers a `Token` from an `ast::Ident`. This creates a raw identifier if necessary.
use syntax_pos::{BytePos, Mark, Span, DUMMY_SP};
#[cfg(target_arch = "x86_64")]
-use rustc_data_structures::static_assert;
+use rustc_data_structures::static_assert_size;
use rustc_data_structures::sync::Lrc;
use serialize::{Decoder, Decodable, Encoder, Encodable};
use smallvec::{SmallVec, smallvec};
// `TokenStream` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(target_arch = "x86_64")]
-static_assert!(MEM_SIZE_OF_TOKEN_STREAM: mem::size_of::<TokenStream>() == 8);
+static_assert_size!(TokenStream, 8);
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum IsJoint {
eh_personality,
eh_unwind_resume,
enable,
+ err,
Err,
except,
exclusive_range_pattern,
fundamental,
future,
Future,
+ gen_future,
generators,
generic_associated_types,
generic_param_attrs,
never,
never_type,
next,
+ __next,
nll,
no_builtins,
no_core,
Pending,
pin,
Pin,
+ pinned,
platform_intrinsics,
plugin,
plugin_registrar,
trivial_bounds,
Try,
try_blocks,
+ try_trait,
tuple_indexing,
ty,
type_alias_enum_variants,
uniform_paths,
universal_impl_trait,
unmarked_api,
+ unreachable_code,
unrestricted_attribute_tokens,
unsafe_destructor_blind_to_params,
unsafe_no_drop_flag,
use_nested_groups,
usize,
v1,
+ val,
vis,
visible_private_types,
volatile,
}
impl LocalInternedString {
+ /// Maps a string to its interned representation.
+ pub fn intern(string: &str) -> Self {
+ let string = with_interner(|interner| {
+ let symbol = interner.intern(string);
+ interner.strings[symbol.0.as_usize()]
+ });
+ LocalInternedString {
+ string: unsafe { std::mem::transmute::<&str, &str>(string) }
+ }
+ }
+
pub fn as_interned_str(self) -> InternedString {
InternedString {
symbol: Symbol::intern(self.string)
impl Decodable for LocalInternedString {
fn decode<D: Decoder>(d: &mut D) -> Result<LocalInternedString, D::Error> {
- Ok(Symbol::intern(&d.read_str()?).as_str())
+ Ok(LocalInternedString::intern(&d.read_str()?))
}
}
}
impl InternedString {
+ /// Maps a string to its interned representation.
+ pub fn intern(string: &str) -> Self {
+ InternedString {
+ symbol: Symbol::intern(string)
+ }
+ }
+
pub fn with<F: FnOnce(&str) -> R, R>(self, f: F) -> R {
let str = with_interner(|interner| {
interner.get(self.symbol) as *const str
impl Decodable for InternedString {
fn decode<D: Decoder>(d: &mut D) -> Result<InternedString, D::Error> {
- Ok(Symbol::intern(&d.read_str()?).as_interned_str())
+ Ok(InternedString::intern(&d.read_str()?))
}
}
use term;
// FIXME(#54291): rustc and/or LLVM don't yet support building with panic-unwind
-// on aarch64-pc-windows-msvc, so we don't link libtest against
-// libunwind (for the time being), even though it means that
-// libtest won't be fully functional on this platform.
+// on aarch64-pc-windows-msvc, or thumbv7a-pc-windows-msvc
+// so we don't link libtest against libunwind (for the time being)
+// even though it means that libtest won't be fully functional on
+// these platforms.
//
// See also: https://github.com/rust-lang/rust/issues/54190#issuecomment-422904437
-#[cfg(not(all(windows, target_arch = "aarch64")))]
+#[cfg(not(all(windows, any(target_arch = "aarch64", target_arch = "arm"))))]
extern crate panic_unwind;
pub use self::ColorConfig::*;
cfg.flag("-std=c99");
cfg.flag("-std=c++11");
cfg.flag("-nostdinc++");
- if cfg.is_flag_supported("-funwind-tables").unwrap_or_default() &&
- cfg.is_flag_supported("-fno-exceptions").unwrap_or_default() {
- cfg.flag("-funwind-tables");
- cfg.flag("-fno-exceptions");
- }
+ cfg.flag("-fno-exceptions");
cfg.flag("-fno-rtti");
cfg.flag("-fstrict-aliasing");
+ cfg.flag("-funwind-tables");
}
let mut unwind_sources = vec![
-Subproject commit eb38a1888d1d29b2d2c6b31428a5201cd8fba0ff
+Subproject commit 2c5656ae593851d0b2336a727cc14b77a06b8ac0
// compile-flags: -O
#![crate_type="lib"]
-#![feature(maybe_uninit)]
use std::mem::MaybeUninit;
// ignore-netbsd
// ignore-openbsd
// ignore-solaris
+// ignore-sgx no dynamic linking
// aux-build:dummy.rs
// aux-build:wrapper.rs
// ignore-netbsd
// ignore-openbsd
// ignore-solaris
+// ignore-sgx
// compile-flags: -C no-prepopulate-passes -C panic=abort -O
// Test what happens we save incremental compilation state that makes
// use of foreign items. This used to ICE (#34991).
+// ignore-sgx no libc
// revisions: rpass1
--- /dev/null
+// revisions:rpass1 rpass2
+// compile-flags: --crate-type cdylib
+// skip-codegen
+
+#![deny(unused_attributes)]
+
+#[no_mangle]
+pub extern "C" fn rust_no_mangle() -> i32 {
+ 42
+}
// bb0: {
// ...
// _5 = const true;
-// assert(move _5, "index out of bounds: the len is move _4 but the index is _3") -> bb1;
+// assert(const true, "index out of bounds: the len is move _4 but the index is _3") -> bb1;
// }
// bb1: {
// _1 = _2[_3];
// bb0: {
// ...
// _2 = (const 2u32, const false);
-// assert(!move (_2.1: bool), "attempt to add with overflow") -> bb1;
+// assert(!const false, "attempt to add with overflow") -> bb1;
// }
// END rustc.main.ConstProp.after.mir
--- /dev/null
+#[inline(never)]
+fn foo(_: i32) { }
+
+fn main() {
+ match 1 {
+ 1 => foo(0),
+ _ => foo(-1),
+ }
+}
+
+// END RUST SOURCE
+// START rustc.main.ConstProp.before.mir
+// bb0: {
+// ...
+// _1 = const 1i32;
+// switchInt(_1) -> [1i32: bb1, otherwise: bb2];
+// }
+// END rustc.main.ConstProp.before.mir
+// START rustc.main.ConstProp.after.mir
+// bb0: {
+// ...
+// switchInt(const 1i32) -> [1i32: bb1, otherwise: bb2];
+// }
+// END rustc.main.ConstProp.after.mir
+// START rustc.main.SimplifyBranches-after-const-prop.before.mir
+// bb0: {
+// ...
+// _1 = const 1i32;
+// switchInt(const 1i32) -> [1i32: bb1, otherwise: bb2];
+// }
+// END rustc.main.SimplifyBranches-after-const-prop.before.mir
+// START rustc.main.SimplifyBranches-after-const-prop.after.mir
+// bb0: {
+// ...
+// _1 = const 1i32;
+// goto -> bb1;
+// }
+// END rustc.main.SimplifyBranches-after-const-prop.after.mir
}
// END RUST SOURCE
-// START rustc.main.SimplifyBranches-after-copy-prop.before.mir
+// START rustc.main.SimplifyBranches-after-const-prop.before.mir
// bb0: {
// ...
// switchInt(const false) -> [false: bb3, otherwise: bb1];
// }
-// END rustc.main.SimplifyBranches-after-copy-prop.before.mir
-// START rustc.main.SimplifyBranches-after-copy-prop.after.mir
+// END rustc.main.SimplifyBranches-after-const-prop.before.mir
+// START rustc.main.SimplifyBranches-after-const-prop.after.mir
// bb0: {
// ...
// goto -> bb3;
// }
-// END rustc.main.SimplifyBranches-after-copy-prop.after.mir
+// END rustc.main.SimplifyBranches-after-const-prop.after.mir
// no-prefer-dynamic
// ignore-cloudabi
// ignore-emscripten
+// ignore-sgx no processes
// ignore-macos this needs valgrind 3.11 or higher; see
// https://github.com/rust-lang/rust/pull/30365#issuecomment-165763679
// ignore-cloudabi no env and process
// ignore-emscripten no processes
+// ignore-sgx no processes
use std::{env, panic};
use std::io::prelude::*;
#![allow(deprecated)]
// ignore-cloudabi no process support
// ignore-emscripten no threads support
+// ignore-sgx no processes
use std::{env, fmt, process, sync, thread};
// ignore-cloudabi spawning processes is not supported
// ignore-emscripten spawning processes is not supported
// normalize-stderr-test ".*\n" -> ""
+// ignore-sgx no processes
// Note that above `-opt-bisect-limit=0` is used to basically disable
// optimizations. It creates tons of output on stderr, hence we normalize
// ignore-cloudabi spawning processes is not supported
// ignore-emscripten spawning processes is not supported
// ignore-openbsd no support for libbacktrace without filename
+// ignore-sgx no processes
// compile-flags:-g
use std::env;
// ignore-wasm32-bare no libc to test with
+// ignore-sgx no libc
#![feature(rustc_private)]
// pretty-expanded FIXME #23616
// ignore-cloudabi no target_family
// ignore-wasm32-bare no target_family
+// ignore-sgx
#[cfg(windows)]
pub fn main() {
// run-pass
// ignore-cloudabi no target_family
// ignore-wasm32-bare no target_family
+// ignore-sgx
// pretty-expanded FIXME #23616
// ignore-pretty issue #37199
// ignore-cloudabi no processes
// ignore-emscripten no processes
+// ignore-sgx no processes
#![feature(process_exec)]
// ignore-windows - this is a unix-specific test
// ignore-cloudabi no processes
// ignore-emscripten no processes
+// ignore-sgx no processes
#![feature(process_exec, rustc_private)]
extern crate libc;
// compile-flags:--test
// ignore-cloudabi no processes
// ignore-emscripten no processes
+// ignore-sgx no processes
// N.B., these tests kill child processes. Valgrind sees these children as leaking
// memory, which makes for some *confusing* logs. That's why these are here
// ignore-cloudabi no processes
// ignore-emscripten no processes
+// ignore-sgx no processes
use std::alloc::{Layout, handle_alloc_error};
use std::env;
// ignore-cloudabi no processes
// ignore-emscripten no processes
+// ignore-sgx no processes
use std::env::args;
use std::process::Command;
// ignore-windows
// ignore-cloudabi no execve
// ignore-emscripten no execve
+// ignore-sgx no execve
// no-prefer-dynamic
#![feature(rustc_private)]
#![allow(deprecated)]
// ignore-cloudabi no environment variables present
// ignore-emscripten env vars don't work?
+// ignore-sgx env vars cannot be modified
use std::env::*;
use std::path::PathBuf;
// exec-env:TEST_EXEC_ENV=22
// ignore-cloudabi no env vars
// ignore-emscripten FIXME: issue #31622
+// ignore-sgx unsupported
use std::env;
// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-haiku
+// ignore-sgx no processes
#![feature(rustc_private)]
// run-pass
// ignore-wasm32-bare no libc to test ffi with
+// ignore-sgx no libc
#![feature(rustc_private)]
// ignore-emscripten
// ignore-wasm32
+// ignore-sgx no processes
use std::env;
use std::process::Command;
}
}
+#[cfg(target_env = "sgx")]
+mod m {
+ #[main]
+ #[cfg(target_arch = "x86_64")]
+ pub fn main() {
+ unsafe {
+ assert_eq!(::rusti::pref_align_of::<u64>(), 8);
+ assert_eq!(::rusti::min_align_of::<u64>(), 8);
+ }
+ }
+}
+
#[cfg(target_os = "windows")]
mod m {
#[main]
#![allow(unused_mut)]
// ignore-wasm32
// ignore-emscripten
+// ignore-sgx no processes
// compile-flags: -C debug_assertions=yes
// edition:2018
// run-pass
// ignore-emscripten no threads support
+// ignore-sgx no thread sleep support
use std::thread;
use std::time::Duration;
// run-pass
// ignore-cloudabi no processes
// ignore-emscripten no processes
+// ignore-sgx no processes
// Make sure that if a process doesn't have its stdio/stderr descriptors set up
// that we don't die in a large ball of fire
// ignore-cloudabi no dylib support
// ignore-emscripten no dylib support
// ignore-musl
+// ignore-sgx no dylib support
// pretty-expanded FIXME #23616
// run-pass
// ignore-wasm32-bare can't block the thread
+// ignore-sgx not supported
#![allow(deprecated)]
use std::thread;
#![allow(unused_mut)]
// ignore-cloudabi no processes
// ignore-emscripten no processes
+// ignore-sgx no processes
use std::env;
use std::io::prelude::*;
+++ /dev/null
-// run-pass
-#![allow(unused_must_use)]
-// ignore-emscripten no threads support
-
-// This test may not always fail, but it can be flaky if the race it used to
-// expose is still present.
-
-#![feature(mpsc_select)]
-#![allow(deprecated)]
-
-use std::sync::mpsc::{channel, Sender, Receiver};
-use std::thread;
-
-fn helper(rx: Receiver<Sender<()>>) {
- for tx in rx.iter() {
- let _ = tx.send(());
- }
-}
-
-fn main() {
- let (tx, rx) = channel();
- let t = thread::spawn(move|| { helper(rx) });
- let (snd, rcv) = channel::<isize>();
- for _ in 1..100000 {
- snd.send(1).unwrap();
- let (tx2, rx2) = channel();
- tx.send(tx2).unwrap();
- select! {
- _ = rx2.recv() => (),
- _ = rcv.recv() => ()
- }
- }
- drop(tx);
- t.join();
-}
#![allow(unused_mut)]
// ignore-cloudabi no processes
// ignore-emscripten no processes
+// ignore-sgx no processes
use std::env;
use std::io::prelude::*;
// run-pass
// ignore-cloudabi no processes
// ignore-emscripten no processes
+// ignore-sgx no processes
use std::env;
use std::process::Command;
// run-pass
// ignore-cloudabi no processes
// ignore-emscripten no processes
+// ignore-sgx no processes
use std::process::Command;
use std::env;
// run-pass
// ignore-wasm32-bare no libc to test ffi with
-
+// ignore-sgx no libc
#![feature(rustc_private)]
extern crate libc;
// run-pass
// ignore-cloudabi no processes
// ignore-emscripten no threads
+// ignore-sgx no processes
use std::thread;
use std::env;
// run-pass
// ignore-cloudabi no processes
// ignore-emscripten no processes
+// ignore-sgx no processes
// Previously libstd would set stdio descriptors of a child process
// by `dup`ing the requested descriptors to inherit directly into the
// run-pass
// ignore-cloudabi no processes
// ignore-emscripten no processes
+// ignore-sgx no processes
use std::process::{Command, Stdio};
use std::env;
#![allow(unused_must_use)]
#![allow(deprecated)]
// ignore-emscripten no threads support
+// ignore-sgx no thread sleep support
use std::sync::mpsc::{TryRecvError, channel};
use std::thread;
// ignore-windows
// ignore-macos
// ignore-emscripten doesn't support this linkage
+// ignore-sgx weak linkage not permitted
// aux-build:linkage1.rs
#![feature(linkage)]
println!("hello {}", "world",);
}
-// select! is too troublesome and unlikely to be stabilized
-
// stringify! is N/A
#[cfg(std)]
// compile-flags:--test
// ignore-emscripten
+// ignore-sgx no thread sleep support
use std::sync::mpsc::channel;
use std::sync::mpsc::TryRecvError;
// ignore-cloudabi no processes
// ignore-emscripten no processes
+// ignore-sgx no processes
fn check_for_no_backtrace(test: std::process::Output) {
assert!(!test.status.success());
// ignore-android
// ignore-cloudabi no processes
// ignore-emscripten no processes
+// ignore-sgx no processes
#![feature(rustc_private)]
// ignore-musl
// ignore-cloudabi no processes
// ignore-emscripten no processes
+// ignore-sgx no processes
#![feature(asm)]
#![feature(rustc_private)]
// no-prefer-dynamic
// ignore-cloudabi no processes
// ignore-emscripten no processes
+// ignore-sgx no processes
// ignore-macos
extern crate exit_success_if_unwind;
// no-prefer-dynamic
// ignore-cloudabi no processes
// ignore-emscripten no processes
+// ignore-sgx no processes
// ignore-macos
use std::process::Command;
// no-prefer-dynamic
// ignore-cloudabi no processes
// ignore-emscripten no processes
+// ignore-sgx no processes
use std::process::Command;
use std::env;
// no-prefer-dynamic
// ignore-cloudabi no processes
// ignore-emscripten no processes
+// ignore-sgx no processes
use std::process::Command;
use std::env;
// This test checks that instantiating an uninhabited type via `mem::{uninitialized,zeroed}` results
// in a runtime panic.
-#![feature(never_type, maybe_uninit)]
+#![feature(never_type)]
use std::{mem, panic};
// ignore-cloudabi no files or I/O
// ignore-wasm32-bare no files or I/O
// ignore-emscripten no files
+// ignore-sgx no files
use std::fs;
use std::io;
// ignore-cloudabi spawning processes is not supported
// ignore-emscripten spawning processes is not supported
+// ignore-sgx no processes
use std::{env, process};
// run-pass
// ignore-cloudabi no processes
// ignore-emscripten no processes
+// ignore-sgx no processes
use std::process::Command;
use std::env;
#![allow(unused_imports)]
// ignore-cloudabi no processes
// ignore-emscripten no processes
+// ignore-sgx no processes
use std::env;
use std::process::{self, Command, Stdio};
// run-pass
// ignore-cloudabi no processes
// ignore-emscripten no processes
+// ignore-sgx no processes
use std::process::Command;
use std::env;
// run-pass
// ignore-cloudabi no processes
// ignore-emscripten no processes
+// ignore-sgx no processes
use std::io::ErrorKind;
use std::process::Command;
// ignore-cloudabi no processes
// ignore-emscripten no processes
+// ignore-sgx no processes
use std::io::prelude::*;
use std::io;
// run-pass
// ignore-cloudabi no processes
// ignore-emscripten no processes
+// ignore-sgx no processes
use std::env;
use std::io;
#![allow(dead_code)]
// ignore-cloudabi stdout does not map to file descriptor 1 by default
// ignore-wasm32-bare no libc
+// ignore-sgx no libc
#![feature(rustc_private)]
// ignore-cloudabi spawning processes is not supported
// ignore-emscripten spawning processes is not supported
+// ignore-sgx no processes
#![feature(start)]
#![allow(unused_imports)]
// ignore-cloudabi can't run commands
// ignore-emscripten can't run commands
+// ignore-sgx no processes
#![feature(rustc_private)]
// ignore-cloudabi no signal handling support
// ignore-wasm32-bare no libc
// ignore-windows
+// ignore-sgx no libc
#![feature(rustc_private)]
extern crate libc;
// ignore-cloudabi no processes
// ignore-emscripten no processes
+// ignore-sgx no processes
// ignore-windows
use std::env;
// ignore-cloudabi no processes
// ignore-emscripten no processes
+// ignore-sgx no processes
use std::env;
use std::io::prelude::*;
#![allow(overflowing_literals)]
// ignore-emscripten
+// ignore-sgx no processes
#![feature(repr_simd, target_feature, cfg_target_feature)]
#![feature(avx512_target_feature)]
// ignore-emscripten no threads support
+// ignore-sgx no thread sleep support
use std::thread::{self, sleep};
use std::time::Duration;
// ignore-wasm
// ignore-cloudabi no processes
// ignore-emscripten no processes
+// ignore-sgx no processes
// ignore-musl FIXME #31506
// ignore-pretty
// compile-flags: -C lto
// ignore-wasm
// ignore-cloudabi no processes
// ignore-emscripten no processes
+// ignore-sgx no processes
// ignore-musl FIXME #31506
use std::mem;
// ignore-cloudabi no processes
// ignore-emscripten no processes
+// ignore-sgx no processes
use std::env;
use std::io::prelude::*;
}
}
+#[cfg(target_env = "sgx")]
+mod m {
+ #[cfg(target_arch = "x86_64")]
+ pub mod m {
+ pub fn align() -> usize { 8 }
+ pub fn size() -> usize { 16 }
+ }
+}
+
#[cfg(target_os = "windows")]
mod m {
#[cfg(target_arch = "x86")]
// ignore-emscripten no threads or sockets support
// ignore-netbsd system ulimit (Too many open files)
// ignore-openbsd system ulimit (Too many open files)
+// ignore-sgx no thread sleep support
use std::io::prelude::*;
use std::net::{TcpListener, TcpStream};
// ignore-cloudabi networking not available
// ignore-wasm32-bare networking not available
+// ignore-sgx ToSocketAddrs cannot be used for DNS Resolution
use std::net::ToSocketAddrs;
#![allow(stable_features)]
// ignore-cloudabi no processes
// ignore-emscripten no processes
+// ignore-sgx no processes
#![feature(process_try_wait)]
--- /dev/null
+// run-pass
+#![allow(dead_code)]
+
+// Tests that unions aren't subject to unsafe non-zero/niche-filling optimizations.
+//
+// For example, if a union `U` can contain both a `&T` and a `*const T`, there's definitely no
+// bit-value that an `Option<U>` could reuse as `None`; this test makes sure that isn't done.
+//
+// Secondly, this tests the status quo (not a guarantee; subject to change!) to not apply such
+// optimizations to types containing unions even if they're theoretically possible. (discussion:
+// https://github.com/rust-lang/rust/issues/36394)
+//
+// Notably this nails down part of the behavior that `MaybeUninit` assumes: that a
+// `Option<MaybeUninit<&u8>>` does not take advantage of non-zero optimization, and thus is a safe
+// construct.
+
+use std::mem::{size_of, transmute};
+
+union U1<A: Copy> {
+ a: A,
+}
+
+union U2<A: Copy, B: Copy> {
+ a: A,
+ b: B,
+}
+
+// Option<E> uses a value other than 0 and 1 as None
+#[derive(Clone,Copy)]
+enum E {
+ A = 0,
+ B = 1,
+}
+
+fn main() {
+ // Unions do not participate in niche-filling/non-zero optimization...
+ assert!(size_of::<Option<U2<&u8, u8>>>() > size_of::<U2<&u8, u8>>());
+ assert!(size_of::<Option<U2<&u8, ()>>>() > size_of::<U2<&u8, ()>>());
+ assert!(size_of::<Option<U2<u8, E>>>() > size_of::<U2<u8, E>>());
+
+ // ...even when theoretically possible:
+ assert!(size_of::<Option<U1<&u8>>>() > size_of::<U1<&u8>>());
+ assert!(size_of::<Option<U2<&u8, &u8>>>() > size_of::<U2<&u8, &u8>>());
+
+ // The unused bits of the () variant can have any value.
+ let zeroed: U2<&u8, ()> = unsafe { transmute(std::ptr::null::<u8>()) };
+
+ if let None = Some(zeroed) {
+ panic!()
+ }
+}
// ignore-cloudabi no processes
// ignore-emscripten no processes
+// ignore-sgx no processes
#![feature(rustc_private)]
// ignore-wasm32-bare no libc to test ffi with
-
+// ignore-sgx no libc
// GetLastError doesn't seem to work with stack switching
#[cfg(windows)]
-//~ ERROR Missing code example in this documentation
-
-#![deny(missing_doc_code_examples)]
+#![deny(missing_doc_code_examples)] //~ ERROR Missing code example in this documentation
/// Some docs.
//~^ ERROR Missing code example in this documentation
error: Missing code example in this documentation
+ --> $DIR/doc-without-codeblock.rs:1:1
+ |
+LL | / #![deny(missing_doc_code_examples)]
+LL | |
+LL | | /// Some docs.
+LL | |
+... |
+LL | | pub fn bar() {}
+LL | | }
+ | |_^
|
note: lint level defined here
- --> $DIR/doc-without-codeblock.rs:3:9
+ --> $DIR/doc-without-codeblock.rs:1:9
|
LL | #![deny(missing_doc_code_examples)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: Missing code example in this documentation
- --> $DIR/doc-without-codeblock.rs:5:1
+ --> $DIR/doc-without-codeblock.rs:3:1
|
LL | /// Some docs.
| ^^^^^^^^^^^^^^
error: Missing code example in this documentation
- --> $DIR/doc-without-codeblock.rs:9:1
+ --> $DIR/doc-without-codeblock.rs:7:1
|
LL | /// And then, the princess died.
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: Missing code example in this documentation
- --> $DIR/doc-without-codeblock.rs:12:5
+ --> $DIR/doc-without-codeblock.rs:10:5
|
LL | /// Or maybe not because she saved herself!
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
--- /dev/null
+#![deny(missing_docs)]
+#![deny(missing_doc_code_examples)]
+
+//! crate level doc
+//! ```
+//! println!("hello"):
+//! ```
+
+
+/// doc
+///
+/// ```
+/// println!("hello");
+/// ```
+fn test() {
+}
+
+#[allow(missing_docs)]
+mod module1 { //~ ERROR
+}
+
+#[allow(missing_doc_code_examples)]
+/// doc
+mod module2 {
+
+ /// doc
+ pub fn test() {}
+}
+
+/// doc
+///
+/// ```
+/// println!("hello");
+/// ```
+pub mod module3 {
+
+ /// doc
+ //~^ ERROR
+ pub fn test() {}
+}
--- /dev/null
+error: Missing code example in this documentation
+ --> $DIR/lint-missing-doc-code-example.rs:19:1
+ |
+LL | / mod module1 {
+LL | | }
+ | |_^
+ |
+note: lint level defined here
+ --> $DIR/lint-missing-doc-code-example.rs:2:9
+ |
+LL | #![deny(missing_doc_code_examples)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Missing code example in this documentation
+ --> $DIR/lint-missing-doc-code-example.rs:37:3
+ |
+LL | /// doc
+ | ^^^^^^^
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+// compile-flags:--test
+// edition:2018
+
+// prior to setting the default edition for the doctest pre-parser, this doctest would fail due to
+// a fatal parsing error
+// see https://github.com/rust-lang/rust/issues/59313
+
+//! ```
+//! #![feature(async_await)]
+//!
+//! fn foo() {
+//! drop(async move {});
+//! }
+//! ```
#[export_name = "bar"]
pub extern "C" fn g() {}
-// @has foo/enum.Foo.html '//*[@class="docblock attributes"]' '#[repr(i64)]'
-// @has foo/enum.Foo.html '//*[@class="docblock attributes"]' '#[must_use]'
+// @has foo/enum.Foo.html '//*[@class="docblock attributes top-attr"]' '#[repr(i64)]'
+// @has foo/enum.Foo.html '//*[@class="docblock attributes top-attr"]' '#[must_use]'
#[repr(i64)]
#[must_use]
pub enum Foo {
--- /dev/null
+#![feature(const_generics)]
+#![crate_name = "foo"]
+
+// ignore-tidy-linelength
+
+pub enum Order {
+ Sorted,
+ Unsorted,
+}
+
+// @has foo/struct.VSet.html '//pre[@class="rust struct"]' 'pub struct VSet<T, const ORDER: Order>'
+// @has foo/struct.VSet.html '//h3[@id="impl-Send"]/code' 'impl<const ORDER: Order, T> Send for VSet<T, ORDER>'
+// @has foo/struct.VSet.html '//h3[@id="impl-Sync"]/code' 'impl<const ORDER: Order, T> Sync for VSet<T, ORDER>'
+pub struct VSet<T, const ORDER: Order> {
+ inner: Vec<T>,
+}
+
+// @has foo/struct.VSet.html '//h3[@id="impl"]/code' 'impl<T> VSet<T, { Order::Sorted }>'
+impl <T> VSet<T, {Order::Sorted}> {
+ pub fn new() -> Self {
+ Self { inner: Vec::new() }
+ }
+}
+
+// @has foo/struct.VSet.html '//h3[@id="impl-1"]/code' 'impl<T> VSet<T, { Order::Unsorted }>'
+impl <T> VSet<T, {Order::Unsorted}> {
+ pub fn new() -> Self {
+ Self { inner: Vec::new() }
+ }
+}
--- /dev/null
+#![deny(intra_doc_link_resolution_failure)]
+
+pub use std::*;
pub fn dummy() {}
// ensure that `extern crate foo;` was inserted into code snips automatically:
-// @matches foo/index.html '//a[@class="test-arrow"][@href="https://example.com/?code=%23!%5Ballow(unused)%5D%0Aextern%20crate%20foo%3B%0Afn%20main()%20%7B%0Ause%20foo%3A%3Adummy%3B%0Adummy()%3B%0A%7D"]' "Run"
+// @matches foo/index.html '//a[@class="test-arrow"][@href="https://example.com/?code=%23!%5Ballow(unused)%5D%0Aextern%20crate%20foo%3B%0Afn%20main()%20%7B%0Ause%20foo%3A%3Adummy%3B%0Adummy()%3B%0A%7D&edition=2015"]' "Run"
//! }
//! ```
-// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D"]' "Run"
-// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn%20main()%20%7B%0Aprintln!(%22Hello%2C%20world!%22)%3B%0A%7D"]' "Run"
-// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0A%23!%5Bfeature(something)%5D%0A%0Afn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D&version=nightly"]' "Run"
+// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D&edition=2015"]' "Run"
+// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn%20main()%20%7B%0Aprintln!(%22Hello%2C%20world!%22)%3B%0A%7D&edition=2015"]' "Run"
+// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0A%23!%5Bfeature(something)%5D%0A%0Afn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D&version=nightly&edition=2015"]' "Run"
// ignore-musl
// ignore-cloudabi
// ignore-emscripten
-
+// ignore-sgx no dynamic libraries
#![crate_type = "cdylib"]
extern crate cdylib_dep;
--- /dev/null
+use std::alloc::Layout;
+
+// ok
+const LAYOUT_VALID: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x08) };
+
+// not ok, since alignment needs to be non-zero.
+const LAYOUT_INVALID: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) };
+//~^ ERROR it is undefined behavior to use this value
+
+fn main() {}
--- /dev/null
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/alloc.rs:7:1
+ |
+LL | const LAYOUT_INVALID: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0 at .align_, but expected something greater or equal to 1
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
//~^ WARN unused attribute
#![path = "3800"] //~ WARN unused attribute
#![automatically_derived] //~ WARN unused attribute
-#![no_mangle] //~ WARN unused attribute
+#![no_mangle]
#![no_link] //~ WARN unused attribute
// see issue-43106-gating-of-derive.rs
#![should_panic] //~ WARN unused attribute
LL | #![automatically_derived]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
-warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:55:1
- |
-LL | #![no_mangle]
- | ^^^^^^^^^^^^^
-
warning: unused attribute
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:56:1
|
#![deny(unused_extern_crates)]
-extern crate core as iso1; //~ ERROR `extern crate` is not idiomatic in the new edition
-extern crate core as iso2; //~ ERROR `extern crate` is not idiomatic in the new edition
-extern crate core as iso3; //~ ERROR `extern crate` is not idiomatic in the new edition
-extern crate core as iso4; //~ ERROR `extern crate` is not idiomatic in the new edition
+// Shouldn't suggest changing to `use`, as new name
+// would no longer be added to the prelude which could cause
+// compilation errors for imports that use the new name in
+// other modules. See #57672.
+extern crate core as iso1;
+extern crate core as iso2;
+extern crate core as iso3;
+extern crate core as iso4;
// Doesn't introduce its extern prelude entry, so it's still considered unused.
extern crate core; //~ ERROR unused extern crate
-error: `extern crate` is not idiomatic in the new edition
- --> $DIR/extern-crate-used.rs:8:1
+error: unused extern crate
+ --> $DIR/extern-crate-used.rs:18:1
|
-LL | extern crate core as iso1;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `use`
+LL | extern crate core;
+ | ^^^^^^^^^^^^^^^^^^ help: remove it
|
note: lint level defined here
--> $DIR/extern-crate-used.rs:6:9
LL | #![deny(unused_extern_crates)]
| ^^^^^^^^^^^^^^^^^^^^
-error: `extern crate` is not idiomatic in the new edition
- --> $DIR/extern-crate-used.rs:9:1
- |
-LL | extern crate core as iso2;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `use`
-
-error: `extern crate` is not idiomatic in the new edition
- --> $DIR/extern-crate-used.rs:10:1
- |
-LL | extern crate core as iso3;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `use`
-
-error: `extern crate` is not idiomatic in the new edition
- --> $DIR/extern-crate-used.rs:11:1
- |
-LL | extern crate core as iso4;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `use`
-
-error: unused extern crate
- --> $DIR/extern-crate-used.rs:14:1
- |
-LL | extern crate core;
- | ^^^^^^^^^^^^^^^^^^ help: remove it
-
-error: aborting due to 5 previous errors
+error: aborting due to previous error
// ignore-cloudabi no processes
// ignore-emscripten no processes
+// ignore-sgx no processes
#![feature(os)]
LL | Err(5)?;
| ^ the trait `std::convert::From<{integer}>` is not implemented for `()`
|
+ = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
= note: required by `std::convert::From::from`
error: aborting due to previous error
// ignore-windows
// ignore-cloudabi
// ignore-emscripten
+// ignore-sgx no processes
use std::process::Command;
// use std::os::unix::process::CommandExt;
error[E0599]: no method named `exec` found for type `&mut std::process::Command` in the current scope
- --> $DIR/issue-39175.rs:14:39
+ --> $DIR/issue-39175.rs:15:39
|
LL | Command::new("echo").arg("hello").exec();
| ^^^^
// FIXME https://github.com/rust-lang/rust/issues/59774
// normalize-stderr-test "thread.*panicked.*Metadata module not compiled.*\n" -> ""
// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> ""
+// ignore-sgx no weak linkages permitted
#![feature(linkage)]
error: must have type `*const T` or `*mut T`
- --> $DIR/linkage2.rs:8:32
+ --> $DIR/linkage2.rs:9:32
|
LL | #[linkage = "extern_weak"] static foo: i32;
| ^^^^^^^^^^^^^^^^
// ignore-musl - no dylibs here
// ignore-cloudabi
// ignore-emscripten
+// ignore-sgx no dynamic lib support
// error-pattern:`panic_unwind` is not compiled with this crate's panic strategy
// This is a test where the local crate, compiled with `panic=abort`, links to
Four(D)
}
+pub union Union1<A: Copy> {
+ a: A,
+}
+
+pub union Union2<A: Copy, B: Copy> {
+ a: A,
+ b: B,
+}
+
#[start]
fn start(_: isize, _: *const *const u8) -> isize {
let _x: MyOption<NonZeroU32> = Default::default();
let _e: Enum4<(), char, (), ()> = Enum4::One(());
let _f: Enum4<(), (), bool, ()> = Enum4::One(());
let _g: Enum4<(), (), (), MyOption<u8>> = Enum4::One(());
+
+ // Unions do not currently participate in niche filling.
+ let _h: MyOption<Union2<NonZeroU32, u32>> = Default::default();
+
+ // ...even when theoretically possible.
+ let _i: MyOption<Union1<NonZeroU32>> = Default::default();
+ let _j: MyOption<Union2<NonZeroU32, NonZeroU32>> = Default::default();
+
0
}
print-type-size field `.pre`: 1 bytes
print-type-size variant `None`: 0 bytes
print-type-size end padding: 1 bytes
+print-type-size type: `MyOption<Union1<std::num::NonZeroU32>>`: 8 bytes, alignment: 4 bytes
+print-type-size discriminant: 4 bytes
+print-type-size variant `Some`: 4 bytes
+print-type-size field `.0`: 4 bytes
+print-type-size variant `None`: 0 bytes
+print-type-size type: `MyOption<Union2<std::num::NonZeroU32, std::num::NonZeroU32>>`: 8 bytes, alignment: 4 bytes
+print-type-size discriminant: 4 bytes
+print-type-size variant `Some`: 4 bytes
+print-type-size field `.0`: 4 bytes
+print-type-size variant `None`: 0 bytes
+print-type-size type: `MyOption<Union2<std::num::NonZeroU32, u32>>`: 8 bytes, alignment: 4 bytes
+print-type-size discriminant: 4 bytes
+print-type-size variant `Some`: 4 bytes
+print-type-size field `.0`: 4 bytes
+print-type-size variant `None`: 0 bytes
print-type-size type: `NestedNonZero`: 8 bytes, alignment: 4 bytes
print-type-size field `.val`: 4 bytes
print-type-size field `.post`: 2 bytes
print-type-size variant `Some`: 4 bytes
print-type-size field `.0`: 4 bytes
print-type-size variant `None`: 0 bytes
+print-type-size type: `Union1<std::num::NonZeroU32>`: 4 bytes, alignment: 4 bytes
+print-type-size variant `Union1`: 4 bytes
+print-type-size field `.a`: 4 bytes
+print-type-size type: `Union2<std::num::NonZeroU32, std::num::NonZeroU32>`: 4 bytes, alignment: 4 bytes
+print-type-size variant `Union2`: 4 bytes
+print-type-size field `.a`: 4 bytes
+print-type-size field `.b`: 4 bytes, offset: 0 bytes, alignment: 4 bytes
+print-type-size type: `Union2<std::num::NonZeroU32, u32>`: 4 bytes, alignment: 4 bytes
+print-type-size variant `Union2`: 4 bytes
+print-type-size field `.a`: 4 bytes
+print-type-size field `.b`: 4 bytes, offset: 0 bytes, alignment: 4 bytes
print-type-size type: `std::num::NonZeroU32`: 4 bytes, alignment: 4 bytes
print-type-size field `.0`: 4 bytes
print-type-size type: `Enum4<(), (), (), MyOption<u8>>`: 2 bytes, alignment: 1 bytes
// run-pass
// ignore-cloudabi no processes
// ignore-emscripten no processes
+// ignore-sgx no processes
// Tests ensuring that `dbg!(expr)` has the expected run-time behavior.
// as well as some compile time properties we expect.
fn validate_stderr(stderr: Vec<String>) {
assert_eq!(stderr, &[
- ":21] Unit = Unit",
+ ":22] Unit = Unit",
- ":22] a = Unit",
+ ":23] a = Unit",
- ":28] Point{x: 42, y: 24,} = Point {",
+ ":29] Point{x: 42, y: 24,} = Point {",
" x: 42,",
" y: 24,",
"}",
- ":29] b = Point {",
+ ":30] b = Point {",
" x: 42,",
" y: 24,",
"}",
- ":37]",
+ ":38]",
- ":41] &a = NoCopy(",
+ ":42] &a = NoCopy(",
" 1337,",
")",
- ":41] dbg!(& a) = NoCopy(",
+ ":42] dbg!(& a) = NoCopy(",
" 1337,",
")",
- ":46] f(&42) = 42",
+ ":47] f(&42) = 42",
"before",
- ":51] { foo += 1; eprintln!(\"before\"); 7331 } = 7331",
+ ":52] { foo += 1; eprintln!(\"before\"); 7331 } = 7331",
- ":59] (\"Yeah\",) = (",
+ ":60] (\"Yeah\",) = (",
" \"Yeah\",",
")",
- ":62] 1 = 1",
- ":62] 2 = 2",
+ ":63] 1 = 1",
+ ":63] 2 = 2",
- ":66] 1u8 = 1",
- ":66] 2u32 = 2",
- ":66] \"Yeah\" = \"Yeah\"",
+ ":67] 1u8 = 1",
+ ":67] 2u32 = 2",
+ ":67] \"Yeah\" = \"Yeah\"",
]);
}
//~^ ERROR unused extern crate
-use edition_lint_paths as bar;
-//~^ ERROR `extern crate` is not idiomatic in the new edition
+// Shouldn't suggest changing to `use`, as `bar`
+// would no longer be added to the prelude which could cause
+// compilation errors for imports that use `bar` in other
+// modules. See #57672.
+extern crate edition_lint_paths as bar;
fn main() {
// This is not considered to *use* the `extern crate` in Rust 2018:
extern crate edition_lint_paths;
//~^ ERROR unused extern crate
+// Shouldn't suggest changing to `use`, as `bar`
+// would no longer be added to the prelude which could cause
+// compilation errors for imports that use `bar` in other
+// modules. See #57672.
extern crate edition_lint_paths as bar;
-//~^ ERROR `extern crate` is not idiomatic in the new edition
fn main() {
// This is not considered to *use* the `extern crate` in Rust 2018:
| ^^^^^^^^^^^^^^^^
= note: #[deny(unused_extern_crates)] implied by #[deny(rust_2018_idioms)]
-error: `extern crate` is not idiomatic in the new edition
- --> $DIR/extern-crate-idiomatic-in-2018.rs:15:1
- |
-LL | extern crate edition_lint_paths as bar;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `use`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
#![warn(rust_2018_idioms)]
-use core as another_name;
+// Shouldn't suggest changing to `use`, as `another_name`
+// would no longer be added to the prelude which could cause
+// compilation errors for imports that use `another_name` in other
+// modules. See #57672.
+extern crate core as another_name;
use remove_extern_crate;
#[macro_use]
extern crate remove_extern_crate as something_else;
#![warn(rust_2018_idioms)]
extern crate core;
+// Shouldn't suggest changing to `use`, as `another_name`
+// would no longer be added to the prelude which could cause
+// compilation errors for imports that use `another_name` in other
+// modules. See #57672.
extern crate core as another_name;
use remove_extern_crate;
#[macro_use]
= note: #[warn(unused_extern_crates)] implied by #[warn(rust_2018_idioms)]
warning: `extern crate` is not idiomatic in the new edition
- --> $DIR/remove-extern-crate.rs:10:1
- |
-LL | extern crate core as another_name;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `use`
-
-warning: `extern crate` is not idiomatic in the new edition
- --> $DIR/remove-extern-crate.rs:28:5
+ --> $DIR/remove-extern-crate.rs:32:5
|
LL | extern crate core;
| ^^^^^^^^^^^^^^^^^^ help: convert it to a `use`
--- /dev/null
+// aux-build:foo.rs
+// compile-flags:--extern foo
+// compile-pass
+// edition:2018
+
+#![deny(unused_extern_crates)]
+
+extern crate foo as foo_renamed;
+
+pub mod m {
+ pub use foo_renamed::Foo;
+}
+
+fn main() {}
LL | Err("")?;
| ^ the trait `std::convert::From<&str>` is not implemented for `i32`
|
+ = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
= help: the following implementations were found:
<i32 as std::convert::From<bool>>
<i32 as std::convert::From<i16>>
LL | x?;
| ^ the trait `std::convert::From<std::option::NoneError>` is not implemented for `()`
|
+ = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
= note: required by `std::convert::From::from`
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
-Subproject commit 11194e3d050f45ff002a775f451ff6222fcd5b2c
+Subproject commit 60a609acaed3bf2b3ec6ab995bccf0f03bc26060
use std::path::PathBuf;
use std::cell::RefCell;
+use syntax::edition::DEFAULT_EDITION;
use syntax::diagnostics::metadata::{get_metadata_dir, ErrorMetadataMap, ErrorMetadata};
use rustdoc::html::markdown::{Markdown, IdMap, ErrorCodes, PLAYGROUND};
Some(ref desc) => {
let mut id_map = self.0.borrow_mut();
write!(output, "{}",
- Markdown(desc, &[], RefCell::new(&mut id_map), ErrorCodes::Yes))?
+ Markdown(desc, &[], RefCell::new(&mut id_map),
+ ErrorCodes::Yes, DEFAULT_EDITION))?
},
None => write!(output, "<p>No description.</p>\n")?,
}
-Subproject commit bc0c76d861a178911f3f506196a7404eda1e690d
+Subproject commit 0c85dbf3df0f545133dca24eccfc9f0f6107c7f8
-Subproject commit 5b8e99bb61958ca8abcb7c5eda70521726be1065
+Subproject commit 9692ca8fd82a8f96a4113dc4b88c1fb1d79c1c60