]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #56914 - glaubitz:ignore-tests, r=alexcrichton
authorkennytm <kennytm@gmail.com>
Sat, 22 Dec 2018 16:07:35 +0000 (00:07 +0800)
committerkennytm <kennytm@gmail.com>
Sat, 22 Dec 2018 18:11:49 +0000 (02:11 +0800)
Ignore ui/target-feature-gate on sparc, sparc64, powerpc, powerpc64 and powerpc64le

The test ui/target-feature-gate is not applicable on sparc, sparc64, powerpc, powerpc64 and powerpc64le and consequently fails there. So just ignore it on these targets.

168 files changed:
src/liballoc/boxed.rs
src/liballoc/collections/vec_deque.rs
src/liballoc/lib.rs
src/liballoc/rc.rs
src/liballoc/sync.rs
src/liballoc/tests/lib.rs
src/liballoc/tests/vec_deque.rs
src/libcore/iter/mod.rs
src/libcore/iter/traits.rs
src/libcore/ops/deref.rs
src/libcore/ops/mod.rs
src/libcore/pin.rs
src/libcore/tests/iter.rs
src/libcore/tests/lib.rs
src/libproc_macro/lib.rs
src/librustc/cfg/construct.rs
src/librustc/dep_graph/dep_node.rs
src/librustc/hir/map/mod.rs
src/librustc/hir/print.rs
src/librustc/ich/hcx.rs
src/librustc/ich/impls_mir.rs
src/librustc/infer/canonical/query_response.rs
src/librustc/infer/mod.rs
src/librustc/lib.rs
src/librustc/middle/lang_items.rs
src/librustc/middle/liveness.rs
src/librustc/mir/mod.rs
src/librustc/mir/visit.rs
src/librustc/session/mod.rs
src/librustc/traits/coherence.rs
src/librustc/traits/fulfill.rs
src/librustc/traits/query/method_autoderef.rs [new file with mode: 0644]
src/librustc/traits/query/mod.rs
src/librustc/ty/context.rs
src/librustc/ty/inhabitedness/mod.rs
src/librustc/ty/layout.rs
src/librustc/ty/mod.rs
src/librustc/ty/query/config.rs
src/librustc/ty/query/job.rs
src/librustc/ty/query/mod.rs
src/librustc/ty/query/plumbing.rs
src/librustc/ty/sty.rs
src/librustc_codegen_ssa/mir/statement.rs
src/librustc_data_structures/fingerprint.rs
src/librustc_data_structures/lib.rs
src/librustc_driver/driver.rs
src/librustc_driver/lib.rs
src/librustc_driver/pretty.rs
src/librustc_driver/test.rs
src/librustc_mir/borrow_check/flows.rs
src/librustc_mir/borrow_check/mod.rs
src/librustc_mir/borrow_check/nll/invalidation.rs
src/librustc_mir/borrow_check/nll/mod.rs
src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs
src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs
src/librustc_mir/borrow_check/nll/type_check/mod.rs
src/librustc_mir/borrow_check/path_utils.rs
src/librustc_mir/borrow_check/places_conflict.rs
src/librustc_mir/build/expr/into.rs
src/librustc_mir/const_eval.rs
src/librustc_mir/dataflow/at_location.rs
src/librustc_mir/dataflow/graphviz.rs
src/librustc_mir/dataflow/impls/borrowed_locals.rs
src/librustc_mir/dataflow/impls/borrows.rs
src/librustc_mir/dataflow/impls/mod.rs
src/librustc_mir/dataflow/impls/storage_liveness.rs
src/librustc_mir/dataflow/mod.rs
src/librustc_mir/dataflow/move_paths/builder.rs
src/librustc_mir/hair/pattern/check_match.rs
src/librustc_mir/interpret/cast.rs
src/librustc_mir/interpret/machine.rs
src/librustc_mir/interpret/step.rs
src/librustc_mir/shim.rs
src/librustc_mir/transform/add_retag.rs
src/librustc_mir/transform/check_unsafety.rs
src/librustc_mir/transform/elaborate_drops.rs
src/librustc_mir/transform/generator.rs
src/librustc_mir/transform/inline.rs
src/librustc_mir/transform/qualify_consts.rs
src/librustc_mir/transform/qualify_min_const_fn.rs
src/librustc_mir/transform/remove_noop_landing_pads.rs
src/librustc_mir/transform/rustc_peek.rs
src/librustc_resolve/build_reduced_graph.rs
src/librustc_resolve/lib.rs
src/librustc_resolve/macros.rs
src/librustc_typeck/check/autoderef.rs
src/librustc_typeck/check/callee.rs
src/librustc_typeck/check/closure.rs
src/librustc_typeck/check/coercion.rs
src/librustc_typeck/check/method/confirm.rs
src/librustc_typeck/check/method/mod.rs
src/librustc_typeck/check/method/probe.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/wfcheck.rs
src/librustc_typeck/lib.rs
src/librustdoc/clean/inline.rs
src/librustdoc/clean/mod.rs
src/librustdoc/core.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/libstd/lib.rs
src/libstd/net/tcp.rs
src/libstd/rt.rs
src/libstd/sys/cloudabi/thread.rs
src/libstd/sys/redox/thread.rs
src/libstd/sys/sgx/thread.rs
src/libstd/sys/unix/net.rs
src/libstd/sys/unix/os.rs
src/libstd/sys/unix/pipe.rs
src/libstd/sys/unix/thread.rs
src/libstd/sys/unix/weak.rs
src/libstd/sys/wasm/thread.rs
src/libstd/sys/windows/thread.rs
src/libsyntax/ext/base.rs
src/libsyntax/ext/expand.rs
src/libsyntax/parse/mod.rs
src/libsyntax/parse/token.rs
src/libsyntax/print/pprust.rs
src/libsyntax/tokenstream.rs
src/libsyntax_ext/deriving/custom.rs
src/libsyntax_ext/proc_macro_server.rs
src/libsyntax_pos/hygiene.rs
src/test/debuginfo/nil-enum.rs [deleted file]
src/test/mir-opt/retag.rs
src/test/mir-opt/uninhabited-enum.rs [new file with mode: 0644]
src/test/pretty/issue-4264.pp
src/test/run-pass/arbitrary_self_types_stdlib_pointers.rs
src/test/run-pass/binding/empty-types-in-patterns.rs
src/test/run-pass/issue-53843.rs [new file with mode: 0644]
src/test/run-pass/issues/issue-41696.rs
src/test/rustdoc/assoc-consts-version.rs [new file with mode: 0644]
src/test/rustdoc/assoc-types.rs
src/test/rustdoc/const-display.rs [new file with mode: 0644]
src/test/rustdoc/deprecated.rs
src/test/rustdoc/internal.rs [new file with mode: 0644]
src/test/rustdoc/issue-27759.rs
src/test/rustdoc/issue-32374.rs
src/test/ui/coercion/coerce-issue-49593-box-never.rs [new file with mode: 0644]
src/test/ui/coherence/auxiliary/coherence_fundamental_trait_lib.rs [new file with mode: 0644]
src/test/ui/coherence/coherence-fundamental-trait-objects.rs [new file with mode: 0644]
src/test/ui/coherence/coherence-fundamental-trait-objects.stderr [new file with mode: 0644]
src/test/ui/consts/const-eval/ub-uninhabit.rs
src/test/ui/consts/const-eval/ub-uninhabit.stderr
src/test/ui/consts/validate_never_arrays.stderr
src/test/ui/feature-gates/feature-gate-arbitrary-self-types.rs
src/test/ui/feature-gates/feature-gate-arbitrary-self-types.stderr
src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.rs
src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr
src/test/ui/issues/issue-56762.rs [new file with mode: 0644]
src/test/ui/issues/issue-56762.stderr [new file with mode: 0644]
src/test/ui/nll/issue-46589.rs [new file with mode: 0644]
src/test/ui/nll/issue-46589.stderr [new file with mode: 0644]
src/test/ui/nll/loan_ends_mid_block_pair.rs
src/test/ui/nll/loan_ends_mid_block_pair.stderr
src/test/ui/privacy/privacy1.rs
src/test/ui/privacy/privacy1.stderr
src/test/ui/proc-macro/auxiliary/dollar-crate-external.rs [new file with mode: 0644]
src/test/ui/proc-macro/auxiliary/dollar-crate.rs [new file with mode: 0644]
src/test/ui/proc-macro/dollar-crate.rs [new file with mode: 0644]
src/test/ui/proc-macro/dollar-crate.stderr [new file with mode: 0644]
src/test/ui/proc-macro/dollar-crate.stdout [new file with mode: 0644]
src/test/ui/span/issue-27522.rs
src/test/ui/span/issue-27522.stderr
src/test/ui/ufcs/ufcs-explicit-self-bad.rs
src/test/ui/ufcs/ufcs-explicit-self-bad.stderr
src/test/ui/uninhabited/privately-uninhabited-dead-code.rs [new file with mode: 0644]

index 83adcce5c742c6f06456703c19ee10dacb60a746..f1581310b48fcfbf192568ca428fe7b8620f1748 100644 (file)
@@ -77,7 +77,9 @@
 use core::marker::{Unpin, Unsize};
 use core::mem;
 use core::pin::Pin;
-use core::ops::{CoerceUnsized, DispatchFromDyn, Deref, DerefMut, Generator, GeneratorState};
+use core::ops::{
+    CoerceUnsized, DispatchFromDyn, Deref, DerefMut, Receiver, Generator, GeneratorState
+};
 use core::ptr::{self, NonNull, Unique};
 use core::task::{LocalWaker, Poll};
 
@@ -583,6 +585,9 @@ fn deref_mut(&mut self) -> &mut T {
     }
 }
 
+#[unstable(feature = "receiver_trait", issue = "0")]
+impl<T: ?Sized> Receiver for Box<T> {}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<I: Iterator + ?Sized> Iterator for Box<I> {
     type Item = I::Item;
index 0c5926fbaf1dcf7623fdc29ff49fc14a69382b16..5171ca254e48628d27137b60fb1c9384cde6cc2d 100644 (file)
@@ -1927,6 +1927,118 @@ pub fn resize_with(&mut self, new_len: usize, generator: impl FnMut()->T) {
             self.truncate(new_len);
         }
     }
+
+    /// Rotates the double-ended queue `mid` places to the left.
+    ///
+    /// Equivalently,
+    /// - Rotates item `mid` into the first position.
+    /// - Pops the first `mid` items and pushes them to the end.
+    /// - Rotates `len() - mid` places to the right.
+    ///
+    /// # Panics
+    ///
+    /// If `mid` is greater than `len()`.  Note that `mid == len()`
+    /// does _not_ panic and is a no-op rotation.
+    ///
+    /// # Complexity
+    ///
+    /// Takes `O(min(mid, len() - mid))` time and no extra space.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(vecdeque_rotate)]
+    ///
+    /// use std::collections::VecDeque;
+    ///
+    /// let mut buf: VecDeque<_> = (0..10).collect();
+    ///
+    /// buf.rotate_left(3);
+    /// assert_eq!(buf, [3, 4, 5, 6, 7, 8, 9, 0, 1, 2]);
+    ///
+    /// for i in 1..10 {
+    ///     assert_eq!(i * 3 % 10, buf[0]);
+    ///     buf.rotate_left(3);
+    /// }
+    /// assert_eq!(buf, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
+    /// ```
+    #[unstable(feature = "vecdeque_rotate", issue = "56686")]
+    pub fn rotate_left(&mut self, mid: usize) {
+        assert!(mid <= self.len());
+        let k = self.len() - mid;
+        if mid <= k {
+            unsafe { self.rotate_left_inner(mid) }
+        } else {
+            unsafe { self.rotate_right_inner(k) }
+        }
+    }
+
+    /// Rotates the double-ended queue `k` places to the right.
+    ///
+    /// Equivalently,
+    /// - Rotates the first item into position `k`.
+    /// - Pops the last `k` items and pushes them to the front.
+    /// - Rotates `len() - k` places to the left.
+    ///
+    /// # Panics
+    ///
+    /// If `k` is greater than `len()`.  Note that `k == len()`
+    /// does _not_ panic and is a no-op rotation.
+    ///
+    /// # Complexity
+    ///
+    /// Takes `O(min(k, len() - k))` time and no extra space.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(vecdeque_rotate)]
+    ///
+    /// use std::collections::VecDeque;
+    ///
+    /// let mut buf: VecDeque<_> = (0..10).collect();
+    ///
+    /// buf.rotate_right(3);
+    /// assert_eq!(buf, [7, 8, 9, 0, 1, 2, 3, 4, 5, 6]);
+    ///
+    /// for i in 1..10 {
+    ///     assert_eq!(0, buf[i * 3 % 10]);
+    ///     buf.rotate_right(3);
+    /// }
+    /// assert_eq!(buf, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
+    /// ```
+    #[unstable(feature = "vecdeque_rotate", issue = "56686")]
+    pub fn rotate_right(&mut self, k: usize) {
+        assert!(k <= self.len());
+        let mid = self.len() - k;
+        if k <= mid {
+            unsafe { self.rotate_right_inner(k) }
+        } else {
+            unsafe { self.rotate_left_inner(mid) }
+        }
+    }
+
+    // Safety: the following two methods require that the rotation amount
+    // be less than half the length of the deque.
+    //
+    // `wrap_copy` requres that `min(x, cap() - x) + copy_len <= cap()`,
+    // but than `min` is never more than half the capacity, regardless of x,
+    // so it's sound to call here because we're calling with something
+    // less than half the length, which is never above half the capacity.
+
+    unsafe fn rotate_left_inner(&mut self, mid: usize) {
+        debug_assert!(mid * 2 <= self.len());
+        self.wrap_copy(self.head, self.tail, mid);
+        self.head = self.wrap_add(self.head, mid);
+        self.tail = self.wrap_add(self.tail, mid);
+    }
+
+    unsafe fn rotate_right_inner(&mut self, k: usize) {
+        debug_assert!(k * 2 <= self.len());
+        self.head = self.wrap_sub(self.head, k);
+        self.tail = self.wrap_sub(self.tail, k);
+        self.wrap_copy(self.tail, self.head, k);
+    }
 }
 
 impl<T: Clone> VecDeque<T> {
index abacc62c8562b0e594477a96904b292cfd7518a6..e00e430fab6ef2f78f68f578ad6916eb0c912749 100644 (file)
 #![feature(ptr_internals)]
 #![feature(ptr_offset_from)]
 #![feature(rustc_attrs)]
+#![feature(receiver_trait)]
 #![feature(specialization)]
 #![feature(split_ascii_whitespace)]
 #![feature(staged_api)]
index 6769a70ddbe0a8333a5335aa159176adde7432e4..3fc70f4ac37a1a3874a554df18394e93fe61427b 100644 (file)
 use core::marker;
 use core::marker::{Unpin, Unsize, PhantomData};
 use core::mem::{self, align_of_val, forget, size_of_val};
-use core::ops::Deref;
+use core::ops::{Deref, Receiver};
 use core::ops::{CoerceUnsized, DispatchFromDyn};
 use core::pin::Pin;
 use core::ptr::{self, NonNull};
@@ -813,6 +813,9 @@ fn deref(&self) -> &T {
     }
 }
 
+#[unstable(feature = "receiver_trait", issue = "0")]
+impl<T: ?Sized> Receiver for Rc<T> {}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc<T> {
     /// Drops the `Rc`.
index e596694fb9d4b6e7070a55f1e8f244bf5c23cd94..557370166081253a40c6bae1d424aa22541ce207 100644 (file)
@@ -24,7 +24,7 @@
 use core::cmp::Ordering;
 use core::intrinsics::abort;
 use core::mem::{self, align_of_val, size_of_val};
-use core::ops::Deref;
+use core::ops::{Deref, Receiver};
 use core::ops::{CoerceUnsized, DispatchFromDyn};
 use core::pin::Pin;
 use core::ptr::{self, NonNull};
@@ -767,6 +767,9 @@ fn deref(&self) -> &T {
     }
 }
 
+#[unstable(feature = "receiver_trait", issue = "0")]
+impl<T: ?Sized> Receiver for Arc<T> {}
+
 impl<T: Clone> Arc<T> {
     /// Makes a mutable reference into the given `Arc`.
     ///
index e514a8a69c020701ea4e42fb31425628901722e8..146abd1b7508aa21acce24c74fdf590644c4cd6d 100644 (file)
 #![feature(drain_filter)]
 #![feature(exact_size_is_empty)]
 #![feature(pattern)]
+#![feature(repeat_generic_slice)]
 #![feature(slice_sort_by_cached_key)]
 #![feature(str_escape)]
 #![feature(try_reserve)]
 #![feature(unboxed_closures)]
-#![feature(repeat_generic_slice)]
+#![feature(vecdeque_rotate)]
 
 extern crate core;
 extern crate rand;
index 1f2a7211c657bec100a3631295a823fe01a6d351..c8a6d86413ad6535a4ea8571908bf08e8e9da8cd 100644 (file)
@@ -1309,3 +1309,137 @@ fn test_try_reserve_exact() {
     }
 
 }
+
+#[test]
+fn test_rotate_nop() {
+    let mut v: VecDeque<_> = (0..10).collect();
+    assert_unchanged(&v);
+
+    v.rotate_left(0);
+    assert_unchanged(&v);
+
+    v.rotate_left(10);
+    assert_unchanged(&v);
+
+    v.rotate_right(0);
+    assert_unchanged(&v);
+
+    v.rotate_right(10);
+    assert_unchanged(&v);
+
+    v.rotate_left(3);
+    v.rotate_right(3);
+    assert_unchanged(&v);
+
+    v.rotate_right(3);
+    v.rotate_left(3);
+    assert_unchanged(&v);
+
+    v.rotate_left(6);
+    v.rotate_right(6);
+    assert_unchanged(&v);
+
+    v.rotate_right(6);
+    v.rotate_left(6);
+    assert_unchanged(&v);
+
+    v.rotate_left(3);
+    v.rotate_left(7);
+    assert_unchanged(&v);
+
+    v.rotate_right(4);
+    v.rotate_right(6);
+    assert_unchanged(&v);
+
+    v.rotate_left(1);
+    v.rotate_left(2);
+    v.rotate_left(3);
+    v.rotate_left(4);
+    assert_unchanged(&v);
+
+    v.rotate_right(1);
+    v.rotate_right(2);
+    v.rotate_right(3);
+    v.rotate_right(4);
+    assert_unchanged(&v);
+
+    fn assert_unchanged(v: &VecDeque<i32>) {
+        assert_eq!(v, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
+    }
+}
+
+#[test]
+fn test_rotate_left_parts() {
+    let mut v: VecDeque<_> = (1..=7).collect();
+    v.rotate_left(2);
+    assert_eq!(v.as_slices(), (&[3, 4, 5, 6, 7, 1][..], &[2][..]));
+    v.rotate_left(2);
+    assert_eq!(v.as_slices(), (&[5, 6, 7, 1][..], &[2, 3, 4][..]));
+    v.rotate_left(2);
+    assert_eq!(v.as_slices(), (&[7, 1][..], &[2, 3, 4, 5, 6][..]));
+    v.rotate_left(2);
+    assert_eq!(v.as_slices(), (&[2, 3, 4, 5, 6, 7, 1][..], &[][..]));
+    v.rotate_left(2);
+    assert_eq!(v.as_slices(), (&[4, 5, 6, 7, 1, 2][..], &[3][..]));
+    v.rotate_left(2);
+    assert_eq!(v.as_slices(), (&[6, 7, 1, 2][..], &[3, 4, 5][..]));
+    v.rotate_left(2);
+    assert_eq!(v.as_slices(), (&[1, 2][..], &[3, 4, 5, 6, 7][..]));
+}
+
+#[test]
+fn test_rotate_right_parts() {
+    let mut v: VecDeque<_> = (1..=7).collect();
+    v.rotate_right(2);
+    assert_eq!(v.as_slices(), (&[6, 7][..], &[1, 2, 3, 4, 5][..]));
+    v.rotate_right(2);
+    assert_eq!(v.as_slices(), (&[4, 5, 6, 7][..], &[1, 2, 3][..]));
+    v.rotate_right(2);
+    assert_eq!(v.as_slices(), (&[2, 3, 4, 5, 6, 7][..], &[1][..]));
+    v.rotate_right(2);
+    assert_eq!(v.as_slices(), (&[7, 1, 2, 3, 4, 5, 6][..], &[][..]));
+    v.rotate_right(2);
+    assert_eq!(v.as_slices(), (&[5, 6][..], &[7, 1, 2, 3, 4][..]));
+    v.rotate_right(2);
+    assert_eq!(v.as_slices(), (&[3, 4, 5, 6][..], &[7, 1, 2][..]));
+    v.rotate_right(2);
+    assert_eq!(v.as_slices(), (&[1, 2, 3, 4, 5, 6][..], &[7][..]));
+}
+
+#[test]
+fn test_rotate_left_random() {
+    let shifts = [
+        6, 1, 0, 11, 12, 1, 11, 7, 9, 3, 6, 1,
+        4, 0, 5, 1, 3, 1, 12, 8, 3, 1, 11, 11,
+        9, 4, 12, 3, 12, 9, 11, 1, 7, 9, 7, 2,
+    ];
+    let n = 12;
+    let mut v: VecDeque<_> = (0..n).collect();
+    let mut total_shift = 0;
+    for shift in shifts.iter().cloned() {
+        v.rotate_left(shift);
+        total_shift += shift;
+        for i in 0..n {
+            assert_eq!(v[i], (i + total_shift) % n);
+        }
+    }
+}
+
+#[test]
+fn test_rotate_right_random() {
+    let shifts = [
+        6, 1, 0, 11, 12, 1, 11, 7, 9, 3, 6, 1,
+        4, 0, 5, 1, 3, 1, 12, 8, 3, 1, 11, 11,
+        9, 4, 12, 3, 12, 9, 11, 1, 7, 9, 7, 2,
+    ];
+    let n = 12;
+    let mut v: VecDeque<_> = (0..n).collect();
+    let mut total_shift = 0;
+    for shift in shifts.iter().cloned() {
+        v.rotate_right(shift);
+        total_shift += shift;
+        for i in 0..n {
+            assert_eq!(v[(i + total_shift) % n], i);
+        }
+    }
+}
index aa23d49672a0bcbba08d441624bec26c78affbb6..e493a3804376ffab9588a482ee078e050cca74a7 100644 (file)
@@ -429,6 +429,9 @@ fn next(&mut self) -> Option<<I as Iterator>::Item> { self.iter.next_back() }
     #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
 
+    #[inline]
+    fn nth(&mut self, n: usize) -> Option<<I as Iterator>::Item> { self.iter.nth_back(n) }
+
     fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R where
         Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try<Ok=B>
     {
@@ -461,6 +464,9 @@ impl<I> DoubleEndedIterator for Rev<I> where I: DoubleEndedIterator {
     #[inline]
     fn next_back(&mut self) -> Option<<I as Iterator>::Item> { self.iter.next() }
 
+    #[inline]
+    fn nth_back(&mut self, n: usize) -> Option<<I as Iterator>::Item> { self.iter.nth(n) }
+
     fn try_rfold<B, F, R>(&mut self, init: B, f: F) -> R where
         Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try<Ok=B>
     {
index 45e5b614db3e0bdea9940be4ec47b57987900bcb..727a60e3596944d0294acb80952268f948c6d7fe 100644 (file)
@@ -427,6 +427,62 @@ pub trait DoubleEndedIterator: Iterator {
     #[stable(feature = "rust1", since = "1.0.0")]
     fn next_back(&mut self) -> Option<Self::Item>;
 
+    /// Returns the `n`th element from the end of the iterator.
+    ///
+    /// This is essentially the reversed version of [`nth`]. Although like most indexing
+    /// operations, the count starts from zero, so `nth_back(0)` returns the first value fro
+    /// the end, `nth_back(1)` the second, and so on.
+    ///
+    /// Note that all elements between the end and the returned element will be
+    /// consumed, including the returned element. This also means that calling
+    /// `nth_back(0)` multiple times on the same iterator will return different
+    /// elements.
+    ///
+    /// `nth_back()` will return [`None`] if `n` is greater than or equal to the length of the
+    /// iterator.
+    ///
+    /// [`None`]: ../../std/option/enum.Option.html#variant.None
+    /// [`nth`]: ../../std/iter/trait.Iterator.html#method.nth
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(iter_nth_back)]
+    /// let a = [1, 2, 3];
+    /// assert_eq!(a.iter().nth_back(2), Some(&1));
+    /// ```
+    ///
+    /// Calling `nth_back()` multiple times doesn't rewind the iterator:
+    ///
+    /// ```
+    /// #![feature(iter_nth_back)]
+    /// let a = [1, 2, 3];
+    ///
+    /// let mut iter = a.iter();
+    ///
+    /// assert_eq!(iter.nth_back(1), Some(&2));
+    /// assert_eq!(iter.nth_back(1), None);
+    /// ```
+    ///
+    /// Returning `None` if there are less than `n + 1` elements:
+    ///
+    /// ```
+    /// #![feature(iter_nth_back)]
+    /// let a = [1, 2, 3];
+    /// assert_eq!(a.iter().nth_back(10), None);
+    /// ```
+    #[inline]
+    #[unstable(feature = "iter_nth_back", issue = "56995")]
+    fn nth_back(&mut self, mut n: usize) -> Option<Self::Item> {
+        for x in self.rev() {
+            if n == 0 { return Some(x) }
+            n -= 1;
+        }
+        None
+    }
+
     /// This is the reverse version of [`try_fold()`]: it takes elements
     /// starting from the back of the iterator.
     ///
@@ -461,8 +517,11 @@ pub trait DoubleEndedIterator: Iterator {
     /// ```
     #[inline]
     #[stable(feature = "iterator_try_fold", since = "1.27.0")]
-    fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R where
-        Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try<Ok=B>
+    fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
+    where
+        Self: Sized,
+        F: FnMut(B, Self::Item) -> R,
+        R: Try<Ok=B>
     {
         let mut accum = init;
         while let Some(x) = self.next_back() {
@@ -524,8 +583,10 @@ fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R where
     /// ```
     #[inline]
     #[stable(feature = "iter_rfold", since = "1.27.0")]
-    fn rfold<B, F>(mut self, accum: B, mut f: F) -> B where
-        Self: Sized, F: FnMut(B, Self::Item) -> B,
+    fn rfold<B, F>(mut self, accum: B, mut f: F) -> B
+    where
+        Self: Sized,
+        F: FnMut(B, Self::Item) -> B,
     {
         self.try_rfold(accum, move |acc, x| Ok::<B, !>(f(acc, x))).unwrap()
     }
@@ -574,7 +635,8 @@ fn rfold<B, F>(mut self, accum: B, mut f: F) -> B where
     /// ```
     #[inline]
     #[stable(feature = "iter_rfind", since = "1.27.0")]
-    fn rfind<P>(&mut self, mut predicate: P) -> Option<Self::Item> where
+    fn rfind<P>(&mut self, mut predicate: P) -> Option<Self::Item>
+    where
         Self: Sized,
         P: FnMut(&Self::Item) -> bool
     {
@@ -587,7 +649,12 @@ fn rfind<P>(&mut self, mut predicate: P) -> Option<Self::Item> where
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I {
-    fn next_back(&mut self) -> Option<I::Item> { (**self).next_back() }
+    fn next_back(&mut self) -> Option<I::Item> {
+        (**self).next_back()
+    }
+    fn nth_back(&mut self, n: usize) -> Option<I::Item> {
+        (**self).nth_back(n)
+    }
 }
 
 /// An iterator that knows its exact length.
index 91a3d77e8b2efa9363fee3ca4419a78871537a3e..ff836f4aa69a678793288708fdf02653616acea7 100644 (file)
@@ -177,3 +177,19 @@ pub trait DerefMut: Deref {
 impl<T: ?Sized> DerefMut for &mut T {
     fn deref_mut(&mut self) -> &mut T { *self }
 }
+
+/// Indicates that a struct can be used as a method receiver, without the
+/// `arbitrary_self_types` feature. This is implemented by stdlib pointer types like `Box<T>`,
+/// `Rc<T>`, `&T`, and `Pin<P>`.
+#[cfg_attr(not(stage0), lang = "receiver")]
+#[unstable(feature = "receiver_trait", issue = "0")]
+#[doc(hidden)]
+pub trait Receiver {
+    // Empty.
+}
+
+#[unstable(feature = "receiver_trait", issue = "0")]
+impl<T: ?Sized> Receiver for &T {}
+
+#[unstable(feature = "receiver_trait", issue = "0")]
+impl<T: ?Sized> Receiver for &mut T {}
index 785f0733df2b85eb3cdbe9023eb434b2fefc5f4f..06740d2e4cd7038137130727c2fe34196c7121cf 100644 (file)
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::deref::{Deref, DerefMut};
 
+#[unstable(feature = "receiver_trait", issue = "0")]
+pub use self::deref::Receiver;
+
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::drop::Drop;
 
index 0ad6e8c7c1c7dcc5d7c1eda0a3a0ab11e62b72eb..521ce9b5f6b698f56efa51bc4a28d6a794f0b117 100644 (file)
 
 use fmt;
 use marker::Sized;
-use ops::{Deref, DerefMut, CoerceUnsized, DispatchFromDyn};
+use ops::{Deref, DerefMut, Receiver, CoerceUnsized, DispatchFromDyn};
 
 #[doc(inline)]
 pub use marker::Unpin;
@@ -302,6 +302,9 @@ fn deref_mut(&mut self) -> &mut P::Target {
     }
 }
 
+#[unstable(feature = "receiver_trait", issue = "0")]
+impl<P: Receiver> Receiver for Pin<P> {}
+
 #[unstable(feature = "pin", issue = "49150")]
 impl<P: fmt::Debug> fmt::Debug for Pin<P> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
index 00b4aa4fa2d7aa34c0cc6fb5a2e781326377e18c..b5633333d01706c3e82f38aac78a6d00245140ac 100644 (file)
@@ -1016,6 +1016,33 @@ fn test_iterator_nth() {
     assert_eq!(v.iter().nth(v.len()), None);
 }
 
+#[test]
+fn test_iterator_nth_back() {
+    let v: &[_] = &[0, 1, 2, 3, 4];
+    for i in 0..v.len() {
+        assert_eq!(v.iter().nth_back(i).unwrap(), &v[v.len() - 1 - i]);
+    }
+    assert_eq!(v.iter().nth_back(v.len()), None);
+}
+
+#[test]
+fn test_iterator_rev_nth_back() {
+    let v: &[_] = &[0, 1, 2, 3, 4];
+    for i in 0..v.len() {
+        assert_eq!(v.iter().rev().nth_back(i).unwrap(), &v[i]);
+    }
+    assert_eq!(v.iter().rev().nth_back(v.len()), None);
+}
+
+#[test]
+fn test_iterator_rev_nth() {
+    let v: &[_] = &[0, 1, 2, 3, 4];
+    for i in 0..v.len() {
+        assert_eq!(v.iter().rev().nth(i).unwrap(), &v[v.len() - 1 - i]);
+    }
+    assert_eq!(v.iter().rev().nth(v.len()), None);
+}
+
 #[test]
 fn test_iterator_last() {
     let v: &[_] = &[0, 1, 2, 3, 4];
index 7d62b4fa90f203cbb4f6c682cc1a7666194ffa63..2377a4733678d1eb33e2b6b4fca2d07b7b9bfd78 100644 (file)
@@ -19,6 +19,7 @@
 #![feature(flt2dec)]
 #![feature(fmt_internals)]
 #![feature(hashmap_internals)]
+#![feature(iter_nth_back)]
 #![feature(iter_unfold)]
 #![feature(pattern)]
 #![feature(range_is_empty)]
index f2b85832dac31759d455051f09a42cefc5f35b39..ebba5c81fe077d455a931def3bb59bb53556591c 100644 (file)
@@ -729,11 +729,6 @@ impl Punct {
     /// which can be further configured with the `set_span` method below.
     #[stable(feature = "proc_macro_lib2", since = "1.29.0")]
     pub fn new(ch: char, spacing: Spacing) -> Punct {
-        const LEGAL_CHARS: &[char] = &['=', '<', '>', '!', '~', '+', '-', '*', '/', '%', '^',
-                                       '&', '|', '@', '.', ',', ';', ':', '#', '$', '?', '\''];
-        if !LEGAL_CHARS.contains(&ch) {
-            panic!("unsupported character `{:?}`", ch)
-        }
         Punct(bridge::client::Punct::new(ch, spacing))
     }
 
@@ -800,16 +795,6 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 pub struct Ident(bridge::client::Ident);
 
 impl Ident {
-    fn is_valid(string: &str) -> bool {
-        let mut chars = string.chars();
-        if let Some(start) = chars.next() {
-            (start == '_' || start.is_xid_start())
-                && chars.all(|cont| cont == '_' || cont.is_xid_continue())
-        } else {
-            false
-        }
-    }
-
     /// Creates a new `Ident` with the given `string` as well as the specified
     /// `span`.
     /// The `string` argument must be a valid identifier permitted by the
@@ -831,18 +816,12 @@ fn is_valid(string: &str) -> bool {
     /// tokens, requires a `Span` to be specified at construction.
     #[stable(feature = "proc_macro_lib2", since = "1.29.0")]
     pub fn new(string: &str, span: Span) -> Ident {
-        if !Ident::is_valid(string) {
-            panic!("`{:?}` is not a valid identifier", string)
-        }
         Ident(bridge::client::Ident::new(string, span.0, false))
     }
 
     /// Same as `Ident::new`, but creates a raw identifier (`r#ident`).
     #[unstable(feature = "proc_macro_raw_ident", issue = "54723")]
     pub fn new_raw(string: &str, span: Span) -> Ident {
-        if !Ident::is_valid(string) {
-            panic!("`{:?}` is not a valid identifier", string)
-        }
         Ident(bridge::client::Ident::new(string, span.0, true))
     }
 
index c5d6ce24c5df4d03ec132032756ff385f7638f22..4881f10fac25e33b123e378ed6118e96da8ed844 100644 (file)
@@ -415,8 +415,8 @@ fn call<'b, I: Iterator<Item=&'b hir::Expr>>(&mut self,
             args: I) -> CFGIndex {
         let func_or_rcvr_exit = self.expr(func_or_rcvr, pred);
         let ret = self.straightline(call_expr, func_or_rcvr_exit, args);
-        // FIXME(canndrew): This is_never should probably be an is_uninhabited.
-        if self.tables.expr_ty(call_expr).is_never() {
+        let m = self.tcx.hir().get_module_parent(call_expr.id);
+        if self.tcx.is_ty_uninhabited_from(m, self.tables.expr_ty(call_expr)) {
             self.add_unreachable_node()
         } else {
             ret
index f0c6196412adb982ce2c12a391620d04bb021e65..f4d7ef59404cca050ad4beda0002d6aab48636b5 100644 (file)
@@ -162,7 +162,9 @@ pub fn can_reconstruct_query_key<$tcx>(&self) -> bool {
                 }
             }
 
-            #[inline]
+            // FIXME: Make `is_anon`, `is_input`, `is_eval_always` and `has_params` properties
+            // of queries
+            #[inline(always)]
             pub fn is_anon(&self) -> bool {
                 match *self {
                     $(
@@ -171,7 +173,7 @@ pub fn is_anon(&self) -> bool {
                 }
             }
 
-            #[inline]
+            #[inline(always)]
             pub fn is_input(&self) -> bool {
                 match *self {
                     $(
@@ -180,7 +182,7 @@ pub fn is_input(&self) -> bool {
                 }
             }
 
-            #[inline]
+            #[inline(always)]
             pub fn is_eval_always(&self) -> bool {
                 match *self {
                     $(
@@ -190,7 +192,7 @@ pub fn is_eval_always(&self) -> bool {
             }
 
             #[allow(unreachable_code)]
-            #[inline]
+            #[inline(always)]
             pub fn has_params(&self) -> bool {
                 match *self {
                     $(
@@ -230,6 +232,7 @@ pub struct DepNode {
 
         impl DepNode {
             #[allow(unreachable_code, non_snake_case)]
+            #[inline(always)]
             pub fn new<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                                        dep: DepConstructor<'gcx>)
                                        -> DepNode
@@ -299,11 +302,11 @@ pub fn new<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
             /// Construct a DepNode from the given DepKind and DefPathHash. This
             /// method will assert that the given DepKind actually requires a
             /// single DefId/DefPathHash parameter.
-            #[inline]
+            #[inline(always)]
             pub fn from_def_path_hash(kind: DepKind,
                                       def_path_hash: DefPathHash)
                                       -> DepNode {
-                assert!(kind.can_reconstruct_query_key() && kind.has_params());
+                debug_assert!(kind.can_reconstruct_query_key() && kind.has_params());
                 DepNode {
                     kind,
                     hash: def_path_hash.0,
@@ -313,9 +316,9 @@ pub fn from_def_path_hash(kind: DepKind,
             /// Create a new, parameterless DepNode. This method will assert
             /// that the DepNode corresponding to the given DepKind actually
             /// does not require any parameters.
-            #[inline]
+            #[inline(always)]
             pub fn new_no_params(kind: DepKind) -> DepNode {
-                assert!(!kind.has_params());
+                debug_assert!(!kind.has_params());
                 DepNode {
                     kind,
                     hash: Fingerprint::ZERO,
@@ -418,14 +421,14 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 
 impl DefPathHash {
-    #[inline]
+    #[inline(always)]
     pub fn to_dep_node(self, kind: DepKind) -> DepNode {
         DepNode::from_def_path_hash(kind, self)
     }
 }
 
 impl DefId {
-    #[inline]
+    #[inline(always)]
     pub fn to_dep_node(self, tcx: TyCtxt<'_, '_, '_>, kind: DepKind) -> DepNode {
         DepNode::from_def_path_hash(kind, tcx.def_path_hash(self))
     }
@@ -666,6 +669,7 @@ pub fn fingerprint_needed_for_crate_hash(self) -> bool {
     [] TypeOpNormalizeFnSig(CanonicalTypeOpNormalizeGoal<'tcx, FnSig<'tcx>>),
 
     [] SubstituteNormalizeAndTestPredicates { key: (DefId, &'tcx Substs<'tcx>) },
+    [] MethodAutoderefSteps(CanonicalTyGoal<'tcx>),
 
     [input] TargetFeaturesWhitelist,
 
index b98e279aef4b964080c76e42e19f3556cf08d4de..de8a375ca6ddec46489d1b9e354f9c011f45ad11 100644 (file)
@@ -159,6 +159,13 @@ pub fn krate<'hir>(&'hir self) -> &'hir Crate {
         self.dep_graph.read(DepNode::new_no_params(DepKind::Krate));
         &self.krate
     }
+
+    /// This is internally in the depedency tracking system.
+    /// Use the `krate` method to ensure your dependency on the
+    /// crate is tracked.
+    pub fn untracked_krate<'hir>(&'hir self) -> &'hir Crate {
+        &self.krate
+    }
 }
 
 /// Represents a mapping from Node IDs to AST elements and their parent
index a24f2fa4bc65243b36ce73887ab8587180ed9f2e..5c6845181afd19725f6f7132cfc58455dbefd8d6 100644 (file)
@@ -1622,8 +1622,7 @@ pub fn print_path(&mut self,
             if i > 0 {
                 self.s.word("::")?
             }
-            if segment.ident.name != keywords::PathRoot.name() &&
-               segment.ident.name != keywords::DollarCrate.name() {
+            if segment.ident.name != keywords::PathRoot.name() {
                self.print_ident(segment.ident)?;
                segment.with_generic_args(|generic_args| {
                    self.print_generic_args(generic_args, segment.infer_types,
@@ -1636,8 +1635,7 @@ pub fn print_path(&mut self,
     }
 
     pub fn print_path_segment(&mut self, segment: &hir::PathSegment) -> io::Result<()> {
-        if segment.ident.name != keywords::PathRoot.name() &&
-           segment.ident.name != keywords::DollarCrate.name() {
+        if segment.ident.name != keywords::PathRoot.name() {
            self.print_ident(segment.ident)?;
            segment.with_generic_args(|generic_args| {
                self.print_generic_args(generic_args, segment.infer_types, false)
@@ -1664,8 +1662,7 @@ pub fn print_qpath(&mut self,
                     if i > 0 {
                         self.s.word("::")?
                     }
-                    if segment.ident.name != keywords::PathRoot.name() &&
-                       segment.ident.name != keywords::DollarCrate.name() {
+                    if segment.ident.name != keywords::PathRoot.name() {
                         self.print_ident(segment.ident)?;
                         segment.with_generic_args(|generic_args| {
                             self.print_generic_args(generic_args,
index 2e56308daf7c25d6ad9796a722e5d13b32bf9099..799c2df8a53c5d3775763165184daa5b26ee06e9 100644 (file)
@@ -86,6 +86,7 @@ impl<'a> StableHashingContext<'a> {
     // The `krate` here is only used for mapping BodyIds to Bodies.
     // Don't use it for anything else or you'll run the risk of
     // leaking data out of the tracking system.
+    #[inline]
     pub fn new(sess: &'a Session,
                krate: &'a hir::Crate,
                definitions: &'a Definitions,
index a46e12be1aeace57d5b28a503e8f90111c98e075..d82020f59a10ecbd4be52055b5fef06fb306d77d 100644 (file)
@@ -200,13 +200,13 @@ fn hash_stable<W: StableHasherResult>(&self,
     SetDiscriminant { place, variant_index },
     StorageLive(place),
     StorageDead(place),
-    EscapeToRaw(place),
-    Retag { fn_entry, two_phase, place },
+    Retag(retag_kind, place),
     AscribeUserType(place, variance, c_ty),
     Nop,
     InlineAsm { asm, outputs, inputs },
 });
 
+impl_stable_hash_for!(enum mir::RetagKind { FnEntry, TwoPhase, Raw, Default });
 impl_stable_hash_for!(enum mir::FakeReadCause { ForMatchGuard, ForMatchedPlace, ForLet });
 
 impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for mir::Place<'gcx> {
index 43bc9d88895d7e74af0c63c4f4432bd5d40a9972..2a8a340ab545280717bbe2a67817fd396f36cdf1 100644 (file)
@@ -117,6 +117,31 @@ pub fn make_canonicalized_query_response<T>(
         Ok(Lrc::new(canonical_result))
     }
 
+    /// A version of `make_canonicalized_query_response` that does
+    /// not pack in obligations, for contexts that want to drop
+    /// pending obligations instead of treating them as an ambiguity (e.g.
+    /// typeck "probing" contexts).
+    ///
+    /// If you DO want to keep track of pending obligations (which
+    /// include all region obligations, so this includes all cases
+    /// that care about regions) with this function, you have to
+    /// do it yourself, by e.g. having them be a part of the answer.
+    pub fn make_query_response_ignoring_pending_obligations<T>(
+        &self,
+        inference_vars: CanonicalVarValues<'tcx>,
+        answer: T
+    ) -> Canonical<'gcx, QueryResponse<'gcx, <T as Lift<'gcx>>::Lifted>>
+    where
+        T: Debug + Lift<'gcx> + TypeFoldable<'tcx>,
+    {
+        self.canonicalize_response(&QueryResponse {
+            var_values: inference_vars,
+            region_constraints: vec![],
+            certainty: Certainty::Proven, // Ambiguities are OK!
+            value: answer,
+        })
+    }
+
     /// Helper for `make_canonicalized_query_response` that does
     /// everything up until the final canonicalization.
     fn make_query_response<T>(
index c961fd5fbd4b1b608797fd555ac40ce188f76738..7ce59b1d9d765e59c0f8c99844731e9f7cf4339a 100644 (file)
@@ -37,7 +37,7 @@
 use ty::fold::TypeFoldable;
 use ty::relate::{RelateResult, TraitObjectMode};
 use ty::subst::{Kind, Substs};
-use ty::{self, GenericParamDefKind, Ty, TyCtxt};
+use ty::{self, GenericParamDefKind, Ty, TyCtxt, CtxtInterners};
 use ty::{FloatVid, IntVid, TyVid};
 use util::nodemap::FxHashMap;
 
@@ -474,6 +474,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 pub struct InferCtxtBuilder<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     global_tcx: TyCtxt<'a, 'gcx, 'gcx>,
     arena: SyncDroplessArena,
+    interners: Option<CtxtInterners<'tcx>>,
     fresh_tables: Option<RefCell<ty::TypeckTables<'tcx>>>,
     trait_object_mode: TraitObjectMode,
 }
@@ -483,6 +484,7 @@ pub fn infer_ctxt(self) -> InferCtxtBuilder<'a, 'gcx, 'tcx> {
         InferCtxtBuilder {
             global_tcx: self,
             arena: SyncDroplessArena::default(),
+            interners: None,
             fresh_tables: None,
             trait_object_mode: TraitObjectMode::NoSquash,
         }
@@ -531,10 +533,13 @@ pub fn enter<R>(&'tcx mut self, f: impl for<'b> FnOnce(InferCtxt<'b, 'gcx, 'tcx>
             global_tcx,
             trait_object_mode,
             ref arena,
+            ref mut interners,
             ref fresh_tables,
         } = *self;
         let in_progress_tables = fresh_tables.as_ref();
-        global_tcx.enter_local(arena, |tcx| {
+        // Check that we haven't entered before
+        assert!(interners.is_none());
+        global_tcx.enter_local(arena, interners, |tcx| {
             f(InferCtxt {
                 tcx,
                 in_progress_tables,
@@ -1270,6 +1275,10 @@ pub fn shallow_resolve(&self, typ: Ty<'tcx>) -> Ty<'tcx> {
         self.inlined_shallow_resolve(typ)
     }
 
+    pub fn root_var(&self, var: ty::TyVid) -> ty::TyVid {
+        self.type_variables.borrow_mut().root_var(var)
+    }
+
     pub fn resolve_type_vars_if_possible<T>(&self, value: &T) -> T
     where
         T: TypeFoldable<'tcx>,
index 4324cfc7b5f10424c51586dfdc3f0fde73acbe78..b76fb0ed08c992e084d04de9b886babbb9deadec 100644 (file)
 #![feature(slice_sort_by_cached_key)]
 #![feature(specialization)]
 #![feature(unboxed_closures)]
+#![feature(thread_local)]
 #![feature(trace_macros)]
 #![feature(trusted_len)]
 #![feature(vec_remove_item)]
 #![feature(step_trait)]
+#![feature(stmt_expr_attributes)]
 #![feature(integer_atomics)]
 #![feature(test)]
 #![feature(in_band_lifetimes)]
index 23ec24d71d2ebc889fbf705d6e8c90c2f1c0b4db..cfcc7c8371976b3e182f5cf2fe1e6046f765a77f 100644 (file)
@@ -301,6 +301,7 @@ pub fn collect<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> LanguageItems {
 
     DerefTraitLangItem,          "deref",              deref_trait,             Target::Trait;
     DerefMutTraitLangItem,       "deref_mut",          deref_mut_trait,         Target::Trait;
+    ReceiverTraitLangItem,       "receiver",           receiver_trait,          Target::Trait;
 
     FnTraitLangItem,             "fn",                 fn_trait,                Target::Trait;
     FnMutTraitLangItem,          "fn_mut",             fn_mut_trait,            Target::Trait;
index 31a75bd106e2cb36c6a9b13deabcb7c6a4375ab7..d1d2fa298a6ca13de98475637deb117528efb00f 100644 (file)
@@ -1197,8 +1197,8 @@ fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
             }
 
             hir::ExprKind::Call(ref f, ref args) => {
-                // FIXME(canndrew): This is_never should really be an is_uninhabited
-                let succ = if self.tables.expr_ty(expr).is_never() {
+                let m = self.ir.tcx.hir().get_module_parent(expr.id);
+                let succ = if self.ir.tcx.is_ty_uninhabited_from(m, self.tables.expr_ty(expr)) {
                     self.s.exit_ln
                 } else {
                     succ
@@ -1208,8 +1208,8 @@ fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
             }
 
             hir::ExprKind::MethodCall(.., ref args) => {
-                // FIXME(canndrew): This is_never should really be an is_uninhabited
-                let succ = if self.tables.expr_ty(expr).is_never() {
+                let m = self.ir.tcx.hir().get_module_parent(expr.id);
+                let succ = if self.ir.tcx.is_ty_uninhabited_from(m, self.tables.expr_ty(expr)) {
                     self.s.exit_ln
                 } else {
                     succ
index 9dff3277917be14134be79dcf017feba80e3dfa4..dc14450e8d22d88f4e979745412558529a9a18d7 100644 (file)
@@ -1788,23 +1788,7 @@ pub enum StatementKind<'tcx> {
     /// by miri and only generated when "-Z mir-emit-retag" is passed.
     /// See <https://internals.rust-lang.org/t/stacked-borrows-an-aliasing-model-for-rust/8153/>
     /// for more details.
-    Retag {
-        /// `fn_entry` indicates whether this is the initial retag that happens in the
-        /// function prolog.
-        fn_entry: bool,
-        /// `two_phase` indicates whether this is just the reservation action of
-        /// a two-phase borrow.
-        two_phase: bool,
-        /// The place to retag
-        place: Place<'tcx>,
-    },
-
-    /// Escape the given reference to a raw pointer, so that it can be accessed
-    /// without precise provenance tracking. These statements are currently only interpreted
-    /// by miri and only generated when "-Z mir-emit-retag" is passed.
-    /// See <https://internals.rust-lang.org/t/stacked-borrows-an-aliasing-model-for-rust/8153/>
-    /// for more details.
-    EscapeToRaw(Operand<'tcx>),
+    Retag(RetagKind, Place<'tcx>),
 
     /// Encodes a user's type ascription. These need to be preserved
     /// intact so that NLL can respect them. For example:
@@ -1824,6 +1808,19 @@ pub enum StatementKind<'tcx> {
     Nop,
 }
 
+/// `RetagKind` describes what kind of retag is to be performed.
+#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, PartialEq, Eq)]
+pub enum RetagKind {
+    /// The initial retag when entering a function
+    FnEntry,
+    /// Retag preparing for a two-phase borrow
+    TwoPhase,
+    /// Retagging raw pointers
+    Raw,
+    /// A "normal" retag
+    Default,
+}
+
 /// The `FakeReadCause` describes the type of pattern why a `FakeRead` statement exists.
 #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug)]
 pub enum FakeReadCause {
@@ -1859,13 +1856,16 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
         match self.kind {
             Assign(ref place, ref rv) => write!(fmt, "{:?} = {:?}", place, rv),
             FakeRead(ref cause, ref place) => write!(fmt, "FakeRead({:?}, {:?})", cause, place),
-            Retag { fn_entry, two_phase, ref place } =>
-                write!(fmt, "Retag({}{}{:?})",
-                    if fn_entry { "[fn entry] " } else { "" },
-                    if two_phase { "[2phase] " } else { "" },
+            Retag(ref kind, ref place) =>
+                write!(fmt, "Retag({}{:?})",
+                    match kind {
+                        RetagKind::FnEntry => "[fn entry] ",
+                        RetagKind::TwoPhase => "[2phase] ",
+                        RetagKind::Raw => "[raw] ",
+                        RetagKind::Default => "",
+                    },
                     place,
                 ),
-            EscapeToRaw(ref place) => write!(fmt, "EscapeToRaw({:?})", place),
             StorageLive(ref place) => write!(fmt, "StorageLive({:?})", place),
             StorageDead(ref place) => write!(fmt, "StorageDead({:?})", place),
             SetDiscriminant {
@@ -2979,6 +2979,7 @@ pub enum ClosureOutlivesSubject<'tcx> {
     SourceInfo,
     UpvarDecl,
     FakeReadCause,
+    RetagKind,
     SourceScope,
     SourceScopeData,
     SourceScopeLocalData,
@@ -3046,8 +3047,7 @@ impl<'tcx> TypeFoldable<'tcx> for StatementKind<'tcx> {
         (StatementKind::StorageLive)(a),
         (StatementKind::StorageDead)(a),
         (StatementKind::InlineAsm) { asm, outputs, inputs },
-        (StatementKind::Retag) { fn_entry, two_phase, place },
-        (StatementKind::EscapeToRaw)(place),
+        (StatementKind::Retag)(kind, place),
         (StatementKind::AscribeUserType)(a, v, b),
         (StatementKind::Nop),
     }
index 237f6bc9c7b45b81627c8028895eab5f95269845..278a4dc1d873aceafd5a672c4721a57a946f4d1c 100644 (file)
@@ -153,11 +153,10 @@ fn visit_ascribe_user_ty(&mut self,
             }
 
             fn visit_retag(&mut self,
-                           fn_entry: & $($mutability)* bool,
-                           two_phase: & $($mutability)* bool,
+                           kind: & $($mutability)* RetagKind,
                            place: & $($mutability)* Place<'tcx>,
                            location: Location) {
-                self.super_retag(fn_entry, two_phase, place, location);
+                self.super_retag(kind, place, location);
             }
 
             fn visit_place(&mut self,
@@ -385,9 +384,6 @@ fn super_statement(&mut self,
                             location
                         );
                     }
-                    StatementKind::EscapeToRaw(ref $($mutability)* op) => {
-                        self.visit_operand(op, location);
-                    }
                     StatementKind::StorageLive(ref $($mutability)* local) => {
                         self.visit_local(
                             local,
@@ -417,10 +413,9 @@ fn super_statement(&mut self,
                             self.visit_operand(input, location);
                         }
                     }
-                    StatementKind::Retag { ref $($mutability)* fn_entry,
-                                           ref $($mutability)* two_phase,
-                                           ref $($mutability)* place } => {
-                        self.visit_retag(fn_entry, two_phase, place, location);
+                    StatementKind::Retag ( ref $($mutability)* kind,
+                                           ref $($mutability)* place ) => {
+                        self.visit_retag(kind, place, location);
                     }
                     StatementKind::AscribeUserType(
                         ref $($mutability)* place,
@@ -725,8 +720,7 @@ fn super_ascribe_user_ty(&mut self,
             }
 
             fn super_retag(&mut self,
-                           _fn_entry: & $($mutability)* bool,
-                           _two_phase: & $($mutability)* bool,
+                           _kind: & $($mutability)* RetagKind,
                            place: & $($mutability)* Place<'tcx>,
                            location: Location) {
                 self.visit_place(
index 12b5646e7f1d17ac6d340c41228c07a8d38ec56e..180019ac3875117294aae733a7f416c417ff1537 100644 (file)
@@ -131,6 +131,9 @@ pub struct Session {
     /// Used by -Z profile-queries in util::common
     pub profile_channel: Lock<Option<mpsc::Sender<ProfileQueriesMsg>>>,
 
+    /// Used by -Z self-profile
+    pub self_profiling_active: bool,
+
     /// Used by -Z self-profile
     pub self_profiling: Lock<SelfProfiler>,
 
@@ -823,10 +826,17 @@ pub fn incr_comp_session_dir_opt(&self) -> Option<cell::Ref<'_, PathBuf>> {
         }
     }
 
+    #[inline(never)]
+    #[cold]
+    fn profiler_active<F: FnOnce(&mut SelfProfiler) -> ()>(&self, f: F) {
+        let mut profiler = self.self_profiling.borrow_mut();
+        f(&mut profiler);
+    }
+
+    #[inline(always)]
     pub fn profiler<F: FnOnce(&mut SelfProfiler) -> ()>(&self, f: F) {
-        if self.opts.debugging_opts.self_profile || self.opts.debugging_opts.profile_json {
-            let mut profiler = self.self_profiling.borrow_mut();
-            f(&mut profiler);
+        if unlikely!(self.self_profiling_active) {
+            self.profiler_active(f)
         }
     }
 
@@ -1145,6 +1155,9 @@ pub fn build_session_(
         CguReuseTracker::new_disabled()
     };
 
+    let self_profiling_active = sopts.debugging_opts.self_profile ||
+                                sopts.debugging_opts.profile_json;
+
     let sess = Session {
         target: target_cfg,
         host,
@@ -1177,6 +1190,7 @@ pub fn build_session_(
         imported_macro_spans: OneThread::new(RefCell::new(FxHashMap::default())),
         incr_comp_session: OneThread::new(RefCell::new(IncrCompSession::NotInitialized)),
         cgu_reuse_tracker,
+        self_profiling_active,
         self_profiling: Lock::new(SelfProfiler::new()),
         profile_channel: Lock::new(None),
         perf_stats: PerfStats {
index af338cd3868fad5ada046912163c41c47d697c3d..853b54df2b92ff9f705c9a1474842e75db90692a 100644 (file)
@@ -397,7 +397,7 @@ fn uncovered_tys<'tcx>(tcx: TyCtxt<'_, '_, '_>, ty: Ty<'tcx>, in_crate: InCrate)
                        -> Vec<Ty<'tcx>> {
     if ty_is_local_constructor(ty, in_crate) {
         vec![]
-    } else if fundamental_ty(tcx, ty) {
+    } else if fundamental_ty(ty) {
         ty.walk_shallow()
           .flat_map(|t| uncovered_tys(tcx, t, in_crate))
           .collect()
@@ -415,14 +415,13 @@ fn is_possibly_remote_type(ty: Ty<'_>, _in_crate: InCrate) -> bool {
 
 fn ty_is_local(tcx: TyCtxt<'_, '_, '_>, ty: Ty<'_>, in_crate: InCrate) -> bool {
     ty_is_local_constructor(ty, in_crate) ||
-        fundamental_ty(tcx, ty) && ty.walk_shallow().any(|t| ty_is_local(tcx, t, in_crate))
+        fundamental_ty(ty) && ty.walk_shallow().any(|t| ty_is_local(tcx, t, in_crate))
 }
 
-fn fundamental_ty(tcx: TyCtxt<'_, '_, '_>, ty: Ty<'_>) -> bool {
+fn fundamental_ty(ty: Ty<'_>) -> bool {
     match ty.sty {
         ty::Ref(..) => true,
         ty::Adt(def, _) => def.is_fundamental(),
-        ty::Dynamic(ref data, ..) => tcx.has_attr(data.principal().def_id(), "fundamental"),
         _ => false
     }
 }
index bc091a4e7e0848e0ebd81fd2f0e3dde53ab44ec7..09c7bd679705a8c3e27e2c270677e90698ceb548 100644 (file)
@@ -61,6 +61,16 @@ pub struct FulfillmentContext<'tcx> {
     // type-lives-for-region constraints, and because the type
     // is well-formed, the constraints should hold.
     register_region_obligations: bool,
+    // Is it OK to register obligations into this infcx inside
+    // an infcx snapshot?
+    //
+    // The "primary fulfillment" in many cases in typeck lives
+    // outside of any snapshot, so any use of it inside a snapshot
+    // will lead to trouble and therefore is checked against, but
+    // other fulfillment contexts sometimes do live inside of
+    // a snapshot (they don't *straddle* a snapshot, so there
+    // is no trouble there).
+    usable_in_snapshot: bool
 }
 
 #[derive(Clone, Debug)]
@@ -74,14 +84,24 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
     pub fn new() -> FulfillmentContext<'tcx> {
         FulfillmentContext {
             predicates: ObligationForest::new(),
-            register_region_obligations: true
+            register_region_obligations: true,
+            usable_in_snapshot: false,
+        }
+    }
+
+    pub fn new_in_snapshot() -> FulfillmentContext<'tcx> {
+        FulfillmentContext {
+            predicates: ObligationForest::new(),
+            register_region_obligations: true,
+            usable_in_snapshot: true,
         }
     }
 
     pub fn new_ignoring_regions() -> FulfillmentContext<'tcx> {
         FulfillmentContext {
             predicates: ObligationForest::new(),
-            register_region_obligations: false
+            register_region_obligations: false,
+            usable_in_snapshot: false
         }
     }
 
@@ -195,7 +215,7 @@ fn register_predicate_obligation<'a, 'gcx>(&mut self,
 
         debug!("register_predicate_obligation(obligation={:?})", obligation);
 
-        assert!(!infcx.is_in_snapshot());
+        assert!(!infcx.is_in_snapshot() || self.usable_in_snapshot);
 
         self.predicates.register_obligation(PendingPredicateObligation {
             obligation,
diff --git a/src/librustc/traits/query/method_autoderef.rs b/src/librustc/traits/query/method_autoderef.rs
new file mode 100644 (file)
index 0000000..175883e
--- /dev/null
@@ -0,0 +1,55 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use rustc_data_structures::sync::Lrc;
+use infer::canonical::{Canonical, QueryResponse};
+use ty::Ty;
+
+#[derive(Debug)]
+pub struct CandidateStep<'tcx> {
+    pub self_ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
+    pub autoderefs: usize,
+    // true if the type results from a dereference of a raw pointer.
+    // when assembling candidates, we include these steps, but not when
+    // picking methods. This so that if we have `foo: *const Foo` and `Foo` has methods
+    // `fn by_raw_ptr(self: *const Self)` and `fn by_ref(&self)`, then
+    // `foo.by_raw_ptr()` will work and `foo.by_ref()` won't.
+    pub from_unsafe_deref: bool,
+    pub unsize: bool,
+}
+
+#[derive(Clone, Debug)]
+pub struct MethodAutoderefStepsResult<'tcx> {
+    /// The valid autoderef steps that could be find.
+    pub steps: Lrc<Vec<CandidateStep<'tcx>>>,
+    /// If Some(T), a type autoderef reported an error on.
+    pub opt_bad_ty: Option<Lrc<MethodAutoderefBadTy<'tcx>>>,
+    /// If `true`, `steps` has been truncated due to reaching the
+    /// recursion limit.
+    pub reached_recursion_limit: bool,
+}
+
+#[derive(Debug)]
+pub struct MethodAutoderefBadTy<'tcx> {
+    pub reached_raw_pointer: bool,
+    pub ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
+}
+
+impl_stable_hash_for!(struct MethodAutoderefBadTy<'tcx> {
+    reached_raw_pointer, ty
+});
+
+impl_stable_hash_for!(struct MethodAutoderefStepsResult<'tcx> {
+    reached_recursion_limit, steps, opt_bad_ty
+});
+
+impl_stable_hash_for!(struct CandidateStep<'tcx> {
+    self_ty, autoderefs, from_unsafe_deref, unsize
+});
index 13683d8544496477fdc55699ca763ec0e1768bf7..b11cb7377645c3a5344e21c60dce6526998e52f2 100644 (file)
@@ -21,6 +21,7 @@
 
 pub mod dropck_outlives;
 pub mod evaluate_obligation;
+pub mod method_autoderef;
 pub mod normalize;
 pub mod normalize_erasing_regions;
 pub mod outlives_bounds;
index e27d7349877fc8e12df51acf45c560b8ce4ae88f..04d96e362a4650c1d57831a70b5ccbc7361ff59b 100644 (file)
@@ -72,6 +72,7 @@
 use std::iter;
 use std::sync::mpsc;
 use std::sync::Arc;
+use std::marker::PhantomData;
 use rustc_target::spec::abi;
 use syntax::ast::{self, NodeId};
 use syntax::attr;
@@ -86,6 +87,7 @@
 pub struct AllArenas<'tcx> {
     pub global: WorkerLocal<GlobalArenas<'tcx>>,
     pub interner: SyncDroplessArena,
+    global_ctxt: Option<GlobalCtxt<'tcx>>,
 }
 
 impl<'tcx> AllArenas<'tcx> {
@@ -93,6 +95,7 @@ pub fn new() -> Self {
         AllArenas {
             global: WorkerLocal::new(|_| GlobalArenas::default()),
             interner: SyncDroplessArena::default(),
+            global_ctxt: None,
         }
     }
 }
@@ -869,12 +872,13 @@ pub struct FreeRegionInfo {
 /// [rustc guide]: https://rust-lang.github.io/rustc-guide/ty.html
 #[derive(Copy, Clone)]
 pub struct TyCtxt<'a, 'gcx: 'tcx, 'tcx: 'a> {
-    gcx: &'a GlobalCtxt<'gcx>,
-    interners: &'a CtxtInterners<'tcx>
+    gcx: &'gcx GlobalCtxt<'gcx>,
+    interners: &'tcx CtxtInterners<'tcx>,
+    dummy: PhantomData<&'a ()>,
 }
 
-impl<'a, 'gcx, 'tcx> Deref for TyCtxt<'a, 'gcx, 'tcx> {
-    type Target = &'a GlobalCtxt<'gcx>;
+impl<'gcx> Deref for TyCtxt<'_, 'gcx, '_> {
+    type Target = &'gcx GlobalCtxt<'gcx>;
     #[inline(always)]
     fn deref(&self) -> &Self::Target {
         &self.gcx
@@ -964,10 +968,11 @@ pub struct GlobalCtxt<'tcx> {
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// Get the global TyCtxt.
     #[inline]
-    pub fn global_tcx(self) -> TyCtxt<'a, 'gcx, 'gcx> {
+    pub fn global_tcx(self) -> TyCtxt<'gcx, 'gcx, 'gcx> {
         TyCtxt {
             gcx: self.gcx,
             interners: &self.gcx.global_interners,
+            dummy: PhantomData,
         }
     }
 
@@ -1105,7 +1110,7 @@ pub fn create_and_enter<F, R>(s: &'tcx Session,
                                   cstore: &'tcx CrateStoreDyn,
                                   local_providers: ty::query::Providers<'tcx>,
                                   extern_providers: ty::query::Providers<'tcx>,
-                                  arenas: &'tcx AllArenas<'tcx>,
+                                  arenas: &'tcx mut AllArenas<'tcx>,
                                   resolutions: ty::Resolutions,
                                   hir: hir_map::Map<'tcx>,
                                   on_disk_query_result_cache: query::OnDiskCache<'tcx>,
@@ -1166,7 +1171,7 @@ pub fn create_and_enter<F, R>(s: &'tcx Session,
                                      Lrc::new(StableVec::new(v)));
         }
 
-        let gcx = &GlobalCtxt {
+        arenas.global_ctxt = Some(GlobalCtxt {
             sess: s,
             cstore,
             global_arenas: &arenas.global,
@@ -1209,7 +1214,9 @@ pub fn create_and_enter<F, R>(s: &'tcx Session,
             alloc_map: Lock::new(interpret::AllocMap::new()),
             tx_to_llvm_workers: Lock::new(tx),
             output_filenames: Arc::new(output_filenames.clone()),
-        };
+        });
+
+        let gcx = arenas.global_ctxt.as_ref().unwrap();
 
         sync::assert_send_val(&gcx);
 
@@ -1336,8 +1343,9 @@ pub fn crate_data_as_rc_any(self, cnum: CrateNum) -> Lrc<dyn Any> {
         self.cstore.crate_data_as_rc_any(cnum)
     }
 
+    #[inline(always)]
     pub fn create_stable_hashing_context(self) -> StableHashingContext<'a> {
-        let krate = self.dep_graph.with_ignore(|| self.hir().krate());
+        let krate = self.gcx.hir_map.forest.untracked_krate();
 
         StableHashingContext::new(self.sess,
                                   krate,
@@ -1609,20 +1617,25 @@ pub fn encode_metadata(self)
     }
 }
 
-impl<'gcx: 'tcx, 'tcx> GlobalCtxt<'gcx> {
+impl<'gcx> GlobalCtxt<'gcx> {
     /// Call the closure with a local `TyCtxt` using the given arena.
-    pub fn enter_local<F, R>(
-        &self,
+    /// `interners` is a slot passed so we can create a CtxtInterners
+    /// with the same lifetime as `arena`.
+    pub fn enter_local<'tcx, F, R>(
+        &'gcx self,
         arena: &'tcx SyncDroplessArena,
+        interners: &'tcx mut Option<CtxtInterners<'tcx>>,
         f: F
     ) -> R
     where
-        F: for<'a> FnOnce(TyCtxt<'a, 'gcx, 'tcx>) -> R
+        F: FnOnce(TyCtxt<'tcx, 'gcx, 'tcx>) -> R,
+        'gcx: 'tcx,
     {
-        let interners = CtxtInterners::new(arena);
+        *interners = Some(CtxtInterners::new(&arena));
         let tcx = TyCtxt {
             gcx: self,
-            interners: &interners,
+            interners: interners.as_ref().unwrap(),
+            dummy: PhantomData,
         };
         ty::tls::with_related_context(tcx.global_tcx(), |icx| {
             let new_icx = ty::tls::ImplicitCtxt {
@@ -1631,8 +1644,8 @@ pub fn enter_local<F, R>(
                 layout_depth: icx.layout_depth,
                 task: icx.task,
             };
-            ty::tls::enter_context(&new_icx, |new_icx| {
-                f(new_icx.tcx)
+            ty::tls::enter_context(&new_icx, |_| {
+                f(tcx)
             })
         })
     }
@@ -1872,6 +1885,7 @@ pub mod tls {
 
     use std::fmt;
     use std::mem;
+    use std::marker::PhantomData;
     use syntax_pos;
     use ty::query;
     use errors::{Diagnostic, TRACK_DIAGNOSTICS};
@@ -1891,10 +1905,10 @@ pub mod tls {
     /// you should also have access to an ImplicitCtxt through the functions
     /// in this module.
     #[derive(Clone)]
-    pub struct ImplicitCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
+    pub struct ImplicitCtxt<'a, 'gcx: 'tcx, 'tcx> {
         /// The current TyCtxt. Initially created by `enter_global` and updated
         /// by `enter_local` with a new local interner
-        pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
+        pub tcx: TyCtxt<'tcx, 'gcx, 'tcx>,
 
         /// The current query job, if any. This is updated by start_job in
         /// ty::query::plumbing when executing a query
@@ -2008,8 +2022,8 @@ pub fn enter_context<'a, 'gcx: 'tcx, 'tcx, F, R>(context: &ImplicitCtxt<'a, 'gcx
     /// creating a initial TyCtxt and ImplicitCtxt.
     /// This happens once per rustc session and TyCtxts only exists
     /// inside the `f` function.
-    pub fn enter_global<'gcx, F, R>(gcx: &GlobalCtxt<'gcx>, f: F) -> R
-        where F: for<'a> FnOnce(TyCtxt<'a, 'gcx, 'gcx>) -> R
+    pub fn enter_global<'gcx, F, R>(gcx: &'gcx GlobalCtxt<'gcx>, f: F) -> R
+        where F: FnOnce(TyCtxt<'gcx, 'gcx, 'gcx>) -> R
     {
         with_thread_locals(|| {
             // Update GCX_PTR to indicate there's a GlobalCtxt available
@@ -2024,6 +2038,7 @@ pub fn enter_global<'gcx, F, R>(gcx: &GlobalCtxt<'gcx>, f: F) -> R
             let tcx = TyCtxt {
                 gcx,
                 interners: &gcx.global_interners,
+                dummy: PhantomData,
             };
             let icx = ImplicitCtxt {
                 tcx,
@@ -2053,6 +2068,7 @@ pub unsafe fn with_global<F, R>(f: F) -> R
         let tcx = TyCtxt {
             gcx,
             interners: &gcx.global_interners,
+            dummy: PhantomData,
         };
         let icx = ImplicitCtxt {
             query: None,
index 721d5e14ccc6378c63520d15d9ca29b3cad346f5..c64811e32f437b6cd9db9f9b65734078a0874694 100644 (file)
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use util::nodemap::{FxHashMap, FxHashSet};
 use ty::context::TyCtxt;
 use ty::{AdtDef, VariantDef, FieldDef, Ty, TyS};
 use ty::{DefId, Substs};
@@ -113,7 +112,7 @@ pub fn is_ty_uninhabited_from_all_modules(self, ty: Ty<'tcx>) -> bool {
     }
 
     fn ty_inhabitedness_forest(self, ty: Ty<'tcx>) -> DefIdForest {
-        ty.uninhabited_from(&mut FxHashMap::default(), self)
+        ty.uninhabited_from(self)
     }
 
     pub fn is_enum_variant_uninhabited_from(self,
@@ -140,7 +139,7 @@ fn variant_inhabitedness_forest(self, variant: &'tcx VariantDef, substs: &'tcx S
         let adt_kind = self.adt_def(adt_def_id).adt_kind();
 
         // Compute inhabitedness forest:
-        variant.uninhabited_from(&mut FxHashMap::default(), self, substs, adt_kind)
+        variant.uninhabited_from(self, substs, adt_kind)
     }
 }
 
@@ -148,12 +147,11 @@ impl<'a, 'gcx, 'tcx> AdtDef {
     /// Calculate the forest of DefIds from which this adt is visibly uninhabited.
     fn uninhabited_from(
         &self,
-        visited: &mut FxHashMap<DefId, FxHashSet<&'tcx Substs<'tcx>>>,
         tcx: TyCtxt<'a, 'gcx, 'tcx>,
         substs: &'tcx Substs<'tcx>) -> DefIdForest
     {
         DefIdForest::intersection(tcx, self.variants.iter().map(|v| {
-            v.uninhabited_from(visited, tcx, substs, self.adt_kind())
+            v.uninhabited_from(tcx, substs, self.adt_kind())
         }))
     }
 }
@@ -162,7 +160,6 @@ impl<'a, 'gcx, 'tcx> VariantDef {
     /// Calculate the forest of DefIds from which this variant is visibly uninhabited.
     fn uninhabited_from(
         &self,
-        visited: &mut FxHashMap<DefId, FxHashSet<&'tcx Substs<'tcx>>>,
         tcx: TyCtxt<'a, 'gcx, 'tcx>,
         substs: &'tcx Substs<'tcx>,
         adt_kind: AdtKind) -> DefIdForest
@@ -175,7 +172,7 @@ fn uninhabited_from(
             AdtKind::Struct => false,
         };
         DefIdForest::union(tcx, self.fields.iter().map(|f| {
-            f.uninhabited_from(visited, tcx, substs, is_enum)
+            f.uninhabited_from(tcx, substs, is_enum)
         }))
     }
 }
@@ -184,13 +181,12 @@ impl<'a, 'gcx, 'tcx> FieldDef {
     /// Calculate the forest of DefIds from which this field is visibly uninhabited.
     fn uninhabited_from(
         &self,
-        visited: &mut FxHashMap<DefId, FxHashSet<&'tcx Substs<'tcx>>>,
         tcx: TyCtxt<'a, 'gcx, 'tcx>,
         substs: &'tcx Substs<'tcx>,
         is_enum: bool,
     ) -> DefIdForest {
-        let mut data_uninhabitedness = move || {
-            self.ty(tcx, substs).uninhabited_from(visited, tcx)
+        let data_uninhabitedness = move || {
+            self.ty(tcx, substs).uninhabited_from(tcx)
         };
         // FIXME(canndrew): Currently enum fields are (incorrectly) stored with
         // Visibility::Invisible so we need to override self.vis if we're
@@ -213,46 +209,16 @@ fn uninhabited_from(
 
 impl<'a, 'gcx, 'tcx> TyS<'tcx> {
     /// Calculate the forest of DefIds from which this type is visibly uninhabited.
-    fn uninhabited_from(
-        &self,
-        visited: &mut FxHashMap<DefId, FxHashSet<&'tcx Substs<'tcx>>>,
-        tcx: TyCtxt<'a, 'gcx, 'tcx>) -> DefIdForest
+    fn uninhabited_from(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> DefIdForest
     {
         match self.sty {
-            Adt(def, substs) => {
-                {
-                    let substs_set = visited.entry(def.did).or_default();
-                    if !substs_set.insert(substs) {
-                        // We are already calculating the inhabitedness of this type.
-                        // The type must contain a reference to itself. Break the
-                        // infinite loop.
-                        return DefIdForest::empty();
-                    }
-                    if substs_set.len() >= tcx.sess.recursion_limit.get() / 4 {
-                        // We have gone very deep, reinstantiating this ADT inside
-                        // itself with different type arguments. We are probably
-                        // hitting an infinite loop. For example, it's possible to write:
-                        //                a type Foo<T>
-                        //      which contains a Foo<(T, T)>
-                        //      which contains a Foo<((T, T), (T, T))>
-                        //      which contains a Foo<(((T, T), (T, T)), ((T, T), (T, T)))>
-                        //      etc.
-                        let error = format!("reached recursion limit while checking \
-                                             inhabitedness of `{}`", self);
-                        tcx.sess.fatal(&error);
-                    }
-                }
-                let ret = def.uninhabited_from(visited, tcx, substs);
-                let substs_set = visited.get_mut(&def.did).unwrap();
-                substs_set.remove(substs);
-                ret
-            }
+            Adt(def, substs) => def.uninhabited_from(tcx, substs),
 
             Never => DefIdForest::full(tcx),
 
             Tuple(ref tys) => {
                 DefIdForest::union(tcx, tys.iter().map(|ty| {
-                    ty.uninhabited_from(visited, tcx)
+                    ty.uninhabited_from(tcx)
                 }))
             }
 
@@ -260,7 +226,7 @@ fn uninhabited_from(
                 match len.assert_usize(tcx) {
                     // If the array is definitely non-empty, it's uninhabited if
                     // the type of its elements is uninhabited.
-                    Some(n) if n != 0 => ty.uninhabited_from(visited, tcx),
+                    Some(n) if n != 0 => ty.uninhabited_from(tcx),
                     _ => DefIdForest::empty()
                 }
             }
index 87d745e5cea77200c82b32185b236248215d3402..f4506c8e8197661a3377f9400b5909c12a046586 100644 (file)
@@ -191,7 +191,14 @@ fn layout_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
         ty::tls::enter_context(&icx, |_| {
             let cx = LayoutCx { tcx, param_env };
-            cx.layout_raw_uncached(ty)
+            let layout = cx.layout_raw_uncached(ty);
+            // Type-level uninhabitedness should always imply ABI uninhabitedness.
+            if let Ok(layout) = layout {
+                if ty.conservative_is_privately_uninhabited(tcx) {
+                    assert!(layout.abi.is_uninhabited());
+                }
+            }
+            layout
         })
     })
 }
@@ -205,12 +212,11 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
 
 pub struct LayoutCx<'tcx, C> {
     pub tcx: C,
-    pub param_env: ty::ParamEnv<'tcx>
+    pub param_env: ty::ParamEnv<'tcx>,
 }
 
 impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
-    fn layout_raw_uncached(&self, ty: Ty<'tcx>)
-                           -> Result<&'tcx LayoutDetails, LayoutError<'tcx>> {
+    fn layout_raw_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx LayoutDetails, LayoutError<'tcx>> {
         let tcx = self.tcx;
         let param_env = self.param_env;
         let dl = self.data_layout();
@@ -551,13 +557,19 @@ enum StructKind {
                 let size = element.size.checked_mul(count, dl)
                     .ok_or(LayoutError::SizeOverflow(ty))?;
 
+                let abi = if count != 0 && ty.conservative_is_privately_uninhabited(tcx) {
+                    Abi::Uninhabited
+                } else {
+                    Abi::Aggregate { sized: true }
+                };
+
                 tcx.intern_layout(LayoutDetails {
                     variants: Variants::Single { index: VariantIdx::new(0) },
                     fields: FieldPlacement::Array {
                         stride: element.size,
                         count
                     },
-                    abi: Abi::Aggregate { sized: true },
+                    abi,
                     align: element.align,
                     size
                 })
index 429b7f03af8e40a058d9b7674fe4c10da06a9dd8..7daaf016c2a66dfec3a97e3b489849d8777c8d7b 100644 (file)
@@ -82,7 +82,7 @@
 pub use self::binding::BindingMode::*;
 
 pub use self::context::{TyCtxt, FreeRegionInfo, GlobalArenas, AllArenas, tls, keep_local};
-pub use self::context::{Lift, TypeckTables};
+pub use self::context::{Lift, TypeckTables, CtxtInterners};
 
 pub use self::instance::{Instance, InstanceDef};
 
index fd9143be679a4ba6bcfdd23ba92aa934be83e235..b320c29dfada5f10a1aad4301ab1bbab70eb06b9 100644 (file)
@@ -827,6 +827,12 @@ fn describe(tcx: TyCtxt<'_, '_, '_>, key: (DefId, &'tcx Substs<'tcx>)) -> Cow<'s
     }
 }
 
+impl<'tcx> QueryDescription<'tcx> for queries::method_autoderef_steps<'tcx> {
+    fn describe(_tcx: TyCtxt<'_, '_, '_>, goal: CanonicalTyGoal<'tcx>) -> Cow<'static, str> {
+        format!("computing autoderef types for `{:?}`", goal).into()
+    }
+}
+
 impl<'tcx> QueryDescription<'tcx> for queries::target_features_whitelist<'tcx> {
     fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> {
         "looking up the whitelist of target features".into()
index 1439e41bb31fd9ba5924683d19947288f657be9a..6e513d68f60f52fe9a372062aaa8314a497d75da 100644 (file)
 use ty::tls;
 use ty::query::Query;
 use ty::query::plumbing::CycleError;
+#[cfg(not(parallel_queries))]
+use ty::query::{
+    plumbing::TryGetJob,
+    config::QueryDescription,
+};
 use ty::context::TyCtxt;
 use errors::Diagnostic;
 use std::process;
@@ -83,36 +88,44 @@ pub fn new(info: QueryInfo<'tcx>, parent: Option<Lrc<QueryJob<'tcx>>>) -> Self {
     ///
     /// For single threaded rustc there's no concurrent jobs running, so if we are waiting for any
     /// query that means that there is a query cycle, thus this always running a cycle error.
-    pub(super) fn await<'lcx>(
+    #[cfg(not(parallel_queries))]
+    #[inline(never)]
+    #[cold]
+    pub(super) fn cycle_error<'lcx, 'a, D: QueryDescription<'tcx>>(
         &self,
         tcx: TyCtxt<'_, 'tcx, 'lcx>,
         span: Span,
-    ) -> Result<(), CycleError<'tcx>> {
-        #[cfg(not(parallel_queries))]
-        {
-            self.find_cycle_in_stack(tcx, span)
-        }
+    ) -> TryGetJob<'a, 'tcx, D> {
+        TryGetJob::JobCompleted(Err(Box::new(self.find_cycle_in_stack(tcx, span))))
+    }
 
-        #[cfg(parallel_queries)]
-        {
-            tls::with_related_context(tcx, move |icx| {
-                let mut waiter = Lrc::new(QueryWaiter {
-                    query: icx.query.clone(),
-                    span,
-                    cycle: Lock::new(None),
-                    condvar: Condvar::new(),
-                });
-                self.latch.await(&waiter);
-                // FIXME: Get rid of this lock. We have ownership of the QueryWaiter
-                // although another thread may still have a Lrc reference so we cannot
-                // use Lrc::get_mut
-                let mut cycle = waiter.cycle.lock();
-                match cycle.take() {
-                    None => Ok(()),
-                    Some(cycle) => Err(cycle)
-                }
-            })
-        }
+    /// Awaits for the query job to complete.
+    ///
+    /// For single threaded rustc there's no concurrent jobs running, so if we are waiting for any
+    /// query that means that there is a query cycle, thus this always running a cycle error.
+    #[cfg(parallel_queries)]
+    pub(super) fn await<'lcx>(
+        &self,
+        tcx: TyCtxt<'_, 'tcx, 'lcx>,
+        span: Span,
+    ) -> Result<(), Box<CycleError<'tcx>>> {
+        tls::with_related_context(tcx, move |icx| {
+            let mut waiter = Lrc::new(QueryWaiter {
+                query: icx.query.clone(),
+                span,
+                cycle: Lock::new(None),
+                condvar: Condvar::new(),
+            });
+            self.latch.await(&waiter);
+            // FIXME: Get rid of this lock. We have ownership of the QueryWaiter
+            // although another thread may still have a Lrc reference so we cannot
+            // use Lrc::get_mut
+            let mut cycle = waiter.cycle.lock();
+            match cycle.take() {
+                None => Ok(()),
+                Some(cycle) => Err(Box::new(cycle))
+            }
+        })
     }
 
     #[cfg(not(parallel_queries))]
@@ -120,7 +133,7 @@ fn find_cycle_in_stack<'lcx>(
         &self,
         tcx: TyCtxt<'_, 'tcx, 'lcx>,
         span: Span,
-    ) -> Result<(), CycleError<'tcx>> {
+    ) -> CycleError<'tcx> {
         // Get the current executing query (waiter) and find the waitee amongst its parents
         let mut current_job = tls::with_related_context(tcx, |icx| icx.query.clone());
         let mut cycle = Vec::new();
@@ -140,7 +153,7 @@ fn find_cycle_in_stack<'lcx>(
                 let usage = job.parent.as_ref().map(|parent| {
                     (job.info.span, parent.info.query.clone())
                 });
-                return Err(CycleError { usage, cycle });
+                return CycleError { usage, cycle };
             }
 
             current_job = job.parent.clone();
index 5cd06fb8a52c015c4418dbd3b0f87974407eda53..c9ffab21b786ccfadf3beb718767cb64a7dc87ff 100644 (file)
@@ -40,6 +40,7 @@
     CanonicalTypeOpSubtypeGoal, CanonicalTypeOpProvePredicateGoal,
     CanonicalTypeOpNormalizeGoal, NoSolution,
 };
+use traits::query::method_autoderef::MethodAutoderefStepsResult;
 use traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult};
 use traits::query::normalize::NormalizationResult;
 use traits::query::outlives_bounds::OutlivesBound;
 
         [] fn substitute_normalize_and_test_predicates:
             substitute_normalize_and_test_predicates_node((DefId, &'tcx Substs<'tcx>)) -> bool,
+
+        [] fn method_autoderef_steps: MethodAutoderefSteps(
+            CanonicalTyGoal<'tcx>
+        ) -> MethodAutoderefStepsResult<'tcx>,
     },
 
     Other {
@@ -705,21 +710,21 @@ pub fn try_adt_sized_constraint(
         self,
         span: Span,
         key: DefId,
-    ) -> Result<&'tcx [Ty<'tcx>], DiagnosticBuilder<'a>> {
+    ) -> Result<&'tcx [Ty<'tcx>], Box<DiagnosticBuilder<'a>>> {
         self.try_get_query::<queries::adt_sized_constraint<'_>>(span, key)
     }
     pub fn try_needs_drop_raw(
         self,
         span: Span,
         key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
-    ) -> Result<bool, DiagnosticBuilder<'a>> {
+    ) -> Result<bool, Box<DiagnosticBuilder<'a>>> {
         self.try_get_query::<queries::needs_drop_raw<'_>>(span, key)
     }
     pub fn try_optimized_mir(
         self,
         span: Span,
         key: DefId,
-    ) -> Result<&'tcx mir::Mir<'tcx>, DiagnosticBuilder<'a>> {
+    ) -> Result<&'tcx mir::Mir<'tcx>, Box<DiagnosticBuilder<'a>>> {
         self.try_get_query::<queries::optimized_mir<'_>>(span, key)
     }
 }
index 5f33d466c4a19f2d5a36ee5ce1feac849963d83c..a73b92ed713ecaf36649cecd9187e3814193a451 100644 (file)
@@ -153,8 +153,18 @@ pub(super) fn try_get(
             };
             mem::drop(lock);
 
-            if let Err(cycle) = job.await(tcx, span) {
-                return TryGetJob::JobCompleted(Err(cycle));
+            // If we are single-threaded we know that we have cycle error,
+            // so we just turn the errror
+            #[cfg(not(parallel_queries))]
+            return job.cycle_error(tcx, span);
+
+            // With parallel queries we might just have to wait on some other
+            // thread
+            #[cfg(parallel_queries)]
+            {
+                if let Err(cycle) = job.await(tcx, span) {
+                    return TryGetJob::JobCompleted(Err(cycle));
+                }
             }
         }
     }
@@ -197,7 +207,7 @@ pub(super) fn start<'lcx, F, R>(
         let r = tls::with_related_context(tcx, move |current_icx| {
             // Update the ImplicitCtxt to point to our new query job
             let new_icx = tls::ImplicitCtxt {
-                tcx,
+                tcx: tcx.global_tcx(),
                 query: Some(self.job.clone()),
                 layout_depth: current_icx.layout_depth,
                 task: current_icx.task,
@@ -241,12 +251,16 @@ pub(super) enum TryGetJob<'a, 'tcx: 'a, D: QueryDescription<'tcx> + 'a> {
     /// The query was already completed.
     /// Returns the result of the query and its dep node index
     /// if it succeeded or a cycle error if it failed
-    JobCompleted(Result<(D::Value, DepNodeIndex), CycleError<'tcx>>),
+    JobCompleted(Result<(D::Value, DepNodeIndex), Box<CycleError<'tcx>>>),
 }
 
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
-    pub(super) fn report_cycle(self, CycleError { usage, cycle: stack }: CycleError<'gcx>)
-        -> DiagnosticBuilder<'a>
+    #[inline(never)]
+    #[cold]
+    pub(super) fn report_cycle(
+        self,
+        box CycleError { usage, cycle: stack }: Box<CycleError<'gcx>>
+    ) -> Box<DiagnosticBuilder<'a>>
     {
         assert!(!stack.is_empty());
 
@@ -280,7 +294,7 @@ pub(super) fn report_cycle(self, CycleError { usage, cycle: stack }: CycleError<
                               &format!("cycle used when {}", query.describe(self)));
             }
 
-            return err
+            return Box::new(err)
         })
     }
 
@@ -345,11 +359,12 @@ pub(super) fn try_mark_green_and_read(self, dep_node: &DepNode) -> Option<DepNod
         }
     }
 
+    #[inline(never)]
     fn try_get_with<Q: QueryDescription<'gcx>>(
         self,
         span: Span,
         key: Q::Key)
-    -> Result<Q::Value, CycleError<'gcx>>
+    -> Result<Q::Value, Box<CycleError<'gcx>>>
     {
         debug!("ty::queries::{}::try_get_with(key={:?}, span={:?})",
                Q::NAME,
@@ -436,7 +451,7 @@ fn load_from_disk_and_cache_in_memory<Q: QueryDescription<'gcx>>(
         job: JobOwner<'a, 'gcx, Q>,
         dep_node_index: DepNodeIndex,
         dep_node: &DepNode
-    ) -> Result<Q::Value, CycleError<'gcx>>
+    ) -> Result<Q::Value, Box<CycleError<'gcx>>>
     {
         // Note this function can be called concurrently from the same query
         // We must ensure that this is handled correctly
@@ -522,7 +537,7 @@ fn force_query_with_job<Q: QueryDescription<'gcx>>(
         key: Q::Key,
         job: JobOwner<'_, 'gcx, Q>,
         dep_node: DepNode)
-    -> Result<(Q::Value, DepNodeIndex), CycleError<'gcx>> {
+    -> Result<(Q::Value, DepNodeIndex), Box<CycleError<'gcx>>> {
         // If the following assertion triggers, it can have two reasons:
         // 1. Something is wrong with DepNode creation, either here or
         //    in DepGraph::try_mark_green()
@@ -611,37 +626,55 @@ fn force_query<Q: QueryDescription<'gcx>>(
         key: Q::Key,
         span: Span,
         dep_node: DepNode
-    ) -> Result<(Q::Value, DepNodeIndex), CycleError<'gcx>> {
+    ) {
+        profq_msg!(
+            self,
+            ProfileQueriesMsg::QueryBegin(span.data(), profq_query_msg!(Q::NAME, self, key))
+        );
+
         // We may be concurrently trying both execute and force a query
         // Ensure that only one of them runs the query
         let job = match JobOwner::try_get(self, span, &key) {
             TryGetJob::NotYetStarted(job) => job,
-            TryGetJob::JobCompleted(result) => return result,
+            TryGetJob::JobCompleted(_) => return,
         };
-        self.force_query_with_job::<Q>(key, job, dep_node)
+        if let Err(e) = self.force_query_with_job::<Q>(key, job, dep_node) {
+            self.report_cycle(e).emit();
+        }
     }
 
     pub(super) fn try_get_query<Q: QueryDescription<'gcx>>(
         self,
         span: Span,
         key: Q::Key,
-    ) -> Result<Q::Value, DiagnosticBuilder<'a>> {
+    ) -> Result<Q::Value, Box<DiagnosticBuilder<'a>>> {
         match self.try_get_with::<Q>(span, key) {
             Ok(e) => Ok(e),
             Err(e) => Err(self.report_cycle(e)),
         }
     }
 
+    // FIXME: Try uninlining this
+    #[inline(always)]
     pub(super) fn get_query<Q: QueryDescription<'gcx>>(
         self,
         span: Span,
         key: Q::Key,
     ) -> Q::Value {
-        self.try_get_query::<Q>(span, key).unwrap_or_else(|mut e| {
-            e.emit();
-            Q::handle_cycle_error(self)
+        self.try_get_with::<Q>(span, key).unwrap_or_else(|e| {
+            self.emit_error::<Q>(e)
         })
     }
+
+    #[inline(never)]
+    #[cold]
+    fn emit_error<Q: QueryDescription<'gcx>>(
+        self,
+        e: Box<CycleError<'gcx>>,
+    ) -> Q::Value {
+        self.report_cycle(e).emit();
+        Q::handle_cycle_error(self)
+    }
 }
 
 macro_rules! handle_cycle_error {
@@ -806,15 +839,18 @@ pub fn $name<F: FnOnce() -> R, R>(f: F) -> R {
         }
 
         impl<$tcx> QueryAccessors<$tcx> for queries::$name<$tcx> {
+            #[inline(always)]
             fn query(key: Self::Key) -> Query<'tcx> {
                 Query::$name(key)
             }
 
+            #[inline(always)]
             fn query_cache<'a>(tcx: TyCtxt<'a, $tcx, '_>) -> &'a Lock<QueryCache<$tcx, Self>> {
                 &tcx.queries.$name
             }
 
             #[allow(unused)]
+            #[inline(always)]
             fn to_dep_node(tcx: TyCtxt<'_, $tcx, '_>, key: &Self::Key) -> DepNode {
                 use dep_graph::DepConstructor::*;
 
@@ -861,6 +897,7 @@ pub struct TyCtxtAt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
 
         impl<'a, 'gcx, 'tcx> Deref for TyCtxtAt<'a, 'gcx, 'tcx> {
             type Target = TyCtxt<'a, 'gcx, 'tcx>;
+            #[inline(always)]
             fn deref(&self) -> &Self::Target {
                 &self.tcx
             }
@@ -869,6 +906,7 @@ fn deref(&self) -> &Self::Target {
         impl<'a, $tcx, 'lcx> TyCtxt<'a, $tcx, 'lcx> {
             /// Return a transparent wrapper for `TyCtxt` which uses
             /// `span` as the location of queries performed through it.
+            #[inline(always)]
             pub fn at(self, span: Span) -> TyCtxtAt<'a, $tcx, 'lcx> {
                 TyCtxtAt {
                     tcx: self,
@@ -877,6 +915,7 @@ pub fn at(self, span: Span) -> TyCtxtAt<'a, $tcx, 'lcx> {
             }
 
             $($(#[$attr])*
+            #[inline(always)]
             pub fn $name(self, key: $K) -> $V {
                 self.at(DUMMY_SP).$name(key)
             })*
@@ -884,6 +923,7 @@ pub fn $name(self, key: $K) -> $V {
 
         impl<'a, $tcx, 'lcx> TyCtxtAt<'a, $tcx, 'lcx> {
             $($(#[$attr])*
+            #[inline(always)]
             pub fn $name(self, key: $K) -> $V {
                 self.tcx.get_query::<queries::$name<'_>>(self.span, key)
             })*
@@ -1023,20 +1063,7 @@ macro_rules! krate {
     macro_rules! force {
         ($query:ident, $key:expr) => {
             {
-                use $crate::util::common::{ProfileQueriesMsg, profq_msg};
-
-                profq_msg!(tcx,
-                    ProfileQueriesMsg::QueryBegin(
-                        DUMMY_SP.data(),
-                        profq_query_msg!(::ty::query::queries::$query::NAME, tcx, $key),
-                    )
-                );
-
-                if let Err(e) = tcx.force_query::<::ty::query::queries::$query<'_>>(
-                    $key, DUMMY_SP, *dep_node
-                ) {
-                    tcx.report_cycle(e).emit();
-                }
+                tcx.force_query::<::ty::query::queries::$query<'_>>($key, DUMMY_SP, *dep_node);
             }
         }
     };
@@ -1089,6 +1116,7 @@ macro_rules! force {
         DepKind::TypeOpNormalizePolyFnSig |
         DepKind::TypeOpNormalizeFnSig |
         DepKind::SubstituteNormalizeAndTestPredicates |
+        DepKind::MethodAutoderefSteps |
         DepKind::InstanceDefSizeEstimate |
         DepKind::ProgramClausesForEnv |
 
index f757f48e987d8233f66f3fe152f232a1f528ee36..2189267cb0b05e130438fb1feaa9ce2e8febe713 100644 (file)
@@ -1543,6 +1543,51 @@ pub fn is_never(&self) -> bool {
         }
     }
 
+    /// Checks whether a type is definitely uninhabited. This is
+    /// conservative: for some types that are uninhabited we return `false`,
+    /// but we only return `true` for types that are definitely uninhabited.
+    /// `ty.conservative_is_privately_uninhabited` implies that any value of type `ty`
+    /// will be `Abi::Uninhabited`. (Note that uninhabited types may have nonzero
+    /// size, to account for partial initialisation. See #49298 for details.)
+    pub fn conservative_is_privately_uninhabited(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> bool {
+        // FIXME(varkor): we can make this less conversative by substituting concrete
+        // type arguments.
+        match self.sty {
+            ty::Never => true,
+            ty::Adt(def, _) if def.is_union() => {
+                // For now, `union`s are never considered uninhabited.
+                false
+            }
+            ty::Adt(def, _) => {
+                // Any ADT is uninhabited if either:
+                // (a) It has no variants (i.e. an empty `enum`);
+                // (b) Each of its variants (a single one in the case of a `struct`) has at least
+                //     one uninhabited field.
+                def.variants.iter().all(|var| {
+                    var.fields.iter().any(|field| {
+                        tcx.type_of(field.did).conservative_is_privately_uninhabited(tcx)
+                    })
+                })
+            }
+            ty::Tuple(tys) => tys.iter().any(|ty| ty.conservative_is_privately_uninhabited(tcx)),
+            ty::Array(ty, len) => {
+                match len.assert_usize(tcx) {
+                    // If the array is definitely non-empty, it's uninhabited if
+                    // the type of its elements is uninhabited.
+                    Some(n) if n != 0 => ty.conservative_is_privately_uninhabited(tcx),
+                    _ => false
+                }
+            }
+            ty::Ref(..) => {
+                // References to uninitialised memory is valid for any type, including
+                // uninhabited types, in unsafe code, so we treat all references as
+                // inhabited.
+                false
+            }
+            _ => false,
+        }
+    }
+
     pub fn is_primitive(&self) -> bool {
         match self.sty {
             Bool | Char | Int(_) | Uint(_) | Float(_) => true,
index 568a7e7e1600f3fe3a3019c11e366f7d66eb8a0d..80539b78c7073c9e75364e7b43a6552fd399ab33 100644 (file)
@@ -106,7 +106,6 @@ pub fn codegen_statement(
             }
             mir::StatementKind::FakeRead(..) |
             mir::StatementKind::Retag { .. } |
-            mir::StatementKind::EscapeToRaw { .. } |
             mir::StatementKind::AscribeUserType(..) |
             mir::StatementKind::Nop => bx,
         }
index aa9ddda2b9364e424c580418ffa3dc3e6e5a2ccc..f8638213b3a2f7cbc456b53301531aa7975f2be2 100644 (file)
@@ -86,6 +86,7 @@ fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
 }
 
 impl stable_hasher::StableHasherResult for Fingerprint {
+    #[inline]
     fn finish(hasher: stable_hasher::StableHasher<Self>) -> Self {
         let (_0, _1) = hasher.finalize();
         Fingerprint(_0, _1)
index 8e0ecb70c689637b34181e2531de90e5eaa47d55..bc2b8f1d6523e20496a762c51243304cd513a61c 100644 (file)
@@ -30,6 +30,8 @@
 #![feature(allow_internal_unstable)]
 #![feature(vec_resize_with)]
 #![feature(hash_raw_entry)]
+#![feature(stmt_expr_attributes)]
+#![feature(core_intrinsics)]
 
 #![cfg_attr(unix, feature(libc))]
 #![cfg_attr(test, feature(test))]
 
 pub use rustc_serialize::hex::ToHex;
 
+#[macro_export]
+macro_rules! likely {
+      ($e:expr) => {
+            #[allow(unused_unsafe)]
+            {
+                  unsafe { std::intrinsics::likely($e) }
+            }
+      }
+}
+
+#[macro_export]
+macro_rules! unlikely {
+    ($e:expr) => {
+            #[allow(unused_unsafe)]
+            {
+                  unsafe { std::intrinsics::unlikely($e) }
+            }
+      }
+}
+
 pub mod macros;
 pub mod svh;
 pub mod base_n;
index 8757c9ff15da6eb23c3fbd8dd86f81074b0854b8..55e052882ea5b6178356874ce54e693f2e85b77f 100644 (file)
@@ -246,8 +246,6 @@ macro_rules! controller_entry_point {
             }
         }
 
-        let arenas = AllArenas::new();
-
         // Construct the HIR map
         let hir_map = time(sess, "indexing hir", || {
             hir_map::map_crate(sess, cstore, &mut hir_forest, &defs)
@@ -263,7 +261,6 @@ macro_rules! controller_entry_point {
                     sess,
                     outdir,
                     output,
-                    &arenas,
                     &cstore,
                     &hir_map,
                     &analysis,
@@ -284,6 +281,8 @@ macro_rules! controller_entry_point {
             None
         };
 
+        let mut arenas = AllArenas::new();
+
         phase_3_run_analysis_passes(
             &*codegen_backend,
             control,
@@ -292,7 +291,7 @@ macro_rules! controller_entry_point {
             hir_map,
             analysis,
             resolutions,
-            &arenas,
+            &mut arenas,
             &crate_name,
             &outputs,
             |tcx, analysis, rx, result| {
@@ -533,7 +532,6 @@ pub struct CompileState<'a, 'tcx: 'a> {
     pub output_filenames: Option<&'a OutputFilenames>,
     pub out_dir: Option<&'a Path>,
     pub out_file: Option<&'a Path>,
-    pub arenas: Option<&'tcx AllArenas<'tcx>>,
     pub expanded_crate: Option<&'a ast::Crate>,
     pub hir_crate: Option<&'a hir::Crate>,
     pub hir_map: Option<&'a hir_map::Map<'tcx>>,
@@ -549,7 +547,6 @@ fn empty(input: &'a Input, session: &'tcx Session, out_dir: &'a Option<PathBuf>)
             session,
             out_dir: out_dir.as_ref().map(|s| &**s),
             out_file: None,
-            arenas: None,
             krate: None,
             registry: None,
             cstore: None,
@@ -605,7 +602,6 @@ fn state_after_hir_lowering(
         session: &'tcx Session,
         out_dir: &'a Option<PathBuf>,
         out_file: &'a Option<PathBuf>,
-        arenas: &'tcx AllArenas<'tcx>,
         cstore: &'tcx CStore,
         hir_map: &'a hir_map::Map<'tcx>,
         analysis: &'a ty::CrateAnalysis,
@@ -617,7 +613,6 @@ fn state_after_hir_lowering(
     ) -> Self {
         CompileState {
             crate_name: Some(crate_name),
-            arenas: Some(arenas),
             cstore: Some(cstore),
             hir_map: Some(hir_map),
             analysis: Some(analysis),
@@ -1216,7 +1211,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(
     hir_map: hir_map::Map<'tcx>,
     mut analysis: ty::CrateAnalysis,
     resolutions: Resolutions,
-    arenas: &'tcx AllArenas<'tcx>,
+    arenas: &'tcx mut AllArenas<'tcx>,
     name: &str,
     output_filenames: &OutputFilenames,
     f: F,
index 41c9b22afe06f968aaf489cf13e050db403db58d..5527c0ad387874a62379cf2f92352b9f0703ddc8 100644 (file)
@@ -25,7 +25,6 @@
 #![feature(rustc_diagnostic_macros)]
 #![feature(slice_sort_by_cached_key)]
 #![feature(set_stdio)]
-#![feature(rustc_stack_internals)]
 #![feature(no_debug)]
 
 #![recursion_limit="256"]
@@ -911,7 +910,6 @@ fn build_controller(self: Box<Self>,
                                                      &state.expanded_crate.take().unwrap(),
                                                      state.crate_name.unwrap(),
                                                      ppm,
-                                                     state.arenas.unwrap(),
                                                      state.output_filenames.unwrap(),
                                                      opt_uii.clone(),
                                                      state.out_file);
@@ -1482,69 +1480,13 @@ pub fn in_named_rustc_thread<F, R>(name: String, f: F) -> Result<R, Box<dyn Any
     where F: FnOnce() -> R + Send + 'static,
           R: Send + 'static,
 {
-    #[cfg(all(unix, not(target_os = "haiku")))]
-    let spawn_thread = unsafe {
-        // Fetch the current resource limits
-        let mut rlim = libc::rlimit {
-            rlim_cur: 0,
-            rlim_max: 0,
-        };
-        if libc::getrlimit(libc::RLIMIT_STACK, &mut rlim) != 0 {
-            let err = io::Error::last_os_error();
-            error!("in_rustc_thread: error calling getrlimit: {}", err);
-            true
-        } else if rlim.rlim_max < STACK_SIZE as libc::rlim_t {
-            true
-        } else if rlim.rlim_cur < STACK_SIZE as libc::rlim_t {
-            std::rt::deinit_stack_guard();
-            rlim.rlim_cur = STACK_SIZE as libc::rlim_t;
-            if libc::setrlimit(libc::RLIMIT_STACK, &mut rlim) != 0 {
-                let err = io::Error::last_os_error();
-                error!("in_rustc_thread: error calling setrlimit: {}", err);
-                std::rt::update_stack_guard();
-                true
-            } else {
-                std::rt::update_stack_guard();
-                false
-            }
-        } else {
-            false
-        }
-    };
-
-    // We set the stack size at link time. See src/rustc/rustc.rs.
-    #[cfg(windows)]
-    let spawn_thread = false;
-
-    #[cfg(target_os = "haiku")]
-    let spawn_thread = unsafe {
-        // Haiku does not have setrlimit implemented for the stack size.
-        // By default it does have the 16 MB stack limit, but we check this in
-        // case the minimum STACK_SIZE changes or Haiku's defaults change.
-        let mut rlim = libc::rlimit {
-            rlim_cur: 0,
-            rlim_max: 0,
-        };
-        if libc::getrlimit(libc::RLIMIT_STACK, &mut rlim) != 0 {
-            let err = io::Error::last_os_error();
-            error!("in_rustc_thread: error calling getrlimit: {}", err);
-            true
-        } else if rlim.rlim_cur >= STACK_SIZE {
-            false
-        } else {
-            true
-        }
-    };
-
-    #[cfg(not(any(windows, unix)))]
-    let spawn_thread = true;
-
-    // The or condition is added from backward compatibility.
-    if spawn_thread || env::var_os("RUST_MIN_STACK").is_some() {
+    // We need a thread for soundness of thread local storage in rustc. For debugging purposes
+    // we allow an escape hatch where everything runs on the main thread.
+    if env::var_os("RUSTC_UNSTABLE_NO_MAIN_THREAD").is_none() {
         let mut cfg = thread::Builder::new().name(name);
 
-        // FIXME: Hacks on hacks. If the env is trying to override the stack size
-        // then *don't* set it explicitly.
+        // If the env is trying to override the stack size then *don't* set it explicitly.
+        // The libstd thread impl will fetch the `RUST_MIN_STACK` env var itself.
         if env::var_os("RUST_MIN_STACK").is_none() {
             cfg = cfg.stack_size(STACK_SIZE);
         }
index b41b0d081ced978b8368c9c4be0bf0b3c61617dd..bc991016bbee5ddf9ff84f0f8df745890bba25dd 100644 (file)
@@ -202,7 +202,6 @@ fn call_with_pp_support_hir<'tcx, A, F>(
         hir_map: &hir_map::Map<'tcx>,
         analysis: &ty::CrateAnalysis,
         resolutions: &Resolutions,
-        arenas: &'tcx AllArenas<'tcx>,
         output_filenames: &OutputFilenames,
         id: &str,
         f: F
@@ -228,6 +227,7 @@ fn call_with_pp_support_hir<'tcx, A, F>(
             PpmTyped => {
                 let control = &driver::CompileController::basic();
                 let codegen_backend = ::get_codegen_backend(sess);
+                let mut arenas = AllArenas::new();
                 abort_on_err(driver::phase_3_run_analysis_passes(&*codegen_backend,
                                                                  control,
                                                                  sess,
@@ -235,7 +235,7 @@ fn call_with_pp_support_hir<'tcx, A, F>(
                                                                  hir_map.clone(),
                                                                  analysis.clone(),
                                                                  resolutions.clone(),
-                                                                 arenas,
+                                                                 &mut arenas,
                                                                  id,
                                                                  output_filenames,
                                                                  |tcx, _, _, _| {
@@ -977,7 +977,6 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
                                                 krate: &ast::Crate,
                                                 crate_name: &str,
                                                 ppm: PpMode,
-                                                arenas: &'tcx AllArenas<'tcx>,
                                                 output_filenames: &OutputFilenames,
                                                 opt_uii: Option<UserIdentifiedItem>,
                                                 ofile: Option<&Path>) {
@@ -988,7 +987,6 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
                             analysis,
                             resolutions,
                             crate_name,
-                            arenas,
                             output_filenames,
                             ppm,
                             opt_uii,
@@ -1026,7 +1024,6 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
                                            hir_map,
                                            analysis,
                                            resolutions,
-                                           arenas,
                                            output_filenames,
                                            crate_name,
                                            move |annotation, krate| {
@@ -1050,7 +1047,6 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
                                            hir_map,
                                            analysis,
                                            resolutions,
-                                           arenas,
                                            output_filenames,
                                            crate_name,
                                            move |_annotation, krate| {
@@ -1066,7 +1062,6 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
                                            hir_map,
                                            analysis,
                                            resolutions,
-                                           arenas,
                                            output_filenames,
                                            crate_name,
                                            move |annotation, _| {
@@ -1100,7 +1095,6 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
                                            hir_map,
                                            analysis,
                                            resolutions,
-                                           arenas,
                                            output_filenames,
                                            crate_name,
                                            move |_annotation, _krate| {
@@ -1130,7 +1124,6 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session,
                                        analysis: &ty::CrateAnalysis,
                                        resolutions: &Resolutions,
                                        crate_name: &str,
-                                       arenas: &'tcx AllArenas<'tcx>,
                                        output_filenames: &OutputFilenames,
                                        ppm: PpMode,
                                        uii: Option<UserIdentifiedItem>,
@@ -1147,6 +1140,7 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session,
 
     let control = &driver::CompileController::basic();
     let codegen_backend = ::get_codegen_backend(sess);
+    let mut arenas = AllArenas::new();
     abort_on_err(driver::phase_3_run_analysis_passes(&*codegen_backend,
                                                      control,
                                                      sess,
@@ -1154,7 +1148,7 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session,
                                                      hir_map.clone(),
                                                      analysis.clone(),
                                                      resolutions.clone(),
-                                                     arenas,
+                                                     &mut arenas,
                                                      crate_name,
                                                      output_filenames,
                                                      |tcx, _, _, _| {
index f9d49f03ee044ff2ed31e6f6814c9b639e3e6954..5b337fbf5bef39a248e50b48d0bbb773803330bb 100644 (file)
@@ -151,7 +151,7 @@ fn test_env_with_pool<F>(
         ).expect("phase 2 aborted")
     };
 
-    let arenas = ty::AllArenas::new();
+    let mut arenas = ty::AllArenas::new();
     let hir_map = hir_map::map_crate(&sess, &cstore, &mut hir_forest, &defs);
 
     // Run just enough stuff to build a tcx.
@@ -168,7 +168,7 @@ fn test_env_with_pool<F>(
         &cstore,
         ty::query::Providers::default(),
         ty::query::Providers::default(),
-        &arenas,
+        &mut arenas,
         resolutions,
         hir_map,
         OnDiskCache::new_empty(sess.source_map()),
index 16bb1ef78dc6f85c2000609280aa2f35b8e1e966..8a58cb056807446cfa61fdfae0b3892722d22470 100644 (file)
@@ -33,9 +33,9 @@
 
 // (forced to be `pub` due to its use as an associated type below.)
 crate struct Flows<'b, 'gcx: 'tcx, 'tcx: 'b> {
-    borrows: FlowAtLocation<Borrows<'b, 'gcx, 'tcx>>,
-    pub uninits: FlowAtLocation<MaybeUninitializedPlaces<'b, 'gcx, 'tcx>>,
-    pub ever_inits: FlowAtLocation<EverInitializedPlaces<'b, 'gcx, 'tcx>>,
+    borrows: FlowAtLocation<'tcx, Borrows<'b, 'gcx, 'tcx>>,
+    pub uninits: FlowAtLocation<'tcx, MaybeUninitializedPlaces<'b, 'gcx, 'tcx>>,
+    pub ever_inits: FlowAtLocation<'tcx, EverInitializedPlaces<'b, 'gcx, 'tcx>>,
 
     /// Polonius Output
     pub polonius_output: Option<Rc<Output<RegionVid, BorrowIndex, LocationIndex>>>,
@@ -43,9 +43,9 @@
 
 impl<'b, 'gcx, 'tcx> Flows<'b, 'gcx, 'tcx> {
     crate fn new(
-        borrows: FlowAtLocation<Borrows<'b, 'gcx, 'tcx>>,
-        uninits: FlowAtLocation<MaybeUninitializedPlaces<'b, 'gcx, 'tcx>>,
-        ever_inits: FlowAtLocation<EverInitializedPlaces<'b, 'gcx, 'tcx>>,
+        borrows: FlowAtLocation<'tcx, Borrows<'b, 'gcx, 'tcx>>,
+        uninits: FlowAtLocation<'tcx, MaybeUninitializedPlaces<'b, 'gcx, 'tcx>>,
+        ever_inits: FlowAtLocation<'tcx, EverInitializedPlaces<'b, 'gcx, 'tcx>>,
         polonius_output: Option<Rc<Output<RegionVid, BorrowIndex, LocationIndex>>>,
     ) -> Self {
         Flows {
index 5eca62938f7a8c821cbe68b18930779f7c770b12..99cc4acb5197b32fa608709dc0ff958509f37b79 100644 (file)
@@ -63,7 +63,7 @@
 mod mutability_errors;
 mod path_utils;
 crate mod place_ext;
-mod places_conflict;
+crate mod places_conflict;
 mod prefixes;
 mod used_muts;
 
@@ -590,7 +590,6 @@ fn visit_statement_entry(
             StatementKind::Nop
             | StatementKind::AscribeUserType(..)
             | StatementKind::Retag { .. }
-            | StatementKind::EscapeToRaw { .. }
             | StatementKind::StorageLive(..) => {
                 // `Nop`, `AscribeUserType`, `Retag`, and `StorageLive` are irrelevant
                 // to borrow check.
@@ -1369,7 +1368,8 @@ fn check_for_invalidation_at_exit(
             place,
             borrow.kind,
             root_place,
-            sd
+            sd,
+            places_conflict::PlaceConflictBias::Overlap,
         ) {
             debug!("check_for_invalidation_at_exit({:?}): INVALID", place);
             // FIXME: should be talking about the region lifetime instead
index 07bda8af62618a6191df91d1533277641add6939..d2810de284a894b6b122356903bf87e7a9725a57 100644 (file)
@@ -135,7 +135,6 @@ fn visit_statement(&mut self,
             StatementKind::Nop |
             StatementKind::AscribeUserType(..) |
             StatementKind::Retag { .. } |
-            StatementKind::EscapeToRaw { .. } |
             StatementKind::StorageLive(..) => {
                 // `Nop`, `AscribeUserType`, `Retag`, and `StorageLive` are irrelevant
                 // to borrow check.
index cd4694351ad0eef51843a7b9213858be4c679db1..1e3a27c8fe5b99ede0ace1899e9628e9237e2b28 100644 (file)
@@ -85,7 +85,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
     mir: &Mir<'tcx>,
     location_table: &LocationTable,
     param_env: ty::ParamEnv<'gcx>,
-    flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'cx, 'gcx, 'tcx>>,
+    flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'cx, 'gcx, 'tcx>>,
     move_data: &MoveData<'tcx>,
     borrow_set: &BorrowSet<'tcx>,
     errors_buffer: &mut Vec<Diagnostic>,
index 9ccdc84db156186a27553fffdb7a15786fcea355..7b216d8e587ccd185d983fa3a72f01c02d6be59f 100644 (file)
@@ -39,7 +39,7 @@ pub(super) fn generate<'gcx, 'tcx>(
     typeck: &mut TypeChecker<'_, 'gcx, 'tcx>,
     mir: &Mir<'tcx>,
     elements: &Rc<RegionValueElements>,
-    flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
+    flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
     move_data: &MoveData<'tcx>,
     location_table: &LocationTable,
 ) {
index bc4e0ca235139c63ab7e5aa54623982a8407ec5d..1fbde2ae59dee5fb794060a414f3b821b9a07985 100644 (file)
@@ -46,7 +46,7 @@ pub(super) fn trace(
     typeck: &mut TypeChecker<'_, 'gcx, 'tcx>,
     mir: &Mir<'tcx>,
     elements: &Rc<RegionValueElements>,
-    flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
+    flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
     move_data: &MoveData<'tcx>,
     liveness_map: &NllLivenessMap,
     location_table: &LocationTable,
@@ -99,7 +99,7 @@ struct LivenessContext<'me, 'typeck, 'flow, 'gcx, 'tcx>
 
     /// Results of dataflow tracking which variables (and paths) have been
     /// initialized.
-    flow_inits: &'me mut FlowAtLocation<MaybeInitializedPlaces<'flow, 'gcx, 'tcx>>,
+    flow_inits: &'me mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'flow, 'gcx, 'tcx>>,
 
     /// Index indicating where each variable is assigned, used, or
     /// dropped.
index 4807abe2bdd19c08dbedbb476ad9b884c2e3311c..d205e4da798c4adb4b6256efd1c0dc979e9129c9 100644 (file)
@@ -123,7 +123,7 @@ pub(crate) fn type_check<'gcx, 'tcx>(
     location_table: &LocationTable,
     borrow_set: &BorrowSet<'tcx>,
     all_facts: &mut Option<AllFacts>,
-    flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
+    flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
     move_data: &MoveData<'tcx>,
     elements: &Rc<RegionValueElements>,
 ) -> MirTypeckResults<'tcx> {
@@ -1316,7 +1316,6 @@ fn check_stmt(&mut self, mir: &Mir<'tcx>, stmt: &Statement<'tcx>, location: Loca
             | StatementKind::StorageDead(..)
             | StatementKind::InlineAsm { .. }
             | StatementKind::Retag { .. }
-            | StatementKind::EscapeToRaw { .. }
             | StatementKind::Nop => {}
         }
     }
@@ -1546,8 +1545,7 @@ fn check_call_dest(
                 }
             }
             None => {
-                // FIXME(canndrew): This is_never should probably be an is_uninhabited
-                if !sig.output().is_never() {
+                if !sig.output().conservative_is_privately_uninhabited(self.tcx()) {
                     span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
                 }
             }
index 9250c04969f989eeb94b76883cdc0762ef70b130..5e17afc3d3cdc94dc1c299d83be2efc27e4a70dd 100644 (file)
@@ -68,6 +68,7 @@ pub(super) fn each_borrow_involving_path<'a, 'tcx, 'gcx: 'tcx, F, I, S> (
             borrowed.kind,
             place,
             access,
+            places_conflict::PlaceConflictBias::Overlap,
         ) {
             debug!(
                 "each_borrow_involving_path: {:?} @ {:?} vs. {:?}/{:?}",
index e24586cca0929ba372e8e084253a839f6e3b4c13..7ebd69c63abf57a6ef85bf1fe76b403d05936206 100644 (file)
 use rustc::ty::{self, TyCtxt};
 use std::cmp::max;
 
+/// When checking if a place conflicts with another place, this enum is used to influence decisions
+/// where a place might be equal or disjoint with another place, such as if `a[i] == a[j]`.
+/// `PlaceConflictBias::Overlap` would bias toward assuming that `i` might equal `j` and that these
+/// places overlap. `PlaceConflictBias::NoOverlap` assumes that for the purposes of the predicate
+/// being run in the calling context, the conservative choice is to assume the compared indices
+/// are disjoint (and therefore, do not overlap).
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+crate enum PlaceConflictBias {
+    Overlap,
+    NoOverlap,
+}
+
+/// Helper function for checking if places conflict with a mutable borrow and deep access depth.
+/// This is used to check for places conflicting outside of the borrow checking code (such as in
+/// dataflow).
+crate fn places_conflict<'gcx, 'tcx>(
+    tcx: TyCtxt<'_, 'gcx, 'tcx>,
+    mir: &Mir<'tcx>,
+    borrow_place: &Place<'tcx>,
+    access_place: &Place<'tcx>,
+    bias: PlaceConflictBias,
+) -> bool {
+    borrow_conflicts_with_place(
+        tcx,
+        mir,
+        borrow_place,
+        BorrowKind::Mut { allow_two_phase_borrow: true },
+        access_place,
+        AccessDepth::Deep,
+        bias,
+    )
+}
+
+/// Checks whether the `borrow_place` conflicts with the `access_place` given a borrow kind and
+/// access depth. The `bias` parameter is used to determine how the unknowable (comparing runtime
+/// array indices, for example) should be interpreted - this depends on what the caller wants in
+/// order to make the conservative choice and preserve soundness.
 pub(super) fn borrow_conflicts_with_place<'gcx, 'tcx>(
     tcx: TyCtxt<'_, 'gcx, 'tcx>,
     mir: &Mir<'tcx>,
@@ -24,10 +61,11 @@ pub(super) fn borrow_conflicts_with_place<'gcx, 'tcx>(
     borrow_kind: BorrowKind,
     access_place: &Place<'tcx>,
     access: AccessDepth,
+    bias: PlaceConflictBias,
 ) -> bool {
     debug!(
-        "borrow_conflicts_with_place({:?},{:?},{:?})",
-        borrow_place, access_place, access
+        "borrow_conflicts_with_place({:?}, {:?}, {:?}, {:?})",
+        borrow_place, access_place, access, bias,
     );
 
     // This Local/Local case is handled by the more general code below, but
@@ -46,7 +84,8 @@ pub(super) fn borrow_conflicts_with_place<'gcx, 'tcx>(
                 borrow_components,
                 borrow_kind,
                 access_components,
-                access
+                access,
+                bias,
             )
         })
     })
@@ -59,6 +98,7 @@ fn place_components_conflict<'gcx, 'tcx>(
     borrow_kind: BorrowKind,
     mut access_components: PlaceComponentsIter<'_, 'tcx>,
     access: AccessDepth,
+    bias: PlaceConflictBias,
 ) -> bool {
     // The borrowck rules for proving disjointness are applied from the "root" of the
     // borrow forwards, iterating over "similar" projections in lockstep until
@@ -121,7 +161,7 @@ fn place_components_conflict<'gcx, 'tcx>(
                 // check whether the components being borrowed vs
                 // accessed are disjoint (as in the second example,
                 // but not the first).
-                match place_element_conflict(tcx, mir, borrow_c, access_c) {
+                match place_element_conflict(tcx, mir, borrow_c, access_c, bias) {
                     Overlap::Arbitrary => {
                         // We have encountered different fields of potentially
                         // the same union - the borrow now partially overlaps.
@@ -190,7 +230,7 @@ fn place_components_conflict<'gcx, 'tcx>(
                         bug!("Tracking borrow behind shared reference.");
                     }
                     (ProjectionElem::Deref, ty::Ref(_, _, hir::MutMutable), AccessDepth::Drop) => {
-                        // Values behind a mutatble reference are not access either by Dropping a
+                        // Values behind a mutable reference are not access either by dropping a
                         // value, or by StorageDead
                         debug!("borrow_conflicts_with_place: drop access behind ptr");
                         return false;
@@ -328,6 +368,7 @@ fn place_element_conflict<'a, 'gcx: 'tcx, 'tcx>(
     mir: &Mir<'tcx>,
     elem1: &Place<'tcx>,
     elem2: &Place<'tcx>,
+    bias: PlaceConflictBias,
 ) -> Overlap {
     match (elem1, elem2) {
         (Place::Local(l1), Place::Local(l2)) => {
@@ -445,10 +486,20 @@ fn place_element_conflict<'a, 'gcx: 'tcx, 'tcx>(
                 | (ProjectionElem::ConstantIndex { .. }, ProjectionElem::Index(..))
                 | (ProjectionElem::Subslice { .. }, ProjectionElem::Index(..)) => {
                     // Array indexes (`a[0]` vs. `a[i]`). These can either be disjoint
-                    // (if the indexes differ) or equal (if they are the same), so this
-                    // is the recursive case that gives "equal *or* disjoint" its meaning.
-                    debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-INDEX");
-                    Overlap::EqualOrDisjoint
+                    // (if the indexes differ) or equal (if they are the same).
+                    match bias {
+                        PlaceConflictBias::Overlap => {
+                            // If we are biased towards overlapping, then this is the recursive
+                            // case that gives "equal *or* disjoint" its meaning.
+                            debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-INDEX");
+                            Overlap::EqualOrDisjoint
+                        }
+                        PlaceConflictBias::NoOverlap => {
+                            // If we are biased towards no overlapping, then this is disjoint.
+                            debug!("place_element_conflict: DISJOINT-ARRAY-INDEX");
+                            Overlap::Disjoint
+                        }
+                    }
                 }
                 (ProjectionElem::ConstantIndex { offset: o1, min_length: _, from_end: false },
                     ProjectionElem::ConstantIndex { offset: o2, min_length: _, from_end: false })
index 0e7305e076edeb3f39f3de319b5b8c3787aaa99d..146bf538306561f1859aa24a579d37e501642b14 100644 (file)
@@ -275,8 +275,6 @@ pub fn into_expr(
                 exit_block.unit()
             }
             ExprKind::Call { ty, fun, args, from_hir_call } => {
-                // FIXME(canndrew): This is_never should probably be an is_uninhabited
-                let diverges = expr.ty.is_never();
                 let intrinsic = match ty.sty {
                     ty::FnDef(def_id, _) => {
                         let f = ty.fn_sig(this.hir.tcx());
@@ -332,7 +330,10 @@ pub fn into_expr(
                             func: fun,
                             args,
                             cleanup: Some(cleanup),
-                            destination: if diverges {
+                            // FIXME(varkor): replace this with an uninhabitedness-based check.
+                            // This requires getting access to the current module to call
+                            // `tcx.is_ty_uninhabited_from`, which is currently tricky to do.
+                            destination: if expr.ty.is_never() {
                                 None
                             } else {
                                 Some((destination.clone(), success))
@@ -421,8 +422,7 @@ pub fn into_expr(
                 });
 
                 let rvalue = unpack!(block = this.as_local_rvalue(block, expr));
-                this.cfg
-                    .push_assign(block, source_info, destination, rvalue);
+                this.cfg.push_assign(block, source_info, destination, rvalue);
                 block.unit()
             }
         };
index 248c5d2db491748426dc7cedc48c3cc7e3c806cc..d5bc83aba7b990d7298833cb35ea6fd8c3bc806a 100644 (file)
@@ -692,12 +692,16 @@ pub fn const_eval_raw_provider<'a, 'tcx>(
         let err = error_to_const_error(&ecx, error);
         // errors in statics are always emitted as fatal errors
         if tcx.is_static(def_id).is_some() {
-            let err = err.report_as_error(ecx.tcx, "could not evaluate static initializer");
-            // check that a static never produces `TooGeneric`
+            let reported_err = err.report_as_error(ecx.tcx,
+                                                   "could not evaluate static initializer");
+            // Ensure that if the above error was either `TooGeneric` or `Reported`
+            // an error must be reported.
             if tcx.sess.err_count() == 0 {
-                span_bug!(ecx.tcx.span, "static eval failure didn't emit an error: {:#?}", err);
+                tcx.sess.delay_span_bug(err.span,
+                                        &format!("static eval failure did not emit an error: {:#?}",
+                                                 reported_err));
             }
-            err
+            reported_err
         } else if def_id.is_local() {
             // constant defined in this crate, we can figure out a lint level!
             match tcx.describe_def(def_id) {
index 52eae5815287425f4f882ed0bbf99ee7bfeb929b..69f6fbb6c80774580a8bb253b72f680d2e371f6a 100644 (file)
@@ -70,19 +70,19 @@ pub trait FlowsAtLocation {
 /// (e.g., via `reconstruct_statement_effect` and
 /// `reconstruct_terminator_effect`; don't forget to call
 /// `apply_local_effect`).
-pub struct FlowAtLocation<BD>
+pub struct FlowAtLocation<'tcx, BD>
 where
-    BD: BitDenotation,
+    BD: BitDenotation<'tcx>,
 {
-    base_results: DataflowResults<BD>,
+    base_results: DataflowResults<'tcx, BD>,
     curr_state: BitSet<BD::Idx>,
     stmt_gen: HybridBitSet<BD::Idx>,
     stmt_kill: HybridBitSet<BD::Idx>,
 }
 
-impl<BD> FlowAtLocation<BD>
+impl<'tcx, BD> FlowAtLocation<'tcx, BD>
 where
-    BD: BitDenotation,
+    BD: BitDenotation<'tcx>,
 {
     /// Iterate over each bit set in the current state.
     pub fn each_state_bit<F>(&self, f: F)
@@ -102,7 +102,7 @@ pub fn each_gen_bit<F>(&self, f: F)
         self.stmt_gen.iter().for_each(f)
     }
 
-    pub fn new(results: DataflowResults<BD>) -> Self {
+    pub fn new(results: DataflowResults<'tcx, BD>) -> Self {
         let bits_per_block = results.sets().bits_per_block();
         let curr_state = BitSet::new_empty(bits_per_block);
         let stmt_gen = HybridBitSet::new_empty(bits_per_block);
@@ -143,8 +143,8 @@ pub fn with_iter_outgoing<F>(&self, f: F)
     }
 }
 
-impl<BD> FlowsAtLocation for FlowAtLocation<BD>
-    where BD: BitDenotation
+impl<'tcx, BD> FlowsAtLocation for FlowAtLocation<'tcx, BD>
+    where BD: BitDenotation<'tcx>
 {
     fn reset_to_entry_of(&mut self, bb: BasicBlock) {
         self.curr_state.overwrite(self.base_results.sets().on_entry_set_for(bb.index()));
@@ -213,9 +213,9 @@ fn apply_local_effect(&mut self, _loc: Location) {
 }
 
 
-impl<'tcx, T> FlowAtLocation<T>
+impl<'tcx, T> FlowAtLocation<'tcx, T>
 where
-    T: HasMoveData<'tcx> + BitDenotation<Idx = MovePathIndex>,
+    T: HasMoveData<'tcx> + BitDenotation<'tcx, Idx = MovePathIndex>,
 {
     pub fn has_any_child_of(&self, mpi: T::Idx) -> Option<T::Idx> {
         // We process `mpi` before the loop below, for two reasons:
index f6a9d46b5e2cbe2ace966bc2debde39f5f19a8d2..45d59b5fb9df12a2dc509e308d8a28744958b143 100644 (file)
 use super::DebugFormatted;
 
 pub trait MirWithFlowState<'tcx> {
-    type BD: BitDenotation;
+    type BD: BitDenotation<'tcx>;
     fn node_id(&self) -> NodeId;
     fn mir(&self) -> &Mir<'tcx>;
-    fn flow_state(&self) -> &DataflowState<Self::BD>;
+    fn flow_state(&self) -> &DataflowState<'tcx, Self::BD>;
 }
 
 impl<'a, 'tcx, BD> MirWithFlowState<'tcx> for DataflowBuilder<'a, 'tcx, BD>
-    where BD: BitDenotation
+    where BD: BitDenotation<'tcx>
 {
     type BD = BD;
     fn node_id(&self) -> NodeId { self.node_id }
     fn mir(&self) -> &Mir<'tcx> { self.flow_state.mir() }
-    fn flow_state(&self) -> &DataflowState<Self::BD> { &self.flow_state.flow_state }
+    fn flow_state(&self) -> &DataflowState<'tcx, Self::BD> { &self.flow_state.flow_state }
 }
 
 struct Graph<'a, 'tcx, MWF:'a, P> where
@@ -53,8 +53,8 @@ pub(crate) fn print_borrowck_graph_to<'a, 'tcx, BD, P>(
     path: &Path,
     render_idx: P)
     -> io::Result<()>
-    where BD: BitDenotation,
-          P: Fn(&BD, BD::Idx) -> DebugFormatted
+    where BD: BitDenotation<'tcx>,
+          P: Fn(&BD, BD::Idx) -> DebugFormatted,
 {
     let g = Graph { mbcx, phantom: PhantomData, render_idx };
     let mut v = Vec::new();
@@ -76,7 +76,7 @@ fn outgoing(mir: &Mir, bb: BasicBlock) -> Vec<Edge> {
 
 impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P>
     where MWF: MirWithFlowState<'tcx>,
-          P: Fn(&MWF::BD, <MWF::BD as BitDenotation>::Idx) -> DebugFormatted,
+          P: Fn(&MWF::BD, <MWF::BD as BitDenotation<'tcx>>::Idx) -> DebugFormatted,
 {
     type Node = Node;
     type Edge = Edge;
@@ -128,7 +128,7 @@ fn edge_label(&'a self, e: &Edge) -> dot::LabelText<'a> {
 
 impl<'a, 'tcx, MWF, P> Graph<'a, 'tcx, MWF, P>
 where MWF: MirWithFlowState<'tcx>,
-      P: Fn(&MWF::BD, <MWF::BD as BitDenotation>::Idx) -> DebugFormatted,
+      P: Fn(&MWF::BD, <MWF::BD as BitDenotation<'tcx>>::Idx) -> DebugFormatted,
 {
     /// Generate the node label
     fn node_label_internal<W: io::Write>(&self,
index 1e279d8dd97083295f2d74e9cf94545bd6aad010..374f7071ffac26ac4f53e7c66a04befd7b92aa30 100644 (file)
@@ -36,7 +36,7 @@ pub fn mir(&self) -> &Mir<'tcx> {
     }
 }
 
-impl<'a, 'tcx> BitDenotation for HaveBeenBorrowedLocals<'a, 'tcx> {
+impl<'a, 'tcx> BitDenotation<'tcx> for HaveBeenBorrowedLocals<'a, 'tcx> {
     type Idx = Local;
     fn name() -> &'static str { "has_been_borrowed_locals" }
     fn bits_per_block(&self) -> usize {
@@ -71,11 +71,13 @@ fn terminator_effect(&self,
         }.visit_terminator(loc.block, self.mir[loc.block].terminator(), loc);
     }
 
-    fn propagate_call_return(&self,
-                             _in_out: &mut BitSet<Local>,
-                             _call_bb: mir::BasicBlock,
-                             _dest_bb: mir::BasicBlock,
-                             _dest_place: &mir::Place) {
+    fn propagate_call_return(
+        &self,
+        _in_out: &mut BitSet<Local>,
+        _call_bb: mir::BasicBlock,
+        _dest_bb: mir::BasicBlock,
+        _dest_place: &mir::Place<'tcx>,
+    ) {
         // Nothing to do when a call returns successfully
     }
 }
index 5e78ef03c2c6b4e7197699b8c478377f9322bf79..078e2fd49804e92e0dcd05ca42807b61a69e6975 100644 (file)
@@ -11,7 +11,6 @@
 use borrow_check::borrow_set::{BorrowSet, BorrowData};
 use borrow_check::place_ext::PlaceExt;
 
-use rustc;
 use rustc::mir::{self, Location, Place, Mir};
 use rustc::ty::TyCtxt;
 use rustc::ty::RegionVid;
@@ -24,6 +23,7 @@
 pub use dataflow::indexes::BorrowIndex;
 use borrow_check::nll::region_infer::RegionInferenceContext;
 use borrow_check::nll::ToRegionVid;
+use borrow_check::places_conflict;
 
 use std::rc::Rc;
 
@@ -191,17 +191,55 @@ fn kill_loans_out_of_scope_at_location(&self,
         }
     }
 
-    fn kill_borrows_on_local(&self,
-                             sets: &mut BlockSets<BorrowIndex>,
-                             local: &rustc::mir::Local)
-    {
-        if let Some(borrow_indexes) = self.borrow_set.local_map.get(local) {
-            sets.kill_all(borrow_indexes);
+    /// Kill any borrows that conflict with `place`.
+    fn kill_borrows_on_place(
+        &self,
+        sets: &mut BlockSets<BorrowIndex>,
+        place: &Place<'tcx>
+    ) {
+        debug!("kill_borrows_on_place: place={:?}", place);
+        // Handle the `Place::Local(..)` case first and exit early.
+        if let Place::Local(local) = place {
+            if let Some(borrow_indices) = self.borrow_set.local_map.get(&local) {
+                debug!("kill_borrows_on_place: borrow_indices={:?}", borrow_indices);
+                sets.kill_all(borrow_indices);
+                return;
+            }
+        }
+
+        // Otherwise, look at all borrows that are live and if they conflict with the assignment
+        // into our place then we can kill them.
+        let mut borrows = sets.on_entry.clone();
+        let _ = borrows.union(sets.gen_set);
+        for borrow_index in borrows.iter() {
+            let borrow_data = &self.borrows()[borrow_index];
+            debug!(
+                "kill_borrows_on_place: borrow_index={:?} borrow_data={:?}",
+                borrow_index, borrow_data,
+            );
+
+            // By passing `PlaceConflictBias::NoOverlap`, we conservatively assume that any given
+            // pair of array indices are unequal, so that when `places_conflict` returns true, we
+            // will be assured that two places being compared definitely denotes the same sets of
+            // locations.
+            if places_conflict::places_conflict(
+                self.tcx,
+                self.mir,
+                place,
+                &borrow_data.borrowed_place,
+                places_conflict::PlaceConflictBias::NoOverlap,
+            ) {
+                debug!(
+                    "kill_borrows_on_place: (kill) borrow_index={:?} borrow_data={:?}",
+                    borrow_index, borrow_data,
+                );
+                sets.kill(borrow_index);
+            }
         }
     }
 }
 
-impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'gcx, 'tcx> {
     type Idx = BorrowIndex;
     fn name() -> &'static str { "borrows" }
     fn bits_per_block(&self) -> usize {
@@ -222,7 +260,7 @@ fn before_statement_effect(&self,
     }
 
     fn statement_effect(&self, sets: &mut BlockSets<BorrowIndex>, location: Location) {
-        debug!("Borrows::statement_effect sets: {:?} location: {:?}", sets, location);
+        debug!("Borrows::statement_effect: sets={:?} location={:?}", sets, location);
 
         let block = &self.mir.basic_blocks().get(location.block).unwrap_or_else(|| {
             panic!("could not find block at location {:?}", location);
@@ -231,20 +269,12 @@ fn statement_effect(&self, sets: &mut BlockSets<BorrowIndex>, location: Location
             panic!("could not find statement at location {:?}");
         });
 
+        debug!("Borrows::statement_effect: stmt={:?}", stmt);
         match stmt.kind {
             mir::StatementKind::Assign(ref lhs, ref rhs) => {
                 // Make sure there are no remaining borrows for variables
                 // that are assigned over.
-                if let Place::Local(ref local) = *lhs {
-                    // FIXME: Handle the case in which we're assigning over
-                    // a projection (`foo.bar`).
-                    self.kill_borrows_on_local(sets, local);
-                }
-
-                // NOTE: if/when the Assign case is revised to inspect
-                // the assigned_place here, make sure to also
-                // re-consider the current implementations of the
-                // propagate_call_return method.
+                self.kill_borrows_on_place(sets, lhs);
 
                 if let mir::Rvalue::Ref(_, _, ref place) = **rhs {
                     if place.ignore_borrow(
@@ -279,19 +309,13 @@ fn statement_effect(&self, sets: &mut BlockSets<BorrowIndex>, location: Location
             mir::StatementKind::StorageDead(local) => {
                 // Make sure there are no remaining borrows for locals that
                 // are gone out of scope.
-                self.kill_borrows_on_local(sets, &local)
+                self.kill_borrows_on_place(sets, &Place::Local(local));
             }
 
             mir::StatementKind::InlineAsm { ref outputs, ref asm, .. } => {
                 for (output, kind) in outputs.iter().zip(&asm.outputs) {
                     if !kind.is_indirect && !kind.is_rw {
-                        // Make sure there are no remaining borrows for direct
-                        // output variables.
-                        if let Place::Local(ref local) = *output {
-                            // FIXME: Handle the case in which we're assigning over
-                            // a projection (`foo.bar`).
-                            self.kill_borrows_on_local(sets, local);
-                        }
+                        self.kill_borrows_on_place(sets, output);
                     }
                 }
             }
@@ -300,7 +324,6 @@ fn statement_effect(&self, sets: &mut BlockSets<BorrowIndex>, location: Location
             mir::StatementKind::SetDiscriminant { .. } |
             mir::StatementKind::StorageLive(..) |
             mir::StatementKind::Retag { .. } |
-            mir::StatementKind::EscapeToRaw { .. } |
             mir::StatementKind::AscribeUserType(..) |
             mir::StatementKind::Nop => {}
 
@@ -316,16 +339,13 @@ fn before_terminator_effect(&self,
 
     fn terminator_effect(&self, _: &mut BlockSets<BorrowIndex>, _: Location) {}
 
-    fn propagate_call_return(&self,
-                             _in_out: &mut BitSet<BorrowIndex>,
-                             _call_bb: mir::BasicBlock,
-                             _dest_bb: mir::BasicBlock,
-                             _dest_place: &mir::Place) {
-        // there are no effects on borrows from method call return...
-        //
-        // ... but if overwriting a place can affect flow state, then
-        // latter is not true; see NOTE on Assign case in
-        // statement_effect_on_borrows.
+    fn propagate_call_return(
+        &self,
+        _in_out: &mut BitSet<BorrowIndex>,
+        _call_bb: mir::BasicBlock,
+        _dest_bb: mir::BasicBlock,
+        _dest_place: &mir::Place<'tcx>,
+    ) {
     }
 }
 
@@ -342,4 +362,3 @@ fn bottom_value() -> bool {
         false // bottom = nothing is reserved or activated yet
     }
 }
-
index c29a855b1d2ebbc9041b1432443c2dde9b525d84..99e1eab82690c825e5812012e4828a28f29209d5 100644 (file)
@@ -293,7 +293,7 @@ fn update_bits(sets: &mut BlockSets<MovePathIndex>, path: MovePathIndex,
     }
 }
 
-impl<'a, 'gcx, 'tcx> BitDenotation for MaybeInitializedPlaces<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for MaybeInitializedPlaces<'a, 'gcx, 'tcx> {
     type Idx = MovePathIndex;
     fn name() -> &'static str { "maybe_init" }
     fn bits_per_block(&self) -> usize {
@@ -331,11 +331,13 @@ fn terminator_effect(&self,
         )
     }
 
-    fn propagate_call_return(&self,
-                             in_out: &mut BitSet<MovePathIndex>,
-                             _call_bb: mir::BasicBlock,
-                             _dest_bb: mir::BasicBlock,
-                             dest_place: &mir::Place) {
+    fn propagate_call_return(
+        &self,
+        in_out: &mut BitSet<MovePathIndex>,
+        _call_bb: mir::BasicBlock,
+        _dest_bb: mir::BasicBlock,
+        dest_place: &mir::Place<'tcx>,
+    ) {
         // when a call returns successfully, that means we need to set
         // the bits for that dest_place to 1 (initialized).
         on_lookup_result_bits(self.tcx, self.mir, self.move_data(),
@@ -344,7 +346,7 @@ fn propagate_call_return(&self,
     }
 }
 
-impl<'a, 'gcx, 'tcx> BitDenotation for MaybeUninitializedPlaces<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for MaybeUninitializedPlaces<'a, 'gcx, 'tcx> {
     type Idx = MovePathIndex;
     fn name() -> &'static str { "maybe_uninit" }
     fn bits_per_block(&self) -> usize {
@@ -387,11 +389,13 @@ fn terminator_effect(&self,
         )
     }
 
-    fn propagate_call_return(&self,
-                             in_out: &mut BitSet<MovePathIndex>,
-                             _call_bb: mir::BasicBlock,
-                             _dest_bb: mir::BasicBlock,
-                             dest_place: &mir::Place) {
+    fn propagate_call_return(
+        &self,
+        in_out: &mut BitSet<MovePathIndex>,
+        _call_bb: mir::BasicBlock,
+        _dest_bb: mir::BasicBlock,
+        dest_place: &mir::Place<'tcx>,
+    ) {
         // when a call returns successfully, that means we need to set
         // the bits for that dest_place to 0 (initialized).
         on_lookup_result_bits(self.tcx, self.mir, self.move_data(),
@@ -400,7 +404,7 @@ fn propagate_call_return(&self,
     }
 }
 
-impl<'a, 'gcx, 'tcx> BitDenotation for DefinitelyInitializedPlaces<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for DefinitelyInitializedPlaces<'a, 'gcx, 'tcx> {
     type Idx = MovePathIndex;
     fn name() -> &'static str { "definite_init" }
     fn bits_per_block(&self) -> usize {
@@ -441,11 +445,13 @@ fn terminator_effect(&self,
         )
     }
 
-    fn propagate_call_return(&self,
-                             in_out: &mut BitSet<MovePathIndex>,
-                             _call_bb: mir::BasicBlock,
-                             _dest_bb: mir::BasicBlock,
-                             dest_place: &mir::Place) {
+    fn propagate_call_return(
+        &self,
+        in_out: &mut BitSet<MovePathIndex>,
+        _call_bb: mir::BasicBlock,
+        _dest_bb: mir::BasicBlock,
+        dest_place: &mir::Place<'tcx>,
+    ) {
         // when a call returns successfully, that means we need to set
         // the bits for that dest_place to 1 (initialized).
         on_lookup_result_bits(self.tcx, self.mir, self.move_data(),
@@ -454,7 +460,7 @@ fn propagate_call_return(&self,
     }
 }
 
-impl<'a, 'gcx, 'tcx> BitDenotation for EverInitializedPlaces<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for EverInitializedPlaces<'a, 'gcx, 'tcx> {
     type Idx = InitIndex;
     fn name() -> &'static str { "ever_init" }
     fn bits_per_block(&self) -> usize {
@@ -530,11 +536,13 @@ fn terminator_effect(&self,
         );
     }
 
-    fn propagate_call_return(&self,
-                             in_out: &mut BitSet<InitIndex>,
-                             call_bb: mir::BasicBlock,
-                             _dest_bb: mir::BasicBlock,
-                             _dest_place: &mir::Place) {
+    fn propagate_call_return(
+        &self,
+        in_out: &mut BitSet<InitIndex>,
+        call_bb: mir::BasicBlock,
+        _dest_bb: mir::BasicBlock,
+        _dest_place: &mir::Place<'tcx>,
+    ) {
         let move_data = self.move_data();
         let bits_per_block = self.bits_per_block();
         let init_loc_map = &move_data.init_loc_map;
index c8faa34df8a2bcda20bbf9320f4709834807b373..caf3d3f7ab6c8d15d4dfcb24e3ad5d888cdb9ab1 100644 (file)
@@ -29,7 +29,7 @@ pub fn mir(&self) -> &Mir<'tcx> {
     }
 }
 
-impl<'a, 'tcx> BitDenotation for MaybeStorageLive<'a, 'tcx> {
+impl<'a, 'tcx> BitDenotation<'tcx> for MaybeStorageLive<'a, 'tcx> {
     type Idx = Local;
     fn name() -> &'static str { "maybe_storage_live" }
     fn bits_per_block(&self) -> usize {
@@ -58,11 +58,13 @@ fn terminator_effect(&self,
         // Terminators have no effect
     }
 
-    fn propagate_call_return(&self,
-                             _in_out: &mut BitSet<Local>,
-                             _call_bb: mir::BasicBlock,
-                             _dest_bb: mir::BasicBlock,
-                             _dest_place: &mir::Place) {
+    fn propagate_call_return(
+        &self,
+        _in_out: &mut BitSet<Local>,
+        _call_bb: mir::BasicBlock,
+        _dest_bb: mir::BasicBlock,
+        _dest_place: &mir::Place<'tcx>,
+    ) {
         // Nothing to do when a call returns successfully
     }
 }
index bd842669a1f9b4538c3b7ca8693c0c320efa78af..efdf0c1efcb171e54fc6deeb8a1b4a9abf489d13 100644 (file)
@@ -44,7 +44,9 @@
 
 pub(crate) use self::move_paths::indexes;
 
-pub(crate) struct DataflowBuilder<'a, 'tcx: 'a, BD> where BD: BitDenotation
+pub(crate) struct DataflowBuilder<'a, 'tcx: 'a, BD>
+where
+    BD: BitDenotation<'tcx>
 {
     node_id: ast::NodeId,
     flow_state: DataflowAnalysis<'a, 'tcx, BD>,
@@ -71,7 +73,7 @@ fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-pub(crate) trait Dataflow<BD: BitDenotation> {
+pub(crate) trait Dataflow<'tcx, BD: BitDenotation<'tcx>> {
     /// Sets up and runs the dataflow problem, using `p` to render results if
     /// implementation so chooses.
     fn dataflow<P>(&mut self, p: P) where P: Fn(&BD, BD::Idx) -> DebugFormatted {
@@ -87,7 +89,9 @@ fn dataflow<P>(&mut self, p: P) where P: Fn(&BD, BD::Idx) -> DebugFormatted {
     fn propagate(&mut self);
 }
 
-impl<'a, 'tcx: 'a, BD> Dataflow<BD> for DataflowBuilder<'a, 'tcx, BD> where BD: BitDenotation
+impl<'a, 'tcx: 'a, BD> Dataflow<'tcx, BD> for DataflowBuilder<'a, 'tcx, BD>
+where
+    BD: BitDenotation<'tcx>
 {
     fn dataflow<P>(&mut self, p: P) where P: Fn(&BD, BD::Idx) -> DebugFormatted {
         self.flow_state.build_sets();
@@ -127,21 +131,21 @@ pub(crate) fn do_dataflow<'a, 'gcx, 'tcx, BD, P>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                                                  dead_unwinds: &BitSet<BasicBlock>,
                                                  bd: BD,
                                                  p: P)
-                                                 -> DataflowResults<BD>
-    where BD: BitDenotation + InitialFlow,
+                                                 -> DataflowResults<'tcx, BD>
+    where BD: BitDenotation<'tcx> + InitialFlow,
           P: Fn(&BD, BD::Idx) -> DebugFormatted
 {
     let flow_state = DataflowAnalysis::new(mir, dead_unwinds, bd);
     flow_state.run(tcx, node_id, attributes, p)
 }
 
-impl<'a, 'gcx: 'tcx, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD> where BD: BitDenotation
+impl<'a, 'gcx: 'tcx, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD> where BD: BitDenotation<'tcx>
 {
     pub(crate) fn run<P>(self,
                          tcx: TyCtxt<'a, 'gcx, 'tcx>,
                          node_id: ast::NodeId,
                          attributes: &[ast::Attribute],
-                         p: P) -> DataflowResults<BD>
+                         p: P) -> DataflowResults<'tcx, BD>
         where P: Fn(&BD, BD::Idx) -> DebugFormatted
     {
         let name_found = |sess: &Session, attrs: &[ast::Attribute], name| -> Option<String> {
@@ -173,12 +177,12 @@ pub(crate) fn run<P>(self,
     }
 }
 
-struct PropagationContext<'b, 'a: 'b, 'tcx: 'a, O> where O: 'b + BitDenotation
+struct PropagationContext<'b, 'a: 'b, 'tcx: 'a, O> where O: 'b + BitDenotation<'tcx>
 {
     builder: &'b mut DataflowAnalysis<'a, 'tcx, O>,
 }
 
-impl<'a, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD> where BD: BitDenotation
+impl<'a, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD> where BD: BitDenotation<'tcx>
 {
     fn propagate(&mut self) {
         let mut temp = BitSet::new_empty(self.flow_state.sets.bits_per_block);
@@ -228,7 +232,7 @@ fn build_sets(&mut self) {
     }
 }
 
-impl<'b, 'a: 'b, 'tcx: 'a, BD> PropagationContext<'b, 'a, 'tcx, BD> where BD: BitDenotation
+impl<'b, 'a: 'b, 'tcx: 'a, BD> PropagationContext<'b, 'a, 'tcx, BD> where BD: BitDenotation<'tcx>
 {
     fn walk_cfg(&mut self, in_out: &mut BitSet<BD::Idx>) {
         let mut dirty_queue: WorkQueue<mir::BasicBlock> =
@@ -259,7 +263,7 @@ fn dataflow_path(context: &str, path: &str) -> PathBuf {
     path
 }
 
-impl<'a, 'tcx: 'a, BD> DataflowBuilder<'a, 'tcx, BD> where BD: BitDenotation
+impl<'a, 'tcx: 'a, BD> DataflowBuilder<'a, 'tcx, BD> where BD: BitDenotation<'tcx>
 {
     fn pre_dataflow_instrumentation<P>(&self, p: P) -> io::Result<()>
         where P: Fn(&BD, BD::Idx) -> DebugFormatted
@@ -347,10 +351,10 @@ fn process_basic_block(&mut self, bb: BasicBlock, flow_state: &mut Self::FlowSta
     fn mir(&self) -> &'a Mir<'tcx>;
 }
 
-pub fn state_for_location<'tcx, T: BitDenotation>(loc: Location,
-                                                  analysis: &T,
-                                                  result: &DataflowResults<T>,
-                                                  mir: &Mir<'tcx>)
+pub fn state_for_location<'tcx, T: BitDenotation<'tcx>>(loc: Location,
+                                                        analysis: &T,
+                                                        result: &DataflowResults<'tcx, T>,
+                                                        mir: &Mir<'tcx>)
     -> BitSet<T::Idx> {
     let mut on_entry = result.sets().on_entry_set_for(loc.block.index()).to_owned();
     let mut kill_set = on_entry.to_hybrid();
@@ -381,25 +385,25 @@ pub fn state_for_location<'tcx, T: BitDenotation>(loc: Location,
     gen_set.to_dense()
 }
 
-pub struct DataflowAnalysis<'a, 'tcx: 'a, O> where O: BitDenotation
+pub struct DataflowAnalysis<'a, 'tcx: 'a, O> where O: BitDenotation<'tcx>
 {
-    flow_state: DataflowState<O>,
+    flow_state: DataflowState<'tcx, O>,
     dead_unwinds: &'a BitSet<mir::BasicBlock>,
     mir: &'a Mir<'tcx>,
 }
 
-impl<'a, 'tcx: 'a, O> DataflowAnalysis<'a, 'tcx, O> where O: BitDenotation
+impl<'a, 'tcx: 'a, O> DataflowAnalysis<'a, 'tcx, O> where O: BitDenotation<'tcx>
 {
-    pub fn results(self) -> DataflowResults<O> {
+    pub fn results(self) -> DataflowResults<'tcx, O> {
         DataflowResults(self.flow_state)
     }
 
     pub fn mir(&self) -> &'a Mir<'tcx> { self.mir }
 }
 
-pub struct DataflowResults<O>(pub(crate) DataflowState<O>) where O: BitDenotation;
+pub struct DataflowResults<'tcx, O>(pub(crate) DataflowState<'tcx, O>) where O: BitDenotation<'tcx>;
 
-impl<O: BitDenotation> DataflowResults<O> {
+impl<'tcx, O: BitDenotation<'tcx>> DataflowResults<'tcx, O> {
     pub fn sets(&self) -> &AllSets<O::Idx> {
         &self.0.sets
     }
@@ -411,7 +415,7 @@ pub fn operator(&self) -> &O {
 
 /// State of a dataflow analysis; couples a collection of bit sets
 /// with operator used to initialize and merge bits during analysis.
-pub struct DataflowState<O: BitDenotation>
+pub struct DataflowState<'tcx, O: BitDenotation<'tcx>>
 {
     /// All the sets for the analysis. (Factored into its
     /// own structure so that we can borrow it mutably
@@ -422,7 +426,7 @@ pub struct DataflowState<O: BitDenotation>
     pub(crate) operator: O,
 }
 
-impl<O: BitDenotation> DataflowState<O> {
+impl<'tcx, O: BitDenotation<'tcx>> DataflowState<'tcx, O> {
     pub(crate) fn interpret_set<'c, P>(&self,
                                        o: &'c O,
                                        set: &BitSet<O::Idx>,
@@ -561,7 +565,7 @@ pub trait InitialFlow {
     fn bottom_value() -> bool;
 }
 
-pub trait BitDenotation: BitSetOperator {
+pub trait BitDenotation<'tcx>: BitSetOperator {
     /// Specifies what index type is used to access the bitvector.
     type Idx: Idx;
 
@@ -687,14 +691,16 @@ fn terminator_effect(&self,
     /// be better to represent this as an additional gen- and
     /// kill-sets associated with each edge coming out of the basic
     /// block.
-    fn propagate_call_return(&self,
-                             in_out: &mut BitSet<Self::Idx>,
-                             call_bb: mir::BasicBlock,
-                             dest_bb: mir::BasicBlock,
-                             dest_place: &mir::Place);
+    fn propagate_call_return(
+        &self,
+        in_out: &mut BitSet<Self::Idx>,
+        call_bb: mir::BasicBlock,
+        dest_bb: mir::BasicBlock,
+        dest_place: &mir::Place<'tcx>,
+    );
 }
 
-impl<'a, 'tcx, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation
+impl<'a, 'tcx, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation<'tcx>
 {
     pub fn new(mir: &'a Mir<'tcx>,
                dead_unwinds: &'a BitSet<mir::BasicBlock>,
@@ -726,8 +732,7 @@ pub fn new(mir: &'a Mir<'tcx>,
     }
 }
 
-impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation
-{
+impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation<'tcx> {
     /// Propagates the bits of `in_out` into all the successors of `bb`,
     /// using bitwise operator denoted by `self.operator`.
     ///
@@ -744,7 +749,7 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation
     fn propagate_bits_into_graph_successors_of(
         &mut self,
         in_out: &mut BitSet<D::Idx>,
-        (bb, bb_data): (mir::BasicBlock, &mir::BasicBlockData),
+        (bb, bb_data): (mir::BasicBlock, &mir::BasicBlockData<'tcx>),
         dirty_list: &mut WorkQueue<mir::BasicBlock>)
     {
         match bb_data.terminator().kind {
index 7fe27e97d3d3bab0488e05d0a0a237b0f5980da2..d201a355a2ae94941a019c9ca3e8bde6f5bd8c58 100644 (file)
@@ -302,7 +302,6 @@ fn gather_statement(&mut self, stmt: &Statement<'tcx>) {
                           "SetDiscriminant should not exist during borrowck");
             }
             StatementKind::Retag { .. } |
-            StatementKind::EscapeToRaw { .. } |
             StatementKind::AscribeUserType(..) |
             StatementKind::Nop => {}
         }
index bfa2e53b9e0cfb545d2eb53d7f0740da0db5cd11..a251b723d61fcff12f6f57ea702431e36ad4c4f6 100644 (file)
@@ -230,7 +230,11 @@ fn check_match(
                 let scrutinee_is_uninhabited = if self.tcx.features().exhaustive_patterns {
                     self.tcx.is_ty_uninhabited_from(module, pat_ty)
                 } else {
-                    self.conservative_is_uninhabited(pat_ty)
+                    match pat_ty.sty {
+                        ty::Never => true,
+                        ty::Adt(def, _) => def.variants.is_empty(),
+                        _ => false
+                    }
                 };
                 if !scrutinee_is_uninhabited {
                     // We know the type is inhabited, so this must be wrong
@@ -258,15 +262,6 @@ fn check_match(
         })
     }
 
-    fn conservative_is_uninhabited(&self, scrutinee_ty: Ty<'tcx>) -> bool {
-        // "rustc-1.0-style" uncontentious uninhabitableness check
-        match scrutinee_ty.sty {
-            ty::Never => true,
-            ty::Adt(def, _) => def.variants.is_empty(),
-            _ => false
-        }
-    }
-
     fn check_irrefutable(&self, pat: &'tcx Pat, origin: &str) {
         let module = self.tcx.hir().get_module_parent(pat.id);
         MatchCheckCtxt::create_and_enter(self.tcx, self.param_env, module, |ref mut cx| {
index 7d636b77ced4ce9453941fd90989e085ac7bfebf..118539fc58ebf2bb2299390554e8adf41bd52f94 100644 (file)
@@ -44,22 +44,16 @@ pub fn cast(
             }
 
             Misc => {
-                let src_layout = src.layout;
                 let src = self.read_immediate(src)?;
 
-                // There are no casts to references
-                assert!(!dest.layout.ty.is_region_ptr());
-                // Hence we make all casts erase the tag
-                let src = src.erase_tag().with_default_tag();
-
-                if self.type_is_fat_ptr(src_layout.ty) {
-                    match (src, self.type_is_fat_ptr(dest.layout.ty)) {
+                if self.type_is_fat_ptr(src.layout.ty) {
+                    match (*src, self.type_is_fat_ptr(dest.layout.ty)) {
                         // pointers to extern types
                         (Immediate::Scalar(_),_) |
                         // slices and trait objects to other slices/trait objects
                         (Immediate::ScalarPair(..), true) => {
                             // No change to immediate
-                            self.write_immediate(src, dest)?;
+                            self.write_immediate(*src, dest)?;
                         }
                         // slices and trait objects to thin pointers (dropping the metadata)
                         (Immediate::ScalarPair(data, _), false) => {
@@ -67,11 +61,11 @@ pub fn cast(
                         }
                     }
                 } else {
-                    match src_layout.variants {
+                    match src.layout.variants {
                         layout::Variants::Single { index } => {
-                            if let Some(def) = src_layout.ty.ty_adt_def() {
+                            if let Some(def) = src.layout.ty.ty_adt_def() {
                                 // Cast from a univariant enum
-                                assert!(src_layout.is_zst());
+                                assert!(src.layout.is_zst());
                                 let discr_val = def
                                     .discriminant_for_variant(*self.tcx, index)
                                     .val;
@@ -84,7 +78,7 @@ pub fn cast(
                         layout::Variants::NicheFilling { .. } => {},
                     }
 
-                    let dest_val = self.cast_scalar(src.to_scalar()?, src_layout, dest.layout)?;
+                    let dest_val = self.cast_scalar(src.to_scalar()?, src.layout, dest.layout)?;
                     self.write_scalar(dest_val, dest)?;
                 }
             }
index 4c7aa887045c718ef2b2c899e4fc27090ab9fc20..e6f3b664c007b5684bb2f761c53305abba04a1c9 100644 (file)
@@ -203,22 +203,12 @@ fn tag_dereference(
     #[inline]
     fn retag(
         _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
-        _fn_entry: bool,
-        _two_phase: bool,
+        _kind: mir::RetagKind,
         _place: PlaceTy<'tcx, Self::PointerTag>,
     ) -> EvalResult<'tcx> {
         Ok(())
     }
 
-    /// Execute an escape-to-raw operation
-    #[inline]
-    fn escape_to_raw(
-        _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
-        _ptr: OpTy<'tcx, Self::PointerTag>,
-    ) -> EvalResult<'tcx> {
-        Ok(())
-    }
-
     /// Called immediately before a new stack frame got pushed
     fn stack_push(
         ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
index a6835e4f167380ed0cb5c525675cfb2b768cfafc..596dba576064623199fc7ffbc73ba7e1c2b53867 100644 (file)
@@ -119,13 +119,9 @@ fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> EvalResult<'tcx> {
             FakeRead(..) => {}
 
             // Stacked Borrows.
-            Retag { fn_entry, two_phase, ref place } => {
+            Retag(kind, ref place) => {
                 let dest = self.eval_place(place)?;
-                M::retag(self, fn_entry, two_phase, dest)?;
-            }
-            EscapeToRaw(ref op) => {
-                let op = self.eval_operand(op, None)?;
-                M::escape_to_raw(self, op)?;
+                M::retag(self, kind, dest)?;
             }
 
             // Statements we do not track.
index 2728833251ac2f6dbd185c00bd79751ad50f3d31..3802b0191272807c97fef68c20f721c8e4d1742f 100644 (file)
@@ -227,20 +227,11 @@ fn build_drop_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         // The first argument (index 0), but add 1 for the return value.
         let dropee_ptr = Place::Local(Local::new(1+0));
         if tcx.sess.opts.debugging_opts.mir_emit_retag {
-            // Function arguments should be retagged
+            // Function arguments should be retagged, and we make this one raw.
             mir.basic_blocks_mut()[START_BLOCK].statements.insert(0, Statement {
                 source_info,
-                kind: StatementKind::Retag {
-                    fn_entry: true,
-                    two_phase: false,
-                    place: dropee_ptr.clone(),
-                },
+                kind: StatementKind::Retag(RetagKind::Raw, dropee_ptr.clone()),
             });
-            // We use raw ptr operations, better prepare the alias tracking for that
-            mir.basic_blocks_mut()[START_BLOCK].statements.insert(1, Statement {
-                source_info,
-                kind: StatementKind::EscapeToRaw(Operand::Copy(dropee_ptr.clone())),
-            })
         }
         let patch = {
             let param_env = tcx.param_env(def_id).with_reveal_all();
index 811b85446cb23b59eb02210a0980bb5f3bd98107..69c0a68ae70516a68eddcf991b12b54abde4bc45 100644 (file)
@@ -118,7 +118,7 @@ fn run_pass<'a, 'tcx>(&self,
             basic_blocks[START_BLOCK].statements.splice(0..0,
                 places.into_iter().map(|place| Statement {
                     source_info,
-                    kind: StatementKind::Retag { fn_entry: true, two_phase: false, place },
+                    kind: StatementKind::Retag(RetagKind::FnEntry, place),
                 })
             );
         }
@@ -154,7 +154,7 @@ fn run_pass<'a, 'tcx>(&self,
         for (source_info, dest_place, dest_block) in returns {
             basic_blocks[dest_block].statements.insert(0, Statement {
                 source_info,
-                kind: StatementKind::Retag { fn_entry: false, two_phase: false, place: dest_place },
+                kind: StatementKind::Retag(RetagKind::Default, dest_place),
             });
         }
 
@@ -164,9 +164,9 @@ fn run_pass<'a, 'tcx>(&self,
             // We want to insert statements as we iterate.  To this end, we
             // iterate backwards using indices.
             for i in (0..block_data.statements.len()).rev() {
-                match block_data.statements[i].kind {
-                    // If we are casting *from* a reference, we may have to escape-to-raw.
-                    StatementKind::Assign(_, box Rvalue::Cast(
+                let (retag_kind, place) = match block_data.statements[i].kind {
+                    // If we are casting *from* a reference, we may have to retag-as-raw.
+                    StatementKind::Assign(ref place, box Rvalue::Cast(
                         CastKind::Misc,
                         ref src,
                         dest_ty,
@@ -175,42 +175,35 @@ fn run_pass<'a, 'tcx>(&self,
                         if src_ty.is_region_ptr() {
                             // The only `Misc` casts on references are those creating raw pointers.
                             assert!(dest_ty.is_unsafe_ptr());
-                            // Insert escape-to-raw before the cast.  We are not concerned
-                            // with stability here: Our EscapeToRaw will not change the value
-                            // that the cast will then use.
-                            // `src` might be a "move", but we rely on this not actually moving
-                            // but just doing a memcpy.  It is crucial that we do EscapeToRaw
-                            // on the src because we need it with its original type.
-                            let source_info = block_data.statements[i].source_info;
-                            block_data.statements.insert(i, Statement {
-                                source_info,
-                                kind: StatementKind::EscapeToRaw(src.clone()),
-                            });
+                            (RetagKind::Raw, place)
+                        } else {
+                            // Some other cast, no retag
+                            continue
                         }
                     }
                     // Assignments of reference or ptr type are the ones where we may have
                     // to update tags.  This includes `x = &[mut] ...` and hence
                     // we also retag after taking a reference!
                     StatementKind::Assign(ref place, box ref rvalue) if needs_retag(place) => {
-                        let two_phase = match rvalue {
-                            Rvalue::Ref(_, borrow_kind, _) =>
-                                borrow_kind.allows_two_phase_borrow(),
-                            _ => false
+                        let kind = match rvalue {
+                            Rvalue::Ref(_, borrow_kind, _)
+                                if borrow_kind.allows_two_phase_borrow()
+                            =>
+                                RetagKind::TwoPhase,
+                            _ =>
+                                RetagKind::Default,
                         };
-                        // Insert a retag after the assignment.
-                        let source_info = block_data.statements[i].source_info;
-                        block_data.statements.insert(i+1, Statement {
-                            source_info,
-                            kind: StatementKind::Retag {
-                                fn_entry: false,
-                                two_phase,
-                                place: place.clone(),
-                            },
-                        });
+                        (kind, place)
                     }
                     // Do nothing for the rest
-                    _ => {},
+                    _ => continue,
                 };
+                // Insert a retag after the statement.
+                let source_info = block_data.statements[i].source_info;
+                block_data.statements.insert(i+1, Statement {
+                    source_info,
+                    kind: StatementKind::Retag(retag_kind, place.clone()),
+                });
             }
         }
     }
index 3607869384077656bcc6591ceb6ee520d9f1bae4..f6b7f817aad5306b7a32fb6ec77e62618bc4fc16 100644 (file)
@@ -117,7 +117,6 @@ fn visit_statement(&mut self,
             StatementKind::StorageLive(..) |
             StatementKind::StorageDead(..) |
             StatementKind::Retag { .. } |
-            StatementKind::EscapeToRaw { .. } |
             StatementKind::AscribeUserType(..) |
             StatementKind::Nop => {
                 // safe (at least as emitted during MIR construction)
index c8056ea3e1f94fd5f2c55e97b907c7ba46815dca..caae5c8553ea78651f0474984470a24a9e3085bc 100644 (file)
@@ -303,8 +303,8 @@ struct ElaborateDropsCtxt<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     mir: &'a Mir<'tcx>,
     env: &'a MoveDataParamEnv<'tcx, 'tcx>,
-    flow_inits: DataflowResults<MaybeInitializedPlaces<'a, 'tcx, 'tcx>>,
-    flow_uninits:  DataflowResults<MaybeUninitializedPlaces<'a, 'tcx, 'tcx>>,
+    flow_inits: DataflowResults<'tcx, MaybeInitializedPlaces<'a, 'tcx, 'tcx>>,
+    flow_uninits:  DataflowResults<'tcx, MaybeUninitializedPlaces<'a, 'tcx, 'tcx>>,
     drop_flags: FxHashMap<MovePathIndex, Local>,
     patch: MirPatch<'tcx>,
 }
index f870e4a2a422701e247c5411e6ea1d9c78eb57e7..fe19accb03137a1d170fdffbea2c80541931b0a4 100644 (file)
@@ -689,7 +689,7 @@ fn create_generator_drop_shim<'a, 'tcx>(
         // Alias tracking must know we changed the type
         mir.basic_blocks_mut()[START_BLOCK].statements.insert(0, Statement {
             source_info,
-            kind: StatementKind::EscapeToRaw(Operand::Copy(Place::Local(self_arg()))),
+            kind: StatementKind::Retag(RetagKind::Raw, Place::Local(self_arg())),
         })
     }
 
index afe0066df1f28dbc6e2ca85bd4d2849c480fbf4d..88424d75baa882e145e1c36a304abd881f1229ff 100644 (file)
@@ -709,16 +709,17 @@ fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockDat
 
     fn visit_retag(
         &mut self,
-        fn_entry: &mut bool,
-        two_phase: &mut bool,
+        kind: &mut RetagKind,
         place: &mut Place<'tcx>,
         loc: Location,
     ) {
-        self.super_retag(fn_entry, two_phase, place, loc);
+        self.super_retag(kind, place, loc);
 
         // We have to patch all inlined retags to be aware that they are no longer
         // happening on function entry.
-        *fn_entry = false;
+        if *kind == RetagKind::FnEntry {
+            *kind = RetagKind::Default;
+        }
     }
 
     fn visit_terminator_kind(&mut self, block: BasicBlock,
index 58a3cb97e4156470fbf715e57063a5f9d779d64d..b854f029e51067709aaf9e159a57caca6b294e62 100644 (file)
@@ -1241,7 +1241,6 @@ fn visit_statement(&mut self, bb: BasicBlock, statement: &Statement<'tcx>, locat
                 StatementKind::StorageDead(_) |
                 StatementKind::InlineAsm {..} |
                 StatementKind::Retag { .. } |
-                StatementKind::EscapeToRaw { .. } |
                 StatementKind::AscribeUserType(..) |
                 StatementKind::Nop => {}
             }
index eee167c3579370a2df560a395c57b0ca67dd8857..c1c5b18915aede665e4734aef2dd786c436a57f2 100644 (file)
@@ -243,7 +243,6 @@ fn check_statement(
         | StatementKind::StorageLive(_)
         | StatementKind::StorageDead(_)
         | StatementKind::Retag { .. }
-        | StatementKind::EscapeToRaw { .. }
         | StatementKind::AscribeUserType(..)
         | StatementKind::Nop => Ok(()),
     }
index 81b010e7dcec9ba8f7bad43a4bd95ad102cf351d..cdab5a1d7b011796f79081ebe4d589df8b277426 100644 (file)
@@ -65,8 +65,7 @@ fn is_nop_landing_pad(
                 StatementKind::Assign { .. } |
                 StatementKind::SetDiscriminant { .. } |
                 StatementKind::InlineAsm { .. } |
-                StatementKind::Retag { .. } |
-                StatementKind::EscapeToRaw { .. } => {
+                StatementKind::Retag { .. } => {
                     return false;
                 }
             }
index c996dc285f7e77f71c1dc7cceb7ea0179fc2538e..e1eeeb8301ce2fce436d557c379492f2e15b405a 100644 (file)
@@ -95,8 +95,8 @@ pub fn sanity_check_via_rustc_peek<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                 mir: &Mir<'tcx>,
                                                 id: ast::NodeId,
                                                 _attributes: &[ast::Attribute],
-                                                results: &DataflowResults<O>)
-    where O: BitDenotation<Idx=MovePathIndex> + HasMoveData<'tcx>
+                                                results: &DataflowResults<'tcx, O>)
+    where O: BitDenotation<'tcx, Idx=MovePathIndex> + HasMoveData<'tcx>
 {
     debug!("sanity_check_via_rustc_peek id: {:?}", id);
     // FIXME: this is not DRY. Figure out way to abstract this and
@@ -110,9 +110,9 @@ pub fn sanity_check_via_rustc_peek<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
 fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                            mir: &Mir<'tcx>,
-                           results: &DataflowResults<O>,
+                           results: &DataflowResults<'tcx, O>,
                            bb: mir::BasicBlock) where
-    O: BitDenotation<Idx=MovePathIndex> + HasMoveData<'tcx>
+    O: BitDenotation<'tcx, Idx=MovePathIndex> + HasMoveData<'tcx>
 {
     let move_data = results.0.operator.move_data();
     let mir::BasicBlockData { ref statements, ref terminator, is_cleanup: _ } = mir[bb];
@@ -162,7 +162,6 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             mir::StatementKind::StorageDead(_) |
             mir::StatementKind::InlineAsm { .. } |
             mir::StatementKind::Retag { .. } |
-            mir::StatementKind::EscapeToRaw { .. } |
             mir::StatementKind::AscribeUserType(..) |
             mir::StatementKind::Nop => continue,
             mir::StatementKind::SetDiscriminant{ .. } =>
index f082d776969ebe418da7b630468ff2f652adc085..6cfa9f95082e0829e3c8d06429eea73bb20d509f 100644 (file)
@@ -1035,4 +1035,15 @@ fn visit_attribute(&mut self, attr: &'a ast::Attribute) {
         }
         visit::walk_attribute(self, attr);
     }
+
+    fn visit_ident(&mut self, ident: Ident) {
+        if ident.name == keywords::DollarCrate.name() {
+            let name = match self.resolver.resolve_crate_root(ident).kind {
+                ModuleKind::Def(_, name) if name != keywords::Invalid.name() => name,
+                _ => keywords::Crate.name(),
+            };
+            ident.span.ctxt().set_dollar_crate_name(name);
+        }
+        visit::walk_ident(self, ident);
+    }
 }
index 36f4497b77fe5331a76b831b9cebec7899d5f61c..794e5741d62ca42265c1645dcc3e77e1f7633f35 100644 (file)
@@ -1173,10 +1173,6 @@ fn is_trait(&self) -> bool {
         }
     }
 
-    fn is_local(&self) -> bool {
-        self.normal_ancestor_id.is_local()
-    }
-
     fn nearest_item_scope(&'a self) -> Module<'a> {
         if self.is_trait() { self.parent.unwrap() } else { self }
     }
index 32f0d84342eddee8811c9fc8cde793ddf1589523..81633c8f57f9e73dac3ddd83b09aa20f460ce983 100644 (file)
@@ -10,7 +10,7 @@
 
 use {AmbiguityError, AmbiguityKind, AmbiguityErrorMisc};
 use {CrateLint, Resolver, ResolutionError, ScopeSet, Weak};
-use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult, Segment, ToNameBinding};
+use {Module, NameBinding, NameBindingKind, PathResult, Segment, ToNameBinding};
 use {is_known_tool, resolve_error};
 use ModuleOrUniformRoot;
 use Namespace::*;
@@ -30,8 +30,6 @@
 use syntax::ext::hygiene::{self, Mark};
 use syntax::ext::tt::macro_rules;
 use syntax::feature_gate::{feature_err, is_builtin_attr_name, GateIssue};
-use syntax::fold::{self, Folder};
-use syntax::ptr::P;
 use syntax::symbol::{Symbol, keywords};
 use syntax::util::lev_distance::find_best_match_for_name;
 use syntax_pos::{Span, DUMMY_SP};
@@ -138,58 +136,6 @@ fn get_module_scope(&mut self, id: ast::NodeId) -> Mark {
         mark
     }
 
-    fn eliminate_crate_var(&mut self, item: P<ast::Item>) -> P<ast::Item> {
-        struct EliminateCrateVar<'b, 'a: 'b>(
-            &'b mut Resolver<'a>, Span
-        );
-
-        impl<'a, 'b> Folder for EliminateCrateVar<'a, 'b> {
-            fn fold_path(&mut self, path: ast::Path) -> ast::Path {
-                match self.fold_qpath(None, path) {
-                    (None, path) => path,
-                    _ => unreachable!(),
-                }
-            }
-
-            fn fold_qpath(&mut self, mut qself: Option<ast::QSelf>, mut path: ast::Path)
-                          -> (Option<ast::QSelf>, ast::Path) {
-                qself = qself.map(|ast::QSelf { ty, path_span, position }| {
-                    ast::QSelf {
-                        ty: self.fold_ty(ty),
-                        path_span: self.new_span(path_span),
-                        position,
-                    }
-                });
-
-                if path.segments[0].ident.name == keywords::DollarCrate.name() {
-                    let module = self.0.resolve_crate_root(path.segments[0].ident);
-                    path.segments[0].ident.name = keywords::PathRoot.name();
-                    if !module.is_local() {
-                        let span = path.segments[0].ident.span;
-                        path.segments.insert(1, match module.kind {
-                            ModuleKind::Def(_, name) => ast::PathSegment::from_ident(
-                                ast::Ident::with_empty_ctxt(name).with_span_pos(span)
-                            ),
-                            _ => unreachable!(),
-                        });
-                        if let Some(qself) = &mut qself {
-                            qself.position += 1;
-                        }
-                    }
-                }
-                (qself, path)
-            }
-
-            fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
-                fold::noop_fold_mac(mac, self)
-            }
-        }
-
-        let ret = EliminateCrateVar(self, item.span).fold_item(item);
-        assert!(ret.len() == 1);
-        ret.into_iter().next().unwrap()
-    }
-
     fn visit_ast_fragment_with_placeholders(&mut self, mark: Mark, fragment: &AstFragment,
                                             derives: &[Mark]) {
         let invocation = self.invocations[&mark];
@@ -259,7 +205,6 @@ fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: Mark, force
             self.definitions.add_parent_module_of_macro_def(invoc.expansion_data.mark,
                                                             normal_module_def_id);
             invoc.expansion_data.mark.set_default_transparency(ext.default_transparency());
-            invoc.expansion_data.mark.set_is_builtin(def_id.krate == CrateNum::BuiltinMacros);
         }
 
         Ok(Some(ext))
index 1b594342c9a7179944fc9f42c7c2fec7f6a476b5..d240f45c7d9a459a7da18758531160d0b4e0b880 100644 (file)
@@ -8,20 +8,18 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use astconv::AstConv;
-
 use super::{FnCtxt, PlaceOp, Needs};
 use super::method::MethodCallee;
 
-use rustc::infer::InferOk;
+use rustc::infer::{InferCtxt, InferOk};
 use rustc::session::DiagnosticMessageId;
-use rustc::traits;
-use rustc::ty::{self, Ty, TraitRef};
+use rustc::traits::{self, TraitEngine};
+use rustc::ty::{self, Ty, TyCtxt, TraitRef};
 use rustc::ty::{ToPredicate, TypeFoldable};
 use rustc::ty::adjustment::{Adjustment, Adjust, OverloadedDeref};
 
 use syntax_pos::Span;
-use syntax::ast::Ident;
+use syntax::ast::{self, Ident};
 
 use std::iter;
 
@@ -32,20 +30,24 @@ enum AutoderefKind {
 }
 
 pub struct Autoderef<'a, 'gcx: 'tcx, 'tcx: 'a> {
-    fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
+    infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+    body_id: ast::NodeId,
+    param_env: ty::ParamEnv<'tcx>,
     steps: Vec<(Ty<'tcx>, AutoderefKind)>,
     cur_ty: Ty<'tcx>,
     obligations: Vec<traits::PredicateObligation<'tcx>>,
     at_start: bool,
     include_raw_pointers: bool,
     span: Span,
+    silence_errors: bool,
+    reached_recursion_limit: bool
 }
 
 impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> {
     type Item = (Ty<'tcx>, usize);
 
     fn next(&mut self) -> Option<Self::Item> {
-        let tcx = self.fcx.tcx;
+        let tcx = self.infcx.tcx;
 
         debug!("autoderef: steps={:?}, cur_ty={:?}",
                self.steps,
@@ -57,24 +59,10 @@ fn next(&mut self) -> Option<Self::Item> {
         }
 
         if self.steps.len() >= *tcx.sess.recursion_limit.get() {
-            // We've reached the recursion limit, error gracefully.
-            let suggested_limit = *tcx.sess.recursion_limit.get() * 2;
-            let msg = format!("reached the recursion limit while auto-dereferencing `{:?}`",
-                              self.cur_ty);
-            let error_id = (DiagnosticMessageId::ErrorId(55), Some(self.span), msg);
-            let fresh = tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id);
-            if fresh {
-                struct_span_err!(tcx.sess,
-                                 self.span,
-                                 E0055,
-                                 "reached the recursion limit while auto-dereferencing `{:?}`",
-                                 self.cur_ty)
-                    .span_label(self.span, "deref recursion limit reached")
-                    .help(&format!(
-                        "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
-                        suggested_limit))
-                    .emit();
+            if !self.silence_errors {
+                report_autoderef_recursion_limit_error(tcx, self.span, self.cur_ty);
             }
+            self.reached_recursion_limit = true;
             return None;
         }
 
@@ -107,10 +95,32 @@ fn next(&mut self) -> Option<Self::Item> {
 }
 
 impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
+    pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+               param_env: ty::ParamEnv<'tcx>,
+               body_id: ast::NodeId,
+               span: Span,
+               base_ty: Ty<'tcx>)
+               -> Autoderef<'a, 'gcx, 'tcx>
+    {
+        Autoderef {
+            infcx,
+            body_id,
+            param_env,
+            steps: vec![],
+            cur_ty: infcx.resolve_type_vars_if_possible(&base_ty),
+            obligations: vec![],
+            at_start: true,
+            include_raw_pointers: false,
+            silence_errors: false,
+            reached_recursion_limit: false,
+            span,
+        }
+    }
+
     fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
         debug!("overloaded_deref_ty({:?})", ty);
 
-        let tcx = self.fcx.tcx();
+        let tcx = self.infcx.tcx;
 
         // <cur_ty as Deref>
         let trait_ref = TraitRef {
@@ -118,43 +128,52 @@ fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
             substs: tcx.mk_substs_trait(self.cur_ty, &[]),
         };
 
-        let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id);
+        let cause = traits::ObligationCause::misc(self.span, self.body_id);
 
         let obligation = traits::Obligation::new(cause.clone(),
-                                                 self.fcx.param_env,
+                                                 self.param_env,
                                                  trait_ref.to_predicate());
-        if !self.fcx.predicate_may_hold(&obligation) {
+        if !self.infcx.predicate_may_hold(&obligation) {
             debug!("overloaded_deref_ty: cannot match obligation");
             return None;
         }
 
-        let mut selcx = traits::SelectionContext::new(self.fcx);
-        let normalized_ty = traits::normalize_projection_type(&mut selcx,
-                                                              self.fcx.param_env,
-                                                              ty::ProjectionTy::from_ref_and_name(
-                                                                  tcx,
-                                                                  trait_ref,
-                                                                  Ident::from_str("Target"),
-                                                              ),
-                                                              cause,
-                                                              0,
-                                                              &mut self.obligations);
-
-        debug!("overloaded_deref_ty({:?}) = {:?}", ty, normalized_ty);
+        let mut fulfillcx = traits::FulfillmentContext::new_in_snapshot();
+        let normalized_ty = fulfillcx.normalize_projection_type(
+            &self.infcx,
+            self.param_env,
+            ty::ProjectionTy::from_ref_and_name(
+                tcx,
+                trait_ref,
+                Ident::from_str("Target"),
+            ),
+            cause);
+        if let Err(e) = fulfillcx.select_where_possible(&self.infcx) {
+            // This shouldn't happen, except for evaluate/fulfill mismatches,
+            // but that's not a reason for an ICE (`predicate_may_hold` is conservative
+            // by design).
+            debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling",
+                   e);
+            return None;
+        }
+        let obligations = fulfillcx.pending_obligations();
+        debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})",
+               ty, normalized_ty, obligations);
+        self.obligations.extend(obligations);
 
-        Some(self.fcx.resolve_type_vars_if_possible(&normalized_ty))
+        Some(self.infcx.resolve_type_vars_if_possible(&normalized_ty))
     }
 
     /// Returns the final type, generating an error if it is an
     /// unresolved inference variable.
-    pub fn unambiguous_final_ty(&self) -> Ty<'tcx> {
-        self.fcx.structurally_resolved_type(self.span, self.cur_ty)
+    pub fn unambiguous_final_ty(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
+        fcx.structurally_resolved_type(self.span, self.cur_ty)
     }
 
     /// Returns the final type we ended up with, which may well be an
     /// inference variable (we will resolve it first, if possible).
     pub fn maybe_ambiguous_final_ty(&self) -> Ty<'tcx> {
-        self.fcx.resolve_type_vars_if_possible(&self.cur_ty)
+        self.infcx.resolve_type_vars_if_possible(&self.cur_ty)
     }
 
     pub fn step_count(&self) -> usize {
@@ -162,19 +181,19 @@ pub fn step_count(&self) -> usize {
     }
 
     /// Returns the adjustment steps.
-    pub fn adjust_steps(&self, needs: Needs)
+    pub fn adjust_steps(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, needs: Needs)
                         -> Vec<Adjustment<'tcx>> {
-        self.fcx.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(needs))
+        fcx.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(fcx, needs))
     }
 
-    pub fn adjust_steps_as_infer_ok(&self, needs: Needs)
+    pub fn adjust_steps_as_infer_ok(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, needs: Needs)
                                     -> InferOk<'tcx, Vec<Adjustment<'tcx>>> {
         let mut obligations = vec![];
         let targets = self.steps.iter().skip(1).map(|&(ty, _)| ty)
             .chain(iter::once(self.cur_ty));
         let steps: Vec<_> = self.steps.iter().map(|&(source, kind)| {
             if let AutoderefKind::Overloaded = kind {
-                self.fcx.try_overloaded_deref(self.span, source, needs)
+                fcx.try_overloaded_deref(self.span, source, needs)
                     .and_then(|InferOk { value: method, obligations: o }| {
                         obligations.extend(o);
                         if let ty::Ref(region, _, mutbl) = method.sig.output().sty {
@@ -211,8 +230,16 @@ pub fn include_raw_pointers(mut self) -> Self {
         self
     }
 
-    pub fn finalize(self) {
-        let fcx = self.fcx;
+    pub fn silence_errors(mut self) -> Self {
+        self.silence_errors = true;
+        self
+    }
+
+    pub fn reached_recursion_limit(&self) -> bool {
+        self.reached_recursion_limit
+    }
+
+    pub fn finalize(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) {
         fcx.register_predicates(self.into_obligations());
     }
 
@@ -221,17 +248,32 @@ pub fn into_obligations(self) -> Vec<traits::PredicateObligation<'tcx>> {
     }
 }
 
+pub fn report_autoderef_recursion_limit_error<'a, 'gcx, 'tcx>(
+    tcx: TyCtxt<'a, 'gcx, 'tcx>, span: Span, ty: Ty<'tcx>)
+{
+    // We've reached the recursion limit, error gracefully.
+    let suggested_limit = *tcx.sess.recursion_limit.get() * 2;
+    let msg = format!("reached the recursion limit while auto-dereferencing `{:?}`",
+                      ty);
+    let error_id = (DiagnosticMessageId::ErrorId(55), Some(span), msg);
+    let fresh = tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id);
+    if fresh {
+        struct_span_err!(tcx.sess,
+                         span,
+                         E0055,
+                         "reached the recursion limit while auto-dereferencing `{:?}`",
+                         ty)
+            .span_label(span, "deref recursion limit reached")
+            .help(&format!(
+                "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
+                suggested_limit))
+            .emit();
+    }
+}
+
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'gcx, 'tcx> {
-        Autoderef {
-            fcx: self,
-            steps: vec![],
-            cur_ty: self.resolve_type_vars_if_possible(&base_ty),
-            obligations: vec![],
-            at_start: true,
-            include_raw_pointers: false,
-            span,
-        }
+        Autoderef::new(self, self.param_env, self.body_id, span, base_ty)
     }
 
     pub fn try_overloaded_deref(&self,
index 75ae868883484e0bd308d9b07d02386331faef7d..0ec181e59d0bf9d9ba83f20771e8eabd36506df0 100644 (file)
@@ -57,7 +57,7 @@ pub fn check_call(&self,
         while result.is_none() && autoderef.next().is_some() {
             result = self.try_overloaded_call_step(call_expr, callee_expr, &autoderef);
         }
-        autoderef.finalize();
+        autoderef.finalize(self);
 
         let output = match result {
             None => {
@@ -89,7 +89,7 @@ fn try_overloaded_call_step(&self,
                                 callee_expr: &'gcx hir::Expr,
                                 autoderef: &Autoderef<'a, 'gcx, 'tcx>)
                                 -> Option<CallStep<'tcx>> {
-        let adjusted_ty = autoderef.unambiguous_final_ty();
+        let adjusted_ty = autoderef.unambiguous_final_ty(self);
         debug!("try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?})",
                call_expr,
                adjusted_ty);
@@ -97,7 +97,7 @@ fn try_overloaded_call_step(&self,
         // If the callee is a bare function or a closure, then we're all set.
         match adjusted_ty.sty {
             ty::FnDef(..) | ty::FnPtr(_) => {
-                let adjustments = autoderef.adjust_steps(Needs::None);
+                let adjustments = autoderef.adjust_steps(self, Needs::None);
                 self.apply_adjustments(callee_expr, adjustments);
                 return Some(CallStep::Builtin(adjusted_ty));
             }
@@ -115,7 +115,7 @@ fn try_overloaded_call_step(&self,
                         infer::FnCall,
                         &closure_ty
                     ).0;
-                    let adjustments = autoderef.adjust_steps(Needs::None);
+                    let adjustments = autoderef.adjust_steps(self, Needs::None);
                     self.record_deferred_call_resolution(def_id, DeferredCallResolution {
                         call_expr,
                         callee_expr,
@@ -145,7 +145,7 @@ fn try_overloaded_call_step(&self,
         }
 
         self.try_overloaded_call_traits(call_expr, adjusted_ty).map(|(autoref, method)| {
-            let mut adjustments = autoderef.adjust_steps(Needs::None);
+            let mut adjustments = autoderef.adjust_steps(self, Needs::None);
             adjustments.extend(autoref);
             self.apply_adjustments(callee_expr, adjustments);
             CallStep::Overloaded(method)
index be15503e47906e7e68ba5452b51010627f453628..f599a2b2ece07aebd033467cff132c03671cab2b 100644 (file)
@@ -20,7 +20,7 @@
 use rustc::infer::type_variable::TypeVariableOrigin;
 use rustc::traits::Obligation;
 use rustc::traits::error_reporting::ArgKind;
-use rustc::ty::{self, ToPolyTraitRef, Ty, GenericParamDefKind};
+use rustc::ty::{self, Ty, GenericParamDefKind};
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::subst::Substs;
 use std::cmp;
@@ -219,13 +219,8 @@ fn deduce_expectations_from_obligations(
         &self,
         expected_vid: ty::TyVid,
     ) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
-        let fulfillment_cx = self.fulfillment_cx.borrow();
-        // Here `expected_ty` is known to be a type inference variable.
-
-        let expected_sig = fulfillment_cx
-            .pending_obligations()
-            .iter()
-            .filter_map(|obligation| {
+        let expected_sig = self.obligations_for_self_ty(expected_vid)
+            .find_map(|(_, obligation)| {
                 debug!(
                     "deduce_expectations_from_obligations: obligation.predicate={:?}",
                     obligation.predicate
@@ -234,52 +229,21 @@ fn deduce_expectations_from_obligations(
                 if let ty::Predicate::Projection(ref proj_predicate) = obligation.predicate {
                     // Given a Projection predicate, we can potentially infer
                     // the complete signature.
-                    let trait_ref = proj_predicate.to_poly_trait_ref(self.tcx);
-                    self.self_type_matches_expected_vid(trait_ref, expected_vid)
-                        .and_then(|_| {
-                            self.deduce_sig_from_projection(
-                                Some(obligation.cause.span),
-                                proj_predicate
-                            )
-                        })
+                    self.deduce_sig_from_projection(
+                        Some(obligation.cause.span),
+                        proj_predicate
+                    )
                 } else {
                     None
                 }
-            })
-            .next();
+            });
 
         // Even if we can't infer the full signature, we may be able to
         // infer the kind. This can occur if there is a trait-reference
         // like `F : Fn<A>`. Note that due to subtyping we could encounter
         // many viable options, so pick the most restrictive.
-        let expected_kind = fulfillment_cx
-            .pending_obligations()
-            .iter()
-            .filter_map(|obligation| {
-                let opt_trait_ref = match obligation.predicate {
-                    ty::Predicate::Projection(ref data) => Some(data.to_poly_trait_ref(self.tcx)),
-                    ty::Predicate::Trait(ref data) => Some(data.to_poly_trait_ref()),
-                    ty::Predicate::Subtype(..) => None,
-                    ty::Predicate::RegionOutlives(..) => None,
-                    ty::Predicate::TypeOutlives(..) => None,
-                    ty::Predicate::WellFormed(..) => None,
-                    ty::Predicate::ObjectSafe(..) => None,
-                    ty::Predicate::ConstEvaluatable(..) => None,
-
-                    // N.B., this predicate is created by breaking down a
-                    // `ClosureType: FnFoo()` predicate, where
-                    // `ClosureType` represents some `Closure`. It can't
-                    // possibly be referring to the current closure,
-                    // because we haven't produced the `Closure` for
-                    // this closure yet; this is exactly why the other
-                    // code is looking for a self type of a unresolved
-                    // inference variable.
-                    ty::Predicate::ClosureKind(..) => None,
-                };
-                opt_trait_ref
-                    .and_then(|tr| self.self_type_matches_expected_vid(tr, expected_vid))
-                    .and_then(|tr| self.tcx.lang_items().fn_trait_kind(tr.def_id()))
-            })
+        let expected_kind = self.obligations_for_self_ty(expected_vid)
+            .filter_map(|(tr, _)| self.tcx.lang_items().fn_trait_kind(tr.def_id()))
             .fold(None, |best, cur| {
                 Some(best.map_or(cur, |best| cmp::min(best, cur)))
             });
@@ -339,22 +303,6 @@ fn deduce_sig_from_projection(
         Some(ExpectedSig { cause_span, sig })
     }
 
-    fn self_type_matches_expected_vid(
-        &self,
-        trait_ref: ty::PolyTraitRef<'tcx>,
-        expected_vid: ty::TyVid,
-    ) -> Option<ty::PolyTraitRef<'tcx>> {
-        let self_ty = self.shallow_resolve(trait_ref.self_ty());
-        debug!(
-            "self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?})",
-            trait_ref, self_ty
-        );
-        match self_ty.sty {
-            ty::Infer(ty::TyVar(v)) if expected_vid == v => Some(trait_ref),
-            _ => None,
-        }
-    }
-
     fn sig_of_closure(
         &self,
         expr_def_id: DefId,
index 8d844fe3a69e4e18d40fb34aed13b9fd4c958652..9a1f9784192c188711d7ec824c781c57b9c8e3e0 100644 (file)
@@ -419,7 +419,7 @@ fn coerce_borrowed_pointer(&self,
 
         let needs = Needs::maybe_mut_place(mt_b.mutbl);
         let InferOk { value: mut adjustments, obligations: o }
-            = autoderef.adjust_steps_as_infer_ok(needs);
+            = autoderef.adjust_steps_as_infer_ok(self, needs);
         obligations.extend(o);
         obligations.extend(autoderef.into_obligations());
 
@@ -579,7 +579,33 @@ fn coerce_unsized(&self, source: Ty<'tcx>, target: Ty<'tcx>) -> CoerceResult<'tc
             };
             match selcx.select(&obligation.with(trait_ref)) {
                 // Uncertain or unimplemented.
-                Ok(None) |
+                Ok(None) => {
+                    if trait_ref.def_id() == unsize_did {
+                        let trait_ref = self.resolve_type_vars_if_possible(&trait_ref);
+                        let self_ty = trait_ref.skip_binder().self_ty();
+                        let unsize_ty = trait_ref.skip_binder().input_types().nth(1).unwrap();
+                        debug!("coerce_unsized: ambiguous unsize case for {:?}", trait_ref);
+                        match (&self_ty.sty, &unsize_ty.sty) {
+                            (ty::Infer(ty::TyVar(v)),
+                             ty::Dynamic(..)) if self.type_var_is_sized(*v) => {
+                                debug!("coerce_unsized: have sized infer {:?}", v);
+                                coercion.obligations.push(obligation);
+                                // `$0: Unsize<dyn Trait>` where we know that `$0: Sized`, try going
+                                // for unsizing.
+                            }
+                            _ => {
+                                // Some other case for `$0: Unsize<Something>`. Note that we
+                                // hit this case even if `Something` is a sized type, so just
+                                // don't do the coercion.
+                                debug!("coerce_unsized: ambiguous unsize");
+                                return Err(TypeError::Mismatch);
+                            }
+                        }
+                    } else {
+                        debug!("coerce_unsized: early return - ambiguous");
+                        return Err(TypeError::Mismatch);
+                    }
+                }
                 Err(traits::Unimplemented) => {
                     debug!("coerce_unsized: early return - can't prove obligation");
                     return Err(TypeError::Mismatch);
index 11fb3889a748df933ec3e656108aeb82abf4662a..3902dddd0d4761d1007d57b6fae75e44a4fcaec6 100644 (file)
@@ -161,9 +161,9 @@ fn adjust_self_ty(&mut self,
         let (_, n) = autoderef.nth(pick.autoderefs).unwrap();
         assert_eq!(n, pick.autoderefs);
 
-        let mut adjustments = autoderef.adjust_steps(Needs::None);
+        let mut adjustments = autoderef.adjust_steps(self, Needs::None);
 
-        let mut target = autoderef.unambiguous_final_ty();
+        let mut target = autoderef.unambiguous_final_ty(self);
 
         if let Some(mutbl) = pick.autoref {
             let region = self.next_region_var(infer::Autoref(self.span));
@@ -202,7 +202,7 @@ fn adjust_self_ty(&mut self,
             assert!(pick.unsize.is_none());
         }
 
-        autoderef.finalize();
+        autoderef.finalize(self);
 
         // Write out the final adjustments.
         self.apply_adjustments(self.self_expr, adjustments);
index 858d8c742dfd9e11213058bf40cc967b6c3ab4b0..5ecbfcd132cf31c7310d6c1c30ca93ba55e43fe2 100644 (file)
@@ -39,6 +39,7 @@
 
 pub fn provide(providers: &mut ty::query::Providers) {
     suggest::provide(providers);
+    probe::provide(providers);
 }
 
 #[derive(Clone, Copy, Debug)]
index dd3c022d53bb3ce45c622f2650250382b3b48004..190419048b4b562b9ca48283a1fa3313e5a7d562 100644 (file)
 use super::{CandidateSource, ImplSource, TraitSource};
 use super::suggest;
 
+use check::autoderef::{self, Autoderef};
 use check::FnCtxt;
 use hir::def_id::DefId;
 use hir::def::Def;
 use namespace::Namespace;
+
+use rustc_data_structures::sync::Lrc;
 use rustc::hir;
 use rustc::lint;
 use rustc::session::config::nightly_options;
 use rustc::ty::subst::{Subst, Substs};
 use rustc::traits::{self, ObligationCause};
-use rustc::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TraitRef, TypeFoldable};
+use rustc::traits::query::{CanonicalTyGoal};
+use rustc::traits::query::method_autoderef::{CandidateStep, MethodAutoderefStepsResult};
+use rustc::traits::query::method_autoderef::{MethodAutoderefBadTy};
+use rustc::ty::{self, ParamEnvAnd, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TraitRef, TypeFoldable};
 use rustc::ty::GenericParamDefKind;
 use rustc::infer::type_variable::TypeVariableOrigin;
 use rustc::util::nodemap::FxHashSet;
 use rustc::infer::{self, InferOk};
+use rustc::infer::canonical::{Canonical, QueryResponse};
+use rustc::infer::canonical::{OriginalQueryValues};
 use rustc::middle::stability;
 use syntax::ast;
 use syntax::util::lev_distance::{lev_distance, find_best_match_for_name};
-use syntax_pos::{Span, symbol::Symbol};
+use syntax_pos::{DUMMY_SP, Span, symbol::Symbol};
 use std::iter;
 use std::mem;
 use std::ops::Deref;
-use std::rc::Rc;
 use std::cmp::max;
 
 use self::CandidateKind::*;
@@ -51,7 +58,12 @@ struct ProbeContext<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     mode: Mode,
     method_name: Option<ast::Ident>,
     return_type: Option<Ty<'tcx>>,
-    steps: Rc<Vec<CandidateStep<'tcx>>>,
+
+    /// This is the OriginalQueryValues for the steps queries
+    /// that are answered in steps.
+    orig_steps_var_values: OriginalQueryValues<'tcx>,
+    steps: Lrc<Vec<CandidateStep<'gcx>>>,
+
     inherent_candidates: Vec<Candidate<'tcx>>,
     extension_candidates: Vec<Candidate<'tcx>>,
     impl_dups: FxHashSet<DefId>,
@@ -81,19 +93,6 @@ fn deref(&self) -> &Self::Target {
     }
 }
 
-#[derive(Debug)]
-struct CandidateStep<'tcx> {
-    self_ty: Ty<'tcx>,
-    autoderefs: usize,
-    // true if the type results from a dereference of a raw pointer.
-    // when assembling candidates, we include these steps, but not when
-    // picking methods. This so that if we have `foo: *const Foo` and `Foo` has methods
-    // `fn by_raw_ptr(self: *const Self)` and `fn by_ref(&self)`, then
-    // `foo.by_raw_ptr()` will work and `foo.by_ref()` won't.
-    from_unsafe_deref: bool,
-    unsize: bool,
-}
-
 #[derive(Debug)]
 struct Candidate<'tcx> {
     xform_self_ty: Ty<'tcx>,
@@ -249,42 +248,111 @@ fn probe_op<OP,R>(&'a self,
                       -> Result<R, MethodError<'tcx>>
         where OP: FnOnce(ProbeContext<'a, 'gcx, 'tcx>) -> Result<R, MethodError<'tcx>>
     {
-        // FIXME(#18741) -- right now, creating the steps involves evaluating the
-        // `*` operator, which registers obligations that then escape into
-        // the global fulfillment context and thus has global
-        // side-effects. This is a bit of a pain to refactor. So just let
-        // it ride, although it's really not great, and in fact could I
-        // think cause spurious errors. Really though this part should
-        // take place in the `self.probe` below.
+        let mut orig_values = OriginalQueryValues::default();
+        let param_env_and_self_ty =
+            self.infcx.canonicalize_query(
+                &ParamEnvAnd {
+                    param_env: self.param_env,
+                    value: self_ty
+                }, &mut orig_values);
+
         let steps = if mode == Mode::MethodCall {
-            match self.create_steps(span, scope_expr_id, self_ty, is_suggestion) {
-                Some(steps) => steps,
-                None => {
-                    return Err(MethodError::NoMatch(NoMatchData::new(Vec::new(),
-                                                                     Vec::new(),
-                                                                     Vec::new(),
-                                                                     None,
-                                                                     mode)))
-                }
-            }
+            self.tcx.method_autoderef_steps(param_env_and_self_ty)
         } else {
-            vec![CandidateStep {
-                     self_ty,
-                     autoderefs: 0,
-                     from_unsafe_deref: false,
-                     unsize: false,
-                 }]
+            self.infcx.probe(|_| {
+                // Mode::Path - the deref steps is "trivial". This turns
+                // our CanonicalQuery into a "trivial" QueryResponse. This
+                // is a bit inefficient, but I don't think that writing
+                // special handling for this "trivial case" is a good idea.
+
+                let infcx = &self.infcx;
+                let (ParamEnvAnd {
+                    param_env: _,
+                    value: self_ty
+                }, canonical_inference_vars) =
+                    infcx.instantiate_canonical_with_fresh_inference_vars(
+                        span, &param_env_and_self_ty);
+                debug!("probe_op: Mode::Path, param_env_and_self_ty={:?} self_ty={:?}",
+                       param_env_and_self_ty, self_ty);
+                MethodAutoderefStepsResult {
+                    steps: Lrc::new(vec![CandidateStep {
+                        self_ty: self.make_query_response_ignoring_pending_obligations(
+                            canonical_inference_vars, self_ty),
+                        autoderefs: 0,
+                        from_unsafe_deref: false,
+                        unsize: false,
+                    }]),
+                    opt_bad_ty: None,
+                    reached_recursion_limit: false
+                }
+            })
         };
 
+        // If our autoderef loop had reached the recursion limit,
+        // report an overflow error, but continue going on with
+        // the truncated autoderef list.
+        if steps.reached_recursion_limit {
+            self.probe(|_| {
+                let ty = &steps.steps.last().unwrap_or_else(|| {
+                    span_bug!(span, "reached the recursion limit in 0 steps?")
+                }).self_ty;
+                let ty = self.probe_instantiate_query_response(span, &orig_values, ty)
+                    .unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty));
+                autoderef::report_autoderef_recursion_limit_error(self.tcx, span,
+                                                                  ty.value);
+            });
+        }
+
+
+        // If we encountered an `_` type or an error type during autoderef, this is
+        // ambiguous.
+        if let Some(bad_ty) = &steps.opt_bad_ty {
+            if is_suggestion.0 {
+                // Ambiguity was encountered during a suggestion. Just keep going.
+                debug!("ProbeContext: encountered ambiguity in suggestion");
+            } else if bad_ty.reached_raw_pointer && !self.tcx.features().arbitrary_self_types {
+                // this case used to be allowed by the compiler,
+                // so we do a future-compat lint here for the 2015 edition
+                // (see https://github.com/rust-lang/rust/issues/46906)
+                if self.tcx.sess.rust_2018() {
+                    span_err!(self.tcx.sess, span, E0699,
+                              "the type of this value must be known \
+                               to call a method on a raw pointer on it");
+                } else {
+                   self.tcx.lint_node(
+                        lint::builtin::TYVAR_BEHIND_RAW_POINTER,
+                        scope_expr_id,
+                        span,
+                        "type annotations needed");
+                }
+            } else {
+                // Encountered a real ambiguity, so abort the lookup. If `ty` is not
+                // an `Err`, report the right "type annotations needed" error pointing
+                // to it.
+                let ty = &bad_ty.ty;
+                let ty = self.probe_instantiate_query_response(span, &orig_values, ty)
+                    .unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty));
+                let ty = self.structurally_resolved_type(span, ty.value);
+                assert_eq!(ty, self.tcx.types.err);
+                return Err(MethodError::NoMatch(NoMatchData::new(Vec::new(),
+                                                                 Vec::new(),
+                                                                 Vec::new(),
+                                                                 None,
+                                                                 mode)));
+            }
+        }
+
         debug!("ProbeContext: steps for self_ty={:?} are {:?}",
                self_ty,
                steps);
 
+
         // this creates one big transaction so that all type variables etc
         // that we create during the probe process are removed later
         self.probe(|_| {
             let mut probe_cx = ProbeContext::new(
-                self, span, mode, method_name, return_type, Rc::new(steps), is_suggestion,
+                self, span, mode, method_name, return_type, orig_values,
+                steps.steps, is_suggestion,
             );
 
             probe_cx.assemble_inherent_candidates();
@@ -297,21 +365,30 @@ fn probe_op<OP,R>(&'a self,
             op(probe_cx)
         })
     }
+}
+
+pub fn provide(providers: &mut ty::query::Providers) {
+    providers.method_autoderef_steps = method_autoderef_steps;
+}
+
+fn method_autoderef_steps<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
+                                          goal: CanonicalTyGoal<'tcx>)
+                                          -> MethodAutoderefStepsResult<'gcx>
+{
+    debug!("method_autoderef_steps({:?})", goal);
 
-    fn create_steps(&self,
-                    span: Span,
-                    scope_expr_id: ast::NodeId,
-                    self_ty: Ty<'tcx>,
-                    is_suggestion: IsSuggestion)
-                    -> Option<Vec<CandidateStep<'tcx>>> {
-        // FIXME: we don't need to create the entire steps in one pass
+    tcx.infer_ctxt().enter_with_canonical(DUMMY_SP, &goal, |ref infcx, goal, inference_vars| {
+        let ParamEnvAnd { param_env, value: self_ty } = goal;
 
-        let mut autoderef = self.autoderef(span, self_ty).include_raw_pointers();
+        let mut autoderef = Autoderef::new(infcx, param_env, ast::DUMMY_NODE_ID, DUMMY_SP, self_ty)
+            .include_raw_pointers()
+            .silence_errors();
         let mut reached_raw_pointer = false;
         let mut steps: Vec<_> = autoderef.by_ref()
             .map(|(ty, d)| {
                 let step = CandidateStep {
-                    self_ty: ty,
+                    self_ty: infcx.make_query_response_ignoring_pending_obligations(
+                        inference_vars.clone(), ty),
                     autoderefs: d,
                     from_unsafe_deref: reached_raw_pointer,
                     unsize: false,
@@ -325,68 +402,52 @@ fn create_steps(&self,
             .collect();
 
         let final_ty = autoderef.maybe_ambiguous_final_ty();
-        match final_ty.sty {
-            ty::Infer(ty::TyVar(_)) => {
-                // Ended in an inference variable. If we are doing
-                // a real method lookup, this is a hard error because it's
-                // possible that there will be multiple applicable methods.
-                if !is_suggestion.0 {
-                    if reached_raw_pointer
-                    && !self.tcx.features().arbitrary_self_types {
-                        // this case used to be allowed by the compiler,
-                        // so we do a future-compat lint here for the 2015 edition
-                        // (see https://github.com/rust-lang/rust/issues/46906)
-                        if self.tcx.sess.rust_2018() {
-                          span_err!(self.tcx.sess, span, E0699,
-                                    "the type of this value must be known \
-                                     to call a method on a raw pointer on it");
-                        } else {
-                            self.tcx.lint_node(
-                                lint::builtin::TYVAR_BEHIND_RAW_POINTER,
-                                scope_expr_id,
-                                span,
-                                "type annotations needed");
-                        }
-                    } else {
-                        let t = self.structurally_resolved_type(span, final_ty);
-                        assert_eq!(t, self.tcx.types.err);
-                        return None
-                    }
-                } else {
-                    // If we're just looking for suggestions,
-                    // though, ambiguity is no big thing, we can
-                    // just ignore it.
-                }
+        let opt_bad_ty = match final_ty.sty {
+            ty::Infer(ty::TyVar(_)) |
+            ty::Error => {
+                Some(MethodAutoderefBadTy {
+                    reached_raw_pointer,
+                    ty: infcx.make_query_response_ignoring_pending_obligations(
+                        inference_vars, final_ty)
+                })
             }
             ty::Array(elem_ty, _) => {
                 let dereferences = steps.len() - 1;
 
                 steps.push(CandidateStep {
-                    self_ty: self.tcx.mk_slice(elem_ty),
+                    self_ty: infcx.make_query_response_ignoring_pending_obligations(
+                        inference_vars, infcx.tcx.mk_slice(elem_ty)),
                     autoderefs: dereferences,
                     // this could be from an unsafe deref if we had
                     // a *mut/const [T; N]
                     from_unsafe_deref: reached_raw_pointer,
                     unsize: true,
                 });
+
+                None
             }
-            ty::Error => return None,
-            _ => (),
-        }
+            _ => None
+        };
 
-        debug!("create_steps: steps={:?}", steps);
+        debug!("method_autoderef_steps: steps={:?} opt_bad_ty={:?}", steps, opt_bad_ty);
 
-        Some(steps)
-    }
+        MethodAutoderefStepsResult {
+            steps: Lrc::new(steps),
+            opt_bad_ty: opt_bad_ty.map(Lrc::new),
+            reached_recursion_limit: autoderef.reached_recursion_limit()
+        }
+    })
 }
 
+
 impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
     fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
            span: Span,
            mode: Mode,
            method_name: Option<ast::Ident>,
            return_type: Option<Ty<'tcx>>,
-           steps: Rc<Vec<CandidateStep<'tcx>>>,
+           orig_steps_var_values: OriginalQueryValues<'tcx>,
+           steps: Lrc<Vec<CandidateStep<'gcx>>>,
            is_suggestion: IsSuggestion)
            -> ProbeContext<'a, 'gcx, 'tcx> {
         ProbeContext {
@@ -398,7 +459,8 @@ fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
             inherent_candidates: Vec::new(),
             extension_candidates: Vec::new(),
             impl_dups: FxHashSet::default(),
-            steps: steps,
+            orig_steps_var_values,
+            steps,
             static_candidates: Vec::new(),
             allow_similar_names: false,
             private_candidate: None,
@@ -443,18 +505,26 @@ fn push_candidate(&mut self,
     fn assemble_inherent_candidates(&mut self) {
         let steps = self.steps.clone();
         for step in steps.iter() {
-            self.assemble_probe(step.self_ty);
+            self.assemble_probe(&step.self_ty);
         }
     }
 
-    fn assemble_probe(&mut self, self_ty: Ty<'tcx>) {
+    fn assemble_probe(&mut self, self_ty: &Canonical<'gcx, QueryResponse<'gcx, Ty<'gcx>>>) {
         debug!("assemble_probe: self_ty={:?}", self_ty);
         let lang_items = self.tcx.lang_items();
 
-        match self_ty.sty {
+        match self_ty.value.value.sty {
             ty::Dynamic(ref data, ..) => {
                 let p = data.principal();
-                self.assemble_inherent_candidates_from_object(self_ty, p);
+                self.fcx.probe(|_| {
+                    let InferOk { value: self_ty, obligations: _ } =
+                        self.fcx.probe_instantiate_query_response(
+                            self.span, &self.orig_steps_var_values, self_ty)
+                        .unwrap_or_else(|_| {
+                            span_bug!(self.span, "{:?} was applicable but now isn't?", self_ty)
+                        });
+                    self.assemble_inherent_candidates_from_object(self_ty);
+                });
                 self.assemble_inherent_impl_candidates_for_type(p.def_id());
             }
             ty::Adt(def, _) => {
@@ -464,7 +534,7 @@ fn assemble_probe(&mut self, self_ty: Ty<'tcx>) {
                 self.assemble_inherent_impl_candidates_for_type(did);
             }
             ty::Param(p) => {
-                self.assemble_inherent_candidates_from_param(self_ty, p);
+                self.assemble_inherent_candidates_from_param(p);
             }
             ty::Char => {
                 let lang_def_id = lang_items.char_impl();
@@ -615,11 +685,16 @@ fn assemble_inherent_impl_probe(&mut self, impl_def_id: DefId) {
     }
 
     fn assemble_inherent_candidates_from_object(&mut self,
-                                                self_ty: Ty<'tcx>,
-                                                principal: ty::PolyExistentialTraitRef<'tcx>) {
+                                                self_ty: Ty<'tcx>) {
         debug!("assemble_inherent_candidates_from_object(self_ty={:?})",
                self_ty);
 
+        let principal = match self_ty.sty {
+            ty::Dynamic(ref data, ..) => data.principal(),
+            _ => span_bug!(self.span, "non-object {:?} in assemble_inherent_candidates_from_object",
+                           self_ty)
+        };
+
         // It is illegal to invoke a method on a trait instance that
         // refers to the `Self` type. An error will be reported by
         // `enforce_object_limitations()` if the method refers to the
@@ -642,7 +717,6 @@ fn assemble_inherent_candidates_from_object(&mut self,
     }
 
     fn assemble_inherent_candidates_from_param(&mut self,
-                                               _rcvr_ty: Ty<'tcx>,
                                                param_ty: ty::ParamTy) {
         // FIXME -- Do we want to commit to this behavior for param bounds?
 
@@ -898,14 +972,22 @@ fn pick_core(&mut self) -> Option<PickResult<'tcx>> {
                 // a raw pointer
                 !step.self_ty.references_error() && !step.from_unsafe_deref
             }).flat_map(|step| {
-                self.pick_by_value_method(step).or_else(|| {
-                self.pick_autorefd_method(step, hir::MutImmutable).or_else(|| {
-                self.pick_autorefd_method(step, hir::MutMutable)
+                let InferOk { value: self_ty, obligations: _ } =
+                    self.fcx.probe_instantiate_query_response(
+                        self.span, &self.orig_steps_var_values, &step.self_ty
+                    ).unwrap_or_else(|_| {
+                        span_bug!(self.span, "{:?} was applicable but now isn't?", step.self_ty)
+                    });
+                self.pick_by_value_method(step, self_ty).or_else(|| {
+                self.pick_autorefd_method(step, self_ty, hir::MutImmutable).or_else(|| {
+                self.pick_autorefd_method(step, self_ty, hir::MutMutable)
             })})})
             .next()
     }
 
-    fn pick_by_value_method(&mut self, step: &CandidateStep<'tcx>) -> Option<PickResult<'tcx>> {
+    fn pick_by_value_method(&mut self, step: &CandidateStep<'gcx>, self_ty: Ty<'tcx>)
+                            -> Option<PickResult<'tcx>>
+    {
         //! For each type `T` in the step list, this attempts to find a
         //! method where the (transformed) self type is exactly `T`. We
         //! do however do one transformation on the adjustment: if we
@@ -918,12 +1000,12 @@ fn pick_by_value_method(&mut self, step: &CandidateStep<'tcx>) -> Option<PickRes
             return None;
         }
 
-        self.pick_method(step.self_ty).map(|r| {
+        self.pick_method(self_ty).map(|r| {
             r.map(|mut pick| {
                 pick.autoderefs = step.autoderefs;
 
                 // Insert a `&*` or `&mut *` if this is a reference type:
-                if let ty::Ref(_, _, mutbl) = step.self_ty.sty {
+                if let ty::Ref(_, _, mutbl) = step.self_ty.value.value.sty {
                     pick.autoderefs += 1;
                     pick.autoref = Some(mutbl);
                 }
@@ -933,7 +1015,10 @@ fn pick_by_value_method(&mut self, step: &CandidateStep<'tcx>) -> Option<PickRes
         })
     }
 
-    fn pick_autorefd_method(&mut self, step: &CandidateStep<'tcx>, mutbl: hir::Mutability)
+    fn pick_autorefd_method(&mut self,
+                            step: &CandidateStep<'gcx>,
+                            self_ty: Ty<'tcx>,
+                            mutbl: hir::Mutability)
                             -> Option<PickResult<'tcx>> {
         let tcx = self.tcx;
 
@@ -943,14 +1028,14 @@ fn pick_autorefd_method(&mut self, step: &CandidateStep<'tcx>, mutbl: hir::Mutab
 
         let autoref_ty = tcx.mk_ref(region,
                                     ty::TypeAndMut {
-                                        ty: step.self_ty, mutbl
+                                        ty: self_ty, mutbl
                                     });
         self.pick_method(autoref_ty).map(|r| {
             r.map(|mut pick| {
                 pick.autoderefs = step.autoderefs;
                 pick.autoref = Some(mutbl);
                 pick.unsize = if step.unsize {
-                    Some(step.self_ty)
+                    Some(self_ty)
                 } else {
                     None
                 };
@@ -1288,7 +1373,9 @@ fn probe_for_lev_candidate(&mut self) -> Result<Option<ty::AssociatedItem>, Meth
         let steps = self.steps.clone();
         self.probe(|_| {
             let mut pcx = ProbeContext::new(self.fcx, self.span, self.mode, self.method_name,
-                                            self.return_type, steps, IsSuggestion(true));
+                                            self.return_type,
+                                            self.orig_steps_var_values.clone(),
+                                            steps, IsSuggestion(true));
             pcx.allow_similar_names = true;
             pcx.assemble_inherent_candidates();
             pcx.assemble_extension_candidates_for_traits_in_scope(ast::DUMMY_NODE_ID)?;
index 957c8d9f19f0ebe1f8e14ea8bb1c0ab4ad1eb087..d45f8fd6de8d9826416516063d2b4fb7befdfabc 100644 (file)
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use middle::lang_items;
 use namespace::Namespace;
+use rustc::infer::{self, InferCtxt, InferOk, InferResult, RegionVariableOrigin};
+use rustc::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
 use rustc_data_structures::indexed_vec::Idx;
 use rustc_data_structures::sync::Lrc;
 use rustc_target::spec::abi::Abi;
-use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin};
 use rustc::infer::opaque_types::OpaqueTypeDecl;
 use rustc::infer::type_variable::{TypeVariableOrigin};
 use rustc::middle::region;
 use rustc::ty::subst::{CanonicalUserSubsts, UnpackedKind, Subst, Substs,
                        UserSelfTy, UserSubsts};
 use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine};
-use rustc::ty::{self, AdtKind, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate,
-                RegionKind};
+use rustc::ty::{self, AdtKind, Ty, TyCtxt, GenericParamDefKind, RegionKind, Visibility,
+                ToPolyTraitRef, ToPredicate};
 use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::query::Providers;
 use session::{CompileIncomplete, config, Session};
 use TypeAndSubsts;
 use lint;
+use util::captures::Captures;
 use util::common::{ErrorReported, indenter};
 use util::nodemap::{DefIdMap, DefIdSet, FxHashMap, FxHashSet, NodeMap};
 
@@ -2555,7 +2557,7 @@ fn lookup_indexing(&self,
         while result.is_none() && autoderef.next().is_some() {
             result = self.try_index_step(expr, base_expr, &autoderef, needs, idx_ty);
         }
-        autoderef.finalize();
+        autoderef.finalize(self);
         result
     }
 
@@ -2572,7 +2574,7 @@ fn try_index_step(&self,
                       index_ty: Ty<'tcx>)
                       -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)>
     {
-        let adjusted_ty = autoderef.unambiguous_final_ty();
+        let adjusted_ty = autoderef.unambiguous_final_ty(self);
         debug!("try_index_step(expr={:?}, base_expr={:?}, adjusted_ty={:?}, \
                                index_ty={:?})",
                expr,
@@ -2602,7 +2604,7 @@ fn try_index_step(&self,
                 debug!("try_index_step: success, using overloaded indexing");
                 let method = self.register_infer_ok_obligations(ok);
 
-                let mut adjustments = autoderef.adjust_steps(needs);
+                let mut adjustments = autoderef.adjust_steps(self, needs);
                 if let ty::Ref(region, _, r_mutbl) = method.sig.inputs()[0].sty {
                     let mutbl = match r_mutbl {
                         hir::MutImmutable => AutoBorrowMutability::Immutable,
@@ -2731,6 +2733,72 @@ fn check_method_argument_types(&self,
         method.sig.output()
     }
 
+    fn self_type_matches_expected_vid(
+        &self,
+        trait_ref: ty::PolyTraitRef<'tcx>,
+        expected_vid: ty::TyVid,
+    ) -> bool {
+        let self_ty = self.shallow_resolve(trait_ref.self_ty());
+        debug!(
+            "self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?}, expected_vid={:?})",
+            trait_ref, self_ty, expected_vid
+        );
+        match self_ty.sty {
+            ty::Infer(ty::TyVar(found_vid)) => {
+                // FIXME: consider using `sub_root_var` here so we
+                // can see through subtyping.
+                let found_vid = self.root_var(found_vid);
+                debug!("self_type_matches_expected_vid - found_vid={:?}", found_vid);
+                expected_vid == found_vid
+            }
+            _ => false
+        }
+    }
+
+    fn obligations_for_self_ty<'b>(&'b self, self_ty: ty::TyVid)
+        -> impl Iterator<Item=(ty::PolyTraitRef<'tcx>, traits::PredicateObligation<'tcx>)>
+           + Captures<'gcx> + 'b
+    {
+        // FIXME: consider using `sub_root_var` here so we
+        // can see through subtyping.
+        let ty_var_root = self.root_var(self_ty);
+        debug!("obligations_for_self_ty: self_ty={:?} ty_var_root={:?} pending_obligations={:?}",
+               self_ty, ty_var_root,
+               self.fulfillment_cx.borrow().pending_obligations());
+
+        self.fulfillment_cx
+            .borrow()
+            .pending_obligations()
+            .into_iter()
+            .filter_map(move |obligation| match obligation.predicate {
+                ty::Predicate::Projection(ref data) =>
+                    Some((data.to_poly_trait_ref(self.tcx), obligation)),
+                ty::Predicate::Trait(ref data) =>
+                    Some((data.to_poly_trait_ref(), obligation)),
+                ty::Predicate::Subtype(..) => None,
+                ty::Predicate::RegionOutlives(..) => None,
+                ty::Predicate::TypeOutlives(..) => None,
+                ty::Predicate::WellFormed(..) => None,
+                ty::Predicate::ObjectSafe(..) => None,
+                ty::Predicate::ConstEvaluatable(..) => None,
+                // N.B., this predicate is created by breaking down a
+                // `ClosureType: FnFoo()` predicate, where
+                // `ClosureType` represents some `Closure`. It can't
+                // possibly be referring to the current closure,
+                // because we haven't produced the `Closure` for
+                // this closure yet; this is exactly why the other
+                // code is looking for a self type of a unresolved
+                // inference variable.
+                ty::Predicate::ClosureKind(..) => None,
+            }).filter(move |(tr, _)| self.self_type_matches_expected_vid(*tr, ty_var_root))
+    }
+
+    fn type_var_is_sized(&self, self_ty: ty::TyVid) -> bool {
+        self.obligations_for_self_ty(self_ty).any(|(tr, _)| {
+            Some(tr.def_id()) == self.tcx.lang_items().sized_trait()
+        })
+    }
+
     /// Generic function that factors out common logic from function calls,
     /// method calls and overloaded operators.
     fn check_argument_types(&self,
@@ -3296,9 +3364,9 @@ fn check_field(&self,
                         // of error recovery.
                         self.write_field_index(expr.id, index);
                         if field.vis.is_accessible_from(def_scope, self.tcx) {
-                            let adjustments = autoderef.adjust_steps(needs);
+                            let adjustments = autoderef.adjust_steps(self, needs);
                             self.apply_adjustments(base, adjustments);
-                            autoderef.finalize();
+                            autoderef.finalize(self);
 
                             self.tcx.check_stability(field.did, Some(expr.id), expr.span);
                             return field_ty;
@@ -3311,9 +3379,9 @@ fn check_field(&self,
                     if let Ok(index) = fstr.parse::<usize>() {
                         if fstr == index.to_string() {
                             if let Some(field_ty) = tys.get(index) {
-                                let adjustments = autoderef.adjust_steps(needs);
+                                let adjustments = autoderef.adjust_steps(self, needs);
                                 self.apply_adjustments(base, adjustments);
-                                autoderef.finalize();
+                                autoderef.finalize(self);
 
                                 self.write_field_index(expr.id, index);
                                 return field_ty;
@@ -3324,7 +3392,7 @@ fn check_field(&self,
                 _ => {}
             }
         }
-        autoderef.unambiguous_final_ty();
+        autoderef.unambiguous_final_ty(self);
 
         if let Some((did, field_ty)) = private_candidate {
             let struct_path = self.tcx().item_path_str(did);
@@ -5372,6 +5440,22 @@ fn with_breakable_ctxt<F: FnOnce() -> R, R>(&self, id: ast::NodeId,
         };
         (ctxt, result)
     }
+
+    /// Instantiate a QueryResponse in a probe context, without a
+    /// good ObligationCause.
+    fn probe_instantiate_query_response(
+        &self,
+        span: Span,
+        original_values: &OriginalQueryValues<'tcx>,
+        query_result: &Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
+    ) -> InferResult<'tcx, Ty<'tcx>>
+    {
+        self.instantiate_query_response_and_region_obligations(
+            &traits::ObligationCause::misc(span, self.body_id),
+            self.param_env,
+            original_values,
+            query_result)
+    }
 }
 
 pub fn check_bounds_are_used<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
index 6471e745aa6fd50dbf6414d7254813ea4424db50..e74b1ae47e39d58eadb488e499630869bd32b9ce 100644 (file)
@@ -13,9 +13,8 @@
 
 use hir::def_id::DefId;
 use rustc::traits::{self, ObligationCauseCode};
-use rustc::ty::{self, Lift, Ty, TyCtxt, TyKind, GenericParamDefKind, TypeFoldable};
+use rustc::ty::{self, Lift, Ty, TyCtxt, TyKind, GenericParamDefKind, TypeFoldable, ToPredicate};
 use rustc::ty::subst::{Subst, Substs};
-use rustc::ty::util::ExplicitSelf;
 use rustc::util::nodemap::{FxHashSet, FxHashMap};
 use rustc::middle::lang_items;
 use rustc::infer::opaque_types::may_define_existential_type;
@@ -749,72 +748,149 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
         &ty::Binder::bind(self_ty)
     );
 
-    let self_arg_ty = sig.inputs()[0];
+    let receiver_ty = sig.inputs()[0];
 
-    let cause = fcx.cause(span, ObligationCauseCode::MethodReceiver);
-    let self_arg_ty = fcx.normalize_associated_types_in(span, &self_arg_ty);
-    let self_arg_ty = fcx.tcx.liberate_late_bound_regions(
+    let receiver_ty = fcx.normalize_associated_types_in(span, &receiver_ty);
+    let receiver_ty = fcx.tcx.liberate_late_bound_regions(
         method.def_id,
-        &ty::Binder::bind(self_arg_ty)
+        &ty::Binder::bind(receiver_ty)
     );
 
-    let mut autoderef = fcx.autoderef(span, self_arg_ty).include_raw_pointers();
+    if fcx.tcx.features().arbitrary_self_types {
+        if !receiver_is_valid(fcx, span, receiver_ty, self_ty, true) {
+            // report error, arbitrary_self_types was enabled
+            fcx.tcx.sess.diagnostic().mut_span_err(
+                span, &format!("invalid method receiver type: {:?}", receiver_ty)
+            ).note("type of `self` must be `Self` or a type that dereferences to it")
+            .help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
+            .code(DiagnosticId::Error("E0307".into()))
+            .emit();
+        }
+    } else {
+        if !receiver_is_valid(fcx, span, receiver_ty, self_ty, false) {
+            if receiver_is_valid(fcx, span, receiver_ty, self_ty, true) {
+                // report error, would have worked with arbitrary_self_types
+                feature_gate::feature_err(
+                    &fcx.tcx.sess.parse_sess,
+                    "arbitrary_self_types",
+                    span,
+                    GateIssue::Language,
+                    &format!(
+                        "`{}` cannot be used as the type of `self` without \
+                            the `arbitrary_self_types` feature",
+                        receiver_ty,
+                    ),
+                ).help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
+                .emit();
+            } else {
+                // report error, would not have worked with arbitrary_self_types
+                fcx.tcx.sess.diagnostic().mut_span_err(
+                    span, &format!("invalid method receiver type: {:?}", receiver_ty)
+                ).note("type must be `Self` or a type that dereferences to it")
+                .help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
+                .code(DiagnosticId::Error("E0307".into()))
+                .emit();
+            }
+        }
+    }
+}
+
+/// returns true if `receiver_ty` would be considered a valid receiver type for `self_ty`. If
+/// `arbitrary_self_types` is enabled, `receiver_ty` must transitively deref to `self_ty`, possibly
+/// through a `*const/mut T` raw pointer. If the feature is not enabled, the requirements are more
+/// strict: `receiver_ty` must implement `Receiver` and directly implement `Deref<Target=self_ty>`.
+///
+/// NB: there are cases this function returns `true` but causes an error to be emitted,
+/// particularly when `receiver_ty` derefs to a type that is the same as `self_ty` but has the
+/// wrong lifetime. Be careful of this if you are calling this function speculatively.
+fn receiver_is_valid<'fcx, 'tcx, 'gcx>(
+    fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
+    span: Span,
+    receiver_ty: Ty<'tcx>,
+    self_ty: Ty<'tcx>,
+    arbitrary_self_types_enabled: bool,
+) -> bool {
+    let cause = fcx.cause(span, traits::ObligationCauseCode::MethodReceiver);
+
+    let can_eq_self = |ty| fcx.infcx.can_eq(fcx.param_env, self_ty, ty).is_ok();
+
+    // `self: Self` is always valid
+    if can_eq_self(receiver_ty) {
+        if let Some(mut err) = fcx.demand_eqtype_with_origin(&cause, self_ty, receiver_ty) {
+            err.emit();
+        }
+        return true
+    }
+
+    let mut autoderef = fcx.autoderef(span, receiver_ty);
+
+    // the `arbitrary_self_types` feature allows raw pointer receivers like `self: *const Self`
+    if arbitrary_self_types_enabled {
+        autoderef = autoderef.include_raw_pointers();
+    }
+
+    // the first type is `receiver_ty`, which we know its not equal to `self_ty`. skip it.
+    autoderef.next();
 
+    // keep dereferencing `receiver_ty` until we get to `self_ty`
     loop {
         if let Some((potential_self_ty, _)) = autoderef.next() {
-            debug!("check_method_receiver: potential self type `{:?}` to match `{:?}`",
+            debug!("receiver_is_valid: potential self type `{:?}` to match `{:?}`",
                 potential_self_ty, self_ty);
 
-            if fcx.infcx.can_eq(fcx.param_env, self_ty, potential_self_ty).is_ok() {
-                autoderef.finalize();
+            if can_eq_self(potential_self_ty) {
+                autoderef.finalize(fcx);
+
                 if let Some(mut err) = fcx.demand_eqtype_with_origin(
-                    &cause, self_ty, potential_self_ty) {
+                    &cause, self_ty, potential_self_ty
+                ) {
                     err.emit();
                 }
+
                 break
             }
         } else {
-            fcx.tcx.sess.diagnostic().mut_span_err(
-                span, &format!("invalid `self` type: {:?}", self_arg_ty))
-            .note(&format!("type must be `{:?}` or a type that dereferences to it", self_ty))
-            .help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
-            .code(DiagnosticId::Error("E0307".into()))
-            .emit();
-            return
+            debug!("receiver_is_valid: type `{:?}` does not deref to `{:?}`",
+                receiver_ty, self_ty);
+            return false
+        }
+
+        // without the `arbitrary_self_types` feature, `receiver_ty` must directly deref to
+        // `self_ty`. Enforce this by only doing one iteration of the loop
+        if !arbitrary_self_types_enabled {
+            return false
         }
     }
 
-    let is_self_ty = |ty| fcx.infcx.can_eq(fcx.param_env, self_ty, ty).is_ok();
-    let self_kind = ExplicitSelf::determine(self_arg_ty, is_self_ty);
+    // without `feature(arbitrary_self_types)`, we require that `receiver_ty` implements `Receiver`
+    if !arbitrary_self_types_enabled {
+        let trait_def_id = match fcx.tcx.lang_items().receiver_trait() {
+            Some(did) => did,
+            None => {
+                debug!("receiver_is_valid: missing Receiver trait");
+                return false
+            }
+        };
 
-    if !fcx.tcx.features().arbitrary_self_types {
-        match self_kind {
-            ExplicitSelf::ByValue |
-            ExplicitSelf::ByReference(_, _) |
-            ExplicitSelf::ByBox => (),
+        let trait_ref = ty::TraitRef{
+            def_id: trait_def_id,
+            substs: fcx.tcx.mk_substs_trait(receiver_ty, &[]),
+        };
 
-            ExplicitSelf::ByRawPointer(_) => {
-                feature_gate::feature_err(
-                    &fcx.tcx.sess.parse_sess,
-                    "arbitrary_self_types",
-                    span,
-                    GateIssue::Language,
-                    "raw pointer `self` is unstable")
-                .help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
-                .emit();
-            }
+        let obligation = traits::Obligation::new(
+            cause.clone(),
+            fcx.param_env,
+            trait_ref.to_predicate()
+        );
 
-            ExplicitSelf::Other => {
-                feature_gate::feature_err(
-                    &fcx.tcx.sess.parse_sess,
-                    "arbitrary_self_types",
-                    span,
-                    GateIssue::Language,"arbitrary `self` types are unstable")
-                .help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
-                .emit();
-            }
+        if !fcx.predicate_must_hold(&obligation) {
+            debug!("receiver_is_valid: type `{:?}` does not implement `Receiver` trait",
+                receiver_ty);
+            return false
         }
     }
+
+    true
 }
 
 fn check_variances_for_type_defn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
index 8d6fb8b7f39485c43e938887e94391c8afdc40f5..fdc81a6ed1a9c3821954ef1fb74f7f9a3fdbcc9e 100644 (file)
@@ -90,6 +90,7 @@
 extern crate syntax_pos;
 
 extern crate arena;
+
 #[macro_use] extern crate rustc;
 extern crate rustc_platform_intrinsics as intrinsics;
 extern crate rustc_data_structures;
index 217345548c8c943cb68fede8b9d9b60625eda71e..4bd3c6a84556d132f6942ce5ab7db97c99e8266d 100644 (file)
@@ -207,7 +207,7 @@ pub fn build_external_trait(cx: &DocContext, did: DefId) -> clean::Trait {
 fn build_external_function(cx: &DocContext, did: DefId) -> clean::Function {
     let sig = cx.tcx.fn_sig(did);
 
-    let constness = if cx.tcx.is_const_fn(did) {
+    let constness = if cx.tcx.is_min_const_fn(did) {
         hir::Constness::Const
     } else {
         hir::Constness::NotConst
index 3678aab87c290ecc7976485c5b2652753241ce81..01ead05999b21ac2aad9fe77251b3faadf769aa7 100644 (file)
@@ -478,7 +478,7 @@ pub fn stability_class(&self) -> Option<String> {
                 classes.push("unstable");
             }
 
-            if !s.deprecated_since.is_empty() {
+            if s.deprecation.is_some() {
                 classes.push("deprecated");
             }
 
@@ -503,6 +503,15 @@ pub fn is_non_exhaustive(&self) -> bool {
     pub fn type_(&self) -> ItemType {
         ItemType::from(self)
     }
+
+    /// Returns the info in the item's `#[deprecated]` or `#[rustc_deprecated]` attributes.
+    ///
+    /// If the item is not deprecated, returns `None`.
+    pub fn deprecation(&self) -> Option<&Deprecation> {
+        self.deprecation
+            .as_ref()
+            .or_else(|| self.stability.as_ref().and_then(|s| s.deprecation.as_ref()))
+    }
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
@@ -1674,6 +1683,12 @@ fn clean(&self, cx: &DocContext) -> Item {
             (self.generics.clean(cx), (&self.decl, self.body).clean(cx))
         });
 
+        let did = cx.tcx.hir().local_def_id(self.id);
+        let constness = if cx.tcx.is_min_const_fn(did) {
+            hir::Constness::Const
+        } else {
+            hir::Constness::NotConst
+        };
         Item {
             name: Some(self.name.clean(cx)),
             attrs: self.attrs.clean(cx),
@@ -1681,11 +1696,11 @@ fn clean(&self, cx: &DocContext) -> Item {
             visibility: self.vis.clean(cx),
             stability: self.stab.clean(cx),
             deprecation: self.depr.clean(cx),
-            def_id: cx.tcx.hir().local_def_id(self.id),
+            def_id: did,
             inner: FunctionItem(Function {
                 decl,
                 generics,
-                header: self.header,
+                header: hir::FnHeader { constness, ..self.header },
             }),
         }
     }
@@ -2009,7 +2024,7 @@ fn clean(&self, cx: &DocContext) -> Item {
                     ty::TraitContainer(_) => self.defaultness.has_value()
                 };
                 if provided {
-                    let constness = if cx.tcx.is_const_fn(self.def_id) {
+                    let constness = if cx.tcx.is_min_const_fn(self.def_id) {
                         hir::Constness::Const
                     } else {
                         hir::Constness::NotConst
@@ -3838,40 +3853,37 @@ fn clean(&self, cx: &DocContext) -> Item {
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct Stability {
     pub level: stability::StabilityLevel,
-    pub feature: String,
+    pub feature: Option<String>,
     pub since: String,
-    pub deprecated_since: String,
-    pub deprecated_reason: String,
-    pub unstable_reason: String,
-    pub issue: Option<u32>
+    pub deprecation: Option<Deprecation>,
+    pub unstable_reason: Option<String>,
+    pub issue: Option<u32>,
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct Deprecation {
-    pub since: String,
-    pub note: String,
+    pub since: Option<String>,
+    pub note: Option<String>,
 }
 
 impl Clean<Stability> for attr::Stability {
     fn clean(&self, _: &DocContext) -> Stability {
         Stability {
             level: stability::StabilityLevel::from_attr_level(&self.level),
-            feature: self.feature.to_string(),
+            feature: Some(self.feature.to_string()).filter(|f| !f.is_empty()),
             since: match self.level {
                 attr::Stable {ref since} => since.to_string(),
                 _ => String::new(),
             },
-            deprecated_since: match self.rustc_depr {
-                Some(attr::RustcDeprecation {ref since, ..}) => since.to_string(),
-                _=> String::new(),
-            },
-            deprecated_reason: match self.rustc_depr {
-                Some(ref depr) => depr.reason.to_string(),
-                _ => String::new(),
-            },
+            deprecation: self.rustc_depr.as_ref().map(|d| {
+                Deprecation {
+                    note: Some(d.reason.to_string()).filter(|r| !r.is_empty()),
+                    since: Some(d.since.to_string()).filter(|d| !d.is_empty()),
+                }
+            }),
             unstable_reason: match self.level {
-                attr::Unstable { reason: Some(ref reason), .. } => reason.to_string(),
-                _ => String::new(),
+                attr::Unstable { reason: Some(ref reason), .. } => Some(reason.to_string()),
+                _ => None,
             },
             issue: match self.level {
                 attr::Unstable {issue, ..} => Some(issue),
@@ -3890,8 +3902,8 @@ fn clean(&self, dc: &DocContext) -> Stability {
 impl Clean<Deprecation> for attr::Deprecation {
     fn clean(&self, _: &DocContext) -> Deprecation {
         Deprecation {
-            since: self.since.as_ref().map_or(String::new(), |s| s.to_string()),
-            note: self.note.as_ref().map_or(String::new(), |s| s.to_string()),
+            since: self.since.map(|s| s.to_string()).filter(|s| !s.is_empty()),
+            note: self.note.map(|n| n.to_string()).filter(|n| !n.is_empty()),
         }
     }
 }
index 15527d7d14133ca95a323aa11d507e4a4d975e4e..fa74e7094f6d358fe8037e7ee6fac5d45605cd65 100644 (file)
@@ -485,7 +485,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
             glob_map: if resolver.make_glob_map { Some(resolver.glob_map.clone()) } else { None },
         };
 
-        let arenas = AllArenas::new();
+        let mut arenas = AllArenas::new();
         let hir_map = hir_map::map_crate(&sess, &*cstore, &mut hir_forest, &defs);
         let output_filenames = driver::build_output_filenames(&input,
                                                             &None,
@@ -501,7 +501,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
                                                         hir_map,
                                                         analysis,
                                                         resolutions,
-                                                        &arenas,
+                                                        &mut arenas,
                                                         &name,
                                                         &output_filenames,
                                                         |tcx, analysis, _, result| {
index 46002c089cf9f36d84d5673e6f33cd48fce0011e..2ee4db3a539fb1272d3e787c8a26c85458815772 100644 (file)
@@ -65,7 +65,7 @@
 use rustc::util::nodemap::{FxHashMap, FxHashSet};
 use rustc_data_structures::flock;
 
-use clean::{self, AttributesExt, GetDefId, SelfTy, Mutability};
+use clean::{self, AttributesExt, Deprecation, GetDefId, SelfTy, Mutability};
 use config::RenderOptions;
 use doctree;
 use fold::DocFolder;
@@ -2458,7 +2458,7 @@ fn document_full(w: &mut fmt::Formatter, item: &clean::Item,
 
 fn document_stability(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item,
                       is_hidden: bool) -> fmt::Result {
-    let stabilities = short_stability(item, cx, true);
+    let stabilities = short_stability(item, cx);
     if !stabilities.is_empty() {
         write!(w, "<div class='stability{}'>", if is_hidden { " hidden" } else { "" })?;
         for stability in stabilities {
@@ -2651,18 +2651,6 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: usize, idx2: usize) -> Ordering
             _ => {
                 if myitem.name.is_none() { continue }
 
-                let stabilities = short_stability(myitem, cx, false);
-
-                let stab_docs = if !stabilities.is_empty() {
-                    stabilities.iter()
-                               .map(|s| format!("[{}]", s))
-                               .collect::<Vec<_>>()
-                               .as_slice()
-                               .join(" ")
-                } else {
-                    String::new()
-                };
-
                 let unsafety_flag = match myitem.inner {
                     clean::FunctionItem(ref func) | clean::ForeignFunctionItem(ref func)
                     if func.header.unsafety == hir::Unsafety::Unsafe => {
@@ -2683,11 +2671,11 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: usize, idx2: usize) -> Ordering
                        <tr class='{stab}{add}module-item'>\
                            <td><a class=\"{class}\" href=\"{href}\" \
                                   title='{title}'>{name}</a>{unsafety_flag}</td>\
-                           <td class='docblock-short'>{stab_docs}{docs}\
+                           <td class='docblock-short'>{stab_tags}{docs}\
                            </td>\
                        </tr>",
                        name = *myitem.name.as_ref().unwrap(),
-                       stab_docs = stab_docs,
+                       stab_tags = stability_tags(myitem),
                        docs = MarkdownSummaryLine(doc_value, &myitem.links()),
                        class = myitem.type_(),
                        add = add,
@@ -2714,101 +2702,123 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: usize, idx2: usize) -> Ordering
     Ok(())
 }
 
-fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec<String> {
+/// Render the stability and deprecation tags that are displayed in the item's summary at the
+/// module level.
+fn stability_tags(item: &clean::Item) -> String {
+    let mut tags = String::new();
+
+    // The trailing space after each tag is to space it properly against the rest of the docs.
+    if item.deprecation().is_some() {
+        tags.push_str("[<div class='stab deprecated'>Deprecated</div>] ");
+    }
+
+    if let Some(stab) = item
+        .stability
+        .as_ref()
+        .filter(|s| s.level == stability::Unstable)
+    {
+        if stab.feature.as_ref().map(|s| &**s) == Some("rustc_private") {
+            tags.push_str("[<div class='stab internal'>Internal</div>] ");
+        } else {
+            tags.push_str("[<div class='stab unstable'>Experimental</div>] ");
+        }
+    }
+
+    if let Some(ref cfg) = item.attrs.cfg {
+        tags.push_str(&format!(
+            "[<div class='stab portability'>{}</div>] ",
+            cfg.render_short_html()
+        ));
+    }
+
+    tags
+}
+
+/// Render the stability and/or deprecation warning that is displayed at the top of the item's
+/// documentation.
+fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> {
     let mut stability = vec![];
     let error_codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build());
 
-    if let Some(stab) = item.stability.as_ref() {
-        let deprecated_reason = if show_reason && !stab.deprecated_reason.is_empty() {
-            format!(": {}", stab.deprecated_reason)
+    if let Some(Deprecation { since, note }) = &item.deprecation() {
+        let mut message = if let Some(since) = since {
+            if stability::deprecation_in_effect(since) {
+                format!("Deprecated since {}", Escape(since))
+            } else {
+                format!("Deprecating in {}", Escape(since))
+            }
         } else {
-            String::new()
+            String::from("Deprecated")
         };
-        if !stab.deprecated_since.is_empty() {
-            let since = if show_reason {
-                format!(" since {}", Escape(&stab.deprecated_since))
-            } else {
-                String::new()
-            };
+
+        if let Some(note) = note {
             let mut ids = cx.id_map.borrow_mut();
-            let html = MarkdownHtml(&deprecated_reason, RefCell::new(&mut ids), error_codes);
-            let text = if stability::deprecation_in_effect(&stab.deprecated_since) {
-                format!("Deprecated{}{}", since, html)
+            let html = MarkdownHtml(&note, RefCell::new(&mut ids), error_codes);
+            message.push_str(&format!(": {}", html));
+        }
+        stability.push(format!("<div class='stab deprecated'>{}</div>", message));
+    }
+
+    if let Some(stab) = item
+        .stability
+        .as_ref()
+        .filter(|stab| stab.level == stability::Unstable)
+    {
+        let is_rustc_private = stab.feature.as_ref().map(|s| &**s) == Some("rustc_private");
+
+        let mut message = if is_rustc_private {
+            "<span class='emoji'>⚙️</span> This is an internal compiler API."
+        } else {
+            "<span class='emoji'>🔬</span> This is a nightly-only experimental API."
+        }
+        .to_owned();
+
+        if let Some(feature) = stab.feature.as_ref() {
+            let mut feature = format!("<code>{}</code>", Escape(&feature));
+            if let (Some(url), Some(issue)) = (&cx.shared.issue_tracker_base_url, stab.issue) {
+                feature.push_str(&format!(
+                    "&nbsp;<a href=\"{url}{issue}\">#{issue}</a>",
+                    url = url,
+                    issue = issue
+                ));
+            }
+
+            message.push_str(&format!(" ({})", feature));
+        }
+
+        if let Some(unstable_reason) = &stab.unstable_reason {
+            // Provide a more informative message than the compiler help.
+            let unstable_reason = if is_rustc_private {
+                "This crate is being loaded from the sysroot, a permanently unstable location \
+                for private compiler dependencies. It is not intended for general use. Prefer \
+                using a public version of this crate from \
+                [crates.io](https://crates.io) via [`Cargo.toml`]\
+                (https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html)."
             } else {
-                format!("Deprecating in {}{}", Escape(&stab.deprecated_since), html)
+                unstable_reason
             };
-            stability.push(format!("<div class='stab deprecated'>{}</div>", text))
-        };
 
-        if stab.level == stability::Unstable {
-            if show_reason {
-                let unstable_extra = match (!stab.feature.is_empty(),
-                                            &cx.shared.issue_tracker_base_url,
-                                            stab.issue) {
-                    (true, &Some(ref tracker_url), Some(issue_no)) if issue_no > 0 =>
-                        format!(" (<code>{} </code><a href=\"{}{}\">#{}</a>)",
-                                Escape(&stab.feature), tracker_url, issue_no, issue_no),
-                    (false, &Some(ref tracker_url), Some(issue_no)) if issue_no > 0 =>
-                        format!(" (<a href=\"{}{}\">#{}</a>)", Escape(&tracker_url), issue_no,
-                                issue_no),
-                    (true, ..) =>
-                        format!(" (<code>{}</code>)", Escape(&stab.feature)),
-                    _ => String::new(),
-                };
-                if stab.unstable_reason.is_empty() {
-                    stability.push(format!("<div class='stab unstable'>\
-                                            <span class=microscope>🔬</span> \
-                                            This is a nightly-only experimental API. {}\
-                                            </div>",
-                                           unstable_extra));
-                } else {
-                    let mut ids = cx.id_map.borrow_mut();
-                    let text = format!("<summary><span class=microscope>🔬</span> \
-                                        This is a nightly-only experimental API. {}\
-                                        </summary>{}",
-                                       unstable_extra,
-                                       MarkdownHtml(
-                                           &stab.unstable_reason,
-                                           RefCell::new(&mut ids),
-                                           error_codes));
-                    stability.push(format!("<div class='stab unstable'><details>{}</details></div>",
-                                   text));
-                }
-            } else {
-                stability.push("<div class='stab unstable'>Experimental</div>".to_string())
-            }
-        };
-    } else if let Some(depr) = item.deprecation.as_ref() {
-        let note = if show_reason && !depr.note.is_empty() {
-            format!(": {}", depr.note)
-        } else {
-            String::new()
-        };
-        let since = if show_reason && !depr.since.is_empty() {
-            format!(" since {}", Escape(&depr.since))
-        } else {
-            String::new()
-        };
+            let mut ids = cx.id_map.borrow_mut();
+            message = format!(
+                "<details><summary>{}</summary>{}</details>",
+                message,
+                MarkdownHtml(&unstable_reason, RefCell::new(&mut ids), error_codes)
+            );
+        }
 
-        let mut ids = cx.id_map.borrow_mut();
-        let text = if stability::deprecation_in_effect(&depr.since) {
-            format!("Deprecated{}{}",
-                    since,
-                    MarkdownHtml(&note, RefCell::new(&mut ids), error_codes))
+        let class = if is_rustc_private {
+            "internal"
         } else {
-            format!("Deprecating in {}{}",
-                    Escape(&depr.since),
-                    MarkdownHtml(&note, RefCell::new(&mut ids), error_codes))
+            "unstable"
         };
-        stability.push(format!("<div class='stab deprecated'>{}</div>", text))
+        stability.push(format!("<div class='stab {}'>{}</div>", class, message));
     }
 
     if let Some(ref cfg) = item.attrs.cfg {
-        stability.push(format!("<div class='stab portability'>{}</div>", if show_reason {
+        stability.push(format!(
+            "<div class='stab portability'>{}</div>",
             cfg.render_long_html()
-        } else {
-            cfg.render_short_html()
-        }));
+        ));
     }
 
     stability
@@ -3037,15 +3047,14 @@ fn trait_item(w: &mut fmt::Formatter, cx: &Context, m: &clean::Item, t: &clean::
         let item_type = m.type_();
         let id = cx.derive_id(format!("{}.{}", item_type, name));
         let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
-        write!(w, "{extra}<h3 id='{id}' class='method'>\
-                   <span id='{ns_id}' class='invisible'><code>",
+        write!(w, "{extra}<h3 id='{id}' class='method'><code id='{ns_id}'>",
                extra = render_spotlight_traits(m)?,
                id = id,
                ns_id = ns_id)?;
         render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl)?;
         write!(w, "</code>")?;
         render_stability_since(w, m, t)?;
-        write!(w, "</span></h3>")?;
+        write!(w, "</h3>")?;
         document(w, cx, m)?;
         Ok(())
     }
@@ -3237,13 +3246,14 @@ fn assoc_type<W: fmt::Write>(w: &mut W, it: &clean::Item,
     Ok(())
 }
 
-fn render_stability_since_raw<'a>(w: &mut fmt::Formatter,
-                                  ver: Option<&'a str>,
-                                  containing_ver: Option<&'a str>) -> fmt::Result {
+fn render_stability_since_raw<'a, T: fmt::Write>(
+    w: &mut T,
+    ver: Option<&'a str>,
+    containing_ver: Option<&'a str>,
+) -> fmt::Result {
     if let Some(v) = ver {
         if containing_ver != ver && v.len() > 0 {
-            write!(w, "<div class='since' title='Stable since Rust version {0}'>{0}</div>",
-                   v)?
+            write!(w, "<div class='since' title='Stable since Rust version {0}'>{0}</div>", v)?
         }
     }
     Ok(())
@@ -3373,11 +3383,10 @@ fn item_struct(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
                 let ns_id = cx.derive_id(format!("{}.{}",
                                               field.name.as_ref().unwrap(),
                                               ItemType::StructField.name_space()));
-                write!(w, "<span id=\"{id}\" class=\"{item_type} small-section-header\">
-                           <a href=\"#{id}\" class=\"anchor field\"></a>
-                           <span id=\"{ns_id}\" class='invisible'>
-                           <code>{name}: {ty}</code>
-                           </span></span>",
+                write!(w, "<span id=\"{id}\" class=\"{item_type} small-section-header\">\
+                           <a href=\"#{id}\" class=\"anchor field\"></a>\
+                           <code id=\"{ns_id}\">{name}: {ty}</code>\
+                           </span>",
                        item_type = ItemType::StructField,
                        id = id,
                        ns_id = ns_id,
@@ -3509,7 +3518,7 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
                                           ItemType::Variant.name_space()));
             write!(w, "<span id=\"{id}\" class=\"variant small-section-header\">\
                        <a href=\"#{id}\" class=\"anchor field\"></a>\
-                       <span id='{ns_id}' class='invisible'><code>{name}",
+                       <code id='{ns_id}'>{name}",
                    id = id,
                    ns_id = ns_id,
                    name = variant.name.as_ref().unwrap())?;
@@ -3525,7 +3534,7 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
                     write!(w, ")")?;
                 }
             }
-            write!(w, "</code></span></span>")?;
+            write!(w, "</code></span>")?;
             document(w, cx, variant)?;
 
             use clean::{Variant, VariantKind};
@@ -3552,8 +3561,8 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
                                                       ItemType::StructField.name_space()));
                         write!(w, "<span id=\"{id}\" class=\"variant small-section-header\">\
                                    <a href=\"#{id}\" class=\"anchor field\"></a>\
-                                   <span id='{ns_id}' class='invisible'><code>{f}:&nbsp;{t}\
-                                   </code></span></span>",
+                                   <code id='{ns_id}'>{f}:&nbsp;{t}\
+                                   </code></span>",
                                id = id,
                                ns_id = ns_id,
                                f = field.name.as_ref().unwrap(),
@@ -3998,7 +4007,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
                    id, i.inner_impl())?;
         }
         write!(w, "<a href='#{}' class='anchor'></a>", id)?;
-        write!(w, "</span></td><td><span class='out-of-band'>")?;
+        write!(w, "</td><td><span class='out-of-band'>")?;
         let since = i.impl_item.stability.as_ref().map(|s| &s.since[..]);
         if let Some(l) = (Item { item: &i.impl_item, cx: cx }).src_href() {
             write!(w, "<div class='ghost'></div>")?;
@@ -4008,7 +4017,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
         } else {
             render_stability_since_raw(w, since, outer_version)?;
         }
-        write!(w, "</span></td></tr></tbody></table></h3>")?;
+        write!(w, "</span></td></tr></tbody></table></span></h3>")?;
         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>",
@@ -4044,52 +4053,73 @@ fn doc_impl_item(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item,
                     let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
                     write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class)?;
                     write!(w, "{}", spotlight_decl(decl)?)?;
-                    write!(w, "<span id='{}' class='invisible'>", ns_id)?;
-                    write!(w, "<table class='table-display'><tbody><tr><td><code>")?;
+                    write!(w, "<table id='{}' class='table-display'><tbody><tr><td><code>", ns_id)?;
                     render_assoc_item(w, item, link.anchor(&id), ItemType::Impl)?;
                     write!(w, "</code>")?;
                     if let Some(l) = (Item { cx, item }).src_href() {
-                        write!(w, "</span></td><td><span class='out-of-band'>")?;
+                        write!(w, "</td><td><span class='out-of-band'>")?;
                         write!(w, "<div class='ghost'></div>")?;
                         render_stability_since_raw(w, item.stable_since(), outer_version)?;
-                        write!(w, "<a class='srclink' href='{}' title='{}'>[src]</a>",
+                        write!(w, "<a class='srclink' href='{}' title='{}'>[src]</a></span>",
                                l, "goto source code")?;
                     } else {
                         write!(w, "</td><td>")?;
                         render_stability_since_raw(w, item.stable_since(), outer_version)?;
                     }
-                    write!(w, "</td></tr></tbody></table></span></h4>")?;
+                    write!(w, "</td></tr></tbody></table></h4>")?;
                 }
             }
             clean::TypedefItem(ref tydef, _) => {
                 let id = cx.derive_id(format!("{}.{}", ItemType::AssociatedType, name));
                 let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
                 write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class)?;
-                write!(w, "<span id='{}' class='invisible'><code>", ns_id)?;
+                write!(w, "<code id='{}'>", ns_id)?;
                 assoc_type(w, item, &Vec::new(), Some(&tydef.type_), link.anchor(&id))?;
-                write!(w, "</code></span></h4>\n")?;
+                write!(w, "</code></h4>")?;
             }
             clean::AssociatedConstItem(ref ty, ref default) => {
+                let mut version = String::new();
+
+                render_stability_since_raw(&mut version, item.stable_since(), outer_version)?;
+
                 let id = cx.derive_id(format!("{}.{}", item_type, name));
                 let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
                 write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class)?;
-                write!(w, "<span id='{}' class='invisible'><code>", ns_id)?;
+                if !version.is_empty() {
+                    write!(w, "<table id='{}' class='table-display'><tbody><tr><td><code>", ns_id)?;
+                } else {
+                    write!(w, "<code id='{}'>", ns_id)?;
+                }
                 assoc_const(w, item, ty, default.as_ref(), link.anchor(&id))?;
+                if !version.is_empty() {
+                    write!(w, "</code>")?;
+                }
                 let src = if let Some(l) = (Item { cx, item }).src_href() {
+                    if !version.is_empty() {
+                        write!(w, "</td><td><span class='out-of-band'>")?;
+                        write!(w, "<div class='ghost'></div>{}", version)?;
+                    }
                     format!("<a class='srclink' href='{}' title='{}'>[src]</a>",
                             l, "goto source code")
                 } else {
+                    if !version.is_empty() {
+                        write!(w, "</td><td>{}", version)?;
+                    }
                     String::new()
                 };
-                write!(w, "</code>{}</span></h4>\n", src)?;
+                if version.is_empty() {
+                    write!(w, "</code>{}</h4>", src)?;
+                } else {
+                    write!(w, "{}</span></td></tr></tbody></table></h4>", src)?;
+                }
             }
             clean::AssociatedTypeItem(ref bounds, ref default) => {
                 let id = cx.derive_id(format!("{}.{}", item_type, name));
                 let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
                 write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class)?;
-                write!(w, "<span id='{}' class='invisible'><code>", ns_id)?;
+                write!(w, "<code id='{}'>", ns_id)?;
                 assoc_type(w, item, bounds, default.as_ref(), link.anchor(&id))?;
-                write!(w, "</code></span></h4>\n")?;
+                write!(w, "</code></h4>")?;
             }
             clean::StrippedItem(..) => return Ok(()),
             _ => panic!("can't make docs for trait item with name {:?}", item.name)
index 1480c54ce4084f51a50a7141bab0bc2a4c807e20..3958986e492775f5f7335e92c50370222bdf3b8b 100644 (file)
@@ -611,7 +611,7 @@ a {
        text-decoration: underline;
 }
 
-.invisible > .srclink {
+.invisible > .srclink, h4 > code + .srclink {
        position: absolute;
        top: 0;
        right: 0;
@@ -769,7 +769,7 @@ body.blur > :not(#help) {
        display: list-item;
 }
 
-.stab .microscope {
+.stab .emoji {
        font-size: 1.5em;
 }
 
index 2cd1a8580890c44320934c700e905799097790a4..be3ffed2b2659f70e8b7933258e0536bcdd21c96 100644 (file)
@@ -174,6 +174,10 @@ a {
        color: #D2991D;
 }
 
+.stab.internal a {
+       color: #304FFE;
+}
+
 a.test-arrow {
        color: #dedede;
 }
@@ -199,6 +203,7 @@ a.test-arrow {
 }
 
 .stab.unstable { background: #FFF5D6; border-color: #FFC600; color: #404040; }
+.stab.internal { background: #FFB9B3; border-color: #B71C1C; color: #404040; }
 .stab.deprecated { background: #F3DFFF; border-color: #7F0087;  color: #404040; }
 .stab.portability { background: #C4ECFF; border-color: #7BA5DB;  color: #404040; }
 
index 4cf35f64d19a4463cb4d1cc071baf19fffd6d79f..4ae10492ae6b2a23e55b20567102a62e76f80dd9 100644 (file)
@@ -174,6 +174,10 @@ a {
        color: #3873AD;
 }
 
+.stab.internal a {
+       color: #304FFE;
+}
+
 a.test-arrow {
        color: #f5f5f5;
 }
@@ -200,6 +204,7 @@ a.test-arrow {
 }
 
 .stab.unstable { background: #FFF5D6; border-color: #FFC600; }
+.stab.internal { background: #FFB9B3; border-color: #B71C1C; }
 .stab.deprecated { background: #F3DFFF; border-color: #7F0087; }
 .stab.portability { background: #C4ECFF; border-color: #7BA5DB; }
 
index ead38f2112687144b85198b463c86a451779cb55..9042cb3c72d6079538b4ccfeec4130d2edb2adc7 100644 (file)
 #![feature(cfg_target_vendor)]
 #![feature(char_error_internals)]
 #![feature(compiler_builtins_lib)]
+#![feature(concat_idents)]
 #![feature(const_int_ops)]
 #![feature(const_ip)]
 #![feature(const_raw_ptr_deref)]
index 5aa043b0fcb2c37769e976b507c4de9453ac7a1a..347e795c4f71d6b54b5f44b3f2061e6fc87dcc22 100644 (file)
@@ -729,6 +729,9 @@ pub fn try_clone(&self) -> io::Result<TcpListener> {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
+        // On WASM, `TcpStream` is uninhabited (as it's unsupported) and so
+        // the `a` variable here is technically unused.
+        #[cfg_attr(target_arch = "wasm32", allow(unused_variables))]
         self.0.accept().map(|(a, b)| (TcpStream(a), b))
     }
 
index 9e957bd87d79e3ac4daa224a43847b63b8709150..fdaf2a821faad876c653fd78c91ba12addf080db 100644 (file)
@@ -73,18 +73,3 @@ fn lang_start<T: ::process::Termination + 'static>
 {
     lang_start_internal(&move || main().report(), argc, argv)
 }
-
-/// Function used for reverting changes to the main stack before setrlimit().
-/// This is POSIX (non-Linux) specific and unlikely to be directly stabilized.
-#[unstable(feature = "rustc_stack_internals", issue = "0")]
-pub unsafe fn deinit_stack_guard() {
-    ::sys::thread::guard::deinit();
-}
-
-/// Function used for resetting the main stack guard address after setrlimit().
-/// This is POSIX specific and unlikely to be directly stabilized.
-#[unstable(feature = "rustc_stack_internals", issue = "0")]
-pub unsafe fn update_stack_guard() {
-    let main_guard = ::sys::thread::guard::init();
-    ::sys_common::thread_info::reset_guard(main_guard);
-}
index 177321439d83cec4940e0c41dd22083a028db4b2..a64e0f068497a803e6e33789b5236ab6b6a8e2d6 100644 (file)
@@ -121,7 +121,6 @@ pub unsafe fn current() -> Option<Guard> {
     pub unsafe fn init() -> Option<Guard> {
         None
     }
-    pub unsafe fn deinit() {}
 }
 
 fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
index ff86180538283c4ed092535a9f800a240837dcc4..ca014fd576bd3743b7d5a113844c36921502f559 100644 (file)
@@ -92,5 +92,4 @@ pub mod guard {
     pub type Guard = !;
     pub unsafe fn current() -> Option<Guard> { None }
     pub unsafe fn init() -> Option<Guard> { None }
-    pub unsafe fn deinit() {}
 }
index 9de12a5e6f154367a005a5c64f52081385efb37b..9f3c4536cb5b6d6a91c773fd11d920b819111da1 100644 (file)
@@ -97,5 +97,4 @@ pub mod guard {
     pub type Guard = !;
     pub unsafe fn current() -> Option<Guard> { None }
     pub unsafe fn init() -> Option<Guard> { None }
-    pub unsafe fn deinit() {}
 }
index d922be520d4be988538b1bb95855474124c83e4e..f30817e69ab0e77b84b7696c79a51cb2f96a4560 100644 (file)
@@ -203,18 +203,21 @@ pub fn accept(&self, storage: *mut sockaddr, len: *mut socklen_t)
         // Linux. This was added in 2.6.28, however, and because we support
         // 2.6.18 we must detect this support dynamically.
         if cfg!(target_os = "linux") {
-            weak! {
-                fn accept4(c_int, *mut sockaddr, *mut socklen_t, c_int) -> c_int
+            syscall! {
+                fn accept4(
+                    fd: c_int,
+                    addr: *mut sockaddr,
+                    addr_len: *mut socklen_t,
+                    flags: c_int
+                ) -> c_int
             }
-            if let Some(accept) = accept4.get() {
-                let res = cvt_r(|| unsafe {
-                    accept(self.0.raw(), storage, len, SOCK_CLOEXEC)
-                });
-                match res {
-                    Ok(fd) => return Ok(Socket(FileDesc::new(fd))),
-                    Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {}
-                    Err(e) => return Err(e),
-                }
+            let res = cvt_r(|| unsafe {
+                accept4(self.0.raw(), storage, len, SOCK_CLOEXEC)
+            });
+            match res {
+                Ok(fd) => return Ok(Socket(FileDesc::new(fd))),
+                Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {}
+                Err(e) => return Err(e),
             }
         }
 
index 03e81a720dc640ececa2e08bb32e631a30547b67..6e8ee44599406a991b4869187684ca39bb2ed474 100644 (file)
@@ -67,7 +67,8 @@ pub fn errno() -> i32 {
 }
 
 /// Sets the platform-specific value of errno
-#[cfg(any(target_os = "solaris", target_os = "fuchsia"))] // only needed for readdir so far
+#[cfg(all(not(target_os = "linux"),
+          not(target_os = "dragonfly")))] // needed for readdir and syscall!
 pub fn set_errno(e: i32) {
     unsafe {
         *errno_location() = e as c_int
@@ -84,6 +85,18 @@ pub fn errno() -> i32 {
     unsafe { errno as i32 }
 }
 
+#[cfg(target_os = "dragonfly")]
+pub fn set_errno(e: i32) {
+    extern {
+        #[thread_local]
+        static mut errno: c_int;
+    }
+
+    unsafe {
+        errno = e;
+    }
+}
+
 /// Gets a detailed string description for the given error number.
 pub fn error_string(errno: i32) -> String {
     extern {
index 0a5dccddddae250c9e6cd35531b921bbf18f9ca4..24b2959a3fa01576ce26c286078b37fdb0f63f5f 100644 (file)
@@ -22,7 +22,7 @@
 pub struct AnonPipe(FileDesc);
 
 pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
-    weak! { fn pipe2(*mut c_int, c_int) -> c_int }
+    syscall! { fn pipe2(fds: *mut c_int, flags: c_int) -> c_int }
     static INVALID: AtomicBool = ATOMIC_BOOL_INIT;
 
     let mut fds = [0; 2];
@@ -39,22 +39,20 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
        !INVALID.load(Ordering::SeqCst)
     {
 
-        if let Some(pipe) = pipe2.get() {
-            // Note that despite calling a glibc function here we may still
-            // get ENOSYS. Glibc has `pipe2` since 2.9 and doesn't try to
-            // emulate on older kernels, so if you happen to be running on
-            // an older kernel you may see `pipe2` as a symbol but still not
-            // see the syscall.
-            match cvt(unsafe { pipe(fds.as_mut_ptr(), libc::O_CLOEXEC) }) {
-                Ok(_) => {
-                    return Ok((AnonPipe(FileDesc::new(fds[0])),
-                               AnonPipe(FileDesc::new(fds[1]))));
-                }
-                Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {
-                    INVALID.store(true, Ordering::SeqCst);
-                }
-                Err(e) => return Err(e),
+        // Note that despite calling a glibc function here we may still
+        // get ENOSYS. Glibc has `pipe2` since 2.9 and doesn't try to
+        // emulate on older kernels, so if you happen to be running on
+        // an older kernel you may see `pipe2` as a symbol but still not
+        // see the syscall.
+        match cvt(unsafe { pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC) }) {
+            Ok(_) => {
+                return Ok((AnonPipe(FileDesc::new(fds[0])),
+                            AnonPipe(FileDesc::new(fds[1]))));
+            }
+            Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {
+                INVALID.store(true, Ordering::SeqCst);
             }
+            Err(e) => return Err(e),
         }
     }
     cvt(unsafe { libc::pipe(fds.as_mut_ptr()) })?;
index 4ff060018ae330a5d99f51abc968ed7f934aacbd..e0d2c620498b69398299b43d51ba1c4dbff56efe 100644 (file)
@@ -211,7 +211,6 @@ pub mod guard {
     pub type Guard = Range<usize>;
     pub unsafe fn current() -> Option<Guard> { None }
     pub unsafe fn init() -> Option<Guard> { None }
-    pub unsafe fn deinit() {}
 }
 
 
@@ -355,26 +354,6 @@ pub unsafe fn init() -> Option<Guard> {
         }
     }
 
-    pub unsafe fn deinit() {
-        if !cfg!(target_os = "linux") {
-            if let Some(stackaddr) = get_stack_start_aligned() {
-                // Remove the protection on the guard page.
-                // FIXME: we cannot unmap the page, because when we mmap()
-                // above it may be already mapped by the OS, which we can't
-                // detect from mmap()'s return value. If we unmap this page,
-                // it will lead to failure growing stack size on platforms like
-                // macOS. Instead, just restore the page to a writable state.
-                // This ain't Linux, so we probably don't need to care about
-                // execstack.
-                let result = mprotect(stackaddr, PAGE_SIZE, PROT_READ | PROT_WRITE);
-
-                if result != 0 {
-                    panic!("unable to reset the guard page");
-                }
-            }
-        }
-    }
-
     #[cfg(any(target_os = "macos",
               target_os = "bitrig",
               target_os = "openbsd",
index 18944be58ee7e6d3fc0618fd6bc003a140a70d2b..7d293f1c47a9aa8ed3cf1043afb3d3a2bf211047 100644 (file)
@@ -77,3 +77,38 @@ unsafe fn fetch(name: &str) -> usize {
     };
     libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) as usize
 }
+
+#[cfg(not(target_os = "linux"))]
+macro_rules! syscall {
+    (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
+        unsafe fn $name($($arg_name: $t),*) -> $ret {
+            use libc;
+            use super::os;
+
+            weak! { fn $name($($t),*) -> $ret }
+
+            if let Some(fun) = $name.get() {
+                fun($($arg_name),*)
+            } else {
+                os::set_errno(libc::ENOSYS);
+                -1
+            }
+        }
+    )
+}
+
+#[cfg(target_os = "linux")]
+macro_rules! syscall {
+    (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
+        unsafe fn $name($($arg_name:$t),*) -> $ret {
+            // This looks like a hack, but concat_idents only accepts idents
+            // (not paths).
+            use libc::*;
+
+            syscall(
+                concat_idents!(SYS_, $name),
+                $($arg_name as c_long),*
+            ) as $ret
+        }
+    )
+}
index 3d74ffdc14a596befac7ac8a9a862581267a8929..f9abb0b825a3409f3b6216d87d7bae4d1ee995aa 100644 (file)
@@ -68,7 +68,6 @@ pub mod guard {
     pub type Guard = !;
     pub unsafe fn current() -> Option<Guard> { None }
     pub unsafe fn init() -> Option<Guard> { None }
-    pub unsafe fn deinit() {}
 }
 
 cfg_if! {
index 1a97dd10ced8d2c284b299b84a8f5c3caa236c17..621ae2fda58c3556212e356f84634ad58ccf7089 100644 (file)
@@ -98,5 +98,4 @@ pub mod guard {
     pub type Guard = !;
     pub unsafe fn current() -> Option<Guard> { None }
     pub unsafe fn init() -> Option<Guard> { None }
-    pub unsafe fn deinit() {}
 }
index 310cf27689bc51c13856537f01ddba972b8aedaf..b807a65f6aed60d86d63b27274a38a85cf78bedf 100644 (file)
@@ -732,7 +732,6 @@ pub fn edition(&self) -> Edition {
 pub trait Resolver {
     fn next_node_id(&mut self) -> ast::NodeId;
     fn get_module_scope(&mut self, id: ast::NodeId) -> Mark;
-    fn eliminate_crate_var(&mut self, item: P<ast::Item>) -> P<ast::Item>;
 
     fn visit_ast_fragment_with_placeholders(&mut self, mark: Mark, fragment: &AstFragment,
                                             derives: &[Mark]);
@@ -766,7 +765,6 @@ pub fn determined(determined: bool) -> Determinacy {
 impl Resolver for DummyResolver {
     fn next_node_id(&mut self) -> ast::NodeId { ast::DUMMY_NODE_ID }
     fn get_module_scope(&mut self, _id: ast::NodeId) -> Mark { Mark::root() }
-    fn eliminate_crate_var(&mut self, item: P<ast::Item>) -> P<ast::Item> { item }
 
     fn visit_ast_fragment_with_placeholders(&mut self, _invoc: Mark, _fragment: &AstFragment,
                                             _derives: &[Mark]) {}
index 03c7aa9682477701d5fc0efa52ba72b720088418..57ccc3e981720a7dede977a971dc7a3ef73c7f7c 100644 (file)
@@ -203,10 +203,7 @@ fn macro_bang_format(path: &ast::Path) -> ExpnFormat {
         if i != 0 {
             path_str.push_str("::");
         }
-
-        if segment.ident.name != keywords::PathRoot.name() &&
-            segment.ident.name != keywords::DollarCrate.name()
-        {
+        if segment.ident.name != keywords::PathRoot.name() {
             path_str.push_str(&segment.ident.as_str())
         }
     }
index e3cccacb3c3db9343d138227091df9cc2278d163..200b1cecc03d6a61fed2417393ef4496249a7b47 100644 (file)
@@ -81,6 +81,7 @@ pub fn with_span_handler(handler: Handler, source_map: Lrc<SourceMap>) -> ParseS
         }
     }
 
+    #[inline]
     pub fn source_map(&self) -> &SourceMap {
         &self.source_map
     }
index ed7466574596fc586159abdc3d37c78c3783842c..badcc4ed8762d10e63f3492b2a1906417e07ad35 100644 (file)
@@ -633,7 +633,9 @@ pub fn interpolated_to_tokenstream(&self, sess: &ParseSess, span: Span)
             (&Shebang(a), &Shebang(b)) => a == b,
 
             (&Lifetime(a), &Lifetime(b)) => a.name == b.name,
-            (&Ident(a, b), &Ident(c, d)) => a.name == c.name && b == d,
+            (&Ident(a, b), &Ident(c, d)) => b == d && (a.name == c.name ||
+                                                       a.name == keywords::DollarCrate.name() ||
+                                                       c.name == keywords::DollarCrate.name()),
 
             (&Literal(ref a, b), &Literal(ref c, d)) => {
                 b == d && a.probably_equal_for_proc_macro(c)
index 41165c7e36d58414bebd5ee358bec038d6594280..5e7707f4e5c3c4dc45bae63b9238a3201b20281f 100644 (file)
@@ -16,7 +16,6 @@
 use attr;
 use source_map::{self, SourceMap, Spanned};
 use syntax_pos::{self, BytePos};
-use syntax_pos::hygiene::{Mark, SyntaxContext};
 use parse::token::{self, BinOpToken, Token};
 use parse::lexer::comments;
 use parse::{self, ParseSess};
@@ -724,12 +723,12 @@ fn print_attribute_path(&mut self, path: &ast::Path) -> io::Result<()> {
             if i > 0 {
                 self.writer().word("::")?
             }
-            if segment.ident.name != keywords::PathRoot.name() &&
-               segment.ident.name != keywords::DollarCrate.name()
-            {
-                self.writer().word(segment.ident.as_str().get())?;
-            } else if segment.ident.name == keywords::DollarCrate.name() {
-                self.print_dollar_crate(segment.ident.span.ctxt())?;
+            if segment.ident.name != keywords::PathRoot.name() {
+                if segment.ident.name == keywords::DollarCrate.name() {
+                    self.print_dollar_crate(segment.ident)?;
+                } else {
+                    self.writer().word(segment.ident.as_str().get())?;
+                }
             }
         }
         Ok(())
@@ -843,17 +842,19 @@ fn space_if_not_bol(&mut self) -> io::Result<()> {
 
     fn nbsp(&mut self) -> io::Result<()> { self.writer().word(" ") }
 
-    fn print_dollar_crate(&mut self, mut ctxt: SyntaxContext) -> io::Result<()> {
-        if let Some(mark) = ctxt.adjust(Mark::root()) {
-            // Make a best effort to print something that complies
-            if mark.is_builtin() {
-                if let Some(name) = std_inject::injected_crate_name() {
-                    self.writer().word("::")?;
-                    self.writer().word(name)?;
-                }
-            }
+    // AST pretty-printer is used as a fallback for turning AST structures into token streams for
+    // proc macros. Additionally, proc macros may stringify their input and expect it survive the
+    // stringification (especially true for proc macro derives written between Rust 1.15 and 1.30).
+    // So we need to somehow pretty-print `$crate` in paths in a way preserving at least some of
+    // its hygiene data, most importantly name of the crate it refers to.
+    // As a result we print `$crate` as `crate` if it refers to the local crate
+    // and as `::other_crate_name` if it refers to some other crate.
+    fn print_dollar_crate(&mut self, ident: ast::Ident) -> io::Result<()> {
+        let name = ident.span.ctxt().dollar_crate_name();
+        if !ast::Ident::with_empty_ctxt(name).is_path_segment_keyword() {
+            self.writer().word("::")?;
         }
-        Ok(())
+        self.writer().word(name.as_str().get())
     }
 }
 
@@ -2463,14 +2464,15 @@ fn print_path_segment(&mut self,
                           colons_before_params: bool)
                           -> io::Result<()>
     {
-        if segment.ident.name != keywords::PathRoot.name() &&
-           segment.ident.name != keywords::DollarCrate.name() {
-            self.print_ident(segment.ident)?;
+        if segment.ident.name != keywords::PathRoot.name() {
+            if segment.ident.name == keywords::DollarCrate.name() {
+                self.print_dollar_crate(segment.ident)?;
+            } else {
+                self.print_ident(segment.ident)?;
+            }
             if let Some(ref args) = segment.args {
                 self.print_generic_args(args, colons_before_params)?;
             }
-        } else if segment.ident.name == keywords::DollarCrate.name() {
-            self.print_dollar_crate(segment.ident.span.ctxt())?;
         }
         Ok(())
     }
index c11ef33f931d8ab94a82ba8ceca62795333595f1..013ecd3d343c28c6c0422db40938956421e2e912 100644 (file)
@@ -348,7 +348,9 @@ fn semantic_tree(tree: &TokenTree) -> bool {
                 | TokenTree::Token(_, Token::Semi)
                 // The pretty printer collapses whitespace arbitrarily and can
                 // introduce whitespace from `NoDelim`.
-                | TokenTree::Token(_, Token::Whitespace) => false,
+                | TokenTree::Token(_, Token::Whitespace)
+                // The pretty printer can turn `$crate` into `::crate_name`
+                | TokenTree::Token(_, Token::ModSep) => false,
                 _ => true
             }
         }
index 5c82d1911383ee3bee9761e90feac47e4d321a48..cc2fa68568713283ef2d78df097aecc6107ca4ab 100644 (file)
@@ -74,7 +74,6 @@ fn expand(&self,
         // Mark attributes as known, and used.
         MarkAttrs(&self.attrs).visit_item(&item);
 
-        let item = ecx.resolver.eliminate_crate_var(item);
         let token = Token::interpolated(token::NtItem(item));
         let input = tokenstream::TokenTree::Token(DUMMY_SP, token).into();
 
index a04d6c92b7817d7f6174c77f467cdb3d53cc025d..ca960cbe41b5d288a7e78aa3a590aa4f122f52dd 100644 (file)
@@ -81,29 +81,23 @@ macro_rules! tt {
                     $($field $(: $value)*,)*
                     span,
                 })
-            )
+            );
+            ($ty:ident::$method:ident($($value:expr),*)) => (
+                TokenTree::$ty(self::$ty::$method($($value,)* span))
+            );
         }
         macro_rules! op {
             ($a:expr) => {
-                tt!(Punct { ch: $a, joint })
+                tt!(Punct::new($a, joint))
             };
             ($a:expr, $b:expr) => {{
-                stack.push(tt!(Punct { ch: $b, joint }));
-                tt!(Punct {
-                    ch: $a,
-                    joint: true
-                })
+                stack.push(tt!(Punct::new($b, joint)));
+                tt!(Punct::new($a, true))
             }};
             ($a:expr, $b:expr, $c:expr) => {{
-                stack.push(tt!(Punct { ch: $c, joint }));
-                stack.push(tt!(Punct {
-                    ch: $b,
-                    joint: true
-                }));
-                tt!(Punct {
-                    ch: $a,
-                    joint: true
-                })
+                stack.push(tt!(Punct::new($c, joint)));
+                stack.push(tt!(Punct::new($b, true)));
+                tt!(Punct::new($a, true))
             }};
         }
 
@@ -156,20 +150,13 @@ macro_rules! op {
             Question => op!('?'),
             SingleQuote => op!('\''),
 
-            Ident(ident, is_raw) => tt!(Ident {
-                sym: ident.name,
-                is_raw
-            }),
+            Ident(ident, false) if ident.name == keywords::DollarCrate.name() =>
+                tt!(Ident::dollar_crate()),
+            Ident(ident, is_raw) => tt!(Ident::new(ident.name, is_raw)),
             Lifetime(ident) => {
                 let ident = ident.without_first_quote();
-                stack.push(tt!(Ident {
-                    sym: ident.name,
-                    is_raw: false
-                }));
-                tt!(Punct {
-                    ch: '\'',
-                    joint: true
-                })
+                stack.push(tt!(Ident::new(ident.name, false)));
+                tt!(Punct::new('\'', true))
             }
             Literal(lit, suffix) => tt!(Literal { lit, suffix }),
             DocComment(c) => {
@@ -193,15 +180,9 @@ macro_rules! op {
                     span: DelimSpan::from_single(span),
                 }));
                 if style == ast::AttrStyle::Inner {
-                    stack.push(tt!(Punct {
-                        ch: '!',
-                        joint: false
-                    }));
+                    stack.push(tt!(Punct::new('!', false)));
                 }
-                tt!(Punct {
-                    ch: '#',
-                    joint: false
-                })
+                tt!(Punct::new('#', false))
             }
 
             Interpolated(_) => {
@@ -237,7 +218,7 @@ fn to_internal(self) -> TokenStream {
                 )
                 .into();
             }
-            TokenTree::Ident(self::Ident { sym, span, is_raw }) => {
+            TokenTree::Ident(self::Ident { sym, is_raw, span }) => {
                 let token = Ident(ast::Ident::new(sym, span), is_raw);
                 return tokenstream::TokenTree::Token(span, token).into();
             }
@@ -338,11 +319,52 @@ pub struct Punct {
     span: Span,
 }
 
+impl Punct {
+    fn new(ch: char, joint: bool, span: Span) -> Punct {
+        const LEGAL_CHARS: &[char] = &['=', '<', '>', '!', '~', '+', '-', '*', '/', '%', '^',
+                                       '&', '|', '@', '.', ',', ';', ':', '#', '$', '?', '\''];
+        if !LEGAL_CHARS.contains(&ch) {
+            panic!("unsupported character `{:?}`", ch)
+        }
+        Punct { ch, joint, span }
+    }
+}
+
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Ident {
     sym: Symbol,
-    span: Span,
     is_raw: bool,
+    span: Span,
+}
+
+impl Ident {
+    fn is_valid(string: &str) -> bool {
+        let mut chars = string.chars();
+        if let Some(start) = chars.next() {
+            (start == '_' || start.is_xid_start())
+                && chars.all(|cont| cont == '_' || cont.is_xid_continue())
+        } else {
+            false
+        }
+    }
+    fn new(sym: Symbol, is_raw: bool, span: Span) -> Ident {
+        let string = sym.as_str().get();
+        if !Self::is_valid(string) {
+            panic!("`{:?}` is not a valid identifier", string)
+        }
+        if is_raw {
+            let normalized_sym = Symbol::intern(string);
+            if normalized_sym == keywords::Underscore.name() ||
+               ast::Ident::with_empty_ctxt(normalized_sym).is_path_segment_keyword() {
+                panic!("`{:?}` is not a valid raw identifier", string)
+            }
+        }
+        Ident { sym, is_raw, span }
+    }
+    fn dollar_crate(span: Span) -> Ident {
+        // `$crate` is accepted as an ident only if it comes from the compiler.
+        Ident { sym: keywords::DollarCrate.name(), is_raw: false, span }
+    }
 }
 
 // FIXME(eddyb) `Literal` should not expose internal `Debug` impls.
@@ -492,11 +514,7 @@ fn set_span(&mut self, group: &mut Self::Group, span: Self::Span) {
 
 impl server::Punct for Rustc<'_> {
     fn new(&mut self, ch: char, spacing: Spacing) -> Self::Punct {
-        Punct {
-            ch,
-            joint: spacing == Spacing::Joint,
-            span: server::Span::call_site(self),
-        }
+        Punct::new(ch, spacing == Spacing::Joint, server::Span::call_site(self))
     }
     fn as_char(&mut self, punct: Self::Punct) -> char {
         punct.ch
@@ -518,14 +536,7 @@ fn with_span(&mut self, punct: Self::Punct, span: Self::Span) -> Self::Punct {
 
 impl server::Ident for Rustc<'_> {
     fn new(&mut self, string: &str, span: Self::Span, is_raw: bool) -> Self::Ident {
-        let sym = Symbol::intern(string);
-        if is_raw
-            && (sym == keywords::Underscore.name()
-                || ast::Ident::with_empty_ctxt(sym).is_path_segment_keyword())
-        {
-            panic!("`{:?}` is not a valid raw identifier", string)
-        }
-        Ident { sym, span, is_raw }
+        Ident::new(Symbol::intern(string), is_raw, span)
     }
     fn span(&mut self, ident: Self::Ident) -> Self::Span {
         ident.span
index 74f63b5e2c6045394fd6242f4966fd08cf36f1cc..3dc884a94c0dc200be3bd9b4410b895777a79bf6 100644 (file)
 use GLOBALS;
 use Span;
 use edition::{Edition, DEFAULT_EDITION};
-use symbol::Symbol;
+use symbol::{keywords, Symbol};
 
 use serialize::{Encodable, Decodable, Encoder, Decoder};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use std::fmt;
+use std::{fmt, mem};
 
 /// A SyntaxContext represents a chain of macro expansions (represented by marks).
 #[derive(Clone, Copy, PartialEq, Eq, Default, PartialOrd, Ord, Hash)]
@@ -37,6 +37,8 @@ struct SyntaxContextData {
     opaque: SyntaxContext,
     // This context, but with all transparent marks filtered away.
     opaque_and_semitransparent: SyntaxContext,
+    // Name of the crate to which `$crate` with this context would resolve.
+    dollar_crate_name: Symbol,
 }
 
 /// A mark is a unique id associated with a macro expansion.
@@ -47,7 +49,6 @@ struct SyntaxContextData {
 struct MarkData {
     parent: Mark,
     default_transparency: Transparency,
-    is_builtin: bool,
     expn_info: Option<ExpnInfo>,
 }
 
@@ -77,7 +78,6 @@ pub fn fresh(parent: Mark) -> Self {
                 parent,
                 // By default expansions behave like `macro_rules`.
                 default_transparency: Transparency::SemiTransparent,
-                is_builtin: false,
                 expn_info: None,
             });
             Mark(data.marks.len() as u32 - 1)
@@ -121,18 +121,6 @@ pub fn set_default_transparency(self, transparency: Transparency) {
         HygieneData::with(|data| data.marks[self.0 as usize].default_transparency = transparency)
     }
 
-    #[inline]
-    pub fn is_builtin(self) -> bool {
-        assert_ne!(self, Mark::root());
-        HygieneData::with(|data| data.marks[self.0 as usize].is_builtin)
-    }
-
-    #[inline]
-    pub fn set_is_builtin(self, is_builtin: bool) {
-        assert_ne!(self, Mark::root());
-        HygieneData::with(|data| data.marks[self.0 as usize].is_builtin = is_builtin)
-    }
-
     pub fn is_descendant_of(mut self, ancestor: Mark) -> bool {
         HygieneData::with(|data| {
             while self != ancestor {
@@ -206,7 +194,6 @@ impl HygieneData {
                 // If the root is opaque, then loops searching for an opaque mark
                 // will automatically stop after reaching it.
                 default_transparency: Transparency::Opaque,
-                is_builtin: true,
                 expn_info: None,
             }],
             syntax_contexts: vec![SyntaxContextData {
@@ -215,6 +202,7 @@ impl HygieneData {
                 prev_ctxt: SyntaxContext(0),
                 opaque: SyntaxContext(0),
                 opaque_and_semitransparent: SyntaxContext(0),
+                dollar_crate_name: keywords::DollarCrate.name(),
             }],
             markings: FxHashMap::default(),
             default_edition: DEFAULT_EDITION,
@@ -262,7 +250,6 @@ pub fn allocate_directly(expansion_info: ExpnInfo) -> Self {
             data.marks.push(MarkData {
                 parent: Mark::root(),
                 default_transparency: Transparency::SemiTransparent,
-                is_builtin: false,
                 expn_info: Some(expansion_info),
             });
 
@@ -274,6 +261,7 @@ pub fn allocate_directly(expansion_info: ExpnInfo) -> Self {
                 prev_ctxt: SyntaxContext::empty(),
                 opaque: SyntaxContext::empty(),
                 opaque_and_semitransparent: SyntaxContext::empty(),
+                dollar_crate_name: keywords::DollarCrate.name(),
             });
             SyntaxContext(data.syntax_contexts.len() as u32 - 1)
         })
@@ -340,6 +328,7 @@ fn apply_mark_internal(self, mark: Mark, transparency: Transparency) -> SyntaxCo
                         prev_ctxt,
                         opaque: new_opaque,
                         opaque_and_semitransparent: new_opaque,
+                        dollar_crate_name: keywords::DollarCrate.name(),
                     });
                     new_opaque
                 });
@@ -357,6 +346,7 @@ fn apply_mark_internal(self, mark: Mark, transparency: Transparency) -> SyntaxCo
                         prev_ctxt,
                         opaque,
                         opaque_and_semitransparent: new_opaque_and_semitransparent,
+                        dollar_crate_name: keywords::DollarCrate.name(),
                     });
                     new_opaque_and_semitransparent
                 });
@@ -372,6 +362,7 @@ fn apply_mark_internal(self, mark: Mark, transparency: Transparency) -> SyntaxCo
                     prev_ctxt,
                     opaque,
                     opaque_and_semitransparent,
+                    dollar_crate_name: keywords::DollarCrate.name(),
                 });
                 new_opaque_and_semitransparent_and_transparent
             })
@@ -526,6 +517,21 @@ pub fn modern_and_legacy(self) -> SyntaxContext {
     pub fn outer(self) -> Mark {
         HygieneData::with(|data| data.syntax_contexts[self.0 as usize].outer_mark)
     }
+
+    pub fn dollar_crate_name(self) -> Symbol {
+        HygieneData::with(|data| data.syntax_contexts[self.0 as usize].dollar_crate_name)
+    }
+
+    pub fn set_dollar_crate_name(self, dollar_crate_name: Symbol) {
+        HygieneData::with(|data| {
+            let prev_dollar_crate_name = mem::replace(
+                &mut data.syntax_contexts[self.0 as usize].dollar_crate_name, dollar_crate_name
+            );
+            assert!(dollar_crate_name == prev_dollar_crate_name ||
+                    prev_dollar_crate_name == keywords::DollarCrate.name(),
+                    "$crate name is reset for a syntax context");
+        })
+    }
 }
 
 impl fmt::Debug for SyntaxContext {
diff --git a/src/test/debuginfo/nil-enum.rs b/src/test/debuginfo/nil-enum.rs
deleted file mode 100644 (file)
index ab42b2e..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// NOTE Instantiating an empty enum is UB. This test may break in the future.
-
-// LLDB can't handle zero-sized values
-// ignore-lldb
-
-
-// Require LLVM with DW_TAG_variant_part and a gdb that can read it.
-// gdb 8.2.0 crashes on this test case, see
-// https://sourceware.org/bugzilla/show_bug.cgi?id=23626
-// This will be fixed in the next release, which will be >= 8.2.1.
-// min-system-llvm-version: 7.0
-// min-gdb-version: 8.2.1
-
-// compile-flags:-g
-// gdb-command:run
-
-// gdb-command:print first
-// gdbr-check:$1 = nil_enum::ANilEnum {<No data fields>}
-
-// gdb-command:print second
-// gdbr-check:$2 = nil_enum::AnotherNilEnum {<No data fields>}
-
-#![allow(unused_variables)]
-#![feature(omit_gdb_pretty_printer_section)]
-#![feature(maybe_uninit)]
-#![omit_gdb_pretty_printer_section]
-
-use std::mem::MaybeUninit;
-
-enum ANilEnum {}
-enum AnotherNilEnum {}
-
-// This test relies on gdbg printing the string "{<No data fields>}" for empty
-// structs (which may change some time)
-// The error from gdbr is expected since nil enums are not supposed to exist.
-fn main() {
-    unsafe {
-        let first: ANilEnum = MaybeUninit::uninitialized().into_inner();
-        let second: AnotherNilEnum = MaybeUninit::uninitialized().into_inner();
-
-        zzz(); // #break
-    }
-}
-
-fn zzz() {()}
index 7da55c0868cd2bf6d5a3611dd1482f706dc88ff4..f48862ff9330b107dcd32013f4f8481f52b24c70 100644 (file)
@@ -87,8 +87,8 @@ fn main() {
 //         ...
 //         _14 = &mut (*_10);
 //         Retag(_14);
-//         EscapeToRaw(move _14);
 //         _13 = move _14 as *mut i32 (Misc);
+//         Retag([raw] _13);
 //         ...
 //         _17 = move _18(move _19) -> bb2;
 //     }
diff --git a/src/test/mir-opt/uninhabited-enum.rs b/src/test/mir-opt/uninhabited-enum.rs
new file mode 100644 (file)
index 0000000..904a9c4
--- /dev/null
@@ -0,0 +1,37 @@
+#![feature(never_type)]
+
+pub enum Void {}
+
+#[no_mangle]
+pub fn process_never(input: *const !) {
+   let _input = unsafe { &*input };
+}
+
+#[no_mangle]
+pub fn process_void(input: *const Void) {
+   let _input = unsafe { &*input };
+   // In the future, this should end with `unreachable`, but we currently only do
+   // unreachability analysis for `!`.
+}
+
+fn main() {}
+
+// END RUST SOURCE
+//
+// START rustc.process_never.SimplifyLocals.after.mir
+// bb0: {
+//     StorageLive(_2);
+//     _2 = &(*_1);
+//     StorageDead(_2);
+//     unreachable;
+// }
+// END rustc.process_never.SimplifyLocals.after.mir
+//
+// START rustc.process_void.SimplifyLocals.after.mir
+// bb0: {
+//     StorageLive(_2);
+//     _2 = &(*_1);
+//     StorageDead(_2);
+//     return;
+// }
+// END rustc.process_void.SimplifyLocals.after.mir
index 5f42b86c82a81e3c3984675c28a10c6431c81b7a..3b01ab3a47b6a30ada6d0ac8dc2d936d208f7dda 100644 (file)
@@ -39,8 +39,8 @@ pub fn bar() ({
 
 
 
-                  ((::fmt::format as
-                       for<'r> fn(std::fmt::Arguments<'r>) -> std::string::String {std::fmt::format})(((<::fmt::Arguments>::new_v1
+                  (($crate::fmt::format as
+                       for<'r> fn(std::fmt::Arguments<'r>) -> std::string::String {std::fmt::format})(((<$crate::fmt::Arguments>::new_v1
                                                                                                            as
                                                                                                            fn(&[&str], &[std::fmt::ArgumentV1<'_>]) -> std::fmt::Arguments<'_> {std::fmt::Arguments<'_>::new_v1})((&([("test"
                                                                                                                                                                                                                           as
index 80a7ce9691126a4aa3892b61a0d8a463548797d5..6ec70bb8c09c840ca7c1c11ebc1ce8c4427fccca 100644 (file)
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(arbitrary_self_types)]
 #![feature(pin)]
 #![feature(rustc_attrs)]
 
@@ -23,6 +22,7 @@ trait Trait {
     fn by_arc(self: Arc<Self>) -> i64;
     fn by_pin_mut(self: Pin<&mut Self>) -> i64;
     fn by_pin_box(self: Pin<Box<Self>>) -> i64;
+    fn by_pin_pin_pin_ref(self: Pin<Pin<Pin<&Self>>>) -> i64;
 }
 
 impl Trait for i64 {
@@ -38,6 +38,9 @@ fn by_pin_mut(self: Pin<&mut Self>) -> i64 {
     fn by_pin_box(self: Pin<Box<Self>>) -> i64 {
         *self
     }
+    fn by_pin_pin_pin_ref(self: Pin<Pin<Pin<&Self>>>) -> i64 {
+        *self
+    }
 }
 
 fn main() {
@@ -53,4 +56,8 @@ fn main() {
 
     let pin_box = Into::<Pin<Box<i64>>>::into(Box::new(4i64)) as Pin<Box<dyn Trait>>;
     assert_eq!(4, pin_box.by_pin_box());
+
+    let value = 5i64;
+    let pin_pin_pin_ref = Pin::new(Pin::new(Pin::new(&value))) as Pin<Pin<Pin<&dyn Trait>>>;
+    assert_eq!(5, pin_pin_pin_ref.by_pin_pin_pin_ref());
 }
index 7fb7eec12560145768c1e4e5efc0035b9c908520..f595bb0da9a27737fde9c6a50011d387bd2da612 100644 (file)
@@ -14,6 +14,7 @@
 #![feature(slice_patterns)]
 #![allow(unreachable_patterns)]
 #![allow(unreachable_code)]
+#![allow(unused_variables)]
 
 #[allow(dead_code)]
 fn foo(z: !) {
diff --git a/src/test/run-pass/issue-53843.rs b/src/test/run-pass/issue-53843.rs
new file mode 100644 (file)
index 0000000..4b15ecb
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::ops::Deref;
+
+pub struct Pin<P>(P);
+
+impl<P, T> Deref for Pin<P>
+where
+    P: Deref<Target=T>,
+{
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        &*self.0
+    }
+}
+
+impl<P> Pin<P> {
+    fn poll(self) {}
+}
+
+fn main() {
+    let mut unit = ();
+    let pin = Pin(&mut unit);
+    pin.poll();
+}
index 3937f9c1930777c4f18869b019f0449fef6ea242..5a5a2adc124e63ec4c4ccb5fee3b658647ea2245 100644 (file)
@@ -11,6 +11,7 @@
 // run-pass
 #![allow(dead_code)]
 #![allow(unused_variables)]
+#![recursion_limit = "128"]
 // this used to cause exponential code-size blowup during LLVM passes.
 
 #![feature(test)]
diff --git a/src/test/rustdoc/assoc-consts-version.rs b/src/test/rustdoc/assoc-consts-version.rs
new file mode 100644 (file)
index 0000000..2295be2
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-tidy-linelength
+
+#![crate_name = "foo"]
+
+#![feature(staged_api)]
+
+#![stable(since="1.1.1", feature="rust1")]
+
+#[stable(since="1.1.1", feature="rust1")]
+pub struct SomeStruct;
+
+impl SomeStruct {
+    // @has 'foo/struct.SomeStruct.html' '//*[@id="SOME_CONST.v"]//div[@class="since"]' '1.1.2'
+    #[stable(since="1.1.2", feature="rust2")]
+    pub const SOME_CONST: usize = 0;
+}
index d152be33f4c7426e272c19978b31438cbc98ad68..100bf7af0e9b307d0d199892b02fae9d204a1993 100644 (file)
@@ -15,9 +15,9 @@
 // @has assoc_types/trait.Index.html
 pub trait Index<I: ?Sized> {
     // @has - '//*[@id="associatedtype.Output"]//code' 'type Output: ?Sized'
-    // @has - '//*[@id="Output.t"]//code' 'type Output: ?Sized'
+    // @has - '//code[@id="Output.t"]' 'type Output: ?Sized'
     type Output: ?Sized;
-    // @has - '//*[@id="index.v"]//code' 'fn index'
+    // @has - '//code[@id="index.v"]' 'fn index'
     // @has - '//*[@id="tymethod.index"]//code' \
     //      "fn index<'a>(&'a self, index: I) -> &'a Self::Output"
     // @has - '//*[@id="tymethod.index"]//code//a[@href="../assoc_types/trait.Index.html#associatedtype.Output"]' \
diff --git a/src/test/rustdoc/const-display.rs b/src/test/rustdoc/const-display.rs
new file mode 100644 (file)
index 0000000..8ac0d07
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_name = "foo"]
+
+#![unstable(feature = "humans",
+            reason = "who ever let humans program computers, we're apparently really bad at it",
+            issue = "0")]
+
+#![feature(rustc_const_unstable, const_fn, foo, foo2)]
+#![feature(min_const_unsafe_fn)]
+#![feature(staged_api)]
+
+// @has 'foo/fn.foo.html' '//pre' 'pub unsafe fn foo() -> u32'
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature="foo")]
+pub const unsafe fn foo() -> u32 { 42 }
+
+// @has 'foo/fn.foo2.html' '//pre' 'pub fn foo2() -> u32'
+#[unstable(feature = "humans", issue="0")]
+pub const fn foo2() -> u32 { 42 }
+
+// @has 'foo/fn.bar2.html' '//pre' 'pub const fn bar2() -> u32'
+#[stable(feature = "rust1", since = "1.0.0")]
+pub const fn bar2() -> u32 { 42 }
+
+// @has 'foo/fn.foo2_gated.html' '//pre' 'pub unsafe fn foo2_gated() -> u32'
+#[unstable(feature = "foo2", issue="0")]
+pub const unsafe fn foo2_gated() -> u32 { 42 }
+
+// @has 'foo/fn.bar2_gated.html' '//pre' 'pub const unsafe fn bar2_gated() -> u32'
+#[stable(feature = "rust1", since = "1.0.0")]
+pub const unsafe fn bar2_gated() -> u32 { 42 }
+
+// @has 'foo/fn.bar_not_gated.html' '//pre' 'pub unsafe fn bar_not_gated() -> u32'
+pub const unsafe fn bar_not_gated() -> u32 { 42 }
index 744304a62c216ec0a61768d85b9a9b367241f419..63447ad169002377940202115ba6d429ec2822aa 100644 (file)
 
 #![feature(deprecated)]
 
+// @matches deprecated/index.html '//*[@class="docblock-short"]' \
+//      '^\[Deprecated\] Deprecated docs'
 // @has deprecated/struct.S.html '//*[@class="stab deprecated"]' \
 //      'Deprecated since 1.0.0: text'
+/// Deprecated docs
 #[deprecated(since = "1.0.0", note = "text")]
 pub struct S;
+
+// @matches deprecated/index.html '//*[@class="docblock-short"]' '^Docs'
+/// Docs
+pub struct T;
+
+// @matches deprecated/struct.U.html '//*[@class="stab deprecated"]' \
+//      'Deprecated since 1.0.0$'
+#[deprecated(since = "1.0.0")]
+pub struct U;
+
+// @matches deprecated/struct.V.html '//*[@class="stab deprecated"]' \
+//      'Deprecated: text$'
+#[deprecated(note = "text")]
+pub struct V;
+
+// @matches deprecated/struct.W.html '//*[@class="stab deprecated"]' \
+//      'Deprecated$'
+#[deprecated]
+pub struct W;
diff --git a/src/test/rustdoc/internal.rs b/src/test/rustdoc/internal.rs
new file mode 100644 (file)
index 0000000..ba58da1
--- /dev/null
@@ -0,0 +1,10 @@
+// compile-flags: -Z force-unstable-if-unmarked
+
+// @matches internal/index.html '//*[@class="docblock-short"]' \
+//      '^\[Internal\] Docs'
+// @has internal/struct.S.html '//*[@class="stab internal"]' \
+//      'This is an internal compiler API. (rustc_private)'
+/// Docs
+pub struct S;
+
+fn main() {}
index e82e93230aa07bf587a993254928cffffbd15491..4723b04a078be75e405bd989305e1c934cabf31c 100644 (file)
 #![unstable(feature="test", issue="27759")]
 
 // @has issue_27759/unstable/index.html
-// @has - '<code>test </code>'
-// @has - '<a href="http://issue_url/27759">#27759</a>'
+// @has - '<code>test</code>&nbsp;<a href="http://issue_url/27759">#27759</a>'
 #[unstable(feature="test", issue="27759")]
 pub mod unstable {
     // @has issue_27759/unstable/fn.issue.html
-    // @has - '<code>test_function </code>'
-    // @has - '<a href="http://issue_url/1234567890">#1234567890</a>'
-    #[unstable(feature="test_function", issue="1234567890")]
+    // @has - '<code>test_function</code>&nbsp;<a href="http://issue_url/12345">#12345</a>'
+    #[unstable(feature="test_function", issue="12345")]
     pub fn issue() {}
 }
index 6d1f8bc1cf9bac27ccfcd6421b6dceea06d9e32c..34423d0176d2d44403c42aaf657beec5d1a20b07 100644 (file)
 
 #![unstable(feature="test", issue = "32374")]
 
-// @has issue_32374/index.html '//*[@class="docblock-short"]' \
-//      '[Deprecated] [Experimental]'
+// @matches issue_32374/index.html '//*[@class="docblock-short"]' \
+//      '^\[Deprecated\] \[Experimental\] Docs'
 
 // @has issue_32374/struct.T.html '//*[@class="stab deprecated"]' \
 //      'Deprecated since 1.0.0: text'
-// @has - '<code>test </code>'
-// @has - '<a href="http://issue_url/32374">#32374</a>'
+// @has - '<code>test</code>&nbsp;<a href="http://issue_url/32374">#32374</a>'
 // @matches issue_32374/struct.T.html '//*[@class="stab unstable"]' \
-//      '🔬 This is a nightly-only experimental API.  \(test #32374\)$'
+//      '🔬 This is a nightly-only experimental API. \(test #32374\)$'
+/// Docs
 #[rustc_deprecated(since = "1.0.0", reason = "text")]
 #[unstable(feature = "test", issue = "32374")]
 pub struct T;
diff --git a/src/test/ui/coercion/coerce-issue-49593-box-never.rs b/src/test/ui/coercion/coerce-issue-49593-box-never.rs
new file mode 100644 (file)
index 0000000..bea8586
--- /dev/null
@@ -0,0 +1,62 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-pass
+
+#![feature(never_type)]
+#![allow(unreachable_code)]
+
+use std::error::Error;
+use std::mem;
+
+fn raw_ptr_box<T>(t: T) -> *mut T {
+    panic!()
+}
+
+fn foo(x: !) -> Box<dyn Error> {
+    /* *mut $0 is coerced to Box<dyn Error> here */ Box::<_ /* ! */>::new(x)
+}
+
+fn foo_raw_ptr(x: !) -> *mut dyn Error {
+    /* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x)
+}
+
+fn no_coercion(d: *mut dyn Error) -> *mut dyn Error {
+    /* an unsize coercion won't compile here, and it is indeed not used
+       because there is nothing requiring the _ to be Sized */
+    d as *mut _
+}
+
+trait Xyz {}
+struct S;
+struct T;
+impl Xyz for S {}
+impl Xyz for T {}
+
+fn foo_no_never() {
+    let mut x /* : Option<S> */ = None;
+    let mut first_iter = false;
+    loop {
+        if !first_iter {
+            let y: Box<dyn Xyz>
+                = /* Box<$0> is coerced to Box<Xyz> here */ Box::new(x.unwrap());
+        }
+
+        x = Some(S);
+        first_iter = true;
+    }
+
+    let mut y : Option<S> = None;
+    // assert types are equal
+    mem::swap(&mut x, &mut y);
+}
+
+fn main() {
+}
diff --git a/src/test/ui/coherence/auxiliary/coherence_fundamental_trait_lib.rs b/src/test/ui/coherence/auxiliary/coherence_fundamental_trait_lib.rs
new file mode 100644 (file)
index 0000000..21aaea4
--- /dev/null
@@ -0,0 +1,7 @@
+#![crate_type = "rlib"]
+#![feature(fundamental)]
+
+pub trait Misc {}
+
+#[fundamental]
+pub trait Fundamental<T> {}
diff --git a/src/test/ui/coherence/coherence-fundamental-trait-objects.rs b/src/test/ui/coherence/coherence-fundamental-trait-objects.rs
new file mode 100644 (file)
index 0000000..dd127bf
--- /dev/null
@@ -0,0 +1,15 @@
+// Check that trait objects from #[fundamental] traits are not
+// treated as #[fundamental] types - the 2 meanings of #[fundamental]
+// are distinct.
+
+// aux-build:coherence_fundamental_trait_lib.rs
+
+extern crate coherence_fundamental_trait_lib;
+
+use coherence_fundamental_trait_lib::{Fundamental, Misc};
+
+pub struct Local;
+impl Misc for dyn Fundamental<Local> {}
+//~^ ERROR E0117
+
+fn main() {}
diff --git a/src/test/ui/coherence/coherence-fundamental-trait-objects.stderr b/src/test/ui/coherence/coherence-fundamental-trait-objects.stderr
new file mode 100644 (file)
index 0000000..cefcac2
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+  --> $DIR/coherence-fundamental-trait-objects.rs:12:1
+   |
+LL | impl Misc for dyn Fundamental<Local> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate
+   |
+   = note: the impl does not reference any types defined in this crate
+   = note: define and implement a trait or new type instead
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0117`.
index 74713af2ea033114ee9ed28e9b45338efa55f52f..42cba02f579b781cdc6c369cba77a15b6af10c37 100644 (file)
@@ -1,13 +1,3 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 #![feature(const_transmute)]
 #![allow(const_err)] // make sure we cannot allow away the errors tested here
 
 #[derive(Copy, Clone)]
 enum Bar {}
 
-const BAD_BAD_BAD: Bar = unsafe { mem::transmute(()) };
+union TransmuteUnion<A: Clone + Copy, B: Clone + Copy> {
+    a: A,
+    b: B,
+}
+
+const BAD_BAD_BAD: Bar = unsafe { (TransmuteUnion::<(), Bar> { a: () }).b };
 //~^ ERROR it is undefined behavior to use this value
 
 const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
 //~^ ERROR it is undefined behavior to use this value
 
-const BAD_BAD_ARRAY: [Bar; 1] = unsafe { mem::transmute(()) };
+const BAD_BAD_ARRAY: [Bar; 1] = unsafe { (TransmuteUnion::<(), [Bar; 1]> { a: () }).b };
 //~^ ERROR it is undefined behavior to use this value
 
-fn main() {
-}
+fn main() {}
index c5ac72b639c05a94292c40ec0722d284d9c6633a..c8842ecc23ca29054bdc396bce1532c761c0a2a1 100644 (file)
@@ -1,13 +1,13 @@
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-uninhabit.rs:19:1
+  --> $DIR/ub-uninhabit.rs:14:1
    |
-LL | const BAD_BAD_BAD: Bar = unsafe { mem::transmute(()) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type
+LL | const BAD_BAD_BAD: Bar = unsafe { (TransmuteUnion::<(), Bar> { a: () }).b };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-uninhabit.rs:22:1
+  --> $DIR/ub-uninhabit.rs:17:1
    |
 LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type at .<deref>
@@ -15,10 +15,10 @@ LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-uninhabit.rs:25:1
+  --> $DIR/ub-uninhabit.rs:20:1
    |
-LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { mem::transmute(()) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type at [0]
+LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { (TransmuteUnion::<(), [Bar; 1]> { a: () }).b };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
 
index 0b639240bb3483dd4e87c25c7387d29076d13c02..b9d181a76dd9bb5c9b137ab9af64b06fd3882295 100644 (file)
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/validate_never_arrays.rs:3:1
    |
 LL | const FOO: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; //~ ERROR undefined behavior
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type at .<deref>[0]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type at .<deref>
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
 
index ff0306f199310c271a112045bf5073571661f927..84cd5c2bffa6203cdd78e078bbaff41f0c76e21d 100644 (file)
@@ -8,20 +8,32 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::rc::Rc;
+use std::{
+    ops::Deref,
+};
+
+struct Ptr<T: ?Sized>(Box<T>);
+
+impl<T: ?Sized> Deref for Ptr<T> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        &*self.0
+    }
+}
 
 trait Foo {
-    fn foo(self: Rc<Box<Self>>); //~ ERROR arbitrary `self` types are unstable
+    fn foo(self: Ptr<Self>); //~ ERROR `Ptr<Self>` cannot be used as the type of `self` without
 }
 
 struct Bar;
 
 impl Foo for Bar {
-    fn foo(self: Rc<Box<Self>>) {} //~ ERROR arbitrary `self` types are unstable
+    fn foo(self: Ptr<Self>) {} //~ ERROR `Ptr<Bar>` cannot be used as the type of `self` without
 }
 
 impl Bar {
-    fn bar(self: Box<Rc<Self>>) {} //~ ERROR arbitrary `self` types are unstable
+    fn bar(self: Box<Ptr<Self>>) {} //~ ERROR `std::boxed::Box<Ptr<Bar>>` cannot be used as the
 }
 
 fn main() {}
index ea259aa22adfb3d295403a8765e9cc9b92c59273..c70774b3710de1f15f3de34495d1e80a52361287 100644 (file)
@@ -1,26 +1,26 @@
-error[E0658]: arbitrary `self` types are unstable (see issue #44874)
-  --> $DIR/feature-gate-arbitrary-self-types.rs:14:18
+error[E0658]: `Ptr<Self>` cannot be used as the type of `self` without the `arbitrary_self_types` feature (see issue #44874)
+  --> $DIR/feature-gate-arbitrary-self-types.rs:26:18
    |
-LL |     fn foo(self: Rc<Box<Self>>); //~ ERROR arbitrary `self` types are unstable
-   |                  ^^^^^^^^^^^^^
+LL |     fn foo(self: Ptr<Self>); //~ ERROR `Ptr<Self>` cannot be used as the type of `self` without
+   |                  ^^^^^^^^^
    |
    = help: add #![feature(arbitrary_self_types)] to the crate attributes to enable
    = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`
 
-error[E0658]: arbitrary `self` types are unstable (see issue #44874)
-  --> $DIR/feature-gate-arbitrary-self-types.rs:20:18
+error[E0658]: `Ptr<Bar>` cannot be used as the type of `self` without the `arbitrary_self_types` feature (see issue #44874)
+  --> $DIR/feature-gate-arbitrary-self-types.rs:32:18
    |
-LL |     fn foo(self: Rc<Box<Self>>) {} //~ ERROR arbitrary `self` types are unstable
-   |                  ^^^^^^^^^^^^^
+LL |     fn foo(self: Ptr<Self>) {} //~ ERROR `Ptr<Bar>` cannot be used as the type of `self` without
+   |                  ^^^^^^^^^
    |
    = help: add #![feature(arbitrary_self_types)] to the crate attributes to enable
    = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`
 
-error[E0658]: arbitrary `self` types are unstable (see issue #44874)
-  --> $DIR/feature-gate-arbitrary-self-types.rs:24:18
+error[E0658]: `std::boxed::Box<Ptr<Bar>>` cannot be used as the type of `self` without the `arbitrary_self_types` feature (see issue #44874)
+  --> $DIR/feature-gate-arbitrary-self-types.rs:36:18
    |
-LL |     fn bar(self: Box<Rc<Self>>) {} //~ ERROR arbitrary `self` types are unstable
-   |                  ^^^^^^^^^^^^^
+LL |     fn bar(self: Box<Ptr<Self>>) {} //~ ERROR `std::boxed::Box<Ptr<Bar>>` cannot be used as the
+   |                  ^^^^^^^^^^^^^^
    |
    = help: add #![feature(arbitrary_self_types)] to the crate attributes to enable
    = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`
index 29e51727edcfd8c3f576d8cfd9892f681794cc69..6d42460ba5684e3868334eef132e093522dab4e2 100644 (file)
 
 impl Foo {
     fn foo(self: *const Self) {}
-    //~^ ERROR raw pointer `self` is unstable
+    //~^ ERROR `*const Foo` cannot be used as the type of `self` without
 }
 
 trait Bar {
     fn bar(self: *const Self);
-    //~^ ERROR raw pointer `self` is unstable
+    //~^ ERROR `*const Self` cannot be used as the type of `self` without
 }
 
 impl Bar for () {
     fn bar(self: *const Self) {}
-    //~^ ERROR raw pointer `self` is unstable
+    //~^ ERROR `*const ()` cannot be used as the type of `self` without
 }
 
 fn main() {}
index 5ed9a0f4ed0408694b2db9fad8ac479c09077c14..b8cc7dee9867d2d75a9df2fcb13a12ffac567995 100644 (file)
@@ -1,4 +1,4 @@
-error[E0658]: raw pointer `self` is unstable (see issue #44874)
+error[E0658]: `*const Self` cannot be used as the type of `self` without the `arbitrary_self_types` feature (see issue #44874)
   --> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:19:18
    |
 LL |     fn bar(self: *const Self);
@@ -7,7 +7,7 @@ LL |     fn bar(self: *const Self);
    = help: add #![feature(arbitrary_self_types)] to the crate attributes to enable
    = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`
 
-error[E0658]: raw pointer `self` is unstable (see issue #44874)
+error[E0658]: `*const Foo` cannot be used as the type of `self` without the `arbitrary_self_types` feature (see issue #44874)
   --> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:14:18
    |
 LL |     fn foo(self: *const Self) {}
@@ -16,7 +16,7 @@ LL |     fn foo(self: *const Self) {}
    = help: add #![feature(arbitrary_self_types)] to the crate attributes to enable
    = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`
 
-error[E0658]: raw pointer `self` is unstable (see issue #44874)
+error[E0658]: `*const ()` cannot be used as the type of `self` without the `arbitrary_self_types` feature (see issue #44874)
   --> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:24:18
    |
 LL |     fn bar(self: *const Self) {}
diff --git a/src/test/ui/issues/issue-56762.rs b/src/test/ui/issues/issue-56762.rs
new file mode 100644 (file)
index 0000000..97b66b2
--- /dev/null
@@ -0,0 +1,18 @@
+// only-x86_64
+const HUGE_SIZE: usize = !0usize / 8;
+
+
+pub struct TooBigArray {
+    arr: [u8; HUGE_SIZE],
+}
+
+impl TooBigArray {
+    pub const fn new() -> Self {
+        TooBigArray { arr: [0x00; HUGE_SIZE], }
+    }
+}
+
+static MY_TOO_BIG_ARRAY_1: TooBigArray = TooBigArray::new();
+static MY_TOO_BIG_ARRAY_2: [u8; HUGE_SIZE] = [0x00; HUGE_SIZE];
+
+fn main() { }
diff --git a/src/test/ui/issues/issue-56762.stderr b/src/test/ui/issues/issue-56762.stderr
new file mode 100644 (file)
index 0000000..83d5dc6
--- /dev/null
@@ -0,0 +1,4 @@
+error: the type `[u8; 2305843009213693951]` is too big for the current architecture
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/nll/issue-46589.rs b/src/test/ui/nll/issue-46589.rs
new file mode 100644 (file)
index 0000000..82e7365
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(nll)]
+
+struct Foo;
+
+impl Foo {
+    fn get_self(&mut self) -> Option<&mut Self> {
+        Some(self)
+    }
+
+    fn new_self(&mut self) -> &mut Self {
+        self
+    }
+
+    fn trigger_bug(&mut self) {
+        let other = &mut (&mut *self);
+
+        *other = match (*other).get_self() {
+            Some(s) => s,
+            None => (*other).new_self()
+            //~^ ERROR cannot borrow `**other` as mutable more than once at a time [E0499]
+        };
+
+        let c = other;
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/issue-46589.stderr b/src/test/ui/nll/issue-46589.stderr
new file mode 100644 (file)
index 0000000..6df2983
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0499]: cannot borrow `**other` as mutable more than once at a time
+  --> $DIR/issue-46589.rs:29:21
+   |
+LL |         *other = match (*other).get_self() {
+   |                        -------- first mutable borrow occurs here
+LL |             Some(s) => s,
+LL |             None => (*other).new_self()
+   |                     ^^^^^^^^
+   |                     |
+   |                     second mutable borrow occurs here
+   |                     first borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0499`.
index 97126e98cbf3ad3ab09efb5401d057d15990ad68..320d80438b06781a69cb9c1ca18a2adedbf8bdaa 100644 (file)
@@ -27,10 +27,8 @@ fn nll_fail() {
     //~| ERROR (Mir) [E0506]
     data.0 = 'f';
     //~^ ERROR (Ast) [E0506]
-    //~| ERROR (Mir) [E0506]
     data.0 = 'g';
     //~^ ERROR (Ast) [E0506]
-    //~| ERROR (Mir) [E0506]
     capitalize(c);
 }
 
index 9afae71edbe11c07ad0c44c79d83c2b821831e3f..3ba3fa15a5387672c06010f3ef6fbb6ca71e6668 100644 (file)
@@ -17,7 +17,7 @@ LL |     data.0 = 'f';
    |     ^^^^^^^^^^^^ assignment to borrowed `data.0` occurs here
 
 error[E0506]: cannot assign to `data.0` because it is borrowed (Ast)
-  --> $DIR/loan_ends_mid_block_pair.rs:31:5
+  --> $DIR/loan_ends_mid_block_pair.rs:30:5
    |
 LL |     let c = &mut data.0;
    |                  ------ borrow of `data.0` occurs here
@@ -26,7 +26,7 @@ LL |     data.0 = 'g';
    |     ^^^^^^^^^^^^ assignment to borrowed `data.0` occurs here
 
 error[E0506]: cannot assign to `data.0` because it is borrowed (Ast)
-  --> $DIR/loan_ends_mid_block_pair.rs:41:5
+  --> $DIR/loan_ends_mid_block_pair.rs:39:5
    |
 LL |     let c = &mut data.0;
    |                  ------ borrow of `data.0` occurs here
@@ -35,7 +35,7 @@ LL |     data.0 = 'e';
    |     ^^^^^^^^^^^^ assignment to borrowed `data.0` occurs here
 
 error[E0506]: cannot assign to `data.0` because it is borrowed (Ast)
-  --> $DIR/loan_ends_mid_block_pair.rs:43:5
+  --> $DIR/loan_ends_mid_block_pair.rs:41:5
    |
 LL |     let c = &mut data.0;
    |                  ------ borrow of `data.0` occurs here
@@ -44,7 +44,7 @@ LL |     data.0 = 'f';
    |     ^^^^^^^^^^^^ assignment to borrowed `data.0` occurs here
 
 error[E0506]: cannot assign to `data.0` because it is borrowed (Ast)
-  --> $DIR/loan_ends_mid_block_pair.rs:45:5
+  --> $DIR/loan_ends_mid_block_pair.rs:43:5
    |
 LL |     let c = &mut data.0;
    |                  ------ borrow of `data.0` occurs here
@@ -64,30 +64,6 @@ LL |     data.0 = 'e';
 LL |     capitalize(c);
    |                - borrow later used here
 
-error[E0506]: cannot assign to `data.0` because it is borrowed (Mir)
-  --> $DIR/loan_ends_mid_block_pair.rs:28:5
-   |
-LL |     let c = &mut data.0;
-   |             ----------- borrow of `data.0` occurs here
-...
-LL |     data.0 = 'f';
-   |     ^^^^^^^^^^^^ assignment to borrowed `data.0` occurs here
-...
-LL |     capitalize(c);
-   |                - borrow later used here
-
-error[E0506]: cannot assign to `data.0` because it is borrowed (Mir)
-  --> $DIR/loan_ends_mid_block_pair.rs:31:5
-   |
-LL |     let c = &mut data.0;
-   |             ----------- borrow of `data.0` occurs here
-...
-LL |     data.0 = 'g';
-   |     ^^^^^^^^^^^^ assignment to borrowed `data.0` occurs here
-...
-LL |     capitalize(c);
-   |                - borrow later used here
-
-error: aborting due to 9 previous errors
+error: aborting due to 7 previous errors
 
 For more information about this error, try `rustc --explain E0506`.
index 9aff4bbc41c9c8b5378a1c9d1e2446bcc2a256ef..c336cc6299eb55b6837e47d155ae0081c05cad89 100644 (file)
@@ -17,6 +17,20 @@ pub trait Sized {}
 #[lang="copy"]
 pub trait Copy {}
 
+#[lang="deref"]
+pub trait Deref {
+    type Target;
+}
+
+#[lang="receiver"]
+pub trait Receiver: Deref {}
+
+impl<'a, T> Deref for &'a T {
+    type Target = T;
+}
+
+impl<'a, T> Receiver for &'a T {}
+
 mod bar {
     // shouldn't bring in too much
     pub use self::glob::*;
index d6197575447e61dbd8a4aee4695f5e2688ebbad9..54e01cca6c43a49652a75dd09dc2c862631dbacb 100644 (file)
 error[E0603]: module `baz` is private
-  --> $DIR/privacy1.rs:128:18
+  --> $DIR/privacy1.rs:142:18
    |
 LL |         use bar::baz::{foo, bar};
    |                  ^^^
 
 error[E0603]: module `baz` is private
-  --> $DIR/privacy1.rs:136:18
+  --> $DIR/privacy1.rs:150:18
    |
 LL |         use bar::baz;
    |                  ^^^
 
 error[E0603]: module `i` is private
-  --> $DIR/privacy1.rs:160:20
+  --> $DIR/privacy1.rs:174:20
    |
 LL |     use self::foo::i::A; //~ ERROR: module `i` is private
    |                    ^
 
 error[E0603]: module `baz` is private
-  --> $DIR/privacy1.rs:100:16
+  --> $DIR/privacy1.rs:114:16
    |
 LL |         ::bar::baz::A::foo();   //~ ERROR: module `baz` is private
    |                ^^^
 
 error[E0603]: module `baz` is private
-  --> $DIR/privacy1.rs:101:16
+  --> $DIR/privacy1.rs:115:16
    |
 LL |         ::bar::baz::A::bar();   //~ ERROR: module `baz` is private
    |                ^^^
 
 error[E0603]: module `baz` is private
-  --> $DIR/privacy1.rs:103:16
+  --> $DIR/privacy1.rs:117:16
    |
 LL |         ::bar::baz::A.foo2();   //~ ERROR: module `baz` is private
    |                ^^^
 
 error[E0603]: module `baz` is private
-  --> $DIR/privacy1.rs:104:16
+  --> $DIR/privacy1.rs:118:16
    |
 LL |         ::bar::baz::A.bar2();   //~ ERROR: module `baz` is private
    |                ^^^
 
 error[E0603]: trait `B` is private
-  --> $DIR/privacy1.rs:108:16
+  --> $DIR/privacy1.rs:122:16
    |
 LL |         ::bar::B::foo();        //~ ERROR: trait `B` is private
    |                ^
 
 error[E0603]: function `epriv` is private
-  --> $DIR/privacy1.rs:114:20
+  --> $DIR/privacy1.rs:128:20
    |
 LL |             ::bar::epriv(); //~ ERROR: function `epriv` is private
    |                    ^^^^^
 
 error[E0603]: module `baz` is private
-  --> $DIR/privacy1.rs:123:16
+  --> $DIR/privacy1.rs:137:16
    |
 LL |         ::bar::baz::foo(); //~ ERROR: module `baz` is private
    |                ^^^
 
 error[E0603]: module `baz` is private
-  --> $DIR/privacy1.rs:124:16
+  --> $DIR/privacy1.rs:138:16
    |
 LL |         ::bar::baz::bar(); //~ ERROR: module `baz` is private
    |                ^^^
 
 error[E0603]: trait `B` is private
-  --> $DIR/privacy1.rs:152:17
+  --> $DIR/privacy1.rs:166:17
    |
 LL |     impl ::bar::B for f32 { fn foo() -> f32 { 1.0 } }
    |                 ^
 
 error[E0624]: method `bar` is private
-  --> $DIR/privacy1.rs:73:9
+  --> $DIR/privacy1.rs:87:9
    |
 LL |         self::baz::A::bar(); //~ ERROR: method `bar` is private
    |         ^^^^^^^^^^^^^^^^^
 
 error[E0624]: method `bar` is private
-  --> $DIR/privacy1.rs:91:5
+  --> $DIR/privacy1.rs:105:5
    |
 LL |     bar::A::bar(); //~ ERROR: method `bar` is private
    |     ^^^^^^^^^^^
 
 error[E0624]: method `bar` is private
-  --> $DIR/privacy1.rs:98:9
+  --> $DIR/privacy1.rs:112:9
    |
 LL |         ::bar::A::bar();        //~ ERROR: method `bar` is private
    |         ^^^^^^^^^^^^^
 
 error[E0624]: method `bar` is private
-  --> $DIR/privacy1.rs:101:9
+  --> $DIR/privacy1.rs:115:9
    |
 LL |         ::bar::baz::A::bar();   //~ ERROR: module `baz` is private
    |         ^^^^^^^^^^^^^^^^^^
 
 error[E0624]: method `bar2` is private
-  --> $DIR/privacy1.rs:104:23
+  --> $DIR/privacy1.rs:118:23
    |
 LL |         ::bar::baz::A.bar2();   //~ ERROR: module `baz` is private
    |                       ^^^^
diff --git a/src/test/ui/proc-macro/auxiliary/dollar-crate-external.rs b/src/test/ui/proc-macro/auxiliary/dollar-crate-external.rs
new file mode 100644 (file)
index 0000000..8f15a2b
--- /dev/null
@@ -0,0 +1,16 @@
+pub type S = u8;
+
+#[macro_export]
+macro_rules! external {
+    () => {
+        dollar_crate::m! {
+            struct M($crate::S);
+        }
+
+        #[dollar_crate::a]
+        struct A($crate::S);
+
+        #[derive(dollar_crate::d)]
+        struct D($crate::S);
+    };
+}
diff --git a/src/test/ui/proc-macro/auxiliary/dollar-crate.rs b/src/test/ui/proc-macro/auxiliary/dollar-crate.rs
new file mode 100644 (file)
index 0000000..d0ea850
--- /dev/null
@@ -0,0 +1,28 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro]
+pub fn m(input: TokenStream) -> TokenStream {
+    println!("PROC MACRO INPUT (PRETTY-PRINTED): {}", input);
+    println!("PROC MACRO INPUT: {:#?}", input);
+    input.into_iter().collect()
+}
+
+#[proc_macro_attribute]
+pub fn a(_args: TokenStream, input: TokenStream) -> TokenStream {
+    println!("ATTRIBUTE INPUT (PRETTY-PRINTED): {}", input);
+    println!("ATTRIBUTE INPUT: {:#?}", input);
+    input.into_iter().collect()
+}
+
+#[proc_macro_derive(d)]
+pub fn d(input: TokenStream) -> TokenStream {
+    println!("DERIVE INPUT (PRETTY-PRINTED): {}", input);
+    println!("DERIVE INPUT: {:#?}", input);
+    input.into_iter().collect()
+}
diff --git a/src/test/ui/proc-macro/dollar-crate.rs b/src/test/ui/proc-macro/dollar-crate.rs
new file mode 100644 (file)
index 0000000..1460e9a
--- /dev/null
@@ -0,0 +1,40 @@
+// edition:2018
+// aux-build:dollar-crate.rs
+// aux-build:dollar-crate-external.rs
+
+// Anonymize unstable non-dummy spans while still showing dummy spans `0..0`.
+// normalize-stdout-test "bytes\([^0]\w*\.\.(\w+)\)" -> "bytes(LO..$1)"
+// normalize-stdout-test "bytes\((\w+)\.\.[^0]\w*\)" -> "bytes($1..HI)"
+
+extern crate dollar_crate;
+extern crate dollar_crate_external;
+
+type S = u8;
+
+mod local {
+    use crate::dollar_crate;
+
+    macro_rules! local {
+        () => {
+            dollar_crate::m! {
+                struct M($crate::S);
+            }
+
+            #[dollar_crate::a]
+            struct A($crate::S);
+
+            #[derive(dollar_crate::d)]
+            struct D($crate::S); //~ ERROR the name `D` is defined multiple times
+        };
+    }
+
+    local!();
+}
+
+mod external {
+    use crate::dollar_crate_external;
+
+    dollar_crate_external::external!(); //~ ERROR the name `D` is defined multiple times
+}
+
+fn main() {}
diff --git a/src/test/ui/proc-macro/dollar-crate.stderr b/src/test/ui/proc-macro/dollar-crate.stderr
new file mode 100644 (file)
index 0000000..08de3c7
--- /dev/null
@@ -0,0 +1,29 @@
+error[E0428]: the name `D` is defined multiple times
+  --> $DIR/dollar-crate.rs:27:13
+   |
+LL |             struct D($crate::S); //~ ERROR the name `D` is defined multiple times
+   |             ^^^^^^^^^^^^^^^^^^^^
+   |             |
+   |             `D` redefined here
+   |             previous definition of the type `D` here
+...
+LL |     local!();
+   |     --------- in this macro invocation
+   |
+   = note: `D` must be defined only once in the type namespace of this module
+
+error[E0428]: the name `D` is defined multiple times
+  --> $DIR/dollar-crate.rs:37:5
+   |
+LL |     dollar_crate_external::external!(); //~ ERROR the name `D` is defined multiple times
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     |
+   |     `D` redefined here
+   |     previous definition of the type `D` here
+   |
+   = note: `D` must be defined only once in the type namespace of this module
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0428`.
diff --git a/src/test/ui/proc-macro/dollar-crate.stdout b/src/test/ui/proc-macro/dollar-crate.stdout
new file mode 100644 (file)
index 0000000..c47b360
--- /dev/null
@@ -0,0 +1,240 @@
+PROC MACRO INPUT (PRETTY-PRINTED): struct M ( $crate :: S ) ;
+PROC MACRO INPUT: TokenStream [
+    Ident {
+        ident: "struct",
+        span: #2 bytes(LO..HI)
+    },
+    Ident {
+        ident: "M",
+        span: #2 bytes(LO..HI)
+    },
+    Group {
+        delimiter: Parenthesis,
+        stream: TokenStream [
+            Ident {
+                ident: "$crate",
+                span: #2 bytes(LO..HI)
+            },
+            Punct {
+                ch: ':',
+                spacing: Joint,
+                span: #2 bytes(LO..HI)
+            },
+            Punct {
+                ch: ':',
+                spacing: Alone,
+                span: #2 bytes(LO..HI)
+            },
+            Ident {
+                ident: "S",
+                span: #2 bytes(LO..HI)
+            }
+        ],
+        span: #2 bytes(LO..HI)
+    },
+    Punct {
+        ch: ';',
+        spacing: Alone,
+        span: #2 bytes(LO..HI)
+    }
+]
+ATTRIBUTE INPUT (PRETTY-PRINTED): struct A(crate::S);
+ATTRIBUTE INPUT: TokenStream [
+    Ident {
+        ident: "struct",
+        span: #2 bytes(LO..HI)
+    },
+    Ident {
+        ident: "A",
+        span: #2 bytes(LO..HI)
+    },
+    Group {
+        delimiter: Parenthesis,
+        stream: TokenStream [
+            Ident {
+                ident: "$crate",
+                span: #2 bytes(LO..HI)
+            },
+            Punct {
+                ch: ':',
+                spacing: Joint,
+                span: #2 bytes(LO..HI)
+            },
+            Punct {
+                ch: ':',
+                spacing: Alone,
+                span: #2 bytes(LO..HI)
+            },
+            Ident {
+                ident: "S",
+                span: #2 bytes(LO..HI)
+            }
+        ],
+        span: #2 bytes(LO..HI)
+    },
+    Punct {
+        ch: ';',
+        spacing: Alone,
+        span: #2 bytes(LO..HI)
+    }
+]
+DERIVE INPUT (PRETTY-PRINTED): struct D(crate::S);
+DERIVE INPUT: TokenStream [
+    Ident {
+        ident: "struct",
+        span: #2 bytes(LO..HI)
+    },
+    Ident {
+        ident: "D",
+        span: #2 bytes(LO..HI)
+    },
+    Group {
+        delimiter: Parenthesis,
+        stream: TokenStream [
+            Ident {
+                ident: "$crate",
+                span: #2 bytes(LO..HI)
+            },
+            Punct {
+                ch: ':',
+                spacing: Joint,
+                span: #2 bytes(LO..HI)
+            },
+            Punct {
+                ch: ':',
+                spacing: Alone,
+                span: #2 bytes(LO..HI)
+            },
+            Ident {
+                ident: "S",
+                span: #2 bytes(LO..HI)
+            }
+        ],
+        span: #2 bytes(LO..HI)
+    },
+    Punct {
+        ch: ';',
+        spacing: Alone,
+        span: #2 bytes(LO..HI)
+    }
+]
+PROC MACRO INPUT (PRETTY-PRINTED): struct M ( $crate :: S ) ;
+PROC MACRO INPUT: TokenStream [
+    Ident {
+        ident: "struct",
+        span: #10 bytes(LO..HI)
+    },
+    Ident {
+        ident: "M",
+        span: #10 bytes(LO..HI)
+    },
+    Group {
+        delimiter: Parenthesis,
+        stream: TokenStream [
+            Ident {
+                ident: "$crate",
+                span: #10 bytes(LO..HI)
+            },
+            Punct {
+                ch: ':',
+                spacing: Joint,
+                span: #10 bytes(LO..HI)
+            },
+            Punct {
+                ch: ':',
+                spacing: Alone,
+                span: #10 bytes(LO..HI)
+            },
+            Ident {
+                ident: "S",
+                span: #10 bytes(LO..HI)
+            }
+        ],
+        span: #10 bytes(LO..HI)
+    },
+    Punct {
+        ch: ';',
+        spacing: Alone,
+        span: #10 bytes(LO..HI)
+    }
+]
+ATTRIBUTE INPUT (PRETTY-PRINTED): struct A(::dollar_crate_external::S);
+ATTRIBUTE INPUT: TokenStream [
+    Ident {
+        ident: "struct",
+        span: #10 bytes(LO..HI)
+    },
+    Ident {
+        ident: "A",
+        span: #10 bytes(LO..HI)
+    },
+    Group {
+        delimiter: Parenthesis,
+        stream: TokenStream [
+            Ident {
+                ident: "$crate",
+                span: #10 bytes(LO..HI)
+            },
+            Punct {
+                ch: ':',
+                spacing: Joint,
+                span: #10 bytes(LO..HI)
+            },
+            Punct {
+                ch: ':',
+                spacing: Alone,
+                span: #10 bytes(LO..HI)
+            },
+            Ident {
+                ident: "S",
+                span: #10 bytes(LO..HI)
+            }
+        ],
+        span: #10 bytes(LO..HI)
+    },
+    Punct {
+        ch: ';',
+        spacing: Alone,
+        span: #10 bytes(LO..HI)
+    }
+]
+DERIVE INPUT (PRETTY-PRINTED): struct D(::dollar_crate_external::S);
+DERIVE INPUT: TokenStream [
+    Ident {
+        ident: "struct",
+        span: #10 bytes(LO..HI)
+    },
+    Ident {
+        ident: "D",
+        span: #10 bytes(LO..HI)
+    },
+    Group {
+        delimiter: Parenthesis,
+        stream: TokenStream [
+            Ident {
+                ident: "$crate",
+                span: #10 bytes(LO..HI)
+            },
+            Punct {
+                ch: ':',
+                spacing: Joint,
+                span: #10 bytes(LO..HI)
+            },
+            Punct {
+                ch: ':',
+                spacing: Alone,
+                span: #10 bytes(LO..HI)
+            },
+            Ident {
+                ident: "S",
+                span: #10 bytes(LO..HI)
+            }
+        ],
+        span: #10 bytes(LO..HI)
+    },
+    Punct {
+        ch: ';',
+        spacing: Alone,
+        span: #10 bytes(LO..HI)
+    }
+]
index 1e3eba4bf3631fabbfb47c80755a7bb25774bddb..11c90833e7181aed0075ee8d3f7d2694117e3788 100644 (file)
@@ -13,7 +13,7 @@
 struct SomeType {}
 
 trait Foo {
-    fn handler(self: &SomeType); //~ ERROR invalid `self` type
+    fn handler(self: &SomeType); //~ ERROR invalid method receiver type
 }
 
 fn main() {}
index 9b61ecae6512ee395f55ef9a7ac32b0bfdd42c90..767b99a92cb2df777ac5228894bf8881a9a8d03f 100644 (file)
@@ -1,7 +1,7 @@
-error[E0307]: invalid `self` type: &SomeType
+error[E0307]: invalid method receiver type: &SomeType
   --> $DIR/issue-27522.rs:16:22
    |
-LL |     fn handler(self: &SomeType); //~ ERROR invalid `self` type
+LL |     fn handler(self: &SomeType); //~ ERROR invalid method receiver type
    |                      ^^^^^^^^^
    |
    = note: type must be `Self` or a type that dereferences to it
index a0d1f2dc3312e4b5784ac7d726303659ef0b6b48..f87541b56acf920f02d9f3afb25e2d5a07ba391b 100644 (file)
@@ -16,7 +16,7 @@ struct Foo {
 
 impl Foo {
     fn foo(self: isize, x: isize) -> isize {
-        //~^ ERROR invalid `self` type
+        //~^ ERROR invalid method receiver type
         self.f + x
     }
 }
@@ -27,11 +27,11 @@ struct Bar<T> {
 
 impl<T> Bar<T> {
     fn foo(self: Bar<isize>, x: isize) -> isize {
-        //~^ ERROR invalid `self` type
+        //~^ ERROR invalid method receiver type
         x
     }
     fn bar(self: &Bar<usize>, x: isize) -> isize {
-        //~^ ERROR invalid `self` type
+        //~^ ERROR invalid method receiver type
         x
     }
 }
index fce74605cad38f67e814c7a719617665e3910a18..a229dabcce4a4c6e95e90e79f371f8683a6e621f 100644 (file)
@@ -1,28 +1,28 @@
-error[E0307]: invalid `self` type: isize
+error[E0307]: invalid method receiver type: isize
   --> $DIR/ufcs-explicit-self-bad.rs:18:18
    |
 LL |     fn foo(self: isize, x: isize) -> isize {
    |                  ^^^^^
    |
-   = note: type must be `Foo` or a type that dereferences to it
+   = note: type must be `Self` or a type that dereferences to it
    = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`
 
-error[E0307]: invalid `self` type: Bar<isize>
+error[E0307]: invalid method receiver type: Bar<isize>
   --> $DIR/ufcs-explicit-self-bad.rs:29:18
    |
 LL |     fn foo(self: Bar<isize>, x: isize) -> isize {
    |                  ^^^^^^^^^^
    |
-   = note: type must be `Bar<T>` or a type that dereferences to it
+   = note: type must be `Self` or a type that dereferences to it
    = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`
 
-error[E0307]: invalid `self` type: &Bar<usize>
+error[E0307]: invalid method receiver type: &Bar<usize>
   --> $DIR/ufcs-explicit-self-bad.rs:33:18
    |
 LL |     fn bar(self: &Bar<usize>, x: isize) -> isize {
    |                  ^^^^^^^^^^^
    |
-   = note: type must be `Bar<T>` or a type that dereferences to it
+   = note: type must be `Self` or a type that dereferences to it
    = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`
 
 error[E0308]: mismatched method receiver
diff --git a/src/test/ui/uninhabited/privately-uninhabited-dead-code.rs b/src/test/ui/uninhabited/privately-uninhabited-dead-code.rs
new file mode 100644 (file)
index 0000000..9fe8a5c
--- /dev/null
@@ -0,0 +1,20 @@
+// compile-pass
+
+#![deny(unused_variables)]
+
+mod foo {
+    enum Bar {}
+
+    #[allow(dead_code)]
+    pub struct Foo {
+        value: Bar, // "privately" uninhabited
+    }
+
+    pub fn give_foo() -> Foo { panic!() }
+}
+
+fn main() {
+    let a = 42;
+    foo::give_foo();
+    println!("Hello, {}", a); // ok: we can't tell that this code is dead
+}