Auto merge of #41773 - frewsxcv:rollup, r=frewsxcv
Rollup of 9 pull requests - Successful merges: #41064, #41307, #41512, #41582, #41678, #41722, #41734, #41761, #41763 - Failed merges:
This commit is contained in:
commit
42a4f373c9
75 changed files with 1495 additions and 955 deletions
|
@ -1 +1 @@
|
||||||
Subproject commit 616b98444ff4eb5260deee95ee3e090dfd98b947
|
Subproject commit 6fa139b1630a9bb95dcd60cfc90aff9c19e54580
|
|
@ -277,8 +277,7 @@ impl<T> Arc<T> {
|
||||||
atomic::fence(Acquire);
|
atomic::fence(Acquire);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr = *this.ptr;
|
let elem = ptr::read(&this.ptr.as_ref().data);
|
||||||
let elem = ptr::read(&(*ptr).data);
|
|
||||||
|
|
||||||
// Make a weak pointer to clean up the implicit strong-weak reference
|
// Make a weak pointer to clean up the implicit strong-weak reference
|
||||||
let _weak = Weak { ptr: this.ptr };
|
let _weak = Weak { ptr: this.ptr };
|
||||||
|
@ -306,7 +305,7 @@ impl<T> Arc<T> {
|
||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "rc_raw", since = "1.17.0")]
|
#[stable(feature = "rc_raw", since = "1.17.0")]
|
||||||
pub fn into_raw(this: Self) -> *const T {
|
pub fn into_raw(this: Self) -> *const T {
|
||||||
let ptr = unsafe { &(**this.ptr).data as *const _ };
|
let ptr: *const T = &*this;
|
||||||
mem::forget(this);
|
mem::forget(this);
|
||||||
ptr
|
ptr
|
||||||
}
|
}
|
||||||
|
@ -345,7 +344,7 @@ impl<T> Arc<T> {
|
||||||
// `data` field from the pointer.
|
// `data` field from the pointer.
|
||||||
let ptr = (ptr as *const u8).offset(-offset_of!(ArcInner<T>, data));
|
let ptr = (ptr as *const u8).offset(-offset_of!(ArcInner<T>, data));
|
||||||
Arc {
|
Arc {
|
||||||
ptr: Shared::new(ptr as *const _),
|
ptr: Shared::new(ptr as *mut u8 as *mut _),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -452,17 +451,17 @@ impl<T: ?Sized> Arc<T> {
|
||||||
// `ArcInner` structure itself is `Sync` because the inner data is
|
// `ArcInner` structure itself is `Sync` because the inner data is
|
||||||
// `Sync` as well, so we're ok loaning out an immutable pointer to these
|
// `Sync` as well, so we're ok loaning out an immutable pointer to these
|
||||||
// contents.
|
// contents.
|
||||||
unsafe { &**self.ptr }
|
unsafe { self.ptr.as_ref() }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Non-inlined part of `drop`.
|
// Non-inlined part of `drop`.
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
unsafe fn drop_slow(&mut self) {
|
unsafe fn drop_slow(&mut self) {
|
||||||
let ptr = self.ptr.as_mut_ptr();
|
let ptr = self.ptr.as_ptr();
|
||||||
|
|
||||||
// Destroy the data at this time, even though we may not free the box
|
// Destroy the data at this time, even though we may not free the box
|
||||||
// allocation itself (there may still be weak pointers lying around).
|
// allocation itself (there may still be weak pointers lying around).
|
||||||
ptr::drop_in_place(&mut (*ptr).data);
|
ptr::drop_in_place(&mut self.ptr.as_mut().data);
|
||||||
|
|
||||||
if self.inner().weak.fetch_sub(1, Release) == 1 {
|
if self.inner().weak.fetch_sub(1, Release) == 1 {
|
||||||
atomic::fence(Acquire);
|
atomic::fence(Acquire);
|
||||||
|
@ -488,9 +487,7 @@ impl<T: ?Sized> Arc<T> {
|
||||||
/// assert!(!Arc::ptr_eq(&five, &other_five));
|
/// assert!(!Arc::ptr_eq(&five, &other_five));
|
||||||
/// ```
|
/// ```
|
||||||
pub fn ptr_eq(this: &Self, other: &Self) -> bool {
|
pub fn ptr_eq(this: &Self, other: &Self) -> bool {
|
||||||
let this_ptr: *const ArcInner<T> = *this.ptr;
|
this.ptr.as_ptr() == other.ptr.as_ptr()
|
||||||
let other_ptr: *const ArcInner<T> = *other.ptr;
|
|
||||||
this_ptr == other_ptr
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -621,7 +618,7 @@ impl<T: Clone> Arc<T> {
|
||||||
// here (due to zeroing) because data is no longer accessed by
|
// here (due to zeroing) because data is no longer accessed by
|
||||||
// other threads (due to there being no more strong refs at this
|
// other threads (due to there being no more strong refs at this
|
||||||
// point).
|
// point).
|
||||||
let mut swap = Arc::new(ptr::read(&(**weak.ptr).data));
|
let mut swap = Arc::new(ptr::read(&weak.ptr.as_ref().data));
|
||||||
mem::swap(this, &mut swap);
|
mem::swap(this, &mut swap);
|
||||||
mem::forget(swap);
|
mem::forget(swap);
|
||||||
}
|
}
|
||||||
|
@ -634,8 +631,7 @@ impl<T: Clone> Arc<T> {
|
||||||
// As with `get_mut()`, the unsafety is ok because our reference was
|
// As with `get_mut()`, the unsafety is ok because our reference was
|
||||||
// either unique to begin with, or became one upon cloning the contents.
|
// either unique to begin with, or became one upon cloning the contents.
|
||||||
unsafe {
|
unsafe {
|
||||||
let inner = &mut *this.ptr.as_mut_ptr();
|
&mut this.ptr.as_mut().data
|
||||||
&mut inner.data
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -677,8 +673,7 @@ impl<T: ?Sized> Arc<T> {
|
||||||
// the Arc itself to be `mut`, so we're returning the only possible
|
// the Arc itself to be `mut`, so we're returning the only possible
|
||||||
// reference to the inner data.
|
// reference to the inner data.
|
||||||
unsafe {
|
unsafe {
|
||||||
let inner = &mut *this.ptr.as_mut_ptr();
|
Some(&mut this.ptr.as_mut().data)
|
||||||
Some(&mut inner.data)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -878,7 +873,7 @@ impl<T: ?Sized> Weak<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn inner(&self) -> &ArcInner<T> {
|
fn inner(&self) -> &ArcInner<T> {
|
||||||
// See comments above for why this is "safe"
|
// See comments above for why this is "safe"
|
||||||
unsafe { &**self.ptr }
|
unsafe { self.ptr.as_ref() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -962,7 +957,7 @@ impl<T: ?Sized> Drop for Weak<T> {
|
||||||
/// assert!(other_weak_foo.upgrade().is_none());
|
/// assert!(other_weak_foo.upgrade().is_none());
|
||||||
/// ```
|
/// ```
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let ptr = *self.ptr;
|
let ptr = self.ptr.as_ptr();
|
||||||
|
|
||||||
// If we find out that we were the last weak pointer, then its time to
|
// If we find out that we were the last weak pointer, then its time to
|
||||||
// deallocate the data entirely. See the discussion in Arc::drop() about
|
// deallocate the data entirely. See the discussion in Arc::drop() about
|
||||||
|
@ -1143,7 +1138,7 @@ impl<T: ?Sized + fmt::Debug> fmt::Debug for Arc<T> {
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl<T: ?Sized> fmt::Pointer for Arc<T> {
|
impl<T: ?Sized> fmt::Pointer for Arc<T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
fmt::Pointer::fmt(&*self.ptr, f)
|
fmt::Pointer::fmt(&self.ptr, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -156,7 +156,7 @@ fn make_place<T>() -> IntermediateBox<T> {
|
||||||
let align = mem::align_of::<T>();
|
let align = mem::align_of::<T>();
|
||||||
|
|
||||||
let p = if size == 0 {
|
let p = if size == 0 {
|
||||||
heap::EMPTY as *mut u8
|
mem::align_of::<T>() as *mut u8
|
||||||
} else {
|
} else {
|
||||||
let p = unsafe { heap::allocate(size, align) };
|
let p = unsafe { heap::allocate(size, align) };
|
||||||
if p.is_null() {
|
if p.is_null() {
|
||||||
|
|
|
@ -138,7 +138,9 @@ pub fn usable_size(size: usize, align: usize) -> usize {
|
||||||
///
|
///
|
||||||
/// This preserves the non-null invariant for types like `Box<T>`. The address
|
/// This preserves the non-null invariant for types like `Box<T>`. The address
|
||||||
/// may overlap with non-zero-size memory allocations.
|
/// may overlap with non-zero-size memory allocations.
|
||||||
pub const EMPTY: *mut () = 0x1 as *mut ();
|
#[rustc_deprecated(since = "1.19", reason = "Use Unique/Shared::empty() instead")]
|
||||||
|
#[unstable(feature = "heap_api", issue = "27700")]
|
||||||
|
pub const EMPTY: *mut () = 1 as *mut ();
|
||||||
|
|
||||||
/// The allocator for unique pointers.
|
/// The allocator for unique pointers.
|
||||||
// This function must not unwind. If it does, MIR trans will fail.
|
// This function must not unwind. If it does, MIR trans will fail.
|
||||||
|
@ -147,7 +149,7 @@ pub const EMPTY: *mut () = 0x1 as *mut ();
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
|
unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
EMPTY as *mut u8
|
align as *mut u8
|
||||||
} else {
|
} else {
|
||||||
let ptr = allocate(size, align);
|
let ptr = allocate(size, align);
|
||||||
if ptr.is_null() {
|
if ptr.is_null() {
|
||||||
|
|
|
@ -22,13 +22,13 @@ use core::cmp;
|
||||||
/// involved. This type is excellent for building your own data structures like Vec and VecDeque.
|
/// involved. This type is excellent for building your own data structures like Vec and VecDeque.
|
||||||
/// In particular:
|
/// In particular:
|
||||||
///
|
///
|
||||||
/// * Produces heap::EMPTY on zero-sized types
|
/// * Produces Unique::empty() on zero-sized types
|
||||||
/// * Produces heap::EMPTY on zero-length allocations
|
/// * Produces Unique::empty() on zero-length allocations
|
||||||
/// * Catches all overflows in capacity computations (promotes them to "capacity overflow" panics)
|
/// * Catches all overflows in capacity computations (promotes them to "capacity overflow" panics)
|
||||||
/// * Guards against 32-bit systems allocating more than isize::MAX bytes
|
/// * Guards against 32-bit systems allocating more than isize::MAX bytes
|
||||||
/// * Guards against overflowing your length
|
/// * Guards against overflowing your length
|
||||||
/// * Aborts on OOM
|
/// * Aborts on OOM
|
||||||
/// * Avoids freeing heap::EMPTY
|
/// * Avoids freeing Unique::empty()
|
||||||
/// * Contains a ptr::Unique and thus endows the user with all related benefits
|
/// * Contains a ptr::Unique and thus endows the user with all related benefits
|
||||||
///
|
///
|
||||||
/// This type does not in anyway inspect the memory that it manages. When dropped it *will*
|
/// This type does not in anyway inspect the memory that it manages. When dropped it *will*
|
||||||
|
@ -55,15 +55,13 @@ impl<T> RawVec<T> {
|
||||||
/// it makes a RawVec with capacity `usize::MAX`. Useful for implementing
|
/// it makes a RawVec with capacity `usize::MAX`. Useful for implementing
|
||||||
/// delayed allocation.
|
/// delayed allocation.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
unsafe {
|
// !0 is usize::MAX. This branch should be stripped at compile time.
|
||||||
// !0 is usize::MAX. This branch should be stripped at compile time.
|
let cap = if mem::size_of::<T>() == 0 { !0 } else { 0 };
|
||||||
let cap = if mem::size_of::<T>() == 0 { !0 } else { 0 };
|
|
||||||
|
|
||||||
// heap::EMPTY doubles as "unallocated" and "zero-sized allocation"
|
// Unique::empty() doubles as "unallocated" and "zero-sized allocation"
|
||||||
RawVec {
|
RawVec {
|
||||||
ptr: Unique::new(heap::EMPTY as *mut T),
|
ptr: Unique::empty(),
|
||||||
cap: cap,
|
cap: cap,
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +99,7 @@ impl<T> RawVec<T> {
|
||||||
|
|
||||||
// handles ZSTs and `cap = 0` alike
|
// handles ZSTs and `cap = 0` alike
|
||||||
let ptr = if alloc_size == 0 {
|
let ptr = if alloc_size == 0 {
|
||||||
heap::EMPTY as *mut u8
|
mem::align_of::<T>() as *mut u8
|
||||||
} else {
|
} else {
|
||||||
let align = mem::align_of::<T>();
|
let align = mem::align_of::<T>();
|
||||||
let ptr = if zeroed {
|
let ptr = if zeroed {
|
||||||
|
@ -148,10 +146,10 @@ impl<T> RawVec<T> {
|
||||||
|
|
||||||
impl<T> RawVec<T> {
|
impl<T> RawVec<T> {
|
||||||
/// Gets a raw pointer to the start of the allocation. Note that this is
|
/// Gets a raw pointer to the start of the allocation. Note that this is
|
||||||
/// heap::EMPTY if `cap = 0` or T is zero-sized. In the former case, you must
|
/// Unique::empty() if `cap = 0` or T is zero-sized. In the former case, you must
|
||||||
/// be careful.
|
/// be careful.
|
||||||
pub fn ptr(&self) -> *mut T {
|
pub fn ptr(&self) -> *mut T {
|
||||||
*self.ptr
|
self.ptr.as_ptr()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the capacity of the allocation.
|
/// Gets the capacity of the allocation.
|
||||||
|
@ -563,7 +561,7 @@ unsafe impl<#[may_dangle] T> Drop for RawVec<T> {
|
||||||
|
|
||||||
let num_bytes = elem_size * self.cap;
|
let num_bytes = elem_size * self.cap;
|
||||||
unsafe {
|
unsafe {
|
||||||
heap::deallocate(*self.ptr as *mut _, num_bytes, align);
|
heap::deallocate(self.ptr() as *mut u8, num_bytes, align);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -230,7 +230,7 @@ use core::cell::Cell;
|
||||||
use core::cmp::Ordering;
|
use core::cmp::Ordering;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::hash::{Hash, Hasher};
|
use core::hash::{Hash, Hasher};
|
||||||
use core::intrinsics::{abort, assume};
|
use core::intrinsics::abort;
|
||||||
use core::marker;
|
use core::marker;
|
||||||
use core::marker::Unsize;
|
use core::marker::Unsize;
|
||||||
use core::mem::{self, align_of_val, forget, size_of, size_of_val, uninitialized};
|
use core::mem::{self, align_of_val, forget, size_of, size_of_val, uninitialized};
|
||||||
|
@ -358,7 +358,7 @@ impl<T> Rc<T> {
|
||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "rc_raw", since = "1.17.0")]
|
#[stable(feature = "rc_raw", since = "1.17.0")]
|
||||||
pub fn into_raw(this: Self) -> *const T {
|
pub fn into_raw(this: Self) -> *const T {
|
||||||
let ptr = unsafe { &mut (*this.ptr.as_mut_ptr()).value as *const _ };
|
let ptr: *const T = &*this;
|
||||||
mem::forget(this);
|
mem::forget(this);
|
||||||
ptr
|
ptr
|
||||||
}
|
}
|
||||||
|
@ -395,7 +395,11 @@ impl<T> Rc<T> {
|
||||||
pub unsafe fn from_raw(ptr: *const T) -> Self {
|
pub unsafe fn from_raw(ptr: *const T) -> Self {
|
||||||
// To find the corresponding pointer to the `RcBox` we need to subtract the offset of the
|
// To find the corresponding pointer to the `RcBox` we need to subtract the offset of the
|
||||||
// `value` field from the pointer.
|
// `value` field from the pointer.
|
||||||
Rc { ptr: Shared::new((ptr as *const u8).offset(-offset_of!(RcBox<T>, value)) as *const _) }
|
|
||||||
|
let ptr = (ptr as *const u8).offset(-offset_of!(RcBox<T>, value));
|
||||||
|
Rc {
|
||||||
|
ptr: Shared::new(ptr as *mut u8 as *mut _)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -451,7 +455,7 @@ impl<T> Rc<[T]> {
|
||||||
// Free the original allocation without freeing its (moved) contents.
|
// Free the original allocation without freeing its (moved) contents.
|
||||||
box_free(Box::into_raw(value));
|
box_free(Box::into_raw(value));
|
||||||
|
|
||||||
Rc { ptr: Shared::new(ptr as *const _) }
|
Rc { ptr: Shared::new(ptr as *mut _) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -553,8 +557,9 @@ impl<T: ?Sized> Rc<T> {
|
||||||
#[stable(feature = "rc_unique", since = "1.4.0")]
|
#[stable(feature = "rc_unique", since = "1.4.0")]
|
||||||
pub fn get_mut(this: &mut Self) -> Option<&mut T> {
|
pub fn get_mut(this: &mut Self) -> Option<&mut T> {
|
||||||
if Rc::is_unique(this) {
|
if Rc::is_unique(this) {
|
||||||
let inner = unsafe { &mut *this.ptr.as_mut_ptr() };
|
unsafe {
|
||||||
Some(&mut inner.value)
|
Some(&mut this.ptr.as_mut().value)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -578,9 +583,7 @@ impl<T: ?Sized> Rc<T> {
|
||||||
/// assert!(!Rc::ptr_eq(&five, &other_five));
|
/// assert!(!Rc::ptr_eq(&five, &other_five));
|
||||||
/// ```
|
/// ```
|
||||||
pub fn ptr_eq(this: &Self, other: &Self) -> bool {
|
pub fn ptr_eq(this: &Self, other: &Self) -> bool {
|
||||||
let this_ptr: *const RcBox<T> = *this.ptr;
|
this.ptr.as_ptr() == other.ptr.as_ptr()
|
||||||
let other_ptr: *const RcBox<T> = *other.ptr;
|
|
||||||
this_ptr == other_ptr
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -623,7 +626,7 @@ impl<T: Clone> Rc<T> {
|
||||||
} else if Rc::weak_count(this) != 0 {
|
} else if Rc::weak_count(this) != 0 {
|
||||||
// Can just steal the data, all that's left is Weaks
|
// Can just steal the data, all that's left is Weaks
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut swap = Rc::new(ptr::read(&(**this.ptr).value));
|
let mut swap = Rc::new(ptr::read(&this.ptr.as_ref().value));
|
||||||
mem::swap(this, &mut swap);
|
mem::swap(this, &mut swap);
|
||||||
swap.dec_strong();
|
swap.dec_strong();
|
||||||
// Remove implicit strong-weak ref (no need to craft a fake
|
// Remove implicit strong-weak ref (no need to craft a fake
|
||||||
|
@ -637,8 +640,9 @@ impl<T: Clone> Rc<T> {
|
||||||
// reference count is guaranteed to be 1 at this point, and we required
|
// reference count is guaranteed to be 1 at this point, and we required
|
||||||
// the `Rc<T>` itself to be `mut`, so we're returning the only possible
|
// the `Rc<T>` itself to be `mut`, so we're returning the only possible
|
||||||
// reference to the inner value.
|
// reference to the inner value.
|
||||||
let inner = unsafe { &mut *this.ptr.as_mut_ptr() };
|
unsafe {
|
||||||
&mut inner.value
|
&mut this.ptr.as_mut().value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -683,12 +687,12 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc<T> {
|
||||||
/// ```
|
/// ```
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr = self.ptr.as_mut_ptr();
|
let ptr = self.ptr.as_ptr();
|
||||||
|
|
||||||
self.dec_strong();
|
self.dec_strong();
|
||||||
if self.strong() == 0 {
|
if self.strong() == 0 {
|
||||||
// destroy the contained object
|
// destroy the contained object
|
||||||
ptr::drop_in_place(&mut (*ptr).value);
|
ptr::drop_in_place(self.ptr.as_mut());
|
||||||
|
|
||||||
// remove the implicit "strong weak" pointer now that we've
|
// remove the implicit "strong weak" pointer now that we've
|
||||||
// destroyed the contents.
|
// destroyed the contents.
|
||||||
|
@ -925,7 +929,7 @@ impl<T: ?Sized + fmt::Debug> fmt::Debug for Rc<T> {
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl<T: ?Sized> fmt::Pointer for Rc<T> {
|
impl<T: ?Sized> fmt::Pointer for Rc<T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
fmt::Pointer::fmt(&*self.ptr, f)
|
fmt::Pointer::fmt(&self.ptr, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1067,7 +1071,7 @@ impl<T: ?Sized> Drop for Weak<T> {
|
||||||
/// ```
|
/// ```
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr = *self.ptr;
|
let ptr = self.ptr.as_ptr();
|
||||||
|
|
||||||
self.dec_weak();
|
self.dec_weak();
|
||||||
// the weak count starts at 1, and will only go to zero if all
|
// the weak count starts at 1, and will only go to zero if all
|
||||||
|
@ -1175,12 +1179,7 @@ impl<T: ?Sized> RcBoxPtr<T> for Rc<T> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn inner(&self) -> &RcBox<T> {
|
fn inner(&self) -> &RcBox<T> {
|
||||||
unsafe {
|
unsafe {
|
||||||
// Safe to assume this here, as if it weren't true, we'd be breaking
|
self.ptr.as_ref()
|
||||||
// the contract anyway.
|
|
||||||
// This allows the null check to be elided in the destructor if we
|
|
||||||
// manipulated the reference count in the same function.
|
|
||||||
assume(!(*(&self.ptr as *const _ as *const *const ())).is_null());
|
|
||||||
&(**self.ptr)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1189,12 +1188,7 @@ impl<T: ?Sized> RcBoxPtr<T> for Weak<T> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn inner(&self) -> &RcBox<T> {
|
fn inner(&self) -> &RcBox<T> {
|
||||||
unsafe {
|
unsafe {
|
||||||
// Safe to assume this here, as if it weren't true, we'd be breaking
|
self.ptr.as_ref()
|
||||||
// the contract anyway.
|
|
||||||
// This allows the null check to be elided in the destructor if we
|
|
||||||
// manipulated the reference count in the same function.
|
|
||||||
assume(!(*(&self.ptr as *const _ as *const *const ())).is_null());
|
|
||||||
&(**self.ptr)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,6 @@
|
||||||
#![feature(alloc)]
|
#![feature(alloc)]
|
||||||
#![feature(core_intrinsics)]
|
#![feature(core_intrinsics)]
|
||||||
#![feature(dropck_eyepatch)]
|
#![feature(dropck_eyepatch)]
|
||||||
#![feature(heap_api)]
|
|
||||||
#![feature(generic_param_attrs)]
|
#![feature(generic_param_attrs)]
|
||||||
#![feature(staged_api)]
|
#![feature(staged_api)]
|
||||||
#![cfg_attr(test, feature(test))]
|
#![cfg_attr(test, feature(test))]
|
||||||
|
@ -48,7 +47,6 @@ use std::mem;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
|
|
||||||
use alloc::heap;
|
|
||||||
use alloc::raw_vec::RawVec;
|
use alloc::raw_vec::RawVec;
|
||||||
|
|
||||||
/// An arena that can hold objects of only one type.
|
/// An arena that can hold objects of only one type.
|
||||||
|
@ -140,7 +138,7 @@ impl<T> TypedArena<T> {
|
||||||
unsafe {
|
unsafe {
|
||||||
if mem::size_of::<T>() == 0 {
|
if mem::size_of::<T>() == 0 {
|
||||||
self.ptr.set(intrinsics::arith_offset(self.ptr.get() as *mut u8, 1) as *mut T);
|
self.ptr.set(intrinsics::arith_offset(self.ptr.get() as *mut u8, 1) as *mut T);
|
||||||
let ptr = heap::EMPTY as *mut T;
|
let ptr = mem::align_of::<T>() as *mut T;
|
||||||
// Don't drop the object. This `write` is equivalent to `forget`.
|
// Don't drop the object. This `write` is equivalent to `forget`.
|
||||||
ptr::write(ptr, object);
|
ptr::write(ptr, object);
|
||||||
&mut *ptr
|
&mut *ptr
|
||||||
|
|
|
@ -152,12 +152,12 @@ impl<K, V> BoxedNode<K, V> {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn from_ptr(ptr: NonZero<*const LeafNode<K, V>>) -> Self {
|
unsafe fn from_ptr(ptr: NonZero<*const LeafNode<K, V>>) -> Self {
|
||||||
BoxedNode { ptr: Unique::new(*ptr as *mut LeafNode<K, V>) }
|
BoxedNode { ptr: Unique::new(ptr.get() as *mut LeafNode<K, V>) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_ptr(&self) -> NonZero<*const LeafNode<K, V>> {
|
fn as_ptr(&self) -> NonZero<*const LeafNode<K, V>> {
|
||||||
unsafe {
|
unsafe {
|
||||||
NonZero::new(*self.ptr as *const LeafNode<K, V>)
|
NonZero::new(self.ptr.as_ptr())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -241,7 +241,7 @@ impl<K, V> Root<K, V> {
|
||||||
pub fn pop_level(&mut self) {
|
pub fn pop_level(&mut self) {
|
||||||
debug_assert!(self.height > 0);
|
debug_assert!(self.height > 0);
|
||||||
|
|
||||||
let top = *self.node.ptr as *mut u8;
|
let top = self.node.ptr.as_ptr() as *mut u8;
|
||||||
|
|
||||||
self.node = unsafe {
|
self.node = unsafe {
|
||||||
BoxedNode::from_ptr(self.as_mut()
|
BoxedNode::from_ptr(self.as_mut()
|
||||||
|
@ -308,7 +308,7 @@ unsafe impl<K: Send, V: Send, Type> Send
|
||||||
impl<BorrowType, K, V> NodeRef<BorrowType, K, V, marker::Internal> {
|
impl<BorrowType, K, V> NodeRef<BorrowType, K, V, marker::Internal> {
|
||||||
fn as_internal(&self) -> &InternalNode<K, V> {
|
fn as_internal(&self) -> &InternalNode<K, V> {
|
||||||
unsafe {
|
unsafe {
|
||||||
&*(*self.node as *const InternalNode<K, V>)
|
&*(self.node.get() as *const InternalNode<K, V>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -316,7 +316,7 @@ impl<BorrowType, K, V> NodeRef<BorrowType, K, V, marker::Internal> {
|
||||||
impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::Internal> {
|
impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::Internal> {
|
||||||
fn as_internal_mut(&mut self) -> &mut InternalNode<K, V> {
|
fn as_internal_mut(&mut self) -> &mut InternalNode<K, V> {
|
||||||
unsafe {
|
unsafe {
|
||||||
&mut *(*self.node as *mut InternalNode<K, V>)
|
&mut *(self.node.get() as *mut InternalNode<K, V>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -358,7 +358,7 @@ impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> {
|
||||||
|
|
||||||
fn as_leaf(&self) -> &LeafNode<K, V> {
|
fn as_leaf(&self) -> &LeafNode<K, V> {
|
||||||
unsafe {
|
unsafe {
|
||||||
&**self.node
|
&*self.node.get()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -510,7 +510,7 @@ impl<'a, K, V, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
|
||||||
|
|
||||||
fn as_leaf_mut(&mut self) -> &mut LeafNode<K, V> {
|
fn as_leaf_mut(&mut self) -> &mut LeafNode<K, V> {
|
||||||
unsafe {
|
unsafe {
|
||||||
&mut *(*self.node as *mut LeafNode<K, V>)
|
&mut *(self.node.get() as *mut LeafNode<K, V>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1253,13 +1253,13 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::
|
||||||
}
|
}
|
||||||
|
|
||||||
heap::deallocate(
|
heap::deallocate(
|
||||||
*right_node.node as *mut u8,
|
right_node.node.get() as *mut u8,
|
||||||
mem::size_of::<InternalNode<K, V>>(),
|
mem::size_of::<InternalNode<K, V>>(),
|
||||||
mem::align_of::<InternalNode<K, V>>()
|
mem::align_of::<InternalNode<K, V>>()
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
heap::deallocate(
|
heap::deallocate(
|
||||||
*right_node.node as *mut u8,
|
right_node.node.get() as *mut u8,
|
||||||
mem::size_of::<LeafNode<K, V>>(),
|
mem::size_of::<LeafNode<K, V>>(),
|
||||||
mem::align_of::<LeafNode<K, V>>()
|
mem::align_of::<LeafNode<K, V>>()
|
||||||
);
|
);
|
||||||
|
|
|
@ -161,7 +161,7 @@ impl<T> LinkedList<T> {
|
||||||
|
|
||||||
match self.head {
|
match self.head {
|
||||||
None => self.tail = node,
|
None => self.tail = node,
|
||||||
Some(head) => (*head.as_mut_ptr()).prev = node,
|
Some(mut head) => head.as_mut().prev = node,
|
||||||
}
|
}
|
||||||
|
|
||||||
self.head = node;
|
self.head = node;
|
||||||
|
@ -173,12 +173,12 @@ impl<T> LinkedList<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn pop_front_node(&mut self) -> Option<Box<Node<T>>> {
|
fn pop_front_node(&mut self) -> Option<Box<Node<T>>> {
|
||||||
self.head.map(|node| unsafe {
|
self.head.map(|node| unsafe {
|
||||||
let node = Box::from_raw(node.as_mut_ptr());
|
let node = Box::from_raw(node.as_ptr());
|
||||||
self.head = node.next;
|
self.head = node.next;
|
||||||
|
|
||||||
match self.head {
|
match self.head {
|
||||||
None => self.tail = None,
|
None => self.tail = None,
|
||||||
Some(head) => (*head.as_mut_ptr()).prev = None,
|
Some(mut head) => head.as_mut().prev = None,
|
||||||
}
|
}
|
||||||
|
|
||||||
self.len -= 1;
|
self.len -= 1;
|
||||||
|
@ -196,7 +196,7 @@ impl<T> LinkedList<T> {
|
||||||
|
|
||||||
match self.tail {
|
match self.tail {
|
||||||
None => self.head = node,
|
None => self.head = node,
|
||||||
Some(tail) => (*tail.as_mut_ptr()).next = node,
|
Some(mut tail) => tail.as_mut().next = node,
|
||||||
}
|
}
|
||||||
|
|
||||||
self.tail = node;
|
self.tail = node;
|
||||||
|
@ -208,12 +208,12 @@ impl<T> LinkedList<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn pop_back_node(&mut self) -> Option<Box<Node<T>>> {
|
fn pop_back_node(&mut self) -> Option<Box<Node<T>>> {
|
||||||
self.tail.map(|node| unsafe {
|
self.tail.map(|node| unsafe {
|
||||||
let node = Box::from_raw(node.as_mut_ptr());
|
let node = Box::from_raw(node.as_ptr());
|
||||||
self.tail = node.prev;
|
self.tail = node.prev;
|
||||||
|
|
||||||
match self.tail {
|
match self.tail {
|
||||||
None => self.head = None,
|
None => self.head = None,
|
||||||
Some(tail) => (*tail.as_mut_ptr()).next = None,
|
Some(mut tail) => tail.as_mut().next = None,
|
||||||
}
|
}
|
||||||
|
|
||||||
self.len -= 1;
|
self.len -= 1;
|
||||||
|
@ -285,11 +285,11 @@ impl<T> LinkedList<T> {
|
||||||
pub fn append(&mut self, other: &mut Self) {
|
pub fn append(&mut self, other: &mut Self) {
|
||||||
match self.tail {
|
match self.tail {
|
||||||
None => mem::swap(self, other),
|
None => mem::swap(self, other),
|
||||||
Some(tail) => {
|
Some(mut tail) => {
|
||||||
if let Some(other_head) = other.head.take() {
|
if let Some(mut other_head) = other.head.take() {
|
||||||
unsafe {
|
unsafe {
|
||||||
(*tail.as_mut_ptr()).next = Some(other_head);
|
tail.as_mut().next = Some(other_head);
|
||||||
(*other_head.as_mut_ptr()).prev = Some(tail);
|
other_head.as_mut().prev = Some(tail);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.tail = other.tail.take();
|
self.tail = other.tail.take();
|
||||||
|
@ -477,7 +477,9 @@ impl<T> LinkedList<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub fn front(&self) -> Option<&T> {
|
pub fn front(&self) -> Option<&T> {
|
||||||
self.head.map(|node| unsafe { &(**node).element })
|
unsafe {
|
||||||
|
self.head.as_ref().map(|node| &node.as_ref().element)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Provides a mutable reference to the front element, or `None` if the list
|
/// Provides a mutable reference to the front element, or `None` if the list
|
||||||
|
@ -503,7 +505,9 @@ impl<T> LinkedList<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub fn front_mut(&mut self) -> Option<&mut T> {
|
pub fn front_mut(&mut self) -> Option<&mut T> {
|
||||||
self.head.map(|node| unsafe { &mut (*node.as_mut_ptr()).element })
|
unsafe {
|
||||||
|
self.head.as_mut().map(|node| &mut node.as_mut().element)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Provides a reference to the back element, or `None` if the list is
|
/// Provides a reference to the back element, or `None` if the list is
|
||||||
|
@ -523,7 +527,9 @@ impl<T> LinkedList<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub fn back(&self) -> Option<&T> {
|
pub fn back(&self) -> Option<&T> {
|
||||||
self.tail.map(|node| unsafe { &(**node).element })
|
unsafe {
|
||||||
|
self.tail.as_ref().map(|node| &node.as_ref().element)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Provides a mutable reference to the back element, or `None` if the list
|
/// Provides a mutable reference to the back element, or `None` if the list
|
||||||
|
@ -549,7 +555,9 @@ impl<T> LinkedList<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub fn back_mut(&mut self) -> Option<&mut T> {
|
pub fn back_mut(&mut self) -> Option<&mut T> {
|
||||||
self.tail.map(|node| unsafe { &mut (*node.as_mut_ptr()).element })
|
unsafe {
|
||||||
|
self.tail.as_mut().map(|node| &mut node.as_mut().element)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds an element first in the list.
|
/// Adds an element first in the list.
|
||||||
|
@ -694,9 +702,9 @@ impl<T> LinkedList<T> {
|
||||||
let second_part_head;
|
let second_part_head;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
second_part_head = (*split_node.unwrap().as_mut_ptr()).next.take();
|
second_part_head = split_node.unwrap().as_mut().next.take();
|
||||||
if let Some(head) = second_part_head {
|
if let Some(mut head) = second_part_head {
|
||||||
(*head.as_mut_ptr()).prev = None;
|
head.as_mut().prev = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -788,7 +796,8 @@ impl<'a, T> Iterator for Iter<'a, T> {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
self.head.map(|node| unsafe {
|
self.head.map(|node| unsafe {
|
||||||
let node = &**node;
|
// Need an unbound lifetime to get 'a
|
||||||
|
let node = &*node.as_ptr();
|
||||||
self.len -= 1;
|
self.len -= 1;
|
||||||
self.head = node.next;
|
self.head = node.next;
|
||||||
&node.element
|
&node.element
|
||||||
|
@ -810,7 +819,8 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
self.tail.map(|node| unsafe {
|
self.tail.map(|node| unsafe {
|
||||||
let node = &**node;
|
// Need an unbound lifetime to get 'a
|
||||||
|
let node = &*node.as_ptr();
|
||||||
self.len -= 1;
|
self.len -= 1;
|
||||||
self.tail = node.prev;
|
self.tail = node.prev;
|
||||||
&node.element
|
&node.element
|
||||||
|
@ -835,7 +845,8 @@ impl<'a, T> Iterator for IterMut<'a, T> {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
self.head.map(|node| unsafe {
|
self.head.map(|node| unsafe {
|
||||||
let node = &mut *node.as_mut_ptr();
|
// Need an unbound lifetime to get 'a
|
||||||
|
let node = &mut *node.as_ptr();
|
||||||
self.len -= 1;
|
self.len -= 1;
|
||||||
self.head = node.next;
|
self.head = node.next;
|
||||||
&mut node.element
|
&mut node.element
|
||||||
|
@ -857,7 +868,8 @@ impl<'a, T> DoubleEndedIterator for IterMut<'a, T> {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
self.tail.map(|node| unsafe {
|
self.tail.map(|node| unsafe {
|
||||||
let node = &mut *node.as_mut_ptr();
|
// Need an unbound lifetime to get 'a
|
||||||
|
let node = &mut *node.as_ptr();
|
||||||
self.len -= 1;
|
self.len -= 1;
|
||||||
self.tail = node.prev;
|
self.tail = node.prev;
|
||||||
&mut node.element
|
&mut node.element
|
||||||
|
@ -903,8 +915,8 @@ impl<'a, T> IterMut<'a, T> {
|
||||||
pub fn insert_next(&mut self, element: T) {
|
pub fn insert_next(&mut self, element: T) {
|
||||||
match self.head {
|
match self.head {
|
||||||
None => self.list.push_back(element),
|
None => self.list.push_back(element),
|
||||||
Some(head) => unsafe {
|
Some(mut head) => unsafe {
|
||||||
let prev = match (**head).prev {
|
let mut prev = match head.as_ref().prev {
|
||||||
None => return self.list.push_front(element),
|
None => return self.list.push_front(element),
|
||||||
Some(prev) => prev,
|
Some(prev) => prev,
|
||||||
};
|
};
|
||||||
|
@ -915,8 +927,8 @@ impl<'a, T> IterMut<'a, T> {
|
||||||
element: element,
|
element: element,
|
||||||
})));
|
})));
|
||||||
|
|
||||||
(*prev.as_mut_ptr()).next = node;
|
prev.as_mut().next = node;
|
||||||
(*head.as_mut_ptr()).prev = node;
|
head.as_mut().prev = node;
|
||||||
|
|
||||||
self.list.len += 1;
|
self.list.len += 1;
|
||||||
},
|
},
|
||||||
|
@ -948,7 +960,9 @@ impl<'a, T> IterMut<'a, T> {
|
||||||
if self.len == 0 {
|
if self.len == 0 {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
self.head.map(|node| unsafe { &mut (*node.as_mut_ptr()).element })
|
unsafe {
|
||||||
|
self.head.as_mut().map(|node| &mut node.as_mut().element)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1276,21 +1290,21 @@ mod tests {
|
||||||
assert_eq!(0, list.len);
|
assert_eq!(0, list.len);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Some(node) => node_ptr = &**node,
|
Some(node) => node_ptr = &*node.as_ptr(),
|
||||||
}
|
}
|
||||||
loop {
|
loop {
|
||||||
match (last_ptr, node_ptr.prev) {
|
match (last_ptr, node_ptr.prev) {
|
||||||
(None, None) => {}
|
(None, None) => {}
|
||||||
(None, _) => panic!("prev link for head"),
|
(None, _) => panic!("prev link for head"),
|
||||||
(Some(p), Some(pptr)) => {
|
(Some(p), Some(pptr)) => {
|
||||||
assert_eq!(p as *const Node<T>, *pptr as *const Node<T>);
|
assert_eq!(p as *const Node<T>, pptr.as_ptr() as *const Node<T>);
|
||||||
}
|
}
|
||||||
_ => panic!("prev link is none, not good"),
|
_ => panic!("prev link is none, not good"),
|
||||||
}
|
}
|
||||||
match node_ptr.next {
|
match node_ptr.next {
|
||||||
Some(next) => {
|
Some(next) => {
|
||||||
last_ptr = Some(node_ptr);
|
last_ptr = Some(node_ptr);
|
||||||
node_ptr = &**next;
|
node_ptr = &*next.as_ptr();
|
||||||
len += 1;
|
len += 1;
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
|
|
@ -67,7 +67,6 @@
|
||||||
#![stable(feature = "rust1", since = "1.0.0")]
|
#![stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
use alloc::heap::EMPTY;
|
|
||||||
use alloc::raw_vec::RawVec;
|
use alloc::raw_vec::RawVec;
|
||||||
use borrow::ToOwned;
|
use borrow::ToOwned;
|
||||||
use borrow::Cow;
|
use borrow::Cow;
|
||||||
|
@ -1776,9 +1775,9 @@ impl<T> SpecExtend<T, IntoIter<T>> for Vec<T> {
|
||||||
// A common case is passing a vector into a function which immediately
|
// A common case is passing a vector into a function which immediately
|
||||||
// re-collects into a vector. We can short circuit this if the IntoIter
|
// re-collects into a vector. We can short circuit this if the IntoIter
|
||||||
// has not been advanced at all.
|
// has not been advanced at all.
|
||||||
if *iterator.buf == iterator.ptr as *mut T {
|
if iterator.buf.as_ptr() as *const _ == iterator.ptr {
|
||||||
unsafe {
|
unsafe {
|
||||||
let vec = Vec::from_raw_parts(*iterator.buf as *mut T,
|
let vec = Vec::from_raw_parts(iterator.buf.as_ptr(),
|
||||||
iterator.len(),
|
iterator.len(),
|
||||||
iterator.cap);
|
iterator.cap);
|
||||||
mem::forget(iterator);
|
mem::forget(iterator);
|
||||||
|
@ -2192,7 +2191,8 @@ impl<T> Iterator for IntoIter<T> {
|
||||||
self.ptr = arith_offset(self.ptr as *const i8, 1) as *mut T;
|
self.ptr = arith_offset(self.ptr as *const i8, 1) as *mut T;
|
||||||
|
|
||||||
// Use a non-null pointer value
|
// Use a non-null pointer value
|
||||||
Some(ptr::read(EMPTY as *mut T))
|
// (self.ptr might be null because of wrapping)
|
||||||
|
Some(ptr::read(1 as *mut T))
|
||||||
} else {
|
} else {
|
||||||
let old = self.ptr;
|
let old = self.ptr;
|
||||||
self.ptr = self.ptr.offset(1);
|
self.ptr = self.ptr.offset(1);
|
||||||
|
@ -2231,7 +2231,8 @@ impl<T> DoubleEndedIterator for IntoIter<T> {
|
||||||
self.end = arith_offset(self.end as *const i8, -1) as *mut T;
|
self.end = arith_offset(self.end as *const i8, -1) as *mut T;
|
||||||
|
|
||||||
// Use a non-null pointer value
|
// Use a non-null pointer value
|
||||||
Some(ptr::read(EMPTY as *mut T))
|
// (self.end might be null because of wrapping)
|
||||||
|
Some(ptr::read(1 as *mut T))
|
||||||
} else {
|
} else {
|
||||||
self.end = self.end.offset(-1);
|
self.end = self.end.offset(-1);
|
||||||
|
|
||||||
|
@ -2269,7 +2270,7 @@ unsafe impl<#[may_dangle] T> Drop for IntoIter<T> {
|
||||||
for _x in self.by_ref() {}
|
for _x in self.by_ref() {}
|
||||||
|
|
||||||
// RawVec handles deallocation
|
// RawVec handles deallocation
|
||||||
let _ = unsafe { RawVec::from_raw_parts(self.buf.as_mut_ptr(), self.cap) };
|
let _ = unsafe { RawVec::from_raw_parts(self.buf.as_ptr(), self.cap) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2334,7 +2335,7 @@ impl<'a, T> Drop for Drain<'a, T> {
|
||||||
|
|
||||||
if self.tail_len > 0 {
|
if self.tail_len > 0 {
|
||||||
unsafe {
|
unsafe {
|
||||||
let source_vec = &mut *self.vec.as_mut_ptr();
|
let source_vec = self.vec.as_mut();
|
||||||
// memmove back untouched tail, update to new length
|
// memmove back untouched tail, update to new length
|
||||||
let start = source_vec.len();
|
let start = source_vec.len();
|
||||||
let tail = self.tail_start;
|
let tail = self.tail_start;
|
||||||
|
@ -2456,8 +2457,7 @@ impl<'a, I: Iterator> Drop for Splice<'a, I> {
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
if self.drain.tail_len == 0 {
|
if self.drain.tail_len == 0 {
|
||||||
let vec = &mut *self.drain.vec.as_mut_ptr();
|
self.drain.vec.as_mut().extend(self.replace_with.by_ref());
|
||||||
vec.extend(self.replace_with.by_ref());
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2498,7 +2498,7 @@ impl<'a, T> Drain<'a, T> {
|
||||||
/// Fill that range as much as possible with new elements from the `replace_with` iterator.
|
/// Fill that range as much as possible with new elements from the `replace_with` iterator.
|
||||||
/// Return whether we filled the entire range. (`replace_with.next()` didn’t return `None`.)
|
/// Return whether we filled the entire range. (`replace_with.next()` didn’t return `None`.)
|
||||||
unsafe fn fill<I: Iterator<Item=T>>(&mut self, replace_with: &mut I) -> bool {
|
unsafe fn fill<I: Iterator<Item=T>>(&mut self, replace_with: &mut I) -> bool {
|
||||||
let vec = &mut *self.vec.as_mut_ptr();
|
let vec = self.vec.as_mut();
|
||||||
let range_start = vec.len;
|
let range_start = vec.len;
|
||||||
let range_end = self.tail_start;
|
let range_end = self.tail_start;
|
||||||
let range_slice = slice::from_raw_parts_mut(
|
let range_slice = slice::from_raw_parts_mut(
|
||||||
|
@ -2518,7 +2518,7 @@ impl<'a, T> Drain<'a, T> {
|
||||||
|
|
||||||
/// Make room for inserting more elements before the tail.
|
/// Make room for inserting more elements before the tail.
|
||||||
unsafe fn move_tail(&mut self, extra_capacity: usize) {
|
unsafe fn move_tail(&mut self, extra_capacity: usize) {
|
||||||
let vec = &mut *self.vec.as_mut_ptr();
|
let vec = self.vec.as_mut();
|
||||||
let used_capacity = self.tail_start + self.tail_len;
|
let used_capacity = self.tail_start + self.tail_len;
|
||||||
vec.buf.reserve(used_capacity, extra_capacity);
|
vec.buf.reserve(used_capacity, extra_capacity);
|
||||||
|
|
||||||
|
|
|
@ -2160,7 +2160,7 @@ impl<'a, T: 'a> Drop for Drain<'a, T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
for _ in self.by_ref() {}
|
for _ in self.by_ref() {}
|
||||||
|
|
||||||
let source_deque = unsafe { &mut *self.deque.as_mut_ptr() };
|
let source_deque = unsafe { self.deque.as_mut() };
|
||||||
|
|
||||||
// T = source_deque_tail; H = source_deque_head; t = drain_tail; h = drain_head
|
// T = source_deque_tail; H = source_deque_head; t = drain_tail; h = drain_head
|
||||||
//
|
//
|
||||||
|
|
|
@ -132,7 +132,6 @@
|
||||||
//! use std::cell::Cell;
|
//! use std::cell::Cell;
|
||||||
//! use std::ptr::Shared;
|
//! use std::ptr::Shared;
|
||||||
//! use std::intrinsics::abort;
|
//! use std::intrinsics::abort;
|
||||||
//! use std::intrinsics::assume;
|
|
||||||
//!
|
//!
|
||||||
//! struct Rc<T: ?Sized> {
|
//! struct Rc<T: ?Sized> {
|
||||||
//! ptr: Shared<RcBox<T>>
|
//! ptr: Shared<RcBox<T>>
|
||||||
|
@ -171,8 +170,7 @@
|
||||||
//! impl<T: ?Sized> RcBoxPtr<T> for Rc<T> {
|
//! impl<T: ?Sized> RcBoxPtr<T> for Rc<T> {
|
||||||
//! fn inner(&self) -> &RcBox<T> {
|
//! fn inner(&self) -> &RcBox<T> {
|
||||||
//! unsafe {
|
//! unsafe {
|
||||||
//! assume(!(*(&self.ptr as *const _ as *const *const ())).is_null());
|
//! self.ptr.as_ref()
|
||||||
//! &(**self.ptr)
|
|
||||||
//! }
|
//! }
|
||||||
//! }
|
//! }
|
||||||
//! }
|
//! }
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
reason = "needs an RFC to flesh out the design",
|
reason = "needs an RFC to flesh out the design",
|
||||||
issue = "27730")]
|
issue = "27730")]
|
||||||
|
|
||||||
use ops::{CoerceUnsized, Deref};
|
use ops::CoerceUnsized;
|
||||||
|
|
||||||
/// Unsafe trait to indicate what types are usable with the NonZero struct
|
/// Unsafe trait to indicate what types are usable with the NonZero struct
|
||||||
pub unsafe trait Zeroable {}
|
pub unsafe trait Zeroable {}
|
||||||
|
@ -46,15 +46,10 @@ impl<T: Zeroable> NonZero<T> {
|
||||||
pub const unsafe fn new(inner: T) -> NonZero<T> {
|
pub const unsafe fn new(inner: T) -> NonZero<T> {
|
||||||
NonZero(inner)
|
NonZero(inner)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Zeroable> Deref for NonZero<T> {
|
/// Gets the inner value.
|
||||||
type Target = T;
|
pub fn get(self) -> T {
|
||||||
|
self.0
|
||||||
#[inline]
|
|
||||||
fn deref(&self) -> &T {
|
|
||||||
let NonZero(ref inner) = *self;
|
|
||||||
inner
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
#![stable(feature = "rust1", since = "1.0.0")]
|
#![stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
|
||||||
use intrinsics;
|
use intrinsics;
|
||||||
use ops::{CoerceUnsized, Deref};
|
use ops::CoerceUnsized;
|
||||||
use fmt;
|
use fmt;
|
||||||
use hash;
|
use hash;
|
||||||
use marker::{PhantomData, Unsize};
|
use marker::{PhantomData, Unsize};
|
||||||
|
@ -957,13 +957,25 @@ impl<T: ?Sized> PartialOrd for *mut T {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A wrapper around a raw non-null `*mut T` that indicates that the possessor
|
/// A wrapper around a raw non-null `*mut T` that indicates that the possessor
|
||||||
/// of this wrapper owns the referent. This in turn implies that the
|
/// of this wrapper owns the referent. Useful for building abstractions like
|
||||||
/// `Unique<T>` is `Send`/`Sync` if `T` is `Send`/`Sync`, unlike a raw
|
/// `Box<T>`, `Vec<T>`, `String`, and `HashMap<K, V>`.
|
||||||
/// `*mut T` (which conveys no particular ownership semantics). It
|
///
|
||||||
/// also implies that the referent of the pointer should not be
|
/// Unlike `*mut T`, `Unique<T>` behaves "as if" it were an instance of `T`.
|
||||||
/// modified without a unique path to the `Unique` reference. Useful
|
/// It implements `Send`/`Sync` if `T` is `Send`/`Sync`. It also implies
|
||||||
/// for building abstractions like `Vec<T>` or `Box<T>`, which
|
/// the kind of strong aliasing guarantees an instance of `T` can expect:
|
||||||
/// internally use raw pointers to manage the memory that they own.
|
/// the referent of the pointer should not be modified without a unique path to
|
||||||
|
/// its owning Unique.
|
||||||
|
///
|
||||||
|
/// If you're uncertain of whether it's correct to use `Unique` for your purposes,
|
||||||
|
/// consider using `Shared`, which has weaker semantics.
|
||||||
|
///
|
||||||
|
/// Unlike `*mut T`, the pointer must always be non-null, even if the pointer
|
||||||
|
/// is never dereferenced. This is so that enums may use this forbidden value
|
||||||
|
/// as a discriminant -- `Option<Unique<T>>` has the same size as `Unique<T>`.
|
||||||
|
/// However the pointer may still dangle if it isn't dereferenced.
|
||||||
|
///
|
||||||
|
/// Unlike `*mut T`, `Unique<T>` is covariant over `T`. This should always be correct
|
||||||
|
/// for any type which upholds Unique's aliasing requirements.
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
#[unstable(feature = "unique", reason = "needs an RFC to flesh out design",
|
#[unstable(feature = "unique", reason = "needs an RFC to flesh out design",
|
||||||
issue = "27730")]
|
issue = "27730")]
|
||||||
|
@ -991,6 +1003,20 @@ unsafe impl<T: Send + ?Sized> Send for Unique<T> { }
|
||||||
#[unstable(feature = "unique", issue = "27730")]
|
#[unstable(feature = "unique", issue = "27730")]
|
||||||
unsafe impl<T: Sync + ?Sized> Sync for Unique<T> { }
|
unsafe impl<T: Sync + ?Sized> Sync for Unique<T> { }
|
||||||
|
|
||||||
|
#[unstable(feature = "unique", issue = "27730")]
|
||||||
|
impl<T: Sized> Unique<T> {
|
||||||
|
/// Creates a new `Shared` that is dangling, but well-aligned.
|
||||||
|
///
|
||||||
|
/// This is useful for initializing types which lazily allocate, like
|
||||||
|
/// `Vec::new` does.
|
||||||
|
pub fn empty() -> Self {
|
||||||
|
unsafe {
|
||||||
|
let ptr = mem::align_of::<T>() as *mut T;
|
||||||
|
Unique::new(ptr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[unstable(feature = "unique", issue = "27730")]
|
#[unstable(feature = "unique", issue = "27730")]
|
||||||
impl<T: ?Sized> Unique<T> {
|
impl<T: ?Sized> Unique<T> {
|
||||||
/// Creates a new `Unique`.
|
/// Creates a new `Unique`.
|
||||||
|
@ -1002,41 +1028,72 @@ impl<T: ?Sized> Unique<T> {
|
||||||
Unique { pointer: NonZero::new(ptr), _marker: PhantomData }
|
Unique { pointer: NonZero::new(ptr), _marker: PhantomData }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Acquires the underlying `*mut` pointer.
|
||||||
|
pub fn as_ptr(self) -> *mut T {
|
||||||
|
self.pointer.get() as *mut T
|
||||||
|
}
|
||||||
|
|
||||||
/// Dereferences the content.
|
/// Dereferences the content.
|
||||||
pub unsafe fn get(&self) -> &T {
|
///
|
||||||
&**self.pointer
|
/// The resulting lifetime is bound to self so this behaves "as if"
|
||||||
|
/// it were actually an instance of T that is getting borrowed. If a longer
|
||||||
|
/// (unbound) lifetime is needed, use `&*my_ptr.ptr()`.
|
||||||
|
pub unsafe fn as_ref(&self) -> &T {
|
||||||
|
&*self.as_ptr()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mutably dereferences the content.
|
/// Mutably dereferences the content.
|
||||||
pub unsafe fn get_mut(&mut self) -> &mut T {
|
///
|
||||||
&mut ***self
|
/// The resulting lifetime is bound to self so this behaves "as if"
|
||||||
|
/// it were actually an instance of T that is getting borrowed. If a longer
|
||||||
|
/// (unbound) lifetime is needed, use `&mut *my_ptr.ptr()`.
|
||||||
|
pub unsafe fn as_mut(&mut self) -> &mut T {
|
||||||
|
&mut *self.as_ptr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "shared", issue = "27730")]
|
||||||
|
impl<T: ?Sized> Clone for Unique<T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "shared", issue = "27730")]
|
||||||
|
impl<T: ?Sized> Copy for Unique<T> { }
|
||||||
|
|
||||||
#[unstable(feature = "unique", issue = "27730")]
|
#[unstable(feature = "unique", issue = "27730")]
|
||||||
impl<T: ?Sized, U: ?Sized> CoerceUnsized<Unique<U>> for Unique<T> where T: Unsize<U> { }
|
impl<T: ?Sized, U: ?Sized> CoerceUnsized<Unique<U>> for Unique<T> where T: Unsize<U> { }
|
||||||
|
|
||||||
#[unstable(feature = "unique", issue= "27730")]
|
|
||||||
impl<T:?Sized> Deref for Unique<T> {
|
|
||||||
type Target = *mut T;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn deref(&self) -> &*mut T {
|
|
||||||
unsafe { mem::transmute(&*self.pointer) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[unstable(feature = "unique", issue = "27730")]
|
#[unstable(feature = "unique", issue = "27730")]
|
||||||
impl<T> fmt::Pointer for Unique<T> {
|
impl<T: ?Sized> fmt::Pointer for Unique<T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
fmt::Pointer::fmt(&*self.pointer, f)
|
fmt::Pointer::fmt(&self.as_ptr(), f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A wrapper around a raw non-null `*mut T` that indicates that the possessor
|
/// A wrapper around a raw `*mut T` that indicates that the possessor
|
||||||
/// of this wrapper has shared ownership of the referent. Useful for
|
/// of this wrapper has shared ownership of the referent. Useful for
|
||||||
/// building abstractions like `Rc<T>` or `Arc<T>`, which internally
|
/// building abstractions like `Rc<T>`, `Arc<T>`, or doubly-linked lists, which
|
||||||
/// use raw pointers to manage the memory that they own.
|
/// internally use aliased raw pointers to manage the memory that they own.
|
||||||
|
///
|
||||||
|
/// This is similar to `Unique`, except that it doesn't make any aliasing
|
||||||
|
/// guarantees, and doesn't derive Send and Sync. Note that unlike `&T`,
|
||||||
|
/// Shared has no special mutability requirements. Shared may mutate data
|
||||||
|
/// aliased by other Shared pointers. More precise rules require Rust to
|
||||||
|
/// develop an actual aliasing model.
|
||||||
|
///
|
||||||
|
/// Unlike `*mut T`, the pointer must always be non-null, even if the pointer
|
||||||
|
/// is never dereferenced. This is so that enums may use this forbidden value
|
||||||
|
/// as a discriminant -- `Option<Shared<T>>` has the same size as `Shared<T>`.
|
||||||
|
/// However the pointer may still dangle if it isn't dereferenced.
|
||||||
|
///
|
||||||
|
/// Unlike `*mut T`, `Shared<T>` is covariant over `T`. If this is incorrect
|
||||||
|
/// for your use case, you should include some PhantomData in your type to
|
||||||
|
/// provide invariance, such as `PhantomData<Cell<T>>` or `PhantomData<&'a mut T>`.
|
||||||
|
/// Usually this won't be necessary; covariance is correct for Rc, Arc, and LinkedList
|
||||||
|
/// because they provide a public API that follows the normal shared XOR mutable
|
||||||
|
/// rules of Rust.
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
#[unstable(feature = "shared", reason = "needs an RFC to flesh out design",
|
#[unstable(feature = "shared", reason = "needs an RFC to flesh out design",
|
||||||
issue = "27730")]
|
issue = "27730")]
|
||||||
|
@ -1060,6 +1117,20 @@ impl<T: ?Sized> !Send for Shared<T> { }
|
||||||
#[unstable(feature = "shared", issue = "27730")]
|
#[unstable(feature = "shared", issue = "27730")]
|
||||||
impl<T: ?Sized> !Sync for Shared<T> { }
|
impl<T: ?Sized> !Sync for Shared<T> { }
|
||||||
|
|
||||||
|
#[unstable(feature = "shared", issue = "27730")]
|
||||||
|
impl<T: Sized> Shared<T> {
|
||||||
|
/// Creates a new `Shared` that is dangling, but well-aligned.
|
||||||
|
///
|
||||||
|
/// This is useful for initializing types which lazily allocate, like
|
||||||
|
/// `Vec::new` does.
|
||||||
|
pub fn empty() -> Self {
|
||||||
|
unsafe {
|
||||||
|
let ptr = mem::align_of::<T>() as *mut T;
|
||||||
|
Shared::new(ptr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[unstable(feature = "shared", issue = "27730")]
|
#[unstable(feature = "shared", issue = "27730")]
|
||||||
impl<T: ?Sized> Shared<T> {
|
impl<T: ?Sized> Shared<T> {
|
||||||
/// Creates a new `Shared`.
|
/// Creates a new `Shared`.
|
||||||
|
@ -1067,16 +1138,38 @@ impl<T: ?Sized> Shared<T> {
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// `ptr` must be non-null.
|
/// `ptr` must be non-null.
|
||||||
pub unsafe fn new(ptr: *const T) -> Self {
|
pub unsafe fn new(ptr: *mut T) -> Self {
|
||||||
Shared { pointer: NonZero::new(ptr), _marker: PhantomData }
|
Shared { pointer: NonZero::new(ptr), _marker: PhantomData }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[unstable(feature = "shared", issue = "27730")]
|
/// Acquires the underlying `*mut` pointer.
|
||||||
impl<T: ?Sized> Shared<T> {
|
pub fn as_ptr(self) -> *mut T {
|
||||||
|
self.pointer.get() as *mut T
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Dereferences the content.
|
||||||
|
///
|
||||||
|
/// The resulting lifetime is bound to self so this behaves "as if"
|
||||||
|
/// it were actually an instance of T that is getting borrowed. If a longer
|
||||||
|
/// (unbound) lifetime is needed, use `&*my_ptr.ptr()`.
|
||||||
|
pub unsafe fn as_ref(&self) -> &T {
|
||||||
|
&*self.as_ptr()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mutably dereferences the content.
|
||||||
|
///
|
||||||
|
/// The resulting lifetime is bound to self so this behaves "as if"
|
||||||
|
/// it were actually an instance of T that is getting borrowed. If a longer
|
||||||
|
/// (unbound) lifetime is needed, use `&mut *my_ptr.ptr_mut()`.
|
||||||
|
pub unsafe fn as_mut(&mut self) -> &mut T {
|
||||||
|
&mut *self.as_ptr()
|
||||||
|
}
|
||||||
|
|
||||||
/// Acquires the underlying pointer as a `*mut` pointer.
|
/// Acquires the underlying pointer as a `*mut` pointer.
|
||||||
|
#[rustc_deprecated(since = "1.19", reason = "renamed to `as_ptr` for ergonomics/consistency")]
|
||||||
|
#[unstable(feature = "shared", issue = "27730")]
|
||||||
pub unsafe fn as_mut_ptr(&self) -> *mut T {
|
pub unsafe fn as_mut_ptr(&self) -> *mut T {
|
||||||
**self as _
|
self.as_ptr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1094,18 +1187,8 @@ impl<T: ?Sized> Copy for Shared<T> { }
|
||||||
impl<T: ?Sized, U: ?Sized> CoerceUnsized<Shared<U>> for Shared<T> where T: Unsize<U> { }
|
impl<T: ?Sized, U: ?Sized> CoerceUnsized<Shared<U>> for Shared<T> where T: Unsize<U> { }
|
||||||
|
|
||||||
#[unstable(feature = "shared", issue = "27730")]
|
#[unstable(feature = "shared", issue = "27730")]
|
||||||
impl<T: ?Sized> Deref for Shared<T> {
|
impl<T: ?Sized> fmt::Pointer for Shared<T> {
|
||||||
type Target = *const T;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn deref(&self) -> &*const T {
|
|
||||||
unsafe { mem::transmute(&*self.pointer) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[unstable(feature = "shared", issue = "27730")]
|
|
||||||
impl<T> fmt::Pointer for Shared<T> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
fmt::Pointer::fmt(&*self.pointer, f)
|
fmt::Pointer::fmt(&self.as_ptr(), f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,12 +31,12 @@ fn test_match_on_nonzero_option() {
|
||||||
NonZero::new(42)
|
NonZero::new(42)
|
||||||
});
|
});
|
||||||
match a {
|
match a {
|
||||||
Some(val) => assert_eq!(*val, 42),
|
Some(val) => assert_eq!(val.get(), 42),
|
||||||
None => panic!("unexpected None while matching on Some(NonZero(_))")
|
None => panic!("unexpected None while matching on Some(NonZero(_))")
|
||||||
}
|
}
|
||||||
|
|
||||||
match unsafe { Some(NonZero::new(43)) } {
|
match unsafe { Some(NonZero::new(43)) } {
|
||||||
Some(val) => assert_eq!(*val, 43),
|
Some(val) => assert_eq!(val.get(), 43),
|
||||||
None => panic!("unexpected None while matching on Some(NonZero(_))")
|
None => panic!("unexpected None while matching on Some(NonZero(_))")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -166,10 +166,10 @@ fn test_set_memory() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_unsized_unique() {
|
fn test_unsized_unique() {
|
||||||
let xs: &mut [i32] = &mut [1, 2, 3];
|
let xs: &[i32] = &[1, 2, 3];
|
||||||
let ptr = unsafe { Unique::new(xs as *mut [i32]) };
|
let ptr = unsafe { Unique::new(xs as *const [i32] as *mut [i32]) };
|
||||||
let ys = unsafe { &mut **ptr };
|
let ys = unsafe { ptr.as_ref() };
|
||||||
let zs: &mut [i32] = &mut [1, 2, 3];
|
let zs: &[i32] = &[1, 2, 3];
|
||||||
assert!(ys == zs);
|
assert!(ys == zs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,14 +62,14 @@ pub struct Bytes {
|
||||||
impl Deref for Bytes {
|
impl Deref for Bytes {
|
||||||
type Target = [u8];
|
type Target = [u8];
|
||||||
fn deref(&self) -> &[u8] {
|
fn deref(&self) -> &[u8] {
|
||||||
unsafe { slice::from_raw_parts(*self.ptr, self.len) }
|
unsafe { slice::from_raw_parts(self.ptr.as_ptr(), self.len) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Bytes {
|
impl Drop for Bytes {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
libc::free(*self.ptr as *mut _);
|
libc::free(self.ptr.as_ptr() as *mut _);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit c34a802d1eb037b44c5252078c7270b5472e0f65
|
Subproject commit 03562b0cb26a00f49d4eaf18ca3e49608110b0c8
|
|
@ -81,6 +81,7 @@ pub enum DepNode<D: Clone + Debug> {
|
||||||
TransCrateItem(D),
|
TransCrateItem(D),
|
||||||
TransInlinedItem(D),
|
TransInlinedItem(D),
|
||||||
TransWriteMetadata,
|
TransWriteMetadata,
|
||||||
|
CrateVariances,
|
||||||
|
|
||||||
// Nodes representing bits of computed IR in the tcx. Each shared
|
// Nodes representing bits of computed IR in the tcx. Each shared
|
||||||
// table in the tcx (or elsewhere) maps to one of these
|
// table in the tcx (or elsewhere) maps to one of these
|
||||||
|
@ -89,6 +90,8 @@ pub enum DepNode<D: Clone + Debug> {
|
||||||
// predicates for an item wind up in `ItemSignature`).
|
// predicates for an item wind up in `ItemSignature`).
|
||||||
AssociatedItems(D),
|
AssociatedItems(D),
|
||||||
ItemSignature(D),
|
ItemSignature(D),
|
||||||
|
ItemVarianceConstraints(D),
|
||||||
|
ItemVariances(D),
|
||||||
IsForeignItem(D),
|
IsForeignItem(D),
|
||||||
TypeParamPredicates((D, D)),
|
TypeParamPredicates((D, D)),
|
||||||
SizedConstraint(D),
|
SizedConstraint(D),
|
||||||
|
@ -180,6 +183,7 @@ impl<D: Clone + Debug> DepNode<D> {
|
||||||
TransCrateItem,
|
TransCrateItem,
|
||||||
AssociatedItems,
|
AssociatedItems,
|
||||||
ItemSignature,
|
ItemSignature,
|
||||||
|
ItemVariances,
|
||||||
IsForeignItem,
|
IsForeignItem,
|
||||||
AssociatedItemDefIds,
|
AssociatedItemDefIds,
|
||||||
InherentImpls,
|
InherentImpls,
|
||||||
|
@ -201,6 +205,7 @@ impl<D: Clone + Debug> DepNode<D> {
|
||||||
MirKrate => Some(MirKrate),
|
MirKrate => Some(MirKrate),
|
||||||
TypeckBodiesKrate => Some(TypeckBodiesKrate),
|
TypeckBodiesKrate => Some(TypeckBodiesKrate),
|
||||||
Coherence => Some(Coherence),
|
Coherence => Some(Coherence),
|
||||||
|
CrateVariances => Some(CrateVariances),
|
||||||
Resolve => Some(Resolve),
|
Resolve => Some(Resolve),
|
||||||
Variance => Some(Variance),
|
Variance => Some(Variance),
|
||||||
PrivacyAccessLevels(k) => Some(PrivacyAccessLevels(k)),
|
PrivacyAccessLevels(k) => Some(PrivacyAccessLevels(k)),
|
||||||
|
@ -232,6 +237,8 @@ impl<D: Clone + Debug> DepNode<D> {
|
||||||
TransInlinedItem(ref d) => op(d).map(TransInlinedItem),
|
TransInlinedItem(ref d) => op(d).map(TransInlinedItem),
|
||||||
AssociatedItems(ref d) => op(d).map(AssociatedItems),
|
AssociatedItems(ref d) => op(d).map(AssociatedItems),
|
||||||
ItemSignature(ref d) => op(d).map(ItemSignature),
|
ItemSignature(ref d) => op(d).map(ItemSignature),
|
||||||
|
ItemVariances(ref d) => op(d).map(ItemVariances),
|
||||||
|
ItemVarianceConstraints(ref d) => op(d).map(ItemVarianceConstraints),
|
||||||
IsForeignItem(ref d) => op(d).map(IsForeignItem),
|
IsForeignItem(ref d) => op(d).map(IsForeignItem),
|
||||||
TypeParamPredicates((ref item, ref param)) => {
|
TypeParamPredicates((ref item, ref param)) => {
|
||||||
Some(TypeParamPredicates((try_opt!(op(item)), try_opt!(op(param)))))
|
Some(TypeParamPredicates((try_opt!(op(item)), try_opt!(op(param)))))
|
||||||
|
|
|
@ -18,7 +18,6 @@ mod raii;
|
||||||
mod safe;
|
mod safe;
|
||||||
mod shadow;
|
mod shadow;
|
||||||
mod thread;
|
mod thread;
|
||||||
mod visit;
|
|
||||||
|
|
||||||
pub use self::dep_tracking_map::{DepTrackingMap, DepTrackingMapConfig};
|
pub use self::dep_tracking_map::{DepTrackingMap, DepTrackingMapConfig};
|
||||||
pub use self::dep_node::DepNode;
|
pub use self::dep_node::DepNode;
|
||||||
|
@ -28,5 +27,4 @@ pub use self::graph::WorkProduct;
|
||||||
pub use self::query::DepGraphQuery;
|
pub use self::query::DepGraphQuery;
|
||||||
pub use self::safe::AssertDepGraphSafe;
|
pub use self::safe::AssertDepGraphSafe;
|
||||||
pub use self::safe::DepGraphSafe;
|
pub use self::safe::DepGraphSafe;
|
||||||
pub use self::visit::visit_all_item_likes_in_krate;
|
|
||||||
pub use self::raii::DepTask;
|
pub use self::raii::DepTask;
|
||||||
|
|
|
@ -1,77 +0,0 @@
|
||||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
use hir;
|
|
||||||
use hir::def_id::DefId;
|
|
||||||
use hir::itemlikevisit::ItemLikeVisitor;
|
|
||||||
use ty::TyCtxt;
|
|
||||||
|
|
||||||
use super::dep_node::DepNode;
|
|
||||||
|
|
||||||
/// Visit all the items in the krate in some order. When visiting a
|
|
||||||
/// particular item, first create a dep-node by calling `dep_node_fn`
|
|
||||||
/// and push that onto the dep-graph stack of tasks, and also create a
|
|
||||||
/// read edge from the corresponding AST node. This is used in
|
|
||||||
/// compiler passes to automatically record the item that they are
|
|
||||||
/// working on.
|
|
||||||
pub fn visit_all_item_likes_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|
||||||
mut dep_node_fn: F,
|
|
||||||
visitor: &mut V)
|
|
||||||
where F: FnMut(DefId) -> DepNode<DefId>, V: ItemLikeVisitor<'tcx>
|
|
||||||
{
|
|
||||||
struct TrackingVisitor<'visit, 'tcx: 'visit, F: 'visit, V: 'visit> {
|
|
||||||
tcx: TyCtxt<'visit, 'tcx, 'tcx>,
|
|
||||||
dep_node_fn: &'visit mut F,
|
|
||||||
visitor: &'visit mut V,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'visit, 'tcx, F, V> ItemLikeVisitor<'tcx> for TrackingVisitor<'visit, 'tcx, F, V>
|
|
||||||
where F: FnMut(DefId) -> DepNode<DefId>, V: ItemLikeVisitor<'tcx>
|
|
||||||
{
|
|
||||||
fn visit_item(&mut self, i: &'tcx hir::Item) {
|
|
||||||
let item_def_id = self.tcx.hir.local_def_id(i.id);
|
|
||||||
let task_id = (self.dep_node_fn)(item_def_id);
|
|
||||||
let _task = self.tcx.dep_graph.in_task(task_id.clone());
|
|
||||||
debug!("Started task {:?}", task_id);
|
|
||||||
self.tcx.dep_graph.read(DepNode::Hir(item_def_id));
|
|
||||||
self.visitor.visit_item(i);
|
|
||||||
debug!("Ended task {:?}", task_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_trait_item(&mut self, i: &'tcx hir::TraitItem) {
|
|
||||||
let trait_item_def_id = self.tcx.hir.local_def_id(i.id);
|
|
||||||
let task_id = (self.dep_node_fn)(trait_item_def_id);
|
|
||||||
let _task = self.tcx.dep_graph.in_task(task_id.clone());
|
|
||||||
debug!("Started task {:?}", task_id);
|
|
||||||
self.tcx.dep_graph.read(DepNode::Hir(trait_item_def_id));
|
|
||||||
self.visitor.visit_trait_item(i);
|
|
||||||
debug!("Ended task {:?}", task_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_impl_item(&mut self, i: &'tcx hir::ImplItem) {
|
|
||||||
let impl_item_def_id = self.tcx.hir.local_def_id(i.id);
|
|
||||||
let task_id = (self.dep_node_fn)(impl_item_def_id);
|
|
||||||
let _task = self.tcx.dep_graph.in_task(task_id.clone());
|
|
||||||
debug!("Started task {:?}", task_id);
|
|
||||||
self.tcx.dep_graph.read(DepNode::Hir(impl_item_def_id));
|
|
||||||
self.visitor.visit_impl_item(i);
|
|
||||||
debug!("Ended task {:?}", task_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let krate = tcx.dep_graph.with_ignore(|| tcx.hir.krate());
|
|
||||||
let mut tracking_visitor = TrackingVisitor {
|
|
||||||
tcx: tcx,
|
|
||||||
dep_node_fn: &mut dep_node_fn,
|
|
||||||
visitor: visitor,
|
|
||||||
};
|
|
||||||
krate.visit_all_item_likes(&mut tracking_visitor)
|
|
||||||
}
|
|
||||||
|
|
|
@ -88,7 +88,7 @@ pub enum NestedVisitorMap<'this, 'tcx: 'this> {
|
||||||
/// that are inside of an item-like.
|
/// that are inside of an item-like.
|
||||||
///
|
///
|
||||||
/// **This is the most common choice.** A very commmon pattern is
|
/// **This is the most common choice.** A very commmon pattern is
|
||||||
/// to use `tcx.visit_all_item_likes_in_krate()` as an outer loop,
|
/// to use `visit_all_item_likes()` as an outer loop,
|
||||||
/// and to have the visitor that visits the contents of each item
|
/// and to have the visitor that visits the contents of each item
|
||||||
/// using this setting.
|
/// using this setting.
|
||||||
OnlyBodies(&'this Map<'tcx>),
|
OnlyBodies(&'this Map<'tcx>),
|
||||||
|
|
|
@ -19,9 +19,8 @@ use super::intravisit::Visitor;
|
||||||
///
|
///
|
||||||
/// 1. **Shallow visit**: Get a simple callback for every item (or item-like thing) in the HIR.
|
/// 1. **Shallow visit**: Get a simple callback for every item (or item-like thing) in the HIR.
|
||||||
/// - Example: find all items with a `#[foo]` attribute on them.
|
/// - Example: find all items with a `#[foo]` attribute on them.
|
||||||
/// - How: Implement `ItemLikeVisitor` and call `tcx.visit_all_item_likes_in_krate()`.
|
/// - How: Implement `ItemLikeVisitor` and call `tcx.hir.krate().visit_all_item_likes()`.
|
||||||
/// - Pro: Efficient; just walks the lists of item-like things, not the nodes themselves.
|
/// - Pro: Efficient; just walks the lists of item-like things, not the nodes themselves.
|
||||||
/// - Pro: Integrates well into dependency tracking.
|
|
||||||
/// - Con: Don't get information about nesting
|
/// - Con: Don't get information about nesting
|
||||||
/// - Con: Don't have methods for specific bits of HIR, like "on
|
/// - Con: Don't have methods for specific bits of HIR, like "on
|
||||||
/// every expr, do this".
|
/// every expr, do this".
|
||||||
|
@ -30,7 +29,7 @@ use super::intravisit::Visitor;
|
||||||
/// within one another.
|
/// within one another.
|
||||||
/// - Example: Examine each expression to look for its type and do some check or other.
|
/// - Example: Examine each expression to look for its type and do some check or other.
|
||||||
/// - How: Implement `intravisit::Visitor` and use
|
/// - How: Implement `intravisit::Visitor` and use
|
||||||
/// `tcx.visit_all_item_likes_in_krate(visitor.as_deep_visitor())`. Within
|
/// `tcx.hir.krate().visit_all_item_likes(visitor.as_deep_visitor())`. Within
|
||||||
/// your `intravisit::Visitor` impl, implement methods like
|
/// your `intravisit::Visitor` impl, implement methods like
|
||||||
/// `visit_expr()`; don't forget to invoke
|
/// `visit_expr()`; don't forget to invoke
|
||||||
/// `intravisit::walk_visit_expr()` to keep walking the subparts.
|
/// `intravisit::walk_visit_expr()` to keep walking the subparts.
|
||||||
|
|
|
@ -470,9 +470,6 @@ pub struct GlobalCtxt<'tcx> {
|
||||||
|
|
||||||
pub lang_items: middle::lang_items::LanguageItems,
|
pub lang_items: middle::lang_items::LanguageItems,
|
||||||
|
|
||||||
/// True if the variance has been computed yet; false otherwise.
|
|
||||||
pub variance_computed: Cell<bool>,
|
|
||||||
|
|
||||||
/// Set of used unsafe nodes (functions or blocks). Unsafe nodes not
|
/// Set of used unsafe nodes (functions or blocks). Unsafe nodes not
|
||||||
/// present in this set can be warned about.
|
/// present in this set can be warned about.
|
||||||
pub used_unsafe: RefCell<NodeSet>,
|
pub used_unsafe: RefCell<NodeSet>,
|
||||||
|
@ -744,7 +741,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
dep_graph: dep_graph.clone(),
|
dep_graph: dep_graph.clone(),
|
||||||
types: common_types,
|
types: common_types,
|
||||||
named_region_map: named_region_map,
|
named_region_map: named_region_map,
|
||||||
variance_computed: Cell::new(false),
|
|
||||||
trait_map: resolutions.trait_map,
|
trait_map: resolutions.trait_map,
|
||||||
export_map: resolutions.export_map,
|
export_map: resolutions.export_map,
|
||||||
fulfilled_predicates: RefCell::new(fulfilled_predicates),
|
fulfilled_predicates: RefCell::new(fulfilled_predicates),
|
||||||
|
|
|
@ -266,6 +266,12 @@ impl<'tcx> QueryDescription for queries::crate_inherent_impls_overlap_check<'tcx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> QueryDescription for queries::crate_variances<'tcx> {
|
||||||
|
fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
|
||||||
|
format!("computing the variances for items in this crate")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx> QueryDescription for queries::mir_shims<'tcx> {
|
impl<'tcx> QueryDescription for queries::mir_shims<'tcx> {
|
||||||
fn describe(tcx: TyCtxt, def: ty::InstanceDef<'tcx>) -> String {
|
fn describe(tcx: TyCtxt, def: ty::InstanceDef<'tcx>) -> String {
|
||||||
format!("generating MIR shim for `{}`",
|
format!("generating MIR shim for `{}`",
|
||||||
|
@ -549,18 +555,6 @@ macro_rules! define_map_struct {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Detect things with the `pub` modifier
|
|
||||||
(tcx: $tcx:tt,
|
|
||||||
input: (([pub $($other_modifiers:tt)*] $attrs:tt $name:tt) $($input:tt)*),
|
|
||||||
output: $output:tt) => {
|
|
||||||
define_map_struct! {
|
|
||||||
tcx: $tcx,
|
|
||||||
ready: ([pub] $attrs $name),
|
|
||||||
input: ($($input)*),
|
|
||||||
output: $output
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// No modifiers left? This is a private item.
|
// No modifiers left? This is a private item.
|
||||||
(tcx: $tcx:tt,
|
(tcx: $tcx:tt,
|
||||||
input: (([] $attrs:tt $name:tt) $($input:tt)*),
|
input: (([] $attrs:tt $name:tt) $($input:tt)*),
|
||||||
|
@ -687,9 +681,13 @@ define_maps! { <'tcx>
|
||||||
/// True if this is a foreign item (i.e., linked via `extern { ... }`).
|
/// True if this is a foreign item (i.e., linked via `extern { ... }`).
|
||||||
[] is_foreign_item: IsForeignItem(DefId) -> bool,
|
[] is_foreign_item: IsForeignItem(DefId) -> bool,
|
||||||
|
|
||||||
|
/// Get a map with the variance of every item; use `item_variance`
|
||||||
|
/// instead.
|
||||||
|
[] crate_variances: crate_variances(CrateNum) -> Rc<ty::CrateVariancesMap>,
|
||||||
|
|
||||||
/// Maps from def-id of a type or region parameter to its
|
/// Maps from def-id of a type or region parameter to its
|
||||||
/// (inferred) variance.
|
/// (inferred) variance.
|
||||||
[pub] variances_of: ItemSignature(DefId) -> Rc<Vec<ty::Variance>>,
|
[] variances_of: ItemVariances(DefId) -> Rc<Vec<ty::Variance>>,
|
||||||
|
|
||||||
/// Maps from an impl/trait def-id to a list of the def-ids of its items
|
/// Maps from an impl/trait def-id to a list of the def-ids of its items
|
||||||
[] associated_item_def_ids: AssociatedItemDefIds(DefId) -> Rc<Vec<DefId>>,
|
[] associated_item_def_ids: AssociatedItemDefIds(DefId) -> Rc<Vec<DefId>>,
|
||||||
|
@ -825,3 +823,7 @@ fn const_eval_dep_node((def_id, _): (DefId, &Substs)) -> DepNode<DefId> {
|
||||||
fn mir_keys(_: CrateNum) -> DepNode<DefId> {
|
fn mir_keys(_: CrateNum) -> DepNode<DefId> {
|
||||||
DepNode::MirKeys
|
DepNode::MirKeys
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn crate_variances(_: CrateNum) -> DepNode<DefId> {
|
||||||
|
DepNode::CrateVariances
|
||||||
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ pub use self::IntVarValue::*;
|
||||||
pub use self::LvaluePreference::*;
|
pub use self::LvaluePreference::*;
|
||||||
pub use self::fold::TypeFoldable;
|
pub use self::fold::TypeFoldable;
|
||||||
|
|
||||||
use dep_graph::{self, DepNode};
|
use dep_graph::DepNode;
|
||||||
use hir::{map as hir_map, FreevarMap, TraitMap};
|
use hir::{map as hir_map, FreevarMap, TraitMap};
|
||||||
use hir::def::{Def, CtorKind, ExportMap};
|
use hir::def::{Def, CtorKind, ExportMap};
|
||||||
use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
|
use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
|
||||||
|
@ -55,9 +55,9 @@ use rustc_const_math::ConstInt;
|
||||||
use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter;
|
use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter;
|
||||||
use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
|
use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
|
||||||
HashStable};
|
HashStable};
|
||||||
|
use rustc_data_structures::transitive_relation::TransitiveRelation;
|
||||||
|
|
||||||
use hir;
|
use hir;
|
||||||
use hir::itemlikevisit::ItemLikeVisitor;
|
|
||||||
|
|
||||||
pub use self::sty::{Binder, DebruijnIndex};
|
pub use self::sty::{Binder, DebruijnIndex};
|
||||||
pub use self::sty::{FnSig, PolyFnSig};
|
pub use self::sty::{FnSig, PolyFnSig};
|
||||||
|
@ -309,6 +309,27 @@ pub enum Variance {
|
||||||
Bivariant, // T<A> <: T<B> -- e.g., unused type parameter
|
Bivariant, // T<A> <: T<B> -- e.g., unused type parameter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The crate variances map is computed during typeck and contains the
|
||||||
|
/// variance of every item in the local crate. You should not use it
|
||||||
|
/// directly, because to do so will make your pass dependent on the
|
||||||
|
/// HIR of every item in the local crate. Instead, use
|
||||||
|
/// `tcx.variances_of()` to get the variance for a *particular*
|
||||||
|
/// item.
|
||||||
|
pub struct CrateVariancesMap {
|
||||||
|
/// This relation tracks the dependencies between the variance of
|
||||||
|
/// various items. In particular, if `a < b`, then the variance of
|
||||||
|
/// `a` depends on the sources of `b`.
|
||||||
|
pub dependencies: TransitiveRelation<DefId>,
|
||||||
|
|
||||||
|
/// For each item with generics, maps to a vector of the variance
|
||||||
|
/// of its generics. If an item has no generics, it will have no
|
||||||
|
/// entry.
|
||||||
|
pub variances: FxHashMap<DefId, Rc<Vec<ty::Variance>>>,
|
||||||
|
|
||||||
|
/// An empty vector, useful for cloning.
|
||||||
|
pub empty_variance: Rc<Vec<ty::Variance>>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, RustcDecodable, RustcEncodable)]
|
#[derive(Clone, Copy, Debug, RustcDecodable, RustcEncodable)]
|
||||||
pub struct MethodCallee<'tcx> {
|
pub struct MethodCallee<'tcx> {
|
||||||
/// Impl method ID, for inherent methods, or trait method ID, otherwise.
|
/// Impl method ID, for inherent methods, or trait method ID, otherwise.
|
||||||
|
@ -2543,14 +2564,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
self.mk_region(ty::ReScope(self.node_extent(id)))
|
self.mk_region(ty::ReScope(self.node_extent(id)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn visit_all_item_likes_in_krate<V,F>(self,
|
|
||||||
dep_node_fn: F,
|
|
||||||
visitor: &mut V)
|
|
||||||
where F: FnMut(DefId) -> DepNode<DefId>, V: ItemLikeVisitor<'gcx>
|
|
||||||
{
|
|
||||||
dep_graph::visit_all_item_likes_in_krate(self.global_tcx(), dep_node_fn, visitor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Looks up the span of `impl_did` if the impl is local; otherwise returns `Err`
|
/// Looks up the span of `impl_did` if the impl is local; otherwise returns `Err`
|
||||||
/// with the name of the crate containing the impl.
|
/// with the name of the crate containing the impl.
|
||||||
pub fn span_of_impl(self, impl_did: DefId) -> Result<Span, Symbol> {
|
pub fn span_of_impl(self, impl_did: DefId) -> Result<Span, Symbol> {
|
||||||
|
|
|
@ -124,14 +124,8 @@ fn relate_item_substs<'a, 'gcx, 'tcx, R>(relation: &mut R,
|
||||||
a_subst,
|
a_subst,
|
||||||
b_subst);
|
b_subst);
|
||||||
|
|
||||||
let variances;
|
let opt_variances = relation.tcx().variances_of(item_def_id);
|
||||||
let opt_variances = if relation.tcx().variance_computed.get() {
|
relate_substs(relation, Some(&opt_variances), a_subst, b_subst)
|
||||||
variances = relation.tcx().variances_of(item_def_id);
|
|
||||||
Some(&*variances)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
relate_substs(relation, opt_variances, a_subst, b_subst)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn relate_substs<'a, 'gcx, 'tcx, R>(relation: &mut R,
|
pub fn relate_substs<'a, 'gcx, 'tcx, R>(relation: &mut R,
|
||||||
|
|
|
@ -72,7 +72,7 @@ impl<'tcx> From<ty::Region<'tcx>> for Kind<'tcx> {
|
||||||
impl<'tcx> Kind<'tcx> {
|
impl<'tcx> Kind<'tcx> {
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn downcast<T>(self, tag: usize) -> Option<&'tcx T> {
|
unsafe fn downcast<T>(self, tag: usize) -> Option<&'tcx T> {
|
||||||
let ptr = *self.ptr;
|
let ptr = self.ptr.get();
|
||||||
if ptr & TAG_MASK == tag {
|
if ptr & TAG_MASK == tag {
|
||||||
Some(&*((ptr & !TAG_MASK) as *const _))
|
Some(&*((ptr & !TAG_MASK) as *const _))
|
||||||
} else {
|
} else {
|
||||||
|
@ -102,7 +102,7 @@ impl<'tcx> fmt::Debug for Kind<'tcx> {
|
||||||
} else if let Some(r) = self.as_region() {
|
} else if let Some(r) = self.as_region() {
|
||||||
write!(f, "{:?}", r)
|
write!(f, "{:?}", r)
|
||||||
} else {
|
} else {
|
||||||
write!(f, "<unknwon @ {:p}>", *self.ptr as *const ())
|
write!(f, "<unknwon @ {:p}>", self.ptr.get() as *const ())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ mod indexes {
|
||||||
unsafe { $Index(NonZero::new(idx + 1)) }
|
unsafe { $Index(NonZero::new(idx + 1)) }
|
||||||
}
|
}
|
||||||
fn index(self) -> usize {
|
fn index(self) -> usize {
|
||||||
*self.0 - 1
|
self.0.get() - 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -255,7 +255,7 @@ impl<'a, A: Array> Drop for Drain<'a, A> {
|
||||||
|
|
||||||
if self.tail_len > 0 {
|
if self.tail_len > 0 {
|
||||||
unsafe {
|
unsafe {
|
||||||
let source_array_vec = &mut *self.array_vec.as_mut_ptr();
|
let source_array_vec = self.array_vec.as_mut();
|
||||||
// memmove back untouched tail, update to new length
|
// memmove back untouched tail, update to new length
|
||||||
let start = source_array_vec.len();
|
let start = source_array_vec.len();
|
||||||
let tail = self.tail_start;
|
let tail = self.tail_start;
|
||||||
|
|
|
@ -23,6 +23,6 @@ impl NodeIndex {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(self) -> usize {
|
pub fn get(self) -> usize {
|
||||||
(*self.index - 1) as usize
|
(self.index.get() - 1) as usize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,21 +9,23 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use bitvec::BitMatrix;
|
use bitvec::BitMatrix;
|
||||||
use stable_hasher::{HashStable, StableHasher, StableHasherResult};
|
use fx::FxHashMap;
|
||||||
use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
|
use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
|
||||||
|
use stable_hasher::{HashStable, StableHasher, StableHasherResult};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
use std::hash::Hash;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct TransitiveRelation<T: Debug + PartialEq> {
|
pub struct TransitiveRelation<T: Clone + Debug + Eq + Hash + Clone> {
|
||||||
// List of elements. This is used to map from a T to a usize. We
|
// List of elements. This is used to map from a T to a usize.
|
||||||
// expect domain to be small so just use a linear list versus a
|
|
||||||
// hashmap or something.
|
|
||||||
elements: Vec<T>,
|
elements: Vec<T>,
|
||||||
|
|
||||||
|
// Maps each element to an index.
|
||||||
|
map: FxHashMap<T, Index>,
|
||||||
|
|
||||||
// List of base edges in the graph. Require to compute transitive
|
// List of base edges in the graph. Require to compute transitive
|
||||||
// closure.
|
// closure.
|
||||||
edges: Vec<Edge>,
|
edges: Vec<Edge>,
|
||||||
|
@ -40,19 +42,20 @@ pub struct TransitiveRelation<T: Debug + PartialEq> {
|
||||||
closure: RefCell<Option<BitMatrix>>,
|
closure: RefCell<Option<BitMatrix>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, PartialOrd, RustcEncodable, RustcDecodable)]
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
|
||||||
struct Index(usize);
|
struct Index(usize);
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)]
|
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)]
|
||||||
struct Edge {
|
struct Edge {
|
||||||
source: Index,
|
source: Index,
|
||||||
target: Index,
|
target: Index,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Debug + PartialEq> TransitiveRelation<T> {
|
impl<T: Clone + Debug + Eq + Hash + Clone> TransitiveRelation<T> {
|
||||||
pub fn new() -> TransitiveRelation<T> {
|
pub fn new() -> TransitiveRelation<T> {
|
||||||
TransitiveRelation {
|
TransitiveRelation {
|
||||||
elements: vec![],
|
elements: vec![],
|
||||||
|
map: FxHashMap(),
|
||||||
edges: vec![],
|
edges: vec![],
|
||||||
closure: RefCell::new(None),
|
closure: RefCell::new(None),
|
||||||
}
|
}
|
||||||
|
@ -63,21 +66,27 @@ impl<T: Debug + PartialEq> TransitiveRelation<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn index(&self, a: &T) -> Option<Index> {
|
fn index(&self, a: &T) -> Option<Index> {
|
||||||
self.elements.iter().position(|e| *e == *a).map(Index)
|
self.map.get(a).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_index(&mut self, a: T) -> Index {
|
fn add_index(&mut self, a: T) -> Index {
|
||||||
match self.index(&a) {
|
let &mut TransitiveRelation {
|
||||||
Some(i) => i,
|
ref mut elements,
|
||||||
None => {
|
ref closure,
|
||||||
self.elements.push(a);
|
ref mut map,
|
||||||
|
..
|
||||||
|
} = self;
|
||||||
|
|
||||||
// if we changed the dimensions, clear the cache
|
map.entry(a.clone())
|
||||||
*self.closure.borrow_mut() = None;
|
.or_insert_with(|| {
|
||||||
|
elements.push(a);
|
||||||
|
|
||||||
Index(self.elements.len() - 1)
|
// if we changed the dimensions, clear the cache
|
||||||
}
|
*closure.borrow_mut() = None;
|
||||||
}
|
|
||||||
|
Index(elements.len() - 1)
|
||||||
|
})
|
||||||
|
.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Applies the (partial) function to each edge and returns a new
|
/// Applies the (partial) function to each edge and returns a new
|
||||||
|
@ -85,7 +94,7 @@ impl<T: Debug + PartialEq> TransitiveRelation<T> {
|
||||||
/// `None`.
|
/// `None`.
|
||||||
pub fn maybe_map<F, U>(&self, mut f: F) -> Option<TransitiveRelation<U>>
|
pub fn maybe_map<F, U>(&self, mut f: F) -> Option<TransitiveRelation<U>>
|
||||||
where F: FnMut(&T) -> Option<U>,
|
where F: FnMut(&T) -> Option<U>,
|
||||||
U: Debug + PartialEq,
|
U: Clone + Debug + Eq + Hash + Clone,
|
||||||
{
|
{
|
||||||
let mut result = TransitiveRelation::new();
|
let mut result = TransitiveRelation::new();
|
||||||
for edge in &self.edges {
|
for edge in &self.edges {
|
||||||
|
@ -125,6 +134,20 @@ impl<T: Debug + PartialEq> TransitiveRelation<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a vector of all things less than `a`.
|
||||||
|
///
|
||||||
|
/// Really this probably ought to be `impl Iterator<Item=&T>`, but
|
||||||
|
/// I'm too lazy to make that work, and -- given the caching
|
||||||
|
/// strategy -- it'd be a touch tricky anyhow.
|
||||||
|
pub fn less_than(&self, a: &T) -> Vec<&T> {
|
||||||
|
match self.index(a) {
|
||||||
|
Some(a) => self.with_closure(|closure| {
|
||||||
|
closure.iter(a.0).map(|i| &self.elements[i]).collect()
|
||||||
|
}),
|
||||||
|
None => vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Picks what I am referring to as the "postdominating"
|
/// Picks what I am referring to as the "postdominating"
|
||||||
/// upper-bound for `a` and `b`. This is usually the least upper
|
/// upper-bound for `a` and `b`. This is usually the least upper
|
||||||
/// bound, but in cases where there is no single least upper
|
/// bound, but in cases where there is no single least upper
|
||||||
|
@ -335,7 +358,7 @@ fn pare_down(candidates: &mut Vec<usize>, closure: &BitMatrix) {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Encodable for TransitiveRelation<T>
|
impl<T> Encodable for TransitiveRelation<T>
|
||||||
where T: Encodable + Debug + PartialEq
|
where T: Clone + Encodable + Debug + Eq + Hash + Clone
|
||||||
{
|
{
|
||||||
fn encode<E: Encoder>(&self, s: &mut E) -> Result<(), E::Error> {
|
fn encode<E: Encoder>(&self, s: &mut E) -> Result<(), E::Error> {
|
||||||
s.emit_struct("TransitiveRelation", 2, |s| {
|
s.emit_struct("TransitiveRelation", 2, |s| {
|
||||||
|
@ -347,19 +370,23 @@ impl<T> Encodable for TransitiveRelation<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Decodable for TransitiveRelation<T>
|
impl<T> Decodable for TransitiveRelation<T>
|
||||||
where T: Decodable + Debug + PartialEq
|
where T: Clone + Decodable + Debug + Eq + Hash + Clone
|
||||||
{
|
{
|
||||||
fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
|
fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
|
||||||
d.read_struct("TransitiveRelation", 2, |d| {
|
d.read_struct("TransitiveRelation", 2, |d| {
|
||||||
let elements = d.read_struct_field("elements", 0, |d| Decodable::decode(d))?;
|
let elements: Vec<T> = d.read_struct_field("elements", 0, |d| Decodable::decode(d))?;
|
||||||
let edges = d.read_struct_field("edges", 1, |d| Decodable::decode(d))?;
|
let edges = d.read_struct_field("edges", 1, |d| Decodable::decode(d))?;
|
||||||
Ok(TransitiveRelation { elements, edges, closure: RefCell::new(None) })
|
let map = elements.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(index, elem)| (elem.clone(), Index(index)))
|
||||||
|
.collect();
|
||||||
|
Ok(TransitiveRelation { elements, edges, map, closure: RefCell::new(None) })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CTX, T> HashStable<CTX> for TransitiveRelation<T>
|
impl<CTX, T> HashStable<CTX> for TransitiveRelation<T>
|
||||||
where T: HashStable<CTX> + PartialEq + Debug
|
where T: HashStable<CTX> + Eq + Debug + Clone + Hash
|
||||||
{
|
{
|
||||||
fn hash_stable<W: StableHasherResult>(&self,
|
fn hash_stable<W: StableHasherResult>(&self,
|
||||||
hcx: &mut CTX,
|
hcx: &mut CTX,
|
||||||
|
@ -369,6 +396,8 @@ impl<CTX, T> HashStable<CTX> for TransitiveRelation<T>
|
||||||
let TransitiveRelation {
|
let TransitiveRelation {
|
||||||
ref elements,
|
ref elements,
|
||||||
ref edges,
|
ref edges,
|
||||||
|
// "map" is just a copy of elements vec
|
||||||
|
map: _,
|
||||||
// "closure" is just a copy of the data above
|
// "closure" is just a copy of the data above
|
||||||
closure: _
|
closure: _
|
||||||
} = *self;
|
} = *self;
|
||||||
|
|
|
@ -51,7 +51,7 @@ use rustc::ty::TyCtxt;
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_data_structures::graph::{Direction, INCOMING, OUTGOING, NodeIndex};
|
use rustc_data_structures::graph::{Direction, INCOMING, OUTGOING, NodeIndex};
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
use rustc::hir::itemlikevisit::ItemLikeVisitor;
|
use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
|
||||||
use rustc::ich::{ATTR_IF_THIS_CHANGED, ATTR_THEN_THIS_WOULD_NEED};
|
use rustc::ich::{ATTR_IF_THIS_CHANGED, ATTR_THEN_THIS_WOULD_NEED};
|
||||||
use graphviz::IntoCow;
|
use graphviz::IntoCow;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
@ -80,7 +80,7 @@ pub fn assert_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
||||||
if_this_changed: vec![],
|
if_this_changed: vec![],
|
||||||
then_this_would_need: vec![] };
|
then_this_would_need: vec![] };
|
||||||
visitor.process_attrs(ast::CRATE_NODE_ID, &tcx.hir.krate().attrs);
|
visitor.process_attrs(ast::CRATE_NODE_ID, &tcx.hir.krate().attrs);
|
||||||
tcx.hir.krate().visit_all_item_likes(&mut visitor);
|
tcx.hir.krate().visit_all_item_likes(&mut visitor.as_deep_visitor());
|
||||||
(visitor.if_this_changed, visitor.then_this_would_need)
|
(visitor.if_this_changed, visitor.then_this_would_need)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -166,17 +166,29 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> ItemLikeVisitor<'tcx> for IfThisChanged<'a, 'tcx> {
|
impl<'a, 'tcx> Visitor<'tcx> for IfThisChanged<'a, 'tcx> {
|
||||||
|
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
|
||||||
|
NestedVisitorMap::OnlyBodies(&self.tcx.hir)
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_item(&mut self, item: &'tcx hir::Item) {
|
fn visit_item(&mut self, item: &'tcx hir::Item) {
|
||||||
self.process_attrs(item.id, &item.attrs);
|
self.process_attrs(item.id, &item.attrs);
|
||||||
|
intravisit::walk_item(self, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
|
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
|
||||||
self.process_attrs(trait_item.id, &trait_item.attrs);
|
self.process_attrs(trait_item.id, &trait_item.attrs);
|
||||||
|
intravisit::walk_trait_item(self, trait_item);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
|
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
|
||||||
self.process_attrs(impl_item.id, &impl_item.attrs);
|
self.process_attrs(impl_item.id, &impl_item.attrs);
|
||||||
|
intravisit::walk_impl_item(self, impl_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_struct_field(&mut self, s: &'tcx hir::StructField) {
|
||||||
|
self.process_attrs(s.id, &s.attrs);
|
||||||
|
intravisit::walk_struct_field(self, s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -240,8 +240,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
|
impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
|
||||||
fn encode_item_variances(&mut self, def_id: DefId) -> LazySeq<ty::Variance> {
|
fn encode_variances_of(&mut self, def_id: DefId) -> LazySeq<ty::Variance> {
|
||||||
debug!("EntryBuilder::encode_item_variances({:?})", def_id);
|
debug!("EntryBuilder::encode_variances_of({:?})", def_id);
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
self.lazy_seq_from_slice(&tcx.variances_of(def_id))
|
self.lazy_seq_from_slice(&tcx.variances_of(def_id))
|
||||||
}
|
}
|
||||||
|
@ -824,7 +824,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
|
||||||
hir::ItemEnum(..) |
|
hir::ItemEnum(..) |
|
||||||
hir::ItemStruct(..) |
|
hir::ItemStruct(..) |
|
||||||
hir::ItemUnion(..) |
|
hir::ItemUnion(..) |
|
||||||
hir::ItemTrait(..) => self.encode_item_variances(def_id),
|
hir::ItemTrait(..) => self.encode_variances_of(def_id),
|
||||||
_ => LazySeq::empty(),
|
_ => LazySeq::empty(),
|
||||||
},
|
},
|
||||||
generics: match item.node {
|
generics: match item.node {
|
||||||
|
|
|
@ -293,6 +293,7 @@ pub fn provide(providers: &mut Providers) {
|
||||||
collect::provide(providers);
|
collect::provide(providers);
|
||||||
coherence::provide(providers);
|
coherence::provide(providers);
|
||||||
check::provide(providers);
|
check::provide(providers);
|
||||||
|
variance::provide(providers);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
|
pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
|
||||||
|
@ -307,9 +308,6 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
|
||||||
|
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
time(time_passes, "variance inference", ||
|
|
||||||
variance::infer_variance(tcx));
|
|
||||||
|
|
||||||
tcx.sess.track_errors(|| {
|
tcx.sess.track_errors(|| {
|
||||||
time(time_passes, "impl wf inference", ||
|
time(time_passes, "impl wf inference", ||
|
||||||
impl_wf_check::impl_wf_check(tcx));
|
impl_wf_check::impl_wf_check(tcx));
|
||||||
|
@ -320,6 +318,11 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
|
||||||
coherence::check_coherence(tcx));
|
coherence::check_coherence(tcx));
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
tcx.sess.track_errors(|| {
|
||||||
|
time(time_passes, "variance testing", ||
|
||||||
|
variance::test::test_variance(tcx));
|
||||||
|
})?;
|
||||||
|
|
||||||
time(time_passes, "wf checking", || check::check_wf_new(tcx))?;
|
time(time_passes, "wf checking", || check::check_wf_new(tcx))?;
|
||||||
|
|
||||||
time(time_passes, "item-types checking", || check::check_item_types(tcx))?;
|
time(time_passes, "item-types checking", || check::check_item_types(tcx))?;
|
||||||
|
|
|
@ -97,51 +97,29 @@ types involved before considering variance.
|
||||||
|
|
||||||
#### Dependency graph management
|
#### Dependency graph management
|
||||||
|
|
||||||
Because variance works in two phases, if we are not careful, we wind
|
Because variance is a whole-crate inference, its dependency graph
|
||||||
up with a muddled mess of a dep-graph. Basically, when gathering up
|
can become quite muddled if we are not careful. To resolve this, we refactor
|
||||||
the constraints, things are fairly well-structured, but then we do a
|
into two queries:
|
||||||
fixed-point iteration and write the results back where they
|
|
||||||
belong. You can't give this fixed-point iteration a single task
|
|
||||||
because it reads from (and writes to) the variance of all types in the
|
|
||||||
crate. In principle, we *could* switch the "current task" in a very
|
|
||||||
fine-grained way while propagating constraints in the fixed-point
|
|
||||||
iteration and everything would be automatically tracked, but that
|
|
||||||
would add some overhead and isn't really necessary anyway.
|
|
||||||
|
|
||||||
Instead what we do is to add edges into the dependency graph as we
|
- `crate_variances` computes the variance for all items in the current crate.
|
||||||
construct the constraint set: so, if computing the constraints for
|
- `variances_of` accesses the variance for an individual reading; it
|
||||||
node `X` requires loading the inference variables from node `Y`, then
|
works by requesting `crate_variances` and extracting the relevant data.
|
||||||
we can add an edge `Y -> X`, since the variance we ultimately infer
|
|
||||||
for `Y` will affect the variance we ultimately infer for `X`.
|
If you limit yourself to reading `variances_of`, your code will only
|
||||||
|
depend then on the inference inferred for that particular item.
|
||||||
|
|
||||||
At this point, we've basically mirrored the inference graph in the
|
Eventually, the goal is to rely on the red-green dependency management
|
||||||
dependency graph. This means we can just completely ignore the
|
algorithm. At the moment, however, we rely instead on a hack, where
|
||||||
fixed-point iteration, since it is just shuffling values along this
|
`variances_of` ignores the dependencies of accessing
|
||||||
graph. In other words, if we added the fine-grained switching of tasks
|
`crate_variances` and instead computes the *correct* dependencies
|
||||||
I described earlier, all it would show is that we repeatedly read the
|
itself. To this end, when we build up the constraints in the system,
|
||||||
values described by the constraints, but those edges were already
|
we also built up a transitive `dependencies` relation as part of the
|
||||||
added when building the constraints in the first place.
|
crate map. A `(X, Y)` pair is added to the map each time we have a
|
||||||
|
constraint that the variance of some inferred for the item `X` depends
|
||||||
Here is how this is implemented (at least as of the time of this
|
on the variance of some element of `Y`. This is to some extent a
|
||||||
writing). The associated `DepNode` for the variance map is (at least
|
mirroring of the inference graph in the dependency graph. This means
|
||||||
presently) `Signature(DefId)`. This means that, in `constraints.rs`,
|
we can just completely ignore the fixed-point iteration, since it is
|
||||||
when we visit an item to load up its constraints, we set
|
just shuffling values along this graph.
|
||||||
`Signature(DefId)` as the current task (the "memoization" pattern
|
|
||||||
described in the `dep-graph` README). Then whenever we find an
|
|
||||||
embedded type or trait, we add a synthetic read of `Signature(DefId)`,
|
|
||||||
which covers the variances we will compute for all of its
|
|
||||||
parameters. This read is synthetic (i.e., we call
|
|
||||||
`variance_map.read()`) because, in fact, the final variance is not yet
|
|
||||||
computed -- the read *will* occur (repeatedly) during the fixed-point
|
|
||||||
iteration phase.
|
|
||||||
|
|
||||||
In fact, we don't really *need* this synthetic read. That's because we
|
|
||||||
do wind up looking up the `TypeScheme` or `TraitDef` for all
|
|
||||||
references types/traits, and those reads add an edge from
|
|
||||||
`Signature(DefId)` (that is, they share the same dep node as
|
|
||||||
variance). However, I've kept the synthetic reads in place anyway,
|
|
||||||
just for future-proofing (in case we change the dep-nodes in the
|
|
||||||
future), and because it makes the intention a bit clearer I think.
|
|
||||||
|
|
||||||
### Addendum: Variance on traits
|
### Addendum: Variance on traits
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
use hir::def_id::DefId;
|
use hir::def_id::DefId;
|
||||||
use middle::resolve_lifetime as rl;
|
use middle::resolve_lifetime as rl;
|
||||||
|
use rustc::dep_graph::{AssertDepGraphSafe, DepNode};
|
||||||
use rustc::ty::subst::Substs;
|
use rustc::ty::subst::Substs;
|
||||||
use rustc::ty::{self, Ty, TyCtxt};
|
use rustc::ty::{self, Ty, TyCtxt};
|
||||||
use rustc::hir::map as hir_map;
|
use rustc::hir::map as hir_map;
|
||||||
|
@ -22,12 +23,12 @@ use syntax::ast;
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
use rustc::hir::itemlikevisit::ItemLikeVisitor;
|
use rustc::hir::itemlikevisit::ItemLikeVisitor;
|
||||||
|
|
||||||
|
use rustc_data_structures::transitive_relation::TransitiveRelation;
|
||||||
|
|
||||||
use super::terms::*;
|
use super::terms::*;
|
||||||
use super::terms::VarianceTerm::*;
|
use super::terms::VarianceTerm::*;
|
||||||
use super::xform::*;
|
use super::xform::*;
|
||||||
|
|
||||||
use dep_graph::DepNode::ItemSignature as VarianceDepNode;
|
|
||||||
|
|
||||||
pub struct ConstraintContext<'a, 'tcx: 'a> {
|
pub struct ConstraintContext<'a, 'tcx: 'a> {
|
||||||
pub terms_cx: TermsContext<'a, 'tcx>,
|
pub terms_cx: TermsContext<'a, 'tcx>,
|
||||||
|
|
||||||
|
@ -38,6 +39,11 @@ pub struct ConstraintContext<'a, 'tcx: 'a> {
|
||||||
bivariant: VarianceTermPtr<'a>,
|
bivariant: VarianceTermPtr<'a>,
|
||||||
|
|
||||||
pub constraints: Vec<Constraint<'a>>,
|
pub constraints: Vec<Constraint<'a>>,
|
||||||
|
|
||||||
|
/// This relation tracks the dependencies between the variance of
|
||||||
|
/// various items. In particular, if `a < b`, then the variance of
|
||||||
|
/// `a` depends on the sources of `b`.
|
||||||
|
pub dependencies: TransitiveRelation<DefId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Declares that the variable `decl_id` appears in a location with
|
/// Declares that the variable `decl_id` appears in a location with
|
||||||
|
@ -48,6 +54,20 @@ pub struct Constraint<'a> {
|
||||||
pub variance: &'a VarianceTerm<'a>,
|
pub variance: &'a VarianceTerm<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// To build constriants, we visit one item (type, trait) at a time
|
||||||
|
/// and look at its contents. So e.g. if we have
|
||||||
|
///
|
||||||
|
/// struct Foo<T> {
|
||||||
|
/// b: Bar<T>
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// then while we are visiting `Bar<T>`, the `CurrentItem` would have
|
||||||
|
/// the def-id and generics of `Foo`.
|
||||||
|
pub struct CurrentItem<'a> {
|
||||||
|
def_id: DefId,
|
||||||
|
generics: &'a ty::Generics,
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_constraints_from_crate<'a, 'tcx>(terms_cx: TermsContext<'a, 'tcx>)
|
pub fn add_constraints_from_crate<'a, 'tcx>(terms_cx: TermsContext<'a, 'tcx>)
|
||||||
-> ConstraintContext<'a, 'tcx> {
|
-> ConstraintContext<'a, 'tcx> {
|
||||||
let tcx = terms_cx.tcx;
|
let tcx = terms_cx.tcx;
|
||||||
|
@ -62,10 +82,10 @@ pub fn add_constraints_from_crate<'a, 'tcx>(terms_cx: TermsContext<'a, 'tcx>)
|
||||||
invariant: invariant,
|
invariant: invariant,
|
||||||
bivariant: bivariant,
|
bivariant: bivariant,
|
||||||
constraints: Vec::new(),
|
constraints: Vec::new(),
|
||||||
|
dependencies: TransitiveRelation::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// See README.md for a discussion on dep-graph management.
|
tcx.hir.krate().visit_all_item_likes(&mut constraint_cx);
|
||||||
tcx.visit_all_item_likes_in_krate(VarianceDepNode, &mut constraint_cx);
|
|
||||||
|
|
||||||
constraint_cx
|
constraint_cx
|
||||||
}
|
}
|
||||||
|
@ -73,50 +93,32 @@ pub fn add_constraints_from_crate<'a, 'tcx>(terms_cx: TermsContext<'a, 'tcx>)
|
||||||
impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> {
|
impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> {
|
||||||
fn visit_item(&mut self, item: &hir::Item) {
|
fn visit_item(&mut self, item: &hir::Item) {
|
||||||
let tcx = self.terms_cx.tcx;
|
let tcx = self.terms_cx.tcx;
|
||||||
let did = tcx.hir.local_def_id(item.id);
|
let def_id = tcx.hir.local_def_id(item.id);
|
||||||
|
|
||||||
debug!("visit_item item={}", tcx.hir.node_to_string(item.id));
|
|
||||||
|
|
||||||
|
// Encapsulate constructing the constraints into a task we can
|
||||||
|
// reference later. This can go away once the red-green
|
||||||
|
// algorithm is in place.
|
||||||
|
//
|
||||||
|
// See README.md for a detailed discussion
|
||||||
|
// on dep-graph management.
|
||||||
match item.node {
|
match item.node {
|
||||||
hir::ItemEnum(..) |
|
hir::ItemEnum(..) |
|
||||||
hir::ItemStruct(..) |
|
hir::ItemStruct(..) |
|
||||||
hir::ItemUnion(..) => {
|
hir::ItemUnion(..) => {
|
||||||
let generics = tcx.generics_of(did);
|
tcx.dep_graph.with_task(DepNode::ItemVarianceConstraints(def_id),
|
||||||
|
AssertDepGraphSafe(self),
|
||||||
// Not entirely obvious: constraints on structs/enums do not
|
def_id,
|
||||||
// affect the variance of their type parameters. See discussion
|
visit_item_task);
|
||||||
// in comment at top of module.
|
|
||||||
//
|
|
||||||
// self.add_constraints_from_generics(generics);
|
|
||||||
|
|
||||||
for field in tcx.adt_def(did).all_fields() {
|
|
||||||
self.add_constraints_from_ty(generics,
|
|
||||||
tcx.type_of(field.did),
|
|
||||||
self.covariant);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
hir::ItemTrait(..) => {
|
_ => {
|
||||||
let generics = tcx.generics_of(did);
|
// Nothing to do here, skip the task.
|
||||||
let trait_ref = ty::TraitRef {
|
|
||||||
def_id: did,
|
|
||||||
substs: Substs::identity_for_item(tcx, did)
|
|
||||||
};
|
|
||||||
self.add_constraints_from_trait_ref(generics,
|
|
||||||
trait_ref,
|
|
||||||
self.invariant);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
hir::ItemExternCrate(_) |
|
fn visit_item_task<'a, 'tcx>(ccx: AssertDepGraphSafe<&mut ConstraintContext<'a, 'tcx>>,
|
||||||
hir::ItemUse(..) |
|
def_id: DefId)
|
||||||
hir::ItemStatic(..) |
|
{
|
||||||
hir::ItemConst(..) |
|
ccx.0.build_constraints_for_item(def_id);
|
||||||
hir::ItemFn(..) |
|
|
||||||
hir::ItemMod(..) |
|
|
||||||
hir::ItemForeignMod(..) |
|
|
||||||
hir::ItemGlobalAsm(..) |
|
|
||||||
hir::ItemTy(..) |
|
|
||||||
hir::ItemImpl(..) |
|
|
||||||
hir::ItemDefaultImpl(..) => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,16 +142,64 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
||||||
self.terms_cx.tcx
|
self.terms_cx.tcx
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inferred_index(&self, param_id: ast::NodeId) -> InferredIndex {
|
fn build_constraints_for_item(&mut self, def_id: DefId) {
|
||||||
match self.terms_cx.inferred_map.get(¶m_id) {
|
let tcx = self.tcx();
|
||||||
Some(&index) => index,
|
let id = self.tcx().hir.as_local_node_id(def_id).unwrap();
|
||||||
None => {
|
let item = tcx.hir.expect_item(id);
|
||||||
bug!("no inferred index entry for {}",
|
debug!("visit_item item={}", tcx.hir.node_to_string(item.id));
|
||||||
self.tcx().hir.node_to_string(param_id));
|
|
||||||
|
match item.node {
|
||||||
|
hir::ItemEnum(..) |
|
||||||
|
hir::ItemStruct(..) |
|
||||||
|
hir::ItemUnion(..) => {
|
||||||
|
let generics = tcx.generics_of(def_id);
|
||||||
|
let current_item = &CurrentItem { def_id, generics };
|
||||||
|
|
||||||
|
// Not entirely obvious: constraints on structs/enums do not
|
||||||
|
// affect the variance of their type parameters. See discussion
|
||||||
|
// in comment at top of module.
|
||||||
|
//
|
||||||
|
// self.add_constraints_from_generics(generics);
|
||||||
|
|
||||||
|
for field in tcx.adt_def(def_id).all_fields() {
|
||||||
|
self.add_constraints_from_ty(current_item,
|
||||||
|
tcx.type_of(field.did),
|
||||||
|
self.covariant);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hir::ItemTrait(..) |
|
||||||
|
hir::ItemExternCrate(_) |
|
||||||
|
hir::ItemUse(..) |
|
||||||
|
hir::ItemStatic(..) |
|
||||||
|
hir::ItemConst(..) |
|
||||||
|
hir::ItemFn(..) |
|
||||||
|
hir::ItemMod(..) |
|
||||||
|
hir::ItemForeignMod(..) |
|
||||||
|
hir::ItemGlobalAsm(..) |
|
||||||
|
hir::ItemTy(..) |
|
||||||
|
hir::ItemImpl(..) |
|
||||||
|
hir::ItemDefaultImpl(..) => {
|
||||||
|
span_bug!(item.span, "`build_constraints_for_item` invoked for non-type-def");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Load the generics for another item, adding a corresponding
|
||||||
|
/// relation into the dependencies to indicate that the variance
|
||||||
|
/// for `current` relies on `def_id`.
|
||||||
|
fn read_generics(&mut self, current: &CurrentItem, def_id: DefId) -> &'tcx ty::Generics {
|
||||||
|
let generics = self.tcx().generics_of(def_id);
|
||||||
|
if self.tcx().dep_graph.is_fully_enabled() {
|
||||||
|
self.dependencies.add(current.def_id, def_id);
|
||||||
|
}
|
||||||
|
generics
|
||||||
|
}
|
||||||
|
|
||||||
|
fn opt_inferred_index(&self, param_id: ast::NodeId) -> Option<&InferredIndex> {
|
||||||
|
self.terms_cx.inferred_map.get(¶m_id)
|
||||||
|
}
|
||||||
|
|
||||||
fn find_binding_for_lifetime(&self, param_id: ast::NodeId) -> ast::NodeId {
|
fn find_binding_for_lifetime(&self, param_id: ast::NodeId) -> ast::NodeId {
|
||||||
let tcx = self.terms_cx.tcx;
|
let tcx = self.terms_cx.tcx;
|
||||||
assert!(is_lifetime(&tcx.hir, param_id));
|
assert!(is_lifetime(&tcx.hir, param_id));
|
||||||
|
@ -228,8 +278,27 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
||||||
// Parameter on an item defined within current crate:
|
// Parameter on an item defined within current crate:
|
||||||
// variance not yet inferred, so return a symbolic
|
// variance not yet inferred, so return a symbolic
|
||||||
// variance.
|
// variance.
|
||||||
let InferredIndex(index) = self.inferred_index(param_node_id);
|
if let Some(&InferredIndex(index)) = self.opt_inferred_index(param_node_id) {
|
||||||
self.terms_cx.inferred_infos[index].term
|
self.terms_cx.inferred_infos[index].term
|
||||||
|
} else {
|
||||||
|
// If there is no inferred entry for a type parameter,
|
||||||
|
// it must be declared on a (locally defiend) trait -- they don't
|
||||||
|
// get inferreds because they are always invariant.
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
let item_node_id = self.tcx().hir.as_local_node_id(item_def_id).unwrap();
|
||||||
|
let item = self.tcx().hir.expect_item(item_node_id);
|
||||||
|
let success = match item.node {
|
||||||
|
hir::ItemTrait(..) => true,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
if !success {
|
||||||
|
bug!("parameter {:?} has no inferred, but declared on non-trait: {:?}",
|
||||||
|
item_def_id,
|
||||||
|
item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.invariant
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Parameter on an item defined within another crate:
|
// Parameter on an item defined within another crate:
|
||||||
// variance already inferred, just look it up.
|
// variance already inferred, just look it up.
|
||||||
|
@ -279,7 +348,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_constraints_from_trait_ref(&mut self,
|
fn add_constraints_from_trait_ref(&mut self,
|
||||||
generics: &ty::Generics,
|
current: &CurrentItem,
|
||||||
trait_ref: ty::TraitRef<'tcx>,
|
trait_ref: ty::TraitRef<'tcx>,
|
||||||
variance: VarianceTermPtr<'a>) {
|
variance: VarianceTermPtr<'a>) {
|
||||||
debug!("add_constraints_from_trait_ref: trait_ref={:?} variance={:?}",
|
debug!("add_constraints_from_trait_ref: trait_ref={:?} variance={:?}",
|
||||||
|
@ -288,12 +357,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
||||||
|
|
||||||
let trait_generics = self.tcx().generics_of(trait_ref.def_id);
|
let trait_generics = self.tcx().generics_of(trait_ref.def_id);
|
||||||
|
|
||||||
// This edge is actually implied by the call to
|
self.add_constraints_from_substs(current,
|
||||||
// `trait_def`, but I'm trying to be future-proof. See
|
|
||||||
// README.md for a discussion on dep-graph management.
|
|
||||||
self.tcx().dep_graph.read(VarianceDepNode(trait_ref.def_id));
|
|
||||||
|
|
||||||
self.add_constraints_from_substs(generics,
|
|
||||||
trait_ref.def_id,
|
trait_ref.def_id,
|
||||||
&trait_generics.types,
|
&trait_generics.types,
|
||||||
&trait_generics.regions,
|
&trait_generics.regions,
|
||||||
|
@ -305,7 +369,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
||||||
/// in a context with the generics defined in `generics` and
|
/// in a context with the generics defined in `generics` and
|
||||||
/// ambient variance `variance`
|
/// ambient variance `variance`
|
||||||
fn add_constraints_from_ty(&mut self,
|
fn add_constraints_from_ty(&mut self,
|
||||||
generics: &ty::Generics,
|
current: &CurrentItem,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
variance: VarianceTermPtr<'a>) {
|
variance: VarianceTermPtr<'a>) {
|
||||||
debug!("add_constraints_from_ty(ty={:?}, variance={:?})",
|
debug!("add_constraints_from_ty(ty={:?}, variance={:?})",
|
||||||
|
@ -325,34 +389,29 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
||||||
|
|
||||||
ty::TyRef(region, ref mt) => {
|
ty::TyRef(region, ref mt) => {
|
||||||
let contra = self.contravariant(variance);
|
let contra = self.contravariant(variance);
|
||||||
self.add_constraints_from_region(generics, region, contra);
|
self.add_constraints_from_region(current, region, contra);
|
||||||
self.add_constraints_from_mt(generics, mt, variance);
|
self.add_constraints_from_mt(current, mt, variance);
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::TyArray(typ, _) |
|
ty::TyArray(typ, _) |
|
||||||
ty::TySlice(typ) => {
|
ty::TySlice(typ) => {
|
||||||
self.add_constraints_from_ty(generics, typ, variance);
|
self.add_constraints_from_ty(current, typ, variance);
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::TyRawPtr(ref mt) => {
|
ty::TyRawPtr(ref mt) => {
|
||||||
self.add_constraints_from_mt(generics, mt, variance);
|
self.add_constraints_from_mt(current, mt, variance);
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::TyTuple(subtys, _) => {
|
ty::TyTuple(subtys, _) => {
|
||||||
for &subty in subtys {
|
for &subty in subtys {
|
||||||
self.add_constraints_from_ty(generics, subty, variance);
|
self.add_constraints_from_ty(current, subty, variance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::TyAdt(def, substs) => {
|
ty::TyAdt(def, substs) => {
|
||||||
let adt_generics = self.tcx().generics_of(def.did);
|
let adt_generics = self.read_generics(current, def.did);
|
||||||
|
|
||||||
// This edge is actually implied by the call to
|
self.add_constraints_from_substs(current,
|
||||||
// `trait_def`, but I'm trying to be future-proof. See
|
|
||||||
// README.md for a discussion on dep-graph management.
|
|
||||||
self.tcx().dep_graph.read(VarianceDepNode(def.did));
|
|
||||||
|
|
||||||
self.add_constraints_from_substs(generics,
|
|
||||||
def.did,
|
def.did,
|
||||||
&adt_generics.types,
|
&adt_generics.types,
|
||||||
&adt_generics.regions,
|
&adt_generics.regions,
|
||||||
|
@ -364,12 +423,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
||||||
let trait_ref = &data.trait_ref;
|
let trait_ref = &data.trait_ref;
|
||||||
let trait_generics = self.tcx().generics_of(trait_ref.def_id);
|
let trait_generics = self.tcx().generics_of(trait_ref.def_id);
|
||||||
|
|
||||||
// This edge is actually implied by the call to
|
self.add_constraints_from_substs(current,
|
||||||
// `trait_def`, but I'm trying to be future-proof. See
|
|
||||||
// README.md for a discussion on dep-graph management.
|
|
||||||
self.tcx().dep_graph.read(VarianceDepNode(trait_ref.def_id));
|
|
||||||
|
|
||||||
self.add_constraints_from_substs(generics,
|
|
||||||
trait_ref.def_id,
|
trait_ref.def_id,
|
||||||
&trait_generics.types,
|
&trait_generics.types,
|
||||||
&trait_generics.regions,
|
&trait_generics.regions,
|
||||||
|
@ -380,25 +434,25 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
||||||
ty::TyDynamic(ref data, r) => {
|
ty::TyDynamic(ref data, r) => {
|
||||||
// The type `Foo<T+'a>` is contravariant w/r/t `'a`:
|
// The type `Foo<T+'a>` is contravariant w/r/t `'a`:
|
||||||
let contra = self.contravariant(variance);
|
let contra = self.contravariant(variance);
|
||||||
self.add_constraints_from_region(generics, r, contra);
|
self.add_constraints_from_region(current, r, contra);
|
||||||
|
|
||||||
if let Some(p) = data.principal() {
|
if let Some(p) = data.principal() {
|
||||||
let poly_trait_ref = p.with_self_ty(self.tcx(), self.tcx().types.err);
|
let poly_trait_ref = p.with_self_ty(self.tcx(), self.tcx().types.err);
|
||||||
self.add_constraints_from_trait_ref(generics, poly_trait_ref.0, variance);
|
self.add_constraints_from_trait_ref(current, poly_trait_ref.0, variance);
|
||||||
}
|
}
|
||||||
|
|
||||||
for projection in data.projection_bounds() {
|
for projection in data.projection_bounds() {
|
||||||
self.add_constraints_from_ty(generics, projection.0.ty, self.invariant);
|
self.add_constraints_from_ty(current, projection.0.ty, self.invariant);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::TyParam(ref data) => {
|
ty::TyParam(ref data) => {
|
||||||
assert_eq!(generics.parent, None);
|
assert_eq!(current.generics.parent, None);
|
||||||
let mut i = data.idx as usize;
|
let mut i = data.idx as usize;
|
||||||
if !generics.has_self || i > 0 {
|
if !current.generics.has_self || i > 0 {
|
||||||
i -= generics.regions.len();
|
i -= current.generics.regions.len();
|
||||||
}
|
}
|
||||||
let def_id = generics.types[i].def_id;
|
let def_id = current.generics.types[i].def_id;
|
||||||
let node_id = self.tcx().hir.as_local_node_id(def_id).unwrap();
|
let node_id = self.tcx().hir.as_local_node_id(def_id).unwrap();
|
||||||
match self.terms_cx.inferred_map.get(&node_id) {
|
match self.terms_cx.inferred_map.get(&node_id) {
|
||||||
Some(&index) => {
|
Some(&index) => {
|
||||||
|
@ -414,7 +468,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
||||||
|
|
||||||
ty::TyFnDef(.., sig) |
|
ty::TyFnDef(.., sig) |
|
||||||
ty::TyFnPtr(sig) => {
|
ty::TyFnPtr(sig) => {
|
||||||
self.add_constraints_from_sig(generics, sig, variance);
|
self.add_constraints_from_sig(current, sig, variance);
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::TyError => {
|
ty::TyError => {
|
||||||
|
@ -433,7 +487,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
||||||
/// Adds constraints appropriate for a nominal type (enum, struct,
|
/// Adds constraints appropriate for a nominal type (enum, struct,
|
||||||
/// object, etc) appearing in a context with ambient variance `variance`
|
/// object, etc) appearing in a context with ambient variance `variance`
|
||||||
fn add_constraints_from_substs(&mut self,
|
fn add_constraints_from_substs(&mut self,
|
||||||
generics: &ty::Generics,
|
current: &CurrentItem,
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
type_param_defs: &[ty::TypeParameterDef],
|
type_param_defs: &[ty::TypeParameterDef],
|
||||||
region_param_defs: &[ty::RegionParameterDef],
|
region_param_defs: &[ty::RegionParameterDef],
|
||||||
|
@ -451,44 +505,44 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
||||||
debug!("add_constraints_from_substs: variance_decl={:?} variance_i={:?}",
|
debug!("add_constraints_from_substs: variance_decl={:?} variance_i={:?}",
|
||||||
variance_decl,
|
variance_decl,
|
||||||
variance_i);
|
variance_i);
|
||||||
self.add_constraints_from_ty(generics, substs_ty, variance_i);
|
self.add_constraints_from_ty(current, substs_ty, variance_i);
|
||||||
}
|
}
|
||||||
|
|
||||||
for p in region_param_defs {
|
for p in region_param_defs {
|
||||||
let variance_decl = self.declared_variance(p.def_id, def_id, p.index as usize);
|
let variance_decl = self.declared_variance(p.def_id, def_id, p.index as usize);
|
||||||
let variance_i = self.xform(variance, variance_decl);
|
let variance_i = self.xform(variance, variance_decl);
|
||||||
let substs_r = substs.region_for_def(p);
|
let substs_r = substs.region_for_def(p);
|
||||||
self.add_constraints_from_region(generics, substs_r, variance_i);
|
self.add_constraints_from_region(current, substs_r, variance_i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds constraints appropriate for a function with signature
|
/// Adds constraints appropriate for a function with signature
|
||||||
/// `sig` appearing in a context with ambient variance `variance`
|
/// `sig` appearing in a context with ambient variance `variance`
|
||||||
fn add_constraints_from_sig(&mut self,
|
fn add_constraints_from_sig(&mut self,
|
||||||
generics: &ty::Generics,
|
current: &CurrentItem,
|
||||||
sig: ty::PolyFnSig<'tcx>,
|
sig: ty::PolyFnSig<'tcx>,
|
||||||
variance: VarianceTermPtr<'a>) {
|
variance: VarianceTermPtr<'a>) {
|
||||||
let contra = self.contravariant(variance);
|
let contra = self.contravariant(variance);
|
||||||
for &input in sig.0.inputs() {
|
for &input in sig.0.inputs() {
|
||||||
self.add_constraints_from_ty(generics, input, contra);
|
self.add_constraints_from_ty(current, input, contra);
|
||||||
}
|
}
|
||||||
self.add_constraints_from_ty(generics, sig.0.output(), variance);
|
self.add_constraints_from_ty(current, sig.0.output(), variance);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds constraints appropriate for a region appearing in a
|
/// Adds constraints appropriate for a region appearing in a
|
||||||
/// context with ambient variance `variance`
|
/// context with ambient variance `variance`
|
||||||
fn add_constraints_from_region(&mut self,
|
fn add_constraints_from_region(&mut self,
|
||||||
generics: &ty::Generics,
|
current: &CurrentItem,
|
||||||
region: ty::Region<'tcx>,
|
region: ty::Region<'tcx>,
|
||||||
variance: VarianceTermPtr<'a>) {
|
variance: VarianceTermPtr<'a>) {
|
||||||
match *region {
|
match *region {
|
||||||
ty::ReEarlyBound(ref data) => {
|
ty::ReEarlyBound(ref data) => {
|
||||||
assert_eq!(generics.parent, None);
|
assert_eq!(current.generics.parent, None);
|
||||||
let i = data.index as usize - generics.has_self as usize;
|
let i = data.index as usize - current.generics.has_self as usize;
|
||||||
let def_id = generics.regions[i].def_id;
|
let def_id = current.generics.regions[i].def_id;
|
||||||
let node_id = self.tcx().hir.as_local_node_id(def_id).unwrap();
|
let node_id = self.tcx().hir.as_local_node_id(def_id).unwrap();
|
||||||
if self.is_to_be_inferred(node_id) {
|
if self.is_to_be_inferred(node_id) {
|
||||||
let index = self.inferred_index(node_id);
|
let &index = self.opt_inferred_index(node_id).unwrap();
|
||||||
self.add_constraint(index, variance);
|
self.add_constraint(index, variance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -518,17 +572,17 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
||||||
/// Adds constraints appropriate for a mutability-type pair
|
/// Adds constraints appropriate for a mutability-type pair
|
||||||
/// appearing in a context with ambient variance `variance`
|
/// appearing in a context with ambient variance `variance`
|
||||||
fn add_constraints_from_mt(&mut self,
|
fn add_constraints_from_mt(&mut self,
|
||||||
generics: &ty::Generics,
|
current: &CurrentItem,
|
||||||
mt: &ty::TypeAndMut<'tcx>,
|
mt: &ty::TypeAndMut<'tcx>,
|
||||||
variance: VarianceTermPtr<'a>) {
|
variance: VarianceTermPtr<'a>) {
|
||||||
match mt.mutbl {
|
match mt.mutbl {
|
||||||
hir::MutMutable => {
|
hir::MutMutable => {
|
||||||
let invar = self.invariant(variance);
|
let invar = self.invariant(variance);
|
||||||
self.add_constraints_from_ty(generics, mt.ty, invar);
|
self.add_constraints_from_ty(current, mt.ty, invar);
|
||||||
}
|
}
|
||||||
|
|
||||||
hir::MutImmutable => {
|
hir::MutImmutable => {
|
||||||
self.add_constraints_from_ty(generics, mt.ty, variance);
|
self.add_constraints_from_ty(current, mt.ty, variance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,12 @@
|
||||||
//! parameters. See README.md for details.
|
//! parameters. See README.md for details.
|
||||||
|
|
||||||
use arena;
|
use arena;
|
||||||
use rustc::ty::TyCtxt;
|
use rustc::dep_graph::DepNode;
|
||||||
|
use rustc::hir;
|
||||||
|
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
|
||||||
|
use rustc::ty::{self, CrateVariancesMap, TyCtxt};
|
||||||
|
use rustc::ty::maps::Providers;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
/// Defines the `TermsContext` basically houses an arena where we can
|
/// Defines the `TermsContext` basically houses an arena where we can
|
||||||
/// allocate terms.
|
/// allocate terms.
|
||||||
|
@ -24,13 +29,67 @@ mod constraints;
|
||||||
/// Code to solve constraints and write out the results.
|
/// Code to solve constraints and write out the results.
|
||||||
mod solve;
|
mod solve;
|
||||||
|
|
||||||
|
/// Code to write unit tests of variance.
|
||||||
|
pub mod test;
|
||||||
|
|
||||||
/// Code for transforming variances.
|
/// Code for transforming variances.
|
||||||
mod xform;
|
mod xform;
|
||||||
|
|
||||||
pub fn infer_variance<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
pub fn provide(providers: &mut Providers) {
|
||||||
|
*providers = Providers {
|
||||||
|
variances_of,
|
||||||
|
crate_variances,
|
||||||
|
..*providers
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn crate_variances<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum)
|
||||||
|
-> Rc<CrateVariancesMap> {
|
||||||
|
assert_eq!(crate_num, LOCAL_CRATE);
|
||||||
let mut arena = arena::TypedArena::new();
|
let mut arena = arena::TypedArena::new();
|
||||||
let terms_cx = terms::determine_parameters_to_be_inferred(tcx, &mut arena);
|
let terms_cx = terms::determine_parameters_to_be_inferred(tcx, &mut arena);
|
||||||
let constraints_cx = constraints::add_constraints_from_crate(terms_cx);
|
let constraints_cx = constraints::add_constraints_from_crate(terms_cx);
|
||||||
solve::solve_constraints(constraints_cx);
|
Rc::new(solve::solve_constraints(constraints_cx))
|
||||||
tcx.variance_computed.set(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn variances_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_def_id: DefId)
|
||||||
|
-> Rc<Vec<ty::Variance>> {
|
||||||
|
let item_id = tcx.hir.as_local_node_id(item_def_id).expect("expected local def-id");
|
||||||
|
let item = tcx.hir.expect_item(item_id);
|
||||||
|
match item.node {
|
||||||
|
hir::ItemTrait(..) => {
|
||||||
|
// Traits are always invariant.
|
||||||
|
let generics = tcx.generics_of(item_def_id);
|
||||||
|
assert!(generics.parent.is_none());
|
||||||
|
Rc::new(vec![ty::Variance::Invariant; generics.count()])
|
||||||
|
}
|
||||||
|
|
||||||
|
hir::ItemEnum(..) |
|
||||||
|
hir::ItemStruct(..) |
|
||||||
|
hir::ItemUnion(..) => {
|
||||||
|
// Everything else must be inferred.
|
||||||
|
|
||||||
|
// Lacking red/green, we read the variances for all items here
|
||||||
|
// but ignore the dependencies, then re-synthesize the ones we need.
|
||||||
|
let crate_map = tcx.dep_graph.with_ignore(|| tcx.crate_variances(LOCAL_CRATE));
|
||||||
|
tcx.dep_graph.read(DepNode::ItemVarianceConstraints(item_def_id));
|
||||||
|
for &dep_def_id in crate_map.dependencies.less_than(&item_def_id) {
|
||||||
|
if dep_def_id.is_local() {
|
||||||
|
tcx.dep_graph.read(DepNode::ItemVarianceConstraints(dep_def_id));
|
||||||
|
} else {
|
||||||
|
tcx.dep_graph.read(DepNode::ItemVariances(dep_def_id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
crate_map.variances.get(&item_def_id)
|
||||||
|
.unwrap_or(&crate_map.empty_variance)
|
||||||
|
.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
// Variance not relevant.
|
||||||
|
span_bug!(item.span, "asked to compute variance for wrong kind of item")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,9 @@
|
||||||
//! optimal solution to the constraints. The final variance for each
|
//! optimal solution to the constraints. The final variance for each
|
||||||
//! inferred is then written into the `variance_map` in the tcx.
|
//! inferred is then written into the `variance_map` in the tcx.
|
||||||
|
|
||||||
|
use rustc::hir::def_id::DefId;
|
||||||
use rustc::ty;
|
use rustc::ty;
|
||||||
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use super::constraints::*;
|
use super::constraints::*;
|
||||||
|
@ -31,8 +33,8 @@ struct SolveContext<'a, 'tcx: 'a> {
|
||||||
solutions: Vec<ty::Variance>,
|
solutions: Vec<ty::Variance>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn solve_constraints(constraints_cx: ConstraintContext) {
|
pub fn solve_constraints(constraints_cx: ConstraintContext) -> ty::CrateVariancesMap {
|
||||||
let ConstraintContext { terms_cx, constraints, .. } = constraints_cx;
|
let ConstraintContext { terms_cx, dependencies, constraints, .. } = constraints_cx;
|
||||||
|
|
||||||
let solutions = terms_cx.inferred_infos
|
let solutions = terms_cx.inferred_infos
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -45,7 +47,10 @@ pub fn solve_constraints(constraints_cx: ConstraintContext) {
|
||||||
solutions: solutions,
|
solutions: solutions,
|
||||||
};
|
};
|
||||||
solutions_cx.solve();
|
solutions_cx.solve();
|
||||||
solutions_cx.write();
|
let variances = solutions_cx.create_map();
|
||||||
|
let empty_variance = Rc::new(Vec::new());
|
||||||
|
|
||||||
|
ty::CrateVariancesMap { dependencies, variances, empty_variance }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> SolveContext<'a, 'tcx> {
|
impl<'a, 'tcx> SolveContext<'a, 'tcx> {
|
||||||
|
@ -83,7 +88,7 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write(&self) {
|
fn create_map(&self) -> FxHashMap<DefId, Rc<Vec<ty::Variance>>> {
|
||||||
// Collect all the variances for a particular item and stick
|
// Collect all the variances for a particular item and stick
|
||||||
// them into the variance map. We rely on the fact that we
|
// them into the variance map. We rely on the fact that we
|
||||||
// generate all the inferreds for a particular item
|
// generate all the inferreds for a particular item
|
||||||
|
@ -95,11 +100,7 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> {
|
||||||
|
|
||||||
let tcx = self.terms_cx.tcx;
|
let tcx = self.terms_cx.tcx;
|
||||||
|
|
||||||
// Ignore the writes here because the relevant edges were
|
let mut map = FxHashMap();
|
||||||
// already accounted for in `constraints.rs`. See the section
|
|
||||||
// on dependency graph management in README.md for more
|
|
||||||
// information.
|
|
||||||
let _ignore = tcx.dep_graph.in_ignore();
|
|
||||||
|
|
||||||
let solutions = &self.solutions;
|
let solutions = &self.solutions;
|
||||||
let inferred_infos = &self.terms_cx.inferred_infos;
|
let inferred_infos = &self.terms_cx.inferred_infos;
|
||||||
|
@ -127,19 +128,10 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> {
|
||||||
|
|
||||||
let item_def_id = tcx.hir.local_def_id(item_id);
|
let item_def_id = tcx.hir.local_def_id(item_id);
|
||||||
|
|
||||||
// For unit testing: check for a special "rustc_variance"
|
map.insert(item_def_id, Rc::new(item_variances));
|
||||||
// attribute and report an error with various results if found.
|
|
||||||
if tcx.has_attr(item_def_id, "rustc_variance") {
|
|
||||||
span_err!(tcx.sess,
|
|
||||||
tcx.hir.span(item_id),
|
|
||||||
E0208,
|
|
||||||
"{:?}",
|
|
||||||
item_variances);
|
|
||||||
}
|
|
||||||
|
|
||||||
tcx.maps.variances_of.borrow_mut()
|
|
||||||
.insert(item_def_id, Rc::new(item_variances));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
map
|
||||||
}
|
}
|
||||||
|
|
||||||
fn evaluate(&self, term: VarianceTermPtr<'a>) -> ty::Variance {
|
fn evaluate(&self, term: VarianceTermPtr<'a>) -> ty::Variance {
|
||||||
|
|
|
@ -32,8 +32,6 @@ use self::VarianceTerm::*;
|
||||||
|
|
||||||
pub type VarianceTermPtr<'a> = &'a VarianceTerm<'a>;
|
pub type VarianceTermPtr<'a> = &'a VarianceTerm<'a>;
|
||||||
|
|
||||||
use dep_graph::DepNode::ItemSignature as VarianceDepNode;
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct InferredIndex(pub usize);
|
pub struct InferredIndex(pub usize);
|
||||||
|
|
||||||
|
@ -109,7 +107,7 @@ pub fn determine_parameters_to_be_inferred<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>
|
||||||
};
|
};
|
||||||
|
|
||||||
// See README.md for a discussion on dep-graph management.
|
// See README.md for a discussion on dep-graph management.
|
||||||
tcx.visit_all_item_likes_in_krate(|def_id| VarianceDepNode(def_id), &mut terms_cx);
|
tcx.hir.krate().visit_all_item_likes(&mut terms_cx);
|
||||||
|
|
||||||
terms_cx
|
terms_cx
|
||||||
}
|
}
|
||||||
|
@ -139,7 +137,6 @@ fn lang_items(tcx: TyCtxt) -> Vec<(ast::NodeId, Vec<ty::Variance>)> {
|
||||||
impl<'a, 'tcx> TermsContext<'a, 'tcx> {
|
impl<'a, 'tcx> TermsContext<'a, 'tcx> {
|
||||||
fn add_inferreds_for_item(&mut self,
|
fn add_inferreds_for_item(&mut self,
|
||||||
item_id: ast::NodeId,
|
item_id: ast::NodeId,
|
||||||
has_self: bool,
|
|
||||||
generics: &hir::Generics) {
|
generics: &hir::Generics) {
|
||||||
//! Add "inferreds" for the generic parameters declared on this
|
//! Add "inferreds" for the generic parameters declared on this
|
||||||
//! item. This has a lot of annoying parameters because we are
|
//! item. This has a lot of annoying parameters because we are
|
||||||
|
@ -149,38 +146,17 @@ impl<'a, 'tcx> TermsContext<'a, 'tcx> {
|
||||||
//!
|
//!
|
||||||
|
|
||||||
// NB: In the code below for writing the results back into the
|
// NB: In the code below for writing the results back into the
|
||||||
// tcx, we rely on the fact that all inferreds for a particular
|
// `CrateVariancesMap`, we rely on the fact that all inferreds
|
||||||
// item are assigned continuous indices.
|
// for a particular item are assigned continuous indices.
|
||||||
|
|
||||||
let inferreds_on_entry = self.num_inferred();
|
for (p, i) in generics.lifetimes.iter().zip(0..) {
|
||||||
|
|
||||||
if has_self {
|
|
||||||
self.add_inferred(item_id, 0, item_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i, p) in generics.lifetimes.iter().enumerate() {
|
|
||||||
let id = p.lifetime.id;
|
let id = p.lifetime.id;
|
||||||
let i = has_self as usize + i;
|
|
||||||
self.add_inferred(item_id, i, id);
|
self.add_inferred(item_id, i, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i, p) in generics.ty_params.iter().enumerate() {
|
for (p, i) in generics.ty_params.iter().zip(generics.lifetimes.len()..) {
|
||||||
let i = has_self as usize + generics.lifetimes.len() + i;
|
|
||||||
self.add_inferred(item_id, i, p.id);
|
self.add_inferred(item_id, i, p.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this item has no type or lifetime parameters,
|
|
||||||
// then there are no variances to infer, so just
|
|
||||||
// insert an empty entry into the variance map.
|
|
||||||
// Arguably we could just leave the map empty in this
|
|
||||||
// case but it seems cleaner to be able to distinguish
|
|
||||||
// "invalid item id" from "item id with no
|
|
||||||
// parameters".
|
|
||||||
if self.num_inferred() == inferreds_on_entry {
|
|
||||||
let item_def_id = self.tcx.hir.local_def_id(item_id);
|
|
||||||
self.tcx.maps.variances_of.borrow_mut()
|
|
||||||
.insert(item_def_id, self.empty_variances.clone());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_inferred(&mut self, item_id: ast::NodeId, index: usize, param_id: ast::NodeId) {
|
fn add_inferred(&mut self, item_id: ast::NodeId, index: usize, param_id: ast::NodeId) {
|
||||||
|
@ -232,15 +208,10 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> {
|
||||||
hir::ItemEnum(_, ref generics) |
|
hir::ItemEnum(_, ref generics) |
|
||||||
hir::ItemStruct(_, ref generics) |
|
hir::ItemStruct(_, ref generics) |
|
||||||
hir::ItemUnion(_, ref generics) => {
|
hir::ItemUnion(_, ref generics) => {
|
||||||
self.add_inferreds_for_item(item.id, false, generics);
|
self.add_inferreds_for_item(item.id, generics);
|
||||||
}
|
|
||||||
hir::ItemTrait(_, ref generics, ..) => {
|
|
||||||
// Note: all inputs for traits are ultimately
|
|
||||||
// constrained to be invariant. See `visit_item` in
|
|
||||||
// the impl for `ConstraintContext` in `constraints.rs`.
|
|
||||||
self.add_inferreds_for_item(item.id, true, generics);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hir::ItemTrait(..) |
|
||||||
hir::ItemExternCrate(_) |
|
hir::ItemExternCrate(_) |
|
||||||
hir::ItemUse(..) |
|
hir::ItemUse(..) |
|
||||||
hir::ItemDefaultImpl(..) |
|
hir::ItemDefaultImpl(..) |
|
||||||
|
|
41
src/librustc_typeck/variance/test.rs
Normal file
41
src/librustc_typeck/variance/test.rs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
use rustc::hir;
|
||||||
|
use rustc::hir::itemlikevisit::ItemLikeVisitor;
|
||||||
|
use rustc::ty::TyCtxt;
|
||||||
|
|
||||||
|
pub fn test_variance<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
||||||
|
tcx.hir.krate().visit_all_item_likes(&mut VarianceTest { tcx });
|
||||||
|
}
|
||||||
|
|
||||||
|
struct VarianceTest<'a, 'tcx: 'a> {
|
||||||
|
tcx: TyCtxt<'a, 'tcx, 'tcx>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'tcx> ItemLikeVisitor<'tcx> for VarianceTest<'a, 'tcx> {
|
||||||
|
fn visit_item(&mut self, item: &'tcx hir::Item) {
|
||||||
|
let item_def_id = self.tcx.hir.local_def_id(item.id);
|
||||||
|
|
||||||
|
// For unit testing: check for a special "rustc_variance"
|
||||||
|
// attribute and report an error with various results if found.
|
||||||
|
if self.tcx.has_attr(item_def_id, "rustc_variance") {
|
||||||
|
let variances_of = self.tcx.variances_of(item_def_id);
|
||||||
|
span_err!(self.tcx.sess,
|
||||||
|
item.span,
|
||||||
|
E0208,
|
||||||
|
"{:?}",
|
||||||
|
variances_of);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem) { }
|
||||||
|
fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem) { }
|
||||||
|
}
|
|
@ -104,7 +104,8 @@ pub fn run_core(search_paths: SearchPaths,
|
||||||
externs: config::Externs,
|
externs: config::Externs,
|
||||||
input: Input,
|
input: Input,
|
||||||
triple: Option<String>,
|
triple: Option<String>,
|
||||||
maybe_sysroot: Option<PathBuf>) -> (clean::Crate, RenderInfo)
|
maybe_sysroot: Option<PathBuf>,
|
||||||
|
allow_warnings: bool) -> (clean::Crate, RenderInfo)
|
||||||
{
|
{
|
||||||
// Parse, resolve, and typecheck the given crate.
|
// Parse, resolve, and typecheck the given crate.
|
||||||
|
|
||||||
|
@ -119,7 +120,7 @@ pub fn run_core(search_paths: SearchPaths,
|
||||||
maybe_sysroot: maybe_sysroot,
|
maybe_sysroot: maybe_sysroot,
|
||||||
search_paths: search_paths,
|
search_paths: search_paths,
|
||||||
crate_types: vec![config::CrateTypeRlib],
|
crate_types: vec![config::CrateTypeRlib],
|
||||||
lint_opts: vec![(warning_lint, lint::Allow)],
|
lint_opts: if !allow_warnings { vec![(warning_lint, lint::Allow)] } else { vec![] },
|
||||||
lint_cap: Some(lint::Allow),
|
lint_cap: Some(lint::Allow),
|
||||||
externs: externs,
|
externs: externs,
|
||||||
target_triple: triple.unwrap_or(config::host_triple().to_string()),
|
target_triple: triple.unwrap_or(config::host_triple().to_string()),
|
||||||
|
|
|
@ -137,7 +137,6 @@ r##"<!DOCTYPE html>
|
||||||
window.rootPath = "{root_path}";
|
window.rootPath = "{root_path}";
|
||||||
window.currentCrate = "{krate}";
|
window.currentCrate = "{krate}";
|
||||||
</script>
|
</script>
|
||||||
<script src="{root_path}jquery.js"></script>
|
|
||||||
<script src="{root_path}main.js"></script>
|
<script src="{root_path}main.js"></script>
|
||||||
<script defer src="{root_path}search-index.js"></script>
|
<script defer src="{root_path}search-index.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -660,8 +660,6 @@ fn write_shared(cx: &Context,
|
||||||
// Add all the static files. These may already exist, but we just
|
// Add all the static files. These may already exist, but we just
|
||||||
// overwrite them anyway to make sure that they're fresh and up-to-date.
|
// overwrite them anyway to make sure that they're fresh and up-to-date.
|
||||||
|
|
||||||
write(cx.dst.join("jquery.js"),
|
|
||||||
include_bytes!("static/jquery-2.1.4.min.js"))?;
|
|
||||||
write(cx.dst.join("main.js"),
|
write(cx.dst.join("main.js"),
|
||||||
include_bytes!("static/main.js"))?;
|
include_bytes!("static/main.js"))?;
|
||||||
write(cx.dst.join("rustdoc.css"),
|
write(cx.dst.join("rustdoc.css"),
|
||||||
|
|
|
@ -27,11 +27,6 @@ included, and carry their own copyright notices and license terms:
|
||||||
Licensed under the SIL Open Font License, Version 1.1.
|
Licensed under the SIL Open Font License, Version 1.1.
|
||||||
See Heuristica-LICENSE.txt.
|
See Heuristica-LICENSE.txt.
|
||||||
|
|
||||||
* jQuery (jquery-2.1.4.min.js):
|
|
||||||
|
|
||||||
Copyright 2005, 2015 jQuery Foundation, Inc.
|
|
||||||
Licensed under the MIT license (see LICENSE-MIT.txt).
|
|
||||||
|
|
||||||
* rustdoc.css, main.js, and playpen.js:
|
* rustdoc.css, main.js, and playpen.js:
|
||||||
|
|
||||||
Copyright 2015 The Rust Developers.
|
Copyright 2015 The Rust Developers.
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -37,10 +37,63 @@
|
||||||
"associatedconstant",
|
"associatedconstant",
|
||||||
"union"];
|
"union"];
|
||||||
|
|
||||||
|
function hasClass(elem, className) {
|
||||||
|
if (elem && className && elem.className) {
|
||||||
|
var elemClass = elem.className;
|
||||||
|
var start = elemClass.indexOf(className);
|
||||||
|
if (start == -1) {
|
||||||
|
return false;
|
||||||
|
} else if (elemClass.length == className.length) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
if (start > 0 && elemClass[start - 1] != ' ') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var end = start + className.length;
|
||||||
|
if (end < elemClass.length && elemClass[end] != ' ') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addClass(elem, className) {
|
||||||
|
if (elem && className && !hasClass(elem, className)) {
|
||||||
|
if (elem.className && elem.className.length > 0) {
|
||||||
|
elem.className += ' ' + className;
|
||||||
|
} else {
|
||||||
|
elem.className = className;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeClass(elem, className) {
|
||||||
|
if (elem && className && elem.className) {
|
||||||
|
elem.className = (" " + elem.className + " ").replace(" " + className + " ", " ")
|
||||||
|
.trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onEach(arr, func) {
|
||||||
|
if (arr && arr.length > 0 && func) {
|
||||||
|
for (var i = 0; i < arr.length; i++) {
|
||||||
|
func(arr[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isHidden(elem) {
|
||||||
|
return (elem.offsetParent === null)
|
||||||
|
}
|
||||||
|
|
||||||
// used for special search precedence
|
// used for special search precedence
|
||||||
var TY_PRIMITIVE = itemTypes.indexOf("primitive");
|
var TY_PRIMITIVE = itemTypes.indexOf("primitive");
|
||||||
|
|
||||||
$('.js-only').removeClass('js-only');
|
onEach(document.getElementsByClassName('js-only'), function(e) {
|
||||||
|
removeClass(e, 'js-only');
|
||||||
|
});
|
||||||
|
|
||||||
function getQueryStringParams() {
|
function getQueryStringParams() {
|
||||||
var params = {};
|
var params = {};
|
||||||
|
@ -65,18 +118,28 @@
|
||||||
from = parseInt(match[1], 10);
|
from = parseInt(match[1], 10);
|
||||||
to = Math.min(50000, parseInt(match[2] || match[1], 10));
|
to = Math.min(50000, parseInt(match[2] || match[1], 10));
|
||||||
from = Math.min(from, to);
|
from = Math.min(from, to);
|
||||||
if ($('#' + from).length === 0) {
|
var elem = document.getElementById(from);
|
||||||
|
if (!elem) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ev === null) { $('#' + from)[0].scrollIntoView(); };
|
if (ev === null) {
|
||||||
$('.line-numbers span').removeClass('line-highlighted');
|
var x = document.getElementById(from);
|
||||||
|
if (x) {
|
||||||
|
x.scrollIntoView();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
onEach(document.getElementsByClassName('line-numbers'), function(e) {
|
||||||
|
onEach(e.getElementsByTagName('span'), function(i_e) {
|
||||||
|
removeClass(i_e, 'line-highlighted');
|
||||||
|
});
|
||||||
|
})
|
||||||
for (i = from; i <= to; ++i) {
|
for (i = from; i <= to; ++i) {
|
||||||
$('#' + i).addClass('line-highlighted');
|
addClass(document.getElementById(i), 'line-highlighted');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
highlightSourceLines(null);
|
highlightSourceLines(null);
|
||||||
$(window).on('hashchange', highlightSourceLines);
|
window.onhashchange = highlightSourceLines;
|
||||||
|
|
||||||
// Gets the human-readable string for the virtual-key code of the
|
// Gets the human-readable string for the virtual-key code of the
|
||||||
// given KeyboardEvent, ev.
|
// given KeyboardEvent, ev.
|
||||||
|
@ -99,23 +162,25 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleShortcut(ev) {
|
function handleShortcut(ev) {
|
||||||
if (document.activeElement.tagName == "INPUT")
|
if (document.activeElement.tagName === "INPUT")
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Don't interfere with browser shortcuts
|
// Don't interfere with browser shortcuts
|
||||||
if (ev.ctrlKey || ev.altKey || ev.metaKey)
|
if (ev.ctrlKey || ev.altKey || ev.metaKey)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
var help = document.getElementById("help");
|
||||||
switch (getVirtualKey(ev)) {
|
switch (getVirtualKey(ev)) {
|
||||||
case "Escape":
|
case "Escape":
|
||||||
if (!$("#help").hasClass("hidden")) {
|
var search = document.getElementById("search");
|
||||||
|
if (!hasClass(help, "hidden")) {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
$("#help").addClass("hidden");
|
addClass(help, "hidden");
|
||||||
$("body").removeClass("blur");
|
removeClass(document.body, "blur");
|
||||||
} else if (!$("#search").hasClass("hidden")) {
|
} else if (!hasClass(search, "hidden")) {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
$("#search").addClass("hidden");
|
addClass(search, "hidden");
|
||||||
$("#main").removeClass("hidden");
|
removeClass(document.getElementById("main"), "hidden");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -131,42 +196,76 @@
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "?":
|
case "?":
|
||||||
if (ev.shiftKey && $("#help").hasClass("hidden")) {
|
if (ev.shiftKey && hasClass(help, "hidden")) {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
$("#help").removeClass("hidden");
|
removeClass(help, "hidden");
|
||||||
$("body").addClass("blur");
|
addClass(document.body, "blur");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).on("keypress", handleShortcut);
|
document.onkeypress = handleShortcut;
|
||||||
$(document).on("keydown", handleShortcut);
|
document.onkeydown = handleShortcut;
|
||||||
$(document).on("click", function(ev) {
|
document.onclick = function(ev) {
|
||||||
if (!$(ev.target).closest("#help > div").length) {
|
if (hasClass(ev.target, 'collapse-toggle')) {
|
||||||
$("#help").addClass("hidden");
|
collapseDocs(ev.target);
|
||||||
$("body").removeClass("blur");
|
} else if (hasClass(ev.target.parentNode, 'collapse-toggle')) {
|
||||||
}
|
collapseDocs(ev.target.parentNode);
|
||||||
});
|
} else if (ev.target.tagName === 'SPAN' && hasClass(ev.target.parentNode, 'line-numbers')) {
|
||||||
|
var prev_id = 0;
|
||||||
|
|
||||||
$('.version-selector').on('change', function() {
|
function set_fragment(name) {
|
||||||
var i, match,
|
if (browserSupportsHistoryApi()) {
|
||||||
url = document.location.href,
|
history.replaceState(null, null, '#' + name);
|
||||||
stripped = '',
|
window.hashchange();
|
||||||
len = rootPath.match(/\.\.\//g).length + 1;
|
} else {
|
||||||
|
location.replace('#' + name);
|
||||||
for (i = 0; i < len; ++i) {
|
}
|
||||||
match = url.match(/\/[^\/]*$/);
|
|
||||||
if (i < len - 1) {
|
|
||||||
stripped = match[0] + stripped;
|
|
||||||
}
|
}
|
||||||
url = url.substring(0, url.length - match[0].length);
|
|
||||||
|
var cur_id = parseInt(ev.target.id, 10);
|
||||||
|
|
||||||
|
if (ev.shiftKey && prev_id) {
|
||||||
|
if (prev_id > cur_id) {
|
||||||
|
var tmp = prev_id;
|
||||||
|
prev_id = cur_id;
|
||||||
|
cur_id = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_fragment(prev_id + '-' + cur_id);
|
||||||
|
} else {
|
||||||
|
prev_id = cur_id;
|
||||||
|
|
||||||
|
set_fragment(cur_id);
|
||||||
|
}
|
||||||
|
} else if (!hasClass(document.getElementById("help"), "hidden")) {
|
||||||
|
addClass(document.getElementById("help"), "hidden");
|
||||||
|
removeClass(document.body, "blur");
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
url += '/' + $('.version-selector').val() + stripped;
|
var x = document.getElementsByClassName('version-selector');
|
||||||
|
if (x.length > 0) {
|
||||||
|
x[0].onchange = function() {
|
||||||
|
var i, match,
|
||||||
|
url = document.location.href,
|
||||||
|
stripped = '',
|
||||||
|
len = rootPath.match(/\.\.\//g).length + 1;
|
||||||
|
|
||||||
document.location.href = url;
|
for (i = 0; i < len; ++i) {
|
||||||
});
|
match = url.match(/\/[^\/]*$/);
|
||||||
|
if (i < len - 1) {
|
||||||
|
stripped = match[0] + stripped;
|
||||||
|
}
|
||||||
|
url = url.substring(0, url.length - match[0].length);
|
||||||
|
}
|
||||||
|
|
||||||
|
url += '/' + document.getElementsByClassName('version-selector')[0].value + stripped;
|
||||||
|
|
||||||
|
document.location.href = url;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A function to compute the Levenshtein distance between two strings
|
* A function to compute the Levenshtein distance between two strings
|
||||||
|
@ -214,8 +313,8 @@
|
||||||
// but only if the input bar is empty. This avoid the obnoxious issue
|
// but only if the input bar is empty. This avoid the obnoxious issue
|
||||||
// where you start trying to do a search, and the index loads, and
|
// where you start trying to do a search, and the index loads, and
|
||||||
// suddenly your search is gone!
|
// suddenly your search is gone!
|
||||||
if ($(".search-input")[0].value === "") {
|
if (document.getElementsByClassName("search-input")[0].value === "") {
|
||||||
$(".search-input")[0].value = params.search || '';
|
document.getElementsByClassName("search-input")[0].value = params.search || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -484,7 +583,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function getQuery() {
|
function getQuery() {
|
||||||
var matches, type, query, raw = $('.search-input').val();
|
var matches, type, query, raw =
|
||||||
|
document.getElementsByClassName('search-input')[0].value;
|
||||||
query = raw;
|
query = raw;
|
||||||
|
|
||||||
matches = query.match(/^(fn|mod|struct|enum|trait|type|const|macro)\s*:\s*/i);
|
matches = query.match(/^(fn|mod|struct|enum|trait|type|const|macro)\s*:\s*/i);
|
||||||
|
@ -502,54 +602,92 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function initSearchNav() {
|
function initSearchNav() {
|
||||||
var hoverTimeout, $results = $('.search-results .result');
|
var hoverTimeout;
|
||||||
|
|
||||||
$results.on('click', function() {
|
var click_func = function(e) {
|
||||||
var dst = $(this).find('a')[0];
|
var el = e.target;
|
||||||
|
// to retrieve the real "owner" of the event.
|
||||||
|
while (el.tagName !== 'TR') {
|
||||||
|
el = el.parentNode;
|
||||||
|
}
|
||||||
|
var dst = e.target.getElementsByTagName('a');
|
||||||
|
if (dst.length < 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dst = dst[0];
|
||||||
if (window.location.pathname === dst.pathname) {
|
if (window.location.pathname === dst.pathname) {
|
||||||
$('#search').addClass('hidden');
|
addClass(document.getElementById('search'), 'hidden');
|
||||||
$('#main').removeClass('hidden');
|
removeClass(document.getElementById('main'), 'hidden');
|
||||||
document.location.href = dst.href;
|
document.location.href = dst.href;
|
||||||
}
|
}
|
||||||
}).on('mouseover', function() {
|
};
|
||||||
var $el = $(this);
|
var mouseover_func = function(e) {
|
||||||
|
var el = e.target;
|
||||||
|
// to retrieve the real "owner" of the event.
|
||||||
|
while (el.tagName !== 'TR') {
|
||||||
|
el = el.parentNode;
|
||||||
|
}
|
||||||
clearTimeout(hoverTimeout);
|
clearTimeout(hoverTimeout);
|
||||||
hoverTimeout = setTimeout(function() {
|
hoverTimeout = setTimeout(function() {
|
||||||
$results.removeClass('highlighted');
|
onEach(document.getElementsByClassName('search-results'), function(e) {
|
||||||
$el.addClass('highlighted');
|
onEach(e.getElementsByClassName('result'), function(i_e) {
|
||||||
|
removeClass(i_e, 'highlighted');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
addClass(el, 'highlighted');
|
||||||
}, 20);
|
}, 20);
|
||||||
|
};
|
||||||
|
onEach(document.getElementsByClassName('search-results'), function(e) {
|
||||||
|
onEach(e.getElementsByClassName('result'), function(i_e) {
|
||||||
|
i_e.onclick = click_func;
|
||||||
|
i_e.onmouseover = mouseover_func;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).off('keydown.searchnav');
|
var search_input = document.getElementsByClassName('search-input')[0];
|
||||||
$(document).on('keydown.searchnav', function(e) {
|
search_input.onkeydown = null;
|
||||||
var $active = $results.filter('.highlighted');
|
search_input.onkeydown = function(e) {
|
||||||
|
var actives = [];
|
||||||
|
onEach(document.getElementsByClassName('search-results'), function(e) {
|
||||||
|
onEach(document.getElementsByClassName('highlighted'), function(e) {
|
||||||
|
actives.push(e);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
if (e.which === 38) { // up
|
if (e.which === 38) { // up
|
||||||
if (!$active.length || !$active.prev()) {
|
if (!actives.length || !actives[0].previousElementSibling) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$active.prev().addClass('highlighted');
|
addClass(actives[0].previousElementSibling, 'highlighted');
|
||||||
$active.removeClass('highlighted');
|
removeClass(actives[0], 'highlighted');
|
||||||
} else if (e.which === 40) { // down
|
} else if (e.which === 40) { // down
|
||||||
if (!$active.length) {
|
if (!actives.length) {
|
||||||
$results.first().addClass('highlighted');
|
var results = document.getElementsByClassName('search-results');
|
||||||
} else if ($active.next().length) {
|
if (results.length > 0) {
|
||||||
$active.next().addClass('highlighted');
|
var res = results[0].getElementsByClassName('result');
|
||||||
$active.removeClass('highlighted');
|
if (res.length > 0) {
|
||||||
|
addClass(res[0], 'highlighted');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (actives[0].nextElementSibling) {
|
||||||
|
addClass(actives[0].nextElementSibling, 'highlighted');
|
||||||
|
removeClass(actives[0], 'highlighted');
|
||||||
}
|
}
|
||||||
} else if (e.which === 13) { // return
|
} else if (e.which === 13) { // return
|
||||||
if ($active.length) {
|
if (actives.length) {
|
||||||
document.location.href = $active.find('a').prop('href');
|
document.location.href = actives[0].getElementsByTagName('a')[0].href;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (actives.length > 0) {
|
||||||
$active.removeClass('highlighted');
|
removeClass(actives[0], 'highlighted');
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function escape(content) {
|
function escape(content) {
|
||||||
return $('<h1/>').text(content).html();
|
let h1 = document.createElement('h1');
|
||||||
|
h1.textContent = content;
|
||||||
|
return h1.innerHTML;
|
||||||
}
|
}
|
||||||
|
|
||||||
function showResults(results) {
|
function showResults(results) {
|
||||||
|
@ -619,10 +757,19 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
output += "</p>";
|
output += "</p>";
|
||||||
$('#main.content').addClass('hidden');
|
addClass(document.getElementById('main'), 'hidden');
|
||||||
$('#search.content').removeClass('hidden').html(output);
|
var search = document.getElementById('search');
|
||||||
$('#search .desc').width($('#search').width() - 40 -
|
removeClass(search, 'hidden');
|
||||||
$('#search td:first-child').first().width());
|
search.innerHTML = output;
|
||||||
|
var tds = search.getElementsByTagName('td');
|
||||||
|
var td_width = 0;
|
||||||
|
if (tds.length > 0) {
|
||||||
|
td_width = tds[0].offsetWidth;
|
||||||
|
}
|
||||||
|
var width = search.offsetWidth - 40 - td_width;
|
||||||
|
onEach(search.getElementsByClassName('desc'), function(e) {
|
||||||
|
e.style.width = width + 'px';
|
||||||
|
});
|
||||||
initSearchNav();
|
initSearchNav();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -645,17 +792,15 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update document title to maintain a meaningful browser history
|
// Update document title to maintain a meaningful browser history
|
||||||
$(document).prop("title", "Results for " + query.query + " - Rust");
|
document.title = "Results for " + query.query + " - Rust";
|
||||||
|
|
||||||
// Because searching is incremental by character, only the most
|
// Because searching is incremental by character, only the most
|
||||||
// recent search query is added to the browser history.
|
// recent search query is added to the browser history.
|
||||||
if (browserSupportsHistoryApi()) {
|
if (browserSupportsHistoryApi()) {
|
||||||
if (!history.state && !params.search) {
|
if (!history.state && !params.search) {
|
||||||
history.pushState(query, "", "?search=" +
|
history.pushState(query, "", "?search=" + encodeURIComponent(query.raw));
|
||||||
encodeURIComponent(query.raw));
|
|
||||||
} else {
|
} else {
|
||||||
history.replaceState(query, "", "?search=" +
|
history.replaceState(query, "", "?search=" + encodeURIComponent(query.raw));
|
||||||
encodeURIComponent(query.raw));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -744,49 +889,68 @@
|
||||||
|
|
||||||
function startSearch() {
|
function startSearch() {
|
||||||
var searchTimeout;
|
var searchTimeout;
|
||||||
$(".search-input").on("keyup input",function() {
|
var callback = function() {
|
||||||
|
var search_input = document.getElementsByClassName('search-input');
|
||||||
|
if (search_input.length < 1) { return; }
|
||||||
|
search_input = search_input[0];
|
||||||
clearTimeout(searchTimeout);
|
clearTimeout(searchTimeout);
|
||||||
if ($(this).val().length === 0) {
|
if (search_input.value.length === 0) {
|
||||||
if (browserSupportsHistoryApi()) {
|
if (browserSupportsHistoryApi()) {
|
||||||
history.replaceState("", "std - Rust", "?search=");
|
history.replaceState("", "std - Rust", "?search=");
|
||||||
}
|
}
|
||||||
$('#main.content').removeClass('hidden');
|
var main = document.getElementById('main');
|
||||||
$('#search.content').addClass('hidden');
|
if (hasClass(main, 'content')) {
|
||||||
|
removeClass(main, 'hidden');
|
||||||
|
}
|
||||||
|
var search_c = document.getElementById('search');
|
||||||
|
if (hasClass(search_c, 'content')) {
|
||||||
|
addClass(search_c, 'hidden');
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
searchTimeout = setTimeout(search, 500);
|
searchTimeout = setTimeout(search, 500);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
$('.search-form').on('submit', function(e){
|
var search_input = document.getElementsByClassName("search-input")[0];
|
||||||
|
search_input.onkeyup = callback;
|
||||||
|
search_input.oninput = callback;
|
||||||
|
document.getElementsByClassName("search-form")[0].onsubmit = function(e){
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
clearTimeout(searchTimeout);
|
clearTimeout(searchTimeout);
|
||||||
search();
|
search();
|
||||||
});
|
};
|
||||||
$('.search-input').on('change paste', function(e) {
|
search_input.onchange = function(e) {
|
||||||
// Do NOT e.preventDefault() here. It will prevent pasting.
|
// Do NOT e.preventDefault() here. It will prevent pasting.
|
||||||
clearTimeout(searchTimeout);
|
clearTimeout(searchTimeout);
|
||||||
// zero-timeout necessary here because at the time of event handler execution the
|
// zero-timeout necessary here because at the time of event handler execution the
|
||||||
// pasted content is not in the input field yet. Shouldn’t make any difference for
|
// pasted content is not in the input field yet. Shouldn’t make any difference for
|
||||||
// change, though.
|
// change, though.
|
||||||
setTimeout(search, 0);
|
setTimeout(search, 0);
|
||||||
});
|
};
|
||||||
|
search_input.onpaste = search_input.onchange;
|
||||||
|
|
||||||
// Push and pop states are used to add search results to the browser
|
// Push and pop states are used to add search results to the browser
|
||||||
// history.
|
// history.
|
||||||
if (browserSupportsHistoryApi()) {
|
if (browserSupportsHistoryApi()) {
|
||||||
// Store the previous <title> so we can revert back to it later.
|
// Store the previous <title> so we can revert back to it later.
|
||||||
var previousTitle = $(document).prop("title");
|
var previousTitle = document.title;
|
||||||
|
|
||||||
$(window).on('popstate', function(e) {
|
window.onpopstate = function(e) {
|
||||||
var params = getQueryStringParams();
|
var params = getQueryStringParams();
|
||||||
// When browsing back from search results the main page
|
// When browsing back from search results the main page
|
||||||
// visibility must be reset.
|
// visibility must be reset.
|
||||||
if (!params.search) {
|
if (!params.search) {
|
||||||
$('#main.content').removeClass('hidden');
|
var main = document.getElementById('main');
|
||||||
$('#search.content').addClass('hidden');
|
if (hasClass(main, 'content')) {
|
||||||
|
removeClass(main, 'hidden');
|
||||||
|
}
|
||||||
|
var search = document.getElementById('search');
|
||||||
|
if (hasClass(main, 'content')) {
|
||||||
|
addClass(main, 'hidden');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Revert to the previous title manually since the History
|
// Revert to the previous title manually since the History
|
||||||
// API ignores the title parameter.
|
// API ignores the title parameter.
|
||||||
$(document).prop("title", previousTitle);
|
document.title = previousTitle;
|
||||||
// When browsing forward to search results the previous
|
// When browsing forward to search results the previous
|
||||||
// search will be repeated, so the currentResults are
|
// search will be repeated, so the currentResults are
|
||||||
// cleared to ensure the search is successful.
|
// cleared to ensure the search is successful.
|
||||||
|
@ -795,14 +959,14 @@
|
||||||
// perform the search. This will empty the bar if there's
|
// perform the search. This will empty the bar if there's
|
||||||
// nothing there, which lets you really go back to a
|
// nothing there, which lets you really go back to a
|
||||||
// previous state with nothing in the bar.
|
// previous state with nothing in the bar.
|
||||||
$('.search-input').val(params.search);
|
document.getElementsByClassName('search-input')[0].value = params.search;
|
||||||
// Some browsers fire 'onpopstate' for every page load
|
// Some browsers fire 'onpopstate' for every page load
|
||||||
// (Chrome), while others fire the event only when actually
|
// (Chrome), while others fire the event only when actually
|
||||||
// popping a state (Firefox), which is why search() is
|
// popping a state (Firefox), which is why search() is
|
||||||
// called both here and at the end of the startSearch()
|
// called both here and at the end of the startSearch()
|
||||||
// function.
|
// function.
|
||||||
search();
|
search();
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
search();
|
search();
|
||||||
}
|
}
|
||||||
|
@ -812,10 +976,12 @@
|
||||||
|
|
||||||
// Draw a convenient sidebar of known crates if we have a listing
|
// Draw a convenient sidebar of known crates if we have a listing
|
||||||
if (rootPath === '../') {
|
if (rootPath === '../') {
|
||||||
var sidebar = $('.sidebar');
|
var sidebar = document.getElementsByClassName('sidebar')[0];
|
||||||
var div = $('<div>').attr('class', 'block crate');
|
var div = document.createElement('div');
|
||||||
div.append($('<h3>').text('Crates'));
|
div.className = 'block crate';
|
||||||
var ul = $('<ul>').appendTo(div);
|
div.innerHTML = '<h3>Crates</h3>';
|
||||||
|
var ul = document.createElement('ul');
|
||||||
|
div.appendChild(ul);
|
||||||
|
|
||||||
var crates = [];
|
var crates = [];
|
||||||
for (var crate in rawSearchIndex) {
|
for (var crate in rawSearchIndex) {
|
||||||
|
@ -828,12 +994,17 @@
|
||||||
if (crates[i] === window.currentCrate) {
|
if (crates[i] === window.currentCrate) {
|
||||||
klass += ' current';
|
klass += ' current';
|
||||||
}
|
}
|
||||||
var link = $('<a>', {'href': '../' + crates[i] + '/index.html',
|
var link = document.createElement('a');
|
||||||
'title': rawSearchIndex[crates[i]].doc,
|
link.href = '../' + crates[i] + '/index.html';
|
||||||
'class': klass}).text(crates[i]);
|
link.title = rawSearchIndex[crates[i]].doc;
|
||||||
ul.append($('<li>').append(link));
|
link.className = klass;
|
||||||
|
link.textContent = crates[i];
|
||||||
|
|
||||||
|
var li = document.createElement('li');
|
||||||
|
li.appendChild(link);
|
||||||
|
ul.appendChild(li);
|
||||||
}
|
}
|
||||||
sidebar.append(div);
|
sidebar.appendChild(div);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -841,16 +1012,19 @@
|
||||||
|
|
||||||
// delayed sidebar rendering.
|
// delayed sidebar rendering.
|
||||||
function initSidebarItems(items) {
|
function initSidebarItems(items) {
|
||||||
var sidebar = $('.sidebar');
|
var sidebar = document.getElementsByClassName('sidebar')[0];
|
||||||
var current = window.sidebarCurrent;
|
var current = window.sidebarCurrent;
|
||||||
|
|
||||||
function block(shortty, longty) {
|
function block(shortty, longty) {
|
||||||
var filtered = items[shortty];
|
var filtered = items[shortty];
|
||||||
if (!filtered) { return; }
|
if (!filtered) { return; }
|
||||||
|
|
||||||
var div = $('<div>').attr('class', 'block ' + shortty);
|
var div = document.createElement('div');
|
||||||
div.append($('<h3>').text(longty));
|
div.className = 'block ' + shortty;
|
||||||
var ul = $('<ul>').appendTo(div);
|
var h3 = document.createElement('h3');
|
||||||
|
h3.textContent = longty;
|
||||||
|
div.appendChild(h3);
|
||||||
|
var ul = document.createElement('ul');
|
||||||
|
|
||||||
for (var i = 0; i < filtered.length; ++i) {
|
for (var i = 0; i < filtered.length; ++i) {
|
||||||
var item = filtered[i];
|
var item = filtered[i];
|
||||||
|
@ -867,12 +1041,17 @@
|
||||||
} else {
|
} else {
|
||||||
path = shortty + '.' + name + '.html';
|
path = shortty + '.' + name + '.html';
|
||||||
}
|
}
|
||||||
var link = $('<a>', {'href': current.relpath + path,
|
var link = document.createElement('a');
|
||||||
'title': desc,
|
link.href = current.relpath + path;
|
||||||
'class': klass}).text(name);
|
link.title = desc;
|
||||||
ul.append($('<li>').append(link));
|
link.className = klass;
|
||||||
|
link.textContent = name;
|
||||||
|
var li = document.createElement('li');
|
||||||
|
li.appendChild(link);
|
||||||
|
ul.appendChild(li);
|
||||||
}
|
}
|
||||||
sidebar.append(div);
|
div.appendChild(ul);
|
||||||
|
sidebar.appendChild(div);
|
||||||
}
|
}
|
||||||
|
|
||||||
block("primitive", "Primitive Types");
|
block("primitive", "Primitive Types");
|
||||||
|
@ -890,21 +1069,25 @@
|
||||||
window.initSidebarItems = initSidebarItems;
|
window.initSidebarItems = initSidebarItems;
|
||||||
|
|
||||||
window.register_implementors = function(imp) {
|
window.register_implementors = function(imp) {
|
||||||
var list = $('#implementors-list');
|
var list = document.getElementById('implementors-list');
|
||||||
var libs = Object.getOwnPropertyNames(imp);
|
var libs = Object.getOwnPropertyNames(imp);
|
||||||
for (var i = 0; i < libs.length; ++i) {
|
for (var i = 0; i < libs.length; ++i) {
|
||||||
if (libs[i] === currentCrate) { continue; }
|
if (libs[i] === currentCrate) { continue; }
|
||||||
var structs = imp[libs[i]];
|
var structs = imp[libs[i]];
|
||||||
for (var j = 0; j < structs.length; ++j) {
|
for (var j = 0; j < structs.length; ++j) {
|
||||||
var code = $('<code>').append(structs[j]);
|
var code = document.createElement('code');
|
||||||
$.each(code.find('a'), function(idx, a) {
|
code.innerHTML = structs[j];
|
||||||
var href = $(a).attr('href');
|
|
||||||
|
var x = code.getElementsByTagName('a');
|
||||||
|
for (var i = 0; i < x.length; i++) {
|
||||||
|
var href = x[i].href;
|
||||||
if (href && href.indexOf('http') !== 0) {
|
if (href && href.indexOf('http') !== 0) {
|
||||||
$(a).attr('href', rootPath + href);
|
x[i].href = rootPath + href;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
var li = $('<li>').append(code);
|
var li = document.createElement('li');
|
||||||
list.append(li);
|
li.appendChild(code);
|
||||||
|
list.appendChild(li);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -922,146 +1105,186 @@
|
||||||
return "\u2212"; // "\u2212" is '−' minus sign
|
return "\u2212"; // "\u2212" is '−' minus sign
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleAllDocs() {
|
function onEveryMatchingChild(elem, className, func) {
|
||||||
var toggle = $("#toggle-all-docs");
|
if (elem && className && func) {
|
||||||
if (toggle.hasClass("will-expand")) {
|
for (var i = 0; i < elem.childNodes.length; i++) {
|
||||||
toggle.removeClass("will-expand");
|
if (hasClass(elem.childNodes[i], className)) {
|
||||||
toggle.children(".inner").text(labelForToggleButton(false));
|
func(elem.childNodes[i]);
|
||||||
toggle.attr("title", "collapse all docs");
|
|
||||||
$(".docblock").show();
|
|
||||||
$(".toggle-label").hide();
|
|
||||||
$(".toggle-wrapper").removeClass("collapsed");
|
|
||||||
$(".collapse-toggle").children(".inner").text(labelForToggleButton(false));
|
|
||||||
} else {
|
|
||||||
toggle.addClass("will-expand");
|
|
||||||
toggle.children(".inner").text(labelForToggleButton(true));
|
|
||||||
toggle.attr("title", "expand all docs");
|
|
||||||
$(".docblock").hide();
|
|
||||||
$(".toggle-label").show();
|
|
||||||
$(".toggle-wrapper").addClass("collapsed");
|
|
||||||
$(".collapse-toggle").children(".inner").text(labelForToggleButton(true));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function collapseDocs(toggle, animate) {
|
|
||||||
var relatedDoc = toggle.parent().next();
|
|
||||||
if (relatedDoc.is(".stability")) {
|
|
||||||
relatedDoc = relatedDoc.next();
|
|
||||||
}
|
|
||||||
if (relatedDoc.is(".docblock")) {
|
|
||||||
if (relatedDoc.is(":visible")) {
|
|
||||||
if (animate === true) {
|
|
||||||
relatedDoc.slideUp({
|
|
||||||
duration: 'fast',
|
|
||||||
easing: 'linear',
|
|
||||||
complete: function() {
|
|
||||||
toggle.children(".toggle-label").fadeIn();
|
|
||||||
toggle.parent(".toggle-wrapper").addClass("collapsed");
|
|
||||||
toggle.children(".inner").text(labelForToggleButton(true));
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
relatedDoc.hide();
|
onEveryMatchingChild(elem.childNodes[i], className, func);
|
||||||
toggle.children(".toggle-label").show();
|
|
||||||
toggle.parent(".toggle-wrapper").addClass("collapsed");
|
|
||||||
toggle.children(".inner").text(labelForToggleButton(true));
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
relatedDoc.slideDown({duration: 'fast', easing: 'linear'});
|
|
||||||
toggle.parent(".toggle-wrapper").removeClass("collapsed");
|
|
||||||
toggle.children(".inner").text(labelForToggleButton(false));
|
|
||||||
toggle.children(".toggle-label").hide();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$("#toggle-all-docs").on("click", toggleAllDocs);
|
function toggleAllDocs() {
|
||||||
|
var toggle = document.getElementById("toggle-all-docs");
|
||||||
|
if (hasClass(toggle, "will-expand")) {
|
||||||
|
removeClass(toggle, "will-expand");
|
||||||
|
onEveryMatchingChild(toggle, "inner", function(e) {
|
||||||
|
e.innerHTML = labelForToggleButton(false);
|
||||||
|
});
|
||||||
|
toggle.title = "collapse all docs";
|
||||||
|
onEach(document.getElementsByClassName("docblock"), function(e) {
|
||||||
|
e.style.display = 'block';
|
||||||
|
});
|
||||||
|
onEach(document.getElementsByClassName("toggle-label"), function(e) {
|
||||||
|
e.style.display = 'none';
|
||||||
|
});
|
||||||
|
onEach(document.getElementsByClassName("toggle-wrapper"), function(e) {
|
||||||
|
removeClass(e, "collapsed");
|
||||||
|
});
|
||||||
|
onEach(document.getElementsByClassName("collapse-toggle"), function(e) {
|
||||||
|
onEveryMatchingChild(e, "inner", function(i_e) {
|
||||||
|
i_e.innerHTML = labelForToggleButton(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
addClass(toggle, "will-expand");
|
||||||
|
onEveryMatchingChild(toggle, "inner", function(e) {
|
||||||
|
e.innerHTML = labelForToggleButton(true);
|
||||||
|
});
|
||||||
|
toggle.title = "expand all docs";
|
||||||
|
onEach(document.getElementsByClassName("docblock"), function(e) {
|
||||||
|
e.style.display = 'none';
|
||||||
|
});
|
||||||
|
onEach(document.getElementsByClassName("toggle-label"), function(e) {
|
||||||
|
e.style.display = 'inline-block';
|
||||||
|
});
|
||||||
|
onEach(document.getElementsByClassName("toggle-wrapper"), function(e) {
|
||||||
|
addClass(e, "collapsed");
|
||||||
|
});
|
||||||
|
onEach(document.getElementsByClassName("collapse-toggle"), function(e) {
|
||||||
|
onEveryMatchingChild(e, "inner", function(i_e) {
|
||||||
|
i_e.innerHTML = labelForToggleButton(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$(document).on("click", ".collapse-toggle", function() {
|
function collapseDocs(toggle) {
|
||||||
collapseDocs($(this), true)
|
if (!toggle || !toggle.parentNode) {
|
||||||
});
|
return;
|
||||||
|
}
|
||||||
$(function() {
|
var relatedDoc = toggle.parentNode.nextElementSibling;
|
||||||
var toggle = $("<a/>", {'href': 'javascript:void(0)', 'class': 'collapse-toggle'})
|
if (hasClass(relatedDoc, "stability")) {
|
||||||
.html("[<span class='inner'></span>]");
|
relatedDoc = relatedDoc.nextElementSibling;
|
||||||
toggle.children(".inner").text(labelForToggleButton(false));
|
}
|
||||||
|
if (hasClass(relatedDoc, "docblock")) {
|
||||||
$(".method, .impl-items > .associatedconstant").each(function() {
|
if (!isHidden(relatedDoc)) {
|
||||||
if ($(this).next().is(".docblock") ||
|
relatedDoc.style.display = 'none';
|
||||||
($(this).next().is(".stability") && $(this).next().next().is(".docblock"))) {
|
onEach(toggle.childNodes, function(e) {
|
||||||
$(this).children().last().after(toggle.clone());
|
if (hasClass(e, 'toggle-label')) {
|
||||||
}
|
e.style.display = 'inline-block';
|
||||||
});
|
}
|
||||||
|
if (hasClass(e, 'inner')) {
|
||||||
var mainToggle =
|
e.innerHTML = labelForToggleButton(true);
|
||||||
$(toggle.clone()).append(
|
}
|
||||||
$('<span/>', {'class': 'toggle-label'})
|
});
|
||||||
.css('display', 'none')
|
addClass(toggle.parentNode, 'collapsed');
|
||||||
.html(' Expand description'));
|
|
||||||
var wrapper = $("<div class='toggle-wrapper'>").append(mainToggle);
|
|
||||||
$("#main > .docblock").before(wrapper);
|
|
||||||
|
|
||||||
$(".docblock.autohide").each(function() {
|
|
||||||
var wrap = $(this).prev();
|
|
||||||
if (wrap.is(".toggle-wrapper")) {
|
|
||||||
var toggle = wrap.children().first();
|
|
||||||
if ($(this).children().first().is("h3")) {
|
|
||||||
toggle.children(".toggle-label")
|
|
||||||
.text(" Show " + $(this).children().first().text());
|
|
||||||
}
|
|
||||||
$(this).hide();
|
|
||||||
wrap.addClass("collapsed");
|
|
||||||
toggle.children(".inner").text(labelForToggleButton(true));
|
|
||||||
toggle.children(".toggle-label").show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var mainToggle =
|
|
||||||
$(toggle).append(
|
|
||||||
$('<span/>', {'class': 'toggle-label'})
|
|
||||||
.css('display', 'none')
|
|
||||||
.html(' Expand attributes'));
|
|
||||||
var wrapper = $("<div class='toggle-wrapper toggle-attributes'>").append(mainToggle);
|
|
||||||
$("#main > pre > .attributes").each(function() {
|
|
||||||
$(this).before(wrapper);
|
|
||||||
collapseDocs($($(this).prev().children()[0]), false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$('pre.line-numbers').on('click', 'span', function() {
|
|
||||||
var prev_id = 0;
|
|
||||||
|
|
||||||
function set_fragment(name) {
|
|
||||||
if (browserSupportsHistoryApi()) {
|
|
||||||
history.replaceState(null, null, '#' + name);
|
|
||||||
$(window).trigger('hashchange');
|
|
||||||
} else {
|
} else {
|
||||||
location.replace('#' + name);
|
relatedDoc.style.display = 'block';
|
||||||
|
removeClass(toggle.parentNode, 'collapsed');
|
||||||
|
onEach(toggle.childNodes, function(e) {
|
||||||
|
if (hasClass(e, 'toggle-label')) {
|
||||||
|
e.style.display = 'none';
|
||||||
|
}
|
||||||
|
if (hasClass(e, 'inner')) {
|
||||||
|
e.innerHTML = labelForToggleButton(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return function(ev) {
|
var x = document.getElementById('toggle-all-docs');
|
||||||
var cur_id = parseInt(ev.target.id, 10);
|
if (x) {
|
||||||
|
x.onclick = toggleAllDocs;
|
||||||
|
}
|
||||||
|
|
||||||
if (ev.shiftKey && prev_id) {
|
function insertAfter(newNode, referenceNode) {
|
||||||
if (prev_id > cur_id) {
|
referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
|
||||||
var tmp = prev_id;
|
}
|
||||||
prev_id = cur_id;
|
|
||||||
cur_id = tmp;
|
var toggle = document.createElement('a');
|
||||||
|
toggle.href = 'javascript:void(0)';
|
||||||
|
toggle.className = 'collapse-toggle';
|
||||||
|
toggle.innerHTML = "[<span class='inner'>"+labelForToggleButton(false)+"</span>]";
|
||||||
|
|
||||||
|
var func = function(e) {
|
||||||
|
var next = e.nextElementSibling;
|
||||||
|
if (!next) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (hasClass(next, 'docblock') ||
|
||||||
|
(hasClass(next, 'stability') &&
|
||||||
|
hasClass(next.nextElementSibling, 'docblock'))) {
|
||||||
|
insertAfter(toggle.cloneNode(true), e.childNodes[e.childNodes.length - 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onEach(document.getElementsByClassName('method'), func);
|
||||||
|
onEach(document.getElementsByClassName('impl-items'), function(e) {
|
||||||
|
onEach(e.getElementsByClassName('associatedconstant'), func);
|
||||||
|
});
|
||||||
|
|
||||||
|
var span = document.createElement('span');
|
||||||
|
span.className = 'toggle-label';
|
||||||
|
span.style.display = 'none';
|
||||||
|
span.innerHTML = ' Expand description';
|
||||||
|
|
||||||
|
var mainToggle = toggle.cloneNode(true);
|
||||||
|
mainToggle.appendChild(span);
|
||||||
|
|
||||||
|
var wrapper = document.createElement('div');
|
||||||
|
wrapper.className = 'toggle-wrapper';
|
||||||
|
wrapper.appendChild(mainToggle);
|
||||||
|
|
||||||
|
onEach(document.getElementById('main').getElementsByClassName('docblock'), function(e) {
|
||||||
|
if (e.parentNode.id === "main") {
|
||||||
|
e.parentNode.insertBefore(wrapper, e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onEach(document.getElementsByClassName('docblock'), function(e) {
|
||||||
|
if (hasClass(e, 'autohide')) {
|
||||||
|
var wrap = e.previousElementSibling;
|
||||||
|
if (wrap && hasClass(wrap, 'toggle-wrapper')) {
|
||||||
|
var toggle = wrap.childNodes[0];
|
||||||
|
if (e.childNodes[0].tagName === 'H3') {
|
||||||
|
onEach(toggle.getElementsByClassName('toggle-label'), function(i_e) {
|
||||||
|
i_e.innerHTML = " Show " + e.childNodes[0].innerHTML;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
e.style.display = 'none';
|
||||||
set_fragment(prev_id + '-' + cur_id);
|
addClass(wrap, 'collapsed');
|
||||||
} else {
|
onEach(toggle.getElementsByClassName('inner'), function(e) {
|
||||||
prev_id = cur_id;
|
e.innerHTML = labelForToggleButton(true);
|
||||||
|
});
|
||||||
set_fragment(cur_id);
|
onEach(toggle.getElementsByClassName('toggle-label'), function(e) {
|
||||||
|
e.style.display = 'block';
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}());
|
})
|
||||||
|
|
||||||
|
var span = document.createElement('span');
|
||||||
|
span.className = 'toggle-label';
|
||||||
|
span.style.display = 'none';
|
||||||
|
span.innerHTML = ' Expand attributes';
|
||||||
|
toggle.appendChild(span);
|
||||||
|
|
||||||
|
var wrapper = document.createElement('div');
|
||||||
|
wrapper.className = 'toggle-wrapper toggle-attributes';
|
||||||
|
wrapper.appendChild(toggle);
|
||||||
|
onEach(document.getElementById('main').getElementsByTagName('pre'), function(e) {
|
||||||
|
onEach(e.getElementsByClassName('attributes'), function(i_e) {
|
||||||
|
i_e.parentNode.insertBefore(wrapper, i_e);
|
||||||
|
collapseDocs(i_e.previousSibling.childNodes[0]);
|
||||||
|
});
|
||||||
|
});
|
||||||
}());
|
}());
|
||||||
|
|
||||||
// Sets the focus on the search bar at the top of the page
|
// Sets the focus on the search bar at the top of the page
|
||||||
function focusSearchBar() {
|
function focusSearchBar() {
|
||||||
$('.search-input').focus();
|
document.getElementsByClassName('search-input')[0].focus();
|
||||||
}
|
}
|
||||||
|
|
|
@ -173,6 +173,7 @@ pub fn opts() -> Vec<RustcOptGroup> {
|
||||||
or `#![doc(html_playground_url=...)]`",
|
or `#![doc(html_playground_url=...)]`",
|
||||||
"URL")),
|
"URL")),
|
||||||
unstable(optflag("", "enable-commonmark", "to enable commonmark doc rendering/testing")),
|
unstable(optflag("", "enable-commonmark", "to enable commonmark doc rendering/testing")),
|
||||||
|
unstable(optflag("", "display-warnings", "to print code warnings when testing doc")),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,14 +281,16 @@ pub fn main_args(args: &[String]) -> isize {
|
||||||
let crate_name = matches.opt_str("crate-name");
|
let crate_name = matches.opt_str("crate-name");
|
||||||
let playground_url = matches.opt_str("playground-url");
|
let playground_url = matches.opt_str("playground-url");
|
||||||
let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from);
|
let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from);
|
||||||
|
let display_warnings = matches.opt_present("display-warnings");
|
||||||
|
|
||||||
match (should_test, markdown_input) {
|
match (should_test, markdown_input) {
|
||||||
(true, true) => {
|
(true, true) => {
|
||||||
return markdown::test(input, cfgs, libs, externs, test_args, maybe_sysroot, render_type)
|
return markdown::test(input, cfgs, libs, externs, test_args, maybe_sysroot, render_type,
|
||||||
|
display_warnings)
|
||||||
}
|
}
|
||||||
(true, false) => {
|
(true, false) => {
|
||||||
return test::run(input, cfgs, libs, externs, test_args, crate_name, maybe_sysroot,
|
return test::run(input, cfgs, libs, externs, test_args, crate_name, maybe_sysroot,
|
||||||
render_type)
|
render_type, display_warnings)
|
||||||
}
|
}
|
||||||
(false, true) => return markdown::render(input,
|
(false, true) => return markdown::render(input,
|
||||||
output.unwrap_or(PathBuf::from("doc")),
|
output.unwrap_or(PathBuf::from("doc")),
|
||||||
|
@ -389,13 +392,15 @@ where R: 'static + Send, F: 'static + Send + FnOnce(Output) -> R {
|
||||||
|
|
||||||
let cr = PathBuf::from(cratefile);
|
let cr = PathBuf::from(cratefile);
|
||||||
info!("starting to run rustc");
|
info!("starting to run rustc");
|
||||||
|
let display_warnings = matches.opt_present("display-warnings");
|
||||||
|
|
||||||
let (tx, rx) = channel();
|
let (tx, rx) = channel();
|
||||||
rustc_driver::monitor(move || {
|
rustc_driver::monitor(move || {
|
||||||
use rustc::session::config::Input;
|
use rustc::session::config::Input;
|
||||||
|
|
||||||
let (mut krate, renderinfo) =
|
let (mut krate, renderinfo) =
|
||||||
core::run_core(paths, cfgs, externs, Input::File(cr), triple, maybe_sysroot);
|
core::run_core(paths, cfgs, externs, Input::File(cr), triple, maybe_sysroot,
|
||||||
|
display_warnings);
|
||||||
|
|
||||||
info!("finished with rustc");
|
info!("finished with rustc");
|
||||||
|
|
||||||
|
|
|
@ -150,7 +150,7 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
|
||||||
/// Run any tests/code examples in the markdown file `input`.
|
/// Run any tests/code examples in the markdown file `input`.
|
||||||
pub fn test(input: &str, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
|
pub fn test(input: &str, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
|
||||||
mut test_args: Vec<String>, maybe_sysroot: Option<PathBuf>,
|
mut test_args: Vec<String>, maybe_sysroot: Option<PathBuf>,
|
||||||
render_type: RenderType) -> isize {
|
render_type: RenderType, display_warnings: bool) -> isize {
|
||||||
let input_str = match load_string(input) {
|
let input_str = match load_string(input) {
|
||||||
Ok(s) => s,
|
Ok(s) => s,
|
||||||
Err(LoadStringError::ReadFail) => return 1,
|
Err(LoadStringError::ReadFail) => return 1,
|
||||||
|
@ -166,6 +166,7 @@ pub fn test(input: &str, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
|
||||||
old_find_testable_code(&input_str, &mut collector, DUMMY_SP);
|
old_find_testable_code(&input_str, &mut collector, DUMMY_SP);
|
||||||
find_testable_code(&input_str, &mut collector, DUMMY_SP);
|
find_testable_code(&input_str, &mut collector, DUMMY_SP);
|
||||||
test_args.insert(0, "rustdoctest".to_string());
|
test_args.insert(0, "rustdoctest".to_string());
|
||||||
testing::test_main(&test_args, collector.tests);
|
testing::test_main(&test_args, collector.tests,
|
||||||
|
testing::Options::new().display_output(display_warnings));
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,8 @@ pub fn run(input: &str,
|
||||||
mut test_args: Vec<String>,
|
mut test_args: Vec<String>,
|
||||||
crate_name: Option<String>,
|
crate_name: Option<String>,
|
||||||
maybe_sysroot: Option<PathBuf>,
|
maybe_sysroot: Option<PathBuf>,
|
||||||
render_type: RenderType)
|
render_type: RenderType,
|
||||||
|
display_warnings: bool)
|
||||||
-> isize {
|
-> isize {
|
||||||
let input_path = PathBuf::from(input);
|
let input_path = PathBuf::from(input);
|
||||||
let input = config::Input::File(input_path.clone());
|
let input = config::Input::File(input_path.clone());
|
||||||
|
@ -127,7 +128,8 @@ pub fn run(input: &str,
|
||||||
test_args.insert(0, "rustdoctest".to_string());
|
test_args.insert(0, "rustdoctest".to_string());
|
||||||
|
|
||||||
testing::test_main(&test_args,
|
testing::test_main(&test_args,
|
||||||
collector.tests.into_iter().collect());
|
collector.tests.into_iter().collect(),
|
||||||
|
testing::Options::new().display_output(display_warnings));
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,11 +43,16 @@ fn main() {
|
||||||
println!("cargo:rustc-link-lib=pthread");
|
println!("cargo:rustc-link-lib=pthread");
|
||||||
} else if target.contains("apple-darwin") {
|
} else if target.contains("apple-darwin") {
|
||||||
println!("cargo:rustc-link-lib=System");
|
println!("cargo:rustc-link-lib=System");
|
||||||
|
|
||||||
|
// res_init and friends require -lresolv on macOS/iOS.
|
||||||
|
// See #41582 and http://blog.achernya.com/2013/03/os-x-has-silly-libsystem.html
|
||||||
|
println!("cargo:rustc-link-lib=resolv");
|
||||||
} else if target.contains("apple-ios") {
|
} else if target.contains("apple-ios") {
|
||||||
println!("cargo:rustc-link-lib=System");
|
println!("cargo:rustc-link-lib=System");
|
||||||
println!("cargo:rustc-link-lib=objc");
|
println!("cargo:rustc-link-lib=objc");
|
||||||
println!("cargo:rustc-link-lib=framework=Security");
|
println!("cargo:rustc-link-lib=framework=Security");
|
||||||
println!("cargo:rustc-link-lib=framework=Foundation");
|
println!("cargo:rustc-link-lib=framework=Foundation");
|
||||||
|
println!("cargo:rustc-link-lib=resolv");
|
||||||
} else if target.contains("windows") {
|
} else if target.contains("windows") {
|
||||||
println!("cargo:rustc-link-lib=advapi32");
|
println!("cargo:rustc-link-lib=advapi32");
|
||||||
println!("cargo:rustc-link-lib=ws2_32");
|
println!("cargo:rustc-link-lib=ws2_32");
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use alloc::heap::{EMPTY, allocate, deallocate};
|
use alloc::heap::{allocate, deallocate};
|
||||||
|
|
||||||
use cmp;
|
use cmp;
|
||||||
use hash::{BuildHasher, Hash, Hasher};
|
use hash::{BuildHasher, Hash, Hasher};
|
||||||
|
@ -33,6 +33,7 @@ use self::BucketState::*;
|
||||||
type HashUint = usize;
|
type HashUint = usize;
|
||||||
|
|
||||||
const EMPTY_BUCKET: HashUint = 0;
|
const EMPTY_BUCKET: HashUint = 0;
|
||||||
|
const EMPTY: usize = 1;
|
||||||
|
|
||||||
/// Special `Unique<HashUint>` that uses the lower bit of the pointer
|
/// Special `Unique<HashUint>` that uses the lower bit of the pointer
|
||||||
/// to expose a boolean tag.
|
/// to expose a boolean tag.
|
||||||
|
@ -49,24 +50,25 @@ impl TaggedHashUintPtr {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn set_tag(&mut self, value: bool) {
|
fn set_tag(&mut self, value: bool) {
|
||||||
let usize_ptr = &*self.0 as *const *mut HashUint as *mut usize;
|
let mut usize_ptr = self.0.as_ptr() as usize;
|
||||||
unsafe {
|
unsafe {
|
||||||
if value {
|
if value {
|
||||||
*usize_ptr |= 1;
|
usize_ptr |= 1;
|
||||||
} else {
|
} else {
|
||||||
*usize_ptr &= !1;
|
usize_ptr &= !1;
|
||||||
}
|
}
|
||||||
|
self.0 = Unique::new(usize_ptr as *mut HashUint)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn tag(&self) -> bool {
|
fn tag(&self) -> bool {
|
||||||
(*self.0 as usize) & 1 == 1
|
(self.0.as_ptr() as usize) & 1 == 1
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn ptr(&self) -> *mut HashUint {
|
fn ptr(&self) -> *mut HashUint {
|
||||||
(*self.0 as usize & !1) as *mut HashUint
|
(self.0.as_ptr() as usize & !1) as *mut HashUint
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1112,10 +1114,12 @@ impl<'a, K, V> Iterator for Drain<'a, K, V> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn next(&mut self) -> Option<(SafeHash, K, V)> {
|
fn next(&mut self) -> Option<(SafeHash, K, V)> {
|
||||||
self.iter.next().map(|raw| unsafe {
|
self.iter.next().map(|raw| {
|
||||||
(*self.table.as_mut_ptr()).size -= 1;
|
unsafe {
|
||||||
let (k, v) = ptr::read(raw.pair());
|
self.table.as_mut().size -= 1;
|
||||||
(SafeHash { hash: ptr::replace(&mut *raw.hash(), EMPTY_BUCKET) }, k, v)
|
let (k, v) = ptr::read(raw.pair());
|
||||||
|
(SafeHash { hash: ptr::replace(&mut *raw.hash(), EMPTY_BUCKET) }, k, v)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,3 +38,8 @@ pub unsafe fn destroy(key: Key) {
|
||||||
let r = libc::pthread_key_delete(key);
|
let r = libc::pthread_key_delete(key);
|
||||||
debug_assert_eq!(r, 0);
|
debug_assert_eq!(r, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn requires_synchronized_create() -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
|
@ -935,7 +935,6 @@ extern "system" {
|
||||||
args: *const c_void)
|
args: *const c_void)
|
||||||
-> DWORD;
|
-> DWORD;
|
||||||
pub fn TlsAlloc() -> DWORD;
|
pub fn TlsAlloc() -> DWORD;
|
||||||
pub fn TlsFree(dwTlsIndex: DWORD) -> BOOL;
|
|
||||||
pub fn TlsGetValue(dwTlsIndex: DWORD) -> LPVOID;
|
pub fn TlsGetValue(dwTlsIndex: DWORD) -> LPVOID;
|
||||||
pub fn TlsSetValue(dwTlsIndex: DWORD, lpTlsvalue: LPVOID) -> BOOL;
|
pub fn TlsSetValue(dwTlsIndex: DWORD, lpTlsvalue: LPVOID) -> BOOL;
|
||||||
pub fn GetLastError() -> DWORD;
|
pub fn GetLastError() -> DWORD;
|
||||||
|
|
|
@ -8,10 +8,11 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
use mem;
|
||||||
use ptr;
|
use ptr;
|
||||||
|
use sync::atomic::AtomicPtr;
|
||||||
|
use sync::atomic::Ordering::SeqCst;
|
||||||
use sys::c;
|
use sys::c;
|
||||||
use sys_common::mutex::Mutex;
|
|
||||||
use sys_common;
|
|
||||||
|
|
||||||
pub type Key = c::DWORD;
|
pub type Key = c::DWORD;
|
||||||
pub type Dtor = unsafe extern fn(*mut u8);
|
pub type Dtor = unsafe extern fn(*mut u8);
|
||||||
|
@ -34,8 +35,6 @@ pub type Dtor = unsafe extern fn(*mut u8);
|
||||||
// * All TLS destructors are tracked by *us*, not the windows runtime. This
|
// * All TLS destructors are tracked by *us*, not the windows runtime. This
|
||||||
// means that we have a global list of destructors for each TLS key that
|
// means that we have a global list of destructors for each TLS key that
|
||||||
// we know about.
|
// we know about.
|
||||||
// * When a TLS key is destroyed, we're sure to remove it from the dtor list
|
|
||||||
// if it's in there.
|
|
||||||
// * When a thread exits, we run over the entire list and run dtors for all
|
// * When a thread exits, we run over the entire list and run dtors for all
|
||||||
// non-null keys. This attempts to match Unix semantics in this regard.
|
// non-null keys. This attempts to match Unix semantics in this regard.
|
||||||
//
|
//
|
||||||
|
@ -50,13 +49,6 @@ pub type Dtor = unsafe extern fn(*mut u8);
|
||||||
// [2]: https://github.com/ChromiumWebApps/chromium/blob/master/base
|
// [2]: https://github.com/ChromiumWebApps/chromium/blob/master/base
|
||||||
// /threading/thread_local_storage_win.cc#L42
|
// /threading/thread_local_storage_win.cc#L42
|
||||||
|
|
||||||
// NB these are specifically not types from `std::sync` as they currently rely
|
|
||||||
// on poisoning and this module needs to operate at a lower level than requiring
|
|
||||||
// the thread infrastructure to be in place (useful on the borders of
|
|
||||||
// initialization/destruction).
|
|
||||||
static DTOR_LOCK: Mutex = Mutex::new();
|
|
||||||
static mut DTORS: *mut Vec<(Key, Dtor)> = ptr::null_mut();
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
// Native bindings
|
// Native bindings
|
||||||
//
|
//
|
||||||
|
@ -85,81 +77,64 @@ pub unsafe fn get(key: Key) -> *mut u8 {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn destroy(key: Key) {
|
pub unsafe fn destroy(_key: Key) {
|
||||||
if unregister_dtor(key) {
|
rtabort!("can't destroy tls keys on windows")
|
||||||
// FIXME: Currently if a key has a destructor associated with it we
|
}
|
||||||
// can't actually ever unregister it. If we were to
|
|
||||||
// unregister it, then any key destruction would have to be
|
#[inline]
|
||||||
// serialized with respect to actually running destructors.
|
pub fn requires_synchronized_create() -> bool {
|
||||||
//
|
true
|
||||||
// We want to avoid a race where right before run_dtors runs
|
|
||||||
// some destructors TlsFree is called. Allowing the call to
|
|
||||||
// TlsFree would imply that the caller understands that *all
|
|
||||||
// known threads* are not exiting, which is quite a difficult
|
|
||||||
// thing to know!
|
|
||||||
//
|
|
||||||
// For now we just leak all keys with dtors to "fix" this.
|
|
||||||
// Note that source [2] above shows precedent for this sort
|
|
||||||
// of strategy.
|
|
||||||
} else {
|
|
||||||
let r = c::TlsFree(key);
|
|
||||||
debug_assert!(r != 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
// Dtor registration
|
// Dtor registration
|
||||||
//
|
//
|
||||||
// These functions are associated with registering and unregistering
|
// Windows has no native support for running destructors so we manage our own
|
||||||
// destructors. They're pretty simple, they just push onto a vector and scan
|
// list of destructors to keep track of how to destroy keys. We then install a
|
||||||
// a vector currently.
|
// callback later to get invoked whenever a thread exits, running all
|
||||||
|
// appropriate destructors.
|
||||||
//
|
//
|
||||||
// FIXME: This could probably be at least a little faster with a BTree.
|
// Currently unregistration from this list is not supported. A destructor can be
|
||||||
|
// registered but cannot be unregistered. There's various simplifying reasons
|
||||||
|
// for doing this, the big ones being:
|
||||||
|
//
|
||||||
|
// 1. Currently we don't even support deallocating TLS keys, so normal operation
|
||||||
|
// doesn't need to deallocate a destructor.
|
||||||
|
// 2. There is no point in time where we know we can unregister a destructor
|
||||||
|
// because it could always be getting run by some remote thread.
|
||||||
|
//
|
||||||
|
// Typically processes have a statically known set of TLS keys which is pretty
|
||||||
|
// small, and we'd want to keep this memory alive for the whole process anyway
|
||||||
|
// really.
|
||||||
|
//
|
||||||
|
// Perhaps one day we can fold the `Box` here into a static allocation,
|
||||||
|
// expanding the `StaticKey` structure to contain not only a slot for the TLS
|
||||||
|
// key but also a slot for the destructor queue on windows. An optimization for
|
||||||
|
// another day!
|
||||||
|
|
||||||
unsafe fn init_dtors() {
|
static DTORS: AtomicPtr<Node> = AtomicPtr::new(ptr::null_mut());
|
||||||
if !DTORS.is_null() { return }
|
|
||||||
|
|
||||||
let dtors = box Vec::<(Key, Dtor)>::new();
|
struct Node {
|
||||||
|
dtor: Dtor,
|
||||||
let res = sys_common::at_exit(move|| {
|
key: Key,
|
||||||
DTOR_LOCK.lock();
|
next: *mut Node,
|
||||||
let dtors = DTORS;
|
|
||||||
DTORS = 1 as *mut _;
|
|
||||||
Box::from_raw(dtors);
|
|
||||||
assert!(DTORS as usize == 1); // can't re-init after destructing
|
|
||||||
DTOR_LOCK.unlock();
|
|
||||||
});
|
|
||||||
if res.is_ok() {
|
|
||||||
DTORS = Box::into_raw(dtors);
|
|
||||||
} else {
|
|
||||||
DTORS = 1 as *mut _;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn register_dtor(key: Key, dtor: Dtor) {
|
unsafe fn register_dtor(key: Key, dtor: Dtor) {
|
||||||
DTOR_LOCK.lock();
|
let mut node = Box::new(Node {
|
||||||
init_dtors();
|
key: key,
|
||||||
assert!(DTORS as usize != 0);
|
dtor: dtor,
|
||||||
assert!(DTORS as usize != 1,
|
next: ptr::null_mut(),
|
||||||
"cannot create new TLS keys after the main thread has exited");
|
});
|
||||||
(*DTORS).push((key, dtor));
|
|
||||||
DTOR_LOCK.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn unregister_dtor(key: Key) -> bool {
|
let mut head = DTORS.load(SeqCst);
|
||||||
DTOR_LOCK.lock();
|
loop {
|
||||||
init_dtors();
|
node.next = head;
|
||||||
assert!(DTORS as usize != 0);
|
match DTORS.compare_exchange(head, &mut *node, SeqCst, SeqCst) {
|
||||||
assert!(DTORS as usize != 1,
|
Ok(_) => return mem::forget(node),
|
||||||
"cannot unregister destructors after the main thread has exited");
|
Err(cur) => head = cur,
|
||||||
let ret = {
|
}
|
||||||
let dtors = &mut *DTORS;
|
}
|
||||||
let before = dtors.len();
|
|
||||||
dtors.retain(|&(k, _)| k != key);
|
|
||||||
dtors.len() != before
|
|
||||||
};
|
|
||||||
DTOR_LOCK.unlock();
|
|
||||||
ret
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
|
@ -196,16 +171,12 @@ unsafe fn unregister_dtor(key: Key) -> bool {
|
||||||
// # Ok, what's up with running all these destructors?
|
// # Ok, what's up with running all these destructors?
|
||||||
//
|
//
|
||||||
// This will likely need to be improved over time, but this function
|
// This will likely need to be improved over time, but this function
|
||||||
// attempts a "poor man's" destructor callback system. To do this we clone a
|
// attempts a "poor man's" destructor callback system. Once we've got a list
|
||||||
// local copy of the dtor list to start out with. This is our fudgy attempt
|
// of what to run, we iterate over all keys, check their values, and then run
|
||||||
// to not hold the lock while destructors run and not worry about the list
|
// destructors if the values turn out to be non null (setting them to null just
|
||||||
// changing while we're looking at it.
|
// beforehand). We do this a few times in a loop to basically match Unix
|
||||||
//
|
// semantics. If we don't reach a fixed point after a short while then we just
|
||||||
// Once we've got a list of what to run, we iterate over all keys, check
|
// inevitably leak something most likely.
|
||||||
// their values, and then run destructors if the values turn out to be non
|
|
||||||
// null (setting them to null just beforehand). We do this a few times in a
|
|
||||||
// loop to basically match Unix semantics. If we don't reach a fixed point
|
|
||||||
// after a short while then we just inevitably leak something most likely.
|
|
||||||
//
|
//
|
||||||
// # The article mentions weird stuff about "/INCLUDE"?
|
// # The article mentions weird stuff about "/INCLUDE"?
|
||||||
//
|
//
|
||||||
|
@ -259,25 +230,21 @@ unsafe extern "system" fn on_tls_callback(h: c::LPVOID,
|
||||||
unsafe fn run_dtors() {
|
unsafe fn run_dtors() {
|
||||||
let mut any_run = true;
|
let mut any_run = true;
|
||||||
for _ in 0..5 {
|
for _ in 0..5 {
|
||||||
if !any_run { break }
|
if !any_run {
|
||||||
|
break
|
||||||
|
}
|
||||||
any_run = false;
|
any_run = false;
|
||||||
let dtors = {
|
let mut cur = DTORS.load(SeqCst);
|
||||||
DTOR_LOCK.lock();
|
while !cur.is_null() {
|
||||||
let ret = if DTORS as usize <= 1 {
|
let ptr = c::TlsGetValue((*cur).key);
|
||||||
Vec::new()
|
|
||||||
} else {
|
|
||||||
(*DTORS).iter().map(|s| *s).collect()
|
|
||||||
};
|
|
||||||
DTOR_LOCK.unlock();
|
|
||||||
ret
|
|
||||||
};
|
|
||||||
for &(key, dtor) in &dtors {
|
|
||||||
let ptr = c::TlsGetValue(key);
|
|
||||||
if !ptr.is_null() {
|
if !ptr.is_null() {
|
||||||
c::TlsSetValue(key, ptr::null_mut());
|
c::TlsSetValue((*cur).key, ptr::null_mut());
|
||||||
dtor(ptr as *mut _);
|
((*cur).dtor)(ptr as *mut _);
|
||||||
any_run = true;
|
any_run = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cur = (*cur).next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -177,9 +177,22 @@ pub fn lookup_host(host: &str) -> io::Result<LookupHost> {
|
||||||
};
|
};
|
||||||
let mut res = ptr::null_mut();
|
let mut res = ptr::null_mut();
|
||||||
unsafe {
|
unsafe {
|
||||||
cvt_gai(c::getaddrinfo(c_host.as_ptr(), ptr::null(), &hints,
|
match cvt_gai(c::getaddrinfo(c_host.as_ptr(), ptr::null(), &hints, &mut res)) {
|
||||||
&mut res))?;
|
Ok(_) => {
|
||||||
Ok(LookupHost { original: res, cur: res })
|
Ok(LookupHost { original: res, cur: res })
|
||||||
|
},
|
||||||
|
#[cfg(unix)]
|
||||||
|
Err(e) => {
|
||||||
|
// The lookup failure could be caused by using a stale /etc/resolv.conf.
|
||||||
|
// See https://github.com/rust-lang/rust/issues/41570.
|
||||||
|
// We therefore force a reload of the nameserver information.
|
||||||
|
c::res_init();
|
||||||
|
Err(e)
|
||||||
|
},
|
||||||
|
// the cfg is needed here to avoid an "unreachable pattern" warning
|
||||||
|
#[cfg(not(unix))]
|
||||||
|
Err(e) => Err(e),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,7 @@
|
||||||
use sync::atomic::{self, AtomicUsize, Ordering};
|
use sync::atomic::{self, AtomicUsize, Ordering};
|
||||||
|
|
||||||
use sys::thread_local as imp;
|
use sys::thread_local as imp;
|
||||||
|
use sys_common::mutex::Mutex;
|
||||||
|
|
||||||
/// A type for TLS keys that are statically allocated.
|
/// A type for TLS keys that are statically allocated.
|
||||||
///
|
///
|
||||||
|
@ -145,20 +146,6 @@ impl StaticKey {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn set(&self, val: *mut u8) { imp::set(self.key(), val) }
|
pub unsafe fn set(&self, val: *mut u8) { imp::set(self.key(), val) }
|
||||||
|
|
||||||
/// Deallocates this OS TLS key.
|
|
||||||
///
|
|
||||||
/// This function is unsafe as there is no guarantee that the key is not
|
|
||||||
/// currently in use by other threads or will not ever be used again.
|
|
||||||
///
|
|
||||||
/// Note that this does *not* run the user-provided destructor if one was
|
|
||||||
/// specified at definition time. Doing so must be done manually.
|
|
||||||
pub unsafe fn destroy(&self) {
|
|
||||||
match self.key.swap(0, Ordering::SeqCst) {
|
|
||||||
0 => {}
|
|
||||||
n => { imp::destroy(n as imp::Key) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn key(&self) -> imp::Key {
|
unsafe fn key(&self) -> imp::Key {
|
||||||
match self.key.load(Ordering::Relaxed) {
|
match self.key.load(Ordering::Relaxed) {
|
||||||
|
@ -168,6 +155,24 @@ impl StaticKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn lazy_init(&self) -> usize {
|
unsafe fn lazy_init(&self) -> usize {
|
||||||
|
// Currently the Windows implementation of TLS is pretty hairy, and
|
||||||
|
// it greatly simplifies creation if we just synchronize everything.
|
||||||
|
//
|
||||||
|
// Additionally a 0-index of a tls key hasn't been seen on windows, so
|
||||||
|
// we just simplify the whole branch.
|
||||||
|
if imp::requires_synchronized_create() {
|
||||||
|
static INIT_LOCK: Mutex = Mutex::new();
|
||||||
|
INIT_LOCK.lock();
|
||||||
|
let mut key = self.key.load(Ordering::SeqCst);
|
||||||
|
if key == 0 {
|
||||||
|
key = imp::create(self.dtor) as usize;
|
||||||
|
self.key.store(key, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
INIT_LOCK.unlock();
|
||||||
|
assert!(key != 0);
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
|
||||||
// POSIX allows the key created here to be 0, but the compare_and_swap
|
// POSIX allows the key created here to be 0, but the compare_and_swap
|
||||||
// below relies on using 0 as a sentinel value to check who won the
|
// below relies on using 0 as a sentinel value to check who won the
|
||||||
// race to set the shared TLS key. As far as I know, there is no
|
// race to set the shared TLS key. As far as I know, there is no
|
||||||
|
@ -227,7 +232,9 @@ impl Key {
|
||||||
|
|
||||||
impl Drop for Key {
|
impl Drop for Key {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe { imp::destroy(self.key) }
|
// Right now Windows doesn't support TLS key destruction, but this also
|
||||||
|
// isn't used anywhere other than tests, so just leak the TLS key.
|
||||||
|
// unsafe { imp::destroy(self.key) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// NOTE: The following code was generated by "src/etc/unicode.py", do not edit directly
|
// NOTE: The following code was generated by "./unicode.py", do not edit directly
|
||||||
|
|
||||||
#![allow(missing_docs, non_upper_case_globals, non_snake_case)]
|
#![allow(missing_docs, non_upper_case_globals, non_snake_case)]
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ preamble = '''// Copyright 2012-2016 The Rust Project Developers. See the COPYRI
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// NOTE: The following code was generated by "src/etc/unicode.py", do not edit directly
|
// NOTE: The following code was generated by "./unicode.py", do not edit directly
|
||||||
|
|
||||||
#![allow(missing_docs, non_upper_case_globals, non_snake_case)]
|
#![allow(missing_docs, non_upper_case_globals, non_snake_case)]
|
||||||
'''
|
'''
|
|
@ -2700,6 +2700,19 @@ impl<'a> Parser<'a> {
|
||||||
let (span, e) = self.interpolated_or_expr_span(e)?;
|
let (span, e) = self.interpolated_or_expr_span(e)?;
|
||||||
(span, self.mk_unary(UnOp::Not, e))
|
(span, self.mk_unary(UnOp::Not, e))
|
||||||
}
|
}
|
||||||
|
// Suggest `!` for bitwise negation when encountering a `~`
|
||||||
|
token::Tilde => {
|
||||||
|
self.bump();
|
||||||
|
let e = self.parse_prefix_expr(None);
|
||||||
|
let (span, e) = self.interpolated_or_expr_span(e)?;
|
||||||
|
let span_of_tilde = lo;
|
||||||
|
let mut err = self.diagnostic().struct_span_err(span_of_tilde,
|
||||||
|
"`~` can not be used as an unary operator");
|
||||||
|
err.span_label(span_of_tilde, &"did you mean `!`?");
|
||||||
|
err.help("use `!` instead of `~` if you meant to perform bitwise negation");
|
||||||
|
err.emit();
|
||||||
|
(span, self.mk_unary(UnOp::Not, e))
|
||||||
|
}
|
||||||
token::BinOp(token::Minus) => {
|
token::BinOp(token::Minus) => {
|
||||||
self.bump();
|
self.bump();
|
||||||
let e = self.parse_prefix_expr(None);
|
let e = self.parse_prefix_expr(None);
|
||||||
|
|
|
@ -442,7 +442,7 @@ We're going to be building a module that looks more or less like:
|
||||||
mod __test {
|
mod __test {
|
||||||
extern crate test (name = "test", vers = "...");
|
extern crate test (name = "test", vers = "...");
|
||||||
fn main() {
|
fn main() {
|
||||||
test::test_main_static(&::os::args()[], tests)
|
test::test_main_static(&::os::args()[], tests, test::Options::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
static tests : &'static [test::TestDescAndFn] = &[
|
static tests : &'static [test::TestDescAndFn] = &[
|
||||||
|
@ -478,7 +478,7 @@ fn mk_main(cx: &mut TestCtxt) -> P<ast::Item> {
|
||||||
// pub fn main() {
|
// pub fn main() {
|
||||||
// #![main]
|
// #![main]
|
||||||
// use std::slice::AsSlice;
|
// use std::slice::AsSlice;
|
||||||
// test::test_main_static(::std::os::args().as_slice(), TESTS);
|
// test::test_main_static(::std::os::args().as_slice(), TESTS, test::Options::new());
|
||||||
// }
|
// }
|
||||||
|
|
||||||
let sp = ignored_span(cx, DUMMY_SP);
|
let sp = ignored_span(cx, DUMMY_SP);
|
||||||
|
|
|
@ -76,7 +76,7 @@ pub mod test {
|
||||||
pub use {Bencher, TestName, TestResult, TestDesc, TestDescAndFn, TestOpts, TrFailed,
|
pub use {Bencher, TestName, TestResult, TestDesc, TestDescAndFn, TestOpts, TrFailed,
|
||||||
TrFailedMsg, TrIgnored, TrOk, Metric, MetricMap, StaticTestFn, StaticTestName,
|
TrFailedMsg, TrIgnored, TrOk, Metric, MetricMap, StaticTestFn, StaticTestName,
|
||||||
DynTestName, DynTestFn, run_test, test_main, test_main_static, filter_tests,
|
DynTestName, DynTestFn, run_test, test_main, test_main_static, filter_tests,
|
||||||
parse_opts, StaticBenchFn, ShouldPanic};
|
parse_opts, StaticBenchFn, ShouldPanic, Options};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod stats;
|
pub mod stats;
|
||||||
|
@ -252,14 +252,34 @@ impl Clone for MetricMap {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// In case we want to add other options as well, just add them in this struct.
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub struct Options {
|
||||||
|
display_output: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Options {
|
||||||
|
pub fn new() -> Options {
|
||||||
|
Options {
|
||||||
|
display_output: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn display_output(mut self, display_output: bool) -> Options {
|
||||||
|
self.display_output = display_output;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// The default console test runner. It accepts the command line
|
// The default console test runner. It accepts the command line
|
||||||
// arguments and a vector of test_descs.
|
// arguments and a vector of test_descs.
|
||||||
pub fn test_main(args: &[String], tests: Vec<TestDescAndFn>) {
|
pub fn test_main(args: &[String], tests: Vec<TestDescAndFn>, options: Options) {
|
||||||
let opts = match parse_opts(args) {
|
let mut opts = match parse_opts(args) {
|
||||||
Some(Ok(o)) => o,
|
Some(Ok(o)) => o,
|
||||||
Some(Err(msg)) => panic!("{:?}", msg),
|
Some(Err(msg)) => panic!("{:?}", msg),
|
||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
|
opts.options = options;
|
||||||
if opts.list {
|
if opts.list {
|
||||||
if let Err(e) = list_tests_console(&opts, tests) {
|
if let Err(e) = list_tests_console(&opts, tests) {
|
||||||
panic!("io error when listing tests: {:?}", e);
|
panic!("io error when listing tests: {:?}", e);
|
||||||
|
@ -301,16 +321,17 @@ pub fn test_main_static(tests: &[TestDescAndFn]) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
test_main(&args, owned_tests)
|
test_main(&args, owned_tests, Options::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub enum ColorConfig {
|
pub enum ColorConfig {
|
||||||
AutoColor,
|
AutoColor,
|
||||||
AlwaysColor,
|
AlwaysColor,
|
||||||
NeverColor,
|
NeverColor,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct TestOpts {
|
pub struct TestOpts {
|
||||||
pub list: bool,
|
pub list: bool,
|
||||||
pub filter: Option<String>,
|
pub filter: Option<String>,
|
||||||
|
@ -324,6 +345,7 @@ pub struct TestOpts {
|
||||||
pub quiet: bool,
|
pub quiet: bool,
|
||||||
pub test_threads: Option<usize>,
|
pub test_threads: Option<usize>,
|
||||||
pub skip: Vec<String>,
|
pub skip: Vec<String>,
|
||||||
|
pub options: Options,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestOpts {
|
impl TestOpts {
|
||||||
|
@ -342,6 +364,7 @@ impl TestOpts {
|
||||||
quiet: false,
|
quiet: false,
|
||||||
test_threads: None,
|
test_threads: None,
|
||||||
skip: vec![],
|
skip: vec![],
|
||||||
|
options: Options::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -481,6 +504,7 @@ pub fn parse_opts(args: &[String]) -> Option<OptRes> {
|
||||||
quiet: quiet,
|
quiet: quiet,
|
||||||
test_threads: test_threads,
|
test_threads: test_threads,
|
||||||
skip: matches.opt_strs("skip"),
|
skip: matches.opt_strs("skip"),
|
||||||
|
options: Options::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(Ok(test_opts))
|
Some(Ok(test_opts))
|
||||||
|
@ -521,7 +545,9 @@ struct ConsoleTestState<T> {
|
||||||
measured: usize,
|
measured: usize,
|
||||||
metrics: MetricMap,
|
metrics: MetricMap,
|
||||||
failures: Vec<(TestDesc, Vec<u8>)>,
|
failures: Vec<(TestDesc, Vec<u8>)>,
|
||||||
|
not_failures: Vec<(TestDesc, Vec<u8>)>,
|
||||||
max_name_len: usize, // number of columns to fill when aligning names
|
max_name_len: usize, // number of columns to fill when aligning names
|
||||||
|
options: Options,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Write> ConsoleTestState<T> {
|
impl<T: Write> ConsoleTestState<T> {
|
||||||
|
@ -547,7 +573,9 @@ impl<T: Write> ConsoleTestState<T> {
|
||||||
measured: 0,
|
measured: 0,
|
||||||
metrics: MetricMap::new(),
|
metrics: MetricMap::new(),
|
||||||
failures: Vec::new(),
|
failures: Vec::new(),
|
||||||
|
not_failures: Vec::new(),
|
||||||
max_name_len: 0,
|
max_name_len: 0,
|
||||||
|
options: opts.options,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -703,9 +731,38 @@ impl<T: Write> ConsoleTestState<T> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn write_outputs(&mut self) -> io::Result<()> {
|
||||||
|
self.write_plain("\nsuccesses:\n")?;
|
||||||
|
let mut successes = Vec::new();
|
||||||
|
let mut stdouts = String::new();
|
||||||
|
for &(ref f, ref stdout) in &self.not_failures {
|
||||||
|
successes.push(f.name.to_string());
|
||||||
|
if !stdout.is_empty() {
|
||||||
|
stdouts.push_str(&format!("---- {} stdout ----\n\t", f.name));
|
||||||
|
let output = String::from_utf8_lossy(stdout);
|
||||||
|
stdouts.push_str(&output);
|
||||||
|
stdouts.push_str("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !stdouts.is_empty() {
|
||||||
|
self.write_plain("\n")?;
|
||||||
|
self.write_plain(&stdouts)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.write_plain("\nsuccesses:\n")?;
|
||||||
|
successes.sort();
|
||||||
|
for name in &successes {
|
||||||
|
self.write_plain(&format!(" {}\n", name))?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn write_run_finish(&mut self) -> io::Result<bool> {
|
pub fn write_run_finish(&mut self) -> io::Result<bool> {
|
||||||
assert!(self.passed + self.failed + self.ignored + self.measured == self.total);
|
assert!(self.passed + self.failed + self.ignored + self.measured == self.total);
|
||||||
|
|
||||||
|
if self.options.display_output {
|
||||||
|
self.write_outputs()?;
|
||||||
|
}
|
||||||
let success = self.failed == 0;
|
let success = self.failed == 0;
|
||||||
if !success {
|
if !success {
|
||||||
self.write_failures()?;
|
self.write_failures()?;
|
||||||
|
@ -824,7 +881,10 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Resu
|
||||||
st.write_log_result(&test, &result)?;
|
st.write_log_result(&test, &result)?;
|
||||||
st.write_result(&result)?;
|
st.write_result(&result)?;
|
||||||
match result {
|
match result {
|
||||||
TrOk => st.passed += 1,
|
TrOk => {
|
||||||
|
st.passed += 1;
|
||||||
|
st.not_failures.push((test, stdout));
|
||||||
|
}
|
||||||
TrIgnored => st.ignored += 1,
|
TrIgnored => st.ignored += 1,
|
||||||
TrMetrics(mm) => {
|
TrMetrics(mm) => {
|
||||||
let tname = test.name;
|
let tname = test.name;
|
||||||
|
@ -901,6 +961,8 @@ fn should_sort_failures_before_printing_them() {
|
||||||
max_name_len: 10,
|
max_name_len: 10,
|
||||||
metrics: MetricMap::new(),
|
metrics: MetricMap::new(),
|
||||||
failures: vec![(test_b, Vec::new()), (test_a, Vec::new())],
|
failures: vec![(test_b, Vec::new()), (test_a, Vec::new())],
|
||||||
|
options: Options::new(),
|
||||||
|
not_failures: Vec::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
st.write_failures().unwrap();
|
st.write_failures().unwrap();
|
||||||
|
|
|
@ -58,13 +58,15 @@ mod signatures {
|
||||||
fn method(&self, x: u32) { }
|
fn method(&self, x: u32) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK
|
|
||||||
struct WillChanges {
|
struct WillChanges {
|
||||||
|
#[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK
|
||||||
x: WillChange,
|
x: WillChange,
|
||||||
|
#[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK
|
||||||
y: WillChange
|
y: WillChange
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK
|
// The fields change, not the type itself.
|
||||||
|
#[rustc_then_this_would_need(ItemSignature)] //~ ERROR no path
|
||||||
fn indirect(x: WillChanges) { }
|
fn indirect(x: WillChanges) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,15 +23,21 @@ fn main() { }
|
||||||
#[rustc_if_this_changed]
|
#[rustc_if_this_changed]
|
||||||
type TypeAlias = u32;
|
type TypeAlias = u32;
|
||||||
|
|
||||||
#[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK
|
// The type alias directly affects the type of the field,
|
||||||
|
// not the enclosing struct:
|
||||||
|
#[rustc_then_this_would_need(ItemSignature)] //~ ERROR no path
|
||||||
struct Struct {
|
struct Struct {
|
||||||
|
#[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK
|
||||||
x: TypeAlias,
|
x: TypeAlias,
|
||||||
y: u32
|
y: u32
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK
|
#[rustc_then_this_would_need(ItemSignature)] //~ ERROR no path
|
||||||
enum Enum {
|
enum Enum {
|
||||||
Variant1(TypeAlias),
|
Variant1 {
|
||||||
|
#[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK
|
||||||
|
t: TypeAlias
|
||||||
|
},
|
||||||
Variant2(i32)
|
Variant2(i32)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
32
src/test/compile-fail/dep-graph-variance-alias.rs
Normal file
32
src/test/compile-fail/dep-graph-variance-alias.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Test that changing what a `type` points to does not go unnoticed
|
||||||
|
// by the variance analysis.
|
||||||
|
|
||||||
|
// compile-flags: -Z query-dep-graph
|
||||||
|
|
||||||
|
#![feature(rustc_attrs)]
|
||||||
|
#![allow(dead_code)]
|
||||||
|
#![allow(unused_variables)]
|
||||||
|
|
||||||
|
fn main() { }
|
||||||
|
|
||||||
|
struct Foo<T> {
|
||||||
|
f: T
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rustc_if_this_changed]
|
||||||
|
type TypeAlias<T> = Foo<T>;
|
||||||
|
|
||||||
|
#[rustc_then_this_would_need(ItemVariances)] //~ ERROR OK
|
||||||
|
struct Use<T> {
|
||||||
|
x: TypeAlias<T>
|
||||||
|
}
|
|
@ -60,7 +60,6 @@ struct Test6<'a, 'b:'a> { //~ ERROR [-, o]
|
||||||
|
|
||||||
#[rustc_variance]
|
#[rustc_variance]
|
||||||
struct Test7<'a> { //~ ERROR [*]
|
struct Test7<'a> { //~ ERROR [*]
|
||||||
//~^ ERROR parameter `'a` is never used
|
|
||||||
x: isize
|
x: isize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
#[rustc_variance]
|
#[rustc_variance]
|
||||||
enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR [+, -, o, *]
|
enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR [+, -, o, *]
|
||||||
//~^ ERROR parameter `'d` is never used
|
|
||||||
Test8A(extern "Rust" fn(&'a isize)),
|
Test8A(extern "Rust" fn(&'a isize)),
|
||||||
Test8B(&'b [isize]),
|
Test8B(&'b [isize]),
|
||||||
Test8C(&'b mut &'c str),
|
Test8C(&'b mut &'c str),
|
||||||
|
@ -24,19 +23,16 @@ enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR [+, -, o, *]
|
||||||
|
|
||||||
#[rustc_variance]
|
#[rustc_variance]
|
||||||
struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR [*, o, -, +]
|
struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR [*, o, -, +]
|
||||||
//~^ ERROR parameter `'w` is never used
|
|
||||||
f: Base<'z, 'y, 'x, 'w>
|
f: Base<'z, 'y, 'x, 'w>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustc_variance] // Combine - and + to yield o
|
#[rustc_variance] // Combine - and + to yield o
|
||||||
struct Derived2<'a, 'b:'a, 'c> { //~ ERROR [o, o, *]
|
struct Derived2<'a, 'b:'a, 'c> { //~ ERROR [o, o, *]
|
||||||
//~^ ERROR parameter `'c` is never used
|
|
||||||
f: Base<'a, 'a, 'b, 'c>
|
f: Base<'a, 'a, 'b, 'c>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustc_variance] // Combine + and o to yield o (just pay attention to 'a here)
|
#[rustc_variance] // Combine + and o to yield o (just pay attention to 'a here)
|
||||||
struct Derived3<'a:'b, 'b, 'c> { //~ ERROR [o, -, *]
|
struct Derived3<'a:'b, 'b, 'c> { //~ ERROR [o, -, *]
|
||||||
//~^ ERROR parameter `'c` is never used
|
|
||||||
f: Base<'a, 'b, 'a, 'c>
|
f: Base<'a, 'b, 'a, 'c>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,8 +30,7 @@ struct TestStruct<U,T:Setter<U>> { //~ ERROR [+, +]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustc_variance]
|
#[rustc_variance]
|
||||||
enum TestEnum<U,T:Setter<U>> {//~ ERROR [*, +]
|
enum TestEnum<U,T:Setter<U>> { //~ ERROR [*, +]
|
||||||
//~^ ERROR parameter `U` is never used
|
|
||||||
Foo(T)
|
Foo(T)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,13 +50,11 @@ trait TestTrait3<U> { //~ ERROR [o, o]
|
||||||
|
|
||||||
#[rustc_variance]
|
#[rustc_variance]
|
||||||
struct TestContraStruct<U,T:Setter<U>> { //~ ERROR [*, +]
|
struct TestContraStruct<U,T:Setter<U>> { //~ ERROR [*, +]
|
||||||
//~^ ERROR parameter `U` is never used
|
|
||||||
t: T
|
t: T
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustc_variance]
|
#[rustc_variance]
|
||||||
struct TestBox<U,T:Getter<U>+Setter<U>> { //~ ERROR [*, +]
|
struct TestBox<U,T:Getter<U>+Setter<U>> { //~ ERROR [*, +]
|
||||||
//~^ ERROR parameter `U` is never used
|
|
||||||
t: T
|
t: T
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,6 +72,7 @@ else
|
||||||
endif
|
endif
|
||||||
else
|
else
|
||||||
ifeq ($(UNAME),Darwin)
|
ifeq ($(UNAME),Darwin)
|
||||||
|
EXTRACFLAGS := -lresolv
|
||||||
else
|
else
|
||||||
ifeq ($(UNAME),FreeBSD)
|
ifeq ($(UNAME),FreeBSD)
|
||||||
EXTRACFLAGS := -lm -lpthread -lgcc_s
|
EXTRACFLAGS := -lm -lpthread -lgcc_s
|
||||||
|
|
23
src/test/run-pass-fulldeps/auxiliary/issue_24106.rs
Normal file
23
src/test/run-pass-fulldeps/auxiliary/issue_24106.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![crate_type="lib"]
|
||||||
|
|
||||||
|
enum E { E0 = 0, E1 = 1 }
|
||||||
|
const E0_U8: u8 = E::E0 as u8;
|
||||||
|
const E1_U8: u8 = E::E1 as u8;
|
||||||
|
|
||||||
|
pub fn go<T>() {
|
||||||
|
match 0 {
|
||||||
|
E0_U8 => (),
|
||||||
|
E1_U8 => (),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
17
src/test/run-pass-fulldeps/issue_24106.rs
Normal file
17
src/test/run-pass-fulldeps/issue_24106.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// aux-build:issue_24106.rs
|
||||||
|
|
||||||
|
extern crate issue_24106;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
issue_24106::go::<()>();
|
||||||
|
}
|
13
src/test/ui/did_you_mean/issue-41679.rs
Normal file
13
src/test/ui/did_you_mean/issue-41679.rs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = ~1;
|
||||||
|
}
|
10
src/test/ui/did_you_mean/issue-41679.stderr
Normal file
10
src/test/ui/did_you_mean/issue-41679.stderr
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
error: `~` can not be used as an unary operator
|
||||||
|
--> $DIR/issue-41679.rs:12:13
|
||||||
|
|
|
||||||
|
12 | let x = ~1;
|
||||||
|
| ^ did you mean `!`?
|
||||||
|
|
|
||||||
|
= help: use `!` instead of `~` if you meant to perform bitwise negation
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
|
@ -336,6 +336,7 @@ pub fn test_opts(config: &Config) -> test::TestOpts {
|
||||||
test_threads: None,
|
test_threads: None,
|
||||||
skip: vec![],
|
skip: vec![],
|
||||||
list: false,
|
list: false,
|
||||||
|
options: test::Options::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -101,7 +101,7 @@ pub fn check(path: &Path, bad: &mut bool) {
|
||||||
filename.starts_with(".#") {
|
filename.starts_with(".#") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if filename == "miniz.c" || filename.contains("jquery") {
|
if filename == "miniz.c" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue