From: Mazdak Farrokhzad Date: Mon, 20 May 2019 21:03:07 +0000 (+0200) Subject: Rollup merge of #60959 - petrochenkov:sassert, r=estebank X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=581cf70367d89af738a4f6be5eda8b7f157de25e;hp=88fa5c6a45a533a78c698a22f4b16002a3bc9fc3;p=rust.git Rollup merge of #60959 - petrochenkov:sassert, r=estebank rustc: Improve type size assertions Now they - Tell what the new size is, when it changes - Do not require passing an identifier ``` ::: src\libsyntax\parse\token.rs:223:1 | 223 | static_assert_size!(Token, 123); | -------------------------------- in this macro invocation | = note: expected type `[(); 123]` found type `[(); 16]` ``` --- diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 7826ac94718..be0af8be7b2 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -683,7 +683,7 @@ fn run(self, builder: &Builder<'_>) { target: self.target, mode: "ui", suite: "rustdoc-ui", - path: None, + path: Some("src/test/rustdoc-ui"), compare_mode: None, }) } diff --git a/src/ci/docker/x86_64-gnu-tools/checkregression.py b/src/ci/docker/x86_64-gnu-tools/checkregression.py index 8aa90319d66..0cc0a6329e5 100755 --- a/src/ci/docker/x86_64-gnu-tools/checkregression.py +++ b/src/ci/docker/x86_64-gnu-tools/checkregression.py @@ -21,12 +21,7 @@ if __name__ == '__main__': 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: diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index ddc6481eec7..41ff06d70ff 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -37,6 +37,8 @@ fn __rust_realloc(ptr: *mut u8, /// /// 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; @@ -54,6 +56,10 @@ fn __rust_realloc(ptr: *mut u8, /// /// See [`GlobalAlloc::alloc`]. /// +/// [`Global`]: struct.Global.html +/// [`Alloc`]: trait.Alloc.html +/// [`GlobalAlloc::alloc`]: trait.GlobalAlloc.html#tymethod.alloc +/// /// # Examples /// /// ``` @@ -87,6 +93,10 @@ pub unsafe fn alloc(layout: Layout) -> *mut u8 { /// # 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) { @@ -105,6 +115,10 @@ 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 { @@ -124,6 +138,10 @@ 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 /// /// ``` diff --git a/src/liballoc/collections/binary_heap.rs b/src/liballoc/collections/binary_heap.rs index 39fcfaa7893..c5a0b6e877b 100644 --- a/src/liballoc/collections/binary_heap.rs +++ b/src/liballoc/collections/binary_heap.rs @@ -231,6 +231,20 @@ /// 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 { data: Vec, @@ -384,6 +398,10 @@ pub fn with_capacity(capacity: usize) -> BinaryHeap { /// } /// 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> { if self.is_empty() { @@ -411,6 +429,11 @@ pub fn peek_mut(&mut self) -> Option> { /// 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 { self.data.pop().map(|mut item| { @@ -438,6 +461,22 @@ pub fn pop(&mut self) -> Option { /// 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(); @@ -650,6 +689,10 @@ pub fn iter(&self) -> Iter<'_, T> { /// 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) diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 2edd946ff11..d90036eaf49 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -109,7 +109,7 @@ #![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)] diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 43c1a3b7767..2f6d745d146 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -886,7 +886,7 @@ pub trait Pointer { /// /// # Examples /// -/// Basic usage with `i32`: +/// Basic usage with `f64`: /// /// ``` /// let x = 42.0; // 42.0 is '4.2e1' in scientific notation @@ -929,7 +929,7 @@ pub trait LowerExp { /// /// # Examples /// -/// Basic usage with `f32`: +/// Basic usage with `f64`: /// /// ``` /// let x = 42.0; // 42.0 is '4.2E1' in scientific notation diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 28db55578c3..4a70329b64b 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -125,7 +125,7 @@ #![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] diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 9fb071d2952..24bee6355a7 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -63,62 +63,6 @@ /// 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 = 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(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 @@ -465,29 +409,37 @@ pub const fn needs_drop() -> bool { /// 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 { @@ -498,130 +450,23 @@ pub unsafe fn zeroed() -> 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`] 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; 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![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::()` 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`]: 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 { intrinsics::panic_if_uninhabited::(); @@ -899,7 +744,6 @@ pub fn discriminant(v: &T) -> Discriminant { } } -// 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. @@ -908,6 +752,7 @@ pub fn discriminant(v: &T) -> Discriminant { /// 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`] instead. /// /// # Examples /// @@ -942,6 +787,7 @@ pub fn discriminant(v: &T) -> Discriminant { /// ``` /// /// [`mem::zeroed`]: fn.zeroed.html +/// [`MaybeUninit`]: union.MaybeUninit.html #[stable(feature = "manually_drop", since = "1.20.0")] #[lang = "manually_drop"] #[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -1042,17 +888,18 @@ fn deref_mut(&mut self) -> &mut T { } } -/// 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! @@ -1067,7 +914,6 @@ fn deref_mut(&mut self) -> &mut T { /// 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! @@ -1078,10 +924,9 @@ fn deref_mut(&mut self) -> &mut T { /// 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! @@ -1091,37 +936,154 @@ fn deref_mut(&mut self) -> &mut T { /// (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`] +/// 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` does not cause +/// *immediate* undefined behavior, but will cause undefined behavior with most +/// safe operations (including dropping it). +/// +/// [`Vec`]: ../../std/vec/struct.Vec.html +/// +/// # Examples +/// /// `MaybeUninit` 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` 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` 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) { +/// // `write` does not drop the old contents, which is important. +/// out.write(vec![1, 2, 3]); +/// } +/// +/// let mut v: MaybeUninit> = 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` 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>; 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; 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; 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`. That means it is not possible +/// to create a struct by calling `MaybeUninit::uninit::()` and then writing +/// to its fields. +/// +/// [ub]: ../../reference/behavior-considered-undefined.html +/// +/// # Layout +/// +/// `MaybeUninit` is guaranteed to have the same size and alignment as `T`: +/// +/// ```rust +/// use std::mem::{MaybeUninit, size_of, align_of}; +/// assert_eq!(size_of::>(), size_of::()); +/// assert_eq!(align_of::>(), align_of::()); +/// ``` +/// +/// However remember that a type *containing* a `MaybeUninit` is not necessarily the same +/// layout; Rust does not in general guarantee that the fields of a `Foo` have the same order as +/// a `Foo` even if `T` and `U` have the same size and alignment. Furthermore because any bit +/// value is valid for a `MaybeUninit` 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::>(), 1); +/// assert_eq!(size_of::>>(), 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 { uninit: (), value: ManuallyDrop, } -#[unstable(feature = "maybe_uninit", issue = "53491")] +#[stable(feature = "maybe_uninit", since = "1.36.0")] impl Clone for MaybeUninit { #[inline(always)] fn clone(&self) -> Self { @@ -1132,10 +1094,13 @@ fn clone(&self) -> Self { impl MaybeUninit { /// Creates a new `MaybeUninit` initialized with the given value. + /// It is safe to call [`assume_init`] on the return value of this function. /// /// Note that dropping a `MaybeUninit` 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 { MaybeUninit { value: ManuallyDrop::new(val) } @@ -1145,7 +1110,11 @@ pub const fn new(val: T) -> MaybeUninit { /// /// Note that dropping a `MaybeUninit` 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 { MaybeUninit { uninit: () } @@ -1166,7 +1135,6 @@ pub const fn uninit() -> MaybeUninit { /// 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(); @@ -1178,7 +1146,6 @@ pub const fn uninit() -> MaybeUninit { /// cannot hold 0 as a valid value. /// /// ```rust,no_run - /// #![feature(maybe_uninit)] /// use std::mem::MaybeUninit; /// /// enum NotZero { One = 1, Two = 2 }; @@ -1188,7 +1155,7 @@ pub const fn uninit() -> MaybeUninit { /// // 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 { let mut u = MaybeUninit::::uninit(); @@ -1202,7 +1169,7 @@ pub fn zeroed() -> MaybeUninit { /// 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 { @@ -1213,13 +1180,14 @@ pub fn write(&mut self, val: T) -> &mut T { /// Gets a pointer to the contained value. Reading from this pointer or turning it /// into a reference is undefined behavior unless the `MaybeUninit` is initialized. + /// Writing to memory that this pointer (non-transitively) points to is undefined behavior + /// (except inside an `UnsafeCell`). /// /// # Examples /// /// Correct usage of this method: /// /// ```rust - /// #![feature(maybe_uninit)] /// use std::mem::MaybeUninit; /// /// let mut x = MaybeUninit::>::uninit(); @@ -1232,7 +1200,6 @@ pub fn write(&mut self, val: T) -> &mut T { /// *Incorrect* usage of this method: /// /// ```rust,no_run - /// #![feature(maybe_uninit)] /// use std::mem::MaybeUninit; /// /// let x = MaybeUninit::>::uninit(); @@ -1242,7 +1209,7 @@ pub fn write(&mut self, val: T) -> &mut T { /// /// (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 } @@ -1256,7 +1223,6 @@ pub fn as_ptr(&self) -> *const T { /// Correct usage of this method: /// /// ```rust - /// #![feature(maybe_uninit)] /// use std::mem::MaybeUninit; /// /// let mut x = MaybeUninit::>::uninit(); @@ -1271,7 +1237,6 @@ pub fn as_ptr(&self) -> *const T { /// *Incorrect* usage of this method: /// /// ```rust,no_run - /// #![feature(maybe_uninit)] /// use std::mem::MaybeUninit; /// /// let mut x = MaybeUninit::>::uninit(); @@ -1281,7 +1246,7 @@ pub fn as_ptr(&self) -> *const T { /// /// (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 } @@ -1294,15 +1259,17 @@ pub fn as_mut_ptr(&mut self) -> *mut T { /// # Safety /// /// It is up to the caller to guarantee that the `MaybeUninit` 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::::uninit(); @@ -1314,14 +1281,13 @@ pub fn as_mut_ptr(&mut self) -> *mut T { /// *Incorrect* usage of this method: /// /// ```rust,no_run - /// #![feature(maybe_uninit)] /// use std::mem::MaybeUninit; /// /// let x = MaybeUninit::>::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::(); @@ -1338,13 +1304,15 @@ pub unsafe fn assume_init(self) -> T { /// /// It is up to the caller to guarantee that the `MaybeUninit` 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`. 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 @@ -1352,7 +1320,7 @@ pub unsafe fn assume_init(self) -> T { /// Correct usage of this method: /// /// ```rust - /// #![feature(maybe_uninit)] + /// #![feature(maybe_uninit_extra)] /// use std::mem::MaybeUninit; /// /// let mut x = MaybeUninit::::uninit(); @@ -1373,7 +1341,7 @@ pub unsafe fn assume_init(self) -> T { /// *Incorrect* usage of this method: /// /// ```rust,no_run - /// #![feature(maybe_uninit)] + /// #![feature(maybe_uninit_extra)] /// use std::mem::MaybeUninit; /// /// let mut x = MaybeUninit::>>::uninit(); @@ -1383,7 +1351,7 @@ pub unsafe fn assume_init(self) -> T { /// // 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::(); diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index ada784e9ce7..dd321dcdfae 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -155,12 +155,12 @@ /// location first: /// ``` /// use std::ptr; -/// use std::mem; +/// use std::mem::{self, MaybeUninit}; /// /// unsafe fn drop_after_copy(to_drop: *mut T) { -/// let mut copy: T = mem::uninitialized(); -/// ptr::copy(to_drop, &mut copy, 1); -/// drop(copy); +/// let mut copy: MaybeUninit = MaybeUninit::uninit(); +/// ptr::copy(to_drop, copy.as_mut_ptr(), 1); +/// drop(copy.assume_init()); /// } /// /// #[repr(packed, C)] diff --git a/src/libcore/task/wake.rs b/src/libcore/task/wake.rs index b4e91249832..a6d611d2e93 100644 --- a/src/libcore/task/wake.rs +++ b/src/libcore/task/wake.rs @@ -10,6 +10,8 @@ /// /// 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 { @@ -55,6 +57,8 @@ pub const fn new(data: *const (), vtable: &'static RawWakerVTable) -> 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 { @@ -65,6 +69,9 @@ 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`]. @@ -73,6 +80,9 @@ pub struct RawWakerVTable { /// 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`]. @@ -80,6 +90,9 @@ pub struct RawWakerVTable { /// /// 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. @@ -87,6 +100,8 @@ pub struct RawWakerVTable { /// 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 ()), } @@ -128,6 +143,9 @@ impl RawWakerVTable { /// 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"))] @@ -201,6 +219,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// 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 { @@ -266,6 +286,9 @@ pub fn will_wake(&self, other: &Waker) -> bool { /// 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 { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 970f6ba0177..3ec4d4e8cc8 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -855,10 +855,6 @@ fn diagnostic(&self) -> &errors::Handler { self.sess.diagnostic() } - fn str_to_ident(&self, s: &'static str) -> Ident { - Ident::with_empty_ctxt(Symbol::gensym(s)) - } - fn with_anonymous_lifetime_mode( &mut self, anonymous_lifetime_mode: AnonymousLifetimeMode, @@ -4621,18 +4617,18 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr { ); 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)); @@ -4771,17 +4767,13 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr { 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()` @@ -4802,7 +4794,8 @@ fn lower_expr(&mut self, e: &Expr) -> hir::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]) }; @@ -4812,7 +4805,7 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr { // `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, @@ -4828,7 +4821,7 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr { // `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]; @@ -5552,7 +5545,7 @@ fn lower_await( // 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 (); @@ -5580,12 +5573,12 @@ fn lower_await( 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 = ; 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, @@ -5621,11 +5614,11 @@ fn lower_await( )) }; - // `::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( diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 3ca79cb8501..57304c5ed37 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -609,9 +609,9 @@ pub fn own_counts(&self) -> GenericParamCount { 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); } } diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 4b6e7da3330..e4505a24037 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -194,20 +194,20 @@ fn msg_span_from_early_bound_and_free_regions( 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; } diff --git a/src/librustc/infer/error_reporting/nice_region_error/util.rs b/src/librustc/infer/error_reporting/nice_region_error/util.rs index 3ed28a1f988..feade7a8f56 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/util.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/util.rs @@ -43,7 +43,7 @@ pub(super) fn find_arg_with_region( ) -> Option> { 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), ), diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index e713cf8d805..7e1e751e856 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -828,8 +828,8 @@ fn path_qualified( // 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)), }]) } @@ -845,9 +845,10 @@ fn path_append_impl( // This shouldn't ever be needed, but just in case: path.push(match trait_ref { Some(trait_ref) => { - Symbol::intern(&format!("", trait_ref, self_ty)).as_str() + LocalInternedString::intern(&format!("", trait_ref, + self_ty)) }, - None => Symbol::intern(&format!("", self_ty)).as_str(), + None => LocalInternedString::intern(&format!("", self_ty)), }); Ok(path) diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 68b65f9b4a1..9c4683e0946 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -778,6 +778,9 @@ fn lint_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cnum: CrateNum) 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); diff --git a/src/librustc/mir/mono.rs b/src/librustc/mir/mono.rs index e82e90ede8c..a26468b0fb6 100644 --- a/src/librustc/mir/mono.rs +++ b/src/librustc/mir/mono.rs @@ -1,6 +1,6 @@ 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; @@ -280,7 +280,7 @@ pub fn build_cgu_name(&mut self, 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)) } } @@ -336,6 +336,6 @@ pub fn build_cgu_name_no_mangle(&mut self, write!(cgu_name, ".{}", special_suffix).unwrap(); } - Symbol::intern(&cgu_name[..]).as_interned_str() + InternedString::intern(&cgu_name[..]) } } diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 1c8ea5c7b9c..55216f644a1 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -18,7 +18,8 @@ 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)] @@ -539,7 +540,7 @@ fn receiver_is_dispatchable( // 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]` diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 400a0f526c4..404fadbc78a 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -312,17 +312,15 @@ fn visit_binder>(&mut self, t: &ty::Binder) -> bool { } 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()), + ), } ); } @@ -334,8 +332,6 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { } 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 { @@ -344,9 +340,7 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { } ty::BoundRegion::BrAnon(var) => { - self.regions.insert(Symbol::intern( - &format!("'^{}", var) - ).as_interned_str()); + self.regions.insert(InternedString::intern(&format!("'^{}", var))); } _ => (), diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 1e4bb37c44e..91e996178e7 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -3405,7 +3405,7 @@ pub struct SymbolName { impl SymbolName { pub fn new(name: &str) -> SymbolName { SymbolName { - name: Symbol::intern(name).as_interned_str() + name: InternedString::intern(name) } } diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index 8e98d4d85b9..91b708d7dbe 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -7,10 +7,8 @@ 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 _}; @@ -1285,10 +1283,10 @@ pub fn pretty_in_binder( { 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 diff --git a/src/librustc/ty/query/values.rs b/src/librustc/ty/query/values.rs index a4b8d365a12..2fb318a47be 100644 --- a/src/librustc/ty/query/values.rs +++ b/src/librustc/ty/query/values.rs @@ -1,7 +1,7 @@ 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; @@ -28,7 +28,7 @@ fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> { impl<'tcx> Value<'tcx> for ty::SymbolName { fn from_cycle_error<'a>(_: TyCtxt<'a, 'tcx, 'tcx>) -> Self { - ty::SymbolName { name: Symbol::intern("").as_interned_str() } + ty::SymbolName { name: InternedString::intern("") } } } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 269064af93b..e8f3bad4d3e 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -1136,7 +1136,7 @@ pub fn is_self(&self) -> bool { // 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 } } diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs index cb59cf41a3c..66ba95810a6 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/src/librustc_codegen_llvm/back/write.rs @@ -795,10 +795,10 @@ fn create_msvc_imps( 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_" diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index ceb08f94367..9ae0e26196d 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -20,7 +20,7 @@ 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::*; @@ -213,7 +213,7 @@ fn codegen_intrinsic_call( } "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" => { diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index 6320d8a671d..1c793996c83 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/src/librustc_codegen_ssa/back/write.rs @@ -248,6 +248,7 @@ pub struct CodegenContext { pub tm_factory: TargetMachineFactory, 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 @@ -1103,6 +1104,7 @@ fn start_executing_work( 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, }; diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index 96b8558c1d2..c7dd019fc3e 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -15,7 +15,7 @@ use std::borrow::Cow; -use syntax::symbol::Symbol; +use syntax::symbol::LocalInternedString; use syntax_pos::Pos; use super::{FunctionCx, LocalRef}; @@ -401,7 +401,7 @@ fn codegen_assert_terminator<'b>( // 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); @@ -423,7 +423,7 @@ fn codegen_assert_terminator<'b>( } _ => { 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, @@ -535,7 +535,7 @@ fn codegen_call_terminator<'b>( 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); @@ -543,7 +543,7 @@ fn codegen_call_terminator<'b>( "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, diff --git a/src/librustc_codegen_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs index d50a9a1607b..6915687ceba 100644 --- a/src/librustc_codegen_utils/symbol_names.rs +++ b/src/librustc_codegen_utils/symbol_names.rs @@ -101,7 +101,7 @@ 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; @@ -238,13 +238,13 @@ fn compute_symbol_name(tcx: TyCtxt<'_, 'tcx, 'tcx>, instance: Instance<'tcx>) -> 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)); } } @@ -322,7 +322,7 @@ fn compute_symbol_name(tcx: TyCtxt<'_, 'tcx, 'tcx>, instance: Instance<'tcx>) -> 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 diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs index fa573907d4c..2b844aa24d4 100644 --- a/src/librustc_data_structures/stable_hasher.rs +++ b/src/librustc_data_structures/stable_hasher.rs @@ -15,7 +15,6 @@ /// extended to 64 bits if needed. pub struct StableHasher { state: SipHasher128, - bytes_hashed: u64, width: PhantomData, } @@ -33,7 +32,6 @@ impl StableHasher { pub fn new() -> Self { StableHasher { state: SipHasher128::new_with_keys(0, 0), - bytes_hashed: 0, width: PhantomData, } } @@ -61,11 +59,6 @@ impl StableHasher { pub fn finalize(self) -> (u64, u64) { self.state.finish128() } - - #[inline] - pub fn bytes_hashed(&self) -> u64 { - self.bytes_hashed - } } impl Hasher for StableHasher { @@ -76,37 +69,31 @@ fn finish(&self) -> u64 { #[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] @@ -115,37 +102,31 @@ fn write_usize(&mut self, i: usize) { // 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] @@ -154,12 +135,35 @@ fn write_isize(&mut self, i: isize) { // 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` 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 { fn hash_stable(&self, hcx: &mut CTX, diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 7f2a1c0b4b1..3e00ba3c620 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -95,7 +95,7 @@ enum LoadError<'a> { 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(), } } } @@ -365,8 +365,8 @@ fn resolve_crate<'b>( 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(), diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs index 7d7dd1061a9..3832c8ee227 100644 --- a/src/librustc_metadata/locator.rs +++ b/src/librustc_metadata/locator.rs @@ -321,7 +321,7 @@ pub fn maybe_load_library_crate(&mut self) -> Option { } } - 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), @@ -901,8 +901,7 @@ fn get_metadata_section_imp(target: &Target, 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())); diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs index 4ced31593b1..4d8acd241ac 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs @@ -12,7 +12,6 @@ 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; @@ -60,8 +59,8 @@ impl RegionName { } #[allow(dead_code)] - crate fn name(&self) -> &InternedString { - &self.name + crate fn name(&self) -> InternedString { + self.name } crate fn highlight_region_name( @@ -206,7 +205,7 @@ fn give_name_from_error_region( 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) @@ -223,7 +222,7 @@ fn give_name_from_error_region( 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), @@ -306,7 +305,7 @@ fn get_named_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); @@ -791,6 +790,6 @@ fn synthesize_region_name(&self, counter: &mut usize) -> InternedString { let c = *counter; *counter += 1; - Name::intern(&format!("'{:?}", c)).as_interned_str() + InternedString::intern(&format!("'{:?}", c)) } } diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index db827afdb94..d4c1e5416d5 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -613,7 +613,9 @@ pub fn storage_live( 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 . Ok(mem::replace(&mut self.frame_mut().locals[local].value, local_val)) } diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs index 999e7402afd..6b40245d39a 100644 --- a/src/librustc_mir/monomorphize/item.rs +++ b/src/librustc_mir/monomorphize/item.rs @@ -10,7 +10,7 @@ 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; @@ -61,7 +61,7 @@ fn symbol_name(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::SymbolName { 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)) } } } diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index fab07a2290e..394d1f06029 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -12,7 +12,7 @@ use rustc::mir::*; use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext}; -use syntax::symbol::{Symbol, sym}; +use syntax::symbol::{InternedString, sym}; use std::ops::Bound; @@ -167,9 +167,9 @@ fn visit_rvalue(&mut self, (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, }], &[]); }, @@ -185,9 +185,8 @@ fn visit_rvalue(&mut self, 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, }], &[]); } @@ -212,13 +211,11 @@ fn visit_place(&mut self, 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) }], &[]); } @@ -315,12 +312,10 @@ fn visit_place(&mut self, 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) }], &[]); } @@ -340,8 +335,8 @@ fn require_unsafe( 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, }], &[]); } @@ -441,8 +436,8 @@ fn check_mut_borrowing_layout_constrained_field( 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, }], &[]); } diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 4e214c3c725..8f3dd72c4f2 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -546,6 +546,10 @@ fn replace_with_const(&self, rval: &mut Rvalue<'tcx>, value: Const<'tcx>, span: } } } + + 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>, @@ -639,7 +643,7 @@ fn visit_statement( 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); } } @@ -656,75 +660,112 @@ fn visit_terminator( 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 { .. } => { } } } } diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 40c60caffa4..c6191e6b579 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -7,7 +7,7 @@ use crate::require_same_types; use rustc_target::spec::abi::Abi; -use syntax::symbol::Symbol; +use syntax::symbol::InternedString; use rustc::hir; @@ -80,7 +80,7 @@ pub fn intrisic_operation_unsafety(intrinsic: &str) -> hir::Unsafety { /// 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 = || { @@ -397,7 +397,7 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, 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) }; diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 6527e8655b5..711d79f95f5 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -39,7 +39,7 @@ 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}; @@ -1082,7 +1082,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty .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 { @@ -1097,7 +1097,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty params.extend(upvars.iter().zip((dummy_args.len() as u32)..).map(|(_, i)| { ty::GenericParamDef { index: type_start + i, - name: Symbol::intern("").as_interned_str(), + name: InternedString::intern(""), def_id, pure_wrt_drop: false, kind: ty::GenericParamDefKind::Type { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index f91cb469e46..e434623d4a1 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -3408,6 +3408,7 @@ pub struct Span { pub locol: usize, pub hiline: usize, pub hicol: usize, + pub original: syntax_pos::Span, } impl Span { @@ -3416,8 +3417,13 @@ pub fn empty() -> 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 for syntax_pos::Span { @@ -3436,6 +3442,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Span { locol: lo.col.to_usize(), hiline: hi.line, hicol: hi.col.to_usize(), + original: *self, } } } diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 4fae7e080b1..6b490f730af 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -13,7 +13,7 @@ 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; @@ -386,6 +386,18 @@ pub fn from_matches(matches: &getopts::Matches) -> Result { } } + 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( @@ -393,20 +405,12 @@ pub fn from_matches(matches: &getopts::Matches) -> Result { &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) => { diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs index 0378b12662d..d604ba11d41 100644 --- a/src/librustdoc/externalfiles.rs +++ b/src/librustdoc/externalfiles.rs @@ -3,6 +3,7 @@ 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; @@ -23,7 +24,7 @@ pub struct ExternalHtml { 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 { let codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()); load_external_files(in_header, diag) @@ -34,7 +35,8 @@ pub fn load(in_header: &[String], before_content: &[String], after_content: &[St .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) @@ -43,7 +45,8 @@ pub fn load(in_header: &[String], before_content: &[String], after_content: &[St .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 { diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index acf019fd225..ae0bd1aafa8 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -182,14 +182,14 @@ pub fn render( let p = SlashChecker(&p); if layout.logo.is_empty() { format!("\ - logo", +
\ + logo
", path=p, static_root_path=static_root_path, suffix=page.resource_suffix) } else { format!("\ - logo", +
logo
", p, layout.logo) } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index a3b041c6954..12d10254c4d 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -8,12 +8,16 @@ //! ``` //! #![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 //! ``` @@ -42,14 +46,21 @@ fn opts() -> Options { /// 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)]); @@ -146,13 +157,15 @@ fn slugify(c: char) -> Option { struct CodeBlocks<'a, I: Iterator>> { inner: I, check_error_codes: ErrorCodes, + edition: Edition, } impl<'a, I: Iterator>> 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, } } } @@ -177,6 +190,9 @@ fn next(&mut self) -> Option { 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 { @@ -202,22 +218,14 @@ fn next(&mut self) -> Option { .collect::>>().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. @@ -247,8 +255,8 @@ fn dont_escape(c: u8) -> bool { 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 }; @@ -259,7 +267,7 @@ fn dont_escape(c: u8) -> bool { 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)))); @@ -270,7 +278,7 @@ fn dont_escape(c: u8) -> bool { 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)); @@ -659,7 +667,7 @@ fn parse(string: &str, allow_error_code_check: ErrorCodes) -> LangString { 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 @@ -678,7 +686,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 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); @@ -688,7 +696,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 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()); @@ -699,7 +707,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { { 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); } @@ -712,7 +720,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 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 @@ -728,7 +736,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 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); @@ -1046,7 +1054,7 @@ mod tests { 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() { @@ -1098,7 +1106,8 @@ fn v() -> Vec { 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); } @@ -1120,7 +1129,8 @@ fn t(input: &str, expect: &str) { 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); } @@ -1157,7 +1167,8 @@ fn t(input: &str, expect: &str) { 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); } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 36ce89558db..b628bd450d3 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -47,6 +47,7 @@ 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; @@ -108,6 +109,8 @@ struct Context { /// 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>, pub shared: Arc, @@ -514,7 +517,8 @@ pub fn run(mut krate: clean::Crate, options: RenderOptions, passes: FxHashSet, 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 { @@ -604,6 +608,7 @@ pub fn run(mut krate: clean::Crate, 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), }; @@ -1128,7 +1133,7 @@ fn to_json_string(&self) -> String { 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)); @@ -2553,7 +2558,7 @@ fn render_markdown(w: &mut fmt::Formatter<'_>, if is_hidden { " hidden" } else { "" }, prefix, Markdown(md_text, &links, RefCell::new(&mut ids), - cx.codes)) + cx.codes, cx.edition)) } fn document_short( @@ -2918,7 +2923,7 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec { 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!("
{}
", message)); @@ -2967,7 +2972,7 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec { message = format!( "
{}{}
", message, - MarkdownHtml(&unstable_reason, RefCell::new(&mut ids), error_codes) + MarkdownHtml(&unstable_reason, RefCell::new(&mut ids), error_codes, cx.edition) ); } @@ -4197,7 +4202,8 @@ fn render_impl(w: &mut fmt::Formatter<'_>, cx: &Context, i: &Impl, link: AssocIt if let Some(ref dox) = cx.shared.maybe_collapsed_doc_value(&i.impl_item) { let mut ids = cx.id_map.borrow_mut(); write!(w, "
{}
", - 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))?; } } diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 522b6d60a18..0493bf7c5c0 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -182,12 +182,25 @@ nav.sub { 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; @@ -658,18 +671,18 @@ a { 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 { @@ -998,6 +1011,195 @@ h3 > .collapse-toggle, h4 > .collapse-toggle { 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) { @@ -1030,14 +1232,20 @@ h3 > .collapse-toggle, h4 > .collapse-toggle { 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; @@ -1118,125 +1326,12 @@ h3 > .collapse-toggle, h4 > .collapse-toggle { 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; @@ -1311,8 +1406,29 @@ h4 > .important-traits { #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 { @@ -1412,63 +1528,6 @@ kbd { 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 */ @@ -1520,39 +1579,6 @@ kbd { 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; diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index f1255f52247..e44ae2ad10c 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -164,20 +164,21 @@ a.test-arrow { 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 { diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index c052e6b37ad..4c37000dde2 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -164,21 +164,21 @@ a.test-arrow { 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 { diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 5b76f6861de..f5061b67182 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -391,7 +391,10 @@ fn main_args(args: &[String]) -> i32 { 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) => {} } @@ -399,7 +402,8 @@ fn main_args(args: &[String]) -> i32 { // 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 { @@ -410,7 +414,7 @@ fn main_args(args: &[String]) -> i32 { 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, @@ -418,6 +422,7 @@ fn main_args(args: &[String]) -> i32 { passes.into_iter().collect(), renderinfo, &diag, + edition, ) { Ok(_) => rustc_driver::EXIT_SUCCESS, Err(e) => { diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index c496dde8426..b0a37ea9c80 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -5,6 +5,7 @@ use errors; use testing; +use syntax::edition::Edition; use syntax::source_map::DUMMY_SP; use syntax::feature_gate::UnstableFeatures; @@ -36,7 +37,12 @@ fn extract_leading_metadata<'a>(s: &'a str) -> (Vec<&'a str>, &'a str) { /// 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"); @@ -76,9 +82,9 @@ pub fn render(input: PathBuf, options: RenderOptions, diag: &errors::Handler) -> 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!( diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 9e108e605c8..2c382a1c175 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -321,7 +321,7 @@ fn fold_item(&mut self, mut item: Item) -> Option { 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. @@ -332,7 +332,7 @@ fn fold_item(&mut self, mut item: Item) -> Option { 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; } @@ -357,7 +357,7 @@ fn fold_item(&mut self, mut item: Item) -> Option { }; 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; } @@ -368,7 +368,7 @@ fn fold_item(&mut self, mut item: Item) -> Option { } else { ambiguity_error( cx, - &item.attrs, + &item, path_str, &dox, link_range, @@ -381,7 +381,7 @@ fn fold_item(&mut self, mut item: Item) -> Option { 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 } } @@ -452,16 +452,24 @@ fn macro_resolve(cx: &DocContext<'_>, path_str: &str) -> Option { /// 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>, ) { + 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), ); @@ -495,12 +503,20 @@ fn resolution_failure( fn ambiguity_error( cx: &DocContext<'_>, - attrs: &Attributes, + item: &Item, path_str: &str, dox: &str, link_range: Option>, candidates: PerNS>, ) { + 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); @@ -532,7 +548,7 @@ fn ambiguity_error( let mut diag = cx.tcx.struct_span_lint_hir( lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE, - hir::CRATE_HIR_ID, + hir_id, sp, &msg, ); diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index 99aca063471..d9af33ac5b6 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -1,7 +1,6 @@ //! 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; @@ -314,10 +313,13 @@ pub fn look_for_tests<'tcx>( 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, @@ -336,10 +338,11 @@ fn add_test(&mut self, _: String, _: LangString, _: 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 && @@ -347,7 +350,7 @@ fn add_test(&mut self, _: String, _: LangString, _: usize) { !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(); diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index e40dbe52ffe..0cc99da6407 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -167,7 +167,7 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize, maybe_sysroot: Option, linker: Option, edition: Edition, persist_doctests: Option) { 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::() => { @@ -356,7 +356,8 @@ fn path(&self) -> &std::path::Path { 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(); @@ -390,6 +391,8 @@ pub fn make_test(s: &str, 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; @@ -397,6 +400,7 @@ pub fn make_test(s: &str, // 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); @@ -880,6 +884,7 @@ fn visit_macro_def(&mut self, macro_def: &'hir hir::MacroDef) { #[cfg(test)] mod tests { use super::{TestOptions, make_test}; + use syntax::edition::DEFAULT_EDITION; #[test] fn make_test_basic() { @@ -892,7 +897,7 @@ 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)); } @@ -908,7 +913,7 @@ fn make_test_crate_name_no_use() { 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)); } @@ -927,7 +932,7 @@ fn main() { 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)); } @@ -949,7 +954,7 @@ fn main() { 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)); } @@ -968,7 +973,7 @@ fn main() { 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)); } @@ -988,7 +993,7 @@ fn main() { 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)); } @@ -1006,7 +1011,7 @@ fn main() { 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)); } @@ -1026,7 +1031,7 @@ fn main() { 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. @@ -1039,7 +1044,7 @@ fn main() { 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)); } @@ -1057,7 +1062,7 @@ fn make_test_crate_attrs() { 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)); } @@ -1074,7 +1079,7 @@ fn make_test_with_main() { 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)); } @@ -1091,7 +1096,7 @@ fn make_test_fake_main() { 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)); } @@ -1106,7 +1111,7 @@ fn make_test_dont_insert_main() { "#![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)); } @@ -1121,7 +1126,7 @@ fn make_test_display_warnings() { "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)); } @@ -1140,7 +1145,7 @@ 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)); let input = @@ -1155,7 +1160,7 @@ fn main() { 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)); } @@ -1174,7 +1179,7 @@ fn main() {} 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)); } } diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index 4241f47b661..ff52974775b 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -173,6 +173,9 @@ unsafe fn realloc(&mut self, /// 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); @@ -183,6 +186,8 @@ pub fn set_alloc_error_hook(hook: fn(Layout)) { /// *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); diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 478f63ab3d7..5a2fe2b244f 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -2494,7 +2494,10 @@ pub fn new() -> DefaultHasher { #[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() diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 62282006a40..aeb822fa99e 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -218,6 +218,8 @@ mod private { impl<'a, E: Error + 'a> From for Box { /// Converts a type of [`Error`] into a box of dyn [`Error`]. /// + /// [`Error`]: ../error/trait.Error.html + /// /// # Examples /// /// ``` @@ -255,6 +257,8 @@ impl<'a, E: Error + Send + Sync + 'a> From for Box Box { impl From for Box { /// Converts a [`String`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. /// + /// [`Error`]: ../error/trait.Error.html + /// /// # Examples /// /// ``` @@ -329,6 +335,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { impl From for Box { /// Converts a [`String`] into a box of dyn [`Error`]. /// + /// [`Error`]: ../error/trait.Error.html + /// /// # Examples /// /// ``` @@ -350,6 +358,8 @@ fn from(str_err: String) -> Box { impl<'a> From<&str> for Box { /// Converts a [`str`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. /// + /// [`Error`]: ../error/trait.Error.html + /// /// # Examples /// /// ``` @@ -370,6 +380,8 @@ fn from(err: &str) -> Box { impl From<&str> for Box { /// Converts a [`str`] into a box of dyn [`Error`]. /// + /// [`Error`]: ../error/trait.Error.html + /// /// # Examples /// /// ``` @@ -389,6 +401,9 @@ fn from(err: &str) -> Box { impl<'a, 'b> From> for Box { /// Converts a [`Cow`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. /// + /// [`Cow`]: ../borrow/enum.Cow.html + /// [`Error`]: ../error/trait.Error.html + /// /// # Examples /// /// ``` @@ -410,6 +425,9 @@ fn from(err: Cow<'b, str>) -> Box { impl<'a> From> for Box { /// Converts a [`Cow`] into a box of dyn [`Error`]. /// + /// [`Cow`]: ../borrow/enum.Cow.html + /// [`Error`]: ../error/trait.Error.html + /// /// # Examples /// /// ``` diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 13aee783750..c7c5849a00f 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -351,6 +351,8 @@ impl From for OsString { /// 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) } } diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 991b45fd4a2..616b5eb836f 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -1812,6 +1812,8 @@ pub fn canonicalize>(path: P) -> io::Result { /// function.) /// * `path` already exists. /// +/// [`create_dir_all`]: fn.create_dir_all.html +/// /// # Examples /// /// ```no_run diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 5be2687d8f5..e309f81192c 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -754,7 +754,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// 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 diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 2401946536f..e044b46e0d0 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -272,7 +272,6 @@ #![feature(libc)] #![feature(link_args)] #![feature(linkage)] -#![feature(maybe_uninit)] #![feature(needs_panic_runtime)] #![feature(never_type)] #![feature(nll)] diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 03aebeda47c..9af7bba97aa 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -357,61 +357,6 @@ macro_rules! dbg { }; } -/// 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) => ({ diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index e7923e381f1..ca86a175058 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -546,6 +546,9 @@ fn from_inner(addr: c::sockaddr_in6) -> SocketAddrV6 { #[stable(feature = "ip_from_ip", since = "1.16.0")] impl From 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) } @@ -554,6 +557,9 @@ fn from(sock4: SocketAddrV4) -> SocketAddr { #[stable(feature = "ip_from_ip", since = "1.16.0")] impl From 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) } @@ -567,6 +573,13 @@ impl> From<(I, u16)> for SocketAddr { /// 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) } diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 04353fde1b4..69ecd201063 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -116,7 +116,6 @@ //! ``` #![stable(feature = "rust1", since = "1.0.0")] -#![allow(deprecated)] // for mpsc_select // A description of how Rust's channel implementation works // @@ -263,6 +262,8 @@ // 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, @@ -275,18 +276,8 @@ 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; @@ -1514,78 +1505,6 @@ pub fn try_iter(&self) -> TryIter<'_, T> { } -impl select::Packet for Receiver { - 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; diff --git a/src/libstd/sync/mpsc/oneshot.rs b/src/libstd/sync/mpsc/oneshot.rs index 5c516d5de0f..e7a5cc46b31 100644 --- a/src/libstd/sync/mpsc/oneshot.rs +++ b/src/libstd/sync/mpsc/oneshot.rs @@ -24,7 +24,6 @@ pub use self::Failure::*; pub use self::UpgradeResult::*; -pub use self::SelectionResult::*; use self::MyUpgrade::*; use crate::sync::mpsc::Receiver; @@ -66,12 +65,6 @@ pub enum UpgradeResult { UpWoke(SignalToken), } -pub enum SelectionResult { - SelCanceled, - SelUpgraded(SignalToken, Receiver), - SelSuccess, -} - enum MyUpgrade { NothingSent, SendUsed, @@ -264,71 +257,6 @@ pub fn drop_port(&self) { // 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> { - 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 { - 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. // diff --git a/src/libstd/sync/mpsc/select.rs b/src/libstd/sync/mpsc/select.rs deleted file mode 100644 index d1b5f2deccc..00000000000 --- a/src/libstd/sync/mpsc/select.rs +++ /dev/null @@ -1,352 +0,0 @@ -//! 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, - next_id: Cell, -} - -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, -} - -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) -> 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 { 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 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 fmt::Debug for Handle<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Handle").finish() - } -} diff --git a/src/libstd/sync/mpsc/select_tests.rs b/src/libstd/sync/mpsc/select_tests.rs deleted file mode 100644 index 18d93462c78..00000000000 --- a/src/libstd/sync/mpsc/select_tests.rs +++ /dev/null @@ -1,413 +0,0 @@ -#![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::(); - let (tx2, rx2) = channel::(); - 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::(); - let (_tx2, rx2) = channel::(); - let (_tx3, rx3) = channel::(); - let (_tx4, rx4) = channel::(); - let (tx5, rx5) = channel::(); - 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::(); - let (tx2, rx2) = channel::(); - drop(tx2); - - select! { - _a1 = rx1.recv() => { panic!() }, - a2 = rx2.recv() => { assert!(a2.is_err()); } - } -} - -#[test] -fn unblocks() { - let (tx1, rx1) = channel::(); - let (_tx2, rx2) = channel::(); - let (tx3, rx3) = channel::(); - - 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::(); - let (tx2, rx2) = channel::(); - 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::(); - let (tx2, rx2) = channel::(); - 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::(); - let (_tx2, rx2) = channel::(); - 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::(); - let (_tx2, rx2) = channel::(); - 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::(1); - tx.send(1).unwrap(); - select! { - n = rx.recv() => { assert_eq!(n.unwrap(), 1); } - } -} - -#[test] -fn sync2() { - let (tx, rx) = sync_channel::(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::(0); - let (tx2, rx2): (Sender, Receiver) = 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); - } - } -} diff --git a/src/libstd/sync/mpsc/shared.rs b/src/libstd/sync/mpsc/shared.rs index cc70a620365..dbcdcdac932 100644 --- a/src/libstd/sync/mpsc/shared.rs +++ b/src/libstd/sync/mpsc/shared.rs @@ -9,6 +9,7 @@ /// channels are quite similar, and this is no coincidence! pub use self::Failure::*; +use self::StartResult::*; use core::cmp; use core::intrinsics::abort; @@ -19,8 +20,6 @@ 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; @@ -57,6 +56,12 @@ pub enum Failure { Disconnected, } +#[derive(PartialEq, Eq)] +enum StartResult { + Installed, + Abort, +} + impl Packet { // Creation of a packet *must* be followed by a call to postinit_lock // and later by inherit_blocker @@ -394,16 +399,6 @@ fn take_to_wake(&self) -> SignalToken { // 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) { @@ -415,22 +410,6 @@ fn bump(&self, amt: isize) -> isize { } } - // 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. // diff --git a/src/libstd/sync/mpsc/stream.rs b/src/libstd/sync/mpsc/stream.rs index 7ae6f68b514..40877282761 100644 --- a/src/libstd/sync/mpsc/stream.rs +++ b/src/libstd/sync/mpsc/stream.rs @@ -9,7 +9,6 @@ pub use self::Failure::*; pub use self::UpgradeResult::*; -pub use self::SelectionResult::*; use self::Message::*; use core::cmp; @@ -60,12 +59,6 @@ pub enum UpgradeResult { UpWoke(SignalToken), } -pub enum SelectionResult { - SelSuccess, - SelCanceled, - SelUpgraded(SignalToken, Receiver), -} - // 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 enum Message { @@ -338,27 +331,6 @@ pub fn drop_port(&self) { // 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> { - // 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) { @@ -370,31 +342,6 @@ fn bump(&self, amt: isize) -> isize { } } - // 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 { - 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> { diff --git a/src/libstd/sync/mpsc/sync.rs b/src/libstd/sync/mpsc/sync.rs index b2d9f4c6491..3c4f8e077c9 100644 --- a/src/libstd/sync/mpsc/sync.rs +++ b/src/libstd/sync/mpsc/sync.rs @@ -33,7 +33,6 @@ 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; @@ -406,42 +405,6 @@ pub fn drop_port(&self) { 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 Drop for Packet { diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 11ac34fcb24..87c2318a937 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -376,6 +376,8 @@ fn drop(&mut self) { impl From for Mutex { /// Creates a new mutex in an unlocked state ready for use. /// This is equivalent to [`Mutex::new`]. + /// + /// [`Mutex::new`]: ../../std/sync/struct.Mutex.html#method.new fn from(t: T) -> Self { Mutex::new(t) } diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index 1299a744095..b1b56f321fc 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -453,6 +453,8 @@ fn default() -> RwLock { impl From for RwLock { /// Creates a new instance of an `RwLock` which is unlocked. /// This is equivalent to [`RwLock::new`]. + /// + /// [`RwLock::new`]: ../../std/sync/struct.RwLock.html#method.new fn from(t: T) -> Self { RwLock::new(t) } diff --git a/src/libstd/sys/unix/rand.rs b/src/libstd/sys/unix/rand.rs index 77f1439e17b..71c62461ee9 100644 --- a/src/libstd/sys/unix/rand.rs +++ b/src/libstd/sys/unix/rand.rs @@ -47,7 +47,12 @@ fn getrandom_fill_bytes(v: &mut [u8]) -> bool { 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 { diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index fce28ffd9c3..35de4f4008b 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -443,6 +443,7 @@ pub fn spawn(self, f: F) -> io::Result> where /// [`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> where F: FnOnce() -> T, F: Send + 'a, T: Send + 'a diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 8a066f3f4a0..5b1a9bb739f 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -998,7 +998,7 @@ pub fn is_builtin_attr(attr: &ast::Attribute) -> bool { (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), ( diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 01b126f48b3..aa9028d4a6b 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -229,6 +229,7 @@ eh_personality, eh_unwind_resume, enable, + err, Err, except, exclusive_range_pattern, @@ -260,6 +261,7 @@ fundamental, future, Future, + gen_future, generators, generic_associated_types, generic_param_attrs, @@ -361,6 +363,7 @@ never, never_type, next, + __next, nll, no_builtins, no_core, @@ -406,6 +409,7 @@ Pending, pin, Pin, + pinned, platform_intrinsics, plugin, plugin_registrar, @@ -569,6 +573,7 @@ trivial_bounds, Try, try_blocks, + try_trait, tuple_indexing, ty, type_alias_enum_variants, @@ -587,6 +592,7 @@ uniform_paths, universal_impl_trait, unmarked_api, + unreachable_code, unrestricted_attribute_tokens, unsafe_destructor_blind_to_params, unsafe_no_drop_flag, @@ -601,6 +607,7 @@ use_nested_groups, usize, v1, + val, vis, visible_private_types, volatile, @@ -1029,6 +1036,17 @@ pub struct LocalInternedString { } 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) @@ -1105,7 +1123,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { impl Decodable for LocalInternedString { fn decode(d: &mut D) -> Result { - Ok(Symbol::intern(&d.read_str()?).as_str()) + Ok(LocalInternedString::intern(&d.read_str()?)) } } @@ -1134,6 +1152,13 @@ pub struct InternedString { } impl InternedString { + /// Maps a string to its interned representation. + pub fn intern(string: &str) -> Self { + InternedString { + symbol: Symbol::intern(string) + } + } + pub fn with R, R>(self, f: F) -> R { let str = with_interner(|interner| { interner.get(self.symbol) as *const str @@ -1236,7 +1261,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { impl Decodable for InternedString { fn decode(d: &mut D) -> Result { - Ok(Symbol::intern(&d.read_str()?).as_interned_str()) + Ok(InternedString::intern(&d.read_str()?)) } } diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index c6afa90e4ee..7f7db2a2125 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -37,12 +37,13 @@ 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::*; diff --git a/src/test/codegen/box-maybe-uninit.rs b/src/test/codegen/box-maybe-uninit.rs index 0dd67bb95cc..5004f787cde 100644 --- a/src/test/codegen/box-maybe-uninit.rs +++ b/src/test/codegen/box-maybe-uninit.rs @@ -1,6 +1,5 @@ // compile-flags: -O #![crate_type="lib"] -#![feature(maybe_uninit)] use std::mem::MaybeUninit; diff --git a/src/test/incremental/no_mangle.rs b/src/test/incremental/no_mangle.rs new file mode 100644 index 00000000000..1b17886a4f9 --- /dev/null +++ b/src/test/incremental/no_mangle.rs @@ -0,0 +1,10 @@ +// revisions:rpass1 rpass2 +// compile-flags: --crate-type cdylib +// skip-codegen + +#![deny(unused_attributes)] + +#[no_mangle] +pub extern "C" fn rust_no_mangle() -> i32 { + 42 +} diff --git a/src/test/mir-opt/const_prop/array_index.rs b/src/test/mir-opt/const_prop/array_index.rs index 4b97af68ff0..dd22eb5d604 100644 --- a/src/test/mir-opt/const_prop/array_index.rs +++ b/src/test/mir-opt/const_prop/array_index.rs @@ -23,7 +23,7 @@ fn main() { // 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]; diff --git a/src/test/mir-opt/const_prop/checked_add.rs b/src/test/mir-opt/const_prop/checked_add.rs index 0718316307c..fe98cf24eec 100644 --- a/src/test/mir-opt/const_prop/checked_add.rs +++ b/src/test/mir-opt/const_prop/checked_add.rs @@ -16,6 +16,6 @@ fn main() { // 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 diff --git a/src/test/mir-opt/const_prop/switch_int.rs b/src/test/mir-opt/const_prop/switch_int.rs new file mode 100644 index 00000000000..0df1112ec3e --- /dev/null +++ b/src/test/mir-opt/const_prop/switch_int.rs @@ -0,0 +1,38 @@ +#[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 diff --git a/src/test/mir-opt/simplify_if.rs b/src/test/mir-opt/simplify_if.rs index b2a99a6d446..35512b94c0c 100644 --- a/src/test/mir-opt/simplify_if.rs +++ b/src/test/mir-opt/simplify_if.rs @@ -5,15 +5,15 @@ fn main() { } // 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 diff --git a/src/test/run-pass/issues/issue-13494.rs b/src/test/run-pass/issues/issue-13494.rs deleted file mode 100644 index 12be97702a9..00000000000 --- a/src/test/run-pass/issues/issue-13494.rs +++ /dev/null @@ -1,35 +0,0 @@ -// 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>) { - 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::(); - 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(); -} diff --git a/src/test/run-pass/macros/macro-comma-support.rs b/src/test/run-pass/macros/macro-comma-support.rs index 904f2e2c7fd..12a612c153a 100644 --- a/src/test/run-pass/macros/macro-comma-support.rs +++ b/src/test/run-pass/macros/macro-comma-support.rs @@ -233,8 +233,6 @@ fn println() { println!("hello {}", "world",); } -// select! is too troublesome and unlikely to be stabilized - // stringify! is N/A #[cfg(std)] diff --git a/src/test/run-pass/panic-uninitialized-zeroed.rs b/src/test/run-pass/panic-uninitialized-zeroed.rs index 3f6e489bb83..4ca4b407bd4 100644 --- a/src/test/run-pass/panic-uninitialized-zeroed.rs +++ b/src/test/run-pass/panic-uninitialized-zeroed.rs @@ -2,7 +2,7 @@ // 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}; diff --git a/src/test/run-pass/union/union-nonzero.rs b/src/test/run-pass/union/union-nonzero.rs new file mode 100644 index 00000000000..bd84b46bf3d --- /dev/null +++ b/src/test/run-pass/union/union-nonzero.rs @@ -0,0 +1,51 @@ +// 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` 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>` does not take advantage of non-zero optimization, and thus is a safe +// construct. + +use std::mem::{size_of, transmute}; + +union U1 { + a: A, +} + +union U2 { + a: A, + b: B, +} + +// Option 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::>>() > size_of::>()); + assert!(size_of::>>() > size_of::>()); + assert!(size_of::>>() > size_of::>()); + + // ...even when theoretically possible: + assert!(size_of::>>() > size_of::>()); + assert!(size_of::>>() > size_of::>()); + + // The unused bits of the () variant can have any value. + let zeroed: U2<&u8, ()> = unsafe { transmute(std::ptr::null::()) }; + + if let None = Some(zeroed) { + panic!() + } +} diff --git a/src/test/rustdoc-ui/doc-without-codeblock.rs b/src/test/rustdoc-ui/doc-without-codeblock.rs index aa3f539ba32..4b2a91e9c81 100644 --- a/src/test/rustdoc-ui/doc-without-codeblock.rs +++ b/src/test/rustdoc-ui/doc-without-codeblock.rs @@ -1,6 +1,4 @@ -//~ 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 diff --git a/src/test/rustdoc-ui/doc-without-codeblock.stderr b/src/test/rustdoc-ui/doc-without-codeblock.stderr index 208bdedf24d..23c07c4d32d 100644 --- a/src/test/rustdoc-ui/doc-without-codeblock.stderr +++ b/src/test/rustdoc-ui/doc-without-codeblock.stderr @@ -1,25 +1,35 @@ 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! | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/rustdoc-ui/lint-missing-doc-code-example.rs b/src/test/rustdoc-ui/lint-missing-doc-code-example.rs new file mode 100644 index 00000000000..ffe0ddcd8c9 --- /dev/null +++ b/src/test/rustdoc-ui/lint-missing-doc-code-example.rs @@ -0,0 +1,40 @@ +#![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() {} +} diff --git a/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr b/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr new file mode 100644 index 00000000000..97a52a13e3f --- /dev/null +++ b/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr @@ -0,0 +1,21 @@ +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 + diff --git a/src/test/rustdoc/async-move-doctest.rs b/src/test/rustdoc/async-move-doctest.rs new file mode 100644 index 00000000000..42723132782 --- /dev/null +++ b/src/test/rustdoc/async-move-doctest.rs @@ -0,0 +1,14 @@ +// 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 {}); +//! } +//! ``` diff --git a/src/test/rustdoc/intra-link-libstd-re-export.rs b/src/test/rustdoc/intra-link-libstd-re-export.rs new file mode 100644 index 00000000000..6f239292ec2 --- /dev/null +++ b/src/test/rustdoc/intra-link-libstd-re-export.rs @@ -0,0 +1,3 @@ +#![deny(intra_doc_link_resolution_failure)] + +pub use std::*; diff --git a/src/test/rustdoc/playground-arg.rs b/src/test/rustdoc/playground-arg.rs index fb1be7397e6..018716ad45a 100644 --- a/src/test/rustdoc/playground-arg.rs +++ b/src/test/rustdoc/playground-arg.rs @@ -11,4 +11,4 @@ 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" diff --git a/src/test/rustdoc/playground.rs b/src/test/rustdoc/playground.rs index 1b76e6c8853..9971c7b4297 100644 --- a/src/test/rustdoc/playground.rs +++ b/src/test/rustdoc/playground.rs @@ -24,6 +24,6 @@ //! } //! ``` -// @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" diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs index 0129a3f72b2..ca0a432d339 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs +++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs @@ -52,7 +52,7 @@ //~^ 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 diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr index dcbe13a749f..c7081205e14 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr @@ -1152,12 +1152,6 @@ warning: 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 | diff --git a/src/test/ui/print_type_sizes/niche-filling.rs b/src/test/ui/print_type_sizes/niche-filling.rs index bed1e32a601..0127261b2b7 100644 --- a/src/test/ui/print_type_sizes/niche-filling.rs +++ b/src/test/ui/print_type_sizes/niche-filling.rs @@ -57,6 +57,15 @@ pub enum Enum4 { Four(D) } +pub union Union1 { + a: A, +} + +pub union Union2 { + a: A, + b: B, +} + #[start] fn start(_: isize, _: *const *const u8) -> isize { let _x: MyOption = Default::default(); @@ -69,5 +78,13 @@ fn start(_: isize, _: *const *const u8) -> isize { let _e: Enum4<(), char, (), ()> = Enum4::One(()); let _f: Enum4<(), (), bool, ()> = Enum4::One(()); let _g: Enum4<(), (), (), MyOption> = Enum4::One(()); + + // Unions do not currently participate in niche filling. + let _h: MyOption> = Default::default(); + + // ...even when theoretically possible. + let _i: MyOption> = Default::default(); + let _j: MyOption> = Default::default(); + 0 } diff --git a/src/test/ui/print_type_sizes/niche-filling.stdout b/src/test/ui/print_type_sizes/niche-filling.stdout index 9cdb2ae4f57..301edc0d086 100644 --- a/src/test/ui/print_type_sizes/niche-filling.stdout +++ b/src/test/ui/print_type_sizes/niche-filling.stdout @@ -14,6 +14,21 @@ print-type-size field `.post`: 2 bytes 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>`: 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>`: 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>`: 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 @@ -36,6 +51,17 @@ print-type-size type: `MyOption`: 4 bytes, alignment: 4 by 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`: 4 bytes, alignment: 4 bytes +print-type-size variant `Union1`: 4 bytes +print-type-size field `.a`: 4 bytes +print-type-size type: `Union2`: 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`: 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>`: 2 bytes, alignment: 1 bytes diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs index 04986b59ea0..38bd3fc006d 100644 --- a/src/tools/error_index_generator/main.rs +++ b/src/tools/error_index_generator/main.rs @@ -15,6 +15,7 @@ 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}; @@ -97,7 +98,8 @@ fn error_code_block(&self, output: &mut dyn Write, info: &ErrorMetadata, 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, "

No description.

\n")?, } diff --git a/src/tools/miri b/src/tools/miri index bc0c76d861a..0c85dbf3df0 160000 --- a/src/tools/miri +++ b/src/tools/miri @@ -1 +1 @@ -Subproject commit bc0c76d861a178911f3f506196a7404eda1e690d +Subproject commit 0c85dbf3df0f545133dca24eccfc9f0f6107c7f8 diff --git a/src/tools/rls b/src/tools/rls index 5b8e99bb619..9692ca8fd82 160000 --- a/src/tools/rls +++ b/src/tools/rls @@ -1 +1 @@ -Subproject commit 5b8e99bb61958ca8abcb7c5eda70521726be1065 +Subproject commit 9692ca8fd82a8f96a4113dc4b88c1fb1d79c1c60