From: kennytm Date: Sat, 22 Dec 2018 16:07:35 +0000 (+0800) Subject: Rollup merge of #56914 - glaubitz:ignore-tests, r=alexcrichton X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=beaf07182253e8055b5b9abc5919bab6559d53f7;hp=a153d485fe9fbd0dd4f16c0dfa29bf5d75cd63df;p=rust.git Rollup merge of #56914 - glaubitz:ignore-tests, r=alexcrichton 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. --- diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 83adcce5c74..f1581310b48 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -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 Receiver for Box {} + #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for Box { type Item = I::Item; diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs index 0c5926fbaf1..5171ca254e4 100644 --- a/src/liballoc/collections/vec_deque.rs +++ b/src/liballoc/collections/vec_deque.rs @@ -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 VecDeque { diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index abacc62c856..e00e430fab6 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -104,6 +104,7 @@ #![feature(ptr_internals)] #![feature(ptr_offset_from)] #![feature(rustc_attrs)] +#![feature(receiver_trait)] #![feature(specialization)] #![feature(split_ascii_whitespace)] #![feature(staged_api)] diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 6769a70ddbe..3fc70f4ac37 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -253,7 +253,7 @@ 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 Receiver for Rc {} + #[stable(feature = "rust1", since = "1.0.0")] unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc { /// Drops the `Rc`. diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index e596694fb9d..55737016608 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -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 Receiver for Arc {} + impl Arc { /// Makes a mutable reference into the given `Arc`. /// diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index e514a8a69c0..146abd1b750 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -13,11 +13,12 @@ #![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; diff --git a/src/liballoc/tests/vec_deque.rs b/src/liballoc/tests/vec_deque.rs index 1f2a7211c65..c8a6d86413a 100644 --- a/src/liballoc/tests/vec_deque.rs +++ b/src/liballoc/tests/vec_deque.rs @@ -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) { + 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); + } + } +} diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index aa23d49672a..e493a380437 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -429,6 +429,9 @@ fn next(&mut self) -> Option<::Item> { self.iter.next_back() } #[inline] fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + #[inline] + fn nth(&mut self, n: usize) -> Option<::Item> { self.iter.nth_back(n) } + fn try_fold(&mut self, init: B, f: F) -> R where Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try { @@ -461,6 +464,9 @@ impl DoubleEndedIterator for Rev where I: DoubleEndedIterator { #[inline] fn next_back(&mut self) -> Option<::Item> { self.iter.next() } + #[inline] + fn nth_back(&mut self, n: usize) -> Option<::Item> { self.iter.nth(n) } + fn try_rfold(&mut self, init: B, f: F) -> R where Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try { diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index 45e5b614db3..727a60e3596 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -427,6 +427,62 @@ pub trait DoubleEndedIterator: Iterator { #[stable(feature = "rust1", since = "1.0.0")] fn next_back(&mut self) -> Option; + /// 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 { + 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(&mut self, init: B, mut f: F) -> R where - Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try + fn try_rfold(&mut self, init: B, mut f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try { let mut accum = init; while let Some(x) = self.next_back() { @@ -524,8 +583,10 @@ fn try_rfold(&mut self, init: B, mut f: F) -> R where /// ``` #[inline] #[stable(feature = "iter_rfold", since = "1.27.0")] - fn rfold(mut self, accum: B, mut f: F) -> B where - Self: Sized, F: FnMut(B, Self::Item) -> B, + fn rfold(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::(f(acc, x))).unwrap() } @@ -574,7 +635,8 @@ fn rfold(mut self, accum: B, mut f: F) -> B where /// ``` #[inline] #[stable(feature = "iter_rfind", since = "1.27.0")] - fn rfind

(&mut self, mut predicate: P) -> Option where + fn rfind

(&mut self, mut predicate: P) -> Option + where Self: Sized, P: FnMut(&Self::Item) -> bool { @@ -587,7 +649,12 @@ fn rfind

(&mut self, mut predicate: P) -> Option where #[stable(feature = "rust1", since = "1.0.0")] impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I { - fn next_back(&mut self) -> Option { (**self).next_back() } + fn next_back(&mut self) -> Option { + (**self).next_back() + } + fn nth_back(&mut self, n: usize) -> Option { + (**self).nth_back(n) + } } /// An iterator that knows its exact length. diff --git a/src/libcore/ops/deref.rs b/src/libcore/ops/deref.rs index 91a3d77e8b2..ff836f4aa69 100644 --- a/src/libcore/ops/deref.rs +++ b/src/libcore/ops/deref.rs @@ -177,3 +177,19 @@ pub trait DerefMut: Deref { impl 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`, +/// `Rc`, `&T`, and `Pin

`. +#[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 Receiver for &T {} + +#[unstable(feature = "receiver_trait", issue = "0")] +impl Receiver for &mut T {} diff --git a/src/libcore/ops/mod.rs b/src/libcore/ops/mod.rs index 785f0733df2..06740d2e4cd 100644 --- a/src/libcore/ops/mod.rs +++ b/src/libcore/ops/mod.rs @@ -178,6 +178,9 @@ #[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; diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index 0ad6e8c7c1c..521ce9b5f6b 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -101,7 +101,7 @@ 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 Receiver for Pin

{} + #[unstable(feature = "pin", issue = "49150")] impl fmt::Debug for Pin

{ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index 00b4aa4fa2d..b5633333d01 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -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]; diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 7d62b4fa90f..2377a473367 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -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)] diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index f2b85832dac..ebba5c81fe0 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -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)) } diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index c5d6ce24c5d..4881f10fac2 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -415,8 +415,8 @@ fn call<'b, I: Iterator>(&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 diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index f0c6196412a..f4d7ef59404 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -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, diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index b98e279aef4..de8a375ca6d 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -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 diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index a24f2fa4bc6..5c6845181af 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -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, diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs index 2e56308daf7..799c2df8a53 100644 --- a/src/librustc/ich/hcx.rs +++ b/src/librustc/ich/hcx.rs @@ -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, diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index a46e12be1ae..d82020f59a1 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -200,13 +200,13 @@ fn hash_stable(&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> for mir::Place<'gcx> { diff --git a/src/librustc/infer/canonical/query_response.rs b/src/librustc/infer/canonical/query_response.rs index 43bc9d88895..2a8a340ab54 100644 --- a/src/librustc/infer/canonical/query_response.rs +++ b/src/librustc/infer/canonical/query_response.rs @@ -117,6 +117,31 @@ pub fn make_canonicalized_query_response( 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( + &self, + inference_vars: CanonicalVarValues<'tcx>, + answer: T + ) -> Canonical<'gcx, QueryResponse<'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( diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index c961fd5fbd4..7ce59b1d9d7 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -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>, fresh_tables: Option>>, 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(&'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(&self, value: &T) -> T where T: TypeFoldable<'tcx>, diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 4324cfc7b5f..b76fb0ed08c 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -60,10 +60,12 @@ #![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)] diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 23ec24d71d2..cfcc7c83719 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -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; diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 31a75bd106e..d1d2fa298a6 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -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 diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 9dff3277917..dc14450e8d2 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1788,23 +1788,7 @@ pub enum StatementKind<'tcx> { /// by miri and only generated when "-Z mir-emit-retag" is passed. /// See /// 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 - /// 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), } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 237f6bc9c7b..278a4dc1d87 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -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( diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 12b5646e7f1..180019ac387 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -131,6 +131,9 @@ pub struct Session { /// Used by -Z profile-queries in util::common pub profile_channel: Lock>>, + /// Used by -Z self-profile + pub self_profiling_active: bool, + /// Used by -Z self-profile pub self_profiling: Lock, @@ -823,10 +826,17 @@ pub fn incr_comp_session_dir_opt(&self) -> Option> { } } + #[inline(never)] + #[cold] + fn profiler_active ()>(&self, f: F) { + let mut profiler = self.self_profiling.borrow_mut(); + f(&mut profiler); + } + + #[inline(always)] pub fn profiler ()>(&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 { diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index af338cd3868..853b54df2b9 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -397,7 +397,7 @@ fn uncovered_tys<'tcx>(tcx: TyCtxt<'_, '_, '_>, ty: Ty<'tcx>, in_crate: InCrate) -> Vec> { 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 } } diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index bc091a4e7e0..09c7bd67970 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -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 index 00000000000..175883eb2a7 --- /dev/null +++ b/src/librustc/traits/query/method_autoderef.rs @@ -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 or the MIT license +// , 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>>, + /// If Some(T), a type autoderef reported an error on. + pub opt_bad_ty: Option>>, + /// 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 +}); diff --git a/src/librustc/traits/query/mod.rs b/src/librustc/traits/query/mod.rs index 13683d85444..b11cb737764 100644 --- a/src/librustc/traits/query/mod.rs +++ b/src/librustc/traits/query/mod.rs @@ -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; diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index e27d7349877..04d96e362a4 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -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>, pub interner: SyncDroplessArena, + global_ctxt: Option>, } 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(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(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(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 { 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( - &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>, 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( 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: F) -> R let tcx = TyCtxt { gcx, interners: &gcx.global_interners, + dummy: PhantomData, }; let icx = ImplicitCtxt { query: None, diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs index 721d5e14ccc..c64811e32f4 100644 --- a/src/librustc/ty/inhabitedness/mod.rs +++ b/src/librustc/ty/inhabitedness/mod.rs @@ -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>>, 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>>, 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>>, 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>>, - 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 - // 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() } } diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 87d745e5cea..f4506c8e819 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -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 }) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 429b7f03af8..7daaf016c2a 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -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}; diff --git a/src/librustc/ty/query/config.rs b/src/librustc/ty/query/config.rs index fd9143be679..b320c29dfad 100644 --- a/src/librustc/ty/query/config.rs +++ b/src/librustc/ty/query/config.rs @@ -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() diff --git a/src/librustc/ty/query/job.rs b/src/librustc/ty/query/job.rs index 1439e41bb31..6e513d68f60 100644 --- a/src/librustc/ty/query/job.rs +++ b/src/librustc/ty/query/job.rs @@ -18,6 +18,11 @@ 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>>) -> 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>> { + 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(); diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index 5cd06fb8a52..c9ffab21b78 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -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; @@ -668,6 +669,10 @@ [] 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>> { self.try_get_query::>(span, key) } pub fn try_needs_drop_raw( self, span: Span, key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, - ) -> Result> { + ) -> Result>> { self.try_get_query::>(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>> { self.try_get_query::>(span, key) } } diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index 5f33d466c4a..a73b92ed713 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -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>>), } 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> + ) -> Box> { 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>( self, span: Span, key: Q::Key) - -> Result> + -> Result>> { debug!("ty::queries::{}::try_get_with(key={:?}, span={:?})", Q::NAME, @@ -436,7 +451,7 @@ fn load_from_disk_and_cache_in_memory>( job: JobOwner<'a, 'gcx, Q>, dep_node_index: DepNodeIndex, dep_node: &DepNode - ) -> Result> + ) -> Result>> { // 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>( key: Q::Key, job: JobOwner<'_, 'gcx, Q>, dep_node: DepNode) - -> Result<(Q::Value, DepNodeIndex), CycleError<'gcx>> { + -> Result<(Q::Value, DepNodeIndex), Box>> { // 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>( 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::(key, job, dep_node) + if let Err(e) = self.force_query_with_job::(key, job, dep_node) { + self.report_cycle(e).emit(); + } } pub(super) fn try_get_query>( self, span: Span, key: Q::Key, - ) -> Result> { + ) -> Result>> { match self.try_get_with::(span, key) { Ok(e) => Ok(e), Err(e) => Err(self.report_cycle(e)), } } + // FIXME: Try uninlining this + #[inline(always)] pub(super) fn get_query>( self, span: Span, key: Q::Key, ) -> Q::Value { - self.try_get_query::(span, key).unwrap_or_else(|mut e| { - e.emit(); - Q::handle_cycle_error(self) + self.try_get_with::(span, key).unwrap_or_else(|e| { + self.emit_error::(e) }) } + + #[inline(never)] + #[cold] + fn emit_error>( + self, + e: Box>, + ) -> Q::Value { + self.report_cycle(e).emit(); + Q::handle_cycle_error(self) + } } macro_rules! handle_cycle_error { @@ -806,15 +839,18 @@ pub fn $name 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> { &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::>(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 | diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index f757f48e987..2189267cb0b 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -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, diff --git a/src/librustc_codegen_ssa/mir/statement.rs b/src/librustc_codegen_ssa/mir/statement.rs index 568a7e7e160..80539b78c70 100644 --- a/src/librustc_codegen_ssa/mir/statement.rs +++ b/src/librustc_codegen_ssa/mir/statement.rs @@ -106,7 +106,6 @@ pub fn codegen_statement( } mir::StatementKind::FakeRead(..) | mir::StatementKind::Retag { .. } | - mir::StatementKind::EscapeToRaw { .. } | mir::StatementKind::AscribeUserType(..) | mir::StatementKind::Nop => bx, } diff --git a/src/librustc_data_structures/fingerprint.rs b/src/librustc_data_structures/fingerprint.rs index aa9ddda2b93..f8638213b3a 100644 --- a/src/librustc_data_structures/fingerprint.rs +++ b/src/librustc_data_structures/fingerprint.rs @@ -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 { let (_0, _1) = hasher.finalize(); Fingerprint(_0, _1) diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 8e0ecb70c68..bc2b8f1d652 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -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))] @@ -58,6 +60,26 @@ 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; diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 8757c9ff15d..55e052882ea 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -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) 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, out_file: &'a Option, - 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, diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 41c9b22afe0..5527c0ad387 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -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, &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(name: String, f: F) -> Result 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); } diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index b41b0d081ce..bc991016bbe 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -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, 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, @@ -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, _, _, _| { diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index f9d49f03ee0..5b337fbf5be 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -151,7 +151,7 @@ fn test_env_with_pool( ).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( &cstore, ty::query::Providers::default(), ty::query::Providers::default(), - &arenas, + &mut arenas, resolutions, hir_map, OnDiskCache::new_empty(sess.source_map()), diff --git a/src/librustc_mir/borrow_check/flows.rs b/src/librustc_mir/borrow_check/flows.rs index 16bb1ef78dc..8a58cb05680 100644 --- a/src/librustc_mir/borrow_check/flows.rs +++ b/src/librustc_mir/borrow_check/flows.rs @@ -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>, - pub uninits: FlowAtLocation>, - pub ever_inits: FlowAtLocation>, + 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>>, @@ -43,9 +43,9 @@ impl<'b, 'gcx, 'tcx> Flows<'b, 'gcx, 'tcx> { crate fn new( - borrows: FlowAtLocation>, - uninits: FlowAtLocation>, - ever_inits: FlowAtLocation>, + 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>>, ) -> Self { Flows { diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 5eca62938f7..99cc4acb519 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -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 diff --git a/src/librustc_mir/borrow_check/nll/invalidation.rs b/src/librustc_mir/borrow_check/nll/invalidation.rs index 07bda8af626..d2810de284a 100644 --- a/src/librustc_mir/borrow_check/nll/invalidation.rs +++ b/src/librustc_mir/borrow_check/nll/invalidation.rs @@ -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. diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index cd4694351ad..1e3a27c8fe5 100644 --- a/src/librustc_mir/borrow_check/nll/mod.rs +++ b/src/librustc_mir/borrow_check/nll/mod.rs @@ -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>, + flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'cx, 'gcx, 'tcx>>, move_data: &MoveData<'tcx>, borrow_set: &BorrowSet<'tcx>, errors_buffer: &mut Vec, diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs index 9ccdc84db15..7b216d8e587 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs @@ -39,7 +39,7 @@ pub(super) fn generate<'gcx, 'tcx>( typeck: &mut TypeChecker<'_, 'gcx, 'tcx>, mir: &Mir<'tcx>, elements: &Rc, - flow_inits: &mut FlowAtLocation>, + flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'_, 'gcx, 'tcx>>, move_data: &MoveData<'tcx>, location_table: &LocationTable, ) { diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs index bc4e0ca2351..1fbde2ae59d 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs @@ -46,7 +46,7 @@ pub(super) fn trace( typeck: &mut TypeChecker<'_, 'gcx, 'tcx>, mir: &Mir<'tcx>, elements: &Rc, - flow_inits: &mut FlowAtLocation>, + 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>, + flow_inits: &'me mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'flow, 'gcx, 'tcx>>, /// Index indicating where each variable is assigned, used, or /// dropped. diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 4807abe2bdd..d205e4da798 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -123,7 +123,7 @@ pub(crate) fn type_check<'gcx, 'tcx>( location_table: &LocationTable, borrow_set: &BorrowSet<'tcx>, all_facts: &mut Option, - flow_inits: &mut FlowAtLocation>, + flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'_, 'gcx, 'tcx>>, move_data: &MoveData<'tcx>, elements: &Rc, ) -> 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); } } diff --git a/src/librustc_mir/borrow_check/path_utils.rs b/src/librustc_mir/borrow_check/path_utils.rs index 9250c04969f..5e17afc3d3c 100644 --- a/src/librustc_mir/borrow_check/path_utils.rs +++ b/src/librustc_mir/borrow_check/path_utils.rs @@ -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. {:?}/{:?}", diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs index e24586cca09..7ebd69c63ab 100644 --- a/src/librustc_mir/borrow_check/places_conflict.rs +++ b/src/librustc_mir/borrow_check/places_conflict.rs @@ -17,6 +17,43 @@ 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 }) diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 0e7305e076e..146bf538306 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -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() } }; diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 248c5d2db49..d5bc83aba7b 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -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) { diff --git a/src/librustc_mir/dataflow/at_location.rs b/src/librustc_mir/dataflow/at_location.rs index 52eae581528..69f6fbb6c80 100644 --- a/src/librustc_mir/dataflow/at_location.rs +++ b/src/librustc_mir/dataflow/at_location.rs @@ -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 +pub struct FlowAtLocation<'tcx, BD> where - BD: BitDenotation, + BD: BitDenotation<'tcx>, { - base_results: DataflowResults, + base_results: DataflowResults<'tcx, BD>, curr_state: BitSet, stmt_gen: HybridBitSet, stmt_kill: HybridBitSet, } -impl FlowAtLocation +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(&self, f: F) @@ -102,7 +102,7 @@ pub fn each_gen_bit(&self, f: F) self.stmt_gen.iter().for_each(f) } - pub fn new(results: DataflowResults) -> 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(&self, f: F) } } -impl FlowsAtLocation for FlowAtLocation - 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 +impl<'tcx, T> FlowAtLocation<'tcx, T> where - T: HasMoveData<'tcx> + BitDenotation, + T: HasMoveData<'tcx> + BitDenotation<'tcx, Idx = MovePathIndex>, { pub fn has_any_child_of(&self, mpi: T::Idx) -> Option { // We process `mpi` before the loop below, for two reasons: diff --git a/src/librustc_mir/dataflow/graphviz.rs b/src/librustc_mir/dataflow/graphviz.rs index f6a9d46b5e2..45d59b5fb9d 100644 --- a/src/librustc_mir/dataflow/graphviz.rs +++ b/src/librustc_mir/dataflow/graphviz.rs @@ -25,19 +25,19 @@ 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; + 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.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 { impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P> where MWF: MirWithFlowState<'tcx>, - P: Fn(&MWF::BD, ::Idx) -> DebugFormatted, + P: Fn(&MWF::BD, >::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, ::Idx) -> DebugFormatted, + P: Fn(&MWF::BD, >::Idx) -> DebugFormatted, { /// Generate the node label fn node_label_internal(&self, diff --git a/src/librustc_mir/dataflow/impls/borrowed_locals.rs b/src/librustc_mir/dataflow/impls/borrowed_locals.rs index 1e279d8dd97..374f7071ffa 100644 --- a/src/librustc_mir/dataflow/impls/borrowed_locals.rs +++ b/src/librustc_mir/dataflow/impls/borrowed_locals.rs @@ -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, - _call_bb: mir::BasicBlock, - _dest_bb: mir::BasicBlock, - _dest_place: &mir::Place) { + fn propagate_call_return( + &self, + _in_out: &mut BitSet, + _call_bb: mir::BasicBlock, + _dest_bb: mir::BasicBlock, + _dest_place: &mir::Place<'tcx>, + ) { // Nothing to do when a call returns successfully } } diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index 5e78ef03c2c..078e2fd4980 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -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, - 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, + 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, 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, 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, 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, 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, _: Location) {} - fn propagate_call_return(&self, - _in_out: &mut BitSet, - _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, + _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 } } - diff --git a/src/librustc_mir/dataflow/impls/mod.rs b/src/librustc_mir/dataflow/impls/mod.rs index c29a855b1d2..99e1eab8269 100644 --- a/src/librustc_mir/dataflow/impls/mod.rs +++ b/src/librustc_mir/dataflow/impls/mod.rs @@ -293,7 +293,7 @@ fn update_bits(sets: &mut BlockSets, 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, - _call_bb: mir::BasicBlock, - _dest_bb: mir::BasicBlock, - dest_place: &mir::Place) { + fn propagate_call_return( + &self, + in_out: &mut BitSet, + _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, - _call_bb: mir::BasicBlock, - _dest_bb: mir::BasicBlock, - dest_place: &mir::Place) { + fn propagate_call_return( + &self, + in_out: &mut BitSet, + _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, - _call_bb: mir::BasicBlock, - _dest_bb: mir::BasicBlock, - dest_place: &mir::Place) { + fn propagate_call_return( + &self, + in_out: &mut BitSet, + _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, - call_bb: mir::BasicBlock, - _dest_bb: mir::BasicBlock, - _dest_place: &mir::Place) { + fn propagate_call_return( + &self, + in_out: &mut BitSet, + 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; diff --git a/src/librustc_mir/dataflow/impls/storage_liveness.rs b/src/librustc_mir/dataflow/impls/storage_liveness.rs index c8faa34df8a..caf3d3f7ab6 100644 --- a/src/librustc_mir/dataflow/impls/storage_liveness.rs +++ b/src/librustc_mir/dataflow/impls/storage_liveness.rs @@ -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, - _call_bb: mir::BasicBlock, - _dest_bb: mir::BasicBlock, - _dest_place: &mir::Place) { + fn propagate_call_return( + &self, + _in_out: &mut BitSet, + _call_bb: mir::BasicBlock, + _dest_bb: mir::BasicBlock, + _dest_place: &mir::Place<'tcx>, + ) { // Nothing to do when a call returns successfully } } diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs index bd842669a1f..efdf0c1efcb 100644 --- a/src/librustc_mir/dataflow/mod.rs +++ b/src/librustc_mir/dataflow/mod.rs @@ -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 { +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

(&mut self, p: P) where P: Fn(&BD, BD::Idx) -> DebugFormatted { @@ -87,7 +89,9 @@ fn dataflow

(&mut self, p: P) where P: Fn(&BD, BD::Idx) -> DebugFormatted { fn propagate(&mut self); } -impl<'a, 'tcx: 'a, BD> Dataflow 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

(&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, bd: BD, p: P) - -> DataflowResults - 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

(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, node_id: ast::NodeId, attributes: &[ast::Attribute], - p: P) -> DataflowResults + p: P) -> DataflowResults<'tcx, BD> where P: Fn(&BD, BD::Idx) -> DebugFormatted { let name_found = |sess: &Session, attrs: &[ast::Attribute], name| -> Option { @@ -173,12 +177,12 @@ pub(crate) fn run

(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) { let mut dirty_queue: WorkQueue = @@ -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

(&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, - mir: &Mir<'tcx>) +pub fn state_for_location<'tcx, T: BitDenotation<'tcx>>(loc: Location, + analysis: &T, + result: &DataflowResults<'tcx, T>, + mir: &Mir<'tcx>) -> BitSet { 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, + flow_state: DataflowState<'tcx, O>, dead_unwinds: &'a BitSet, 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 { + pub fn results(self) -> DataflowResults<'tcx, O> { DataflowResults(self.flow_state) } pub fn mir(&self) -> &'a Mir<'tcx> { self.mir } } -pub struct DataflowResults(pub(crate) DataflowState) where O: BitDenotation; +pub struct DataflowResults<'tcx, O>(pub(crate) DataflowState<'tcx, O>) where O: BitDenotation<'tcx>; -impl DataflowResults { +impl<'tcx, O: BitDenotation<'tcx>> DataflowResults<'tcx, O> { pub fn sets(&self) -> &AllSets { &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 +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 pub(crate) operator: O, } -impl DataflowState { +impl<'tcx, O: BitDenotation<'tcx>> DataflowState<'tcx, O> { pub(crate) fn interpret_set<'c, P>(&self, o: &'c O, set: &BitSet, @@ -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, - call_bb: mir::BasicBlock, - dest_bb: mir::BasicBlock, - dest_place: &mir::Place); + fn propagate_call_return( + &self, + in_out: &mut BitSet, + 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, @@ -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, - (bb, bb_data): (mir::BasicBlock, &mir::BasicBlockData), + (bb, bb_data): (mir::BasicBlock, &mir::BasicBlockData<'tcx>), dirty_list: &mut WorkQueue) { match bb_data.terminator().kind { diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index 7fe27e97d3d..d201a355a2a 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -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 => {} } diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index bfa2e53b9e0..a251b723d61 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -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| { diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index 7d636b77ced..118539fc58e 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -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)?; } } diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs index 4c7aa887045..e6f3b664c00 100644 --- a/src/librustc_mir/interpret/machine.rs +++ b/src/librustc_mir/interpret/machine.rs @@ -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>, diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index a6835e4f167..596dba57606 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -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. diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 2728833251a..3802b019127 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -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(); diff --git a/src/librustc_mir/transform/add_retag.rs b/src/librustc_mir/transform/add_retag.rs index 811b85446cb..69c0a68ae70 100644 --- a/src/librustc_mir/transform/add_retag.rs +++ b/src/librustc_mir/transform/add_retag.rs @@ -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()), + }); } } } diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 36078693840..f6b7f817aad 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -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) diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index c8056ea3e1f..caae5c8553e 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -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>, - flow_uninits: DataflowResults>, + flow_inits: DataflowResults<'tcx, MaybeInitializedPlaces<'a, 'tcx, 'tcx>>, + flow_uninits: DataflowResults<'tcx, MaybeUninitializedPlaces<'a, 'tcx, 'tcx>>, drop_flags: FxHashMap, patch: MirPatch<'tcx>, } diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index f870e4a2a42..fe19accb031 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -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())), }) } diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index afe0066df1f..88424d75baa 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -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, diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 58a3cb97e41..b854f029e51 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -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 => {} } diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index eee167c3579..c1c5b18915a 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -243,7 +243,6 @@ fn check_statement( | StatementKind::StorageLive(_) | StatementKind::StorageDead(_) | StatementKind::Retag { .. } - | StatementKind::EscapeToRaw { .. } | StatementKind::AscribeUserType(..) | StatementKind::Nop => Ok(()), } diff --git a/src/librustc_mir/transform/remove_noop_landing_pads.rs b/src/librustc_mir/transform/remove_noop_landing_pads.rs index 81b010e7dce..cdab5a1d7b0 100644 --- a/src/librustc_mir/transform/remove_noop_landing_pads.rs +++ b/src/librustc_mir/transform/remove_noop_landing_pads.rs @@ -65,8 +65,7 @@ fn is_nop_landing_pad( StatementKind::Assign { .. } | StatementKind::SetDiscriminant { .. } | StatementKind::InlineAsm { .. } | - StatementKind::Retag { .. } | - StatementKind::EscapeToRaw { .. } => { + StatementKind::Retag { .. } => { return false; } } diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs index c996dc285f7..e1eeeb8301c 100644 --- a/src/librustc_mir/transform/rustc_peek.rs +++ b/src/librustc_mir/transform/rustc_peek.rs @@ -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) - where O: BitDenotation + 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, + results: &DataflowResults<'tcx, O>, bb: mir::BasicBlock) where - O: BitDenotation + 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{ .. } => diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index f082d776969..6cfa9f95082 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -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); + } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 36f4497b77f..794e5741d62 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -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 } } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 32f0d84342e..81633c8f57f 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -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) -> P { - 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, mut path: ast::Path) - -> (Option, 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)) diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index 1b594342c9a..d240f45c7d9 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -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>, 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 { - 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 { } 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 { } 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> { debug!("overloaded_deref_ty({:?})", ty); - let tcx = self.fcx.tcx(); + let tcx = self.infcx.tcx; // let trait_ref = TraitRef { @@ -118,43 +128,52 @@ fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option> { 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> { - 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>> { 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> { } } +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, diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 75ae8688834..0ec181e59d0 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -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> { - 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) diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index be15503e479..f599a2b2ece 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -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>, Option) { - 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`. 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> { - 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, diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 8d844fe3a69..9a1f9784192 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -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` where we know that `$0: Sized`, try going + // for unsizing. + } + _ => { + // Some other case for `$0: Unsize`. 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); diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 11fb3889a74..3902dddd0d4 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -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); diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 858d8c742df..5ecbfcd132c 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -39,6 +39,7 @@ pub fn provide(providers: &mut ty::query::Providers) { suggest::provide(providers); + probe::provide(providers); } #[derive(Clone, Copy, Debug)] diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index dd3c022d53b..190419048b4 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -13,28 +13,35 @@ 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, return_type: Option>, - steps: Rc>>, + + /// This is the OriginalQueryValues for the steps queries + /// that are answered in steps. + orig_steps_var_values: OriginalQueryValues<'tcx>, + steps: Lrc>>, + inherent_candidates: Vec>, extension_candidates: Vec>, impl_dups: FxHashSet, @@ -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(&'a self, -> Result> where OP: FnOnce(ProbeContext<'a, 'gcx, 'tcx>) -> Result> { - // 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, ¶m_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(&'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>> { - // 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, return_type: Option>, - steps: Rc>>, + orig_steps_var_values: OriginalQueryValues<'tcx>, + steps: Lrc>>, 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> { // 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> { + fn pick_by_value_method(&mut self, step: &CandidateStep<'gcx>, self_ty: Ty<'tcx>) + -> Option> + { //! 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) -> Option, mutbl: hir::Mutability) + fn pick_autorefd_method(&mut self, + step: &CandidateStep<'gcx>, + self_ty: Ty<'tcx>, + mutbl: hir::Mutability) -> Option> { 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, 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)?; diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 957c8d9f19f..d45f8fd6de8 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -102,10 +102,11 @@ 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; @@ -113,8 +114,8 @@ 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; @@ -142,6 +143,7 @@ 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, 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::() { 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 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>, diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 6471e745aa6..e74b1ae47e3 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -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`") + .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`") + .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`") + .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`. +/// +/// 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`") - .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`") - .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`") - .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>, diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 8d6fb8b7f39..fdc81a6ed1a 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -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; diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 217345548c8..4bd3c6a8455 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -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 diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 3678aab87c2..01ead05999b 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -478,7 +478,7 @@ pub fn stability_class(&self) -> Option { 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, pub since: String, - pub deprecated_since: String, - pub deprecated_reason: String, - pub unstable_reason: String, - pub issue: Option + pub deprecation: Option, + pub unstable_reason: Option, + pub issue: Option, } #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Deprecation { - pub since: String, - pub note: String, + pub since: Option, + pub note: Option, } impl Clean 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 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()), } } } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 15527d7d141..fa74e7094f6 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -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| { diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 46002c089cf..2ee4db3a539 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -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, "

", 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::>() - .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 \ {name}{unsafety_flag}\ - {stab_docs}{docs}\ + {stab_tags}{docs}\ \ ", 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 { +/// 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("[
Deprecated
] "); + } + + 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("[
Internal
] "); + } else { + tags.push_str("[
Experimental
] "); + } + } + + if let Some(ref cfg) = item.attrs.cfg { + tags.push_str(&format!( + "[
{}
] ", + 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 { 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(¬e, RefCell::new(&mut ids), error_codes); + message.push_str(&format!(": {}", html)); + } + stability.push(format!("
{}
", 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 { + "⚙️ This is an internal compiler API." + } else { + "🔬 This is a nightly-only experimental API." + } + .to_owned(); + + if let Some(feature) = stab.feature.as_ref() { + let mut feature = format!("{}", Escape(&feature)); + if let (Some(url), Some(issue)) = (&cx.shared.issue_tracker_base_url, stab.issue) { + feature.push_str(&format!( + " #{issue}", + 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!("
{}
", 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!(" ({} #{})", - Escape(&stab.feature), tracker_url, issue_no, issue_no), - (false, &Some(ref tracker_url), Some(issue_no)) if issue_no > 0 => - format!(" (#{})", Escape(&tracker_url), issue_no, - issue_no), - (true, ..) => - format!(" ({})", Escape(&stab.feature)), - _ => String::new(), - }; - if stab.unstable_reason.is_empty() { - stability.push(format!("
\ - 🔬 \ - This is a nightly-only experimental API. {}\ -
", - unstable_extra)); - } else { - let mut ids = cx.id_map.borrow_mut(); - let text = format!("🔬 \ - This is a nightly-only experimental API. {}\ - {}", - unstable_extra, - MarkdownHtml( - &stab.unstable_reason, - RefCell::new(&mut ids), - error_codes)); - stability.push(format!("
{}
", - text)); - } - } else { - stability.push("
Experimental
".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!( + "
{}{}
", + 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(¬e, RefCell::new(&mut ids), error_codes)) + let class = if is_rustc_private { + "internal" } else { - format!("Deprecating in {}{}", - Escape(&depr.since), - MarkdownHtml(¬e, RefCell::new(&mut ids), error_codes)) + "unstable" }; - stability.push(format!("
{}
", text)) + stability.push(format!("
{}
", class, message)); } if let Some(ref cfg) = item.attrs.cfg { - stability.push(format!("
{}
", if show_reason { + stability.push(format!( + "
{}
", 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}

\ -

")?; document(w, cx, m)?; Ok(()) } @@ -3237,13 +3246,14 @@ fn assoc_type(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, "
{0}
", - v)? + write!(w, "
{0}
", 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, " - - ", + write!(w, "\ + \ + {name}: {ty}\ + ", 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, "\ \ - ")?; + write!(w, "")?; 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, "\ \ - ", + {f}: {t}\ + ", 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, "", id)?; - write!(w, "")?; + write!(w, "")?; 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, "
")?; @@ -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, "
")?; + write!(w, "
")?; if let Some(ref dox) = cx.shared.maybe_collapsed_doc_value(&i.impl_item) { let mut ids = cx.id_map.borrow_mut(); write!(w, "
{}
", @@ -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, "

", id, item_type, extra_class)?; write!(w, "{}", spotlight_decl(decl)?)?; - write!(w, "

")?; } } 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, "

", id, item_type, extra_class)?; - write!(w, "

\n")?; + write!(w, "")?; } 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, "

", id, item_type, extra_class)?; - write!(w, "

", 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, "

", id, item_type, extra_class)?; - write!(w, "

\n")?; + write!(w, "")?; } clean::StrippedItem(..) => return Ok(()), _ => panic!("can't make docs for trait item with name {:?}", item.name) diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 1480c54ce40..3958986e492 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -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; } diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index 2cd1a858089..be3ffed2b26 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -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; } diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index 4cf35f64d19..4ae10492ae6 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -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; } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index ead38f21126..9042cb3c72d 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -250,6 +250,7 @@ #![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)] diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 5aa043b0fcb..347e795c4f7 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -729,6 +729,9 @@ pub fn try_clone(&self) -> io::Result { /// ``` #[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)) } diff --git a/src/libstd/rt.rs b/src/libstd/rt.rs index 9e957bd87d7..fdaf2a821fa 100644 --- a/src/libstd/rt.rs +++ b/src/libstd/rt.rs @@ -73,18 +73,3 @@ fn lang_start { 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); -} diff --git a/src/libstd/sys/cloudabi/thread.rs b/src/libstd/sys/cloudabi/thread.rs index 177321439d8..a64e0f06849 100644 --- a/src/libstd/sys/cloudabi/thread.rs +++ b/src/libstd/sys/cloudabi/thread.rs @@ -121,7 +121,6 @@ pub unsafe fn current() -> Option { pub unsafe fn init() -> Option { None } - pub unsafe fn deinit() {} } fn min_stack_size(_: *const libc::pthread_attr_t) -> usize { diff --git a/src/libstd/sys/redox/thread.rs b/src/libstd/sys/redox/thread.rs index ff861805382..ca014fd576b 100644 --- a/src/libstd/sys/redox/thread.rs +++ b/src/libstd/sys/redox/thread.rs @@ -92,5 +92,4 @@ pub mod guard { pub type Guard = !; pub unsafe fn current() -> Option { None } pub unsafe fn init() -> Option { None } - pub unsafe fn deinit() {} } diff --git a/src/libstd/sys/sgx/thread.rs b/src/libstd/sys/sgx/thread.rs index 9de12a5e6f1..9f3c4536cb5 100644 --- a/src/libstd/sys/sgx/thread.rs +++ b/src/libstd/sys/sgx/thread.rs @@ -97,5 +97,4 @@ pub mod guard { pub type Guard = !; pub unsafe fn current() -> Option { None } pub unsafe fn init() -> Option { None } - pub unsafe fn deinit() {} } diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index d922be520d4..f30817e69ab 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -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), } } diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index 03e81a720dc..6e8ee445994 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -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 { diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index 0a5dccdddda..24b2959a3fa 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -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()) })?; diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index 4ff060018ae..e0d2c620498 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -211,7 +211,6 @@ pub mod guard { pub type Guard = Range; pub unsafe fn current() -> Option { None } pub unsafe fn init() -> Option { None } - pub unsafe fn deinit() {} } @@ -355,26 +354,6 @@ pub unsafe fn init() -> Option { } } - 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", diff --git a/src/libstd/sys/unix/weak.rs b/src/libstd/sys/unix/weak.rs index 18944be58ee..7d293f1c47a 100644 --- a/src/libstd/sys/unix/weak.rs +++ b/src/libstd/sys/unix/weak.rs @@ -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 + } + ) +} diff --git a/src/libstd/sys/wasm/thread.rs b/src/libstd/sys/wasm/thread.rs index 3d74ffdc14a..f9abb0b825a 100644 --- a/src/libstd/sys/wasm/thread.rs +++ b/src/libstd/sys/wasm/thread.rs @@ -68,7 +68,6 @@ pub mod guard { pub type Guard = !; pub unsafe fn current() -> Option { None } pub unsafe fn init() -> Option { None } - pub unsafe fn deinit() {} } cfg_if! { diff --git a/src/libstd/sys/windows/thread.rs b/src/libstd/sys/windows/thread.rs index 1a97dd10ced..621ae2fda58 100644 --- a/src/libstd/sys/windows/thread.rs +++ b/src/libstd/sys/windows/thread.rs @@ -98,5 +98,4 @@ pub mod guard { pub type Guard = !; pub unsafe fn current() -> Option { None } pub unsafe fn init() -> Option { None } - pub unsafe fn deinit() {} } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 310cf27689b..b807a65f6ae 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -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) -> P; 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) -> P { item } fn visit_ast_fragment_with_placeholders(&mut self, _invoc: Mark, _fragment: &AstFragment, _derives: &[Mark]) {} diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 03c7aa96824..57ccc3e9817 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -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()) } } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index e3cccacb3c3..200b1cecc03 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -81,6 +81,7 @@ pub fn with_span_handler(handler: Handler, source_map: Lrc) -> ParseS } } + #[inline] pub fn source_map(&self) -> &SourceMap { &self.source_map } diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index ed746657459..badcc4ed876 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -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) diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 41165c7e36d..5e7707f4e5c 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -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(()) } diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index c11ef33f931..013ecd3d343 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -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 } } diff --git a/src/libsyntax_ext/deriving/custom.rs b/src/libsyntax_ext/deriving/custom.rs index 5c82d191138..cc2fa685687 100644 --- a/src/libsyntax_ext/deriving/custom.rs +++ b/src/libsyntax_ext/deriving/custom.rs @@ -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(); diff --git a/src/libsyntax_ext/proc_macro_server.rs b/src/libsyntax_ext/proc_macro_server.rs index a04d6c92b78..ca960cbe41b 100644 --- a/src/libsyntax_ext/proc_macro_server.rs +++ b/src/libsyntax_ext/proc_macro_server.rs @@ -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 diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index 74f63b5e2c6..3dc884a94c0 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -18,11 +18,11 @@ 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, } @@ -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 index ab42b2eff99..00000000000 --- a/src/test/debuginfo/nil-enum.rs +++ /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 or the MIT license -// , 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 {} - -// gdb-command:print second -// gdbr-check:$2 = nil_enum::AnotherNilEnum {} - -#![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 "{}" 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() {()} diff --git a/src/test/mir-opt/retag.rs b/src/test/mir-opt/retag.rs index 7da55c0868c..f48862ff933 100644 --- a/src/test/mir-opt/retag.rs +++ b/src/test/mir-opt/retag.rs @@ -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 index 00000000000..904a9c43c1b --- /dev/null +++ b/src/test/mir-opt/uninhabited-enum.rs @@ -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 diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index 5f42b86c82a..3b01ab3a47b 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -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 diff --git a/src/test/run-pass/arbitrary_self_types_stdlib_pointers.rs b/src/test/run-pass/arbitrary_self_types_stdlib_pointers.rs index 80a7ce96911..6ec70bb8c09 100644 --- a/src/test/run-pass/arbitrary_self_types_stdlib_pointers.rs +++ b/src/test/run-pass/arbitrary_self_types_stdlib_pointers.rs @@ -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) -> i64; fn by_pin_mut(self: Pin<&mut Self>) -> i64; fn by_pin_box(self: Pin>) -> i64; + fn by_pin_pin_pin_ref(self: Pin>>) -> i64; } impl Trait for i64 { @@ -38,6 +38,9 @@ fn by_pin_mut(self: Pin<&mut Self>) -> i64 { fn by_pin_box(self: Pin>) -> i64 { *self } + fn by_pin_pin_pin_ref(self: Pin>>) -> i64 { + *self + } } fn main() { @@ -53,4 +56,8 @@ fn main() { let pin_box = Into::>>::into(Box::new(4i64)) as Pin>; 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>>; + assert_eq!(5, pin_pin_pin_ref.by_pin_pin_pin_ref()); } diff --git a/src/test/run-pass/binding/empty-types-in-patterns.rs b/src/test/run-pass/binding/empty-types-in-patterns.rs index 7fb7eec1256..f595bb0da9a 100644 --- a/src/test/run-pass/binding/empty-types-in-patterns.rs +++ b/src/test/run-pass/binding/empty-types-in-patterns.rs @@ -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 index 00000000000..4b15ecb3e54 --- /dev/null +++ b/src/test/run-pass/issue-53843.rs @@ -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 or the MIT license +// , 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); + +impl Deref for Pin

+where + P: Deref, +{ + type Target = T; + + fn deref(&self) -> &T { + &*self.0 + } +} + +impl

Pin

{ + fn poll(self) {} +} + +fn main() { + let mut unit = (); + let pin = Pin(&mut unit); + pin.poll(); +} diff --git a/src/test/run-pass/issues/issue-41696.rs b/src/test/run-pass/issues/issue-41696.rs index 3937f9c1930..5a5a2adc124 100644 --- a/src/test/run-pass/issues/issue-41696.rs +++ b/src/test/run-pass/issues/issue-41696.rs @@ -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 index 00000000000..2295be27258 --- /dev/null +++ b/src/test/rustdoc/assoc-consts-version.rs @@ -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 or the MIT license +// , 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; +} diff --git a/src/test/rustdoc/assoc-types.rs b/src/test/rustdoc/assoc-types.rs index d152be33f4c..100bf7af0e9 100644 --- a/src/test/rustdoc/assoc-types.rs +++ b/src/test/rustdoc/assoc-types.rs @@ -15,9 +15,9 @@ // @has assoc_types/trait.Index.html pub trait Index { // @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 index 00000000000..8ac0d07ceef --- /dev/null +++ b/src/test/rustdoc/const-display.rs @@ -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 or the MIT license +// , 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 } diff --git a/src/test/rustdoc/deprecated.rs b/src/test/rustdoc/deprecated.rs index 744304a62c2..63447ad1690 100644 --- a/src/test/rustdoc/deprecated.rs +++ b/src/test/rustdoc/deprecated.rs @@ -10,7 +10,29 @@ #![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 index 00000000000..ba58da138a8 --- /dev/null +++ b/src/test/rustdoc/internal.rs @@ -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() {} diff --git a/src/test/rustdoc/issue-27759.rs b/src/test/rustdoc/issue-27759.rs index e82e93230aa..4723b04a078 100644 --- a/src/test/rustdoc/issue-27759.rs +++ b/src/test/rustdoc/issue-27759.rs @@ -14,13 +14,11 @@ #![unstable(feature="test", issue="27759")] // @has issue_27759/unstable/index.html -// @has - 'test ' -// @has - '#27759' +// @has - 'test #27759' #[unstable(feature="test", issue="27759")] pub mod unstable { // @has issue_27759/unstable/fn.issue.html - // @has - 'test_function ' - // @has - '#1234567890' - #[unstable(feature="test_function", issue="1234567890")] + // @has - 'test_function #12345' + #[unstable(feature="test_function", issue="12345")] pub fn issue() {} } diff --git a/src/test/rustdoc/issue-32374.rs b/src/test/rustdoc/issue-32374.rs index 6d1f8bc1cf9..34423d0176d 100644 --- a/src/test/rustdoc/issue-32374.rs +++ b/src/test/rustdoc/issue-32374.rs @@ -13,15 +13,15 @@ #![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 - 'test ' -// @has - '#32374' +// @has - 'test #32374' // @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 index 00000000000..bea8586452e --- /dev/null +++ b/src/test/ui/coercion/coerce-issue-49593-box-never.rs @@ -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 or the MIT license +// , 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) -> *mut T { + panic!() +} + +fn foo(x: !) -> Box { + /* *mut $0 is coerced to Box 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 */ = None; + let mut first_iter = false; + loop { + if !first_iter { + let y: Box + = /* Box<$0> is coerced to Box here */ Box::new(x.unwrap()); + } + + x = Some(S); + first_iter = true; + } + + let mut y : Option = 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 index 00000000000..21aaea47963 --- /dev/null +++ b/src/test/ui/coherence/auxiliary/coherence_fundamental_trait_lib.rs @@ -0,0 +1,7 @@ +#![crate_type = "rlib"] +#![feature(fundamental)] + +pub trait Misc {} + +#[fundamental] +pub trait Fundamental {} 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 index 00000000000..dd127bf7f4b --- /dev/null +++ b/src/test/ui/coherence/coherence-fundamental-trait-objects.rs @@ -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 {} +//~^ 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 index 00000000000..cefcac2c517 --- /dev/null +++ b/src/test/ui/coherence/coherence-fundamental-trait-objects.stderr @@ -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 {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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`. diff --git a/src/test/ui/consts/const-eval/ub-uninhabit.rs b/src/test/ui/consts/const-eval/ub-uninhabit.rs index 74713af2ea0..42cba02f579 100644 --- a/src/test/ui/consts/const-eval/ub-uninhabit.rs +++ b/src/test/ui/consts/const-eval/ub-uninhabit.rs @@ -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 or the MIT license -// , 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 @@ -16,14 +6,18 @@ #[derive(Copy, Clone)] enum Bar {} -const BAD_BAD_BAD: Bar = unsafe { mem::transmute(()) }; +union TransmuteUnion { + 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() {} diff --git a/src/test/ui/consts/const-eval/ub-uninhabit.stderr b/src/test/ui/consts/const-eval/ub-uninhabit.stderr index c5ac72b639c..c8842ecc23c 100644 --- a/src/test/ui/consts/const-eval/ub-uninhabit.stderr +++ b/src/test/ui/consts/const-eval/ub-uninhabit.stderr @@ -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 . @@ -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 diff --git a/src/test/ui/consts/validate_never_arrays.stderr b/src/test/ui/consts/validate_never_arrays.stderr index 0b639240bb3..b9d181a76dd 100644 --- a/src/test/ui/consts/validate_never_arrays.stderr +++ b/src/test/ui/consts/validate_never_arrays.stderr @@ -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 .[0] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type at . | = 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 diff --git a/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.rs b/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.rs index ff0306f1993..84cd5c2bffa 100644 --- a/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.rs +++ b/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.rs @@ -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(Box); + +impl Deref for Ptr { + type Target = T; + + fn deref(&self) -> &T { + &*self.0 + } +} trait Foo { - fn foo(self: Rc>); //~ ERROR arbitrary `self` types are unstable + fn foo(self: Ptr); //~ ERROR `Ptr` cannot be used as the type of `self` without } struct Bar; impl Foo for Bar { - fn foo(self: Rc>) {} //~ ERROR arbitrary `self` types are unstable + fn foo(self: Ptr) {} //~ ERROR `Ptr` cannot be used as the type of `self` without } impl Bar { - fn bar(self: Box>) {} //~ ERROR arbitrary `self` types are unstable + fn bar(self: Box>) {} //~ ERROR `std::boxed::Box>` cannot be used as the } fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.stderr b/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.stderr index ea259aa22ad..c70774b3710 100644 --- a/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.stderr +++ b/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.stderr @@ -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` 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>); //~ ERROR arbitrary `self` types are unstable - | ^^^^^^^^^^^^^ +LL | fn foo(self: Ptr); //~ ERROR `Ptr` 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` -error[E0658]: arbitrary `self` types are unstable (see issue #44874) - --> $DIR/feature-gate-arbitrary-self-types.rs:20:18 +error[E0658]: `Ptr` 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>) {} //~ ERROR arbitrary `self` types are unstable - | ^^^^^^^^^^^^^ +LL | fn foo(self: Ptr) {} //~ ERROR `Ptr` 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` -error[E0658]: arbitrary `self` types are unstable (see issue #44874) - --> $DIR/feature-gate-arbitrary-self-types.rs:24:18 +error[E0658]: `std::boxed::Box>` 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>) {} //~ ERROR arbitrary `self` types are unstable - | ^^^^^^^^^^^^^ +LL | fn bar(self: Box>) {} //~ ERROR `std::boxed::Box>` 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` diff --git a/src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.rs b/src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.rs index 29e51727edc..6d42460ba56 100644 --- a/src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.rs +++ b/src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.rs @@ -12,17 +12,17 @@ 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() {} diff --git a/src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr b/src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr index 5ed9a0f4ed0..b8cc7dee986 100644 --- a/src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr +++ b/src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr @@ -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` -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` -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 index 00000000000..97b66b2c7c9 --- /dev/null +++ b/src/test/ui/issues/issue-56762.rs @@ -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 index 00000000000..83d5dc62e61 --- /dev/null +++ b/src/test/ui/issues/issue-56762.stderr @@ -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 index 00000000000..82e73651f43 --- /dev/null +++ b/src/test/ui/nll/issue-46589.rs @@ -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 or the MIT license +// , 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 index 00000000000..6df2983f465 --- /dev/null +++ b/src/test/ui/nll/issue-46589.stderr @@ -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`. diff --git a/src/test/ui/nll/loan_ends_mid_block_pair.rs b/src/test/ui/nll/loan_ends_mid_block_pair.rs index 97126e98cbf..320d80438b0 100644 --- a/src/test/ui/nll/loan_ends_mid_block_pair.rs +++ b/src/test/ui/nll/loan_ends_mid_block_pair.rs @@ -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); } diff --git a/src/test/ui/nll/loan_ends_mid_block_pair.stderr b/src/test/ui/nll/loan_ends_mid_block_pair.stderr index 9afae71edbe..3ba3fa15a53 100644 --- a/src/test/ui/nll/loan_ends_mid_block_pair.stderr +++ b/src/test/ui/nll/loan_ends_mid_block_pair.stderr @@ -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`. diff --git a/src/test/ui/privacy/privacy1.rs b/src/test/ui/privacy/privacy1.rs index 9aff4bbc41c..c336cc6299e 100644 --- a/src/test/ui/privacy/privacy1.rs +++ b/src/test/ui/privacy/privacy1.rs @@ -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::*; diff --git a/src/test/ui/privacy/privacy1.stderr b/src/test/ui/privacy/privacy1.stderr index d6197575447..54e01cca6c4 100644 --- a/src/test/ui/privacy/privacy1.stderr +++ b/src/test/ui/privacy/privacy1.stderr @@ -1,101 +1,101 @@ 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 index 00000000000..8f15a2b975b --- /dev/null +++ b/src/test/ui/proc-macro/auxiliary/dollar-crate-external.rs @@ -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 index 00000000000..d0ea850d4e3 --- /dev/null +++ b/src/test/ui/proc-macro/auxiliary/dollar-crate.rs @@ -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 index 00000000000..1460e9a3b2d --- /dev/null +++ b/src/test/ui/proc-macro/dollar-crate.rs @@ -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 index 00000000000..08de3c7d1a6 --- /dev/null +++ b/src/test/ui/proc-macro/dollar-crate.stderr @@ -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 index 00000000000..c47b3603f41 --- /dev/null +++ b/src/test/ui/proc-macro/dollar-crate.stdout @@ -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) + } +] diff --git a/src/test/ui/span/issue-27522.rs b/src/test/ui/span/issue-27522.rs index 1e3eba4bf36..11c90833e71 100644 --- a/src/test/ui/span/issue-27522.rs +++ b/src/test/ui/span/issue-27522.rs @@ -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() {} diff --git a/src/test/ui/span/issue-27522.stderr b/src/test/ui/span/issue-27522.stderr index 9b61ecae651..767b99a92cb 100644 --- a/src/test/ui/span/issue-27522.stderr +++ b/src/test/ui/span/issue-27522.stderr @@ -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 diff --git a/src/test/ui/ufcs/ufcs-explicit-self-bad.rs b/src/test/ui/ufcs/ufcs-explicit-self-bad.rs index a0d1f2dc331..f87541b56ac 100644 --- a/src/test/ui/ufcs/ufcs-explicit-self-bad.rs +++ b/src/test/ui/ufcs/ufcs-explicit-self-bad.rs @@ -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 { impl Bar { fn foo(self: Bar, x: isize) -> isize { - //~^ ERROR invalid `self` type + //~^ ERROR invalid method receiver type x } fn bar(self: &Bar, x: isize) -> isize { - //~^ ERROR invalid `self` type + //~^ ERROR invalid method receiver type x } } diff --git a/src/test/ui/ufcs/ufcs-explicit-self-bad.stderr b/src/test/ui/ufcs/ufcs-explicit-self-bad.stderr index fce74605cad..a229dabcce4 100644 --- a/src/test/ui/ufcs/ufcs-explicit-self-bad.stderr +++ b/src/test/ui/ufcs/ufcs-explicit-self-bad.stderr @@ -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` -error[E0307]: invalid `self` type: Bar +error[E0307]: invalid method receiver type: Bar --> $DIR/ufcs-explicit-self-bad.rs:29:18 | LL | fn foo(self: Bar, x: isize) -> isize { | ^^^^^^^^^^ | - = note: type must be `Bar` 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` -error[E0307]: invalid `self` type: &Bar +error[E0307]: invalid method receiver type: &Bar --> $DIR/ufcs-explicit-self-bad.rs:33:18 | LL | fn bar(self: &Bar, x: isize) -> isize { | ^^^^^^^^^^^ | - = note: type must be `Bar` 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` 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 index 00000000000..9fe8a5c832c --- /dev/null +++ b/src/test/ui/uninhabited/privately-uninhabited-dead-code.rs @@ -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 +}