]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #60959 - petrochenkov:sassert, r=estebank
authorMazdak Farrokhzad <twingoow@gmail.com>
Mon, 20 May 2019 21:03:07 +0000 (23:03 +0200)
committerGitHub <noreply@github.com>
Mon, 20 May 2019 21:03:07 +0000 (23:03 +0200)
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]`
```

100 files changed:
src/bootstrap/test.rs
src/ci/docker/x86_64-gnu-tools/checkregression.py
src/liballoc/alloc.rs
src/liballoc/collections/binary_heap.rs
src/liballoc/lib.rs
src/libcore/fmt/mod.rs
src/libcore/lib.rs
src/libcore/mem.rs
src/libcore/ptr.rs
src/libcore/task/wake.rs
src/librustc/hir/lowering.rs
src/librustc/hir/mod.rs
src/librustc/infer/error_reporting/mod.rs
src/librustc/infer/error_reporting/nice_region_error/util.rs
src/librustc/lint/context.rs
src/librustc/lint/mod.rs
src/librustc/mir/mono.rs
src/librustc/traits/object_safety.rs
src/librustc/traits/structural_impls.rs
src/librustc/ty/mod.rs
src/librustc/ty/print/pretty.rs
src/librustc/ty/query/values.rs
src/librustc/ty/sty.rs
src/librustc_codegen_llvm/back/write.rs
src/librustc_codegen_llvm/intrinsic.rs
src/librustc_codegen_ssa/back/write.rs
src/librustc_codegen_ssa/mir/block.rs
src/librustc_codegen_utils/symbol_names.rs
src/librustc_data_structures/stable_hasher.rs
src/librustc_metadata/creader.rs
src/librustc_metadata/locator.rs
src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs
src/librustc_mir/interpret/eval_context.rs
src/librustc_mir/monomorphize/item.rs
src/librustc_mir/transform/check_unsafety.rs
src/librustc_mir/transform/const_prop.rs
src/librustc_typeck/check/intrinsic.rs
src/librustc_typeck/collect.rs
src/librustdoc/clean/mod.rs
src/librustdoc/config.rs
src/librustdoc/externalfiles.rs
src/librustdoc/html/layout.rs
src/librustdoc/html/markdown.rs
src/librustdoc/html/render.rs
src/librustdoc/html/static/rustdoc.css
src/librustdoc/html/static/themes/dark.css
src/librustdoc/html/static/themes/light.css
src/librustdoc/lib.rs
src/librustdoc/markdown.rs
src/librustdoc/passes/collect_intra_doc_links.rs
src/librustdoc/passes/mod.rs
src/librustdoc/test.rs
src/libstd/alloc.rs
src/libstd/collections/hash/map.rs
src/libstd/error.rs
src/libstd/ffi/os_str.rs
src/libstd/fs.rs
src/libstd/io/buffered.rs
src/libstd/lib.rs
src/libstd/macros.rs
src/libstd/net/addr.rs
src/libstd/sync/mpsc/mod.rs
src/libstd/sync/mpsc/oneshot.rs
src/libstd/sync/mpsc/select.rs [deleted file]
src/libstd/sync/mpsc/select_tests.rs [deleted file]
src/libstd/sync/mpsc/shared.rs
src/libstd/sync/mpsc/stream.rs
src/libstd/sync/mpsc/sync.rs
src/libstd/sync/mutex.rs
src/libstd/sync/rwlock.rs
src/libstd/sys/unix/rand.rs
src/libstd/thread/mod.rs
src/libsyntax/feature_gate.rs
src/libsyntax_pos/symbol.rs
src/libtest/lib.rs
src/test/codegen/box-maybe-uninit.rs
src/test/incremental/no_mangle.rs [new file with mode: 0644]
src/test/mir-opt/const_prop/array_index.rs
src/test/mir-opt/const_prop/checked_add.rs
src/test/mir-opt/const_prop/switch_int.rs [new file with mode: 0644]
src/test/mir-opt/simplify_if.rs
src/test/run-pass/issues/issue-13494.rs [deleted file]
src/test/run-pass/macros/macro-comma-support.rs
src/test/run-pass/panic-uninitialized-zeroed.rs
src/test/run-pass/union/union-nonzero.rs [new file with mode: 0644]
src/test/rustdoc-ui/doc-without-codeblock.rs
src/test/rustdoc-ui/doc-without-codeblock.stderr
src/test/rustdoc-ui/lint-missing-doc-code-example.rs [new file with mode: 0644]
src/test/rustdoc-ui/lint-missing-doc-code-example.stderr [new file with mode: 0644]
src/test/rustdoc/async-move-doctest.rs [new file with mode: 0644]
src/test/rustdoc/intra-link-libstd-re-export.rs [new file with mode: 0644]
src/test/rustdoc/playground-arg.rs
src/test/rustdoc/playground.rs
src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs
src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr
src/test/ui/print_type_sizes/niche-filling.rs
src/test/ui/print_type_sizes/niche-filling.stdout
src/tools/error_index_generator/main.rs
src/tools/miri
src/tools/rls

index 7826ac9471806043c1b00505e13cbe9ffab424c6..be0af8be7b272bc615aab84985faa07db286c449 100644 (file)
@@ -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,
         })
     }
index 8aa90319d661520bbe1657a8cce2cec6b697b8b9..0cc0a6329e5bf779060a19762329296fd935c8dd 100755 (executable)
@@ -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:
index ddc6481eec78e9d703b4a26499cd60cac93b8cca..41ff06d70ff09eb7897af0f71c5385e42807483d 100644 (file)
@@ -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
 ///
 /// ```
index 39fcfaa789377bb575fabda5be8fccc790468885..c5a0b6e877b65f124f61e925ab8989c5e02547e1 100644 (file)
 /// assert_eq!(heap.pop(), Some(Reverse(5)));
 /// assert_eq!(heap.pop(), None);
 /// ```
+///
+/// # Time complexity
+///
+/// | [push] | [pop]    | [peek]/[peek\_mut] |
+/// |--------|----------|--------------------|
+/// | O(1)~  | O(log n) | O(1)               |
+///
+/// The value for `push` is an expected cost; the method documentation gives a
+/// more detailed analysis.
+///
+/// [push]: #method.push
+/// [pop]: #method.pop
+/// [peek]: #method.peek
+/// [peek\_mut]: #method.peek_mut
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct BinaryHeap<T> {
     data: Vec<T>,
@@ -384,6 +398,10 @@ pub fn with_capacity(capacity: usize) -> BinaryHeap<T> {
     /// }
     /// assert_eq!(heap.peek(), Some(&2));
     /// ```
+    ///
+    /// # Time complexity
+    ///
+    /// Cost is O(1) in the worst case.
     #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
     pub fn peek_mut(&mut self) -> Option<PeekMut<'_, T>> {
         if self.is_empty() {
@@ -411,6 +429,11 @@ pub fn peek_mut(&mut self) -> Option<PeekMut<'_, T>> {
     /// assert_eq!(heap.pop(), Some(1));
     /// assert_eq!(heap.pop(), None);
     /// ```
+    ///
+    /// # Time complexity
+    ///
+    /// The worst case cost of `pop` on a heap containing *n* elements is O(log
+    /// n).
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn pop(&mut self) -> Option<T> {
         self.data.pop().map(|mut item| {
@@ -438,6 +461,22 @@ pub fn pop(&mut self) -> Option<T> {
     /// 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)
index 2edd946ff11cfa91ce2c397ec2edd85df0a81582..d90036eaf49b8f3da6389d23e8f978f69fe5984e 100644 (file)
 #![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)]
index 43c1a3b7767ab647838c9f4f3702e0a29271a881..2f6d745d146d647d3fd5716e57db7dc020964b39 100644 (file)
@@ -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
index 28db55578c3de7972a2d19b1795a337675e925b3..4a70329b64bc983a7d43b0b4214be77d892c8447 100644 (file)
 #![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]
index 9fb071d29524bee5abfc0694c77f155da4a1b405..24bee6355a7ccfe41f9e868b32a71718b52a2fcb 100644 (file)
 /// The practical use cases for `forget` are rather specialized and mainly come
 /// up in unsafe or FFI code.
 ///
-/// ## Use case 1
-///
-/// You have created an uninitialized value using [`mem::uninitialized`][uninit].
-/// You must either initialize or `forget` it on every computation path before
-/// Rust drops it automatically, like at the end of a scope or after a panic.
-/// Running the destructor on an uninitialized value would be [undefined behavior][ub].
-///
-/// ```
-/// use std::mem;
-/// use std::ptr;
-///
-/// # let some_condition = false;
-/// unsafe {
-///     let mut uninit_vec: Vec<u32> = mem::uninitialized();
-///
-///     if some_condition {
-///         // Initialize the variable.
-///         ptr::write(&mut uninit_vec, Vec::new());
-///     } else {
-///         // Forget the uninitialized value so its destructor doesn't run.
-///         mem::forget(uninit_vec);
-///     }
-/// }
-/// ```
-///
-/// ## Use case 2
-///
-/// You have duplicated the bytes making up a value, without doing a proper
-/// [`Clone`][clone]. You need the value's destructor to run only once,
-/// because a double `free` is undefined behavior.
-///
-/// An example is a possible implementation of [`mem::swap`][swap]:
-///
-/// ```
-/// use std::mem;
-/// use std::ptr;
-///
-/// # #[allow(dead_code)]
-/// fn swap<T>(x: &mut T, y: &mut T) {
-///     unsafe {
-///         // Give ourselves some scratch space to work with
-///         let mut t: T = mem::uninitialized();
-///
-///         // Perform the swap, `&mut` pointers never alias
-///         ptr::copy_nonoverlapping(&*x, &mut t, 1);
-///         ptr::copy_nonoverlapping(&*y, x, 1);
-///         ptr::copy_nonoverlapping(&t, y, 1);
-///
-///         // y and t now point to the same thing, but we need to completely
-///         // forget `t` because we do not want to run the destructor for `T`
-///         // on its value, which is still owned somewhere outside this function.
-///         mem::forget(t);
-///     }
-/// }
-/// ```
-///
 /// [drop]: fn.drop.html
 /// [uninit]: fn.uninitialized.html
 /// [clone]: ../clone/trait.Clone.html
@@ -465,29 +409,37 @@ pub const fn needs_drop<T>() -> 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>() -> T {
@@ -498,130 +450,23 @@ pub unsafe fn zeroed<T>() -> T {
 /// Bypasses Rust's normal memory-initialization checks by pretending to
 /// produce a value of type `T`, while doing nothing at all.
 ///
-/// **This is incredibly dangerous and should not be done lightly. Deeply
-/// consider initializing your memory with a default value instead.**
-///
-/// This is useful for FFI functions and initializing arrays sometimes,
-/// but should generally be avoided.
-///
-/// # Undefined behavior
-///
-/// It is [undefined behavior][ub] to read uninitialized memory, even just an
-/// uninitialized boolean. For instance, if you branch on the value of such
-/// a boolean, your program may take one, both, or neither of the branches.
-///
-/// Writing to the uninitialized value is similarly dangerous. Rust believes the
-/// value is initialized, and will therefore try to [`Drop`] the uninitialized
-/// value and its fields if you try to overwrite it in a normal manner. The only way
-/// to safely initialize an uninitialized value is with [`ptr::write`][write],
-/// [`ptr::copy`][copy], or [`ptr::copy_nonoverlapping`][copy_no].
-///
-/// If the value does implement [`Drop`], it must be initialized before
-/// it goes out of scope (and therefore would be dropped). Note that this
-/// includes a `panic` occurring and unwinding the stack suddenly.
+/// **This functon is deprecated.** Use [`MaybeUninit<T>`] instead.
 ///
-/// If you partially initialize an array, you may need to use
-/// [`ptr::drop_in_place`][drop_in_place] to remove the elements you have fully
-/// initialized followed by [`mem::forget`][mem_forget] to prevent drop running
-/// on the array. If a partially allocated array is dropped this will lead to
-/// undefined behaviour.
-///
-/// # Examples
-///
-/// Here's how to safely initialize an array of [`Vec`]s.
-///
-/// ```
-/// use std::mem;
-/// use std::ptr;
-///
-/// // Only declare the array. This safely leaves it
-/// // uninitialized in a way that Rust will track for us.
-/// // However we can't initialize it element-by-element
-/// // safely, and we can't use the `[value; 1000]`
-/// // constructor because it only works with `Copy` data.
-/// let mut data: [Vec<u32>; 1000];
-///
-/// unsafe {
-///     // So we need to do this to initialize it.
-///     data = mem::uninitialized();
-///
-///     // DANGER ZONE: if anything panics or otherwise
-///     // incorrectly reads the array here, we will have
-///     // Undefined Behavior.
-///
-///     // It's ok to mutably iterate the data, since this
-///     // doesn't involve reading it at all.
-///     // (ptr and len are statically known for arrays)
-///     for elem in &mut data[..] {
-///         // *elem = Vec::new() would try to drop the
-///         // uninitialized memory at `elem` -- bad!
-///         //
-///         // Vec::new doesn't allocate or do really
-///         // anything. It's only safe to call here
-///         // because we know it won't panic.
-///         ptr::write(elem, Vec::new());
-///     }
-///
-///     // SAFE ZONE: everything is initialized.
-/// }
-///
-/// println!("{:?}", &data[0]);
-/// ```
-///
-/// This example emphasizes exactly how delicate and dangerous using `mem::uninitialized`
-/// can be. Note that the [`vec!`] macro *does* let you initialize every element with a
-/// value that is only [`Clone`], so the following is semantically equivalent and
-/// vastly less dangerous, as long as you can live with an extra heap
-/// allocation:
-///
-/// ```
-/// let data: Vec<Vec<u32>> = vec![Vec::new(); 1000];
-/// println!("{:?}", &data[0]);
-/// ```
-///
-/// This example shows how to handle partially initialized arrays, which could
-/// be found in low-level datastructures.
-///
-/// ```
-/// use std::mem;
-/// use std::ptr;
-///
-/// // Count the number of elements we have assigned.
-/// let mut data_len: usize = 0;
-/// let mut data: [String; 1000];
-///
-/// unsafe {
-///     data = mem::uninitialized();
-///
-///     for elem in &mut data[0..500] {
-///         ptr::write(elem, String::from("hello"));
-///         data_len += 1;
-///     }
-///
-///     // For each item in the array, drop if we allocated it.
-///     for i in &mut data[0..data_len] {
-///         ptr::drop_in_place(i);
-///     }
-/// }
-/// // Forget the data. If this is allowed to drop, you may see a crash such as:
-/// // 'mem_uninit_test(2457,0x7fffb55dd380) malloc: *** error for object
-/// // 0x7ff3b8402920: pointer being freed was not allocated'
-/// mem::forget(data);
-/// ```
+/// The reason for deprecation is that the function basically cannot be used
+/// correctly: [the Rust compiler assumes][inv] that values are properly initialized.
+/// As a consequence, calling e.g. `mem::uninitialized::<bool>()` causes immediate
+/// undefined behavior for returning a `bool` that is not definitely either `true`
+/// or `false`. Worse, truly uninitialized memory like what gets returned here
+/// is special in that the compiler knows that it does not have a fixed value.
+/// This makes it undefined behavior to have uninitialized data in a variable even
+/// if that variable has an integer type.
+/// (Notice that the rules around uninitialized integers are not finalized yet, but
+/// until they are, it is advisable to avoid them.)
 ///
-/// [`Vec`]: ../../std/vec/struct.Vec.html
-/// [`vec!`]: ../../std/macro.vec.html
-/// [`Clone`]: ../../std/clone/trait.Clone.html
-/// [ub]: ../../reference/behavior-considered-undefined.html
-/// [write]: ../ptr/fn.write.html
-/// [drop_in_place]: ../ptr/fn.drop_in_place.html
-/// [mem_zeroed]: fn.zeroed.html
-/// [mem_forget]: fn.forget.html
-/// [copy]: ../intrinsics/fn.copy.html
-/// [copy_no]: ../intrinsics/fn.copy_nonoverlapping.html
-/// [`Drop`]: ../ops/trait.Drop.html
+/// [`MaybeUninit<T>`]: union.MaybeUninit.html
+/// [inv]: union.MaybeUninit.html#initialization-invariant
 #[inline]
-#[rustc_deprecated(since = "2.0.0", reason = "use `mem::MaybeUninit::uninit` instead")]
+#[rustc_deprecated(since = "1.40.0", reason = "use `mem::MaybeUninit` instead")]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub unsafe fn uninitialized<T>() -> T {
     intrinsics::panic_if_uninhabited::<T>();
@@ -899,7 +744,6 @@ pub fn discriminant<T>(v: &T) -> Discriminant<T> {
     }
 }
 
-// FIXME: Reference `MaybeUninit` from these docs, once that is stable.
 /// A wrapper to inhibit compiler from automatically calling `T`’s destructor.
 ///
 /// This wrapper is 0-cost.
@@ -908,6 +752,7 @@ pub fn discriminant<T>(v: &T) -> Discriminant<T> {
 /// As a consequence, it has *no effect* on the assumptions that the compiler makes
 /// about all values being initialized at their type.  In particular, initializing
 /// a `ManuallyDrop<&mut T>` with [`mem::zeroed`] is undefined behavior.
+/// If you need to handle uninitialized data, use [`MaybeUninit<T>`] instead.
 ///
 /// # Examples
 ///
@@ -942,6 +787,7 @@ pub fn discriminant<T>(v: &T) -> Discriminant<T> {
 /// ```
 ///
 /// [`mem::zeroed`]: fn.zeroed.html
+/// [`MaybeUninit<T>`]: union.MaybeUninit.html
 #[stable(feature = "manually_drop", since = "1.20.0")]
 #[lang = "manually_drop"]
 #[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -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<T>`]
+/// is considered initialized because the only requirement the compiler knows about it
+/// is that the data pointer must be non-null. Creating such a `Vec<T>` does not cause
+/// *immediate* undefined behavior, but will cause undefined behavior with most
+/// safe operations (including dropping it).
+///
+/// [`Vec<T>`]: ../../std/vec/struct.Vec.html
+///
+/// # Examples
+///
 /// `MaybeUninit<T>` serves to enable unsafe code to deal with uninitialized data.
 /// It is a signal to the compiler indicating that the data here might *not*
 /// be initialized:
 ///
 /// ```rust
-/// #![feature(maybe_uninit)]
 /// use std::mem::MaybeUninit;
 ///
 /// // Create an explicitly uninitialized reference. The compiler knows that data inside
 /// // a `MaybeUninit<T>` may be invalid, and hence this is not UB:
 /// let mut x = MaybeUninit::<&i32>::uninit();
 /// // Set it to a valid value.
-/// x.write(&0);
+/// unsafe { x.as_mut_ptr().write(&0); }
 /// // Extract the initialized data -- this is only allowed *after* properly
 /// // initializing `x`!
 /// let x = unsafe { x.assume_init() };
 /// ```
 ///
 /// The compiler then knows to not make any incorrect assumptions or optimizations on this code.
-//
-// FIXME before stabilizing, explain how to initialize a struct field-by-field.
+///
+/// ## out-pointers
+///
+/// You can use `MaybeUninit<T>` to implement "out-pointers": instead of returning data
+/// from a function, pass it a pointer to some (uninitialized) memory to put the
+/// result into. This can be useful when it is important for the caller to control
+/// how the memory the result is stored in gets allocated, and you want to avoid
+/// unnecessary moves.
+///
+/// ```
+/// use std::mem::MaybeUninit;
+///
+/// unsafe fn make_vec(out: *mut Vec<i32>) {
+///     // `write` does not drop the old contents, which is important.
+///     out.write(vec![1, 2, 3]);
+/// }
+///
+/// let mut v: MaybeUninit<Vec<i32>> = MaybeUninit::uninit();
+/// unsafe { make_vec(v.as_mut_ptr()); }
+/// // Now we know `v` is initialized! This also makes sure the vector gets
+/// // properly dropped.
+/// let v = unsafe { v.assume_init() };
+/// assert_eq!(&v, &[1, 2, 3]);
+/// ```
+///
+/// ## Initializing an array element-by-element
+///
+/// `MaybeUninit<T>` can be used to initialize a large array element-by-element:
+///
+/// ```
+/// use std::mem::{self, MaybeUninit};
+/// use std::ptr;
+///
+/// let data = {
+///     // Create an uninitialized array of `MaybeUninit`. The `assume_init` is
+///     // safe because the type we are claiming to have initialized here is a
+///     // bunch of `MaybeUninit`s, which do not require initialization.
+///     let mut data: [MaybeUninit<Vec<u32>>; 1000] = unsafe {
+///         MaybeUninit::uninit().assume_init()
+///     };
+///
+///     // Dropping a `MaybeUninit` does nothing, so if there is a panic during this loop,
+///     // we have a memory leak, but there is no memory safety issue.
+///     for elem in &mut data[..] {
+///         unsafe { ptr::write(elem.as_mut_ptr(), vec![42]); }
+///     }
+///
+///     // Everything is initialized. Transmute the array to the
+///     // initialized type.
+///     unsafe { mem::transmute::<_, [Vec<u32>; 1000]>(data) }
+/// };
+///
+/// assert_eq!(&data[0], &[42]);
+/// ```
+///
+/// You can also work with partially initialized arrays, which could
+/// be found in low-level datastructures.
+///
+/// ```
+/// use std::mem::MaybeUninit;
+/// use std::ptr;
+///
+/// // Create an uninitialized array of `MaybeUninit`. The `assume_init` is
+/// // safe because the type we are claiming to have initialized here is a
+/// // bunch of `MaybeUninit`s, which do not require initialization.
+/// let mut data: [MaybeUninit<String>; 1000] = unsafe { MaybeUninit::uninit().assume_init() };
+/// // Count the number of elements we have assigned.
+/// let mut data_len: usize = 0;
+///
+/// for elem in &mut data[0..500] {
+///     unsafe { ptr::write(elem.as_mut_ptr(), String::from("hello")); }
+///     data_len += 1;
+/// }
+///
+/// // For each item in the array, drop if we allocated it.
+/// for elem in &mut data[0..data_len] {
+///     unsafe { ptr::drop_in_place(elem.as_mut_ptr()); }
+/// }
+/// ```
+///
+/// ## Initializing a struct field-by-field
+///
+/// There is currently no supported way to create a raw pointer or reference
+/// to a field of a struct inside `MaybeUninit<Struct>`. That means it is not possible
+/// to create a struct by calling `MaybeUninit::uninit::<Struct>()` and then writing
+/// to its fields.
+///
+/// [ub]: ../../reference/behavior-considered-undefined.html
+///
+/// # Layout
+///
+/// `MaybeUninit<T>` is guaranteed to have the same size and alignment as `T`:
+///
+/// ```rust
+/// use std::mem::{MaybeUninit, size_of, align_of};
+/// assert_eq!(size_of::<MaybeUninit<u64>>(), size_of::<u64>());
+/// assert_eq!(align_of::<MaybeUninit<u64>>(), align_of::<u64>());
+/// ```
+///
+/// However remember that a type *containing* a `MaybeUninit<T>` is not necessarily the same
+/// layout; Rust does not in general guarantee that the fields of a `Foo<T>` have the same order as
+/// a `Foo<U>` even if `T` and `U` have the same size and alignment. Furthermore because any bit
+/// value is valid for a `MaybeUninit<T>` the compiler can't apply non-zero/niche-filling
+/// optimizations, potentially resulting in a larger size:
+///
+/// ```rust
+/// # use std::mem::{MaybeUninit, size_of, align_of};
+/// assert_eq!(size_of::<Option<bool>>(), 1);
+/// assert_eq!(size_of::<Option<MaybeUninit<bool>>>(), 2);
+/// ```
 #[allow(missing_debug_implementations)]
-#[unstable(feature = "maybe_uninit", issue = "53491")]
+#[stable(feature = "maybe_uninit", since = "1.36.0")]
 #[derive(Copy)]
-// NOTE: after stabilizing `MaybeUninit`, proceed to deprecate `mem::uninitialized`.
 pub union MaybeUninit<T> {
     uninit: (),
     value: ManuallyDrop<T>,
 }
 
-#[unstable(feature = "maybe_uninit", issue = "53491")]
+#[stable(feature = "maybe_uninit", since = "1.36.0")]
 impl<T: Copy> Clone for MaybeUninit<T> {
     #[inline(always)]
     fn clone(&self) -> Self {
@@ -1132,10 +1094,13 @@ fn clone(&self) -> Self {
 
 impl<T> MaybeUninit<T> {
     /// Creates a new `MaybeUninit<T>` initialized with the given value.
+    /// It is safe to call [`assume_init`] on the return value of this function.
     ///
     /// Note that dropping a `MaybeUninit<T>` will never call `T`'s drop code.
     /// It is your responsibility to make sure `T` gets dropped if it got initialized.
-    #[unstable(feature = "maybe_uninit", issue = "53491")]
+    ///
+    /// [`assume_init`]: #method.assume_init
+    #[stable(feature = "maybe_uninit", since = "1.36.0")]
     #[inline(always)]
     pub const fn new(val: T) -> MaybeUninit<T> {
         MaybeUninit { value: ManuallyDrop::new(val) }
@@ -1145,7 +1110,11 @@ pub const fn new(val: T) -> MaybeUninit<T> {
     ///
     /// Note that dropping a `MaybeUninit<T>` will never call `T`'s drop code.
     /// It is your responsibility to make sure `T` gets dropped if it got initialized.
-    #[unstable(feature = "maybe_uninit", issue = "53491")]
+    ///
+    /// See the [type-level documentation][type] for some examples.
+    ///
+    /// [type]: union.MaybeUninit.html
+    #[stable(feature = "maybe_uninit", since = "1.36.0")]
     #[inline(always)]
     pub const fn uninit() -> MaybeUninit<T> {
         MaybeUninit { uninit: () }
@@ -1166,7 +1135,6 @@ pub const fn uninit() -> MaybeUninit<T> {
     /// 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<T> {
     /// 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<T> {
     /// // Inside a pair, we create a `NotZero` that does not have a valid discriminant.
     /// // This is undefined behavior.
     /// ```
-    #[unstable(feature = "maybe_uninit", issue = "53491")]
+    #[stable(feature = "maybe_uninit", since = "1.36.0")]
     #[inline]
     pub fn zeroed() -> MaybeUninit<T> {
         let mut u = MaybeUninit::<T>::uninit();
@@ -1202,7 +1169,7 @@ pub fn zeroed() -> MaybeUninit<T> {
     /// 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<T>` is initialized.
+    /// Writing to memory that this pointer (non-transitively) points to is undefined behavior
+    /// (except inside an `UnsafeCell<T>`).
     ///
     /// # Examples
     ///
     /// Correct usage of this method:
     ///
     /// ```rust
-    /// #![feature(maybe_uninit)]
     /// use std::mem::MaybeUninit;
     ///
     /// let mut x = MaybeUninit::<Vec<u32>>::uninit();
@@ -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::<Vec<u32>>::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::<Vec<u32>>::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::<Vec<u32>>::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<T>` really is in an initialized
-    /// state. Calling this when the content is not yet fully initialized causes undefined
-    /// behavior.
+    /// state. Calling this when the content is not yet fully initialized causes immediate undefined
+    /// behavior. The [type-level documentation][inv] contains more information about
+    /// this initialization invariant.
+    ///
+    /// [inv]: #initialization-invariant
     ///
     /// # Examples
     ///
     /// Correct usage of this method:
     ///
     /// ```rust
-    /// #![feature(maybe_uninit)]
     /// use std::mem::MaybeUninit;
     ///
     /// let mut x = MaybeUninit::<bool>::uninit();
@@ -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::<Vec<u32>>::uninit();
     /// let x_init = unsafe { x.assume_init() };
     /// // `x` had not been initialized yet, so this last line caused undefined behavior.
     /// ```
-    #[unstable(feature = "maybe_uninit", issue = "53491")]
+    #[stable(feature = "maybe_uninit", since = "1.36.0")]
     #[inline(always)]
     pub unsafe fn assume_init(self) -> T {
         intrinsics::panic_if_uninhabited::<T>();
@@ -1338,13 +1304,15 @@ pub unsafe fn assume_init(self) -> T {
     ///
     /// It is up to the caller to guarantee that the `MaybeUninit<T>` really is in an initialized
     /// state. Calling this when the content is not yet fully initialized causes undefined
-    /// behavior.
+    /// behavior. The [type-level documentation][inv] contains more information about
+    /// this initialization invariant.
     ///
     /// Moreover, this leaves a copy of the same data behind in the `MaybeUninit<T>`. When using
     /// multiple copies of the data (by calling `read` multiple times, or first
     /// calling `read` and then [`assume_init`]), it is your responsibility
     /// to ensure that that data may indeed be duplicated.
     ///
+    /// [inv]: #initialization-invariant
     /// [`assume_init`]: #method.assume_init
     ///
     /// # Examples
@@ -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::<u32>::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::<Option<Vec<u32>>>::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::<T>();
index ada784e9ce70504171dadec906a592d59e66e991..dd321dcdfae6c8ab200a688aff273c8eb940854f 100644 (file)
 /// location first:
 /// ```
 /// use std::ptr;
-/// use std::mem;
+/// use std::mem::{self, MaybeUninit};
 ///
 /// unsafe fn drop_after_copy<T>(to_drop: *mut T) {
-///     let mut copy: T = mem::uninitialized();
-///     ptr::copy(to_drop, &mut copy, 1);
-///     drop(copy);
+///     let mut copy: MaybeUninit<T> = MaybeUninit::uninit();
+///     ptr::copy(to_drop, copy.as_mut_ptr(), 1);
+///     drop(copy.assume_init());
 /// }
 ///
 /// #[repr(packed, C)]
index b4e91249832051d7d6fa7482669c6f5bfbb186e7..a6d611d2e93c4b83847a9791a39a28bb1a270e14 100644 (file)
@@ -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 {
index 970f6ba01773557ebc8d94203fba55f4160b52f8..3ec4d4e8cc8f68350eba397be435676d2c89fc91 100644 (file)
@@ -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<R>(
         &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(<expr>)`
@@ -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 = <expr>;
         let expr = P(self.lower_expr(expr));
-        let pinned_ident = self.str_to_ident("pinned");
+        let pinned_ident = Ident::with_empty_ctxt(sym::pinned);
         let (pinned_pat, pinned_pat_hid) = self.pat_ident_binding_mode(
             span,
             pinned_ident,
@@ -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(
index 3ca79cb850128fe3b3dd9bd67f5187195ce6d696..57304c5ed37aec722b0f860cab48ff126235fb2f 100644 (file)
@@ -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);
             }
         }
index 4b6e7da333081891add336eb6ac22a3fd79f80b0..e4505a240379f0047bbde6f12e9f1e85c2f7612d 100644 (file)
@@ -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;
                 }
index 3ed28a1f9882562f495db732b2052a5dc41f46b9..feade7a8f56f26d1c8b7e4b73e8bca45f4d8af60 100644 (file)
@@ -43,7 +43,7 @@ pub(super) fn find_arg_with_region(
     ) -> Option<AnonymousArgInfo<'_>> {
         let (id, bound_region) = match *anon_region {
             ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region),
-            ty::ReEarlyBound(ref ebr) => (
+            ty::ReEarlyBound(ebr) => (
                 self.tcx().parent(ebr.def_id).unwrap(),
                 ty::BoundRegion::BrNamed(ebr.def_id, ebr.name),
             ),
index e713cf8d805531669f4d6a4759d046986e0240f2..7e1e751e856478197de92a2e69dc2e2b86ebcea3 100644 (file)
@@ -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!("<impl {} for {}>", trait_ref, self_ty)).as_str()
+                        LocalInternedString::intern(&format!("<impl {} for {}>", trait_ref,
+                                                    self_ty))
                     },
-                    None => Symbol::intern(&format!("<impl {}>", self_ty)).as_str(),
+                    None => LocalInternedString::intern(&format!("<impl {}>", self_ty)),
                 });
 
                 Ok(path)
index 68b65f9b4a1ccfa9c948d76a4f1b8310e209f9a3..9c4683e094634eea384d348ff8c2b9785a6c6dfe 100644 (file)
@@ -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);
 
index e82e90ede8c103daf1c91cca1a5daa669612b3bc..a26468b0fb6ce0560bc1a1cb46c404dddd0a1872 100644 (file)
@@ -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<I, C, S>(&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<I, C, S>(&mut self,
             write!(cgu_name, ".{}", special_suffix).unwrap();
         }
 
-        Symbol::intern(&cgu_name[..]).as_interned_str()
+        InternedString::intern(&cgu_name[..])
     }
 }
index 1c8ea5c7b9c5b0dd437301f536a24c15e19472f9..55216f644a180626fdf1eb15369ce64999fe8c1a 100644 (file)
@@ -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]`
index 400a0f526c4ef887e3bdf7c8c7ade4816b4fa13d..404fadbc78afce2119335eff2afcfde7e9876c04 100644 (file)
@@ -312,17 +312,15 @@ fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> 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)));
                     }
 
                     _ => (),
index 1e4bb37c44ef13cbeedc9aec2f9cc19c3e12973d..91e996178e7d54904cbdde900e8524bf60d1f5da 100644 (file)
@@ -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)
         }
     }
 
index 8e98d4d85b9cc04d437fc2d24d014575ae819de4..91b708d7dbe10339d00813f79f85cfd108a4f57b 100644 (file)
@@ -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<T>(
     {
         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
index a4b8d365a12ef3b01c2e449973147a0bf9474d2b..2fb318a47befd80f6919cd0b22c9eb56bbe3f8f4 100644 (file)
@@ -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("<error>").as_interned_str() }
+        ty::SymbolName { name: InternedString::intern("<error>") }
     }
 }
 
index 269064af93bc078beae1ab0f30124a0d24ce8591..e8f3bad4d3ee32832666fd66f72f4cc502707da8 100644 (file)
@@ -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
     }
 }
 
index cb59cf41a3ca531a8adeecac42debee4d6279ed1..66ba95810a62516a109462f740955fed5c54afb8 100644 (file)
@@ -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_"
index ceb08f943678b15a97aa5273effc4741dd962229..9ae0e26196d94fb142ef516b6a2942fca28c5cb9 100644 (file)
@@ -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" => {
index 6320d8a671ddbfd66f87de8060b86e9641839956..1c793996c83db65cc1cc2960546f358197812253 100644 (file)
@@ -248,6 +248,7 @@ pub struct CodegenContext<B: WriteBackendMethods> {
     pub tm_factory: TargetMachineFactory<B>,
     pub msvc_imps_needed: bool,
     pub target_pointer_width: String,
+    pub target_arch: String,
     pub debuginfo: config::DebugInfo,
 
     // Number of cgus excluding the allocator/metadata modules
@@ -1103,6 +1104,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
         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,
     };
index 96b8558c1d2c447f2b8149f6d71cf647f5696260..c7dd019fc3eb8abb464c0bcca87e15059a312c76 100644 (file)
@@ -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,
index d50a9a1607b240da1f7c3b2fceb125c3e2148162..6915687ceba930d0bde8a5844293a7e7465ca89e 100644 (file)
 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
index fa573907d4c735a68752bc5c59076b67e3c0c676..2b844aa24d49c92a6d5bdbd165762f5a00908b31 100644 (file)
@@ -15,7 +15,6 @@
 /// extended to 64 bits if needed.
 pub struct StableHasher<W> {
     state: SipHasher128,
-    bytes_hashed: u64,
     width: PhantomData<W>,
 }
 
@@ -33,7 +32,6 @@ impl<W: StableHasherResult> StableHasher<W> {
     pub fn new() -> Self {
         StableHasher {
             state: SipHasher128::new_with_keys(0, 0),
-            bytes_hashed: 0,
             width: PhantomData,
         }
     }
@@ -61,11 +59,6 @@ impl<W> StableHasher<W> {
     pub fn finalize(self) -> (u64, u64) {
         self.state.finish128()
     }
-
-    #[inline]
-    pub fn bytes_hashed(&self) -> u64 {
-        self.bytes_hashed
-    }
 }
 
 impl<W> Hasher for StableHasher<W> {
@@ -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<CTX>` can be hashed in a way that is
 /// stable across multiple compilation sessions.
+///
+/// Note that `HashStable` imposes rather more strict requirements than usual
+/// hash functions:
+///
+/// - Stable hashes are sometimes used as identifiers. Therefore they must
+///   conform to the corresponding `PartialEq` implementations:
+///
+///     - `x == y` implies `hash_stable(x) == hash_stable(y)`, and
+///     - `x != y` implies `hash_stable(x) != hash_stable(y)`.
+///
+///   That second condition is usually not required for hash functions
+///   (e.g. `Hash`). In practice this means that `hash_stable` must feed any
+///   information into the hasher that a `PartialEq` comparision takes into
+///   account. See [#49300](https://github.com/rust-lang/rust/issues/49300)
+///   for an example where violating this invariant has caused trouble in the
+///   past.
+///
+/// - `hash_stable()` must be independent of the current
+///    compilation session. E.g. they must not hash memory addresses or other
+///    things that are "randomly" assigned per compilation session.
+///
+/// - `hash_stable()` must be independent of the host architecture. The
+///   `StableHasher` takes care of endianness and `isize`/`usize` platform
+///   differences.
 pub trait HashStable<CTX> {
     fn hash_stable<W: StableHasherResult>(&self,
                                           hcx: &mut CTX,
index 7f2a1c0b4b1d11d6f28a1fe96c60e1a920a23020..3e00ba3c62004bf435cea8598604e15a7a274b55 100644 (file)
@@ -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(),
index 7d7dd1061a959db19aa1b8571db02167691c78a2..3832c8ee227de1208bab95dd5bf864d93ccc964f 100644 (file)
@@ -321,7 +321,7 @@ pub fn maybe_load_library_crate(&mut self) -> Option<Library> {
         }
     }
 
-    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()));
index 4ced31593b1ae6cc0264bcdb6bb160eb4c51eb99..4d8acd241acd893f17910c81d87d8b09d8b979b6 100644 (file)
@@ -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))
     }
 }
index db827afdb94f4481096d600aa8db0cd5ec599e9d..d4c1e5416d565c50232d271ac1ec800c2c899f3b 100644 (file)
@@ -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 <https://github.com/rust-lang/rust/issues/42371>.
         Ok(mem::replace(&mut self.frame_mut().locals[local].value, local_val))
     }
 
index 999e7402afd93a57f64787feee4416534a6a2d33..6b40245d39a8eae5fb7c094cb85f3d8bd0d122d0 100644 (file)
@@ -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))
                 }
             }
         }
index fab07a2290eb5a31efc5bebf8a33aede8a6c7269..394d1f06029cb6459f2e579b50d770d9dddbd32a 100644 (file)
@@ -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,
                                 }], &[]);
                             }
index 4e214c3c7253ee71d8455d5e0cf5d6367a895041..8f3dd72c4f2450a82ca151b53d8ebbe9128b72d6 100644 (file)
@@ -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 { .. } => { }
         }
     }
 }
index 40c60caffa42d8eb7dd81d67af010c49b924e428..c6191e6b579ce45c036876db9c47656585997c97 100644 (file)
@@ -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)
     };
 
index 6527e8655b5ef21bb6d93a7b65f5fed7c8c098fa..711d79f95f53a658d42a1fff866a78c9a78ff4e5 100644 (file)
@@ -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("<upvar>").as_interned_str(),
+                    name: InternedString::intern("<upvar>"),
                     def_id,
                     pure_wrt_drop: false,
                     kind: ty::GenericParamDefKind::Type {
index f91cb469e462992755890455c1501e86d64a266c..e434623d4a12759fe3f1bb82cef4fa0cd11fca18 100644 (file)
@@ -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<Span> 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,
         }
     }
 }
index 4fae7e080b14aef046cf68e4c73af475a0bc436a..6b490f730afa0c951cab05c7dd5fcb79841321a7 100644 (file)
@@ -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<Options, i32> {
             }
         }
 
+        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<Options, i32> {
                 &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) => {
index 0378b12662da26fa5fd6ee525f7ae5d8b244d18a..d604ba11d41860fd39f0b70d56dd6051a9bb9424 100644 (file)
@@ -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<ExternalHtml> {
         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 {
index acf019fd2254dfd52bf7804a66a708bfec525845..ae0bd1aafa8f159393fce8482bc54eb47e314e27 100644 (file)
@@ -182,14 +182,14 @@ pub fn render<T: fmt::Display, S: fmt::Display>(
         let p = SlashChecker(&p);
         if layout.logo.is_empty() {
             format!("<a href='{path}index.html'>\
-                     <img src='{static_root_path}rust-logo{suffix}.png' \
-                          alt='logo' width='100'></a>",
+                     <div class='logo-container'>\
+                     <img src='{static_root_path}rust-logo{suffix}.png' alt='logo'></div></a>",
                     path=p,
                     static_root_path=static_root_path,
                     suffix=page.resource_suffix)
         } else {
             format!("<a href='{}index.html'>\
-                     <img src='{}' alt='logo' width='100'></a>",
+                     <div class='logo-container'><img src='{}' alt='logo'></div></a>",
                     p,
                     layout.logo)
         }
index a3b041c6954c58b7c93eb524971652b1d7781952..12d10254c4d09ecf7574ca63ed0d75643dd7c393 100644 (file)
@@ -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<char> {
 struct CodeBlocks<'a, I: Iterator<Item = Event<'a>>> {
     inner: I,
     check_error_codes: ErrorCodes,
+    edition: Edition,
 }
 
 impl<'a, I: Iterator<Item = Event<'a>>> CodeBlocks<'a, I> {
-    fn new(iter: I, error_codes: ErrorCodes) -> Self {
+    fn new(iter: I, error_codes: ErrorCodes, edition: Edition) -> Self {
         CodeBlocks {
             inner: iter,
             check_error_codes: error_codes,
+            edition,
         }
     }
 }
@@ -177,6 +190,9 @@ fn next(&mut self) -> Option<Self::Item> {
             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<Self::Item> {
                     .collect::<Vec<Cow<'_, str>>>().join("\n");
                 let krate = krate.as_ref().map(|s| &**s);
                 let (test, _) = test::make_test(&test, krate, false,
-                                           &Default::default());
+                                           &Default::default(), edition);
                 let channel = if test.contains("#![feature(") {
                     "&amp;version=nightly"
                 } else {
                     ""
                 };
 
-                let edition_string = if let Some(e @ Edition::Edition2018) = edition {
-                    format!("&amp;edition={}{}", e,
-                            if channel == "&amp;version=nightly" { "" }
-                            else { "&amp;version=nightly" })
-                } else if let Some(e) = edition {
-                    format!("&amp;edition={}", e)
-                } else {
-                    "".to_owned()
-                };
+                let edition_string = format!("&amp;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<String> {
     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);
         }
 
index 36ce89558db7b81edc6eb0fd10c099ef5096ba81..b628bd450d314b8a690dea5e0beae786db59a0ef 100644 (file)
@@ -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<RefCell<IdMap>>,
     pub shared: Arc<SharedContext>,
@@ -514,7 +517,8 @@ pub fn run(mut krate: clean::Crate,
            options: RenderOptions,
            passes: FxHashSet<String>,
            renderinfo: RenderInfo,
-           diag: &errors::Handler) -> Result<(), Error> {
+           diag: &errors::Handler,
+           edition: Edition) -> Result<(), Error> {
     // need to save a copy of the options for rendering the index page
     let md_opts = options.clone();
     let RenderOptions {
@@ -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<String> {
 
         if let Some(note) = note {
             let mut ids = cx.id_map.borrow_mut();
-            let html = MarkdownHtml(&note, RefCell::new(&mut ids), error_codes);
+            let html = MarkdownHtml(&note, RefCell::new(&mut ids), error_codes, cx.edition);
             message.push_str(&format!(": {}", html));
         }
         stability.push(format!("<div class='stab deprecated'>{}</div>", message));
@@ -2967,7 +2972,7 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> {
             message = format!(
                 "<details><summary>{}</summary>{}</details>",
                 message,
-                MarkdownHtml(&unstable_reason, RefCell::new(&mut ids), error_codes)
+                MarkdownHtml(&unstable_reason, RefCell::new(&mut ids), error_codes, cx.edition)
             );
         }
 
@@ -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, "<div class='docblock'>{}</div>",
-                   Markdown(&*dox, &i.impl_item.links(), RefCell::new(&mut ids), cx.codes))?;
+                   Markdown(&*dox, &i.impl_item.links(), RefCell::new(&mut ids),
+                            cx.codes, cx.edition))?;
         }
     }
 
index 522b6d60a18d82facc2d3a32d394fde68eb2dd01..0493bf7c5c0f51c9045f89337db911f0c1a2d0a6 100644 (file)
@@ -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;
index f1255f52247376bd1e7f8285dd10bb695e33b592..e44ae2ad10cee286cba893f9ac63cffd2f96e6de 100644 (file)
@@ -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 {
index c052e6b37ade7a51e9ac9bfad44763811af9e74b..4c37000dde2c5e4f6840309b237eae17d85e0461 100644 (file)
@@ -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 {
index 5b76f6861de79b084739f850186c562626032695..f5061b671828e04e704509fa535b531ba6cc941d 100644 (file)
@@ -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) => {
index c496dde8426c0fd8ba84bf64b8b43e0e5954fbe6..b0a37ea9c8081f50025fad2cfa5d50f5b0e80e1d 100644 (file)
@@ -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!(
index 9e108e605c8bba9fc42a9f57cb2a22a519fe911d..2c382a1c1759632806bb316f621aa582564b9fe0 100644 (file)
@@ -321,7 +321,7 @@ fn fold_item(&mut self, mut item: Item) -> Option<Item> {
                         if let Ok(res) = self.resolve(path_str, ns, &current_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<Item> {
                         if let Ok(res) = self.resolve(path_str, ns, &current_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<Item> {
                         };
 
                         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<Item> {
                         } 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<Item> {
                         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<Res> {
 /// line containing the failure as a note as well.
 fn resolution_failure(
     cx: &DocContext<'_>,
-    attrs: &Attributes,
+    item: &Item,
     path_str: &str,
     dox: &str,
     link_range: Option<Range<usize>>,
 ) {
+    let hir_id = match cx.as_local_hir_id(item.def_id) {
+        Some(hir_id) => hir_id,
+        None => {
+            // If non-local, no need to check anything.
+            return;
+        }
+    };
+    let attrs = &item.attrs;
     let sp = span_of_attrs(attrs);
 
     let mut diag = cx.tcx.struct_span_lint_hir(
         lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE,
-        hir::CRATE_HIR_ID,
+        hir_id,
         sp,
         &format!("`[{}]` cannot be resolved, ignoring it...", path_str),
     );
@@ -495,12 +503,20 @@ fn resolution_failure(
 
 fn ambiguity_error(
     cx: &DocContext<'_>,
-    attrs: &Attributes,
+    item: &Item,
     path_str: &str,
     dox: &str,
     link_range: Option<Range<usize>>,
     candidates: PerNS<Option<Res>>,
 ) {
+    let hir_id = match cx.as_local_hir_id(item.def_id) {
+        Some(hir_id) => hir_id,
+        None => {
+            // If non-local, no need to check anything.
+            return;
+        }
+    };
+    let attrs = &item.attrs;
     let sp = span_of_attrs(attrs);
 
     let mut msg = format!("`{}` is ", path_str);
@@ -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,
     );
index 99aca0634710fdc88ac688cf1ffb45bac9ce7cba..d9af33ac5b622a39f288c14b3eca760c02900245 100644 (file)
@@ -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();
index e40dbe52ffe6423ecb9e259e7bfcd8b931a98088..0cc99da64079c006efb0df5493b1c210ac6cecf0 100644 (file)
@@ -167,7 +167,7 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize,
             maybe_sysroot: Option<PathBuf>, linker: Option<PathBuf>, edition: Edition,
             persist_doctests: Option<PathBuf>) {
     let (test, line_offset) = match panic::catch_unwind(|| {
-        make_test(test, Some(cratename), as_test_harness, opts)
+        make_test(test, Some(cratename), as_test_harness, opts, edition)
     }) {
         Ok((test, line_offset)) => (test, line_offset),
         Err(cause) if cause.is::<errors::FatalErrorMarker>() => {
@@ -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));
     }
 }
index 4241f47b661d721b742a0b9bc8124592d7efeb8e..ff52974775b05268e1a4b3b49a704340a6f24d50 100644 (file)
@@ -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);
index 478f63ab3d7f7bbb8e08ffb2e0b7550cd6bd6995..5a2fe2b244f556d16127daf3244da70fed785ecc 100644 (file)
@@ -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()
index 62282006a40248df320c8eedc5c99c37b5b4683c..aeb822fa99e66a6fd1920de1c16aea4203ff4677 100644 (file)
@@ -218,6 +218,8 @@ mod private {
 impl<'a, E: Error + 'a> From<E> for Box<dyn Error + 'a> {
     /// Converts a type of [`Error`] into a box of dyn [`Error`].
     ///
+    /// [`Error`]: ../error/trait.Error.html
+    ///
     /// # Examples
     ///
     /// ```
@@ -255,6 +257,8 @@ impl<'a, E: Error + Send + Sync + 'a> From<E> for Box<dyn Error + Send + Sync +
     /// Converts a type of [`Error`] + [`Send`] + [`Sync`] into a box of dyn [`Error`] +
     /// [`Send`] + [`Sync`].
     ///
+    /// [`Error`]: ../error/trait.Error.html
+    ///
     /// # Examples
     ///
     /// ```
@@ -296,6 +300,8 @@ fn from(err: E) -> Box<dyn Error + Send + Sync + 'a> {
 impl From<String> for Box<dyn Error + Send + Sync> {
     /// Converts a [`String`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
     ///
+    /// [`Error`]: ../error/trait.Error.html
+    ///
     /// # Examples
     ///
     /// ```
@@ -329,6 +335,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 impl From<String> for Box<dyn Error> {
     /// 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<dyn Error> {
 impl<'a> From<&str> for Box<dyn Error + Send + Sync + 'a> {
     /// Converts a [`str`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
     ///
+    /// [`Error`]: ../error/trait.Error.html
+    ///
     /// # Examples
     ///
     /// ```
@@ -370,6 +380,8 @@ fn from(err: &str) -> Box<dyn Error + Send + Sync + 'a> {
 impl From<&str> for Box<dyn Error> {
     /// Converts a [`str`] into a box of dyn [`Error`].
     ///
+    /// [`Error`]: ../error/trait.Error.html
+    ///
     /// # Examples
     ///
     /// ```
@@ -389,6 +401,9 @@ fn from(err: &str) -> Box<dyn Error> {
 impl<'a, 'b> From<Cow<'b, str>> for Box<dyn Error + Send + Sync + 'a> {
     /// Converts a [`Cow`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
     ///
+    /// [`Cow`]: ../borrow/enum.Cow.html
+    /// [`Error`]: ../error/trait.Error.html
+    ///
     /// # Examples
     ///
     /// ```
@@ -410,6 +425,9 @@ fn from(err: Cow<'b, str>) -> Box<dyn Error + Send + Sync + 'a> {
 impl<'a> From<Cow<'a, str>> for Box<dyn Error> {
     /// Converts a [`Cow`] into a box of dyn [`Error`].
     ///
+    /// [`Cow`]: ../borrow/enum.Cow.html
+    /// [`Error`]: ../error/trait.Error.html
+    ///
     /// # Examples
     ///
     /// ```
index 13aee783750f1dfbb8a9cc81fcddcce61890baa0..c7c5849a00fa03e7ded2fe25de405f195575d0f2 100644 (file)
@@ -351,6 +351,8 @@ impl From<String> 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) }
     }
index 991b45fd4a2ec2caf03b10b4d49237967226c7f2..616b5eb836ffd6c8c20163cd752790ade30ef170 100644 (file)
@@ -1812,6 +1812,8 @@ pub fn canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
 ///   function.)
 /// * `path` already exists.
 ///
+/// [`create_dir_all`]: fn.create_dir_all.html
+///
 /// # Examples
 ///
 /// ```no_run
index 5be2687d8f5ff3bb14af96ab9c413ec7d46d123e..e309f81192cf3ffb7322bd4540da7beb5c384461 100644 (file)
@@ -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
index 2401946536ffa0f9af76ad43871d03ac4eb0aa12..e044b46e0d0763252baf5254a69fe57f88d1e5b8 100644 (file)
 #![feature(libc)]
 #![feature(link_args)]
 #![feature(linkage)]
-#![feature(maybe_uninit)]
 #![feature(needs_panic_runtime)]
 #![feature(never_type)]
 #![feature(nll)]
index 03aebeda47c4851f707c2d2ffb39682e166c4dcf..9af7bba97aa58de06daab2106874f17909a16cd6 100644 (file)
@@ -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) => ({
index e7923e381f1407205c647012acf15c81aab40644..ca86a175058b512dd2259349393a2c200565f920 100644 (file)
@@ -546,6 +546,9 @@ fn from_inner(addr: c::sockaddr_in6) -> SocketAddrV6 {
 #[stable(feature = "ip_from_ip", since = "1.16.0")]
 impl From<SocketAddrV4> for SocketAddr {
     /// Converts a [`SocketAddrV4`] into a [`SocketAddr::V4`].
+    ///
+    /// [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html
+    /// [`SocketAddr::V4`]: ../../std/net/enum.SocketAddr.html#variant.V4
     fn from(sock4: SocketAddrV4) -> SocketAddr {
         SocketAddr::V4(sock4)
     }
@@ -554,6 +557,9 @@ fn from(sock4: SocketAddrV4) -> SocketAddr {
 #[stable(feature = "ip_from_ip", since = "1.16.0")]
 impl From<SocketAddrV6> for SocketAddr {
     /// Converts a [`SocketAddrV6`] into a [`SocketAddr::V6`].
+    ///
+    /// [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html
+    /// [`SocketAddr::V6`]: ../../std/net/enum.SocketAddr.html#variant.V6
     fn from(sock6: SocketAddrV6) -> SocketAddr {
         SocketAddr::V6(sock6)
     }
@@ -567,6 +573,13 @@ impl<I: Into<IpAddr>> 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)
     }
index 04353fde1b4d97620d17ad07702446d130dc5073..69ecd201063b034baf0f8d5df0074823a89ecda6 100644 (file)
 //! ```
 
 #![stable(feature = "rust1", since = "1.0.0")]
-#![allow(deprecated)] // for mpsc_select
 
 // A description of how Rust's channel implementation works
 //
 // believe that there is anything fundamental that needs to change about these
 // channels, however, in order to support a more efficient select().
 //
+// FIXME: Select is now removed, so these factors are ready to be cleaned up!
+//
 // # Conclusion
 //
 // And now that you've seen all the races that I found and attempted to fix,
 use crate::cell::UnsafeCell;
 use crate::time::{Duration, Instant};
 
-#[unstable(feature = "mpsc_select", issue = "27800")]
-pub use self::select::{Select, Handle};
-use self::select::StartResult;
-use self::select::StartResult::*;
-use self::blocking::SignalToken;
-
-#[cfg(all(test, not(target_os = "emscripten")))]
-mod select_tests;
-
 mod blocking;
 mod oneshot;
-mod select;
 mod shared;
 mod stream;
 mod sync;
@@ -1514,78 +1505,6 @@ pub fn try_iter(&self) -> TryIter<'_, T> {
 
 }
 
-impl<T> select::Packet for Receiver<T> {
-    fn can_recv(&self) -> bool {
-        loop {
-            let new_port = match *unsafe { self.inner() } {
-                Flavor::Oneshot(ref p) => {
-                    match p.can_recv() {
-                        Ok(ret) => return ret,
-                        Err(upgrade) => upgrade,
-                    }
-                }
-                Flavor::Stream(ref p) => {
-                    match p.can_recv() {
-                        Ok(ret) => return ret,
-                        Err(upgrade) => upgrade,
-                    }
-                }
-                Flavor::Shared(ref p) => return p.can_recv(),
-                Flavor::Sync(ref p) => return p.can_recv(),
-            };
-            unsafe {
-                mem::swap(self.inner_mut(),
-                          new_port.inner_mut());
-            }
-        }
-    }
-
-    fn start_selection(&self, mut token: SignalToken) -> StartResult {
-        loop {
-            let (t, new_port) = match *unsafe { self.inner() } {
-                Flavor::Oneshot(ref p) => {
-                    match p.start_selection(token) {
-                        oneshot::SelSuccess => return Installed,
-                        oneshot::SelCanceled => return Abort,
-                        oneshot::SelUpgraded(t, rx) => (t, rx),
-                    }
-                }
-                Flavor::Stream(ref p) => {
-                    match p.start_selection(token) {
-                        stream::SelSuccess => return Installed,
-                        stream::SelCanceled => return Abort,
-                        stream::SelUpgraded(t, rx) => (t, rx),
-                    }
-                }
-                Flavor::Shared(ref p) => return p.start_selection(token),
-                Flavor::Sync(ref p) => return p.start_selection(token),
-            };
-            token = t;
-            unsafe {
-                mem::swap(self.inner_mut(), new_port.inner_mut());
-            }
-        }
-    }
-
-    fn abort_selection(&self) -> bool {
-        let mut was_upgrade = false;
-        loop {
-            let result = match *unsafe { self.inner() } {
-                Flavor::Oneshot(ref p) => p.abort_selection(),
-                Flavor::Stream(ref p) => p.abort_selection(was_upgrade),
-                Flavor::Shared(ref p) => return p.abort_selection(was_upgrade),
-                Flavor::Sync(ref p) => return p.abort_selection(),
-            };
-            let new_port = match result { Ok(b) => return b, Err(p) => p };
-            was_upgrade = true;
-            unsafe {
-                mem::swap(self.inner_mut(),
-                          new_port.inner_mut());
-            }
-        }
-    }
-}
-
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T> Iterator for Iter<'a, T> {
     type Item = T;
index 5c516d5de0f176ed735d8e2cc7a6de488d5e83c2..e7a5cc46b31a857912e23bc880fac2c97d4580e2 100644 (file)
@@ -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<T> {
-    SelCanceled,
-    SelUpgraded(SignalToken, Receiver<T>),
-    SelSuccess,
-}
-
 enum MyUpgrade<T> {
     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<bool, Receiver<T>> {
-        unsafe {
-            match self.state.load(Ordering::SeqCst) {
-                EMPTY => Ok(false), // Welp, we tried
-                DATA => Ok(true),   // we have some un-acquired data
-                DISCONNECTED if (*self.data.get()).is_some() => Ok(true), // we have data
-                DISCONNECTED => {
-                    match ptr::replace(self.upgrade.get(), SendUsed) {
-                        // The other end sent us an upgrade, so we need to
-                        // propagate upwards whether the upgrade can receive
-                        // data
-                        GoUp(upgrade) => Err(upgrade),
-
-                        // If the other end disconnected without sending an
-                        // upgrade, then we have data to receive (the channel is
-                        // disconnected).
-                        up => { ptr::write(self.upgrade.get(), up); Ok(true) }
-                    }
-                }
-                _ => unreachable!(), // we're the "one blocker"
-            }
-        }
-    }
-
-    // Attempts to start selection on this port. This can either succeed, fail
-    // because there is data, or fail because there is an upgrade pending.
-    pub fn start_selection(&self, token: SignalToken) -> SelectionResult<T> {
-        unsafe {
-            let ptr = token.cast_to_usize();
-            match self.state.compare_and_swap(EMPTY, ptr, Ordering::SeqCst) {
-                EMPTY => SelSuccess,
-                DATA => {
-                    drop(SignalToken::cast_from_usize(ptr));
-                    SelCanceled
-                }
-                DISCONNECTED if (*self.data.get()).is_some() => {
-                    drop(SignalToken::cast_from_usize(ptr));
-                    SelCanceled
-                }
-                DISCONNECTED => {
-                    match ptr::replace(self.upgrade.get(), SendUsed) {
-                        // The other end sent us an upgrade, so we need to
-                        // propagate upwards whether the upgrade can receive
-                        // data
-                        GoUp(upgrade) => {
-                            SelUpgraded(SignalToken::cast_from_usize(ptr), upgrade)
-                        }
-
-                        // If the other end disconnected without sending an
-                        // upgrade, then we have data to receive (the channel is
-                        // disconnected).
-                        up => {
-                            ptr::write(self.upgrade.get(), up);
-                            drop(SignalToken::cast_from_usize(ptr));
-                            SelCanceled
-                        }
-                    }
-                }
-                _ => unreachable!(), // we're the "one blocker"
-            }
-        }
-    }
-
     // Remove a previous selecting thread from this port. This ensures that the
     // blocked thread will no longer be visible to any other threads.
     //
diff --git a/src/libstd/sync/mpsc/select.rs b/src/libstd/sync/mpsc/select.rs
deleted file mode 100644 (file)
index d1b5f2d..0000000
+++ /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<SelectInner>,
-    next_id: Cell<usize>,
-}
-
-struct SelectInner {
-    head: *mut Handle<'static, ()>,
-    tail: *mut Handle<'static, ()>,
-}
-
-impl !marker::Send for Select {}
-
-/// A handle to a receiver which is currently a member of a `Select` set of
-/// receivers. This handle is used to keep the receiver in the set as well as
-/// interact with the underlying receiver.
-pub struct Handle<'rx, T:Send+'rx> {
-    /// The ID of this handle, used to compare against the return value of
-    /// `Select::wait()`.
-    id: usize,
-    selector: *mut SelectInner,
-    next: *mut Handle<'static, ()>,
-    prev: *mut Handle<'static, ()>,
-    added: bool,
-    packet: &'rx (dyn Packet+'rx),
-
-    // due to our fun transmutes, we be sure to place this at the end. (nothing
-    // previous relies on T)
-    rx: &'rx Receiver<T>,
-}
-
-struct Packets { cur: *mut Handle<'static, ()> }
-
-#[doc(hidden)]
-#[derive(PartialEq, Eq)]
-pub enum StartResult {
-    Installed,
-    Abort,
-}
-
-#[doc(hidden)]
-pub trait Packet {
-    fn can_recv(&self) -> bool;
-    fn start_selection(&self, token: SignalToken) -> StartResult;
-    fn abort_selection(&self) -> bool;
-}
-
-impl Select {
-    /// Creates a new selection structure. This set is initially empty.
-    ///
-    /// Usage of this struct directly can sometimes be burdensome, and usage is much easier through
-    /// the `select!` macro.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(mpsc_select)]
-    ///
-    /// use std::sync::mpsc::Select;
-    ///
-    /// let select = Select::new();
-    /// ```
-    pub fn new() -> Select {
-        Select {
-            inner: UnsafeCell::new(SelectInner {
-                head: ptr::null_mut(),
-                tail: ptr::null_mut(),
-            }),
-            next_id: Cell::new(1),
-        }
-    }
-
-    /// Creates a new handle into this receiver set for a new receiver. Note
-    /// that this does *not* add the receiver to the receiver set, for that you
-    /// must call the `add` method on the handle itself.
-    pub fn handle<'a, T: Send>(&'a self, rx: &'a Receiver<T>) -> Handle<'a, T> {
-        let id = self.next_id.get();
-        self.next_id.set(id + 1);
-        Handle {
-            id,
-            selector: self.inner.get(),
-            next: ptr::null_mut(),
-            prev: ptr::null_mut(),
-            added: false,
-            rx,
-            packet: rx,
-        }
-    }
-
-    /// Waits for an event on this receiver set. The returned value is *not* an
-    /// index, but rather an ID. This ID can be queried against any active
-    /// `Handle` structures (each one has an `id` method). The handle with
-    /// the matching `id` will have some sort of event available on it. The
-    /// event could either be that data is available or the corresponding
-    /// channel has been closed.
-    pub fn wait(&self) -> usize {
-        self.wait2(true)
-    }
-
-    /// Helper method for skipping the preflight checks during testing
-    pub(super) fn wait2(&self, do_preflight_checks: bool) -> usize {
-        // Note that this is currently an inefficient implementation. We in
-        // theory have knowledge about all receivers in the set ahead of time,
-        // so this method shouldn't really have to iterate over all of them yet
-        // again. The idea with this "receiver set" interface is to get the
-        // interface right this time around, and later this implementation can
-        // be optimized.
-        //
-        // This implementation can be summarized by:
-        //
-        //      fn select(receivers) {
-        //          if any receiver ready { return ready index }
-        //          deschedule {
-        //              block on all receivers
-        //          }
-        //          unblock on all receivers
-        //          return ready index
-        //      }
-        //
-        // Most notably, the iterations over all of the receivers shouldn't be
-        // necessary.
-        unsafe {
-            // Stage 1: preflight checks. Look for any packets ready to receive
-            if do_preflight_checks {
-                for handle in self.iter() {
-                    if (*handle).packet.can_recv() {
-                        return (*handle).id();
-                    }
-                }
-            }
-
-            // Stage 2: begin the blocking process
-            //
-            // Create a number of signal tokens, and install each one
-            // sequentially until one fails. If one fails, then abort the
-            // selection on the already-installed tokens.
-            let (wait_token, signal_token) = blocking::tokens();
-            for (i, handle) in self.iter().enumerate() {
-                match (*handle).packet.start_selection(signal_token.clone()) {
-                    StartResult::Installed => {}
-                    StartResult::Abort => {
-                        // Go back and abort the already-begun selections
-                        for handle in self.iter().take(i) {
-                            (*handle).packet.abort_selection();
-                        }
-                        return (*handle).id;
-                    }
-                }
-            }
-
-            // Stage 3: no messages available, actually block
-            wait_token.wait();
-
-            // Stage 4: there *must* be message available; find it.
-            //
-            // Abort the selection process on each receiver. If the abort
-            // process returns `true`, then that means that the receiver is
-            // ready to receive some data. Note that this also means that the
-            // receiver may have yet to have fully read the `to_wake` field and
-            // woken us up (although the wakeup is guaranteed to fail).
-            //
-            // This situation happens in the window of where a sender invokes
-            // increment(), sees -1, and then decides to wake up the thread. After
-            // all this is done, the sending thread will set `selecting` to
-            // `false`. Until this is done, we cannot return. If we were to
-            // return, then a sender could wake up a receiver which has gone
-            // back to sleep after this call to `select`.
-            //
-            // Note that it is a "fairly small window" in which an increment()
-            // views that it should wake a thread up until the `selecting` bit
-            // is set to false. For now, the implementation currently just spins
-            // in a yield loop. This is very distasteful, but this
-            // implementation is already nowhere near what it should ideally be.
-            // A rewrite should focus on avoiding a yield loop, and for now this
-            // implementation is tying us over to a more efficient "don't
-            // iterate over everything every time" implementation.
-            let mut ready_id = usize::MAX;
-            for handle in self.iter() {
-                if (*handle).packet.abort_selection() {
-                    ready_id = (*handle).id;
-                }
-            }
-
-            // We must have found a ready receiver
-            assert!(ready_id != usize::MAX);
-            return ready_id;
-        }
-    }
-
-    fn iter(&self) -> Packets { Packets { cur: unsafe { &*self.inner.get() }.head } }
-}
-
-impl<'rx, T: Send> Handle<'rx, T> {
-    /// Retrieves the ID of this handle.
-    #[inline]
-    pub fn id(&self) -> usize { self.id }
-
-    /// Blocks to receive a value on the underlying receiver, returning `Some` on
-    /// success or `None` if the channel disconnects. This function has the same
-    /// semantics as `Receiver.recv`
-    pub fn recv(&mut self) -> Result<T, RecvError> { self.rx.recv() }
-
-    /// Adds this handle to the receiver set that the handle was created from. This
-    /// method can be called multiple times, but it has no effect if `add` was
-    /// called previously.
-    ///
-    /// This method is unsafe because it requires that the `Handle` is not moved
-    /// while it is added to the `Select` set.
-    pub unsafe fn add(&mut self) {
-        if self.added { return }
-        let selector = &mut *self.selector;
-        let me = self as *mut Handle<'rx, T> as *mut Handle<'static, ()>;
-
-        if selector.head.is_null() {
-            selector.head = me;
-            selector.tail = me;
-        } else {
-            (*me).prev = selector.tail;
-            assert!((*me).next.is_null());
-            (*selector.tail).next = me;
-            selector.tail = me;
-        }
-        self.added = true;
-    }
-
-    /// Removes this handle from the `Select` set. This method is unsafe because
-    /// it has no guarantee that the `Handle` was not moved since `add` was
-    /// called.
-    pub unsafe fn remove(&mut self) {
-        if !self.added { return }
-
-        let selector = &mut *self.selector;
-        let me = self as *mut Handle<'rx, T> as *mut Handle<'static, ()>;
-
-        if self.prev.is_null() {
-            assert_eq!(selector.head, me);
-            selector.head = self.next;
-        } else {
-            (*self.prev).next = self.next;
-        }
-        if self.next.is_null() {
-            assert_eq!(selector.tail, me);
-            selector.tail = self.prev;
-        } else {
-            (*self.next).prev = self.prev;
-        }
-
-        self.next = ptr::null_mut();
-        self.prev = ptr::null_mut();
-
-        self.added = false;
-    }
-}
-
-impl Drop for Select {
-    fn drop(&mut self) {
-        unsafe {
-            assert!((&*self.inner.get()).head.is_null());
-            assert!((&*self.inner.get()).tail.is_null());
-        }
-    }
-}
-
-impl<T: Send> Drop for Handle<'_, T> {
-    fn drop(&mut self) {
-        unsafe { self.remove() }
-    }
-}
-
-impl Iterator for Packets {
-    type Item = *mut Handle<'static, ()>;
-
-    fn next(&mut self) -> Option<*mut Handle<'static, ()>> {
-        if self.cur.is_null() {
-            None
-        } else {
-            let ret = Some(self.cur);
-            unsafe { self.cur = (*self.cur).next; }
-            ret
-        }
-    }
-}
-
-impl fmt::Debug for Select {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("Select").finish()
-    }
-}
-
-impl<T: Send> fmt::Debug for Handle<'_, T> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("Handle").finish()
-    }
-}
diff --git a/src/libstd/sync/mpsc/select_tests.rs b/src/libstd/sync/mpsc/select_tests.rs
deleted file mode 100644 (file)
index 18d9346..0000000
+++ /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::<i32>();
-    let (tx2, rx2) = channel::<i32>();
-    tx1.send(1).unwrap();
-    select! {
-        foo = rx1.recv() => { assert_eq!(foo.unwrap(), 1); },
-        _bar = rx2.recv() => { panic!() }
-    }
-    tx2.send(2).unwrap();
-    select! {
-        _foo = rx1.recv() => { panic!() },
-        bar = rx2.recv() => { assert_eq!(bar.unwrap(), 2) }
-    }
-    drop(tx1);
-    select! {
-        foo = rx1.recv() => { assert!(foo.is_err()); },
-        _bar = rx2.recv() => { panic!() }
-    }
-    drop(tx2);
-    select! {
-        bar = rx2.recv() => { assert!(bar.is_err()); }
-    }
-}
-
-#[test]
-fn smoke2() {
-    let (_tx1, rx1) = channel::<i32>();
-    let (_tx2, rx2) = channel::<i32>();
-    let (_tx3, rx3) = channel::<i32>();
-    let (_tx4, rx4) = channel::<i32>();
-    let (tx5, rx5) = channel::<i32>();
-    tx5.send(4).unwrap();
-    select! {
-        _foo = rx1.recv() => { panic!("1") },
-        _foo = rx2.recv() => { panic!("2") },
-        _foo = rx3.recv() => { panic!("3") },
-        _foo = rx4.recv() => { panic!("4") },
-        foo = rx5.recv() => { assert_eq!(foo.unwrap(), 4); }
-    }
-}
-
-#[test]
-fn closed() {
-    let (_tx1, rx1) = channel::<i32>();
-    let (tx2, rx2) = channel::<i32>();
-    drop(tx2);
-
-    select! {
-        _a1 = rx1.recv() => { panic!() },
-        a2 = rx2.recv() => { assert!(a2.is_err()); }
-    }
-}
-
-#[test]
-fn unblocks() {
-    let (tx1, rx1) = channel::<i32>();
-    let (_tx2, rx2) = channel::<i32>();
-    let (tx3, rx3) = channel::<i32>();
-
-    let _t = thread::spawn(move|| {
-        for _ in 0..20 { thread::yield_now(); }
-        tx1.send(1).unwrap();
-        rx3.recv().unwrap();
-        for _ in 0..20 { thread::yield_now(); }
-    });
-
-    select! {
-        a = rx1.recv() => { assert_eq!(a.unwrap(), 1); },
-        _b = rx2.recv() => { panic!() }
-    }
-    tx3.send(1).unwrap();
-    select! {
-        a = rx1.recv() => { assert!(a.is_err()) },
-        _b = rx2.recv() => { panic!() }
-    }
-}
-
-#[test]
-fn both_ready() {
-    let (tx1, rx1) = channel::<i32>();
-    let (tx2, rx2) = channel::<i32>();
-    let (tx3, rx3) = channel::<()>();
-
-    let _t = thread::spawn(move|| {
-        for _ in 0..20 { thread::yield_now(); }
-        tx1.send(1).unwrap();
-        tx2.send(2).unwrap();
-        rx3.recv().unwrap();
-    });
-
-    select! {
-        a = rx1.recv() => { assert_eq!(a.unwrap(), 1); },
-        a = rx2.recv() => { assert_eq!(a.unwrap(), 2); }
-    }
-    select! {
-        a = rx1.recv() => { assert_eq!(a.unwrap(), 1); },
-        a = rx2.recv() => { assert_eq!(a.unwrap(), 2); }
-    }
-    assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty));
-    assert_eq!(rx2.try_recv(), Err(TryRecvError::Empty));
-    tx3.send(()).unwrap();
-}
-
-#[test]
-fn stress() {
-    const AMT: i32 = 10000;
-    let (tx1, rx1) = channel::<i32>();
-    let (tx2, rx2) = channel::<i32>();
-    let (tx3, rx3) = channel::<()>();
-
-    let _t = thread::spawn(move|| {
-        for i in 0..AMT {
-            if i % 2 == 0 {
-                tx1.send(i).unwrap();
-            } else {
-                tx2.send(i).unwrap();
-            }
-            rx3.recv().unwrap();
-        }
-    });
-
-    for i in 0..AMT {
-        select! {
-            i1 = rx1.recv() => { assert!(i % 2 == 0 && i == i1.unwrap()); },
-            i2 = rx2.recv() => { assert!(i % 2 == 1 && i == i2.unwrap()); }
-        }
-        tx3.send(()).unwrap();
-    }
-}
-
-#[allow(unused_must_use)]
-#[test]
-fn cloning() {
-    let (tx1, rx1) = channel::<i32>();
-    let (_tx2, rx2) = channel::<i32>();
-    let (tx3, rx3) = channel::<()>();
-
-    let _t = thread::spawn(move|| {
-        rx3.recv().unwrap();
-        tx1.clone();
-        assert_eq!(rx3.try_recv(), Err(TryRecvError::Empty));
-        tx1.send(2).unwrap();
-        rx3.recv().unwrap();
-    });
-
-    tx3.send(()).unwrap();
-    select! {
-        _i1 = rx1.recv() => {},
-        _i2 = rx2.recv() => panic!()
-    }
-    tx3.send(()).unwrap();
-}
-
-#[allow(unused_must_use)]
-#[test]
-fn cloning2() {
-    let (tx1, rx1) = channel::<i32>();
-    let (_tx2, rx2) = channel::<i32>();
-    let (tx3, rx3) = channel::<()>();
-
-    let _t = thread::spawn(move|| {
-        rx3.recv().unwrap();
-        tx1.clone();
-        assert_eq!(rx3.try_recv(), Err(TryRecvError::Empty));
-        tx1.send(2).unwrap();
-        rx3.recv().unwrap();
-    });
-
-    tx3.send(()).unwrap();
-    select! {
-        _i1 = rx1.recv() => {},
-        _i2 = rx2.recv() => panic!()
-    }
-    tx3.send(()).unwrap();
-}
-
-#[test]
-fn cloning3() {
-    let (tx1, rx1) = channel::<()>();
-    let (tx2, rx2) = channel::<()>();
-    let (tx3, rx3) = channel::<()>();
-    let _t = thread::spawn(move|| {
-        let s = Select::new();
-        let mut h1 = s.handle(&rx1);
-        let mut h2 = s.handle(&rx2);
-        unsafe { h2.add(); }
-        unsafe { h1.add(); }
-        assert_eq!(s.wait(), h2.id());
-        tx3.send(()).unwrap();
-    });
-
-    for _ in 0..1000 { thread::yield_now(); }
-    drop(tx1.clone());
-    tx2.send(()).unwrap();
-    rx3.recv().unwrap();
-}
-
-#[test]
-fn preflight1() {
-    let (tx, rx) = channel();
-    tx.send(()).unwrap();
-    select! {
-        _n = rx.recv() => {}
-    }
-}
-
-#[test]
-fn preflight2() {
-    let (tx, rx) = channel();
-    tx.send(()).unwrap();
-    tx.send(()).unwrap();
-    select! {
-        _n = rx.recv() => {}
-    }
-}
-
-#[test]
-fn preflight3() {
-    let (tx, rx) = channel();
-    drop(tx.clone());
-    tx.send(()).unwrap();
-    select! {
-        _n = rx.recv() => {}
-    }
-}
-
-#[test]
-fn preflight4() {
-    let (tx, rx) = channel();
-    tx.send(()).unwrap();
-    let s = Select::new();
-    let mut h = s.handle(&rx);
-    unsafe { h.add(); }
-    assert_eq!(s.wait2(false), h.id());
-}
-
-#[test]
-fn preflight5() {
-    let (tx, rx) = channel();
-    tx.send(()).unwrap();
-    tx.send(()).unwrap();
-    let s = Select::new();
-    let mut h = s.handle(&rx);
-    unsafe { h.add(); }
-    assert_eq!(s.wait2(false), h.id());
-}
-
-#[test]
-fn preflight6() {
-    let (tx, rx) = channel();
-    drop(tx.clone());
-    tx.send(()).unwrap();
-    let s = Select::new();
-    let mut h = s.handle(&rx);
-    unsafe { h.add(); }
-    assert_eq!(s.wait2(false), h.id());
-}
-
-#[test]
-fn preflight7() {
-    let (tx, rx) = channel::<()>();
-    drop(tx);
-    let s = Select::new();
-    let mut h = s.handle(&rx);
-    unsafe { h.add(); }
-    assert_eq!(s.wait2(false), h.id());
-}
-
-#[test]
-fn preflight8() {
-    let (tx, rx) = channel();
-    tx.send(()).unwrap();
-    drop(tx);
-    rx.recv().unwrap();
-    let s = Select::new();
-    let mut h = s.handle(&rx);
-    unsafe { h.add(); }
-    assert_eq!(s.wait2(false), h.id());
-}
-
-#[test]
-fn preflight9() {
-    let (tx, rx) = channel();
-    drop(tx.clone());
-    tx.send(()).unwrap();
-    drop(tx);
-    rx.recv().unwrap();
-    let s = Select::new();
-    let mut h = s.handle(&rx);
-    unsafe { h.add(); }
-    assert_eq!(s.wait2(false), h.id());
-}
-
-#[test]
-fn oneshot_data_waiting() {
-    let (tx1, rx1) = channel();
-    let (tx2, rx2) = channel();
-    let _t = thread::spawn(move|| {
-        select! {
-            _n = rx1.recv() => {}
-        }
-        tx2.send(()).unwrap();
-    });
-
-    for _ in 0..100 { thread::yield_now() }
-    tx1.send(()).unwrap();
-    rx2.recv().unwrap();
-}
-
-#[test]
-fn stream_data_waiting() {
-    let (tx1, rx1) = channel();
-    let (tx2, rx2) = channel();
-    tx1.send(()).unwrap();
-    tx1.send(()).unwrap();
-    rx1.recv().unwrap();
-    rx1.recv().unwrap();
-    let _t = thread::spawn(move|| {
-        select! {
-            _n = rx1.recv() => {}
-        }
-        tx2.send(()).unwrap();
-    });
-
-    for _ in 0..100 { thread::yield_now() }
-    tx1.send(()).unwrap();
-    rx2.recv().unwrap();
-}
-
-#[test]
-fn shared_data_waiting() {
-    let (tx1, rx1) = channel();
-    let (tx2, rx2) = channel();
-    drop(tx1.clone());
-    tx1.send(()).unwrap();
-    rx1.recv().unwrap();
-    let _t = thread::spawn(move|| {
-        select! {
-            _n = rx1.recv() => {}
-        }
-        tx2.send(()).unwrap();
-    });
-
-    for _ in 0..100 { thread::yield_now() }
-    tx1.send(()).unwrap();
-    rx2.recv().unwrap();
-}
-
-#[test]
-fn sync1() {
-    let (tx, rx) = sync_channel::<i32>(1);
-    tx.send(1).unwrap();
-    select! {
-        n = rx.recv() => { assert_eq!(n.unwrap(), 1); }
-    }
-}
-
-#[test]
-fn sync2() {
-    let (tx, rx) = sync_channel::<i32>(0);
-    let _t = thread::spawn(move|| {
-        for _ in 0..100 { thread::yield_now() }
-        tx.send(1).unwrap();
-    });
-    select! {
-        n = rx.recv() => { assert_eq!(n.unwrap(), 1); }
-    }
-}
-
-#[test]
-fn sync3() {
-    let (tx1, rx1) = sync_channel::<i32>(0);
-    let (tx2, rx2): (Sender<i32>, Receiver<i32>) = channel();
-    let _t = thread::spawn(move|| { tx1.send(1).unwrap(); });
-    let _t = thread::spawn(move|| { tx2.send(2).unwrap(); });
-    select! {
-        n = rx1.recv() => {
-            let n = n.unwrap();
-            assert_eq!(n, 1);
-            assert_eq!(rx2.recv().unwrap(), 2);
-        },
-        n = rx2.recv() => {
-            let n = n.unwrap();
-            assert_eq!(n, 2);
-            assert_eq!(rx1.recv().unwrap(), 1);
-        }
-    }
-}
index cc70a62036590b4b514fdbd0639dbf93d64e6f74..dbcdcdac9326855330847013db2d442e233e5623 100644 (file)
@@ -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<T> Packet<T> {
     // 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.
     //
index 7ae6f68b514595d305bb993f1a73896f622a4f49..40877282761790cd78c989d9eb37fad0cd92c181 100644 (file)
@@ -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<T> {
-    SelSuccess,
-    SelCanceled,
-    SelUpgraded(SignalToken, Receiver<T>),
-}
-
 // Any message could contain an "upgrade request" to a new shared port, so the
 // internal queue it's a queue of T, but rather Message<T>
 enum Message<T> {
@@ -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<bool, Receiver<T>> {
-        // We peek at the queue to see if there's anything on it, and we use
-        // this return value to determine if we should pop from the queue and
-        // upgrade this channel immediately. If it looks like we've got an
-        // upgrade pending, then go through the whole recv rigamarole to update
-        // the internal state.
-        match self.queue.peek() {
-            Some(&mut GoUp(..)) => {
-                match self.recv(None) {
-                    Err(Upgraded(port)) => Err(port),
-                    _ => unreachable!(),
-                }
-            }
-            Some(..) => Ok(true),
-            None => Ok(false)
-        }
-    }
-
     // increment the count on the channel (used for selection)
     fn bump(&self, amt: isize) -> isize {
         match self.queue.producer_addition().cnt.fetch_add(amt, Ordering::SeqCst) {
@@ -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<T> {
-        match self.decrement(token) {
-            Ok(()) => SelSuccess,
-            Err(token) => {
-                let ret = match self.queue.peek() {
-                    Some(&mut GoUp(..)) => {
-                        match self.queue.pop() {
-                            Some(GoUp(port)) => SelUpgraded(token, port),
-                            _ => unreachable!(),
-                        }
-                    }
-                    Some(..) => SelCanceled,
-                    None => SelCanceled,
-                };
-                // Undo our decrement above, and we should be guaranteed that the
-                // previous value is positive because we're not going to sleep
-                let prev = self.bump(1);
-                assert!(prev == DISCONNECTED || prev >= 0);
-                ret
-            }
-        }
-    }
-
     // Removes a previous thread from being blocked in this port
     pub fn abort_selection(&self,
                            was_upgrade: bool) -> Result<bool, Receiver<T>> {
index b2d9f4c6491e4026c8429cd6ffa11b0d57cdb64c..3c4f8e077c922ee536340b607fc3e2c2b29179cc 100644 (file)
@@ -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<T> Drop for Packet<T> {
index 11ac34fcb24f6c9097fda20e33d6e944d74a6b3c..87c2318a9377c56ff3b3922915d664cd2aeaeaa8 100644 (file)
@@ -376,6 +376,8 @@ fn drop(&mut self) {
 impl<T> From<T> for Mutex<T> {
     /// Creates a new mutex in an unlocked state ready for use.
     /// This is equivalent to [`Mutex::new`].
+    ///
+    /// [`Mutex::new`]: ../../std/sync/struct.Mutex.html#method.new
     fn from(t: T) -> Self {
         Mutex::new(t)
     }
index 1299a74409560263edc6b5b3f7e71c8c6336b4fe..b1b56f321fc6b8fb162c68a7ba2362de91621ab3 100644 (file)
@@ -453,6 +453,8 @@ fn default() -> RwLock<T> {
 impl<T> From<T> for RwLock<T> {
     /// Creates a new instance of an `RwLock<T>` which is unlocked.
     /// This is equivalent to [`RwLock::new`].
+    ///
+    /// [`RwLock::new`]: ../../std/sync/struct.RwLock.html#method.new
     fn from(t: T) -> Self {
         RwLock::new(t)
     }
index 77f1439e17b10324c7d67d25ab036d7755a27922..71c62461ee9cb4aef5aa6e01652c37165842f25e 100644 (file)
@@ -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 {
index fce28ffd9c3880714fab7b8727459e6efd74f5cf..35de4f4008b6723a67aa2c567ee4fde6987c0067 100644 (file)
@@ -443,6 +443,7 @@ pub fn spawn<F, T>(self, f: F) -> io::Result<JoinHandle<T>> 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<JoinHandle<T>> where
         F: FnOnce() -> T, F: Send + 'a, T: Send + 'a
index 8a066f3f4a093a82c2fd96c84727d31a166520c3..5b1a9bb739ff8346ec9e889b313d0bebf67129e2 100644 (file)
@@ -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),
     (
index 01b126f48b327151c0e988deec216b1a8372295e..aa9028d4a6bad3758d5ed57bfa1a76defb85bdda 100644 (file)
         eh_personality,
         eh_unwind_resume,
         enable,
+        err,
         Err,
         except,
         exclusive_range_pattern,
         fundamental,
         future,
         Future,
+        gen_future,
         generators,
         generic_associated_types,
         generic_param_attrs,
         never,
         never_type,
         next,
+        __next,
         nll,
         no_builtins,
         no_core,
         Pending,
         pin,
         Pin,
+        pinned,
         platform_intrinsics,
         plugin,
         plugin_registrar,
         trivial_bounds,
         Try,
         try_blocks,
+        try_trait,
         tuple_indexing,
         ty,
         type_alias_enum_variants,
         uniform_paths,
         universal_impl_trait,
         unmarked_api,
+        unreachable_code,
         unrestricted_attribute_tokens,
         unsafe_destructor_blind_to_params,
         unsafe_no_drop_flag,
         use_nested_groups,
         usize,
         v1,
+        val,
         vis,
         visible_private_types,
         volatile,
@@ -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: Decoder>(d: &mut D) -> Result<LocalInternedString, D::Error> {
-        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<F: FnOnce(&str) -> 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: Decoder>(d: &mut D) -> Result<InternedString, D::Error> {
-        Ok(Symbol::intern(&d.read_str()?).as_interned_str())
+        Ok(InternedString::intern(&d.read_str()?))
     }
 }
 
index c6afa90e4ee614d5c85d2961c8b1bff7424d955f..7f7db2a21251ac8864bcc07faf4a30001c2d6634 100644 (file)
 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::*;
index 0dd67bb95ccaa5d500d2ef6157eedbfc933985d9..5004f787cde190725b2b5d3b69a117a319fcb0a6 100644 (file)
@@ -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 (file)
index 0000000..1b17886
--- /dev/null
@@ -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
+}
index 4b97af68ff08af727a4f923e58c95e9ed4e4bedf..dd22eb5d604ea51b84d8586ebfc26c6e16bcb038 100644 (file)
@@ -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];
index 0718316307c5edbb5dda0f88983a9c33196079d8..fe98cf24eec009ecc6416033e5b7a38e787a6dae 100644 (file)
@@ -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 (file)
index 0000000..0df1112
--- /dev/null
@@ -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
index b2a99a6d446bbfe113c245ef2c0a33462371e38e..35512b94c0c8cf8f96c87db6ab2350ae51118525 100644 (file)
@@ -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 (file)
index 12be977..0000000
+++ /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<Sender<()>>) {
-    for tx in rx.iter() {
-        let _ = tx.send(());
-    }
-}
-
-fn main() {
-    let (tx, rx) = channel();
-    let t = thread::spawn(move|| { helper(rx) });
-    let (snd, rcv) = channel::<isize>();
-    for _ in 1..100000 {
-        snd.send(1).unwrap();
-        let (tx2, rx2) = channel();
-        tx.send(tx2).unwrap();
-        select! {
-            _ = rx2.recv() => (),
-            _ = rcv.recv() => ()
-        }
-    }
-    drop(tx);
-    t.join();
-}
index 904f2e2c7fd7eff21de27eb8080a4fc4455d7931..12a612c153ad62f085884b66c058e350a9dbeeb0 100644 (file)
@@ -233,8 +233,6 @@ fn println() {
     println!("hello {}", "world",);
 }
 
-// select! is too troublesome and unlikely to be stabilized
-
 // stringify! is N/A
 
 #[cfg(std)]
index 3f6e489bb83275f6f7b7bbee03806579e91ea459..4ca4b407bd4ff2b70ca60e3aed042874bc8efcec 100644 (file)
@@ -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 (file)
index 0000000..bd84b46
--- /dev/null
@@ -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<U>` could reuse as `None`; this test makes sure that isn't done.
+//
+// Secondly, this tests the status quo (not a guarantee; subject to change!) to not apply such
+// optimizations to types containing unions even if they're theoretically possible. (discussion:
+// https://github.com/rust-lang/rust/issues/36394)
+//
+// Notably this nails down part of the behavior that `MaybeUninit` assumes: that a
+// `Option<MaybeUninit<&u8>>` does not take advantage of non-zero optimization, and thus is a safe
+// construct.
+
+use std::mem::{size_of, transmute};
+
+union U1<A: Copy> {
+    a: A,
+}
+
+union U2<A: Copy, B: Copy> {
+    a: A,
+    b: B,
+}
+
+// Option<E> uses a value other than 0 and 1 as None
+#[derive(Clone,Copy)]
+enum E {
+    A = 0,
+    B = 1,
+}
+
+fn main() {
+    // Unions do not participate in niche-filling/non-zero optimization...
+    assert!(size_of::<Option<U2<&u8, u8>>>() > size_of::<U2<&u8, u8>>());
+    assert!(size_of::<Option<U2<&u8, ()>>>() > size_of::<U2<&u8, ()>>());
+    assert!(size_of::<Option<U2<u8, E>>>() > size_of::<U2<u8, E>>());
+
+    // ...even when theoretically possible:
+    assert!(size_of::<Option<U1<&u8>>>() > size_of::<U1<&u8>>());
+    assert!(size_of::<Option<U2<&u8, &u8>>>() > size_of::<U2<&u8, &u8>>());
+
+    // The unused bits of the () variant can have any value.
+    let zeroed: U2<&u8, ()> = unsafe { transmute(std::ptr::null::<u8>()) };
+
+    if let None = Some(zeroed) {
+        panic!()
+    }
+}
index aa3f539ba32a314c3961181b4e54fabbbf807e67..4b2a91e9c812722f4a6f66beb1692e8ea56037a6 100644 (file)
@@ -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
index 208bdedf24ddb6b10aebd044bdfc6b5118fb770e..23c07c4d32d64359d43a4a4ead40dbac4ba40050 100644 (file)
@@ -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 (file)
index 0000000..ffe0ddc
--- /dev/null
@@ -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 (file)
index 0000000..97a52a1
--- /dev/null
@@ -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 (file)
index 0000000..4272313
--- /dev/null
@@ -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 (file)
index 0000000..6f23929
--- /dev/null
@@ -0,0 +1,3 @@
+#![deny(intra_doc_link_resolution_failure)]
+
+pub use std::*;
index fb1be7397e65d659875e7231a18fc77e3d81c5bb..018716ad45af344f5fafd908b9b6cbe97004379d 100644 (file)
@@ -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"
index 1b76e6c885349c6bec037c1912f8ac89455f90f6..9971c7b4297a25d9162d580f6bb0097a279a028e 100644 (file)
@@ -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"
index 0129a3f72b2422d0b7c59ef6fd6ebc1b7c778f0d..ca0a432d3396e1a446f26c91c5018a5b000d115c 100644 (file)
@@ -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
index dcbe13a749f69b981661308165761959c3a26d47..c7081205e148195bdc5e2007bd025d2ffaf59a3f 100644 (file)
@@ -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
    |
index bed1e32a60158110c5182368ac219abdaf61c402..0127261b2b7d0a6111f68b71c1af2690c5c7819b 100644 (file)
@@ -57,6 +57,15 @@ pub enum Enum4<A, B, C, D> {
     Four(D)
 }
 
+pub union Union1<A: Copy> {
+    a: A,
+}
+
+pub union Union2<A: Copy, B: Copy> {
+    a: A,
+    b: B,
+}
+
 #[start]
 fn start(_: isize, _: *const *const u8) -> isize {
     let _x: MyOption<NonZeroU32> = Default::default();
@@ -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<u8>> = Enum4::One(());
+
+    // Unions do not currently participate in niche filling.
+    let _h: MyOption<Union2<NonZeroU32, u32>> = Default::default();
+
+    // ...even when theoretically possible.
+    let _i: MyOption<Union1<NonZeroU32>> = Default::default();
+    let _j: MyOption<Union2<NonZeroU32, NonZeroU32>> = Default::default();
+
     0
 }
index 9cdb2ae4f57e0aeb99097f211545210d8c75f1c2..301edc0d086b11fee1b251fd47b5ab7ebba36190 100644 (file)
@@ -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<Union1<std::num::NonZeroU32>>`: 8 bytes, alignment: 4 bytes
+print-type-size     discriminant: 4 bytes
+print-type-size     variant `Some`: 4 bytes
+print-type-size         field `.0`: 4 bytes
+print-type-size     variant `None`: 0 bytes
+print-type-size type: `MyOption<Union2<std::num::NonZeroU32, std::num::NonZeroU32>>`: 8 bytes, alignment: 4 bytes
+print-type-size     discriminant: 4 bytes
+print-type-size     variant `Some`: 4 bytes
+print-type-size         field `.0`: 4 bytes
+print-type-size     variant `None`: 0 bytes
+print-type-size type: `MyOption<Union2<std::num::NonZeroU32, u32>>`: 8 bytes, alignment: 4 bytes
+print-type-size     discriminant: 4 bytes
+print-type-size     variant `Some`: 4 bytes
+print-type-size         field `.0`: 4 bytes
+print-type-size     variant `None`: 0 bytes
 print-type-size type: `NestedNonZero`: 8 bytes, alignment: 4 bytes
 print-type-size     field `.val`: 4 bytes
 print-type-size     field `.post`: 2 bytes
@@ -36,6 +51,17 @@ print-type-size type: `MyOption<std::num::NonZeroU32>`: 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<std::num::NonZeroU32>`: 4 bytes, alignment: 4 bytes
+print-type-size     variant `Union1`: 4 bytes
+print-type-size         field `.a`: 4 bytes
+print-type-size type: `Union2<std::num::NonZeroU32, std::num::NonZeroU32>`: 4 bytes, alignment: 4 bytes
+print-type-size     variant `Union2`: 4 bytes
+print-type-size         field `.a`: 4 bytes
+print-type-size         field `.b`: 4 bytes, offset: 0 bytes, alignment: 4 bytes
+print-type-size type: `Union2<std::num::NonZeroU32, u32>`: 4 bytes, alignment: 4 bytes
+print-type-size     variant `Union2`: 4 bytes
+print-type-size         field `.a`: 4 bytes
+print-type-size         field `.b`: 4 bytes, offset: 0 bytes, alignment: 4 bytes
 print-type-size type: `std::num::NonZeroU32`: 4 bytes, alignment: 4 bytes
 print-type-size     field `.0`: 4 bytes
 print-type-size type: `Enum4<(), (), (), MyOption<u8>>`: 2 bytes, alignment: 1 bytes
index 04986b59ea0f1afeee4df464bf31e649bbab707d..38bd3fc006dcca0ec84f395b5f1b382f3b574faf 100644 (file)
@@ -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, "<p>No description.</p>\n")?,
         }
index bc0c76d861a178911f3f506196a7404eda1e690d..0c85dbf3df0f545133dca24eccfc9f0f6107c7f8 160000 (submodule)
@@ -1 +1 @@
-Subproject commit bc0c76d861a178911f3f506196a7404eda1e690d
+Subproject commit 0c85dbf3df0f545133dca24eccfc9f0f6107c7f8
index 5b8e99bb61958ca8abcb7c5eda70521726be1065..9692ca8fd82a8f96a4113dc4b88c1fb1d79c1c60 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 5b8e99bb61958ca8abcb7c5eda70521726be1065
+Subproject commit 9692ca8fd82a8f96a4113dc4b88c1fb1d79c1c60