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)
#![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)]
///
/// # 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
#![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)]
///
/// 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 {
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(
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);
}
}
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),
),
// 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);
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[..])
}
}
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]`
}
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)));
}
_ => (),
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>") }
}
}
// 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
}
}
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
/// 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,
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(),
}
}
- 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 { .. } => { }
}
}
}
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)
};
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 {
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) => {
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 {
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>,
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)
);
}
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))?;
}
}
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;
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
#![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
(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),
(
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::*;
// compile-flags: -O
#![crate_type="lib"]
-#![feature(maybe_uninit)]
use std::mem::MaybeUninit;
--- /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
+++ /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();
-}
println!("hello {}", "world",);
}
-// select! is too troublesome and unlikely to be stabilized
-
// stringify! is N/A
#[cfg(std)]
// 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};
--- /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!()
+ }
+}
-//~ 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 {});
+//! }
+//! ```
--- /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"
//~^ 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
|
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
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